Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dfe4f6c6de | ||
|
|
a09c8ad666 | ||
|
|
ec598c351b | ||
|
|
eba0f93bc0 | ||
|
|
99800d4aa9 | ||
|
|
70d56c951a | ||
|
|
b810e2f8da | ||
|
|
1abe14296e | ||
|
|
6920e898d1 | ||
|
|
dd71639264 | ||
|
|
2dcc552ce0 | ||
|
|
55387e8fd0 | ||
|
|
7e3e9da860 | ||
|
|
00f509405b |
249
README.md
249
README.md
@@ -153,10 +153,10 @@ Additional options:
|
|||||||
- `--source-map "filename='<NAME>'"` to specify the name of the source map.
|
- `--source-map "filename='<NAME>'"` to specify the name of the source map.
|
||||||
|
|
||||||
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
|
- `--source-map "root='<URL>'"` to pass the URL where the original files can be found.
|
||||||
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
|
|
||||||
`//# sourceMappingURL=` directive.
|
|
||||||
|
|
||||||
- `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
|
- `--source-map "url='<URL>'"` to specify the URL where the source map can be found.
|
||||||
|
Otherwise UglifyJS assumes HTTP `X-SourceMap` is being used and will omit the
|
||||||
|
`//# sourceMappingURL=` directive.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@@ -203,11 +203,9 @@ Example:
|
|||||||
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:
|
||||||
|
|
||||||
- `toplevel` — mangle names declared in the top level scope (disabled by
|
- `toplevel` (default `false`) -- mangle names declared in the top level scope.
|
||||||
default).
|
|
||||||
|
|
||||||
- `eval` — mangle names visible in scopes where `eval` or `with` are used
|
- `eval` (default `false`) -- mangle names visible in scopes where `eval` or `with` are used.
|
||||||
(disabled by default).
|
|
||||||
|
|
||||||
When mangling is enabled but you want to prevent certain names from being
|
When mangling is enabled but you want to prevent certain names from being
|
||||||
mangled, you can declare those names with `--mangle reserved` — pass a
|
mangled, you can declare those names with `--mangle reserved` — pass a
|
||||||
@@ -510,6 +508,9 @@ if (result.error) throw result.error;
|
|||||||
|
|
||||||
- `ie8` (default `false`) - set to `true` to support IE8.
|
- `ie8` (default `false`) - set to `true` to support IE8.
|
||||||
|
|
||||||
|
- `keep_fnames` (default: `false`) - pass `true` to prevent discarding or mangling
|
||||||
|
of function names. Useful for code relying on `Function.prototype.name`.
|
||||||
|
|
||||||
## Minify options structure
|
## Minify options structure
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@@ -590,111 +591,78 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
## Parse options
|
## Parse options
|
||||||
|
|
||||||
- `bare_returns` (default `false`) -- support top level `return` statements
|
- `bare_returns` (default `false`) -- support top level `return` statements
|
||||||
|
|
||||||
- `html5_comments` (default `true`)
|
- `html5_comments` (default `true`)
|
||||||
|
|
||||||
- `shebang` (default `true`) -- support `#!command` as the first line
|
- `shebang` (default `true`) -- support `#!command` as the first line
|
||||||
|
|
||||||
## Compress options
|
## Compress options
|
||||||
|
|
||||||
- `sequences` (default: true) -- join consecutive simple statements using the
|
- `booleans` (default: `true`) -- various optimizations for boolean context, for example `!!a
|
||||||
comma operator. May be set to a positive integer to specify the maximum number
|
? b : c → a ? b : c`
|
||||||
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
|
- `cascade` (default: `true`) -- small optimization for sequences, transform `x, x` into `x`
|
||||||
example `foo["bar"] → foo.bar`
|
and `x = something(), x` into `x = something()`
|
||||||
|
|
||||||
- `dead_code` -- remove unreachable code
|
- `collapse_vars` (default: `true`) -- Collapse single-use non-constant variables - side
|
||||||
|
effects permitting.
|
||||||
|
|
||||||
- `drop_debugger` -- remove `debugger;` statements
|
- `comparisons` (default: `true`) -- apply certain optimizations to binary nodes, for example:
|
||||||
|
|
||||||
- `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.
|
|
||||||
|
|
||||||
- `unsafe_Func` (default: false) -- compress and mangle `Function(args, code)`
|
|
||||||
when both `args` and `code` are string literals.
|
|
||||||
|
|
||||||
- `unsafe_math` (default: false) -- optimize numerical expressions like
|
|
||||||
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
|
|
||||||
|
|
||||||
- `unsafe_proto` (default: false) -- optimize expressions like
|
|
||||||
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
|
|
||||||
|
|
||||||
- `unsafe_regexp` (default: false) -- enable substitutions of variables with
|
|
||||||
`RegExp` values the same way as if they are constants.
|
|
||||||
|
|
||||||
- `conditionals` -- apply optimizations for `if`-s and conditional
|
|
||||||
expressions
|
|
||||||
|
|
||||||
- `comparisons` -- apply certain optimizations to binary nodes, for example:
|
|
||||||
`!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
|
`!(a <= b) → a > b` (only when `unsafe_comps`), attempts to negate binary
|
||||||
nodes, 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
|
- `conditionals` (default: `true`) -- apply optimizations for `if`-s and conditional
|
||||||
|
expressions
|
||||||
|
|
||||||
- `booleans` -- various optimizations for boolean context, for example `!!a
|
- `dead_code` (default: `true`) -- remove unreachable code
|
||||||
? b : c → a ? b : c`
|
|
||||||
|
|
||||||
- `typeofs` -- default `true`. Transforms `typeof foo == "undefined"` into
|
- `drop_console` (default: `false`) -- default `false`. Pass `true` to discard calls to
|
||||||
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
|
`console.*` functions. If you wish to drop a specific function call
|
||||||
earlier versions due to known issues.
|
such as `console.info` and/or retain side effects from function arguments
|
||||||
|
after dropping the function call then use `pure_funcs` instead.
|
||||||
|
|
||||||
- `loops` -- optimizations for `do`, `while` and `for` loops when we can
|
- `drop_debugger` (default: `true`) -- remove `debugger;` statements
|
||||||
statically determine the condition
|
|
||||||
|
|
||||||
- `unused` -- drop unreferenced functions and variables (simple direct variable
|
- `evaluate` (default: `true`) -- attempt to evaluate constant expressions
|
||||||
assignments do not count as references unless set to `"keep_assign"`)
|
|
||||||
|
|
||||||
- `toplevel` -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`)
|
- `expression` (default: `false`) -- default `false`. Pass `true` to preserve completion values
|
||||||
in the top level scope (`false` by default, `true` to drop both unreferenced
|
from terminal statements without `return`, e.g. in bookmarklets.
|
||||||
functions and variables)
|
|
||||||
|
|
||||||
- `top_retain` -- prevent specific toplevel functions and variables from `unused`
|
- `global_defs` (default: `{}`) -- see [conditional compilation](#conditional-compilation)
|
||||||
removal (can be array, comma-separated, RegExp or function. Implies `toplevel`)
|
|
||||||
|
|
||||||
- `hoist_funs` -- hoist function declarations
|
- `hoist_funs` (default: `true`) -- hoist function declarations
|
||||||
|
|
||||||
- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`
|
- `hoist_vars` (default: `false`) -- hoist `var` declarations (this is `false`
|
||||||
by default because it seems to increase the size of the output in general)
|
by default because it seems to increase the size of the output in general)
|
||||||
|
|
||||||
- `if_return` -- optimizations for if/return and if/continue
|
- `if_return` (default: `true`) -- optimizations for if/return and if/continue
|
||||||
|
|
||||||
- `inline` -- embed simple functions
|
- `inline` (default: `true`) -- embed simple functions
|
||||||
|
|
||||||
- `join_vars` -- join consecutive `var` statements
|
- `join_vars` (default: `true`) -- join consecutive `var` statements
|
||||||
|
|
||||||
- `cascade` -- small optimization for sequences, transform `x, x` into `x`
|
- `keep_fargs` (default: `true`) -- default `true`. Prevents the
|
||||||
and `x = something(), x` into `x = something()`
|
compressor from discarding unused function arguments. You need this
|
||||||
|
for code which relies on `Function.length`.
|
||||||
|
|
||||||
- `collapse_vars` -- Collapse single-use non-constant variables - side
|
- `keep_infinity` (default: `false`) -- default `false`. Pass `true` to prevent `Infinity` from
|
||||||
effects permitting.
|
being compressed into `1/0`, which may cause performance issues on Chrome.
|
||||||
|
|
||||||
- `reduce_vars` -- Improve optimization on variables assigned with and
|
- `loops` (default: `true`) -- optimizations for `do`, `while` and `for` loops when we can
|
||||||
used as constant values.
|
statically determine the condition
|
||||||
|
|
||||||
- `warnings` -- display warnings when dropping unreachable code or unused
|
- `negate_iife` (default: `true`) -- negate "Immediately-Called Function Expressions"
|
||||||
declarations etc.
|
|
||||||
|
|
||||||
- `negate_iife` -- negate "Immediately-Called Function Expressions"
|
|
||||||
where the return value is discarded, to avoid the parens that the
|
where the return value is discarded, to avoid the parens that the
|
||||||
code generator would insert.
|
code generator would insert.
|
||||||
|
|
||||||
- `pure_getters` -- the default is `false`. If you pass `true` for
|
- `passes` (default: `1`) -- The maximum number of times to run compress.
|
||||||
this, UglifyJS will assume that object property access
|
In some cases more than one pass leads to further compressed code. Keep in
|
||||||
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
|
mind more passes will take more time.
|
||||||
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
|
|
||||||
`foo` is certain to not throw, i.e. not `null` or `undefined`.
|
|
||||||
|
|
||||||
- `pure_funcs` -- default `null`. You can pass an array of names and
|
- `properties` (default: `true`) -- rewrite property access using the dot notation, for
|
||||||
|
example `foo["bar"] → foo.bar`
|
||||||
|
|
||||||
|
- `pure_funcs` (default: `null`) -- You can pass an array of names and
|
||||||
UglifyJS will assume that those functions do not produce side
|
UglifyJS will assume that those functions do not produce side
|
||||||
effects. DANGER: will not check if the name is redefined in scope.
|
effects. DANGER: will not check if the name is redefined in scope.
|
||||||
An example case here, for instance `var q = Math.floor(a/b)`. If
|
An example case here, for instance `var q = Math.floor(a/b)`. If
|
||||||
@@ -705,34 +673,69 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
statement would get discarded. The current implementation adds some
|
statement would get discarded. The current implementation adds some
|
||||||
overhead (compression will be slower).
|
overhead (compression will be slower).
|
||||||
|
|
||||||
- `drop_console` -- default `false`. Pass `true` to discard calls to
|
- `pure_getters` (default: `"strict"`) -- If you pass `true` for
|
||||||
`console.*` functions. If you wish to drop a specific function call
|
this, UglifyJS will assume that object property access
|
||||||
such as `console.info` and/or retain side effects from function arguments
|
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
|
||||||
after dropping the function call then use `pure_funcs` instead.
|
Specify `"strict"` to treat `foo.bar` as side-effect-free only when
|
||||||
|
`foo` is certain to not throw, i.e. not `null` or `undefined`.
|
||||||
|
|
||||||
- `expression` -- default `false`. Pass `true` to preserve completion values
|
- `reduce_vars` (default: `true`) -- Improve optimization on variables assigned with and
|
||||||
from terminal statements without `return`, e.g. in bookmarklets.
|
used as constant values.
|
||||||
|
|
||||||
- `keep_fargs` -- default `true`. Prevents the
|
- `sequences` (default: `true`) -- join consecutive simple statements using the
|
||||||
compressor from discarding unused function arguments. You need this
|
comma operator. May be set to a positive integer to specify the maximum number
|
||||||
for code which relies on `Function.length`.
|
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.
|
||||||
|
|
||||||
- `keep_fnames` -- default `false`. Pass `true` to prevent the
|
- `side_effects` (default: `true`) -- default `true`. Pass `false` to disable potentially dropping
|
||||||
compressor from discarding function names. Useful for code relying on
|
|
||||||
`Function.prototype.name`. See also: the `keep_fnames` [mangle option](#mangle).
|
|
||||||
|
|
||||||
- `passes` -- default `1`. The maximum number of times to run compress.
|
|
||||||
In some cases more than one pass leads to further compressed code. Keep in
|
|
||||||
mind more passes will take more time.
|
|
||||||
|
|
||||||
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
|
|
||||||
being compressed into `1/0`, which may cause performance issues on Chrome.
|
|
||||||
|
|
||||||
- `side_effects` -- default `true`. Pass `false` to disable potentially dropping
|
|
||||||
functions marked as "pure". A function call is marked as "pure" if a comment
|
functions marked as "pure". A function call is marked as "pure" if a comment
|
||||||
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
||||||
example: `/*@__PURE__*/foo();`
|
example: `/*@__PURE__*/foo();`
|
||||||
|
|
||||||
|
- `switches` (default: `true`) -- de-duplicate and remove unreachable `switch` branches
|
||||||
|
|
||||||
|
- `toplevel` (default: `false`) -- drop unreferenced functions (`"funcs"`) and/or variables (`"vars"`)
|
||||||
|
in the top level scope (`false` by default, `true` to drop both unreferenced
|
||||||
|
functions and variables)
|
||||||
|
|
||||||
|
- `top_retain` (default: `null`) -- prevent specific toplevel functions and variables from `unused`
|
||||||
|
removal (can be array, comma-separated, RegExp or function. Implies `toplevel`)
|
||||||
|
|
||||||
|
- `typeofs` (default: `true`) -- default `true`. Transforms `typeof foo == "undefined"` into
|
||||||
|
`foo === void 0`. Note: recommend to set this value to `false` for IE10 and
|
||||||
|
earlier versions due to known issues.
|
||||||
|
|
||||||
|
- `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.
|
||||||
|
|
||||||
|
- `unsafe` (default: `false`) -- apply "unsafe" transformations (discussion below)
|
||||||
|
|
||||||
|
- `unsafe_Func` (default: `false`) -- compress and mangle `Function(args, code)`
|
||||||
|
when both `args` and `code` are string literals.
|
||||||
|
|
||||||
|
- `unsafe_math` (default: `false`) -- optimize numerical expressions like
|
||||||
|
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
|
||||||
|
|
||||||
|
- `unsafe_proto` (default: `false`) -- optimize expressions like
|
||||||
|
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
|
||||||
|
|
||||||
|
- `unsafe_regexp` (default: `false`) -- enable substitutions of variables with
|
||||||
|
`RegExp` values the same way as if they are constants.
|
||||||
|
|
||||||
|
- `unused` (default: `true`) -- drop unreferenced functions and variables (simple direct variable
|
||||||
|
assignments do not count as references unless set to `"keep_assign"`)
|
||||||
|
|
||||||
|
- `warnings` (default: `false`) -- display warnings when dropping unreachable code or unused
|
||||||
|
declarations etc.
|
||||||
|
|
||||||
## Mangle options
|
## Mangle options
|
||||||
|
|
||||||
- `reserved` (default `[]`). Pass an array of identifiers that should be
|
- `reserved` (default `[]`). Pass an array of identifiers that should be
|
||||||
@@ -741,10 +744,6 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
|
|||||||
- `toplevel` (default `false`). Pass `true` to mangle names declared in the
|
- `toplevel` (default `false`). Pass `true` to mangle names declared in the
|
||||||
top level scope.
|
top level scope.
|
||||||
|
|
||||||
- `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](#compress-options).
|
|
||||||
|
|
||||||
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
|
- `eval` (default `false`). Pass `true` to mangle names visible in scopes
|
||||||
where `eval` or `with` are used.
|
where `eval` or `with` are used.
|
||||||
|
|
||||||
@@ -772,16 +771,20 @@ UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
|
|||||||
|
|
||||||
### Mangle properties options
|
### Mangle properties options
|
||||||
|
|
||||||
- `reserved` (default: `[]`) -- Do not mangle property names listed in the
|
|
||||||
`reserved` array.
|
|
||||||
- `regex` (default: `null`) -— Pass a RegExp literal to only mangle property
|
|
||||||
names matching the regular expression.
|
|
||||||
- `keep_quoted` (default: `false`) -— Only mangle unquoted property names.
|
|
||||||
- `debug` (default: `false`) -— Mangle names with the original name still present.
|
|
||||||
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
|
|
||||||
- `builtins` (default: `false`) -- Use `true` to allow the mangling of builtin
|
- `builtins` (default: `false`) -- Use `true` to allow the mangling of builtin
|
||||||
DOM properties. Not recommended to override this setting.
|
DOM properties. Not recommended to override this setting.
|
||||||
|
|
||||||
|
- `debug` (default: `false`) -— Mangle names with the original name still present.
|
||||||
|
Pass an empty string `""` to enable, or a non-empty string to set the debug suffix.
|
||||||
|
|
||||||
|
- `keep_quoted` (default: `false`) -— Only mangle unquoted property names.
|
||||||
|
|
||||||
|
- `regex` (default: `null`) -— Pass a RegExp literal to only mangle property
|
||||||
|
names matching the regular expression.
|
||||||
|
|
||||||
|
- `reserved` (default: `[]`) -- Do not mangle property names listed in the
|
||||||
|
`reserved` array.
|
||||||
|
|
||||||
## Output options
|
## Output 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
|
||||||
@@ -790,31 +793,43 @@ can pass additional arguments that control the code output:
|
|||||||
|
|
||||||
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
|
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
|
||||||
regexps (affects directives with non-ascii characters becoming invalid)
|
regexps (affects directives with non-ascii characters becoming invalid)
|
||||||
|
|
||||||
- `beautify` (default `true`) -- whether to actually beautify the output.
|
- `beautify` (default `true`) -- whether to actually beautify the output.
|
||||||
Passing `-b` will set this to true, but you might need to pass `-b` even
|
Passing `-b` will set this to true, but you might need to pass `-b` even
|
||||||
when you want to generate minified code, in order to specify additional
|
when you want to generate minified code, in order to specify additional
|
||||||
arguments, so you can use `-b beautify=false` to override it.
|
arguments, so you can use `-b beautify=false` to override it.
|
||||||
|
|
||||||
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
|
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
|
||||||
`do`, `while` or `with` statements, even if their body is a single
|
`do`, `while` or `with` statements, even if their body is a single
|
||||||
statement.
|
statement.
|
||||||
|
|
||||||
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
|
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
|
||||||
comments, `"some"` to preserve some comments, a regular expression string
|
comments, `"some"` to preserve some comments, a regular expression string
|
||||||
(e.g. `/^!/`) or a function.
|
(e.g. `/^!/`) or a function.
|
||||||
- `indent_level` (default 4)
|
|
||||||
- `indent_start` (default 0) -- prefix all lines by that many spaces
|
- `indent_level` (default `4`)
|
||||||
|
|
||||||
|
- `indent_start` (default `0`) -- prefix all lines by that many spaces
|
||||||
|
|
||||||
- `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
|
||||||
|
|
||||||
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
||||||
quotes from property names in object literals.
|
quotes from property names in object literals.
|
||||||
|
|
||||||
- `max_line_len` (default `false`) -- maximum line length (for uglified code)
|
- `max_line_len` (default `false`) -- maximum line length (for uglified code)
|
||||||
|
|
||||||
- `preamble` (default `null`) -- when passed it must be a string and
|
- `preamble` (default `null`) -- when passed it must be a string and
|
||||||
it will be prepended to the output literally. The source map will
|
it will be prepended to the output literally. The source map will
|
||||||
adjust for this text. Can be used to insert a comment containing
|
adjust for this text. Can be used to insert a comment containing
|
||||||
licensing information, for example.
|
licensing information, for example.
|
||||||
|
|
||||||
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
|
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
|
||||||
only works if `beautify` is set to `false`.
|
only works if `beautify` is set to `false`.
|
||||||
|
|
||||||
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
||||||
objects
|
objects
|
||||||
|
|
||||||
- `quote_style` (default `0`) -- preferred quote style for strings (affects
|
- `quote_style` (default `0`) -- preferred quote style for strings (affects
|
||||||
quoted property names and directives as well):
|
quoted property names and directives as well):
|
||||||
- `0` -- prefers double quotes, switches to single quotes when there are
|
- `0` -- prefers double quotes, switches to single quotes when there are
|
||||||
@@ -822,16 +837,20 @@ 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
|
||||||
|
|
||||||
- `semicolons` (default `true`) -- separate statements with semicolons. If
|
- `semicolons` (default `true`) -- separate statements with semicolons. If
|
||||||
you pass `false` then whenever possible we will use a newline instead of a
|
you pass `false` then whenever possible we will use a newline instead of a
|
||||||
semicolon, leading to more readable output of uglified code (size before
|
semicolon, leading to more readable output of uglified code (size before
|
||||||
gzip could be smaller; size after gzip insignificantly larger).
|
gzip could be smaller; size after gzip insignificantly larger).
|
||||||
|
|
||||||
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
||||||
- `width` (default 80) -- only takes effect when beautification is on, this
|
|
||||||
|
- `width` (default `80`) -- only takes effect when beautification is on, this
|
||||||
specifies an (orientative) line width that the beautifier will try to
|
specifies an (orientative) line width that the beautifier will try to
|
||||||
obey. It refers to the width of the line text (excluding indentation).
|
obey. It refers to the width of the line text (excluding indentation).
|
||||||
It doesn't work very well currently, but it does make the code generated
|
It doesn't work very well currently, but it does make the code generated
|
||||||
by UglifyJS more readable.
|
by UglifyJS more readable.
|
||||||
|
|
||||||
- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
|
- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
|
||||||
function expressions. See
|
function expressions. See
|
||||||
[#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
|
[#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
|
||||||
|
|||||||
@@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
|
|||||||
$documentation: "Represents a debugger statement",
|
$documentation: "Represents a debugger statement",
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
|
|
||||||
var AST_Directive = DEFNODE("Directive", "value scope quote", {
|
var AST_Directive = DEFNODE("Directive", "value quote", {
|
||||||
$documentation: "Represents a directive, like \"use strict\";",
|
$documentation: "Represents a directive, like \"use strict\";",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
|
||||||
scope: "[AST_Scope/S] The scope that this directive affects",
|
|
||||||
quote: "[string] the original quote character"
|
quote: "[string] the original quote character"
|
||||||
},
|
},
|
||||||
}, AST_Statement);
|
}, AST_Statement);
|
||||||
@@ -299,10 +298,9 @@ var AST_With = DEFNODE("With", "expression", {
|
|||||||
|
|
||||||
/* -----[ scope and functions ]----- */
|
/* -----[ scope and functions ]----- */
|
||||||
|
|
||||||
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
|
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
|
||||||
$documentation: "Base class for all statements introducing a lexical scope",
|
$documentation: "Base class for all statements introducing a lexical scope",
|
||||||
$propdoc: {
|
$propdoc: {
|
||||||
directives: "[string*/S] an array of directives declared in this scope",
|
|
||||||
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
|
||||||
functions: "[Object/S] like `variables`, but only lists function declarations",
|
functions: "[Object/S] like `variables`, but only lists function declarations",
|
||||||
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",
|
||||||
|
|||||||
@@ -285,6 +285,10 @@ merge(Compressor.prototype, {
|
|||||||
|
|
||||||
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
|
AST_Node.DEFMETHOD("reset_opt_flags", function(compressor, rescan) {
|
||||||
var reduce_vars = rescan && compressor.option("reduce_vars");
|
var reduce_vars = rescan && compressor.option("reduce_vars");
|
||||||
|
// Stack of look-up tables to keep track of whether a `SymbolDef` has been
|
||||||
|
// properly assigned before use:
|
||||||
|
// - `push()` & `pop()` when visiting conditional branches
|
||||||
|
// - backup & restore via `save_ids` when visiting out-of-order sections
|
||||||
var safe_ids = Object.create(null);
|
var safe_ids = Object.create(null);
|
||||||
var suppressor = new TreeWalker(function(node) {
|
var suppressor = new TreeWalker(function(node) {
|
||||||
if (!(node instanceof AST_Symbol)) return;
|
if (!(node instanceof AST_Symbol)) return;
|
||||||
@@ -293,6 +297,8 @@ merge(Compressor.prototype, {
|
|||||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
});
|
});
|
||||||
|
var in_loop = null;
|
||||||
|
var loop_ids = Object.create(null);
|
||||||
var tw = new TreeWalker(function(node, descend) {
|
var tw = new TreeWalker(function(node, descend) {
|
||||||
node._squeezed = false;
|
node._squeezed = false;
|
||||||
node._optimized = false;
|
node._optimized = false;
|
||||||
@@ -303,7 +309,7 @@ merge(Compressor.prototype, {
|
|||||||
var d = node.definition();
|
var d = node.definition();
|
||||||
d.references.push(node);
|
d.references.push(node);
|
||||||
if (d.fixed === undefined || !safe_to_read(d)
|
if (d.fixed === undefined || !safe_to_read(d)
|
||||||
|| is_modified(node, 0, is_immutable(node.fixed_value()))) {
|
|| is_modified(node, 0, is_immutable(node))) {
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
} else {
|
} else {
|
||||||
var parent = tw.parent();
|
var parent = tw.parent();
|
||||||
@@ -325,6 +331,7 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return node.value;
|
return node.value;
|
||||||
};
|
};
|
||||||
|
loop_ids[d.id] = in_loop;
|
||||||
mark(d, false);
|
mark(d, false);
|
||||||
descend();
|
descend();
|
||||||
} else {
|
} else {
|
||||||
@@ -380,6 +387,7 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = function() {
|
d.fixed = function() {
|
||||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||||
};
|
};
|
||||||
|
loop_ids[d.id] = in_loop;
|
||||||
mark(d, true);
|
mark(d, true);
|
||||||
} else {
|
} else {
|
||||||
d.fixed = false;
|
d.fixed = false;
|
||||||
@@ -391,10 +399,9 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Accessor) {
|
if (node instanceof AST_Accessor) {
|
||||||
var save_ids = safe_ids;
|
push();
|
||||||
safe_ids = Object.create(null);
|
|
||||||
descend();
|
descend();
|
||||||
safe_ids = save_ids;
|
pop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Binary
|
if (node instanceof AST_Binary
|
||||||
@@ -428,10 +435,13 @@ merge(Compressor.prototype, {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_DWLoop) {
|
if (node instanceof AST_DWLoop) {
|
||||||
|
var saved_loop = in_loop;
|
||||||
|
in_loop = node;
|
||||||
push();
|
push();
|
||||||
node.condition.walk(tw);
|
node.condition.walk(tw);
|
||||||
node.body.walk(tw);
|
node.body.walk(tw);
|
||||||
pop();
|
pop();
|
||||||
|
in_loop = saved_loop;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_LabeledStatement) {
|
if (node instanceof AST_LabeledStatement) {
|
||||||
@@ -442,6 +452,8 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
if (node instanceof AST_For) {
|
if (node instanceof AST_For) {
|
||||||
if (node.init) node.init.walk(tw);
|
if (node.init) node.init.walk(tw);
|
||||||
|
var saved_loop = in_loop;
|
||||||
|
in_loop = node;
|
||||||
if (node.condition) {
|
if (node.condition) {
|
||||||
push();
|
push();
|
||||||
node.condition.walk(tw);
|
node.condition.walk(tw);
|
||||||
@@ -455,14 +467,18 @@ merge(Compressor.prototype, {
|
|||||||
node.step.walk(tw);
|
node.step.walk(tw);
|
||||||
pop();
|
pop();
|
||||||
}
|
}
|
||||||
|
in_loop = saved_loop;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_ForIn) {
|
if (node instanceof AST_ForIn) {
|
||||||
node.init.walk(suppressor);
|
node.init.walk(suppressor);
|
||||||
node.object.walk(tw);
|
node.object.walk(tw);
|
||||||
|
var saved_loop = in_loop;
|
||||||
|
in_loop = node;
|
||||||
push();
|
push();
|
||||||
node.body.walk(tw);
|
node.body.walk(tw);
|
||||||
pop();
|
pop();
|
||||||
|
in_loop = saved_loop;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_Try) {
|
if (node instanceof AST_Try) {
|
||||||
@@ -532,10 +548,23 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
def.references = [];
|
def.references = [];
|
||||||
def.should_replace = undefined;
|
def.should_replace = undefined;
|
||||||
|
def.single_use = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_immutable(value) {
|
function is_immutable(node) {
|
||||||
return value && value.is_constant() || value instanceof AST_Lambda;
|
var value = node.fixed_value();
|
||||||
|
if (!value) return false;
|
||||||
|
if (value.is_constant()) return true;
|
||||||
|
if (compressor.option("unused")) {
|
||||||
|
var d = node.definition();
|
||||||
|
if (d.single_use === undefined) {
|
||||||
|
d.single_use = loop_ids[d.id] === in_loop
|
||||||
|
&& d.scope === node.scope
|
||||||
|
&& value.is_constant_expression();
|
||||||
|
}
|
||||||
|
if (d.references.length == 1 && d.single_use) return true;
|
||||||
|
}
|
||||||
|
return value instanceof AST_Lambda;
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_modified(node, level, immutable) {
|
function is_modified(node, level, immutable) {
|
||||||
@@ -809,7 +838,7 @@ merge(Compressor.prototype, {
|
|||||||
var sym;
|
var sym;
|
||||||
if (node instanceof AST_Call
|
if (node instanceof AST_Call
|
||||||
|| node instanceof AST_Exit
|
|| node instanceof AST_Exit
|
||||||
|| node instanceof AST_PropAccess
|
|| node instanceof AST_PropAccess && node.has_side_effects(compressor)
|
||||||
|| node instanceof AST_SymbolRef
|
|| node instanceof AST_SymbolRef
|
||||||
&& (lvalues[node.name]
|
&& (lvalues[node.name]
|
||||||
|| side_effects && !references_in_scope(node.definition()))
|
|| side_effects && !references_in_scope(node.definition()))
|
||||||
@@ -842,6 +871,8 @@ merge(Compressor.prototype, {
|
|||||||
&& !fn.uses_eval
|
&& !fn.uses_eval
|
||||||
&& (iife = compressor.parent()) instanceof AST_Call
|
&& (iife = compressor.parent()) instanceof AST_Call
|
||||||
&& iife.expression === fn) {
|
&& iife.expression === fn) {
|
||||||
|
var fn_strict = compressor.has_directive("use strict");
|
||||||
|
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
|
||||||
var names = Object.create(null);
|
var names = Object.create(null);
|
||||||
for (var i = fn.argnames.length; --i >= 0;) {
|
for (var i = fn.argnames.length; --i >= 0;) {
|
||||||
var sym = fn.argnames[i];
|
var sym = fn.argnames[i];
|
||||||
@@ -859,7 +890,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
arg = null;
|
arg = null;
|
||||||
}
|
}
|
||||||
if (node instanceof AST_This && !tw.find_parent(AST_Scope)) {
|
if (node instanceof AST_This && (fn_strict || !tw.find_parent(AST_Scope))) {
|
||||||
arg = null;
|
arg = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2110,6 +2141,22 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
def(AST_Node, return_false);
|
def(AST_Node, return_false);
|
||||||
def(AST_Constant, return_true);
|
def(AST_Constant, return_true);
|
||||||
|
def(AST_Function, function(){
|
||||||
|
var self = this;
|
||||||
|
var result = true;
|
||||||
|
self.walk(new TreeWalker(function(node) {
|
||||||
|
if (!result) return true;
|
||||||
|
if (node instanceof AST_SymbolRef) {
|
||||||
|
var def = node.definition();
|
||||||
|
if (self.enclosed.indexOf(def) >= 0
|
||||||
|
&& self.variables.get(def.name) !== def) {
|
||||||
|
result = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
return result;
|
||||||
|
});
|
||||||
def(AST_Unary, function(){
|
def(AST_Unary, function(){
|
||||||
return this.expression.is_constant_expression();
|
return this.expression.is_constant_expression();
|
||||||
});
|
});
|
||||||
@@ -4073,12 +4120,13 @@ merge(Compressor.prototype, {
|
|||||||
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
d.fixed = fixed = make_node(AST_Function, fixed, fixed);
|
||||||
}
|
}
|
||||||
if (compressor.option("unused")
|
if (compressor.option("unused")
|
||||||
&& fixed instanceof AST_Function
|
|
||||||
&& d.references.length == 1
|
&& d.references.length == 1
|
||||||
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
&& (d.single_use || fixed instanceof AST_Function
|
||||||
&& !d.scope.uses_eval
|
&& !(d.scope.uses_arguments && d.orig[0] instanceof AST_SymbolFunarg)
|
||||||
&& compressor.find_parent(AST_Scope) === fixed.parent_scope) {
|
&& !d.scope.uses_eval
|
||||||
return fixed.clone(true);
|
&& compressor.find_parent(AST_Scope) === fixed.parent_scope)) {
|
||||||
|
var value = fixed.optimize(compressor);
|
||||||
|
return value === fixed ? fixed.clone(true) : value;
|
||||||
}
|
}
|
||||||
if (compressor.option("evaluate") && fixed) {
|
if (compressor.option("evaluate") && fixed) {
|
||||||
if (d.should_replace === undefined) {
|
if (d.should_replace === undefined) {
|
||||||
|
|||||||
@@ -482,13 +482,17 @@ function OutputStream(options) {
|
|||||||
nodetype.DEFMETHOD("_codegen", generator);
|
nodetype.DEFMETHOD("_codegen", generator);
|
||||||
};
|
};
|
||||||
|
|
||||||
var use_asm = false;
|
|
||||||
var in_directive = false;
|
var in_directive = false;
|
||||||
|
var active_scope = null;
|
||||||
|
var use_asm = null;
|
||||||
|
|
||||||
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
AST_Node.DEFMETHOD("print", function(stream, force_parens){
|
||||||
var self = this, generator = self._codegen, prev_use_asm = use_asm;
|
var self = this, generator = self._codegen;
|
||||||
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
|
if (self instanceof AST_Scope) {
|
||||||
use_asm = true;
|
active_scope = self;
|
||||||
|
}
|
||||||
|
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
|
||||||
|
use_asm = active_scope;
|
||||||
}
|
}
|
||||||
function doit() {
|
function doit() {
|
||||||
self.add_comments(stream);
|
self.add_comments(stream);
|
||||||
@@ -502,8 +506,8 @@ function OutputStream(options) {
|
|||||||
doit();
|
doit();
|
||||||
}
|
}
|
||||||
stream.pop_node();
|
stream.pop_node();
|
||||||
if (self instanceof AST_Scope) {
|
if (self === use_asm) {
|
||||||
use_asm = prev_use_asm;
|
use_asm = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);
|
||||||
|
|||||||
@@ -1054,6 +1054,8 @@ function parse($TEXT, options) {
|
|||||||
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
|
var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null;
|
||||||
if (in_statement && !name)
|
if (in_statement && !name)
|
||||||
unexpected();
|
unexpected();
|
||||||
|
if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration))
|
||||||
|
unexpected(prev());
|
||||||
expect("(");
|
expect("(");
|
||||||
var argnames = [];
|
var argnames = [];
|
||||||
for (var first = true; !is("punc", ")");) {
|
for (var first = true; !is("punc", ")");) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"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-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"version": "3.1.1",
|
"version": "3.1.4",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"commander": "~2.11.0",
|
"commander": "~2.11.0",
|
||||||
"source-map": "~0.5.1"
|
"source-map": "~0.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "~5.1.1",
|
"acorn": "~5.1.1",
|
||||||
|
|||||||
@@ -104,3 +104,65 @@ asm_mixed: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asm_toplevel: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
function f() {
|
||||||
|
0.0;
|
||||||
|
(function(){
|
||||||
|
0.0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
|
||||||
|
}
|
||||||
|
|
||||||
|
asm_function_expression: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
0.0;
|
||||||
|
var a = function() {
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
function f() {
|
||||||
|
0.0;
|
||||||
|
return function(){
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
|
||||||
|
}
|
||||||
|
|
||||||
|
asm_nested_functions: {
|
||||||
|
options = {}
|
||||||
|
input: {
|
||||||
|
0.0;
|
||||||
|
function a() {
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
function b() {
|
||||||
|
0.0;
|
||||||
|
function c(){
|
||||||
|
"use asm";
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
function d(){
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
0.0;
|
||||||
|
}
|
||||||
|
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
|
||||||
|
}
|
||||||
|
|||||||
@@ -1268,22 +1268,21 @@ collapse_vars_short_circuited_conditions: {
|
|||||||
|
|
||||||
collapse_vars_regexp: {
|
collapse_vars_regexp: {
|
||||||
options = {
|
options = {
|
||||||
collapse_vars: true,
|
|
||||||
loops: false,
|
|
||||||
sequences: true,
|
|
||||||
dead_code: true,
|
|
||||||
conditionals: true,
|
|
||||||
comparisons: true,
|
|
||||||
evaluate: true,
|
|
||||||
booleans: true,
|
booleans: true,
|
||||||
unused: true,
|
cascade: true,
|
||||||
hoist_funs: true,
|
collapse_vars: true,
|
||||||
keep_fargs: true,
|
comparisons: true,
|
||||||
|
conditionals: true,
|
||||||
|
dead_code: true,
|
||||||
|
evaluate: true,
|
||||||
if_return: true,
|
if_return: true,
|
||||||
join_vars: true,
|
join_vars: true,
|
||||||
cascade: true,
|
hoist_funs: true,
|
||||||
side_effects: true,
|
keep_fargs: true,
|
||||||
|
loops: false,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
unused: true,
|
||||||
}
|
}
|
||||||
input: {
|
input: {
|
||||||
function f1() {
|
function f1() {
|
||||||
@@ -1292,12 +1291,12 @@ collapse_vars_regexp: {
|
|||||||
return [rx, k];
|
return [rx, k];
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
var rx = /[abc123]+/;
|
var rx = /ab*/g;
|
||||||
return function(s) {
|
return function(s) {
|
||||||
return rx.exec(s);
|
return rx.exec(s);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(function(){
|
(function() {
|
||||||
var result;
|
var result;
|
||||||
var s = 'acdabcdeabbb';
|
var s = 'acdabcdeabbb';
|
||||||
var rx = /ab*/g;
|
var rx = /ab*/g;
|
||||||
@@ -1305,22 +1304,35 @@ collapse_vars_regexp: {
|
|||||||
console.log(result[0]);
|
console.log(result[0]);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
(function() {
|
||||||
|
var result;
|
||||||
|
var s = 'acdabcdeabbb';
|
||||||
|
var rx = f2();
|
||||||
|
while (result = rx(s)) {
|
||||||
|
console.log(result[0]);
|
||||||
|
}
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f1() {
|
function f1() {
|
||||||
return [/[A-Z]+/, 9];
|
return [/[A-Z]+/, 9];
|
||||||
}
|
}
|
||||||
function f2() {
|
function f2() {
|
||||||
var rx = /[abc123]+/;
|
var rx = /ab*/g;
|
||||||
return function(s) {
|
return function(s) {
|
||||||
return rx.exec(s);
|
return rx.exec(s);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(function(){
|
(function() {
|
||||||
var result, rx = /ab*/g;
|
var result, rx = /ab*/g;
|
||||||
while (result = rx.exec("acdabcdeabbb"))
|
while (result = rx.exec("acdabcdeabbb"))
|
||||||
console.log(result[0]);
|
console.log(result[0]);
|
||||||
})();
|
})();
|
||||||
|
(function() {
|
||||||
|
var result, rx = f2();
|
||||||
|
while (result = rx("acdabcdeabbb"))
|
||||||
|
console.log(result[0]);
|
||||||
|
})();
|
||||||
}
|
}
|
||||||
expect_stdout: true
|
expect_stdout: true
|
||||||
}
|
}
|
||||||
@@ -1834,9 +1846,9 @@ issue_1858: {
|
|||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function(x) {
|
console.log(function(x) {
|
||||||
var a = {}, b = a.b = x;
|
var a = {}, b = a.b = 1;
|
||||||
return a.b + b;
|
return a.b + b;
|
||||||
}(1));
|
}());
|
||||||
}
|
}
|
||||||
expect_stdout: "2"
|
expect_stdout: "2"
|
||||||
}
|
}
|
||||||
@@ -2451,3 +2463,140 @@ issue_2313_2: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "0"
|
expect_stdout: "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_2319_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
return !function() {
|
||||||
|
return this;
|
||||||
|
}();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2319_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
console.log(function(a) {
|
||||||
|
"use strict";
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(function(a) {
|
||||||
|
"use strict";
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect_stdout: "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2319_3: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(a) {
|
||||||
|
return a;
|
||||||
|
}(!function() {
|
||||||
|
return this;
|
||||||
|
}()));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
"use strict";
|
||||||
|
console.log(function(a) {
|
||||||
|
return !function() {
|
||||||
|
return this;
|
||||||
|
}();
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
expect_stdout: "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_side_effects_1: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
console.log(C);
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
console.log({
|
||||||
|
bar: function() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}.bar());
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
prop_side_effects_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
pure_getters: "strict",
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
console.log(C);
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1);
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -751,12 +751,12 @@ issue_1583: {
|
|||||||
expect: {
|
expect: {
|
||||||
function m(t) {
|
function m(t) {
|
||||||
(function(e) {
|
(function(e) {
|
||||||
t = e();
|
t = function() {
|
||||||
})(function() {
|
return (function(a) {
|
||||||
return (function(a) {
|
return function(a) {};
|
||||||
return a;
|
})();
|
||||||
})(function(a) {});
|
}();
|
||||||
});
|
})();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1021,6 +1021,7 @@ issue_1964_1: {
|
|||||||
input: {
|
input: {
|
||||||
function f() {
|
function f() {
|
||||||
var long_variable_name = /\s/;
|
var long_variable_name = /\s/;
|
||||||
|
console.log(long_variable_name.source);
|
||||||
return "a b c".split(long_variable_name)[1];
|
return "a b c".split(long_variable_name)[1];
|
||||||
}
|
}
|
||||||
console.log(f());
|
console.log(f());
|
||||||
@@ -1028,11 +1029,15 @@ issue_1964_1: {
|
|||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
var long_variable_name = /\s/;
|
var long_variable_name = /\s/;
|
||||||
|
console.log(long_variable_name.source);
|
||||||
return "a b c".split(long_variable_name)[1];
|
return "a b c".split(long_variable_name)[1];
|
||||||
}
|
}
|
||||||
console.log(f());
|
console.log(f());
|
||||||
}
|
}
|
||||||
expect_stdout: "b"
|
expect_stdout: [
|
||||||
|
"\\s",
|
||||||
|
"b",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
issue_1964_2: {
|
issue_1964_2: {
|
||||||
@@ -1045,17 +1050,22 @@ issue_1964_2: {
|
|||||||
input: {
|
input: {
|
||||||
function f() {
|
function f() {
|
||||||
var long_variable_name = /\s/;
|
var long_variable_name = /\s/;
|
||||||
|
console.log(long_variable_name.source);
|
||||||
return "a b c".split(long_variable_name)[1];
|
return "a b c".split(long_variable_name)[1];
|
||||||
}
|
}
|
||||||
console.log(f());
|
console.log(f());
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
function f() {
|
function f() {
|
||||||
|
console.log(/\s/.source);
|
||||||
return "a b c".split(/\s/)[1];
|
return "a b c".split(/\s/)[1];
|
||||||
}
|
}
|
||||||
console.log(f());
|
console.log(f());
|
||||||
}
|
}
|
||||||
expect_stdout: "b"
|
expect_stdout: [
|
||||||
|
"\\s",
|
||||||
|
"b",
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
array_slice_index: {
|
array_slice_index: {
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ unsafe_evaluate: {
|
|||||||
options = {
|
options = {
|
||||||
evaluate : true,
|
evaluate : true,
|
||||||
reduce_vars : true,
|
reduce_vars : true,
|
||||||
|
side_effects : true,
|
||||||
unsafe : true,
|
unsafe : true,
|
||||||
unused : true
|
unused : true
|
||||||
}
|
}
|
||||||
@@ -1898,10 +1899,7 @@ redefine_farg_3: {
|
|||||||
console.log(f([]), g([]), h([]));
|
console.log(f([]), g([]), h([]));
|
||||||
}
|
}
|
||||||
expect: {
|
expect: {
|
||||||
console.log(function(a) {
|
console.log(typeof [], "number", "undefined");
|
||||||
var a;
|
|
||||||
return typeof a;
|
|
||||||
}([]), "number", "undefined");
|
|
||||||
}
|
}
|
||||||
expect_stdout: "object number undefined"
|
expect_stdout: "object number undefined"
|
||||||
}
|
}
|
||||||
@@ -2549,7 +2547,7 @@ issue_1922_2: {
|
|||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
accessor: {
|
accessor_1: {
|
||||||
options = {
|
options = {
|
||||||
evaluate: true,
|
evaluate: true,
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
@@ -2578,6 +2576,33 @@ accessor: {
|
|||||||
expect_stdout: "1 1"
|
expect_stdout: "1 1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
accessor_2: {
|
||||||
|
options = {
|
||||||
|
collapse_vars: true,
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var A = 1;
|
||||||
|
var B = {
|
||||||
|
get c() {
|
||||||
|
console.log(A);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
B.c;
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
({
|
||||||
|
get c() {
|
||||||
|
console.log(1);
|
||||||
|
}
|
||||||
|
}).c;
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
for_in_prop: {
|
for_in_prop: {
|
||||||
options = {
|
options = {
|
||||||
reduce_vars: true,
|
reduce_vars: true,
|
||||||
@@ -2602,3 +2627,270 @@ for_in_prop: {
|
|||||||
}
|
}
|
||||||
expect_stdout: "1"
|
expect_stdout: "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj_var_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
bar: function() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}.bar());
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_var_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_arg_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
function f(obj) {
|
||||||
|
return obj.bar();
|
||||||
|
}
|
||||||
|
console.log(f({
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
bar: function() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}.bar());
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_arg_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unsafe: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var C = 1;
|
||||||
|
function f(obj) {
|
||||||
|
return obj.bar();
|
||||||
|
}
|
||||||
|
console.log(f({
|
||||||
|
bar: function() {
|
||||||
|
return C + C;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(2);
|
||||||
|
}
|
||||||
|
expect_stdout: "2"
|
||||||
|
}
|
||||||
|
|
||||||
|
func_arg_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 42;
|
||||||
|
!function(a) {
|
||||||
|
console.log(a());
|
||||||
|
}(function() {
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(42);
|
||||||
|
}
|
||||||
|
expect_stdout: "42"
|
||||||
|
}
|
||||||
|
|
||||||
|
func_arg_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
side_effects: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 42;
|
||||||
|
!function(a) {
|
||||||
|
console.log(a());
|
||||||
|
}(function(a) {
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(void 0);
|
||||||
|
}
|
||||||
|
expect_stdout: "undefined"
|
||||||
|
}
|
||||||
|
|
||||||
|
regex_loop: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f(x) {
|
||||||
|
for (var r, s = "acdabcdeabbb"; r = x().exec(s);)
|
||||||
|
console.log(r[0]);
|
||||||
|
}
|
||||||
|
var a = /ab*/g;
|
||||||
|
f(function() {
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = /ab*/g;
|
||||||
|
(function(x) {
|
||||||
|
for (var r, s = "acdabcdeabbb"; r = x().exec(s);)
|
||||||
|
console.log(r[0]);
|
||||||
|
})(function() {
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
expect_stdout: true
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_for_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
for (var i = o.a--; i; i--)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var i = { a: 1 }.a--; i; i--)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_for_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
for (var i; i = o.a--;)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var o = { a: 1 };
|
||||||
|
for (var i; i = o.a--;)
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
expect_stdout: "1"
|
||||||
|
}
|
||||||
|
|
||||||
|
array_forin_1: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [ 1, 2, 3 ];
|
||||||
|
for (var b in a)
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
for (var b in [ 1, 2, 3 ])
|
||||||
|
console.log(b);
|
||||||
|
}
|
||||||
|
expect_stdout: [
|
||||||
|
"0",
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
array_forin_2: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = [];
|
||||||
|
for (var b in [ 1, 2, 3 ])
|
||||||
|
a.push(b);
|
||||||
|
console.log(a.length);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = [];
|
||||||
|
for (var b in [ 1, 2, 3 ])
|
||||||
|
a.push(b);
|
||||||
|
console.log(a.length);
|
||||||
|
}
|
||||||
|
expect_stdout: "3"
|
||||||
|
}
|
||||||
|
|||||||
@@ -73,6 +73,12 @@ describe("minify", function() {
|
|||||||
assert.strictEqual(run_code(compressed), run_code(original));
|
assert.strictEqual(run_code(compressed), run_code(original));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should not parse invalid use of reserved words", function() {
|
||||||
|
assert.strictEqual(Uglify.minify("function enum(){}").error, undefined);
|
||||||
|
assert.strictEqual(Uglify.minify("function static(){}").error, undefined);
|
||||||
|
assert.strictEqual(Uglify.minify("function this(){}").error.message, "Unexpected token: name (this)");
|
||||||
|
});
|
||||||
|
|
||||||
describe("keep_quoted_props", function() {
|
describe("keep_quoted_props", function() {
|
||||||
it("Should preserve quotes in object literals", function() {
|
it("Should preserve quotes in object literals", function() {
|
||||||
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
var js = 'var foo = {"x": 1, y: 2, \'z\': 3};';
|
||||||
|
|||||||
Reference in New Issue
Block a user