Compare commits
317 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8e67d157e | ||
|
|
e870c7db45 | ||
|
|
6500f8c52c | ||
|
|
4d2f7d83af | ||
|
|
99945fcd04 | ||
|
|
0d952ae43d | ||
|
|
593677d2ff | ||
|
|
c69294c449 | ||
|
|
2a06c7758e | ||
|
|
7ee1ec91a2 | ||
|
|
233fb62bd8 | ||
|
|
6637c267a5 | ||
|
|
99233c44cc | ||
|
|
33528002b4 | ||
|
|
20542a37a8 | ||
|
|
5fd12451f9 | ||
|
|
ba939ccd6c | ||
|
|
3a5f354846 | ||
|
|
fcde6109b0 | ||
|
|
e3bd223dac | ||
|
|
6c8db6eae1 | ||
|
|
3ff0b9e0c9 | ||
|
|
464a942a95 | ||
|
|
d7a4a4a462 | ||
|
|
759b3f7d6d | ||
|
|
958b6c2e57 | ||
|
|
ab15d676d7 | ||
|
|
66761d7ecf | ||
|
|
3afad58a93 | ||
|
|
170e8b519e | ||
|
|
f8684f418a | ||
|
|
881bda7f59 | ||
|
|
9854deb626 | ||
|
|
d6814050dd | ||
|
|
252fc65558 | ||
|
|
8108c7ffaf | ||
|
|
ba9936a572 | ||
|
|
905b601178 | ||
|
|
63fb2d5a44 | ||
|
|
85a5fc0aeb | ||
|
|
4fba3e0b80 | ||
|
|
9d398d999c | ||
|
|
f47b2b52a5 | ||
|
|
fedb6191a1 | ||
|
|
5bf617ebde | ||
|
|
0b82e1cd5b | ||
|
|
9aef34a816 | ||
|
|
0ac6918a41 | ||
|
|
65ee5af78c | ||
|
|
c6fa291571 | ||
|
|
bce4307e9e | ||
|
|
96ad94ab41 | ||
|
|
a5b60217ce | ||
|
|
44fd6694eb | ||
|
|
e48db3a8b6 | ||
|
|
e637bdaf4e | ||
|
|
d558abbdb7 | ||
|
|
4aed0830e5 | ||
|
|
d2dda34b2a | ||
|
|
c3a10c135e | ||
|
|
92e4340732 | ||
|
|
7b22f2031f | ||
|
|
3b14582d6b | ||
|
|
274e1b3dc7 | ||
|
|
de58b0289d | ||
|
|
efea52a4f4 | ||
|
|
763bd36b60 | ||
|
|
0552dbd93c | ||
|
|
18c63ff3d8 | ||
|
|
e04ef56243 | ||
|
|
5d60484553 | ||
|
|
3c846e6f7b | ||
|
|
2850dc69fd | ||
|
|
94205c3a37 | ||
|
|
2ada34b229 | ||
|
|
db396da734 | ||
|
|
0262b4244c | ||
|
|
73ca767d06 | ||
|
|
3ec11c781b | ||
|
|
a79ff060d0 | ||
|
|
43991f8d2f | ||
|
|
6b82069e1a | ||
|
|
276b9a31cd | ||
|
|
5801fa39e9 | ||
|
|
f0ab1b02e6 | ||
|
|
36c28e02fd | ||
|
|
e1c3861832 | ||
|
|
ecfd881ac6 | ||
|
|
81b7335267 | ||
|
|
bb010c2253 | ||
|
|
03b6121194 | ||
|
|
3ef092332b | ||
|
|
540c19792f | ||
|
|
80d1c8206b | ||
|
|
d36faffeca | ||
|
|
7c8c9b94bc | ||
|
|
f5eeed7665 | ||
|
|
80cfd063e2 | ||
|
|
aa45f6586e | ||
|
|
0c80d21e01 | ||
|
|
375c88245a | ||
|
|
ea3430102c | ||
|
|
9de7199b88 | ||
|
|
ae07714927 | ||
|
|
0e41a3fad4 | ||
|
|
61e850ceb5 | ||
|
|
992b6b9fcc | ||
|
|
7b71344051 | ||
|
|
605362f89d | ||
|
|
fbbaa42ee5 | ||
|
|
099992ecae | ||
|
|
d78ae20e64 | ||
|
|
5c02d65ddb | ||
|
|
d36067cd35 | ||
|
|
f1b2134dd1 | ||
|
|
74cda80d3b | ||
|
|
9a3a848cc8 | ||
|
|
a1a4c2ada7 | ||
|
|
189dbf02b6 | ||
|
|
42ecd42ac0 | ||
|
|
a10f6a96d7 | ||
|
|
0d232a1422 | ||
|
|
285bffd2c6 | ||
|
|
61c233a08e | ||
|
|
d2d716483a | ||
|
|
f16033aafd | ||
|
|
ae5366a31d | ||
|
|
6b23cbc852 | ||
|
|
7f9bc9e863 | ||
|
|
13219cebcb | ||
|
|
93a6e5780e | ||
|
|
fe55e0d93d | ||
|
|
e1f0747e4c | ||
|
|
e37b67d013 | ||
|
|
ad18689d92 | ||
|
|
0f80b1058d | ||
|
|
0d48af3f36 | ||
|
|
4613644cce | ||
|
|
718e475613 | ||
|
|
aa5dd15352 | ||
|
|
5bff65c132 | ||
|
|
24bc09b79b | ||
|
|
37c17d5541 | ||
|
|
120948fa48 | ||
|
|
66e6f0c3cb | ||
|
|
f7447efa8c | ||
|
|
f4d36a58c2 | ||
|
|
6d1c3e1aec | ||
|
|
73cc0505f5 | ||
|
|
c75f5a1fd8 | ||
|
|
39d8880f2c | ||
|
|
5538ec7bd8 | ||
|
|
f101d6429b | ||
|
|
fe06fc85d3 | ||
|
|
f36a1eaa8b | ||
|
|
a64bdda9ae | ||
|
|
01d19b4b52 | ||
|
|
f0c1a01bc2 | ||
|
|
7be680d3f8 | ||
|
|
57dab1e1db | ||
|
|
21b3c890a1 | ||
|
|
fb0ec720a4 | ||
|
|
7971ed33d1 | ||
|
|
885835a655 | ||
|
|
4c64554808 | ||
|
|
548beeb6b1 | ||
|
|
e3066f9577 | ||
|
|
e391367488 | ||
|
|
18ddf2f7b5 | ||
|
|
f8ee5a0785 | ||
|
|
b467a3c877 | ||
|
|
f2d48e9019 | ||
|
|
5e314bf3e9 | ||
|
|
05ba26c7c8 | ||
|
|
87b72364a4 | ||
|
|
0e3ff1f970 | ||
|
|
ec3e74d7f4 | ||
|
|
62bda71c85 | ||
|
|
83e0939088 | ||
|
|
9798d96e37 | ||
|
|
6006dd933d | ||
|
|
ac2caf1088 | ||
|
|
8511e80f48 | ||
|
|
91bc3f1f92 | ||
|
|
8463b48f90 | ||
|
|
e3342a3cf6 | ||
|
|
524a8a42a4 | ||
|
|
7bf59b5bcd | ||
|
|
025f3e9596 | ||
|
|
8258edd8a5 | ||
|
|
8669ca219b | ||
|
|
71652690b6 | ||
|
|
37693d2812 | ||
|
|
8fbe200012 | ||
|
|
1a34a13e33 | ||
|
|
ef772b0049 | ||
|
|
6fcabbde08 | ||
|
|
14f290f8ab | ||
|
|
e2e09d5754 | ||
|
|
448a8d3845 | ||
|
|
514936beb8 | ||
|
|
f5c09d0bbf | ||
|
|
014f655c5f | ||
|
|
bf30dc3038 | ||
|
|
ef2ef07cbd | ||
|
|
1a4440080d | ||
|
|
ac0086a745 | ||
|
|
2494daaf68 | ||
|
|
9b404f9de6 | ||
|
|
5344b7dab8 | ||
|
|
0007a53b9c | ||
|
|
1dd05f44eb | ||
|
|
bf7b122ab2 | ||
|
|
e29048b54a | ||
|
|
2eeb640eca | ||
|
|
ceb200fe81 | ||
|
|
f5f8239057 | ||
|
|
6f9d051784 | ||
|
|
931862e97f | ||
|
|
1d0127de21 | ||
|
|
2d8fc61677 | ||
|
|
1e31011874 | ||
|
|
75cdbf19aa | ||
|
|
4339bd5cfa | ||
|
|
1ab2fdaa10 | ||
|
|
eda540f6ec | ||
|
|
90a330da16 | ||
|
|
cad1f9cbd1 | ||
|
|
f6203bd5a8 | ||
|
|
03cf94ebe8 | ||
|
|
c3087dd179 | ||
|
|
2c305af478 | ||
|
|
72e6f64ca8 | ||
|
|
b9fac687ff | ||
|
|
2c88eb6fbe | ||
|
|
a67e3bfdd3 | ||
|
|
27142df4f5 | ||
|
|
5e4c7f4245 | ||
|
|
b521b4b926 | ||
|
|
aa9de76370 | ||
|
|
5a083a938d | ||
|
|
7a30d826b8 | ||
|
|
be55a09edf | ||
|
|
15a148ff6d | ||
|
|
428e19fed2 | ||
|
|
f65e55dff4 | ||
|
|
b634018618 | ||
|
|
fa3300f314 | ||
|
|
bd0886a2c0 | ||
|
|
248f304f02 | ||
|
|
dc5f70eab5 | ||
|
|
df8c5623af | ||
|
|
a790c09c91 | ||
|
|
8f35a363d9 | ||
|
|
d2190c2bf3 | ||
|
|
ea10642572 | ||
|
|
547561a568 | ||
|
|
c16d538ce7 | ||
|
|
73d082df2e | ||
|
|
50b8d7272c | ||
|
|
7d11b96f48 | ||
|
|
eab99a1c3d | ||
|
|
19e2fb134d | ||
|
|
f4919e3a25 | ||
|
|
bb700daa4c | ||
|
|
263577d5eb | ||
|
|
63287c0e68 | ||
|
|
c5ed2292bf | ||
|
|
b70670b69f | ||
|
|
9dd97605bc | ||
|
|
e4c5302406 | ||
|
|
bea3d90771 | ||
|
|
785c6064cc | ||
|
|
b214d3786f | ||
|
|
7cf79c302b | ||
|
|
a14c6b6574 | ||
|
|
f1b7094a57 | ||
|
|
0358e376f0 | ||
|
|
b47f7b76b9 | ||
|
|
582cc55cff | ||
|
|
8979579e55 | ||
|
|
0d6e08c541 | ||
|
|
e2daee9a65 | ||
|
|
9cd118ca3d | ||
|
|
cfd5c6155c | ||
|
|
1a5a4bd631 | ||
|
|
63e1a8e1fd | ||
|
|
7055af8221 | ||
|
|
aafe2e1db3 | ||
|
|
118105db43 | ||
|
|
63d04fff69 | ||
|
|
8c9cc920fb | ||
|
|
d09f0adae3 | ||
|
|
3fa9265ce4 | ||
|
|
3a81f60982 | ||
|
|
f2348dd98b | ||
|
|
253c7c2325 | ||
|
|
bb0a762d12 | ||
|
|
8cc86fee60 | ||
|
|
88fb83aa81 | ||
|
|
95b4507c02 | ||
|
|
afdaeba37d | ||
|
|
037199bfe2 | ||
|
|
583fac0a0f | ||
|
|
e8158279ff | ||
|
|
78e98d2611 | ||
|
|
8d14efe818 | ||
|
|
83ba338bd0 | ||
|
|
7c10b25346 | ||
|
|
cb9d16fbe4 | ||
|
|
5d8da864c5 | ||
|
|
85b527ba3d | ||
|
|
1c6efdae34 | ||
|
|
b0ca896d98 | ||
|
|
78a217b94c | ||
|
|
a89d233318 | ||
|
|
dfa395f6ff |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
|||||||
|
/node_modules/
|
||||||
|
/npm-debug.log
|
||||||
tmp/
|
tmp/
|
||||||
node_modules/
|
|
||||||
|
|||||||
11
.travis.yml
11
.travis.yml
@@ -1,7 +1,10 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
|
before_install: "npm install -g npm"
|
||||||
node_js:
|
node_js:
|
||||||
- "0.4"
|
- "iojs"
|
||||||
- "0.6"
|
- "0.12"
|
||||||
- "0.8"
|
|
||||||
- "0.10"
|
- "0.10"
|
||||||
- "0.11"
|
- "4"
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
sudo: false
|
||||||
|
|||||||
322
README.md
322
README.md
@@ -1,6 +1,6 @@
|
|||||||
UglifyJS 2
|
UglifyJS 2
|
||||||
==========
|
==========
|
||||||
[](https://travis-ci.org/mishoo/UglifyJS2)
|
[](https://travis-ci.org/mishoo/UglifyJS2)
|
||||||
|
|
||||||
UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit.
|
UglifyJS is a JavaScript parser, minifier, compressor or beautifier toolkit.
|
||||||
|
|
||||||
@@ -44,65 +44,96 @@ variable/function declared in another file will be matched properly.
|
|||||||
If you want to read from STDIN instead, pass a single dash instead of input
|
If you want to read from STDIN instead, pass a single dash instead of input
|
||||||
files.
|
files.
|
||||||
|
|
||||||
|
If you wish to pass your options before the input files, separate the two with
|
||||||
|
a double dash to prevent input files being used as option arguments:
|
||||||
|
|
||||||
|
uglifyjs --compress --mangle -- input.js
|
||||||
|
|
||||||
The available options are:
|
The available options are:
|
||||||
|
|
||||||
```
|
```
|
||||||
--source-map Specify an output file where to generate source map.
|
--source-map Specify an output file where to generate source
|
||||||
[string]
|
map.
|
||||||
--source-map-root The path to the original source to be included in the
|
--source-map-root The path to the original source to be included
|
||||||
source map. [string]
|
in the source map.
|
||||||
--source-map-url The path to the source map to be added in //#
|
--source-map-url The path to the source map to be added in //#
|
||||||
sourceMappingURL. Defaults to the value passed with
|
sourceMappingURL. Defaults to the value passed
|
||||||
--source-map. [string]
|
with --source-map.
|
||||||
--in-source-map Input source map, useful if you're compressing JS that was
|
--source-map-include-sources Pass this flag if you want to include the
|
||||||
generated from some other original code.
|
content of source files in the source map as
|
||||||
--screw-ie8 Pass this flag if you don't care about full compliance
|
sourcesContent property.
|
||||||
with Internet Explorer 6-8 quirks (by default UglifyJS
|
--in-source-map Input source map, useful if you're compressing
|
||||||
will try to be IE-proof). [boolean]
|
JS that was generated from some other original
|
||||||
--expr Parse a single expression, rather than a program (for
|
code.
|
||||||
parsing JSON) [boolean]
|
--screw-ie8 Pass this flag if you don't care about full
|
||||||
-p, --prefix Skip prefix for original filenames that appear in source
|
compliance with Internet Explorer 6-8 quirks
|
||||||
maps. For example -p 3 will drop 3 directories from file
|
(by default UglifyJS will try to be IE-proof).
|
||||||
names and ensure they are relative paths. You can also
|
--expr Parse a single expression, rather than a
|
||||||
specify -p relative, which will make UglifyJS figure out
|
program (for parsing JSON)
|
||||||
itself the relative paths between original sources, the
|
-p, --prefix Skip prefix for original filenames that appear
|
||||||
source map and the output file. [string]
|
in source maps. For example -p 3 will drop 3
|
||||||
-o, --output Output file (default STDOUT).
|
directories from file names and ensure they are
|
||||||
-b, --beautify Beautify output/specify output options. [string]
|
relative paths. You can also specify -p
|
||||||
-m, --mangle Mangle names/pass mangler options. [string]
|
relative, which will make UglifyJS figure out
|
||||||
-r, --reserved Reserved names to exclude from mangling.
|
itself the relative paths between original
|
||||||
-c, --compress Enable compressor/pass compressor options. Pass options
|
sources, the source map and the output file.
|
||||||
like -c hoist_vars=false,if_return=false. Use -c with no
|
-o, --output Output file (default STDOUT).
|
||||||
argument to use the default compression options. [string]
|
-b, --beautify Beautify output/specify output options.
|
||||||
-d, --define Global definitions [string]
|
-m, --mangle Mangle names/pass mangler options.
|
||||||
-e, --enclose Embed everything in a big function, with a configurable
|
-r, --reserved Reserved names to exclude from mangling.
|
||||||
parameter/argument list. [string]
|
-c, --compress Enable compressor/pass compressor options. Pass
|
||||||
--comments Preserve copyright comments in the output. By default this
|
options like -c
|
||||||
works like Google Closure, keeping JSDoc-style comments
|
hoist_vars=false,if_return=false. Use -c with
|
||||||
that contain "@license" or "@preserve". You can optionally
|
no argument to use the default compression
|
||||||
pass one of the following arguments to this flag:
|
options.
|
||||||
- "all" to keep all comments
|
-d, --define Global definitions
|
||||||
- a valid JS regexp (needs to start with a slash) to keep
|
-e, --enclose Embed everything in a big function, with a
|
||||||
only comments that match.
|
configurable parameter/argument list.
|
||||||
Note that currently not *all* comments can be kept when
|
--comments Preserve copyright comments in the output. By
|
||||||
compression is on, because of dead code removal or
|
default this works like Google Closure, keeping
|
||||||
cascading statements into sequences. [string]
|
JSDoc-style comments that contain "@license" or
|
||||||
--stats Display operations run time on STDERR. [boolean]
|
"@preserve". You can optionally pass one of the
|
||||||
--acorn Use Acorn for parsing. [boolean]
|
following arguments to this flag:
|
||||||
--spidermonkey Assume input files are SpiderMonkey AST format (as JSON).
|
- "all" to keep all comments
|
||||||
[boolean]
|
- a valid JS regexp (needs to start with a
|
||||||
--self Build itself (UglifyJS2) as a library (implies
|
slash) to keep only comments that match.
|
||||||
--wrap=UglifyJS --export-all) [boolean]
|
Note that currently not *all* comments can be
|
||||||
--wrap Embed everything in a big function, making the “exports”
|
kept when compression is on, because of dead
|
||||||
and “global” variables available. You need to pass an
|
code removal or cascading statements into
|
||||||
argument to this option to specify the name that your
|
sequences.
|
||||||
module will take when included in, say, a browser.
|
--preamble Preamble to prepend to the output. You can use
|
||||||
[string]
|
this to insert a comment, for example for
|
||||||
--export-all Only used when --wrap, this tells UglifyJS to add code to
|
licensing information. This will not be
|
||||||
automatically export all globals. [boolean]
|
parsed, but the source map will adjust for its
|
||||||
--lint Display some scope warnings [boolean]
|
presence.
|
||||||
-v, --verbose Verbose [boolean]
|
--stats Display operations run time on STDERR.
|
||||||
-V, --version Print version number and exit. [boolean]
|
--acorn Use Acorn for parsing.
|
||||||
|
--spidermonkey Assume input files are SpiderMonkey AST format
|
||||||
|
(as JSON).
|
||||||
|
--self Build itself (UglifyJS2) as a library (implies
|
||||||
|
--wrap=UglifyJS --export-all)
|
||||||
|
--wrap Embed everything in a big function, making the
|
||||||
|
“exports” and “global” variables available. You
|
||||||
|
need to pass an argument to this option to
|
||||||
|
specify the name that your module will take
|
||||||
|
when included in, say, a browser.
|
||||||
|
--export-all Only used when --wrap, this tells UglifyJS to
|
||||||
|
add code to automatically export all globals.
|
||||||
|
--lint Display some scope warnings
|
||||||
|
-v, --verbose Verbose
|
||||||
|
-V, --version Print version number and exit.
|
||||||
|
--noerr Don't throw an error for unknown options in -c,
|
||||||
|
-b or -m.
|
||||||
|
--bare-returns Allow return outside of functions. Useful when
|
||||||
|
minifying CommonJS modules.
|
||||||
|
--keep-fnames Do not mangle/drop function names. Useful for
|
||||||
|
code relying on Function.prototype.name.
|
||||||
|
--reserved-file File containing reserved names
|
||||||
|
--reserve-domprops Make (most?) DOM properties reserved for
|
||||||
|
--mangle-props
|
||||||
|
--mangle-props Mangle property names
|
||||||
|
--mangle-regex Only mangle property names matching the regex
|
||||||
|
--name-cache File to hold mangled names mappings
|
||||||
```
|
```
|
||||||
|
|
||||||
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
||||||
@@ -165,7 +196,7 @@ To enable the mangler you need to pass `--mangle` (`-m`). The following
|
|||||||
- `toplevel` — mangle names declared in the toplevel scope (disabled by
|
- `toplevel` — mangle names declared in the toplevel scope (disabled by
|
||||||
default).
|
default).
|
||||||
|
|
||||||
- `eval` — mangle names visible in scopes where `eval` or `when` are used
|
- `eval` — mangle names visible in scopes where `eval` or `with` are used
|
||||||
(disabled by default).
|
(disabled by default).
|
||||||
|
|
||||||
When mangling is enabled but you want to prevent certain names from being
|
When mangling is enabled but you want to prevent certain names from being
|
||||||
@@ -176,6 +207,73 @@ comma-separated list of names. For example:
|
|||||||
|
|
||||||
to prevent the `require`, `exports` and `$` names from being changed.
|
to prevent the `require`, `exports` and `$` names from being changed.
|
||||||
|
|
||||||
|
### Mangling property names (`--mangle-props`)
|
||||||
|
|
||||||
|
**Note:** this will probably break your code. Mangling property names is a
|
||||||
|
separate step, different from variable name mangling. Pass
|
||||||
|
`--mangle-props`. It will mangle all properties that are seen in some
|
||||||
|
object literal, or that are assigned to. For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
var x = {
|
||||||
|
foo: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
x.bar = 2;
|
||||||
|
x["baz"] = 3;
|
||||||
|
x[condition ? "moo" : "boo"] = 4;
|
||||||
|
console.log(x.something());
|
||||||
|
```
|
||||||
|
|
||||||
|
In the above code, `foo`, `bar`, `baz`, `moo` and `boo` will be replaced
|
||||||
|
with single characters, while `something()` will be left as is.
|
||||||
|
|
||||||
|
In order for this to be of any use, we should avoid mangling standard JS
|
||||||
|
names. For instance, if your code would contain `x.length = 10`, then
|
||||||
|
`length` becomes a candidate for mangling and it will be mangled throughout
|
||||||
|
the code, regardless if it's being used as part of your own objects or
|
||||||
|
accessing an array's length. To avoid that, you can use `--reserved-file`
|
||||||
|
to pass a filename that should contain the names to be excluded from
|
||||||
|
mangling. This file can be used both for excluding variable names and
|
||||||
|
property names. It could look like this, for example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"vars": [ "define", "require", ... ],
|
||||||
|
"props": [ "length", "prototype", ... ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`--reserved-file` can be an array of file names (either a single
|
||||||
|
comma-separated argument, or you can pass multiple `--reserved-file`
|
||||||
|
arguments) — in this case it will exclude names from all those files.
|
||||||
|
|
||||||
|
A default exclusion file is provided in `tools/domprops.json` which should
|
||||||
|
cover most standard JS and DOM properties defined in various browsers. Pass
|
||||||
|
`--reserve-domprops` to read that in.
|
||||||
|
|
||||||
|
You can also use a regular expression to define which property names should be
|
||||||
|
mangled. For example, `--mangle-regex="/^_/"` will only mangle property names
|
||||||
|
that start with an underscore.
|
||||||
|
|
||||||
|
When you compress multiple files using this option, in order for them to
|
||||||
|
work together in the end we need to ensure somehow that one property gets
|
||||||
|
mangled to the same name in all of them. For this, pass `--name-cache
|
||||||
|
filename.json` and UglifyJS will maintain these mappings in a file which can
|
||||||
|
then be reused. It should be initially empty. Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
rm -f /tmp/cache.json # start fresh
|
||||||
|
uglifyjs file1.js file2.js --mangle-props --name-cache /tmp/cache.json -o part1.js
|
||||||
|
uglifyjs file3.js file4.js --mangle-props --name-cache /tmp/cache.json -o part2.js
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, `part1.js` and `part2.js` will be consistent with each other in terms
|
||||||
|
of mangled property names.
|
||||||
|
|
||||||
|
Using the name cache is not necessary if you compress all your files in a
|
||||||
|
single call to UglifyJS.
|
||||||
|
|
||||||
## Compressor options
|
## Compressor options
|
||||||
|
|
||||||
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
||||||
@@ -184,35 +282,79 @@ you can pass a comma-separated list of options. Options are in the form
|
|||||||
to set `true`; it's effectively a shortcut for `foo=true`).
|
to set `true`; it's effectively a shortcut for `foo=true`).
|
||||||
|
|
||||||
- `sequences` -- join consecutive simple statements using the comma operator
|
- `sequences` -- join consecutive simple statements using the comma operator
|
||||||
|
|
||||||
- `properties` -- rewrite property access using the dot notation, for
|
- `properties` -- rewrite property access using the dot notation, for
|
||||||
example `foo["bar"] → foo.bar`
|
example `foo["bar"] → foo.bar`
|
||||||
|
|
||||||
- `dead_code` -- remove unreachable code
|
- `dead_code` -- remove unreachable code
|
||||||
|
|
||||||
- `drop_debugger` -- remove `debugger;` statements
|
- `drop_debugger` -- remove `debugger;` statements
|
||||||
|
|
||||||
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
|
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
|
||||||
|
|
||||||
- `conditionals` -- apply optimizations for `if`-s and conditional
|
- `conditionals` -- apply optimizations for `if`-s and conditional
|
||||||
expressions
|
expressions
|
||||||
|
|
||||||
- `comparisons` -- apply certain optimizations to binary nodes, for example:
|
- `comparisons` -- apply certain optimizations to binary nodes, for example:
|
||||||
`!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes,
|
`!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes,
|
||||||
e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
|
e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
|
||||||
|
|
||||||
- `evaluate` -- attempt to evaluate constant expressions
|
- `evaluate` -- attempt to evaluate constant expressions
|
||||||
|
|
||||||
- `booleans` -- various optimizations for boolean context, for example `!!a
|
- `booleans` -- various optimizations for boolean context, for example `!!a
|
||||||
? b : c → a ? b : c`
|
? b : c → a ? b : c`
|
||||||
|
|
||||||
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
||||||
statically determine the condition
|
statically determine the condition
|
||||||
|
|
||||||
- `unused` -- drop unreferenced functions and variables
|
- `unused` -- drop unreferenced functions and variables
|
||||||
|
|
||||||
- `hoist_funs` -- hoist function declarations
|
- `hoist_funs` -- hoist function declarations
|
||||||
|
|
||||||
- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`
|
- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`
|
||||||
by default because it seems to increase the size of the output in general)
|
by default because it seems to increase the size of the output in general)
|
||||||
|
|
||||||
- `if_return` -- optimizations for if/return and if/continue
|
- `if_return` -- optimizations for if/return and if/continue
|
||||||
|
|
||||||
- `join_vars` -- join consecutive `var` statements
|
- `join_vars` -- join consecutive `var` statements
|
||||||
|
|
||||||
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
||||||
and `x = something(), x` into `x = something()`
|
and `x = something(), x` into `x = something()`
|
||||||
|
|
||||||
- `warnings` -- display warnings when dropping unreachable code or unused
|
- `warnings` -- display warnings when dropping unreachable code or unused
|
||||||
declarations etc.
|
declarations etc.
|
||||||
|
|
||||||
- `negate_iife` -- negate "Immediately-Called Function Expressions"
|
- `negate_iife` -- negate "Immediately-Called Function Expressions"
|
||||||
where the return value is discarded, to avoid the parens that the
|
where the return value is discarded, to avoid the parens that the
|
||||||
code generator would insert.
|
code generator would insert.
|
||||||
|
|
||||||
|
- `pure_getters` -- the default is `false`. If you pass `true` for
|
||||||
|
this, UglifyJS will assume that object property access
|
||||||
|
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
|
||||||
|
|
||||||
|
- `pure_funcs` -- default `null`. You can pass an array of names and
|
||||||
|
UglifyJS will assume that those functions do not produce side
|
||||||
|
effects. DANGER: will not check if the name is redefined in scope.
|
||||||
|
An example case here, for instance `var q = Math.floor(a/b)`. If
|
||||||
|
variable `q` is not used elsewhere, UglifyJS will drop it, but will
|
||||||
|
still keep the `Math.floor(a/b)`, not knowing what it does. You can
|
||||||
|
pass `pure_funcs: [ 'Math.floor' ]` to let it know that this
|
||||||
|
function won't produce any side effect, in which case the whole
|
||||||
|
statement would get discarded. The current implementation adds some
|
||||||
|
overhead (compression will be slower).
|
||||||
|
|
||||||
|
- `drop_console` -- default `false`. Pass `true` to discard calls to
|
||||||
|
`console.*` functions.
|
||||||
|
|
||||||
|
- `keep_fargs` -- default `false`. Pass `true` to prevent the
|
||||||
|
compressor from discarding unused function arguments. You need this
|
||||||
|
for code which relies on `Function.length`.
|
||||||
|
|
||||||
|
- `keep_fnames` -- default `false`. Pass `true` to prevent the
|
||||||
|
compressor from mangling/discarding function names. Useful for code relying on
|
||||||
|
`Function.prototype.name`.
|
||||||
|
|
||||||
|
|
||||||
### The `unsafe` option
|
### The `unsafe` option
|
||||||
|
|
||||||
It enables some transformations that *might* break code logic in certain
|
It enables some transformations that *might* break code logic in certain
|
||||||
@@ -220,14 +362,15 @@ contrived cases, but should be fine for most code. You might want to try it
|
|||||||
on your own code, it should reduce the minified size. Here's what happens
|
on your own code, it should reduce the minified size. Here's what happens
|
||||||
when this flag is on:
|
when this flag is on:
|
||||||
|
|
||||||
- `new Array(1, 2, 3)` or `Array(1, 2, 3)` → `[1, 2, 3 ]`
|
- `new Array(1, 2, 3)` or `Array(1, 2, 3)` → `[ 1, 2, 3 ]`
|
||||||
- `new Object()` → `{}`
|
- `new Object()` → `{}`
|
||||||
- `String(exp)` or `exp.toString()` → `"" + exp`
|
- `String(exp)` or `exp.toString()` → `"" + exp`
|
||||||
- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
|
- `new Object/RegExp/Function/Error/Array (...)` → we discard the `new`
|
||||||
- `typeof foo == "undefined"` → `foo === void 0`
|
- `typeof foo == "undefined"` → `foo === void 0`
|
||||||
- `void 0` → `"undefined"` (if there is a variable named "undefined" in
|
- `void 0` → `undefined` (if there is a variable named "undefined" in
|
||||||
scope; we do it because the variable name will be mangled, typically
|
scope; we do it because the variable name will be mangled, typically
|
||||||
reduced to a single character).
|
reduced to a single character)
|
||||||
|
- discards unused function arguments (affects `function.length`)
|
||||||
|
|
||||||
### Conditional compilation
|
### Conditional compilation
|
||||||
|
|
||||||
@@ -296,6 +439,17 @@ can pass additional arguments that control the code output:
|
|||||||
you pass `false` then whenever possible we will use a newline instead of a
|
you pass `false` then whenever possible we will use a newline instead of a
|
||||||
semicolon, leading to more readable output of uglified code (size before
|
semicolon, leading to more readable output of uglified code (size before
|
||||||
gzip could be smaller; size after gzip insignificantly larger).
|
gzip could be smaller; size after gzip insignificantly larger).
|
||||||
|
- `preamble` (default `null`) -- when passed it must be a string and
|
||||||
|
it will be prepended to the output literally. The source map will
|
||||||
|
adjust for this text. Can be used to insert a comment containing
|
||||||
|
licensing information, for example.
|
||||||
|
- `quote_style` (default `0`) -- preferred quote style for strings (affects
|
||||||
|
quoted property names and directives as well):
|
||||||
|
- `0` -- prefers double quotes, switches to single quotes when there are
|
||||||
|
more double quotes in the string itself.
|
||||||
|
- `1` -- always use single quotes
|
||||||
|
- `2` -- always use double quotes
|
||||||
|
- `3` -- always use the original quotes
|
||||||
|
|
||||||
### Keeping copyright notices or other comments
|
### Keeping copyright notices or other comments
|
||||||
|
|
||||||
@@ -353,6 +507,38 @@ Acorn is really fast (e.g. 250ms instead of 380ms on some 650K code), but
|
|||||||
converting the SpiderMonkey tree that Acorn produces takes another 150ms so
|
converting the SpiderMonkey tree that Acorn produces takes another 150ms so
|
||||||
in total it's a bit more than just using UglifyJS's own parser.
|
in total it's a bit more than just using UglifyJS's own parser.
|
||||||
|
|
||||||
|
### Using UglifyJS to transform SpiderMonkey AST
|
||||||
|
|
||||||
|
Now you can use UglifyJS as any other intermediate tool for transforming
|
||||||
|
JavaScript ASTs in SpiderMonkey format.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
function uglify(ast, options, mangle) {
|
||||||
|
// Conversion from SpiderMonkey AST to internal format
|
||||||
|
var uAST = UglifyJS.AST_Node.from_mozilla_ast(ast);
|
||||||
|
|
||||||
|
// Compression
|
||||||
|
uAST.figure_out_scope();
|
||||||
|
uAST = uAST.transform(UglifyJS.Compressor(options));
|
||||||
|
|
||||||
|
// Mangling (optional)
|
||||||
|
if (mangle) {
|
||||||
|
uAST.figure_out_scope();
|
||||||
|
uAST.compute_char_frequency();
|
||||||
|
uAST.mangle_names();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back-conversion to SpiderMonkey AST
|
||||||
|
return uAST.to_mozilla_ast();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Check out
|
||||||
|
[original blog post](http://rreverser.com/using-mozilla-ast-with-uglifyjs/)
|
||||||
|
for details.
|
||||||
|
|
||||||
API Reference
|
API Reference
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
@@ -415,6 +601,16 @@ var result = UglifyJS.minify("compiled.js", {
|
|||||||
// same as before, it returns `code` and `map`
|
// same as before, it returns `code` and `map`
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If your input source map is not in a file, you can pass it in as an object
|
||||||
|
using the `inSourceMap` argument:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify("compiled.js", {
|
||||||
|
inSourceMap: JSON.parse(my_source_map_string),
|
||||||
|
outSourceMap: "minified.js.map"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
The `inSourceMap` is only used if you also request `outSourceMap` (it makes
|
The `inSourceMap` is only used if you also request `outSourceMap` (it makes
|
||||||
no sense otherwise).
|
no sense otherwise).
|
||||||
|
|
||||||
@@ -462,7 +658,7 @@ something like this:
|
|||||||
```javascript
|
```javascript
|
||||||
var toplevel = null;
|
var toplevel = null;
|
||||||
files.forEach(function(file){
|
files.forEach(function(file){
|
||||||
var code = fs.readFileSync(file);
|
var code = fs.readFileSync(file, "utf8");
|
||||||
toplevel = UglifyJS.parse(code, {
|
toplevel = UglifyJS.parse(code, {
|
||||||
filename: file,
|
filename: file,
|
||||||
toplevel: toplevel
|
toplevel: toplevel
|
||||||
@@ -529,7 +725,7 @@ or, for a shortcut you can do:
|
|||||||
var code = compressed_ast.print_to_string(options);
|
var code = compressed_ast.print_to_string(options);
|
||||||
```
|
```
|
||||||
|
|
||||||
As usual, `options` is optional. The output stream accepts a lot of otions,
|
As usual, `options` is optional. The output stream accepts a lot of options,
|
||||||
most of them documented above in section “Beautifier options”. The two
|
most of them documented above in section “Beautifier options”. The two
|
||||||
which we care about here are `source_map` and `comments`.
|
which we care about here are `source_map` and `comments`.
|
||||||
|
|
||||||
|
|||||||
77
bin/extract-props.js
Executable file
77
bin/extract-props.js
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
#! /usr/bin/env node
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var U2 = require("../tools/node");
|
||||||
|
var fs = require("fs");
|
||||||
|
var yargs = require("yargs");
|
||||||
|
var ARGS = yargs
|
||||||
|
.describe("o", "Output file")
|
||||||
|
.argv;
|
||||||
|
var files = ARGS._.slice();
|
||||||
|
var output = {
|
||||||
|
vars: {},
|
||||||
|
props: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ARGS.o) try {
|
||||||
|
output = JSON.parse(fs.readFileSync(ARGS.o, "utf8"));
|
||||||
|
} catch(ex) {}
|
||||||
|
|
||||||
|
files.forEach(getProps);
|
||||||
|
|
||||||
|
if (ARGS.o) {
|
||||||
|
fs.writeFileSync(ARGS.o, JSON.stringify(output, null, 2), "utf8");
|
||||||
|
} else {
|
||||||
|
console.log("%s", JSON.stringify(output, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProps(filename) {
|
||||||
|
var code = fs.readFileSync(filename, "utf8");
|
||||||
|
var ast = U2.parse(code);
|
||||||
|
|
||||||
|
ast.walk(new U2.TreeWalker(function(node){
|
||||||
|
if (node instanceof U2.AST_ObjectKeyVal) {
|
||||||
|
add(node.key);
|
||||||
|
}
|
||||||
|
else if (node instanceof U2.AST_ObjectProperty) {
|
||||||
|
add(node.key.name);
|
||||||
|
}
|
||||||
|
else if (node instanceof U2.AST_Dot) {
|
||||||
|
add(node.property);
|
||||||
|
}
|
||||||
|
else if (node instanceof U2.AST_Sub) {
|
||||||
|
addStrings(node.property);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
function addStrings(node) {
|
||||||
|
var out = {};
|
||||||
|
try {
|
||||||
|
(function walk(node){
|
||||||
|
node.walk(new U2.TreeWalker(function(node){
|
||||||
|
if (node instanceof U2.AST_Seq) {
|
||||||
|
walk(node.cdr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof U2.AST_String) {
|
||||||
|
add(node.value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof U2.AST_Conditional) {
|
||||||
|
walk(node.consequent);
|
||||||
|
walk(node.alternative);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw out;
|
||||||
|
}));
|
||||||
|
})(node);
|
||||||
|
} catch(ex) {
|
||||||
|
if (ex !== out) throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(name) {
|
||||||
|
output.props[name] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
243
bin/uglifyjs
243
bin/uglifyjs
@@ -5,12 +5,12 @@
|
|||||||
|
|
||||||
var UglifyJS = require("../tools/node");
|
var UglifyJS = require("../tools/node");
|
||||||
var sys = require("util");
|
var sys = require("util");
|
||||||
var optimist = require("optimist");
|
var yargs = require("yargs");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var async = require("async");
|
var async = require("async");
|
||||||
var acorn;
|
var acorn;
|
||||||
var ARGS = optimist
|
var ARGS = yargs
|
||||||
.usage("$0 input1.js [input2.js ...] [options]\n\
|
.usage("$0 input1.js [input2.js ...] [options]\n\
|
||||||
Use a single dash to read input from the standard input.\
|
Use a single dash to read input from the standard input.\
|
||||||
\n\n\
|
\n\n\
|
||||||
@@ -22,6 +22,7 @@ mangling you need to use `-c` and `-m`.\
|
|||||||
.describe("source-map", "Specify an output file where to generate source map.")
|
.describe("source-map", "Specify an output file where to generate source map.")
|
||||||
.describe("source-map-root", "The path to the original source to be included in the source map.")
|
.describe("source-map-root", "The path to the original source to be included in the source map.")
|
||||||
.describe("source-map-url", "The path to the source map to be added in //# sourceMappingURL. Defaults to the value passed with --source-map.")
|
.describe("source-map-url", "The path to the source map to be added in //# sourceMappingURL. Defaults to the value passed with --source-map.")
|
||||||
|
.describe("source-map-include-sources", "Pass this flag if you want to include the content of source files in the source map as sourcesContent property.")
|
||||||
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
|
.describe("in-source-map", "Input source map, useful if you're compressing JS that was generated from some other original code.")
|
||||||
.describe("screw-ie8", "Pass this flag if you don't care about full compliance with Internet Explorer 6-8 quirks (by default UglifyJS will try to be IE-proof).")
|
.describe("screw-ie8", "Pass this flag if you don't care about full compliance with Internet Explorer 6-8 quirks (by default UglifyJS will try to be IE-proof).")
|
||||||
.describe("expr", "Parse a single expression, rather than a program (for parsing JSON)")
|
.describe("expr", "Parse a single expression, rather than a program (for parsing JSON)")
|
||||||
@@ -48,6 +49,10 @@ You can optionally pass one of the following arguments to this flag:\n\
|
|||||||
Note that currently not *all* comments can be kept when compression is on, \
|
Note that currently not *all* comments can be kept when compression is on, \
|
||||||
because of dead code removal or cascading statements into sequences.")
|
because of dead code removal or cascading statements into sequences.")
|
||||||
|
|
||||||
|
.describe("preamble", "Preamble to prepend to the output. You can use this to insert a \
|
||||||
|
comment, for example for licensing information. This will not be \
|
||||||
|
parsed, but the source map will adjust for its presence.")
|
||||||
|
|
||||||
.describe("stats", "Display operations run time on STDERR.")
|
.describe("stats", "Display operations run time on STDERR.")
|
||||||
.describe("acorn", "Use Acorn for parsing.")
|
.describe("acorn", "Use Acorn for parsing.")
|
||||||
.describe("spidermonkey", "Assume input files are SpiderMonkey AST format (as JSON).")
|
.describe("spidermonkey", "Assume input files are SpiderMonkey AST format (as JSON).")
|
||||||
@@ -58,6 +63,15 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.describe("lint", "Display some scope warnings")
|
.describe("lint", "Display some scope warnings")
|
||||||
.describe("v", "Verbose")
|
.describe("v", "Verbose")
|
||||||
.describe("V", "Print version number and exit.")
|
.describe("V", "Print version number and exit.")
|
||||||
|
.describe("noerr", "Don't throw an error for unknown options in -c, -b or -m.")
|
||||||
|
.describe("bare-returns", "Allow return outside of functions. Useful when minifying CommonJS modules.")
|
||||||
|
.describe("keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.")
|
||||||
|
.describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)")
|
||||||
|
.describe("reserved-file", "File containing reserved names")
|
||||||
|
.describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props")
|
||||||
|
.describe("mangle-props", "Mangle property names")
|
||||||
|
.describe("mangle-regex", "Only mangle property names matching the regex")
|
||||||
|
.describe("name-cache", "File to hold mangled names mappings")
|
||||||
|
|
||||||
.alias("p", "prefix")
|
.alias("p", "prefix")
|
||||||
.alias("o", "output")
|
.alias("o", "output")
|
||||||
@@ -69,29 +83,46 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.alias("r", "reserved")
|
.alias("r", "reserved")
|
||||||
.alias("V", "version")
|
.alias("V", "version")
|
||||||
.alias("e", "enclose")
|
.alias("e", "enclose")
|
||||||
|
.alias("q", "quotes")
|
||||||
|
|
||||||
.string("source-map")
|
.string("source-map")
|
||||||
.string("source-map-root")
|
.string("source-map-root")
|
||||||
.string("source-map-url")
|
.string("source-map-url")
|
||||||
.string("b")
|
.string("b")
|
||||||
|
.string("beautify")
|
||||||
.string("m")
|
.string("m")
|
||||||
|
.string("mangle")
|
||||||
.string("c")
|
.string("c")
|
||||||
|
.string("compress")
|
||||||
.string("d")
|
.string("d")
|
||||||
|
.string("define")
|
||||||
.string("e")
|
.string("e")
|
||||||
|
.string("enclose")
|
||||||
.string("comments")
|
.string("comments")
|
||||||
.string("wrap")
|
.string("wrap")
|
||||||
.string("p")
|
.string("p")
|
||||||
|
.string("prefix")
|
||||||
|
.string("name-cache")
|
||||||
|
.array("reserved-file")
|
||||||
|
|
||||||
.boolean("expr")
|
.boolean("expr")
|
||||||
|
.boolean("source-map-include-sources")
|
||||||
.boolean("screw-ie8")
|
.boolean("screw-ie8")
|
||||||
.boolean("export-all")
|
.boolean("export-all")
|
||||||
.boolean("self")
|
.boolean("self")
|
||||||
.boolean("v")
|
.boolean("v")
|
||||||
|
.boolean("verbose")
|
||||||
.boolean("stats")
|
.boolean("stats")
|
||||||
.boolean("acorn")
|
.boolean("acorn")
|
||||||
.boolean("spidermonkey")
|
.boolean("spidermonkey")
|
||||||
.boolean("lint")
|
.boolean("lint")
|
||||||
.boolean("V")
|
.boolean("V")
|
||||||
|
.boolean("version")
|
||||||
|
.boolean("noerr")
|
||||||
|
.boolean("bare-returns")
|
||||||
|
.boolean("keep-fnames")
|
||||||
|
.boolean("mangle-props")
|
||||||
|
.boolean("reserve-domprops")
|
||||||
|
|
||||||
.wrap(80)
|
.wrap(80)
|
||||||
|
|
||||||
@@ -100,20 +131,26 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
|
|
||||||
normalize(ARGS);
|
normalize(ARGS);
|
||||||
|
|
||||||
|
if (ARGS.noerr) {
|
||||||
|
UglifyJS.DefaultsError.croak = function(msg, defs) {
|
||||||
|
print_error("WARN: " + msg);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (ARGS.version || ARGS.V) {
|
if (ARGS.version || ARGS.V) {
|
||||||
var json = require("../package.json");
|
var json = require("../package.json");
|
||||||
sys.puts(json.name + ' ' + json.version);
|
print(json.name + ' ' + json.version);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.ast_help) {
|
if (ARGS.ast_help) {
|
||||||
var desc = UglifyJS.describe_ast();
|
var desc = UglifyJS.describe_ast();
|
||||||
sys.puts(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2));
|
print(typeof desc == "string" ? desc : JSON.stringify(desc, null, 2));
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.h || ARGS.help) {
|
if (ARGS.h || ARGS.help) {
|
||||||
sys.puts(optimist.help());
|
print(yargs.help());
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +161,15 @@ if (ARGS.acorn) {
|
|||||||
var COMPRESS = getOptions("c", true);
|
var COMPRESS = getOptions("c", true);
|
||||||
var MANGLE = getOptions("m", true);
|
var MANGLE = getOptions("m", true);
|
||||||
var BEAUTIFY = getOptions("b", true);
|
var BEAUTIFY = getOptions("b", true);
|
||||||
|
var RESERVED = null;
|
||||||
|
|
||||||
|
if (ARGS.reserved_file) ARGS.reserved_file.forEach(function(filename){
|
||||||
|
RESERVED = UglifyJS.readReservedFile(filename, RESERVED);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (ARGS.reserve_domprops) {
|
||||||
|
RESERVED = UglifyJS.readDefaultReservedFile(RESERVED);
|
||||||
|
}
|
||||||
|
|
||||||
if (ARGS.d) {
|
if (ARGS.d) {
|
||||||
if (COMPRESS) COMPRESS.global_defs = getOptions("d");
|
if (COMPRESS) COMPRESS.global_defs = getOptions("d");
|
||||||
@@ -133,8 +179,36 @@ if (ARGS.r) {
|
|||||||
if (MANGLE) MANGLE.except = ARGS.r.replace(/^\s+|\s+$/g).split(/\s*,+\s*/);
|
if (MANGLE) MANGLE.except = ARGS.r.replace(/^\s+|\s+$/g).split(/\s*,+\s*/);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RESERVED && MANGLE) {
|
||||||
|
if (!MANGLE.except) MANGLE.except = RESERVED.vars;
|
||||||
|
else MANGLE.except = MANGLE.except.concat(RESERVED.vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readNameCache(key) {
|
||||||
|
return UglifyJS.readNameCache(ARGS.name_cache, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeNameCache(key, cache) {
|
||||||
|
return UglifyJS.writeNameCache(ARGS.name_cache, key, cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractRegex(str) {
|
||||||
|
if (/^\/.*\/[a-zA-Z]*$/.test(str)) {
|
||||||
|
var regex_pos = str.lastIndexOf("/");
|
||||||
|
return new RegExp(str.substr(1, regex_pos - 1), str.substr(regex_pos + 1));
|
||||||
|
} else {
|
||||||
|
throw new Error("Invalid regular expression: " + str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ARGS.quotes === true) {
|
||||||
|
ARGS.quotes = 3;
|
||||||
|
}
|
||||||
|
|
||||||
var OUTPUT_OPTIONS = {
|
var OUTPUT_OPTIONS = {
|
||||||
beautify: BEAUTIFY ? true : false
|
beautify : BEAUTIFY ? true : false,
|
||||||
|
preamble : ARGS.preamble || null,
|
||||||
|
quote_style : ARGS.quotes != null ? ARGS.quotes : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ARGS.screw_ie8) {
|
if (ARGS.screw_ie8) {
|
||||||
@@ -143,12 +217,21 @@ if (ARGS.screw_ie8) {
|
|||||||
OUTPUT_OPTIONS.screw_ie8 = true;
|
OUTPUT_OPTIONS.screw_ie8 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ARGS.keep_fnames) {
|
||||||
|
if (COMPRESS) COMPRESS.keep_fnames = true;
|
||||||
|
if (MANGLE) MANGLE.keep_fnames = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (BEAUTIFY)
|
if (BEAUTIFY)
|
||||||
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
|
UglifyJS.merge(OUTPUT_OPTIONS, BEAUTIFY);
|
||||||
|
|
||||||
if (ARGS.comments) {
|
if (ARGS.comments != null) {
|
||||||
if (/^\//.test(ARGS.comments)) {
|
if (/^\/.*\/[a-zA-Z]*$/.test(ARGS.comments)) {
|
||||||
OUTPUT_OPTIONS.comments = new Function("return(" + ARGS.comments + ")")();
|
try {
|
||||||
|
OUTPUT_OPTIONS.comments = extractRegex(ARGS.comments);
|
||||||
|
} catch (e) {
|
||||||
|
print_error("ERROR: Invalid --comments: " + e.message);
|
||||||
|
}
|
||||||
} else if (ARGS.comments == "all") {
|
} else if (ARGS.comments == "all") {
|
||||||
OUTPUT_OPTIONS.comments = true;
|
OUTPUT_OPTIONS.comments = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -167,11 +250,10 @@ var files = ARGS._.slice();
|
|||||||
|
|
||||||
if (ARGS.self) {
|
if (ARGS.self) {
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
sys.error("WARN: Ignoring input files since --self was passed");
|
print_error("WARN: Ignoring input files since --self was passed");
|
||||||
}
|
}
|
||||||
files = UglifyJS.FILES;
|
files = UglifyJS.FILES;
|
||||||
if (!ARGS.wrap) ARGS.wrap = "UglifyJS";
|
if (!ARGS.wrap) ARGS.wrap = "UglifyJS";
|
||||||
ARGS.export_all = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ORIG_MAP = ARGS.in_source_map;
|
var ORIG_MAP = ARGS.in_source_map;
|
||||||
@@ -179,7 +261,7 @@ var ORIG_MAP = ARGS.in_source_map;
|
|||||||
if (ORIG_MAP) {
|
if (ORIG_MAP) {
|
||||||
ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP));
|
ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP));
|
||||||
if (files.length == 0) {
|
if (files.length == 0) {
|
||||||
sys.error("INFO: Using file from the input source map: " + ORIG_MAP.file);
|
print_error("INFO: Using file from the input source map: " + ORIG_MAP.file);
|
||||||
files = [ ORIG_MAP.file ];
|
files = [ ORIG_MAP.file ];
|
||||||
}
|
}
|
||||||
if (ARGS.source_map_root == null) {
|
if (ARGS.source_map_root == null) {
|
||||||
@@ -192,12 +274,12 @@ if (files.length == 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (files.indexOf("-") >= 0 && ARGS.source_map) {
|
if (files.indexOf("-") >= 0 && ARGS.source_map) {
|
||||||
sys.error("ERROR: Source map doesn't work with input from STDIN");
|
print_error("ERROR: Source map doesn't work with input from STDIN");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (files.filter(function(el){ return el == "-" }).length > 1) {
|
if (files.filter(function(el){ return el == "-" }).length > 1) {
|
||||||
sys.error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
|
print_error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +287,7 @@ var STATS = {};
|
|||||||
var OUTPUT_FILE = ARGS.o;
|
var OUTPUT_FILE = ARGS.o;
|
||||||
var TOPLEVEL = null;
|
var TOPLEVEL = null;
|
||||||
var P_RELATIVE = ARGS.p && ARGS.p == "relative";
|
var P_RELATIVE = ARGS.p && ARGS.p == "relative";
|
||||||
|
var SOURCES_CONTENT = {};
|
||||||
|
|
||||||
var SOURCE_MAP = ARGS.source_map ? UglifyJS.SourceMap({
|
var SOURCE_MAP = ARGS.source_map ? UglifyJS.SourceMap({
|
||||||
file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE,
|
file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE,
|
||||||
@@ -219,9 +302,9 @@ try {
|
|||||||
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
|
var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS);
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex instanceof UglifyJS.DefaultsError) {
|
if (ex instanceof UglifyJS.DefaultsError) {
|
||||||
sys.error(ex.msg);
|
print_error(ex.msg);
|
||||||
sys.error("Supported options:");
|
print_error("Supported options:");
|
||||||
sys.error(sys.inspect(ex.defs));
|
print_error(sys.inspect(ex.defs));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,12 +312,12 @@ try {
|
|||||||
async.eachLimit(files, 1, function (file, cb) {
|
async.eachLimit(files, 1, function (file, cb) {
|
||||||
read_whole_file(file, function (err, code) {
|
read_whole_file(file, function (err, code) {
|
||||||
if (err) {
|
if (err) {
|
||||||
sys.error("ERROR: can't read file: " + file);
|
print_error("ERROR: can't read file: " + file);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (ARGS.p != null) {
|
if (ARGS.p != null) {
|
||||||
if (P_RELATIVE) {
|
if (P_RELATIVE) {
|
||||||
file = path.relative(path.dirname(ARGS.source_map), file);
|
file = path.relative(path.dirname(ARGS.source_map), file).replace(/\\/g, '/');
|
||||||
} else {
|
} else {
|
||||||
var p = parseInt(ARGS.p, 10);
|
var p = parseInt(ARGS.p, 10);
|
||||||
if (!isNaN(p)) {
|
if (!isNaN(p)) {
|
||||||
@@ -242,6 +325,7 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SOURCES_CONTENT[file] = code;
|
||||||
time_it("parse", function(){
|
time_it("parse", function(){
|
||||||
if (ARGS.spidermonkey) {
|
if (ARGS.spidermonkey) {
|
||||||
var program = JSON.parse(code);
|
var program = JSON.parse(code);
|
||||||
@@ -251,17 +335,27 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
else if (ARGS.acorn) {
|
else if (ARGS.acorn) {
|
||||||
TOPLEVEL = acorn.parse(code, {
|
TOPLEVEL = acorn.parse(code, {
|
||||||
locations : true,
|
locations : true,
|
||||||
trackComments : true,
|
|
||||||
sourceFile : file,
|
sourceFile : file,
|
||||||
program : TOPLEVEL
|
program : TOPLEVEL
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TOPLEVEL = UglifyJS.parse(code, {
|
try {
|
||||||
filename : file,
|
TOPLEVEL = UglifyJS.parse(code, {
|
||||||
toplevel : TOPLEVEL,
|
filename : file,
|
||||||
expression : ARGS.expr,
|
toplevel : TOPLEVEL,
|
||||||
});
|
expression : ARGS.expr,
|
||||||
|
bare_returns : ARGS.bare_returns,
|
||||||
|
});
|
||||||
|
} catch(ex) {
|
||||||
|
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
||||||
|
print_error("Parse error at " + file + ":" + ex.line + "," + ex.col);
|
||||||
|
print_error(ex.message);
|
||||||
|
print_error(ex.stack);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
cb();
|
cb();
|
||||||
@@ -271,11 +365,11 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
|
TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ARGS.wrap) {
|
if (ARGS.wrap != null) {
|
||||||
TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
|
TOPLEVEL = TOPLEVEL.wrap_commonjs(ARGS.wrap, ARGS.export_all);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.enclose) {
|
if (ARGS.enclose != null) {
|
||||||
var arg_parameter_list = ARGS.enclose;
|
var arg_parameter_list = ARGS.enclose;
|
||||||
if (arg_parameter_list === true) {
|
if (arg_parameter_list === true) {
|
||||||
arg_parameter_list = [];
|
arg_parameter_list = [];
|
||||||
@@ -286,16 +380,35 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
TOPLEVEL = TOPLEVEL.wrap_enclose(arg_parameter_list);
|
TOPLEVEL = TOPLEVEL.wrap_enclose(arg_parameter_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint;
|
if (ARGS.mangle_props || ARGS.name_cache) (function(){
|
||||||
|
var reserved = RESERVED ? RESERVED.props : null;
|
||||||
|
var cache = readNameCache("props");
|
||||||
|
var regex;
|
||||||
|
|
||||||
if (SCOPE_IS_NEEDED) {
|
try {
|
||||||
time_it("scope", function(){
|
regex = ARGS.mangle_regex ? extractRegex(ARGS.mangle_regex) : null;
|
||||||
TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 });
|
} catch (e) {
|
||||||
if (ARGS.lint) {
|
print_error("ERROR: Invalid --mangle-regex: " + e.message);
|
||||||
TOPLEVEL.scope_warnings();
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
|
||||||
|
reserved : reserved,
|
||||||
|
cache : cache,
|
||||||
|
only_cache : !ARGS.mangle_props,
|
||||||
|
regex : regex
|
||||||
});
|
});
|
||||||
}
|
writeNameCache("props", cache);
|
||||||
|
})();
|
||||||
|
|
||||||
|
var TL_CACHE = readNameCache("vars");
|
||||||
|
|
||||||
|
time_it("scope", function(){
|
||||||
|
TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8, cache: TL_CACHE });
|
||||||
|
if (ARGS.lint) {
|
||||||
|
TOPLEVEL.scope_warnings();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (COMPRESS) {
|
if (COMPRESS) {
|
||||||
time_it("squeeze", function(){
|
time_it("squeeze", function(){
|
||||||
@@ -303,18 +416,28 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCOPE_IS_NEEDED) {
|
time_it("scope", function(){
|
||||||
time_it("scope", function(){
|
TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8, cache: TL_CACHE });
|
||||||
TOPLEVEL.figure_out_scope({ screw_ie8: ARGS.screw_ie8 });
|
if (MANGLE && !TL_CACHE) {
|
||||||
if (MANGLE) {
|
TOPLEVEL.compute_char_frequency(MANGLE);
|
||||||
TOPLEVEL.compute_char_frequency(MANGLE);
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MANGLE) time_it("mangle", function(){
|
if (MANGLE) time_it("mangle", function(){
|
||||||
|
MANGLE.cache = TL_CACHE;
|
||||||
TOPLEVEL.mangle_names(MANGLE);
|
TOPLEVEL.mangle_names(MANGLE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
writeNameCache("vars", TL_CACHE);
|
||||||
|
|
||||||
|
if (ARGS.source_map_include_sources) {
|
||||||
|
for (var file in SOURCES_CONTENT) {
|
||||||
|
if (SOURCES_CONTENT.hasOwnProperty(file)) {
|
||||||
|
SOURCE_MAP.get().setSourceContent(file, SOURCES_CONTENT[file]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
time_it("generate", function(){
|
time_it("generate", function(){
|
||||||
TOPLEVEL.print(output);
|
TOPLEVEL.print(output);
|
||||||
});
|
});
|
||||||
@@ -334,16 +457,15 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
if (OUTPUT_FILE) {
|
if (OUTPUT_FILE) {
|
||||||
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
|
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
|
||||||
} else {
|
} else {
|
||||||
sys.print(output);
|
print(output);
|
||||||
sys.error("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.stats) {
|
if (ARGS.stats) {
|
||||||
sys.error(UglifyJS.string_template("Timing information (compressed {count} files):", {
|
print_error(UglifyJS.string_template("Timing information (compressed {count} files):", {
|
||||||
count: files.length
|
count: files.length
|
||||||
}));
|
}));
|
||||||
for (var i in STATS) if (STATS.hasOwnProperty(i)) {
|
for (var i in STATS) if (STATS.hasOwnProperty(i)) {
|
||||||
sys.error(UglifyJS.string_template("- {name}: {time}s", {
|
print_error(UglifyJS.string_template("- {name}: {time}s", {
|
||||||
name: i,
|
name: i,
|
||||||
time: (STATS[i] / 1000).toFixed(3)
|
time: (STATS[i] / 1000).toFixed(3)
|
||||||
}));
|
}));
|
||||||
@@ -362,21 +484,19 @@ function normalize(o) {
|
|||||||
|
|
||||||
function getOptions(x, constants) {
|
function getOptions(x, constants) {
|
||||||
x = ARGS[x];
|
x = ARGS[x];
|
||||||
if (!x) return null;
|
if (x == null) return null;
|
||||||
var ret = {};
|
var ret = {};
|
||||||
if (x !== true) {
|
if (x !== "") {
|
||||||
var ast;
|
var ast;
|
||||||
try {
|
try {
|
||||||
ast = UglifyJS.parse(x);
|
ast = UglifyJS.parse(x, { expression: true });
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
||||||
sys.error("Error parsing arguments in: " + x);
|
print_error("Error parsing arguments in: " + x);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.walk(new UglifyJS.TreeWalker(function(node){
|
ast.walk(new UglifyJS.TreeWalker(function(node){
|
||||||
if (node instanceof UglifyJS.AST_Toplevel) return; // descend
|
|
||||||
if (node instanceof UglifyJS.AST_SimpleStatement) return; // descend
|
|
||||||
if (node instanceof UglifyJS.AST_Seq) return; // descend
|
if (node instanceof UglifyJS.AST_Seq) return; // descend
|
||||||
if (node instanceof UglifyJS.AST_Assign) {
|
if (node instanceof UglifyJS.AST_Assign) {
|
||||||
var name = node.left.print_to_string({ beautify: false }).replace(/-/g, "_");
|
var name = node.left.print_to_string({ beautify: false }).replace(/-/g, "_");
|
||||||
@@ -386,8 +506,13 @@ function getOptions(x, constants) {
|
|||||||
ret[name] = value;
|
ret[name] = value;
|
||||||
return true; // no descend
|
return true; // no descend
|
||||||
}
|
}
|
||||||
sys.error(node.TYPE)
|
if (node instanceof UglifyJS.AST_Symbol || node instanceof UglifyJS.AST_Binary) {
|
||||||
sys.error("Error parsing arguments in: " + x);
|
var name = node.print_to_string({ beautify: false }).replace(/-/g, "_");
|
||||||
|
ret[name] = true;
|
||||||
|
return true; // no descend
|
||||||
|
}
|
||||||
|
print_error(node.TYPE)
|
||||||
|
print_error("Error parsing arguments in: " + x);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -419,3 +544,11 @@ function time_it(name, cont) {
|
|||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function print_error(msg) {
|
||||||
|
console.error("%s", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
function print(txt) {
|
||||||
|
console.log("%s", txt);
|
||||||
|
}
|
||||||
|
|||||||
106
lib/ast.js
106
lib/ast.js
@@ -81,10 +81,11 @@ function DEFNODE(type, props, methods, base) {
|
|||||||
ctor.DEFMETHOD = function(name, method) {
|
ctor.DEFMETHOD = function(name, method) {
|
||||||
this.prototype[name] = method;
|
this.prototype[name] = method;
|
||||||
};
|
};
|
||||||
|
exports["AST_" + type] = ctor;
|
||||||
return ctor;
|
return ctor;
|
||||||
};
|
};
|
||||||
|
|
||||||
var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_before file", {
|
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file", {
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
var AST_Node = DEFNODE("Node", "start end", {
|
var AST_Node = DEFNODE("Node", "start end", {
|
||||||
@@ -120,11 +121,12 @@ var AST_Debugger = DEFNODE("Debugger", null, {
|
|||||||
$documentation: "Represents a debugger statement",
|
$documentation: "Represents a debugger statement",
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
var AST_Directive = DEFNODE("Directive", "value scope", {
|
var AST_Directive = DEFNODE("Directive", "value scope quote", {
|
||||||
$documentation: "Represents a directive, like \"use strict\";",
|
$documentation: "Represents a directive, like \"use strict\";",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
||||||
scope: "[AST_Scope/S] The scope that this directive affects"
|
scope: "[AST_Scope/S] The scope that this directive affects",
|
||||||
|
quote: "[string] the original quote character"
|
||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
@@ -197,25 +199,35 @@ var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
|
|||||||
}
|
}
|
||||||
}, AST_StatementWithBody);
|
}, AST_StatementWithBody);
|
||||||
|
|
||||||
|
var AST_IterationStatement = DEFNODE("IterationStatement", null, {
|
||||||
|
$documentation: "Internal class. All loops inherit from it."
|
||||||
|
}, AST_StatementWithBody);
|
||||||
|
|
||||||
var AST_DWLoop = DEFNODE("DWLoop", "condition", {
|
var AST_DWLoop = DEFNODE("DWLoop", "condition", {
|
||||||
$documentation: "Base class for do/while statements",
|
$documentation: "Base class for do/while statements",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
|
condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
|
||||||
},
|
}
|
||||||
|
}, AST_IterationStatement);
|
||||||
|
|
||||||
|
var AST_Do = DEFNODE("Do", null, {
|
||||||
|
$documentation: "A `do` statement",
|
||||||
|
_walk: function(visitor) {
|
||||||
|
return visitor._visit(this, function(){
|
||||||
|
this.body._walk(visitor);
|
||||||
|
this.condition._walk(visitor);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, AST_DWLoop);
|
||||||
|
|
||||||
|
var AST_While = DEFNODE("While", null, {
|
||||||
|
$documentation: "A `while` statement",
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
this.condition._walk(visitor);
|
this.condition._walk(visitor);
|
||||||
this.body._walk(visitor);
|
this.body._walk(visitor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, AST_StatementWithBody);
|
|
||||||
|
|
||||||
var AST_Do = DEFNODE("Do", null, {
|
|
||||||
$documentation: "A `do` statement",
|
|
||||||
}, AST_DWLoop);
|
|
||||||
|
|
||||||
var AST_While = DEFNODE("While", null, {
|
|
||||||
$documentation: "A `while` statement",
|
|
||||||
}, AST_DWLoop);
|
}, AST_DWLoop);
|
||||||
|
|
||||||
var AST_For = DEFNODE("For", "init condition step", {
|
var AST_For = DEFNODE("For", "init condition step", {
|
||||||
@@ -233,7 +245,7 @@ var AST_For = DEFNODE("For", "init condition step", {
|
|||||||
this.body._walk(visitor);
|
this.body._walk(visitor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, AST_StatementWithBody);
|
}, AST_IterationStatement);
|
||||||
|
|
||||||
var AST_ForIn = DEFNODE("ForIn", "init name object", {
|
var AST_ForIn = DEFNODE("ForIn", "init name object", {
|
||||||
$documentation: "A `for ... in` statement",
|
$documentation: "A `for ... in` statement",
|
||||||
@@ -249,7 +261,7 @@ var AST_ForIn = DEFNODE("ForIn", "init name object", {
|
|||||||
this.body._walk(visitor);
|
this.body._walk(visitor);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, AST_StatementWithBody);
|
}, AST_IterationStatement);
|
||||||
|
|
||||||
var AST_With = DEFNODE("With", "expression", {
|
var AST_With = DEFNODE("With", "expression", {
|
||||||
$documentation: "A `with` statement",
|
$documentation: "A `with` statement",
|
||||||
@@ -291,10 +303,10 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||||||
var parameters = [];
|
var parameters = [];
|
||||||
|
|
||||||
arg_parameter_pairs.forEach(function(pair) {
|
arg_parameter_pairs.forEach(function(pair) {
|
||||||
var split = pair.split(":");
|
var splitAt = pair.lastIndexOf(":");
|
||||||
|
|
||||||
args.push(split[0]);
|
args.push(pair.substr(0, splitAt));
|
||||||
parameters.push(split[1]);
|
parameters.push(pair.substr(splitAt + 1));
|
||||||
});
|
});
|
||||||
|
|
||||||
var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
|
var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
|
||||||
@@ -318,12 +330,11 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
var wrapped_tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))";
|
var wrapped_tl = "(function(exports, global){ '$ORIG'; '$EXPORTS'; global['" + name + "'] = exports; }({}, (function(){return this}())))";
|
||||||
wrapped_tl = parse(wrapped_tl);
|
wrapped_tl = parse(wrapped_tl);
|
||||||
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
|
wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(node){
|
||||||
if (node instanceof AST_SimpleStatement) {
|
if (node instanceof AST_Directive) {
|
||||||
node = node.body;
|
switch (node.value) {
|
||||||
if (node instanceof AST_String) switch (node.getValue()) {
|
|
||||||
case "$ORIG":
|
case "$ORIG":
|
||||||
return MAP.splice(self.body);
|
return MAP.splice(self.body);
|
||||||
case "$EXPORTS":
|
case "$EXPORTS":
|
||||||
@@ -367,7 +378,7 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
|
|||||||
}, AST_Scope);
|
}, AST_Scope);
|
||||||
|
|
||||||
var AST_Accessor = DEFNODE("Accessor", null, {
|
var AST_Accessor = DEFNODE("Accessor", null, {
|
||||||
$documentation: "A setter/getter function"
|
$documentation: "A setter/getter function. The `name` property is always null."
|
||||||
}, AST_Lambda);
|
}, AST_Lambda);
|
||||||
|
|
||||||
var AST_Function = DEFNODE("Function", null, {
|
var AST_Function = DEFNODE("Function", null, {
|
||||||
@@ -494,12 +505,6 @@ var AST_Try = DEFNODE("Try", "bcatch bfinally", {
|
|||||||
}
|
}
|
||||||
}, AST_Block);
|
}, AST_Block);
|
||||||
|
|
||||||
// XXX: this is wrong according to ECMA-262 (12.4). the catch block
|
|
||||||
// should introduce another scope, as the argname should be visible
|
|
||||||
// only inside the catch block. However, doing it this way because of
|
|
||||||
// IE which simply introduces the name in the surrounding scope. If
|
|
||||||
// we ever want to fix this then AST_Catch should inherit from
|
|
||||||
// AST_Scope.
|
|
||||||
var AST_Catch = DEFNODE("Catch", "argname", {
|
var AST_Catch = DEFNODE("Catch", "argname", {
|
||||||
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
@@ -752,7 +757,7 @@ var AST_Object = DEFNODE("Object", "properties", {
|
|||||||
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
||||||
$documentation: "Base class for literal object properties",
|
$documentation: "Base class for literal object properties",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
key: "[string] the property name; it's always a plain string in our AST, no matter if it was a string, number or identifier in original code",
|
key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
|
||||||
value: "[AST_Node] property value. For setters and getters this is an AST_Function."
|
value: "[AST_Node] property value. For setters and getters this is an AST_Function."
|
||||||
},
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
@@ -762,8 +767,11 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
|
var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", {
|
||||||
$documentation: "A key: value object property",
|
$documentation: "A key: value object property",
|
||||||
|
$propdoc: {
|
||||||
|
quote: "[string] the original quote character"
|
||||||
|
}
|
||||||
}, AST_ObjectProperty);
|
}, AST_ObjectProperty);
|
||||||
|
|
||||||
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
|
||||||
@@ -821,7 +829,11 @@ var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
|
|||||||
var AST_Label = DEFNODE("Label", "references", {
|
var AST_Label = DEFNODE("Label", "references", {
|
||||||
$documentation: "Symbol naming a label (declaration)",
|
$documentation: "Symbol naming a label (declaration)",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
references: "[AST_LabelRef*] a list of nodes referring to this label"
|
references: "[AST_LoopControl*] a list of nodes referring to this label"
|
||||||
|
},
|
||||||
|
initialize: function() {
|
||||||
|
this.references = [];
|
||||||
|
this.thedef = this;
|
||||||
}
|
}
|
||||||
}, AST_Symbol);
|
}, AST_Symbol);
|
||||||
|
|
||||||
@@ -844,17 +856,19 @@ var AST_Constant = DEFNODE("Constant", null, {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var AST_String = DEFNODE("String", "value", {
|
var AST_String = DEFNODE("String", "value quote", {
|
||||||
$documentation: "A string literal",
|
$documentation: "A string literal",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
value: "[string] the contents of this string"
|
value: "[string] the contents of this string",
|
||||||
|
quote: "[string] the original quote character"
|
||||||
}
|
}
|
||||||
}, AST_Constant);
|
}, AST_Constant);
|
||||||
|
|
||||||
var AST_Number = DEFNODE("Number", "value", {
|
var AST_Number = DEFNODE("Number", "value literal", {
|
||||||
$documentation: "A number literal",
|
$documentation: "A number literal",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
value: "[number] the numeric value"
|
value: "[number] the numeric value",
|
||||||
|
literal: "[string] numeric value as string (optional)"
|
||||||
}
|
}
|
||||||
}, AST_Constant);
|
}, AST_Constant);
|
||||||
|
|
||||||
@@ -968,21 +982,15 @@ TreeWalker.prototype = {
|
|||||||
},
|
},
|
||||||
loopcontrol_target: function(label) {
|
loopcontrol_target: function(label) {
|
||||||
var stack = this.stack;
|
var stack = this.stack;
|
||||||
if (label) {
|
if (label) for (var i = stack.length; --i >= 0;) {
|
||||||
for (var i = stack.length; --i >= 0;) {
|
var x = stack[i];
|
||||||
var x = stack[i];
|
if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
|
||||||
if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
|
return x.body;
|
||||||
return x.body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (var i = stack.length; --i >= 0;) {
|
|
||||||
var x = stack[i];
|
|
||||||
if (x instanceof AST_Switch
|
|
||||||
|| x instanceof AST_For
|
|
||||||
|| x instanceof AST_ForIn
|
|
||||||
|| x instanceof AST_DWLoop) return x;
|
|
||||||
}
|
}
|
||||||
|
} else for (var i = stack.length; --i >= 0;) {
|
||||||
|
var x = stack[i];
|
||||||
|
if (x instanceof AST_Switch || x instanceof AST_IterationStatement)
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
804
lib/compress.js
804
lib/compress.js
File diff suppressed because it is too large
Load Diff
@@ -46,53 +46,68 @@
|
|||||||
(function(){
|
(function(){
|
||||||
|
|
||||||
var MOZ_TO_ME = {
|
var MOZ_TO_ME = {
|
||||||
TryStatement : function(M) {
|
ExpressionStatement: function(M) {
|
||||||
|
var expr = M.expression;
|
||||||
|
if (expr.type === "Literal" && typeof expr.value === "string") {
|
||||||
|
return new AST_Directive({
|
||||||
|
start: my_start_token(M),
|
||||||
|
end: my_end_token(M),
|
||||||
|
value: expr.value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return new AST_SimpleStatement({
|
||||||
|
start: my_start_token(M),
|
||||||
|
end: my_end_token(M),
|
||||||
|
body: from_moz(expr)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
TryStatement: function(M) {
|
||||||
|
var handlers = M.handlers || [M.handler];
|
||||||
|
if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) {
|
||||||
|
throw new Error("Multiple catch clauses are not supported.");
|
||||||
|
}
|
||||||
return new AST_Try({
|
return new AST_Try({
|
||||||
start : my_start_token(M),
|
start : my_start_token(M),
|
||||||
end : my_end_token(M),
|
end : my_end_token(M),
|
||||||
body : from_moz(M.block).body,
|
body : from_moz(M.block).body,
|
||||||
bcatch : from_moz(M.handlers[0]),
|
bcatch : from_moz(handlers[0]),
|
||||||
bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
|
bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
CatchClause : function(M) {
|
Property: function(M) {
|
||||||
return new AST_Catch({
|
var key = M.key;
|
||||||
start : my_start_token(M),
|
var name = key.type == "Identifier" ? key.name : key.value;
|
||||||
end : my_end_token(M),
|
var args = {
|
||||||
argname : from_moz(M.param),
|
start : my_start_token(key),
|
||||||
body : from_moz(M.body).body
|
end : my_end_token(M.value),
|
||||||
});
|
key : name,
|
||||||
|
value : from_moz(M.value)
|
||||||
|
};
|
||||||
|
switch (M.kind) {
|
||||||
|
case "init":
|
||||||
|
return new AST_ObjectKeyVal(args);
|
||||||
|
case "set":
|
||||||
|
args.value.name = from_moz(key);
|
||||||
|
return new AST_ObjectSetter(args);
|
||||||
|
case "get":
|
||||||
|
args.value.name = from_moz(key);
|
||||||
|
return new AST_ObjectGetter(args);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ObjectExpression : function(M) {
|
ObjectExpression: function(M) {
|
||||||
return new AST_Object({
|
return new AST_Object({
|
||||||
start : my_start_token(M),
|
start : my_start_token(M),
|
||||||
end : my_end_token(M),
|
end : my_end_token(M),
|
||||||
properties : M.properties.map(function(prop){
|
properties : M.properties.map(function(prop){
|
||||||
var key = prop.key;
|
prop.type = "Property";
|
||||||
var name = key.type == "Identifier" ? key.name : key.value;
|
return from_moz(prop)
|
||||||
var args = {
|
|
||||||
start : my_start_token(key),
|
|
||||||
end : my_end_token(prop.value),
|
|
||||||
key : name,
|
|
||||||
value : from_moz(prop.value)
|
|
||||||
};
|
|
||||||
switch (prop.kind) {
|
|
||||||
case "init":
|
|
||||||
return new AST_ObjectKeyVal(args);
|
|
||||||
case "set":
|
|
||||||
args.value.name = from_moz(key);
|
|
||||||
return new AST_ObjectSetter(args);
|
|
||||||
case "get":
|
|
||||||
args.value.name = from_moz(key);
|
|
||||||
return new AST_ObjectGetter(args);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
SequenceExpression : function(M) {
|
SequenceExpression: function(M) {
|
||||||
return AST_Seq.from_array(M.expressions.map(from_moz));
|
return AST_Seq.from_array(M.expressions.map(from_moz));
|
||||||
},
|
},
|
||||||
MemberExpression : function(M) {
|
MemberExpression: function(M) {
|
||||||
return new (M.computed ? AST_Sub : AST_Dot)({
|
return new (M.computed ? AST_Sub : AST_Dot)({
|
||||||
start : my_start_token(M),
|
start : my_start_token(M),
|
||||||
end : my_end_token(M),
|
end : my_end_token(M),
|
||||||
@@ -100,7 +115,7 @@
|
|||||||
expression : from_moz(M.object)
|
expression : from_moz(M.object)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
SwitchCase : function(M) {
|
SwitchCase: function(M) {
|
||||||
return new (M.test ? AST_Case : AST_Default)({
|
return new (M.test ? AST_Case : AST_Default)({
|
||||||
start : my_start_token(M),
|
start : my_start_token(M),
|
||||||
end : my_end_token(M),
|
end : my_end_token(M),
|
||||||
@@ -108,7 +123,14 @@
|
|||||||
body : M.consequent.map(from_moz)
|
body : M.consequent.map(from_moz)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
Literal : function(M) {
|
VariableDeclaration: function(M) {
|
||||||
|
return new (M.kind === "const" ? AST_Const : AST_Var)({
|
||||||
|
start : my_start_token(M),
|
||||||
|
end : my_end_token(M),
|
||||||
|
definitions : M.declarations.map(from_moz)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
Literal: function(M) {
|
||||||
var val = M.value, args = {
|
var val = M.value, args = {
|
||||||
start : my_start_token(M),
|
start : my_start_token(M),
|
||||||
end : my_end_token(M)
|
end : my_end_token(M)
|
||||||
@@ -128,12 +150,9 @@
|
|||||||
return new AST_RegExp(args);
|
return new AST_RegExp(args);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
UnaryExpression: From_Moz_Unary,
|
|
||||||
UpdateExpression: From_Moz_Unary,
|
|
||||||
Identifier: function(M) {
|
Identifier: function(M) {
|
||||||
var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
|
var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
|
||||||
return new (M.name == "this" ? AST_This
|
return new ( p.type == "LabeledStatement" ? AST_Label
|
||||||
: p.type == "LabeledStatement" ? AST_Label
|
|
||||||
: p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar)
|
: p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : AST_SymbolVar)
|
||||||
: p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
|
: p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)
|
||||||
: p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
|
: p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg)
|
||||||
@@ -147,7 +166,8 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function From_Moz_Unary(M) {
|
MOZ_TO_ME.UpdateExpression =
|
||||||
|
MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) {
|
||||||
var prefix = "prefix" in M ? M.prefix
|
var prefix = "prefix" in M ? M.prefix
|
||||||
: M.type == "UnaryExpression" ? true : false;
|
: M.type == "UnaryExpression" ? true : false;
|
||||||
return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
|
return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({
|
||||||
@@ -158,14 +178,9 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var ME_TO_MOZ = {};
|
|
||||||
|
|
||||||
map("Node", AST_Node);
|
|
||||||
map("Program", AST_Toplevel, "body@body");
|
map("Program", AST_Toplevel, "body@body");
|
||||||
map("Function", AST_Function, "id>name, params@argnames, body%body");
|
|
||||||
map("EmptyStatement", AST_EmptyStatement);
|
map("EmptyStatement", AST_EmptyStatement);
|
||||||
map("BlockStatement", AST_BlockStatement, "body@body");
|
map("BlockStatement", AST_BlockStatement, "body@body");
|
||||||
map("ExpressionStatement", AST_SimpleStatement, "expression>body");
|
|
||||||
map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
|
map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
|
||||||
map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
|
map("LabeledStatement", AST_LabeledStatement, "label>label, body>body");
|
||||||
map("BreakStatement", AST_Break, "label>label");
|
map("BreakStatement", AST_Break, "label>label");
|
||||||
@@ -180,71 +195,261 @@
|
|||||||
map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
|
map("ForInStatement", AST_ForIn, "left>init, right>object, body>body");
|
||||||
map("DebuggerStatement", AST_Debugger);
|
map("DebuggerStatement", AST_Debugger);
|
||||||
map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body");
|
map("FunctionDeclaration", AST_Defun, "id>name, params@argnames, body%body");
|
||||||
map("VariableDeclaration", AST_Var, "declarations@definitions");
|
|
||||||
map("VariableDeclarator", AST_VarDef, "id>name, init>value");
|
map("VariableDeclarator", AST_VarDef, "id>name, init>value");
|
||||||
|
map("CatchClause", AST_Catch, "param>argname, body%body");
|
||||||
|
|
||||||
map("ThisExpression", AST_This);
|
map("ThisExpression", AST_This);
|
||||||
map("ArrayExpression", AST_Array, "elements@elements");
|
map("ArrayExpression", AST_Array, "elements@elements");
|
||||||
map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body");
|
map("FunctionExpression", AST_Function, "id>name, params@argnames, body%body");
|
||||||
map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
|
map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right");
|
||||||
map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
|
|
||||||
map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
|
map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right");
|
||||||
|
map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
|
||||||
map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
|
map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative");
|
||||||
map("NewExpression", AST_New, "callee>expression, arguments@args");
|
map("NewExpression", AST_New, "callee>expression, arguments@args");
|
||||||
map("CallExpression", AST_Call, "callee>expression, arguments@args");
|
map("CallExpression", AST_Call, "callee>expression, arguments@args");
|
||||||
|
|
||||||
|
def_to_moz(AST_Directive, function To_Moz_Directive(M) {
|
||||||
|
return {
|
||||||
|
type: "ExpressionStatement",
|
||||||
|
expression: {
|
||||||
|
type: "Literal",
|
||||||
|
value: M.value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) {
|
||||||
|
return {
|
||||||
|
type: "ExpressionStatement",
|
||||||
|
expression: to_moz(M.body)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) {
|
||||||
|
return {
|
||||||
|
type: "SwitchCase",
|
||||||
|
test: to_moz(M.expression),
|
||||||
|
consequent: M.body.map(to_moz)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Try, function To_Moz_TryStatement(M) {
|
||||||
|
return {
|
||||||
|
type: "TryStatement",
|
||||||
|
block: to_moz_block(M),
|
||||||
|
handler: to_moz(M.bcatch),
|
||||||
|
guardedHandlers: [],
|
||||||
|
finalizer: to_moz(M.bfinally)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Catch, function To_Moz_CatchClause(M) {
|
||||||
|
return {
|
||||||
|
type: "CatchClause",
|
||||||
|
param: to_moz(M.argname),
|
||||||
|
guard: null,
|
||||||
|
body: to_moz_block(M)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) {
|
||||||
|
return {
|
||||||
|
type: "VariableDeclaration",
|
||||||
|
kind: M instanceof AST_Const ? "const" : "var",
|
||||||
|
declarations: M.definitions.map(to_moz)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Seq, function To_Moz_SequenceExpression(M) {
|
||||||
|
return {
|
||||||
|
type: "SequenceExpression",
|
||||||
|
expressions: M.to_array().map(to_moz)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) {
|
||||||
|
var isComputed = M instanceof AST_Sub;
|
||||||
|
return {
|
||||||
|
type: "MemberExpression",
|
||||||
|
object: to_moz(M.expression),
|
||||||
|
computed: isComputed,
|
||||||
|
property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Unary, function To_Moz_Unary(M) {
|
||||||
|
return {
|
||||||
|
type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression",
|
||||||
|
operator: M.operator,
|
||||||
|
prefix: M instanceof AST_UnaryPrefix,
|
||||||
|
argument: to_moz(M.expression)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) {
|
||||||
|
return {
|
||||||
|
type: M.operator == "&&" || M.operator == "||" ? "LogicalExpression" : "BinaryExpression",
|
||||||
|
left: to_moz(M.left),
|
||||||
|
operator: M.operator,
|
||||||
|
right: to_moz(M.right)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) {
|
||||||
|
return {
|
||||||
|
type: "ObjectExpression",
|
||||||
|
properties: M.properties.map(to_moz)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_ObjectProperty, function To_Moz_Property(M) {
|
||||||
|
var key = (
|
||||||
|
is_identifier(M.key)
|
||||||
|
? {type: "Identifier", name: M.key}
|
||||||
|
: {type: "Literal", value: M.key}
|
||||||
|
);
|
||||||
|
var kind;
|
||||||
|
if (M instanceof AST_ObjectKeyVal) {
|
||||||
|
kind = "init";
|
||||||
|
} else
|
||||||
|
if (M instanceof AST_ObjectGetter) {
|
||||||
|
kind = "get";
|
||||||
|
} else
|
||||||
|
if (M instanceof AST_ObjectSetter) {
|
||||||
|
kind = "set";
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: "Property",
|
||||||
|
kind: kind,
|
||||||
|
key: key,
|
||||||
|
value: to_moz(M.value)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Symbol, function To_Moz_Identifier(M) {
|
||||||
|
var def = M.definition();
|
||||||
|
return {
|
||||||
|
type: "Identifier",
|
||||||
|
name: def ? def.mangled_name || def.name : M.name
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Constant, function To_Moz_Literal(M) {
|
||||||
|
var value = M.value;
|
||||||
|
if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) {
|
||||||
|
return {
|
||||||
|
type: "UnaryExpression",
|
||||||
|
operator: "-",
|
||||||
|
prefix: true,
|
||||||
|
argument: {
|
||||||
|
type: "Literal",
|
||||||
|
value: -value
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: "Literal",
|
||||||
|
value: value
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Atom, function To_Moz_Atom(M) {
|
||||||
|
return {
|
||||||
|
type: "Identifier",
|
||||||
|
name: String(M.value)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
|
||||||
|
AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast);
|
||||||
|
AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null });
|
||||||
|
|
||||||
|
AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast);
|
||||||
|
AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast);
|
||||||
|
|
||||||
/* -----[ tools ]----- */
|
/* -----[ tools ]----- */
|
||||||
|
|
||||||
function my_start_token(moznode) {
|
function my_start_token(moznode) {
|
||||||
|
var loc = moznode.loc, start = loc && loc.start;
|
||||||
|
var range = moznode.range;
|
||||||
return new AST_Token({
|
return new AST_Token({
|
||||||
file : moznode.loc && moznode.loc.source,
|
file : loc && loc.source,
|
||||||
line : moznode.loc && moznode.loc.start.line,
|
line : start && start.line,
|
||||||
col : moznode.loc && moznode.loc.start.column,
|
col : start && start.column,
|
||||||
pos : moznode.start,
|
pos : range ? range[0] : moznode.start,
|
||||||
endpos : moznode.start
|
endline : start && start.line,
|
||||||
|
endcol : start && start.column,
|
||||||
|
endpos : range ? range[0] : moznode.start
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function my_end_token(moznode) {
|
function my_end_token(moznode) {
|
||||||
|
var loc = moznode.loc, end = loc && loc.end;
|
||||||
|
var range = moznode.range;
|
||||||
return new AST_Token({
|
return new AST_Token({
|
||||||
file : moznode.loc && moznode.loc.source,
|
file : loc && loc.source,
|
||||||
line : moznode.loc && moznode.loc.end.line,
|
line : end && end.line,
|
||||||
col : moznode.loc && moznode.loc.end.column,
|
col : end && end.column,
|
||||||
pos : moznode.end,
|
pos : range ? range[1] : moznode.end,
|
||||||
endpos : moznode.end
|
endline : end && end.line,
|
||||||
|
endcol : end && end.column,
|
||||||
|
endpos : range ? range[1] : moznode.end
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function map(moztype, mytype, propmap) {
|
function map(moztype, mytype, propmap) {
|
||||||
var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
|
var moz_to_me = "function From_Moz_" + moztype + "(M){\n";
|
||||||
moz_to_me += "return new mytype({\n" +
|
moz_to_me += "return new U2." + mytype.name + "({\n" +
|
||||||
"start: my_start_token(M),\n" +
|
"start: my_start_token(M),\n" +
|
||||||
"end: my_end_token(M)";
|
"end: my_end_token(M)";
|
||||||
|
|
||||||
|
var me_to_moz = "function To_Moz_" + moztype + "(M){\n";
|
||||||
|
me_to_moz += "return {\n" +
|
||||||
|
"type: " + JSON.stringify(moztype);
|
||||||
|
|
||||||
if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){
|
if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop){
|
||||||
var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
|
var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i.exec(prop);
|
||||||
if (!m) throw new Error("Can't understand property map: " + prop);
|
if (!m) throw new Error("Can't understand property map: " + prop);
|
||||||
var moz = "M." + m[1], how = m[2], my = m[3];
|
var moz = m[1], how = m[2], my = m[3];
|
||||||
moz_to_me += ",\n" + my + ": ";
|
moz_to_me += ",\n" + my + ": ";
|
||||||
if (how == "@") {
|
me_to_moz += ",\n" + moz + ": ";
|
||||||
moz_to_me += moz + ".map(from_moz)";
|
switch (how) {
|
||||||
} else if (how == ">") {
|
case "@":
|
||||||
moz_to_me += "from_moz(" + moz + ")";
|
moz_to_me += "M." + moz + ".map(from_moz)";
|
||||||
} else if (how == "=") {
|
me_to_moz += "M." + my + ".map(to_moz)";
|
||||||
moz_to_me += moz;
|
break;
|
||||||
} else if (how == "%") {
|
case ">":
|
||||||
moz_to_me += "from_moz(" + moz + ").body";
|
moz_to_me += "from_moz(M." + moz + ")";
|
||||||
} else throw new Error("Can't understand operator in propmap: " + prop);
|
me_to_moz += "to_moz(M." + my + ")";
|
||||||
|
break;
|
||||||
|
case "=":
|
||||||
|
moz_to_me += "M." + moz;
|
||||||
|
me_to_moz += "M." + my;
|
||||||
|
break;
|
||||||
|
case "%":
|
||||||
|
moz_to_me += "from_moz(M." + moz + ").body";
|
||||||
|
me_to_moz += "to_moz_block(M)";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error("Can't understand operator in propmap: " + prop);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
moz_to_me += "\n})}";
|
|
||||||
|
|
||||||
// moz_to_me = parse(moz_to_me).print_to_string({ beautify: true });
|
moz_to_me += "\n})\n}";
|
||||||
// console.log(moz_to_me);
|
me_to_moz += "\n}\n}";
|
||||||
|
|
||||||
moz_to_me = new Function("mytype", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
|
//moz_to_me = parse(moz_to_me).print_to_string({ beautify: true });
|
||||||
mytype, my_start_token, my_end_token, from_moz
|
//me_to_moz = parse(me_to_moz).print_to_string({ beautify: true });
|
||||||
|
//console.log(moz_to_me);
|
||||||
|
|
||||||
|
moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
|
||||||
|
exports, my_start_token, my_end_token, from_moz
|
||||||
);
|
);
|
||||||
return MOZ_TO_ME[moztype] = moz_to_me;
|
me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")(
|
||||||
|
to_moz, to_moz_block
|
||||||
|
);
|
||||||
|
MOZ_TO_ME[moztype] = moz_to_me;
|
||||||
|
def_to_moz(mytype, me_to_moz);
|
||||||
};
|
};
|
||||||
|
|
||||||
var FROM_MOZ_STACK = null;
|
var FROM_MOZ_STACK = null;
|
||||||
@@ -264,4 +469,39 @@
|
|||||||
return ast;
|
return ast;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function set_moz_loc(mynode, moznode, myparent) {
|
||||||
|
var start = mynode.start;
|
||||||
|
var end = mynode.end;
|
||||||
|
if (start.pos != null && end.endpos != null) {
|
||||||
|
moznode.range = [start.pos, end.endpos];
|
||||||
|
}
|
||||||
|
if (start.line) {
|
||||||
|
moznode.loc = {
|
||||||
|
start: {line: start.line, column: start.col},
|
||||||
|
end: end.endline ? {line: end.endline, column: end.endcol} : null
|
||||||
|
};
|
||||||
|
if (start.file) {
|
||||||
|
moznode.loc.source = start.file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return moznode;
|
||||||
|
};
|
||||||
|
|
||||||
|
function def_to_moz(mytype, handler) {
|
||||||
|
mytype.DEFMETHOD("to_mozilla_ast", function() {
|
||||||
|
return set_moz_loc(this, handler(this));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function to_moz(node) {
|
||||||
|
return node != null ? node.to_mozilla_ast() : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function to_moz_block(node) {
|
||||||
|
return {
|
||||||
|
type: "BlockStatement",
|
||||||
|
body: node.body.map(to_moz)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
302
lib/output.js
302
lib/output.js
@@ -46,21 +46,25 @@
|
|||||||
function OutputStream(options) {
|
function OutputStream(options) {
|
||||||
|
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
indent_start : 0,
|
indent_start : 0,
|
||||||
indent_level : 4,
|
indent_level : 4,
|
||||||
quote_keys : false,
|
quote_keys : false,
|
||||||
space_colon : true,
|
space_colon : true,
|
||||||
ascii_only : false,
|
ascii_only : false,
|
||||||
inline_script : false,
|
unescape_regexps : false,
|
||||||
width : 80,
|
inline_script : false,
|
||||||
max_line_len : 32000,
|
width : 80,
|
||||||
beautify : false,
|
max_line_len : 32000,
|
||||||
source_map : null,
|
beautify : false,
|
||||||
bracketize : false,
|
source_map : null,
|
||||||
semicolons : true,
|
bracketize : false,
|
||||||
comments : false,
|
semicolons : true,
|
||||||
preserve_line : false,
|
comments : false,
|
||||||
screw_ie8 : false,
|
shebang : true,
|
||||||
|
preserve_line : false,
|
||||||
|
screw_ie8 : false,
|
||||||
|
preamble : null,
|
||||||
|
quote_style : 0
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
var indentation = 0;
|
var indentation = 0;
|
||||||
@@ -82,9 +86,9 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function make_string(str) {
|
function make_string(str, quote) {
|
||||||
var dq = 0, sq = 0;
|
var dq = 0, sq = 0;
|
||||||
str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g, function(s){
|
str = str.replace(/[\\\b\f\n\r\t\x22\x27\u2028\u2029\0\ufeff]/g, function(s){
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case "\\": return "\\\\";
|
case "\\": return "\\\\";
|
||||||
case "\b": return "\\b";
|
case "\b": return "\\b";
|
||||||
@@ -96,16 +100,31 @@ function OutputStream(options) {
|
|||||||
case '"': ++dq; return '"';
|
case '"': ++dq; return '"';
|
||||||
case "'": ++sq; return "'";
|
case "'": ++sq; return "'";
|
||||||
case "\0": return "\\x00";
|
case "\0": return "\\x00";
|
||||||
|
case "\ufeff": return "\\ufeff";
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
|
function quote_single() {
|
||||||
|
return "'" + str.replace(/\x27/g, "\\'") + "'";
|
||||||
|
}
|
||||||
|
function quote_double() {
|
||||||
|
return '"' + str.replace(/\x22/g, '\\"') + '"';
|
||||||
|
}
|
||||||
if (options.ascii_only) str = to_ascii(str);
|
if (options.ascii_only) str = to_ascii(str);
|
||||||
if (dq > sq) return "'" + str.replace(/\x27/g, "\\'") + "'";
|
switch (options.quote_style) {
|
||||||
else return '"' + str.replace(/\x22/g, '\\"') + '"';
|
case 1:
|
||||||
|
return quote_single();
|
||||||
|
case 2:
|
||||||
|
return quote_double();
|
||||||
|
case 3:
|
||||||
|
return quote == "'" ? quote_single() : quote_double();
|
||||||
|
default:
|
||||||
|
return dq > sq ? quote_single() : quote_double();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function encode_string(str) {
|
function encode_string(str, quote) {
|
||||||
var ret = make_string(str);
|
var ret = make_string(str, quote);
|
||||||
if (options.inline_script)
|
if (options.inline_script)
|
||||||
ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
|
ret = ret.replace(/<\x2fscript([>\/\t\n\f\r ])/gi, "<\\/script$1");
|
||||||
return ret;
|
return ret;
|
||||||
@@ -143,6 +162,8 @@ function OutputStream(options) {
|
|||||||
str = String(str);
|
str = String(str);
|
||||||
var ch = str.charAt(0);
|
var ch = str.charAt(0);
|
||||||
if (might_need_semicolon) {
|
if (might_need_semicolon) {
|
||||||
|
might_need_semicolon = false;
|
||||||
|
|
||||||
if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
|
if ((!ch || ";}".indexOf(ch) < 0) && !/[;]$/.test(last)) {
|
||||||
if (options.semicolons || requireSemicolonChars(ch)) {
|
if (options.semicolons || requireSemicolonChars(ch)) {
|
||||||
OUTPUT += ";";
|
OUTPUT += ";";
|
||||||
@@ -153,12 +174,17 @@ function OutputStream(options) {
|
|||||||
current_pos++;
|
current_pos++;
|
||||||
current_line++;
|
current_line++;
|
||||||
current_col = 0;
|
current_col = 0;
|
||||||
|
|
||||||
|
if (/^\s+$/.test(str)) {
|
||||||
|
// reset the semicolon flag, since we didn't print one
|
||||||
|
// now and might still have to later
|
||||||
|
might_need_semicolon = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.beautify)
|
if (!options.beautify)
|
||||||
might_need_space = false;
|
might_need_space = false;
|
||||||
}
|
}
|
||||||
might_need_semicolon = false;
|
|
||||||
maybe_newline();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
|
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
|
||||||
@@ -219,7 +245,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
var newline = options.beautify ? function() {
|
var newline = options.beautify ? function() {
|
||||||
print("\n");
|
print("\n");
|
||||||
} : noop;
|
} : maybe_newline;
|
||||||
|
|
||||||
var semicolon = options.beautify ? function() {
|
var semicolon = options.beautify ? function() {
|
||||||
print(";");
|
print(";");
|
||||||
@@ -299,6 +325,10 @@ function OutputStream(options) {
|
|||||||
return OUTPUT;
|
return OUTPUT;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (options.preamble) {
|
||||||
|
print(options.preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n"));
|
||||||
|
}
|
||||||
|
|
||||||
var stack = [];
|
var stack = [];
|
||||||
return {
|
return {
|
||||||
get : get,
|
get : get,
|
||||||
@@ -317,7 +347,7 @@ function OutputStream(options) {
|
|||||||
force_semicolon : force_semicolon,
|
force_semicolon : force_semicolon,
|
||||||
to_ascii : to_ascii,
|
to_ascii : to_ascii,
|
||||||
print_name : function(name) { print(make_name(name)) },
|
print_name : function(name) { print(make_name(name)) },
|
||||||
print_string : function(str) { print(encode_string(str)) },
|
print_string : function(str, quote) { print(encode_string(str, quote)) },
|
||||||
next_indent : next_indent,
|
next_indent : next_indent,
|
||||||
with_indent : with_indent,
|
with_indent : with_indent,
|
||||||
with_block : with_block,
|
with_block : with_block,
|
||||||
@@ -374,53 +404,82 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
AST_Node.DEFMETHOD("add_comments", function(output){
|
AST_Node.DEFMETHOD("add_comments", function(output){
|
||||||
var c = output.option("comments"), self = this;
|
var c = output.option("comments"), self = this;
|
||||||
if (c) {
|
var start = self.start;
|
||||||
var start = self.start;
|
if (start && !start._comments_dumped) {
|
||||||
if (start && !start._comments_dumped) {
|
start._comments_dumped = true;
|
||||||
start._comments_dumped = true;
|
var comments = start.comments_before || [];
|
||||||
var comments = start.comments_before;
|
|
||||||
|
|
||||||
// XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
|
// XXX: ugly fix for https://github.com/mishoo/UglifyJS2/issues/112
|
||||||
// if this node is `return` or `throw`, we cannot allow comments before
|
// and https://github.com/mishoo/UglifyJS2/issues/372
|
||||||
// the returned or thrown value.
|
if (self instanceof AST_Exit && self.value) {
|
||||||
if (self instanceof AST_Exit &&
|
self.value.walk(new TreeWalker(function(node){
|
||||||
self.value && self.value.start.comments_before.length > 0) {
|
if (node.start && node.start.comments_before) {
|
||||||
comments = (comments || []).concat(self.value.start.comments_before);
|
comments = comments.concat(node.start.comments_before);
|
||||||
self.value.start.comments_before = [];
|
node.start.comments_before = [];
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Function ||
|
||||||
|
node instanceof AST_Array ||
|
||||||
|
node instanceof AST_Object)
|
||||||
|
{
|
||||||
|
return true; // don't go inside.
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if (c.test) {
|
if (!c) {
|
||||||
comments = comments.filter(function(comment){
|
comments = comments.filter(function(comment) {
|
||||||
return c.test(comment.value);
|
return comment.type == "comment5";
|
||||||
});
|
});
|
||||||
} else if (typeof c == "function") {
|
} else if (c.test) {
|
||||||
comments = comments.filter(function(comment){
|
comments = comments.filter(function(comment){
|
||||||
return c(self, comment);
|
return c.test(comment.value) || comment.type == "comment5";
|
||||||
});
|
});
|
||||||
}
|
} else if (typeof c == "function") {
|
||||||
comments.forEach(function(c){
|
comments = comments.filter(function(comment){
|
||||||
if (c.type == "comment1") {
|
return c(self, comment) || comment.type == "comment5";
|
||||||
output.print("//" + c.value + "\n");
|
|
||||||
output.indent();
|
|
||||||
}
|
|
||||||
else if (c.type == "comment2") {
|
|
||||||
output.print("/*" + c.value + "*/");
|
|
||||||
if (start.nlb) {
|
|
||||||
output.print("\n");
|
|
||||||
output.indent();
|
|
||||||
} else {
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep single line comments after nlb, after nlb
|
||||||
|
if (!output.option("beautify") && comments.length > 0 &&
|
||||||
|
/comment[134]/.test(comments[0].type) &&
|
||||||
|
output.col() !== 0 && comments[0].nlb)
|
||||||
|
{
|
||||||
|
output.print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
comments.forEach(function(c){
|
||||||
|
if (/comment[134]/.test(c.type)) {
|
||||||
|
output.print("//" + c.value + "\n");
|
||||||
|
output.indent();
|
||||||
|
}
|
||||||
|
else if (c.type == "comment2") {
|
||||||
|
output.print("/*" + c.value + "*/");
|
||||||
|
if (start.nlb) {
|
||||||
|
output.print("\n");
|
||||||
|
output.indent();
|
||||||
|
} else {
|
||||||
|
output.space();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (output.pos() === 0 && c.type == "comment5" && output.option("shebang")) {
|
||||||
|
output.print("#!" + c.value + "\n");
|
||||||
|
output.indent();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/* -----[ PARENTHESES ]----- */
|
/* -----[ PARENTHESES ]----- */
|
||||||
|
|
||||||
function PARENS(nodetype, func) {
|
function PARENS(nodetype, func) {
|
||||||
nodetype.DEFMETHOD("needs_parens", func);
|
if (Array.isArray(nodetype)) {
|
||||||
|
nodetype.forEach(function(nodetype){
|
||||||
|
PARENS(nodetype, func);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
nodetype.DEFMETHOD("needs_parens", func);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PARENS(AST_Node, function(){
|
PARENS(AST_Node, function(){
|
||||||
@@ -439,7 +498,7 @@ function OutputStream(options) {
|
|||||||
return first_in_statement(output);
|
return first_in_statement(output);
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Unary, function(output){
|
PARENS([ AST_Unary, AST_Undefined ], function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
return p instanceof AST_PropAccess && p.expression === this;
|
return p instanceof AST_PropAccess && p.expression === this;
|
||||||
});
|
});
|
||||||
@@ -450,7 +509,7 @@ function OutputStream(options) {
|
|||||||
|| p instanceof AST_Unary // !(foo, bar, baz)
|
|| p instanceof AST_Unary // !(foo, bar, baz)
|
||||||
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|
|| p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8
|
||||||
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|
|| p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4
|
||||||
|| p instanceof AST_Dot // (1, {foo:2}).foo ==> 2
|
|| p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2
|
||||||
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
|| p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ]
|
||||||
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|
|| p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2
|
||||||
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
|
|| p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30)
|
||||||
@@ -475,11 +534,7 @@ function OutputStream(options) {
|
|||||||
var so = this.operator, sp = PRECEDENCE[so];
|
var so = this.operator, sp = PRECEDENCE[so];
|
||||||
if (pp > sp
|
if (pp > sp
|
||||||
|| (pp == sp
|
|| (pp == sp
|
||||||
&& this === p.right
|
&& this === p.right)) {
|
||||||
&& !(so == po &&
|
|
||||||
(so == "*" ||
|
|
||||||
so == "&&" ||
|
|
||||||
so == "||")))) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -506,8 +561,17 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Call, function(output){
|
PARENS(AST_Call, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent(), p1;
|
||||||
return p instanceof AST_New && p.expression === this;
|
if (p instanceof AST_New && p.expression === this)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// workaround for Safari bug.
|
||||||
|
// https://bugs.webkit.org/show_bug.cgi?id=123506
|
||||||
|
return this.expression instanceof AST_Function
|
||||||
|
&& p instanceof AST_PropAccess
|
||||||
|
&& p.expression === this
|
||||||
|
&& (p1 = output.parent(1)) instanceof AST_Assign
|
||||||
|
&& p1.left === p;
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_New, function(output){
|
PARENS(AST_New, function(output){
|
||||||
@@ -524,13 +588,7 @@ function OutputStream(options) {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_NaN, function(output){
|
PARENS([ AST_Assign, AST_Conditional ], function (output){
|
||||||
var p = output.parent();
|
|
||||||
if (p instanceof AST_PropAccess && p.expression === this)
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
function assign_and_conditional_paren_rules(output) {
|
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
// !(a = false) → true
|
// !(a = false) → true
|
||||||
if (p instanceof AST_Unary)
|
if (p instanceof AST_Unary)
|
||||||
@@ -547,15 +605,12 @@ function OutputStream(options) {
|
|||||||
// (a = foo)["prop"] —or— (a = foo).prop
|
// (a = foo)["prop"] —or— (a = foo).prop
|
||||||
if (p instanceof AST_PropAccess && p.expression === this)
|
if (p instanceof AST_PropAccess && p.expression === this)
|
||||||
return true;
|
return true;
|
||||||
};
|
});
|
||||||
|
|
||||||
PARENS(AST_Assign, assign_and_conditional_paren_rules);
|
|
||||||
PARENS(AST_Conditional, assign_and_conditional_paren_rules);
|
|
||||||
|
|
||||||
/* -----[ PRINTERS ]----- */
|
/* -----[ PRINTERS ]----- */
|
||||||
|
|
||||||
DEFPRINT(AST_Directive, function(self, output){
|
DEFPRINT(AST_Directive, function(self, output){
|
||||||
output.print_string(self.value);
|
output.print_string(self.value, self.quote);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Debugger, function(self, output){
|
DEFPRINT(AST_Debugger, function(self, output){
|
||||||
@@ -637,7 +692,7 @@ function OutputStream(options) {
|
|||||||
output.print("for");
|
output.print("for");
|
||||||
output.space();
|
output.space();
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
if (self.init) {
|
if (self.init && !(self.init instanceof AST_EmptyStatement)) {
|
||||||
if (self.init instanceof AST_Definitions) {
|
if (self.init instanceof AST_Definitions) {
|
||||||
self.init.print(output);
|
self.init.print(output);
|
||||||
} else {
|
} else {
|
||||||
@@ -977,8 +1032,12 @@ function OutputStream(options) {
|
|||||||
DEFPRINT(AST_UnaryPrefix, function(self, output){
|
DEFPRINT(AST_UnaryPrefix, function(self, output){
|
||||||
var op = self.operator;
|
var op = self.operator;
|
||||||
output.print(op);
|
output.print(op);
|
||||||
if (/^[a-z]/i.test(op))
|
if (/^[a-z]/i.test(op)
|
||||||
|
|| (/[+-]$/.test(op)
|
||||||
|
&& self.expression instanceof AST_UnaryPrefix
|
||||||
|
&& /^[+-]/.test(self.expression.operator))) {
|
||||||
output.space();
|
output.space();
|
||||||
|
}
|
||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_UnaryPostfix, function(self, output){
|
DEFPRINT(AST_UnaryPostfix, function(self, output){
|
||||||
@@ -989,7 +1048,18 @@ function OutputStream(options) {
|
|||||||
self.left.print(output);
|
self.left.print(output);
|
||||||
output.space();
|
output.space();
|
||||||
output.print(self.operator);
|
output.print(self.operator);
|
||||||
output.space();
|
if (self.operator == "<"
|
||||||
|
&& self.right instanceof AST_UnaryPrefix
|
||||||
|
&& self.right.operator == "!"
|
||||||
|
&& self.right.expression instanceof AST_UnaryPrefix
|
||||||
|
&& self.right.expression.operator == "--") {
|
||||||
|
// space is mandatory to avoid outputting <!--
|
||||||
|
// http://javascript.spec.whatwg.org/#comment-syntax
|
||||||
|
output.print(" ");
|
||||||
|
} else {
|
||||||
|
// the space is optional depending on "beautify"
|
||||||
|
output.space();
|
||||||
|
}
|
||||||
self.right.print(output);
|
self.right.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Conditional, function(self, output){
|
DEFPRINT(AST_Conditional, function(self, output){
|
||||||
@@ -1036,6 +1106,7 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
DEFPRINT(AST_ObjectKeyVal, function(self, output){
|
DEFPRINT(AST_ObjectKeyVal, function(self, output){
|
||||||
var key = self.key;
|
var key = self.key;
|
||||||
|
var quote = self.quote;
|
||||||
if (output.option("quote_keys")) {
|
if (output.option("quote_keys")) {
|
||||||
output.print_string(key + "");
|
output.print_string(key + "");
|
||||||
} else if ((typeof key == "number"
|
} else if ((typeof key == "number"
|
||||||
@@ -1046,17 +1117,21 @@ function OutputStream(options) {
|
|||||||
} else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
|
} else if (RESERVED_WORDS(key) ? output.option("screw_ie8") : is_identifier_string(key)) {
|
||||||
output.print_name(key);
|
output.print_name(key);
|
||||||
} else {
|
} else {
|
||||||
output.print_string(key);
|
output.print_string(key, quote);
|
||||||
}
|
}
|
||||||
output.colon();
|
output.colon();
|
||||||
self.value.print(output);
|
self.value.print(output);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ObjectSetter, function(self, output){
|
DEFPRINT(AST_ObjectSetter, function(self, output){
|
||||||
output.print("set");
|
output.print("set");
|
||||||
|
output.space();
|
||||||
|
self.key.print(output);
|
||||||
self.value._do_print(output, true);
|
self.value._do_print(output, true);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_ObjectGetter, function(self, output){
|
DEFPRINT(AST_ObjectGetter, function(self, output){
|
||||||
output.print("get");
|
output.print("get");
|
||||||
|
output.space();
|
||||||
|
self.key.print(output);
|
||||||
self.value._do_print(output, true);
|
self.value._do_print(output, true);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Symbol, function(self, output){
|
DEFPRINT(AST_Symbol, function(self, output){
|
||||||
@@ -1068,10 +1143,10 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
DEFPRINT(AST_Hole, noop);
|
DEFPRINT(AST_Hole, noop);
|
||||||
DEFPRINT(AST_Infinity, function(self, output){
|
DEFPRINT(AST_Infinity, function(self, output){
|
||||||
output.print("1/0");
|
output.print("Infinity");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_NaN, function(self, output){
|
DEFPRINT(AST_NaN, function(self, output){
|
||||||
output.print("0/0");
|
output.print("NaN");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_This, function(self, output){
|
DEFPRINT(AST_This, function(self, output){
|
||||||
output.print("this");
|
output.print("this");
|
||||||
@@ -1080,15 +1155,58 @@ function OutputStream(options) {
|
|||||||
output.print(self.getValue());
|
output.print(self.getValue());
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_String, function(self, output){
|
DEFPRINT(AST_String, function(self, output){
|
||||||
output.print_string(self.getValue());
|
output.print_string(self.getValue(), self.quote);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Number, function(self, output){
|
DEFPRINT(AST_Number, function(self, output){
|
||||||
output.print(make_num(self.getValue()));
|
if (self.literal !== undefined
|
||||||
|
&& +self.literal === self.value /* paranoid check */
|
||||||
|
&& self.scope && self.scope.has_directive('use asm')) {
|
||||||
|
output.print(self.literal);
|
||||||
|
} else {
|
||||||
|
output.print(make_num(self.getValue()));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function regexp_safe_literal(code) {
|
||||||
|
return [
|
||||||
|
0x5c , // \
|
||||||
|
0x2f , // /
|
||||||
|
0x2e , // .
|
||||||
|
0x2b , // +
|
||||||
|
0x2a , // *
|
||||||
|
0x3f , // ?
|
||||||
|
0x28 , // (
|
||||||
|
0x29 , // )
|
||||||
|
0x5b , // [
|
||||||
|
0x5d , // ]
|
||||||
|
0x7b , // {
|
||||||
|
0x7d , // }
|
||||||
|
0x24 , // $
|
||||||
|
0x5e , // ^
|
||||||
|
0x3a , // :
|
||||||
|
0x7c , // |
|
||||||
|
0x21 , // !
|
||||||
|
0x0a , // \n
|
||||||
|
0x0d , // \r
|
||||||
|
0x00 , // \0
|
||||||
|
0xfeff , // Unicode BOM
|
||||||
|
0x2028 , // unicode "line separator"
|
||||||
|
0x2029 , // unicode "paragraph separator"
|
||||||
|
].indexOf(code) < 0;
|
||||||
|
};
|
||||||
|
|
||||||
DEFPRINT(AST_RegExp, function(self, output){
|
DEFPRINT(AST_RegExp, function(self, output){
|
||||||
var str = self.getValue().toString();
|
var str = self.getValue().toString();
|
||||||
if (output.option("ascii_only"))
|
if (output.option("ascii_only")) {
|
||||||
str = output.to_ascii(str);
|
str = output.to_ascii(str);
|
||||||
|
} else if (output.option("unescape_regexps")) {
|
||||||
|
str = str.split("\\\\").map(function(str){
|
||||||
|
return str.replace(/\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}/g, function(s){
|
||||||
|
var code = parseInt(s.substr(2), 16);
|
||||||
|
return regexp_safe_literal(code) ? String.fromCharCode(code) : s;
|
||||||
|
});
|
||||||
|
}).join("\\\\");
|
||||||
|
}
|
||||||
output.print(str);
|
output.print(str);
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
if (p instanceof AST_Binary && /^in/.test(p.operator) && p.left === self)
|
||||||
|
|||||||
274
lib/parse.js
274
lib/parse.js
@@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with';
|
var KEYWORDS = 'break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with';
|
||||||
var KEYWORDS_ATOM = 'false null true';
|
var KEYWORDS_ATOM = 'false null true';
|
||||||
var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile'
|
var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized this throws transient volatile yield'
|
||||||
+ " " + KEYWORDS_ATOM + " " + KEYWORDS;
|
+ " " + KEYWORDS_ATOM + " " + KEYWORDS;
|
||||||
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';
|
var KEYWORDS_BEFORE_EXPRESSION = 'return new delete throw else case';
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ var OPERATORS = makePredicate([
|
|||||||
"||"
|
"||"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000"));
|
var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\uFEFF"));
|
||||||
|
|
||||||
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
|
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
|
||||||
|
|
||||||
@@ -120,7 +120,8 @@ var REGEXP_MODIFIERS = makePredicate(characters("gmsiy"));
|
|||||||
|
|
||||||
// regexps adapted from http://xregexp.com/plugins/#unicode
|
// regexps adapted from http://xregexp.com/plugins/#unicode
|
||||||
var UNICODE = {
|
var UNICODE = {
|
||||||
letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u0523\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0621-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971\\u0972\\u097B-\\u097F\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C33\\u0C35-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D28\\u0D2A-\\u0D39\\u0D3D\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC\\u0EDD\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8B\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10D0-\\u10FA\\u10FC\\u1100-\\u1159\\u115F-\\u11A2\\u11A8-\\u11F9\\u1200-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u1676\\u1681-\\u169A\\u16A0-\\u16EA\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u1900-\\u191C\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19A9\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u2094\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2C6F\\u2C71-\\u2C7D\\u2C80-\\u2CE4\\u2D00-\\u2D25\\u2D30-\\u2D65\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31B7\\u31F0-\\u31FF\\u3400\\u4DB5\\u4E00\\u9FC3\\uA000-\\uA48C\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA65F\\uA662-\\uA66E\\uA67F-\\uA697\\uA717-\\uA71F\\uA722-\\uA788\\uA78B\\uA78C\\uA7FB-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA90A-\\uA925\\uA930-\\uA946\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAC00\\uD7A3\\uF900-\\uFA2D\\uFA30-\\uFA6A\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
|
letter: new RegExp("[\\u0041-\\u005A\\u0061-\\u007A\\u00AA\\u00B5\\u00BA\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05D0-\\u05EA\\u05F0-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u08A0-\\u08B2\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58\\u0C59\\u0C60\\u0C61\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D05-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D60\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E87\\u0E88\\u0E8A\\u0E8D\\u0E94-\\u0E97\\u0E99-\\u0E9F\\u0EA1-\\u0EA3\\u0EA5\\u0EA7\\u0EAA\\u0EAB\\u0EAD-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F4\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F8\\u1700-\\u170C\\u170E-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1877\\u1880-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19C1-\\u19C7\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4B\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1CE9-\\u1CEC\\u1CEE-\\u1CF1\\u1CF5\\u1CF6\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2160-\\u2188\\u2C00-\\u2C2E\\u2C30-\\u2C5E\\u2C60-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312D\\u3131-\\u318E\\u31A0-\\u31BA\\u31F0-\\u31FF\\u3400-\\u4DB5\\u4E00-\\u9FCC\\uA000-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA78E\\uA790-\\uA7AD\\uA7B0\\uA7B1\\uA7F7-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB5F\\uAB64\\uAB65\\uABC0-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]"),
|
||||||
|
digit: new RegExp("[\\u0030-\\u0039\\u0660-\\u0669\\u06F0-\\u06F9\\u07C0-\\u07C9\\u0966-\\u096F\\u09E6-\\u09EF\\u0A66-\\u0A6F\\u0AE6-\\u0AEF\\u0B66-\\u0B6F\\u0BE6-\\u0BEF\\u0C66-\\u0C6F\\u0CE6-\\u0CEF\\u0D66-\\u0D6F\\u0DE6-\\u0DEF\\u0E50-\\u0E59\\u0ED0-\\u0ED9\\u0F20-\\u0F29\\u1040-\\u1049\\u1090-\\u1099\\u17E0-\\u17E9\\u1810-\\u1819\\u1946-\\u194F\\u19D0-\\u19D9\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1B50-\\u1B59\\u1BB0-\\u1BB9\\u1C40-\\u1C49\\u1C50-\\u1C59\\uA620-\\uA629\\uA8D0-\\uA8D9\\uA900-\\uA909\\uA9D0-\\uA9D9\\uA9F0-\\uA9F9\\uAA50-\\uAA59\\uABF0-\\uABF9\\uFF10-\\uFF19]"),
|
||||||
non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
|
non_spacing_mark: new RegExp("[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]"),
|
||||||
space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
|
space_combining_mark: new RegExp("[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]"),
|
||||||
connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
|
connector_punctuation: new RegExp("[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]")
|
||||||
@@ -133,13 +134,17 @@ function is_letter(code) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function is_digit(code) {
|
function is_digit(code) {
|
||||||
return code >= 48 && code <= 57; //XXX: find out if "UnicodeDigit" means something else than 0..9
|
return code >= 48 && code <= 57;
|
||||||
};
|
};
|
||||||
|
|
||||||
function is_alphanumeric_char(code) {
|
function is_alphanumeric_char(code) {
|
||||||
return is_digit(code) || is_letter(code);
|
return is_digit(code) || is_letter(code);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function is_unicode_digit(code) {
|
||||||
|
return UNICODE.digit.test(String.fromCharCode(code));
|
||||||
|
}
|
||||||
|
|
||||||
function is_unicode_combining_mark(ch) {
|
function is_unicode_combining_mark(ch) {
|
||||||
return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
|
return UNICODE.non_spacing_mark.test(ch) || UNICODE.space_combining_mark.test(ch);
|
||||||
};
|
};
|
||||||
@@ -164,18 +169,12 @@ function is_identifier_char(ch) {
|
|||||||
|| code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
|
|| code == 8205 // \u200d: zero-width joiner <ZWJ> (in my ECMA-262 PDF, this is also 200c)
|
||||||
|| is_unicode_combining_mark(ch)
|
|| is_unicode_combining_mark(ch)
|
||||||
|| is_unicode_connector_punctuation(ch)
|
|| is_unicode_connector_punctuation(ch)
|
||||||
|
|| is_unicode_digit(code)
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
||||||
function is_identifier_string(str){
|
function is_identifier_string(str){
|
||||||
var i = str.length;
|
return /^[a-z_$][a-z0-9_$]*$/i.test(str);
|
||||||
if (i == 0) return false;
|
|
||||||
if (is_digit(str.charCodeAt(0))) return false;
|
|
||||||
while (--i >= 0) {
|
|
||||||
if (!is_identifier_char(str.charAt(i)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function parse_js_number(num) {
|
function parse_js_number(num) {
|
||||||
@@ -188,8 +187,9 @@ function parse_js_number(num) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function JS_Parse_Error(message, line, col, pos) {
|
function JS_Parse_Error(message, filename, line, col, pos) {
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
this.filename = filename;
|
||||||
this.line = line;
|
this.line = line;
|
||||||
this.col = col;
|
this.col = col;
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
@@ -201,7 +201,7 @@ JS_Parse_Error.prototype.toString = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function js_error(message, filename, line, col, pos) {
|
function js_error(message, filename, line, col, pos) {
|
||||||
throw new JS_Parse_Error(message, line, col, pos);
|
throw new JS_Parse_Error(message, filename, line, col, pos);
|
||||||
};
|
};
|
||||||
|
|
||||||
function is_token(token, type, val) {
|
function is_token(token, type, val) {
|
||||||
@@ -210,10 +210,10 @@ function is_token(token, type, val) {
|
|||||||
|
|
||||||
var EX_EOF = {};
|
var EX_EOF = {};
|
||||||
|
|
||||||
function tokenizer($TEXT, filename) {
|
function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
|
|
||||||
var S = {
|
var S = {
|
||||||
text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/\uFEFF/g, ''),
|
text : $TEXT,
|
||||||
filename : filename,
|
filename : filename,
|
||||||
pos : 0,
|
pos : 0,
|
||||||
tokpos : 0,
|
tokpos : 0,
|
||||||
@@ -232,16 +232,29 @@ function tokenizer($TEXT, filename) {
|
|||||||
var ch = S.text.charAt(S.pos++);
|
var ch = S.text.charAt(S.pos++);
|
||||||
if (signal_eof && !ch)
|
if (signal_eof && !ch)
|
||||||
throw EX_EOF;
|
throw EX_EOF;
|
||||||
if (ch == "\n") {
|
if ("\r\n\u2028\u2029".indexOf(ch) >= 0) {
|
||||||
S.newline_before = S.newline_before || !in_string;
|
S.newline_before = S.newline_before || !in_string;
|
||||||
++S.line;
|
++S.line;
|
||||||
S.col = 0;
|
S.col = 0;
|
||||||
|
if (!in_string && ch == "\r" && peek() == "\n") {
|
||||||
|
// treat a \r\n sequence as a single \n
|
||||||
|
++S.pos;
|
||||||
|
ch = "\n";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
++S.col;
|
++S.col;
|
||||||
}
|
}
|
||||||
return ch;
|
return ch;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function forward(i) {
|
||||||
|
while (i-- > 0) next();
|
||||||
|
};
|
||||||
|
|
||||||
|
function looking_at(str) {
|
||||||
|
return S.text.substr(S.pos, str.length) == str;
|
||||||
|
};
|
||||||
|
|
||||||
function find(what, signal_eof) {
|
function find(what, signal_eof) {
|
||||||
var pos = S.text.indexOf(what, S.pos);
|
var pos = S.text.indexOf(what, S.pos);
|
||||||
if (signal_eof && pos == -1) throw EX_EOF;
|
if (signal_eof && pos == -1) throw EX_EOF;
|
||||||
@@ -254,19 +267,23 @@ function tokenizer($TEXT, filename) {
|
|||||||
S.tokpos = S.pos;
|
S.tokpos = S.pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var prev_was_dot = false;
|
||||||
function token(type, value, is_comment) {
|
function token(type, value, is_comment) {
|
||||||
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
|
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
|
||||||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
|
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
|
||||||
(type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
|
(type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
|
||||||
|
prev_was_dot = (type == "punc" && value == ".");
|
||||||
var ret = {
|
var ret = {
|
||||||
type : type,
|
type : type,
|
||||||
value : value,
|
value : value,
|
||||||
line : S.tokline,
|
line : S.tokline,
|
||||||
col : S.tokcol,
|
col : S.tokcol,
|
||||||
pos : S.tokpos,
|
pos : S.tokpos,
|
||||||
endpos : S.pos,
|
endline : S.line,
|
||||||
nlb : S.newline_before,
|
endcol : S.col,
|
||||||
file : filename
|
endpos : S.pos,
|
||||||
|
nlb : S.newline_before,
|
||||||
|
file : filename
|
||||||
};
|
};
|
||||||
if (!is_comment) {
|
if (!is_comment) {
|
||||||
ret.comments_before = S.comments_before;
|
ret.comments_before = S.comments_before;
|
||||||
@@ -281,7 +298,8 @@ function tokenizer($TEXT, filename) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function skip_whitespace() {
|
function skip_whitespace() {
|
||||||
while (WHITESPACE_CHARS(peek()))
|
var ch;
|
||||||
|
while (WHITESPACE_CHARS(ch = peek()) || ch == "\u2028" || ch == "\u2029")
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -317,7 +335,11 @@ function tokenizer($TEXT, filename) {
|
|||||||
if (prefix) num = prefix + num;
|
if (prefix) num = prefix + num;
|
||||||
var valid = parse_js_number(num);
|
var valid = parse_js_number(num);
|
||||||
if (!isNaN(valid)) {
|
if (!isNaN(valid)) {
|
||||||
return token("num", valid);
|
var tok = token("num", valid);
|
||||||
|
if (num.indexOf('.') >= 0) {
|
||||||
|
tok.literal = num;
|
||||||
|
}
|
||||||
|
return tok;
|
||||||
} else {
|
} else {
|
||||||
parse_error("Invalid syntax: " + num);
|
parse_error("Invalid syntax: " + num);
|
||||||
}
|
}
|
||||||
@@ -336,8 +358,13 @@ function tokenizer($TEXT, filename) {
|
|||||||
case 120 : return String.fromCharCode(hex_bytes(2)); // \x
|
case 120 : return String.fromCharCode(hex_bytes(2)); // \x
|
||||||
case 117 : return String.fromCharCode(hex_bytes(4)); // \u
|
case 117 : return String.fromCharCode(hex_bytes(4)); // \u
|
||||||
case 10 : return ""; // newline
|
case 10 : return ""; // newline
|
||||||
default : return ch;
|
case 13 : // \r
|
||||||
|
if (peek() == "\n") { // DOS newline
|
||||||
|
next(true, in_string);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return ch;
|
||||||
};
|
};
|
||||||
|
|
||||||
function hex_bytes(n) {
|
function hex_bytes(n) {
|
||||||
@@ -351,10 +378,10 @@ function tokenizer($TEXT, filename) {
|
|||||||
return num;
|
return num;
|
||||||
};
|
};
|
||||||
|
|
||||||
var read_string = with_eof_error("Unterminated string constant", function(){
|
var read_string = with_eof_error("Unterminated string constant", function(quote_char){
|
||||||
var quote = next(), ret = "";
|
var quote = next(), ret = "";
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var ch = next(true);
|
var ch = next(true, true);
|
||||||
if (ch == "\\") {
|
if (ch == "\\") {
|
||||||
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
|
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
|
||||||
// https://github.com/mishoo/UglifyJS/issues/178
|
// https://github.com/mishoo/UglifyJS/issues/178
|
||||||
@@ -376,11 +403,13 @@ function tokenizer($TEXT, filename) {
|
|||||||
else if (ch == quote) break;
|
else if (ch == quote) break;
|
||||||
ret += ch;
|
ret += ch;
|
||||||
}
|
}
|
||||||
return token("string", ret);
|
var tok = token("string", ret);
|
||||||
|
tok.quote = quote_char;
|
||||||
|
return tok;
|
||||||
});
|
});
|
||||||
|
|
||||||
function read_line_comment() {
|
function skip_line_comment(type) {
|
||||||
next();
|
var regex_allowed = S.regex_allowed;
|
||||||
var i = find("\n"), ret;
|
var i = find("\n"), ret;
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
ret = S.text.substr(S.pos);
|
ret = S.text.substr(S.pos);
|
||||||
@@ -389,11 +418,14 @@ function tokenizer($TEXT, filename) {
|
|||||||
ret = S.text.substring(S.pos, i);
|
ret = S.text.substring(S.pos, i);
|
||||||
S.pos = i;
|
S.pos = i;
|
||||||
}
|
}
|
||||||
return token("comment1", ret, true);
|
S.col = S.tokcol + (S.pos - S.tokpos);
|
||||||
|
S.comments_before.push(token(type, ret, true));
|
||||||
|
S.regex_allowed = regex_allowed;
|
||||||
|
return next_token();
|
||||||
};
|
};
|
||||||
|
|
||||||
var read_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
|
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
|
||||||
next();
|
var regex_allowed = S.regex_allowed;
|
||||||
var i = find("*/", true);
|
var i = find("*/", true);
|
||||||
var text = S.text.substring(S.pos, i);
|
var text = S.text.substring(S.pos, i);
|
||||||
var a = text.split("\n"), n = a.length;
|
var a = text.split("\n"), n = a.length;
|
||||||
@@ -403,8 +435,11 @@ function tokenizer($TEXT, filename) {
|
|||||||
if (n > 1) S.col = a[n - 1].length;
|
if (n > 1) S.col = a[n - 1].length;
|
||||||
else S.col += a[n - 1].length;
|
else S.col += a[n - 1].length;
|
||||||
S.col += 2;
|
S.col += 2;
|
||||||
S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
|
var nlb = S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
|
||||||
return token("comment2", text, true);
|
S.comments_before.push(token("comment2", text, true));
|
||||||
|
S.regex_allowed = regex_allowed;
|
||||||
|
S.newline_before = nlb;
|
||||||
|
return next_token();
|
||||||
});
|
});
|
||||||
|
|
||||||
function read_name() {
|
function read_name() {
|
||||||
@@ -449,7 +484,11 @@ function tokenizer($TEXT, filename) {
|
|||||||
regexp += ch;
|
regexp += ch;
|
||||||
}
|
}
|
||||||
var mods = read_name();
|
var mods = read_name();
|
||||||
return token("regexp", new RegExp(regexp, mods));
|
try {
|
||||||
|
return token("regexp", new RegExp(regexp, mods));
|
||||||
|
} catch(e) {
|
||||||
|
parse_error(e.message);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function read_operator(prefix) {
|
function read_operator(prefix) {
|
||||||
@@ -468,16 +507,13 @@ function tokenizer($TEXT, filename) {
|
|||||||
|
|
||||||
function handle_slash() {
|
function handle_slash() {
|
||||||
next();
|
next();
|
||||||
var regex_allowed = S.regex_allowed;
|
|
||||||
switch (peek()) {
|
switch (peek()) {
|
||||||
case "/":
|
case "/":
|
||||||
S.comments_before.push(read_line_comment());
|
next();
|
||||||
S.regex_allowed = regex_allowed;
|
return skip_line_comment("comment1");
|
||||||
return next_token();
|
|
||||||
case "*":
|
case "*":
|
||||||
S.comments_before.push(read_multiline_comment());
|
next();
|
||||||
S.regex_allowed = regex_allowed;
|
return skip_multiline_comment();
|
||||||
return next_token();
|
|
||||||
}
|
}
|
||||||
return S.regex_allowed ? read_regexp("") : read_operator("/");
|
return S.regex_allowed ? read_regexp("") : read_operator("/");
|
||||||
};
|
};
|
||||||
@@ -491,6 +527,7 @@ function tokenizer($TEXT, filename) {
|
|||||||
|
|
||||||
function read_word() {
|
function read_word() {
|
||||||
var word = read_name();
|
var word = read_name();
|
||||||
|
if (prev_was_dot) return token("name", word);
|
||||||
return KEYWORDS_ATOM(word) ? token("atom", word)
|
return KEYWORDS_ATOM(word) ? token("atom", word)
|
||||||
: !KEYWORDS(word) ? token("name", word)
|
: !KEYWORDS(word) ? token("name", word)
|
||||||
: OPERATORS(word) ? token("operator", word)
|
: OPERATORS(word) ? token("operator", word)
|
||||||
@@ -513,11 +550,21 @@ function tokenizer($TEXT, filename) {
|
|||||||
return read_regexp(force_regexp);
|
return read_regexp(force_regexp);
|
||||||
skip_whitespace();
|
skip_whitespace();
|
||||||
start_token();
|
start_token();
|
||||||
|
if (html5_comments) {
|
||||||
|
if (looking_at("<!--")) {
|
||||||
|
forward(4);
|
||||||
|
return skip_line_comment("comment3");
|
||||||
|
}
|
||||||
|
if (looking_at("-->") && S.newline_before) {
|
||||||
|
forward(3);
|
||||||
|
return skip_line_comment("comment4");
|
||||||
|
}
|
||||||
|
}
|
||||||
var ch = peek();
|
var ch = peek();
|
||||||
if (!ch) return token("eof");
|
if (!ch) return token("eof");
|
||||||
var code = ch.charCodeAt(0);
|
var code = ch.charCodeAt(0);
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case 34: case 39: return read_string();
|
case 34: case 39: return read_string(ch);
|
||||||
case 46: return handle_dot();
|
case 46: return handle_dot();
|
||||||
case 47: return handle_slash();
|
case 47: return handle_slash();
|
||||||
}
|
}
|
||||||
@@ -525,6 +572,13 @@ function tokenizer($TEXT, filename) {
|
|||||||
if (PUNC_CHARS(ch)) return token("punc", next());
|
if (PUNC_CHARS(ch)) return token("punc", next());
|
||||||
if (OPERATOR_CHARS(ch)) return read_operator();
|
if (OPERATOR_CHARS(ch)) return read_operator();
|
||||||
if (code == 92 || is_identifier_start(code)) return read_word();
|
if (code == 92 || is_identifier_start(code)) return read_word();
|
||||||
|
|
||||||
|
if (shebang) {
|
||||||
|
if (S.pos == 0 && looking_at("#!")) {
|
||||||
|
forward(2);
|
||||||
|
return skip_line_comment("comment5");
|
||||||
|
}
|
||||||
|
}
|
||||||
parse_error("Unexpected character '" + ch + "'");
|
parse_error("Unexpected character '" + ch + "'");
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -556,10 +610,10 @@ var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
|
|||||||
var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
|
var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
|
||||||
|
|
||||||
var PRECEDENCE = (function(a, ret){
|
var PRECEDENCE = (function(a, ret){
|
||||||
for (var i = 0, n = 1; i < a.length; ++i, ++n) {
|
for (var i = 0; i < a.length; ++i) {
|
||||||
var b = a[i];
|
var b = a[i];
|
||||||
for (var j = 0; j < b.length; ++j) {
|
for (var j = 0; j < b.length; ++j) {
|
||||||
ret[b[j]] = n;
|
ret[b[j]] = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -588,14 +642,20 @@ var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "nam
|
|||||||
function parse($TEXT, options) {
|
function parse($TEXT, options) {
|
||||||
|
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
strict : false,
|
strict : false,
|
||||||
filename : null,
|
filename : null,
|
||||||
toplevel : null,
|
toplevel : null,
|
||||||
expression : false
|
expression : false,
|
||||||
|
html5_comments : true,
|
||||||
|
bare_returns : false,
|
||||||
|
shebang : true,
|
||||||
});
|
});
|
||||||
|
|
||||||
var S = {
|
var S = {
|
||||||
input : typeof $TEXT == "string" ? tokenizer($TEXT, options.filename) : $TEXT,
|
input : (typeof $TEXT == "string"
|
||||||
|
? tokenizer($TEXT, options.filename,
|
||||||
|
options.html5_comments, options.shebang)
|
||||||
|
: $TEXT),
|
||||||
token : null,
|
token : null,
|
||||||
prev : null,
|
prev : null,
|
||||||
peeked : null,
|
peeked : null,
|
||||||
@@ -688,18 +748,28 @@ function parse($TEXT, options) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var statement = embed_tokens(function() {
|
function handle_regexp() {
|
||||||
var tmp;
|
|
||||||
if (is("operator", "/") || is("operator", "/=")) {
|
if (is("operator", "/") || is("operator", "/=")) {
|
||||||
S.peeked = null;
|
S.peeked = null;
|
||||||
S.token = S.input(S.token.value.substr(1)); // force regexp
|
S.token = S.input(S.token.value.substr(1)); // force regexp
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var statement = embed_tokens(function() {
|
||||||
|
var tmp;
|
||||||
|
handle_regexp();
|
||||||
switch (S.token.type) {
|
switch (S.token.type) {
|
||||||
case "string":
|
case "string":
|
||||||
var dir = S.in_directives, stat = simple_statement();
|
var dir = S.in_directives, stat = simple_statement();
|
||||||
// XXXv2: decide how to fix directives
|
// XXXv2: decide how to fix directives
|
||||||
if (dir && stat.body instanceof AST_String && !is("punc", ","))
|
if (dir && stat.body instanceof AST_String && !is("punc", ",")) {
|
||||||
return new AST_Directive({ value: stat.body.value });
|
return new AST_Directive({
|
||||||
|
start : stat.body.start,
|
||||||
|
end : stat.body.end,
|
||||||
|
quote : stat.body.quote,
|
||||||
|
value : stat.body.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
return stat;
|
return stat;
|
||||||
case "num":
|
case "num":
|
||||||
case "regexp":
|
case "regexp":
|
||||||
@@ -758,13 +828,13 @@ function parse($TEXT, options) {
|
|||||||
return for_();
|
return for_();
|
||||||
|
|
||||||
case "function":
|
case "function":
|
||||||
return function_(true);
|
return function_(AST_Defun);
|
||||||
|
|
||||||
case "if":
|
case "if":
|
||||||
return if_();
|
return if_();
|
||||||
|
|
||||||
case "return":
|
case "return":
|
||||||
if (S.in_function == 0)
|
if (S.in_function == 0 && !options.bare_returns)
|
||||||
croak("'return' outside of function");
|
croak("'return' outside of function");
|
||||||
return new AST_Return({
|
return new AST_Return({
|
||||||
value: ( is("punc", ";")
|
value: ( is("punc", ";")
|
||||||
@@ -821,6 +891,18 @@ function parse($TEXT, options) {
|
|||||||
S.labels.push(label);
|
S.labels.push(label);
|
||||||
var stat = statement();
|
var stat = statement();
|
||||||
S.labels.pop();
|
S.labels.pop();
|
||||||
|
if (!(stat instanceof AST_IterationStatement)) {
|
||||||
|
// check for `continue` that refers to this label.
|
||||||
|
// those should be reported as syntax errors.
|
||||||
|
// https://github.com/mishoo/UglifyJS2/issues/287
|
||||||
|
label.references.forEach(function(ref){
|
||||||
|
if (ref instanceof AST_Continue) {
|
||||||
|
ref = ref.label.start;
|
||||||
|
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
|
||||||
|
ref.line, ref.col, ref.pos);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
return new AST_LabeledStatement({ body: stat, label: label });
|
return new AST_LabeledStatement({ body: stat, label: label });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -829,18 +911,22 @@ function parse($TEXT, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function break_cont(type) {
|
function break_cont(type) {
|
||||||
var label = null;
|
var label = null, ldef;
|
||||||
if (!can_insert_semicolon()) {
|
if (!can_insert_semicolon()) {
|
||||||
label = as_symbol(AST_LabelRef, true);
|
label = as_symbol(AST_LabelRef, true);
|
||||||
}
|
}
|
||||||
if (label != null) {
|
if (label != null) {
|
||||||
if (!find_if(function(l){ return l.name == label.name }, S.labels))
|
ldef = find_if(function(l){ return l.name == label.name }, S.labels);
|
||||||
|
if (!ldef)
|
||||||
croak("Undefined label " + label.name);
|
croak("Undefined label " + label.name);
|
||||||
|
label.thedef = ldef;
|
||||||
}
|
}
|
||||||
else if (S.in_loop == 0)
|
else if (S.in_loop == 0)
|
||||||
croak(type.TYPE + " not inside a loop or switch");
|
croak(type.TYPE + " not inside a loop or switch");
|
||||||
semicolon();
|
semicolon();
|
||||||
return new type({ label: label });
|
var stat = new type({ label: label });
|
||||||
|
if (ldef) ldef.references.push(stat);
|
||||||
|
return stat;
|
||||||
};
|
};
|
||||||
|
|
||||||
function for_() {
|
function for_() {
|
||||||
@@ -886,19 +972,12 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var function_ = function(in_statement, ctor) {
|
var function_ = function(ctor) {
|
||||||
var is_accessor = ctor === AST_Accessor;
|
var in_statement = ctor === AST_Defun;
|
||||||
var name = (is("name") ? as_symbol(in_statement
|
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
|
||||||
? AST_SymbolDefun
|
|
||||||
: is_accessor
|
|
||||||
? AST_SymbolAccessor
|
|
||||||
: AST_SymbolLambda)
|
|
||||||
: is_accessor && (is("string") || is("num")) ? as_atom_node()
|
|
||||||
: null);
|
|
||||||
if (in_statement && !name)
|
if (in_statement && !name)
|
||||||
unexpected();
|
unexpected();
|
||||||
expect("(");
|
expect("(");
|
||||||
if (!ctor) ctor = in_statement ? AST_Defun : AST_Function;
|
|
||||||
return new ctor({
|
return new ctor({
|
||||||
name: name,
|
name: name,
|
||||||
argnames: (function(first, a){
|
argnames: (function(first, a){
|
||||||
@@ -1047,7 +1126,7 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var new_ = function() {
|
var new_ = function(allow_calls) {
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
expect_token("operator", "new");
|
expect_token("operator", "new");
|
||||||
var newexp = expr_atom(false), args;
|
var newexp = expr_atom(false), args;
|
||||||
@@ -1062,19 +1141,26 @@ function parse($TEXT, options) {
|
|||||||
expression : newexp,
|
expression : newexp,
|
||||||
args : args,
|
args : args,
|
||||||
end : prev()
|
end : prev()
|
||||||
}), true);
|
}), allow_calls);
|
||||||
};
|
};
|
||||||
|
|
||||||
function as_atom_node() {
|
function as_atom_node() {
|
||||||
var tok = S.token, ret;
|
var tok = S.token, ret;
|
||||||
switch (tok.type) {
|
switch (tok.type) {
|
||||||
case "name":
|
case "name":
|
||||||
return as_symbol(AST_SymbolRef);
|
case "keyword":
|
||||||
|
ret = _make_symbol(AST_SymbolRef);
|
||||||
|
break;
|
||||||
case "num":
|
case "num":
|
||||||
ret = new AST_Number({ start: tok, end: tok, value: tok.value });
|
ret = new AST_Number({ start: tok, end: tok, value: tok.value, literal: tok.literal });
|
||||||
break;
|
break;
|
||||||
case "string":
|
case "string":
|
||||||
ret = new AST_String({ start: tok, end: tok, value: tok.value });
|
ret = new AST_String({
|
||||||
|
start : tok,
|
||||||
|
end : tok,
|
||||||
|
value : tok.value,
|
||||||
|
quote : tok.quote
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
case "regexp":
|
case "regexp":
|
||||||
ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
|
ret = new AST_RegExp({ start: tok, end: tok, value: tok.value });
|
||||||
@@ -1099,7 +1185,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
var expr_atom = function(allow_calls) {
|
var expr_atom = function(allow_calls) {
|
||||||
if (is("operator", "new")) {
|
if (is("operator", "new")) {
|
||||||
return new_();
|
return new_(allow_calls);
|
||||||
}
|
}
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
if (is("punc")) {
|
if (is("punc")) {
|
||||||
@@ -1120,7 +1206,7 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
if (is("keyword", "function")) {
|
if (is("keyword", "function")) {
|
||||||
next();
|
next();
|
||||||
var func = function_(false);
|
var func = function_(AST_Function);
|
||||||
func.start = start;
|
func.start = start;
|
||||||
func.end = prev();
|
func.end = prev();
|
||||||
return subscripts(func, allow_calls);
|
return subscripts(func, allow_calls);
|
||||||
@@ -1168,8 +1254,8 @@ function parse($TEXT, options) {
|
|||||||
if (name == "get") {
|
if (name == "get") {
|
||||||
a.push(new AST_ObjectGetter({
|
a.push(new AST_ObjectGetter({
|
||||||
start : start,
|
start : start,
|
||||||
key : name,
|
key : as_atom_node(),
|
||||||
value : function_(false, AST_Accessor),
|
value : function_(AST_Accessor),
|
||||||
end : prev()
|
end : prev()
|
||||||
}));
|
}));
|
||||||
continue;
|
continue;
|
||||||
@@ -1177,8 +1263,8 @@ function parse($TEXT, options) {
|
|||||||
if (name == "set") {
|
if (name == "set") {
|
||||||
a.push(new AST_ObjectSetter({
|
a.push(new AST_ObjectSetter({
|
||||||
start : start,
|
start : start,
|
||||||
key : name,
|
key : as_atom_node(),
|
||||||
value : function_(false, AST_Accessor),
|
value : function_(AST_Accessor),
|
||||||
end : prev()
|
end : prev()
|
||||||
}));
|
}));
|
||||||
continue;
|
continue;
|
||||||
@@ -1187,6 +1273,7 @@ function parse($TEXT, options) {
|
|||||||
expect(":");
|
expect(":");
|
||||||
a.push(new AST_ObjectKeyVal({
|
a.push(new AST_ObjectKeyVal({
|
||||||
start : start,
|
start : start,
|
||||||
|
quote : start.quote,
|
||||||
key : name,
|
key : name,
|
||||||
value : expression(false),
|
value : expression(false),
|
||||||
end : prev()
|
end : prev()
|
||||||
@@ -1226,17 +1313,21 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function _make_symbol(type) {
|
||||||
|
var name = S.token.value;
|
||||||
|
return new (name == "this" ? AST_This : type)({
|
||||||
|
name : String(name),
|
||||||
|
start : S.token,
|
||||||
|
end : S.token
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
function as_symbol(type, noerror) {
|
function as_symbol(type, noerror) {
|
||||||
if (!is("name")) {
|
if (!is("name")) {
|
||||||
if (!noerror) croak("Name expected");
|
if (!noerror) croak("Name expected");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var name = S.token.value;
|
var sym = _make_symbol(type);
|
||||||
var sym = new (name == "this" ? AST_This : type)({
|
|
||||||
name : String(S.token.value),
|
|
||||||
start : S.token,
|
|
||||||
end : S.token
|
|
||||||
});
|
|
||||||
next();
|
next();
|
||||||
return sym;
|
return sym;
|
||||||
};
|
};
|
||||||
@@ -1279,6 +1370,7 @@ function parse($TEXT, options) {
|
|||||||
var start = S.token;
|
var start = S.token;
|
||||||
if (is("operator") && UNARY_PREFIX(start.value)) {
|
if (is("operator") && UNARY_PREFIX(start.value)) {
|
||||||
next();
|
next();
|
||||||
|
handle_regexp();
|
||||||
var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
|
var ex = make_unary(AST_UnaryPrefix, start.value, maybe_unary(allow_calls));
|
||||||
ex.start = start;
|
ex.start = start;
|
||||||
ex.end = prev();
|
ex.end = prev();
|
||||||
@@ -1334,7 +1426,7 @@ function parse($TEXT, options) {
|
|||||||
condition : expr,
|
condition : expr,
|
||||||
consequent : yes,
|
consequent : yes,
|
||||||
alternative : expression(false, no_in),
|
alternative : expression(false, no_in),
|
||||||
end : peek()
|
end : prev()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
|
|||||||
223
lib/propmangle.js
Normal file
223
lib/propmangle.js
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
/***********************************************************************
|
||||||
|
|
||||||
|
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||||
|
https://github.com/mishoo/UglifyJS2
|
||||||
|
|
||||||
|
-------------------------------- (C) ---------------------------------
|
||||||
|
|
||||||
|
Author: Mihai Bazon
|
||||||
|
<mihai.bazon@gmail.com>
|
||||||
|
http://mihai.bazon.net/blog
|
||||||
|
|
||||||
|
Distributed under the BSD license:
|
||||||
|
|
||||||
|
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above
|
||||||
|
copyright notice, this list of conditions and the following
|
||||||
|
disclaimer in the documentation and/or other materials
|
||||||
|
provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||||
|
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||||
|
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||||
|
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function find_builtins() {
|
||||||
|
var a = [];
|
||||||
|
[ Object, Array, Function, Number,
|
||||||
|
String, Boolean, Error, Math,
|
||||||
|
Date, RegExp
|
||||||
|
].forEach(function(ctor){
|
||||||
|
Object.getOwnPropertyNames(ctor).map(add);
|
||||||
|
if (ctor.prototype) {
|
||||||
|
Object.getOwnPropertyNames(ctor.prototype).map(add);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
function add(name) {
|
||||||
|
push_uniq(a, name);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mangle_properties(ast, options) {
|
||||||
|
options = defaults(options, {
|
||||||
|
reserved : null,
|
||||||
|
cache : null,
|
||||||
|
only_cache : false,
|
||||||
|
regex : null
|
||||||
|
});
|
||||||
|
|
||||||
|
var reserved = options.reserved;
|
||||||
|
if (reserved == null)
|
||||||
|
reserved = find_builtins();
|
||||||
|
|
||||||
|
var cache = options.cache;
|
||||||
|
if (cache == null) {
|
||||||
|
cache = {
|
||||||
|
cname: -1,
|
||||||
|
props: new Dictionary()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var regex = options.regex;
|
||||||
|
|
||||||
|
var names_to_mangle = [];
|
||||||
|
var unmangleable = [];
|
||||||
|
|
||||||
|
// step 1: find candidates to mangle
|
||||||
|
ast.walk(new TreeWalker(function(node){
|
||||||
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
|
add(node.key);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
|
// setter or getter, since KeyVal is handled above
|
||||||
|
add(node.key.name);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Dot) {
|
||||||
|
if (this.parent() instanceof AST_Assign) {
|
||||||
|
add(node.property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Sub) {
|
||||||
|
if (this.parent() instanceof AST_Assign) {
|
||||||
|
addStrings(node.property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// step 2: transform the tree, renaming properties
|
||||||
|
return ast.transform(new TreeTransformer(function(node){
|
||||||
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
|
node.key = mangle(node.key);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
|
// setter or getter
|
||||||
|
node.key.name = mangle(node.key.name);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Dot) {
|
||||||
|
node.property = mangle(node.property);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Sub) {
|
||||||
|
node.property = mangleStrings(node.property);
|
||||||
|
}
|
||||||
|
// else if (node instanceof AST_String) {
|
||||||
|
// if (should_mangle(node.value)) {
|
||||||
|
// AST_Node.warn(
|
||||||
|
// "Found \"{prop}\" property candidate for mangling in an arbitrary string [{file}:{line},{col}]", {
|
||||||
|
// file : node.start.file,
|
||||||
|
// line : node.start.line,
|
||||||
|
// col : node.start.col,
|
||||||
|
// prop : node.value
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}));
|
||||||
|
|
||||||
|
// only function declarations after this line
|
||||||
|
|
||||||
|
function can_mangle(name) {
|
||||||
|
if (unmangleable.indexOf(name) >= 0) return false;
|
||||||
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
|
if (options.only_cache) {
|
||||||
|
return cache.props.has(name);
|
||||||
|
}
|
||||||
|
if (/^[0-9.]+$/.test(name)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function should_mangle(name) {
|
||||||
|
if (regex && !regex.test(name)) return false;
|
||||||
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
|
return cache.props.has(name)
|
||||||
|
|| names_to_mangle.indexOf(name) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(name) {
|
||||||
|
if (can_mangle(name))
|
||||||
|
push_uniq(names_to_mangle, name);
|
||||||
|
|
||||||
|
if (!should_mangle(name)) {
|
||||||
|
push_uniq(unmangleable, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mangle(name) {
|
||||||
|
if (!should_mangle(name)) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mangled = cache.props.get(name);
|
||||||
|
if (!mangled) {
|
||||||
|
do {
|
||||||
|
mangled = base54(++cache.cname);
|
||||||
|
} while (!can_mangle(mangled));
|
||||||
|
cache.props.set(name, mangled);
|
||||||
|
}
|
||||||
|
return mangled;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addStrings(node) {
|
||||||
|
var out = {};
|
||||||
|
try {
|
||||||
|
(function walk(node){
|
||||||
|
node.walk(new TreeWalker(function(node){
|
||||||
|
if (node instanceof AST_Seq) {
|
||||||
|
walk(node.cdr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_String) {
|
||||||
|
add(node.value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (node instanceof AST_Conditional) {
|
||||||
|
walk(node.consequent);
|
||||||
|
walk(node.alternative);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw out;
|
||||||
|
}));
|
||||||
|
})(node);
|
||||||
|
} catch(ex) {
|
||||||
|
if (ex !== out) throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mangleStrings(node) {
|
||||||
|
return node.transform(new TreeTransformer(function(node){
|
||||||
|
if (node instanceof AST_Seq) {
|
||||||
|
node.cdr = mangleStrings(node.cdr);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_String) {
|
||||||
|
node.value = mangle(node.value);
|
||||||
|
}
|
||||||
|
else if (node instanceof AST_Conditional) {
|
||||||
|
node.consequent = mangleStrings(node.consequent);
|
||||||
|
node.alternative = mangleStrings(node.alternative);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
164
lib/scope.js
164
lib/scope.js
@@ -57,45 +57,61 @@ function SymbolDef(scope, index, orig) {
|
|||||||
|
|
||||||
SymbolDef.prototype = {
|
SymbolDef.prototype = {
|
||||||
unmangleable: function(options) {
|
unmangleable: function(options) {
|
||||||
return (this.global && !(options && options.toplevel))
|
if (!options) options = {};
|
||||||
|
|
||||||
|
return (this.global && !options.toplevel)
|
||||||
|| this.undeclared
|
|| this.undeclared
|
||||||
|| (!(options && options.eval) && (this.scope.uses_eval || this.scope.uses_with));
|
|| (!options.eval && (this.scope.uses_eval || this.scope.uses_with))
|
||||||
|
|| (options.keep_fnames
|
||||||
|
&& (this.orig[0] instanceof AST_SymbolLambda
|
||||||
|
|| this.orig[0] instanceof AST_SymbolDefun));
|
||||||
},
|
},
|
||||||
mangle: function(options) {
|
mangle: function(options) {
|
||||||
if (!this.mangled_name && !this.unmangleable(options)) {
|
var cache = options.cache && options.cache.props;
|
||||||
|
if (this.global && cache && cache.has(this.name)) {
|
||||||
|
this.mangled_name = cache.get(this.name);
|
||||||
|
}
|
||||||
|
else if (!this.mangled_name && !this.unmangleable(options)) {
|
||||||
var s = this.scope;
|
var s = this.scope;
|
||||||
if (this.orig[0] instanceof AST_SymbolLambda && !options.screw_ie8)
|
if (!options.screw_ie8 && this.orig[0] instanceof AST_SymbolLambda)
|
||||||
s = s.parent_scope;
|
s = s.parent_scope;
|
||||||
this.mangled_name = s.next_mangled(options);
|
this.mangled_name = s.next_mangled(options, this);
|
||||||
|
if (this.global && cache) {
|
||||||
|
cache.set(this.name, this.mangled_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||||
// This does what ast_add_scope did in UglifyJS v1.
|
options = defaults(options, {
|
||||||
//
|
screw_ie8: false,
|
||||||
// Part of it could be done at parse time, but it would complicate
|
cache: null
|
||||||
// the parser (and it's already kinda complex). It's also worth
|
});
|
||||||
// having it separated because we might need to call it multiple
|
|
||||||
// times on the same tree.
|
|
||||||
|
|
||||||
// pass 1: setup scope chaining and handle definitions
|
// pass 1: setup scope chaining and handle definitions
|
||||||
var self = this;
|
var self = this;
|
||||||
var scope = self.parent_scope = null;
|
var scope = self.parent_scope = null;
|
||||||
var labels = new Dictionary();
|
var defun = null;
|
||||||
var nesting = 0;
|
var nesting = 0;
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
|
if (options.screw_ie8 && node instanceof AST_Catch) {
|
||||||
|
var save_scope = scope;
|
||||||
|
scope = new AST_Scope(node);
|
||||||
|
scope.init_scope_vars(nesting);
|
||||||
|
scope.parent_scope = save_scope;
|
||||||
|
descend();
|
||||||
|
scope = save_scope;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
node.init_scope_vars(nesting);
|
node.init_scope_vars(nesting);
|
||||||
var save_scope = node.parent_scope = scope;
|
var save_scope = node.parent_scope = scope;
|
||||||
var save_labels = labels;
|
var save_defun = defun;
|
||||||
++nesting;
|
defun = scope = node;
|
||||||
scope = node;
|
++nesting; descend(); --nesting;
|
||||||
labels = new Dictionary();
|
|
||||||
descend();
|
|
||||||
labels = save_labels;
|
|
||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
--nesting;
|
defun = save_defun;
|
||||||
return true; // don't descend again in TreeWalker
|
return true; // don't descend again in TreeWalker
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Directive) {
|
if (node instanceof AST_Directive) {
|
||||||
@@ -103,29 +119,20 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
push_uniq(scope.directives, node.value);
|
push_uniq(scope.directives, node.value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_Number) {
|
||||||
|
node.scope = scope;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_With) {
|
if (node instanceof AST_With) {
|
||||||
for (var s = scope; s; s = s.parent_scope)
|
for (var s = scope; s; s = s.parent_scope)
|
||||||
s.uses_with = true;
|
s.uses_with = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LabeledStatement) {
|
|
||||||
var l = node.label;
|
|
||||||
if (labels.has(l.name))
|
|
||||||
throw new Error(string_template("Label {name} defined twice", l));
|
|
||||||
labels.set(l.name, l);
|
|
||||||
descend();
|
|
||||||
labels.del(l.name);
|
|
||||||
return true; // no descend again
|
|
||||||
}
|
|
||||||
if (node instanceof AST_Symbol) {
|
if (node instanceof AST_Symbol) {
|
||||||
node.scope = scope;
|
node.scope = scope;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Label) {
|
|
||||||
node.thedef = node;
|
|
||||||
node.init_scope_vars();
|
|
||||||
}
|
|
||||||
if (node instanceof AST_SymbolLambda) {
|
if (node instanceof AST_SymbolLambda) {
|
||||||
scope.def_function(node);
|
defun.def_function(node);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolDefun) {
|
else if (node instanceof AST_SymbolDefun) {
|
||||||
// Careful here, the scope where this should be defined is
|
// Careful here, the scope where this should be defined is
|
||||||
@@ -133,31 +140,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
// scope when we encounter the AST_Defun node (which is
|
// scope when we encounter the AST_Defun node (which is
|
||||||
// instanceof AST_Scope) but we get to the symbol a bit
|
// instanceof AST_Scope) but we get to the symbol a bit
|
||||||
// later.
|
// later.
|
||||||
(node.scope = scope.parent_scope).def_function(node);
|
(node.scope = defun.parent_scope).def_function(node);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolVar
|
else if (node instanceof AST_SymbolVar
|
||||||
|| node instanceof AST_SymbolConst) {
|
|| node instanceof AST_SymbolConst) {
|
||||||
var def = scope.def_variable(node);
|
var def = defun.def_variable(node);
|
||||||
def.constant = node instanceof AST_SymbolConst;
|
def.constant = node instanceof AST_SymbolConst;
|
||||||
def.init = tw.parent().value;
|
def.init = tw.parent().value;
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolCatch) {
|
else if (node instanceof AST_SymbolCatch) {
|
||||||
// XXX: this is wrong according to ECMA-262 (12.4). the
|
(options.screw_ie8 ? scope : defun)
|
||||||
// `catch` argument name should be visible only inside the
|
.def_variable(node);
|
||||||
// catch block. For a quick fix AST_Catch should inherit
|
|
||||||
// from AST_Scope. Keeping it this way because of IE,
|
|
||||||
// which doesn't obey the standard. (it introduces the
|
|
||||||
// identifier in the enclosing scope)
|
|
||||||
scope.def_variable(node);
|
|
||||||
}
|
|
||||||
if (node instanceof AST_LabelRef) {
|
|
||||||
var sym = labels.get(node.name);
|
|
||||||
if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", {
|
|
||||||
name: node.name,
|
|
||||||
line: node.start.line,
|
|
||||||
col: node.start.col
|
|
||||||
}));
|
|
||||||
node.thedef = sym;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
@@ -173,10 +166,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
func = prev_func;
|
func = prev_func;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LabelRef) {
|
|
||||||
node.reference();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var name = node.name;
|
var name = node.name;
|
||||||
var sym = node.scope.find_variable(name);
|
var sym = node.scope.find_variable(name);
|
||||||
@@ -195,7 +184,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope)
|
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope)
|
||||||
s.uses_eval = true;
|
s.uses_eval = true;
|
||||||
}
|
}
|
||||||
if (name == "arguments") {
|
if (func && name == "arguments") {
|
||||||
func.uses_arguments = true;
|
func.uses_arguments = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -206,6 +195,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.walk(tw);
|
self.walk(tw);
|
||||||
|
|
||||||
|
if (options.cache) {
|
||||||
|
this.cname = options.cache.cname;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
||||||
@@ -241,14 +234,6 @@ AST_SymbolRef.DEFMETHOD("reference", function() {
|
|||||||
this.frame = this.scope.nesting - def.scope.nesting;
|
this.frame = this.scope.nesting - def.scope.nesting;
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Label.DEFMETHOD("init_scope_vars", function(){
|
|
||||||
this.references = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_LabelRef.DEFMETHOD("reference", function(){
|
|
||||||
this.thedef.references.push(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("find_variable", function(name){
|
AST_Scope.DEFMETHOD("find_variable", function(name){
|
||||||
if (name instanceof AST_Symbol) name = name.name;
|
if (name instanceof AST_Symbol) name = name.name;
|
||||||
return this.variables.get(name)
|
return this.variables.get(name)
|
||||||
@@ -282,6 +267,11 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
|
|||||||
out: while (true) {
|
out: while (true) {
|
||||||
var m = base54(++this.cname);
|
var m = base54(++this.cname);
|
||||||
if (!is_identifier(m)) continue; // skip over "do"
|
if (!is_identifier(m)) continue; // skip over "do"
|
||||||
|
|
||||||
|
// https://github.com/mishoo/UglifyJS2/issues/242 -- do not
|
||||||
|
// shadow a name excepted from mangling.
|
||||||
|
if (options.except.indexOf(m) >= 0) continue;
|
||||||
|
|
||||||
// we must ensure that the mangled name does not shadow a name
|
// we must ensure that the mangled name does not shadow a name
|
||||||
// from some parent scope that is referenced in this or in
|
// from some parent scope that is referenced in this or in
|
||||||
// inner scopes.
|
// inner scopes.
|
||||||
@@ -294,6 +284,19 @@ AST_Scope.DEFMETHOD("next_mangled", function(options){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
||||||
|
// #179, #326
|
||||||
|
// in Safari strict mode, something like (function x(x){...}) is a syntax error;
|
||||||
|
// a function expression's argument cannot shadow the function expression's name
|
||||||
|
|
||||||
|
var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition();
|
||||||
|
while (true) {
|
||||||
|
var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
|
||||||
|
if (!(tricky_def && tricky_def.mangled_name == name))
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("references", function(sym){
|
AST_Scope.DEFMETHOD("references", function(sym){
|
||||||
if (sym instanceof AST_Symbol) sym = sym.definition();
|
if (sym instanceof AST_Symbol) sym = sym.definition();
|
||||||
return this.enclosed.indexOf(sym) < 0 ? null : sym;
|
return this.enclosed.indexOf(sym) < 0 ? null : sym;
|
||||||
@@ -340,11 +343,12 @@ AST_Symbol.DEFMETHOD("global", function(){
|
|||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
|
AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options){
|
||||||
return defaults(options, {
|
return defaults(options, {
|
||||||
except : [],
|
except : [],
|
||||||
eval : false,
|
eval : false,
|
||||||
sort : false,
|
sort : false,
|
||||||
toplevel : false,
|
toplevel : false,
|
||||||
screw_ie8 : false
|
screw_ie8 : false,
|
||||||
|
keep_fnames : false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -356,6 +360,15 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
// the AST_SymbolDeclaration that it points to).
|
// the AST_SymbolDeclaration that it points to).
|
||||||
var lname = -1;
|
var lname = -1;
|
||||||
var to_mangle = [];
|
var to_mangle = [];
|
||||||
|
|
||||||
|
if (options.cache) {
|
||||||
|
this.globals.each(function(symbol){
|
||||||
|
if (options.except.indexOf(symbol.name) < 0) {
|
||||||
|
to_mangle.push(symbol);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var tw = new TreeWalker(function(node, descend){
|
var tw = new TreeWalker(function(node, descend){
|
||||||
if (node instanceof AST_LabeledStatement) {
|
if (node instanceof AST_LabeledStatement) {
|
||||||
// lname is incremented when we get to the AST_Label
|
// lname is incremented when we get to the AST_Label
|
||||||
@@ -383,9 +396,17 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
node.mangled_name = name;
|
node.mangled_name = name;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (options.screw_ie8 && node instanceof AST_SymbolCatch) {
|
||||||
|
to_mangle.push(node.definition());
|
||||||
|
return;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
this.walk(tw);
|
this.walk(tw);
|
||||||
to_mangle.forEach(function(def){ def.mangle(options) });
|
to_mangle.forEach(function(def){ def.mangle(options) });
|
||||||
|
|
||||||
|
if (options.cache) {
|
||||||
|
options.cache.cname = this.cname;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options){
|
||||||
@@ -485,7 +506,9 @@ var base54 = (function() {
|
|||||||
base54.freq = function(){ return frequency };
|
base54.freq = function(){ return frequency };
|
||||||
function base54(num) {
|
function base54(num) {
|
||||||
var ret = "", base = 54;
|
var ret = "", base = 54;
|
||||||
|
num++;
|
||||||
do {
|
do {
|
||||||
|
num--;
|
||||||
ret += String.fromCharCode(chars[num % base]);
|
ret += String.fromCharCode(chars[num % base]);
|
||||||
num = Math.floor(num / base);
|
num = Math.floor(num / base);
|
||||||
base = 64;
|
base = 64;
|
||||||
@@ -546,6 +569,7 @@ AST_Toplevel.DEFMETHOD("scope_warnings", function(options){
|
|||||||
}
|
}
|
||||||
if (options.unreferenced
|
if (options.unreferenced
|
||||||
&& (node instanceof AST_SymbolDeclaration || node instanceof AST_Label)
|
&& (node instanceof AST_SymbolDeclaration || node instanceof AST_Label)
|
||||||
|
&& !(node instanceof AST_SymbolCatch)
|
||||||
&& node.unreferenced()) {
|
&& node.unreferenced()) {
|
||||||
AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
|
AST_Node.warn("{type} {name} is declared but not referenced [{file}:{line},{col}]", {
|
||||||
type: node instanceof AST_Label ? "Label" : "Symbol",
|
type: node instanceof AST_Label ? "Label" : "Symbol",
|
||||||
|
|||||||
@@ -49,33 +49,44 @@ function SourceMap(options) {
|
|||||||
file : null,
|
file : null,
|
||||||
root : null,
|
root : null,
|
||||||
orig : null,
|
orig : null,
|
||||||
});
|
|
||||||
var generator = new MOZ_SourceMap.SourceMapGenerator({
|
orig_line_diff : 0,
|
||||||
file : options.file,
|
dest_line_diff : 0,
|
||||||
sourceRoot : options.root
|
|
||||||
});
|
});
|
||||||
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
|
var orig_map = options.orig && new MOZ_SourceMap.SourceMapConsumer(options.orig);
|
||||||
|
var generator;
|
||||||
|
if (orig_map) {
|
||||||
|
generator = MOZ_SourceMap.SourceMapGenerator.fromSourceMap(orig_map);
|
||||||
|
} else {
|
||||||
|
generator = new MOZ_SourceMap.SourceMapGenerator({
|
||||||
|
file : options.file,
|
||||||
|
sourceRoot : options.root
|
||||||
|
});
|
||||||
|
}
|
||||||
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
|
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
|
||||||
if (orig_map) {
|
if (orig_map) {
|
||||||
var info = orig_map.originalPositionFor({
|
var info = orig_map.originalPositionFor({
|
||||||
line: orig_line,
|
line: orig_line,
|
||||||
column: orig_col
|
column: orig_col
|
||||||
});
|
});
|
||||||
|
if (info.source === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
source = info.source;
|
source = info.source;
|
||||||
orig_line = info.line;
|
orig_line = info.line;
|
||||||
orig_col = info.column;
|
orig_col = info.column;
|
||||||
name = info.name;
|
name = info.name || name;
|
||||||
}
|
}
|
||||||
generator.addMapping({
|
generator.addMapping({
|
||||||
generated : { line: gen_line, column: gen_col },
|
generated : { line: gen_line + options.dest_line_diff, column: gen_col },
|
||||||
original : { line: orig_line, column: orig_col },
|
original : { line: orig_line + options.orig_line_diff, column: orig_col },
|
||||||
source : source,
|
source : source,
|
||||||
name : name
|
name : name
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
return {
|
return {
|
||||||
add : add,
|
add : add,
|
||||||
get : function() { return generator },
|
get : function() { return generator },
|
||||||
toString : function() { return generator.toString() }
|
toString : function() { return JSON.stringify(generator.toJSON()); }
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
21
lib/utils.js
21
lib/utils.js
@@ -82,16 +82,23 @@ function repeat_string(str, i) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function DefaultsError(msg, defs) {
|
function DefaultsError(msg, defs) {
|
||||||
|
Error.call(this, msg);
|
||||||
this.msg = msg;
|
this.msg = msg;
|
||||||
this.defs = defs;
|
this.defs = defs;
|
||||||
};
|
};
|
||||||
|
DefaultsError.prototype = Object.create(Error.prototype);
|
||||||
|
DefaultsError.prototype.constructor = DefaultsError;
|
||||||
|
|
||||||
|
DefaultsError.croak = function(msg, defs) {
|
||||||
|
throw new DefaultsError(msg, defs);
|
||||||
|
};
|
||||||
|
|
||||||
function defaults(args, defs, croak) {
|
function defaults(args, defs, croak) {
|
||||||
if (args === true)
|
if (args === true)
|
||||||
args = {};
|
args = {};
|
||||||
var ret = args || {};
|
var ret = args || {};
|
||||||
if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i))
|
if (croak) for (var i in ret) if (ret.hasOwnProperty(i) && !defs.hasOwnProperty(i))
|
||||||
throw new DefaultsError("`" + i + "` is not a supported option", defs);
|
DefaultsError.croak("`" + i + "` is not a supported option", defs);
|
||||||
for (var i in defs) if (defs.hasOwnProperty(i)) {
|
for (var i in defs) if (defs.hasOwnProperty(i)) {
|
||||||
ret[i] = (args && args.hasOwnProperty(i)) ? args[i] : defs[i];
|
ret[i] = (args && args.hasOwnProperty(i)) ? args[i] : defs[i];
|
||||||
}
|
}
|
||||||
@@ -99,10 +106,12 @@ function defaults(args, defs, croak) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function merge(obj, ext) {
|
function merge(obj, ext) {
|
||||||
|
var count = 0;
|
||||||
for (var i in ext) if (ext.hasOwnProperty(i)) {
|
for (var i in ext) if (ext.hasOwnProperty(i)) {
|
||||||
obj[i] = ext[i];
|
obj[i] = ext[i];
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
return obj;
|
return count;
|
||||||
};
|
};
|
||||||
|
|
||||||
function noop() {};
|
function noop() {};
|
||||||
@@ -291,5 +300,11 @@ Dictionary.prototype = {
|
|||||||
for (var i in this._values)
|
for (var i in this._values)
|
||||||
ret.push(f(this._values[i], i.substr(1)));
|
ret.push(f(this._values[i], i.substr(1)));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
},
|
||||||
|
toObject: function() { return this._values }
|
||||||
|
};
|
||||||
|
Dictionary.fromObject = function(obj) {
|
||||||
|
var dict = new Dictionary();
|
||||||
|
dict._size = merge(dict._values, obj);
|
||||||
|
return dict;
|
||||||
};
|
};
|
||||||
|
|||||||
128
npm-shrinkwrap.json
generated
Normal file
128
npm-shrinkwrap.json
generated
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
{
|
||||||
|
"name": "uglify-js",
|
||||||
|
"version": "2.4.24",
|
||||||
|
"dependencies": {
|
||||||
|
"abbrev": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"from": "abbrev@>=1.0.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz"
|
||||||
|
},
|
||||||
|
"amdefine": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "amdefine@>=0.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz"
|
||||||
|
},
|
||||||
|
"async": {
|
||||||
|
"version": "0.2.10",
|
||||||
|
"from": "async@>=0.2.6 <0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
|
||||||
|
},
|
||||||
|
"camelcase": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"from": "camelcase@>=1.0.2 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
|
||||||
|
},
|
||||||
|
"decamelize": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "decamelize@>=1.0.0 <2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz"
|
||||||
|
},
|
||||||
|
"deep-is": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"from": "deep-is@>=0.1.2 <0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
|
||||||
|
},
|
||||||
|
"esprima": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"from": "esprima@>=1.1.1 <1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-1.1.1.tgz"
|
||||||
|
},
|
||||||
|
"estraverse": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"from": "estraverse@>=1.5.1 <1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.5.1.tgz"
|
||||||
|
},
|
||||||
|
"esutils": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"from": "esutils@>=1.0.0 <1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/esutils/-/esutils-1.0.0.tgz"
|
||||||
|
},
|
||||||
|
"fast-levenshtein": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"from": "fast-levenshtein@>=1.0.0 <1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
|
||||||
|
},
|
||||||
|
"levn": {
|
||||||
|
"version": "0.2.5",
|
||||||
|
"from": "levn@>=0.2.5 <0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
|
||||||
|
},
|
||||||
|
"nopt": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"from": "nopt@>=2.1.2 <2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz"
|
||||||
|
},
|
||||||
|
"optionator": {
|
||||||
|
"version": "0.5.0",
|
||||||
|
"from": "optionator@>=0.5.0 <0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz"
|
||||||
|
},
|
||||||
|
"prelude-ls": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"from": "prelude-ls@>=1.1.1 <1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
|
||||||
|
},
|
||||||
|
"reflect": {
|
||||||
|
"version": "0.1.3",
|
||||||
|
"from": "git://github.com/zaach/reflect.js.git",
|
||||||
|
"resolved": "git://github.com/zaach/reflect.js.git#286bcd79661c96ecc404357d3c0e35fdb54a6967"
|
||||||
|
},
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.5.1",
|
||||||
|
"from": "source-map@>=0.5.1 <0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.1.tgz"
|
||||||
|
},
|
||||||
|
"type-check": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"from": "type-check@>=0.3.1 <0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.1.tgz"
|
||||||
|
},
|
||||||
|
"uglify-js": {
|
||||||
|
"version": "2.4.24",
|
||||||
|
"from": "git://github.com/mishoo/UglifyJS2.git",
|
||||||
|
"resolved": "git://github.com/mishoo/UglifyJS2.git#2a06c7758e24a64740473c8031eafbb7fefa213f",
|
||||||
|
"dependencies": {
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.1.34",
|
||||||
|
"from": "source-map@0.1.34",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uglify-to-browserify": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"from": "uglify-to-browserify@>=1.0.0 <1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz"
|
||||||
|
},
|
||||||
|
"window-size": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"from": "window-size@0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
|
||||||
|
},
|
||||||
|
"wordwrap": {
|
||||||
|
"version": "0.0.2",
|
||||||
|
"from": "wordwrap@0.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
|
||||||
|
},
|
||||||
|
"yargs": {
|
||||||
|
"version": "3.5.4",
|
||||||
|
"from": "yargs@>=3.5.4 <3.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz"
|
||||||
|
},
|
||||||
|
"zeparser": {
|
||||||
|
"version": "0.0.7",
|
||||||
|
"from": "git://github.com/qfox/ZeParser.git",
|
||||||
|
"resolved": "git://github.com/qfox/ZeParser.git#c99240c5ba7054c467733800ff38265958a2dda9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
78
package.json
78
package.json
@@ -1,30 +1,52 @@
|
|||||||
{
|
{
|
||||||
"name": "uglify-js",
|
"name": "uglify-js",
|
||||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
"description": "JavaScript parser, mangler/compressor and beautifier toolkit",
|
||||||
"homepage": "http://lisperator.net/uglifyjs",
|
"homepage": "http://lisperator.net/uglifyjs",
|
||||||
"main": "tools/node.js",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"version": "2.4.0",
|
"license": "BSD-2-Clause",
|
||||||
"engines": { "node" : ">=0.4.0" },
|
"version": "2.5.0",
|
||||||
"maintainers": [{
|
"engines": {
|
||||||
"name": "Mihai Bazon",
|
"node": ">=0.8.0"
|
||||||
"email": "mihai.bazon@gmail.com",
|
},
|
||||||
"web": "http://lisperator.net/"
|
"maintainers": [
|
||||||
}],
|
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
|
||||||
"repository": {
|
],
|
||||||
"type": "git",
|
"repository": {
|
||||||
"url": "https://github.com/mishoo/UglifyJS2.git"
|
"type": "git",
|
||||||
},
|
"url": "https://github.com/mishoo/UglifyJS2.git"
|
||||||
"dependencies": {
|
},
|
||||||
"async" : "~0.2.6",
|
"bugs": {
|
||||||
"source-map" : "~0.1.7",
|
"url": "https://github.com/mishoo/UglifyJS2/issues"
|
||||||
"optimist" : "~0.3.5",
|
},
|
||||||
"uglify-to-browserify": "~1.0.0"
|
"main": "tools/node.js",
|
||||||
},
|
"bin": {
|
||||||
"browserify": {
|
"uglifyjs": "bin/uglifyjs"
|
||||||
"transform": [ "uglify-to-browserify" ]
|
},
|
||||||
},
|
"files": [
|
||||||
"bin": {
|
"bin",
|
||||||
"uglifyjs" : "bin/uglifyjs"
|
"lib",
|
||||||
},
|
"tools",
|
||||||
"scripts": {"test": "node test/run-tests.js"}
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"async": "~0.2.6",
|
||||||
|
"source-map": "~0.5.1",
|
||||||
|
"uglify-to-browserify": "~1.0.0",
|
||||||
|
"yargs": "~3.5.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"acorn": "~0.6.0",
|
||||||
|
"escodegen": "~1.3.3",
|
||||||
|
"esfuzz": "~0.3.1",
|
||||||
|
"estraverse": "~1.5.1"
|
||||||
|
},
|
||||||
|
"browserify": {
|
||||||
|
"transform": [
|
||||||
|
"uglify-to-browserify"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"shrinkwrap": "rm ./npm-shrinkwrap.json; rm -rf ./node_modules; npm i && npm shrinkwrap && npm outdated",
|
||||||
|
"test": "node test/run-tests.js"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
67
test/compress/angular-inject.js
vendored
Normal file
67
test/compress/angular-inject.js
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
ng_inject_defun: {
|
||||||
|
options = {
|
||||||
|
angular: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
/*@ngInject*/
|
||||||
|
function Controller(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function Controller(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
Controller.$inject=['dependency']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ng_inject_assignment: {
|
||||||
|
options = {
|
||||||
|
angular: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
/*@ngInject*/
|
||||||
|
var Controller = function(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var Controller = function(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}
|
||||||
|
Controller.$inject=['dependency']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ng_inject_inline: {
|
||||||
|
options = {
|
||||||
|
angular: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
angular.module('a').
|
||||||
|
factory('b',
|
||||||
|
/*@ngInject*/
|
||||||
|
function(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}).
|
||||||
|
directive('c',
|
||||||
|
/*@ngInject*/
|
||||||
|
function(anotherDependency) {
|
||||||
|
return anotherDependency;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
angular.module('a').
|
||||||
|
factory('b',[
|
||||||
|
'dependency',
|
||||||
|
function(dependency) {
|
||||||
|
return dependency;
|
||||||
|
}]).
|
||||||
|
directive('c',[
|
||||||
|
'anotherDependency',
|
||||||
|
function(anotherDependency) {
|
||||||
|
return anotherDependency;
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,3 +12,63 @@ holes_and_undefined: {
|
|||||||
z=[1,void 0,3];
|
z=[1,void 0,3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constant_join: {
|
||||||
|
options = {
|
||||||
|
unsafe : true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var a = [ "foo", "bar", "baz" ].join("");
|
||||||
|
var a1 = [ "foo", "bar", "baz" ].join();
|
||||||
|
var b = [ "foo", 1, 2, 3, "bar" ].join("");
|
||||||
|
var c = [ boo(), "foo", 1, 2, 3, "bar", bar() ].join("");
|
||||||
|
var c1 = [ boo(), bar(), "foo", 1, 2, 3, "bar", bar() ].join("");
|
||||||
|
var c2 = [ 1, 2, "foo", "bar", baz() ].join("");
|
||||||
|
var d = [ "foo", 1 + 2 + "bar", "baz" ].join("-");
|
||||||
|
var e = [].join(foo + bar);
|
||||||
|
var f = [].join("");
|
||||||
|
var g = [].join("foo");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "foobarbaz";
|
||||||
|
var a1 = "foo,bar,baz";
|
||||||
|
var b = "foo123bar";
|
||||||
|
var c = boo() + "foo123bar" + bar();
|
||||||
|
var c1 = "" + boo() + bar() + "foo123bar" + bar();
|
||||||
|
var c2 = "12foobar" + baz();
|
||||||
|
var d = "foo-3bar-baz";
|
||||||
|
var e = [].join(foo + bar);
|
||||||
|
var f = "";
|
||||||
|
var g = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constant_join_2: {
|
||||||
|
options = {
|
||||||
|
unsafe : true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var a = [ "foo", "bar", boo(), "baz", "x", "y" ].join("");
|
||||||
|
var b = [ "foo", "bar", boo(), "baz", "x", "y" ].join("-");
|
||||||
|
var c = [ "foo", "bar", boo(), "baz", "x", "y" ].join("really-long-separator");
|
||||||
|
var d = [ "foo", "bar", boo(),
|
||||||
|
[ "foo", 1, 2, 3, "bar" ].join("+"),
|
||||||
|
"baz", "x", "y" ].join("-");
|
||||||
|
var e = [ "foo", "bar", boo(),
|
||||||
|
[ "foo", 1, 2, 3, "bar" ].join("+"),
|
||||||
|
"baz", "x", "y" ].join("really-long-separator");
|
||||||
|
var f = [ "str", "str" + variable, "foo", "bar", "moo" + foo ].join("");
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "foobar" + boo() + "bazxy";
|
||||||
|
var b = [ "foo-bar", boo(), "baz-x-y" ].join("-");
|
||||||
|
var c = [ "foo", "bar", boo(), "baz", "x", "y" ].join("really-long-separator");
|
||||||
|
var d = [ "foo-bar", boo(), "foo+1+2+3+bar-baz-x-y" ].join("-");
|
||||||
|
var e = [ "foo", "bar", boo(),
|
||||||
|
"foo+1+2+3+bar",
|
||||||
|
"baz", "x", "y" ].join("really-long-separator");
|
||||||
|
var f = "strstr" + variable + "foobarmoo" + foo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
106
test/compress/asm.js
Normal file
106
test/compress/asm.js
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
asm_mixed: {
|
||||||
|
options = {
|
||||||
|
sequences : true,
|
||||||
|
properties : true,
|
||||||
|
dead_code : true,
|
||||||
|
drop_debugger : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
loops : true,
|
||||||
|
unused : true,
|
||||||
|
hoist_funs : true,
|
||||||
|
keep_fargs : true,
|
||||||
|
keep_fnames : false,
|
||||||
|
hoist_vars : true,
|
||||||
|
if_return : true,
|
||||||
|
join_vars : true,
|
||||||
|
cascade : true,
|
||||||
|
side_effects : true,
|
||||||
|
negate_iife : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
// adapted from http://asmjs.org/spec/latest/
|
||||||
|
function asm_GeometricMean(stdlib, foreign, buffer) {
|
||||||
|
"use asm";
|
||||||
|
var exp = stdlib.Math.exp;
|
||||||
|
var log = stdlib.Math.log;
|
||||||
|
var values = new stdlib.Float64Array(buffer);
|
||||||
|
function logSum(start, end) {
|
||||||
|
start = start|0;
|
||||||
|
end = end|0;
|
||||||
|
var sum = 0.0, p = 0, q = 0;
|
||||||
|
// asm.js forces byte addressing of the heap by requiring shifting by 3
|
||||||
|
for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {
|
||||||
|
sum = sum + +log(values[p>>3]);
|
||||||
|
}
|
||||||
|
return +sum;
|
||||||
|
}
|
||||||
|
function geometricMean(start, end) {
|
||||||
|
start = start|0;
|
||||||
|
end = end|0;
|
||||||
|
return +exp(+logSum(start, end) / +((end - start)|0));
|
||||||
|
}
|
||||||
|
return { geometricMean: geometricMean };
|
||||||
|
}
|
||||||
|
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
||||||
|
var exp = stdlib.Math.exp;
|
||||||
|
var log = stdlib.Math.log;
|
||||||
|
var values = new stdlib.Float64Array(buffer);
|
||||||
|
function logSum(start, end) {
|
||||||
|
start = start|0;
|
||||||
|
end = end|0;
|
||||||
|
var sum = 0.0, p = 0, q = 0;
|
||||||
|
// asm.js forces byte addressing of the heap by requiring shifting by 3
|
||||||
|
for (p = start << 3, q = end << 3; (p|0) < (q|0); p = (p + 8)|0) {
|
||||||
|
sum = sum + +log(values[p>>3]);
|
||||||
|
}
|
||||||
|
return +sum;
|
||||||
|
}
|
||||||
|
function geometricMean(start, end) {
|
||||||
|
start = start|0;
|
||||||
|
end = end|0;
|
||||||
|
return +exp(+logSum(start, end) / +((end - start)|0));
|
||||||
|
}
|
||||||
|
return { geometricMean: geometricMean };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function asm_GeometricMean(stdlib, foreign, buffer) {
|
||||||
|
"use asm";
|
||||||
|
var exp = stdlib.Math.exp;
|
||||||
|
var log = stdlib.Math.log;
|
||||||
|
var values = new stdlib.Float64Array(buffer);
|
||||||
|
function logSum(start, end) {
|
||||||
|
start = start | 0;
|
||||||
|
end = end | 0;
|
||||||
|
var sum = 0.0, p = 0, q = 0;
|
||||||
|
for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) {
|
||||||
|
sum = sum + +log(values[p >> 3]);
|
||||||
|
}
|
||||||
|
return +sum;
|
||||||
|
}
|
||||||
|
function geometricMean(start, end) {
|
||||||
|
start = start | 0;
|
||||||
|
end = end | 0;
|
||||||
|
return +exp(+logSum(start, end) / +(end - start | 0));
|
||||||
|
}
|
||||||
|
return { geometricMean: geometricMean };
|
||||||
|
}
|
||||||
|
function no_asm_GeometricMean(stdlib, foreign, buffer) {
|
||||||
|
function logSum(start, end) {
|
||||||
|
start = 0 | start, end = 0 | end;
|
||||||
|
var sum = 0, p = 0, q = 0;
|
||||||
|
for (p = start << 3, q = end << 3; (0 | q) > (0 | p); p = p + 8 | 0) sum += +log(values[p >> 3]);
|
||||||
|
return +sum;
|
||||||
|
}
|
||||||
|
function geometricMean(start, end) {
|
||||||
|
return start = 0 | start, end = 0 | end, +exp(+logSum(start, end) / +(end - start | 0));
|
||||||
|
}
|
||||||
|
var exp = stdlib.Math.exp, log = stdlib.Math.log, values = new stdlib.Float64Array(buffer);
|
||||||
|
return { geometricMean: geometricMean };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
22
test/compress/concat-strings.js
Normal file
22
test/compress/concat-strings.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
concat_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var a = "foo" + "bar" + x() + "moo" + "foo" + y() + "x" + "y" + "z" + q();
|
||||||
|
var b = "foo" + 1 + x() + 2 + "boo";
|
||||||
|
var c = 1 + x() + 2 + "boo";
|
||||||
|
|
||||||
|
// this CAN'T safely be shortened to 1 + x() + "5boo"
|
||||||
|
var d = 1 + x() + 2 + 3 + "boo";
|
||||||
|
|
||||||
|
var e = 1 + x() + 2 + "X" + 3 + "boo";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = "foobar" + x() + "moofoo" + y() + "xyz" + q();
|
||||||
|
var b = "foo1" + x() + "2boo";
|
||||||
|
var c = 1 + x() + 2 + "boo";
|
||||||
|
var d = 1 + x() + 2 + 3 + "boo";
|
||||||
|
var e = 1 + x() + 2 + "X3boo";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,6 +53,7 @@ ifs_3_should_warn: {
|
|||||||
booleans : true
|
booleans : true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
|
var x, y;
|
||||||
if (x && !(x + "1") && y) { // 1
|
if (x && !(x + "1") && y) { // 1
|
||||||
var qq;
|
var qq;
|
||||||
foo();
|
foo();
|
||||||
@@ -68,6 +69,7 @@ ifs_3_should_warn: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var x, y;
|
||||||
var qq; bar(); // 1
|
var qq; bar(); // 1
|
||||||
var jj; foo(); // 2
|
var jj; foo(); // 2
|
||||||
}
|
}
|
||||||
@@ -84,7 +86,9 @@ ifs_4: {
|
|||||||
x(foo)[10].bar.baz = something_else();
|
x(foo)[10].bar.baz = something_else();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
x(foo)[10].bar.baz = (foo && bar) ? something() : something_else();
|
foo && bar
|
||||||
|
? x(foo)[10].bar.baz = something()
|
||||||
|
: x(foo)[10].bar.baz = something_else();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,6 +135,7 @@ ifs_6: {
|
|||||||
comparisons: true
|
comparisons: true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
|
var x;
|
||||||
if (!foo && !bar && !baz && !boo) {
|
if (!foo && !bar && !baz && !boo) {
|
||||||
x = 10;
|
x = 10;
|
||||||
} else {
|
} else {
|
||||||
@@ -138,6 +143,404 @@ ifs_6: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var x;
|
||||||
x = foo || bar || baz || boo ? 20 : 10;
|
x = foo || bar || baz || boo ? 20 : 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cond_1: {
|
||||||
|
options = {
|
||||||
|
conditionals: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var do_something; // if undeclared it's assumed to have side-effects
|
||||||
|
if (some_condition()) {
|
||||||
|
do_something(x);
|
||||||
|
} else {
|
||||||
|
do_something(y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var do_something;
|
||||||
|
do_something(some_condition() ? x : y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_2: {
|
||||||
|
options = {
|
||||||
|
conditionals: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var x, FooBar;
|
||||||
|
if (some_condition()) {
|
||||||
|
x = new FooBar(1);
|
||||||
|
} else {
|
||||||
|
x = new FooBar(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var x, FooBar;
|
||||||
|
x = new FooBar(some_condition() ? 1 : 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_3: {
|
||||||
|
options = {
|
||||||
|
conditionals: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var FooBar;
|
||||||
|
if (some_condition()) {
|
||||||
|
new FooBar(1);
|
||||||
|
} else {
|
||||||
|
FooBar(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var FooBar;
|
||||||
|
some_condition() ? new FooBar(1) : FooBar(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_4: {
|
||||||
|
options = {
|
||||||
|
conditionals: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var do_something;
|
||||||
|
if (some_condition()) {
|
||||||
|
do_something();
|
||||||
|
} else {
|
||||||
|
do_something();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var do_something;
|
||||||
|
some_condition(), do_something();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_5: {
|
||||||
|
options = {
|
||||||
|
conditionals: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
if (some_condition()) {
|
||||||
|
if (some_other_condition()) {
|
||||||
|
do_something();
|
||||||
|
} else {
|
||||||
|
alternate();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alternate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (some_condition()) {
|
||||||
|
if (some_other_condition()) {
|
||||||
|
do_something();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
some_condition() && some_other_condition() ? do_something() : alternate();
|
||||||
|
some_condition() && some_other_condition() && do_something();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_7: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var x, y, z, a, b;
|
||||||
|
// compress these
|
||||||
|
if (y) {
|
||||||
|
x = 1+1;
|
||||||
|
} else {
|
||||||
|
x = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y) {
|
||||||
|
x = 1+1;
|
||||||
|
} else if (z) {
|
||||||
|
x = 2;
|
||||||
|
} else {
|
||||||
|
x = 3-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = y ? 'foo' : 'fo'+'o';
|
||||||
|
|
||||||
|
x = y ? 'foo' : y ? 'foo' : 'fo'+'o';
|
||||||
|
|
||||||
|
// Compress conditions that have side effects
|
||||||
|
if (condition()) {
|
||||||
|
x = 10+10;
|
||||||
|
} else {
|
||||||
|
x = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z) {
|
||||||
|
x = 'fuji';
|
||||||
|
} else if (condition()) {
|
||||||
|
x = 'fu'+'ji';
|
||||||
|
} else {
|
||||||
|
x = 'fuji';
|
||||||
|
}
|
||||||
|
|
||||||
|
x = condition() ? 'foobar' : 'foo'+'bar';
|
||||||
|
|
||||||
|
// don't compress these
|
||||||
|
x = y ? a : b;
|
||||||
|
|
||||||
|
x = y ? 'foo' : 'fo';
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var x, y, z, a, b;
|
||||||
|
x = 2;
|
||||||
|
x = 2;
|
||||||
|
x = 'foo';
|
||||||
|
x = 'foo';
|
||||||
|
x = (condition(), 20);
|
||||||
|
x = z ? 'fuji' : (condition(), 'fuji');
|
||||||
|
x = (condition(), 'foobar');
|
||||||
|
x = y ? a : b;
|
||||||
|
x = y ? 'foo' : 'fo';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_7_1: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var x;
|
||||||
|
// access to global should be assumed to have side effects
|
||||||
|
if (y) {
|
||||||
|
x = 1+1;
|
||||||
|
} else {
|
||||||
|
x = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var x;
|
||||||
|
x = (y, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_8: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
// compress these
|
||||||
|
a = condition ? true : false;
|
||||||
|
|
||||||
|
a = !condition ? true : false;
|
||||||
|
|
||||||
|
a = condition() ? true : false;
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = true;
|
||||||
|
} else {
|
||||||
|
a = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = condition ? false : true;
|
||||||
|
|
||||||
|
a = !condition ? false : true;
|
||||||
|
|
||||||
|
a = condition() ? false : true;
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = false;
|
||||||
|
} else {
|
||||||
|
a = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't compress these
|
||||||
|
a = condition ? 1 : false;
|
||||||
|
|
||||||
|
a = !condition ? true : 0;
|
||||||
|
|
||||||
|
a = condition ? 1 : 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
a = !!condition;
|
||||||
|
a = !condition;
|
||||||
|
a = !!condition();
|
||||||
|
a = !!condition;
|
||||||
|
a = !condition;
|
||||||
|
a = !!condition;
|
||||||
|
a = !condition();
|
||||||
|
a = !condition;
|
||||||
|
a = condition ? 1 : false;
|
||||||
|
a = condition ? 0 : true;
|
||||||
|
a = condition ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conditional_and: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
// compress these
|
||||||
|
|
||||||
|
a = true && condition;
|
||||||
|
a = 1 && console.log("a");
|
||||||
|
a = 2 * 3 && 2 * condition;
|
||||||
|
a = 5 == 5 && condition + 3;
|
||||||
|
a = "string" && 4 - condition;
|
||||||
|
a = 5 + "" && condition / 5;
|
||||||
|
a = -4.5 && 6 << condition;
|
||||||
|
a = 6 && 7;
|
||||||
|
|
||||||
|
a = false && condition;
|
||||||
|
a = NaN && console.log("b");
|
||||||
|
a = 0 && console.log("c");
|
||||||
|
a = undefined && 2 * condition;
|
||||||
|
a = null && condition + 3;
|
||||||
|
a = 2 * 3 - 6 && 4 - condition;
|
||||||
|
a = 10 == 7 && condition / 5;
|
||||||
|
a = !"string" && 6 % condition;
|
||||||
|
a = 0 && 7;
|
||||||
|
|
||||||
|
// don't compress these
|
||||||
|
|
||||||
|
a = condition && true;
|
||||||
|
a = console.log("a") && 2;
|
||||||
|
a = 4 - condition && "string";
|
||||||
|
a = 6 << condition && -4.5;
|
||||||
|
|
||||||
|
a = condition && false;
|
||||||
|
a = console.log("b") && NaN;
|
||||||
|
a = console.log("c") && 0;
|
||||||
|
a = 2 * condition && undefined;
|
||||||
|
a = condition + 3 && null;
|
||||||
|
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
|
||||||
|
a = condition;
|
||||||
|
a = console.log("a");
|
||||||
|
a = 2 * condition;
|
||||||
|
a = condition + 3;
|
||||||
|
a = 4 - condition;
|
||||||
|
a = condition / 5;
|
||||||
|
a = 6 << condition;
|
||||||
|
a = 7;
|
||||||
|
|
||||||
|
a = false;
|
||||||
|
a = NaN;
|
||||||
|
a = 0;
|
||||||
|
a = void 0;
|
||||||
|
a = null;
|
||||||
|
a = 0;
|
||||||
|
a = false;
|
||||||
|
a = false;
|
||||||
|
a = 0;
|
||||||
|
|
||||||
|
a = condition && true;
|
||||||
|
a = console.log("a") && 2;
|
||||||
|
a = 4 - condition && "string";
|
||||||
|
a = 6 << condition && -4.5;
|
||||||
|
|
||||||
|
a = condition && false;
|
||||||
|
a = console.log("b") && NaN;
|
||||||
|
a = console.log("c") && 0;
|
||||||
|
a = 2 * condition && void 0;
|
||||||
|
a = condition + 3 && null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conditional_or: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
// compress these
|
||||||
|
|
||||||
|
a = true || condition;
|
||||||
|
a = 1 || console.log("a");
|
||||||
|
a = 2 * 3 || 2 * condition;
|
||||||
|
a = 5 == 5 || condition + 3;
|
||||||
|
a = "string" || 4 - condition;
|
||||||
|
a = 5 + "" || condition / 5;
|
||||||
|
a = -4.5 || 6 << condition;
|
||||||
|
a = 6 || 7;
|
||||||
|
|
||||||
|
a = false || condition;
|
||||||
|
a = 0 || console.log("b");
|
||||||
|
a = NaN || console.log("c");
|
||||||
|
a = undefined || 2 * condition;
|
||||||
|
a = null || condition + 3;
|
||||||
|
a = 2 * 3 - 6 || 4 - condition;
|
||||||
|
a = 10 == 7 || condition / 5;
|
||||||
|
a = !"string" || 6 % condition;
|
||||||
|
a = null || 7;
|
||||||
|
|
||||||
|
a = console.log(undefined && condition || null);
|
||||||
|
a = console.log(undefined || condition && null);
|
||||||
|
|
||||||
|
// don't compress these
|
||||||
|
|
||||||
|
a = condition || true;
|
||||||
|
a = console.log("a") || 2;
|
||||||
|
a = 4 - condition || "string";
|
||||||
|
a = 6 << condition || -4.5;
|
||||||
|
|
||||||
|
a = condition || false;
|
||||||
|
a = console.log("b") || NaN;
|
||||||
|
a = console.log("c") || 0;
|
||||||
|
a = 2 * condition || undefined;
|
||||||
|
a = condition + 3 || null;
|
||||||
|
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a;
|
||||||
|
|
||||||
|
a = true;
|
||||||
|
a = 1;
|
||||||
|
a = 6;
|
||||||
|
a = true;
|
||||||
|
a = "string";
|
||||||
|
a = "5";
|
||||||
|
a = -4.5;
|
||||||
|
a = 6;
|
||||||
|
|
||||||
|
a = condition;
|
||||||
|
a = console.log("b");
|
||||||
|
a = console.log("c");
|
||||||
|
a = 2 * condition;
|
||||||
|
a = condition + 3;
|
||||||
|
a = 4 - condition;
|
||||||
|
a = condition / 5;
|
||||||
|
a = 6 % condition;
|
||||||
|
a = 7;
|
||||||
|
|
||||||
|
a = console.log(null);
|
||||||
|
a = console.log(condition && null);
|
||||||
|
|
||||||
|
a = condition || true;
|
||||||
|
a = console.log("a") || 2;
|
||||||
|
a = 4 - condition || "string";
|
||||||
|
a = 6 << condition || -4.5;
|
||||||
|
|
||||||
|
a = condition || false;
|
||||||
|
a = console.log("b") || NaN;
|
||||||
|
a = console.log("c") || 0;
|
||||||
|
a = 2 * condition || void 0;
|
||||||
|
a = condition + 3 || null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,89 +1,89 @@
|
|||||||
dead_code_1: {
|
dead_code_1: {
|
||||||
options = {
|
options = {
|
||||||
dead_code: true
|
dead_code: true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
function f() {
|
function f() {
|
||||||
a();
|
a();
|
||||||
b();
|
b();
|
||||||
x = 10;
|
x = 10;
|
||||||
return;
|
return;
|
||||||
if (x) {
|
if (x) {
|
||||||
y();
|
y();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
a();
|
a();
|
||||||
b();
|
b();
|
||||||
x = 10;
|
x = 10;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dead_code_2_should_warn: {
|
dead_code_2_should_warn: {
|
||||||
options = {
|
options = {
|
||||||
dead_code: true
|
dead_code: true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
function f() {
|
function f() {
|
||||||
g();
|
g();
|
||||||
x = 10;
|
x = 10;
|
||||||
throw "foo";
|
throw "foo";
|
||||||
// completely discarding the `if` would introduce some
|
// completely discarding the `if` would introduce some
|
||||||
// bugs. UglifyJS v1 doesn't deal with this issue; in v2
|
// bugs. UglifyJS v1 doesn't deal with this issue; in v2
|
||||||
// we copy any declarations to the upper scope.
|
// we copy any declarations to the upper scope.
|
||||||
if (x) {
|
if (x) {
|
||||||
y();
|
y();
|
||||||
var x;
|
var x;
|
||||||
function g(){};
|
function g(){};
|
||||||
// but nested declarations should not be kept.
|
// but nested declarations should not be kept.
|
||||||
(function(){
|
(function(){
|
||||||
var q;
|
var q;
|
||||||
function y(){};
|
function y(){};
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
g();
|
g();
|
||||||
x = 10;
|
x = 10;
|
||||||
throw "foo";
|
throw "foo";
|
||||||
var x;
|
var x;
|
||||||
function g(){};
|
function g(){};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dead_code_constant_boolean_should_warn_more: {
|
dead_code_constant_boolean_should_warn_more: {
|
||||||
options = {
|
options = {
|
||||||
dead_code : true,
|
dead_code : true,
|
||||||
loops : true,
|
loops : true,
|
||||||
booleans : true,
|
booleans : true,
|
||||||
conditionals : true,
|
conditionals : true,
|
||||||
evaluate : true
|
evaluate : true
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
while (!((foo && bar) || (x + "0"))) {
|
while (!((foo && bar) || (x + "0"))) {
|
||||||
console.log("unreachable");
|
console.log("unreachable");
|
||||||
var foo;
|
var foo;
|
||||||
function bar() {}
|
function bar() {}
|
||||||
}
|
}
|
||||||
for (var x = 10; x && (y || x) && (!typeof x); ++x) {
|
for (var x = 10, y; x && (y || x) && (!typeof x); ++x) {
|
||||||
asdf();
|
asdf();
|
||||||
foo();
|
foo();
|
||||||
var moo;
|
var moo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var foo;
|
var foo;
|
||||||
function bar() {}
|
function bar() {}
|
||||||
// nothing for the while
|
// nothing for the while
|
||||||
// as for the for, it should keep:
|
// as for the for, it should keep:
|
||||||
var x = 10;
|
var x = 10, y;
|
||||||
var moo;
|
var moo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
test/compress/drop-console.js
Normal file
24
test/compress/drop-console.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
drop_console_1: {
|
||||||
|
options = {};
|
||||||
|
input: {
|
||||||
|
console.log('foo');
|
||||||
|
console.log.apply(console, arguments);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log('foo');
|
||||||
|
console.log.apply(console, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_console_1: {
|
||||||
|
options = { drop_console: true };
|
||||||
|
input: {
|
||||||
|
console.log('foo');
|
||||||
|
console.log.apply(console, arguments);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
// with regular compression these will be stripped out as well
|
||||||
|
void 0;
|
||||||
|
void 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
unused_funarg_1: {
|
unused_funarg_1: {
|
||||||
options = { unused: true };
|
options = { unused: true, keep_fargs: false };
|
||||||
input: {
|
input: {
|
||||||
function f(a, b, c, d, e) {
|
function f(a, b, c, d, e) {
|
||||||
return a + b;
|
return a + b;
|
||||||
@@ -13,7 +13,7 @@ unused_funarg_1: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unused_funarg_2: {
|
unused_funarg_2: {
|
||||||
options = { unused: true };
|
options = { unused: true, keep_fargs: false };
|
||||||
input: {
|
input: {
|
||||||
function f(a, b, c, d, e) {
|
function f(a, b, c, d, e) {
|
||||||
return a + c;
|
return a + c;
|
||||||
@@ -119,3 +119,61 @@ unused_keep_setter_arg: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unused_var_in_catch: {
|
||||||
|
options = { unused: true };
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch(ex) {
|
||||||
|
var x = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch(ex) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
used_var_in_catch: {
|
||||||
|
options = { unused: true };
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch(ex) {
|
||||||
|
var x = 10;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
try {
|
||||||
|
foo();
|
||||||
|
} catch(ex) {
|
||||||
|
var x = 10;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_fnames: {
|
||||||
|
options = { unused: true, keep_fnames: true, unsafe: true };
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
return function bar(baz) {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
return function bar(baz) {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
24
test/compress/issue-126.js
Normal file
24
test/compress/issue-126.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
concatenate_rhs_strings: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
unsafe: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
foo(bar() + 123 + "Hello" + "World");
|
||||||
|
foo(bar() + (123 + "Hello") + "World");
|
||||||
|
foo((bar() + 123) + "Hello" + "World");
|
||||||
|
foo(bar() + 123 + "Hello" + "World" + ("Foo" + "Bar"));
|
||||||
|
foo("Foo" + "Bar" + bar() + 123 + "Hello" + "World" + ("Foo" + "Bar"));
|
||||||
|
foo("Hello" + bar() + 123 + "World");
|
||||||
|
foo(bar() + 'Foo' + (10 + parseInt('10')));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
foo(bar() + 123 + "HelloWorld");
|
||||||
|
foo(bar() + "123HelloWorld");
|
||||||
|
foo((bar() + 123) + "HelloWorld");
|
||||||
|
foo(bar() + 123 + "HelloWorldFooBar");
|
||||||
|
foo("FooBar" + bar() + "123HelloWorldFooBar");
|
||||||
|
foo("Hello" + bar() + "123World");
|
||||||
|
foo(bar() + 'Foo' + (10 + parseInt('10')));
|
||||||
|
}
|
||||||
|
}
|
||||||
11
test/compress/issue-208.js
Normal file
11
test/compress/issue-208.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
do_not_update_lhs: {
|
||||||
|
options = { global_defs: { DEBUG: false } };
|
||||||
|
input: { DEBUG = false; }
|
||||||
|
expect: { DEBUG = false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
do_update_rhs: {
|
||||||
|
options = { global_defs: { DEBUG: false } };
|
||||||
|
input: { MY_DEBUG = DEBUG; }
|
||||||
|
expect: { MY_DEBUG = false; }
|
||||||
|
}
|
||||||
11
test/compress/issue-267.js
Normal file
11
test/compress/issue-267.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
issue_267: {
|
||||||
|
options = { comparisons: true };
|
||||||
|
input: {
|
||||||
|
x = a % b / b * c * 2;
|
||||||
|
x = a % b * 2
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
x = a % b / b * c * 2;
|
||||||
|
x = a % b * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
66
test/compress/issue-269.js
Normal file
66
test/compress/issue-269.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
issue_269_1: {
|
||||||
|
options = {unsafe: true};
|
||||||
|
input: {
|
||||||
|
f(
|
||||||
|
String(x),
|
||||||
|
Number(x),
|
||||||
|
Boolean(x),
|
||||||
|
|
||||||
|
String(),
|
||||||
|
Number(),
|
||||||
|
Boolean()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
f(
|
||||||
|
x + '', +x, !!x,
|
||||||
|
'', 0, false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_269_dangers: {
|
||||||
|
options = {unsafe: true};
|
||||||
|
input: {
|
||||||
|
f(
|
||||||
|
String(x, x),
|
||||||
|
Number(x, x),
|
||||||
|
Boolean(x, x)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
f(String(x, x), Number(x, x), Boolean(x, x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_269_in_scope: {
|
||||||
|
options = {unsafe: true};
|
||||||
|
input: {
|
||||||
|
var String, Number, Boolean;
|
||||||
|
f(
|
||||||
|
String(x),
|
||||||
|
Number(x, x),
|
||||||
|
Boolean(x)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var String, Number, Boolean;
|
||||||
|
f(String(x), Number(x, x), Boolean(x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strings_concat: {
|
||||||
|
options = {unsafe: true};
|
||||||
|
input: {
|
||||||
|
f(
|
||||||
|
String(x + 'str'),
|
||||||
|
String('str' + x)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
f(
|
||||||
|
x + 'str',
|
||||||
|
'str' + x
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
test/compress/issue-597.js
Normal file
25
test/compress/issue-597.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
NaN_and_Infinity_must_have_parens: {
|
||||||
|
options = {};
|
||||||
|
input: {
|
||||||
|
Infinity.toString();
|
||||||
|
NaN.toString();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(1/0).toString();
|
||||||
|
NaN.toString(); // transformation to 0/0 dropped
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: {
|
||||||
|
options = {};
|
||||||
|
input: {
|
||||||
|
var Infinity, NaN;
|
||||||
|
Infinity.toString();
|
||||||
|
NaN.toString();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var Infinity, NaN;
|
||||||
|
Infinity.toString();
|
||||||
|
NaN.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
21
test/compress/issue-611.js
Normal file
21
test/compress/issue-611.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
issue_611: {
|
||||||
|
options = {
|
||||||
|
sequences: true,
|
||||||
|
side_effects: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
define(function() {
|
||||||
|
function fn() {}
|
||||||
|
if (fn()) {
|
||||||
|
fn();
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
define(function() {
|
||||||
|
function fn(){}
|
||||||
|
if (fn()) return void fn();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
22
test/compress/issue-637.js
Normal file
22
test/compress/issue-637.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
wrongly_optimized: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
booleans: true,
|
||||||
|
evaluate: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
function func() {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
if (func() || true) {
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function func() {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
// TODO: optimize to `func(), bar()`
|
||||||
|
(func(), 0) || bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
37
test/compress/issue-747.js
Normal file
37
test/compress/issue-747.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
dont_reuse_prop: {
|
||||||
|
mangle_props = {
|
||||||
|
regex: /asd/
|
||||||
|
};
|
||||||
|
|
||||||
|
input: {
|
||||||
|
var obj = {};
|
||||||
|
obj.a = 123;
|
||||||
|
obj.asd = 256;
|
||||||
|
console.log(obj.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj = {};
|
||||||
|
obj.a = 123;
|
||||||
|
obj.b = 256;
|
||||||
|
console.log(obj.a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unmangleable_props_should_always_be_reserved: {
|
||||||
|
mangle_props = {
|
||||||
|
regex: /asd/
|
||||||
|
};
|
||||||
|
|
||||||
|
input: {
|
||||||
|
var obj = {};
|
||||||
|
obj.asd = 256;
|
||||||
|
obj.a = 123;
|
||||||
|
console.log(obj.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj = {};
|
||||||
|
obj.b = 256;
|
||||||
|
obj.a = 123;
|
||||||
|
console.log(obj.a);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
test/compress/issue-751.js
Normal file
29
test/compress/issue-751.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
negate_booleans_1: {
|
||||||
|
options = {
|
||||||
|
comparisons: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var a = !a || !b || !c || !d || !e || !f;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = !(a && b && c && d && e && f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
negate_booleans_2: {
|
||||||
|
options = {
|
||||||
|
comparisons: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var match = !x && // should not touch this one
|
||||||
|
(!z || c) &&
|
||||||
|
(!k || d) &&
|
||||||
|
the_stuff();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var match = !x &&
|
||||||
|
(!z || c) &&
|
||||||
|
(!k || d) &&
|
||||||
|
the_stuff();
|
||||||
|
}
|
||||||
|
}
|
||||||
23
test/compress/issue-782.js
Normal file
23
test/compress/issue-782.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
remove_redundant_sequence_items: {
|
||||||
|
options = { side_effects: true };
|
||||||
|
input: {
|
||||||
|
(0, 1, logThis)();
|
||||||
|
(0, 1, _decorators.logThis)();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(0, logThis)();
|
||||||
|
(0, _decorators.logThis)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_remove_lexical_binding_sequence: {
|
||||||
|
options = { side_effects: true };
|
||||||
|
input: {
|
||||||
|
(0, logThis)();
|
||||||
|
(0, _decorators.logThis)();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(0, logThis)();
|
||||||
|
(0, _decorators.logThis)();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,16 +60,16 @@ negate_iife_4: {
|
|||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
if ((function(){ return true })()) {
|
if ((function(){ return true })()) {
|
||||||
console.log(true);
|
foo(true);
|
||||||
} else {
|
} else {
|
||||||
console.log(false);
|
bar(false);
|
||||||
}
|
}
|
||||||
(function(){
|
(function(){
|
||||||
console.log("something");
|
console.log("something");
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
!function(){ return true }() ? console.log(false) : console.log(true), function(){
|
!function(){ return true }() ? bar(false) : foo(true), function(){
|
||||||
console.log("something");
|
console.log("something");
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
|
|||||||
12
test/compress/new.js
Normal file
12
test/compress/new.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
new_statement: {
|
||||||
|
input: {
|
||||||
|
new x(1);
|
||||||
|
new x(1)(2);
|
||||||
|
new x(1)(2)(3);
|
||||||
|
new new x(1);
|
||||||
|
new new x(1)(2);
|
||||||
|
new (new x(1))(2);
|
||||||
|
(new new x(1))(2);
|
||||||
|
}
|
||||||
|
expect_exact: "new x(1);new x(1)(2);new x(1)(2)(3);new new x(1);new new x(1)(2);new new x(1)(2);(new new x(1))(2);"
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ dot_properties: {
|
|||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
a["if"] = "if";
|
a["if"] = "if";
|
||||||
a["*"] = "asterisk";
|
a["*"] = "asterisk";
|
||||||
a.\u0EB3 = "unicode";
|
a["\u0EB3"] = "unicode";
|
||||||
a[""] = "whitespace";
|
a[""] = "whitespace";
|
||||||
a["1_1"] = "foo";
|
a["1_1"] = "foo";
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,27 @@ dot_properties_es5: {
|
|||||||
a.foo = "bar";
|
a.foo = "bar";
|
||||||
a.if = "if";
|
a.if = "if";
|
||||||
a["*"] = "asterisk";
|
a["*"] = "asterisk";
|
||||||
a.\u0EB3 = "unicode";
|
a["\u0EB3"] = "unicode";
|
||||||
a[""] = "whitespace";
|
a[""] = "whitespace";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evaluate_length: {
|
||||||
|
options = {
|
||||||
|
properties: true,
|
||||||
|
unsafe: true,
|
||||||
|
evaluate: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
a = "foo".length;
|
||||||
|
a = ("foo" + "bar")["len" + "gth"];
|
||||||
|
a = b.length;
|
||||||
|
a = ("foo" + b).length;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a = 3;
|
||||||
|
a = 6;
|
||||||
|
a = b.length;
|
||||||
|
a = ("foo" + b).length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -91,9 +91,11 @@ make_sequences_4: {
|
|||||||
lift_sequences_1: {
|
lift_sequences_1: {
|
||||||
options = { sequences: true };
|
options = { sequences: true };
|
||||||
input: {
|
input: {
|
||||||
|
var foo, x, y, bar;
|
||||||
foo = !(x(), y(), bar());
|
foo = !(x(), y(), bar());
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var foo, x, y, bar;
|
||||||
x(), y(), foo = !bar();
|
x(), y(), foo = !bar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,19 +103,25 @@ lift_sequences_1: {
|
|||||||
lift_sequences_2: {
|
lift_sequences_2: {
|
||||||
options = { sequences: true, evaluate: true };
|
options = { sequences: true, evaluate: true };
|
||||||
input: {
|
input: {
|
||||||
q = 1 + (foo(), bar(), 5) + 7 * (5 / (3 - (a(), (QW=ER), c(), 2))) - (x(), y(), 5);
|
var foo, bar;
|
||||||
|
foo.x = (foo = {}, 10);
|
||||||
|
bar = (bar = {}, 10);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
foo(), bar(), a(), QW = ER, c(), x(), y(), q = 36
|
var foo, bar;
|
||||||
|
foo.x = (foo = {}, 10),
|
||||||
|
bar = {}, bar = 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lift_sequences_3: {
|
lift_sequences_3: {
|
||||||
options = { sequences: true, conditionals: true };
|
options = { sequences: true, conditionals: true };
|
||||||
input: {
|
input: {
|
||||||
|
var x, foo, bar, baz;
|
||||||
x = (foo(), bar(), baz()) ? 10 : 20;
|
x = (foo(), bar(), baz()) ? 10 : 20;
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var x, foo, bar, baz;
|
||||||
foo(), bar(), x = baz() ? 10 : 20;
|
foo(), bar(), x = baz() ? 10 : 20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,9 +129,11 @@ lift_sequences_3: {
|
|||||||
lift_sequences_4: {
|
lift_sequences_4: {
|
||||||
options = { side_effects: true };
|
options = { side_effects: true };
|
||||||
input: {
|
input: {
|
||||||
|
var x, foo, bar, baz;
|
||||||
x = (foo, bar, baz);
|
x = (foo, bar, baz);
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
|
var x, foo, bar, baz;
|
||||||
x = baz;
|
x = baz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
test/compress/unicode.js
Normal file
17
test/compress/unicode.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
unicode_parse_variables: {
|
||||||
|
options = {};
|
||||||
|
input: {
|
||||||
|
var a = {};
|
||||||
|
a.你好 = 456;
|
||||||
|
|
||||||
|
var ↂωↂ = 123;
|
||||||
|
var l০ = 3; // 2nd char is a unicode digit
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = {};
|
||||||
|
a.你好 = 456;
|
||||||
|
|
||||||
|
var ↂωↂ = 123;
|
||||||
|
var l০ = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
103
test/mozilla-ast.js
Normal file
103
test/mozilla-ast.js
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// Testing UglifyJS <-> SpiderMonkey AST conversion
|
||||||
|
// through generative testing.
|
||||||
|
|
||||||
|
var UglifyJS = require(".."),
|
||||||
|
escodegen = require("escodegen"),
|
||||||
|
esfuzz = require("esfuzz"),
|
||||||
|
estraverse = require("estraverse"),
|
||||||
|
prefix = Array(20).join("\b") + " ";
|
||||||
|
|
||||||
|
// Normalizes input AST for UglifyJS in order to get correct comparison.
|
||||||
|
|
||||||
|
function normalizeInput(ast) {
|
||||||
|
return estraverse.replace(ast, {
|
||||||
|
enter: function(node, parent) {
|
||||||
|
switch (node.type) {
|
||||||
|
// Internally mark all the properties with semi-standard type "Property".
|
||||||
|
case "ObjectExpression":
|
||||||
|
node.properties.forEach(function (property) {
|
||||||
|
property.type = "Property";
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Since UglifyJS doesn"t recognize different types of property keys,
|
||||||
|
// decision on SpiderMonkey node type is based on check whether key
|
||||||
|
// can be valid identifier or not - so we do in input AST.
|
||||||
|
case "Property":
|
||||||
|
var key = node.key;
|
||||||
|
if (key.type === "Literal" && typeof key.value === "string" && UglifyJS.is_identifier(key.value)) {
|
||||||
|
node.key = {
|
||||||
|
type: "Identifier",
|
||||||
|
name: key.value
|
||||||
|
};
|
||||||
|
} else if (key.type === "Identifier" && !UglifyJS.is_identifier(key.name)) {
|
||||||
|
node.key = {
|
||||||
|
type: "Literal",
|
||||||
|
value: key.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// UglifyJS internally flattens all the expression sequences - either
|
||||||
|
// to one element (if sequence contains only one element) or flat list.
|
||||||
|
case "SequenceExpression":
|
||||||
|
node.expressions = node.expressions.reduce(function flatten(list, expr) {
|
||||||
|
return list.concat(expr.type === "SequenceExpression" ? expr.expressions.reduce(flatten, []) : [expr]);
|
||||||
|
}, []);
|
||||||
|
if (node.expressions.length === 1) {
|
||||||
|
return node.expressions[0];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function(options) {
|
||||||
|
console.log("--- UglifyJS <-> Mozilla AST conversion");
|
||||||
|
|
||||||
|
for (var counter = 0; counter < options.iterations; counter++) {
|
||||||
|
process.stdout.write(prefix + counter + "/" + options.iterations);
|
||||||
|
|
||||||
|
var ast1 = normalizeInput(esfuzz.generate({
|
||||||
|
maxDepth: options.maxDepth
|
||||||
|
}));
|
||||||
|
|
||||||
|
var ast2 =
|
||||||
|
UglifyJS
|
||||||
|
.AST_Node
|
||||||
|
.from_mozilla_ast(ast1)
|
||||||
|
.to_mozilla_ast();
|
||||||
|
|
||||||
|
var astPair = [
|
||||||
|
{name: 'expected', value: ast1},
|
||||||
|
{name: 'actual', value: ast2}
|
||||||
|
];
|
||||||
|
|
||||||
|
var jsPair = astPair.map(function(item) {
|
||||||
|
return {
|
||||||
|
name: item.name,
|
||||||
|
value: escodegen.generate(item.value)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (jsPair[0].value !== jsPair[1].value) {
|
||||||
|
var fs = require("fs");
|
||||||
|
var acorn = require("acorn");
|
||||||
|
|
||||||
|
fs.existsSync("tmp") || fs.mkdirSync("tmp");
|
||||||
|
|
||||||
|
jsPair.forEach(function (item) {
|
||||||
|
var fileName = "tmp/dump_" + item.name;
|
||||||
|
var ast = acorn.parse(item.value);
|
||||||
|
fs.writeFileSync(fileName + ".js", item.value);
|
||||||
|
fs.writeFileSync(fileName + ".json", JSON.stringify(ast, null, 2));
|
||||||
|
});
|
||||||
|
|
||||||
|
process.stdout.write("\n");
|
||||||
|
throw new Error("Got different outputs, check out tmp/dump_*.{js,json} for codes and ASTs.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stdout.write(prefix + "Probability of error is less than " + (100 / options.iterations) + "%, stopping.\n");
|
||||||
|
};
|
||||||
@@ -7,8 +7,21 @@ var assert = require("assert");
|
|||||||
var sys = require("util");
|
var sys = require("util");
|
||||||
|
|
||||||
var tests_dir = path.dirname(module.filename);
|
var tests_dir = path.dirname(module.filename);
|
||||||
|
var failures = 0;
|
||||||
|
var failed_files = {};
|
||||||
|
|
||||||
run_compress_tests();
|
run_compress_tests();
|
||||||
|
if (failures) {
|
||||||
|
sys.error("\n!!! Failed " + failures + " test cases.");
|
||||||
|
sys.error("!!! " + Object.keys(failed_files).join(", "));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var run_ast_conversion_tests = require("./mozilla-ast");
|
||||||
|
|
||||||
|
run_ast_conversion_tests({
|
||||||
|
iterations: 1000
|
||||||
|
});
|
||||||
|
|
||||||
/* -----[ utils ]----- */
|
/* -----[ utils ]----- */
|
||||||
|
|
||||||
@@ -18,7 +31,7 @@ function tmpl() {
|
|||||||
|
|
||||||
function log() {
|
function log() {
|
||||||
var txt = tmpl.apply(this, arguments);
|
var txt = tmpl.apply(this, arguments);
|
||||||
sys.puts(txt);
|
console.log("%s", txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
function log_directory(dir) {
|
function log_directory(dir) {
|
||||||
@@ -71,9 +84,17 @@ function run_compress_tests() {
|
|||||||
warnings: false
|
warnings: false
|
||||||
});
|
});
|
||||||
var cmp = new U.Compressor(options, true);
|
var cmp = new U.Compressor(options, true);
|
||||||
var expect = make_code(as_toplevel(test.expect), false);
|
var expect;
|
||||||
|
if (test.expect) {
|
||||||
|
expect = make_code(as_toplevel(test.expect), false);
|
||||||
|
} else {
|
||||||
|
expect = test.expect_exact;
|
||||||
|
}
|
||||||
var input = as_toplevel(test.input);
|
var input = as_toplevel(test.input);
|
||||||
var input_code = make_code(test.input);
|
var input_code = make_code(test.input);
|
||||||
|
if (test.mangle_props) {
|
||||||
|
input = U.mangle_properties(input, test.mangle_props);
|
||||||
|
}
|
||||||
var output = input.transform(cmp);
|
var output = input.transform(cmp);
|
||||||
output.figure_out_scope();
|
output.figure_out_scope();
|
||||||
output = make_code(output, false);
|
output = make_code(output, false);
|
||||||
@@ -83,6 +104,8 @@ function run_compress_tests() {
|
|||||||
output: output,
|
output: output,
|
||||||
expected: expect
|
expected: expect
|
||||||
});
|
});
|
||||||
|
failures++;
|
||||||
|
failed_files[file] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var tests = parse_test(path.resolve(dir, file));
|
var tests = parse_test(path.resolve(dir, file));
|
||||||
@@ -135,7 +158,7 @@ function parse_test(file) {
|
|||||||
}
|
}
|
||||||
if (node instanceof U.AST_LabeledStatement) {
|
if (node instanceof U.AST_LabeledStatement) {
|
||||||
assert.ok(
|
assert.ok(
|
||||||
node.label.name == "input" || node.label.name == "expect",
|
node.label.name == "input" || node.label.name == "expect" || node.label.name == "expect_exact",
|
||||||
tmpl("Unsupported label {name} [{line},{col}]", {
|
tmpl("Unsupported label {name} [{line},{col}]", {
|
||||||
name: node.label.name,
|
name: node.label.name,
|
||||||
line: node.label.start.line,
|
line: node.label.start.line,
|
||||||
@@ -147,7 +170,16 @@ function parse_test(file) {
|
|||||||
if (stat.body.length == 1) stat = stat.body[0];
|
if (stat.body.length == 1) stat = stat.body[0];
|
||||||
else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
|
else if (stat.body.length == 0) stat = new U.AST_EmptyStatement();
|
||||||
}
|
}
|
||||||
test[node.label.name] = stat;
|
if (node.label.name === "expect_exact") {
|
||||||
|
if (!(stat.TYPE === "SimpleStatement" && stat.body.TYPE === "String")) {
|
||||||
|
throw new Error(
|
||||||
|
"The value of the expect_exact clause should be a string, " +
|
||||||
|
"like `expect_exact: \"some.exact.javascript;\"`");
|
||||||
|
}
|
||||||
|
test[node.label.name] = stat.body.start.value
|
||||||
|
} else {
|
||||||
|
test[node.label.name] = stat;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
5603
tools/domprops.json
Normal file
5603
tools/domprops.json
Normal file
File diff suppressed because it is too large
Load Diff
17
tools/exports.js
Normal file
17
tools/exports.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
exports["Compressor"] = Compressor;
|
||||||
|
exports["DefaultsError"] = DefaultsError;
|
||||||
|
exports["Dictionary"] = Dictionary;
|
||||||
|
exports["JS_Parse_Error"] = JS_Parse_Error;
|
||||||
|
exports["MAP"] = MAP;
|
||||||
|
exports["OutputStream"] = OutputStream;
|
||||||
|
exports["SourceMap"] = SourceMap;
|
||||||
|
exports["TreeTransformer"] = TreeTransformer;
|
||||||
|
exports["TreeWalker"] = TreeWalker;
|
||||||
|
exports["base54"] = base54;
|
||||||
|
exports["defaults"] = defaults;
|
||||||
|
exports["mangle_properties"] = mangle_properties;
|
||||||
|
exports["merge"] = merge;
|
||||||
|
exports["parse"] = parse;
|
||||||
|
exports["push_uniq"] = push_uniq;
|
||||||
|
exports["string_template"] = string_template;
|
||||||
|
exports["is_identifier"] = is_identifier;
|
||||||
173
tools/node.js
173
tools/node.js
@@ -1,26 +1,5 @@
|
|||||||
var path = require("path");
|
var path = require("path");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var vm = require("vm");
|
|
||||||
var sys = require("util");
|
|
||||||
|
|
||||||
var UglifyJS = vm.createContext({
|
|
||||||
sys : sys,
|
|
||||||
console : console,
|
|
||||||
MOZ_SourceMap : require("source-map")
|
|
||||||
});
|
|
||||||
|
|
||||||
function load_global(file) {
|
|
||||||
file = path.resolve(path.dirname(module.filename), file);
|
|
||||||
try {
|
|
||||||
var code = fs.readFileSync(file, "utf8");
|
|
||||||
return vm.runInContext(code, UglifyJS, file);
|
|
||||||
} catch(ex) {
|
|
||||||
// XXX: in case of a syntax error, the message is kinda
|
|
||||||
// useless. (no location information).
|
|
||||||
sys.debug("ERROR in file: " + file + " / " + ex);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var FILES = exports.FILES = [
|
var FILES = exports.FILES = [
|
||||||
"../lib/utils.js",
|
"../lib/utils.js",
|
||||||
@@ -31,26 +10,29 @@ var FILES = exports.FILES = [
|
|||||||
"../lib/output.js",
|
"../lib/output.js",
|
||||||
"../lib/compress.js",
|
"../lib/compress.js",
|
||||||
"../lib/sourcemap.js",
|
"../lib/sourcemap.js",
|
||||||
"../lib/mozilla-ast.js"
|
"../lib/mozilla-ast.js",
|
||||||
|
"../lib/propmangle.js",
|
||||||
|
"./exports.js",
|
||||||
].map(function(file){
|
].map(function(file){
|
||||||
return path.join(path.dirname(fs.realpathSync(__filename)), file);
|
return fs.realpathSync(path.join(path.dirname(__filename), file));
|
||||||
});
|
});
|
||||||
|
|
||||||
FILES.forEach(load_global);
|
var UglifyJS = exports;
|
||||||
|
|
||||||
|
new Function("MOZ_SourceMap", "exports", FILES.map(function(file){
|
||||||
|
return fs.readFileSync(file, "utf8");
|
||||||
|
}).join("\n\n"))(
|
||||||
|
require("source-map"),
|
||||||
|
UglifyJS
|
||||||
|
);
|
||||||
|
|
||||||
UglifyJS.AST_Node.warn_function = function(txt) {
|
UglifyJS.AST_Node.warn_function = function(txt) {
|
||||||
sys.error("WARN: " + txt);
|
console.error("WARN: %s", txt);
|
||||||
};
|
};
|
||||||
|
|
||||||
// XXX: perhaps we shouldn't export everything but heck, I'm lazy.
|
|
||||||
for (var i in UglifyJS) {
|
|
||||||
if (UglifyJS.hasOwnProperty(i)) {
|
|
||||||
exports[i] = UglifyJS[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.minify = function(files, options) {
|
exports.minify = function(files, options) {
|
||||||
options = UglifyJS.defaults(options, {
|
options = UglifyJS.defaults(options, {
|
||||||
|
spidermonkey : false,
|
||||||
outSourceMap : null,
|
outSourceMap : null,
|
||||||
sourceRoot : null,
|
sourceRoot : null,
|
||||||
inSourceMap : null,
|
inSourceMap : null,
|
||||||
@@ -60,40 +42,57 @@ exports.minify = function(files, options) {
|
|||||||
output : null,
|
output : null,
|
||||||
compress : {}
|
compress : {}
|
||||||
});
|
});
|
||||||
if (typeof files == "string")
|
|
||||||
files = [ files ];
|
|
||||||
|
|
||||||
UglifyJS.base54.reset();
|
UglifyJS.base54.reset();
|
||||||
|
|
||||||
// 1. parse
|
// 1. parse
|
||||||
var toplevel = null;
|
var haveScope = false;
|
||||||
files.forEach(function(file){
|
var toplevel = null,
|
||||||
var code = options.fromString
|
sourcesContent = {};
|
||||||
? file
|
|
||||||
: fs.readFileSync(file, "utf8");
|
if (options.spidermonkey) {
|
||||||
toplevel = UglifyJS.parse(code, {
|
toplevel = UglifyJS.AST_Node.from_mozilla_ast(files);
|
||||||
filename: options.fromString ? "?" : file,
|
} else {
|
||||||
toplevel: toplevel
|
if (typeof files == "string")
|
||||||
|
files = [ files ];
|
||||||
|
files.forEach(function(file, i){
|
||||||
|
var code = options.fromString
|
||||||
|
? file
|
||||||
|
: fs.readFileSync(file, "utf8");
|
||||||
|
sourcesContent[file] = code;
|
||||||
|
toplevel = UglifyJS.parse(code, {
|
||||||
|
filename: options.fromString ? i : file,
|
||||||
|
toplevel: toplevel
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
if (options.wrap) {
|
||||||
|
toplevel = toplevel.wrap_commonjs(options.wrap, options.exportAll);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. compress
|
// 2. compress
|
||||||
if (options.compress) {
|
if (options.compress) {
|
||||||
var compress = { warnings: options.warnings };
|
var compress = { warnings: options.warnings };
|
||||||
UglifyJS.merge(compress, options.compress);
|
UglifyJS.merge(compress, options.compress);
|
||||||
toplevel.figure_out_scope();
|
toplevel.figure_out_scope();
|
||||||
|
haveScope = true;
|
||||||
var sq = UglifyJS.Compressor(compress);
|
var sq = UglifyJS.Compressor(compress);
|
||||||
toplevel = toplevel.transform(sq);
|
toplevel = toplevel.transform(sq);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. mangle
|
// 3. mangle
|
||||||
if (options.mangle) {
|
if (options.mangle) {
|
||||||
toplevel.figure_out_scope();
|
toplevel.figure_out_scope(options.mangle);
|
||||||
toplevel.compute_char_frequency();
|
haveScope = true;
|
||||||
|
toplevel.compute_char_frequency(options.mangle);
|
||||||
toplevel.mangle_names(options.mangle);
|
toplevel.mangle_names(options.mangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. output
|
// 4. scope (if needed)
|
||||||
|
if (!haveScope) {
|
||||||
|
toplevel.figure_out_scope();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. output
|
||||||
var inMap = options.inSourceMap;
|
var inMap = options.inSourceMap;
|
||||||
var output = {};
|
var output = {};
|
||||||
if (typeof options.inSourceMap == "string") {
|
if (typeof options.inSourceMap == "string") {
|
||||||
@@ -105,15 +104,33 @@ exports.minify = function(files, options) {
|
|||||||
orig: inMap,
|
orig: inMap,
|
||||||
root: options.sourceRoot
|
root: options.sourceRoot
|
||||||
});
|
});
|
||||||
|
if (options.sourceMapIncludeSources) {
|
||||||
|
for (var file in sourcesContent) {
|
||||||
|
if (sourcesContent.hasOwnProperty(file)) {
|
||||||
|
output.source_map.get().setSourceContent(file, sourcesContent[file]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (options.output) {
|
if (options.output) {
|
||||||
UglifyJS.merge(output, options.output);
|
UglifyJS.merge(output, options.output);
|
||||||
}
|
}
|
||||||
var stream = UglifyJS.OutputStream(output);
|
var stream = UglifyJS.OutputStream(output);
|
||||||
toplevel.print(stream);
|
toplevel.print(stream);
|
||||||
|
|
||||||
|
if (options.outSourceMap && "string" === typeof options.outSourceMap) {
|
||||||
|
stream += "\n//# sourceMappingURL=" + options.outSourceMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
var source_map = output.source_map;
|
||||||
|
if (source_map) {
|
||||||
|
source_map = source_map + "";
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code : stream + "",
|
code : stream + "",
|
||||||
map : output.source_map + ""
|
map : source_map
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -165,3 +182,63 @@ exports.describe_ast = function() {
|
|||||||
doitem(UglifyJS.AST_Node);
|
doitem(UglifyJS.AST_Node);
|
||||||
return out + "";
|
return out + "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function readReservedFile(filename, reserved) {
|
||||||
|
if (!reserved) {
|
||||||
|
reserved = { vars: [], props: [] };
|
||||||
|
}
|
||||||
|
var data = fs.readFileSync(filename, "utf8");
|
||||||
|
data = JSON.parse(data);
|
||||||
|
if (data.vars) {
|
||||||
|
data.vars.forEach(function(name){
|
||||||
|
UglifyJS.push_uniq(reserved.vars, name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (data.props) {
|
||||||
|
data.props.forEach(function(name){
|
||||||
|
UglifyJS.push_uniq(reserved.props, name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return reserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.readReservedFile = readReservedFile;
|
||||||
|
|
||||||
|
exports.readDefaultReservedFile = function(reserved) {
|
||||||
|
return readReservedFile(path.join(__dirname, "domprops.json"), reserved);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.readNameCache = function(filename, key) {
|
||||||
|
var cache = null;
|
||||||
|
if (filename) {
|
||||||
|
try {
|
||||||
|
var cache = fs.readFileSync(filename, "utf8");
|
||||||
|
cache = JSON.parse(cache)[key];
|
||||||
|
if (!cache) throw "init";
|
||||||
|
cache.props = UglifyJS.Dictionary.fromObject(cache.props);
|
||||||
|
} catch(ex) {
|
||||||
|
cache = {
|
||||||
|
cname: -1,
|
||||||
|
props: new UglifyJS.Dictionary()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.writeNameCache = function(filename, key, cache) {
|
||||||
|
if (filename) {
|
||||||
|
var data;
|
||||||
|
try {
|
||||||
|
data = fs.readFileSync(filename, "utf8");
|
||||||
|
data = JSON.parse(data);
|
||||||
|
} catch(ex) {
|
||||||
|
data = {};
|
||||||
|
}
|
||||||
|
data[key] = {
|
||||||
|
cname: cache.cname,
|
||||||
|
props: cache.props.toObject()
|
||||||
|
};
|
||||||
|
fs.writeFileSync(filename, JSON.stringify(data, null, 2), "utf8");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
61
tools/props.html
Normal file
61
tools/props.html
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>(function(){
|
||||||
|
var props = {};
|
||||||
|
|
||||||
|
function addObject(obj) {
|
||||||
|
if (obj == null) return;
|
||||||
|
try {
|
||||||
|
Object.getOwnPropertyNames(obj).forEach(add);
|
||||||
|
} catch(ex) {}
|
||||||
|
if (obj.prototype) {
|
||||||
|
Object.getOwnPropertyNames(obj.prototype).forEach(add);
|
||||||
|
}
|
||||||
|
if (typeof obj == "function") {
|
||||||
|
try {
|
||||||
|
Object.getOwnPropertyNames(new obj).forEach(add);
|
||||||
|
} catch(ex) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(name) {
|
||||||
|
props[name] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.getOwnPropertyNames(window).forEach(function(thing){
|
||||||
|
addObject(window[thing]);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
addObject(new Event("click"));
|
||||||
|
addObject(new Event("contextmenu"));
|
||||||
|
addObject(new Event("mouseup"));
|
||||||
|
addObject(new Event("mousedown"));
|
||||||
|
addObject(new Event("keydown"));
|
||||||
|
addObject(new Event("keypress"));
|
||||||
|
addObject(new Event("keyup"));
|
||||||
|
} catch(ex) {}
|
||||||
|
|
||||||
|
var ta = document.createElement("textarea");
|
||||||
|
ta.style.width = "100%";
|
||||||
|
ta.style.height = "20em";
|
||||||
|
ta.style.boxSizing = "border-box";
|
||||||
|
<!-- ta.value = Object.keys(props).sort(cmp).map(function(name){ -->
|
||||||
|
<!-- return JSON.stringify(name); -->
|
||||||
|
<!-- }).join(",\n"); -->
|
||||||
|
ta.value = JSON.stringify({
|
||||||
|
vars: [],
|
||||||
|
props: Object.keys(props).sort(cmp)
|
||||||
|
}, null, 2);
|
||||||
|
document.body.appendChild(ta);
|
||||||
|
|
||||||
|
function cmp(a, b) {
|
||||||
|
a = a.toLowerCase();
|
||||||
|
b = b.toLowerCase();
|
||||||
|
return a < b ? -1 : a > b ? 1 : 0;
|
||||||
|
}
|
||||||
|
})();</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user