Compare commits
23 Commits
harmony-v3
...
v3.0.10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3c4a8e9e7 | ||
|
|
7e164aba8f | ||
|
|
22aedef849 | ||
|
|
58fae7dc07 | ||
|
|
5bf8d7e949 | ||
|
|
1df9d06f4a | ||
|
|
3408fc9d32 | ||
|
|
eae26756f1 | ||
|
|
43add9416b | ||
|
|
efcf167e5e | ||
|
|
6ed90913ca | ||
|
|
569c21e952 | ||
|
|
87c3a2c0ce | ||
|
|
baef8bf050 | ||
|
|
0813c5316f | ||
|
|
c88139492d | ||
|
|
cb45886512 | ||
|
|
050474ab44 | ||
|
|
f6c805ae1d | ||
|
|
9464d3c20f | ||
|
|
f18abd1b9c | ||
|
|
3be06ad085 | ||
|
|
265008c948 |
@@ -1,5 +1,4 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
before_install: "npm install -g npm"
|
|
||||||
node_js:
|
node_js:
|
||||||
- "0.10"
|
- "0.10"
|
||||||
- "0.12"
|
- "0.12"
|
||||||
|
|||||||
613
README.md
613
README.md
@@ -1,11 +1,10 @@
|
|||||||
UglifyJS 3
|
UglifyJS 3
|
||||||
==========
|
==========
|
||||||
[](https://travis-ci.org/mishoo/UglifyJS2)
|
|
||||||
|
|
||||||
UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
|
UglifyJS is a JavaScript parser, minifier, compressor and beautifier toolkit.
|
||||||
|
|
||||||
#### Note:
|
#### Note:
|
||||||
- **`uglify-js@3.x` has a simplified API and CLI that is not backwards compatible with [`uglify-js@2.x`](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
|
- **`uglify-js@3` has a simplified [API](#api-reference) and [CLI](#command-line-usage) that is not backwards compatible with [`uglify-js@2`](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
|
||||||
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
|
- **Documentation for UglifyJS `2.x` releases can be found [here](https://github.com/mishoo/UglifyJS2/tree/v2.x)**.
|
||||||
- `uglify-js` only supports ECMAScript 5 (ES5).
|
- `uglify-js` only supports ECMAScript 5 (ES5).
|
||||||
- Those wishing to minify
|
- Those wishing to minify
|
||||||
@@ -25,8 +24,7 @@ From NPM for programmatic use:
|
|||||||
|
|
||||||
npm install uglify-js
|
npm install uglify-js
|
||||||
|
|
||||||
Usage
|
# Command line usage
|
||||||
-----
|
|
||||||
|
|
||||||
uglifyjs [input files] [options]
|
uglifyjs [input files] [options]
|
||||||
|
|
||||||
@@ -43,7 +41,7 @@ a double dash to prevent input files being used as option arguments:
|
|||||||
|
|
||||||
uglifyjs --compress --mangle -- input.js
|
uglifyjs --compress --mangle -- input.js
|
||||||
|
|
||||||
The available options are:
|
### Command line options
|
||||||
|
|
||||||
```
|
```
|
||||||
-h, --help Print usage information.
|
-h, --help Print usage information.
|
||||||
@@ -142,7 +140,7 @@ The available options are:
|
|||||||
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
Specify `--output` (`-o`) to declare the output file. Otherwise the output
|
||||||
goes to STDOUT.
|
goes to STDOUT.
|
||||||
|
|
||||||
## Source map options
|
## CLI source map options
|
||||||
|
|
||||||
UglifyJS can generate a source map file, which is highly useful for
|
UglifyJS can generate a source map file, which is highly useful for
|
||||||
debugging your compressed JavaScript. To get a source map, pass
|
debugging your compressed JavaScript. To get a source map, pass
|
||||||
@@ -186,7 +184,20 @@ To use this feature pass `--source-map content="/path/to/input/source.map"`
|
|||||||
or `--source-map content=inline` if the source map is included inline with
|
or `--source-map content=inline` if the source map is included inline with
|
||||||
the sources.
|
the sources.
|
||||||
|
|
||||||
## Mangler options
|
## CLI compress options
|
||||||
|
|
||||||
|
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
||||||
|
you can pass a comma-separated list of [compress options](#compress-options).
|
||||||
|
|
||||||
|
Options are in the form `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`).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
uglifyjs file.js -c toplevel,sequences=false
|
||||||
|
|
||||||
|
## CLI mangle options
|
||||||
|
|
||||||
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:
|
||||||
@@ -205,14 +216,14 @@ comma-separated list of names. For example:
|
|||||||
|
|
||||||
to prevent the `require`, `exports` and `$` names from being changed.
|
to prevent the `require`, `exports` and `$` names from being changed.
|
||||||
|
|
||||||
### Mangling property names (`--mangle-props`)
|
### CLI mangling property names (`--mangle-props`)
|
||||||
|
|
||||||
**Note:** this will probably break your code. Mangling property names is a
|
**Note:** this will probably break your code. Mangling property names is a
|
||||||
separate step, different from variable name mangling. Pass
|
separate step, different from variable name mangling. Pass
|
||||||
`--mangle-props`. It will mangle all properties that are seen in some
|
`--mangle-props`. It will mangle all properties that are seen in some
|
||||||
object literal, or that are assigned to. For example:
|
object literal, or that are assigned to. For example:
|
||||||
|
|
||||||
```js
|
```javascript
|
||||||
var x = {
|
var x = {
|
||||||
foo: 1
|
foo: 1
|
||||||
};
|
};
|
||||||
@@ -243,10 +254,10 @@ mangled to the same name in all of them. For this, pass `--name-cache filename.
|
|||||||
and UglifyJS will maintain these mappings in a file which can then be reused.
|
and UglifyJS will maintain these mappings in a file which can then be reused.
|
||||||
It should be initially empty. Example:
|
It should be initially empty. Example:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
rm -f /tmp/cache.json # start fresh
|
$ rm -f /tmp/cache.json # start fresh
|
||||||
uglifyjs file1.js file2.js --mangle-props --name-cache /tmp/cache.json -o part1.js
|
$ uglifyjs file1.js file2.js --mangle-props --name-cache /tmp/cache.json -o part1.js
|
||||||
uglifyjs file3.js file4.js --mangle-props --name-cache /tmp/cache.json -o part2.js
|
$ uglifyjs file3.js file4.js --mangle-props --name-cache /tmp/cache.json -o part2.js
|
||||||
```
|
```
|
||||||
|
|
||||||
Now, `part1.js` and `part2.js` will be consistent with each other in terms
|
Now, `part1.js` and `part2.js` will be consistent with each other in terms
|
||||||
@@ -255,18 +266,18 @@ of mangled property names.
|
|||||||
Using the name cache is not necessary if you compress all your files in a
|
Using the name cache is not necessary if you compress all your files in a
|
||||||
single call to UglifyJS.
|
single call to UglifyJS.
|
||||||
|
|
||||||
#### Mangling unquoted names (`--mangle-props keep_quoted`)
|
### Mangling unquoted names (`--mangle-props keep_quoted`)
|
||||||
|
|
||||||
Using quoted property name (`o["foo"]`) reserves the property name (`foo`)
|
Using quoted property name (`o["foo"]`) reserves the property name (`foo`)
|
||||||
so that it is not mangled throughout the entire script even when used in an
|
so that it is not mangled throughout the entire script even when used in an
|
||||||
unquoted style (`o.foo`). Example:
|
unquoted style (`o.foo`). Example:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
$ echo 'var o={"foo":1, bar:3}; o.foo += o.bar; console.log(o.foo);' | uglifyjs --mangle-props keep_quoted -mc
|
$ echo 'var o={"foo":1, bar:3}; o.foo += o.bar; console.log(o.foo);' | uglifyjs --mangle-props keep_quoted -mc
|
||||||
var o={foo:1,a:3};o.foo+=o.a,console.log(o.foo);
|
var o={foo:1,a:3};o.foo+=o.a,console.log(o.foo);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Debugging property name mangling
|
### Debugging property name mangling
|
||||||
|
|
||||||
You can also pass `--mangle-props debug` in order to mangle property names
|
You can also pass `--mangle-props debug` in order to mangle property names
|
||||||
without completely obscuring them. For example the property `o.foo`
|
without completely obscuring them. For example the property `o.foo`
|
||||||
@@ -281,12 +292,181 @@ random number on every compile to simulate mangling changing with different
|
|||||||
inputs (e.g. as you update the input script with new properties), and to help
|
inputs (e.g. as you update the input script with new properties), and to help
|
||||||
identify mistakes like writing mangled keys to storage.
|
identify mistakes like writing mangled keys to storage.
|
||||||
|
|
||||||
## Compressor options
|
|
||||||
|
|
||||||
You need to pass `--compress` (`-c`) to enable the compressor. Optionally
|
# API Reference
|
||||||
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
|
Assuming installation via NPM, you can load UglifyJS in your application
|
||||||
to set `true`; it's effectively a shortcut for `foo=true`).
|
like this:
|
||||||
|
```javascript
|
||||||
|
var UglifyJS = require("uglify-js");
|
||||||
|
```
|
||||||
|
|
||||||
|
There is a single high level minification function, `minify(code, options)`, which will
|
||||||
|
performs all the steps in a configurable manner.
|
||||||
|
Example:
|
||||||
|
```javascript
|
||||||
|
var code = "function add(first, second) { return first + second; }";
|
||||||
|
var result = UglifyJS.minify(code);
|
||||||
|
console.log(result.error); // runtime error, or `undefined` if no error
|
||||||
|
console.log(result.code); // minified output: function add(n,d){return n+d}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also compress multiple files:
|
||||||
|
```javascript
|
||||||
|
var code = {
|
||||||
|
"file1.js": "function add(first, second) { return first + second; }",
|
||||||
|
"file2.js": "console.log(add(1 + 2, 3 + 4));"
|
||||||
|
};
|
||||||
|
var result = UglifyJS.minify(code);
|
||||||
|
console.log(result.code); // function add(d,n){return d+n}console.log(add(3,7));
|
||||||
|
```
|
||||||
|
|
||||||
|
The `toplevel` option:
|
||||||
|
```javascript
|
||||||
|
var code = {
|
||||||
|
"file1.js": "function add(first, second) { return first + second; }",
|
||||||
|
"file2.js": "console.log(add(1 + 2, 3 + 4));"
|
||||||
|
};
|
||||||
|
var options = { toplevel: true };
|
||||||
|
var result = UglifyJS.minify(code, options);
|
||||||
|
console.log(result.code); // console.log(function(n,o){return n+o}(3,7));
|
||||||
|
```
|
||||||
|
|
||||||
|
To produce warnings:
|
||||||
|
```javascript
|
||||||
|
var code = "function f(){ var u; return 2 + 3; }";
|
||||||
|
var options = { warnings: true };
|
||||||
|
var result = UglifyJS.minify(code, options);
|
||||||
|
console.log(result.error); // runtime error, `undefined` in this case
|
||||||
|
console.log(result.warnings); // [ 'Dropping unused variable u [0:1,18]' ]
|
||||||
|
console.log(result.code); // function f(){return 5}
|
||||||
|
```
|
||||||
|
|
||||||
|
An error example:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify({"foo.js" : "if (0) else console.log(1);"});
|
||||||
|
console.log(JSON.stringify(result.error));
|
||||||
|
// {"message":"Unexpected token: keyword (else)","filename":"foo.js","line":1,"col":7,"pos":7}
|
||||||
|
```
|
||||||
|
Note: unlike `uglify-js@2.x`, the `3.x` API does not throw errors. To
|
||||||
|
achieve a similar effect one could do the following:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify(code, options);
|
||||||
|
if (result.error) throw result.error;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Minify options
|
||||||
|
|
||||||
|
- `warnings` (default `false`) — pass `true` to return compressor warnings
|
||||||
|
in `result.warnings`. Use the value `"verbose"` for more detailed warnings.
|
||||||
|
|
||||||
|
- `parse` (default `{}`) — pass an object if you wish to specify some
|
||||||
|
additional [parse options](#parse-options).
|
||||||
|
|
||||||
|
- `compress` (default `{}`) — pass `false` to skip compressing entirely.
|
||||||
|
Pass an object to specify custom [compress options](#compress-options).
|
||||||
|
|
||||||
|
- `mangle` (default `true`) — pass `false` to skip mangling names, or pass
|
||||||
|
an object to specify [mangle options](#mangle-options) (see below).
|
||||||
|
|
||||||
|
- `mangle.properties` (default `false`) — a subcategory of the mangle option.
|
||||||
|
Pass an object to specify custom [mangle property options](#mangle-properties-options).
|
||||||
|
|
||||||
|
- `output` (default `null`) — pass an object if you wish to specify
|
||||||
|
additional [output options](#output-options). The defaults are optimized
|
||||||
|
for best compression.
|
||||||
|
|
||||||
|
- `sourceMap` (default `false`) - pass an object if you wish to specify
|
||||||
|
[source map options](#source-map-options).
|
||||||
|
|
||||||
|
- `toplevel` (default `false`) - set to `true` if you wish to enable top level
|
||||||
|
variable and function name mangling and to drop unused variables and functions.
|
||||||
|
|
||||||
|
- `ie8` (default `false`) - set to `true` to support IE8.
|
||||||
|
|
||||||
|
## Minify options structure
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
{
|
||||||
|
warnings: false,
|
||||||
|
parse: {
|
||||||
|
// parse options
|
||||||
|
},
|
||||||
|
compress: {
|
||||||
|
// compress options
|
||||||
|
},
|
||||||
|
mangle: {
|
||||||
|
// mangle options
|
||||||
|
|
||||||
|
properties: {
|
||||||
|
// mangle property options
|
||||||
|
}
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
// output options
|
||||||
|
},
|
||||||
|
sourceMap: {
|
||||||
|
// source map options
|
||||||
|
},
|
||||||
|
toplevel: false,
|
||||||
|
ie8: false,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Source map options
|
||||||
|
|
||||||
|
To generate a source map:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, {
|
||||||
|
sourceMap: {
|
||||||
|
filename: "out.js",
|
||||||
|
url: "out.js.map"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log(result.code); // minified output
|
||||||
|
console.log(result.map); // source map
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the source map is not saved in a file, it's just returned in
|
||||||
|
`result.map`. The value passed for `sourceMap.url` is only used to set
|
||||||
|
`//# sourceMappingURL=out.js.map` in `result.code`. The value of
|
||||||
|
`filename` is only used to set `file` attribute (see [the spec][sm-spec])
|
||||||
|
in source map file.
|
||||||
|
|
||||||
|
You can set option `sourceMap.url` to be `"inline"` and source map will
|
||||||
|
be appended to code.
|
||||||
|
|
||||||
|
You can also specify sourceRoot property to be included in source map:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, {
|
||||||
|
sourceMap: {
|
||||||
|
root: "http://example.com/src",
|
||||||
|
url: "out.js.map"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're compressing compiled JavaScript and have a source map for it, you
|
||||||
|
can use `sourceMap.content`:
|
||||||
|
```javascript
|
||||||
|
var result = UglifyJS.minify({"compiled.js": "compiled code"}, {
|
||||||
|
sourceMap: {
|
||||||
|
content: "content from compiled.js.map",
|
||||||
|
url: "minified.js.map"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// same as before, it returns `code` and `map`
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.url`.
|
||||||
|
|
||||||
|
## Parse options
|
||||||
|
|
||||||
|
- `bare_returns` (default `false`) -- support top level `return` statements
|
||||||
|
- `html5_comments` (default `true`)
|
||||||
|
- `shebang` (default `true`) -- support `#!command` as the first line
|
||||||
|
|
||||||
|
## Compress options
|
||||||
|
|
||||||
- `sequences` (default: true) -- join consecutive simple statements using the
|
- `sequences` (default: true) -- join consecutive simple statements using the
|
||||||
comma operator. May be set to a positive integer to specify the maximum number
|
comma operator. May be set to a positive integer to specify the maximum number
|
||||||
@@ -319,6 +499,9 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
|||||||
- `unsafe_proto` (default: false) -- optimize expressions like
|
- `unsafe_proto` (default: false) -- optimize expressions like
|
||||||
`Array.prototype.slice.call(a)` into `[].slice.call(a)`
|
`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
|
- `conditionals` -- apply optimizations for `if`-s and conditional
|
||||||
expressions
|
expressions
|
||||||
|
|
||||||
@@ -356,8 +539,8 @@ 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` -- Collapse single-use `var` and `const` definitions
|
- `collapse_vars` -- Collapse single-use non-constant variables - side
|
||||||
when possible.
|
effects permitting.
|
||||||
|
|
||||||
- `reduce_vars` -- Improve optimization on variables assigned with and
|
- `reduce_vars` -- Improve optimization on variables assigned with and
|
||||||
used as constant values.
|
used as constant values.
|
||||||
@@ -409,13 +592,139 @@ to set `true`; it's effectively a shortcut for `foo=true`).
|
|||||||
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
|
- `keep_infinity` -- default `false`. Pass `true` to prevent `Infinity` from
|
||||||
being compressed into `1/0`, which may cause performance issues on Chrome.
|
being compressed into `1/0`, which may cause performance issues on Chrome.
|
||||||
|
|
||||||
- `side_effects` -- default `false`. Pass `true` to potentially drop functions
|
- `side_effects` -- default `true`. Pass `false` to disable potentially dropping
|
||||||
marked as "pure". A function call is marked as "pure" if a comment annotation
|
functions marked as "pure". A function call is marked as "pure" if a comment
|
||||||
`/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For example:
|
annotation `/*@__PURE__*/` or `/*#__PURE__*/` immediately precedes the call. For
|
||||||
`/*@__PURE__*/foo()`;
|
example: `/*@__PURE__*/foo();`
|
||||||
|
|
||||||
|
## Mangle options
|
||||||
|
|
||||||
### The `unsafe` option
|
- `reserved` - 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](#compress-options).
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// test.js
|
||||||
|
var globalVar;
|
||||||
|
function funcName(firstLongName, anotherLongName) {
|
||||||
|
var myVariable = firstLongName + anotherLongName;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```javascript
|
||||||
|
var code = fs.readFileSync("test.js", "utf8");
|
||||||
|
|
||||||
|
UglifyJS.minify(code).code;
|
||||||
|
// 'function funcName(a,n){}var globalVar;'
|
||||||
|
|
||||||
|
UglifyJS.minify(code, { mangle: { reserved: ['firstLongName'] } }).code;
|
||||||
|
// 'function funcName(firstLongName,a){}var globalVar;'
|
||||||
|
|
||||||
|
UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
|
||||||
|
// 'function n(n,a){}var a;'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mangle properties options
|
||||||
|
|
||||||
|
- `regex` — Pass a RegExp to only mangle certain names
|
||||||
|
- `keep_quoted` — Only mangle unquoted property names
|
||||||
|
- `debug` — Mangle names with the original name still present. Defaults to `false`.
|
||||||
|
Pass an empty string to enable, or a non-empty string to set the suffix.
|
||||||
|
|
||||||
|
## Output options
|
||||||
|
|
||||||
|
The code generator tries to output shortest code possible by default. In
|
||||||
|
case you want beautified output, pass `--beautify` (`-b`). Optionally you
|
||||||
|
can pass additional arguments that control the code output:
|
||||||
|
|
||||||
|
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
|
||||||
|
regexps (affects directives with non-ascii characters becoming invalid)
|
||||||
|
- `beautify` (default `true`) -- whether to actually beautify the output.
|
||||||
|
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
|
||||||
|
arguments, so you can use `-b beautify=false` to override it.
|
||||||
|
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
|
||||||
|
`do`, `while` or `with` statements, even if their body is a single
|
||||||
|
statement.
|
||||||
|
- `comments` (default `false`) -- pass `true` or `"all"` to preserve all
|
||||||
|
comments, `"some"` to preserve some comments, a regular expression string
|
||||||
|
(e.g. `/^!/`) or a function.
|
||||||
|
- `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
|
||||||
|
`</script` in strings
|
||||||
|
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
||||||
|
quotes from property names in object literals.
|
||||||
|
- `max_line_len` (default `false`) -- maximum line length (for uglified code)
|
||||||
|
- `preamble` (default `null`) -- when passed it must be a string and
|
||||||
|
it will be prepended to the output literally. The source map will
|
||||||
|
adjust for this text. Can be used to insert a comment containing
|
||||||
|
licensing information, for example.
|
||||||
|
- `preserve_line` (default `false`) -- pass `true` to preserve lines, but it
|
||||||
|
only works if `beautify` is set to `false`.
|
||||||
|
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
||||||
|
objects
|
||||||
|
- `quote_style` (default `0`) -- preferred quote style for strings (affects
|
||||||
|
quoted property names and directives as well):
|
||||||
|
- `0` -- prefers double quotes, switches to single quotes when there are
|
||||||
|
more double quotes in the string itself.
|
||||||
|
- `1` -- always use single quotes
|
||||||
|
- `2` -- always use double quotes
|
||||||
|
- `3` -- always use the original quotes
|
||||||
|
- `semicolons` (default `true`) -- separate statements with semicolons. If
|
||||||
|
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
|
||||||
|
gzip could be smaller; size after gzip insignificantly larger).
|
||||||
|
- `shebang` (default `true`) -- preserve shebang `#!` in preamble (bash scripts)
|
||||||
|
- `width` (default 80) -- only takes effect when beautification is on, this
|
||||||
|
specifies an (orientative) line width that the beautifier will try to
|
||||||
|
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
|
||||||
|
by UglifyJS more readable.
|
||||||
|
- `wrap_iife` (default `false`) -- pass `true` to wrap immediately invoked
|
||||||
|
function expressions. See
|
||||||
|
[#640](https://github.com/mishoo/UglifyJS2/issues/640) for more details.
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
|
||||||
|
### Keeping copyright notices or other comments
|
||||||
|
|
||||||
|
You can pass `--comments` to retain certain comments in the output. By
|
||||||
|
default it will keep JSDoc-style comments that contain "@preserve",
|
||||||
|
"@license" or "@cc_on" (conditional compilation for IE). You can pass
|
||||||
|
`--comments all` to keep all the comments, or a valid JavaScript regexp to
|
||||||
|
keep only comments that match this regexp. For example `--comments /^!/`
|
||||||
|
will keep comments like `/*! Copyright Notice */`.
|
||||||
|
|
||||||
|
Note, however, that there might be situations where comments are lost. For
|
||||||
|
example:
|
||||||
|
```javascript
|
||||||
|
function f() {
|
||||||
|
/** @preserve Foo Bar */
|
||||||
|
function g() {
|
||||||
|
// this function is never called
|
||||||
|
}
|
||||||
|
return something();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Even though it has "@preserve", the comment will be lost because the inner
|
||||||
|
function `g` (which is the AST node to which the comment is attached to) is
|
||||||
|
discarded by the compressor as not referenced.
|
||||||
|
|
||||||
|
The safest comments where to place copyright information (or other info that
|
||||||
|
needs to be kept in the output) are comments attached to toplevel nodes.
|
||||||
|
|
||||||
|
### The `unsafe` `compress` option
|
||||||
|
|
||||||
It enables some transformations that *might* break code logic in certain
|
It enables some transformations that *might* break code logic in certain
|
||||||
contrived cases, but should be fine for most code. You might want to try it
|
contrived cases, but should be fine for most code. You might want to try it
|
||||||
@@ -453,8 +762,8 @@ Another way of doing that is to declare your globals as constants in a
|
|||||||
separate file and include it into the build. For example you can have a
|
separate file and include it into the build. For example you can have a
|
||||||
`build/defines.js` file with the following:
|
`build/defines.js` file with the following:
|
||||||
```javascript
|
```javascript
|
||||||
const DEBUG = false;
|
var DEBUG = false;
|
||||||
const PRODUCTION = true;
|
var PRODUCTION = true;
|
||||||
// etc.
|
// etc.
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -468,12 +777,13 @@ code as usual. The build will contain the `const` declarations if you use
|
|||||||
them. If you are targeting < ES6 environments which does not support `const`,
|
them. If you are targeting < ES6 environments which does not support `const`,
|
||||||
using `var` with `reduce_vars` (enabled by default) should suffice.
|
using `var` with `reduce_vars` (enabled by default) should suffice.
|
||||||
|
|
||||||
#### Conditional compilation, API
|
### Conditional compilation API
|
||||||
|
|
||||||
You can also use conditional compilation via the programmatic API. With the difference that the
|
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:
|
property name is `global_defs` and is a compressor property:
|
||||||
|
|
||||||
```js
|
```javascript
|
||||||
uglifyJS.minify(fs.readFileSync("input.js", "utf8"), {
|
var result = uglifyJS.minify(fs.readFileSync("input.js", "utf8"), {
|
||||||
compress: {
|
compress: {
|
||||||
dead_code: true,
|
dead_code: true,
|
||||||
global_defs: {
|
global_defs: {
|
||||||
@@ -483,81 +793,46 @@ uglifyJS.minify(fs.readFileSync("input.js", "utf8"), {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
## Beautifier options
|
### Using native Uglify AST with `minify()`
|
||||||
|
|
||||||
The code generator tries to output shortest code possible by default. In
|
|
||||||
case you want beautified output, pass `--beautify` (`-b`). Optionally you
|
|
||||||
can pass additional arguments that control the code 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
|
|
||||||
when you want to generate minified code, in order to specify additional
|
|
||||||
arguments, so you can use `-b beautify=false` to override it.
|
|
||||||
- `indent_level` (default 4)
|
|
||||||
- `indent_start` (default 0) -- prefix all lines by that many spaces
|
|
||||||
- `quote_keys` (default `false`) -- pass `true` to quote all keys in literal
|
|
||||||
objects
|
|
||||||
- `space_colon` (default `true`) -- insert a space after the colon signs
|
|
||||||
- `ascii_only` (default `false`) -- escape Unicode characters in strings and
|
|
||||||
regexps (affects directives with non-ascii characters becoming invalid)
|
|
||||||
- `inline_script` (default `false`) -- escape the slash in occurrences of
|
|
||||||
`</script` in strings
|
|
||||||
- `width` (default 80) -- only takes effect when beautification is on, this
|
|
||||||
specifies an (orientative) line width that the beautifier will try to
|
|
||||||
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
|
|
||||||
by UglifyJS more readable.
|
|
||||||
- `max_line_len` (default 32000) -- maximum line length (for uglified code)
|
|
||||||
- `bracketize` (default `false`) -- always insert brackets in `if`, `for`,
|
|
||||||
`do`, `while` or `with` statements, even if their body is a single
|
|
||||||
statement.
|
|
||||||
- `semicolons` (default `true`) -- separate statements with semicolons. If
|
|
||||||
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
|
|
||||||
gzip could be smaller; size after gzip insignificantly larger).
|
|
||||||
- `preamble` (default `null`) -- when passed it must be a string and
|
|
||||||
it will be prepended to the output literally. The source map will
|
|
||||||
adjust for this text. Can be used to insert a comment containing
|
|
||||||
licensing information, for example.
|
|
||||||
- `quote_style` (default `0`) -- preferred quote style for strings (affects
|
|
||||||
quoted property names and directives as well):
|
|
||||||
- `0` -- prefers double quotes, switches to single quotes when there are
|
|
||||||
more double quotes in the string itself.
|
|
||||||
- `1` -- always use single quotes
|
|
||||||
- `2` -- always use double quotes
|
|
||||||
- `3` -- always use the original quotes
|
|
||||||
- `keep_quoted_props` (default `false`) -- when turned on, prevents stripping
|
|
||||||
quotes from property names in object literals.
|
|
||||||
|
|
||||||
### Keeping copyright notices or other comments
|
|
||||||
|
|
||||||
You can pass `--comments` to retain certain comments in the output. By
|
|
||||||
default it will keep JSDoc-style comments that contain "@preserve",
|
|
||||||
"@license" or "@cc_on" (conditional compilation for IE). You can pass
|
|
||||||
`--comments all` to keep all the comments, or a valid JavaScript regexp to
|
|
||||||
keep only comments that match this regexp. For example `--comments /^!/`
|
|
||||||
will keep comments like `/*! Copyright Notice */`.
|
|
||||||
|
|
||||||
Note, however, that there might be situations where comments are lost. For
|
|
||||||
example:
|
|
||||||
```javascript
|
```javascript
|
||||||
function f() {
|
// example: parse only, produce native Uglify AST
|
||||||
/** @preserve Foo Bar */
|
|
||||||
function g() {
|
var result = UglifyJS.minify(code, {
|
||||||
// this function is never called
|
parse: {},
|
||||||
|
compress: false,
|
||||||
|
mangle: false,
|
||||||
|
output: {
|
||||||
|
ast: true,
|
||||||
|
code: false // optional - faster if false
|
||||||
}
|
}
|
||||||
return something();
|
});
|
||||||
|
|
||||||
|
// result.ast contains native Uglify AST
|
||||||
|
```
|
||||||
|
```javascript
|
||||||
|
// example: accept native Uglify AST input and then compress and mangle
|
||||||
|
// to produce both code and native AST.
|
||||||
|
|
||||||
|
var result = UglifyJS.minify(ast, {
|
||||||
|
compress: {},
|
||||||
|
mangle: {},
|
||||||
|
output: {
|
||||||
|
ast: true,
|
||||||
|
code: true // optional - faster if false
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// result.ast contains native Uglify AST
|
||||||
|
// result.code contains the minified code in string form.
|
||||||
```
|
```
|
||||||
|
|
||||||
Even though it has "@preserve", the comment will be lost because the inner
|
### Working with Uglify AST
|
||||||
function `g` (which is the AST node to which the comment is attached to) is
|
|
||||||
discarded by the compressor as not referenced.
|
|
||||||
|
|
||||||
The safest comments where to place copyright information (or other info that
|
Transversal and transformation of the native AST can be performed through
|
||||||
needs to be kept in the output) are comments attached to toplevel nodes.
|
[`TreeWalker`](http://lisperator.net/uglifyjs/walk) and
|
||||||
|
[`TreeTransformer`](http://lisperator.net/uglifyjs/transform) respectively.
|
||||||
|
|
||||||
## Support for the SpiderMonkey AST
|
### ESTree / SpiderMonkey AST
|
||||||
|
|
||||||
UglifyJS has its own abstract syntax tree format; for
|
UglifyJS has its own abstract syntax tree format; for
|
||||||
[practical reasons](http://lisperator.net/blog/uglifyjs-why-not-switching-to-spidermonkey-ast/)
|
[practical reasons](http://lisperator.net/blog/uglifyjs-why-not-switching-to-spidermonkey-ast/)
|
||||||
@@ -585,141 +860,5 @@ Acorn is really fast (e.g. 250ms instead of 380ms on some 650K code), but
|
|||||||
converting the SpiderMonkey tree that Acorn produces takes another 150ms so
|
converting the SpiderMonkey tree that Acorn produces takes another 150ms so
|
||||||
in total it's a bit more than just using UglifyJS's own parser.
|
in total it's a bit more than just using UglifyJS's own parser.
|
||||||
|
|
||||||
API Reference
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Assuming installation via NPM, you can load UglifyJS in your application
|
|
||||||
like this:
|
|
||||||
```javascript
|
|
||||||
var UglifyJS = require("uglify-js");
|
|
||||||
```
|
|
||||||
|
|
||||||
There is a single toplevel function, `minify(files, options)`, which will
|
|
||||||
performs all the steps in a configurable manner.
|
|
||||||
Example:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify("var b = function() {};");
|
|
||||||
console.log(result.code); // minified output
|
|
||||||
console.log(result.error); // runtime error
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also compress multiple files:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify({
|
|
||||||
"file1.js": "var a = function() {};",
|
|
||||||
"file2.js": "var b = function() {};"
|
|
||||||
});
|
|
||||||
console.log(result.code);
|
|
||||||
```
|
|
||||||
|
|
||||||
To generate a source map:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, {
|
|
||||||
sourceMap: {
|
|
||||||
filename: "out.js",
|
|
||||||
url: "out.js.map"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log(result.code); // minified output
|
|
||||||
console.log(result.map); // source map
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the source map is not saved in a file, it's just returned in
|
|
||||||
`result.map`. The value passed for `sourceMap.url` is only used to set
|
|
||||||
`//# sourceMappingURL=out.js.map` in `result.code`. The value of
|
|
||||||
`filename` is only used to set `file` attribute (see [the spec][sm-spec])
|
|
||||||
in source map file.
|
|
||||||
|
|
||||||
You can set option `sourceMap.url` to be `"inline"` and source map will
|
|
||||||
be appended to code.
|
|
||||||
|
|
||||||
You can also specify sourceRoot property to be included in source map:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify({"file1.js": "var a = function() {};"}, {
|
|
||||||
sourceMap: {
|
|
||||||
root: "http://example.com/src",
|
|
||||||
url: "out.js.map"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're compressing compiled JavaScript and have a source map for it, you
|
|
||||||
can use `sourceMap.content`:
|
|
||||||
```javascript
|
|
||||||
var result = UglifyJS.minify({"compiled.js": "compiled code"}, {
|
|
||||||
sourceMap: {
|
|
||||||
content: "content from compiled.js.map",
|
|
||||||
url: "minified.js.map"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// same as before, it returns `code` and `map`
|
|
||||||
```
|
|
||||||
|
|
||||||
If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.url`.
|
|
||||||
|
|
||||||
Other options:
|
|
||||||
|
|
||||||
- `warnings` (default `false`) — pass `true` to display compressor warnings.
|
|
||||||
|
|
||||||
- `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
|
|
||||||
additional [output options](#beautifier-options). The defaults are optimized
|
|
||||||
for best compression.
|
|
||||||
|
|
||||||
- `compress` (default `{}`) — pass `false` to skip compressing entirely.
|
|
||||||
Pass an object to specify custom [compressor options](#compressor-options).
|
|
||||||
|
|
||||||
- `parse` (default {}) — pass an object if you wish to specify some
|
|
||||||
additional [parser options](#the-parser).
|
|
||||||
|
|
||||||
##### mangle
|
|
||||||
|
|
||||||
- `reserved` - 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
|
|
||||||
// test.js
|
|
||||||
var globalVar;
|
|
||||||
function funcName(firstLongName, anotherLongName)
|
|
||||||
{
|
|
||||||
var myVariable = firstLongName + anotherLongName;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
```javascript
|
|
||||||
var code = fs.readFileSync("test.js", "utf8");
|
|
||||||
|
|
||||||
UglifyJS.minify(code).code;
|
|
||||||
// 'function funcName(a,n){}var globalVar;'
|
|
||||||
|
|
||||||
UglifyJS.minify(code, { mangle: { reserved: ['firstLongName'] } }).code;
|
|
||||||
// 'function funcName(firstLongName,a){}var globalVar;'
|
|
||||||
|
|
||||||
UglifyJS.minify(code, { mangle: { toplevel: true } }).code;
|
|
||||||
// 'function n(n,a){}var a;'
|
|
||||||
```
|
|
||||||
|
|
||||||
##### mangle.properties options
|
|
||||||
|
|
||||||
- `regex` — Pass a RegExp to only mangle certain names
|
|
||||||
- `keep_quoted` — Only mangle unquoted property names
|
|
||||||
- `debug` — Mangle names with the original name still present. Defaults to `false`.
|
|
||||||
Pass an empty string to enable, or a non-empty string to set the suffix.
|
|
||||||
|
|
||||||
[acorn]: https://github.com/ternjs/acorn
|
[acorn]: https://github.com/ternjs/acorn
|
||||||
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
|
[sm-spec]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k
|
||||||
|
|||||||
@@ -21,8 +21,7 @@ var options = {
|
|||||||
compress: false,
|
compress: false,
|
||||||
mangle: false
|
mangle: false
|
||||||
};
|
};
|
||||||
program._name = info.name;
|
program.version(info.name + ' ' + info.version);
|
||||||
program.version(info.version);
|
|
||||||
program.parseArgv = program.parse;
|
program.parseArgv = program.parse;
|
||||||
program.parse = undefined;
|
program.parse = undefined;
|
||||||
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
|
program.option("-p, --parse <options>", "Specify parser options.", parse_js("parse", true));
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ function Compressor(options, false_by_default) {
|
|||||||
unsafe_comps : false,
|
unsafe_comps : false,
|
||||||
unsafe_math : false,
|
unsafe_math : false,
|
||||||
unsafe_proto : false,
|
unsafe_proto : false,
|
||||||
|
unsafe_regexp : false,
|
||||||
unused : !false_by_default,
|
unused : !false_by_default,
|
||||||
warnings : false,
|
warnings : false,
|
||||||
}, true);
|
}, true);
|
||||||
@@ -913,12 +914,12 @@ merge(Compressor.prototype, {
|
|||||||
continue loop;
|
continue loop;
|
||||||
case stat instanceof AST_If:
|
case stat instanceof AST_If:
|
||||||
if (stat.body instanceof AST_Return) {
|
if (stat.body instanceof AST_Return) {
|
||||||
|
var value = stat.body.value;
|
||||||
//---
|
//---
|
||||||
// pretty silly case, but:
|
// pretty silly case, but:
|
||||||
// if (foo()) return; return; ==> foo(); return;
|
// if (foo()) return; return; ==> foo(); return;
|
||||||
if (((in_lambda && ret.length == 0)
|
if ((in_lambda && ret.length == 0 || ret[0] instanceof AST_Return && !ret[0].value)
|
||||||
|| (ret[0] instanceof AST_Return && !ret[0].value))
|
&& !value && !stat.alternative) {
|
||||||
&& !stat.body.value && !stat.alternative) {
|
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
var cond = make_node(AST_SimpleStatement, stat.condition, {
|
var cond = make_node(AST_SimpleStatement, stat.condition, {
|
||||||
body: stat.condition
|
body: stat.condition
|
||||||
@@ -928,7 +929,7 @@ merge(Compressor.prototype, {
|
|||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
// if (foo()) return x; return y; ==> return foo() ? x : y;
|
||||||
if (ret[0] instanceof AST_Return && stat.body.value && ret[0].value && !stat.alternative) {
|
if (ret[0] instanceof AST_Return && value && ret[0].value && !stat.alternative) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.alternative = ret[0];
|
stat.alternative = ret[0];
|
||||||
@@ -938,7 +939,7 @@ merge(Compressor.prototype, {
|
|||||||
//---
|
//---
|
||||||
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
// if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined;
|
||||||
if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return)
|
if (multiple_if_returns && (ret.length == 0 || ret[0] instanceof AST_Return)
|
||||||
&& stat.body.value && !stat.alternative && in_lambda) {
|
&& 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, {
|
||||||
@@ -948,8 +949,8 @@ merge(Compressor.prototype, {
|
|||||||
continue loop;
|
continue loop;
|
||||||
}
|
}
|
||||||
//---
|
//---
|
||||||
// if (foo()) return; [ else x... ]; y... ==> if (!foo()) { x...; y... }
|
// if (foo()) return [ void bar() ]; [ else x...; ] y... ==> if (!foo()) { x...; y... } else bar();
|
||||||
if (!stat.body.value && in_lambda) {
|
if (in_lambda && (!value || value instanceof AST_UnaryPrefix && value.operator == "void")) {
|
||||||
CHANGED = true;
|
CHANGED = true;
|
||||||
stat = stat.clone();
|
stat = stat.clone();
|
||||||
stat.condition = stat.condition.negate(compressor);
|
stat.condition = stat.condition.negate(compressor);
|
||||||
@@ -958,11 +959,12 @@ merge(Compressor.prototype, {
|
|||||||
stat.body = make_node(AST_BlockStatement, stat, {
|
stat.body = make_node(AST_BlockStatement, stat, {
|
||||||
body: body
|
body: body
|
||||||
});
|
});
|
||||||
stat.alternative = null;
|
stat.alternative = value ? make_node(AST_SimpleStatement, value, {
|
||||||
|
body: value.expression
|
||||||
|
}) : null;
|
||||||
ret = funs.concat([ stat.transform(compressor) ]);
|
ret = funs.concat([ stat.transform(compressor) ]);
|
||||||
continue loop;
|
continue loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---
|
//---
|
||||||
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
// if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e;
|
||||||
//
|
//
|
||||||
@@ -3765,7 +3767,7 @@ merge(Compressor.prototype, {
|
|||||||
if (fixed) {
|
if (fixed) {
|
||||||
if (d.should_replace === undefined) {
|
if (d.should_replace === undefined) {
|
||||||
var init = fixed.evaluate(compressor);
|
var init = fixed.evaluate(compressor);
|
||||||
if (init !== fixed) {
|
if (init !== fixed && (compressor.option("unsafe_regexp") || !(init instanceof RegExp))) {
|
||||||
init = make_node_from_constant(init, fixed);
|
init = make_node_from_constant(init, fixed);
|
||||||
var value_length = init.optimize(compressor).print_to_string().length;
|
var value_length = init.optimize(compressor).print_to_string().length;
|
||||||
var fn;
|
var fn;
|
||||||
|
|||||||
@@ -70,8 +70,6 @@ function OutputStream(options) {
|
|||||||
semicolons : true,
|
semicolons : true,
|
||||||
shebang : true,
|
shebang : true,
|
||||||
source_map : null,
|
source_map : null,
|
||||||
space_colon : true,
|
|
||||||
unescape_regexps : false,
|
|
||||||
width : 80,
|
width : 80,
|
||||||
wrap_iife : false,
|
wrap_iife : false,
|
||||||
}, true);
|
}, true);
|
||||||
@@ -357,7 +355,7 @@ function OutputStream(options) {
|
|||||||
|
|
||||||
function colon() {
|
function colon() {
|
||||||
print(":");
|
print(":");
|
||||||
if (options.space_colon) space();
|
space();
|
||||||
};
|
};
|
||||||
|
|
||||||
var add_mapping = options.source_map ? function(token, name) {
|
var add_mapping = options.source_map ? function(token, name) {
|
||||||
@@ -1261,45 +1259,14 @@ function OutputStream(options) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function regexp_safe_literal(code) {
|
|
||||||
return [
|
|
||||||
0x5c , // \
|
|
||||||
0x2f , // /
|
|
||||||
0x2e , // .
|
|
||||||
0x2b , // +
|
|
||||||
0x2a , // *
|
|
||||||
0x3f , // ?
|
|
||||||
0x28 , // (
|
|
||||||
0x29 , // )
|
|
||||||
0x5b , // [
|
|
||||||
0x5d , // ]
|
|
||||||
0x7b , // {
|
|
||||||
0x7d , // }
|
|
||||||
0x24 , // $
|
|
||||||
0x5e , // ^
|
|
||||||
0x3a , // :
|
|
||||||
0x7c , // |
|
|
||||||
0x21 , // !
|
|
||||||
0x0a , // \n
|
|
||||||
0x0d , // \r
|
|
||||||
0x00 , // \0
|
|
||||||
0xfeff , // Unicode BOM
|
|
||||||
0x2028 , // unicode "line separator"
|
|
||||||
0x2029 , // unicode "paragraph separator"
|
|
||||||
].indexOf(code) < 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
DEFPRINT(AST_RegExp, function(self, output){
|
DEFPRINT(AST_RegExp, function(self, output){
|
||||||
var str = self.getValue().toString();
|
var regexp = self.getValue();
|
||||||
|
var str = regexp.toString();
|
||||||
|
if (regexp.raw_source) {
|
||||||
|
str = "/" + regexp.raw_source + str.slice(str.lastIndexOf("/"));
|
||||||
|
}
|
||||||
if (output.option("ascii_only")) {
|
if (output.option("ascii_only")) {
|
||||||
str = output.to_ascii(str);
|
str = output.to_ascii(str);
|
||||||
} else if (output.option("unescape_regexps")) {
|
|
||||||
str = str.split("\\\\").map(function(str){
|
|
||||||
return str.replace(/\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}/g, function(s){
|
|
||||||
var code = parseInt(s.substr(2), 16);
|
|
||||||
return regexp_safe_literal(code) ? String.fromCharCode(code) : s;
|
|
||||||
});
|
|
||||||
}).join("\\\\");
|
|
||||||
}
|
}
|
||||||
output.print(str);
|
output.print(str);
|
||||||
var p = output.parent();
|
var p = output.parent();
|
||||||
|
|||||||
76
lib/parse.js
76
lib/parse.js
@@ -285,7 +285,11 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
|
S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX(value)) ||
|
||||||
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
|
(type == "keyword" && KEYWORDS_BEFORE_EXPRESSION(value)) ||
|
||||||
(type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
|
(type == "punc" && PUNC_BEFORE_EXPRESSION(value)));
|
||||||
prev_was_dot = (type == "punc" && value == ".");
|
if (type == "punc" && value == ".") {
|
||||||
|
prev_was_dot = true;
|
||||||
|
} else if (!is_comment) {
|
||||||
|
prev_was_dot = false;
|
||||||
|
}
|
||||||
var ret = {
|
var ret = {
|
||||||
type : type,
|
type : type,
|
||||||
value : value,
|
value : value,
|
||||||
@@ -473,29 +477,31 @@ function tokenizer($TEXT, filename, html5_comments, shebang) {
|
|||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
var read_regexp = with_eof_error("Unterminated regular expression", function(regexp){
|
var read_regexp = with_eof_error("Unterminated regular expression", function(source) {
|
||||||
var prev_backslash = false, ch, in_class = false;
|
var prev_backslash = false, ch, in_class = false;
|
||||||
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
|
while ((ch = next(true))) if (NEWLINE_CHARS(ch)) {
|
||||||
parse_error("Unexpected line terminator");
|
parse_error("Unexpected line terminator");
|
||||||
} else if (prev_backslash) {
|
} else if (prev_backslash) {
|
||||||
regexp += "\\" + ch;
|
source += "\\" + ch;
|
||||||
prev_backslash = false;
|
prev_backslash = false;
|
||||||
} else if (ch == "[") {
|
} else if (ch == "[") {
|
||||||
in_class = true;
|
in_class = true;
|
||||||
regexp += ch;
|
source += ch;
|
||||||
} else if (ch == "]" && in_class) {
|
} else if (ch == "]" && in_class) {
|
||||||
in_class = false;
|
in_class = false;
|
||||||
regexp += ch;
|
source += ch;
|
||||||
} else if (ch == "/" && !in_class) {
|
} else if (ch == "/" && !in_class) {
|
||||||
break;
|
break;
|
||||||
} else if (ch == "\\") {
|
} else if (ch == "\\") {
|
||||||
prev_backslash = true;
|
prev_backslash = true;
|
||||||
} else {
|
} else {
|
||||||
regexp += ch;
|
source += ch;
|
||||||
}
|
}
|
||||||
var mods = read_name();
|
var mods = read_name();
|
||||||
try {
|
try {
|
||||||
return token("regexp", new RegExp(regexp, mods));
|
var regexp = new RegExp(source, mods);
|
||||||
|
regexp.raw_source = source;
|
||||||
|
return token("regexp", regexp);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
parse_error(e.message);
|
parse_error(e.message);
|
||||||
}
|
}
|
||||||
@@ -801,17 +807,16 @@ function parse($TEXT, options) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var statement = embed_tokens(function() {
|
var statement = embed_tokens(function() {
|
||||||
var tmp;
|
|
||||||
handle_regexp();
|
handle_regexp();
|
||||||
switch (S.token.type) {
|
switch (S.token.type) {
|
||||||
case "string":
|
case "string":
|
||||||
if (S.in_directives) {
|
if (S.in_directives) {
|
||||||
tmp = peek();
|
var token = peek();
|
||||||
if (S.token.raw.indexOf("\\") == -1
|
if (S.token.raw.indexOf("\\") == -1
|
||||||
&& (tmp.nlb
|
&& (token.nlb
|
||||||
|| is_token(tmp, "eof")
|
|| is_token(token, "eof")
|
||||||
|| is_token(tmp, "punc", ";")
|
|| is_token(token, "punc", ";")
|
||||||
|| is_token(tmp, "punc", "}"))) {
|
|| is_token(token, "punc", "}"))) {
|
||||||
S.input.add_directive(S.token.value);
|
S.input.add_directive(S.token.value);
|
||||||
} else {
|
} else {
|
||||||
S.in_directives = false;
|
S.in_directives = false;
|
||||||
@@ -850,72 +855,97 @@ function parse($TEXT, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "keyword":
|
case "keyword":
|
||||||
switch (tmp = S.token.value, next(), tmp) {
|
switch (S.token.value) {
|
||||||
case "break":
|
case "break":
|
||||||
|
next();
|
||||||
return break_cont(AST_Break);
|
return break_cont(AST_Break);
|
||||||
|
|
||||||
case "continue":
|
case "continue":
|
||||||
|
next();
|
||||||
return break_cont(AST_Continue);
|
return break_cont(AST_Continue);
|
||||||
|
|
||||||
case "debugger":
|
case "debugger":
|
||||||
|
next();
|
||||||
semicolon();
|
semicolon();
|
||||||
return new AST_Debugger();
|
return new AST_Debugger();
|
||||||
|
|
||||||
case "do":
|
case "do":
|
||||||
|
next();
|
||||||
|
var body = in_loop(statement);
|
||||||
|
expect_token("keyword", "while");
|
||||||
|
var condition = parenthesised();
|
||||||
|
semicolon(true);
|
||||||
return new AST_Do({
|
return new AST_Do({
|
||||||
body : in_loop(statement),
|
body : body,
|
||||||
condition : (expect_token("keyword", "while"), tmp = parenthesised(), semicolon(true), tmp)
|
condition : condition
|
||||||
});
|
});
|
||||||
|
|
||||||
case "while":
|
case "while":
|
||||||
|
next();
|
||||||
return new AST_While({
|
return new AST_While({
|
||||||
condition : parenthesised(),
|
condition : parenthesised(),
|
||||||
body : in_loop(statement)
|
body : in_loop(statement)
|
||||||
});
|
});
|
||||||
|
|
||||||
case "for":
|
case "for":
|
||||||
|
next();
|
||||||
return for_();
|
return for_();
|
||||||
|
|
||||||
case "function":
|
case "function":
|
||||||
|
next();
|
||||||
return function_(AST_Defun);
|
return function_(AST_Defun);
|
||||||
|
|
||||||
case "if":
|
case "if":
|
||||||
|
next();
|
||||||
return if_();
|
return if_();
|
||||||
|
|
||||||
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("'return' outside of function");
|
||||||
|
next();
|
||||||
|
var value = null;
|
||||||
|
if (is("punc", ";")) {
|
||||||
|
next();
|
||||||
|
} else if (!can_insert_semicolon()) {
|
||||||
|
value = expression(true);
|
||||||
|
semicolon();
|
||||||
|
}
|
||||||
return new AST_Return({
|
return new AST_Return({
|
||||||
value: ( is("punc", ";")
|
value: value
|
||||||
? (next(), null)
|
|
||||||
: can_insert_semicolon()
|
|
||||||
? null
|
|
||||||
: (tmp = expression(true), semicolon(), tmp) )
|
|
||||||
});
|
});
|
||||||
|
|
||||||
case "switch":
|
case "switch":
|
||||||
|
next();
|
||||||
return new AST_Switch({
|
return new AST_Switch({
|
||||||
expression : parenthesised(),
|
expression : parenthesised(),
|
||||||
body : in_loop(switch_body_)
|
body : in_loop(switch_body_)
|
||||||
});
|
});
|
||||||
|
|
||||||
case "throw":
|
case "throw":
|
||||||
|
next();
|
||||||
if (S.token.nlb)
|
if (S.token.nlb)
|
||||||
croak("Illegal newline after 'throw'");
|
croak("Illegal newline after 'throw'");
|
||||||
|
var value = expression(true);
|
||||||
|
semicolon();
|
||||||
return new AST_Throw({
|
return new AST_Throw({
|
||||||
value: (tmp = expression(true), semicolon(), tmp)
|
value: value
|
||||||
});
|
});
|
||||||
|
|
||||||
case "try":
|
case "try":
|
||||||
|
next();
|
||||||
return try_();
|
return try_();
|
||||||
|
|
||||||
case "var":
|
case "var":
|
||||||
return tmp = var_(), semicolon(), tmp;
|
next();
|
||||||
|
var node = var_();
|
||||||
|
semicolon();
|
||||||
|
return node;
|
||||||
|
|
||||||
case "with":
|
case "with":
|
||||||
if (S.input.has_directive("use strict")) {
|
if (S.input.has_directive("use strict")) {
|
||||||
croak("Strict mode may not include a with statement");
|
croak("Strict mode may not include a with statement");
|
||||||
}
|
}
|
||||||
|
next();
|
||||||
return new AST_With({
|
return new AST_With({
|
||||||
expression : parenthesised(),
|
expression : parenthesised(),
|
||||||
body : statement()
|
body : statement()
|
||||||
|
|||||||
@@ -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.0.5",
|
"version": "3.0.10",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.8.0"
|
"node": ">=0.8.0"
|
||||||
},
|
},
|
||||||
@@ -34,10 +34,11 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "~5.0.3",
|
"acorn": "~5.0.3",
|
||||||
"mocha": "~2.3.4"
|
"mocha": "~2.3.4",
|
||||||
|
"semver": "~5.3.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test/run-tests.js"
|
"test": "node test/run-tests.js"
|
||||||
},
|
},
|
||||||
"keywords": ["uglify", "uglify-js", "minify", "minifier"]
|
"keywords": ["uglify", "uglify-js", "minify", "minifier", "es5"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -990,3 +990,50 @@ Infinity_NaN_undefined_LHS: {
|
|||||||
"}",
|
"}",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_1964_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe_regexp: false,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var long_variable_name = /\s/;
|
||||||
|
return "a b c".split(long_variable_name)[1];
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
var long_variable_name = /\s/;
|
||||||
|
return "a b c".split(long_variable_name)[1];
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect_stdout: "b"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_1964_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
unsafe_regexp: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function f() {
|
||||||
|
var long_variable_name = /\s/;
|
||||||
|
return "a b c".split(long_variable_name)[1];
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function f() {
|
||||||
|
return "a b c".split(/\s/)[1];
|
||||||
|
}
|
||||||
|
console.log(f());
|
||||||
|
}
|
||||||
|
expect_stdout: "b"
|
||||||
|
}
|
||||||
|
|||||||
@@ -302,3 +302,25 @@ issue_1437_conditionals: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_512: {
|
||||||
|
options = {
|
||||||
|
conditionals: true,
|
||||||
|
if_return: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
function a() {
|
||||||
|
if (b()) {
|
||||||
|
c();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
function a() {
|
||||||
|
if (!b()) throw e;
|
||||||
|
c();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
31
test/compress/issue-1943.js
Normal file
31
test/compress/issue-1943.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
operator: {
|
||||||
|
input: {
|
||||||
|
a. //comment
|
||||||
|
typeof
|
||||||
|
}
|
||||||
|
expect_exact: "a.typeof;"
|
||||||
|
}
|
||||||
|
|
||||||
|
name: {
|
||||||
|
input: {
|
||||||
|
a. //comment
|
||||||
|
b
|
||||||
|
}
|
||||||
|
expect_exact: "a.b;"
|
||||||
|
}
|
||||||
|
|
||||||
|
keyword: {
|
||||||
|
input: {
|
||||||
|
a. //comment
|
||||||
|
default
|
||||||
|
}
|
||||||
|
expect_exact: "a.default;"
|
||||||
|
}
|
||||||
|
|
||||||
|
atom: {
|
||||||
|
input: {
|
||||||
|
a. //comment
|
||||||
|
true
|
||||||
|
}
|
||||||
|
expect_exact: "a.true;"
|
||||||
|
}
|
||||||
12
test/compress/node_version.js
Normal file
12
test/compress/node_version.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
eval_let: {
|
||||||
|
input: {
|
||||||
|
eval("let a;");
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
eval("let a;");
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
expect_stdout: ""
|
||||||
|
node_version: ">=6"
|
||||||
|
}
|
||||||
@@ -8,3 +8,12 @@ octal_escape_sequence: {
|
|||||||
var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30";
|
var border_check = "\x20\x30\x38\x30\x00\x30\xc0\x30";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
issue_1929: {
|
||||||
|
input: {
|
||||||
|
function f(s) {
|
||||||
|
return s.split(/[\\/]/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect_exact: "function f(s){return s.split(/[\\\\/]/)}"
|
||||||
|
}
|
||||||
|
|||||||
1
test/input/invalid/else.js
Normal file
1
test/input/invalid/else.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
if (0) else 1;
|
||||||
1
test/input/invalid/return.js
Normal file
1
test/input/invalid/return.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
return 42;
|
||||||
@@ -19,7 +19,9 @@ describe("bin/uglifyjs", function () {
|
|||||||
eval(stdout);
|
eval(stdout);
|
||||||
|
|
||||||
assert.strictEqual(typeof WrappedUglifyJS, 'object');
|
assert.strictEqual(typeof WrappedUglifyJS, 'object');
|
||||||
assert.strictEqual(WrappedUglifyJS.minify("foo([true,,2+3]);").code, "foo([!0,,5]);");
|
var result = WrappedUglifyJS.minify("foo([true,,2+3]);");
|
||||||
|
assert.strictEqual(result.error, undefined);
|
||||||
|
assert.strictEqual(result.code, "foo([!0,,5]);");
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@@ -469,6 +471,36 @@ describe("bin/uglifyjs", function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Should throw syntax error (else)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/else.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/else.js:1,7",
|
||||||
|
"if (0) else 1;",
|
||||||
|
" ^",
|
||||||
|
"ERROR: Unexpected token: keyword (else)"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Should throw syntax error (return)", function(done) {
|
||||||
|
var command = uglifyjscmd + ' test/input/invalid/return.js';
|
||||||
|
|
||||||
|
exec(command, function (err, stdout, stderr) {
|
||||||
|
assert.ok(err);
|
||||||
|
assert.strictEqual(stdout, "");
|
||||||
|
assert.strictEqual(stderr.split(/\n/).slice(0, 4).join("\n"), [
|
||||||
|
"Parse error at test/input/invalid/return.js:1,0",
|
||||||
|
"return 42;",
|
||||||
|
"^",
|
||||||
|
"ERROR: 'return' outside of function"
|
||||||
|
].join("\n"));
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it("Should handle literal string as source map input", function(done) {
|
it("Should handle literal string as source map input", function(done) {
|
||||||
var command = [
|
var command = [
|
||||||
uglifyjscmd,
|
uglifyjscmd,
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ describe("spidermonkey export/import sanity test", function() {
|
|||||||
|
|
||||||
eval(stdout);
|
eval(stdout);
|
||||||
assert.strictEqual(typeof SpiderUglify, "object");
|
assert.strictEqual(typeof SpiderUglify, "object");
|
||||||
assert.strictEqual(SpiderUglify.minify("foo([true,,2+3]);").code, "foo([!0,,5]);");
|
var result = SpiderUglify.minify("foo([true,,2+3]);");
|
||||||
|
assert.strictEqual(result.error, undefined);
|
||||||
|
assert.strictEqual(result.code, "foo([!0,,5]);");
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ var path = require("path");
|
|||||||
var fs = require("fs");
|
var fs = require("fs");
|
||||||
var assert = require("assert");
|
var assert = require("assert");
|
||||||
var sandbox = require("./sandbox");
|
var sandbox = require("./sandbox");
|
||||||
|
var semver = require("semver");
|
||||||
|
|
||||||
var tests_dir = path.dirname(module.filename);
|
var tests_dir = path.dirname(module.filename);
|
||||||
var failures = 0;
|
var failures = 0;
|
||||||
@@ -164,7 +165,8 @@ function run_compress_tests() {
|
|||||||
failed_files[file] = 1;
|
failed_files[file] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (test.expect_stdout) {
|
if (test.expect_stdout
|
||||||
|
&& (!test.node_version || semver.satisfies(process.version, test.node_version))) {
|
||||||
var stdout = sandbox.run_code(input_code);
|
var stdout = sandbox.run_code(input_code);
|
||||||
if (test.expect_stdout === true) {
|
if (test.expect_stdout === true) {
|
||||||
test.expect_stdout = stdout;
|
test.expect_stdout = stdout;
|
||||||
@@ -274,7 +276,14 @@ function parse_test(file) {
|
|||||||
if (node instanceof U.AST_LabeledStatement) {
|
if (node instanceof U.AST_LabeledStatement) {
|
||||||
var label = node.label;
|
var label = node.label;
|
||||||
assert.ok(
|
assert.ok(
|
||||||
["input", "expect", "expect_exact", "expect_warnings", "expect_stdout"].indexOf(label.name) >= 0,
|
[
|
||||||
|
"input",
|
||||||
|
"expect",
|
||||||
|
"expect_exact",
|
||||||
|
"expect_warnings",
|
||||||
|
"expect_stdout",
|
||||||
|
"node_version",
|
||||||
|
].indexOf(label.name) >= 0,
|
||||||
tmpl("Unsupported label {name} [{line},{col}]", {
|
tmpl("Unsupported label {name} [{line},{col}]", {
|
||||||
name: label.name,
|
name: label.name,
|
||||||
line: label.start.line,
|
line: label.start.line,
|
||||||
@@ -282,7 +291,7 @@ function parse_test(file) {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
var stat = node.body;
|
var stat = node.body;
|
||||||
if (label.name == "expect_exact") {
|
if (label.name == "expect_exact" || label.name == "node_version") {
|
||||||
test[label.name] = read_string(stat);
|
test[label.name] = read_string(stat);
|
||||||
} else if (label.name == "expect_stdout") {
|
} else if (label.name == "expect_stdout") {
|
||||||
if (stat.TYPE == "SimpleStatement" && stat.body instanceof U.AST_Boolean) {
|
if (stat.TYPE == "SimpleStatement" && stat.body instanceof U.AST_Boolean) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
var semver = require("semver");
|
||||||
var vm = require("vm");
|
var vm = require("vm");
|
||||||
|
|
||||||
function safe_log(arg, level) {
|
function safe_log(arg, level) {
|
||||||
@@ -63,7 +64,7 @@ exports.run_code = function(code) {
|
|||||||
process.stdout.write = original_write;
|
process.stdout.write = original_write;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
exports.same_stdout = ~process.version.lastIndexOf("v0.12.", 0) ? function(expected, actual) {
|
exports.same_stdout = semver.satisfies(process.version, "0.12") ? function(expected, actual) {
|
||||||
if (typeof expected != typeof actual) return false;
|
if (typeof expected != typeof actual) return false;
|
||||||
if (typeof expected != "string") {
|
if (typeof expected != "string") {
|
||||||
if (expected.name != actual.name) return false;
|
if (expected.name != actual.name) return false;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
exports["Dictionary"] = Dictionary;
|
exports["Dictionary"] = Dictionary;
|
||||||
exports["TreeWalker"] = TreeWalker;
|
exports["TreeWalker"] = TreeWalker;
|
||||||
|
exports["TreeTransformer"] = TreeTransformer;
|
||||||
exports["minify"] = minify;
|
exports["minify"] = minify;
|
||||||
exports["_push_uniq"] = push_uniq;
|
exports["_push_uniq"] = push_uniq;
|
||||||
|
|||||||
Reference in New Issue
Block a user