Compare commits
211 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
614db97cca | ||
|
|
d854523783 | ||
|
|
781f26eda1 | ||
|
|
37f4395cc0 | ||
|
|
de619ae5a6 | ||
|
|
86859f6d7e | ||
|
|
dcdcfe4d39 | ||
|
|
72306b9885 | ||
|
|
38756b1f26 | ||
|
|
85a09fc3b6 | ||
|
|
307b88d6cc | ||
|
|
fb049d3a81 | ||
|
|
67cca43358 | ||
|
|
642273c290 | ||
|
|
e8b23c7798 | ||
|
|
9edbe93df5 | ||
|
|
af37ecafe1 | ||
|
|
41a9329409 | ||
|
|
7eb52d2837 | ||
|
|
eb63fece2f | ||
|
|
2d8af8947e | ||
|
|
2650182f47 | ||
|
|
572b97b0bb | ||
|
|
698705a820 | ||
|
|
debc525fa1 | ||
|
|
5576e2737a | ||
|
|
b40d5de69c | ||
|
|
b7ef7840f3 | ||
|
|
85924bb32e | ||
|
|
a97690fc72 | ||
|
|
02c638209e | ||
|
|
030611b729 | ||
|
|
335b72df03 | ||
|
|
3a7d53f3cf | ||
|
|
9676167aac | ||
|
|
1840a0b282 | ||
|
|
ace8aaa0f4 | ||
|
|
0c003c92a8 | ||
|
|
85fbf86d7b | ||
|
|
aa82027a17 | ||
|
|
55c592dd43 | ||
|
|
fc1abd1c11 | ||
|
|
e645ba84cf | ||
|
|
6c99816855 | ||
|
|
2149bfb707 | ||
|
|
d7971ba0e4 | ||
|
|
5c4cfaa0a7 | ||
|
|
bb9c9707aa | ||
|
|
6c8e001fee | ||
|
|
9c53c7ada7 | ||
|
|
f99b7b630d | ||
|
|
ea31da2455 | ||
|
|
4d7746baf3 | ||
|
|
31d5825a86 | ||
|
|
8287ef6781 | ||
|
|
5cb5305cf3 | ||
|
|
00ad57e393 | ||
|
|
09d5707a8a | ||
|
|
1e390269d4 | ||
|
|
bc49dfd27a | ||
|
|
27eedbc302 | ||
|
|
5f464b41e2 | ||
|
|
bcc1318d4b | ||
|
|
a0e03c9df4 | ||
|
|
6641dcafb6 | ||
|
|
d2945744f2 | ||
|
|
35bc716625 | ||
|
|
f39fd3d583 | ||
|
|
65887d9a56 | ||
|
|
e9224ab444 | ||
|
|
4d9a085687 | ||
|
|
4fe630431c | ||
|
|
c55dd5ed74 | ||
|
|
e4fa4b109a | ||
|
|
4b4528ee05 | ||
|
|
187a0caf9d | ||
|
|
b5a7a231f7 | ||
|
|
3907a5e3b2 | ||
|
|
b434b75b36 | ||
|
|
c70d176f35 | ||
|
|
9317237372 | ||
|
|
98434258d0 | ||
|
|
45ddb9caeb | ||
|
|
9bcf702a6e | ||
|
|
f68de86a17 | ||
|
|
c3c7587796 | ||
|
|
07bb7262d0 | ||
|
|
21befe583f | ||
|
|
a9d4a6291b | ||
|
|
ee6c9fabb7 | ||
|
|
102d1b9137 | ||
|
|
294861ba96 | ||
|
|
11b0efdf84 | ||
|
|
5486b68850 | ||
|
|
bdd8e34f63 | ||
|
|
6547437725 | ||
|
|
9662228f6a | ||
|
|
31a9b05c96 | ||
|
|
63b01fe8f9 | ||
|
|
7a4ed9d200 | ||
|
|
d5c651a5e5 | ||
|
|
cdba43cfa4 | ||
|
|
a123e232b9 | ||
|
|
601780acc1 | ||
|
|
7c3fee9e31 | ||
|
|
929de2b0de | ||
|
|
12e6ad326c | ||
|
|
00c8d1d241 | ||
|
|
af2472d85e | ||
|
|
3eb9101918 | ||
|
|
0a38a688f9 | ||
|
|
f4c2ea37bf | ||
|
|
915f907186 | ||
|
|
799509e145 | ||
|
|
b5a7197ae5 | ||
|
|
1b703349cf | ||
|
|
4a7179ff91 | ||
|
|
f97da4294a | ||
|
|
918c17bd88 | ||
|
|
8b71c6559b | ||
|
|
26641f3fb2 | ||
|
|
ebe118dc79 | ||
|
|
70e5b6f15b | ||
|
|
57e0fafd5c | ||
|
|
8439c8ba98 | ||
|
|
5c4e470d43 | ||
|
|
6605d15783 | ||
|
|
ac8db977b9 | ||
|
|
88b77ddaa9 | ||
|
|
fe4e9f9d97 | ||
|
|
8c6af09ae0 | ||
|
|
6f3e35bb3f | ||
|
|
174404c0f3 | ||
|
|
60c4030a4d | ||
|
|
ac810dc07a | ||
|
|
0cabedc526 | ||
|
|
5cd26c005b | ||
|
|
bd99b00413 | ||
|
|
9e2f9f7910 | ||
|
|
e87c77ed41 | ||
|
|
774bda13cd | ||
|
|
15b5f70338 | ||
|
|
7f48d5b33c | ||
|
|
b6968b6bd2 | ||
|
|
08b80302eb | ||
|
|
645626ebe8 | ||
|
|
d895c09c70 | ||
|
|
08623aa6a7 | ||
|
|
c898a26117 | ||
|
|
619adb0308 | ||
|
|
7691bebea5 | ||
|
|
3c4346728e | ||
|
|
18d37ac761 | ||
|
|
63d35f8f6d | ||
|
|
7dbe961b2d | ||
|
|
94c4daaf9e | ||
|
|
37ee9de902 | ||
|
|
83db98ad3b | ||
|
|
bd0ae6569f | ||
|
|
841a661071 | ||
|
|
7491d07666 | ||
|
|
335e349314 | ||
|
|
2a88d07b3a | ||
|
|
a887cde9f2 | ||
|
|
b5623b19d4 | ||
|
|
6b2861e086 | ||
|
|
d5138f7467 | ||
|
|
eac67b2816 | ||
|
|
ce10072824 | ||
|
|
dff54a6552 | ||
|
|
1940fb682c | ||
|
|
17eef5a3c2 | ||
|
|
9f1f21b810 | ||
|
|
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 | ||
|
|
4fba3e0b80 | ||
|
|
65ee5af78c |
@@ -1,10 +1,10 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
before_install: "npm install -g npm"
|
before_install: "npm install -g npm"
|
||||||
node_js:
|
node_js:
|
||||||
- "iojs"
|
|
||||||
- "0.12"
|
- "0.12"
|
||||||
- "0.11"
|
|
||||||
- "0.10"
|
- "0.10"
|
||||||
|
- "4"
|
||||||
|
- "6"
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
sudo: false
|
sudo: false
|
||||||
|
|||||||
163
README.md
163
README.md
@@ -65,9 +65,11 @@ The available options are:
|
|||||||
--in-source-map Input source map, useful if you're compressing
|
--in-source-map Input source map, useful if you're compressing
|
||||||
JS that was generated from some other original
|
JS that was generated from some other original
|
||||||
code.
|
code.
|
||||||
--screw-ie8 Pass this flag if you don't care about full
|
--screw-ie8 Use this flag if you don't wish to support
|
||||||
compliance with Internet Explorer 6-8 quirks
|
Internet Explorer 6-8 quirks.
|
||||||
(by default UglifyJS will try to be IE-proof).
|
By default UglifyJS will not try to be IE-proof.
|
||||||
|
--support-ie8 Use this flag to support Internet Explorer 6-8 quirks.
|
||||||
|
Note: may break standards compliant `catch` identifiers.
|
||||||
--expr Parse a single expression, rather than a
|
--expr Parse a single expression, rather than a
|
||||||
program (for parsing JSON)
|
program (for parsing JSON)
|
||||||
-p, --prefix Skip prefix for original filenames that appear
|
-p, --prefix Skip prefix for original filenames that appear
|
||||||
@@ -125,15 +127,28 @@ The available options are:
|
|||||||
--noerr Don't throw an error for unknown options in -c,
|
--noerr Don't throw an error for unknown options in -c,
|
||||||
-b or -m.
|
-b or -m.
|
||||||
--bare-returns Allow return outside of functions. Useful when
|
--bare-returns Allow return outside of functions. Useful when
|
||||||
minifying CommonJS modules.
|
minifying CommonJS modules and Userscripts that
|
||||||
|
may be anonymous function wrapped (IIFE) by the
|
||||||
|
.user.js engine `caller`.
|
||||||
--keep-fnames Do not mangle/drop function names. Useful for
|
--keep-fnames Do not mangle/drop function names. Useful for
|
||||||
code relying on Function.prototype.name.
|
code relying on Function.prototype.name.
|
||||||
--reserved-file File containing reserved names
|
--reserved-file File containing reserved names
|
||||||
--reserve-domprops Make (most?) DOM properties reserved for
|
--reserve-domprops Make (most?) DOM properties reserved for
|
||||||
--mangle-props
|
--mangle-props
|
||||||
--mangle-props Mangle property names
|
--mangle-props Mangle property names (default `0`). Set to
|
||||||
|
`true` or `1` to mangle all property names. Set
|
||||||
|
to `unquoted` or `2` to only mangle unquoted
|
||||||
|
property names. Mode `2` also enables the
|
||||||
|
`keep_quoted_props` beautifier option to
|
||||||
|
preserve the quotes around property names and
|
||||||
|
disables the `properties` compressor option to
|
||||||
|
prevent rewriting quoted properties with dot
|
||||||
|
notation. You can override these by setting
|
||||||
|
them explicitly on the command line.
|
||||||
--mangle-regex Only mangle property names matching the regex
|
--mangle-regex Only mangle property names matching the regex
|
||||||
--name-cache File to hold mangled names mappings
|
--name-cache File to hold mangled names mappings
|
||||||
|
--pure-funcs List of functions that can be safely removed if
|
||||||
|
their return value is not used [array]
|
||||||
```
|
```
|
||||||
|
|
||||||
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
||||||
@@ -188,11 +203,6 @@ input files from the command line.
|
|||||||
To enable the mangler you need to pass `--mangle` (`-m`). The following
|
To enable the mangler you need to pass `--mangle` (`-m`). The following
|
||||||
(comma-separated) options are supported:
|
(comma-separated) options are supported:
|
||||||
|
|
||||||
- `sort` — to assign shorter names to most frequently used variables. This
|
|
||||||
saves a few hundred bytes on jQuery before gzip, but the output is
|
|
||||||
_bigger_ after gzip (and seems to happen for other libraries I tried it
|
|
||||||
on) therefore it's not enabled by default.
|
|
||||||
|
|
||||||
- `toplevel` — mangle names declared in the toplevel scope (disabled by
|
- `toplevel` — mangle names declared in the toplevel scope (disabled by
|
||||||
default).
|
default).
|
||||||
|
|
||||||
@@ -281,7 +291,14 @@ you can pass a comma-separated list of options. Options are in the form
|
|||||||
`foo=bar`, or just `foo` (the latter implies a boolean option that you want
|
`foo=bar`, or just `foo` (the latter implies a boolean option that you want
|
||||||
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` (default: true) -- join consecutive simple statements using the
|
||||||
|
comma operator. May be set to a positive integer to specify the maximum number
|
||||||
|
of consecutive comma sequences that will be generated. If this option is set to
|
||||||
|
`true` then the default `sequences` limit is `200`. Set option to `false` or `0`
|
||||||
|
to disable. The smallest `sequences` length is `2`. A `sequences` value of `1`
|
||||||
|
is grandfathered to be equivalent to `true` and as such means `200`. On rare
|
||||||
|
occasions the default sequences limit leads to very slow compress times in which
|
||||||
|
case a value of `20` or less is recommended.
|
||||||
|
|
||||||
- `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`
|
||||||
@@ -292,12 +309,19 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
|||||||
|
|
||||||
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
|
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
|
||||||
|
|
||||||
|
- `unsafe_comps` (default: false) -- Reverse `<` and `<=` to `>` and `>=` to
|
||||||
|
allow improved compression. This might be unsafe when an at least one of two
|
||||||
|
operands is an object with computed values due the use of methods like `get`,
|
||||||
|
or `valueOf`. This could cause change in execution order after operands in the
|
||||||
|
comparison are switching. Compression only works if both `comparisons` and
|
||||||
|
`unsafe_comps` are both set to true.
|
||||||
|
|
||||||
- `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_comps`), attempts to negate binary
|
||||||
e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
|
nodes, 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
|
||||||
|
|
||||||
@@ -321,6 +345,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
|||||||
- `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()`
|
||||||
|
|
||||||
|
- `collapse_vars` -- default `false`. Collapse single-use `var` and `const`
|
||||||
|
definitions when possible.
|
||||||
|
|
||||||
- `warnings` -- display warnings when dropping unreachable code or unused
|
- `warnings` -- display warnings when dropping unreachable code or unused
|
||||||
declarations etc.
|
declarations etc.
|
||||||
|
|
||||||
@@ -346,10 +373,18 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
|||||||
- `drop_console` -- default `false`. Pass `true` to discard calls to
|
- `drop_console` -- default `false`. Pass `true` to discard calls to
|
||||||
`console.*` functions.
|
`console.*` functions.
|
||||||
|
|
||||||
- `keep_fargs` -- default `false`. Pass `true` to prevent the
|
- `keep_fargs` -- default `true`. Prevents the
|
||||||
compressor from discarding unused function arguments. You need this
|
compressor from discarding unused function arguments. You need this
|
||||||
for code which relies on `Function.length`.
|
for code which relies on `Function.length`.
|
||||||
|
|
||||||
|
- `keep_fnames` -- default `false`. Pass `true` to prevent the
|
||||||
|
compressor from discarding function names. Useful for code relying on
|
||||||
|
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
||||||
|
|
||||||
|
- `passes` -- default `1`. Number of times to run compress. Use an
|
||||||
|
integer argument larger than 1 to further reduce code size in some cases.
|
||||||
|
Note: raising the number of passes will increase uglify compress time.
|
||||||
|
|
||||||
### 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
|
||||||
@@ -365,7 +400,6 @@ when this flag is on:
|
|||||||
- `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
|
||||||
|
|
||||||
@@ -389,6 +423,8 @@ separate file and include it into the build. For example you can have a
|
|||||||
```javascript
|
```javascript
|
||||||
const DEBUG = false;
|
const DEBUG = false;
|
||||||
const PRODUCTION = true;
|
const PRODUCTION = true;
|
||||||
|
// Alternative for environments that don't support `const`
|
||||||
|
/** @const */ var STAGING = false;
|
||||||
// etc.
|
// etc.
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -398,10 +434,26 @@ and build your code like this:
|
|||||||
|
|
||||||
UglifyJS will notice the constants and, since they cannot be altered, it
|
UglifyJS will notice the constants and, since they cannot be altered, it
|
||||||
will evaluate references to them to the value itself and drop unreachable
|
will evaluate references to them to the value itself and drop unreachable
|
||||||
code as usual. The possible downside of this approach is that the build
|
code as usual. The build will contain the `const` declarations if you use
|
||||||
will contain the `const` declarations.
|
them. If you are targeting < ES6 environments, use `/** @const */ var`.
|
||||||
|
|
||||||
<a name="codegen-options"></a>
|
<a name="codegen-options"></a>
|
||||||
|
|
||||||
|
#### Conditional compilation, API
|
||||||
|
You can also use conditional compilation via the programmatic API. With the difference that the
|
||||||
|
property name is `global_defs` and is a compressor property:
|
||||||
|
|
||||||
|
```js
|
||||||
|
uglifyJS.minify([ "input.js"], {
|
||||||
|
compress: {
|
||||||
|
dead_code: true,
|
||||||
|
global_defs: {
|
||||||
|
DEBUG: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## Beautifier options
|
## Beautifier options
|
||||||
|
|
||||||
The code generator tries to output shortest code possible by default. In
|
The code generator tries to output shortest code possible by default. In
|
||||||
@@ -418,7 +470,7 @@ can pass additional arguments that control the code output:
|
|||||||
objects
|
objects
|
||||||
- `space-colon` (default `true`) -- insert a space after the colon signs
|
- `space-colon` (default `true`) -- insert a space after the colon signs
|
||||||
- `ascii-only` (default `false`) -- escape Unicode characters in strings and
|
- `ascii-only` (default `false`) -- escape Unicode characters in strings and
|
||||||
regexps
|
regexps (affects directives with non-ascii characters becoming invalid)
|
||||||
- `inline-script` (default `false`) -- escape the slash in occurrences of
|
- `inline-script` (default `false`) -- escape the slash in occurrences of
|
||||||
`</script` in strings
|
`</script` in strings
|
||||||
- `width` (default 80) -- only takes effect when beautification is on, this
|
- `width` (default 80) -- only takes effect when beautification is on, this
|
||||||
@@ -445,6 +497,8 @@ can pass additional arguments that control the code output:
|
|||||||
- `1` -- always use single quotes
|
- `1` -- always use single quotes
|
||||||
- `2` -- always use double quotes
|
- `2` -- always use double quotes
|
||||||
- `3` -- always use the original quotes
|
- `3` -- always use the original quotes
|
||||||
|
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
||||||
|
quotes from property names in object literals.
|
||||||
|
|
||||||
### Keeping copyright notices or other comments
|
### Keeping copyright notices or other comments
|
||||||
|
|
||||||
@@ -574,6 +628,14 @@ console.log(result.code); // minified output
|
|||||||
console.log(result.map);
|
console.log(result.map);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To generate a source map with the fromString option, you can also use an object:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify({"file1.js": "var a = function () {};"}, {
|
||||||
|
outSourceMap: "out.js.map",
|
||||||
|
fromString: true
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
Note that the source map is not saved in a file, it's just returned in
|
Note that the source map is not saved in a file, it's just returned in
|
||||||
`result.map`. The value passed for `outSourceMap` is only used to set the
|
`result.map`. The value passed for `outSourceMap` is only used to set the
|
||||||
`file` attribute in the source map (see [the spec][sm-spec]).
|
`file` attribute in the source map (see [the spec][sm-spec]).
|
||||||
@@ -609,6 +671,17 @@ var result = UglifyJS.minify("compiled.js", {
|
|||||||
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).
|
||||||
|
|
||||||
|
To set the source map url, use the `sourceMapUrl` option.
|
||||||
|
If you're using the X-SourceMap header instead, you can just set the `sourceMapUrl` option to false.
|
||||||
|
Defaults to outSourceMap:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify([ "file1.js" ], {
|
||||||
|
outSourceMap: "out.js.map",
|
||||||
|
sourceMapUrl: "localhost/out.js.map"
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
Other options:
|
Other options:
|
||||||
|
|
||||||
- `warnings` (default `false`) — pass `true` to display compressor warnings.
|
- `warnings` (default `false`) — pass `true` to display compressor warnings.
|
||||||
@@ -616,7 +689,11 @@ Other options:
|
|||||||
- `fromString` (default `false`) — if you pass `true` then you can pass
|
- `fromString` (default `false`) — if you pass `true` then you can pass
|
||||||
JavaScript source code, rather than file names.
|
JavaScript source code, rather than file names.
|
||||||
|
|
||||||
- `mangle` — pass `false` to skip mangling names.
|
- `mangle` (default `true`) — pass `false` to skip mangling names, or pass
|
||||||
|
an object to specify mangling options (see below).
|
||||||
|
|
||||||
|
- `mangleProperties` (default `false`) — pass an object to specify custom
|
||||||
|
mangle property options.
|
||||||
|
|
||||||
- `output` (default `null`) — pass an object if you wish to specify
|
- `output` (default `null`) — pass an object if you wish to specify
|
||||||
additional [output options][codegen]. The defaults are optimized
|
additional [output options][codegen]. The defaults are optimized
|
||||||
@@ -625,6 +702,48 @@ Other options:
|
|||||||
- `compress` (default `{}`) — pass `false` to skip compressing entirely.
|
- `compress` (default `{}`) — pass `false` to skip compressing entirely.
|
||||||
Pass an object to specify custom [compressor options][compressor].
|
Pass an object to specify custom [compressor options][compressor].
|
||||||
|
|
||||||
|
- `parse` (default {}) — pass an object if you wish to specify some
|
||||||
|
additional [parser options][parser]. (not all options available... see below)
|
||||||
|
|
||||||
|
##### mangle
|
||||||
|
|
||||||
|
- `except` - pass an array of identifiers that should be excluded from mangling
|
||||||
|
|
||||||
|
- `toplevel` — mangle names declared in the toplevel scope (disabled by
|
||||||
|
default).
|
||||||
|
|
||||||
|
- `eval` — mangle names visible in scopes where eval or with are used
|
||||||
|
(disabled by default).
|
||||||
|
|
||||||
|
- `keep_fnames` -- default `false`. Pass `true` to not mangle
|
||||||
|
function names. Useful for code relying on `Function.prototype.name`.
|
||||||
|
See also: the `keep_fnames` [compress option](#compressor-options).
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
//tst.js
|
||||||
|
var globalVar;
|
||||||
|
function funcName(firstLongName, anotherLongName)
|
||||||
|
{
|
||||||
|
var myVariable = firstLongName + anotherLongName;
|
||||||
|
}
|
||||||
|
|
||||||
|
UglifyJS.minify("tst.js").code;
|
||||||
|
// 'function funcName(a,n){}var globalVar;'
|
||||||
|
|
||||||
|
UglifyJS.minify("tst.js", { mangle: { except: ['firstLongName'] } }).code;
|
||||||
|
// 'function funcName(firstLongName,a){}var globalVar;'
|
||||||
|
|
||||||
|
UglifyJS.minify("tst.js", { mangle: { toplevel: true } }).code;
|
||||||
|
// 'function n(n,a){}var a;'
|
||||||
|
```
|
||||||
|
|
||||||
|
##### mangleProperties options
|
||||||
|
|
||||||
|
- `regex` — Pass a RegExp to only mangle certain names (maps to the `--mangle-regex` CLI arguments option)
|
||||||
|
- `ignore_quoted` – Only mangle unquoted property names (maps to the `--mangle-props 2` CLI arguments option)
|
||||||
|
|
||||||
We could add more options to `UglifyJS.minify` — if you need additional
|
We could add more options to `UglifyJS.minify` — if you need additional
|
||||||
functionality please suggest!
|
functionality please suggest!
|
||||||
|
|
||||||
@@ -643,6 +762,9 @@ properties are available:
|
|||||||
|
|
||||||
- `strict` — disable automatic semicolon insertion and support for trailing
|
- `strict` — disable automatic semicolon insertion and support for trailing
|
||||||
comma in arrays and objects
|
comma in arrays and objects
|
||||||
|
- `bare_returns` — Allow return outside of functions. (maps to the
|
||||||
|
`--bare-returns` CLI arguments option and available to `minify` `parse`
|
||||||
|
other options object)
|
||||||
- `filename` — the name of the file where this code is coming from
|
- `filename` — the name of the file where this code is coming from
|
||||||
- `toplevel` — a `toplevel` node (as returned by a previous invocation of
|
- `toplevel` — a `toplevel` node (as returned by a previous invocation of
|
||||||
`parse`)
|
`parse`)
|
||||||
@@ -777,8 +899,9 @@ The `source_map_options` (optional) can contain the following properties:
|
|||||||
came from. It can be simply a string in JSON, or a JSON object containing
|
came from. It can be simply a string in JSON, or a JSON object containing
|
||||||
the original source map.
|
the original source map.
|
||||||
|
|
||||||
[acorn]: https://github.com/marijnh/acorn
|
[acorn]: https://github.com/ternjs/acorn
|
||||||
[source-map]: https://github.com/mozilla/source-map
|
[source-map]: https://github.com/mozilla/source-map
|
||||||
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
|
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit
|
||||||
[codegen]: http://lisperator.net/uglifyjs/codegen
|
[codegen]: http://lisperator.net/uglifyjs/codegen
|
||||||
[compressor]: http://lisperator.net/uglifyjs/compress
|
[compressor]: http://lisperator.net/uglifyjs/compress
|
||||||
|
[parser]: http://lisperator.net/uglifyjs/parser
|
||||||
|
|||||||
24
appveyor.yml
Normal file
24
appveyor.yml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- nodejs_version: "0.10"
|
||||||
|
- nodejs_version: "0.12"
|
||||||
|
- nodejs_version: "4.0"
|
||||||
|
- nodejs_version: "6.0"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
platform:
|
||||||
|
- x86
|
||||||
|
- x64
|
||||||
|
|
||||||
|
install:
|
||||||
|
- ps: Install-Product node $env:nodejs_version $env:platform
|
||||||
|
- npm install
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- node --version
|
||||||
|
- npm --version
|
||||||
|
- npm test
|
||||||
|
|
||||||
|
build: off
|
||||||
114
bin/uglifyjs
114
bin/uglifyjs
@@ -10,6 +10,7 @@ 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 screw_ie8 = true;
|
||||||
var ARGS = yargs
|
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.\
|
||||||
@@ -24,7 +25,8 @@ mangling you need to use `-c` and `-m`.\
|
|||||||
.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("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", "Do not support Internet Explorer 6-8 quirks. This flag is enabled by default.")
|
||||||
|
.describe("support-ie8", "Support non-standard Internet Explorer 6-8 javascript. Note: may break standards compliant `catch` identifiers.")
|
||||||
.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)")
|
||||||
.describe("p", "Skip prefix for original filenames that appear in source maps. \
|
.describe("p", "Skip prefix for original filenames that appear in source maps. \
|
||||||
For example -p 3 will drop 3 directories from file names and ensure they are relative paths. \
|
For example -p 3 will drop 3 directories from file names and ensure they are relative paths. \
|
||||||
@@ -69,9 +71,11 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)")
|
.describe("quotes", "Quote style (0 - auto, 1 - single, 2 - double, 3 - original)")
|
||||||
.describe("reserved-file", "File containing reserved names")
|
.describe("reserved-file", "File containing reserved names")
|
||||||
.describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props")
|
.describe("reserve-domprops", "Make (most?) DOM properties reserved for --mangle-props")
|
||||||
.describe("mangle-props", "Mangle property names")
|
.describe("mangle-props", "Mangle property names (0 - disabled, 1 - mangle all properties, 2 - mangle unquoted properies)")
|
||||||
.describe("mangle-regex", "Only mangle property names matching the regex")
|
.describe("mangle-regex", "Only mangle property names matching the regex")
|
||||||
.describe("name-cache", "File to hold mangled names mappings")
|
.describe("name-cache", "File to hold mangled names mappings")
|
||||||
|
.describe("pure-funcs", "List of functions that can be safely removed if their return value is not used")
|
||||||
|
.describe("dump-spidermonkey-ast", "Dump SpiderMonkey AST to stdout.")
|
||||||
|
|
||||||
.alias("p", "prefix")
|
.alias("p", "prefix")
|
||||||
.alias("o", "output")
|
.alias("o", "output")
|
||||||
@@ -103,11 +107,14 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.string("p")
|
.string("p")
|
||||||
.string("prefix")
|
.string("prefix")
|
||||||
.string("name-cache")
|
.string("name-cache")
|
||||||
|
|
||||||
.array("reserved-file")
|
.array("reserved-file")
|
||||||
|
.array("pure-funcs")
|
||||||
|
|
||||||
.boolean("expr")
|
.boolean("expr")
|
||||||
.boolean("source-map-include-sources")
|
.boolean("source-map-include-sources")
|
||||||
.boolean("screw-ie8")
|
.boolean("screw-ie8")
|
||||||
|
.boolean("support-ie8")
|
||||||
.boolean("export-all")
|
.boolean("export-all")
|
||||||
.boolean("self")
|
.boolean("self")
|
||||||
.boolean("v")
|
.boolean("v")
|
||||||
@@ -115,13 +122,13 @@ You need to pass an argument to this option to specify the name that your module
|
|||||||
.boolean("stats")
|
.boolean("stats")
|
||||||
.boolean("acorn")
|
.boolean("acorn")
|
||||||
.boolean("spidermonkey")
|
.boolean("spidermonkey")
|
||||||
|
.boolean("dump-spidermonkey-ast")
|
||||||
.boolean("lint")
|
.boolean("lint")
|
||||||
.boolean("V")
|
.boolean("V")
|
||||||
.boolean("version")
|
.boolean("version")
|
||||||
.boolean("noerr")
|
.boolean("noerr")
|
||||||
.boolean("bare-returns")
|
.boolean("bare-returns")
|
||||||
.boolean("keep-fnames")
|
.boolean("keep-fnames")
|
||||||
.boolean("mangle-props")
|
|
||||||
.boolean("reserve-domprops")
|
.boolean("reserve-domprops")
|
||||||
|
|
||||||
.wrap(80)
|
.wrap(80)
|
||||||
@@ -175,6 +182,10 @@ if (ARGS.d) {
|
|||||||
if (COMPRESS) COMPRESS.global_defs = getOptions("d");
|
if (COMPRESS) COMPRESS.global_defs = getOptions("d");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ARGS.pure_funcs) {
|
||||||
|
if (COMPRESS) COMPRESS.pure_funcs = ARGS.pure_funcs;
|
||||||
|
}
|
||||||
|
|
||||||
if (ARGS.r) {
|
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*/);
|
||||||
}
|
}
|
||||||
@@ -205,18 +216,32 @@ if (ARGS.quotes === true) {
|
|||||||
ARGS.quotes = 3;
|
ARGS.quotes = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ARGS.mangle_props === true) {
|
||||||
|
ARGS.mangle_props = 1;
|
||||||
|
} else if (ARGS.mangle_props === "unquoted") {
|
||||||
|
ARGS.mangle_props = 2;
|
||||||
|
}
|
||||||
|
|
||||||
var OUTPUT_OPTIONS = {
|
var OUTPUT_OPTIONS = {
|
||||||
beautify : BEAUTIFY ? true : false,
|
beautify : BEAUTIFY ? true : false,
|
||||||
preamble : ARGS.preamble || null,
|
preamble : ARGS.preamble || null,
|
||||||
quote_style : ARGS.quotes != null ? ARGS.quotes : 0
|
quote_style : ARGS.quotes != null ? ARGS.quotes : 0
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ARGS.screw_ie8) {
|
if (ARGS.mangle_props == 2) {
|
||||||
if (COMPRESS) COMPRESS.screw_ie8 = true;
|
OUTPUT_OPTIONS.keep_quoted_props = true;
|
||||||
if (MANGLE) MANGLE.screw_ie8 = true;
|
if (COMPRESS && !("properties" in COMPRESS))
|
||||||
OUTPUT_OPTIONS.screw_ie8 = true;
|
COMPRESS.properties = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ARGS.support_ie8 === true && ARGS.screw_ie8 !== true) {
|
||||||
|
screw_ie8 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (COMPRESS) COMPRESS.screw_ie8 = screw_ie8;
|
||||||
|
if (MANGLE) MANGLE.screw_ie8 = screw_ie8;
|
||||||
|
OUTPUT_OPTIONS.screw_ie8 = screw_ie8;
|
||||||
|
|
||||||
if (ARGS.keep_fnames) {
|
if (ARGS.keep_fnames) {
|
||||||
if (COMPRESS) COMPRESS.keep_fnames = true;
|
if (COMPRESS) COMPRESS.keep_fnames = true;
|
||||||
if (MANGLE) MANGLE.keep_fnames = true;
|
if (MANGLE) MANGLE.keep_fnames = true;
|
||||||
@@ -248,13 +273,15 @@ if (ARGS.comments != null) {
|
|||||||
|
|
||||||
var files = ARGS._.slice();
|
var files = ARGS._.slice();
|
||||||
|
|
||||||
|
if (process.platform === "win32")
|
||||||
|
files = UglifyJS.simple_glob(files);
|
||||||
|
|
||||||
if (ARGS.self) {
|
if (ARGS.self) {
|
||||||
if (files.length > 0) {
|
if (files.length > 0) {
|
||||||
print_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;
|
||||||
@@ -394,20 +421,21 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
|
TOPLEVEL = UglifyJS.mangle_properties(TOPLEVEL, {
|
||||||
reserved : reserved,
|
reserved : reserved,
|
||||||
cache : cache,
|
cache : cache,
|
||||||
only_cache : !ARGS.mangle_props,
|
only_cache : !ARGS.mangle_props,
|
||||||
regex : regex
|
regex : regex,
|
||||||
|
ignore_quoted : ARGS.mangle_props == 2
|
||||||
});
|
});
|
||||||
writeNameCache("props", cache);
|
writeNameCache("props", cache);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint;
|
var SCOPE_IS_NEEDED = COMPRESS || MANGLE || ARGS.lint
|
||||||
var TL_CACHE = readNameCache("vars");
|
var TL_CACHE = readNameCache("vars");
|
||||||
|
|
||||||
if (SCOPE_IS_NEEDED) {
|
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: screw_ie8, cache: TL_CACHE });
|
||||||
if (ARGS.lint) {
|
if (ARGS.lint) {
|
||||||
TOPLEVEL.scope_warnings();
|
TOPLEVEL.scope_warnings();
|
||||||
}
|
}
|
||||||
@@ -416,13 +444,13 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
|
|
||||||
if (COMPRESS) {
|
if (COMPRESS) {
|
||||||
time_it("squeeze", function(){
|
time_it("squeeze", function(){
|
||||||
TOPLEVEL = TOPLEVEL.transform(compressor);
|
TOPLEVEL = compressor.compress(TOPLEVEL);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCOPE_IS_NEEDED) {
|
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: screw_ie8, cache: TL_CACHE });
|
||||||
if (MANGLE && !TL_CACHE) {
|
if (MANGLE && !TL_CACHE) {
|
||||||
TOPLEVEL.compute_char_frequency(MANGLE);
|
TOPLEVEL.compute_char_frequency(MANGLE);
|
||||||
}
|
}
|
||||||
@@ -444,26 +472,30 @@ async.eachLimit(files, 1, function (file, cb) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
time_it("generate", function(){
|
if (ARGS.dump_spidermonkey_ast) {
|
||||||
TOPLEVEL.print(output);
|
print(JSON.stringify(TOPLEVEL.to_mozilla_ast(), null, 2));
|
||||||
});
|
|
||||||
|
|
||||||
output = output.get();
|
|
||||||
|
|
||||||
if (SOURCE_MAP) {
|
|
||||||
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
|
|
||||||
var source_map_url = ARGS.source_map_url || (
|
|
||||||
P_RELATIVE
|
|
||||||
? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map)
|
|
||||||
: ARGS.source_map
|
|
||||||
);
|
|
||||||
output += "\n//# sourceMappingURL=" + source_map_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OUTPUT_FILE) {
|
|
||||||
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
|
|
||||||
} else {
|
} else {
|
||||||
print(output);
|
time_it("generate", function(){
|
||||||
|
TOPLEVEL.print(output);
|
||||||
|
});
|
||||||
|
|
||||||
|
output = output.get();
|
||||||
|
|
||||||
|
if (SOURCE_MAP) {
|
||||||
|
fs.writeFileSync(ARGS.source_map, SOURCE_MAP, "utf8");
|
||||||
|
var source_map_url = ARGS.source_map_url || (
|
||||||
|
P_RELATIVE
|
||||||
|
? path.relative(path.dirname(OUTPUT_FILE), ARGS.source_map)
|
||||||
|
: ARGS.source_map
|
||||||
|
);
|
||||||
|
output += "\n//# sourceMappingURL=" + source_map_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OUTPUT_FILE) {
|
||||||
|
fs.writeFileSync(OUTPUT_FILE, output, "utf8");
|
||||||
|
} else {
|
||||||
|
print(output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ARGS.stats) {
|
if (ARGS.stats) {
|
||||||
@@ -488,17 +520,19 @@ function normalize(o) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOptions(x, constants) {
|
function getOptions(flag, constants) {
|
||||||
x = ARGS[x];
|
var x = ARGS[flag];
|
||||||
if (x == null) return null;
|
if (x == null || x === false) return null;
|
||||||
var ret = {};
|
var ret = {};
|
||||||
if (x !== "") {
|
if (x !== "") {
|
||||||
|
if (Array.isArray(x)) x = x.map(function (v) { return "(" + v + ")"; }).join(", ");
|
||||||
|
|
||||||
var ast;
|
var ast;
|
||||||
try {
|
try {
|
||||||
ast = UglifyJS.parse(x, { expression: true });
|
ast = UglifyJS.parse(x, { expression: true });
|
||||||
} catch(ex) {
|
} catch(ex) {
|
||||||
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
if (ex instanceof UglifyJS.JS_Parse_Error) {
|
||||||
print_error("Error parsing arguments in: " + x);
|
print_error("Error parsing arguments for flag `" + flag + "': " + x);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -518,7 +552,7 @@ function getOptions(x, constants) {
|
|||||||
return true; // no descend
|
return true; // no descend
|
||||||
}
|
}
|
||||||
print_error(node.TYPE)
|
print_error(node.TYPE)
|
||||||
print_error("Error parsing arguments in: " + x);
|
print_error("Error parsing arguments for flag `" + flag + "': " + x);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
52
lib/ast.js
52
lib/ast.js
@@ -71,7 +71,7 @@ function DEFNODE(type, props, methods, base) {
|
|||||||
if (type) {
|
if (type) {
|
||||||
ctor.prototype.TYPE = ctor.TYPE = type;
|
ctor.prototype.TYPE = ctor.TYPE = type;
|
||||||
}
|
}
|
||||||
if (methods) for (i in methods) if (methods.hasOwnProperty(i)) {
|
if (methods) for (i in methods) if (HOP(methods, i)) {
|
||||||
if (/^\$/.test(i)) {
|
if (/^\$/.test(i)) {
|
||||||
ctor[i.substr(1)] = methods[i];
|
ctor[i.substr(1)] = methods[i];
|
||||||
} else {
|
} else {
|
||||||
@@ -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 endline endcol endpos nlb comments_before file", {
|
var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before file raw", {
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
var AST_Node = DEFNODE("Node", "start end", {
|
var AST_Node = DEFNODE("Node", "start end", {
|
||||||
@@ -329,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":
|
||||||
@@ -633,6 +633,13 @@ var AST_Seq = DEFNODE("Seq", "car cdr", {
|
|||||||
p = p.cdr;
|
p = p.cdr;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
len: function() {
|
||||||
|
if (this.cdr instanceof AST_Seq) {
|
||||||
|
return this.cdr.len() + 1;
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
},
|
||||||
_walk: function(visitor) {
|
_walk: function(visitor) {
|
||||||
return visitor._visit(this, function(){
|
return visitor._visit(this, function(){
|
||||||
this.car._walk(visitor);
|
this.car._walk(visitor);
|
||||||
@@ -864,10 +871,11 @@ var AST_String = DEFNODE("String", "value quote", {
|
|||||||
}
|
}
|
||||||
}, 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);
|
||||||
|
|
||||||
@@ -926,27 +934,36 @@ var AST_True = DEFNODE("True", null, {
|
|||||||
function TreeWalker(callback) {
|
function TreeWalker(callback) {
|
||||||
this.visit = callback;
|
this.visit = callback;
|
||||||
this.stack = [];
|
this.stack = [];
|
||||||
|
this.directives = Object.create(null);
|
||||||
};
|
};
|
||||||
TreeWalker.prototype = {
|
TreeWalker.prototype = {
|
||||||
_visit: function(node, descend) {
|
_visit: function(node, descend) {
|
||||||
this.stack.push(node);
|
this.push(node);
|
||||||
var ret = this.visit(node, descend ? function(){
|
var ret = this.visit(node, descend ? function(){
|
||||||
descend.call(node);
|
descend.call(node);
|
||||||
} : noop);
|
} : noop);
|
||||||
if (!ret && descend) {
|
if (!ret && descend) {
|
||||||
descend.call(node);
|
descend.call(node);
|
||||||
}
|
}
|
||||||
this.stack.pop();
|
this.pop(node);
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
parent: function(n) {
|
parent: function(n) {
|
||||||
return this.stack[this.stack.length - 2 - (n || 0)];
|
return this.stack[this.stack.length - 2 - (n || 0)];
|
||||||
},
|
},
|
||||||
push: function (node) {
|
push: function (node) {
|
||||||
|
if (node instanceof AST_Lambda) {
|
||||||
|
this.directives = Object.create(this.directives);
|
||||||
|
} else if (node instanceof AST_Directive) {
|
||||||
|
this.directives[node.value] = this.directives[node.value] ? "up" : true;
|
||||||
|
}
|
||||||
this.stack.push(node);
|
this.stack.push(node);
|
||||||
},
|
},
|
||||||
pop: function() {
|
pop: function(node) {
|
||||||
return this.stack.pop();
|
this.stack.pop();
|
||||||
|
if (node instanceof AST_Lambda) {
|
||||||
|
this.directives = Object.getPrototypeOf(this.directives);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
self: function() {
|
self: function() {
|
||||||
return this.stack[this.stack.length - 1];
|
return this.stack[this.stack.length - 1];
|
||||||
@@ -959,7 +976,16 @@ TreeWalker.prototype = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
has_directive: function(type) {
|
has_directive: function(type) {
|
||||||
return this.find_parent(AST_Scope).has_directive(type);
|
var dir = this.directives[type];
|
||||||
|
if (dir) return dir;
|
||||||
|
var node = this.stack[this.stack.length - 1];
|
||||||
|
if (node instanceof AST_Scope) {
|
||||||
|
for (var i = 0; i < node.body.length; ++i) {
|
||||||
|
var st = node.body[i];
|
||||||
|
if (!(st instanceof AST_Directive)) break;
|
||||||
|
if (st.value == type) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
in_boolean_context: function() {
|
in_boolean_context: function() {
|
||||||
var stack = this.stack;
|
var stack = this.stack;
|
||||||
|
|||||||
626
lib/compress.js
626
lib/compress.js
@@ -61,31 +61,52 @@ function Compressor(options, false_by_default) {
|
|||||||
loops : !false_by_default,
|
loops : !false_by_default,
|
||||||
unused : !false_by_default,
|
unused : !false_by_default,
|
||||||
hoist_funs : !false_by_default,
|
hoist_funs : !false_by_default,
|
||||||
keep_fargs : false,
|
keep_fargs : true,
|
||||||
keep_fnames : false,
|
keep_fnames : false,
|
||||||
hoist_vars : false,
|
hoist_vars : false,
|
||||||
if_return : !false_by_default,
|
if_return : !false_by_default,
|
||||||
join_vars : !false_by_default,
|
join_vars : !false_by_default,
|
||||||
|
collapse_vars : false,
|
||||||
cascade : !false_by_default,
|
cascade : !false_by_default,
|
||||||
side_effects : !false_by_default,
|
side_effects : !false_by_default,
|
||||||
pure_getters : false,
|
pure_getters : false,
|
||||||
pure_funcs : null,
|
pure_funcs : null,
|
||||||
negate_iife : !false_by_default,
|
negate_iife : !false_by_default,
|
||||||
screw_ie8 : false,
|
screw_ie8 : true,
|
||||||
drop_console : false,
|
drop_console : false,
|
||||||
angular : false,
|
angular : false,
|
||||||
|
|
||||||
warnings : true,
|
warnings : true,
|
||||||
global_defs : {}
|
global_defs : {},
|
||||||
|
passes : 1,
|
||||||
}, true);
|
}, true);
|
||||||
|
var sequences = this.options["sequences"];
|
||||||
|
this.sequences_limit = sequences == 1 ? 200 : sequences | 0;
|
||||||
|
this.warnings_produced = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
Compressor.prototype = new TreeTransformer;
|
Compressor.prototype = new TreeTransformer;
|
||||||
merge(Compressor.prototype, {
|
merge(Compressor.prototype, {
|
||||||
option: function(key) { return this.options[key] },
|
option: function(key) { return this.options[key] },
|
||||||
warn: function() {
|
compress: function(node) {
|
||||||
if (this.options.warnings)
|
var passes = +this.options.passes || 1;
|
||||||
AST_Node.warn.apply(AST_Node, arguments);
|
for (var pass = 0; pass < passes && pass < 3; ++pass) {
|
||||||
|
if (pass > 0) node.clear_opt_flags();
|
||||||
|
node = node.transform(this);
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
},
|
||||||
|
warn: function(text, props) {
|
||||||
|
if (this.options.warnings) {
|
||||||
|
// only emit unique warnings
|
||||||
|
var message = string_template(text, props);
|
||||||
|
if (!(message in this.warnings_produced)) {
|
||||||
|
this.warnings_produced[message] = true;
|
||||||
|
AST_Node.warn.apply(AST_Node, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear_warnings: function() {
|
||||||
|
this.warnings_produced = {};
|
||||||
},
|
},
|
||||||
before: function(node, descend, in_list) {
|
before: function(node, descend, in_list) {
|
||||||
if (node._squeezed) return node;
|
if (node._squeezed) return node;
|
||||||
@@ -111,6 +132,7 @@ merge(Compressor.prototype, {
|
|||||||
node.DEFMETHOD("optimize", function(compressor){
|
node.DEFMETHOD("optimize", function(compressor){
|
||||||
var self = this;
|
var self = this;
|
||||||
if (self._optimized) return self;
|
if (self._optimized) return self;
|
||||||
|
if (compressor.has_directive("use asm")) return self;
|
||||||
var opt = optimizer(self, compressor);
|
var opt = optimizer(self, compressor);
|
||||||
opt._optimized = true;
|
opt._optimized = true;
|
||||||
if (opt === self) return opt;
|
if (opt === self) return opt;
|
||||||
@@ -127,6 +149,15 @@ merge(Compressor.prototype, {
|
|||||||
return this.print_to_string() == node.print_to_string();
|
return this.print_to_string() == node.print_to_string();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Node.DEFMETHOD("clear_opt_flags", function(){
|
||||||
|
this.walk(new TreeWalker(function(node){
|
||||||
|
if (!(node instanceof AST_Directive || node instanceof AST_Constant)) {
|
||||||
|
node._squeezed = false;
|
||||||
|
node._optimized = false;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
function make_node(ctor, orig, props) {
|
function make_node(ctor, orig, props) {
|
||||||
if (!props) props = {};
|
if (!props) props = {};
|
||||||
if (orig) {
|
if (orig) {
|
||||||
@@ -154,9 +185,18 @@ merge(Compressor.prototype, {
|
|||||||
value: val
|
value: val
|
||||||
}).optimize(compressor);
|
}).optimize(compressor);
|
||||||
case "number":
|
case "number":
|
||||||
return make_node(isNaN(val) ? AST_NaN : AST_Number, orig, {
|
if (isNaN(val)) {
|
||||||
value: val
|
return make_node(AST_NaN, orig);
|
||||||
}).optimize(compressor);
|
}
|
||||||
|
|
||||||
|
if ((1 / val) < 0) {
|
||||||
|
return make_node(AST_UnaryPrefix, orig, {
|
||||||
|
operator: "-",
|
||||||
|
expression: make_node(AST_Number, orig, { value: -val })
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return make_node(AST_Number, orig, { value: val }).optimize(compressor);
|
||||||
case "boolean":
|
case "boolean":
|
||||||
return make_node(val ? AST_True : AST_False, orig).optimize(compressor);
|
return make_node(val ? AST_True : AST_False, orig).optimize(compressor);
|
||||||
case "undefined":
|
case "undefined":
|
||||||
@@ -174,6 +214,23 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// we shouldn't compress (1,func)(something) to
|
||||||
|
// func(something) because that changes the meaning of
|
||||||
|
// the func (becomes lexical instead of global).
|
||||||
|
function maintain_this_binding(parent, orig, val) {
|
||||||
|
if (parent instanceof AST_Call && parent.expression === orig) {
|
||||||
|
if (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name === "eval") {
|
||||||
|
return make_node(AST_Seq, orig, {
|
||||||
|
car: make_node(AST_Number, orig, {
|
||||||
|
value: 0
|
||||||
|
}),
|
||||||
|
cdr: val
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
function as_statement_array(thing) {
|
function as_statement_array(thing) {
|
||||||
if (thing === null) return [];
|
if (thing === null) return [];
|
||||||
if (thing instanceof AST_BlockStatement) return thing.body;
|
if (thing instanceof AST_BlockStatement) return thing.body;
|
||||||
@@ -198,7 +255,7 @@ merge(Compressor.prototype, {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function tighten_body(statements, compressor) {
|
function tighten_body(statements, compressor) {
|
||||||
var CHANGED;
|
var CHANGED, max_iter = 10;
|
||||||
do {
|
do {
|
||||||
CHANGED = false;
|
CHANGED = false;
|
||||||
if (compressor.option("angular")) {
|
if (compressor.option("angular")) {
|
||||||
@@ -211,13 +268,16 @@ merge(Compressor.prototype, {
|
|||||||
if (compressor.option("if_return")) {
|
if (compressor.option("if_return")) {
|
||||||
statements = handle_if_return(statements, compressor);
|
statements = handle_if_return(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("sequences")) {
|
if (compressor.sequences_limit > 0) {
|
||||||
statements = sequencesize(statements, compressor);
|
statements = sequencesize(statements, compressor);
|
||||||
}
|
}
|
||||||
if (compressor.option("join_vars")) {
|
if (compressor.option("join_vars")) {
|
||||||
statements = join_consecutive_vars(statements, compressor);
|
statements = join_consecutive_vars(statements, compressor);
|
||||||
}
|
}
|
||||||
} while (CHANGED);
|
if (compressor.option("collapse_vars")) {
|
||||||
|
statements = collapse_single_use_vars(statements, compressor);
|
||||||
|
}
|
||||||
|
} while (CHANGED && max_iter-- > 0);
|
||||||
|
|
||||||
if (compressor.option("negate_iife")) {
|
if (compressor.option("negate_iife")) {
|
||||||
negate_iifes(statements, compressor);
|
negate_iifes(statements, compressor);
|
||||||
@@ -225,6 +285,160 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
return statements;
|
return statements;
|
||||||
|
|
||||||
|
function collapse_single_use_vars(statements, compressor) {
|
||||||
|
// Iterate statements backwards looking for a statement with a var/const
|
||||||
|
// declaration immediately preceding it. Grab the rightmost var definition
|
||||||
|
// and if it has exactly one reference then attempt to replace its reference
|
||||||
|
// in the statement with the var value and then erase the var definition.
|
||||||
|
|
||||||
|
var self = compressor.self();
|
||||||
|
var var_defs_removed = false;
|
||||||
|
for (var stat_index = statements.length; --stat_index >= 0;) {
|
||||||
|
var stat = statements[stat_index];
|
||||||
|
if (stat instanceof AST_Definitions) continue;
|
||||||
|
|
||||||
|
// Process child blocks of statement if present.
|
||||||
|
[stat, stat.body, stat.alternative, stat.bcatch, stat.bfinally].forEach(function(node) {
|
||||||
|
node && node.body && collapse_single_use_vars(node.body, compressor);
|
||||||
|
});
|
||||||
|
|
||||||
|
// The variable definition must precede a statement.
|
||||||
|
if (stat_index <= 0) break;
|
||||||
|
var prev_stat_index = stat_index - 1;
|
||||||
|
var prev_stat = statements[prev_stat_index];
|
||||||
|
if (!(prev_stat instanceof AST_Definitions)) continue;
|
||||||
|
var var_defs = prev_stat.definitions;
|
||||||
|
if (var_defs == null) continue;
|
||||||
|
|
||||||
|
var var_names_seen = {};
|
||||||
|
var side_effects_encountered = false;
|
||||||
|
var lvalues_encountered = false;
|
||||||
|
var lvalues = {};
|
||||||
|
|
||||||
|
// Scan variable definitions from right to left.
|
||||||
|
for (var var_defs_index = var_defs.length; --var_defs_index >= 0;) {
|
||||||
|
|
||||||
|
// Obtain var declaration and var name with basic sanity check.
|
||||||
|
var var_decl = var_defs[var_defs_index];
|
||||||
|
if (var_decl.value == null) break;
|
||||||
|
var var_name = var_decl.name.name;
|
||||||
|
if (!var_name || !var_name.length) break;
|
||||||
|
|
||||||
|
// Bail if we've seen a var definition of same name before.
|
||||||
|
if (var_name in var_names_seen) break;
|
||||||
|
var_names_seen[var_name] = true;
|
||||||
|
|
||||||
|
// Only interested in cases with just one reference to the variable.
|
||||||
|
var def = self.find_variable && self.find_variable(var_name);
|
||||||
|
if (!def || !def.references || def.references.length !== 1 || var_name == "arguments") {
|
||||||
|
side_effects_encountered = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
var ref = def.references[0];
|
||||||
|
|
||||||
|
// Don't replace ref if eval() or with statement in scope.
|
||||||
|
if (ref.scope.uses_eval || ref.scope.uses_with) break;
|
||||||
|
|
||||||
|
// Constant single use vars can be replaced in any scope.
|
||||||
|
if (!(var_decl.value instanceof AST_RegExp) && var_decl.value.is_constant(compressor)) {
|
||||||
|
var ctt = new TreeTransformer(function(node) {
|
||||||
|
if (node === ref)
|
||||||
|
return replace_var(node, ctt.parent(), true);
|
||||||
|
});
|
||||||
|
stat.transform(ctt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restrict var replacement to constants if side effects encountered.
|
||||||
|
if (side_effects_encountered |= lvalues_encountered) continue;
|
||||||
|
|
||||||
|
// Non-constant single use vars can only be replaced in same scope.
|
||||||
|
if (ref.scope !== self) {
|
||||||
|
side_effects_encountered |= var_decl.value.has_side_effects(compressor);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect lvalues in var value.
|
||||||
|
var tw = new TreeWalker(function(node){
|
||||||
|
if (node instanceof AST_SymbolRef && is_lvalue(node, tw.parent())) {
|
||||||
|
lvalues[node.name] = lvalues_encountered = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var_decl.value.walk(tw);
|
||||||
|
|
||||||
|
// Replace the non-constant single use var in statement if side effect free.
|
||||||
|
var unwind = false;
|
||||||
|
var tt = new TreeTransformer(
|
||||||
|
function preorder(node) {
|
||||||
|
if (unwind) return node;
|
||||||
|
var parent = tt.parent();
|
||||||
|
if (node instanceof AST_Lambda
|
||||||
|
|| node instanceof AST_Try
|
||||||
|
|| node instanceof AST_With
|
||||||
|
|| node instanceof AST_Case
|
||||||
|
|| node instanceof AST_IterationStatement
|
||||||
|
|| (parent instanceof AST_If && node !== parent.condition)
|
||||||
|
|| (parent instanceof AST_Conditional && node !== parent.condition)
|
||||||
|
|| (parent instanceof AST_Binary
|
||||||
|
&& (parent.operator == "&&" || parent.operator == "||")
|
||||||
|
&& node === parent.right)
|
||||||
|
|| (parent instanceof AST_Switch && node !== parent.expression)) {
|
||||||
|
return side_effects_encountered = unwind = true, node;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function postorder(node) {
|
||||||
|
if (unwind) return node;
|
||||||
|
if (node === ref)
|
||||||
|
return unwind = true, replace_var(node, tt.parent(), false);
|
||||||
|
if (side_effects_encountered |= node.has_side_effects(compressor))
|
||||||
|
return unwind = true, node;
|
||||||
|
if (lvalues_encountered && node instanceof AST_SymbolRef && node.name in lvalues) {
|
||||||
|
side_effects_encountered = true;
|
||||||
|
return unwind = true, node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
stat.transform(tt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove extraneous empty statments in block after removing var definitions.
|
||||||
|
// Leave at least one statement in `statements`.
|
||||||
|
if (var_defs_removed) for (var i = statements.length; --i >= 0;) {
|
||||||
|
if (statements.length > 1 && statements[i] instanceof AST_EmptyStatement)
|
||||||
|
statements.splice(i, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return statements;
|
||||||
|
|
||||||
|
function is_lvalue(node, parent) {
|
||||||
|
return node instanceof AST_SymbolRef && (
|
||||||
|
(parent instanceof AST_Assign && node === parent.left)
|
||||||
|
|| (parent instanceof AST_Unary && parent.expression === node
|
||||||
|
&& (parent.operator == "++" || parent.operator == "--")));
|
||||||
|
}
|
||||||
|
function replace_var(node, parent, is_constant) {
|
||||||
|
if (is_lvalue(node, parent)) return node;
|
||||||
|
|
||||||
|
// Remove var definition and return its value to the TreeTransformer to replace.
|
||||||
|
var value = maintain_this_binding(parent, node, var_decl.value);
|
||||||
|
var_decl.value = null;
|
||||||
|
|
||||||
|
var_defs.splice(var_defs_index, 1);
|
||||||
|
if (var_defs.length === 0) {
|
||||||
|
statements[prev_stat_index] = make_node(AST_EmptyStatement, self);
|
||||||
|
var_defs_removed = true;
|
||||||
|
}
|
||||||
|
// Further optimize statement after substitution.
|
||||||
|
stat.clear_opt_flags();
|
||||||
|
|
||||||
|
compressor.warn("Replacing " + (is_constant ? "constant" : "variable") +
|
||||||
|
" " + var_name + " [{file}:{line},{col}]", node.start);
|
||||||
|
CHANGED = true;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function process_for_angular(statements) {
|
function process_for_angular(statements) {
|
||||||
function has_inject(comment) {
|
function has_inject(comment) {
|
||||||
return /@ngInject/.test(comment.value);
|
return /@ngInject/.test(comment.value);
|
||||||
@@ -323,6 +537,7 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
function handle_if_return(statements, compressor) {
|
function handle_if_return(statements, compressor) {
|
||||||
var self = compressor.self();
|
var self = compressor.self();
|
||||||
|
var multiple_if_returns = has_multiple_if_returns(statements);
|
||||||
var in_lambda = self instanceof AST_Lambda;
|
var in_lambda = self instanceof AST_Lambda;
|
||||||
var ret = [];
|
var ret = [];
|
||||||
loop: for (var i = statements.length; --i >= 0;) {
|
loop: for (var i = statements.length; --i >= 0;) {
|
||||||
@@ -360,7 +575,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
||||||
if ((ret.length == 0 || ret[0] instanceof AST_Return) && stat.body.value && !stat.alternative && in_lambda) {
|
if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return)
|
||||||
|
&& stat.body.value && !stat.alternative && in_lambda) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
stat.alternative = ret[0] || make_node(AST_Return, stat, {
|
||||||
@@ -375,15 +591,22 @@ merge(Compressor.prototype, {
|
|||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.condition = stat.condition.negate(compressor);
|
stat.condition = stat.condition.negate(compressor);
|
||||||
|
var body = as_statement_array(stat.alternative).concat(ret);
|
||||||
|
var funs = extract_functions_from_statement_array(body);
|
||||||
stat.body = make_node(AST_BlockStatement, stat, {
|
stat.body = make_node(AST_BlockStatement, stat, {
|
||||||
body: as_statement_array(stat.alternative).concat(ret)
|
body: body
|
||||||
});
|
});
|
||||||
stat.alternative = null;
|
stat.alternative = null;
|
||||||
ret = [ stat.transform(compressor) ];
|
ret = funs.concat([ stat.transform(compressor) ]);
|
||||||
continue loop;
|
continue loop;
|
||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
if (ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
|
// XXX: what was the intention of this case?
|
||||||
|
// if sequences is not enabled, this can lead to an endless loop (issue #866).
|
||||||
|
// however, with sequences on this helps producing slightly better output for
|
||||||
|
// the example code.
|
||||||
|
if (compressor.option("sequences")
|
||||||
|
&& ret.length == 1 && in_lambda && ret[0] instanceof AST_SimpleStatement
|
||||||
&& (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {
|
&& (!stat.alternative || stat.alternative instanceof AST_SimpleStatement)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
ret.push(make_node(AST_Return, ret[0], {
|
ret.push(make_node(AST_Return, ret[0], {
|
||||||
@@ -445,6 +668,17 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
function has_multiple_if_returns(statements) {
|
||||||
|
var n = 0;
|
||||||
|
for (var i = statements.length; --i >= 0;) {
|
||||||
|
var stat = statements[i];
|
||||||
|
if (stat instanceof AST_If && stat.body instanceof AST_Return) {
|
||||||
|
if (++n > 1) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function eliminate_dead_code(statements, compressor) {
|
function eliminate_dead_code(statements, compressor) {
|
||||||
@@ -489,8 +723,12 @@ merge(Compressor.prototype, {
|
|||||||
seq = [];
|
seq = [];
|
||||||
};
|
};
|
||||||
statements.forEach(function(stat){
|
statements.forEach(function(stat){
|
||||||
if (stat instanceof AST_SimpleStatement && seq.length < 2000) seq.push(stat.body);
|
if (stat instanceof AST_SimpleStatement && seqLength(seq) < compressor.sequences_limit) {
|
||||||
else push_seq(), ret.push(stat);
|
seq.push(stat.body);
|
||||||
|
} else {
|
||||||
|
push_seq();
|
||||||
|
ret.push(stat);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
push_seq();
|
push_seq();
|
||||||
ret = sequencesize_2(ret, compressor);
|
ret = sequencesize_2(ret, compressor);
|
||||||
@@ -498,6 +736,18 @@ merge(Compressor.prototype, {
|
|||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function seqLength(a) {
|
||||||
|
for (var len = 0, i = 0; i < a.length; ++i) {
|
||||||
|
var stat = a[i];
|
||||||
|
if (stat instanceof AST_Seq) {
|
||||||
|
len += stat.len();
|
||||||
|
} else {
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
};
|
||||||
|
|
||||||
function sequencesize_2(statements, compressor) {
|
function sequencesize_2(statements, compressor) {
|
||||||
function cons_seq(right) {
|
function cons_seq(right) {
|
||||||
ret.pop();
|
ret.pop();
|
||||||
@@ -560,7 +810,7 @@ merge(Compressor.prototype, {
|
|||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
}
|
}
|
||||||
else if (stat instanceof AST_For
|
else if (stat instanceof AST_For
|
||||||
&& prev instanceof AST_Definitions
|
&& prev instanceof AST_Var
|
||||||
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
&& (!stat.init || stat.init.TYPE == prev.TYPE)) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
a.pop();
|
a.pop();
|
||||||
@@ -585,6 +835,9 @@ merge(Compressor.prototype, {
|
|||||||
if (stat instanceof AST_SimpleStatement) {
|
if (stat instanceof AST_SimpleStatement) {
|
||||||
stat.body = (function transform(thing) {
|
stat.body = (function transform(thing) {
|
||||||
return thing.transform(new TreeTransformer(function(node){
|
return thing.transform(new TreeTransformer(function(node){
|
||||||
|
if (node instanceof AST_New) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
if (node instanceof AST_Call && node.expression instanceof AST_Function) {
|
if (node instanceof AST_Call && node.expression instanceof AST_Function) {
|
||||||
return make_node(AST_UnaryPrefix, node, {
|
return make_node(AST_UnaryPrefix, node, {
|
||||||
operator: "!",
|
operator: "!",
|
||||||
@@ -616,8 +869,22 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function extract_functions_from_statement_array(statements) {
|
||||||
|
var funs = [];
|
||||||
|
for (var i = statements.length - 1; i >= 0; --i) {
|
||||||
|
var stat = statements[i];
|
||||||
|
if (stat instanceof AST_Defun) {
|
||||||
|
statements.splice(i, 1);
|
||||||
|
funs.unshift(stat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return funs;
|
||||||
|
}
|
||||||
|
|
||||||
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
function extract_declarations_from_unreachable_code(compressor, stat, target) {
|
||||||
compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
if (!(stat instanceof AST_Defun)) {
|
||||||
|
compressor.warn("Dropping unreachable code [{file}:{line},{col}]", stat.start);
|
||||||
|
}
|
||||||
stat.walk(new TreeWalker(function(node){
|
stat.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_Definitions) {
|
if (node instanceof AST_Definitions) {
|
||||||
compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
|
compressor.warn("Declarations in unreachable code! [{file}:{line},{col}]", node.start);
|
||||||
@@ -720,6 +987,32 @@ merge(Compressor.prototype, {
|
|||||||
return [ this ];
|
return [ this ];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
AST_Node.DEFMETHOD("is_constant", function(compressor){
|
||||||
|
// Accomodate when compress option evaluate=false
|
||||||
|
// as well as the common constant expressions !0 and !1
|
||||||
|
return this instanceof AST_Constant
|
||||||
|
|| (this instanceof AST_UnaryPrefix && this.operator == "!"
|
||||||
|
&& this.expression instanceof AST_Constant)
|
||||||
|
|| this.evaluate(compressor).length > 1;
|
||||||
|
});
|
||||||
|
// Obtain the constant value of an expression already known to be constant.
|
||||||
|
// Result only valid iff this.is_constant(compressor) is true.
|
||||||
|
AST_Node.DEFMETHOD("constant_value", function(compressor){
|
||||||
|
// Accomodate when option evaluate=false.
|
||||||
|
if (this instanceof AST_Constant) return this.value;
|
||||||
|
// Accomodate the common constant expressions !0 and !1 when option evaluate=false.
|
||||||
|
if (this instanceof AST_UnaryPrefix
|
||||||
|
&& this.operator == "!"
|
||||||
|
&& this.expression instanceof AST_Constant) {
|
||||||
|
return !this.expression.value;
|
||||||
|
}
|
||||||
|
var result = this.evaluate(compressor)
|
||||||
|
if (result.length > 1) {
|
||||||
|
return result[1];
|
||||||
|
}
|
||||||
|
// should never be reached
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
def(AST_Statement, function(){
|
def(AST_Statement, function(){
|
||||||
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
||||||
});
|
});
|
||||||
@@ -759,42 +1052,43 @@ merge(Compressor.prototype, {
|
|||||||
return typeof e;
|
return typeof e;
|
||||||
case "void": return void ev(e, compressor);
|
case "void": return void ev(e, compressor);
|
||||||
case "~": return ~ev(e, compressor);
|
case "~": return ~ev(e, compressor);
|
||||||
case "-":
|
case "-": return -ev(e, compressor);
|
||||||
e = ev(e, compressor);
|
|
||||||
if (e === 0) throw def;
|
|
||||||
return -e;
|
|
||||||
case "+": return +ev(e, compressor);
|
case "+": return +ev(e, compressor);
|
||||||
}
|
}
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
def(AST_Binary, function(c){
|
def(AST_Binary, function(c){
|
||||||
var left = this.left, right = this.right;
|
var left = this.left, right = this.right, result;
|
||||||
switch (this.operator) {
|
switch (this.operator) {
|
||||||
case "&&" : return ev(left, c) && ev(right, c);
|
case "&&" : result = ev(left, c) && ev(right, c); break;
|
||||||
case "||" : return ev(left, c) || ev(right, c);
|
case "||" : result = ev(left, c) || ev(right, c); break;
|
||||||
case "|" : return ev(left, c) | ev(right, c);
|
case "|" : result = ev(left, c) | ev(right, c); break;
|
||||||
case "&" : return ev(left, c) & ev(right, c);
|
case "&" : result = ev(left, c) & ev(right, c); break;
|
||||||
case "^" : return ev(left, c) ^ ev(right, c);
|
case "^" : result = ev(left, c) ^ ev(right, c); break;
|
||||||
case "+" : return ev(left, c) + ev(right, c);
|
case "+" : result = ev(left, c) + ev(right, c); break;
|
||||||
case "*" : return ev(left, c) * ev(right, c);
|
case "*" : result = ev(left, c) * ev(right, c); break;
|
||||||
case "/" : return ev(left, c) / ev(right, c);
|
case "/" : result = ev(left, c) / ev(right, c); break;
|
||||||
case "%" : return ev(left, c) % ev(right, c);
|
case "%" : result = ev(left, c) % ev(right, c); break;
|
||||||
case "-" : return ev(left, c) - ev(right, c);
|
case "-" : result = ev(left, c) - ev(right, c); break;
|
||||||
case "<<" : return ev(left, c) << ev(right, c);
|
case "<<" : result = ev(left, c) << ev(right, c); break;
|
||||||
case ">>" : return ev(left, c) >> ev(right, c);
|
case ">>" : result = ev(left, c) >> ev(right, c); break;
|
||||||
case ">>>" : return ev(left, c) >>> ev(right, c);
|
case ">>>" : result = ev(left, c) >>> ev(right, c); break;
|
||||||
case "==" : return ev(left, c) == ev(right, c);
|
case "==" : result = ev(left, c) == ev(right, c); break;
|
||||||
case "===" : return ev(left, c) === ev(right, c);
|
case "===" : result = ev(left, c) === ev(right, c); break;
|
||||||
case "!=" : return ev(left, c) != ev(right, c);
|
case "!=" : result = ev(left, c) != ev(right, c); break;
|
||||||
case "!==" : return ev(left, c) !== ev(right, c);
|
case "!==" : result = ev(left, c) !== ev(right, c); break;
|
||||||
case "<" : return ev(left, c) < ev(right, c);
|
case "<" : result = ev(left, c) < ev(right, c); break;
|
||||||
case "<=" : return ev(left, c) <= ev(right, c);
|
case "<=" : result = ev(left, c) <= ev(right, c); break;
|
||||||
case ">" : return ev(left, c) > ev(right, c);
|
case ">" : result = ev(left, c) > ev(right, c); break;
|
||||||
case ">=" : return ev(left, c) >= ev(right, c);
|
case ">=" : result = ev(left, c) >= ev(right, c); break;
|
||||||
case "in" : return ev(left, c) in ev(right, c);
|
default:
|
||||||
case "instanceof" : return ev(left, c) instanceof ev(right, c);
|
throw def;
|
||||||
}
|
}
|
||||||
throw def;
|
if (isNaN(result) && c.find_parent(AST_With)) {
|
||||||
|
// leave original expression as is
|
||||||
|
throw def;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
});
|
});
|
||||||
def(AST_Conditional, function(compressor){
|
def(AST_Conditional, function(compressor){
|
||||||
return ev(this.condition, compressor)
|
return ev(this.condition, compressor)
|
||||||
@@ -802,8 +1096,16 @@ merge(Compressor.prototype, {
|
|||||||
: ev(this.alternative, compressor);
|
: ev(this.alternative, compressor);
|
||||||
});
|
});
|
||||||
def(AST_SymbolRef, function(compressor){
|
def(AST_SymbolRef, function(compressor){
|
||||||
var d = this.definition();
|
if (this._evaluating) throw def;
|
||||||
if (d && d.constant && d.init) return ev(d.init, compressor);
|
this._evaluating = true;
|
||||||
|
try {
|
||||||
|
var d = this.definition();
|
||||||
|
if (d && d.constant && d.init) {
|
||||||
|
return ev(d.init, compressor);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this._evaluating = false;
|
||||||
|
}
|
||||||
throw def;
|
throw def;
|
||||||
});
|
});
|
||||||
def(AST_Dot, function(compressor){
|
def(AST_Dot, function(compressor){
|
||||||
@@ -896,6 +1198,7 @@ merge(Compressor.prototype, {
|
|||||||
def(AST_Call, function(compressor){
|
def(AST_Call, function(compressor){
|
||||||
var pure = compressor.option("pure_funcs");
|
var pure = compressor.option("pure_funcs");
|
||||||
if (!pure) return true;
|
if (!pure) return true;
|
||||||
|
if (typeof pure == "function") return pure(this);
|
||||||
return pure.indexOf(this.expression.print_to_string()) < 0;
|
return pure.indexOf(this.expression.print_to_string()) < 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -989,7 +1292,7 @@ merge(Compressor.prototype, {
|
|||||||
/* -----[ optimizers ]----- */
|
/* -----[ optimizers ]----- */
|
||||||
|
|
||||||
OPT(AST_Directive, function(self, compressor){
|
OPT(AST_Directive, function(self, compressor){
|
||||||
if (self.scope.has_directive(self.value) !== self.scope) {
|
if (compressor.has_directive(self.value) === "up") {
|
||||||
return make_node(AST_EmptyStatement, self);
|
return make_node(AST_EmptyStatement, self);
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -1025,11 +1328,14 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
AST_Scope.DEFMETHOD("drop_unused", function(compressor){
|
AST_Scope.DEFMETHOD("drop_unused", function(compressor){
|
||||||
var self = this;
|
var self = this;
|
||||||
|
if (compressor.has_directive("use asm")) return self;
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& !(self instanceof AST_Toplevel)
|
&& !(self instanceof AST_Toplevel)
|
||||||
&& !self.uses_eval
|
&& !self.uses_eval
|
||||||
|
&& !self.uses_with
|
||||||
) {
|
) {
|
||||||
var in_use = [];
|
var in_use = [];
|
||||||
|
var in_use_ids = {}; // avoid expensive linear scans of in_use
|
||||||
var initializations = new Dictionary();
|
var initializations = new Dictionary();
|
||||||
// pass 1: find out which symbols are directly used in
|
// pass 1: find out which symbols are directly used in
|
||||||
// this scope (not in nested scopes).
|
// this scope (not in nested scopes).
|
||||||
@@ -1052,7 +1358,11 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
push_uniq(in_use, node.definition());
|
var node_def = node.definition();
|
||||||
|
if (!(node_def.id in in_use_ids)) {
|
||||||
|
in_use_ids[node_def.id] = true;
|
||||||
|
in_use.push(node_def);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
@@ -1075,7 +1385,11 @@ merge(Compressor.prototype, {
|
|||||||
if (init) init.forEach(function(init){
|
if (init) init.forEach(function(init){
|
||||||
var tw = new TreeWalker(function(node){
|
var tw = new TreeWalker(function(node){
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
push_uniq(in_use, node.definition());
|
var node_def = node.definition();
|
||||||
|
if (!(node_def.id in in_use_ids)) {
|
||||||
|
in_use_ids[node_def.id] = true;
|
||||||
|
in_use.push(node_def);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
init.walk(tw);
|
init.walk(tw);
|
||||||
@@ -1086,7 +1400,7 @@ merge(Compressor.prototype, {
|
|||||||
var tt = new TreeTransformer(
|
var tt = new TreeTransformer(
|
||||||
function before(node, descend, in_list) {
|
function before(node, descend, in_list) {
|
||||||
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
|
if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) {
|
||||||
if (compressor.option("unsafe") && !compressor.option("keep_fargs")) {
|
if (!compressor.option("keep_fargs")) {
|
||||||
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
for (var a = node.argnames, i = a.length; --i >= 0;) {
|
||||||
var sym = a[i];
|
var sym = a[i];
|
||||||
if (sym.unreferenced()) {
|
if (sym.unreferenced()) {
|
||||||
@@ -1103,7 +1417,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Defun && node !== self) {
|
if (node instanceof AST_Defun && node !== self) {
|
||||||
if (!member(node.name.definition(), in_use)) {
|
if (!(node.name.definition().id in in_use_ids)) {
|
||||||
compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {
|
compressor.warn("Dropping unused function {name} [{file}:{line},{col}]", {
|
||||||
name : node.name.name,
|
name : node.name.name,
|
||||||
file : node.name.start.file,
|
file : node.name.start.file,
|
||||||
@@ -1116,7 +1430,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
|
if (node instanceof AST_Definitions && !(tt.parent() instanceof AST_ForIn)) {
|
||||||
var def = node.definitions.filter(function(def){
|
var def = node.definitions.filter(function(def){
|
||||||
if (member(def.name.definition(), in_use)) return true;
|
if (def.name.definition().id in in_use_ids) return true;
|
||||||
var w = {
|
var w = {
|
||||||
name : def.name.name,
|
name : def.name.name,
|
||||||
file : def.name.start.file,
|
file : def.name.start.file,
|
||||||
@@ -1204,9 +1518,10 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
|
AST_Scope.DEFMETHOD("hoist_declarations", function(compressor){
|
||||||
|
var self = this;
|
||||||
|
if (compressor.has_directive("use asm")) return self;
|
||||||
var hoist_funs = compressor.option("hoist_funs");
|
var hoist_funs = compressor.option("hoist_funs");
|
||||||
var hoist_vars = compressor.option("hoist_vars");
|
var hoist_vars = compressor.option("hoist_vars");
|
||||||
var self = this;
|
|
||||||
if (hoist_funs || hoist_vars) {
|
if (hoist_funs || hoist_vars) {
|
||||||
var dirs = [];
|
var dirs = [];
|
||||||
var hoisted = [];
|
var hoisted = [];
|
||||||
@@ -1241,7 +1556,10 @@ merge(Compressor.prototype, {
|
|||||||
var seq = node.to_assignments();
|
var seq = node.to_assignments();
|
||||||
var p = tt.parent();
|
var p = tt.parent();
|
||||||
if (p instanceof AST_ForIn && p.init === node) {
|
if (p instanceof AST_ForIn && p.init === node) {
|
||||||
if (seq == null) return node.definitions[0].name;
|
if (seq == null) {
|
||||||
|
var def = node.definitions[0].name;
|
||||||
|
return make_node(AST_SymbolRef, def, def);
|
||||||
|
}
|
||||||
return seq;
|
return seq;
|
||||||
}
|
}
|
||||||
if (p instanceof AST_For && p.init === node) {
|
if (p instanceof AST_For && p.init === node) {
|
||||||
@@ -1472,9 +1790,13 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (is_empty(self.alternative)) self.alternative = null;
|
if (is_empty(self.alternative)) self.alternative = null;
|
||||||
var negated = self.condition.negate(compressor);
|
var negated = self.condition.negate(compressor);
|
||||||
var negated_is_best = best_of(self.condition, negated) === negated;
|
var self_condition_length = self.condition.print_to_string().length;
|
||||||
|
var negated_length = negated.print_to_string().length;
|
||||||
|
var negated_is_best = negated_length < self_condition_length;
|
||||||
if (self.alternative && negated_is_best) {
|
if (self.alternative && negated_is_best) {
|
||||||
negated_is_best = false; // because we already do the switch here.
|
negated_is_best = false; // because we already do the switch here.
|
||||||
|
// no need to swap values of self_condition_length and negated_length
|
||||||
|
// here because they are only used in an equality comparison later on.
|
||||||
self.condition = negated;
|
self.condition = negated;
|
||||||
var tmp = self.body;
|
var tmp = self.body;
|
||||||
self.body = self.alternative || make_node(AST_EmptyStatement);
|
self.body = self.alternative || make_node(AST_EmptyStatement);
|
||||||
@@ -1496,6 +1818,13 @@ merge(Compressor.prototype, {
|
|||||||
}).transform(compressor);
|
}).transform(compressor);
|
||||||
}
|
}
|
||||||
if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
|
if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) {
|
||||||
|
if (self_condition_length === negated_length && !negated_is_best
|
||||||
|
&& self.condition instanceof AST_Binary && self.condition.operator == "||") {
|
||||||
|
// although the code length of self.condition and negated are the same,
|
||||||
|
// negated does not require additional surrounding parentheses.
|
||||||
|
// see https://github.com/mishoo/UglifyJS2/issues/979
|
||||||
|
negated_is_best = true;
|
||||||
|
}
|
||||||
if (negated_is_best) return make_node(AST_SimpleStatement, self, {
|
if (negated_is_best) return make_node(AST_SimpleStatement, self, {
|
||||||
body: make_node(AST_Binary, self, {
|
body: make_node(AST_Binary, self, {
|
||||||
operator : "||",
|
operator : "||",
|
||||||
@@ -1909,17 +2238,7 @@ merge(Compressor.prototype, {
|
|||||||
if (!compressor.option("side_effects"))
|
if (!compressor.option("side_effects"))
|
||||||
return self;
|
return self;
|
||||||
if (!self.car.has_side_effects(compressor)) {
|
if (!self.car.has_side_effects(compressor)) {
|
||||||
// we shouldn't compress (1,eval)(something) to
|
return maintain_this_binding(compressor.parent(), self, self.cdr);
|
||||||
// eval(something) because that changes the meaning of
|
|
||||||
// eval (becomes lexical instead of global).
|
|
||||||
var p;
|
|
||||||
if (!(self.cdr instanceof AST_SymbolRef
|
|
||||||
&& self.cdr.name == "eval"
|
|
||||||
&& self.cdr.undeclared()
|
|
||||||
&& (p = compressor.parent()) instanceof AST_Call
|
|
||||||
&& p.expression === self)) {
|
|
||||||
return self.cdr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (compressor.option("cascade")) {
|
if (compressor.option("cascade")) {
|
||||||
if (self.car instanceof AST_Assign
|
if (self.car instanceof AST_Assign
|
||||||
@@ -2031,15 +2350,14 @@ merge(Compressor.prototype, {
|
|||||||
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
var commutativeOperators = makePredicate("== === != !== * & | ^");
|
||||||
|
|
||||||
OPT(AST_Binary, function(self, compressor){
|
OPT(AST_Binary, function(self, compressor){
|
||||||
var reverse = compressor.has_directive("use asm") ? noop
|
function reverse(op, force) {
|
||||||
: function(op, force) {
|
if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) {
|
||||||
if (force || !(self.left.has_side_effects(compressor) || self.right.has_side_effects(compressor))) {
|
if (op) self.operator = op;
|
||||||
if (op) self.operator = op;
|
var tmp = self.left;
|
||||||
var tmp = self.left;
|
self.left = self.right;
|
||||||
self.left = self.right;
|
self.right = tmp;
|
||||||
self.right = tmp;
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
if (commutativeOperators(self.operator)) {
|
if (commutativeOperators(self.operator)) {
|
||||||
if (self.right instanceof AST_Constant
|
if (self.right instanceof AST_Constant
|
||||||
&& !(self.left instanceof AST_Constant)) {
|
&& !(self.left instanceof AST_Constant)) {
|
||||||
@@ -2107,27 +2425,25 @@ merge(Compressor.prototype, {
|
|||||||
if (compressor.option("conditionals")) {
|
if (compressor.option("conditionals")) {
|
||||||
if (self.operator == "&&") {
|
if (self.operator == "&&") {
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
var rr = self.right.evaluate(compressor);
|
|
||||||
if (ll.length > 1) {
|
if (ll.length > 1) {
|
||||||
if (ll[1]) {
|
if (ll[1]) {
|
||||||
compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start);
|
||||||
return rr[0];
|
return maintain_this_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]);
|
||||||
} else {
|
} else {
|
||||||
compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
|
compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start);
|
||||||
return ll[0];
|
return maintain_this_binding(compressor.parent(), self, ll[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (self.operator == "||") {
|
else if (self.operator == "||") {
|
||||||
var ll = self.left.evaluate(compressor);
|
var ll = self.left.evaluate(compressor);
|
||||||
var rr = self.right.evaluate(compressor);
|
|
||||||
if (ll.length > 1) {
|
if (ll.length > 1) {
|
||||||
if (ll[1]) {
|
if (ll[1]) {
|
||||||
compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start);
|
||||||
return ll[0];
|
return maintain_this_binding(compressor.parent(), self, ll[0]);
|
||||||
} else {
|
} else {
|
||||||
compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start);
|
compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start);
|
||||||
return rr[0];
|
return maintain_this_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2192,9 +2508,11 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
self = best_of(self, negated);
|
self = best_of(self, negated);
|
||||||
}
|
}
|
||||||
switch (self.operator) {
|
if (compressor.option("unsafe_comps")) {
|
||||||
case "<": reverse(">"); break;
|
switch (self.operator) {
|
||||||
case "<=": reverse(">="); break;
|
case "<": reverse(">"); break;
|
||||||
|
case "<=": reverse(">="); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (self.operator == "+" && self.right instanceof AST_String
|
if (self.operator == "+" && self.right instanceof AST_String
|
||||||
@@ -2276,18 +2594,29 @@ merge(Compressor.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_SymbolRef, function(self, compressor){
|
OPT(AST_SymbolRef, function(self, compressor){
|
||||||
if (self.undeclared()) {
|
function isLHS(symbol, parent) {
|
||||||
|
return (
|
||||||
|
parent instanceof AST_Binary &&
|
||||||
|
parent.operator === '=' &&
|
||||||
|
parent.left === symbol
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.undeclared() && !isLHS(self, compressor.parent())) {
|
||||||
var defines = compressor.option("global_defs");
|
var defines = compressor.option("global_defs");
|
||||||
if (defines && defines.hasOwnProperty(self.name)) {
|
if (defines && HOP(defines, self.name)) {
|
||||||
return make_node_from_constant(compressor, defines[self.name], self);
|
return make_node_from_constant(compressor, defines[self.name], self);
|
||||||
}
|
}
|
||||||
switch (self.name) {
|
// testing against !self.scope.uses_with first is an optimization
|
||||||
case "undefined":
|
if (!self.scope.uses_with || !compressor.find_parent(AST_With)) {
|
||||||
return make_node(AST_Undefined, self);
|
switch (self.name) {
|
||||||
case "NaN":
|
case "undefined":
|
||||||
return make_node(AST_NaN, self).transform(compressor);
|
return make_node(AST_Undefined, self);
|
||||||
case "Infinity":
|
case "NaN":
|
||||||
return make_node(AST_Infinity, self).transform(compressor);
|
return make_node(AST_NaN, self).transform(compressor);
|
||||||
|
case "Infinity":
|
||||||
|
return make_node(AST_Infinity, self).transform(compressor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
@@ -2344,10 +2673,10 @@ merge(Compressor.prototype, {
|
|||||||
if (cond.length > 1) {
|
if (cond.length > 1) {
|
||||||
if (cond[1]) {
|
if (cond[1]) {
|
||||||
compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
|
compressor.warn("Condition always true [{file}:{line},{col}]", self.start);
|
||||||
return self.consequent;
|
return maintain_this_binding(compressor.parent(), self, self.consequent);
|
||||||
} else {
|
} else {
|
||||||
compressor.warn("Condition always false [{file}:{line},{col}]", self.start);
|
compressor.warn("Condition always false [{file}:{line},{col}]", self.start);
|
||||||
return self.alternative;
|
return maintain_this_binding(compressor.parent(), self, self.alternative);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var negated = cond[0].negate(compressor);
|
var negated = cond[0].negate(compressor);
|
||||||
@@ -2415,32 +2744,86 @@ merge(Compressor.prototype, {
|
|||||||
alternative: alternative
|
alternative: alternative
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// x=y?1:1 --> x=1
|
// y?1:1 --> 1
|
||||||
if (consequent instanceof AST_Constant
|
if (consequent.is_constant(compressor)
|
||||||
&& alternative instanceof AST_Constant
|
&& alternative.is_constant(compressor)
|
||||||
&& consequent.equivalent_to(alternative)) {
|
&& consequent.equivalent_to(alternative)) {
|
||||||
|
var consequent_value = consequent.constant_value(compressor);
|
||||||
if (self.condition.has_side_effects(compressor)) {
|
if (self.condition.has_side_effects(compressor)) {
|
||||||
return AST_Seq.from_array([self.condition, make_node_from_constant(compressor, consequent.value, self)]);
|
return AST_Seq.from_array([self.condition, make_node_from_constant(compressor, consequent_value, self)]);
|
||||||
} else {
|
} else {
|
||||||
return make_node_from_constant(compressor, consequent.value, self);
|
return make_node_from_constant(compressor, consequent_value, self);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// x=y?true:false --> x=!!y
|
|
||||||
if (consequent instanceof AST_True
|
if (is_true(self.consequent)) {
|
||||||
&& alternative instanceof AST_False) {
|
if (is_false(self.alternative)) {
|
||||||
self.condition = self.condition.negate(compressor);
|
// c ? true : false ---> !!c
|
||||||
return make_node(AST_UnaryPrefix, self.condition, {
|
return booleanize(self.condition);
|
||||||
operator: "!",
|
}
|
||||||
expression: self.condition
|
// c ? true : x ---> !!c || x
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator: "||",
|
||||||
|
left: booleanize(self.condition),
|
||||||
|
right: self.alternative
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// x=y?false:true --> x=!y
|
if (is_false(self.consequent)) {
|
||||||
if (consequent instanceof AST_False
|
if (is_true(self.alternative)) {
|
||||||
&& alternative instanceof AST_True) {
|
// c ? false : true ---> !c
|
||||||
return self.condition.negate(compressor)
|
return booleanize(self.condition.negate(compressor));
|
||||||
|
}
|
||||||
|
// c ? false : x ---> !c && x
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator: "&&",
|
||||||
|
left: booleanize(self.condition.negate(compressor)),
|
||||||
|
right: self.alternative
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
if (is_true(self.alternative)) {
|
||||||
|
// c ? x : true ---> !c || x
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator: "||",
|
||||||
|
left: booleanize(self.condition.negate(compressor)),
|
||||||
|
right: self.consequent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (is_false(self.alternative)) {
|
||||||
|
// c ? x : false ---> !!c && x
|
||||||
|
return make_node(AST_Binary, self, {
|
||||||
|
operator: "&&",
|
||||||
|
left: booleanize(self.condition),
|
||||||
|
right: self.consequent
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
|
||||||
|
function booleanize(node) {
|
||||||
|
if (node.is_boolean()) return node;
|
||||||
|
// !!expression
|
||||||
|
return make_node(AST_UnaryPrefix, node, {
|
||||||
|
operator: "!",
|
||||||
|
expression: node.negate(compressor)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// AST_True or !0
|
||||||
|
function is_true(node) {
|
||||||
|
return node instanceof AST_True
|
||||||
|
|| (node instanceof AST_UnaryPrefix
|
||||||
|
&& node.operator == "!"
|
||||||
|
&& node.expression instanceof AST_Constant
|
||||||
|
&& !node.expression.value);
|
||||||
|
}
|
||||||
|
// AST_False or !1
|
||||||
|
function is_false(node) {
|
||||||
|
return node instanceof AST_False
|
||||||
|
|| (node instanceof AST_UnaryPrefix
|
||||||
|
&& node.operator == "!"
|
||||||
|
&& node.expression instanceof AST_Constant
|
||||||
|
&& !!node.expression.value);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
OPT(AST_Boolean, function(self, compressor){
|
OPT(AST_Boolean, function(self, compressor){
|
||||||
@@ -2512,4 +2895,11 @@ merge(Compressor.prototype, {
|
|||||||
OPT(AST_Object, literals_in_boolean_context);
|
OPT(AST_Object, literals_in_boolean_context);
|
||||||
OPT(AST_RegExp, literals_in_boolean_context);
|
OPT(AST_RegExp, literals_in_boolean_context);
|
||||||
|
|
||||||
|
OPT(AST_Return, function(self, compressor){
|
||||||
|
if (self.value instanceof AST_Undefined) {
|
||||||
|
self.value = null;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -45,20 +45,55 @@
|
|||||||
|
|
||||||
(function(){
|
(function(){
|
||||||
|
|
||||||
var MOZ_TO_ME = {
|
var normalize_directives = function(body) {
|
||||||
ExpressionStatement: function(M) {
|
var in_directive = true;
|
||||||
var expr = M.expression;
|
|
||||||
if (expr.type === "Literal" && typeof expr.value === "string") {
|
for (var i = 0; i < body.length; i++) {
|
||||||
return new AST_Directive({
|
if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) {
|
||||||
start: my_start_token(M),
|
body[i] = new AST_Directive({
|
||||||
end: my_end_token(M),
|
start: body[i].start,
|
||||||
value: expr.value
|
end: body[i].end,
|
||||||
|
value: body[i].body.value
|
||||||
});
|
});
|
||||||
|
} else if (in_directive && !(body[i] instanceof AST_Statement && body[i].body instanceof AST_String)) {
|
||||||
|
in_directive = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return body;
|
||||||
|
};
|
||||||
|
|
||||||
|
var MOZ_TO_ME = {
|
||||||
|
Program: function(M) {
|
||||||
|
return new AST_Toplevel({
|
||||||
|
start: my_start_token(M),
|
||||||
|
end: my_end_token(M),
|
||||||
|
body: normalize_directives(M.body.map(from_moz))
|
||||||
|
});
|
||||||
|
},
|
||||||
|
FunctionDeclaration: function(M) {
|
||||||
|
return new AST_Defun({
|
||||||
|
start: my_start_token(M),
|
||||||
|
end: my_end_token(M),
|
||||||
|
name: from_moz(M.id),
|
||||||
|
argnames: M.params.map(from_moz),
|
||||||
|
body: normalize_directives(from_moz(M.body).body)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
FunctionExpression: function(M) {
|
||||||
|
return new AST_Function({
|
||||||
|
start: my_start_token(M),
|
||||||
|
end: my_end_token(M),
|
||||||
|
name: from_moz(M.id),
|
||||||
|
argnames: M.params.map(from_moz),
|
||||||
|
body: normalize_directives(from_moz(M.body).body)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
ExpressionStatement: function(M) {
|
||||||
return new AST_SimpleStatement({
|
return new AST_SimpleStatement({
|
||||||
start: my_start_token(M),
|
start: my_start_token(M),
|
||||||
end: my_end_token(M),
|
end: my_end_token(M),
|
||||||
body: from_moz(expr)
|
body: from_moz(M.expression)
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
TryStatement: function(M) {
|
TryStatement: function(M) {
|
||||||
@@ -94,6 +129,15 @@
|
|||||||
return new AST_ObjectGetter(args);
|
return new AST_ObjectGetter(args);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ArrayExpression: function(M) {
|
||||||
|
return new AST_Array({
|
||||||
|
start : my_start_token(M),
|
||||||
|
end : my_end_token(M),
|
||||||
|
elements : M.elements.map(function(elem){
|
||||||
|
return elem === null ? new AST_Hole() : from_moz(elem);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
ObjectExpression: function(M) {
|
ObjectExpression: function(M) {
|
||||||
return new AST_Object({
|
return new AST_Object({
|
||||||
start : my_start_token(M),
|
start : my_start_token(M),
|
||||||
@@ -146,7 +190,14 @@
|
|||||||
case "boolean":
|
case "boolean":
|
||||||
return new (val ? AST_True : AST_False)(args);
|
return new (val ? AST_True : AST_False)(args);
|
||||||
default:
|
default:
|
||||||
args.value = val;
|
var rx = M.regex;
|
||||||
|
if (rx && rx.pattern) {
|
||||||
|
// RegExpLiteral as per ESTree AST spec
|
||||||
|
args.value = new RegExp(rx.pattern, rx.flags).toString();
|
||||||
|
} else {
|
||||||
|
// support legacy RegExp
|
||||||
|
args.value = M.regex && M.raw ? M.raw : val;
|
||||||
|
}
|
||||||
return new AST_RegExp(args);
|
return new AST_RegExp(args);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -178,7 +229,6 @@
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
map("Program", AST_Toplevel, "body@body");
|
|
||||||
map("EmptyStatement", AST_EmptyStatement);
|
map("EmptyStatement", AST_EmptyStatement);
|
||||||
map("BlockStatement", AST_BlockStatement, "body@body");
|
map("BlockStatement", AST_BlockStatement, "body@body");
|
||||||
map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
|
map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative");
|
||||||
@@ -194,13 +244,10 @@
|
|||||||
map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
|
map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body");
|
||||||
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("VariableDeclarator", AST_VarDef, "id>name, init>value");
|
map("VariableDeclarator", AST_VarDef, "id>name, init>value");
|
||||||
map("CatchClause", AST_Catch, "param>argname, body%body");
|
map("CatchClause", AST_Catch, "param>argname, body%body");
|
||||||
|
|
||||||
map("ThisExpression", AST_This);
|
map("ThisExpression", AST_This);
|
||||||
map("ArrayExpression", AST_Array, "elements@elements");
|
|
||||||
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("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("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right");
|
||||||
@@ -208,6 +255,31 @@
|
|||||||
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_Toplevel, function To_Moz_Program(M) {
|
||||||
|
return {
|
||||||
|
type: "Program",
|
||||||
|
body: M.body.map(to_moz)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) {
|
||||||
|
return {
|
||||||
|
type: "FunctionDeclaration",
|
||||||
|
id: to_moz(M.name),
|
||||||
|
params: M.argnames.map(to_moz),
|
||||||
|
body: to_moz_block(M)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Function, function To_Moz_FunctionExpression(M) {
|
||||||
|
return {
|
||||||
|
type: "FunctionExpression",
|
||||||
|
id: to_moz(M.name),
|
||||||
|
params: M.argnames.map(to_moz),
|
||||||
|
body: to_moz_block(M)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
def_to_moz(AST_Directive, function To_Moz_Directive(M) {
|
def_to_moz(AST_Directive, function To_Moz_Directive(M) {
|
||||||
return {
|
return {
|
||||||
type: "ExpressionStatement",
|
type: "ExpressionStatement",
|
||||||
@@ -295,6 +367,13 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_Array, function To_Moz_ArrayExpression(M) {
|
||||||
|
return {
|
||||||
|
type: "ArrayExpression",
|
||||||
|
elements: M.elements.map(to_moz)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) {
|
def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) {
|
||||||
return {
|
return {
|
||||||
type: "ObjectExpression",
|
type: "ObjectExpression",
|
||||||
@@ -334,6 +413,19 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) {
|
||||||
|
var value = M.value;
|
||||||
|
return {
|
||||||
|
type: "Literal",
|
||||||
|
value: value,
|
||||||
|
raw: value.toString(),
|
||||||
|
regex: {
|
||||||
|
pattern: value.source,
|
||||||
|
flags: value.toString().match(/[gimuy]*$/)[0]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
def_to_moz(AST_Constant, function To_Moz_Literal(M) {
|
def_to_moz(AST_Constant, function To_Moz_Literal(M) {
|
||||||
var value = M.value;
|
var value = M.value;
|
||||||
if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) {
|
if (typeof value === 'number' && (value < 0 || (value === 0 && 1 / value < 0))) {
|
||||||
@@ -343,13 +435,15 @@
|
|||||||
prefix: true,
|
prefix: true,
|
||||||
argument: {
|
argument: {
|
||||||
type: "Literal",
|
type: "Literal",
|
||||||
value: -value
|
value: -value,
|
||||||
|
raw: M.start.raw
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
type: "Literal",
|
type: "Literal",
|
||||||
value: value
|
value: value,
|
||||||
|
raw: M.start.raw
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -369,6 +463,12 @@
|
|||||||
|
|
||||||
/* -----[ tools ]----- */
|
/* -----[ tools ]----- */
|
||||||
|
|
||||||
|
function raw_token(moznode) {
|
||||||
|
if (moznode.type == "Literal") {
|
||||||
|
return moznode.raw != null ? moznode.raw : moznode.value + "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function my_start_token(moznode) {
|
function my_start_token(moznode) {
|
||||||
var loc = moznode.loc, start = loc && loc.start;
|
var loc = moznode.loc, start = loc && loc.start;
|
||||||
var range = moznode.range;
|
var range = moznode.range;
|
||||||
@@ -379,7 +479,8 @@
|
|||||||
pos : range ? range[0] : moznode.start,
|
pos : range ? range[0] : moznode.start,
|
||||||
endline : start && start.line,
|
endline : start && start.line,
|
||||||
endcol : start && start.column,
|
endcol : start && start.column,
|
||||||
endpos : range ? range[0] : moznode.start
|
endpos : range ? range[0] : moznode.start,
|
||||||
|
raw : raw_token(moznode),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -393,13 +494,14 @@
|
|||||||
pos : range ? range[1] : moznode.end,
|
pos : range ? range[1] : moznode.end,
|
||||||
endline : end && end.line,
|
endline : end && end.line,
|
||||||
endcol : end && end.column,
|
endcol : end && end.column,
|
||||||
endpos : range ? range[1] : moznode.end
|
endpos : range ? range[1] : moznode.end,
|
||||||
|
raw : raw_token(moznode),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
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.name + "({\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)";
|
||||||
|
|
||||||
@@ -442,8 +544,8 @@
|
|||||||
//me_to_moz = parse(me_to_moz).print_to_string({ beautify: true });
|
//me_to_moz = parse(me_to_moz).print_to_string({ beautify: true });
|
||||||
//console.log(moz_to_me);
|
//console.log(moz_to_me);
|
||||||
|
|
||||||
moz_to_me = new Function("my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
|
moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")(
|
||||||
my_start_token, my_end_token, from_moz
|
exports, my_start_token, my_end_token, from_moz
|
||||||
);
|
);
|
||||||
me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")(
|
me_to_moz = new Function("to_moz", "to_moz_block", "return(" + me_to_moz + ")")(
|
||||||
to_moz, to_moz_block
|
to_moz, to_moz_block
|
||||||
|
|||||||
273
lib/output.js
273
lib/output.js
@@ -43,6 +43,8 @@
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/;
|
||||||
|
|
||||||
function OutputStream(options) {
|
function OutputStream(options) {
|
||||||
|
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
@@ -60,10 +62,12 @@ function OutputStream(options) {
|
|||||||
bracketize : false,
|
bracketize : false,
|
||||||
semicolons : true,
|
semicolons : true,
|
||||||
comments : false,
|
comments : false,
|
||||||
|
shebang : true,
|
||||||
preserve_line : false,
|
preserve_line : false,
|
||||||
screw_ie8 : false,
|
screw_ie8 : true,
|
||||||
preamble : null,
|
preamble : null,
|
||||||
quote_style : 0
|
quote_style : 0,
|
||||||
|
keep_quoted_props: false
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
var indentation = 0;
|
var indentation = 0;
|
||||||
@@ -73,7 +77,7 @@ function OutputStream(options) {
|
|||||||
var OUTPUT = "";
|
var OUTPUT = "";
|
||||||
|
|
||||||
function to_ascii(str, identifier) {
|
function to_ascii(str, identifier) {
|
||||||
return str.replace(/[\u0080-\uffff]/g, function(ch) {
|
return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) {
|
||||||
var code = ch.charCodeAt(0).toString(16);
|
var code = ch.charCodeAt(0).toString(16);
|
||||||
if (code.length <= 2 && !identifier) {
|
if (code.length <= 2 && !identifier) {
|
||||||
while (code.length < 2) code = "0" + code;
|
while (code.length < 2) code = "0" + code;
|
||||||
@@ -87,19 +91,23 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
function make_string(str, quote) {
|
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\ufeff]/g, function(s){
|
str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g,
|
||||||
|
function(s, i){
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case "\\": return "\\\\";
|
|
||||||
case "\b": return "\\b";
|
|
||||||
case "\f": return "\\f";
|
|
||||||
case "\n": return "\\n";
|
|
||||||
case "\r": return "\\r";
|
|
||||||
case "\u2028": return "\\u2028";
|
|
||||||
case "\u2029": return "\\u2029";
|
|
||||||
case '"': ++dq; return '"';
|
case '"': ++dq; return '"';
|
||||||
case "'": ++sq; return "'";
|
case "'": ++sq; return "'";
|
||||||
case "\0": return "\\x00";
|
case "\\": return "\\\\";
|
||||||
|
case "\n": return "\\n";
|
||||||
|
case "\r": return "\\r";
|
||||||
|
case "\t": return "\\t";
|
||||||
|
case "\b": return "\\b";
|
||||||
|
case "\f": return "\\f";
|
||||||
|
case "\x0B": return options.screw_ie8 ? "\\v" : "\\x0B";
|
||||||
|
case "\u2028": return "\\u2028";
|
||||||
|
case "\u2029": return "\\u2029";
|
||||||
case "\ufeff": return "\\ufeff";
|
case "\ufeff": return "\\ufeff";
|
||||||
|
case "\0":
|
||||||
|
return /[0-7]/.test(str.charAt(i+1)) ? "\\x00" : "\\0";
|
||||||
}
|
}
|
||||||
return s;
|
return s;
|
||||||
});
|
});
|
||||||
@@ -124,8 +132,11 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
function encode_string(str, quote) {
|
function encode_string(str, quote) {
|
||||||
var ret = make_string(str, quote);
|
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");
|
||||||
|
ret = ret.replace(/\x3c!--/g, "\\x3c!--");
|
||||||
|
ret = ret.replace(/--\x3e/g, "--\\x3e");
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,6 +172,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 += ";";
|
||||||
@@ -171,11 +184,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
|
if (!options.beautify && options.preserve_line && stack[stack.length - 1]) {
|
||||||
@@ -338,7 +357,18 @@ 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, quote) { print(encode_string(str, quote)) },
|
print_string : function(str, quote, escape_directive) {
|
||||||
|
var encoded = encode_string(str, quote);
|
||||||
|
if (escape_directive === true && encoded.indexOf("\\") === -1) {
|
||||||
|
// Insert semicolons to break directive prologue
|
||||||
|
if (!EXPECT_DIRECTIVE.test(OUTPUT)) {
|
||||||
|
force_semicolon();
|
||||||
|
}
|
||||||
|
force_semicolon();
|
||||||
|
}
|
||||||
|
print(encoded);
|
||||||
|
},
|
||||||
|
encode_string : encode_string,
|
||||||
next_indent : next_indent,
|
next_indent : next_indent,
|
||||||
with_indent : with_indent,
|
with_indent : with_indent,
|
||||||
with_block : with_block,
|
with_block : with_block,
|
||||||
@@ -369,8 +399,14 @@ function OutputStream(options) {
|
|||||||
nodetype.DEFMETHOD("_codegen", generator);
|
nodetype.DEFMETHOD("_codegen", generator);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var use_asm = false;
|
||||||
|
var in_directive = false;
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
||||||
var self = this, generator = self._codegen;
|
var self = this, generator = self._codegen, prev_use_asm = use_asm;
|
||||||
|
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
|
||||||
|
use_asm = true;
|
||||||
|
}
|
||||||
function doit() {
|
function doit() {
|
||||||
self.add_comments(stream);
|
self.add_comments(stream);
|
||||||
self.add_source_map(stream);
|
self.add_source_map(stream);
|
||||||
@@ -383,10 +419,14 @@ function OutputStream(options) {
|
|||||||
doit();
|
doit();
|
||||||
}
|
}
|
||||||
stream.pop_node();
|
stream.pop_node();
|
||||||
|
if (self instanceof AST_Scope) {
|
||||||
|
use_asm = prev_use_asm;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print_to_string", function(options){
|
AST_Node.DEFMETHOD("print_to_string", function(options){
|
||||||
var s = OutputStream(options);
|
var s = OutputStream(options);
|
||||||
|
if (!options) s._readonly = true;
|
||||||
this.print(s);
|
this.print(s);
|
||||||
return s.get();
|
return s.get();
|
||||||
});
|
});
|
||||||
@@ -394,64 +434,71 @@ function OutputStream(options) {
|
|||||||
/* -----[ comments ]----- */
|
/* -----[ comments ]----- */
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("add_comments", function(output){
|
AST_Node.DEFMETHOD("add_comments", function(output){
|
||||||
|
if (output._readonly) return;
|
||||||
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
|
||||||
// and https://github.com/mishoo/UglifyJS2/issues/372
|
// and https://github.com/mishoo/UglifyJS2/issues/372
|
||||||
if (self instanceof AST_Exit && self.value) {
|
if (self instanceof AST_Exit && self.value) {
|
||||||
self.value.walk(new TreeWalker(function(node){
|
self.value.walk(new TreeWalker(function(node){
|
||||||
if (node.start && node.start.comments_before) {
|
if (node.start && node.start.comments_before) {
|
||||||
comments = comments.concat(node.start.comments_before);
|
comments = comments.concat(node.start.comments_before);
|
||||||
node.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) {
|
|
||||||
comments = comments.filter(function(comment){
|
|
||||||
return c.test(comment.value);
|
|
||||||
});
|
|
||||||
} else if (typeof c == "function") {
|
|
||||||
comments = comments.filter(function(comment){
|
|
||||||
return c(self, comment);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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") {
|
if (node instanceof AST_Function ||
|
||||||
output.print("/*" + c.value + "*/");
|
node instanceof AST_Array ||
|
||||||
if (start.nlb) {
|
node instanceof AST_Object)
|
||||||
output.print("\n");
|
{
|
||||||
output.indent();
|
return true; // don't go inside.
|
||||||
} else {
|
|
||||||
output.space();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c) {
|
||||||
|
comments = comments.filter(function(comment) {
|
||||||
|
return comment.type == "comment5";
|
||||||
|
});
|
||||||
|
} else if (c.test) {
|
||||||
|
comments = comments.filter(function(comment){
|
||||||
|
return comment.type == "comment5" || c.test(comment.value);
|
||||||
|
});
|
||||||
|
} else if (typeof c == "function") {
|
||||||
|
comments = comments.filter(function(comment){
|
||||||
|
return comment.type == "comment5" || c(self, comment);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -484,8 +531,11 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
PARENS([ AST_Unary, AST_Undefined ], function(output){
|
PARENS([ AST_Unary, AST_Undefined ], function(output){
|
||||||
|
if (this.expression instanceof AST_Call)
|
||||||
|
return false;
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
return p instanceof AST_PropAccess && p.expression === this;
|
return p instanceof AST_PropAccess && p.expression === this
|
||||||
|
|| p instanceof AST_Call && p.expression === this;
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS(AST_Seq, function(output){
|
PARENS(AST_Seq, function(output){
|
||||||
@@ -561,7 +611,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
PARENS(AST_New, function(output){
|
PARENS(AST_New, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (no_constructor_parens(this, output)
|
if (!need_constructor_parens(this, output)
|
||||||
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
&& (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]()
|
||||||
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
|| p instanceof AST_Call && p.expression === this)) // (new foo)(bar)
|
||||||
return true;
|
return true;
|
||||||
@@ -569,8 +619,12 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
PARENS(AST_Number, function(output){
|
PARENS(AST_Number, function(output){
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
if (this.getValue() < 0 && p instanceof AST_PropAccess && p.expression === this)
|
if (p instanceof AST_PropAccess && p.expression === this) {
|
||||||
return true;
|
var value = this.getValue();
|
||||||
|
if (value < 0 || /^0/.test(make_num(value))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
PARENS([ AST_Assign, AST_Conditional ], function (output){
|
PARENS([ AST_Assign, AST_Conditional ], function (output){
|
||||||
@@ -605,9 +659,16 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
/* -----[ statements ]----- */
|
/* -----[ statements ]----- */
|
||||||
|
|
||||||
function display_body(body, is_toplevel, output) {
|
function display_body(body, is_toplevel, output, allow_directives) {
|
||||||
var last = body.length - 1;
|
var last = body.length - 1;
|
||||||
|
in_directive = allow_directives;
|
||||||
body.forEach(function(stmt, i){
|
body.forEach(function(stmt, i){
|
||||||
|
if (in_directive === true && !(stmt instanceof AST_Directive ||
|
||||||
|
stmt instanceof AST_EmptyStatement ||
|
||||||
|
(stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String)
|
||||||
|
)) {
|
||||||
|
in_directive = false;
|
||||||
|
}
|
||||||
if (!(stmt instanceof AST_EmptyStatement)) {
|
if (!(stmt instanceof AST_EmptyStatement)) {
|
||||||
output.indent();
|
output.indent();
|
||||||
stmt.print(output);
|
stmt.print(output);
|
||||||
@@ -616,7 +677,14 @@ function OutputStream(options) {
|
|||||||
if (is_toplevel) output.newline();
|
if (is_toplevel) output.newline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (in_directive === true &&
|
||||||
|
stmt instanceof AST_SimpleStatement &&
|
||||||
|
stmt.body instanceof AST_String
|
||||||
|
) {
|
||||||
|
in_directive = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
in_directive = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
|
AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output){
|
||||||
@@ -628,7 +696,7 @@ function OutputStream(options) {
|
|||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Toplevel, function(self, output){
|
DEFPRINT(AST_Toplevel, function(self, output){
|
||||||
display_body(self.body, true, output);
|
display_body(self.body, true, output, true);
|
||||||
output.print("");
|
output.print("");
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_LabeledStatement, function(self, output){
|
DEFPRINT(AST_LabeledStatement, function(self, output){
|
||||||
@@ -640,9 +708,9 @@ function OutputStream(options) {
|
|||||||
self.body.print(output);
|
self.body.print(output);
|
||||||
output.semicolon();
|
output.semicolon();
|
||||||
});
|
});
|
||||||
function print_bracketed(body, output) {
|
function print_bracketed(body, output, allow_directives) {
|
||||||
if (body.length > 0) output.with_block(function(){
|
if (body.length > 0) output.with_block(function(){
|
||||||
display_body(body, false, output);
|
display_body(body, false, output, allow_directives);
|
||||||
});
|
});
|
||||||
else output.print("{}");
|
else output.print("{}");
|
||||||
};
|
};
|
||||||
@@ -742,7 +810,7 @@ function OutputStream(options) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
output.space();
|
output.space();
|
||||||
print_bracketed(self.body, output);
|
print_bracketed(self.body, output, true);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Lambda, function(self, output){
|
DEFPRINT(AST_Lambda, function(self, output){
|
||||||
self._do_print(output);
|
self._do_print(output);
|
||||||
@@ -795,8 +863,8 @@ function OutputStream(options) {
|
|||||||
// adds the block brackets if needed.
|
// adds the block brackets if needed.
|
||||||
if (!self.body)
|
if (!self.body)
|
||||||
return output.force_semicolon();
|
return output.force_semicolon();
|
||||||
if (self.body instanceof AST_Do
|
if (self.body instanceof AST_Do) {
|
||||||
&& !output.option("screw_ie8")) {
|
// Unconditionally use the if/do-while workaround for all browsers.
|
||||||
// https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
|
// https://github.com/mishoo/UglifyJS/issues/#issue/57 IE
|
||||||
// croaks with "syntax error" on code like this: if (foo)
|
// croaks with "syntax error" on code like this: if (foo)
|
||||||
// do ... while(cond); else ... we need block brackets
|
// do ... while(cond); else ... we need block brackets
|
||||||
@@ -958,7 +1026,7 @@ function OutputStream(options) {
|
|||||||
/* -----[ other expressions ]----- */
|
/* -----[ other expressions ]----- */
|
||||||
DEFPRINT(AST_Call, function(self, output){
|
DEFPRINT(AST_Call, function(self, output){
|
||||||
self.expression.print(output);
|
self.expression.print(output);
|
||||||
if (self instanceof AST_New && no_constructor_parens(self, output))
|
if (self instanceof AST_New && !need_constructor_parens(self, output))
|
||||||
return;
|
return;
|
||||||
output.with_parens(function(){
|
output.with_parens(function(){
|
||||||
self.args.forEach(function(expr, i){
|
self.args.forEach(function(expr, i){
|
||||||
@@ -999,7 +1067,7 @@ function OutputStream(options) {
|
|||||||
var expr = self.expression;
|
var expr = self.expression;
|
||||||
expr.print(output);
|
expr.print(output);
|
||||||
if (expr instanceof AST_Number && expr.getValue() >= 0) {
|
if (expr instanceof AST_Number && expr.getValue() >= 0) {
|
||||||
if (!/[xa-f.]/i.test(output.last())) {
|
if (!/[xa-f.)]/i.test(output.last())) {
|
||||||
output.print(".");
|
output.print(".");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1030,16 +1098,24 @@ function OutputStream(options) {
|
|||||||
output.print(self.operator);
|
output.print(self.operator);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Binary, function(self, output){
|
DEFPRINT(AST_Binary, function(self, output){
|
||||||
|
var op = self.operator;
|
||||||
self.left.print(output);
|
self.left.print(output);
|
||||||
output.space();
|
if (op[0] == ">" /* ">>" ">>>" ">" ">=" */
|
||||||
output.print(self.operator);
|
&& self.left instanceof AST_UnaryPostfix
|
||||||
if (self.operator == "<"
|
&& self.left.operator == "--") {
|
||||||
|
// space is mandatory to avoid outputting -->
|
||||||
|
output.print(" ");
|
||||||
|
} else {
|
||||||
|
// the space is optional depending on "beautify"
|
||||||
|
output.space();
|
||||||
|
}
|
||||||
|
output.print(op);
|
||||||
|
if ((op == "<" || op == "<<")
|
||||||
&& self.right instanceof AST_UnaryPrefix
|
&& self.right instanceof AST_UnaryPrefix
|
||||||
&& self.right.operator == "!"
|
&& self.right.operator == "!"
|
||||||
&& self.right.expression instanceof AST_UnaryPrefix
|
&& self.right.expression instanceof AST_UnaryPrefix
|
||||||
&& self.right.expression.operator == "--") {
|
&& self.right.expression.operator == "--") {
|
||||||
// space is mandatory to avoid outputting <!--
|
// space is mandatory to avoid outputting <!--
|
||||||
// http://javascript.spec.whatwg.org/#comment-syntax
|
|
||||||
output.print(" ");
|
output.print(" ");
|
||||||
} else {
|
} else {
|
||||||
// the space is optional depending on "beautify"
|
// the space is optional depending on "beautify"
|
||||||
@@ -1100,7 +1176,11 @@ function OutputStream(options) {
|
|||||||
&& parseFloat(key) >= 0) {
|
&& parseFloat(key) >= 0) {
|
||||||
output.print(make_num(key));
|
output.print(make_num(key));
|
||||||
} 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);
|
if (quote && output.option("keep_quoted_props")) {
|
||||||
|
output.print_string(key, quote);
|
||||||
|
} else {
|
||||||
|
output.print_name(key);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
output.print_string(key, quote);
|
output.print_string(key, quote);
|
||||||
}
|
}
|
||||||
@@ -1140,10 +1220,14 @@ 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(), self.quote);
|
output.print_string(self.getValue(), self.quote, in_directive);
|
||||||
});
|
});
|
||||||
DEFPRINT(AST_Number, function(self, output){
|
DEFPRINT(AST_Number, function(self, output){
|
||||||
output.print(make_num(self.getValue()));
|
if (use_asm && self.start && self.start.raw != null) {
|
||||||
|
output.print(self.start.raw);
|
||||||
|
} else {
|
||||||
|
output.print(make_num(self.getValue()));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function regexp_safe_literal(code) {
|
function regexp_safe_literal(code) {
|
||||||
@@ -1236,8 +1320,11 @@ function OutputStream(options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// self should be AST_New. decide if we want to show parens or not.
|
// self should be AST_New. decide if we want to show parens or not.
|
||||||
function no_constructor_parens(self, output) {
|
function need_constructor_parens(self, output) {
|
||||||
return self.args.length == 0 && !output.option("beautify");
|
// Always print parentheses with arguments
|
||||||
|
if (self.args.length > 0) return true;
|
||||||
|
|
||||||
|
return output.option("beautify");
|
||||||
};
|
};
|
||||||
|
|
||||||
function best_of(a) {
|
function best_of(a) {
|
||||||
@@ -1319,6 +1406,12 @@ function OutputStream(options) {
|
|||||||
DEFMAP(AST_Finally, basic_sourcemap_gen);
|
DEFMAP(AST_Finally, basic_sourcemap_gen);
|
||||||
DEFMAP(AST_Definitions, basic_sourcemap_gen);
|
DEFMAP(AST_Definitions, basic_sourcemap_gen);
|
||||||
DEFMAP(AST_Constant, basic_sourcemap_gen);
|
DEFMAP(AST_Constant, basic_sourcemap_gen);
|
||||||
|
DEFMAP(AST_ObjectSetter, function(self, output){
|
||||||
|
output.add_mapping(self.start, self.key.name);
|
||||||
|
});
|
||||||
|
DEFMAP(AST_ObjectGetter, function(self, output){
|
||||||
|
output.add_mapping(self.start, self.key.name);
|
||||||
|
});
|
||||||
DEFMAP(AST_ObjectProperty, function(self, output){
|
DEFMAP(AST_ObjectProperty, function(self, output){
|
||||||
output.add_mapping(self.start, self.key);
|
output.add_mapping(self.start, self.key);
|
||||||
});
|
});
|
||||||
|
|||||||
275
lib/parse.js
275
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 yield'
|
var RESERVED_WORDS = 'abstract boolean byte char class double enum export extends final float goto implements import int interface let 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';
|
||||||
|
|
||||||
@@ -59,7 +59,6 @@ var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^"));
|
|||||||
|
|
||||||
var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
|
var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
|
||||||
var RE_OCT_NUMBER = /^0[0-7]+$/;
|
var RE_OCT_NUMBER = /^0[0-7]+$/;
|
||||||
var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i;
|
|
||||||
|
|
||||||
var OPERATORS = makePredicate([
|
var OPERATORS = makePredicate([
|
||||||
"in",
|
"in",
|
||||||
@@ -108,7 +107,9 @@ 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\uFEFF"));
|
var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\uFEFF"));
|
||||||
|
|
||||||
|
var NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029"));
|
||||||
|
|
||||||
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
|
var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,.;:"));
|
||||||
|
|
||||||
@@ -182,8 +183,9 @@ function parse_js_number(num) {
|
|||||||
return parseInt(num.substr(2), 16);
|
return parseInt(num.substr(2), 16);
|
||||||
} else if (RE_OCT_NUMBER.test(num)) {
|
} else if (RE_OCT_NUMBER.test(num)) {
|
||||||
return parseInt(num.substr(1), 8);
|
return parseInt(num.substr(1), 8);
|
||||||
} else if (RE_DEC_NUMBER.test(num)) {
|
} else {
|
||||||
return parseFloat(num);
|
var val = parseFloat(num);
|
||||||
|
if (val == num) return val;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -210,7 +212,7 @@ function is_token(token, type, val) {
|
|||||||
|
|
||||||
var EX_EOF = {};
|
var EX_EOF = {};
|
||||||
|
|
||||||
function tokenizer($TEXT, filename, html5_comments) {
|
function tokenizer($TEXT, filename, html5_comments, shebang) {
|
||||||
|
|
||||||
var S = {
|
var S = {
|
||||||
text : $TEXT,
|
text : $TEXT,
|
||||||
@@ -223,7 +225,9 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
tokcol : 0,
|
tokcol : 0,
|
||||||
newline_before : false,
|
newline_before : false,
|
||||||
regex_allowed : false,
|
regex_allowed : false,
|
||||||
comments_before : []
|
comments_before : [],
|
||||||
|
directives : {},
|
||||||
|
directive_stack : []
|
||||||
};
|
};
|
||||||
|
|
||||||
function peek() { return S.text.charAt(S.pos); };
|
function peek() { return S.text.charAt(S.pos); };
|
||||||
@@ -232,7 +236,7 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
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 ("\r\n\u2028\u2029".indexOf(ch) >= 0) {
|
if (NEWLINE_CHARS(ch)) {
|
||||||
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;
|
||||||
@@ -255,6 +259,16 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
return S.text.substr(S.pos, str.length) == str;
|
return S.text.substr(S.pos, str.length) == str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function find_eol() {
|
||||||
|
var text = S.text;
|
||||||
|
for (var i = S.pos, n = S.text.length; i < n; ++i) {
|
||||||
|
var ch = text[i];
|
||||||
|
if (NEWLINE_CHARS(ch))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
};
|
||||||
|
|
||||||
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;
|
||||||
@@ -285,6 +299,9 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
nlb : S.newline_before,
|
nlb : S.newline_before,
|
||||||
file : filename
|
file : filename
|
||||||
};
|
};
|
||||||
|
if (/^(?:num|string|regexp)$/i.test(type)) {
|
||||||
|
ret.raw = $TEXT.substring(ret.pos, ret.endpos);
|
||||||
|
}
|
||||||
if (!is_comment) {
|
if (!is_comment) {
|
||||||
ret.comments_before = S.comments_before;
|
ret.comments_before = S.comments_before;
|
||||||
S.comments_before = [];
|
S.comments_before = [];
|
||||||
@@ -298,8 +315,7 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function skip_whitespace() {
|
function skip_whitespace() {
|
||||||
var ch;
|
while (WHITESPACE_CHARS(peek()))
|
||||||
while (WHITESPACE_CHARS(ch = peek()) || ch == "\u2028" || ch == "\u2029")
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -333,11 +349,14 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
return is_alphanumeric_char(code);
|
return is_alphanumeric_char(code);
|
||||||
});
|
});
|
||||||
if (prefix) num = prefix + num;
|
if (prefix) num = prefix + num;
|
||||||
|
if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) {
|
||||||
|
parse_error("SyntaxError: Legacy octal literals are not allowed in strict mode");
|
||||||
|
}
|
||||||
var valid = parse_js_number(num);
|
var valid = parse_js_number(num);
|
||||||
if (!isNaN(valid)) {
|
if (!isNaN(valid)) {
|
||||||
return token("num", valid);
|
return token("num", valid);
|
||||||
} else {
|
} else {
|
||||||
parse_error("Invalid syntax: " + num);
|
parse_error("SyntaxError: Invalid syntax: " + num);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -350,7 +369,6 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
case 98 : return "\b";
|
case 98 : return "\b";
|
||||||
case 118 : return "\u000b"; // \v
|
case 118 : return "\u000b"; // \v
|
||||||
case 102 : return "\f";
|
case 102 : return "\f";
|
||||||
case 48 : return "\0";
|
|
||||||
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
|
||||||
@@ -360,42 +378,44 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ch >= "0" && ch <= "7")
|
||||||
|
return read_octal_escape_sequence(ch);
|
||||||
return ch;
|
return ch;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function read_octal_escape_sequence(ch) {
|
||||||
|
// Read
|
||||||
|
var p = peek();
|
||||||
|
if (p >= "0" && p <= "7") {
|
||||||
|
ch += next(true);
|
||||||
|
if (ch[0] <= "3" && (p = peek()) >= "0" && p <= "7")
|
||||||
|
ch += next(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse
|
||||||
|
if (ch === "0") return "\0";
|
||||||
|
if (ch.length > 0 && next_token.has_directive("use strict"))
|
||||||
|
parse_error("SyntaxError: Legacy octal escape sequences are not allowed in strict mode");
|
||||||
|
return String.fromCharCode(parseInt(ch, 8));
|
||||||
|
}
|
||||||
|
|
||||||
function hex_bytes(n) {
|
function hex_bytes(n) {
|
||||||
var num = 0;
|
var num = 0;
|
||||||
for (; n > 0; --n) {
|
for (; n > 0; --n) {
|
||||||
var digit = parseInt(next(true), 16);
|
var digit = parseInt(next(true), 16);
|
||||||
if (isNaN(digit))
|
if (isNaN(digit))
|
||||||
parse_error("Invalid hex-character pattern in string");
|
parse_error("SyntaxError: Invalid hex-character pattern in string");
|
||||||
num = (num << 4) | digit;
|
num = (num << 4) | digit;
|
||||||
}
|
}
|
||||||
return num;
|
return num;
|
||||||
};
|
};
|
||||||
|
|
||||||
var read_string = with_eof_error("Unterminated string constant", function(quote_char){
|
var read_string = with_eof_error("SyntaxError: Unterminated string constant", function(quote_char){
|
||||||
var quote = next(), ret = "";
|
var quote = next(), ret = "";
|
||||||
for (;;) {
|
for (;;) {
|
||||||
var ch = next(true, true);
|
var ch = next(true, true);
|
||||||
if (ch == "\\") {
|
if (ch == "\\") ch = read_escaped_char(true);
|
||||||
// read OctalEscapeSequence (XXX: deprecated if "strict mode")
|
else if (NEWLINE_CHARS(ch)) parse_error("SyntaxError: Unterminated string constant");
|
||||||
// https://github.com/mishoo/UglifyJS/issues/178
|
|
||||||
var octal_len = 0, first = null;
|
|
||||||
ch = read_while(function(ch){
|
|
||||||
if (ch >= "0" && ch <= "7") {
|
|
||||||
if (!first) {
|
|
||||||
first = ch;
|
|
||||||
return ++octal_len;
|
|
||||||
}
|
|
||||||
else if (first <= "3" && octal_len <= 2) return ++octal_len;
|
|
||||||
else if (first >= "4" && octal_len <= 1) return ++octal_len;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
if (octal_len > 0) ch = String.fromCharCode(parseInt(ch, 8));
|
|
||||||
else ch = read_escaped_char(true);
|
|
||||||
}
|
|
||||||
else if (ch == quote) break;
|
else if (ch == quote) break;
|
||||||
ret += ch;
|
ret += ch;
|
||||||
}
|
}
|
||||||
@@ -406,7 +426,7 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
|
|
||||||
function skip_line_comment(type) {
|
function skip_line_comment(type) {
|
||||||
var regex_allowed = S.regex_allowed;
|
var regex_allowed = S.regex_allowed;
|
||||||
var i = find("\n"), ret;
|
var i = find_eol(), ret;
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
ret = S.text.substr(S.pos);
|
ret = S.text.substr(S.pos);
|
||||||
S.pos = S.text.length;
|
S.pos = S.text.length;
|
||||||
@@ -417,25 +437,18 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
S.col = S.tokcol + (S.pos - S.tokpos);
|
S.col = S.tokcol + (S.pos - S.tokpos);
|
||||||
S.comments_before.push(token(type, ret, true));
|
S.comments_before.push(token(type, ret, true));
|
||||||
S.regex_allowed = regex_allowed;
|
S.regex_allowed = regex_allowed;
|
||||||
return next_token();
|
return next_token;
|
||||||
};
|
};
|
||||||
|
|
||||||
var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function(){
|
var skip_multiline_comment = with_eof_error("SyntaxError: Unterminated multiline comment", function(){
|
||||||
var regex_allowed = S.regex_allowed;
|
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).replace(/\r\n|\r|\u2028|\u2029/g, '\n');
|
||||||
var a = text.split("\n"), n = a.length;
|
|
||||||
// update stream position
|
// update stream position
|
||||||
S.pos = i + 2;
|
forward(text.length /* doesn't count \r\n as 2 char while S.pos - i does */ + 2);
|
||||||
S.line += n - 1;
|
|
||||||
if (n > 1) S.col = a[n - 1].length;
|
|
||||||
else S.col += a[n - 1].length;
|
|
||||||
S.col += 2;
|
|
||||||
var nlb = S.newline_before = S.newline_before || text.indexOf("\n") >= 0;
|
|
||||||
S.comments_before.push(token("comment2", text, true));
|
S.comments_before.push(token("comment2", text, true));
|
||||||
S.regex_allowed = regex_allowed;
|
S.regex_allowed = regex_allowed;
|
||||||
S.newline_before = nlb;
|
return next_token;
|
||||||
return next_token();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function read_name() {
|
function read_name() {
|
||||||
@@ -447,9 +460,9 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (ch != "u") parse_error("Expecting UnicodeEscapeSequence -- uXXXX");
|
if (ch != "u") parse_error("SyntaxError: Expecting UnicodeEscapeSequence -- uXXXX");
|
||||||
ch = read_escaped_char();
|
ch = read_escaped_char();
|
||||||
if (!is_identifier_char(ch)) parse_error("Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
|
if (!is_identifier_char(ch)) parse_error("SyntaxError: Unicode char: " + ch.charCodeAt(0) + " is not valid in identifier");
|
||||||
name += ch;
|
name += ch;
|
||||||
backslash = false;
|
backslash = false;
|
||||||
}
|
}
|
||||||
@@ -461,9 +474,11 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
|
var read_regexp = with_eof_error("SyntaxError: Unterminated regular expression", function(regexp){
|
||||||
var prev_backslash = false, ch, in_class = false;
|
var prev_backslash = false, ch, in_class = false;
|
||||||
while ((ch = next(true))) if (prev_backslash) {
|
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
|
||||||
|
parse_error("SyntaxError: Unexpected line terminator");
|
||||||
|
} else if (prev_backslash) {
|
||||||
regexp += "\\" + ch;
|
regexp += "\\" + ch;
|
||||||
prev_backslash = false;
|
prev_backslash = false;
|
||||||
} else if (ch == "[") {
|
} else if (ch == "[") {
|
||||||
@@ -480,7 +495,11 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
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("SyntaxError: " + e.message);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function read_operator(prefix) {
|
function read_operator(prefix) {
|
||||||
@@ -540,31 +559,47 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
function next_token(force_regexp) {
|
function next_token(force_regexp) {
|
||||||
if (force_regexp != null)
|
if (force_regexp != null)
|
||||||
return read_regexp(force_regexp);
|
return read_regexp(force_regexp);
|
||||||
skip_whitespace();
|
for (;;) {
|
||||||
start_token();
|
skip_whitespace();
|
||||||
if (html5_comments) {
|
start_token();
|
||||||
if (looking_at("<!--")) {
|
if (html5_comments) {
|
||||||
forward(4);
|
if (looking_at("<!--")) {
|
||||||
return skip_line_comment("comment3");
|
forward(4);
|
||||||
|
skip_line_comment("comment3");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (looking_at("-->") && S.newline_before) {
|
||||||
|
forward(3);
|
||||||
|
skip_line_comment("comment4");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (looking_at("-->") && S.newline_before) {
|
var ch = peek();
|
||||||
forward(3);
|
if (!ch) return token("eof");
|
||||||
return skip_line_comment("comment4");
|
var code = ch.charCodeAt(0);
|
||||||
|
switch (code) {
|
||||||
|
case 34: case 39: return read_string(ch);
|
||||||
|
case 46: return handle_dot();
|
||||||
|
case 47: {
|
||||||
|
var tok = handle_slash();
|
||||||
|
if (tok === next_token) continue;
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (is_digit(code)) return read_num();
|
||||||
|
if (PUNC_CHARS(ch)) return token("punc", next());
|
||||||
|
if (OPERATOR_CHARS(ch)) return read_operator();
|
||||||
|
if (code == 92 || is_identifier_start(code)) return read_word();
|
||||||
|
if (shebang) {
|
||||||
|
if (S.pos == 0 && looking_at("#!")) {
|
||||||
|
forward(2);
|
||||||
|
skip_line_comment("comment5");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
var ch = peek();
|
parse_error("SyntaxError: Unexpected character '" + ch + "'");
|
||||||
if (!ch) return token("eof");
|
|
||||||
var code = ch.charCodeAt(0);
|
|
||||||
switch (code) {
|
|
||||||
case 34: case 39: return read_string(ch);
|
|
||||||
case 46: return handle_dot();
|
|
||||||
case 47: return handle_slash();
|
|
||||||
}
|
|
||||||
if (is_digit(code)) return read_num();
|
|
||||||
if (PUNC_CHARS(ch)) return token("punc", next());
|
|
||||||
if (OPERATOR_CHARS(ch)) return read_operator();
|
|
||||||
if (code == 92 || is_identifier_start(code)) return read_word();
|
|
||||||
parse_error("Unexpected character '" + ch + "'");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
next_token.context = function(nc) {
|
next_token.context = function(nc) {
|
||||||
@@ -572,6 +607,35 @@ function tokenizer($TEXT, filename, html5_comments) {
|
|||||||
return S;
|
return S;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
next_token.add_directive = function(directive) {
|
||||||
|
S.directive_stack[S.directive_stack.length - 1].push(directive);
|
||||||
|
|
||||||
|
if (S.directives[directive] === undefined) {
|
||||||
|
S.directives[directive] = 1;
|
||||||
|
} else {
|
||||||
|
S.directives[directive]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
next_token.push_directives_stack = function() {
|
||||||
|
S.directive_stack.push([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
next_token.pop_directives_stack = function() {
|
||||||
|
var directives = S.directive_stack[S.directive_stack.length - 1];
|
||||||
|
|
||||||
|
for (var i = 0; i < directives.length; i++) {
|
||||||
|
S.directives[directives[i]]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
S.directive_stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
next_token.has_directive = function(directive) {
|
||||||
|
return S.directives[directive] !== undefined &&
|
||||||
|
S.directives[directive] > 0;
|
||||||
|
}
|
||||||
|
|
||||||
return next_token;
|
return next_token;
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -633,12 +697,13 @@ function parse($TEXT, options) {
|
|||||||
expression : false,
|
expression : false,
|
||||||
html5_comments : true,
|
html5_comments : true,
|
||||||
bare_returns : false,
|
bare_returns : false,
|
||||||
|
shebang : true,
|
||||||
});
|
});
|
||||||
|
|
||||||
var S = {
|
var S = {
|
||||||
input : (typeof $TEXT == "string"
|
input : (typeof $TEXT == "string"
|
||||||
? tokenizer($TEXT, options.filename,
|
? tokenizer($TEXT, options.filename,
|
||||||
options.html5_comments)
|
options.html5_comments, options.shebang)
|
||||||
: $TEXT),
|
: $TEXT),
|
||||||
token : null,
|
token : null,
|
||||||
prev : null,
|
prev : null,
|
||||||
@@ -691,14 +756,14 @@ function parse($TEXT, options) {
|
|||||||
function unexpected(token) {
|
function unexpected(token) {
|
||||||
if (token == null)
|
if (token == null)
|
||||||
token = S.token;
|
token = S.token;
|
||||||
token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")");
|
token_error(token, "SyntaxError: Unexpected token: " + token.type + " (" + token.value + ")");
|
||||||
};
|
};
|
||||||
|
|
||||||
function expect_token(type, val) {
|
function expect_token(type, val) {
|
||||||
if (is(type, val)) {
|
if (is(type, val)) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
|
token_error(S.token, "SyntaxError: Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»");
|
||||||
};
|
};
|
||||||
|
|
||||||
function expect(punc) { return expect_token("punc", punc); };
|
function expect(punc) { return expect_token("punc", punc); };
|
||||||
@@ -709,9 +774,9 @@ function parse($TEXT, options) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function semicolon() {
|
function semicolon(optional) {
|
||||||
if (is("punc", ";")) next();
|
if (is("punc", ";")) next();
|
||||||
else if (!can_insert_semicolon()) unexpected();
|
else if (!optional && !can_insert_semicolon()) unexpected();
|
||||||
};
|
};
|
||||||
|
|
||||||
function parenthesised() {
|
function parenthesised() {
|
||||||
@@ -744,9 +809,16 @@ function parse($TEXT, options) {
|
|||||||
handle_regexp();
|
handle_regexp();
|
||||||
switch (S.token.type) {
|
switch (S.token.type) {
|
||||||
case "string":
|
case "string":
|
||||||
|
var dir = false;
|
||||||
|
if (S.in_directives === true) {
|
||||||
|
if ((is_token(peek(), "punc", ";") || peek().nlb) && S.token.raw.indexOf("\\") === -1) {
|
||||||
|
S.input.add_directive(S.token.value);
|
||||||
|
} else {
|
||||||
|
S.in_directives = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
var dir = S.in_directives, stat = simple_statement();
|
var dir = S.in_directives, stat = simple_statement();
|
||||||
// XXXv2: decide how to fix directives
|
if (dir) {
|
||||||
if (dir && stat.body instanceof AST_String && !is("punc", ",")) {
|
|
||||||
return new AST_Directive({
|
return new AST_Directive({
|
||||||
start : stat.body.start,
|
start : stat.body.start,
|
||||||
end : stat.body.end,
|
end : stat.body.end,
|
||||||
@@ -778,6 +850,7 @@ function parse($TEXT, options) {
|
|||||||
case "(":
|
case "(":
|
||||||
return simple_statement();
|
return simple_statement();
|
||||||
case ";":
|
case ";":
|
||||||
|
S.in_directives = false;
|
||||||
next();
|
next();
|
||||||
return new AST_EmptyStatement();
|
return new AST_EmptyStatement();
|
||||||
default:
|
default:
|
||||||
@@ -799,7 +872,7 @@ function parse($TEXT, options) {
|
|||||||
case "do":
|
case "do":
|
||||||
return new AST_Do({
|
return new AST_Do({
|
||||||
body : in_loop(statement),
|
body : in_loop(statement),
|
||||||
condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(), tmp)
|
condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(true), tmp)
|
||||||
});
|
});
|
||||||
|
|
||||||
case "while":
|
case "while":
|
||||||
@@ -819,7 +892,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
case "return":
|
case "return":
|
||||||
if (S.in_function == 0 && !options.bare_returns)
|
if (S.in_function == 0 && !options.bare_returns)
|
||||||
croak("'return' outside of function");
|
croak("SyntaxError: 'return' outside of function");
|
||||||
return new AST_Return({
|
return new AST_Return({
|
||||||
value: ( is("punc", ";")
|
value: ( is("punc", ";")
|
||||||
? (next(), null)
|
? (next(), null)
|
||||||
@@ -836,7 +909,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
case "throw":
|
case "throw":
|
||||||
if (S.token.nlb)
|
if (S.token.nlb)
|
||||||
croak("Illegal newline after 'throw'");
|
croak("SyntaxError: Illegal newline after 'throw'");
|
||||||
return new AST_Throw({
|
return new AST_Throw({
|
||||||
value: (tmp = expression(true), semicolon(), tmp)
|
value: (tmp = expression(true), semicolon(), tmp)
|
||||||
});
|
});
|
||||||
@@ -851,6 +924,9 @@ function parse($TEXT, options) {
|
|||||||
return tmp = const_(), semicolon(), tmp;
|
return tmp = const_(), semicolon(), tmp;
|
||||||
|
|
||||||
case "with":
|
case "with":
|
||||||
|
if (S.input.has_directive("use strict")) {
|
||||||
|
croak("SyntaxError: Strict mode may not include a with statement");
|
||||||
|
}
|
||||||
return new AST_With({
|
return new AST_With({
|
||||||
expression : parenthesised(),
|
expression : parenthesised(),
|
||||||
body : statement()
|
body : statement()
|
||||||
@@ -869,7 +945,7 @@ function parse($TEXT, options) {
|
|||||||
// syntactically incorrect if it contains a
|
// syntactically incorrect if it contains a
|
||||||
// LabelledStatement that is enclosed by a
|
// LabelledStatement that is enclosed by a
|
||||||
// LabelledStatement with the same Identifier as label.
|
// LabelledStatement with the same Identifier as label.
|
||||||
croak("Label " + label.name + " defined twice");
|
croak("SyntaxError: Label " + label.name + " defined twice");
|
||||||
}
|
}
|
||||||
expect(":");
|
expect(":");
|
||||||
S.labels.push(label);
|
S.labels.push(label);
|
||||||
@@ -882,7 +958,7 @@ function parse($TEXT, options) {
|
|||||||
label.references.forEach(function(ref){
|
label.references.forEach(function(ref){
|
||||||
if (ref instanceof AST_Continue) {
|
if (ref instanceof AST_Continue) {
|
||||||
ref = ref.label.start;
|
ref = ref.label.start;
|
||||||
croak("Continue label `" + label.name + "` refers to non-IterationStatement.",
|
croak("SyntaxError: Continue label `" + label.name + "` refers to non-IterationStatement.",
|
||||||
ref.line, ref.col, ref.pos);
|
ref.line, ref.col, ref.pos);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -902,11 +978,11 @@ function parse($TEXT, options) {
|
|||||||
if (label != null) {
|
if (label != null) {
|
||||||
ldef = 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)
|
if (!ldef)
|
||||||
croak("Undefined label " + label.name);
|
croak("SyntaxError: Undefined label " + label.name);
|
||||||
label.thedef = ldef;
|
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("SyntaxError: " + type.TYPE + " not inside a loop or switch");
|
||||||
semicolon();
|
semicolon();
|
||||||
var stat = new type({ label: label });
|
var stat = new type({ label: label });
|
||||||
if (ldef) ldef.references.push(stat);
|
if (ldef) ldef.references.push(stat);
|
||||||
@@ -922,7 +998,7 @@ function parse($TEXT, options) {
|
|||||||
: expression(true, true);
|
: expression(true, true);
|
||||||
if (is("operator", "in")) {
|
if (is("operator", "in")) {
|
||||||
if (init instanceof AST_Var && init.definitions.length > 1)
|
if (init instanceof AST_Var && init.definitions.length > 1)
|
||||||
croak("Only one variable declaration allowed in for..in loop");
|
croak("SyntaxError: Only one variable declaration allowed in for..in loop");
|
||||||
next();
|
next();
|
||||||
return for_in(init);
|
return for_in(init);
|
||||||
}
|
}
|
||||||
@@ -975,9 +1051,11 @@ function parse($TEXT, options) {
|
|||||||
body: (function(loop, labels){
|
body: (function(loop, labels){
|
||||||
++S.in_function;
|
++S.in_function;
|
||||||
S.in_directives = true;
|
S.in_directives = true;
|
||||||
|
S.input.push_directives_stack();
|
||||||
S.in_loop = 0;
|
S.in_loop = 0;
|
||||||
S.labels = [];
|
S.labels = [];
|
||||||
var a = block_();
|
var a = block_();
|
||||||
|
S.input.pop_directives_stack();
|
||||||
--S.in_function;
|
--S.in_function;
|
||||||
S.in_loop = loop;
|
S.in_loop = loop;
|
||||||
S.labels = labels;
|
S.labels = labels;
|
||||||
@@ -1070,7 +1148,7 @@ function parse($TEXT, options) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!bcatch && !bfinally)
|
if (!bcatch && !bfinally)
|
||||||
croak("Missing catch/finally blocks");
|
croak("SyntaxError: Missing catch/finally blocks");
|
||||||
return new AST_Try({
|
return new AST_Try({
|
||||||
body : body,
|
body : body,
|
||||||
bcatch : bcatch,
|
bcatch : bcatch,
|
||||||
@@ -1110,7 +1188,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;
|
||||||
@@ -1125,7 +1203,7 @@ 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() {
|
||||||
@@ -1162,6 +1240,13 @@ function parse($TEXT, options) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "operator":
|
||||||
|
if (!is_identifier_string(tok.value)) {
|
||||||
|
croak("SyntaxError: Invalid getter/setter name: " + tok.value,
|
||||||
|
tok.line, tok.col, tok.pos);
|
||||||
|
}
|
||||||
|
ret = _make_symbol(AST_SymbolRef);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
return ret;
|
return ret;
|
||||||
@@ -1169,7 +1254,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")) {
|
||||||
@@ -1308,7 +1393,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function as_symbol(type, noerror) {
|
function as_symbol(type, noerror) {
|
||||||
if (!is("name")) {
|
if (!is("name")) {
|
||||||
if (!noerror) croak("Name expected");
|
if (!noerror) croak("SyntaxError: Name expected");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var sym = _make_symbol(type);
|
var sym = _make_symbol(type);
|
||||||
@@ -1372,7 +1457,7 @@ function parse($TEXT, options) {
|
|||||||
|
|
||||||
function make_unary(ctor, op, expr) {
|
function make_unary(ctor, op, expr) {
|
||||||
if ((op == "++" || op == "--") && !is_assignable(expr))
|
if ((op == "++" || op == "--") && !is_assignable(expr))
|
||||||
croak("Invalid use of " + op + " operator");
|
croak("SyntaxError: Invalid use of " + op + " operator");
|
||||||
return new ctor({ operator: op, expression: expr });
|
return new ctor({ operator: op, expression: expr });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1436,7 +1521,7 @@ function parse($TEXT, options) {
|
|||||||
end : prev()
|
end : prev()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
croak("Invalid assignment");
|
croak("SyntaxError: Invalid assignment");
|
||||||
}
|
}
|
||||||
return left;
|
return left;
|
||||||
};
|
};
|
||||||
@@ -1470,8 +1555,10 @@ function parse($TEXT, options) {
|
|||||||
return (function(){
|
return (function(){
|
||||||
var start = S.token;
|
var start = S.token;
|
||||||
var body = [];
|
var body = [];
|
||||||
|
S.input.push_directives_stack();
|
||||||
while (!is("eof"))
|
while (!is("eof"))
|
||||||
body.push(statement());
|
body.push(statement());
|
||||||
|
S.input.pop_directives_stack();
|
||||||
var end = prev();
|
var end = prev();
|
||||||
var toplevel = options.toplevel;
|
var toplevel = options.toplevel;
|
||||||
if (toplevel) {
|
if (toplevel) {
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ function mangle_properties(ast, options) {
|
|||||||
reserved : null,
|
reserved : null,
|
||||||
cache : null,
|
cache : null,
|
||||||
only_cache : false,
|
only_cache : false,
|
||||||
regex : null
|
regex : null,
|
||||||
|
ignore_quoted : false
|
||||||
});
|
});
|
||||||
|
|
||||||
var reserved = options.reserved;
|
var reserved = options.reserved;
|
||||||
@@ -81,50 +82,45 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var regex = options.regex;
|
var regex = options.regex;
|
||||||
|
var ignore_quoted = options.ignore_quoted;
|
||||||
|
|
||||||
var names_to_mangle = [];
|
var names_to_mangle = [];
|
||||||
|
var unmangleable = [];
|
||||||
|
var ignored = {};
|
||||||
|
|
||||||
// step 1: find candidates to mangle
|
// step 1: find candidates to mangle
|
||||||
ast.walk(new TreeWalker(function(node){
|
ast.walk(new TreeWalker(function(node){
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
add(node.key);
|
add(node.key, ignore_quoted && node.quote);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter, since KeyVal is handled above
|
// setter or getter, since KeyVal is handled above
|
||||||
add(node.key.name);
|
add(node.key.name);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Dot) {
|
else if (node instanceof AST_Dot) {
|
||||||
if (this.parent() instanceof AST_Assign) {
|
add(node.property);
|
||||||
add(node.property);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Sub) {
|
else if (node instanceof AST_Sub) {
|
||||||
if (this.parent() instanceof AST_Assign) {
|
addStrings(node.property, ignore_quoted);
|
||||||
addStrings(node.property);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// step 2: transform the tree, renaming properties
|
// step 2: transform the tree, renaming properties
|
||||||
return ast.transform(new TreeTransformer(function(node){
|
return ast.transform(new TreeTransformer(function(node){
|
||||||
if (node instanceof AST_ObjectKeyVal) {
|
if (node instanceof AST_ObjectKeyVal) {
|
||||||
if (should_mangle(node.key)) {
|
if (!(ignore_quoted && node.quote))
|
||||||
node.key = mangle(node.key);
|
node.key = mangle(node.key);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_ObjectProperty) {
|
else if (node instanceof AST_ObjectProperty) {
|
||||||
// setter or getter
|
// setter or getter
|
||||||
if (should_mangle(node.key.name)) {
|
node.key.name = mangle(node.key.name);
|
||||||
node.key.name = mangle(node.key.name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Dot) {
|
else if (node instanceof AST_Dot) {
|
||||||
if (should_mangle(node.property)) {
|
node.property = mangle(node.property);
|
||||||
node.property = mangle(node.property);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Sub) {
|
else if (node instanceof AST_Sub) {
|
||||||
node.property = mangleStrings(node.property);
|
if (!ignore_quoted)
|
||||||
|
node.property = mangleStrings(node.property);
|
||||||
}
|
}
|
||||||
// else if (node instanceof AST_String) {
|
// else if (node instanceof AST_String) {
|
||||||
// if (should_mangle(node.value)) {
|
// if (should_mangle(node.value)) {
|
||||||
@@ -143,6 +139,7 @@ function mangle_properties(ast, options) {
|
|||||||
// only function declarations after this line
|
// only function declarations after this line
|
||||||
|
|
||||||
function can_mangle(name) {
|
function can_mangle(name) {
|
||||||
|
if (unmangleable.indexOf(name) >= 0) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
if (options.only_cache) {
|
if (options.only_cache) {
|
||||||
return cache.props.has(name);
|
return cache.props.has(name);
|
||||||
@@ -152,18 +149,32 @@ function mangle_properties(ast, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function should_mangle(name) {
|
function should_mangle(name) {
|
||||||
|
if (ignore_quoted && name in ignored) return false;
|
||||||
if (regex && !regex.test(name)) return false;
|
if (regex && !regex.test(name)) return false;
|
||||||
if (reserved.indexOf(name) >= 0) return false;
|
if (reserved.indexOf(name) >= 0) return false;
|
||||||
return cache.props.has(name)
|
return cache.props.has(name)
|
||||||
|| names_to_mangle.indexOf(name) >= 0;
|
|| names_to_mangle.indexOf(name) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(name) {
|
function add(name, ignore) {
|
||||||
|
if (ignore) {
|
||||||
|
ignored[name] = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (can_mangle(name))
|
if (can_mangle(name))
|
||||||
push_uniq(names_to_mangle, name);
|
push_uniq(names_to_mangle, name);
|
||||||
|
|
||||||
|
if (!should_mangle(name)) {
|
||||||
|
push_uniq(unmangleable, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mangle(name) {
|
function mangle(name) {
|
||||||
|
if (!should_mangle(name)) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
var mangled = cache.props.get(name);
|
var mangled = cache.props.get(name);
|
||||||
if (!mangled) {
|
if (!mangled) {
|
||||||
do {
|
do {
|
||||||
@@ -174,7 +185,7 @@ function mangle_properties(ast, options) {
|
|||||||
return mangled;
|
return mangled;
|
||||||
}
|
}
|
||||||
|
|
||||||
function addStrings(node) {
|
function addStrings(node, ignore) {
|
||||||
var out = {};
|
var out = {};
|
||||||
try {
|
try {
|
||||||
(function walk(node){
|
(function walk(node){
|
||||||
@@ -184,7 +195,7 @@ function mangle_properties(ast, options) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_String) {
|
if (node instanceof AST_String) {
|
||||||
add(node.value);
|
add(node.value, ignore);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Conditional) {
|
if (node instanceof AST_Conditional) {
|
||||||
@@ -206,9 +217,7 @@ function mangle_properties(ast, options) {
|
|||||||
node.cdr = mangleStrings(node.cdr);
|
node.cdr = mangleStrings(node.cdr);
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_String) {
|
else if (node instanceof AST_String) {
|
||||||
if (should_mangle(node.value)) {
|
node.value = mangle(node.value);
|
||||||
node.value = mangle(node.value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_Conditional) {
|
else if (node instanceof AST_Conditional) {
|
||||||
node.consequent = mangleStrings(node.consequent);
|
node.consequent = mangleStrings(node.consequent);
|
||||||
|
|||||||
91
lib/scope.js
91
lib/scope.js
@@ -53,8 +53,11 @@ function SymbolDef(scope, index, orig) {
|
|||||||
this.undeclared = false;
|
this.undeclared = false;
|
||||||
this.constant = false;
|
this.constant = false;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
|
this.id = SymbolDef.next_id++;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SymbolDef.next_id = 1;
|
||||||
|
|
||||||
SymbolDef.prototype = {
|
SymbolDef.prototype = {
|
||||||
unmangleable: function(options) {
|
unmangleable: function(options) {
|
||||||
if (!options) options = {};
|
if (!options) options = {};
|
||||||
@@ -85,14 +88,16 @@ SymbolDef.prototype = {
|
|||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
||||||
options = defaults(options, {
|
options = defaults(options, {
|
||||||
screw_ie8: false,
|
screw_ie8: true,
|
||||||
cache: null
|
cache: null
|
||||||
});
|
});
|
||||||
|
|
||||||
// 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 defun = null;
|
||||||
|
var last_var_had_const_pragma = false;
|
||||||
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) {
|
if (options.screw_ie8 && node instanceof AST_Catch) {
|
||||||
@@ -108,16 +113,24 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
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_defun = defun;
|
var save_defun = defun;
|
||||||
|
var save_labels = labels;
|
||||||
defun = scope = node;
|
defun = scope = node;
|
||||||
|
labels = new Dictionary();
|
||||||
++nesting; descend(); --nesting;
|
++nesting; descend(); --nesting;
|
||||||
scope = save_scope;
|
scope = save_scope;
|
||||||
defun = save_defun;
|
defun = save_defun;
|
||||||
|
labels = save_labels;
|
||||||
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_LabeledStatement) {
|
||||||
node.scope = scope;
|
var l = node.label;
|
||||||
push_uniq(scope.directives, node.value);
|
if (labels.has(l.name)) {
|
||||||
return true;
|
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_With) {
|
if (node instanceof AST_With) {
|
||||||
for (var s = scope; s; s = s.parent_scope)
|
for (var s = scope; s; s = s.parent_scope)
|
||||||
@@ -127,6 +140,10 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
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.references = [];
|
||||||
|
}
|
||||||
if (node instanceof AST_SymbolLambda) {
|
if (node instanceof AST_SymbolLambda) {
|
||||||
defun.def_function(node);
|
defun.def_function(node);
|
||||||
}
|
}
|
||||||
@@ -138,16 +155,28 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
// later.
|
// later.
|
||||||
(node.scope = defun.parent_scope).def_function(node);
|
(node.scope = defun.parent_scope).def_function(node);
|
||||||
}
|
}
|
||||||
|
else if (node instanceof AST_Var) {
|
||||||
|
last_var_had_const_pragma = node.has_const_pragma();
|
||||||
|
}
|
||||||
else if (node instanceof AST_SymbolVar
|
else if (node instanceof AST_SymbolVar
|
||||||
|| node instanceof AST_SymbolConst) {
|
|| node instanceof AST_SymbolConst) {
|
||||||
var def = defun.def_variable(node);
|
var def = defun.def_variable(node);
|
||||||
def.constant = node instanceof AST_SymbolConst;
|
def.constant = node instanceof AST_SymbolConst || last_var_had_const_pragma;
|
||||||
def.init = tw.parent().value;
|
def.init = tw.parent().value;
|
||||||
}
|
}
|
||||||
else if (node instanceof AST_SymbolCatch) {
|
else if (node instanceof AST_SymbolCatch) {
|
||||||
(options.screw_ie8 ? scope : defun)
|
(options.screw_ie8 ? scope : defun)
|
||||||
.def_variable(node);
|
.def_variable(node);
|
||||||
}
|
}
|
||||||
|
else 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);
|
||||||
|
|
||||||
@@ -162,8 +191,17 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
func = prev_func;
|
func = prev_func;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (node instanceof AST_LoopControl && node.label) {
|
||||||
|
node.label.thedef.references.push(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (node instanceof AST_SymbolRef) {
|
if (node instanceof AST_SymbolRef) {
|
||||||
var name = node.name;
|
var name = node.name;
|
||||||
|
if (name == "eval" && tw.parent() instanceof AST_Call) {
|
||||||
|
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) {
|
||||||
|
s.uses_eval = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
var sym = node.scope.find_variable(name);
|
var sym = node.scope.find_variable(name);
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
var g;
|
var g;
|
||||||
@@ -176,10 +214,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
globals.set(name, g);
|
globals.set(name, g);
|
||||||
}
|
}
|
||||||
node.thedef = g;
|
node.thedef = g;
|
||||||
if (name == "eval" && tw.parent() instanceof AST_Call) {
|
|
||||||
for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope)
|
|
||||||
s.uses_eval = true;
|
|
||||||
}
|
|
||||||
if (func && name == "arguments") {
|
if (func && name == "arguments") {
|
||||||
func.uses_arguments = true;
|
func.uses_arguments = true;
|
||||||
}
|
}
|
||||||
@@ -198,7 +232,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){
|
|||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
||||||
this.directives = []; // contains the directives defined in this scope, i.e. "use strict"
|
|
||||||
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
this.variables = new Dictionary(); // map name to AST_SymbolVar (variables defined in this scope; includes functions)
|
||||||
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
this.functions = new Dictionary(); // map name to AST_SymbolDefun (functions defined in this scope)
|
||||||
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement
|
||||||
@@ -209,13 +242,13 @@ AST_Scope.DEFMETHOD("init_scope_vars", function(nesting){
|
|||||||
this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
|
this.nesting = nesting; // the nesting level of this scope (0 means toplevel)
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("strict", function(){
|
|
||||||
return this.has_directive("use strict");
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
AST_Lambda.DEFMETHOD("init_scope_vars", function(){
|
||||||
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
AST_Scope.prototype.init_scope_vars.apply(this, arguments);
|
||||||
this.uses_arguments = false;
|
this.uses_arguments = false;
|
||||||
|
|
||||||
|
var symbol = new AST_VarDef({ name: "arguments", start: this.start, end: this.end });
|
||||||
|
var def = new SymbolDef(this, this.variables.size(), symbol);
|
||||||
|
this.variables.set(symbol.name, def);
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_SymbolRef.DEFMETHOD("reference", function() {
|
AST_SymbolRef.DEFMETHOD("reference", function() {
|
||||||
@@ -236,11 +269,6 @@ AST_Scope.DEFMETHOD("find_variable", function(name){
|
|||||||
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
|| (this.parent_scope && this.parent_scope.find_variable(name));
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("has_directive", function(value){
|
|
||||||
return this.parent_scope && this.parent_scope.has_directive(value)
|
|
||||||
|| (this.directives.indexOf(value) >= 0 ? this : null);
|
|
||||||
});
|
|
||||||
|
|
||||||
AST_Scope.DEFMETHOD("def_function", function(symbol){
|
AST_Scope.DEFMETHOD("def_function", function(symbol){
|
||||||
this.functions.set(symbol.name, this.def_variable(symbol));
|
this.functions.set(symbol.name, this.def_variable(symbol));
|
||||||
});
|
});
|
||||||
@@ -286,9 +314,13 @@ AST_Function.DEFMETHOD("next_mangled", function(options, def){
|
|||||||
// a function expression's argument cannot shadow the function expression's name
|
// 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();
|
var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition();
|
||||||
|
|
||||||
|
// the function's mangled_name is null when keep_fnames is true
|
||||||
|
var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
|
var name = AST_Lambda.prototype.next_mangled.call(this, options, def);
|
||||||
if (!(tricky_def && tricky_def.mangled_name == name))
|
if (!tricky_name || tricky_name != name)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -337,19 +369,29 @@ AST_Symbol.DEFMETHOD("global", function(){
|
|||||||
return this.definition().global;
|
return this.definition().global;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Var.DEFMETHOD("has_const_pragma", function() {
|
||||||
|
var comments_before = this.start && this.start.comments_before;
|
||||||
|
var lastComment = comments_before && comments_before[comments_before.length - 1];
|
||||||
|
return lastComment && /@const\b/.test(lastComment.value);
|
||||||
|
});
|
||||||
|
|
||||||
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, // Ignored. Flag retained for backwards compatibility.
|
||||||
toplevel : false,
|
toplevel : false,
|
||||||
screw_ie8 : false,
|
screw_ie8 : true,
|
||||||
keep_fnames : false
|
keep_fnames : false
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
||||||
options = this._default_mangler_options(options);
|
options = this._default_mangler_options(options);
|
||||||
|
|
||||||
|
// Never mangle arguments
|
||||||
|
options.except.push('arguments');
|
||||||
|
|
||||||
// We only need to mangle declaration nodes. Special logic wired
|
// We only need to mangle declaration nodes. Special logic wired
|
||||||
// into the code generator will display the mangled name if it's
|
// into the code generator will display the mangled name if it's
|
||||||
// present (and for AST_SymbolRef-s it'll use the mangled name of
|
// present (and for AST_SymbolRef-s it'll use the mangled name of
|
||||||
@@ -380,9 +422,6 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
|
|||||||
a.push(symbol);
|
a.push(symbol);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (options.sort) a.sort(function(a, b){
|
|
||||||
return b.references.length - a.references.length;
|
|
||||||
});
|
|
||||||
to_mangle.push.apply(to_mangle, a);
|
to_mangle.push.apply(to_mangle, a);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,16 +53,21 @@ function SourceMap(options) {
|
|||||||
orig_line_diff : 0,
|
orig_line_diff : 0,
|
||||||
dest_line_diff : 0,
|
dest_line_diff : 0,
|
||||||
});
|
});
|
||||||
|
var generator = new MOZ_SourceMap.SourceMapGenerator({
|
||||||
|
file : options.file,
|
||||||
|
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) {
|
if (orig_map && Array.isArray(options.orig.sources)) {
|
||||||
generator = MOZ_SourceMap.SourceMapGenerator.fromSourceMap(orig_map);
|
options.orig.sources.forEach(function(source) {
|
||||||
} else {
|
var sourceContent = orig_map.sourceContentFor(source, true);
|
||||||
generator = new MOZ_SourceMap.SourceMapGenerator({
|
if (sourceContent) {
|
||||||
file : options.file,
|
generator.setSourceContent(source, sourceContent);
|
||||||
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({
|
||||||
@@ -83,7 +88,7 @@ function SourceMap(options) {
|
|||||||
source : source,
|
source : source,
|
||||||
name : name
|
name : name
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
return {
|
return {
|
||||||
add : add,
|
add : add,
|
||||||
get : function() { return generator },
|
get : function() { return generator },
|
||||||
|
|||||||
@@ -64,13 +64,13 @@ TreeTransformer.prototype = new TreeWalker;
|
|||||||
x = this;
|
x = this;
|
||||||
descend(x, tw);
|
descend(x, tw);
|
||||||
} else {
|
} else {
|
||||||
tw.stack[tw.stack.length - 1] = x = this.clone();
|
tw.stack[tw.stack.length - 1] = x = this;
|
||||||
descend(x, tw);
|
descend(x, tw);
|
||||||
y = tw.after(x, in_list);
|
y = tw.after(x, in_list);
|
||||||
if (y !== undefined) x = y;
|
if (y !== undefined) x = y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tw.pop();
|
tw.pop(this);
|
||||||
return x;
|
return x;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
32
lib/utils.js
32
lib/utils.js
@@ -59,10 +59,7 @@ function characters(str) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function member(name, array) {
|
function member(name, array) {
|
||||||
for (var i = array.length; --i >= 0;)
|
return array.indexOf(name) >= 0;
|
||||||
if (array[i] == name)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function find_if(func, array) {
|
function find_if(func, array) {
|
||||||
@@ -97,17 +94,17 @@ 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 (HOP(ret, i) && !HOP(defs, i))
|
||||||
DefaultsError.croak("`" + 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 (HOP(defs, i)) {
|
||||||
ret[i] = (args && args.hasOwnProperty(i)) ? args[i] : defs[i];
|
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
function merge(obj, ext) {
|
function merge(obj, ext) {
|
||||||
var count = 0;
|
var count = 0;
|
||||||
for (var i in ext) if (ext.hasOwnProperty(i)) {
|
for (var i in ext) if (HOP(ext, i)) {
|
||||||
obj[i] = ext[i];
|
obj[i] = ext[i];
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@@ -150,7 +147,7 @@ var MAP = (function(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (i in a) if (a.hasOwnProperty(i)) if (doit()) break;
|
for (i in a) if (HOP(a, i)) if (doit()) break;
|
||||||
}
|
}
|
||||||
return top.concat(ret);
|
return top.concat(ret);
|
||||||
};
|
};
|
||||||
@@ -230,10 +227,19 @@ function makePredicate(words) {
|
|||||||
}
|
}
|
||||||
cats.push([words[i]]);
|
cats.push([words[i]]);
|
||||||
}
|
}
|
||||||
|
function quote(word) {
|
||||||
|
return JSON.stringify(word).replace(/[\u2028\u2029]/g, function(s) {
|
||||||
|
switch (s) {
|
||||||
|
case "\u2028": return "\\u2028";
|
||||||
|
case "\u2029": return "\\u2029";
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
});
|
||||||
|
}
|
||||||
function compareTo(arr) {
|
function compareTo(arr) {
|
||||||
if (arr.length == 1) return f += "return str === " + JSON.stringify(arr[0]) + ";";
|
if (arr.length == 1) return f += "return str === " + quote(arr[0]) + ";";
|
||||||
f += "switch(str){";
|
f += "switch(str){";
|
||||||
for (var i = 0; i < arr.length; ++i) f += "case " + JSON.stringify(arr[i]) + ":";
|
for (var i = 0; i < arr.length; ++i) f += "case " + quote(arr[i]) + ":";
|
||||||
f += "return true}return false;";
|
f += "return true}return false;";
|
||||||
}
|
}
|
||||||
// When there are more than three length categories, an outer
|
// When there are more than three length categories, an outer
|
||||||
@@ -308,3 +314,7 @@ Dictionary.fromObject = function(obj) {
|
|||||||
dict._size = merge(dict._values, obj);
|
dict._size = merge(dict._values, obj);
|
||||||
return dict;
|
return dict;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function HOP(obj, prop) {
|
||||||
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
||||||
|
}
|
||||||
|
|||||||
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.10.0",
|
||||||
|
"from": "yargs@>=3.10.0 <3.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz"
|
||||||
|
},
|
||||||
|
"zeparser": {
|
||||||
|
"version": "0.0.7",
|
||||||
|
"from": "git://github.com/qfox/ZeParser.git",
|
||||||
|
"resolved": "git://github.com/qfox/ZeParser.git#c99240c5ba7054c467733800ff38265958a2dda9"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
package.json
17
package.json
@@ -3,10 +3,10 @@
|
|||||||
"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",
|
||||||
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
|
||||||
"license": "BSD",
|
"license": "BSD-2-Clause",
|
||||||
"version": "2.4.24",
|
"version": "2.7.2",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
"maintainers": [
|
"maintainers": [
|
||||||
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
|
"Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)"
|
||||||
@@ -30,15 +30,16 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async": "~0.2.6",
|
"async": "~0.2.6",
|
||||||
"source-map": "0.1.34",
|
"source-map": "~0.5.1",
|
||||||
"uglify-to-browserify": "~1.0.0",
|
"uglify-to-browserify": "~1.0.0",
|
||||||
"yargs": "~3.5.4"
|
"yargs": "~3.10.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "~0.6.0",
|
"acorn": "~0.6.0",
|
||||||
"escodegen": "~1.3.3",
|
"escodegen": "~1.3.3",
|
||||||
"esfuzz": "~0.3.1",
|
"esfuzz": "~0.3.1",
|
||||||
"estraverse": "~1.5.1"
|
"estraverse": "~1.5.1",
|
||||||
|
"mocha": "~2.3.4"
|
||||||
},
|
},
|
||||||
"browserify": {
|
"browserify": {
|
||||||
"transform": [
|
"transform": [
|
||||||
@@ -46,6 +47,8 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"shrinkwrap": "rm ./npm-shrinkwrap.json; rm -rf ./node_modules; npm i && npm shrinkwrap && npm outdated",
|
||||||
"test": "node test/run-tests.js"
|
"test": "node test/run-tests.js"
|
||||||
}
|
},
|
||||||
|
"keywords": ["uglify", "uglify-js", "minify", "minifier"]
|
||||||
}
|
}
|
||||||
|
|||||||
36
test/compress/ascii.js
Normal file
36
test/compress/ascii.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
ascii_only_true: {
|
||||||
|
options = {}
|
||||||
|
beautify = {
|
||||||
|
ascii_only : true,
|
||||||
|
screw_ie8 : true,
|
||||||
|
beautify : false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
return "\x000\x001\x007\x008\x00" +
|
||||||
|
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||||
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
||||||
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\b\\t\\n\\v\\f\\r\\x0e\\x0f"+"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f"+\' !"# ... }~\\x7f\\x80\\x81 ... \\xfe\\xff\\u0fff\\uffff\'}'
|
||||||
|
}
|
||||||
|
|
||||||
|
ascii_only_false: {
|
||||||
|
options = {}
|
||||||
|
beautify = {
|
||||||
|
ascii_only : false,
|
||||||
|
screw_ie8 : true,
|
||||||
|
beautify : false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
return "\x000\x001\x007\x008\x00" +
|
||||||
|
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" +
|
||||||
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" +
|
||||||
|
"\x20\x21\x22\x23 ... \x7d\x7e\x7f\x80\x81 ... \xfe\xff\u0fff\uffff";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_exact: 'function f(){return"\\x000\\x001\\x007\\08\\0"+"\\0\x01\x02\x03\x04\x05\x06\x07\\b\\t\\n\\v\\f\\r\x0e\x0f"+"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"+\' !"# ... }~\x7f\x80\x81 ... \xfe\xff\u0fff\uffff\'}'
|
||||||
|
}
|
||||||
|
|
||||||
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 | p) < (0 | q); 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 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1211
test/compress/collapse_vars.js
Normal file
1211
test/compress/collapse_vars.js
Normal file
File diff suppressed because it is too large
Load Diff
76
test/compress/comparing.js
Normal file
76
test/compress/comparing.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
keep_comparisons: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
unsafe_comps: false
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj1 = {
|
||||||
|
valueOf: function() {triggeredFirst();}
|
||||||
|
}
|
||||||
|
var obj2 = {
|
||||||
|
valueOf: function() {triggeredSecond();}
|
||||||
|
}
|
||||||
|
var result1 = obj1 <= obj2;
|
||||||
|
var result2 = obj1 < obj2;
|
||||||
|
var result3 = obj1 >= obj2;
|
||||||
|
var result4 = obj1 > obj2;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj1 = {
|
||||||
|
valueOf: function() {triggeredFirst();}
|
||||||
|
}
|
||||||
|
var obj2 = {
|
||||||
|
valueOf: function() {triggeredSecond();}
|
||||||
|
}
|
||||||
|
var result1 = obj1 <= obj2;
|
||||||
|
var result2 = obj1 < obj2;
|
||||||
|
var result3 = obj1 >= obj2;
|
||||||
|
var result4 = obj1 > obj2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_comparisons_with_unsafe_comps: {
|
||||||
|
options = {
|
||||||
|
comparisons: true,
|
||||||
|
unsafe_comps: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj1 = {
|
||||||
|
valueOf: function() {triggeredFirst();}
|
||||||
|
}
|
||||||
|
var obj2 = {
|
||||||
|
valueOf: function() {triggeredSecond();}
|
||||||
|
}
|
||||||
|
var result1 = obj1 <= obj2;
|
||||||
|
var result2 = obj1 < obj2;
|
||||||
|
var result3 = obj1 >= obj2;
|
||||||
|
var result4 = obj1 > obj2;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var obj1 = {
|
||||||
|
valueOf: function() {triggeredFirst();}
|
||||||
|
}
|
||||||
|
var obj2 = {
|
||||||
|
valueOf: function() {triggeredSecond();}
|
||||||
|
}
|
||||||
|
var result1 = obj2 >= obj1;
|
||||||
|
var result2 = obj2 > obj1;
|
||||||
|
var result3 = obj1 >= obj2;
|
||||||
|
var result4 = obj1 > obj2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_change_in_or_instanceof_expressions: {
|
||||||
|
input: {
|
||||||
|
1 in 1;
|
||||||
|
null in null;
|
||||||
|
1 instanceof 1;
|
||||||
|
null instanceof null;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
1 in 1;
|
||||||
|
null in null;
|
||||||
|
1 instanceof 1;
|
||||||
|
null instanceof null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,9 @@ concat_1: {
|
|||||||
var d = 1 + x() + 2 + 3 + "boo";
|
var d = 1 + x() + 2 + 3 + "boo";
|
||||||
|
|
||||||
var e = 1 + x() + 2 + "X" + 3 + "boo";
|
var e = 1 + x() + 2 + "X" + 3 + "boo";
|
||||||
|
|
||||||
|
// be careful with concatentation with "\0" with octal-looking strings.
|
||||||
|
var f = "\0" + 360 + "\0" + 8 + "\0";
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a = "foobar" + x() + "moofoo" + y() + "xyz" + q();
|
var a = "foobar" + x() + "moofoo" + y() + "xyz" + q();
|
||||||
@@ -18,5 +21,6 @@ concat_1: {
|
|||||||
var c = 1 + x() + 2 + "boo";
|
var c = 1 + x() + 2 + "boo";
|
||||||
var d = 1 + x() + 2 + 3 + "boo";
|
var d = 1 + x() + 2 + 3 + "boo";
|
||||||
var e = 1 + x() + 2 + "X3boo";
|
var e = 1 + x() + 2 + "X3boo";
|
||||||
|
var f = "\x00360\08\0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,59 +332,309 @@ cond_7_1: {
|
|||||||
cond_8: {
|
cond_8: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
evaluate : true
|
evaluate : true,
|
||||||
|
booleans : false
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
var a;
|
var a;
|
||||||
// compress these
|
// compress these
|
||||||
a = condition ? true : false;
|
a = condition ? true : false;
|
||||||
|
|
||||||
a = !condition ? true : false;
|
a = !condition ? true : false;
|
||||||
|
|
||||||
a = condition() ? true : false;
|
a = condition() ? true : false;
|
||||||
|
|
||||||
|
a = condition ? !0 : !1;
|
||||||
|
a = !condition ? !null : !2;
|
||||||
|
a = condition() ? !0 : !-3.5;
|
||||||
|
|
||||||
if (condition) {
|
if (condition) {
|
||||||
a = true;
|
a = true;
|
||||||
} else {
|
} else {
|
||||||
a = false;
|
a = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = !0;
|
||||||
|
} else {
|
||||||
|
a = !1;
|
||||||
|
}
|
||||||
|
|
||||||
a = condition ? false : true;
|
a = condition ? false : true;
|
||||||
|
|
||||||
a = !condition ? false : true;
|
a = !condition ? false : true;
|
||||||
|
|
||||||
a = condition() ? false : true;
|
a = condition() ? false : true;
|
||||||
|
|
||||||
|
a = condition ? !3 : !0;
|
||||||
|
a = !condition ? !2 : !0;
|
||||||
|
a = condition() ? !1 : !0;
|
||||||
|
|
||||||
if (condition) {
|
if (condition) {
|
||||||
a = false;
|
a = false;
|
||||||
} else {
|
} else {
|
||||||
a = true;
|
a = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = !1;
|
||||||
|
} else {
|
||||||
|
a = !0;
|
||||||
|
}
|
||||||
|
|
||||||
// don't compress these
|
// don't compress these
|
||||||
a = condition ? 1 : false;
|
a = condition ? 1 : false;
|
||||||
|
|
||||||
a = !condition ? true : 0;
|
a = !condition ? true : 0;
|
||||||
|
|
||||||
a = condition ? 1 : 0;
|
a = condition ? 1 : 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
var a;
|
var a;
|
||||||
a = !!condition;
|
a = !!condition;
|
||||||
a = !condition;
|
a = !condition;
|
||||||
a = !!condition();
|
a = !!condition();
|
||||||
|
|
||||||
a = !!condition;
|
a = !!condition;
|
||||||
|
a = !condition;
|
||||||
|
a = !!condition();
|
||||||
|
|
||||||
|
a = !!condition;
|
||||||
|
a = !!condition;
|
||||||
|
|
||||||
a = !condition;
|
a = !condition;
|
||||||
a = !!condition;
|
a = !!condition;
|
||||||
a = !condition();
|
a = !condition();
|
||||||
|
|
||||||
a = !condition;
|
a = !condition;
|
||||||
a = condition ? 1 : false;
|
a = !!condition;
|
||||||
a = condition ? 0 : true;
|
a = !condition();
|
||||||
|
|
||||||
|
a = !condition;
|
||||||
|
a = !condition;
|
||||||
|
|
||||||
|
a = !!condition && 1;
|
||||||
|
a = !condition || 0;
|
||||||
a = condition ? 1 : 0;
|
a = condition ? 1 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cond_8b: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
// compress these
|
||||||
|
a = condition ? true : false;
|
||||||
|
a = !condition ? true : false;
|
||||||
|
a = condition() ? true : false;
|
||||||
|
|
||||||
|
a = condition ? !0 : !1;
|
||||||
|
a = !condition ? !null : !2;
|
||||||
|
a = condition() ? !0 : !-3.5;
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = true;
|
||||||
|
} else {
|
||||||
|
a = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = !0;
|
||||||
|
} else {
|
||||||
|
a = !1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = condition ? false : true;
|
||||||
|
a = !condition ? false : true;
|
||||||
|
a = condition() ? false : true;
|
||||||
|
|
||||||
|
a = condition ? !3 : !0;
|
||||||
|
a = !condition ? !2 : !0;
|
||||||
|
a = condition() ? !1 : !0;
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = false;
|
||||||
|
} else {
|
||||||
|
a = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = !1;
|
||||||
|
} else {
|
||||||
|
a = !0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
a = !!condition;
|
||||||
|
a = !condition();
|
||||||
|
|
||||||
|
a = !condition;
|
||||||
|
a = !!condition;
|
||||||
|
a = !condition();
|
||||||
|
|
||||||
|
a = !condition;
|
||||||
|
a = !condition;
|
||||||
|
|
||||||
|
a = !!condition && 1;
|
||||||
|
a = !condition || 0;
|
||||||
|
a = condition ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cond_8c: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : false,
|
||||||
|
booleans : false
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var a;
|
||||||
|
// compress these
|
||||||
|
a = condition ? true : false;
|
||||||
|
a = !condition ? true : false;
|
||||||
|
a = condition() ? true : false;
|
||||||
|
|
||||||
|
a = condition ? !0 : !1;
|
||||||
|
a = !condition ? !null : !2;
|
||||||
|
a = condition() ? !0 : !-3.5;
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = true;
|
||||||
|
} else {
|
||||||
|
a = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = !0;
|
||||||
|
} else {
|
||||||
|
a = !1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = condition ? false : true;
|
||||||
|
a = !condition ? false : true;
|
||||||
|
a = condition() ? false : true;
|
||||||
|
|
||||||
|
a = condition ? !3 : !0;
|
||||||
|
a = !condition ? !2 : !0;
|
||||||
|
a = condition() ? !1 : !0;
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = false;
|
||||||
|
} else {
|
||||||
|
a = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
a = !1;
|
||||||
|
} else {
|
||||||
|
a = !0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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() || !-3.5;
|
||||||
|
|
||||||
|
a = !!condition;
|
||||||
|
a = !!condition;
|
||||||
|
|
||||||
|
a = !condition;
|
||||||
|
a = !!condition;
|
||||||
|
a = !condition();
|
||||||
|
|
||||||
|
a = !condition;
|
||||||
|
a = !!condition;
|
||||||
|
a = !condition();
|
||||||
|
|
||||||
|
a = !condition;
|
||||||
|
a = !condition;
|
||||||
|
|
||||||
|
a = !!condition && 1;
|
||||||
|
a = !condition || 0;
|
||||||
|
a = condition ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ternary_boolean_consequent: {
|
||||||
|
options = {
|
||||||
|
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
|
||||||
|
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
|
||||||
|
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f1() { return a == b ? true : x; }
|
||||||
|
function f2() { return a == b ? false : x; }
|
||||||
|
function f3() { return a < b ? !0 : x; }
|
||||||
|
function f4() { return a < b ? !1 : x; }
|
||||||
|
function f5() { return c ? !0 : x; }
|
||||||
|
function f6() { return c ? false : x; }
|
||||||
|
function f7() { return !c ? true : x; }
|
||||||
|
function f8() { return !c ? !1 : x; }
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1() { return a == b || x; }
|
||||||
|
function f2() { return a != b && x; }
|
||||||
|
function f3() { return a < b || x; }
|
||||||
|
function f4() { return !(a < b) && x; }
|
||||||
|
function f5() { return !!c || x; }
|
||||||
|
function f6() { return !c && x; }
|
||||||
|
function f7() { return !c || x; }
|
||||||
|
function f8() { return !!c && x; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ternary_boolean_alternative: {
|
||||||
|
options = {
|
||||||
|
collapse_vars:true, sequences:true, properties:true, dead_code:true, conditionals:true,
|
||||||
|
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
|
||||||
|
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f1() { return a == b ? x : true; }
|
||||||
|
function f2() { return a == b ? x : false; }
|
||||||
|
function f3() { return a < b ? x : !0; }
|
||||||
|
function f4() { return a < b ? x : !1; }
|
||||||
|
function f5() { return c ? x : true; }
|
||||||
|
function f6() { return c ? x : !1; }
|
||||||
|
function f7() { return !c ? x : !0; }
|
||||||
|
function f8() { return !c ? x : false; }
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1() { return a != b || x; }
|
||||||
|
function f2() { return a == b && x; }
|
||||||
|
function f3() { return !(a < b) || x; }
|
||||||
|
function f4() { return a < b && x; }
|
||||||
|
function f5() { return !c || x; }
|
||||||
|
function f6() { return !!c && x; }
|
||||||
|
function f7() { return !!c || x; }
|
||||||
|
function f8() { return !c && x; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
conditional_and: {
|
conditional_and: {
|
||||||
options = {
|
options = {
|
||||||
conditionals: true,
|
conditionals: true,
|
||||||
@@ -544,3 +794,115 @@ conditional_or: {
|
|||||||
a = condition + 3 || null;
|
a = condition + 3 || null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trivial_boolean_ternary_expressions : {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
f('foo' in m ? true : false);
|
||||||
|
f('foo' in m ? false : true);
|
||||||
|
|
||||||
|
f(g ? true : false);
|
||||||
|
f(foo() ? true : false);
|
||||||
|
f("bar" ? true : false);
|
||||||
|
f(5 ? true : false);
|
||||||
|
f(5.7 ? true : false);
|
||||||
|
f(x - y ? true : false);
|
||||||
|
|
||||||
|
f(x == y ? true : false);
|
||||||
|
f(x === y ? !0 : !1);
|
||||||
|
f(x < y ? !0 : false);
|
||||||
|
f(x <= y ? true : false);
|
||||||
|
f(x > y ? true : !1);
|
||||||
|
f(x >= y ? !0 : !1);
|
||||||
|
|
||||||
|
f(g ? false : true);
|
||||||
|
f(foo() ? false : true);
|
||||||
|
f("bar" ? false : true);
|
||||||
|
f(5 ? false : true);
|
||||||
|
f(5.7 ? false : true);
|
||||||
|
f(x - y ? false : true);
|
||||||
|
|
||||||
|
f(x == y ? !1 : !0);
|
||||||
|
f(x === y ? false : true);
|
||||||
|
|
||||||
|
f(x < y ? false : true);
|
||||||
|
f(x <= y ? false : !0);
|
||||||
|
f(x > y ? !1 : true);
|
||||||
|
f(x >= y ? !1 : !0);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
f('foo' in m);
|
||||||
|
f(!('foo' in m));
|
||||||
|
|
||||||
|
f(!!g);
|
||||||
|
f(!!foo());
|
||||||
|
f(!0);
|
||||||
|
f(!0);
|
||||||
|
f(!0);
|
||||||
|
f(!!(x - y));
|
||||||
|
|
||||||
|
f(x == y);
|
||||||
|
f(x === y);
|
||||||
|
f(x < y);
|
||||||
|
f(x <= y);
|
||||||
|
f(x > y);
|
||||||
|
f(x >= y);
|
||||||
|
|
||||||
|
f(!g);
|
||||||
|
f(!foo());
|
||||||
|
f(!1);
|
||||||
|
f(!1);
|
||||||
|
f(!1);
|
||||||
|
f(!(x - y));
|
||||||
|
|
||||||
|
f(x != y);
|
||||||
|
f(x !== y);
|
||||||
|
|
||||||
|
f(!(x < y));
|
||||||
|
f(!(x <= y));
|
||||||
|
f(!(x > y));
|
||||||
|
f(!(x >= y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1154: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
function f1(x) { return x ? -1 : -1; }
|
||||||
|
function f2(x) { return x ? +2 : +2; }
|
||||||
|
function f3(x) { return x ? ~3 : ~3; }
|
||||||
|
function f4(x) { return x ? !4 : !4; }
|
||||||
|
function f5(x) { return x ? void 5 : void 5; }
|
||||||
|
function f6(x) { return x ? typeof 6 : typeof 6; }
|
||||||
|
|
||||||
|
function g1() { return g() ? -1 : -1; }
|
||||||
|
function g2() { return g() ? +2 : +2; }
|
||||||
|
function g3() { return g() ? ~3 : ~3; }
|
||||||
|
function g4() { return g() ? !4 : !4; }
|
||||||
|
function g5() { return g() ? void 5 : void 5; }
|
||||||
|
function g6() { return g() ? typeof 6 : typeof 6; }
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1(x) { return -1; }
|
||||||
|
function f2(x) { return 2; }
|
||||||
|
function f3(x) { return -4; }
|
||||||
|
function f4(x) { return !1; }
|
||||||
|
function f5(x) { return; }
|
||||||
|
function f6(x) { return "number"; }
|
||||||
|
|
||||||
|
function g1() { return g(), -1; }
|
||||||
|
function g2() { return g(), 2; }
|
||||||
|
function g3() { return g(), -4; }
|
||||||
|
function g4() { return g(), !1; }
|
||||||
|
function g5() { return g(), void 0; }
|
||||||
|
function g6() { return g(), "number"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,3 +87,120 @@ dead_code_constant_boolean_should_warn_more: {
|
|||||||
var moo;
|
var moo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dead_code_const_declaration: {
|
||||||
|
options = {
|
||||||
|
dead_code : true,
|
||||||
|
loops : true,
|
||||||
|
booleans : true,
|
||||||
|
conditionals : true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var unused;
|
||||||
|
const CONST_FOO = false;
|
||||||
|
if (CONST_FOO) {
|
||||||
|
console.log("unreachable");
|
||||||
|
var moo;
|
||||||
|
function bar() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var unused;
|
||||||
|
const CONST_FOO = !1;
|
||||||
|
var moo;
|
||||||
|
function bar() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dead_code_const_annotation: {
|
||||||
|
options = {
|
||||||
|
dead_code : true,
|
||||||
|
loops : true,
|
||||||
|
booleans : true,
|
||||||
|
conditionals : true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var unused;
|
||||||
|
/** @const */ var CONST_FOO_ANN = false;
|
||||||
|
if (CONST_FOO_ANN) {
|
||||||
|
console.log("unreachable");
|
||||||
|
var moo;
|
||||||
|
function bar() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var unused;
|
||||||
|
var CONST_FOO_ANN = !1;
|
||||||
|
var moo;
|
||||||
|
function bar() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dead_code_const_annotation_regex: {
|
||||||
|
options = {
|
||||||
|
dead_code : true,
|
||||||
|
loops : true,
|
||||||
|
booleans : true,
|
||||||
|
conditionals : true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var unused;
|
||||||
|
// @constraint this shouldn't be a constant
|
||||||
|
var CONST_FOO_ANN = false;
|
||||||
|
if (CONST_FOO_ANN) {
|
||||||
|
console.log("reachable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var unused;
|
||||||
|
var CONST_FOO_ANN = !1;
|
||||||
|
CONST_FOO_ANN && console.log('reachable');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dead_code_const_annotation_complex_scope: {
|
||||||
|
options = {
|
||||||
|
dead_code : true,
|
||||||
|
loops : true,
|
||||||
|
booleans : true,
|
||||||
|
conditionals : true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var unused_var;
|
||||||
|
/** @const */ var test = 'test';
|
||||||
|
// @const
|
||||||
|
var CONST_FOO_ANN = false;
|
||||||
|
var unused_var_2;
|
||||||
|
if (CONST_FOO_ANN) {
|
||||||
|
console.log("unreachable");
|
||||||
|
var moo;
|
||||||
|
function bar() {}
|
||||||
|
}
|
||||||
|
if (test === 'test') {
|
||||||
|
var beef = 'good';
|
||||||
|
/** @const */ var meat = 'beef';
|
||||||
|
var pork = 'bad';
|
||||||
|
if (meat === 'pork') {
|
||||||
|
console.log('also unreachable');
|
||||||
|
} else if (pork === 'good') {
|
||||||
|
console.log('reached, not const');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var unused_var;
|
||||||
|
var test = 'test';
|
||||||
|
var CONST_FOO_ANN = !1;
|
||||||
|
var unused_var_2;
|
||||||
|
var moo;
|
||||||
|
function bar() {}
|
||||||
|
var beef = 'good';
|
||||||
|
var meat = 'beef';
|
||||||
|
var pork = 'bad';
|
||||||
|
'good' === pork && console.log('reached, not const');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
unused_funarg_1: {
|
unused_funarg_1: {
|
||||||
options = { unused: true, unsafe: 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, unsafe: 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;
|
||||||
@@ -173,7 +173,7 @@ keep_fnames: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function foo() {
|
function foo() {
|
||||||
return function bar() {};
|
return function bar(baz) {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
test/compress/evaluate.js
Normal file
39
test/compress/evaluate.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
negative_zero: {
|
||||||
|
options = { evaluate: true }
|
||||||
|
input: {
|
||||||
|
console.log(
|
||||||
|
-"",
|
||||||
|
- -"",
|
||||||
|
1 / (-0),
|
||||||
|
1 / (-"")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(
|
||||||
|
-0,
|
||||||
|
0,
|
||||||
|
1 / (-0),
|
||||||
|
1 / (-0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
positive_zero: {
|
||||||
|
options = { evaluate: true }
|
||||||
|
input: {
|
||||||
|
console.log(
|
||||||
|
+"",
|
||||||
|
+ -"",
|
||||||
|
1 / (+0),
|
||||||
|
1 / (+"")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(
|
||||||
|
0,
|
||||||
|
-0,
|
||||||
|
1 / (0),
|
||||||
|
1 / (0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
71
test/compress/html_comments.js
Normal file
71
test/compress/html_comments.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
html_comment_in_expression: {
|
||||||
|
input: {
|
||||||
|
function f(a, b, x, y) { return a < !--b && x-- > y; }
|
||||||
|
}
|
||||||
|
expect_exact: "function f(a,b,x,y){return a< !--b&&x-- >y}";
|
||||||
|
}
|
||||||
|
|
||||||
|
html_comment_in_less_than: {
|
||||||
|
input: {
|
||||||
|
function f(a, b) { return a < !--b; }
|
||||||
|
}
|
||||||
|
expect_exact: "function f(a,b){return a< !--b}";
|
||||||
|
}
|
||||||
|
|
||||||
|
html_comment_in_left_shift: {
|
||||||
|
input: {
|
||||||
|
function f(a, b) { return a << !--b; }
|
||||||
|
}
|
||||||
|
expect_exact: "function f(a,b){return a<< !--b}";
|
||||||
|
}
|
||||||
|
|
||||||
|
html_comment_in_right_shift: {
|
||||||
|
input: {
|
||||||
|
function f(a, b) { return a-- >> b; }
|
||||||
|
}
|
||||||
|
expect_exact: "function f(a,b){return a-- >>b}";
|
||||||
|
}
|
||||||
|
|
||||||
|
html_comment_in_zero_fill_right_shift: {
|
||||||
|
input: {
|
||||||
|
function f(a, b) { return a-- >>> b; }
|
||||||
|
}
|
||||||
|
expect_exact: "function f(a,b){return a-- >>>b}";
|
||||||
|
}
|
||||||
|
|
||||||
|
html_comment_in_greater_than: {
|
||||||
|
input: {
|
||||||
|
function f(a, b) { return a-- > b; }
|
||||||
|
}
|
||||||
|
expect_exact: "function f(a,b){return a-- >b}";
|
||||||
|
}
|
||||||
|
|
||||||
|
html_comment_in_greater_than_or_equal: {
|
||||||
|
input: {
|
||||||
|
function f(a, b) { return a-- >= b; }
|
||||||
|
}
|
||||||
|
expect_exact: "function f(a,b){return a-- >=b}";
|
||||||
|
}
|
||||||
|
|
||||||
|
html_comment_in_right_shift_assign: {
|
||||||
|
input: {
|
||||||
|
// Note: illegal javascript
|
||||||
|
function f(a, b) { return a-- >>= b; }
|
||||||
|
}
|
||||||
|
expect_exact: "function f(a,b){return a-- >>=b}";
|
||||||
|
}
|
||||||
|
|
||||||
|
html_comment_in_zero_fill_right_shift_assign: {
|
||||||
|
input: {
|
||||||
|
// Note: illegal javascript
|
||||||
|
function f(a, b) { return a-- >>>= b; }
|
||||||
|
}
|
||||||
|
expect_exact: "function f(a,b){return a-- >>>=b}";
|
||||||
|
}
|
||||||
|
|
||||||
|
html_comment_in_string_literal: {
|
||||||
|
input: {
|
||||||
|
function f() { return "<!--HTML-->comment in<!--string literal-->"; }
|
||||||
|
}
|
||||||
|
expect_exact: 'function f(){return"\\x3c!--HTML--\\x3ecomment in\\x3c!--string literal--\\x3e"}';
|
||||||
|
}
|
||||||
207
test/compress/if_return.js
Normal file
207
test/compress/if_return.js
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
if_return_1: {
|
||||||
|
options = {
|
||||||
|
if_return : true,
|
||||||
|
sequences : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
unused : true,
|
||||||
|
side_effects : true,
|
||||||
|
dead_code : true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x) {
|
||||||
|
if (x) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x){if(x)return!0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if_return_2: {
|
||||||
|
options = {
|
||||||
|
if_return : true,
|
||||||
|
sequences : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
unused : true,
|
||||||
|
side_effects : true,
|
||||||
|
dead_code : true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y) {
|
||||||
|
if (x)
|
||||||
|
return 3;
|
||||||
|
if (y)
|
||||||
|
return c();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x,y){return x?3:y?c():void 0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if_return_3: {
|
||||||
|
options = {
|
||||||
|
if_return : true,
|
||||||
|
sequences : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
unused : true,
|
||||||
|
side_effects : true,
|
||||||
|
dead_code : true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x) {
|
||||||
|
a();
|
||||||
|
if (x) {
|
||||||
|
b();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x){if(a(),x)return b(),!1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if_return_4: {
|
||||||
|
options = {
|
||||||
|
if_return : true,
|
||||||
|
sequences : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
unused : true,
|
||||||
|
side_effects : true,
|
||||||
|
dead_code : true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x, y) {
|
||||||
|
a();
|
||||||
|
if (x) return 3;
|
||||||
|
b();
|
||||||
|
if (y) return c();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(x,y){return a(),x?3:(b(),y?c():void 0)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if_return_5: {
|
||||||
|
options = {
|
||||||
|
if_return : true,
|
||||||
|
sequences : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
unused : true,
|
||||||
|
side_effects : true,
|
||||||
|
dead_code : true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
if (x)
|
||||||
|
return;
|
||||||
|
return 7;
|
||||||
|
if (y)
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f(){if(!x)return 7}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if_return_6: {
|
||||||
|
options = {
|
||||||
|
if_return : true,
|
||||||
|
sequences : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
unused : true,
|
||||||
|
side_effects : true,
|
||||||
|
dead_code : true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x) {
|
||||||
|
return x ? true : void 0;
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
// suboptimal
|
||||||
|
function f(x){return!!x||void 0}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if_return_7: {
|
||||||
|
options = {
|
||||||
|
if_return : true,
|
||||||
|
sequences : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
unused : true,
|
||||||
|
side_effects : true,
|
||||||
|
dead_code : true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x) {
|
||||||
|
if (x) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
// suboptimal
|
||||||
|
function f(x){return!!x||(foo(),void bar())}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1089: {
|
||||||
|
options = {
|
||||||
|
if_return : true,
|
||||||
|
sequences : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
evaluate : true,
|
||||||
|
booleans : true,
|
||||||
|
unused : true,
|
||||||
|
side_effects : true,
|
||||||
|
dead_code : true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function x() {
|
||||||
|
var f = document.getElementById("fname");
|
||||||
|
if (f.files[0].size > 12345) {
|
||||||
|
alert("alert");
|
||||||
|
f.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function x() {
|
||||||
|
var f = document.getElementById("fname");
|
||||||
|
if (f.files[0].size > 12345)
|
||||||
|
return alert("alert"), f.focus(), !1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
121
test/compress/issue-1034.js
Normal file
121
test/compress/issue-1034.js
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
non_hoisted_function_after_return: {
|
||||||
|
options = {
|
||||||
|
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
|
||||||
|
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
|
||||||
|
if_return: true, join_vars: true, cascade: true, side_effects: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo(x) {
|
||||||
|
if (x) {
|
||||||
|
return bar();
|
||||||
|
not_called1();
|
||||||
|
} else {
|
||||||
|
return baz();
|
||||||
|
not_called2();
|
||||||
|
}
|
||||||
|
function bar() { return 7; }
|
||||||
|
return not_reached;
|
||||||
|
function UnusedFunction() {}
|
||||||
|
function baz() { return 8; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo(x) {
|
||||||
|
return x ? bar() : baz();
|
||||||
|
function bar() { return 7 }
|
||||||
|
function baz() { return 8 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
'WARN: Dropping unreachable code [test/compress/issue-1034.js:11,16]',
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:14,16]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:17,12]",
|
||||||
|
"WARN: Dropping unused function UnusedFunction [test/compress/issue-1034.js:18,21]"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
non_hoisted_function_after_return_2a: {
|
||||||
|
options = {
|
||||||
|
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
|
||||||
|
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
|
||||||
|
if_return: true, join_vars: true, cascade: true, side_effects: true,
|
||||||
|
collapse_vars: false, passes: 2
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo(x) {
|
||||||
|
if (x) {
|
||||||
|
return bar(1);
|
||||||
|
var a = not_called(1);
|
||||||
|
} else {
|
||||||
|
return bar(2);
|
||||||
|
var b = not_called(2);
|
||||||
|
}
|
||||||
|
var c = bar(3);
|
||||||
|
function bar(x) { return 7 - x; }
|
||||||
|
function nope() {}
|
||||||
|
return b || c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo(x) {
|
||||||
|
return bar(x ? 1 : 2);
|
||||||
|
function bar(x) {
|
||||||
|
return 7 - x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:48,16]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:48,16]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:51,16]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:51,16]",
|
||||||
|
"WARN: Dropping unused variable a [test/compress/issue-1034.js:48,20]",
|
||||||
|
"WARN: Dropping unused function nope [test/compress/issue-1034.js:55,21]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:53,12]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:53,12]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:56,12]",
|
||||||
|
"WARN: Dropping unused variable b [test/compress/issue-1034.js:51,20]",
|
||||||
|
"WARN: Dropping unused variable c [test/compress/issue-1034.js:53,16]"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
non_hoisted_function_after_return_2b: {
|
||||||
|
options = {
|
||||||
|
hoist_funs: false, dead_code: true, conditionals: true, comparisons: true,
|
||||||
|
evaluate: true, booleans: true, loops: true, unused: true, keep_fargs: true,
|
||||||
|
if_return: true, join_vars: true, cascade: true, side_effects: true,
|
||||||
|
collapse_vars: false
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo(x) {
|
||||||
|
if (x) {
|
||||||
|
return bar(1);
|
||||||
|
} else {
|
||||||
|
return bar(2);
|
||||||
|
var b;
|
||||||
|
}
|
||||||
|
var c = bar(3);
|
||||||
|
function bar(x) {
|
||||||
|
return 7 - x;
|
||||||
|
}
|
||||||
|
return b || c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo(x) {
|
||||||
|
return bar(x ? 1 : 2);
|
||||||
|
function bar(x) { return 7 - x; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_warnings: [
|
||||||
|
// duplicate warnings no longer emitted
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:95,16]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:95,16]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:97,12]",
|
||||||
|
"WARN: Declarations in unreachable code! [test/compress/issue-1034.js:97,12]",
|
||||||
|
"WARN: Dropping unreachable code [test/compress/issue-1034.js:101,12]",
|
||||||
|
"WARN: Dropping unused variable b [test/compress/issue-1034.js:95,20]",
|
||||||
|
"WARN: Dropping unused variable c [test/compress/issue-1034.js:97,16]"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
39
test/compress/issue-1041.js
Normal file
39
test/compress/issue-1041.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
const_declaration: {
|
||||||
|
options = {
|
||||||
|
evaluate: true
|
||||||
|
};
|
||||||
|
|
||||||
|
input: {
|
||||||
|
const goog = goog || {};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const goog = goog || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const_pragma: {
|
||||||
|
options = {
|
||||||
|
evaluate: true
|
||||||
|
};
|
||||||
|
|
||||||
|
input: {
|
||||||
|
/** @const */ var goog = goog || {};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var goog = goog || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for completeness' sake
|
||||||
|
not_const: {
|
||||||
|
options = {
|
||||||
|
evaluate: true
|
||||||
|
};
|
||||||
|
|
||||||
|
input: {
|
||||||
|
var goog = goog || {};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var goog = goog || {};
|
||||||
|
}
|
||||||
|
}
|
||||||
96
test/compress/issue-1052.js
Normal file
96
test/compress/issue-1052.js
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
multiple_functions: {
|
||||||
|
options = { if_return: true, hoist_funs: false };
|
||||||
|
input: {
|
||||||
|
( function() {
|
||||||
|
if ( !window ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() {}
|
||||||
|
function g() {}
|
||||||
|
} )();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
( function() {
|
||||||
|
function f() {}
|
||||||
|
function g() {}
|
||||||
|
|
||||||
|
// NOTE: other compression steps will reduce this
|
||||||
|
// down to just `window`.
|
||||||
|
if ( window );
|
||||||
|
} )();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
single_function: {
|
||||||
|
options = { if_return: true, hoist_funs: false };
|
||||||
|
input: {
|
||||||
|
( function() {
|
||||||
|
if ( !window ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() {}
|
||||||
|
} )();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
( function() {
|
||||||
|
function f() {}
|
||||||
|
|
||||||
|
if ( window );
|
||||||
|
} )();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deeply_nested: {
|
||||||
|
options = { if_return: true, hoist_funs: false };
|
||||||
|
input: {
|
||||||
|
( function() {
|
||||||
|
if ( !window ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() {}
|
||||||
|
function g() {}
|
||||||
|
|
||||||
|
if ( !document ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function h() {}
|
||||||
|
} )();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
( function() {
|
||||||
|
function f() {}
|
||||||
|
function g() {}
|
||||||
|
|
||||||
|
function h() {}
|
||||||
|
|
||||||
|
// NOTE: other compression steps will reduce this
|
||||||
|
// down to just `window`.
|
||||||
|
if ( window )
|
||||||
|
if (document);
|
||||||
|
} )();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
not_hoisted_when_already_nested: {
|
||||||
|
options = { if_return: true, hoist_funs: false };
|
||||||
|
input: {
|
||||||
|
( function() {
|
||||||
|
if ( !window ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( foo ) function f() {}
|
||||||
|
|
||||||
|
} )();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
( function() {
|
||||||
|
if ( window )
|
||||||
|
if ( foo ) function f() {}
|
||||||
|
} )();
|
||||||
|
}
|
||||||
|
}
|
||||||
240
test/compress/issue-1105.js
Normal file
240
test/compress/issue-1105.js
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
with_in_global_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = 42;
|
||||||
|
with(o) {
|
||||||
|
var foo = 'something'
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o=42;
|
||||||
|
with(o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
with_in_function_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
var o = 42;
|
||||||
|
with(o) {
|
||||||
|
var foo = "something"
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
var o=42;
|
||||||
|
with(o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compress_with_with_in_other_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function foo() {
|
||||||
|
var o = 42;
|
||||||
|
with(o) {
|
||||||
|
var foo = "something"
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
var unused = 42;
|
||||||
|
return something();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function foo() {
|
||||||
|
var o = 42;
|
||||||
|
with(o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o)
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
return something()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
with_using_existing_variable_outside_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var o = {};
|
||||||
|
var unused = {}; // Doesn't get removed because upper scope uses with
|
||||||
|
function foo() {
|
||||||
|
with(o) {
|
||||||
|
var foo = "something"
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
var o = {};
|
||||||
|
var unused = {};
|
||||||
|
function foo() {
|
||||||
|
with(o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o)
|
||||||
|
}
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
check_drop_unused_in_peer_function: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function outer() {
|
||||||
|
var o = {};
|
||||||
|
var unused = {}; // should be kept
|
||||||
|
function foo() { // should be kept
|
||||||
|
function not_in_use() {
|
||||||
|
var nested_unused = "foo"; // should be dropped
|
||||||
|
return 24;
|
||||||
|
}
|
||||||
|
var unused = {}; // should be kept
|
||||||
|
with (o) {
|
||||||
|
var foo = "something";
|
||||||
|
}
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
var unused = {}; // should be dropped
|
||||||
|
doSomethingElse();
|
||||||
|
}
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function outer() {
|
||||||
|
var o = {};
|
||||||
|
var unused = {}; // should be kept
|
||||||
|
function foo() { // should be kept
|
||||||
|
function not_in_use() {
|
||||||
|
return 24;
|
||||||
|
}
|
||||||
|
var unused = {}; // should be kept
|
||||||
|
with (o)
|
||||||
|
var foo = "something";
|
||||||
|
doSomething(o);
|
||||||
|
}
|
||||||
|
function bar() {
|
||||||
|
doSomethingElse();
|
||||||
|
}
|
||||||
|
foo();
|
||||||
|
bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Infinity_not_in_with_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { Infinity: 'oInfinity' };
|
||||||
|
var vInfinity = "Infinity";
|
||||||
|
vInfinity = Infinity;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = { Infinity: 'oInfinity' }
|
||||||
|
var vInfinity = "Infinity"
|
||||||
|
vInfinity = 1/0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Infinity_in_with_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { Infinity: 'oInfinity' };
|
||||||
|
var vInfinity = "Infinity";
|
||||||
|
with (o) { vInfinity = Infinity; }
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = { Infinity: 'oInfinity' }
|
||||||
|
var vInfinity = "Infinity"
|
||||||
|
with (o) vInfinity = Infinity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assorted_Infinity_NaN_undefined_in_with_scope: {
|
||||||
|
options = {
|
||||||
|
unused: true,
|
||||||
|
evaluate: true,
|
||||||
|
dead_code: true,
|
||||||
|
conditionals: true,
|
||||||
|
comparisons: true,
|
||||||
|
booleans: true,
|
||||||
|
hoist_funs: true,
|
||||||
|
keep_fargs: true,
|
||||||
|
if_return: true,
|
||||||
|
join_vars: true,
|
||||||
|
cascade: true,
|
||||||
|
side_effects: true,
|
||||||
|
sequences: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
undefined : 3,
|
||||||
|
NaN : 4,
|
||||||
|
Infinity : 5,
|
||||||
|
}
|
||||||
|
if (o) {
|
||||||
|
f(undefined, void 0);
|
||||||
|
f(NaN, 0/0);
|
||||||
|
f(Infinity, 1/0);
|
||||||
|
f(-Infinity, -(1/0));
|
||||||
|
f(2 + 7 + undefined, 2 + 7 + void 0);
|
||||||
|
}
|
||||||
|
with (o) {
|
||||||
|
f(undefined, void 0);
|
||||||
|
f(NaN, 0/0);
|
||||||
|
f(Infinity, 1/0);
|
||||||
|
f(-Infinity, -(1/0));
|
||||||
|
f(2 + 7 + undefined, 2 + 7 + void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
undefined : 3,
|
||||||
|
NaN : 4,
|
||||||
|
Infinity : 5
|
||||||
|
}
|
||||||
|
if (o) {
|
||||||
|
f(void 0, void 0);
|
||||||
|
f(NaN, NaN);
|
||||||
|
f(1/0, 1/0);
|
||||||
|
f(-(1/0), -(1/0));
|
||||||
|
f(NaN, NaN);
|
||||||
|
}
|
||||||
|
with (o) {
|
||||||
|
f(undefined, void 0);
|
||||||
|
f(NaN, 0/0);
|
||||||
|
f(Infinity, 1/0);
|
||||||
|
f(-Infinity, -(1/0));
|
||||||
|
f(9 + undefined, 9 + void 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -9,3 +9,50 @@ keep_name_of_setter: {
|
|||||||
input: { a = { set foo () {} } }
|
input: { a = { set foo () {} } }
|
||||||
expect: { a = { set foo () {} } }
|
expect: { a = { set foo () {} } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setter_with_operator_keys: {
|
||||||
|
input: {
|
||||||
|
var tokenCodes = {
|
||||||
|
get instanceof(){
|
||||||
|
return test0;
|
||||||
|
},
|
||||||
|
set instanceof(value){
|
||||||
|
test0 = value;
|
||||||
|
},
|
||||||
|
set typeof(value){
|
||||||
|
test1 = value;
|
||||||
|
},
|
||||||
|
get typeof(){
|
||||||
|
return test1;
|
||||||
|
},
|
||||||
|
set else(value){
|
||||||
|
test2 = value;
|
||||||
|
},
|
||||||
|
get else(){
|
||||||
|
return test2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var tokenCodes = {
|
||||||
|
get instanceof(){
|
||||||
|
return test0;
|
||||||
|
},
|
||||||
|
set instanceof(value){
|
||||||
|
test0 = value;
|
||||||
|
},
|
||||||
|
set typeof(value){
|
||||||
|
test1 = value;
|
||||||
|
},
|
||||||
|
get typeof(){
|
||||||
|
return test1;
|
||||||
|
},
|
||||||
|
set else(value){
|
||||||
|
test2 = value;
|
||||||
|
},
|
||||||
|
get else(){
|
||||||
|
return test2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
52
test/compress/issue-1202.js
Normal file
52
test/compress/issue-1202.js
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
mangle_keep_fnames_false: {
|
||||||
|
options = {
|
||||||
|
keep_fnames : true,
|
||||||
|
keep_fargs : true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
keep_fnames : false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
function total() {
|
||||||
|
return function n(a, b, c) {
|
||||||
|
return a + b + c;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
function total() {
|
||||||
|
return function t(n, r, u) {
|
||||||
|
return n + r + u;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_keep_fnames_true: {
|
||||||
|
options = {
|
||||||
|
keep_fnames : true,
|
||||||
|
keep_fargs : true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
keep_fnames : true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
function total() {
|
||||||
|
return function n(a, b, c) {
|
||||||
|
return a + b + c;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
function total() {
|
||||||
|
return function n(t, r, u) {
|
||||||
|
return t + r + u;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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; }
|
||||||
|
}
|
||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
27
test/compress/issue-782.js
Normal file
27
test/compress/issue-782.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
remove_redundant_sequence_items: {
|
||||||
|
options = { side_effects: true };
|
||||||
|
input: {
|
||||||
|
(0, 1, eval)();
|
||||||
|
(0, 1, logThis)();
|
||||||
|
(0, 1, _decorators.logThis)();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(0, eval)();
|
||||||
|
logThis();
|
||||||
|
(0, _decorators.logThis)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_remove_this_binding_sequence: {
|
||||||
|
options = { side_effects: true };
|
||||||
|
input: {
|
||||||
|
(0, eval)();
|
||||||
|
(0, logThis)();
|
||||||
|
(0, _decorators.logThis)();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(0, eval)();
|
||||||
|
logThis();
|
||||||
|
(0, _decorators.logThis)();
|
||||||
|
}
|
||||||
|
}
|
||||||
32
test/compress/issue-892.js
Normal file
32
test/compress/issue-892.js
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
dont_mangle_arguments: {
|
||||||
|
mangle = {
|
||||||
|
};
|
||||||
|
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 : false
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
(function(){
|
||||||
|
var arguments = arguments, not_arguments = 9;
|
||||||
|
console.log(not_arguments, arguments);
|
||||||
|
})(5,6,7);
|
||||||
|
}
|
||||||
|
expect_exact: "(function(){var arguments=arguments,o=9;console.log(o,arguments)})(5,6,7);"
|
||||||
|
}
|
||||||
20
test/compress/issue-913.js
Normal file
20
test/compress/issue-913.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
keep_var_for_in: {
|
||||||
|
options = {
|
||||||
|
hoist_vars: true,
|
||||||
|
unused: true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
(function(obj){
|
||||||
|
var foo = 5;
|
||||||
|
for (var i in obj)
|
||||||
|
return foo;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function(obj){
|
||||||
|
var i, foo = 5;
|
||||||
|
for (i in obj)
|
||||||
|
return foo;
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}
|
||||||
96
test/compress/issue-973.js
Normal file
96
test/compress/issue-973.js
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
this_binding_conditionals: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
evaluate : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
(1 && a)();
|
||||||
|
(0 || a)();
|
||||||
|
(0 || 1 && a)();
|
||||||
|
(1 ? a : 0)();
|
||||||
|
|
||||||
|
(1 && a.b)();
|
||||||
|
(0 || a.b)();
|
||||||
|
(0 || 1 && a.b)();
|
||||||
|
(1 ? a.b : 0)();
|
||||||
|
|
||||||
|
(1 && a[b])();
|
||||||
|
(0 || a[b])();
|
||||||
|
(0 || 1 && a[b])();
|
||||||
|
(1 ? a[b] : 0)();
|
||||||
|
|
||||||
|
(1 && eval)();
|
||||||
|
(0 || eval)();
|
||||||
|
(0 || 1 && eval)();
|
||||||
|
(1 ? eval : 0)();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a();
|
||||||
|
a();
|
||||||
|
a();
|
||||||
|
a();
|
||||||
|
|
||||||
|
(0, a.b)();
|
||||||
|
(0, a.b)();
|
||||||
|
(0, a.b)();
|
||||||
|
(0, a.b)();
|
||||||
|
|
||||||
|
(0, a[b])();
|
||||||
|
(0, a[b])();
|
||||||
|
(0, a[b])();
|
||||||
|
(0, a[b])();
|
||||||
|
|
||||||
|
(0, eval)();
|
||||||
|
(0, eval)();
|
||||||
|
(0, eval)();
|
||||||
|
(0, eval)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this_binding_collapse_vars: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
var c = a; c();
|
||||||
|
var d = a.b; d();
|
||||||
|
var e = eval; e();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a();
|
||||||
|
(0, a.b)();
|
||||||
|
(0, eval)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this_binding_side_effects: {
|
||||||
|
options = {
|
||||||
|
side_effects : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
(function (foo) {
|
||||||
|
(0, foo)();
|
||||||
|
(0, foo.bar)();
|
||||||
|
(0, eval)('console.log(foo);');
|
||||||
|
}());
|
||||||
|
(function (foo) {
|
||||||
|
var eval = console;
|
||||||
|
(0, foo)();
|
||||||
|
(0, foo.bar)();
|
||||||
|
(0, eval)('console.log(foo);');
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
(function (foo) {
|
||||||
|
foo();
|
||||||
|
(0, foo.bar)();
|
||||||
|
(0, eval)('console.log(foo);');
|
||||||
|
}());
|
||||||
|
(function (foo) {
|
||||||
|
var eval = console;
|
||||||
|
foo();
|
||||||
|
(0, foo.bar)();
|
||||||
|
(0, eval)('console.log(foo);');
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
}
|
||||||
88
test/compress/issue-976.js
Normal file
88
test/compress/issue-976.js
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
eval_collapse_vars: {
|
||||||
|
options = {
|
||||||
|
collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true,
|
||||||
|
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
|
||||||
|
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
function f1() {
|
||||||
|
var e = 7;
|
||||||
|
var s = "abcdef";
|
||||||
|
var i = 2;
|
||||||
|
var eval = console.log.bind(console);
|
||||||
|
var x = s.charAt(i++);
|
||||||
|
var y = s.charAt(i++);
|
||||||
|
var z = s.charAt(i++);
|
||||||
|
eval(x, y, z, e);
|
||||||
|
}
|
||||||
|
function p1() { var a = foo(), b = bar(), eval = baz(); return a + b + eval; }
|
||||||
|
function p2() { var a = foo(), b = bar(), eval = baz; return a + b + eval(); }
|
||||||
|
(function f2(eval) {
|
||||||
|
var a = 2;
|
||||||
|
console.log(a - 5);
|
||||||
|
eval("console.log(a);");
|
||||||
|
})(eval);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1() {
|
||||||
|
var e = 7,
|
||||||
|
s = "abcdef",
|
||||||
|
i = 2,
|
||||||
|
eval = console.log.bind(console),
|
||||||
|
x = s.charAt(i++),
|
||||||
|
y = s.charAt(i++),
|
||||||
|
z = s.charAt(i++);
|
||||||
|
eval(x, y, z, e);
|
||||||
|
}
|
||||||
|
function p1() { return foo() + bar() + baz(); }
|
||||||
|
function p2() { var a = foo(), b = bar(), eval = baz; return a + b + eval(); }
|
||||||
|
(function f2(eval) {
|
||||||
|
var a = 2;
|
||||||
|
console.log(a - 5);
|
||||||
|
eval("console.log(a);");
|
||||||
|
})(eval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eval_unused: {
|
||||||
|
options = { unused: true, keep_fargs: false };
|
||||||
|
input: {
|
||||||
|
function f1(a, eval, c, d, e) {
|
||||||
|
return a('c') + eval;
|
||||||
|
}
|
||||||
|
function f2(a, b, c, d, e) {
|
||||||
|
return a + eval('c');
|
||||||
|
}
|
||||||
|
function f3(a, eval, c, d, e) {
|
||||||
|
return a + eval('c');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1(a, eval) {
|
||||||
|
return a('c') + eval;
|
||||||
|
}
|
||||||
|
function f2(a, b, c, d, e) {
|
||||||
|
return a + eval('c');
|
||||||
|
}
|
||||||
|
function f3(a, eval, c, d, e) {
|
||||||
|
return a + eval('c');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eval_mangle: {
|
||||||
|
mangle = {
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
function f1(a, eval, c, d, e) {
|
||||||
|
return a('c') + eval;
|
||||||
|
}
|
||||||
|
function f2(a, b, c, d, e) {
|
||||||
|
return a + eval('c');
|
||||||
|
}
|
||||||
|
function f3(a, eval, c, d, e) {
|
||||||
|
return a + eval('c');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_exact: 'function f1(n,c,e,a,f){return n("c")+c}function f2(a,b,c,d,e){return a+eval("c")}function f3(a,eval,c,d,e){return a+eval("c")}'
|
||||||
|
}
|
||||||
89
test/compress/issue-979.js
Normal file
89
test/compress/issue-979.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
issue979_reported: {
|
||||||
|
options = {
|
||||||
|
sequences:true, properties:true, dead_code:true, conditionals:true,
|
||||||
|
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
|
||||||
|
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f1() {
|
||||||
|
if (a == 1 || b == 2) {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
if (!(a == 1 || b == 2)) {
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f1() {
|
||||||
|
1!=a&&2!=b||foo();
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
1!=a&&2!=b||foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue979_test_negated_is_best: {
|
||||||
|
options = {
|
||||||
|
sequences:true, properties:true, dead_code:true, conditionals:true,
|
||||||
|
comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true,
|
||||||
|
keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f3() {
|
||||||
|
if (a == 1 | b == 2) {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function f4() {
|
||||||
|
if (!(a == 1 | b == 2)) {
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function f5() {
|
||||||
|
if (a == 1 && b == 2) {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function f6() {
|
||||||
|
if (!(a == 1 && b == 2)) {
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function f7() {
|
||||||
|
if (a == 1 || b == 2) {
|
||||||
|
foo();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return bar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f3() {
|
||||||
|
1==a|2==b&&foo();
|
||||||
|
}
|
||||||
|
function f4() {
|
||||||
|
1==a|2==b&&foo();
|
||||||
|
}
|
||||||
|
function f5() {
|
||||||
|
1==a&&2==b&&foo();
|
||||||
|
}
|
||||||
|
function f6() {
|
||||||
|
1!=a||2!=b||foo();
|
||||||
|
}
|
||||||
|
function f7() {
|
||||||
|
return 1!=a&&2!=b?bar():void foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -121,3 +121,69 @@ drop_if_else_break_4: {
|
|||||||
for (; bar() && (x(), y(), foo());) baz(), z(), k();
|
for (; bar() && (x(), y(), foo());) baz(), z(), k();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parse_do_while_with_semicolon: {
|
||||||
|
options = { loops: false };
|
||||||
|
input: {
|
||||||
|
do {
|
||||||
|
x();
|
||||||
|
} while (false);y()
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
do x(); while (false);y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_do_while_without_semicolon: {
|
||||||
|
options = { loops: false };
|
||||||
|
input: {
|
||||||
|
do {
|
||||||
|
x();
|
||||||
|
} while (false)y()
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
do x(); while (false);y();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
keep_collapse_const_in_own_block_scope: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
loops: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var i=2;
|
||||||
|
const c=5;
|
||||||
|
while(i--)
|
||||||
|
console.log(i);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var i=2;
|
||||||
|
const c=5;
|
||||||
|
for(;i--;)
|
||||||
|
console.log(i);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_collapse_const_in_own_block_scope_2: {
|
||||||
|
options = {
|
||||||
|
join_vars: true,
|
||||||
|
loops: true
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
const c=5;
|
||||||
|
var i=2; // Moves to loop, while it did not in previous test
|
||||||
|
while(i--)
|
||||||
|
console.log(i);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
const c=5;
|
||||||
|
for(var i=2;i--;)
|
||||||
|
console.log(i);
|
||||||
|
console.log(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,3 +74,87 @@ negate_iife_4: {
|
|||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
negate_iife_nested: {
|
||||||
|
options = {
|
||||||
|
negate_iife: true,
|
||||||
|
sequences: true,
|
||||||
|
conditionals: true,
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
function Foo(f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
new Foo(function() {
|
||||||
|
(function(x) {
|
||||||
|
(function(y) {
|
||||||
|
console.log(y);
|
||||||
|
})(x);
|
||||||
|
})(7);
|
||||||
|
}).f();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function Foo(f) {
|
||||||
|
this.f = f;
|
||||||
|
}
|
||||||
|
new Foo(function() {
|
||||||
|
!function(x) {
|
||||||
|
!function(y) {
|
||||||
|
console.log(y);
|
||||||
|
}(x);
|
||||||
|
}(7);
|
||||||
|
}).f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
negate_iife_issue_1073: {
|
||||||
|
options = {
|
||||||
|
negate_iife: true,
|
||||||
|
sequences: true,
|
||||||
|
conditionals: true,
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
new (function(a) {
|
||||||
|
return function Foo() {
|
||||||
|
this.x = a;
|
||||||
|
console.log(this);
|
||||||
|
};
|
||||||
|
}(7))();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
new (function(a) {
|
||||||
|
return function Foo() {
|
||||||
|
this.x = a,
|
||||||
|
console.log(this);
|
||||||
|
};
|
||||||
|
}(7))();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1254_negate_iife_false: {
|
||||||
|
options = {
|
||||||
|
negate_iife: false,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
return function() {
|
||||||
|
console.log('test')
|
||||||
|
};
|
||||||
|
})()();
|
||||||
|
}
|
||||||
|
expect_exact: '(function(){return function(){console.log("test")}})()();'
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1254_negate_iife_true: {
|
||||||
|
options = {
|
||||||
|
negate_iife: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
(function() {
|
||||||
|
return function() {
|
||||||
|
console.log('test')
|
||||||
|
};
|
||||||
|
})()();
|
||||||
|
}
|
||||||
|
expect_exact: '!function(){return function(){console.log("test")}}()();'
|
||||||
|
}
|
||||||
|
|||||||
77
test/compress/new.js
Normal file
77
test/compress/new.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
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);"
|
||||||
|
}
|
||||||
|
|
||||||
|
new_statements_2: {
|
||||||
|
input: {
|
||||||
|
new x;
|
||||||
|
new new x;
|
||||||
|
new new new x;
|
||||||
|
new true;
|
||||||
|
new (0);
|
||||||
|
new (!0);
|
||||||
|
new (bar = function(foo) {this.foo=foo;})(123);
|
||||||
|
new (bar = function(foo) {this.foo=foo;})();
|
||||||
|
}
|
||||||
|
expect_exact: "new x;new(new x);new(new(new x));new true;new 0;new(!0);new(bar=function(foo){this.foo=foo})(123);new(bar=function(foo){this.foo=foo});"
|
||||||
|
}
|
||||||
|
|
||||||
|
new_statements_3: {
|
||||||
|
input: {
|
||||||
|
new (function(foo){this.foo=foo;})(1);
|
||||||
|
new (function(foo){this.foo=foo;})();
|
||||||
|
new (function test(foo){this.foo=foo;})(1);
|
||||||
|
new (function test(foo){this.foo=foo;})();
|
||||||
|
}
|
||||||
|
expect_exact: "new function(foo){this.foo=foo}(1);new function(foo){this.foo=foo};new function test(foo){this.foo=foo}(1);new function test(foo){this.foo=foo};"
|
||||||
|
}
|
||||||
|
|
||||||
|
new_with_rewritten_true_value: {
|
||||||
|
options = { booleans: true }
|
||||||
|
input: {
|
||||||
|
new true;
|
||||||
|
}
|
||||||
|
expect_exact: "new(!0);"
|
||||||
|
}
|
||||||
|
|
||||||
|
new_with_many_parameters: {
|
||||||
|
input: {
|
||||||
|
new foo.bar("baz");
|
||||||
|
new x(/123/, 456);
|
||||||
|
}
|
||||||
|
expect_exact: 'new foo.bar("baz");new x(/123/,456);'
|
||||||
|
}
|
||||||
|
|
||||||
|
new_constructor_with_unary_arguments: {
|
||||||
|
input: {
|
||||||
|
new x();
|
||||||
|
new x(-1);
|
||||||
|
new x(-1, -2);
|
||||||
|
new x(void 1, +2, -3, ~4, !5, --a, ++b, c--, d++, typeof e, delete f);
|
||||||
|
new (-1); // should parse despite being invalid at runtime.
|
||||||
|
new (-1)(); // should parse despite being invalid at runtime.
|
||||||
|
new (-1)(-2); // should parse despite being invalid at runtime.
|
||||||
|
}
|
||||||
|
expect_exact: "new x;new x(-1);new x(-1,-2);new x(void 1,+2,-3,~4,!5,--a,++b,c--,d++,typeof e,delete f);new(-1);new(-1);new(-1)(-2);"
|
||||||
|
}
|
||||||
|
|
||||||
|
call_with_unary_arguments: {
|
||||||
|
input: {
|
||||||
|
x();
|
||||||
|
x(-1);
|
||||||
|
x(-1, -2);
|
||||||
|
x(void 1, +2, -3, ~4, !5, --a, ++b, c--, d++, typeof e, delete f);
|
||||||
|
(-1)(); // should parse despite being invalid at runtime.
|
||||||
|
(-1)(-2); // should parse despite being invalid at runtime.
|
||||||
|
}
|
||||||
|
expect_exact: "x();x(-1);x(-1,-2);x(void 1,+2,-3,~4,!5,--a,++b,c--,d++,typeof e,delete f);(-1)();(-1)(-2);"
|
||||||
|
}
|
||||||
19
test/compress/numbers.js
Normal file
19
test/compress/numbers.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
hex_numbers_in_parentheses_for_prototype_functions: {
|
||||||
|
input: {
|
||||||
|
(-2);
|
||||||
|
(-2).toFixed(0);
|
||||||
|
|
||||||
|
(2);
|
||||||
|
(2).toFixed(0);
|
||||||
|
|
||||||
|
(0.2);
|
||||||
|
(0.2).toFixed(0);
|
||||||
|
|
||||||
|
(0.00000002);
|
||||||
|
(0.00000002).toFixed(0);
|
||||||
|
|
||||||
|
(1000000000000000128);
|
||||||
|
(1000000000000000128).toFixed(0);
|
||||||
|
}
|
||||||
|
expect_exact: "-2;(-2).toFixed(0);2;2..toFixed(0);.2;.2.toFixed(0);2e-8;2e-8.toFixed(0);0xde0b6b3a7640080;(0xde0b6b3a7640080).toFixed(0);"
|
||||||
|
}
|
||||||
@@ -12,7 +12,8 @@ keep_properties: {
|
|||||||
|
|
||||||
dot_properties: {
|
dot_properties: {
|
||||||
options = {
|
options = {
|
||||||
properties: true
|
properties: true,
|
||||||
|
screw_ie8: false
|
||||||
};
|
};
|
||||||
input: {
|
input: {
|
||||||
a["foo"] = "bar";
|
a["foo"] = "bar";
|
||||||
@@ -72,3 +73,328 @@ evaluate_length: {
|
|||||||
a = ("foo" + b).length;
|
a = ("foo" + b).length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mangle_properties: {
|
||||||
|
mangle_props = {
|
||||||
|
ignore_quoted: false
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
a["foo"] = "bar";
|
||||||
|
a.color = "red";
|
||||||
|
x = {"bar": 10};
|
||||||
|
a.run(x.bar, a.foo);
|
||||||
|
a['run']({color: "blue", foo: "baz"});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a["a"] = "bar";
|
||||||
|
a.b = "red";
|
||||||
|
x = {c: 10};
|
||||||
|
a.d(x.c, a.a);
|
||||||
|
a['d']({b: "blue", a: "baz"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mangle_unquoted_properties: {
|
||||||
|
options = {
|
||||||
|
properties: false
|
||||||
|
}
|
||||||
|
mangle_props = {
|
||||||
|
ignore_quoted: true
|
||||||
|
}
|
||||||
|
beautify = {
|
||||||
|
beautify: false,
|
||||||
|
quote_style: 3,
|
||||||
|
keep_quoted_props: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
a.top = 1;
|
||||||
|
function f1() {
|
||||||
|
a["foo"] = "bar";
|
||||||
|
a.color = "red";
|
||||||
|
a.stuff = 2;
|
||||||
|
x = {"bar": 10, size: 7};
|
||||||
|
a.size = 9;
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
a.foo = "bar";
|
||||||
|
a['color'] = "red";
|
||||||
|
x = {bar: 10, size: 7};
|
||||||
|
a.size = 9;
|
||||||
|
a.stuff = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
a.a = 1;
|
||||||
|
function f1() {
|
||||||
|
a["foo"] = "bar";
|
||||||
|
a.color = "red";
|
||||||
|
a.b = 2;
|
||||||
|
x = {"bar": 10, c: 7};
|
||||||
|
a.c = 9;
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
a.foo = "bar";
|
||||||
|
a['color'] = "red";
|
||||||
|
x = {bar: 10, c: 7};
|
||||||
|
a.c = 9;
|
||||||
|
a.b = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
first_256_chars_as_properties: {
|
||||||
|
beautify = {
|
||||||
|
ascii_only: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
// Note: some of these unicode character keys are not visible on github.com
|
||||||
|
var o = {
|
||||||
|
"\0":0,"":1,"":2,"":3,"":4,"":5,"":6,"":7,"\b":8,
|
||||||
|
"\t":9,"\n":10,"\v":11,"\f":12,"\r":13,"":14,"":15,"":16,"":17,
|
||||||
|
"":18,"":19,"":20,"":21,"":22,"":23,"":24,"":25,"":26,
|
||||||
|
"":27,"":28,"":29,"":30,"":31," ":32,"!":33,'"':34,"#":35,
|
||||||
|
$:36,"%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,
|
||||||
|
"-":45,".":46,"/":47,"0":48,"1":49,"2":50,"3":51,"4":52,"5":53,"6":54,"7":55,
|
||||||
|
"8":56,"9":57,":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,A:65,
|
||||||
|
B:66,C:67,D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,
|
||||||
|
O:79,P:80,Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,"[":91,
|
||||||
|
"\\":92,"]":93,"^":94,_:95,"`":96,a:97,b:98,c:99,d:100,e:101,
|
||||||
|
f:102,g:103,h:104,i:105,j:106,k:107,l:108,m:109,n:110,o:111,p:112,
|
||||||
|
q:113,r:114,s:115,t:116,u:117,v:118,w:119,x:120,y:121,z:122,"{":123,
|
||||||
|
"|":124,"}":125,"~":126,"":127,"":128,"":129,"":130,"":131,
|
||||||
|
"":132,"
":133,"":134,"":135,"":136,"":137,"":138,"":139,
|
||||||
|
"":140,"":141,"":142,"":143,"":144,"":145,"":146,"":147,
|
||||||
|
"":148,"":149,"":150,"":151,"":152,"":153,"":154,"":155,
|
||||||
|
"":156,"":157,"":158,"":159," ":160,"¡":161,"¢":162,"£":163,
|
||||||
|
"¤":164,"¥":165,"¦":166,"§":167,"¨":168,"©":169,"ª":170,"«":171,
|
||||||
|
"¬":172,"":173,"®":174,"¯":175,"°":176,"±":177,"²":178,"³":179,
|
||||||
|
"´":180,"µ":181,"¶":182,"·":183,"¸":184,"¹":185,"º":186,"»":187,
|
||||||
|
"¼":188,"½":189,"¾":190,"¿":191,"À":192,"Á":193,"Â":194,"Ã":195,
|
||||||
|
"Ä":196,"Å":197,"Æ":198,"Ç":199,"È":200,"É":201,"Ê":202,"Ë":203,
|
||||||
|
"Ì":204,"Í":205,"Î":206,"Ï":207,"Ð":208,"Ñ":209,"Ò":210,"Ó":211,
|
||||||
|
"Ô":212,"Õ":213,"Ö":214,"×":215,"Ø":216,"Ù":217,"Ú":218,"Û":219,
|
||||||
|
"Ü":220,"Ý":221,"Þ":222,"ß":223,"à":224,"á":225,"â":226,"ã":227,
|
||||||
|
"ä":228,"å":229,"æ":230,"ç":231,"è":232,"é":233,"ê":234,"ë":235,
|
||||||
|
"ì":236,"í":237,"î":238,"ï":239,"ð":240,"ñ":241,"ò":242,"ó":243,
|
||||||
|
"ô":244,"õ":245,"ö":246,"÷":247,"ø":248,"ù":249,"ú":250,"û":251,
|
||||||
|
"ü":252,"ý":253,"þ":254,"ÿ":255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
"\0":0,"\x01":1,"\x02":2,"\x03":3,"\x04":4,"\x05":5,"\x06":6,
|
||||||
|
"\x07":7,"\b":8,"\t":9,"\n":10,"\v":11,"\f":12,"\r":13,"\x0e":14,
|
||||||
|
"\x0f":15,"\x10":16,"\x11":17,"\x12":18,"\x13":19,"\x14":20,"\x15":21,
|
||||||
|
"\x16":22,"\x17":23,"\x18":24,"\x19":25,"\x1a":26,"\x1b":27,"\x1c":28,
|
||||||
|
"\x1d":29,"\x1e":30,"\x1f":31," ":32,"!":33,'"':34,"#":35,$:36,
|
||||||
|
"%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,"-":45,
|
||||||
|
".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,
|
||||||
|
":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,A:65,B:66,C:67,
|
||||||
|
D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,
|
||||||
|
Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,"[":91,"\\":92,
|
||||||
|
"]":93,"^":94,_:95,"`":96,a:97,b:98,c:99,d:100,e:101,f:102,g:103,
|
||||||
|
h:104,i:105,j:106,k:107,l:108,m:109,n:110,o:111,p:112,q:113,r:114,
|
||||||
|
s:115,t:116,u:117,v:118,w:119,x:120,y:121,z:122,"{":123,"|":124,
|
||||||
|
"}":125,"~":126,"\x7f":127,"\x80":128,"\x81":129,"\x82":130,"\x83":131,
|
||||||
|
"\x84":132,"\x85":133,"\x86":134,"\x87":135,"\x88":136,"\x89":137,
|
||||||
|
"\x8a":138,"\x8b":139,"\x8c":140,"\x8d":141,"\x8e":142,"\x8f":143,
|
||||||
|
"\x90":144,"\x91":145,"\x92":146,"\x93":147,"\x94":148,"\x95":149,
|
||||||
|
"\x96":150,"\x97":151,"\x98":152,"\x99":153,"\x9a":154,"\x9b":155,
|
||||||
|
"\x9c":156,"\x9d":157,"\x9e":158,"\x9f":159,"\xa0":160,"\xa1":161,
|
||||||
|
"\xa2":162,"\xa3":163,"\xa4":164,"\xa5":165,"\xa6":166,"\xa7":167,
|
||||||
|
"\xa8":168,"\xa9":169,"\xaa":170,"\xab":171,"\xac":172,"\xad":173,
|
||||||
|
"\xae":174,"\xaf":175,"\xb0":176,"\xb1":177,"\xb2":178,"\xb3":179,
|
||||||
|
"\xb4":180,"\xb5":181,"\xb6":182,"\xb7":183,"\xb8":184,"\xb9":185,
|
||||||
|
"\xba":186,"\xbb":187,"\xbc":188,"\xbd":189,"\xbe":190,"\xbf":191,
|
||||||
|
"\xc0":192,"\xc1":193,"\xc2":194,"\xc3":195,"\xc4":196,"\xc5":197,
|
||||||
|
"\xc6":198,"\xc7":199,"\xc8":200,"\xc9":201,"\xca":202,"\xcb":203,
|
||||||
|
"\xcc":204,"\xcd":205,"\xce":206,"\xcf":207,"\xd0":208,"\xd1":209,
|
||||||
|
"\xd2":210,"\xd3":211,"\xd4":212,"\xd5":213,"\xd6":214,"\xd7":215,
|
||||||
|
"\xd8":216,"\xd9":217,"\xda":218,"\xdb":219,"\xdc":220,"\xdd":221,
|
||||||
|
"\xde":222,"\xdf":223,"\xe0":224,"\xe1":225,"\xe2":226,"\xe3":227,
|
||||||
|
"\xe4":228,"\xe5":229,"\xe6":230,"\xe7":231,"\xe8":232,"\xe9":233,
|
||||||
|
"\xea":234,"\xeb":235,"\xec":236,"\xed":237,"\xee":238,"\xef":239,
|
||||||
|
"\xf0":240,"\xf1":241,"\xf2":242,"\xf3":243,"\xf4":244,"\xf5":245,
|
||||||
|
"\xf6":246,"\xf7":247,"\xf8":248,"\xf9":249,"\xfa":250,"\xfb":251,
|
||||||
|
"\xfc":252,"\xfd":253,"\xfe":254,"\xff":255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
first_256_unicode_chars_as_properties: {
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
"\u0000": 0, "\u0001": 1, "\u0002": 2, "\u0003": 3, "\u0004": 4, "\u0005": 5,
|
||||||
|
"\u0006": 6, "\u0007": 7, "\u0008": 8, "\u0009": 9, "\u000A": 10, "\u000B": 11,
|
||||||
|
"\u000C": 12, "\u000D": 13, "\u000E": 14, "\u000F": 15, "\u0010": 16, "\u0011": 17,
|
||||||
|
"\u0012": 18, "\u0013": 19, "\u0014": 20, "\u0015": 21, "\u0016": 22, "\u0017": 23,
|
||||||
|
"\u0018": 24, "\u0019": 25, "\u001A": 26, "\u001B": 27, "\u001C": 28, "\u001D": 29,
|
||||||
|
"\u001E": 30, "\u001F": 31, "\u0020": 32, "\u0021": 33, "\u0022": 34, "\u0023": 35,
|
||||||
|
"\u0024": 36, "\u0025": 37, "\u0026": 38, "\u0027": 39, "\u0028": 40, "\u0029": 41,
|
||||||
|
"\u002A": 42, "\u002B": 43, "\u002C": 44, "\u002D": 45, "\u002E": 46, "\u002F": 47,
|
||||||
|
"\u0030": 48, "\u0031": 49, "\u0032": 50, "\u0033": 51, "\u0034": 52, "\u0035": 53,
|
||||||
|
"\u0036": 54, "\u0037": 55, "\u0038": 56, "\u0039": 57, "\u003A": 58, "\u003B": 59,
|
||||||
|
"\u003C": 60, "\u003D": 61, "\u003E": 62, "\u003F": 63, "\u0040": 64, "\u0041": 65,
|
||||||
|
"\u0042": 66, "\u0043": 67, "\u0044": 68, "\u0045": 69, "\u0046": 70, "\u0047": 71,
|
||||||
|
"\u0048": 72, "\u0049": 73, "\u004A": 74, "\u004B": 75, "\u004C": 76, "\u004D": 77,
|
||||||
|
"\u004E": 78, "\u004F": 79, "\u0050": 80, "\u0051": 81, "\u0052": 82, "\u0053": 83,
|
||||||
|
"\u0054": 84, "\u0055": 85, "\u0056": 86, "\u0057": 87, "\u0058": 88, "\u0059": 89,
|
||||||
|
"\u005A": 90, "\u005B": 91, "\u005C": 92, "\u005D": 93, "\u005E": 94, "\u005F": 95,
|
||||||
|
"\u0060": 96, "\u0061": 97, "\u0062": 98, "\u0063": 99, "\u0064": 100, "\u0065": 101,
|
||||||
|
"\u0066": 102, "\u0067": 103, "\u0068": 104, "\u0069": 105, "\u006A": 106, "\u006B": 107,
|
||||||
|
"\u006C": 108, "\u006D": 109, "\u006E": 110, "\u006F": 111, "\u0070": 112, "\u0071": 113,
|
||||||
|
"\u0072": 114, "\u0073": 115, "\u0074": 116, "\u0075": 117, "\u0076": 118, "\u0077": 119,
|
||||||
|
"\u0078": 120, "\u0079": 121, "\u007A": 122, "\u007B": 123, "\u007C": 124, "\u007D": 125,
|
||||||
|
"\u007E": 126, "\u007F": 127, "\u0080": 128, "\u0081": 129, "\u0082": 130, "\u0083": 131,
|
||||||
|
"\u0084": 132, "\u0085": 133, "\u0086": 134, "\u0087": 135, "\u0088": 136, "\u0089": 137,
|
||||||
|
"\u008A": 138, "\u008B": 139, "\u008C": 140, "\u008D": 141, "\u008E": 142, "\u008F": 143,
|
||||||
|
"\u0090": 144, "\u0091": 145, "\u0092": 146, "\u0093": 147, "\u0094": 148, "\u0095": 149,
|
||||||
|
"\u0096": 150, "\u0097": 151, "\u0098": 152, "\u0099": 153, "\u009A": 154, "\u009B": 155,
|
||||||
|
"\u009C": 156, "\u009D": 157, "\u009E": 158, "\u009F": 159, "\u00A0": 160, "\u00A1": 161,
|
||||||
|
"\u00A2": 162, "\u00A3": 163, "\u00A4": 164, "\u00A5": 165, "\u00A6": 166, "\u00A7": 167,
|
||||||
|
"\u00A8": 168, "\u00A9": 169, "\u00AA": 170, "\u00AB": 171, "\u00AC": 172, "\u00AD": 173,
|
||||||
|
"\u00AE": 174, "\u00AF": 175, "\u00B0": 176, "\u00B1": 177, "\u00B2": 178, "\u00B3": 179,
|
||||||
|
"\u00B4": 180, "\u00B5": 181, "\u00B6": 182, "\u00B7": 183, "\u00B8": 184, "\u00B9": 185,
|
||||||
|
"\u00BA": 186, "\u00BB": 187, "\u00BC": 188, "\u00BD": 189, "\u00BE": 190, "\u00BF": 191,
|
||||||
|
"\u00C0": 192, "\u00C1": 193, "\u00C2": 194, "\u00C3": 195, "\u00C4": 196, "\u00C5": 197,
|
||||||
|
"\u00C6": 198, "\u00C7": 199, "\u00C8": 200, "\u00C9": 201, "\u00CA": 202, "\u00CB": 203,
|
||||||
|
"\u00CC": 204, "\u00CD": 205, "\u00CE": 206, "\u00CF": 207, "\u00D0": 208, "\u00D1": 209,
|
||||||
|
"\u00D2": 210, "\u00D3": 211, "\u00D4": 212, "\u00D5": 213, "\u00D6": 214, "\u00D7": 215,
|
||||||
|
"\u00D8": 216, "\u00D9": 217, "\u00DA": 218, "\u00DB": 219, "\u00DC": 220, "\u00DD": 221,
|
||||||
|
"\u00DE": 222, "\u00DF": 223, "\u00E0": 224, "\u00E1": 225, "\u00E2": 226, "\u00E3": 227,
|
||||||
|
"\u00E4": 228, "\u00E5": 229, "\u00E6": 230, "\u00E7": 231, "\u00E8": 232, "\u00E9": 233,
|
||||||
|
"\u00EA": 234, "\u00EB": 235, "\u00EC": 236, "\u00ED": 237, "\u00EE": 238, "\u00EF": 239,
|
||||||
|
"\u00F0": 240, "\u00F1": 241, "\u00F2": 242, "\u00F3": 243, "\u00F4": 244, "\u00F5": 245,
|
||||||
|
"\u00F6": 246, "\u00F7": 247, "\u00F8": 248, "\u00F9": 249, "\u00FA": 250, "\u00FB": 251,
|
||||||
|
"\u00FC": 252, "\u00FD": 253, "\u00FE": 254, "\u00FF": 255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
"\0":0,"\x01":1,"\x02":2,"\x03":3,"\x04":4,"\x05":5,"\x06":6,
|
||||||
|
"\x07":7,"\b":8,"\t":9,"\n":10,"\v":11,"\f":12,"\r":13,"\x0e":14,
|
||||||
|
"\x0f":15,"\x10":16,"\x11":17,"\x12":18,"\x13":19,"\x14":20,"\x15":21,
|
||||||
|
"\x16":22,"\x17":23,"\x18":24,"\x19":25,"\x1a":26,"\x1b":27,"\x1c":28,
|
||||||
|
"\x1d":29,"\x1e":30,"\x1f":31," ":32,"!":33,'"':34,"#":35,$:36,
|
||||||
|
"%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,"-":45,
|
||||||
|
".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,
|
||||||
|
":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,A:65,B:66,C:67,
|
||||||
|
D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,
|
||||||
|
Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,"[":91,"\\":92,
|
||||||
|
"]":93,"^":94,_:95,"`":96,a:97,b:98,c:99,d:100,e:101,f:102,g:103,
|
||||||
|
h:104,i:105,j:106,k:107,l:108,m:109,n:110,o:111,p:112,q:113,r:114,
|
||||||
|
s:115,t:116,u:117,v:118,w:119,x:120,y:121,z:122,"{":123,"|":124,
|
||||||
|
"}":125,"~":126,"\x7f":127,"\x80":128,"\x81":129,"\x82":130,"\x83":131,
|
||||||
|
"\x84":132,"\x85":133,"\x86":134,"\x87":135,"\x88":136,"\x89":137,
|
||||||
|
"\x8a":138,"\x8b":139,"\x8c":140,"\x8d":141,"\x8e":142,"\x8f":143,
|
||||||
|
"\x90":144,"\x91":145,"\x92":146,"\x93":147,"\x94":148,"\x95":149,
|
||||||
|
"\x96":150,"\x97":151,"\x98":152,"\x99":153,"\x9a":154,"\x9b":155,
|
||||||
|
"\x9c":156,"\x9d":157,"\x9e":158,"\x9f":159,"\xa0":160,"\xa1":161,
|
||||||
|
"\xa2":162,"\xa3":163,"\xa4":164,"\xa5":165,"\xa6":166,"\xa7":167,
|
||||||
|
"\xa8":168,"\xa9":169,"\xaa":170,"\xab":171,"\xac":172,"\xad":173,
|
||||||
|
"\xae":174,"\xaf":175,"\xb0":176,"\xb1":177,"\xb2":178,"\xb3":179,
|
||||||
|
"\xb4":180,"\xb5":181,"\xb6":182,"\xb7":183,"\xb8":184,"\xb9":185,
|
||||||
|
"\xba":186,"\xbb":187,"\xbc":188,"\xbd":189,"\xbe":190,"\xbf":191,
|
||||||
|
"\xc0":192,"\xc1":193,"\xc2":194,"\xc3":195,"\xc4":196,"\xc5":197,
|
||||||
|
"\xc6":198,"\xc7":199,"\xc8":200,"\xc9":201,"\xca":202,"\xcb":203,
|
||||||
|
"\xcc":204,"\xcd":205,"\xce":206,"\xcf":207,"\xd0":208,"\xd1":209,
|
||||||
|
"\xd2":210,"\xd3":211,"\xd4":212,"\xd5":213,"\xd6":214,"\xd7":215,
|
||||||
|
"\xd8":216,"\xd9":217,"\xda":218,"\xdb":219,"\xdc":220,"\xdd":221,
|
||||||
|
"\xde":222,"\xdf":223,"\xe0":224,"\xe1":225,"\xe2":226,"\xe3":227,
|
||||||
|
"\xe4":228,"\xe5":229,"\xe6":230,"\xe7":231,"\xe8":232,"\xe9":233,
|
||||||
|
"\xea":234,"\xeb":235,"\xec":236,"\xed":237,"\xee":238,"\xef":239,
|
||||||
|
"\xf0":240,"\xf1":241,"\xf2":242,"\xf3":243,"\xf4":244,"\xf5":245,
|
||||||
|
"\xf6":246,"\xf7":247,"\xf8":248,"\xf9":249,"\xfa":250,"\xfb":251,
|
||||||
|
"\xfc":252,"\xfd":253,"\xfe":254,"\xff":255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
first_256_hex_chars_as_properties: {
|
||||||
|
input: {
|
||||||
|
var o = {
|
||||||
|
"\x00": 0, "\x01": 1, "\x02": 2, "\x03": 3, "\x04": 4, "\x05": 5,
|
||||||
|
"\x06": 6, "\x07": 7, "\x08": 8, "\x09": 9, "\x0A": 10, "\x0B": 11,
|
||||||
|
"\x0C": 12, "\x0D": 13, "\x0E": 14, "\x0F": 15, "\x10": 16, "\x11": 17,
|
||||||
|
"\x12": 18, "\x13": 19, "\x14": 20, "\x15": 21, "\x16": 22, "\x17": 23,
|
||||||
|
"\x18": 24, "\x19": 25, "\x1A": 26, "\x1B": 27, "\x1C": 28, "\x1D": 29,
|
||||||
|
"\x1E": 30, "\x1F": 31, "\x20": 32, "\x21": 33, "\x22": 34, "\x23": 35,
|
||||||
|
"\x24": 36, "\x25": 37, "\x26": 38, "\x27": 39, "\x28": 40, "\x29": 41,
|
||||||
|
"\x2A": 42, "\x2B": 43, "\x2C": 44, "\x2D": 45, "\x2E": 46, "\x2F": 47,
|
||||||
|
"\x30": 48, "\x31": 49, "\x32": 50, "\x33": 51, "\x34": 52, "\x35": 53,
|
||||||
|
"\x36": 54, "\x37": 55, "\x38": 56, "\x39": 57, "\x3A": 58, "\x3B": 59,
|
||||||
|
"\x3C": 60, "\x3D": 61, "\x3E": 62, "\x3F": 63, "\x40": 64, "\x41": 65,
|
||||||
|
"\x42": 66, "\x43": 67, "\x44": 68, "\x45": 69, "\x46": 70, "\x47": 71,
|
||||||
|
"\x48": 72, "\x49": 73, "\x4A": 74, "\x4B": 75, "\x4C": 76, "\x4D": 77,
|
||||||
|
"\x4E": 78, "\x4F": 79, "\x50": 80, "\x51": 81, "\x52": 82, "\x53": 83,
|
||||||
|
"\x54": 84, "\x55": 85, "\x56": 86, "\x57": 87, "\x58": 88, "\x59": 89,
|
||||||
|
"\x5A": 90, "\x5B": 91, "\x5C": 92, "\x5D": 93, "\x5E": 94, "\x5F": 95,
|
||||||
|
"\x60": 96, "\x61": 97, "\x62": 98, "\x63": 99, "\x64": 100, "\x65": 101,
|
||||||
|
"\x66": 102, "\x67": 103, "\x68": 104, "\x69": 105, "\x6A": 106, "\x6B": 107,
|
||||||
|
"\x6C": 108, "\x6D": 109, "\x6E": 110, "\x6F": 111, "\x70": 112, "\x71": 113,
|
||||||
|
"\x72": 114, "\x73": 115, "\x74": 116, "\x75": 117, "\x76": 118, "\x77": 119,
|
||||||
|
"\x78": 120, "\x79": 121, "\x7A": 122, "\x7B": 123, "\x7C": 124, "\x7D": 125,
|
||||||
|
"\x7E": 126, "\x7F": 127, "\x80": 128, "\x81": 129, "\x82": 130, "\x83": 131,
|
||||||
|
"\x84": 132, "\x85": 133, "\x86": 134, "\x87": 135, "\x88": 136, "\x89": 137,
|
||||||
|
"\x8A": 138, "\x8B": 139, "\x8C": 140, "\x8D": 141, "\x8E": 142, "\x8F": 143,
|
||||||
|
"\x90": 144, "\x91": 145, "\x92": 146, "\x93": 147, "\x94": 148, "\x95": 149,
|
||||||
|
"\x96": 150, "\x97": 151, "\x98": 152, "\x99": 153, "\x9A": 154, "\x9B": 155,
|
||||||
|
"\x9C": 156, "\x9D": 157, "\x9E": 158, "\x9F": 159, "\xA0": 160, "\xA1": 161,
|
||||||
|
"\xA2": 162, "\xA3": 163, "\xA4": 164, "\xA5": 165, "\xA6": 166, "\xA7": 167,
|
||||||
|
"\xA8": 168, "\xA9": 169, "\xAA": 170, "\xAB": 171, "\xAC": 172, "\xAD": 173,
|
||||||
|
"\xAE": 174, "\xAF": 175, "\xB0": 176, "\xB1": 177, "\xB2": 178, "\xB3": 179,
|
||||||
|
"\xB4": 180, "\xB5": 181, "\xB6": 182, "\xB7": 183, "\xB8": 184, "\xB9": 185,
|
||||||
|
"\xBA": 186, "\xBB": 187, "\xBC": 188, "\xBD": 189, "\xBE": 190, "\xBF": 191,
|
||||||
|
"\xC0": 192, "\xC1": 193, "\xC2": 194, "\xC3": 195, "\xC4": 196, "\xC5": 197,
|
||||||
|
"\xC6": 198, "\xC7": 199, "\xC8": 200, "\xC9": 201, "\xCA": 202, "\xCB": 203,
|
||||||
|
"\xCC": 204, "\xCD": 205, "\xCE": 206, "\xCF": 207, "\xD0": 208, "\xD1": 209,
|
||||||
|
"\xD2": 210, "\xD3": 211, "\xD4": 212, "\xD5": 213, "\xD6": 214, "\xD7": 215,
|
||||||
|
"\xD8": 216, "\xD9": 217, "\xDA": 218, "\xDB": 219, "\xDC": 220, "\xDD": 221,
|
||||||
|
"\xDE": 222, "\xDF": 223, "\xE0": 224, "\xE1": 225, "\xE2": 226, "\xE3": 227,
|
||||||
|
"\xE4": 228, "\xE5": 229, "\xE6": 230, "\xE7": 231, "\xE8": 232, "\xE9": 233,
|
||||||
|
"\xEA": 234, "\xEB": 235, "\xEC": 236, "\xED": 237, "\xEE": 238, "\xEF": 239,
|
||||||
|
"\xF0": 240, "\xF1": 241, "\xF2": 242, "\xF3": 243, "\xF4": 244, "\xF5": 245,
|
||||||
|
"\xF6": 246, "\xF7": 247, "\xF8": 248, "\xF9": 249, "\xFA": 250, "\xFB": 251,
|
||||||
|
"\xFC": 252, "\xFD": 253, "\xFE": 254, "\xFF": 255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = {
|
||||||
|
"\0":0,"\x01":1,"\x02":2,"\x03":3,"\x04":4,"\x05":5,"\x06":6,
|
||||||
|
"\x07":7,"\b":8,"\t":9,"\n":10,"\v":11,"\f":12,"\r":13,"\x0e":14,
|
||||||
|
"\x0f":15,"\x10":16,"\x11":17,"\x12":18,"\x13":19,"\x14":20,"\x15":21,
|
||||||
|
"\x16":22,"\x17":23,"\x18":24,"\x19":25,"\x1a":26,"\x1b":27,"\x1c":28,
|
||||||
|
"\x1d":29,"\x1e":30,"\x1f":31," ":32,"!":33,'"':34,"#":35,$:36,
|
||||||
|
"%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,"-":45,
|
||||||
|
".":46,"/":47,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,
|
||||||
|
":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,A:65,B:66,C:67,
|
||||||
|
D:68,E:69,F:70,G:71,H:72,I:73,J:74,K:75,L:76,M:77,N:78,O:79,P:80,
|
||||||
|
Q:81,R:82,S:83,T:84,U:85,V:86,W:87,X:88,Y:89,Z:90,"[":91,"\\":92,
|
||||||
|
"]":93,"^":94,_:95,"`":96,a:97,b:98,c:99,d:100,e:101,f:102,g:103,
|
||||||
|
h:104,i:105,j:106,k:107,l:108,m:109,n:110,o:111,p:112,q:113,r:114,
|
||||||
|
s:115,t:116,u:117,v:118,w:119,x:120,y:121,z:122,"{":123,"|":124,
|
||||||
|
"}":125,"~":126,"\x7f":127,"\x80":128,"\x81":129,"\x82":130,"\x83":131,
|
||||||
|
"\x84":132,"\x85":133,"\x86":134,"\x87":135,"\x88":136,"\x89":137,
|
||||||
|
"\x8a":138,"\x8b":139,"\x8c":140,"\x8d":141,"\x8e":142,"\x8f":143,
|
||||||
|
"\x90":144,"\x91":145,"\x92":146,"\x93":147,"\x94":148,"\x95":149,
|
||||||
|
"\x96":150,"\x97":151,"\x98":152,"\x99":153,"\x9a":154,"\x9b":155,
|
||||||
|
"\x9c":156,"\x9d":157,"\x9e":158,"\x9f":159,"\xa0":160,"\xa1":161,
|
||||||
|
"\xa2":162,"\xa3":163,"\xa4":164,"\xa5":165,"\xa6":166,"\xa7":167,
|
||||||
|
"\xa8":168,"\xa9":169,"\xaa":170,"\xab":171,"\xac":172,"\xad":173,
|
||||||
|
"\xae":174,"\xaf":175,"\xb0":176,"\xb1":177,"\xb2":178,"\xb3":179,
|
||||||
|
"\xb4":180,"\xb5":181,"\xb6":182,"\xb7":183,"\xb8":184,"\xb9":185,
|
||||||
|
"\xba":186,"\xbb":187,"\xbc":188,"\xbd":189,"\xbe":190,"\xbf":191,
|
||||||
|
"\xc0":192,"\xc1":193,"\xc2":194,"\xc3":195,"\xc4":196,"\xc5":197,
|
||||||
|
"\xc6":198,"\xc7":199,"\xc8":200,"\xc9":201,"\xca":202,"\xcb":203,
|
||||||
|
"\xcc":204,"\xcd":205,"\xce":206,"\xcf":207,"\xd0":208,"\xd1":209,
|
||||||
|
"\xd2":210,"\xd3":211,"\xd4":212,"\xd5":213,"\xd6":214,"\xd7":215,
|
||||||
|
"\xd8":216,"\xd9":217,"\xda":218,"\xdb":219,"\xdc":220,"\xdd":221,
|
||||||
|
"\xde":222,"\xdf":223,"\xe0":224,"\xe1":225,"\xe2":226,"\xe3":227,
|
||||||
|
"\xe4":228,"\xe5":229,"\xe6":230,"\xe7":231,"\xe8":232,"\xe9":233,
|
||||||
|
"\xea":234,"\xeb":235,"\xec":236,"\xed":237,"\xee":238,"\xef":239,
|
||||||
|
"\xf0":240,"\xf1":241,"\xf2":242,"\xf3":243,"\xf4":244,"\xf5":245,
|
||||||
|
"\xf6":246,"\xf7":247,"\xf8":248,"\xf9":249,"\xfa":250,"\xfb":251,
|
||||||
|
"\xfc":252,"\xfd":253,"\xfe":254,"\xff":255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
124
test/compress/return_undefined.js
Normal file
124
test/compress/return_undefined.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
return_undefined: {
|
||||||
|
options = {
|
||||||
|
sequences : false,
|
||||||
|
if_return : true,
|
||||||
|
evaluate : true,
|
||||||
|
dead_code : true,
|
||||||
|
conditionals : true,
|
||||||
|
comparisons : true,
|
||||||
|
booleans : true,
|
||||||
|
unused : true,
|
||||||
|
side_effects : true,
|
||||||
|
properties : true,
|
||||||
|
drop_debugger : true,
|
||||||
|
loops : true,
|
||||||
|
hoist_funs : true,
|
||||||
|
keep_fargs : true,
|
||||||
|
keep_fnames : false,
|
||||||
|
hoist_vars : true,
|
||||||
|
join_vars : true,
|
||||||
|
cascade : true,
|
||||||
|
negate_iife : true
|
||||||
|
};
|
||||||
|
input: {
|
||||||
|
function f0() {
|
||||||
|
}
|
||||||
|
function f1() {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
function f2() {
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
function f3() {
|
||||||
|
return void 123;
|
||||||
|
}
|
||||||
|
function f4() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
function f5(a, b) {
|
||||||
|
console.log(a, b);
|
||||||
|
baz(a);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
function f6(a, b) {
|
||||||
|
console.log(a, b);
|
||||||
|
if (a) {
|
||||||
|
foo(b);
|
||||||
|
baz(a);
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
function f7(a, b) {
|
||||||
|
console.log(a, b);
|
||||||
|
if (a) {
|
||||||
|
foo(b);
|
||||||
|
baz(a);
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
function f8(a, b) {
|
||||||
|
foo(a);
|
||||||
|
bar(b);
|
||||||
|
return void 0;
|
||||||
|
}
|
||||||
|
function f9(a, b) {
|
||||||
|
foo(a);
|
||||||
|
bar(b);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
function f10() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
function f11() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function f12() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f0() {}
|
||||||
|
function f1() {}
|
||||||
|
function f2() {}
|
||||||
|
function f3() {}
|
||||||
|
function f4() {}
|
||||||
|
function f5(a, b) {
|
||||||
|
console.log(a, b);
|
||||||
|
baz(a);
|
||||||
|
}
|
||||||
|
function f6(a, b) {
|
||||||
|
console.log(a, b);
|
||||||
|
if (a) {
|
||||||
|
foo(b);
|
||||||
|
baz(a);
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function f7(a, b) {
|
||||||
|
console.log(a, b);
|
||||||
|
if (!a)
|
||||||
|
return a + b;
|
||||||
|
foo(b);
|
||||||
|
baz(a);
|
||||||
|
}
|
||||||
|
function f8(a, b) {
|
||||||
|
foo(a);
|
||||||
|
bar(b);
|
||||||
|
}
|
||||||
|
function f9(a, b) {
|
||||||
|
foo(a);
|
||||||
|
bar(b);
|
||||||
|
}
|
||||||
|
function f10() {
|
||||||
|
return !1;
|
||||||
|
}
|
||||||
|
function f11() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function f12() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
test/compress/screw-ie8.js
Normal file
18
test/compress/screw-ie8.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
do_screw: {
|
||||||
|
options = { screw_ie8: true };
|
||||||
|
beautify = {
|
||||||
|
screw_ie8: true,
|
||||||
|
ascii_only: true
|
||||||
|
};
|
||||||
|
|
||||||
|
input: f("\v");
|
||||||
|
expect_exact: 'f("\\v");';
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_screw: {
|
||||||
|
options = { screw_ie8: false };
|
||||||
|
beautify = { screw_ie8: false, ascii_only: true };
|
||||||
|
|
||||||
|
input: f("\v");
|
||||||
|
expect_exact: 'f("\\x0B");';
|
||||||
|
}
|
||||||
10
test/compress/string-literal.js
Normal file
10
test/compress/string-literal.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
octal_escape_sequence: {
|
||||||
|
input: {
|
||||||
|
var boundaries = "\0\7\00\07\70\77\000\077\300\377";
|
||||||
|
var border_check = "\400\700\0000\3000";
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var boundaries = "\x00\x07\x00\x07\x38\x3f\x00\x3f\xc0\xff";
|
||||||
|
var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30";
|
||||||
|
}
|
||||||
|
}
|
||||||
8
test/input/issue-1236/simple.js
Normal file
8
test/input/issue-1236/simple.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var foo = function foo(x) {
|
||||||
|
return "foo " + x;
|
||||||
|
};
|
||||||
|
console.log(foo("bar"));
|
||||||
|
|
||||||
|
//# sourceMappingURL=simple.js.map
|
||||||
8
test/input/issue-1236/simple.js.map
Normal file
8
test/input/issue-1236/simple.js.map
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"version": 3,
|
||||||
|
"sources": ["index.js"],
|
||||||
|
"names": [],
|
||||||
|
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
|
||||||
|
"file": "simple.js",
|
||||||
|
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
|
||||||
|
}
|
||||||
4
test/input/issue-1242/bar.es5
Normal file
4
test/input/issue-1242/bar.es5
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
function bar(x) {
|
||||||
|
var triple = x * (2 + 1);
|
||||||
|
return triple;
|
||||||
|
}
|
||||||
4
test/input/issue-1242/baz.es5
Normal file
4
test/input/issue-1242/baz.es5
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
function baz(x) {
|
||||||
|
var half = x / 2;
|
||||||
|
return half;
|
||||||
|
}
|
||||||
5
test/input/issue-1242/foo.es5
Normal file
5
test/input/issue-1242/foo.es5
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
var print = console.log.bind(console);
|
||||||
|
function foo(x) {
|
||||||
|
var twice = x * 2;
|
||||||
|
print('Foo:', twice);
|
||||||
|
}
|
||||||
4
test/input/issue-1242/qux.js
Normal file
4
test/input/issue-1242/qux.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
var a = bar(1+2);
|
||||||
|
var b = baz(3+9);
|
||||||
|
print('q' + 'u' + 'x', a, b);
|
||||||
|
foo(5+6);
|
||||||
29
test/mocha.js
Normal file
29
test/mocha.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
var Mocha = require('mocha'),
|
||||||
|
fs = require('fs'),
|
||||||
|
path = require('path');
|
||||||
|
|
||||||
|
// Instantiate a Mocha instance.
|
||||||
|
var mocha = new Mocha({});
|
||||||
|
|
||||||
|
var testDir = __dirname + '/mocha/';
|
||||||
|
|
||||||
|
// Add each .js file to the mocha instance
|
||||||
|
fs.readdirSync(testDir).filter(function(file){
|
||||||
|
// Only keep the .js files
|
||||||
|
return file.substr(-3) === '.js';
|
||||||
|
|
||||||
|
}).forEach(function(file){
|
||||||
|
mocha.addFile(
|
||||||
|
path.join(testDir, file)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = function() {
|
||||||
|
mocha.run(function(failures) {
|
||||||
|
if (failures !== 0) {
|
||||||
|
process.on('exit', function () {
|
||||||
|
process.exit(failures);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
22
test/mocha/arguments.js
Normal file
22
test/mocha/arguments.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
var UglifyJS = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("arguments", function() {
|
||||||
|
it("Should known that arguments in functions are local scoped", function() {
|
||||||
|
var ast = UglifyJS.parse("var arguments; var f = function() {arguments.length}");
|
||||||
|
ast.figure_out_scope();
|
||||||
|
|
||||||
|
// Test scope of `var arguments`
|
||||||
|
assert.strictEqual(ast.find_variable("arguments").global, true);
|
||||||
|
|
||||||
|
// Select arguments symbol in function
|
||||||
|
var symbol = ast.body[1].definitions[0].value.find_variable("arguments");
|
||||||
|
|
||||||
|
assert.strictEqual(symbol.global, false);
|
||||||
|
assert.strictEqual(symbol.scope, ast. // From ast
|
||||||
|
body[1]. // Select 2nd statement (equals to `var f ...`)
|
||||||
|
definitions[0]. // First definition of selected statement
|
||||||
|
value // Select function as scope
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
22
test/mocha/cli.js
Normal file
22
test/mocha/cli.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var exec = require("child_process").exec;
|
||||||
|
|
||||||
|
describe("bin/uglifyjs", function () {
|
||||||
|
it("should produce a functional build when using --self", function (done) {
|
||||||
|
this.timeout(5000);
|
||||||
|
|
||||||
|
var uglifyjs = '"' + process.argv[0] + '" bin/uglifyjs';
|
||||||
|
var command = uglifyjs + ' --self -cm --wrap WrappedUglifyJS';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
eval(stdout);
|
||||||
|
|
||||||
|
assert.strictEqual(typeof WrappedUglifyJS, 'object');
|
||||||
|
assert.strictEqual(true, WrappedUglifyJS.parse('foo;') instanceof WrappedUglifyJS.AST_Node);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
45
test/mocha/comment-filter.js
Normal file
45
test/mocha/comment-filter.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
var UglifyJS = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("comment filters", function() {
|
||||||
|
it("Should be able to filter comments by passing regex", function() {
|
||||||
|
var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\n<!--test5\n<!--!test6\n-->test7\n-->!test8");
|
||||||
|
assert.strictEqual(ast.print_to_string({comments: /^!/}), "/*!test1*/\n//!test3\n//!test6\n//!test8\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should be able to filter comments by passing a function", function() {
|
||||||
|
var ast = UglifyJS.parse("/*TEST 123*/\n//An other comment\n//8 chars.");
|
||||||
|
var f = function(node, comment) {
|
||||||
|
return comment.value.length === 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.strictEqual(ast.print_to_string({comments: f}), "/*TEST 123*/\n//8 chars.\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should be able to get the comment and comment type when using a function", function() {
|
||||||
|
var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\n<!--test5\n<!--!test6\n-->test7\n-->!test8");
|
||||||
|
var f = function(node, comment) {
|
||||||
|
return comment.type == "comment1" || comment.type == "comment3";
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.strictEqual(ast.print_to_string({comments: f}), "//!test3\n//test4\n//test5\n//!test6\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should be able to filter comments by passing a boolean", function() {
|
||||||
|
var ast = UglifyJS.parse("/*!test1*/\n/*test2*/\n//!test3\n//test4\n<!--test5\n<!--!test6\n-->test7\n-->!test8");
|
||||||
|
|
||||||
|
assert.strictEqual(ast.print_to_string({comments: true}), "/*!test1*/\n/*test2*/\n//!test3\n//test4\n//test5\n//!test6\n//test7\n//!test8\n");
|
||||||
|
assert.strictEqual(ast.print_to_string({comments: false}), "");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should never be able to filter comment5 (shebangs)", function() {
|
||||||
|
var ast = UglifyJS.parse("#!Random comment\n//test1\n/*test2*/");
|
||||||
|
var f = function(node, comment) {
|
||||||
|
assert.strictEqual(comment.type === "comment5", false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.strictEqual(ast.print_to_string({comments: f}), "#!Random comment\n//test1\n/*test2*/\n");
|
||||||
|
});
|
||||||
|
});
|
||||||
50
test/mocha/comment.js
Normal file
50
test/mocha/comment.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("Comment", function() {
|
||||||
|
it("Should recognize eol of single line comments", function() {
|
||||||
|
var tests = [
|
||||||
|
"//Some comment 1\n>",
|
||||||
|
"//Some comment 2\r>",
|
||||||
|
"//Some comment 3\r\n>",
|
||||||
|
"//Some comment 4\u2028>",
|
||||||
|
"//Some comment 5\u2029>"
|
||||||
|
];
|
||||||
|
|
||||||
|
var fail = function(e) {
|
||||||
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
|
e.message === "SyntaxError: Unexpected token: operator (>)" &&
|
||||||
|
e.line === 2 &&
|
||||||
|
e.col === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.throws(function() {
|
||||||
|
uglify.parse(tests[i], {fromString: true})
|
||||||
|
}, fail, tests[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should update the position of a multiline comment correctly", function() {
|
||||||
|
var tests = [
|
||||||
|
"/*Some comment 1\n\n\n*/\n>\n\n\n\n\n\n",
|
||||||
|
"/*Some comment 2\r\n\r\n\r\n*/\r\n>\n\n\n\n\n\n",
|
||||||
|
"/*Some comment 3\r\r\r*/\r>\n\n\n\n\n\n",
|
||||||
|
"/*Some comment 4\u2028\u2028\u2028*/\u2028>\n\n\n\n\n\n",
|
||||||
|
"/*Some comment 5\u2029\u2029\u2029*/\u2029>\n\n\n\n\n\n"
|
||||||
|
];
|
||||||
|
|
||||||
|
var fail = function(e) {
|
||||||
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
|
e.message === "SyntaxError: Unexpected token: operator (>)" &&
|
||||||
|
e.line === 5 &&
|
||||||
|
e.col === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.throws(function() {
|
||||||
|
uglify.parse(tests[i], {fromString: true})
|
||||||
|
}, fail, tests[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
27
test/mocha/comment_before_constant.js
Normal file
27
test/mocha/comment_before_constant.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
var Uglify = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("comment before constant", function() {
|
||||||
|
var js = 'function f() { /*c1*/ var /*c2*/ foo = /*c3*/ false; return foo; }';
|
||||||
|
|
||||||
|
it("Should test comment before constant is retained and output after mangle.", function() {
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true,
|
||||||
|
compress: { collapse_vars: false },
|
||||||
|
mangle: {},
|
||||||
|
output: { comments: true },
|
||||||
|
});
|
||||||
|
assert.strictEqual(result.code, 'function f(){/*c1*/var/*c2*/n=/*c3*/!1;return n}');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should test code works when comments disabled.", function() {
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true,
|
||||||
|
compress: { collapse_vars: false },
|
||||||
|
mangle: {},
|
||||||
|
output: {},
|
||||||
|
});
|
||||||
|
assert.strictEqual(result.code, 'function f(){var n=!1;return n}');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
370
test/mocha/directives.js
Normal file
370
test/mocha/directives.js
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("Directives", function() {
|
||||||
|
it ("Should allow tokenizer to store directives state", function() {
|
||||||
|
var tokenizer = uglify.tokenizer("", "foo.js");
|
||||||
|
|
||||||
|
// Stack level 0
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 2
|
||||||
|
tokenizer.push_directives_stack();
|
||||||
|
tokenizer.push_directives_stack();
|
||||||
|
tokenizer.add_directive("use strict");
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 3
|
||||||
|
tokenizer.push_directives_stack();
|
||||||
|
tokenizer.add_directive("use strict");
|
||||||
|
tokenizer.add_directive("use asm");
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 2
|
||||||
|
tokenizer.pop_directives_stack();
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 3
|
||||||
|
tokenizer.push_directives_stack();
|
||||||
|
tokenizer.add_directive("use thing");
|
||||||
|
tokenizer.add_directive("use\\\nasm");
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false); // Directives are strict!
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), true);
|
||||||
|
|
||||||
|
// Stack level 2
|
||||||
|
tokenizer.pop_directives_stack();
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), true);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 1
|
||||||
|
tokenizer.pop_directives_stack();
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
|
||||||
|
// Stack level 0
|
||||||
|
tokenizer.pop_directives_stack();
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use strict"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use asm"), false);
|
||||||
|
assert.strictEqual(tokenizer.has_directive("use thing"), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should know which strings are directive and which ones are not", function() {
|
||||||
|
var test_directive = function(tokenizer, test) {
|
||||||
|
test.directives.map(function(directive) {
|
||||||
|
assert.strictEqual(tokenizer.has_directive(directive), true, directive + " in " + test.input);
|
||||||
|
});
|
||||||
|
test.non_directives.map(function(fake_directive) {
|
||||||
|
assert.strictEqual(tokenizer.has_directive(fake_directive), false, fake_directive + " in " + test.input);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = [
|
||||||
|
{
|
||||||
|
input: '"use strict"\n',
|
||||||
|
directives: ["use strict"],
|
||||||
|
non_directives: ["use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use\\\nstrict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use strict"\n"use asm"\n"use bar"\n',
|
||||||
|
directives: ["use strict", "use asm", "use bar"],
|
||||||
|
non_directives: ["use foo", "use\\x20strict"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use \\\nstrict";"use strict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"\\76";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: [">", "\\76"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use strict"', // no ; or newline
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ';"use strict"',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
// Duplicate above code but put it in a function
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use strict"\n',
|
||||||
|
directives: ["use strict"],
|
||||||
|
non_directives: ["use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use\\\nstrict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use strict"\n"use asm"\n"use bar"\n',
|
||||||
|
directives: ["use strict", "use asm", "use bar"],
|
||||||
|
non_directives: ["use foo", "use\\x20strict"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use \\\nstrict";"use strict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'var foo = function() {"\\76";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: [">", "\\76"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'var foo = function() {"use strict"', // no ; or newline
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'var foo = function() {;"use strict"',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
// Special cases
|
||||||
|
{
|
||||||
|
input: '"1";"2";"3";"4";;"5"',
|
||||||
|
directives: ["1", "2", "3", "4"],
|
||||||
|
non_directives: ["5", "6", "use strict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'if(1){"use strict";',
|
||||||
|
directives: [],
|
||||||
|
non_directives: ["use strict", "use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use strict";try{"use asm";',
|
||||||
|
directives: ["use strict"],
|
||||||
|
non_directives: ["use\nstrict", "use \nstrict", "use asm"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
// Fail parser deliberately to get state at failure
|
||||||
|
var tokenizer = uglify.tokenizer(tests[i].input + "]", "foo.js");
|
||||||
|
|
||||||
|
try {
|
||||||
|
var parser = uglify.parse(tokenizer);
|
||||||
|
throw new Error("Expected parser to fail");
|
||||||
|
} catch (e) {
|
||||||
|
assert.strictEqual(e instanceof uglify.JS_Parse_Error, true);
|
||||||
|
assert.strictEqual(e.message, "SyntaxError: Unexpected token: punc (])");
|
||||||
|
}
|
||||||
|
|
||||||
|
test_directive(tokenizer, tests[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should test EXPECT_DIRECTIVE RegExp", function() {
|
||||||
|
var tests = [
|
||||||
|
["", true],
|
||||||
|
["'test';", true],
|
||||||
|
["'test';;", true],
|
||||||
|
["'tests';\n", true],
|
||||||
|
["'tests'", false],
|
||||||
|
["'tests'; \n\t", true],
|
||||||
|
["'tests';\n\n", true],
|
||||||
|
["\n\n\"use strict\";\n\n", true]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(uglify.EXPECT_DIRECTIVE.test(tests[i][0]), tests[i][1], tests[i][0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should only print 2 semicolons spread over 2 lines in beautify mode", function() {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(
|
||||||
|
'"use strict";\'use strict\';"use strict";"use strict";;\'use strict\';console.log(\'use strict\');',
|
||||||
|
{fromString: true, output: {beautify: true, quote_style: 3}, compress: false}
|
||||||
|
).code,
|
||||||
|
'"use strict";\n\n\'use strict\';\n\n"use strict";\n\n"use strict";\n\n;\'use strict\';\n\nconsole.log(\'use strict\');'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not add double semicolons in non-scoped block statements to avoid strings becoming directives", function() {
|
||||||
|
var tests = [
|
||||||
|
[
|
||||||
|
'{"use\x20strict"}',
|
||||||
|
'{"use strict"}'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'function foo(){"use\x20strict";}', // Valid place for directives
|
||||||
|
'function foo(){"use strict"}'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'try{"use\x20strict"}catch(e){}finally{"use\x20strict"}',
|
||||||
|
'try{"use strict"}catch(e){}finally{"use strict"}'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'if(1){"use\x20strict"} else {"use strict"}',
|
||||||
|
'if(1){"use strict"}else{"use strict"}'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(tests[i][0], {fromString: true, quote_style: 3, compress: false, mangle: false}).code,
|
||||||
|
tests[i][1],
|
||||||
|
tests[i][0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should add double semicolon when relying on automatic semicolon insertion", function() {
|
||||||
|
var code = uglify.minify('"use strict";"use\\x20strict";',
|
||||||
|
{fromString: true, output: {semicolons: false}, compress: false}
|
||||||
|
).code;
|
||||||
|
assert.strictEqual(code, '"use strict";;"use strict"\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should check quote style of directives", function() {
|
||||||
|
var tests = [
|
||||||
|
// 0. Prefer double quotes, unless string contains more double quotes than single quotes
|
||||||
|
[
|
||||||
|
'"testing something";',
|
||||||
|
0,
|
||||||
|
'"testing something";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'use strict';",
|
||||||
|
0,
|
||||||
|
'"use strict";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\\\'use strict\\\'";', // Not a directive as it contains quotes
|
||||||
|
0,
|
||||||
|
';"\'use strict\'";',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\"use strict\"';",
|
||||||
|
0,
|
||||||
|
"'\"use strict\"';",
|
||||||
|
],
|
||||||
|
// 1. Always use single quote
|
||||||
|
[
|
||||||
|
'"testing something";',
|
||||||
|
1,
|
||||||
|
"'testing something';"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'use strict';",
|
||||||
|
1,
|
||||||
|
"'use strict';"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\'use strict\'";',
|
||||||
|
1,
|
||||||
|
// Intentionally causes directive breakage at cost of less logic, usage should be rare anyway
|
||||||
|
"'\\'use strict\\'';",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\\'use strict\\'';", // Not a valid directive
|
||||||
|
1,
|
||||||
|
"'\\'use strict\\'';" // But no ; necessary as directive stays invalid
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\"use strict\"';",
|
||||||
|
1,
|
||||||
|
"'\"use strict\"';",
|
||||||
|
],
|
||||||
|
// 2. Always use double quote
|
||||||
|
[
|
||||||
|
'"testing something";',
|
||||||
|
2,
|
||||||
|
'"testing something";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'use strict';",
|
||||||
|
2,
|
||||||
|
'"use strict";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\'use strict\'";',
|
||||||
|
2,
|
||||||
|
"\"'use strict'\";",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\"use strict\"';",
|
||||||
|
2,
|
||||||
|
// Intentionally causes directive breakage at cost of less logic, usage should be rare anyway
|
||||||
|
'"\\\"use strict\\\"";',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\\"use strict\\"";', // Not a valid directive
|
||||||
|
2,
|
||||||
|
'"\\"use strict\\"";' // But no ; necessary as directive stays invalid
|
||||||
|
],
|
||||||
|
// 3. Always use original
|
||||||
|
[
|
||||||
|
'"testing something";',
|
||||||
|
3,
|
||||||
|
'"testing something";'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'use strict';",
|
||||||
|
3,
|
||||||
|
"'use strict';",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'"\'use strict\'";',
|
||||||
|
3,
|
||||||
|
'"\'use strict\'";',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"'\"use strict\"';",
|
||||||
|
3,
|
||||||
|
"'\"use strict\"';",
|
||||||
|
],
|
||||||
|
];
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(tests[i][0], {fromString: true, output:{quote_style: tests[i][1]}, compress: false}).code,
|
||||||
|
tests[i][2],
|
||||||
|
tests[i][0] + " using mode " + tests[i][1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it("Should be able to compress without side effects", function() {
|
||||||
|
// NOTE: the "use asm" directive disables any optimisation after being defined
|
||||||
|
var tests = [
|
||||||
|
[
|
||||||
|
'"use strict";"use strict";"use strict";"use foo";"use strict";;"use sloppy";doSomething("foo");',
|
||||||
|
'"use strict";"use foo";doSomething("foo");'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
// Nothing gets optimised in the compressor because "use asm" is the first statement
|
||||||
|
'"use asm";"use\\x20strict";1+1;',
|
||||||
|
'"use asm";;"use strict";1+1;' // Yet, the parser noticed that "use strict" wasn't a directive
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(tests[i][0], {fromString: true, compress: {collapse_vars: true, side_effects: true}}).code,
|
||||||
|
tests[i][1],
|
||||||
|
tests[i][0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
89
test/mocha/getter-setter.js
Normal file
89
test/mocha/getter-setter.js
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
var UglifyJS = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("Getters and setters", function() {
|
||||||
|
it("Should not accept operator symbols as getter/setter name", function() {
|
||||||
|
var illegalOperators = [
|
||||||
|
"++",
|
||||||
|
"--",
|
||||||
|
"+",
|
||||||
|
"-",
|
||||||
|
"!",
|
||||||
|
"~",
|
||||||
|
"&",
|
||||||
|
"|",
|
||||||
|
"^",
|
||||||
|
"*",
|
||||||
|
"/",
|
||||||
|
"%",
|
||||||
|
">>",
|
||||||
|
"<<",
|
||||||
|
">>>",
|
||||||
|
"<",
|
||||||
|
">",
|
||||||
|
"<=",
|
||||||
|
">=",
|
||||||
|
"==",
|
||||||
|
"===",
|
||||||
|
"!=",
|
||||||
|
"!==",
|
||||||
|
"?",
|
||||||
|
"=",
|
||||||
|
"+=",
|
||||||
|
"-=",
|
||||||
|
"/=",
|
||||||
|
"*=",
|
||||||
|
"%=",
|
||||||
|
">>=",
|
||||||
|
"<<=",
|
||||||
|
">>>=",
|
||||||
|
"|=",
|
||||||
|
"^=",
|
||||||
|
"&=",
|
||||||
|
"&&",
|
||||||
|
"||"
|
||||||
|
];
|
||||||
|
var generator = function() {
|
||||||
|
var results = [];
|
||||||
|
|
||||||
|
for (var i in illegalOperators) {
|
||||||
|
results.push({
|
||||||
|
code: "var obj = { get " + illegalOperators[i] + "() { return test; }};",
|
||||||
|
operator: illegalOperators[i],
|
||||||
|
method: "get"
|
||||||
|
});
|
||||||
|
results.push({
|
||||||
|
code: "var obj = { set " + illegalOperators[i] + "(value) { test = value}};",
|
||||||
|
operator: illegalOperators[i],
|
||||||
|
method: "set"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|
||||||
|
var testCase = function(data) {
|
||||||
|
return function() {
|
||||||
|
UglifyJS.parse(data.code);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var fail = function(data) {
|
||||||
|
return function (e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
|
e.message === "SyntaxError: Invalid getter/setter name: " + data.operator;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var errorMessage = function(data) {
|
||||||
|
return "Expected but didn't get a syntax error while parsing following line:\n" + data.code;
|
||||||
|
};
|
||||||
|
|
||||||
|
var tests = generator();
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
var test = tests[i];
|
||||||
|
assert.throws(testCase(test), fail(test), errorMessage(test));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
28
test/mocha/glob.js
Normal file
28
test/mocha/glob.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
var Uglify = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("minify() with input file globs", function() {
|
||||||
|
it("minify() with one input file glob string.", function() {
|
||||||
|
var result = Uglify.minify("test/input/issue-1242/foo.*", {
|
||||||
|
compress: { collapse_vars: true }
|
||||||
|
});
|
||||||
|
assert.strictEqual(result.code, 'function foo(o){print("Foo:",2*o)}var print=console.log.bind(console);');
|
||||||
|
});
|
||||||
|
it("minify() with an array of one input file glob.", function() {
|
||||||
|
var result = Uglify.minify([
|
||||||
|
"test/input/issue-1242/b*.es5",
|
||||||
|
], {
|
||||||
|
compress: { collapse_vars: true }
|
||||||
|
});
|
||||||
|
assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}');
|
||||||
|
});
|
||||||
|
it("minify() with an array of multiple input file globs.", function() {
|
||||||
|
var result = Uglify.minify([
|
||||||
|
"test/input/issue-1242/???.es5",
|
||||||
|
"test/input/issue-1242/*.js",
|
||||||
|
], {
|
||||||
|
compress: { collapse_vars: true }
|
||||||
|
});
|
||||||
|
assert.strictEqual(result.code, 'function bar(n){return 3*n}function baz(n){return n/2}function foo(n){print("Foo:",2*n)}var print=console.log.bind(console);print("qux",bar(3),baz(12)),foo(11);');
|
||||||
|
});
|
||||||
|
});
|
||||||
19
test/mocha/huge-number-of-comments.js
Normal file
19
test/mocha/huge-number-of-comments.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
var Uglify = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("Huge number of comments.", function() {
|
||||||
|
it("Should parse and compress code with thousands of consecutive comments", function() {
|
||||||
|
var js = 'function lots_of_comments(x) { return 7 -';
|
||||||
|
var i;
|
||||||
|
for (i = 1; i <= 5000; ++i) { js += "// " + i + "\n"; }
|
||||||
|
for (; i <= 10000; ++i) { js += "/* " + i + " */ /**/"; }
|
||||||
|
js += "x; }";
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true,
|
||||||
|
mangle: false,
|
||||||
|
compress: {}
|
||||||
|
});
|
||||||
|
assert.strictEqual(result.code, "function lots_of_comments(x){return 7-x}");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
43
test/mocha/input-sourcemaps.js
Normal file
43
test/mocha/input-sourcemaps.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
var Uglify = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
var SourceMapConsumer = require("source-map").SourceMapConsumer;
|
||||||
|
|
||||||
|
describe("input sourcemaps", function() {
|
||||||
|
var transpiled = '"use strict";\n\n' +
|
||||||
|
'var foo = function foo(x) {\n return "foo " + x;\n};\n' +
|
||||||
|
'console.log(foo("bar"));\n\n' +
|
||||||
|
'//# sourceMappingURL=bundle.js.map';
|
||||||
|
|
||||||
|
var transpilemap = {
|
||||||
|
"version": 3,
|
||||||
|
"sources": ["index.js"],
|
||||||
|
"names": [],
|
||||||
|
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
|
||||||
|
"file": "bundle.js",
|
||||||
|
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = Uglify.minify(transpiled, {
|
||||||
|
fromString: true,
|
||||||
|
inSourceMap: transpilemap,
|
||||||
|
outSourceMap: true
|
||||||
|
});
|
||||||
|
var map = new SourceMapConsumer(result.map);
|
||||||
|
|
||||||
|
it("Should copy over original sourcesContent", function() {
|
||||||
|
assert.equal(map.sourceContentFor("index.js"), transpilemap.sourcesContent[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Final sourcemap should not have invalid mappings from inputSourceMap (issue #882) ", function() {
|
||||||
|
// The original source has only 2 lines, check that mappings don't have more lines
|
||||||
|
|
||||||
|
var msg = "Mapping should not have higher line number than the original file had";
|
||||||
|
map.eachMapping(function(mapping) {
|
||||||
|
assert.ok(mapping.originalLine <= 2, msg)
|
||||||
|
});
|
||||||
|
|
||||||
|
map.allGeneratedPositionsFor({source: "index.js", line: 1, column: 1}).forEach(function(pos) {
|
||||||
|
assert.ok(pos.line <= 2, msg);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
30
test/mocha/let.js
Normal file
30
test/mocha/let.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
var Uglify = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("let", function() {
|
||||||
|
it("Should not produce `let` as a variable name in mangle", function(done) {
|
||||||
|
this.timeout(10000);
|
||||||
|
|
||||||
|
// Produce a lot of variables in a function and run it through mangle.
|
||||||
|
var s = '"use strict"; function foo() {';
|
||||||
|
for (var i = 0; i < 21000; ++i) {
|
||||||
|
s += "var v" + i + "=0;";
|
||||||
|
}
|
||||||
|
s += '}';
|
||||||
|
var result = Uglify.minify(s, {fromString: true, compress: false});
|
||||||
|
|
||||||
|
// Verify that select keywords and reserved keywords not produced
|
||||||
|
assert.strictEqual(result.code.indexOf("var let="), -1);
|
||||||
|
assert.strictEqual(result.code.indexOf("var do="), -1);
|
||||||
|
assert.strictEqual(result.code.indexOf("var var="), -1);
|
||||||
|
|
||||||
|
// Verify that the variable names that appeared immediately before
|
||||||
|
// and after the erroneously generated `let` variable name still exist
|
||||||
|
// to show the test generated enough symbols.
|
||||||
|
assert(result.code.indexOf("var ket=") >= 0);
|
||||||
|
assert(result.code.indexOf("var met=") >= 0);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
60
test/mocha/line-endings.js
Normal file
60
test/mocha/line-endings.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
var Uglify = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("line-endings", function() {
|
||||||
|
var options = {
|
||||||
|
fromString: true,
|
||||||
|
mangle: false,
|
||||||
|
compress: false,
|
||||||
|
output: {
|
||||||
|
beautify: false,
|
||||||
|
comments: /^!/,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var expected_code = '/*!one\n2\n3*/\nfunction f(x){if(x)return 3}';
|
||||||
|
|
||||||
|
it("Should parse LF line endings", function() {
|
||||||
|
var js = '/*!one\n2\n3*///comment\nfunction f(x) {\n if (x)\n//comment\n return 3;\n}\n';
|
||||||
|
var result = Uglify.minify(js, options);
|
||||||
|
assert.strictEqual(result.code, expected_code);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should parse CR/LF line endings", function() {
|
||||||
|
var js = '/*!one\r\n2\r\n3*///comment\r\nfunction f(x) {\r\n if (x)\r\n//comment\r\n return 3;\r\n}\r\n';
|
||||||
|
var result = Uglify.minify(js, options);
|
||||||
|
assert.strictEqual(result.code, expected_code);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should parse CR line endings", function() {
|
||||||
|
var js = '/*!one\r2\r3*///comment\rfunction f(x) {\r if (x)\r//comment\r return 3;\r}\r';
|
||||||
|
var result = Uglify.minify(js, options);
|
||||||
|
assert.strictEqual(result.code, expected_code);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not allow line terminators in regexp", function() {
|
||||||
|
var inputs = [
|
||||||
|
"/\n/",
|
||||||
|
"/\r/",
|
||||||
|
"/\u2028/",
|
||||||
|
"/\u2029/",
|
||||||
|
"/\\\n/",
|
||||||
|
"/\\\r/",
|
||||||
|
"/\\\u2028/",
|
||||||
|
"/\\\u2029/",
|
||||||
|
"/someRandomTextLike[]()*AndThen\n/"
|
||||||
|
]
|
||||||
|
var test = function(input) {
|
||||||
|
return function() {
|
||||||
|
Uglify.parse(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fail = function(e) {
|
||||||
|
return e instanceof Uglify.JS_Parse_Error &&
|
||||||
|
e.message === "SyntaxError: Unexpected line terminator";
|
||||||
|
}
|
||||||
|
for (var i = 0; i < inputs.length; i++) {
|
||||||
|
assert.throws(test(inputs[i]), fail);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
40
test/mocha/minify-file-map.js
Normal file
40
test/mocha/minify-file-map.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
var Uglify = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("Input file as map", function() {
|
||||||
|
it("Should accept object", function() {
|
||||||
|
var jsMap = {
|
||||||
|
'/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};'
|
||||||
|
};
|
||||||
|
var result = Uglify.minify(jsMap, {fromString: true, outSourceMap: true});
|
||||||
|
|
||||||
|
var map = JSON.parse(result.map);
|
||||||
|
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};');
|
||||||
|
assert.deepEqual(map.sources, ['/scripts/foo.js']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should accept array of objects and strings", function() {
|
||||||
|
var jsSeq = [
|
||||||
|
{'/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};'},
|
||||||
|
'var bar = 15;'
|
||||||
|
];
|
||||||
|
var result = Uglify.minify(jsSeq, {fromString: true, outSourceMap: true});
|
||||||
|
|
||||||
|
var map = JSON.parse(result.map);
|
||||||
|
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;');
|
||||||
|
assert.strictEqual(map.sources[0], '/scripts/foo.js');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should correctly include source", function() {
|
||||||
|
var jsSeq = [
|
||||||
|
{'/scripts/foo.js': 'var foo = {"x": 1, y: 2, \'z\': 3};'},
|
||||||
|
'var bar = 15;'
|
||||||
|
];
|
||||||
|
var result = Uglify.minify(jsSeq, {fromString: true, outSourceMap: true, sourceMapIncludeSources: true});
|
||||||
|
|
||||||
|
var map = JSON.parse(result.map);
|
||||||
|
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3},bar=15;');
|
||||||
|
assert.deepEqual(map.sourcesContent, ['var foo = {"x": 1, y: 2, \'z\': 3};', 'var bar = 15;']);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
78
test/mocha/minify.js
Normal file
78
test/mocha/minify.js
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
var Uglify = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("minify", function() {
|
||||||
|
it("Should test basic sanity of minify with default options", function() {
|
||||||
|
var js = 'function foo(bar) { if (bar) return 3; else return 7; var u = not_called(); }';
|
||||||
|
var result = Uglify.minify(js, {fromString: true});
|
||||||
|
assert.strictEqual(result.code, 'function foo(n){return n?3:7}');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("keep_quoted_props", function() {
|
||||||
|
it("Should preserve quotes in object literals", function() {
|
||||||
|
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true, output: {
|
||||||
|
keep_quoted_props: true
|
||||||
|
}});
|
||||||
|
assert.strictEqual(result.code, 'var foo={"x":1,y:2,"z":3};');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should preserve quote styles when quote_style is 3", function() {
|
||||||
|
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true, output: {
|
||||||
|
keep_quoted_props: true,
|
||||||
|
quote_style: 3
|
||||||
|
}});
|
||||||
|
assert.strictEqual(result.code, 'var foo={"x":1,y:2,\'z\':3};');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not preserve quotes in object literals when disabled", function() {
|
||||||
|
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true, output: {
|
||||||
|
keep_quoted_props: false,
|
||||||
|
quote_style: 3
|
||||||
|
}});
|
||||||
|
assert.strictEqual(result.code, 'var foo={x:1,y:2,z:3};');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("mangleProperties", function() {
|
||||||
|
it("Shouldn't mangle quoted properties", function() {
|
||||||
|
var js = 'a["foo"] = "bar"; a.color = "red"; x = {"bar": 10};';
|
||||||
|
var result = Uglify.minify(js, {
|
||||||
|
fromString: true,
|
||||||
|
compress: {
|
||||||
|
properties: false
|
||||||
|
},
|
||||||
|
mangleProperties: {
|
||||||
|
ignore_quoted: true
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
keep_quoted_props: true,
|
||||||
|
quote_style: 3
|
||||||
|
}
|
||||||
|
});
|
||||||
|
assert.strictEqual(result.code,
|
||||||
|
'a["foo"]="bar",a.a="red",x={"bar":10};');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("inSourceMap", function() {
|
||||||
|
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled (#1236)", function() {
|
||||||
|
var result = Uglify.minify('./test/input/issue-1236/simple.js', {
|
||||||
|
outSourceMap: "simple.js.min.map",
|
||||||
|
inSourceMap: "./test/input/issue-1236/simple.js.map",
|
||||||
|
sourceMapIncludeSources: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var map = JSON.parse(result.map);
|
||||||
|
|
||||||
|
assert.equal(map.sourcesContent.length, 1);
|
||||||
|
assert.equal(map.sourcesContent[0],
|
||||||
|
'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
88
test/mocha/new.js
Normal file
88
test/mocha/new.js
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("New", function() {
|
||||||
|
it("Should add trailing parentheses for new expressions with zero arguments in beautify mode", function() {
|
||||||
|
var tests = [
|
||||||
|
"new x(1);",
|
||||||
|
"new x;",
|
||||||
|
"new new x;",
|
||||||
|
"new (function(foo){this.foo=foo;})(1);",
|
||||||
|
"new (function(foo){this.foo=foo;})();",
|
||||||
|
"new (function test(foo){this.foo=foo;})(1);",
|
||||||
|
"new (function test(foo){this.foo=foo;})();",
|
||||||
|
"new true;",
|
||||||
|
"new (0);",
|
||||||
|
"new (!0);",
|
||||||
|
"new (bar = function(foo) {this.foo=foo;})(123);",
|
||||||
|
"new (bar = function(foo) {this.foo=foo;})();"
|
||||||
|
];
|
||||||
|
var expected = [
|
||||||
|
"new x(1);",
|
||||||
|
"new x();",
|
||||||
|
"new new x()();",
|
||||||
|
"new function(foo) {\n this.foo = foo;\n}(1);",
|
||||||
|
"new function(foo) {\n this.foo = foo;\n}();",
|
||||||
|
"new function test(foo) {\n this.foo = foo;\n}(1);",
|
||||||
|
"new function test(foo) {\n this.foo = foo;\n}();",
|
||||||
|
"new true();",
|
||||||
|
"new 0();",
|
||||||
|
"new (!0)();",
|
||||||
|
"new (bar = function(foo) {\n this.foo = foo;\n})(123);",
|
||||||
|
"new (bar = function(foo) {\n this.foo = foo;\n})();"
|
||||||
|
];
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(tests[i], {
|
||||||
|
fromString: true,
|
||||||
|
output: {beautify: true},
|
||||||
|
compress: false,
|
||||||
|
mangle: false
|
||||||
|
}).code,
|
||||||
|
expected[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not add trailing parentheses for new expressions with zero arguments in non-beautify mode", function() {
|
||||||
|
var tests = [
|
||||||
|
"new x(1);",
|
||||||
|
"new x;",
|
||||||
|
"new new x;",
|
||||||
|
"new (function(foo){this.foo=foo;})(1);",
|
||||||
|
"new (function(foo){this.foo=foo;})();",
|
||||||
|
"new (function test(foo){this.foo=foo;})(1);",
|
||||||
|
"new (function test(foo){this.foo=foo;})();",
|
||||||
|
"new true;",
|
||||||
|
"new (0);",
|
||||||
|
"new (!0);",
|
||||||
|
"new (bar = function(foo) {this.foo=foo;})(123);",
|
||||||
|
"new (bar = function(foo) {this.foo=foo;})();"
|
||||||
|
];
|
||||||
|
var expected = [
|
||||||
|
"new x(1);",
|
||||||
|
"new x;",
|
||||||
|
"new(new x);",
|
||||||
|
"new function(foo){this.foo=foo}(1);",
|
||||||
|
"new function(foo){this.foo=foo};",
|
||||||
|
"new function test(foo){this.foo=foo}(1);",
|
||||||
|
"new function test(foo){this.foo=foo};",
|
||||||
|
"new true;",
|
||||||
|
"new 0;",
|
||||||
|
"new(!0);",
|
||||||
|
"new(bar=function(foo){this.foo=foo})(123);",
|
||||||
|
"new(bar=function(foo){this.foo=foo});"
|
||||||
|
];
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
assert.strictEqual(
|
||||||
|
uglify.minify(tests[i], {
|
||||||
|
fromString: true,
|
||||||
|
output: {beautify: false},
|
||||||
|
compress: false,
|
||||||
|
mangle: false
|
||||||
|
}).code,
|
||||||
|
expected[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
24
test/mocha/number-literal.js
Normal file
24
test/mocha/number-literal.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("Number literals", function () {
|
||||||
|
it("Should not allow legacy octal literals in strict mode", function() {
|
||||||
|
var inputs = [
|
||||||
|
'"use strict";00;',
|
||||||
|
'"use strict"; var foo = 00;'
|
||||||
|
];
|
||||||
|
|
||||||
|
var test = function(input) {
|
||||||
|
return function() {
|
||||||
|
uglify.parse(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var error = function(e) {
|
||||||
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
|
e.message === "SyntaxError: Legacy octal literals are not allowed in strict mode";
|
||||||
|
}
|
||||||
|
for (var i = 0; i < inputs.length; i++) {
|
||||||
|
assert.throws(test(inputs[i]), error, inputs[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
124
test/mocha/spidermonkey.js
Normal file
124
test/mocha/spidermonkey.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var exec = require("child_process").exec;
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("spidermonkey export/import sanity test", function() {
|
||||||
|
it("should produce a functional build when using --self with spidermonkey", function (done) {
|
||||||
|
this.timeout(20000);
|
||||||
|
|
||||||
|
var uglifyjs = '"' + process.argv[0] + '" bin/uglifyjs';
|
||||||
|
var command = uglifyjs + " --self -cm --wrap SpiderUglify --dump-spidermonkey-ast | " +
|
||||||
|
uglifyjs + " --spidermonkey -cm";
|
||||||
|
|
||||||
|
exec(command, function (err, stdout) {
|
||||||
|
if (err) throw err;
|
||||||
|
|
||||||
|
eval(stdout);
|
||||||
|
assert.strictEqual(typeof SpiderUglify, "object");
|
||||||
|
|
||||||
|
var ast = SpiderUglify.parse("foo([true,,2+3]);");
|
||||||
|
assert.strictEqual(true, ast instanceof SpiderUglify.AST_Node);
|
||||||
|
|
||||||
|
ast.figure_out_scope();
|
||||||
|
ast = SpiderUglify.Compressor({}).compress(ast);
|
||||||
|
assert.strictEqual(true, ast instanceof SpiderUglify.AST_Node);
|
||||||
|
|
||||||
|
var stream = SpiderUglify.OutputStream({});
|
||||||
|
ast.print(stream);
|
||||||
|
var code = stream.toString();
|
||||||
|
assert.strictEqual(code, "foo([!0,,5]);");
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should judge between directives and strings correctly on import", function() {
|
||||||
|
var tests = [
|
||||||
|
{
|
||||||
|
input: '"use strict";;"use sloppy"',
|
||||||
|
directives: 1,
|
||||||
|
strings: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: ';"use strict"',
|
||||||
|
directives: 0,
|
||||||
|
strings: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '"use strict"; "use something else";',
|
||||||
|
directives: 2,
|
||||||
|
strings: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use strict";;"use sloppy" }',
|
||||||
|
directives: 1,
|
||||||
|
strings: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'function foo() {;"use strict" }',
|
||||||
|
directives: 0,
|
||||||
|
strings: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'function foo() {"use strict"; "use something else"; }',
|
||||||
|
directives: 2,
|
||||||
|
strings: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'var foo = function() {"use strict";;"use sloppy" }',
|
||||||
|
directives: 1,
|
||||||
|
strings: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'var foo = function() {;"use strict" }',
|
||||||
|
directives: 0,
|
||||||
|
strings: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'var foo = function() {"use strict"; "use something else"; }',
|
||||||
|
directives: 2,
|
||||||
|
strings: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '{"use strict";;"use sloppy" }',
|
||||||
|
directives: 0,
|
||||||
|
strings: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '{;"use strict" }',
|
||||||
|
directives: 0,
|
||||||
|
strings: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: '{"use strict"; "use something else"; }',
|
||||||
|
directives: 0,
|
||||||
|
strings: 2
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var counter_directives;
|
||||||
|
var counter_strings;
|
||||||
|
|
||||||
|
var checkWalker = new uglify.TreeWalker(function(node, descend) {
|
||||||
|
if (node instanceof uglify.AST_String) {
|
||||||
|
counter_strings++;
|
||||||
|
} else if (node instanceof uglify.AST_Directive) {
|
||||||
|
counter_directives++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var i = 0; i < tests.length; i++) {
|
||||||
|
counter_directives = 0;
|
||||||
|
counter_strings = 0;
|
||||||
|
|
||||||
|
var ast = uglify.parse(tests[i].input);
|
||||||
|
var moz_ast = ast.to_mozilla_ast();
|
||||||
|
var from_moz_ast = uglify.AST_Node.from_mozilla_ast(moz_ast);
|
||||||
|
|
||||||
|
from_moz_ast.walk(checkWalker);
|
||||||
|
|
||||||
|
assert.strictEqual(counter_directives, tests[i].directives, "Directives count mismatch for test " + tests[i].input);
|
||||||
|
assert.strictEqual(counter_strings, tests[i].strings, "String count mismatch for test " + tests[i].input);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
81
test/mocha/string-literal.js
Normal file
81
test/mocha/string-literal.js
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
var UglifyJS = require('../../');
|
||||||
|
var assert = require("assert");
|
||||||
|
|
||||||
|
describe("String literals", function() {
|
||||||
|
it("Should throw syntax error if a string literal contains a newline", function() {
|
||||||
|
var inputs = [
|
||||||
|
"'\n'",
|
||||||
|
"'\r'",
|
||||||
|
'"\r\n"',
|
||||||
|
"'\u2028'",
|
||||||
|
'"\u2029"'
|
||||||
|
];
|
||||||
|
|
||||||
|
var test = function(input) {
|
||||||
|
return function() {
|
||||||
|
var ast = UglifyJS.parse(input);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var error = function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
|
e.message === "SyntaxError: Unterminated string constant";
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var input in inputs) {
|
||||||
|
assert.throws(test(inputs[input]), error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not throw syntax error if a string has a line continuation", function() {
|
||||||
|
var output = UglifyJS.parse('var a = "a\\\nb";').print_to_string();
|
||||||
|
assert.equal(output, 'var a="ab";');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should throw error in strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||||
|
var inputs = [
|
||||||
|
'"use strict";\n"\\76";',
|
||||||
|
'"use strict";\nvar foo = "\\76";',
|
||||||
|
'"use strict";\n"\\1";',
|
||||||
|
'"use strict";\n"\\07";',
|
||||||
|
'"use strict";\n"\\011"'
|
||||||
|
];
|
||||||
|
|
||||||
|
var test = function(input) {
|
||||||
|
return function() {
|
||||||
|
var output = UglifyJS.parse(input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var error = function(e) {
|
||||||
|
return e instanceof UglifyJS.JS_Parse_Error &&
|
||||||
|
e.message === "SyntaxError: Legacy octal escape sequences are not allowed in strict mode";
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var input in inputs) {
|
||||||
|
assert.throws(test(inputs[input]), error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not throw error outside strict mode if string contains escaped octalIntegerLiteral", function() {
|
||||||
|
var tests = [
|
||||||
|
['"\\76";', ';">";'],
|
||||||
|
['"\\0"', '"\\0";'],
|
||||||
|
['"\\08"', '"\\08";'],
|
||||||
|
['"\\008"', '"\\08";'],
|
||||||
|
['"\\0008"', '"\\08";'],
|
||||||
|
['"use strict" === "use strict";\n"\\76";', '"use strict"==="use strict";">";'],
|
||||||
|
['"use\\\n strict";\n"\\07";', ';"use strict";"\07";']
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var test in tests) {
|
||||||
|
var output = UglifyJS.parse(tests[test][0]).print_to_string();
|
||||||
|
assert.equal(output, tests[test][1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should not throw error when digit is 8 or 9", function() {
|
||||||
|
assert.equal(UglifyJS.parse('"use strict";"\\08"').print_to_string(), '"use strict";"\\08";');
|
||||||
|
assert.equal(UglifyJS.parse('"use strict";"\\09"').print_to_string(), '"use strict";"\\09";');
|
||||||
|
});
|
||||||
|
});
|
||||||
23
test/mocha/with.js
Normal file
23
test/mocha/with.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
var assert = require("assert");
|
||||||
|
var uglify = require("../../");
|
||||||
|
|
||||||
|
describe("With", function() {
|
||||||
|
it("Should throw syntaxError when using with statement in strict mode", function() {
|
||||||
|
var code = '"use strict";\nthrow NotEarlyError;\nwith ({}) { }';
|
||||||
|
var test = function() {
|
||||||
|
uglify.parse(code);
|
||||||
|
}
|
||||||
|
var error = function(e) {
|
||||||
|
return e instanceof uglify.JS_Parse_Error &&
|
||||||
|
e.message === "SyntaxError: Strict mode may not include a with statement";
|
||||||
|
}
|
||||||
|
assert.throws(test, error);
|
||||||
|
});
|
||||||
|
it("Should set uses_with for scopes involving With statements", function() {
|
||||||
|
var ast = uglify.parse("with(e) {f(1, 2)}");
|
||||||
|
ast.figure_out_scope();
|
||||||
|
assert.equal(ast.uses_with, true);
|
||||||
|
assert.equal(ast.body[0].expression.scope.uses_with, true);
|
||||||
|
assert.equal(ast.body[0].body.body[0].body.expression.scope.uses_with, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -100,4 +100,4 @@ module.exports = function(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
process.stdout.write(prefix + "Probability of error is less than " + (100 / options.iterations) + "%, stopping.\n");
|
process.stdout.write(prefix + "Probability of error is less than " + (100 / options.iterations) + "%, stopping.\n");
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#! /usr/bin/env node
|
#! /usr/bin/env node
|
||||||
|
|
||||||
|
global.UGLIFY_DEBUG = true;
|
||||||
|
|
||||||
var U = require("../tools/node");
|
var U = require("../tools/node");
|
||||||
var path = require("path");
|
var path = require("path");
|
||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
var sys = require("util");
|
|
||||||
|
|
||||||
var tests_dir = path.dirname(module.filename);
|
var tests_dir = path.dirname(module.filename);
|
||||||
var failures = 0;
|
var failures = 0;
|
||||||
@@ -12,11 +13,17 @@ var failed_files = {};
|
|||||||
|
|
||||||
run_compress_tests();
|
run_compress_tests();
|
||||||
if (failures) {
|
if (failures) {
|
||||||
sys.error("\n!!! Failed " + failures + " test cases.");
|
console.error("\n!!! Failed " + failures + " test cases.");
|
||||||
sys.error("!!! " + Object.keys(failed_files).join(", "));
|
console.error("!!! " + Object.keys(failed_files).join(", "));
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mocha_tests = require("./mocha.js");
|
||||||
|
mocha_tests();
|
||||||
|
|
||||||
|
var run_sourcemaps_tests = require('./sourcemaps');
|
||||||
|
run_sourcemaps_tests();
|
||||||
|
|
||||||
var run_ast_conversion_tests = require("./mozilla-ast");
|
var run_ast_conversion_tests = require("./mozilla-ast");
|
||||||
|
|
||||||
run_ast_conversion_tests({
|
run_ast_conversion_tests({
|
||||||
@@ -31,7 +38,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) {
|
||||||
@@ -80,21 +87,42 @@ function run_compress_tests() {
|
|||||||
log_start_file(file);
|
log_start_file(file);
|
||||||
function test_case(test) {
|
function test_case(test) {
|
||||||
log_test(test.name);
|
log_test(test.name);
|
||||||
|
U.base54.reset();
|
||||||
var options = U.defaults(test.options, {
|
var options = U.defaults(test.options, {
|
||||||
warnings: false
|
warnings: false
|
||||||
});
|
});
|
||||||
|
var warnings_emitted = [];
|
||||||
|
var original_warn_function = U.AST_Node.warn_function;
|
||||||
|
if (test.expect_warnings) {
|
||||||
|
U.AST_Node.warn_function = function(text) {
|
||||||
|
warnings_emitted.push("WARN: " + text);
|
||||||
|
};
|
||||||
|
options.warnings = true;
|
||||||
|
}
|
||||||
var cmp = new U.Compressor(options, true);
|
var cmp = new U.Compressor(options, true);
|
||||||
|
var output_options = test.beautify || {};
|
||||||
var expect;
|
var expect;
|
||||||
if (test.expect) {
|
if (test.expect) {
|
||||||
expect = make_code(as_toplevel(test.expect), false);
|
expect = make_code(as_toplevel(test.expect), output_options);
|
||||||
} else {
|
} else {
|
||||||
expect = test.expect_exact;
|
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, {
|
||||||
var output = input.transform(cmp);
|
beautify: true,
|
||||||
|
quote_style: 3,
|
||||||
|
keep_quoted_props: true
|
||||||
|
});
|
||||||
|
if (test.mangle_props) {
|
||||||
|
input = U.mangle_properties(input, test.mangle_props);
|
||||||
|
}
|
||||||
|
var output = cmp.compress(input);
|
||||||
output.figure_out_scope();
|
output.figure_out_scope();
|
||||||
output = make_code(output, false);
|
if (test.mangle) {
|
||||||
|
output.compute_char_frequency(test.mangle);
|
||||||
|
output.mangle_names(test.mangle);
|
||||||
|
}
|
||||||
|
output = make_code(output, output_options);
|
||||||
if (expect != output) {
|
if (expect != output) {
|
||||||
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
|
log("!!! failed\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n---EXPECTED---\n{expected}\n\n", {
|
||||||
input: input_code,
|
input: input_code,
|
||||||
@@ -104,6 +132,40 @@ function run_compress_tests() {
|
|||||||
failures++;
|
failures++;
|
||||||
failed_files[file] = 1;
|
failed_files[file] = 1;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// expect == output
|
||||||
|
try {
|
||||||
|
var reparsed_ast = U.parse(output);
|
||||||
|
} catch (ex) {
|
||||||
|
log("!!! Test matched expected result but cannot parse output\n---INPUT---\n{input}\n---OUTPUT---\n{output}\n--REPARSE ERROR--\n{error}\n\n", {
|
||||||
|
input: input_code,
|
||||||
|
output: output,
|
||||||
|
error: ex.toString(),
|
||||||
|
});
|
||||||
|
failures++;
|
||||||
|
failed_files[file] = 1;
|
||||||
|
}
|
||||||
|
if (test.expect_warnings) {
|
||||||
|
U.AST_Node.warn_function = original_warn_function;
|
||||||
|
var expected_warnings = make_code(test.expect_warnings, {
|
||||||
|
beautify: false,
|
||||||
|
quote_style: 2, // force double quote to match JSON
|
||||||
|
});
|
||||||
|
warnings_emitted = warnings_emitted.map(function(input) {
|
||||||
|
return input.split(process.cwd() + path.sep).join("").split(path.sep).join("/");
|
||||||
|
});
|
||||||
|
var actual_warnings = JSON.stringify(warnings_emitted);
|
||||||
|
if (expected_warnings != actual_warnings) {
|
||||||
|
log("!!! failed\n---INPUT---\n{input}\n---EXPECTED WARNINGS---\n{expected_warnings}\n---ACTUAL WARNINGS---\n{actual_warnings}\n\n", {
|
||||||
|
input: input_code,
|
||||||
|
expected_warnings: expected_warnings,
|
||||||
|
actual_warnings: actual_warnings,
|
||||||
|
});
|
||||||
|
failures++;
|
||||||
|
failed_files[file] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var tests = parse_test(path.resolve(dir, file));
|
var tests = parse_test(path.resolve(dir, file));
|
||||||
for (var i in tests) if (tests.hasOwnProperty(i)) {
|
for (var i in tests) if (tests.hasOwnProperty(i)) {
|
||||||
@@ -117,9 +179,16 @@ function run_compress_tests() {
|
|||||||
|
|
||||||
function parse_test(file) {
|
function parse_test(file) {
|
||||||
var script = fs.readFileSync(file, "utf8");
|
var script = fs.readFileSync(file, "utf8");
|
||||||
var ast = U.parse(script, {
|
// TODO try/catch can be removed after fixing https://github.com/mishoo/UglifyJS2/issues/348
|
||||||
filename: file
|
try {
|
||||||
});
|
var ast = U.parse(script, {
|
||||||
|
filename: file
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Caught error while parsing tests in " + file + "\n");
|
||||||
|
console.log(e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
var tests = {};
|
var tests = {};
|
||||||
var tw = new U.TreeWalker(function(node, descend){
|
var tw = new U.TreeWalker(function(node, descend){
|
||||||
if (node instanceof U.AST_LabeledStatement
|
if (node instanceof U.AST_LabeledStatement
|
||||||
@@ -138,7 +207,7 @@ function parse_test(file) {
|
|||||||
file: file,
|
file: file,
|
||||||
line: node.start.line,
|
line: node.start.line,
|
||||||
col: node.start.col,
|
col: node.start.col,
|
||||||
code: make_code(node, false)
|
code: make_code(node, { beautify: false })
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +224,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 == "expect_exact",
|
["input", "expect", "expect_exact", "expect_warnings"].indexOf(node.label.name) >= 0,
|
||||||
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,
|
||||||
@@ -185,15 +254,15 @@ function parse_test(file) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function make_code(ast, beautify) {
|
function make_code(ast, options) {
|
||||||
if (arguments.length == 1) beautify = true;
|
options.inline_script = true;
|
||||||
var stream = U.OutputStream({ beautify: beautify });
|
var stream = U.OutputStream(options);
|
||||||
ast.print(stream);
|
ast.print(stream);
|
||||||
return stream.get();
|
return stream.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
function evaluate(code) {
|
function evaluate(code) {
|
||||||
if (code instanceof U.AST_Node)
|
if (code instanceof U.AST_Node)
|
||||||
code = make_code(code);
|
code = make_code(code, { beautify: true });
|
||||||
return new Function("return(" + code + ")")();
|
return new Function("return(" + code + ")")();
|
||||||
}
|
}
|
||||||
|
|||||||
40
test/sourcemaps.js
Normal file
40
test/sourcemaps.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
var UglifyJS = require("..");
|
||||||
|
var ok = require("assert");
|
||||||
|
|
||||||
|
module.exports = function () {
|
||||||
|
console.log("--- Sourcemaps tests");
|
||||||
|
|
||||||
|
var basic = source_map([
|
||||||
|
'var x = 1 + 1;'
|
||||||
|
].join('\n'));
|
||||||
|
|
||||||
|
ok.equal(basic.version, 3);
|
||||||
|
ok.deepEqual(basic.names, ['x']);
|
||||||
|
|
||||||
|
var issue836 = source_map([
|
||||||
|
"({",
|
||||||
|
" get enabled() {",
|
||||||
|
" return 3;",
|
||||||
|
" },",
|
||||||
|
" set enabled(x) {",
|
||||||
|
" ;",
|
||||||
|
" }",
|
||||||
|
"});",
|
||||||
|
].join("\n"));
|
||||||
|
|
||||||
|
ok.deepEqual(issue836.names, ['enabled', 'x']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function source_map(js) {
|
||||||
|
var source_map = UglifyJS.SourceMap();
|
||||||
|
var stream = UglifyJS.OutputStream({ source_map: source_map });
|
||||||
|
var parsed = UglifyJS.parse(js);
|
||||||
|
parsed.print(stream);
|
||||||
|
return JSON.parse(source_map.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run standalone
|
||||||
|
if (module.parent === null) {
|
||||||
|
module.exports();
|
||||||
|
}
|
||||||
|
|
||||||
23
tools/exports.js
Normal file
23
tools/exports.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
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["tokenizer"] = tokenizer;
|
||||||
|
exports["is_identifier"] = is_identifier;
|
||||||
|
exports["SymbolDef"] = SymbolDef;
|
||||||
|
|
||||||
|
if (typeof DEBUG !== "undefined" && DEBUG) {
|
||||||
|
exports["EXPECT_DIRECTIVE"] = EXPECT_DIRECTIVE;
|
||||||
|
}
|
||||||
157
tools/node.js
157
tools/node.js
@@ -1,26 +1,11 @@
|
|||||||
var path = require("path");
|
// workaround for tty output truncation upon process.exit()
|
||||||
var fs = require("fs");
|
[process.stdout, process.stderr].forEach(function(stream){
|
||||||
var vm = require("vm");
|
if (stream._handle && stream._handle.setBlocking)
|
||||||
|
stream._handle.setBlocking(true);
|
||||||
var UglifyJS = vm.createContext({
|
|
||||||
console : console,
|
|
||||||
process : process,
|
|
||||||
Buffer : Buffer,
|
|
||||||
MOZ_SourceMap : require("source-map")
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function load_global(file) {
|
var path = require("path");
|
||||||
file = path.resolve(path.dirname(module.filename), file);
|
var fs = require("fs");
|
||||||
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).
|
|
||||||
console.log("ERROR in file: " + file + " / " + ex);
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var FILES = exports.FILES = [
|
var FILES = exports.FILES = [
|
||||||
"../lib/utils.js",
|
"../lib/utils.js",
|
||||||
@@ -32,35 +17,41 @@ var FILES = exports.FILES = [
|
|||||||
"../lib/compress.js",
|
"../lib/compress.js",
|
||||||
"../lib/sourcemap.js",
|
"../lib/sourcemap.js",
|
||||||
"../lib/mozilla-ast.js",
|
"../lib/mozilla-ast.js",
|
||||||
"../lib/propmangle.js"
|
"../lib/propmangle.js",
|
||||||
|
"./exports.js",
|
||||||
].map(function(file){
|
].map(function(file){
|
||||||
return fs.realpathSync(path.join(path.dirname(__filename), file));
|
return fs.realpathSync(path.join(path.dirname(__filename), file));
|
||||||
});
|
});
|
||||||
|
|
||||||
FILES.forEach(load_global);
|
var UglifyJS = exports;
|
||||||
|
|
||||||
|
new Function("MOZ_SourceMap", "exports", "DEBUG", FILES.map(function(file){
|
||||||
|
return fs.readFileSync(file, "utf8");
|
||||||
|
}).join("\n\n"))(
|
||||||
|
require("source-map"),
|
||||||
|
UglifyJS,
|
||||||
|
!!global.UGLIFY_DEBUG
|
||||||
|
);
|
||||||
|
|
||||||
UglifyJS.AST_Node.warn_function = function(txt) {
|
UglifyJS.AST_Node.warn_function = function(txt) {
|
||||||
console.error("WARN: %s", 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,
|
spidermonkey : false,
|
||||||
outSourceMap : null,
|
outSourceMap : null,
|
||||||
sourceRoot : null,
|
sourceRoot : null,
|
||||||
inSourceMap : null,
|
inSourceMap : null,
|
||||||
fromString : false,
|
sourceMapUrl : null,
|
||||||
warnings : false,
|
fromString : false,
|
||||||
mangle : {},
|
warnings : false,
|
||||||
output : null,
|
mangle : {},
|
||||||
compress : {}
|
mangleProperties : false,
|
||||||
|
nameCache : null,
|
||||||
|
output : null,
|
||||||
|
compress : {},
|
||||||
|
parse : {}
|
||||||
});
|
});
|
||||||
UglifyJS.base54.reset();
|
UglifyJS.base54.reset();
|
||||||
|
|
||||||
@@ -71,19 +62,31 @@ exports.minify = function(files, options) {
|
|||||||
if (options.spidermonkey) {
|
if (options.spidermonkey) {
|
||||||
toplevel = UglifyJS.AST_Node.from_mozilla_ast(files);
|
toplevel = UglifyJS.AST_Node.from_mozilla_ast(files);
|
||||||
} else {
|
} else {
|
||||||
if (typeof files == "string")
|
function addFile(file, fileUrl) {
|
||||||
files = [ files ];
|
|
||||||
files.forEach(function(file){
|
|
||||||
var code = options.fromString
|
var code = options.fromString
|
||||||
? file
|
? file
|
||||||
: fs.readFileSync(file, "utf8");
|
: fs.readFileSync(file, "utf8");
|
||||||
sourcesContent[file] = code;
|
sourcesContent[fileUrl] = code;
|
||||||
toplevel = UglifyJS.parse(code, {
|
toplevel = UglifyJS.parse(code, {
|
||||||
filename: options.fromString ? "?" : file,
|
filename: fileUrl,
|
||||||
toplevel: toplevel
|
toplevel: toplevel,
|
||||||
|
bare_returns: options.parse ? options.parse.bare_returns : undefined
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
if (!options.fromString) files = UglifyJS.simple_glob(files);
|
||||||
|
[].concat(files).forEach(function (files, i) {
|
||||||
|
if (typeof files === 'string') {
|
||||||
|
addFile(files, options.fromString ? i : files);
|
||||||
|
} else {
|
||||||
|
for (var fileUrl in files) {
|
||||||
|
addFile(files[fileUrl], fileUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (options.wrap) {
|
||||||
|
toplevel = toplevel.wrap_commonjs(options.wrap, options.exportAll);
|
||||||
|
}
|
||||||
|
|
||||||
// 2. compress
|
// 2. compress
|
||||||
if (options.compress) {
|
if (options.compress) {
|
||||||
@@ -91,21 +94,28 @@ exports.minify = function(files, options) {
|
|||||||
UglifyJS.merge(compress, options.compress);
|
UglifyJS.merge(compress, options.compress);
|
||||||
toplevel.figure_out_scope();
|
toplevel.figure_out_scope();
|
||||||
var sq = UglifyJS.Compressor(compress);
|
var sq = UglifyJS.Compressor(compress);
|
||||||
toplevel = toplevel.transform(sq);
|
toplevel = sq.compress(toplevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. mangle
|
// 3. mangle properties
|
||||||
|
if (options.mangleProperties || options.nameCache) {
|
||||||
|
options.mangleProperties.cache = UglifyJS.readNameCache(options.nameCache, "props");
|
||||||
|
toplevel = UglifyJS.mangle_properties(toplevel, options.mangleProperties);
|
||||||
|
UglifyJS.writeNameCache(options.nameCache, "props", options.mangleProperties.cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. mangle
|
||||||
if (options.mangle) {
|
if (options.mangle) {
|
||||||
toplevel.figure_out_scope(options.mangle);
|
toplevel.figure_out_scope(options.mangle);
|
||||||
toplevel.compute_char_frequency(options.mangle);
|
toplevel.compute_char_frequency(options.mangle);
|
||||||
toplevel.mangle_names(options.mangle);
|
toplevel.mangle_names(options.mangle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. output
|
// 5. output
|
||||||
var inMap = options.inSourceMap;
|
var inMap = options.inSourceMap;
|
||||||
var output = {};
|
var output = {};
|
||||||
if (typeof options.inSourceMap == "string") {
|
if (typeof options.inSourceMap == "string") {
|
||||||
inMap = fs.readFileSync(options.inSourceMap, "utf8");
|
inMap = JSON.parse(fs.readFileSync(options.inSourceMap, "utf8"));
|
||||||
}
|
}
|
||||||
if (options.outSourceMap) {
|
if (options.outSourceMap) {
|
||||||
output.source_map = UglifyJS.SourceMap({
|
output.source_map = UglifyJS.SourceMap({
|
||||||
@@ -128,8 +138,9 @@ exports.minify = function(files, options) {
|
|||||||
var stream = UglifyJS.OutputStream(output);
|
var stream = UglifyJS.OutputStream(output);
|
||||||
toplevel.print(stream);
|
toplevel.print(stream);
|
||||||
|
|
||||||
if(options.outSourceMap){
|
var mappingUrlPrefix = "\n//# sourceMappingURL=";
|
||||||
stream += "\n//# sourceMappingURL=" + options.outSourceMap;
|
if (options.outSourceMap && typeof options.outSourceMap === "string" && options.sourceMapUrl !== false) {
|
||||||
|
stream += mappingUrlPrefix + (typeof options.sourceMapUrl === "string" ? options.sourceMapUrl : options.outSourceMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
var source_map = output.source_map;
|
var source_map = output.source_map;
|
||||||
@@ -251,3 +262,47 @@ exports.writeNameCache = function(filename, key, cache) {
|
|||||||
fs.writeFileSync(filename, JSON.stringify(data, null, 2), "utf8");
|
fs.writeFileSync(filename, JSON.stringify(data, null, 2), "utf8");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A file glob function that only supports "*" and "?" wildcards in the basename.
|
||||||
|
// Example: "foo/bar/*baz??.*.js"
|
||||||
|
// Argument `glob` may be a string or an array of strings.
|
||||||
|
// Returns an array of strings. Garbage in, garbage out.
|
||||||
|
exports.simple_glob = function simple_glob(glob) {
|
||||||
|
var results = [];
|
||||||
|
if (Array.isArray(glob)) {
|
||||||
|
glob.forEach(function(elem) {
|
||||||
|
results = results.concat(simple_glob(elem));
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
if (glob.match(/\*|\?/)) {
|
||||||
|
var dir = path.dirname(glob);
|
||||||
|
try {
|
||||||
|
var entries = fs.readdirSync(dir);
|
||||||
|
} catch (ex) {}
|
||||||
|
if (entries) {
|
||||||
|
var pattern = "^" + (path.basename(glob)
|
||||||
|
.replace(/\(/g, "\\(")
|
||||||
|
.replace(/\)/g, "\\)")
|
||||||
|
.replace(/\{/g, "\\{")
|
||||||
|
.replace(/\}/g, "\\}")
|
||||||
|
.replace(/\[/g, "\\[")
|
||||||
|
.replace(/\]/g, "\\]")
|
||||||
|
.replace(/\+/g, "\\+")
|
||||||
|
.replace(/\^/g, "\\^")
|
||||||
|
.replace(/\$/g, "\\$")
|
||||||
|
.replace(/\*/g, "[^/\\\\]*")
|
||||||
|
.replace(/\./g, "\\.")
|
||||||
|
.replace(/\?/g, ".")) + "$";
|
||||||
|
var mod = process.platform === "win32" ? "i" : "";
|
||||||
|
var rx = new RegExp(pattern, mod);
|
||||||
|
for (var i in entries) {
|
||||||
|
if (rx.test(entries[i]))
|
||||||
|
results.push(dir + "/" + entries[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (results.length === 0)
|
||||||
|
results = [ glob ];
|
||||||
|
return results;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user