forked from daren.hsu/line_push
update
This commit is contained in:
+140
-2
@@ -2,12 +2,150 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
### [2.3.7](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v2.3.6...v2.3.7) (2020-06-03)
|
||||
### [4.2.3](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v4.2.2...v4.2.3) (2020-10-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* security problem ([#258](https://github.com/webpack-contrib/terser-webpack-plugin/issues/258)) ([9954ad5](https://github.com/webpack-contrib/terser-webpack-plugin/commit/9954ad59895dd18b524253784cd13f1b173f99ed))
|
||||
* better minimizing `mjs` assets ([#329](https://github.com/webpack-contrib/terser-webpack-plugin/issues/329)) ([041b392](https://github.com/webpack-contrib/terser-webpack-plugin/commit/041b39208d364c8af9cd2b3f8e503b05a77ae067))
|
||||
* minify `cjs` assets ([#328](https://github.com/webpack-contrib/terser-webpack-plugin/issues/328)) ([b9c694d](https://github.com/webpack-contrib/terser-webpack-plugin/commit/b9c694d2c1193438d3ef72fed8d1789d9a48a367))
|
||||
|
||||
### [4.2.2](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v4.2.1...v4.2.2) (2020-09-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* related asset info ([a75dc8b](https://github.com/webpack-contrib/terser-webpack-plugin/commit/a75dc8bed97daecc509387a23a72699620695ab2))
|
||||
|
||||
### [4.2.1](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v4.2.0...v4.2.1) (2020-09-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* cache for extracted comments ([#314](https://github.com/webpack-contrib/terser-webpack-plugin/issues/314)) ([5340814](https://github.com/webpack-contrib/terser-webpack-plugin/commit/5340814188d53031b0444b8f588995dcbede88fc))
|
||||
* compatibility with webpack@5 ([f5bd8f8](https://github.com/webpack-contrib/terser-webpack-plugin/commit/f5bd8f8b1c0fc807fd00c57207e449056aeea35d))
|
||||
|
||||
## [4.2.0](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v4.1.0...v4.2.0) (2020-09-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* improve caching ([defde64](https://github.com/webpack-contrib/terser-webpack-plugin/commit/defde640c8a2448fe7a5fee95a516af6e1bba8e4))
|
||||
* pass the `terserOptions` to the `minify` option ([#311](https://github.com/webpack-contrib/terser-webpack-plugin/issues/311)) ([4bd622c](https://github.com/webpack-contrib/terser-webpack-plugin/commit/4bd622cdaeb51be5d5151925f64ac1054298a214))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* compatibility with webpack@5 ([#301](https://github.com/webpack-contrib/terser-webpack-plugin/issues/301)) ([9d861d8](https://github.com/webpack-contrib/terser-webpack-plugin/commit/9d861d8484eb36fa62c67f03b980cad2a43c3d2a))
|
||||
|
||||
## [4.1.0](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v4.0.0...v4.1.0) (2020-08-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* pass license files as related assets for webpack@5 ([7d3ae95](https://github.com/webpack-contrib/terser-webpack-plugin/commit/7d3ae95bc890a5211efe234301050815ef8e687e))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* compatibility with `10.13` version of `Node.js`
|
||||
|
||||
## [4.0.0](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.1.0...v4.0.0) (2020-08-04)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* the `warningsFilter` option was removed without replacement,
|
||||
* `terser` version is `5`,
|
||||
* return value of the `minify` option was changed, only `code`/`map`/`extractedComments` are valid
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* improved compatibility with webpack@5
|
||||
|
||||
|
||||
## [3.1.0](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.0.8...v3.1.0) (2020-08-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* show minimized assets in stats for webpack@5 ([#289](https://github.com/webpack-contrib/terser-webpack-plugin/issues/289)) ([d59eae2](https://github.com/webpack-contrib/terser-webpack-plugin/commit/d59eae2108ba43f3f7ce6c83195a8438634a9b55))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* compatibility cache feature with webpack@5 ([5d2bd29](https://github.com/webpack-contrib/terser-webpack-plugin/commit/5d2bd29403f614296795664a81e437712469bc05))
|
||||
* skip double compression for child compilation ([37cc813](https://github.com/webpack-contrib/terser-webpack-plugin/commit/37cc8132df50ad7b374ec2606df1d0e202a579d1))
|
||||
|
||||
### [3.0.8](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.0.7...v3.0.8) (2020-07-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* compatibility with child compilations ([9da4add](https://github.com/webpack-contrib/terser-webpack-plugin/commit/9da4add75390a583366b7f030d366c437a52137b))
|
||||
|
||||
### [3.0.7](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.0.6...v3.0.7) (2020-07-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* uglify additional assets ([100e38e](https://github.com/webpack-contrib/terser-webpack-plugin/commit/100e38e0db035f6eb21bbec2bbc1f8b12aee9f60))
|
||||
|
||||
### [3.0.6](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.0.5...v3.0.6) (2020-06-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not crash on buffer assets ([3c67023](https://github.com/webpack-contrib/terser-webpack-plugin/commit/3c670238952ddd5cbbf17f223e13a921f3b76521))
|
||||
|
||||
### [3.0.5](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.0.4...v3.0.5) (2020-06-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* multi-compiler crash ([f6499af](https://github.com/webpack-contrib/terser-webpack-plugin/commit/f6499afb40f7a3b434c880d555261d62e0de4fd7))
|
||||
|
||||
### [3.0.4](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.0.3...v3.0.4) (2020-06-13)
|
||||
|
||||
|
||||
### Chore
|
||||
|
||||
* update `p-limit` and `serialize-javascript` packages
|
||||
|
||||
### [3.0.3](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.0.1...v3.0.3) (2020-06-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* compatibility with `>= 10.13` versions of Node.js
|
||||
* security problem ([#259](https://github.com/webpack-contrib/terser-webpack-plugin/issues/259)) ([522aa2c](https://github.com/webpack-contrib/terser-webpack-plugin/commit/522aa2cd4e9c4b508b268eef99572c7c808fe0b6))
|
||||
|
||||
### [3.0.2](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.0.1...v3.0.2) (2020-05-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* compatibility with webpack@5 ([#250](https://github.com/webpack-contrib/terser-webpack-plugin/issues/250)) ([d3ff61c](https://github.com/webpack-contrib/terser-webpack-plugin/commit/d3ff61cbb714da8fb6ee1f7659bf6796774ab4cc))
|
||||
|
||||
### [3.0.1](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v3.0.0...v3.0.1) (2020-05-06)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* parallelism in multi compilation mode ([0ee7ed2](https://github.com/webpack-contrib/terser-webpack-plugin/commit/0ee7ed270b8cbf6312cc1009c5aa5f909fc7fbb7))
|
||||
* remove redundant code for the `chunkFilter` option ([#243](https://github.com/webpack-contrib/terser-webpack-plugin/issues/243)) ([7220734](https://github.com/webpack-contrib/terser-webpack-plugin/commit/722073494ae708e7cd94cdb9df26fb483e93e8de))
|
||||
|
||||
## [3.0.0](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v2.3.6...v3.0.0) (2020-05-01)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* minimum supported Node.js version is `10.13`
|
||||
* the `chunkFilter` was removed, please use `test`/`include`/`exclude` options
|
||||
* change arguments order for the `warningFilter` option from `Function<(warning, file, source) -> Boolean>` to `Function<(file, warning, source) -> Boolean>`
|
||||
* when the `extractComments.filename` option is a function it pass only one argument and it is object with `filename`, `basename`, `query` and `hash` properties
|
||||
* if the value from the `extractComments.filename` option conflicts with existing assets, an error will be thrown instead of a warning
|
||||
* use the `optimizeAssets` hook for webpack@5
|
||||
|
||||
### [2.3.6](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v2.3.5...v2.3.6) (2020-04-25)
|
||||
|
||||
|
||||
+25
-99
@@ -109,39 +109,9 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
### `chunkFilter`
|
||||
|
||||
Type: `Function<(chunk) -> boolean>`
|
||||
Default: `() => true`
|
||||
|
||||
Allowing to filter which chunks should be uglified (by default all chunks are uglified).
|
||||
Return `true` to uglify the chunk, `false` otherwise.
|
||||
|
||||
**webpack.config.js**
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
chunkFilter: (chunk) => {
|
||||
// Exclude uglification for the `vendor` chunk
|
||||
if (chunk.name === 'vendor') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### `cache`
|
||||
|
||||
> ⚠ Doesn't work with webpack 5!
|
||||
> ⚠ Ignored in webpack 5! Please use https://webpack.js.org/configuration/other-options/#cache.
|
||||
|
||||
Type: `Boolean|String`
|
||||
Default: `true`
|
||||
@@ -191,7 +161,7 @@ module.exports = {
|
||||
|
||||
### `cacheKeys`
|
||||
|
||||
> ⚠ Doesn't work with webpack 5!
|
||||
> ⚠ Ignored in webpack 5! Please use https://webpack.js.org/configuration/other-options/#cache.
|
||||
|
||||
Type: `Function<(defaultCacheKeys, file) -> Object>`
|
||||
Default: `defaultCacheKeys => defaultCacheKeys`
|
||||
@@ -205,11 +175,9 @@ Default cache keys:
|
||||
terser: require('terser/package.json').version, // terser version
|
||||
'terser-webpack-plugin': require('../package.json').version, // plugin version
|
||||
'terser-webpack-plugin-options': this.options, // plugin options
|
||||
path: compiler.outputPath ? `${compiler.outputPath}/${file}` : file, // asset path
|
||||
hash: crypto
|
||||
.createHash('md4')
|
||||
.update(input)
|
||||
.digest('hex'), // source file hash
|
||||
nodeVersion: process.version, // Node.js version
|
||||
name: file, // asset path
|
||||
contentHash: crypto.createHash('md4').update(input).digest('hex'), // source file hash
|
||||
});
|
||||
```
|
||||
|
||||
@@ -336,17 +304,23 @@ module.exports = {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
minify: (file, sourceMap) => {
|
||||
terserOptions: {
|
||||
myCustomOption: true,
|
||||
},
|
||||
// Can be async
|
||||
minify: (file, sourceMap, minimizerOptions) => {
|
||||
// The `minimizerOptions` option contains option from the `terserOptions` option
|
||||
// You can use `minimizerOptions.myCustomOption`
|
||||
const extractedComments = [];
|
||||
|
||||
// Custom logic for extract comments
|
||||
|
||||
const { error, map, code, warnings } = require('uglify-module') // Or require('./path/to/uglify-module')
|
||||
const { map, code } = require('uglify-module') // Or require('./path/to/uglify-module')
|
||||
.minify(file, {
|
||||
/* Your options for minification */
|
||||
});
|
||||
|
||||
return { error, map, code, warnings, extractedComments };
|
||||
return { map, code, extractedComments };
|
||||
},
|
||||
}),
|
||||
],
|
||||
@@ -371,7 +345,6 @@ module.exports = {
|
||||
new TerserPlugin({
|
||||
terserOptions: {
|
||||
ecma: undefined,
|
||||
warnings: false,
|
||||
parse: {},
|
||||
compress: {},
|
||||
mangle: true, // Note `mangle.properties` is `false` by default.
|
||||
@@ -496,13 +469,9 @@ module.exports = {
|
||||
new TerserPlugin({
|
||||
extractComments: {
|
||||
condition: /^\**!|@preserve|@license|@cc_on/i,
|
||||
filename: (file, fileData) => {
|
||||
// ⚠ webpack 5: there is only fileData parameter
|
||||
|
||||
// A file can contain a query string (for example when you have `output.filename: '[name].js?[chunkhash]'`)
|
||||
// You must consider this
|
||||
// The "fileData" argument contains object with "filename", "basename", "query"
|
||||
return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE.txt$2');
|
||||
filename: (fileData) => {
|
||||
// The "fileData" argument contains object with "filename", "basename", "query" and "hash"
|
||||
return `${fileData.filename}.LICENSE.txt${fileData.query}`;
|
||||
},
|
||||
banner: (licenseFile) => {
|
||||
return `License information can be found in ${licenseFile}`;
|
||||
@@ -530,12 +499,9 @@ module.exports = {
|
||||
new TerserPlugin({
|
||||
extractComments: {
|
||||
condition: 'some',
|
||||
filename: (file, fileData) => {
|
||||
// ⚠ webpack 5: there is only fileData parameter
|
||||
|
||||
// A file can contain a query string (for example when you have `output.filename: '[name].js?[chunkhash]'`)
|
||||
// You must consider this
|
||||
return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE.txt$2');
|
||||
filename: (fileData) => {
|
||||
// The "fileData" argument contains object with "filename", "basename", "query" and "hash"
|
||||
return `${fileData.filename}.LICENSE.txt${fileData.query}`;
|
||||
},
|
||||
banner: (licenseFile) => {
|
||||
return `License information can be found in ${licenseFile}`;
|
||||
@@ -557,6 +523,8 @@ Available placeholders: `[file]`, `[query]` and `[filebase]` (`[base]` for webpa
|
||||
The file where the extracted comments will be stored.
|
||||
Default is to append the suffix `.LICENSE.txt` to the original filename.
|
||||
|
||||
> ⚠️ We highly recommend using the `txt` extension. Using `js`/`cjs`/`mjs` extensions may conflict with existing assets which leads to broken code.
|
||||
|
||||
**webpack.config.js**
|
||||
|
||||
```js
|
||||
@@ -597,12 +565,9 @@ module.exports = {
|
||||
new TerserPlugin({
|
||||
extractComments: {
|
||||
condition: true,
|
||||
filename: (file, fileData) => {
|
||||
// ⚠ webpack 5: there is only fileData parameter
|
||||
|
||||
// A file can contain a query string (for example when you have `output.filename: '[name].js?[chunkhash]'`)
|
||||
// You must consider this
|
||||
return file.replace(/\.(\w+)($|\?)/, '.$1.LICENSE.txt$2');
|
||||
filename: (fileData) => {
|
||||
// The "fileData" argument contains object with "filename", "basename", "query" and "hash"
|
||||
return `${fileData.filename}.LICENSE.txt${fileData.query}`;
|
||||
},
|
||||
banner: (commentsFile) => {
|
||||
return `My custom banner about license information ${commentsFile}`;
|
||||
@@ -614,45 +579,6 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
### `warningsFilter`
|
||||
|
||||
Type: `Function<(warning, source, file) -> Boolean>`
|
||||
Default: `() => true`
|
||||
|
||||
Allow to filter [terser](https://github.com/terser-js/terser) warnings.
|
||||
Return `true` to keep the warning, a falsy value (`false`/`null`/`undefined`) otherwise.
|
||||
|
||||
> ⚠️ The `source` argument will contain `undefined` if you don't use source maps.
|
||||
|
||||
**webpack.config.js**
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [
|
||||
new TerserPlugin({
|
||||
warningsFilter: (warning, source, file) => {
|
||||
if (/Dropping unreachable code/i.test(warning)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (/source\.js/i.test(source)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (/file\.js/i.test(file)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Preserve Comments
|
||||
|
||||
+100
-14
@@ -16,9 +16,9 @@ var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
class Webpack4Cache {
|
||||
constructor(compiler, compilation, options) {
|
||||
this.options = options;
|
||||
this.cacheDir = options.cache === true ? Webpack4Cache.getCacheDirectory() : options.cache;
|
||||
constructor(compilation, options, weakCache) {
|
||||
this.cache = options.cache === true ? Webpack4Cache.getCacheDirectory() : options.cache;
|
||||
this.weakCache = weakCache;
|
||||
}
|
||||
|
||||
static getCacheDirectory() {
|
||||
@@ -27,20 +27,106 @@ class Webpack4Cache {
|
||||
}) || _os.default.tmpdir();
|
||||
}
|
||||
|
||||
isEnabled() {
|
||||
return !!this.cacheDir;
|
||||
async get(cacheData, {
|
||||
RawSource,
|
||||
ConcatSource,
|
||||
SourceMapSource
|
||||
}) {
|
||||
if (!this.cache) {
|
||||
// eslint-disable-next-line no-undefined
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const weakOutput = this.weakCache.get(cacheData.inputSource);
|
||||
|
||||
if (weakOutput) {
|
||||
return weakOutput;
|
||||
} // eslint-disable-next-line no-param-reassign
|
||||
|
||||
|
||||
cacheData.cacheIdent = cacheData.cacheIdent || (0, _serializeJavascript.default)(cacheData.cacheKeys);
|
||||
let cachedResult;
|
||||
|
||||
try {
|
||||
cachedResult = await _cacache.default.get(this.cache, cacheData.cacheIdent);
|
||||
} catch (ignoreError) {
|
||||
// eslint-disable-next-line no-undefined
|
||||
return undefined;
|
||||
}
|
||||
|
||||
cachedResult = JSON.parse(cachedResult.data);
|
||||
|
||||
if (cachedResult.target === 'comments') {
|
||||
return new ConcatSource(cachedResult.value);
|
||||
}
|
||||
|
||||
const {
|
||||
code,
|
||||
name,
|
||||
map,
|
||||
input,
|
||||
inputSourceMap,
|
||||
extractedComments,
|
||||
banner,
|
||||
shebang
|
||||
} = cachedResult;
|
||||
|
||||
if (map) {
|
||||
cachedResult.source = new SourceMapSource(code, name, map, input, inputSourceMap, true);
|
||||
} else {
|
||||
cachedResult.source = new RawSource(code);
|
||||
}
|
||||
|
||||
if (banner) {
|
||||
cachedResult.source = new ConcatSource(shebang ? `${shebang}\n` : '', `/*! ${banner} */\n`, cachedResult.source);
|
||||
}
|
||||
|
||||
if (extractedComments) {
|
||||
cachedResult.extractedCommentsSource = new RawSource(extractedComments);
|
||||
}
|
||||
|
||||
return cachedResult;
|
||||
}
|
||||
|
||||
get(task) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
task.cacheIdent = task.cacheIdent || (0, _serializeJavascript.default)(task.cacheKeys);
|
||||
return _cacache.default.get(this.cacheDir, task.cacheIdent).then(({
|
||||
data
|
||||
}) => JSON.parse(data));
|
||||
}
|
||||
async store(cacheData) {
|
||||
if (!this.cache) {
|
||||
// eslint-disable-next-line no-undefined
|
||||
return undefined;
|
||||
}
|
||||
|
||||
store(task, data) {
|
||||
return _cacache.default.put(this.cacheDir, task.cacheIdent, JSON.stringify(data));
|
||||
if (!this.weakCache.has(cacheData.inputSource)) {
|
||||
if (cacheData.target === 'comments') {
|
||||
this.weakCache.set(cacheData.inputSource, cacheData.output);
|
||||
} else {
|
||||
this.weakCache.set(cacheData.inputSource, cacheData);
|
||||
}
|
||||
}
|
||||
|
||||
let data;
|
||||
|
||||
if (cacheData.target === 'comments') {
|
||||
data = {
|
||||
target: cacheData.target,
|
||||
value: cacheData.output.source()
|
||||
};
|
||||
} else {
|
||||
data = {
|
||||
code: cacheData.code,
|
||||
name: cacheData.name,
|
||||
map: cacheData.map,
|
||||
input: cacheData.input,
|
||||
inputSourceMap: cacheData.inputSourceMap,
|
||||
banner: cacheData.banner,
|
||||
shebang: cacheData.shebang
|
||||
};
|
||||
|
||||
if (cacheData.extractedCommentsSource) {
|
||||
data.extractedComments = cacheData.extractedCommentsSource.source();
|
||||
data.commentsFilename = cacheData.commentsFilename;
|
||||
}
|
||||
}
|
||||
|
||||
return _cacache.default.put(this.cache, cacheData.cacheIdent, JSON.stringify(data));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
-62
@@ -5,76 +5,31 @@ Object.defineProperty(exports, "__esModule", {
|
||||
});
|
||||
exports.default = void 0;
|
||||
|
||||
var _getLazyHashedEtag = _interopRequireDefault(require("webpack/lib/cache/getLazyHashedEtag"));
|
||||
|
||||
var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"));
|
||||
|
||||
var _webpack = require("webpack");
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
// eslint-disable-next-line import/extensions,import/no-unresolved
|
||||
class Cache {
|
||||
constructor(compiler, compilation, options) {
|
||||
this.compiler = compiler;
|
||||
this.compilation = compilation;
|
||||
this.options = options;
|
||||
constructor(compilation) {
|
||||
this.cache = compilation.getCache('TerserWebpackPlugin');
|
||||
}
|
||||
|
||||
isEnabled() {
|
||||
return !!this.compilation.cache;
|
||||
async get(cacheData) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
cacheData.eTag = cacheData.eTag || Array.isArray(cacheData.inputSource) ? cacheData.inputSource.map(item => this.cache.getLazyHashedEtag(item)).reduce((previousValue, currentValue) => this.cache.mergeEtags(previousValue, currentValue)) : this.cache.getLazyHashedEtag(cacheData.inputSource);
|
||||
return this.cache.getPromise(cacheData.name, cacheData.eTag);
|
||||
}
|
||||
|
||||
createCacheIdent(task) {
|
||||
const {
|
||||
outputOptions: {
|
||||
hashSalt,
|
||||
hashDigest,
|
||||
hashDigestLength,
|
||||
hashFunction
|
||||
}
|
||||
} = this.compilation;
|
||||
async store(cacheData) {
|
||||
let data;
|
||||
|
||||
const hash = _webpack.util.createHash(hashFunction);
|
||||
|
||||
if (hashSalt) {
|
||||
hash.update(hashSalt);
|
||||
if (cacheData.target === 'comments') {
|
||||
data = cacheData.output;
|
||||
} else {
|
||||
data = {
|
||||
source: cacheData.source,
|
||||
extractedCommentsSource: cacheData.extractedCommentsSource,
|
||||
commentsFilename: cacheData.commentsFilename
|
||||
};
|
||||
}
|
||||
|
||||
hash.update((0, _serializeJavascript.default)(task.cacheKeys));
|
||||
const digest = hash.digest(hashDigest);
|
||||
const cacheKeys = digest.substr(0, hashDigestLength);
|
||||
return `${this.compilation.compilerPath}/TerserWebpackPlugin/${cacheKeys}/${task.file}`;
|
||||
}
|
||||
|
||||
get(task) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
task.cacheIdent = task.cacheIdent || this.createCacheIdent(task); // eslint-disable-next-line no-param-reassign
|
||||
|
||||
task.cacheETag = task.cacheETag || (0, _getLazyHashedEtag.default)(task.asset);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.compilation.cache.get(task.cacheIdent, task.cacheETag, (err, result) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else if (result) {
|
||||
resolve(result);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
store(task, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.compilation.cache.store(task.cacheIdent, task.cacheETag, data, err => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
});
|
||||
return this.cache.storePromise(cacheData.name, cacheData.eTag, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+422
-283
@@ -7,40 +7,52 @@ exports.default = void 0;
|
||||
|
||||
var _path = _interopRequireDefault(require("path"));
|
||||
|
||||
var _os = _interopRequireDefault(require("os"));
|
||||
|
||||
var _sourceMap = require("source-map");
|
||||
|
||||
var _webpackSources = require("webpack-sources");
|
||||
var _webpack = _interopRequireWildcard(require("webpack"));
|
||||
|
||||
var _RequestShortener = _interopRequireDefault(require("webpack/lib/RequestShortener"));
|
||||
|
||||
var _webpack = require("webpack");
|
||||
|
||||
var _schemaUtils = _interopRequireDefault(require("schema-utils"));
|
||||
var _schemaUtils = require("schema-utils");
|
||||
|
||||
var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"));
|
||||
|
||||
var _package = _interopRequireDefault(require("terser/package.json"));
|
||||
|
||||
var _pLimit = _interopRequireDefault(require("p-limit"));
|
||||
|
||||
var _jestWorker = _interopRequireDefault(require("jest-worker"));
|
||||
|
||||
var _options = _interopRequireDefault(require("./options.json"));
|
||||
|
||||
var _TaskRunner = _interopRequireDefault(require("./TaskRunner"));
|
||||
var _minify = require("./minify");
|
||||
|
||||
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
||||
|
||||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
const warningRegex = /\[.+:([0-9]+),([0-9]+)\]/;
|
||||
// webpack 5 exposes the sources property to ensure the right version of webpack-sources is used
|
||||
const {
|
||||
SourceMapSource,
|
||||
RawSource,
|
||||
ConcatSource
|
||||
} = // eslint-disable-next-line global-require
|
||||
_webpack.default.sources || require('webpack-sources');
|
||||
|
||||
class TerserPlugin {
|
||||
constructor(options = {}) {
|
||||
(0, _schemaUtils.default)(_options.default, options, {
|
||||
(0, _schemaUtils.validate)(_options.default, options, {
|
||||
name: 'Terser Plugin',
|
||||
baseDataPath: 'options'
|
||||
});
|
||||
const {
|
||||
minify,
|
||||
terserOptions = {},
|
||||
test = /\.m?js(\?.*)?$/i,
|
||||
chunkFilter = () => true,
|
||||
warningsFilter = () => true,
|
||||
test = /\.[cm]?js(\?.*)?$/i,
|
||||
extractComments = true,
|
||||
sourceMap,
|
||||
cache = true,
|
||||
@@ -51,8 +63,6 @@ class TerserPlugin {
|
||||
} = options;
|
||||
this.options = {
|
||||
test,
|
||||
chunkFilter,
|
||||
warningsFilter,
|
||||
extractComments,
|
||||
sourceMap,
|
||||
cache,
|
||||
@@ -71,16 +81,7 @@ class TerserPlugin {
|
||||
return Boolean(input && input.version && input.sources && Array.isArray(input.sources) && typeof input.mappings === 'string');
|
||||
}
|
||||
|
||||
static buildSourceMap(inputSourceMap) {
|
||||
if (!inputSourceMap || !TerserPlugin.isSourceMap(inputSourceMap)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new _sourceMap.SourceMapConsumer(inputSourceMap);
|
||||
}
|
||||
|
||||
static buildError(error, file, sourceMap, requestShortener) {
|
||||
// Handling error which should have line, col, filename and message
|
||||
if (error.line) {
|
||||
const original = sourceMap && sourceMap.originalPositionFor({
|
||||
line: error.line,
|
||||
@@ -101,258 +102,408 @@ class TerserPlugin {
|
||||
return new Error(`${file} from Terser\n${error.message}`);
|
||||
}
|
||||
|
||||
static buildWarning(warning, file, sourceMap, requestShortener, warningsFilter) {
|
||||
let warningMessage = warning;
|
||||
let locationMessage = '';
|
||||
let source = null;
|
||||
|
||||
if (sourceMap) {
|
||||
const match = warningRegex.exec(warning);
|
||||
|
||||
if (match) {
|
||||
const line = +match[1];
|
||||
const column = +match[2];
|
||||
const original = sourceMap.originalPositionFor({
|
||||
line,
|
||||
column
|
||||
});
|
||||
|
||||
if (original && original.source && original.source !== file && requestShortener) {
|
||||
({
|
||||
source
|
||||
} = original);
|
||||
warningMessage = `${warningMessage.replace(warningRegex, '')}`;
|
||||
locationMessage = `[${requestShortener.shorten(original.source)}:${original.line},${original.column}]`;
|
||||
}
|
||||
}
|
||||
} // Todo change order in next major release
|
||||
|
||||
|
||||
if (warningsFilter && !warningsFilter(warning, source, file)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return `Terser Plugin: ${warningMessage}${locationMessage}`;
|
||||
}
|
||||
|
||||
static removeQueryString(filename) {
|
||||
let targetFilename = filename;
|
||||
const queryStringIdx = targetFilename.indexOf('?');
|
||||
|
||||
if (queryStringIdx >= 0) {
|
||||
targetFilename = targetFilename.substr(0, queryStringIdx);
|
||||
}
|
||||
|
||||
return targetFilename;
|
||||
}
|
||||
|
||||
static hasAsset(commentFilename, assets) {
|
||||
const assetFilenames = Object.keys(assets).map(assetFilename => TerserPlugin.removeQueryString(assetFilename));
|
||||
return assetFilenames.includes(TerserPlugin.removeQueryString(commentFilename));
|
||||
}
|
||||
|
||||
static isWebpack4() {
|
||||
return _webpack.version[0] === '4';
|
||||
}
|
||||
|
||||
*taskGenerator(compiler, compilation, allExtractedComments, file) {
|
||||
let inputSourceMap;
|
||||
const asset = compilation.assets[file];
|
||||
|
||||
try {
|
||||
let input;
|
||||
|
||||
if (this.options.sourceMap && asset.sourceAndMap) {
|
||||
const {
|
||||
source,
|
||||
map
|
||||
} = asset.sourceAndMap();
|
||||
input = source;
|
||||
|
||||
if (TerserPlugin.isSourceMap(map)) {
|
||||
inputSourceMap = map;
|
||||
} else {
|
||||
inputSourceMap = map;
|
||||
compilation.warnings.push(new Error(`${file} contains invalid source map`));
|
||||
}
|
||||
} else {
|
||||
input = asset.source();
|
||||
inputSourceMap = null;
|
||||
} // Handling comment extraction
|
||||
static getAvailableNumberOfCores(parallel) {
|
||||
// In some cases cpus() returns undefined
|
||||
// https://github.com/nodejs/node/issues/19022
|
||||
const cpus = _os.default.cpus() || {
|
||||
length: 1
|
||||
};
|
||||
return parallel === true ? cpus.length - 1 : Math.min(Number(parallel) || 0, cpus.length - 1);
|
||||
} // eslint-disable-next-line consistent-return
|
||||
|
||||
|
||||
let commentsFilename = false;
|
||||
static getAsset(compilation, name) {
|
||||
// New API
|
||||
if (compilation.getAsset) {
|
||||
return compilation.getAsset(name);
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
|
||||
if (this.options.extractComments) {
|
||||
commentsFilename = this.options.extractComments.filename || '[file].LICENSE.txt[query]';
|
||||
|
||||
if (TerserPlugin.isWebpack4()) {
|
||||
// Todo remove this in next major release
|
||||
if (typeof commentsFilename === 'function') {
|
||||
commentsFilename = commentsFilename.bind(null, file);
|
||||
}
|
||||
}
|
||||
if (compilation.assets[name]) {
|
||||
return {
|
||||
name,
|
||||
source: compilation.assets[name],
|
||||
info: {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let query = '';
|
||||
let filename = file;
|
||||
const querySplit = filename.indexOf('?');
|
||||
static emitAsset(compilation, name, source, assetInfo) {
|
||||
// New API
|
||||
if (compilation.emitAsset) {
|
||||
compilation.emitAsset(name, source, assetInfo);
|
||||
} // eslint-disable-next-line no-param-reassign
|
||||
|
||||
if (querySplit >= 0) {
|
||||
query = filename.substr(querySplit);
|
||||
filename = filename.substr(0, querySplit);
|
||||
}
|
||||
|
||||
const lastSlashIndex = filename.lastIndexOf('/');
|
||||
const basename = lastSlashIndex === -1 ? filename : filename.substr(lastSlashIndex + 1);
|
||||
const data = {
|
||||
filename,
|
||||
basename,
|
||||
query
|
||||
};
|
||||
commentsFilename = compilation.getPath(commentsFilename, data);
|
||||
compilation.assets[name] = source;
|
||||
}
|
||||
|
||||
static updateAsset(compilation, name, newSource, assetInfo) {
|
||||
// New API
|
||||
if (compilation.updateAsset) {
|
||||
compilation.updateAsset(name, newSource, assetInfo);
|
||||
} // eslint-disable-next-line no-param-reassign
|
||||
|
||||
|
||||
compilation.assets[name] = newSource;
|
||||
}
|
||||
|
||||
async optimize(compiler, compilation, assets, CacheEngine, weakCache) {
|
||||
let assetNames;
|
||||
|
||||
if (TerserPlugin.isWebpack4()) {
|
||||
assetNames = [].concat(Array.from(compilation.additionalChunkAssets || [])).concat( // In webpack@4 it is `chunks`
|
||||
Array.from(assets).reduce((acc, chunk) => acc.concat(Array.from(chunk.files || [])), [])).concat(Object.keys(compilation.assets)).filter((assetName, index, existingAssets) => existingAssets.indexOf(assetName) === index).filter(assetName => _webpack.ModuleFilenameHelpers.matchObject.bind( // eslint-disable-next-line no-undefined
|
||||
undefined, this.options)(assetName));
|
||||
} else {
|
||||
assetNames = Object.keys(assets).filter(assetName => _webpack.ModuleFilenameHelpers.matchObject.bind( // eslint-disable-next-line no-undefined
|
||||
undefined, this.options)(assetName));
|
||||
}
|
||||
|
||||
if (assetNames.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const availableNumberOfCores = TerserPlugin.getAvailableNumberOfCores(this.options.parallel);
|
||||
let concurrency = Infinity;
|
||||
let worker;
|
||||
|
||||
if (availableNumberOfCores > 0) {
|
||||
// Do not create unnecessary workers when the number of files is less than the available cores, it saves memory
|
||||
const numWorkers = Math.min(assetNames.length, availableNumberOfCores);
|
||||
concurrency = numWorkers;
|
||||
worker = new _jestWorker.default(require.resolve('./minify'), {
|
||||
numWorkers
|
||||
}); // https://github.com/facebook/jest/issues/8872#issuecomment-524822081
|
||||
|
||||
const workerStdout = worker.getStdout();
|
||||
|
||||
if (workerStdout) {
|
||||
workerStdout.on('data', chunk => {
|
||||
return process.stdout.write(chunk);
|
||||
});
|
||||
}
|
||||
|
||||
if (commentsFilename && TerserPlugin.hasAsset(commentsFilename, compilation.assets)) {
|
||||
// Todo make error and stop uglifing in next major release
|
||||
compilation.warnings.push(new Error(`The comment file "${TerserPlugin.removeQueryString(commentsFilename)}" conflicts with an existing asset, this may lead to code corruption, please use a different name`));
|
||||
const workerStderr = worker.getStderr();
|
||||
|
||||
if (workerStderr) {
|
||||
workerStderr.on('data', chunk => {
|
||||
return process.stderr.write(chunk);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const callback = taskResult => {
|
||||
let {
|
||||
code
|
||||
} = taskResult;
|
||||
const limit = (0, _pLimit.default)(concurrency);
|
||||
const cache = new CacheEngine(compilation, {
|
||||
cache: this.options.cache
|
||||
}, weakCache);
|
||||
const allExtractedComments = new Map();
|
||||
const scheduledTasks = [];
|
||||
|
||||
for (const name of assetNames) {
|
||||
scheduledTasks.push(limit(async () => {
|
||||
const {
|
||||
error,
|
||||
map,
|
||||
warnings
|
||||
} = taskResult;
|
||||
const {
|
||||
extractedComments
|
||||
} = taskResult;
|
||||
let sourceMap = null;
|
||||
info,
|
||||
source: inputSource
|
||||
} = TerserPlugin.getAsset(compilation, name); // Skip double minimize assets from child compilation
|
||||
|
||||
if (error || warnings && warnings.length > 0) {
|
||||
sourceMap = TerserPlugin.buildSourceMap(inputSourceMap);
|
||||
} // Handling results
|
||||
// Error case: add errors, and go to next file
|
||||
|
||||
|
||||
if (error) {
|
||||
compilation.errors.push(TerserPlugin.buildError(error, file, sourceMap, new _RequestShortener.default(compiler.context)));
|
||||
if (info.minimized) {
|
||||
return;
|
||||
}
|
||||
|
||||
const hasExtractedComments = commentsFilename && extractedComments && extractedComments.length > 0;
|
||||
const hasBannerForExtractedComments = hasExtractedComments && this.options.extractComments.banner !== false;
|
||||
let outputSource;
|
||||
let shebang;
|
||||
let input;
|
||||
let inputSourceMap; // TODO refactor after drop webpack@4, webpack@5 always has `sourceAndMap` on sources
|
||||
|
||||
if (hasExtractedComments && hasBannerForExtractedComments && code.startsWith('#!')) {
|
||||
const firstNewlinePosition = code.indexOf('\n');
|
||||
shebang = code.substring(0, firstNewlinePosition);
|
||||
code = code.substring(firstNewlinePosition + 1);
|
||||
}
|
||||
if (this.options.sourceMap && inputSource.sourceAndMap) {
|
||||
const {
|
||||
source,
|
||||
map
|
||||
} = inputSource.sourceAndMap();
|
||||
input = source;
|
||||
|
||||
if (map) {
|
||||
outputSource = new _webpackSources.SourceMapSource(code, file, map, input, inputSourceMap, true);
|
||||
} else {
|
||||
outputSource = new _webpackSources.RawSource(code);
|
||||
} // Write extracted comments to commentsFilename
|
||||
|
||||
|
||||
if (hasExtractedComments) {
|
||||
if (!allExtractedComments[commentsFilename]) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
allExtractedComments[commentsFilename] = [];
|
||||
} // eslint-disable-next-line no-param-reassign
|
||||
|
||||
|
||||
allExtractedComments[commentsFilename] = allExtractedComments[commentsFilename].concat(extractedComments); // Add a banner to the original file
|
||||
|
||||
if (hasBannerForExtractedComments) {
|
||||
let banner = this.options.extractComments.banner || `For license information please see ${_path.default.relative(_path.default.dirname(file), commentsFilename).replace(/\\/g, '/')}`;
|
||||
|
||||
if (typeof banner === 'function') {
|
||||
banner = banner(commentsFilename);
|
||||
}
|
||||
|
||||
if (banner) {
|
||||
outputSource = new _webpackSources.ConcatSource(shebang ? `${shebang}\n` : '', `/*! ${banner} */\n`, outputSource);
|
||||
if (map) {
|
||||
if (TerserPlugin.isSourceMap(map)) {
|
||||
inputSourceMap = map;
|
||||
} else {
|
||||
inputSourceMap = map;
|
||||
compilation.warnings.push(new Error(`${name} contains invalid source map`));
|
||||
}
|
||||
}
|
||||
} // Updating assets
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
} else {
|
||||
input = inputSource.source();
|
||||
inputSourceMap = null;
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(input)) {
|
||||
input = input.toString();
|
||||
}
|
||||
|
||||
compilation.assets[file] = outputSource; // Handling warnings
|
||||
const cacheData = {
|
||||
name,
|
||||
inputSource
|
||||
};
|
||||
|
||||
if (warnings && warnings.length > 0) {
|
||||
warnings.forEach(warning => {
|
||||
const builtWarning = TerserPlugin.buildWarning(warning, file, sourceMap, new _RequestShortener.default(compiler.context), this.options.warningsFilter);
|
||||
if (TerserPlugin.isWebpack4()) {
|
||||
if (this.options.cache) {
|
||||
const {
|
||||
outputOptions: {
|
||||
hashSalt,
|
||||
hashDigest,
|
||||
hashDigestLength,
|
||||
hashFunction
|
||||
}
|
||||
} = compilation;
|
||||
|
||||
if (builtWarning) {
|
||||
compilation.warnings.push(builtWarning);
|
||||
const hash = _webpack.util.createHash(hashFunction);
|
||||
|
||||
if (hashSalt) {
|
||||
hash.update(hashSalt);
|
||||
}
|
||||
|
||||
hash.update(input);
|
||||
const digest = hash.digest(hashDigest);
|
||||
cacheData.input = input;
|
||||
cacheData.inputSourceMap = inputSourceMap;
|
||||
cacheData.cacheKeys = this.options.cacheKeys({
|
||||
terser: _package.default.version,
|
||||
// eslint-disable-next-line global-require
|
||||
'terser-webpack-plugin': require('../package.json').version,
|
||||
'terser-webpack-plugin-options': this.options,
|
||||
name,
|
||||
contentHash: digest.substr(0, hashDigestLength)
|
||||
}, name);
|
||||
}
|
||||
}
|
||||
|
||||
let output = await cache.get(cacheData, {
|
||||
RawSource,
|
||||
ConcatSource,
|
||||
SourceMapSource
|
||||
});
|
||||
|
||||
if (!output) {
|
||||
const minimizerOptions = {
|
||||
name,
|
||||
input,
|
||||
inputSourceMap,
|
||||
minify: this.options.minify,
|
||||
minimizerOptions: this.options.terserOptions,
|
||||
extractComments: this.options.extractComments
|
||||
};
|
||||
|
||||
if (/\.mjs(\?.*)?$/i.test(name)) {
|
||||
this.options.terserOptions.module = true;
|
||||
}
|
||||
|
||||
try {
|
||||
output = await (worker ? worker.transform((0, _serializeJavascript.default)(minimizerOptions)) : (0, _minify.minify)(minimizerOptions));
|
||||
} catch (error) {
|
||||
compilation.errors.push(TerserPlugin.buildError(error, name, inputSourceMap && TerserPlugin.isSourceMap(inputSourceMap) ? new _sourceMap.SourceMapConsumer(inputSourceMap) : null, new _RequestShortener.default(compiler.context)));
|
||||
return;
|
||||
}
|
||||
|
||||
let shebang;
|
||||
|
||||
if (this.options.extractComments.banner !== false && output.extractedComments && output.extractedComments.length > 0 && output.code.startsWith('#!')) {
|
||||
const firstNewlinePosition = output.code.indexOf('\n');
|
||||
shebang = output.code.substring(0, firstNewlinePosition);
|
||||
output.code = output.code.substring(firstNewlinePosition + 1);
|
||||
}
|
||||
|
||||
if (output.map) {
|
||||
output.source = new SourceMapSource(output.code, name, output.map, input, inputSourceMap, true);
|
||||
} else {
|
||||
output.source = new RawSource(output.code);
|
||||
}
|
||||
|
||||
let commentsFilename;
|
||||
|
||||
if (output.extractedComments && output.extractedComments.length > 0) {
|
||||
commentsFilename = this.options.extractComments.filename || '[file].LICENSE.txt[query]';
|
||||
let query = '';
|
||||
let filename = name;
|
||||
const querySplit = filename.indexOf('?');
|
||||
|
||||
if (querySplit >= 0) {
|
||||
query = filename.substr(querySplit);
|
||||
filename = filename.substr(0, querySplit);
|
||||
}
|
||||
|
||||
const lastSlashIndex = filename.lastIndexOf('/');
|
||||
const basename = lastSlashIndex === -1 ? filename : filename.substr(lastSlashIndex + 1);
|
||||
const data = {
|
||||
filename,
|
||||
basename,
|
||||
query
|
||||
};
|
||||
commentsFilename = compilation.getPath(commentsFilename, data);
|
||||
output.commentsFilename = commentsFilename;
|
||||
let banner; // Add a banner to the original file
|
||||
|
||||
if (this.options.extractComments.banner !== false) {
|
||||
banner = this.options.extractComments.banner || `For license information please see ${_path.default.relative(_path.default.dirname(name), commentsFilename).replace(/\\/g, '/')}`;
|
||||
|
||||
if (typeof banner === 'function') {
|
||||
banner = banner(commentsFilename);
|
||||
}
|
||||
|
||||
if (banner) {
|
||||
output.source = new ConcatSource(shebang ? `${shebang}\n` : '', `/*! ${banner} */\n`, output.source);
|
||||
output.banner = banner;
|
||||
output.shebang = shebang;
|
||||
}
|
||||
}
|
||||
|
||||
const extractedCommentsString = output.extractedComments.sort().join('\n\n');
|
||||
output.extractedCommentsSource = new RawSource(`${extractedCommentsString}\n`);
|
||||
}
|
||||
|
||||
await cache.store({ ...output,
|
||||
...cacheData
|
||||
});
|
||||
} // TODO `...` required only for webpack@4
|
||||
|
||||
|
||||
const newInfo = { ...info,
|
||||
minimized: true
|
||||
};
|
||||
const {
|
||||
source,
|
||||
extractedCommentsSource
|
||||
} = output; // Write extracted comments to commentsFilename
|
||||
|
||||
if (extractedCommentsSource) {
|
||||
const {
|
||||
commentsFilename
|
||||
} = output; // TODO `...` required only for webpack@4
|
||||
|
||||
newInfo.related = {
|
||||
license: commentsFilename,
|
||||
...info.related
|
||||
};
|
||||
allExtractedComments.set(name, {
|
||||
extractedCommentsSource,
|
||||
commentsFilename
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const task = {
|
||||
asset,
|
||||
file,
|
||||
input,
|
||||
inputSourceMap,
|
||||
TerserPlugin.updateAsset(compilation, name, source, newInfo);
|
||||
}));
|
||||
}
|
||||
|
||||
await Promise.all(scheduledTasks);
|
||||
|
||||
if (worker) {
|
||||
await worker.end();
|
||||
}
|
||||
|
||||
await Array.from(allExtractedComments).sort().reduce(async (previousPromise, [from, value]) => {
|
||||
const previous = await previousPromise;
|
||||
const {
|
||||
commentsFilename,
|
||||
extractComments: this.options.extractComments,
|
||||
terserOptions: this.options.terserOptions,
|
||||
minify: this.options.minify,
|
||||
callback
|
||||
};
|
||||
extractedCommentsSource
|
||||
} = value;
|
||||
|
||||
if (TerserPlugin.isWebpack4()) {
|
||||
if (previous && previous.commentsFilename === commentsFilename) {
|
||||
const {
|
||||
outputOptions: {
|
||||
hashSalt,
|
||||
hashDigest,
|
||||
hashDigestLength,
|
||||
hashFunction
|
||||
from: previousFrom,
|
||||
source: prevSource
|
||||
} = previous;
|
||||
const mergedName = `${previousFrom}|${from}`;
|
||||
const cacheData = {
|
||||
target: 'comments'
|
||||
};
|
||||
|
||||
if (TerserPlugin.isWebpack4()) {
|
||||
const {
|
||||
outputOptions: {
|
||||
hashSalt,
|
||||
hashDigest,
|
||||
hashDigestLength,
|
||||
hashFunction
|
||||
}
|
||||
} = compilation;
|
||||
|
||||
const previousHash = _webpack.util.createHash(hashFunction);
|
||||
|
||||
const hash = _webpack.util.createHash(hashFunction);
|
||||
|
||||
if (hashSalt) {
|
||||
previousHash.update(hashSalt);
|
||||
hash.update(hashSalt);
|
||||
}
|
||||
} = compilation;
|
||||
|
||||
const hash = _webpack.util.createHash(hashFunction);
|
||||
|
||||
if (hashSalt) {
|
||||
hash.update(hashSalt);
|
||||
}
|
||||
|
||||
hash.update(input);
|
||||
const digest = hash.digest(hashDigest);
|
||||
|
||||
if (this.options.cache) {
|
||||
const defaultCacheKeys = {
|
||||
terser: _package.default.version,
|
||||
// eslint-disable-next-line global-require
|
||||
'terser-webpack-plugin': require('../package.json').version,
|
||||
'terser-webpack-plugin-options': this.options,
|
||||
nodeVersion: process.version,
|
||||
filename: file,
|
||||
previousHash.update(prevSource.source());
|
||||
hash.update(extractedCommentsSource.source());
|
||||
const previousDigest = previousHash.digest(hashDigest);
|
||||
const digest = hash.digest(hashDigest);
|
||||
cacheData.cacheKeys = {
|
||||
mergedName,
|
||||
previousContentHash: previousDigest.substr(0, hashDigestLength),
|
||||
contentHash: digest.substr(0, hashDigestLength)
|
||||
};
|
||||
task.cacheKeys = this.options.cacheKeys(defaultCacheKeys, file);
|
||||
cacheData.inputSource = extractedCommentsSource;
|
||||
} else {
|
||||
const mergedInputSource = [prevSource, extractedCommentsSource];
|
||||
cacheData.name = `${commentsFilename}|${mergedName}`;
|
||||
cacheData.inputSource = mergedInputSource;
|
||||
}
|
||||
} else {
|
||||
task.cacheKeys = {
|
||||
terser: _package.default.version,
|
||||
// eslint-disable-next-line global-require
|
||||
'terser-webpack-plugin': require('../package.json').version,
|
||||
'terser-webpack-plugin-options': this.options
|
||||
|
||||
let output = await cache.get(cacheData, {
|
||||
ConcatSource
|
||||
});
|
||||
|
||||
if (!output) {
|
||||
output = new ConcatSource(Array.from(new Set([...prevSource.source().split('\n\n'), ...extractedCommentsSource.source().split('\n\n')])).join('\n\n'));
|
||||
await cache.store({ ...cacheData,
|
||||
output
|
||||
});
|
||||
}
|
||||
|
||||
TerserPlugin.updateAsset(compilation, commentsFilename, output);
|
||||
return {
|
||||
commentsFilename,
|
||||
from: mergedName,
|
||||
source: output
|
||||
};
|
||||
}
|
||||
|
||||
yield task;
|
||||
} catch (error) {
|
||||
compilation.errors.push(TerserPlugin.buildError(error, file, TerserPlugin.buildSourceMap(inputSourceMap), new _RequestShortener.default(compiler.context)));
|
||||
const existingAsset = TerserPlugin.getAsset(compilation, commentsFilename);
|
||||
|
||||
if (existingAsset) {
|
||||
return {
|
||||
commentsFilename,
|
||||
from: commentsFilename,
|
||||
source: existingAsset.source
|
||||
};
|
||||
}
|
||||
|
||||
TerserPlugin.emitAsset(compilation, commentsFilename, extractedCommentsSource);
|
||||
return {
|
||||
commentsFilename,
|
||||
from,
|
||||
source: extractedCommentsSource
|
||||
};
|
||||
}, Promise.resolve());
|
||||
}
|
||||
|
||||
static getEcmaVersion(environment) {
|
||||
// ES 6th
|
||||
if (environment.arrowFunction || environment.const || environment.destructuring || environment.forOf || environment.module) {
|
||||
return 2015;
|
||||
} // ES 11th
|
||||
|
||||
|
||||
if (environment.bigIntLiteral || environment.dynamicImport) {
|
||||
return 2020;
|
||||
}
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
@@ -361,73 +512,33 @@ class TerserPlugin {
|
||||
output,
|
||||
plugins
|
||||
} = compiler.options;
|
||||
this.options.sourceMap = typeof this.options.sourceMap === 'undefined' ? devtool && !devtool.includes('eval') && !devtool.includes('cheap') && (devtool.includes('source-map') || // Todo remove when `webpack@5` support will be dropped
|
||||
this.options.sourceMap = typeof this.options.sourceMap === 'undefined' ? devtool && !devtool.includes('eval') && !devtool.includes('cheap') && (devtool.includes('source-map') || // Todo remove when `webpack@4` support will be dropped
|
||||
devtool.includes('sourcemap')) || plugins && plugins.some(plugin => plugin instanceof _webpack.SourceMapDevToolPlugin && plugin.options && plugin.options.columns) : Boolean(this.options.sourceMap);
|
||||
|
||||
if (typeof this.options.terserOptions.module === 'undefined' && typeof output.module !== 'undefined') {
|
||||
this.options.terserOptions.module = output.module;
|
||||
}
|
||||
|
||||
if (typeof this.options.terserOptions.ecma === 'undefined' && typeof output.ecmaVersion !== 'undefined') {
|
||||
this.options.terserOptions.ecma = output.ecmaVersion;
|
||||
if (typeof this.options.terserOptions.ecma === 'undefined') {
|
||||
this.options.terserOptions.ecma = TerserPlugin.getEcmaVersion(output.environment || {});
|
||||
}
|
||||
|
||||
const optimizeFn = async (compilation, chunks) => {
|
||||
const matchObject = _webpack.ModuleFilenameHelpers.matchObject.bind( // eslint-disable-next-line no-undefined
|
||||
undefined, this.options);
|
||||
|
||||
const files = [].concat(Array.from(compilation.additionalChunkAssets || [])).concat(Array.from(chunks).filter(chunk => this.options.chunkFilter && this.options.chunkFilter(chunk)).reduce((acc, chunk) => acc.concat(Array.from(chunk.files || [])), [])).filter(file => matchObject(file));
|
||||
|
||||
if (files.length === 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const CacheEngine = TerserPlugin.isWebpack4() ? // eslint-disable-next-line global-require
|
||||
require('./Webpack4Cache').default : // eslint-disable-next-line global-require
|
||||
require('./Webpack5Cache').default;
|
||||
const allExtractedComments = {};
|
||||
const taskGenerator = this.taskGenerator.bind(this, compiler, compilation, allExtractedComments);
|
||||
const taskRunner = new _TaskRunner.default({
|
||||
taskGenerator,
|
||||
files,
|
||||
cache: new CacheEngine(compiler, compilation, this.options),
|
||||
parallel: this.options.parallel
|
||||
});
|
||||
await taskRunner.run();
|
||||
await taskRunner.exit();
|
||||
Object.keys(allExtractedComments).forEach(commentsFilename => {
|
||||
const extractedComments = new Set([...allExtractedComments[commentsFilename].sort()]); // eslint-disable-next-line no-param-reassign
|
||||
|
||||
compilation.assets[commentsFilename] = new _webpackSources.RawSource(`${Array.from(extractedComments).join('\n\n')}\n`);
|
||||
});
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
const plugin = {
|
||||
name: this.constructor.name
|
||||
};
|
||||
compiler.hooks.compilation.tap(plugin, compilation => {
|
||||
const pluginName = this.constructor.name;
|
||||
const weakCache = TerserPlugin.isWebpack4() && (this.options.cache === true || typeof this.options.cache === 'string') ? new WeakMap() : // eslint-disable-next-line no-undefined
|
||||
undefined;
|
||||
compiler.hooks.compilation.tap(pluginName, compilation => {
|
||||
if (this.options.sourceMap) {
|
||||
compilation.hooks.buildModule.tap(plugin, moduleArg => {
|
||||
compilation.hooks.buildModule.tap(pluginName, moduleArg => {
|
||||
// to get detailed location info about errors
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
moduleArg.useSourceMap = true;
|
||||
});
|
||||
}
|
||||
|
||||
if (!TerserPlugin.isWebpack4()) {
|
||||
const hooks = _webpack.javascript.JavascriptModulesPlugin.getCompilationHooks(compilation);
|
||||
if (TerserPlugin.isWebpack4()) {
|
||||
// eslint-disable-next-line global-require
|
||||
const CacheEngine = require('./Webpack4Cache').default;
|
||||
|
||||
const data = (0, _serializeJavascript.default)({
|
||||
terser: _package.default.version,
|
||||
terserOptions: this.options.terserOptions
|
||||
});
|
||||
hooks.chunkHash.tap(plugin, (chunk, hash) => {
|
||||
hash.update('TerserPlugin');
|
||||
hash.update(data);
|
||||
});
|
||||
} else {
|
||||
// Todo remove after drop `webpack@4` compatibility
|
||||
const {
|
||||
mainTemplate,
|
||||
chunkTemplate
|
||||
@@ -438,14 +549,42 @@ class TerserPlugin {
|
||||
}); // Regenerate `contenthash` for minified assets
|
||||
|
||||
for (const template of [mainTemplate, chunkTemplate]) {
|
||||
template.hooks.hashForChunk.tap(plugin, hash => {
|
||||
template.hooks.hashForChunk.tap(pluginName, hash => {
|
||||
hash.update('TerserPlugin');
|
||||
hash.update(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
compilation.hooks.optimizeChunkAssets.tapPromise(plugin, optimizeFn.bind(this, compilation));
|
||||
compilation.hooks.optimizeChunkAssets.tapPromise(pluginName, assets => this.optimize(compiler, compilation, assets, CacheEngine, weakCache));
|
||||
} else {
|
||||
// eslint-disable-next-line global-require
|
||||
const CacheEngine = require('./Webpack5Cache').default; // eslint-disable-next-line global-require
|
||||
|
||||
|
||||
const Compilation = require('webpack/lib/Compilation');
|
||||
|
||||
const hooks = _webpack.javascript.JavascriptModulesPlugin.getCompilationHooks(compilation);
|
||||
|
||||
const data = (0, _serializeJavascript.default)({
|
||||
terser: _package.default.version,
|
||||
terserOptions: this.options.terserOptions
|
||||
});
|
||||
hooks.chunkHash.tap(pluginName, (chunk, hash) => {
|
||||
hash.update('TerserPlugin');
|
||||
hash.update(data);
|
||||
});
|
||||
compilation.hooks.processAssets.tapPromise({
|
||||
name: pluginName,
|
||||
stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE
|
||||
}, assets => this.optimize(compiler, compilation, assets, CacheEngine));
|
||||
compilation.hooks.statsPrinter.tap(pluginName, stats => {
|
||||
stats.hooks.print.for('asset.info.minimized').tap('terser-webpack-plugin', (minimized, {
|
||||
green,
|
||||
formatFlag
|
||||
}) => // eslint-disable-next-line no-undefined
|
||||
minimized ? green(formatFlag('minimized')) : undefined);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+35
-34
@@ -6,7 +6,6 @@ const {
|
||||
|
||||
const buildTerserOptions = ({
|
||||
ecma,
|
||||
warnings,
|
||||
parse = {},
|
||||
compress = {},
|
||||
mangle,
|
||||
@@ -23,8 +22,6 @@ const buildTerserOptions = ({
|
||||
/* eslint-enable camelcase */
|
||||
safari10
|
||||
} = {}) => ({
|
||||
ecma,
|
||||
warnings,
|
||||
parse: { ...parse
|
||||
},
|
||||
compress: typeof compress === 'boolean' ? compress : { ...compress
|
||||
@@ -36,15 +33,16 @@ const buildTerserOptions = ({
|
||||
beautify: false,
|
||||
...output
|
||||
},
|
||||
module,
|
||||
// Ignoring sourceMap from options
|
||||
sourceMap: null,
|
||||
toplevel,
|
||||
nameCache,
|
||||
ie8,
|
||||
ecma,
|
||||
keep_classnames,
|
||||
keep_fnames,
|
||||
safari10
|
||||
ie8,
|
||||
module,
|
||||
nameCache,
|
||||
safari10,
|
||||
toplevel
|
||||
});
|
||||
|
||||
function isObject(value) {
|
||||
@@ -52,13 +50,12 @@ function isObject(value) {
|
||||
return value != null && (type === 'object' || type === 'function');
|
||||
}
|
||||
|
||||
const buildComments = (options, terserOptions, extractedComments) => {
|
||||
const buildComments = (extractComments, terserOptions, extractedComments) => {
|
||||
const condition = {};
|
||||
const commentsOpts = terserOptions.output.comments;
|
||||
const {
|
||||
extractComments
|
||||
} = options;
|
||||
condition.preserve = typeof commentsOpts !== 'undefined' ? commentsOpts : false;
|
||||
comments
|
||||
} = terserOptions.output;
|
||||
condition.preserve = typeof comments !== 'undefined' ? comments : false;
|
||||
|
||||
if (typeof extractComments === 'boolean' && extractComments) {
|
||||
condition.extract = 'some';
|
||||
@@ -71,7 +68,7 @@ const buildComments = (options, terserOptions, extractedComments) => {
|
||||
} else {
|
||||
// No extract
|
||||
// Preserve using "commentsOpts" or "some"
|
||||
condition.preserve = typeof commentsOpts !== 'undefined' ? commentsOpts : 'some';
|
||||
condition.preserve = typeof comments !== 'undefined' ? comments : 'some';
|
||||
condition.extract = false;
|
||||
} // Ensure that both conditions are functions
|
||||
|
||||
@@ -133,22 +130,23 @@ const buildComments = (options, terserOptions, extractedComments) => {
|
||||
};
|
||||
};
|
||||
|
||||
const minify = options => {
|
||||
async function minify(options) {
|
||||
const {
|
||||
file,
|
||||
name,
|
||||
input,
|
||||
inputSourceMap,
|
||||
minify: minifyFn
|
||||
minify: minifyFn,
|
||||
minimizerOptions
|
||||
} = options;
|
||||
|
||||
if (minifyFn) {
|
||||
return minifyFn({
|
||||
[file]: input
|
||||
}, inputSourceMap);
|
||||
[name]: input
|
||||
}, inputSourceMap, minimizerOptions);
|
||||
} // Copy terser options
|
||||
|
||||
|
||||
const terserOptions = buildTerserOptions(options.terserOptions); // Let terser generate a SourceMap
|
||||
const terserOptions = buildTerserOptions(minimizerOptions); // Let terser generate a SourceMap
|
||||
|
||||
if (inputSourceMap) {
|
||||
terserOptions.sourceMap = {
|
||||
@@ -157,22 +155,25 @@ const minify = options => {
|
||||
}
|
||||
|
||||
const extractedComments = [];
|
||||
terserOptions.output.comments = buildComments(options, terserOptions, extractedComments);
|
||||
const {
|
||||
error,
|
||||
map,
|
||||
code,
|
||||
warnings
|
||||
} = terserMinify({
|
||||
[file]: input
|
||||
extractComments
|
||||
} = options;
|
||||
terserOptions.output.comments = buildComments(extractComments, terserOptions, extractedComments);
|
||||
const result = await terserMinify({
|
||||
[name]: input
|
||||
}, terserOptions);
|
||||
return {
|
||||
error,
|
||||
map,
|
||||
code,
|
||||
warnings,
|
||||
return { ...result,
|
||||
extractedComments
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = minify;
|
||||
function transform(options) {
|
||||
// 'use strict' => this === undefined (Clean Scope)
|
||||
// Safer for possible security issues, albeit not critical at all here
|
||||
// eslint-disable-next-line no-new-func, no-param-reassign
|
||||
options = new Function('exports', 'require', 'module', '__filename', '__dirname', `'use strict'\nreturn ${options}`)(exports, require, module, __filename, __dirname);
|
||||
return minify(options);
|
||||
}
|
||||
|
||||
module.exports.minify = minify;
|
||||
module.exports.transform = transform;
|
||||
+45
-48
@@ -1,73 +1,68 @@
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"definitions": {
|
||||
"file-conditions": {
|
||||
"Rule": {
|
||||
"description": "Filtering rule as regex or string.",
|
||||
"anyOf": [
|
||||
{
|
||||
"instanceof": "RegExp"
|
||||
"instanceof": "RegExp",
|
||||
"tsType": "RegExp"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Rules": {
|
||||
"description": "Filtering rules.",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"description": "A rule condition.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Rule"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/Rule"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"title": "TerserPluginOptions",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"test": {
|
||||
"anyOf": [
|
||||
"description": "Include all modules that pass test assertion.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/file-conditions"
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/file-conditions"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "array"
|
||||
"$ref": "#/definitions/Rules"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": {
|
||||
"anyOf": [
|
||||
"description": "Include all modules matching any of these conditions.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/file-conditions"
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/file-conditions"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "array"
|
||||
"$ref": "#/definitions/Rules"
|
||||
}
|
||||
]
|
||||
},
|
||||
"exclude": {
|
||||
"anyOf": [
|
||||
"description": "Exclude all modules matching any of these conditions.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/file-conditions"
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/file-conditions"
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "array"
|
||||
"$ref": "#/definitions/Rules"
|
||||
}
|
||||
]
|
||||
},
|
||||
"chunkFilter": {
|
||||
"instanceof": "Function"
|
||||
},
|
||||
"cache": {
|
||||
"description": "Enable file caching. Ignored in webpack 5, for webpack 5 please use https://webpack.js.org/configuration/other-options/#cache.",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
@@ -78,9 +73,11 @@
|
||||
]
|
||||
},
|
||||
"cacheKeys": {
|
||||
"description": "Allows you to override default cache keys. Ignored in webpack 5, for webpack 5 please use https://webpack.js.org/configuration/other-options/#cache.",
|
||||
"instanceof": "Function"
|
||||
},
|
||||
"parallel": {
|
||||
"description": "Use multi-process parallel running to improve the build speed.",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
@@ -91,16 +88,20 @@
|
||||
]
|
||||
},
|
||||
"sourceMap": {
|
||||
"description": "Enables/Disables generation of source maps.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"minify": {
|
||||
"description": "Allows you to override default minify function.",
|
||||
"instanceof": "Function"
|
||||
},
|
||||
"terserOptions": {
|
||||
"description": "Options for `terser`.",
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
"extractComments": {
|
||||
"description": "Whether comments shall be extracted to a separate file.",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
@@ -160,10 +161,6 @@
|
||||
"type": "object"
|
||||
}
|
||||
]
|
||||
},
|
||||
"warningsFilter": {
|
||||
"instanceof": "Function"
|
||||
}
|
||||
},
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
../acorn/bin/acorn
|
||||
+1
@@ -0,0 +1 @@
|
||||
../terser/bin/terser
|
||||
+798
@@ -0,0 +1,798 @@
|
||||
## 8.7.1 (2021-04-26)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Stop handling `"use strict"` directives in ECMAScript versions before 5.
|
||||
|
||||
Fix an issue where duplicate quoted export names in `export *` syntax were incorrectly checked.
|
||||
|
||||
Add missing type for `tokTypes`.
|
||||
|
||||
## 8.7.0 (2021-12-27)
|
||||
|
||||
### New features
|
||||
|
||||
Support quoted export names.
|
||||
|
||||
Upgrade to Unicode 14.
|
||||
|
||||
Add support for Unicode 13 properties in regular expressions.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Use a loop to find line breaks, because the existing regexp search would overrun the end of the searched range and waste a lot of time in minified code.
|
||||
|
||||
## 8.6.0 (2021-11-18)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a bug where an object literal with multiple `__proto__` properties would incorrectly be accepted if a later property value held an assigment.
|
||||
|
||||
### New features
|
||||
|
||||
Support class private fields with the `in` operator.
|
||||
|
||||
## 8.5.0 (2021-09-06)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Improve context-dependent tokenization in a number of corner cases.
|
||||
|
||||
Fix location tracking after a 0x2028 or 0x2029 character in a string literal (which before did not increase the line number).
|
||||
|
||||
Fix an issue where arrow function bodies in for loop context would inappropriately consume `in` operators.
|
||||
|
||||
Fix wrong end locations stored on SequenceExpression nodes.
|
||||
|
||||
Implement restriction that `for`/`of` loop LHS can't start with `let`.
|
||||
|
||||
### New features
|
||||
|
||||
Add support for ES2022 class static blocks.
|
||||
|
||||
Allow multiple input files to be passed to the CLI tool.
|
||||
|
||||
## 8.4.1 (2021-06-24)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a bug where `allowAwaitOutsideFunction` would allow `await` in class field initializers, and setting `ecmaVersion` to 13 or higher would allow top-level await in non-module sources.
|
||||
|
||||
## 8.4.0 (2021-06-11)
|
||||
|
||||
### New features
|
||||
|
||||
A new option, `allowSuperOutsideMethod`, can be used to suppress the error when `super` is used in the wrong context.
|
||||
|
||||
## 8.3.0 (2021-05-31)
|
||||
|
||||
### New features
|
||||
|
||||
Default `allowAwaitOutsideFunction` to true for ECMAScript 2022 an higher.
|
||||
|
||||
Add support for the `d` ([indices](https://github.com/tc39/proposal-regexp-match-indices)) regexp flag.
|
||||
|
||||
## 8.2.4 (2021-05-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix spec conformity in corner case 'for await (async of ...)'.
|
||||
|
||||
## 8.2.3 (2021-05-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix an issue where the library couldn't parse 'for (async of ...)'.
|
||||
|
||||
Fix a bug in UTF-16 decoding that would read characters incorrectly in some circumstances.
|
||||
|
||||
## 8.2.2 (2021-04-29)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a bug where a class field initialized to an async arrow function wouldn't allow await inside it. Same issue existed for generator arrow functions with yield.
|
||||
|
||||
## 8.2.1 (2021-04-24)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a regression introduced in 8.2.0 where static or async class methods with keyword names fail to parse.
|
||||
|
||||
## 8.2.0 (2021-04-24)
|
||||
|
||||
### New features
|
||||
|
||||
Add support for ES2022 class fields and private methods.
|
||||
|
||||
## 8.1.1 (2021-04-12)
|
||||
|
||||
### Various
|
||||
|
||||
Stop shipping source maps in the NPM package.
|
||||
|
||||
## 8.1.0 (2021-03-09)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a spurious error in nested destructuring arrays.
|
||||
|
||||
### New features
|
||||
|
||||
Expose `allowAwaitOutsideFunction` in CLI interface.
|
||||
|
||||
Make `allowImportExportAnywhere` also apply to `import.meta`.
|
||||
|
||||
## 8.0.5 (2021-01-25)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Adjust package.json to work with Node 12.16.0 and 13.0-13.6.
|
||||
|
||||
## 8.0.4 (2020-10-05)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Make `await x ** y` an error, following the spec.
|
||||
|
||||
Fix potentially exponential regular expression.
|
||||
|
||||
## 8.0.3 (2020-10-02)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a wasteful loop during `Parser` creation when setting `ecmaVersion` to `"latest"`.
|
||||
|
||||
## 8.0.2 (2020-09-30)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Make the TypeScript types reflect the current allowed values for `ecmaVersion`.
|
||||
|
||||
Fix another regexp/division tokenizer issue.
|
||||
|
||||
## 8.0.1 (2020-08-12)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Provide the correct value in the `version` export.
|
||||
|
||||
## 8.0.0 (2020-08-12)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Disallow expressions like `(a = b) = c`.
|
||||
|
||||
Make non-octal escape sequences a syntax error in strict mode.
|
||||
|
||||
### New features
|
||||
|
||||
The package can now be loaded directly as an ECMAScript module in node 13+.
|
||||
|
||||
Update to the set of Unicode properties from ES2021.
|
||||
|
||||
### Breaking changes
|
||||
|
||||
The `ecmaVersion` option is now required. For the moment, omitting it will still work with a warning, but that will change in a future release.
|
||||
|
||||
Some changes to method signatures that may be used by plugins.
|
||||
|
||||
## 7.4.0 (2020-08-03)
|
||||
|
||||
### New features
|
||||
|
||||
Add support for logical assignment operators.
|
||||
|
||||
Add support for numeric separators.
|
||||
|
||||
## 7.3.1 (2020-06-11)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Make the string in the `version` export match the actual library version.
|
||||
|
||||
## 7.3.0 (2020-06-11)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a bug that caused parsing of object patterns with a property named `set` that had a default value to fail.
|
||||
|
||||
### New features
|
||||
|
||||
Add support for optional chaining (`?.`).
|
||||
|
||||
## 7.2.0 (2020-05-09)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix precedence issue in parsing of async arrow functions.
|
||||
|
||||
### New features
|
||||
|
||||
Add support for nullish coalescing.
|
||||
|
||||
Add support for `import.meta`.
|
||||
|
||||
Support `export * as ...` syntax.
|
||||
|
||||
Upgrade to Unicode 13.
|
||||
|
||||
## 6.4.1 (2020-03-09)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
More carefully check for valid UTF16 surrogate pairs in regexp validator.
|
||||
|
||||
## 7.1.1 (2020-03-01)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Treat `\8` and `\9` as invalid escapes in template strings.
|
||||
|
||||
Allow unicode escapes in property names that are keywords.
|
||||
|
||||
Don't error on an exponential operator expression as argument to `await`.
|
||||
|
||||
More carefully check for valid UTF16 surrogate pairs in regexp validator.
|
||||
|
||||
## 7.1.0 (2019-09-24)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Disallow trailing object literal commas when ecmaVersion is less than 5.
|
||||
|
||||
### New features
|
||||
|
||||
Add a static `acorn` property to the `Parser` class that contains the entire module interface, to allow plugins to access the instance of the library that they are acting on.
|
||||
|
||||
## 7.0.0 (2019-08-13)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
Changes the node format for dynamic imports to use the `ImportExpression` node type, as defined in [ESTree](https://github.com/estree/estree/blob/master/es2020.md#importexpression).
|
||||
|
||||
Makes 10 (ES2019) the default value for the `ecmaVersion` option.
|
||||
|
||||
## 6.3.0 (2019-08-12)
|
||||
|
||||
### New features
|
||||
|
||||
`sourceType: "module"` can now be used even when `ecmaVersion` is less than 6, to parse module-style code that otherwise conforms to an older standard.
|
||||
|
||||
## 6.2.1 (2019-07-21)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix bug causing Acorn to treat some characters as identifier characters that shouldn't be treated as such.
|
||||
|
||||
Fix issue where setting the `allowReserved` option to `"never"` allowed reserved words in some circumstances.
|
||||
|
||||
## 6.2.0 (2019-07-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Improve valid assignment checking in `for`/`in` and `for`/`of` loops.
|
||||
|
||||
Disallow binding `let` in patterns.
|
||||
|
||||
### New features
|
||||
|
||||
Support bigint syntax with `ecmaVersion` >= 11.
|
||||
|
||||
Support dynamic `import` syntax with `ecmaVersion` >= 11.
|
||||
|
||||
Upgrade to Unicode version 12.
|
||||
|
||||
## 6.1.1 (2019-02-27)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix bug that caused parsing default exports of with names to fail.
|
||||
|
||||
## 6.1.0 (2019-02-08)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix scope checking when redefining a `var` as a lexical binding.
|
||||
|
||||
### New features
|
||||
|
||||
Split up `parseSubscripts` to use an internal `parseSubscript` method to make it easier to extend with plugins.
|
||||
|
||||
## 6.0.7 (2019-02-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Check that exported bindings are defined.
|
||||
|
||||
Don't treat `\u180e` as a whitespace character.
|
||||
|
||||
Check for duplicate parameter names in methods.
|
||||
|
||||
Don't allow shorthand properties when they are generators or async methods.
|
||||
|
||||
Forbid binding `await` in async arrow function's parameter list.
|
||||
|
||||
## 6.0.6 (2019-01-30)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
The content of class declarations and expressions is now always parsed in strict mode.
|
||||
|
||||
Don't allow `let` or `const` to bind the variable name `let`.
|
||||
|
||||
Treat class declarations as lexical.
|
||||
|
||||
Don't allow a generator function declaration as the sole body of an `if` or `else`.
|
||||
|
||||
Ignore `"use strict"` when after an empty statement.
|
||||
|
||||
Allow string line continuations with special line terminator characters.
|
||||
|
||||
Treat `for` bodies as part of the `for` scope when checking for conflicting bindings.
|
||||
|
||||
Fix bug with parsing `yield` in a `for` loop initializer.
|
||||
|
||||
Implement special cases around scope checking for functions.
|
||||
|
||||
## 6.0.5 (2019-01-02)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix TypeScript type for `Parser.extend` and add `allowAwaitOutsideFunction` to options type.
|
||||
|
||||
Don't treat `let` as a keyword when the next token is `{` on the next line.
|
||||
|
||||
Fix bug that broke checking for parentheses around an object pattern in a destructuring assignment when `preserveParens` was on.
|
||||
|
||||
## 6.0.4 (2018-11-05)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Further improvements to tokenizing regular expressions in corner cases.
|
||||
|
||||
## 6.0.3 (2018-11-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix bug in tokenizing an expression-less return followed by a function followed by a regular expression.
|
||||
|
||||
Remove stray symlink in the package tarball.
|
||||
|
||||
## 6.0.2 (2018-09-26)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix bug where default expressions could fail to parse inside an object destructuring assignment expression.
|
||||
|
||||
## 6.0.1 (2018-09-14)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix wrong value in `version` export.
|
||||
|
||||
## 6.0.0 (2018-09-14)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Better handle variable-redefinition checks for catch bindings and functions directly under if statements.
|
||||
|
||||
Forbid `new.target` in top-level arrow functions.
|
||||
|
||||
Fix issue with parsing a regexp after `yield` in some contexts.
|
||||
|
||||
### New features
|
||||
|
||||
The package now comes with TypeScript definitions.
|
||||
|
||||
### Breaking changes
|
||||
|
||||
The default value of the `ecmaVersion` option is now 9 (2018).
|
||||
|
||||
Plugins work differently, and will have to be rewritten to work with this version.
|
||||
|
||||
The loose parser and walker have been moved into separate packages (`acorn-loose` and `acorn-walk`).
|
||||
|
||||
## 5.7.3 (2018-09-10)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix failure to tokenize regexps after expressions like `x.of`.
|
||||
|
||||
Better error message for unterminated template literals.
|
||||
|
||||
## 5.7.2 (2018-08-24)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Properly handle `allowAwaitOutsideFunction` in for statements.
|
||||
|
||||
Treat function declarations at the top level of modules like let bindings.
|
||||
|
||||
Don't allow async function declarations as the only statement under a label.
|
||||
|
||||
## 5.7.0 (2018-06-15)
|
||||
|
||||
### New features
|
||||
|
||||
Upgraded to Unicode 11.
|
||||
|
||||
## 5.6.0 (2018-05-31)
|
||||
|
||||
### New features
|
||||
|
||||
Allow U+2028 and U+2029 in string when ECMAVersion >= 10.
|
||||
|
||||
Allow binding-less catch statements when ECMAVersion >= 10.
|
||||
|
||||
Add `allowAwaitOutsideFunction` option for parsing top-level `await`.
|
||||
|
||||
## 5.5.3 (2018-03-08)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
A _second_ republish of the code in 5.5.1, this time with yarn, to hopefully get valid timestamps.
|
||||
|
||||
## 5.5.2 (2018-03-08)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
A republish of the code in 5.5.1 in an attempt to solve an issue with the file timestamps in the npm package being 0.
|
||||
|
||||
## 5.5.1 (2018-03-06)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix misleading error message for octal escapes in template strings.
|
||||
|
||||
## 5.5.0 (2018-02-27)
|
||||
|
||||
### New features
|
||||
|
||||
The identifier character categorization is now based on Unicode version 10.
|
||||
|
||||
Acorn will now validate the content of regular expressions, including new ES9 features.
|
||||
|
||||
## 5.4.0 (2018-02-01)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Disallow duplicate or escaped flags on regular expressions.
|
||||
|
||||
Disallow octal escapes in strings in strict mode.
|
||||
|
||||
### New features
|
||||
|
||||
Add support for async iteration.
|
||||
|
||||
Add support for object spread and rest.
|
||||
|
||||
## 5.3.0 (2017-12-28)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix parsing of floating point literals with leading zeroes in loose mode.
|
||||
|
||||
Allow duplicate property names in object patterns.
|
||||
|
||||
Don't allow static class methods named `prototype`.
|
||||
|
||||
Disallow async functions directly under `if` or `else`.
|
||||
|
||||
Parse right-hand-side of `for`/`of` as an assignment expression.
|
||||
|
||||
Stricter parsing of `for`/`in`.
|
||||
|
||||
Don't allow unicode escapes in contextual keywords.
|
||||
|
||||
### New features
|
||||
|
||||
Parsing class members was factored into smaller methods to allow plugins to hook into it.
|
||||
|
||||
## 5.2.1 (2017-10-30)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix a token context corruption bug.
|
||||
|
||||
## 5.2.0 (2017-10-30)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix token context tracking for `class` and `function` in property-name position.
|
||||
|
||||
Make sure `%*` isn't parsed as a valid operator.
|
||||
|
||||
Allow shorthand properties `get` and `set` to be followed by default values.
|
||||
|
||||
Disallow `super` when not in callee or object position.
|
||||
|
||||
### New features
|
||||
|
||||
Support [`directive` property](https://github.com/estree/estree/compare/b3de58c9997504d6fba04b72f76e6dd1619ee4eb...1da8e603237144f44710360f8feb7a9977e905e0) on directive expression statements.
|
||||
|
||||
## 5.1.2 (2017-09-04)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Disable parsing of legacy HTML-style comments in modules.
|
||||
|
||||
Fix parsing of async methods whose names are keywords.
|
||||
|
||||
## 5.1.1 (2017-07-06)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix problem with disambiguating regexp and division after a class.
|
||||
|
||||
## 5.1.0 (2017-07-05)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix tokenizing of regexps in an object-desctructuring `for`/`of` loop and after `yield`.
|
||||
|
||||
Parse zero-prefixed numbers with non-octal digits as decimal.
|
||||
|
||||
Allow object/array patterns in rest parameters.
|
||||
|
||||
Don't error when `yield` is used as a property name.
|
||||
|
||||
Allow `async` as a shorthand object property.
|
||||
|
||||
### New features
|
||||
|
||||
Implement the [template literal revision proposal](https://github.com/tc39/proposal-template-literal-revision) for ES9.
|
||||
|
||||
## 5.0.3 (2017-04-01)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix spurious duplicate variable definition errors for named functions.
|
||||
|
||||
## 5.0.2 (2017-03-30)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
A binary operator after a parenthesized arrow expression is no longer incorrectly treated as an error.
|
||||
|
||||
## 5.0.0 (2017-03-28)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Raise an error for duplicated lexical bindings.
|
||||
|
||||
Fix spurious error when an assignement expression occurred after a spread expression.
|
||||
|
||||
Accept regular expressions after `of` (in `for`/`of`), `yield` (in a generator), and braced arrow functions.
|
||||
|
||||
Allow labels in front or `var` declarations, even in strict mode.
|
||||
|
||||
### Breaking changes
|
||||
|
||||
Parse declarations following `export default` as declaration nodes, not expressions. This means that class and function declarations nodes can now have `null` as their `id`.
|
||||
|
||||
## 4.0.11 (2017-02-07)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Allow all forms of member expressions to be parenthesized as lvalue.
|
||||
|
||||
## 4.0.10 (2017-02-07)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Don't expect semicolons after default-exported functions or classes, even when they are expressions.
|
||||
|
||||
Check for use of `'use strict'` directives in non-simple parameter functions, even when already in strict mode.
|
||||
|
||||
## 4.0.9 (2017-02-06)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix incorrect error raised for parenthesized simple assignment targets, so that `(x) = 1` parses again.
|
||||
|
||||
## 4.0.8 (2017-02-03)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Solve spurious parenthesized pattern errors by temporarily erring on the side of accepting programs that our delayed errors don't handle correctly yet.
|
||||
|
||||
## 4.0.7 (2017-02-02)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Accept invalidly rejected code like `(x).y = 2` again.
|
||||
|
||||
Don't raise an error when a function _inside_ strict code has a non-simple parameter list.
|
||||
|
||||
## 4.0.6 (2017-02-02)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix exponential behavior (manifesting itself as a complete hang for even relatively small source files) introduced by the new 'use strict' check.
|
||||
|
||||
## 4.0.5 (2017-02-02)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Disallow parenthesized pattern expressions.
|
||||
|
||||
Allow keywords as export names.
|
||||
|
||||
Don't allow the `async` keyword to be parenthesized.
|
||||
|
||||
Properly raise an error when a keyword contains a character escape.
|
||||
|
||||
Allow `"use strict"` to appear after other string literal expressions.
|
||||
|
||||
Disallow labeled declarations.
|
||||
|
||||
## 4.0.4 (2016-12-19)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix crash when `export` was followed by a keyword that can't be
|
||||
exported.
|
||||
|
||||
## 4.0.3 (2016-08-16)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Allow regular function declarations inside single-statement `if` branches in loose mode. Forbid them entirely in strict mode.
|
||||
|
||||
Properly parse properties named `async` in ES2017 mode.
|
||||
|
||||
Fix bug where reserved words were broken in ES2017 mode.
|
||||
|
||||
## 4.0.2 (2016-08-11)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Don't ignore period or 'e' characters after octal numbers.
|
||||
|
||||
Fix broken parsing for call expressions in default parameter values of arrow functions.
|
||||
|
||||
## 4.0.1 (2016-08-08)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix false positives in duplicated export name errors.
|
||||
|
||||
## 4.0.0 (2016-08-07)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
The default `ecmaVersion` option value is now 7.
|
||||
|
||||
A number of internal method signatures changed, so plugins might need to be updated.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
The parser now raises errors on duplicated export names.
|
||||
|
||||
`arguments` and `eval` can now be used in shorthand properties.
|
||||
|
||||
Duplicate parameter names in non-simple argument lists now always produce an error.
|
||||
|
||||
### New features
|
||||
|
||||
The `ecmaVersion` option now also accepts year-style version numbers
|
||||
(2015, etc).
|
||||
|
||||
Support for `async`/`await` syntax when `ecmaVersion` is >= 8.
|
||||
|
||||
Support for trailing commas in call expressions when `ecmaVersion` is >= 8.
|
||||
|
||||
## 3.3.0 (2016-07-25)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Fix bug in tokenizing of regexp operator after a function declaration.
|
||||
|
||||
Fix parser crash when parsing an array pattern with a hole.
|
||||
|
||||
### New features
|
||||
|
||||
Implement check against complex argument lists in functions that enable strict mode in ES7.
|
||||
|
||||
## 3.2.0 (2016-06-07)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Improve handling of lack of unicode regexp support in host
|
||||
environment.
|
||||
|
||||
Properly reject shorthand properties whose name is a keyword.
|
||||
|
||||
### New features
|
||||
|
||||
Visitors created with `visit.make` now have their base as _prototype_, rather than copying properties into a fresh object.
|
||||
|
||||
## 3.1.0 (2016-04-18)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
Properly tokenize the division operator directly after a function expression.
|
||||
|
||||
Allow trailing comma in destructuring arrays.
|
||||
|
||||
## 3.0.4 (2016-02-25)
|
||||
|
||||
### Fixes
|
||||
|
||||
Allow update expressions as left-hand-side of the ES7 exponential operator.
|
||||
|
||||
## 3.0.2 (2016-02-10)
|
||||
|
||||
### Fixes
|
||||
|
||||
Fix bug that accidentally made `undefined` a reserved word when parsing ES7.
|
||||
|
||||
## 3.0.0 (2016-02-10)
|
||||
|
||||
### Breaking changes
|
||||
|
||||
The default value of the `ecmaVersion` option is now 6 (used to be 5).
|
||||
|
||||
Support for comprehension syntax (which was dropped from the draft spec) has been removed.
|
||||
|
||||
### Fixes
|
||||
|
||||
`let` and `yield` are now “contextual keywords”, meaning you can mostly use them as identifiers in ES5 non-strict code.
|
||||
|
||||
A parenthesized class or function expression after `export default` is now parsed correctly.
|
||||
|
||||
### New features
|
||||
|
||||
When `ecmaVersion` is set to 7, Acorn will parse the exponentiation operator (`**`).
|
||||
|
||||
The identifier character ranges are now based on Unicode 8.0.0.
|
||||
|
||||
Plugins can now override the `raiseRecoverable` method to override the way non-critical errors are handled.
|
||||
|
||||
## 2.7.0 (2016-01-04)
|
||||
|
||||
### Fixes
|
||||
|
||||
Stop allowing rest parameters in setters.
|
||||
|
||||
Disallow `y` rexexp flag in ES5.
|
||||
|
||||
Disallow `\00` and `\000` escapes in strict mode.
|
||||
|
||||
Raise an error when an import name is a reserved word.
|
||||
|
||||
## 2.6.2 (2015-11-10)
|
||||
|
||||
### Fixes
|
||||
|
||||
Don't crash when no options object is passed.
|
||||
|
||||
## 2.6.0 (2015-11-09)
|
||||
|
||||
### Fixes
|
||||
|
||||
Add `await` as a reserved word in module sources.
|
||||
|
||||
Disallow `yield` in a parameter default value for a generator.
|
||||
|
||||
Forbid using a comma after a rest pattern in an array destructuring.
|
||||
|
||||
### New features
|
||||
|
||||
Support parsing stdin in command-line tool.
|
||||
|
||||
## 2.5.0 (2015-10-27)
|
||||
|
||||
### Fixes
|
||||
|
||||
Fix tokenizer support in the command-line tool.
|
||||
|
||||
Stop allowing `new.target` outside of functions.
|
||||
|
||||
Remove legacy `guard` and `guardedHandler` properties from try nodes.
|
||||
|
||||
Stop allowing multiple `__proto__` properties on an object literal in strict mode.
|
||||
|
||||
Don't allow rest parameters to be non-identifier patterns.
|
||||
|
||||
Check for duplicate paramter names in arrow functions.
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2012-2022 by various contributors (see AUTHORS)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
+273
@@ -0,0 +1,273 @@
|
||||
# Acorn
|
||||
|
||||
A tiny, fast JavaScript parser written in JavaScript.
|
||||
|
||||
## Community
|
||||
|
||||
Acorn is open source software released under an
|
||||
[MIT license](https://github.com/acornjs/acorn/blob/master/acorn/LICENSE).
|
||||
|
||||
You are welcome to
|
||||
[report bugs](https://github.com/acornjs/acorn/issues) or create pull
|
||||
requests on [github](https://github.com/acornjs/acorn). For questions
|
||||
and discussion, please use the
|
||||
[Tern discussion forum](https://discuss.ternjs.net).
|
||||
|
||||
## Installation
|
||||
|
||||
The easiest way to install acorn is from [`npm`](https://www.npmjs.com/):
|
||||
|
||||
```sh
|
||||
npm install acorn
|
||||
```
|
||||
|
||||
Alternately, you can download the source and build acorn yourself:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/acornjs/acorn.git
|
||||
cd acorn
|
||||
npm install
|
||||
```
|
||||
|
||||
## Interface
|
||||
|
||||
**parse**`(input, options)` is the main interface to the library. The
|
||||
`input` parameter is a string, `options` must be an object setting
|
||||
some of the options listed below. The return value will be an abstract
|
||||
syntax tree object as specified by the [ESTree
|
||||
spec](https://github.com/estree/estree).
|
||||
|
||||
```javascript
|
||||
let acorn = require("acorn");
|
||||
console.log(acorn.parse("1 + 1", {ecmaVersion: 2020}));
|
||||
```
|
||||
|
||||
When encountering a syntax error, the parser will raise a
|
||||
`SyntaxError` object with a meaningful message. The error object will
|
||||
have a `pos` property that indicates the string offset at which the
|
||||
error occurred, and a `loc` object that contains a `{line, column}`
|
||||
object referring to that same position.
|
||||
|
||||
Options are provided by in a second argument, which should be an
|
||||
object containing any of these fields (only `ecmaVersion` is
|
||||
required):
|
||||
|
||||
- **ecmaVersion**: Indicates the ECMAScript version to parse. Must be
|
||||
either 3, 5, 6 (or 2015), 7 (2016), 8 (2017), 9 (2018), 10 (2019),
|
||||
11 (2020), 12 (2021), 13 (2022, partial support)
|
||||
or `"latest"` (the latest the library supports). This influences
|
||||
support for strict mode, the set of reserved words, and support
|
||||
for new syntax features.
|
||||
|
||||
**NOTE**: Only 'stage 4' (finalized) ECMAScript features are being
|
||||
implemented by Acorn. Other proposed new features must be
|
||||
implemented through plugins.
|
||||
|
||||
- **sourceType**: Indicate the mode the code should be parsed in. Can be
|
||||
either `"script"` or `"module"`. This influences global strict mode
|
||||
and parsing of `import` and `export` declarations.
|
||||
|
||||
**NOTE**: If set to `"module"`, then static `import` / `export` syntax
|
||||
will be valid, even if `ecmaVersion` is less than 6.
|
||||
|
||||
- **onInsertedSemicolon**: If given a callback, that callback will be
|
||||
called whenever a missing semicolon is inserted by the parser. The
|
||||
callback will be given the character offset of the point where the
|
||||
semicolon is inserted as argument, and if `locations` is on, also a
|
||||
`{line, column}` object representing this position.
|
||||
|
||||
- **onTrailingComma**: Like `onInsertedSemicolon`, but for trailing
|
||||
commas.
|
||||
|
||||
- **allowReserved**: If `false`, using a reserved word will generate
|
||||
an error. Defaults to `true` for `ecmaVersion` 3, `false` for higher
|
||||
versions. When given the value `"never"`, reserved words and
|
||||
keywords can also not be used as property names (as in Internet
|
||||
Explorer's old parser).
|
||||
|
||||
- **allowReturnOutsideFunction**: By default, a return statement at
|
||||
the top level raises an error. Set this to `true` to accept such
|
||||
code.
|
||||
|
||||
- **allowImportExportEverywhere**: By default, `import` and `export`
|
||||
declarations can only appear at a program's top level. Setting this
|
||||
option to `true` allows them anywhere where a statement is allowed,
|
||||
and also allows `import.meta` expressions to appear in scripts
|
||||
(when `sourceType` is not `"module"`).
|
||||
|
||||
- **allowAwaitOutsideFunction**: If `false`, `await` expressions can
|
||||
only appear inside `async` functions. Defaults to `true` for
|
||||
`ecmaVersion` 2022 and later, `false` for lower versions. Setting this option to
|
||||
`true` allows to have top-level `await` expressions. They are
|
||||
still not allowed in non-`async` functions, though.
|
||||
|
||||
- **allowSuperOutsideMethod**: By default, `super` outside a method
|
||||
raises an error. Set this to `true` to accept such code.
|
||||
|
||||
- **allowHashBang**: When this is enabled (off by default), if the
|
||||
code starts with the characters `#!` (as in a shellscript), the
|
||||
first line will be treated as a comment.
|
||||
|
||||
- **locations**: When `true`, each node has a `loc` object attached
|
||||
with `start` and `end` subobjects, each of which contains the
|
||||
one-based line and zero-based column numbers in `{line, column}`
|
||||
form. Default is `false`.
|
||||
|
||||
- **onToken**: If a function is passed for this option, each found
|
||||
token will be passed in same format as tokens returned from
|
||||
`tokenizer().getToken()`.
|
||||
|
||||
If array is passed, each found token is pushed to it.
|
||||
|
||||
Note that you are not allowed to call the parser from the
|
||||
callback—that will corrupt its internal state.
|
||||
|
||||
- **onComment**: If a function is passed for this option, whenever a
|
||||
comment is encountered the function will be called with the
|
||||
following parameters:
|
||||
|
||||
- `block`: `true` if the comment is a block comment, false if it
|
||||
is a line comment.
|
||||
- `text`: The content of the comment.
|
||||
- `start`: Character offset of the start of the comment.
|
||||
- `end`: Character offset of the end of the comment.
|
||||
|
||||
When the `locations` options is on, the `{line, column}` locations
|
||||
of the comment’s start and end are passed as two additional
|
||||
parameters.
|
||||
|
||||
If array is passed for this option, each found comment is pushed
|
||||
to it as object in Esprima format:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"type": "Line" | "Block",
|
||||
"value": "comment text",
|
||||
"start": Number,
|
||||
"end": Number,
|
||||
// If `locations` option is on:
|
||||
"loc": {
|
||||
"start": {line: Number, column: Number}
|
||||
"end": {line: Number, column: Number}
|
||||
},
|
||||
// If `ranges` option is on:
|
||||
"range": [Number, Number]
|
||||
}
|
||||
```
|
||||
|
||||
Note that you are not allowed to call the parser from the
|
||||
callback—that will corrupt its internal state.
|
||||
|
||||
- **ranges**: Nodes have their start and end characters offsets
|
||||
recorded in `start` and `end` properties (directly on the node,
|
||||
rather than the `loc` object, which holds line/column data. To also
|
||||
add a
|
||||
[semi-standardized](https://bugzilla.mozilla.org/show_bug.cgi?id=745678)
|
||||
`range` property holding a `[start, end]` array with the same
|
||||
numbers, set the `ranges` option to `true`.
|
||||
|
||||
- **program**: It is possible to parse multiple files into a single
|
||||
AST by passing the tree produced by parsing the first file as the
|
||||
`program` option in subsequent parses. This will add the toplevel
|
||||
forms of the parsed file to the "Program" (top) node of an existing
|
||||
parse tree.
|
||||
|
||||
- **sourceFile**: When the `locations` option is `true`, you can pass
|
||||
this option to add a `source` attribute in every node’s `loc`
|
||||
object. Note that the contents of this option are not examined or
|
||||
processed in any way; you are free to use whatever format you
|
||||
choose.
|
||||
|
||||
- **directSourceFile**: Like `sourceFile`, but a `sourceFile` property
|
||||
will be added (regardless of the `location` option) directly to the
|
||||
nodes, rather than the `loc` object.
|
||||
|
||||
- **preserveParens**: If this option is `true`, parenthesized expressions
|
||||
are represented by (non-standard) `ParenthesizedExpression` nodes
|
||||
that have a single `expression` property containing the expression
|
||||
inside parentheses.
|
||||
|
||||
**parseExpressionAt**`(input, offset, options)` will parse a single
|
||||
expression in a string, and return its AST. It will not complain if
|
||||
there is more of the string left after the expression.
|
||||
|
||||
**tokenizer**`(input, options)` returns an object with a `getToken`
|
||||
method that can be called repeatedly to get the next token, a `{start,
|
||||
end, type, value}` object (with added `loc` property when the
|
||||
`locations` option is enabled and `range` property when the `ranges`
|
||||
option is enabled). When the token's type is `tokTypes.eof`, you
|
||||
should stop calling the method, since it will keep returning that same
|
||||
token forever.
|
||||
|
||||
In ES6 environment, returned result can be used as any other
|
||||
protocol-compliant iterable:
|
||||
|
||||
```javascript
|
||||
for (let token of acorn.tokenizer(str)) {
|
||||
// iterate over the tokens
|
||||
}
|
||||
|
||||
// transform code to array of tokens:
|
||||
var tokens = [...acorn.tokenizer(str)];
|
||||
```
|
||||
|
||||
**tokTypes** holds an object mapping names to the token type objects
|
||||
that end up in the `type` properties of tokens.
|
||||
|
||||
**getLineInfo**`(input, offset)` can be used to get a `{line,
|
||||
column}` object for a given program string and offset.
|
||||
|
||||
### The `Parser` class
|
||||
|
||||
Instances of the **`Parser`** class contain all the state and logic
|
||||
that drives a parse. It has static methods `parse`,
|
||||
`parseExpressionAt`, and `tokenizer` that match the top-level
|
||||
functions by the same name.
|
||||
|
||||
When extending the parser with plugins, you need to call these methods
|
||||
on the extended version of the class. To extend a parser with plugins,
|
||||
you can use its static `extend` method.
|
||||
|
||||
```javascript
|
||||
var acorn = require("acorn");
|
||||
var jsx = require("acorn-jsx");
|
||||
var JSXParser = acorn.Parser.extend(jsx());
|
||||
JSXParser.parse("foo(<bar/>)", {ecmaVersion: 2020});
|
||||
```
|
||||
|
||||
The `extend` method takes any number of plugin values, and returns a
|
||||
new `Parser` class that includes the extra parser logic provided by
|
||||
the plugins.
|
||||
|
||||
## Command line interface
|
||||
|
||||
The `bin/acorn` utility can be used to parse a file from the command
|
||||
line. It accepts as arguments its input file and the following
|
||||
options:
|
||||
|
||||
- `--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|--ecma10`: Sets the ECMAScript version
|
||||
to parse. Default is version 9.
|
||||
|
||||
- `--module`: Sets the parsing mode to `"module"`. Is set to `"script"` otherwise.
|
||||
|
||||
- `--locations`: Attaches a "loc" object to each node with "start" and
|
||||
"end" subobjects, each of which contains the one-based line and
|
||||
zero-based column numbers in `{line, column}` form.
|
||||
|
||||
- `--allow-hash-bang`: If the code starts with the characters #! (as
|
||||
in a shellscript), the first line will be treated as a comment.
|
||||
|
||||
- `--allow-await-outside-function`: Allows top-level `await` expressions.
|
||||
See the `allowAwaitOutsideFunction` option for more information.
|
||||
|
||||
- `--compact`: No whitespace is used in the AST output.
|
||||
|
||||
- `--silent`: Do not output the AST, just return the exit status.
|
||||
|
||||
- `--help`: Print the usage information and quit.
|
||||
|
||||
The utility spits out the syntax tree as JSON data.
|
||||
|
||||
## Existing plugins
|
||||
|
||||
- [`acorn-jsx`](https://github.com/RReverser/acorn-jsx): Parse [Facebook JSX syntax extensions](https://github.com/facebook/jsx)
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict"
|
||||
|
||||
require("../dist/bin.js")
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
export as namespace acorn
|
||||
export = acorn
|
||||
|
||||
declare namespace acorn {
|
||||
function parse(input: string, options: Options): Node
|
||||
|
||||
function parseExpressionAt(input: string, pos: number, options: Options): Node
|
||||
|
||||
function tokenizer(input: string, options: Options): {
|
||||
getToken(): Token
|
||||
[Symbol.iterator](): Iterator<Token>
|
||||
}
|
||||
|
||||
type ecmaVersion = 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 'latest'
|
||||
|
||||
interface Options {
|
||||
ecmaVersion: ecmaVersion
|
||||
sourceType?: 'script' | 'module'
|
||||
onInsertedSemicolon?: (lastTokEnd: number, lastTokEndLoc?: Position) => void
|
||||
onTrailingComma?: (lastTokEnd: number, lastTokEndLoc?: Position) => void
|
||||
allowReserved?: boolean | 'never'
|
||||
allowReturnOutsideFunction?: boolean
|
||||
allowImportExportEverywhere?: boolean
|
||||
allowAwaitOutsideFunction?: boolean
|
||||
allowSuperOutsideMethod?: boolean
|
||||
allowHashBang?: boolean
|
||||
locations?: boolean
|
||||
onToken?: ((token: Token) => any) | Token[]
|
||||
onComment?: ((
|
||||
isBlock: boolean, text: string, start: number, end: number, startLoc?: Position,
|
||||
endLoc?: Position
|
||||
) => void) | Comment[]
|
||||
ranges?: boolean
|
||||
program?: Node
|
||||
sourceFile?: string
|
||||
directSourceFile?: string
|
||||
preserveParens?: boolean
|
||||
}
|
||||
|
||||
class Parser {
|
||||
// state.js
|
||||
lineStart: number;
|
||||
options: Options;
|
||||
curLine: number;
|
||||
start: number;
|
||||
end: number;
|
||||
input: string;
|
||||
type: TokenType;
|
||||
|
||||
// state.js
|
||||
constructor(options: Options, input: string, startPos?: number)
|
||||
parse(this: Parser): Node
|
||||
|
||||
// tokenize.js
|
||||
next(): void;
|
||||
nextToken(): void;
|
||||
|
||||
// statement.js
|
||||
parseTopLevel(node: Node): Node;
|
||||
|
||||
// node.js
|
||||
finishNode(node: Node, type: string): Node;
|
||||
finishNodeAt(node: Node, type: string, pos: number, loc: Position): Node;
|
||||
|
||||
// location.js
|
||||
raise(pos: number, message: string) : void;
|
||||
raiseRecoverable?(pos: number, message: string) : void;
|
||||
|
||||
// parseutils.js
|
||||
unexpected(pos: number) : void;
|
||||
|
||||
// index.js
|
||||
static acorn: typeof acorn;
|
||||
|
||||
// state.js
|
||||
static parse(this: typeof Parser, input: string, options: Options): Node
|
||||
static parseExpressionAt(this: typeof Parser, input: string, pos: number, options: Options): Node
|
||||
static tokenizer(this: typeof Parser, input: string, options: Options): {
|
||||
getToken(): Token
|
||||
[Symbol.iterator](): Iterator<Token>
|
||||
}
|
||||
static extend(this: typeof Parser, ...plugins: ((BaseParser: typeof Parser) => typeof Parser)[]): typeof Parser
|
||||
}
|
||||
|
||||
interface Position { line: number; column: number; offset: number }
|
||||
|
||||
const defaultOptions: Options
|
||||
|
||||
function getLineInfo(input: string, offset: number): Position
|
||||
|
||||
class SourceLocation {
|
||||
start: Position
|
||||
end: Position
|
||||
source?: string | null
|
||||
constructor(p: Parser, start: Position, end: Position)
|
||||
}
|
||||
|
||||
class Node {
|
||||
type: string
|
||||
start: number
|
||||
end: number
|
||||
loc?: SourceLocation
|
||||
sourceFile?: string
|
||||
range?: [number, number]
|
||||
constructor(parser: Parser, pos: number, loc?: SourceLocation)
|
||||
}
|
||||
|
||||
class TokenType {
|
||||
label: string
|
||||
keyword: string
|
||||
beforeExpr: boolean
|
||||
startsExpr: boolean
|
||||
isLoop: boolean
|
||||
isAssign: boolean
|
||||
prefix: boolean
|
||||
postfix: boolean
|
||||
binop: number
|
||||
updateContext?: (prevType: TokenType) => void
|
||||
constructor(label: string, conf?: any)
|
||||
}
|
||||
|
||||
const tokTypes: {
|
||||
num: TokenType
|
||||
regexp: TokenType
|
||||
string: TokenType
|
||||
name: TokenType
|
||||
privateId: TokenType
|
||||
eof: TokenType
|
||||
bracketL: TokenType
|
||||
bracketR: TokenType
|
||||
braceL: TokenType
|
||||
braceR: TokenType
|
||||
parenL: TokenType
|
||||
parenR: TokenType
|
||||
comma: TokenType
|
||||
semi: TokenType
|
||||
colon: TokenType
|
||||
dot: TokenType
|
||||
question: TokenType
|
||||
questionDot: TokenType
|
||||
arrow: TokenType
|
||||
template: TokenType
|
||||
invalidTemplate: TokenType
|
||||
ellipsis: TokenType
|
||||
backQuote: TokenType
|
||||
dollarBraceL: TokenType
|
||||
eq: TokenType
|
||||
assign: TokenType
|
||||
incDec: TokenType
|
||||
prefix: TokenType
|
||||
logicalOR: TokenType
|
||||
logicalAND: TokenType
|
||||
bitwiseOR: TokenType
|
||||
bitwiseXOR: TokenType
|
||||
bitwiseAND: TokenType
|
||||
equality: TokenType
|
||||
relational: TokenType
|
||||
bitShift: TokenType
|
||||
plusMin: TokenType
|
||||
modulo: TokenType
|
||||
star: TokenType
|
||||
slash: TokenType
|
||||
starstar: TokenType
|
||||
coalesce: TokenType
|
||||
_break: TokenType
|
||||
_case: TokenType
|
||||
_catch: TokenType
|
||||
_continue: TokenType
|
||||
_debugger: TokenType
|
||||
_default: TokenType
|
||||
_do: TokenType
|
||||
_else: TokenType
|
||||
_finally: TokenType
|
||||
_for: TokenType
|
||||
_function: TokenType
|
||||
_if: TokenType
|
||||
_return: TokenType
|
||||
_switch: TokenType
|
||||
_throw: TokenType
|
||||
_try: TokenType
|
||||
_var: TokenType
|
||||
_const: TokenType
|
||||
_while: TokenType
|
||||
_with: TokenType
|
||||
_new: TokenType
|
||||
_this: TokenType
|
||||
_super: TokenType
|
||||
_class: TokenType
|
||||
_extends: TokenType
|
||||
_export: TokenType
|
||||
_import: TokenType
|
||||
_null: TokenType
|
||||
_true: TokenType
|
||||
_false: TokenType
|
||||
_in: TokenType
|
||||
_instanceof: TokenType
|
||||
_typeof: TokenType
|
||||
_void: TokenType
|
||||
_delete: TokenType
|
||||
}
|
||||
|
||||
class TokContext {
|
||||
constructor(token: string, isExpr: boolean, preserveSpace: boolean, override?: (p: Parser) => void)
|
||||
}
|
||||
|
||||
const tokContexts: {
|
||||
b_stat: TokContext
|
||||
b_expr: TokContext
|
||||
b_tmpl: TokContext
|
||||
p_stat: TokContext
|
||||
p_expr: TokContext
|
||||
q_tmpl: TokContext
|
||||
f_expr: TokContext
|
||||
f_stat: TokContext
|
||||
f_expr_gen: TokContext
|
||||
f_gen: TokContext
|
||||
}
|
||||
|
||||
function isIdentifierStart(code: number, astral?: boolean): boolean
|
||||
|
||||
function isIdentifierChar(code: number, astral?: boolean): boolean
|
||||
|
||||
interface AbstractToken {
|
||||
}
|
||||
|
||||
interface Comment extends AbstractToken {
|
||||
type: string
|
||||
value: string
|
||||
start: number
|
||||
end: number
|
||||
loc?: SourceLocation
|
||||
range?: [number, number]
|
||||
}
|
||||
|
||||
class Token {
|
||||
type: TokenType
|
||||
value: any
|
||||
start: number
|
||||
end: number
|
||||
loc?: SourceLocation
|
||||
range?: [number, number]
|
||||
constructor(p: Parser)
|
||||
}
|
||||
|
||||
function isNewLine(code: number): boolean
|
||||
|
||||
const lineBreak: RegExp
|
||||
|
||||
const lineBreakG: RegExp
|
||||
|
||||
const version: string
|
||||
}
|
||||
+5608
File diff suppressed because it is too large
Load Diff
+5577
File diff suppressed because it is too large
Load Diff
+2
@@ -0,0 +1,2 @@
|
||||
import * as acorn from "./acorn";
|
||||
export = acorn;
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var acorn = require('./acorn.js');
|
||||
|
||||
function _interopNamespace(e) {
|
||||
if (e && e.__esModule) return e;
|
||||
var n = Object.create(null);
|
||||
if (e) {
|
||||
Object.keys(e).forEach(function (k) {
|
||||
if (k !== 'default') {
|
||||
var d = Object.getOwnPropertyDescriptor(e, k);
|
||||
Object.defineProperty(n, k, d.get ? d : {
|
||||
enumerable: true,
|
||||
get: function () { return e[k]; }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
n["default"] = e;
|
||||
return Object.freeze(n);
|
||||
}
|
||||
|
||||
var acorn__namespace = /*#__PURE__*/_interopNamespace(acorn);
|
||||
|
||||
var inputFilePaths = [], forceFileName = false, fileMode = false, silent = false, compact = false, tokenize = false;
|
||||
var options = {};
|
||||
|
||||
function help(status) {
|
||||
var print = (status === 0) ? console.log : console.error;
|
||||
print("usage: " + path.basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|...|--ecma2015|--ecma2016|--ecma2017|--ecma2018|...]");
|
||||
print(" [--tokenize] [--locations] [--allow-hash-bang] [--allow-await-outside-function] [--compact] [--silent] [--module] [--help] [--] [<infile>...]");
|
||||
process.exit(status);
|
||||
}
|
||||
|
||||
for (var i = 2; i < process.argv.length; ++i) {
|
||||
var arg = process.argv[i];
|
||||
if (arg[0] !== "-" || arg === "-") { inputFilePaths.push(arg); }
|
||||
else if (arg === "--") {
|
||||
inputFilePaths.push.apply(inputFilePaths, process.argv.slice(i + 1));
|
||||
forceFileName = true;
|
||||
break
|
||||
} else if (arg === "--locations") { options.locations = true; }
|
||||
else if (arg === "--allow-hash-bang") { options.allowHashBang = true; }
|
||||
else if (arg === "--allow-await-outside-function") { options.allowAwaitOutsideFunction = true; }
|
||||
else if (arg === "--silent") { silent = true; }
|
||||
else if (arg === "--compact") { compact = true; }
|
||||
else if (arg === "--help") { help(0); }
|
||||
else if (arg === "--tokenize") { tokenize = true; }
|
||||
else if (arg === "--module") { options.sourceType = "module"; }
|
||||
else {
|
||||
var match = arg.match(/^--ecma(\d+)$/);
|
||||
if (match)
|
||||
{ options.ecmaVersion = +match[1]; }
|
||||
else
|
||||
{ help(1); }
|
||||
}
|
||||
}
|
||||
|
||||
function run(codeList) {
|
||||
var result = [], fileIdx = 0;
|
||||
try {
|
||||
codeList.forEach(function (code, idx) {
|
||||
fileIdx = idx;
|
||||
if (!tokenize) {
|
||||
result = acorn__namespace.parse(code, options);
|
||||
options.program = result;
|
||||
} else {
|
||||
var tokenizer = acorn__namespace.tokenizer(code, options), token;
|
||||
do {
|
||||
token = tokenizer.getToken();
|
||||
result.push(token);
|
||||
} while (token.type !== acorn__namespace.tokTypes.eof)
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(fileMode ? e.message.replace(/\(\d+:\d+\)$/, function (m) { return m.slice(0, 1) + inputFilePaths[fileIdx] + " " + m.slice(1); }) : e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
if (!silent) { console.log(JSON.stringify(result, null, compact ? null : 2)); }
|
||||
}
|
||||
|
||||
if (fileMode = inputFilePaths.length && (forceFileName || !inputFilePaths.includes("-") || inputFilePaths.length !== 1)) {
|
||||
run(inputFilePaths.map(function (path) { return fs.readFileSync(path, "utf8"); }));
|
||||
} else {
|
||||
var code = "";
|
||||
process.stdin.resume();
|
||||
process.stdin.on("data", function (chunk) { return code += chunk; });
|
||||
process.stdin.on("end", function () { return run([code]); });
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"acorn@8.7.1",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "acorn@8.7.1",
|
||||
"_id": "acorn@8.7.1",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
|
||||
"_location": "/terser-webpack-plugin/acorn",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "acorn@8.7.1",
|
||||
"name": "acorn",
|
||||
"escapedName": "acorn",
|
||||
"rawSpec": "8.7.1",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "8.7.1"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/terser-webpack-plugin/terser"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
|
||||
"_spec": "8.7.1",
|
||||
"_where": "/home/node/nuxt",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/acornjs/acorn/issues"
|
||||
},
|
||||
"description": "ECMAScript parser",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
},
|
||||
"exports": {
|
||||
".": [
|
||||
{
|
||||
"import": "./dist/acorn.mjs",
|
||||
"require": "./dist/acorn.js",
|
||||
"default": "./dist/acorn.js"
|
||||
},
|
||||
"./dist/acorn.js"
|
||||
],
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"homepage": "https://github.com/acornjs/acorn",
|
||||
"license": "MIT",
|
||||
"main": "dist/acorn.js",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Marijn Haverbeke",
|
||||
"email": "marijnh@gmail.com",
|
||||
"url": "https://marijnhaverbeke.nl"
|
||||
},
|
||||
{
|
||||
"name": "Ingvar Stepanyan",
|
||||
"email": "me@rreverser.com",
|
||||
"url": "https://rreverser.com/"
|
||||
},
|
||||
{
|
||||
"name": "Adrian Heine",
|
||||
"url": "http://adrianheine.de"
|
||||
}
|
||||
],
|
||||
"module": "dist/acorn.mjs",
|
||||
"name": "acorn",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/acornjs/acorn.git"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "cd ..; npm run build:main"
|
||||
},
|
||||
"types": "dist/acorn.d.ts",
|
||||
"version": "8.7.1"
|
||||
}
|
||||
+1
-1
@@ -43,7 +43,7 @@ function getNodeModuleDirectory(directory) {
|
||||
|
||||
module.exports = (options = {}) => {
|
||||
if (env.CACHE_DIR && !['true', 'false', '1', '0'].includes(env.CACHE_DIR)) {
|
||||
return useDirectory(path.join(env.CACHE_DIR, 'find-cache-dir'), options);
|
||||
return useDirectory(path.join(env.CACHE_DIR, options.name), options);
|
||||
}
|
||||
|
||||
let {cwd: directory = cwd()} = options;
|
||||
|
||||
+12
-12
@@ -1,32 +1,32 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"find-cache-dir@3.3.1",
|
||||
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
|
||||
"find-cache-dir@3.3.2",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "find-cache-dir@3.3.1",
|
||||
"_id": "find-cache-dir@3.3.1",
|
||||
"_from": "find-cache-dir@3.3.2",
|
||||
"_id": "find-cache-dir@3.3.2",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
|
||||
"_integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
|
||||
"_location": "/terser-webpack-plugin/find-cache-dir",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "find-cache-dir@3.3.1",
|
||||
"raw": "find-cache-dir@3.3.2",
|
||||
"name": "find-cache-dir",
|
||||
"escapedName": "find-cache-dir",
|
||||
"rawSpec": "3.3.1",
|
||||
"rawSpec": "3.3.2",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "3.3.1"
|
||||
"fetchSpec": "3.3.2"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/terser-webpack-plugin"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
|
||||
"_spec": "3.3.1",
|
||||
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
|
||||
"_resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
|
||||
"_spec": "3.3.2",
|
||||
"_where": "/home/node/nuxt",
|
||||
"bugs": {
|
||||
"url": "https://github.com/avajs/find-cache-dir/issues"
|
||||
},
|
||||
@@ -75,5 +75,5 @@
|
||||
"scripts": {
|
||||
"test": "xo && nyc ava"
|
||||
},
|
||||
"version": "3.3.1"
|
||||
"version": "3.3.2"
|
||||
}
|
||||
|
||||
+4
-5
@@ -1,4 +1,4 @@
|
||||
# find-cache-dir [](https://travis-ci.org/avajs/find-cache-dir) [](https://coveralls.io/github/avajs/find-cache-dir?branch=master)
|
||||
# find-cache-dir [](https://codecov.io/gh/avajs/find-cache-dir/branch/master)
|
||||
|
||||
> Finds the common standard cache directory
|
||||
|
||||
@@ -103,13 +103,12 @@ This is helpful for actually putting actual files in the cache!
|
||||
|
||||
## Adopters
|
||||
|
||||
- [`AVA`](https://ava.li)
|
||||
- [`ava`](https://avajs.dev)
|
||||
- [`nyc`](https://github.com/istanbuljs/nyc)
|
||||
- [`Storybook`](https://storybook.js.org)
|
||||
- [`storybook`](https://github.com/storybookjs/storybook)
|
||||
- [`babel-loader`](https://github.com/babel/babel-loader)
|
||||
- [`eslint-loader`](https://github.com/MoOx/eslint-loader)
|
||||
- [`Phenomic`](https://phenomic.io)
|
||||
- [`javascripthon-loader`](https://github.com/Beg-in/javascripthon-loader)
|
||||
- [More…](https://www.npmjs.com/browse/depended/find-cache-dir)
|
||||
|
||||
---
|
||||
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
declare namespace pLimit {
|
||||
interface Limit {
|
||||
/**
|
||||
The number of promises that are currently running.
|
||||
*/
|
||||
readonly activeCount: number;
|
||||
|
||||
/**
|
||||
The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).
|
||||
*/
|
||||
readonly pendingCount: number;
|
||||
|
||||
/**
|
||||
Discard pending promises that are waiting to run.
|
||||
|
||||
This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.
|
||||
|
||||
Note: This does not cancel promises that are already running.
|
||||
*/
|
||||
clearQueue: () => void;
|
||||
|
||||
/**
|
||||
@param fn - Promise-returning/async function.
|
||||
@param arguments - Any arguments to pass through to `fn`. Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a lot of functions.
|
||||
@returns The promise returned by calling `fn(...arguments)`.
|
||||
*/
|
||||
<Arguments extends unknown[], ReturnType>(
|
||||
fn: (...arguments: Arguments) => PromiseLike<ReturnType> | ReturnType,
|
||||
...arguments: Arguments
|
||||
): Promise<ReturnType>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Run multiple promise-returning & async functions with limited concurrency.
|
||||
|
||||
@param concurrency - Concurrency limit. Minimum: `1`.
|
||||
@returns A `limit` function.
|
||||
*/
|
||||
declare function pLimit(concurrency: number): pLimit.Limit;
|
||||
|
||||
export = pLimit;
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
const Queue = require('yocto-queue');
|
||||
|
||||
const pLimit = concurrency => {
|
||||
if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) {
|
||||
throw new TypeError('Expected `concurrency` to be a number from 1 and up');
|
||||
}
|
||||
|
||||
const queue = new Queue();
|
||||
let activeCount = 0;
|
||||
|
||||
const next = () => {
|
||||
activeCount--;
|
||||
|
||||
if (queue.size > 0) {
|
||||
queue.dequeue()();
|
||||
}
|
||||
};
|
||||
|
||||
const run = async (fn, resolve, ...args) => {
|
||||
activeCount++;
|
||||
|
||||
const result = (async () => fn(...args))();
|
||||
|
||||
resolve(result);
|
||||
|
||||
try {
|
||||
await result;
|
||||
} catch {}
|
||||
|
||||
next();
|
||||
};
|
||||
|
||||
const enqueue = (fn, resolve, ...args) => {
|
||||
queue.enqueue(run.bind(null, fn, resolve, ...args));
|
||||
|
||||
(async () => {
|
||||
// This function needs to wait until the next microtask before comparing
|
||||
// `activeCount` to `concurrency`, because `activeCount` is updated asynchronously
|
||||
// when the run function is dequeued and called. The comparison in the if-statement
|
||||
// needs to happen asynchronously as well to get an up-to-date value for `activeCount`.
|
||||
await Promise.resolve();
|
||||
|
||||
if (activeCount < concurrency && queue.size > 0) {
|
||||
queue.dequeue()();
|
||||
}
|
||||
})();
|
||||
};
|
||||
|
||||
const generator = (fn, ...args) => new Promise(resolve => {
|
||||
enqueue(fn, resolve, ...args);
|
||||
});
|
||||
|
||||
Object.defineProperties(generator, {
|
||||
activeCount: {
|
||||
get: () => activeCount
|
||||
},
|
||||
pendingCount: {
|
||||
get: () => queue.size
|
||||
},
|
||||
clearQueue: {
|
||||
value: () => {
|
||||
queue.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return generator;
|
||||
};
|
||||
|
||||
module.exports = pLimit;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"p-limit@3.1.0",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "p-limit@3.1.0",
|
||||
"_id": "p-limit@3.1.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||
"_location": "/terser-webpack-plugin/p-limit",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "p-limit@3.1.0",
|
||||
"name": "p-limit",
|
||||
"escapedName": "p-limit",
|
||||
"rawSpec": "3.1.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "3.1.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/terser-webpack-plugin"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
"_spec": "3.1.0",
|
||||
"_where": "/home/node/nuxt",
|
||||
"author": {
|
||||
"name": "Sindre Sorhus",
|
||||
"email": "sindresorhus@gmail.com",
|
||||
"url": "https://sindresorhus.com"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/sindresorhus/p-limit/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"yocto-queue": "^0.1.0"
|
||||
},
|
||||
"description": "Run multiple promise-returning & async functions with limited concurrency",
|
||||
"devDependencies": {
|
||||
"ava": "^2.4.0",
|
||||
"delay": "^4.4.0",
|
||||
"in-range": "^2.0.0",
|
||||
"random-int": "^2.0.1",
|
||||
"time-span": "^4.0.0",
|
||||
"tsd": "^0.13.1",
|
||||
"xo": "^0.35.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"funding": "https://github.com/sponsors/sindresorhus",
|
||||
"homepage": "https://github.com/sindresorhus/p-limit#readme",
|
||||
"keywords": [
|
||||
"promise",
|
||||
"limit",
|
||||
"limited",
|
||||
"concurrency",
|
||||
"throttle",
|
||||
"throat",
|
||||
"rate",
|
||||
"batch",
|
||||
"ratelimit",
|
||||
"task",
|
||||
"queue",
|
||||
"async",
|
||||
"await",
|
||||
"promises",
|
||||
"bluebird"
|
||||
],
|
||||
"license": "MIT",
|
||||
"name": "p-limit",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/sindresorhus/p-limit.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "xo && ava && tsd"
|
||||
},
|
||||
"version": "3.1.0"
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
# p-limit
|
||||
|
||||
> Run multiple promise-returning & async functions with limited concurrency
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
$ npm install p-limit
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const pLimit = require('p-limit');
|
||||
|
||||
const limit = pLimit(1);
|
||||
|
||||
const input = [
|
||||
limit(() => fetchSomething('foo')),
|
||||
limit(() => fetchSomething('bar')),
|
||||
limit(() => doSomething())
|
||||
];
|
||||
|
||||
(async () => {
|
||||
// Only one promise is run at once
|
||||
const result = await Promise.all(input);
|
||||
console.log(result);
|
||||
})();
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### pLimit(concurrency)
|
||||
|
||||
Returns a `limit` function.
|
||||
|
||||
#### concurrency
|
||||
|
||||
Type: `number`\
|
||||
Minimum: `1`\
|
||||
Default: `Infinity`
|
||||
|
||||
Concurrency limit.
|
||||
|
||||
### limit(fn, ...args)
|
||||
|
||||
Returns the promise returned by calling `fn(...args)`.
|
||||
|
||||
#### fn
|
||||
|
||||
Type: `Function`
|
||||
|
||||
Promise-returning/async function.
|
||||
|
||||
#### args
|
||||
|
||||
Any arguments to pass through to `fn`.
|
||||
|
||||
Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a *lot* of functions.
|
||||
|
||||
### limit.activeCount
|
||||
|
||||
The number of promises that are currently running.
|
||||
|
||||
### limit.pendingCount
|
||||
|
||||
The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).
|
||||
|
||||
### limit.clearQueue()
|
||||
|
||||
Discard pending promises that are waiting to run.
|
||||
|
||||
This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.
|
||||
|
||||
Note: This does not cancel promises that are already running.
|
||||
|
||||
## FAQ
|
||||
|
||||
### How is this different from the [`p-queue`](https://github.com/sindresorhus/p-queue) package?
|
||||
|
||||
This package is only about limiting the number of concurrent executions, while `p-queue` is a fully featured queue implementation with lots of different options, introspection, and ability to pause the queue.
|
||||
|
||||
## Related
|
||||
|
||||
- [p-queue](https://github.com/sindresorhus/p-queue) - Promise queue with concurrency control
|
||||
- [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
|
||||
- [p-debounce](https://github.com/sindresorhus/p-debounce) - Debounce promise-returning & async functions
|
||||
- [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency
|
||||
- [More…](https://github.com/sindresorhus/promise-fun)
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<b>
|
||||
<a href="https://tidelift.com/subscription/pkg/npm-p-limit?utm_source=npm-p-limit&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
|
||||
</b>
|
||||
<br>
|
||||
<sub>
|
||||
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
|
||||
</sub>
|
||||
</div>
|
||||
Generated
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
export interface Limit {
|
||||
/**
|
||||
@param fn - Promise-returning/async function.
|
||||
@param arguments - Any arguments to pass through to `fn`. Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a lot of functions.
|
||||
@returns The promise returned by calling `fn(...arguments)`.
|
||||
*/
|
||||
<Arguments extends unknown[], ReturnType>(
|
||||
fn: (...arguments: Arguments) => PromiseLike<ReturnType> | ReturnType,
|
||||
...arguments: Arguments
|
||||
): Promise<ReturnType>;
|
||||
|
||||
/**
|
||||
The number of promises that are currently running.
|
||||
*/
|
||||
readonly activeCount: number;
|
||||
|
||||
/**
|
||||
The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).
|
||||
*/
|
||||
readonly pendingCount: number;
|
||||
|
||||
/**
|
||||
Discard pending promises that are waiting to run.
|
||||
|
||||
This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.
|
||||
|
||||
Note: This does not cancel promises that are already running.
|
||||
*/
|
||||
clearQueue(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
Run multiple promise-returning & async functions with limited concurrency.
|
||||
|
||||
@param concurrency - Concurrency limit. Minimum: `1`.
|
||||
@returns A `limit` function.
|
||||
*/
|
||||
export default function pLimit(concurrency: number): Limit;
|
||||
Generated
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
'use strict';
|
||||
const pTry = require('p-try');
|
||||
|
||||
const pLimit = concurrency => {
|
||||
if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) {
|
||||
return Promise.reject(new TypeError('Expected `concurrency` to be a number from 1 and up'));
|
||||
}
|
||||
|
||||
const queue = [];
|
||||
let activeCount = 0;
|
||||
|
||||
const next = () => {
|
||||
activeCount--;
|
||||
|
||||
if (queue.length > 0) {
|
||||
queue.shift()();
|
||||
}
|
||||
};
|
||||
|
||||
const run = (fn, resolve, ...args) => {
|
||||
activeCount++;
|
||||
|
||||
const result = pTry(fn, ...args);
|
||||
|
||||
resolve(result);
|
||||
|
||||
result.then(next, next);
|
||||
};
|
||||
|
||||
const enqueue = (fn, resolve, ...args) => {
|
||||
if (activeCount < concurrency) {
|
||||
run(fn, resolve, ...args);
|
||||
} else {
|
||||
queue.push(run.bind(null, fn, resolve, ...args));
|
||||
}
|
||||
};
|
||||
|
||||
const generator = (fn, ...args) => new Promise(resolve => enqueue(fn, resolve, ...args));
|
||||
Object.defineProperties(generator, {
|
||||
activeCount: {
|
||||
get: () => activeCount
|
||||
},
|
||||
pendingCount: {
|
||||
get: () => queue.length
|
||||
},
|
||||
clearQueue: {
|
||||
value: () => {
|
||||
queue.length = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return generator;
|
||||
};
|
||||
|
||||
module.exports = pLimit;
|
||||
module.exports.default = pLimit;
|
||||
Generated
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
Generated
Vendored
+87
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"p-limit@2.3.0",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "p-limit@2.3.0",
|
||||
"_id": "p-limit@2.3.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"_location": "/terser-webpack-plugin/p-locate/p-limit",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "p-limit@2.3.0",
|
||||
"name": "p-limit",
|
||||
"escapedName": "p-limit",
|
||||
"rawSpec": "2.3.0",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "2.3.0"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/terser-webpack-plugin/p-locate"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"_spec": "2.3.0",
|
||||
"_where": "/home/node/nuxt",
|
||||
"author": {
|
||||
"name": "Sindre Sorhus",
|
||||
"email": "sindresorhus@gmail.com",
|
||||
"url": "sindresorhus.com"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/sindresorhus/p-limit/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"p-try": "^2.0.0"
|
||||
},
|
||||
"description": "Run multiple promise-returning & async functions with limited concurrency",
|
||||
"devDependencies": {
|
||||
"ava": "^1.2.1",
|
||||
"delay": "^4.1.0",
|
||||
"in-range": "^1.0.0",
|
||||
"random-int": "^1.0.0",
|
||||
"time-span": "^2.0.0",
|
||||
"tsd-check": "^0.3.0",
|
||||
"xo": "^0.24.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts"
|
||||
],
|
||||
"funding": "https://github.com/sponsors/sindresorhus",
|
||||
"homepage": "https://github.com/sindresorhus/p-limit#readme",
|
||||
"keywords": [
|
||||
"promise",
|
||||
"limit",
|
||||
"limited",
|
||||
"concurrency",
|
||||
"throttle",
|
||||
"throat",
|
||||
"rate",
|
||||
"batch",
|
||||
"ratelimit",
|
||||
"task",
|
||||
"queue",
|
||||
"async",
|
||||
"await",
|
||||
"promises",
|
||||
"bluebird"
|
||||
],
|
||||
"license": "MIT",
|
||||
"name": "p-limit",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/sindresorhus/p-limit.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "xo && ava && tsd-check"
|
||||
},
|
||||
"version": "2.3.0"
|
||||
}
|
||||
Generated
Vendored
+101
@@ -0,0 +1,101 @@
|
||||
# p-limit [](https://travis-ci.org/sindresorhus/p-limit)
|
||||
|
||||
> Run multiple promise-returning & async functions with limited concurrency
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
$ npm install p-limit
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const pLimit = require('p-limit');
|
||||
|
||||
const limit = pLimit(1);
|
||||
|
||||
const input = [
|
||||
limit(() => fetchSomething('foo')),
|
||||
limit(() => fetchSomething('bar')),
|
||||
limit(() => doSomething())
|
||||
];
|
||||
|
||||
(async () => {
|
||||
// Only one promise is run at once
|
||||
const result = await Promise.all(input);
|
||||
console.log(result);
|
||||
})();
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### pLimit(concurrency)
|
||||
|
||||
Returns a `limit` function.
|
||||
|
||||
#### concurrency
|
||||
|
||||
Type: `number`\
|
||||
Minimum: `1`\
|
||||
Default: `Infinity`
|
||||
|
||||
Concurrency limit.
|
||||
|
||||
### limit(fn, ...args)
|
||||
|
||||
Returns the promise returned by calling `fn(...args)`.
|
||||
|
||||
#### fn
|
||||
|
||||
Type: `Function`
|
||||
|
||||
Promise-returning/async function.
|
||||
|
||||
#### args
|
||||
|
||||
Any arguments to pass through to `fn`.
|
||||
|
||||
Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a *lot* of functions.
|
||||
|
||||
### limit.activeCount
|
||||
|
||||
The number of promises that are currently running.
|
||||
|
||||
### limit.pendingCount
|
||||
|
||||
The number of promises that are waiting to run (i.e. their internal `fn` was not called yet).
|
||||
|
||||
### limit.clearQueue()
|
||||
|
||||
Discard pending promises that are waiting to run.
|
||||
|
||||
This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.
|
||||
|
||||
Note: This does not cancel promises that are already running.
|
||||
|
||||
## FAQ
|
||||
|
||||
### How is this different from the [`p-queue`](https://github.com/sindresorhus/p-queue) package?
|
||||
|
||||
This package is only about limiting the number of concurrent executions, while `p-queue` is a fully featured queue implementation with lots of different options, introspection, and ability to pause the queue.
|
||||
|
||||
## Related
|
||||
|
||||
- [p-queue](https://github.com/sindresorhus/p-queue) - Promise queue with concurrency control
|
||||
- [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
|
||||
- [p-debounce](https://github.com/sindresorhus/p-debounce) - Debounce promise-returning & async functions
|
||||
- [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency
|
||||
- [More…](https://github.com/sindresorhus/promise-fun)
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<b>
|
||||
<a href="https://tidelift.com/subscription/pkg/npm-p-limit?utm_source=npm-p-limit&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
|
||||
</b>
|
||||
<br>
|
||||
<sub>
|
||||
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
|
||||
</sub>
|
||||
</div>
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Copyright JS Foundation and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+290
@@ -0,0 +1,290 @@
|
||||
<div align="center">
|
||||
<a href="http://json-schema.org">
|
||||
<img width="160" height="160"
|
||||
src="https://raw.githubusercontent.com/webpack-contrib/schema-utils/master/.github/assets/logo.png">
|
||||
</a>
|
||||
<a href="https://github.com/webpack/webpack">
|
||||
<img width="200" height="200"
|
||||
src="https://webpack.js.org/assets/icon-square-big.svg">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
[![npm][npm]][npm-url]
|
||||
[![node][node]][node-url]
|
||||
[![deps][deps]][deps-url]
|
||||
[![tests][tests]][tests-url]
|
||||
[![coverage][cover]][cover-url]
|
||||
[![chat][chat]][chat-url]
|
||||
[![size][size]][size-url]
|
||||
|
||||
# schema-utils
|
||||
|
||||
Package for validate options in loaders and plugins.
|
||||
|
||||
## Getting Started
|
||||
|
||||
To begin, you'll need to install `schema-utils`:
|
||||
|
||||
```console
|
||||
npm install schema-utils
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
**schema.json**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"option": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
import schema from "./path/to/schema.json";
|
||||
import { validate } from "schema-utils";
|
||||
|
||||
const options = { option: true };
|
||||
const configuration = { name: "Loader Name/Plugin Name/Name" };
|
||||
|
||||
validate(schema, options, configuration);
|
||||
```
|
||||
|
||||
### `schema`
|
||||
|
||||
Type: `String`
|
||||
|
||||
JSON schema.
|
||||
|
||||
Simple example of schema:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "This is description of option.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
```
|
||||
|
||||
### `options`
|
||||
|
||||
Type: `Object`
|
||||
|
||||
Object with options.
|
||||
|
||||
```js
|
||||
import schema from "./path/to/schema.json";
|
||||
import { validate } from "schema-utils";
|
||||
|
||||
const options = { foo: "bar" };
|
||||
|
||||
validate(schema, { name: 123 }, { name: "MyPlugin" });
|
||||
```
|
||||
|
||||
### `configuration`
|
||||
|
||||
Allow to configure validator.
|
||||
|
||||
There is an alternative method to configure the `name` and`baseDataPath` options via the `title` property in the schema.
|
||||
For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "My Loader options",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "This is description of option.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
```
|
||||
|
||||
The last word used for the `baseDataPath` option, other words used for the `name` option.
|
||||
Based on the example above the `name` option equals `My Loader`, the `baseDataPath` option equals `options`.
|
||||
|
||||
#### `name`
|
||||
|
||||
Type: `Object`
|
||||
Default: `"Object"`
|
||||
|
||||
Allow to setup name in validation errors.
|
||||
|
||||
```js
|
||||
import schema from "./path/to/schema.json";
|
||||
import { validate } from "schema-utils";
|
||||
|
||||
const options = { foo: "bar" };
|
||||
|
||||
validate(schema, options, { name: "MyPlugin" });
|
||||
```
|
||||
|
||||
```shell
|
||||
Invalid configuration object. MyPlugin has been initialised using a configuration object that does not match the API schema.
|
||||
- configuration.optionName should be a integer.
|
||||
```
|
||||
|
||||
#### `baseDataPath`
|
||||
|
||||
Type: `String`
|
||||
Default: `"configuration"`
|
||||
|
||||
Allow to setup base data path in validation errors.
|
||||
|
||||
```js
|
||||
import schema from "./path/to/schema.json";
|
||||
import { validate } from "schema-utils";
|
||||
|
||||
const options = { foo: "bar" };
|
||||
|
||||
validate(schema, options, { name: "MyPlugin", baseDataPath: "options" });
|
||||
```
|
||||
|
||||
```shell
|
||||
Invalid options object. MyPlugin has been initialised using an options object that does not match the API schema.
|
||||
- options.optionName should be a integer.
|
||||
```
|
||||
|
||||
#### `postFormatter`
|
||||
|
||||
Type: `Function`
|
||||
Default: `undefined`
|
||||
|
||||
Allow to reformat errors.
|
||||
|
||||
```js
|
||||
import schema from "./path/to/schema.json";
|
||||
import { validate } from "schema-utils";
|
||||
|
||||
const options = { foo: "bar" };
|
||||
|
||||
validate(schema, options, {
|
||||
name: "MyPlugin",
|
||||
postFormatter: (formattedError, error) => {
|
||||
if (error.keyword === "type") {
|
||||
return `${formattedError}\nAdditional Information.`;
|
||||
}
|
||||
|
||||
return formattedError;
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
```shell
|
||||
Invalid options object. MyPlugin has been initialized using an options object that does not match the API schema.
|
||||
- options.optionName should be a integer.
|
||||
Additional Information.
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
**schema.json**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"test": {
|
||||
"anyOf": [
|
||||
{ "type": "array" },
|
||||
{ "type": "string" },
|
||||
{ "instanceof": "RegExp" }
|
||||
]
|
||||
},
|
||||
"transform": {
|
||||
"instanceof": "Function"
|
||||
},
|
||||
"sourceMap": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
```
|
||||
|
||||
### `Loader`
|
||||
|
||||
```js
|
||||
import { getOptions } from "loader-utils";
|
||||
import { validate } from "schema-utils";
|
||||
|
||||
import schema from "path/to/schema.json";
|
||||
|
||||
function loader(src, map) {
|
||||
const options = getOptions(this);
|
||||
|
||||
validate(schema, options, {
|
||||
name: "Loader Name",
|
||||
baseDataPath: "options",
|
||||
});
|
||||
|
||||
// Code...
|
||||
}
|
||||
|
||||
export default loader;
|
||||
```
|
||||
|
||||
### `Plugin`
|
||||
|
||||
```js
|
||||
import { validate } from "schema-utils";
|
||||
|
||||
import schema from "path/to/schema.json";
|
||||
|
||||
class Plugin {
|
||||
constructor(options) {
|
||||
validate(schema, options, {
|
||||
name: "Plugin Name",
|
||||
baseDataPath: "options",
|
||||
});
|
||||
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
// Code...
|
||||
}
|
||||
}
|
||||
|
||||
export default Plugin;
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Please take a moment to read our contributing guidelines if you haven't yet done so.
|
||||
|
||||
[CONTRIBUTING](./.github/CONTRIBUTING.md)
|
||||
|
||||
## License
|
||||
|
||||
[MIT](./LICENSE)
|
||||
|
||||
[npm]: https://img.shields.io/npm/v/schema-utils.svg
|
||||
[npm-url]: https://npmjs.com/package/schema-utils
|
||||
[node]: https://img.shields.io/node/v/schema-utils.svg
|
||||
[node-url]: https://nodejs.org
|
||||
[deps]: https://david-dm.org/webpack/schema-utils.svg
|
||||
[deps-url]: https://david-dm.org/webpack/schema-utils
|
||||
[tests]: https://github.com/webpack/schema-utils/workflows/schema-utils/badge.svg
|
||||
[tests-url]: https://github.com/webpack/schema-utils/actions
|
||||
[cover]: https://codecov.io/gh/webpack/schema-utils/branch/master/graph/badge.svg
|
||||
[cover-url]: https://codecov.io/gh/webpack/schema-utils
|
||||
[chat]: https://badges.gitter.im/webpack/webpack.svg
|
||||
[chat-url]: https://gitter.im/webpack/webpack
|
||||
[size]: https://packagephobia.com/badge?p=schema-utils
|
||||
[size-url]: https://packagephobia.com/result?p=schema-utils
|
||||
Generated
Vendored
+74
@@ -0,0 +1,74 @@
|
||||
export default ValidationError;
|
||||
export type JSONSchema6 = import("json-schema").JSONSchema6;
|
||||
export type JSONSchema7 = import("json-schema").JSONSchema7;
|
||||
export type Schema = import("./validate").Schema;
|
||||
export type ValidationErrorConfiguration =
|
||||
import("./validate").ValidationErrorConfiguration;
|
||||
export type PostFormatter = import("./validate").PostFormatter;
|
||||
export type SchemaUtilErrorObject = import("./validate").SchemaUtilErrorObject;
|
||||
declare class ValidationError extends Error {
|
||||
/**
|
||||
* @param {Array<SchemaUtilErrorObject>} errors
|
||||
* @param {Schema} schema
|
||||
* @param {ValidationErrorConfiguration} configuration
|
||||
*/
|
||||
constructor(
|
||||
errors: Array<SchemaUtilErrorObject>,
|
||||
schema: Schema,
|
||||
configuration?: ValidationErrorConfiguration
|
||||
);
|
||||
/** @type {Array<SchemaUtilErrorObject>} */
|
||||
errors: Array<SchemaUtilErrorObject>;
|
||||
/** @type {Schema} */
|
||||
schema: Schema;
|
||||
/** @type {string} */
|
||||
headerName: string;
|
||||
/** @type {string} */
|
||||
baseDataPath: string;
|
||||
/** @type {PostFormatter | null} */
|
||||
postFormatter: PostFormatter | null;
|
||||
/**
|
||||
* @param {string} path
|
||||
* @returns {Schema}
|
||||
*/
|
||||
getSchemaPart(path: string): Schema;
|
||||
/**
|
||||
* @param {Schema} schema
|
||||
* @param {boolean} logic
|
||||
* @param {Array<Object>} prevSchemas
|
||||
* @returns {string}
|
||||
*/
|
||||
formatSchema(
|
||||
schema: Schema,
|
||||
logic?: boolean,
|
||||
prevSchemas?: Array<Object>
|
||||
): string;
|
||||
/**
|
||||
* @param {Schema=} schemaPart
|
||||
* @param {(boolean | Array<string>)=} additionalPath
|
||||
* @param {boolean=} needDot
|
||||
* @param {boolean=} logic
|
||||
* @returns {string}
|
||||
*/
|
||||
getSchemaPartText(
|
||||
schemaPart?: Schema | undefined,
|
||||
additionalPath?: (boolean | Array<string>) | undefined,
|
||||
needDot?: boolean | undefined,
|
||||
logic?: boolean | undefined
|
||||
): string;
|
||||
/**
|
||||
* @param {Schema=} schemaPart
|
||||
* @returns {string}
|
||||
*/
|
||||
getSchemaPartDescription(schemaPart?: Schema | undefined): string;
|
||||
/**
|
||||
* @param {SchemaUtilErrorObject} error
|
||||
* @returns {string}
|
||||
*/
|
||||
formatValidationError(error: SchemaUtilErrorObject): string;
|
||||
/**
|
||||
* @param {Array<SchemaUtilErrorObject>} errors
|
||||
* @returns {string}
|
||||
*/
|
||||
formatValidationErrors(errors: Array<SchemaUtilErrorObject>): string;
|
||||
}
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
import { validate } from "./validate";
|
||||
import { ValidationError } from "./validate";
|
||||
export { validate, ValidationError };
|
||||
node_modules/terser-webpack-plugin/node_modules/schema-utils/declarations/keywords/absolutePath.d.ts
Generated
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
export default addAbsolutePathKeyword;
|
||||
export type Ajv = import("ajv").Ajv;
|
||||
export type ValidateFunction = import("ajv").ValidateFunction;
|
||||
export type SchemaUtilErrorObject = import("../validate").SchemaUtilErrorObject;
|
||||
/**
|
||||
*
|
||||
* @param {Ajv} ajv
|
||||
* @returns {Ajv}
|
||||
*/
|
||||
declare function addAbsolutePathKeyword(ajv: Ajv): Ajv;
|
||||
Generated
Vendored
+79
@@ -0,0 +1,79 @@
|
||||
export = Range;
|
||||
/**
|
||||
* @typedef {[number, boolean]} RangeValue
|
||||
*/
|
||||
/**
|
||||
* @callback RangeValueCallback
|
||||
* @param {RangeValue} rangeValue
|
||||
* @returns {boolean}
|
||||
*/
|
||||
declare class Range {
|
||||
/**
|
||||
* @param {"left" | "right"} side
|
||||
* @param {boolean} exclusive
|
||||
* @returns {">" | ">=" | "<" | "<="}
|
||||
*/
|
||||
static getOperator(
|
||||
side: "left" | "right",
|
||||
exclusive: boolean
|
||||
): ">" | ">=" | "<" | "<=";
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @param {boolean} exclusive is range exclusive
|
||||
* @returns {string}
|
||||
*/
|
||||
static formatRight(value: number, logic: boolean, exclusive: boolean): string;
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @param {boolean} exclusive is range exclusive
|
||||
* @returns {string}
|
||||
*/
|
||||
static formatLeft(value: number, logic: boolean, exclusive: boolean): string;
|
||||
/**
|
||||
* @param {number} start left side value
|
||||
* @param {number} end right side value
|
||||
* @param {boolean} startExclusive is range exclusive from left side
|
||||
* @param {boolean} endExclusive is range exclusive from right side
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @returns {string}
|
||||
*/
|
||||
static formatRange(
|
||||
start: number,
|
||||
end: number,
|
||||
startExclusive: boolean,
|
||||
endExclusive: boolean,
|
||||
logic: boolean
|
||||
): string;
|
||||
/**
|
||||
* @param {Array<RangeValue>} values
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @return {RangeValue} computed value and it's exclusive flag
|
||||
*/
|
||||
static getRangeValue(values: Array<RangeValue>, logic: boolean): RangeValue;
|
||||
/** @type {Array<RangeValue>} */
|
||||
_left: Array<RangeValue>;
|
||||
/** @type {Array<RangeValue>} */
|
||||
_right: Array<RangeValue>;
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {boolean=} exclusive
|
||||
*/
|
||||
left(value: number, exclusive?: boolean | undefined): void;
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {boolean=} exclusive
|
||||
*/
|
||||
right(value: number, exclusive?: boolean | undefined): void;
|
||||
/**
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @return {string} "smart" range string representation
|
||||
*/
|
||||
format(logic?: boolean): string;
|
||||
}
|
||||
declare namespace Range {
|
||||
export { RangeValue, RangeValueCallback };
|
||||
}
|
||||
type RangeValue = [number, boolean];
|
||||
type RangeValueCallback = (rangeValue: RangeValue) => boolean;
|
||||
Generated
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
export function stringHints(schema: Schema, logic: boolean): string[];
|
||||
export function numberHints(schema: Schema, logic: boolean): string[];
|
||||
export type Schema = import("../validate").Schema;
|
||||
Generated
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
export type JSONSchema4 = import("json-schema").JSONSchema4;
|
||||
export type JSONSchema6 = import("json-schema").JSONSchema6;
|
||||
export type JSONSchema7 = import("json-schema").JSONSchema7;
|
||||
export type ErrorObject = import("ajv").ErrorObject;
|
||||
export type Extend = {
|
||||
formatMinimum?: number | undefined;
|
||||
formatMaximum?: number | undefined;
|
||||
formatExclusiveMinimum?: boolean | undefined;
|
||||
formatExclusiveMaximum?: boolean | undefined;
|
||||
link?: string | undefined;
|
||||
};
|
||||
export type Schema = (JSONSchema4 | JSONSchema6 | JSONSchema7) & Extend;
|
||||
export type SchemaUtilErrorObject = ErrorObject & {
|
||||
children?: Array<ErrorObject>;
|
||||
};
|
||||
export type PostFormatter = (
|
||||
formattedError: string,
|
||||
error: SchemaUtilErrorObject
|
||||
) => string;
|
||||
export type ValidationErrorConfiguration = {
|
||||
name?: string | undefined;
|
||||
baseDataPath?: string | undefined;
|
||||
postFormatter?: PostFormatter | undefined;
|
||||
};
|
||||
/**
|
||||
* @param {Schema} schema
|
||||
* @param {Array<object> | object} options
|
||||
* @param {ValidationErrorConfiguration=} configuration
|
||||
* @returns {void}
|
||||
*/
|
||||
export function validate(
|
||||
schema: Schema,
|
||||
options: Array<object> | object,
|
||||
configuration?: ValidationErrorConfiguration | undefined
|
||||
): void;
|
||||
import ValidationError from "./ValidationError";
|
||||
export { ValidationError };
|
||||
Generated
Vendored
+1271
File diff suppressed because it is too large
Load Diff
+11
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
validate,
|
||||
ValidationError
|
||||
} = require("./validate");
|
||||
|
||||
module.exports = {
|
||||
validate,
|
||||
ValidationError
|
||||
};
|
||||
Generated
Vendored
+93
@@ -0,0 +1,93 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.default = void 0;
|
||||
|
||||
/** @typedef {import("ajv").Ajv} Ajv */
|
||||
|
||||
/** @typedef {import("ajv").ValidateFunction} ValidateFunction */
|
||||
|
||||
/** @typedef {import("../validate").SchemaUtilErrorObject} SchemaUtilErrorObject */
|
||||
|
||||
/**
|
||||
* @param {string} message
|
||||
* @param {object} schema
|
||||
* @param {string} data
|
||||
* @returns {SchemaUtilErrorObject}
|
||||
*/
|
||||
function errorMessage(message, schema, data) {
|
||||
return {
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line no-undefined
|
||||
dataPath: undefined,
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line no-undefined
|
||||
schemaPath: undefined,
|
||||
keyword: "absolutePath",
|
||||
params: {
|
||||
absolutePath: data
|
||||
},
|
||||
message,
|
||||
parentSchema: schema
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @param {boolean} shouldBeAbsolute
|
||||
* @param {object} schema
|
||||
* @param {string} data
|
||||
* @returns {SchemaUtilErrorObject}
|
||||
*/
|
||||
|
||||
|
||||
function getErrorFor(shouldBeAbsolute, schema, data) {
|
||||
const message = shouldBeAbsolute ? `The provided value ${JSON.stringify(data)} is not an absolute path!` : `A relative path is expected. However, the provided value ${JSON.stringify(data)} is an absolute path!`;
|
||||
return errorMessage(message, schema, data);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {Ajv} ajv
|
||||
* @returns {Ajv}
|
||||
*/
|
||||
|
||||
|
||||
function addAbsolutePathKeyword(ajv) {
|
||||
ajv.addKeyword("absolutePath", {
|
||||
errors: true,
|
||||
type: "string",
|
||||
|
||||
compile(schema, parentSchema) {
|
||||
/** @type {ValidateFunction} */
|
||||
const callback = data => {
|
||||
let passes = true;
|
||||
const isExclamationMarkPresent = data.includes("!");
|
||||
|
||||
if (isExclamationMarkPresent) {
|
||||
callback.errors = [errorMessage(`The provided value ${JSON.stringify(data)} contains exclamation mark (!) which is not allowed because it's reserved for loader syntax.`, parentSchema, data)];
|
||||
passes = false;
|
||||
} // ?:[A-Za-z]:\\ - Windows absolute path
|
||||
// \\\\ - Windows network absolute path
|
||||
// \/ - Unix-like OS absolute path
|
||||
|
||||
|
||||
const isCorrectAbsolutePath = schema === /^(?:[A-Za-z]:(\\|\/)|\\\\|\/)/.test(data);
|
||||
|
||||
if (!isCorrectAbsolutePath) {
|
||||
callback.errors = [getErrorFor(schema, parentSchema, data)];
|
||||
passes = false;
|
||||
}
|
||||
|
||||
return passes;
|
||||
};
|
||||
|
||||
callback.errors = [];
|
||||
return callback;
|
||||
}
|
||||
|
||||
});
|
||||
return ajv;
|
||||
}
|
||||
|
||||
var _default = addAbsolutePathKeyword;
|
||||
exports.default = _default;
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* @typedef {[number, boolean]} RangeValue
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback RangeValueCallback
|
||||
* @param {RangeValue} rangeValue
|
||||
* @returns {boolean}
|
||||
*/
|
||||
class Range {
|
||||
/**
|
||||
* @param {"left" | "right"} side
|
||||
* @param {boolean} exclusive
|
||||
* @returns {">" | ">=" | "<" | "<="}
|
||||
*/
|
||||
static getOperator(side, exclusive) {
|
||||
if (side === "left") {
|
||||
return exclusive ? ">" : ">=";
|
||||
}
|
||||
|
||||
return exclusive ? "<" : "<=";
|
||||
}
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @param {boolean} exclusive is range exclusive
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
|
||||
static formatRight(value, logic, exclusive) {
|
||||
if (logic === false) {
|
||||
return Range.formatLeft(value, !logic, !exclusive);
|
||||
}
|
||||
|
||||
return `should be ${Range.getOperator("right", exclusive)} ${value}`;
|
||||
}
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @param {boolean} exclusive is range exclusive
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
|
||||
static formatLeft(value, logic, exclusive) {
|
||||
if (logic === false) {
|
||||
return Range.formatRight(value, !logic, !exclusive);
|
||||
}
|
||||
|
||||
return `should be ${Range.getOperator("left", exclusive)} ${value}`;
|
||||
}
|
||||
/**
|
||||
* @param {number} start left side value
|
||||
* @param {number} end right side value
|
||||
* @param {boolean} startExclusive is range exclusive from left side
|
||||
* @param {boolean} endExclusive is range exclusive from right side
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
|
||||
static formatRange(start, end, startExclusive, endExclusive, logic) {
|
||||
let result = "should be";
|
||||
result += ` ${Range.getOperator(logic ? "left" : "right", logic ? startExclusive : !startExclusive)} ${start} `;
|
||||
result += logic ? "and" : "or";
|
||||
result += ` ${Range.getOperator(logic ? "right" : "left", logic ? endExclusive : !endExclusive)} ${end}`;
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @param {Array<RangeValue>} values
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @return {RangeValue} computed value and it's exclusive flag
|
||||
*/
|
||||
|
||||
|
||||
static getRangeValue(values, logic) {
|
||||
let minMax = logic ? Infinity : -Infinity;
|
||||
let j = -1;
|
||||
const predicate = logic ?
|
||||
/** @type {RangeValueCallback} */
|
||||
([value]) => value <= minMax :
|
||||
/** @type {RangeValueCallback} */
|
||||
([value]) => value >= minMax;
|
||||
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
if (predicate(values[i])) {
|
||||
[minMax] = values[i];
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (j > -1) {
|
||||
return values[j];
|
||||
}
|
||||
|
||||
return [Infinity, true];
|
||||
}
|
||||
|
||||
constructor() {
|
||||
/** @type {Array<RangeValue>} */
|
||||
this._left = [];
|
||||
/** @type {Array<RangeValue>} */
|
||||
|
||||
this._right = [];
|
||||
}
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {boolean=} exclusive
|
||||
*/
|
||||
|
||||
|
||||
left(value, exclusive = false) {
|
||||
this._left.push([value, exclusive]);
|
||||
}
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {boolean=} exclusive
|
||||
*/
|
||||
|
||||
|
||||
right(value, exclusive = false) {
|
||||
this._right.push([value, exclusive]);
|
||||
}
|
||||
/**
|
||||
* @param {boolean} logic is not logic applied
|
||||
* @return {string} "smart" range string representation
|
||||
*/
|
||||
|
||||
|
||||
format(logic = true) {
|
||||
const [start, leftExclusive] = Range.getRangeValue(this._left, logic);
|
||||
const [end, rightExclusive] = Range.getRangeValue(this._right, !logic);
|
||||
|
||||
if (!Number.isFinite(start) && !Number.isFinite(end)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const realStart = leftExclusive ? start + 1 : start;
|
||||
const realEnd = rightExclusive ? end - 1 : end; // e.g. 5 < x < 7, 5 < x <= 6, 6 <= x <= 6
|
||||
|
||||
if (realStart === realEnd) {
|
||||
return `should be ${logic ? "" : "!"}= ${realStart}`;
|
||||
} // e.g. 4 < x < ∞
|
||||
|
||||
|
||||
if (Number.isFinite(start) && !Number.isFinite(end)) {
|
||||
return Range.formatLeft(start, logic, leftExclusive);
|
||||
} // e.g. ∞ < x < 4
|
||||
|
||||
|
||||
if (!Number.isFinite(start) && Number.isFinite(end)) {
|
||||
return Range.formatRight(end, logic, rightExclusive);
|
||||
}
|
||||
|
||||
return Range.formatRange(start, end, leftExclusive, rightExclusive, logic);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = Range;
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
"use strict";
|
||||
|
||||
const Range = require("./Range");
|
||||
/** @typedef {import("../validate").Schema} Schema */
|
||||
|
||||
/**
|
||||
* @param {Schema} schema
|
||||
* @param {boolean} logic
|
||||
* @return {string[]}
|
||||
*/
|
||||
|
||||
|
||||
module.exports.stringHints = function stringHints(schema, logic) {
|
||||
const hints = [];
|
||||
let type = "string";
|
||||
const currentSchema = { ...schema
|
||||
};
|
||||
|
||||
if (!logic) {
|
||||
const tmpLength = currentSchema.minLength;
|
||||
const tmpFormat = currentSchema.formatMinimum;
|
||||
const tmpExclusive = currentSchema.formatExclusiveMaximum;
|
||||
currentSchema.minLength = currentSchema.maxLength;
|
||||
currentSchema.maxLength = tmpLength;
|
||||
currentSchema.formatMinimum = currentSchema.formatMaximum;
|
||||
currentSchema.formatMaximum = tmpFormat;
|
||||
currentSchema.formatExclusiveMaximum = !currentSchema.formatExclusiveMinimum;
|
||||
currentSchema.formatExclusiveMinimum = !tmpExclusive;
|
||||
}
|
||||
|
||||
if (typeof currentSchema.minLength === "number") {
|
||||
if (currentSchema.minLength === 1) {
|
||||
type = "non-empty string";
|
||||
} else {
|
||||
const length = Math.max(currentSchema.minLength - 1, 0);
|
||||
hints.push(`should be longer than ${length} character${length > 1 ? "s" : ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof currentSchema.maxLength === "number") {
|
||||
if (currentSchema.maxLength === 0) {
|
||||
type = "empty string";
|
||||
} else {
|
||||
const length = currentSchema.maxLength + 1;
|
||||
hints.push(`should be shorter than ${length} character${length > 1 ? "s" : ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSchema.pattern) {
|
||||
hints.push(`should${logic ? "" : " not"} match pattern ${JSON.stringify(currentSchema.pattern)}`);
|
||||
}
|
||||
|
||||
if (currentSchema.format) {
|
||||
hints.push(`should${logic ? "" : " not"} match format ${JSON.stringify(currentSchema.format)}`);
|
||||
}
|
||||
|
||||
if (currentSchema.formatMinimum) {
|
||||
hints.push(`should be ${currentSchema.formatExclusiveMinimum ? ">" : ">="} ${JSON.stringify(currentSchema.formatMinimum)}`);
|
||||
}
|
||||
|
||||
if (currentSchema.formatMaximum) {
|
||||
hints.push(`should be ${currentSchema.formatExclusiveMaximum ? "<" : "<="} ${JSON.stringify(currentSchema.formatMaximum)}`);
|
||||
}
|
||||
|
||||
return [type].concat(hints);
|
||||
};
|
||||
/**
|
||||
* @param {Schema} schema
|
||||
* @param {boolean} logic
|
||||
* @return {string[]}
|
||||
*/
|
||||
|
||||
|
||||
module.exports.numberHints = function numberHints(schema, logic) {
|
||||
const hints = [schema.type === "integer" ? "integer" : "number"];
|
||||
const range = new Range();
|
||||
|
||||
if (typeof schema.minimum === "number") {
|
||||
range.left(schema.minimum);
|
||||
}
|
||||
|
||||
if (typeof schema.exclusiveMinimum === "number") {
|
||||
range.left(schema.exclusiveMinimum, true);
|
||||
}
|
||||
|
||||
if (typeof schema.maximum === "number") {
|
||||
range.right(schema.maximum);
|
||||
}
|
||||
|
||||
if (typeof schema.exclusiveMaximum === "number") {
|
||||
range.right(schema.exclusiveMaximum, true);
|
||||
}
|
||||
|
||||
const rangeFormat = range.format(logic);
|
||||
|
||||
if (rangeFormat) {
|
||||
hints.push(rangeFormat);
|
||||
}
|
||||
|
||||
if (typeof schema.multipleOf === "number") {
|
||||
hints.push(`should${logic ? "" : " not"} be multiple of ${schema.multipleOf}`);
|
||||
}
|
||||
|
||||
return hints;
|
||||
};
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.validate = validate;
|
||||
Object.defineProperty(exports, "ValidationError", {
|
||||
enumerable: true,
|
||||
get: function () {
|
||||
return _ValidationError.default;
|
||||
}
|
||||
});
|
||||
|
||||
var _absolutePath = _interopRequireDefault(require("./keywords/absolutePath"));
|
||||
|
||||
var _ValidationError = _interopRequireDefault(require("./ValidationError"));
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
// Use CommonJS require for ajv libs so TypeScript consumers aren't locked into esModuleInterop (see #110).
|
||||
const Ajv = require("ajv");
|
||||
|
||||
const ajvKeywords = require("ajv-keywords");
|
||||
/** @typedef {import("json-schema").JSONSchema4} JSONSchema4 */
|
||||
|
||||
/** @typedef {import("json-schema").JSONSchema6} JSONSchema6 */
|
||||
|
||||
/** @typedef {import("json-schema").JSONSchema7} JSONSchema7 */
|
||||
|
||||
/** @typedef {import("ajv").ErrorObject} ErrorObject */
|
||||
|
||||
/**
|
||||
* @typedef {Object} Extend
|
||||
* @property {number=} formatMinimum
|
||||
* @property {number=} formatMaximum
|
||||
* @property {boolean=} formatExclusiveMinimum
|
||||
* @property {boolean=} formatExclusiveMaximum
|
||||
* @property {string=} link
|
||||
*/
|
||||
|
||||
/** @typedef {(JSONSchema4 | JSONSchema6 | JSONSchema7) & Extend} Schema */
|
||||
|
||||
/** @typedef {ErrorObject & { children?: Array<ErrorObject>}} SchemaUtilErrorObject */
|
||||
|
||||
/**
|
||||
* @callback PostFormatter
|
||||
* @param {string} formattedError
|
||||
* @param {SchemaUtilErrorObject} error
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ValidationErrorConfiguration
|
||||
* @property {string=} name
|
||||
* @property {string=} baseDataPath
|
||||
* @property {PostFormatter=} postFormatter
|
||||
*/
|
||||
|
||||
|
||||
const ajv = new Ajv({
|
||||
allErrors: true,
|
||||
verbose: true,
|
||||
$data: true
|
||||
});
|
||||
ajvKeywords(ajv, ["instanceof", "formatMinimum", "formatMaximum", "patternRequired"]); // Custom keywords
|
||||
|
||||
(0, _absolutePath.default)(ajv);
|
||||
/**
|
||||
* @param {Schema} schema
|
||||
* @param {Array<object> | object} options
|
||||
* @param {ValidationErrorConfiguration=} configuration
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
function validate(schema, options, configuration) {
|
||||
let errors = [];
|
||||
|
||||
if (Array.isArray(options)) {
|
||||
errors = Array.from(options, nestedOptions => validateObject(schema, nestedOptions));
|
||||
errors.forEach((list, idx) => {
|
||||
const applyPrefix =
|
||||
/**
|
||||
* @param {SchemaUtilErrorObject} error
|
||||
*/
|
||||
error => {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
error.dataPath = `[${idx}]${error.dataPath}`;
|
||||
|
||||
if (error.children) {
|
||||
error.children.forEach(applyPrefix);
|
||||
}
|
||||
};
|
||||
|
||||
list.forEach(applyPrefix);
|
||||
});
|
||||
errors = errors.reduce((arr, items) => {
|
||||
arr.push(...items);
|
||||
return arr;
|
||||
}, []);
|
||||
} else {
|
||||
errors = validateObject(schema, options);
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
throw new _ValidationError.default(errors, schema, configuration);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {Schema} schema
|
||||
* @param {Array<object> | object} options
|
||||
* @returns {Array<SchemaUtilErrorObject>}
|
||||
*/
|
||||
|
||||
|
||||
function validateObject(schema, options) {
|
||||
const compiledSchema = ajv.compile(schema);
|
||||
const valid = compiledSchema(options);
|
||||
if (valid) return [];
|
||||
return compiledSchema.errors ? filterErrors(compiledSchema.errors) : [];
|
||||
}
|
||||
/**
|
||||
* @param {Array<ErrorObject>} errors
|
||||
* @returns {Array<SchemaUtilErrorObject>}
|
||||
*/
|
||||
|
||||
|
||||
function filterErrors(errors) {
|
||||
/** @type {Array<SchemaUtilErrorObject>} */
|
||||
let newErrors = [];
|
||||
|
||||
for (const error of
|
||||
/** @type {Array<SchemaUtilErrorObject>} */
|
||||
errors) {
|
||||
const {
|
||||
dataPath
|
||||
} = error;
|
||||
/** @type {Array<SchemaUtilErrorObject>} */
|
||||
|
||||
let children = [];
|
||||
newErrors = newErrors.filter(oldError => {
|
||||
if (oldError.dataPath.includes(dataPath)) {
|
||||
if (oldError.children) {
|
||||
children = children.concat(oldError.children.slice(0));
|
||||
} // eslint-disable-next-line no-undefined, no-param-reassign
|
||||
|
||||
|
||||
oldError.children = undefined;
|
||||
children.push(oldError);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (children.length) {
|
||||
error.children = children;
|
||||
}
|
||||
|
||||
newErrors.push(error);
|
||||
}
|
||||
|
||||
return newErrors;
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"schema-utils@3.1.1",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "schema-utils@3.1.1",
|
||||
"_id": "schema-utils@3.1.1",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
|
||||
"_location": "/terser-webpack-plugin/schema-utils",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "schema-utils@3.1.1",
|
||||
"name": "schema-utils",
|
||||
"escapedName": "schema-utils",
|
||||
"rawSpec": "3.1.1",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "3.1.1"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/terser-webpack-plugin"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
|
||||
"_spec": "3.1.1",
|
||||
"_where": "/home/node/nuxt",
|
||||
"author": {
|
||||
"name": "webpack Contrib",
|
||||
"url": "https://github.com/webpack-contrib"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/webpack/schema-utils/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.8",
|
||||
"ajv": "^6.12.5",
|
||||
"ajv-keywords": "^3.5.2"
|
||||
},
|
||||
"description": "webpack Validation Utils",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.14.3",
|
||||
"@babel/core": "^7.14.6",
|
||||
"@babel/preset-env": "^7.14.7",
|
||||
"@commitlint/cli": "^12.1.4",
|
||||
"@commitlint/config-conventional": "^12.1.4",
|
||||
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
|
||||
"babel-jest": "^27.0.6",
|
||||
"cross-env": "^7.0.3",
|
||||
"del": "^6.0.0",
|
||||
"del-cli": "^3.0.1",
|
||||
"eslint": "^7.31.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"husky": "^6.0.0",
|
||||
"jest": "^27.0.6",
|
||||
"lint-staged": "^11.0.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^2.3.2",
|
||||
"standard-version": "^9.3.1",
|
||||
"typescript": "^4.3.5",
|
||||
"webpack": "^5.45.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"declarations"
|
||||
],
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
},
|
||||
"homepage": "https://github.com/webpack/schema-utils",
|
||||
"keywords": [
|
||||
"webpack"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"name": "schema-utils",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/webpack/schema-utils.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm-run-all -p \"build:**\"",
|
||||
"build:code": "cross-env NODE_ENV=production babel src -d dist --copy-files",
|
||||
"build:types": "tsc --declaration --emitDeclarationOnly --outDir declarations && prettier \"declarations/**/*.ts\" --write",
|
||||
"clean": "del-cli dist declarations",
|
||||
"commitlint": "commitlint --from=master",
|
||||
"fix": "npm-run-all fix:js fmt",
|
||||
"fix:js": "npm run lint:js -- --fix",
|
||||
"fmt": "npm run fmt:check -- --write",
|
||||
"fmt:check": "prettier \"{**/*,*}.{js,json,md,yml,css,ts}\" --list-different",
|
||||
"lint": "npm-run-all lint:js lint:types fmt:check",
|
||||
"lint:js": "eslint --cache .",
|
||||
"lint:types": "tsc --pretty --noEmit",
|
||||
"prebuild": "npm run clean",
|
||||
"prepare": "npm run build && husky install",
|
||||
"pretest": "npm run lint",
|
||||
"release": "standard-version",
|
||||
"security": "npm audit --production",
|
||||
"start": "npm run build -- -w",
|
||||
"test": "npm run test:coverage",
|
||||
"test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
|
||||
"test:only": "cross-env NODE_ENV=test jest",
|
||||
"test:watch": "npm run test:only -- --watch"
|
||||
},
|
||||
"types": "declarations/index.d.ts",
|
||||
"version": "3.1.1"
|
||||
}
|
||||
+515
@@ -0,0 +1,515 @@
|
||||
# Changelog
|
||||
|
||||
## v5.14.2
|
||||
|
||||
- Security fix for RegExps that should not be evaluated (regexp DDOS)
|
||||
- Source maps improvements (#1211)
|
||||
- Performance improvements in long property access evaluation (#1213)
|
||||
|
||||
## v5.14.1
|
||||
- keep_numbers option added to TypeScript defs (#1208)
|
||||
- Fixed parsing of nested template strings (#1204)
|
||||
|
||||
## v5.14.0
|
||||
- Switched to @jridgewell/source-map for sourcemap generation (#1190, #1181)
|
||||
- Fixed source maps with non-terminated segments (#1106)
|
||||
- Enabled typescript types to be imported from the package (#1194)
|
||||
- Extra DOM props have been added (#1191)
|
||||
- Delete the AST while generating code, as a means to save RAM
|
||||
|
||||
## v5.13.1
|
||||
- Removed self-assignments (`varname=varname`) (closes #1081)
|
||||
- Separated inlining code (for inlining things into references, or removing IIFEs)
|
||||
- Allow multiple identifiers with the same name in `var` destructuring (eg `var { a, a } = x`) (#1176)
|
||||
|
||||
## v5.13.0
|
||||
|
||||
- All calls to eval() were removed (#1171, #1184)
|
||||
- `source-map` was updated to 0.8.0-beta.0 (#1164)
|
||||
- NavigatorUAData was added to domprops to avoid property mangling (#1166)
|
||||
|
||||
## v5.12.1
|
||||
|
||||
- Fixed an issue with function definitions inside blocks (#1155)
|
||||
- Fixed parens of `new` in some situations (closes #1159)
|
||||
|
||||
## v5.12.0
|
||||
|
||||
- `TERSER_DEBUG_DIR` environment variable
|
||||
- @copyright comments are now preserved with the comments="some" option (#1153)
|
||||
|
||||
## v5.11.0
|
||||
|
||||
- Unicode code point escapes (`\u{abcde}`) are not emitted inside RegExp literals anymore (#1147)
|
||||
- acorn is now a regular dependency
|
||||
|
||||
## v5.10.0
|
||||
|
||||
- Massive optimization to max_line_len (#1109)
|
||||
- Basic support for import assertions
|
||||
- Marked ES2022 Object.hasOwn as a pure function
|
||||
- Fix `delete optional?.property`
|
||||
- New CI/CD pipeline with github actions (#1057)
|
||||
- Fix reordering of switch branches (#1092), (#1084)
|
||||
- Fix error when creating a class property called `get`
|
||||
- Acorn dependency is now an optional peerDependency
|
||||
- Fix mangling collision with exported variables (#1072)
|
||||
- Fix an issue with `return someVariable = (async () => { ... })()` (#1073)
|
||||
|
||||
## v5.9.0
|
||||
|
||||
- Collapsing switch cases with the same bodies (even if they're not next to each other) (#1070).
|
||||
- Fix evaluation of optional chain expressions (#1062)
|
||||
- Fix mangling collision in ESM exports (#1063)
|
||||
- Fix issue with mutating function objects after a second pass (#1047)
|
||||
- Fix for inlining object spread `{ ...obj }` (#1071)
|
||||
- Typescript typings fix (#1069)
|
||||
|
||||
## v5.8.0
|
||||
|
||||
- Fixed shadowing variables while moving code in some cases (#1065)
|
||||
- Stop mangling computed & quoted properties when keep_quoted is enabled.
|
||||
- Fix for mangling private getter/setter and .#private access (#1060, #1068)
|
||||
- Array.from has a new optimization when the unsafe option is set (#737)
|
||||
- Mangle/propmangle let you generate your own identifiers through the nth_identifier option (#1061)
|
||||
- More optimizations to switch statements (#1044)
|
||||
|
||||
## v5.7.2
|
||||
|
||||
- Fixed issues with compressing functions defined in `global_defs` option (#1036)
|
||||
- New recipe for using Terser in gulp was added to RECIPES.md (#1035)
|
||||
- Fixed issues with `??` and `?.` (#1045)
|
||||
- Future reserved words such as `package` no longer require you to disable strict mode to be used as names.
|
||||
- Refactored huge compressor file into multiple more focused files.
|
||||
- Avoided unparenthesized `in` operator in some for loops (it breaks parsing because of for..in loops)
|
||||
- Improved documentation (#1021, #1025)
|
||||
- More type definitions (#1021)
|
||||
|
||||
## v5.7.1
|
||||
|
||||
- Avoided collapsing assignments together if it would place a chain assignment on the left hand side, which is invalid syntax (`a?.b = c`)
|
||||
- Removed undefined from object expansions (`{ ...void 0 }` -> `{}`)
|
||||
- Fix crash when checking if something is nullish or undefined (#1009)
|
||||
- Fixed comparison of private class properties (#1015)
|
||||
- Minor performance improvements (#993)
|
||||
- Fixed scope of function defs in strict mode (they are block scoped)
|
||||
|
||||
## v5.7.0
|
||||
|
||||
- Several compile-time evaluation and inlining fixes
|
||||
- Allow `reduce_funcs` to be disabled again.
|
||||
- Add `spidermonkey` options to parse and format (#974)
|
||||
- Accept `{get = "default val"}` and `{set = "default val"}` in destructuring arguments.
|
||||
- Change package.json export map to help require.resolve (#971)
|
||||
- Improve docs
|
||||
- Fix `export default` of an anonymous class with `extends`
|
||||
|
||||
## v5.6.1
|
||||
|
||||
- Mark assignments to the `.prototype` of a class as pure
|
||||
- Parenthesize `await` on the left of `**` (while accepting legacy non-parenthesised input)
|
||||
- Avoided outputting NUL bytes in optimized RegExps, to stop the output from breaking other tools
|
||||
- Added `exports` to domprops (#939)
|
||||
- Fixed a crash when spreading `...this`
|
||||
- Fixed the computed size of arrow functions, which improves their inlining
|
||||
|
||||
## v5.6.0
|
||||
|
||||
- Added top-level await
|
||||
- Beautify option has been removed in #895
|
||||
- Private properties, getters and setters have been added in #913 and some more commits
|
||||
- Docs improvements: #896, #903, #916
|
||||
|
||||
## v5.5.1
|
||||
|
||||
- Fixed object properties with unicode surrogates on safari.
|
||||
|
||||
## v5.5.0
|
||||
|
||||
- Fixed crash when inlining uninitialized variable into template string.
|
||||
- The sourcemap for dist was removed for being too large.
|
||||
|
||||
## v5.4.0
|
||||
|
||||
- Logical assignment
|
||||
- Change `let x = undefined` to just `let x`
|
||||
- Removed some optimizations for template strings, placing them behind `unsafe` options. Reason: adding strings is not equivalent to template strings, due to valueOf differences.
|
||||
- The AST_Token class was slimmed down in order to use less memory.
|
||||
|
||||
## v5.3.8
|
||||
|
||||
- Restore node 13 support
|
||||
|
||||
## v5.3.7
|
||||
|
||||
Hotfix release, fixes package.json "engines" syntax
|
||||
|
||||
## v5.3.6
|
||||
|
||||
- Fixed parentheses when outputting `??` mixed with `||` and `&&`
|
||||
- Improved hygiene of the symbol generator
|
||||
|
||||
## v5.3.5
|
||||
|
||||
- Avoid moving named functions into default exports.
|
||||
- Enabled transform() for chain expressions. This allows AST transformers to reach inside chain expressions.
|
||||
|
||||
## v5.3.4
|
||||
|
||||
- Fixed a crash when hoisting (with `hoist_vars`) a destructuring variable declaration
|
||||
|
||||
## v5.3.3
|
||||
|
||||
- `source-map` library has been updated, bringing memory usage and CPU time improvements when reading input source maps (the SourceMapConsumer is now WASM based).
|
||||
- The `wrap_func_args` option now also wraps arrow functions, as opposed to only function expressions.
|
||||
|
||||
## v5.3.2
|
||||
|
||||
- Prevented spread operations from being expanded when the expanded array/object contains getters, setters, or array holes.
|
||||
- Fixed _very_ slow self-recursion in some cases of removing extraneous parentheses from `+` operations.
|
||||
|
||||
## v5.3.1
|
||||
|
||||
- An issue with destructuring declarations when `pure_getters` is enabled has been fixed
|
||||
- Fixed a crash when chain expressions need to be shallowly compared
|
||||
- Made inlining functions more conservative to make sure a function that contains a reference to itself isn't moved into a place that can create multiple instances of itself.
|
||||
|
||||
## v5.3.0
|
||||
|
||||
- Fixed a crash when compressing object spreads in some cases
|
||||
- Fixed compiletime evaluation of optional chains (caused typeof a?.b to always return "object")
|
||||
- domprops has been updated to contain every single possible prop
|
||||
|
||||
## v5.2.1
|
||||
|
||||
- The parse step now doesn't accept an `ecma` option, so that all ES code is accepted.
|
||||
- Optional dotted chains now accept keywords, just like dotted expressions (`foo?.default`)
|
||||
|
||||
## v5.2.0
|
||||
|
||||
- Optional chaining syntax is now supported.
|
||||
- Consecutive await expressions don't have unnecessary parens
|
||||
- Taking the variable name's length (after mangling) into consideration when deciding to inline
|
||||
|
||||
## v5.1.0
|
||||
|
||||
- `import.meta` is now supported
|
||||
- Typescript typings have been improved
|
||||
|
||||
## v5.0.0
|
||||
|
||||
- `in` operator now taken into account during property mangle.
|
||||
- Fixed infinite loop in face of a reference loop in some situations.
|
||||
- Kept exports and imports around even if there's something which will throw before them.
|
||||
- The main exported bundle for commonjs, dist/bundle.min.js is no longer minified.
|
||||
|
||||
## v5.0.0-beta.0
|
||||
|
||||
- BREAKING: `minify()` is now async and rejects a promise instead of returning an error.
|
||||
- BREAKING: Internal AST is no longer exposed, so that it can be improved without releasing breaking changes.
|
||||
- BREAKING: Lowest supported node version is 10
|
||||
- BREAKING: There are no more warnings being emitted
|
||||
- Module is now distributed as a dual package - You can `import` and `require()` too.
|
||||
- Inline improvements were made
|
||||
|
||||
|
||||
-----
|
||||
|
||||
## v4.8.1 (backport)
|
||||
|
||||
- Security fix for RegExps that should not be evaluated (regexp DDOS)
|
||||
|
||||
## v4.8.0
|
||||
|
||||
- Support for numeric separators (`million = 1_000_000`) was added.
|
||||
- Assigning properties to a class is now assumed to be pure.
|
||||
- Fixed bug where `yield` wasn't considered a valid property key in generators.
|
||||
|
||||
## v4.7.0
|
||||
|
||||
- A bug was fixed where an arrow function would have the wrong size
|
||||
- `arguments` object is now considered safe to retrieve properties from (useful for `length`, or `0`) even when `pure_getters` is not set.
|
||||
- Fixed erroneous `const` declarations without value (which is invalid) in some corner cases when using `collapse_vars`.
|
||||
|
||||
## v4.6.13
|
||||
|
||||
- Fixed issue where ES5 object properties were being turned into ES6 object properties due to more lax unicode rules.
|
||||
- Fixed parsing of BigInt with lowercase `e` in them.
|
||||
|
||||
## v4.6.12
|
||||
|
||||
- Fixed subtree comparison code, making it see that `[1,[2, 3]]` is different from `[1, 2, [3]]`
|
||||
- Printing of unicode identifiers has been improved
|
||||
|
||||
## v4.6.11
|
||||
|
||||
- Read unused classes' properties and method keys, to figure out if they use other variables.
|
||||
- Prevent inlining into block scopes when there are name collisions
|
||||
- Functions are no longer inlined into parameter defaults, because they live in their own special scope.
|
||||
- When inlining identity functions, take into account the fact they may be used to drop `this` in function calls.
|
||||
- Nullish coalescing operator (`x ?? y`), plus basic optimization for it.
|
||||
- Template literals in binary expressions such as `+` have been further optimized
|
||||
|
||||
## v4.6.10
|
||||
|
||||
- Do not use reduce_vars when classes are present
|
||||
|
||||
## v4.6.9
|
||||
|
||||
- Check if block scopes actually exist in blocks
|
||||
|
||||
## v4.6.8
|
||||
|
||||
- Take into account "executed bits" of classes like static properties or computed keys, when checking if a class evaluation might throw or have side effects.
|
||||
|
||||
## v4.6.7
|
||||
|
||||
- Some new performance gains through a `AST_Node.size()` method which measures a node's source code length without printing it to a string first.
|
||||
- An issue with setting `--comments` to `false` in the CLI has been fixed.
|
||||
- Fixed some issues with inlining
|
||||
- `unsafe_symbols` compress option was added, which turns `Symbol("name")` into just `Symbol()`
|
||||
- Brought back compress performance improvement through the `AST_Node.equivalent_to(other)` method (which was reverted in v4.6.6).
|
||||
|
||||
## v4.6.6
|
||||
|
||||
(hotfix release)
|
||||
|
||||
- Reverted code to 4.6.4 to allow for more time to investigate an issue.
|
||||
|
||||
## v4.6.5 (REVERTED)
|
||||
|
||||
- Improved compress performance through using a new method to see if two nodes are equivalent, instead of printing them to a string.
|
||||
|
||||
## v4.6.4
|
||||
|
||||
- The `"some"` value in the `comments` output option now preserves `@lic` and other important comments when using `//`
|
||||
- `</script>` is now better escaped in regex, and in comments, when using the `inline_script` output option
|
||||
- Fixed an issue when transforming `new RegExp` into `/.../` when slashes are included in the source
|
||||
- `AST_Node.prototype.constructor` now exists, allowing for easier debugging of crashes
|
||||
- Multiple if statements with the same consequents are now collapsed
|
||||
- Typescript typings improvements
|
||||
- Optimizations while looking for surrogate pairs in strings
|
||||
|
||||
## v4.6.3
|
||||
|
||||
- Annotations such as `/*#__NOINLINE__*/` and `/*#__PURE__*/` may now be preserved using the `preserve_annotations` output option
|
||||
- A TypeScript definition update for the `keep_quoted` output option.
|
||||
|
||||
## v4.6.2
|
||||
|
||||
- A bug where functions were inlined into other functions with scope conflicts has been fixed.
|
||||
- `/*#__NOINLINE__*/` annotation fixed for more use cases where inlining happens.
|
||||
|
||||
## v4.6.1
|
||||
|
||||
- Fixed an issue where a class is duplicated by reduce_vars when there's a recursive reference to the class.
|
||||
|
||||
## v4.6.0
|
||||
|
||||
- Fixed issues with recursive class references.
|
||||
- BigInt evaluation has been prevented, stopping Terser from evaluating BigInts like it would do regular numbers.
|
||||
- Class property support has been added
|
||||
|
||||
## v4.5.1
|
||||
|
||||
(hotfix release)
|
||||
|
||||
- Fixed issue where `() => ({})[something]` was not parenthesised correctly.
|
||||
|
||||
## v4.5.0
|
||||
|
||||
- Inlining has been improved
|
||||
- An issue where keep_fnames combined with functions declared through variables was causing name shadowing has been fixed
|
||||
- You can now set the ES version through their year
|
||||
- The output option `keep_numbers` has been added, which prevents Terser from turning `1000` into `1e3` and such
|
||||
- Internal small optimisations and refactors
|
||||
|
||||
## v4.4.3
|
||||
|
||||
- Number and BigInt parsing has been fixed
|
||||
- `/*#__INLINE__*/` annotation fixed for arrow functions with non-block bodies.
|
||||
- Functional tests have been added, using [this repository](https://github.com/terser/terser-functional-tests).
|
||||
- A memory leak, where the entire AST lives on after compression, has been plugged.
|
||||
|
||||
## v4.4.2
|
||||
|
||||
- Fixed a problem with inlining identity functions
|
||||
|
||||
## v4.4.1
|
||||
|
||||
*note:* This introduced a feature, therefore it should have been a minor release.
|
||||
|
||||
- Fixed a crash when `unsafe` was enabled.
|
||||
- An issue has been fixed where `let` statements might be collapsed out of their scope.
|
||||
- Some error messages have been improved by adding quotes around variable names.
|
||||
|
||||
## v4.4.0
|
||||
|
||||
- Added `/*#__INLINE__*/` and `/*#__NOINLINE__*/` annotations for calls. If a call has one of these, it either forces or forbids inlining.
|
||||
|
||||
## v4.3.11
|
||||
|
||||
- Fixed a problem where `window` was considered safe to access, even though there are situations where it isn't (Node.js, workers...)
|
||||
- Fixed an error where `++` and `--` were considered side-effect free
|
||||
- `Number(x)` now needs both `unsafe` and and `unsafe_math` to be compressed into `+x` because `x` might be a `BigInt`
|
||||
- `keep_fnames` now correctly supports regexes when the function is in a variable declaration
|
||||
|
||||
## v4.3.10
|
||||
|
||||
- Fixed syntax error when repeated semicolons were encountered in classes
|
||||
- Fixed invalid output caused by the creation of empty sequences internally
|
||||
- Scopes are now updated when scopes are inlined into them
|
||||
|
||||
## v4.3.9
|
||||
- Fixed issue with mangle's `keep_fnames` option, introduced when adding code to keep variable names of anonymous functions
|
||||
|
||||
## v4.3.8
|
||||
|
||||
- Typescript typings fix
|
||||
|
||||
## v4.3.7
|
||||
|
||||
- Parsing of regex options in the CLI (which broke in v4.3.5) was fixed.
|
||||
- typescript definition updates
|
||||
|
||||
## v4.3.6
|
||||
|
||||
(crash hotfix)
|
||||
|
||||
## v4.3.5
|
||||
|
||||
- Fixed an issue with DOS line endings strings separated by `\` and a new line.
|
||||
- Improved fix for the output size regression related to unused references within the extends section of a class.
|
||||
- Variable names of anonymous functions (eg: `const x = () => { ... }` or `var func = function () {...}`) are now preserved when keep_fnames is true.
|
||||
- Fixed performance degradation introduced for large payloads in v4.2.0
|
||||
|
||||
## v4.3.4
|
||||
|
||||
- Fixed a regression where the output size was increased when unused classes were referred to in the extends clause of a class.
|
||||
- Small typescript typings fixes.
|
||||
- Comments with `@preserve`, `@license`, `@cc_on` as well as comments starting with `/*!` and `/**!` are now preserved by default.
|
||||
|
||||
## v4.3.3
|
||||
|
||||
- Fixed a problem where parsing template strings would mix up octal notation and a slash followed by a zero representing a null character.
|
||||
- Started accepting the name `async` in destructuring arguments with default value.
|
||||
- Now Terser takes into account side effects inside class `extends` clauses.
|
||||
- Added parens whenever there's a comment between a return statement and the returned value, to prevent issues with ASI.
|
||||
- Stopped using raw RegExp objects, since the spec is going to continue to evolve. This ensures Terser is able to process new, unknown RegExp flags and features. This is a breaking change in the AST node AST_RegExp.
|
||||
|
||||
## v4.3.2
|
||||
|
||||
- Typescript typing fix
|
||||
- Ensure that functions can't be inlined, by reduce_vars, into places where they're accessing variables with the same name, but from somewhere else.
|
||||
|
||||
## v4.3.1
|
||||
|
||||
- Fixed an issue from 4.3.0 where any block scope within a for loop erroneously had its parent set to the function scopee
|
||||
- Fixed an issue where compressing IIFEs with argument expansions would result in some parameters becoming undefined
|
||||
- addEventListener options argument's properties are now part of the DOM properties list.
|
||||
|
||||
## v4.3.0
|
||||
|
||||
- Do not drop computed object keys with side effects
|
||||
- Functions passed to other functions in calls are now wrapped in parentheses by default, which speeds up loading most modules
|
||||
- Objects with computed properties are now less likely to be hoisted
|
||||
- Speed and memory efficiency optimizations
|
||||
- Fixed scoping issues with `try` and `switch`
|
||||
|
||||
## v4.2.1
|
||||
|
||||
- Minor refactors
|
||||
- Fixed a bug similar to #369 in collapse_vars
|
||||
- Functions can no longer be inlined into a place where they're going to be compared with themselves.
|
||||
- reduce_funcs option is now legacy, as using reduce_vars without reduce_funcs caused some weird corner cases. As a result, it is now implied in reduce_vars and can't be turned off without turning off reduce_vars.
|
||||
- Bug which would cause a random stack overflow has now been fixed.
|
||||
|
||||
## v4.2.0
|
||||
|
||||
- When the source map URL is `inline`, don't write it to a file.
|
||||
- Fixed output parens when a lambda literal is the tag on a tagged template string.
|
||||
- The `mangle.properties.undeclared` option was added. This enables the property mangler to mangle properties of variables which can be found in the name cache, but whose properties are not known to this Terser run.
|
||||
- The v8 bug where the toString and source representations of regexes like `RegExp("\\\n")` includes an actual newline is now fixed.
|
||||
- Now we're guaranteed to not have duplicate comments in the output
|
||||
- Domprops updates
|
||||
|
||||
## v4.1.4
|
||||
|
||||
- Fixed a crash when inlining a function into somewhere else when it has interdependent, non-removable variables.
|
||||
|
||||
## v4.1.3
|
||||
|
||||
- Several issues with the `reduce_vars` option were fixed.
|
||||
- Starting this version, we only have a dist/bundle.min.js
|
||||
|
||||
## v4.1.2
|
||||
|
||||
- The hotfix was hotfixed
|
||||
|
||||
## v4.1.1
|
||||
|
||||
- Fixed a bug where toplevel scopes were being mixed up with lambda scopes
|
||||
|
||||
## v4.1.0
|
||||
|
||||
- Internal functions were replaced by `Object.assign`, `Array.prototype.some`, `Array.prototype.find` and `Array.prototype.every`.
|
||||
- A serious issue where some ESM-native code was broken was fixed.
|
||||
- Performance improvements were made.
|
||||
- Support for BigInt was added.
|
||||
- Inline efficiency was improved. Functions are now being inlined more proactively instead of being inlined only after another Compressor pass.
|
||||
|
||||
## v4.0.2
|
||||
|
||||
(Hotfix release. Reverts unmapped segments PR [#342](https://github.com/terser/terser/pull/342), which will be put back on Terser when the upstream issue is resolved)
|
||||
|
||||
## v4.0.1
|
||||
|
||||
- Collisions between the arguments of inlined functions and names in the outer scope are now being avoided while inlining
|
||||
- Unmapped segments are now preserved when compressing a file which has source maps
|
||||
- Default values of functions are now correctly converted from Mozilla AST to Terser AST
|
||||
- JSON ⊂ ECMAScript spec (if you don't know what this is you don't need to)
|
||||
- Export AST_* classes to library users
|
||||
- Fixed issue with `collapse_vars` when functions are created with the same name as a variable which already exists
|
||||
- Added `MutationObserverInit` (Object with options for initialising a mutation observer) properties to the DOM property list
|
||||
- Custom `Error` subclasses are now internally used instead of old-school Error inheritance hacks.
|
||||
- Documentation fixes
|
||||
- Performance optimizations
|
||||
|
||||
## v4.0.0
|
||||
|
||||
- **breaking change**: The `variables` property of all scopes has become a standard JavaScript `Map` as opposed to the old bespoke `Dictionary` object.
|
||||
- Typescript definitions were fixed
|
||||
- `terser --help` was fixed
|
||||
- The public interface was cleaned up
|
||||
- Fixed optimisation of `Array` and `new Array`
|
||||
- Added the `keep_quoted=strict` mode to mangle_props, which behaves more like Google Closure Compiler by mangling all unquoted property names, instead of reserving quoted property names automatically.
|
||||
- Fixed parent functions' parameters being shadowed in some cases
|
||||
- Allowed Terser to run in a situation where there are custom functions attached to Object.prototype
|
||||
- And more bug fixes, optimisations and internal changes
|
||||
|
||||
## v3.17.0
|
||||
|
||||
- More DOM properties added to --mangle-properties's DOM property list
|
||||
- Closed issue where if 2 functions had the same argument name, Terser would not inline them together properly
|
||||
- Fixed issue with `hasOwnProperty.call`
|
||||
- You can now list files to minify in a Terser config file
|
||||
- Started replacing `new Array(<number>)` with an array literal
|
||||
- Started using ES6 capabilities like `Set` and the `includes` method for strings and arrays
|
||||
|
||||
## v3.16.1
|
||||
|
||||
- Fixed issue where Terser being imported with `import` would cause it not to work due to the `__esModule` property. (PR #254 was submitted, which was nice, but since it wasn't a pure commonJS approach I decided to go with my own solution)
|
||||
|
||||
## v3.16.0
|
||||
|
||||
- No longer leaves names like Array or Object or window as a SimpleStatement (statement which is just a single expression).
|
||||
- Add support for sections sourcemaps (IndexedSourceMapConsumer)
|
||||
- Drops node.js v4 and starts using commonJS
|
||||
- Is now built with rollup
|
||||
|
||||
## v3.15.0
|
||||
|
||||
- Inlined spread syntax (`[...[1, 2, 3], 4, 5] => [1, 2, 3, 4, 5]`) in arrays and objects.
|
||||
- Fixed typo in compressor warning
|
||||
- Fixed inline source map input bug
|
||||
- Fixed parsing of template literals with unnecessary escapes (Like `\\a`)
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
Terser is released under the BSD license:
|
||||
|
||||
Copyright 2012-2018 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# Our patrons
|
||||
|
||||
These are the first-tier patrons from [Patreon](https://www.patreon.com/fabiosantoscode). My appreciation goes to everyone on this list for supporting the project!
|
||||
|
||||
* 38elements
|
||||
* Alan Orozco
|
||||
* Aria Buckles
|
||||
* CKEditor
|
||||
* Mariusz Nowak
|
||||
* Nakshatra Mukhopadhyay
|
||||
* Philippe Léger
|
||||
* Piotrek Koszuliński
|
||||
* Serhiy Shyyko
|
||||
* Viktor Hubert
|
||||
* 龙腾道
|
||||
+1374
File diff suppressed because it is too large
Load Diff
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "bin",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "terser",
|
||||
"type": "commonjs",
|
||||
"author": "",
|
||||
"license": "BSD-2-Clause",
|
||||
"description": "A package to hold the Terser bin bundle as commonjs while keeping the rest of it ESM."
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
"use strict";
|
||||
|
||||
require("../tools/exit.cjs");
|
||||
|
||||
try {
|
||||
require("source-map-support").install();
|
||||
} catch (err) {}
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const program = require("commander");
|
||||
|
||||
const packageJson = require("../package.json");
|
||||
const { _run_cli: run_cli } = require("..");
|
||||
|
||||
run_cli({ program, packageJson, fs, path }).catch((error) => {
|
||||
console.error(error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
// -*- js -*-
|
||||
/* eslint-env node */
|
||||
|
||||
"use strict";
|
||||
|
||||
process.stderr.write( "DEPRECATION WARNING: uglifyjs binary will soon be discontinued!\n");
|
||||
process.stderr.write("Please use \"terser\" instead.\n\n");
|
||||
|
||||
require("./terser");
|
||||
+30099
File diff suppressed because one or more lines are too long
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "dist",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "bundle.min.js",
|
||||
"type": "commonjs",
|
||||
"author": "",
|
||||
"license": "BSD-2-Clause",
|
||||
"description": "A package to hold the Terser dist bundle as commonjs while keeping the rest of it ESM. Nothing to see here."
|
||||
}
|
||||
+3193
File diff suppressed because it is too large
Load Diff
+479
@@ -0,0 +1,479 @@
|
||||
import { minify, _default_options } from "../main.js";
|
||||
import { parse } from "./parse.js";
|
||||
import {
|
||||
AST_Assign,
|
||||
AST_Array,
|
||||
AST_Constant,
|
||||
AST_Node,
|
||||
AST_PropAccess,
|
||||
AST_RegExp,
|
||||
AST_Sequence,
|
||||
AST_Symbol,
|
||||
AST_Token,
|
||||
walk
|
||||
} from "./ast.js";
|
||||
import { OutputStream } from "./output.js";
|
||||
|
||||
export async function run_cli({ program, packageJson, fs, path }) {
|
||||
const skip_keys = new Set([ "cname", "parent_scope", "scope", "uses_eval", "uses_with" ]);
|
||||
var files = {};
|
||||
var options = {
|
||||
compress: false,
|
||||
mangle: false
|
||||
};
|
||||
const default_options = await _default_options();
|
||||
program.version(packageJson.name + " " + packageJson.version);
|
||||
program.parseArgv = program.parse;
|
||||
program.parse = undefined;
|
||||
|
||||
if (process.argv.includes("ast")) program.helpInformation = describe_ast;
|
||||
else if (process.argv.includes("options")) program.helpInformation = function() {
|
||||
var text = [];
|
||||
for (var option in default_options) {
|
||||
text.push("--" + (option === "sourceMap" ? "source-map" : option) + " options:");
|
||||
text.push(format_object(default_options[option]));
|
||||
text.push("");
|
||||
}
|
||||
return text.join("\n");
|
||||
};
|
||||
|
||||
program.option("-p, --parse <options>", "Specify parser options.", parse_js());
|
||||
program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js());
|
||||
program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js());
|
||||
program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js());
|
||||
program.option("-f, --format [options]", "Format options.", parse_js());
|
||||
program.option("-b, --beautify [options]", "Alias for --format.", parse_js());
|
||||
program.option("-o, --output <file>", "Output file (default STDOUT).");
|
||||
program.option("--comments [filter]", "Preserve copyright comments in the output.");
|
||||
program.option("--config-file <file>", "Read minify() options from JSON file.");
|
||||
program.option("-d, --define <expr>[=value]", "Global definitions.", parse_js("define"));
|
||||
program.option("--ecma <version>", "Specify ECMAScript release: 5, 2015, 2016 or 2017...");
|
||||
program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed output in a big function with configurable arguments and values.");
|
||||
program.option("--ie8", "Support non-standard Internet Explorer 8.");
|
||||
program.option("--keep-classnames", "Do not mangle/drop class names.");
|
||||
program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name.");
|
||||
program.option("--module", "Input is an ES6 module");
|
||||
program.option("--name-cache <file>", "File to hold mangled name mappings.");
|
||||
program.option("--rename", "Force symbol expansion.");
|
||||
program.option("--no-rename", "Disable symbol expansion.");
|
||||
program.option("--safari10", "Support non-standard Safari 10.");
|
||||
program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js());
|
||||
program.option("--timings", "Display operations run time on STDERR.");
|
||||
program.option("--toplevel", "Compress and/or mangle variables in toplevel scope.");
|
||||
program.option("--wrap <name>", "Embed everything as a function with “exports” corresponding to “name” globally.");
|
||||
program.arguments("[files...]").parseArgv(process.argv);
|
||||
if (program.configFile) {
|
||||
options = JSON.parse(read_file(program.configFile));
|
||||
}
|
||||
if (!program.output && program.sourceMap && program.sourceMap.url != "inline") {
|
||||
fatal("ERROR: cannot write source map to STDOUT");
|
||||
}
|
||||
|
||||
[
|
||||
"compress",
|
||||
"enclose",
|
||||
"ie8",
|
||||
"mangle",
|
||||
"module",
|
||||
"safari10",
|
||||
"sourceMap",
|
||||
"toplevel",
|
||||
"wrap"
|
||||
].forEach(function(name) {
|
||||
if (name in program) {
|
||||
options[name] = program[name];
|
||||
}
|
||||
});
|
||||
|
||||
if ("ecma" in program) {
|
||||
if (program.ecma != (program.ecma | 0)) fatal("ERROR: ecma must be an integer");
|
||||
const ecma = program.ecma | 0;
|
||||
if (ecma > 5 && ecma < 2015)
|
||||
options.ecma = ecma + 2009;
|
||||
else
|
||||
options.ecma = ecma;
|
||||
}
|
||||
if (program.format || program.beautify) {
|
||||
const chosenOption = program.format || program.beautify;
|
||||
options.format = typeof chosenOption === "object" ? chosenOption : {};
|
||||
}
|
||||
if (program.comments) {
|
||||
if (typeof options.format != "object") options.format = {};
|
||||
options.format.comments = typeof program.comments == "string" ? (program.comments == "false" ? false : program.comments) : "some";
|
||||
}
|
||||
if (program.define) {
|
||||
if (typeof options.compress != "object") options.compress = {};
|
||||
if (typeof options.compress.global_defs != "object") options.compress.global_defs = {};
|
||||
for (var expr in program.define) {
|
||||
options.compress.global_defs[expr] = program.define[expr];
|
||||
}
|
||||
}
|
||||
if (program.keepClassnames) {
|
||||
options.keep_classnames = true;
|
||||
}
|
||||
if (program.keepFnames) {
|
||||
options.keep_fnames = true;
|
||||
}
|
||||
if (program.mangleProps) {
|
||||
if (program.mangleProps.domprops) {
|
||||
delete program.mangleProps.domprops;
|
||||
} else {
|
||||
if (typeof program.mangleProps != "object") program.mangleProps = {};
|
||||
if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = [];
|
||||
}
|
||||
if (typeof options.mangle != "object") options.mangle = {};
|
||||
options.mangle.properties = program.mangleProps;
|
||||
}
|
||||
if (program.nameCache) {
|
||||
options.nameCache = JSON.parse(read_file(program.nameCache, "{}"));
|
||||
}
|
||||
if (program.output == "ast") {
|
||||
options.format = {
|
||||
ast: true,
|
||||
code: false
|
||||
};
|
||||
}
|
||||
if (program.parse) {
|
||||
if (!program.parse.acorn && !program.parse.spidermonkey) {
|
||||
options.parse = program.parse;
|
||||
} else if (program.sourceMap && program.sourceMap.content == "inline") {
|
||||
fatal("ERROR: inline source map only works with built-in parser");
|
||||
}
|
||||
}
|
||||
if (~program.rawArgs.indexOf("--rename")) {
|
||||
options.rename = true;
|
||||
} else if (!program.rename) {
|
||||
options.rename = false;
|
||||
}
|
||||
|
||||
let convert_path = name => name;
|
||||
if (typeof program.sourceMap == "object" && "base" in program.sourceMap) {
|
||||
convert_path = function() {
|
||||
var base = program.sourceMap.base;
|
||||
delete options.sourceMap.base;
|
||||
return function(name) {
|
||||
return path.relative(base, name);
|
||||
};
|
||||
}();
|
||||
}
|
||||
|
||||
let filesList;
|
||||
if (options.files && options.files.length) {
|
||||
filesList = options.files;
|
||||
|
||||
delete options.files;
|
||||
} else if (program.args.length) {
|
||||
filesList = program.args;
|
||||
}
|
||||
|
||||
if (filesList) {
|
||||
simple_glob(filesList).forEach(function(name) {
|
||||
files[convert_path(name)] = read_file(name);
|
||||
});
|
||||
} else {
|
||||
await new Promise((resolve) => {
|
||||
var chunks = [];
|
||||
process.stdin.setEncoding("utf8");
|
||||
process.stdin.on("data", function(chunk) {
|
||||
chunks.push(chunk);
|
||||
}).on("end", function() {
|
||||
files = [ chunks.join("") ];
|
||||
resolve();
|
||||
});
|
||||
process.stdin.resume();
|
||||
});
|
||||
}
|
||||
|
||||
await run_cli();
|
||||
|
||||
function convert_ast(fn) {
|
||||
return AST_Node.from_mozilla_ast(Object.keys(files).reduce(fn, null));
|
||||
}
|
||||
|
||||
async function run_cli() {
|
||||
var content = program.sourceMap && program.sourceMap.content;
|
||||
if (content && content !== "inline") {
|
||||
options.sourceMap.content = read_file(content, content);
|
||||
}
|
||||
if (program.timings) options.timings = true;
|
||||
|
||||
try {
|
||||
if (program.parse) {
|
||||
if (program.parse.acorn) {
|
||||
files = convert_ast(function(toplevel, name) {
|
||||
return require("acorn").parse(files[name], {
|
||||
ecmaVersion: 2018,
|
||||
locations: true,
|
||||
program: toplevel,
|
||||
sourceFile: name,
|
||||
sourceType: options.module || program.parse.module ? "module" : "script"
|
||||
});
|
||||
});
|
||||
} else if (program.parse.spidermonkey) {
|
||||
files = convert_ast(function(toplevel, name) {
|
||||
var obj = JSON.parse(files[name]);
|
||||
if (!toplevel) return obj;
|
||||
toplevel.body = toplevel.body.concat(obj.body);
|
||||
return toplevel;
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
fatal(ex);
|
||||
}
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await minify(files, options, fs);
|
||||
} catch (ex) {
|
||||
if (ex.name == "SyntaxError") {
|
||||
print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col);
|
||||
var col = ex.col;
|
||||
var lines = files[ex.filename].split(/\r?\n/);
|
||||
var line = lines[ex.line - 1];
|
||||
if (!line && !col) {
|
||||
line = lines[ex.line - 2];
|
||||
col = line.length;
|
||||
}
|
||||
if (line) {
|
||||
var limit = 70;
|
||||
if (col > limit) {
|
||||
line = line.slice(col - limit);
|
||||
col = limit;
|
||||
}
|
||||
print_error(line.slice(0, 80));
|
||||
print_error(line.slice(0, col).replace(/\S/g, " ") + "^");
|
||||
}
|
||||
}
|
||||
if (ex.defs) {
|
||||
print_error("Supported options:");
|
||||
print_error(format_object(ex.defs));
|
||||
}
|
||||
fatal(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (program.output == "ast") {
|
||||
if (!options.compress && !options.mangle) {
|
||||
result.ast.figure_out_scope({});
|
||||
}
|
||||
console.log(JSON.stringify(result.ast, function(key, value) {
|
||||
if (value) switch (key) {
|
||||
case "thedef":
|
||||
return symdef(value);
|
||||
case "enclosed":
|
||||
return value.length ? value.map(symdef) : undefined;
|
||||
case "variables":
|
||||
case "globals":
|
||||
return value.size ? collect_from_map(value, symdef) : undefined;
|
||||
}
|
||||
if (skip_keys.has(key)) return;
|
||||
if (value instanceof AST_Token) return;
|
||||
if (value instanceof Map) return;
|
||||
if (value instanceof AST_Node) {
|
||||
var result = {
|
||||
_class: "AST_" + value.TYPE
|
||||
};
|
||||
if (value.block_scope) {
|
||||
result.variables = value.block_scope.variables;
|
||||
result.enclosed = value.block_scope.enclosed;
|
||||
}
|
||||
value.CTOR.PROPS.forEach(function(prop) {
|
||||
result[prop] = value[prop];
|
||||
});
|
||||
return result;
|
||||
}
|
||||
return value;
|
||||
}, 2));
|
||||
} else if (program.output == "spidermonkey") {
|
||||
try {
|
||||
const minified = await minify(
|
||||
result.code,
|
||||
{
|
||||
compress: false,
|
||||
mangle: false,
|
||||
format: {
|
||||
ast: true,
|
||||
code: false
|
||||
}
|
||||
},
|
||||
fs
|
||||
);
|
||||
console.log(JSON.stringify(minified.ast.to_mozilla_ast(), null, 2));
|
||||
} catch (ex) {
|
||||
fatal(ex);
|
||||
return;
|
||||
}
|
||||
} else if (program.output) {
|
||||
fs.writeFileSync(program.output, result.code);
|
||||
if (options.sourceMap && options.sourceMap.url !== "inline" && result.map) {
|
||||
fs.writeFileSync(program.output + ".map", result.map);
|
||||
}
|
||||
} else {
|
||||
console.log(result.code);
|
||||
}
|
||||
if (program.nameCache) {
|
||||
fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache));
|
||||
}
|
||||
if (result.timings) for (var phase in result.timings) {
|
||||
print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s");
|
||||
}
|
||||
}
|
||||
|
||||
function fatal(message) {
|
||||
if (message instanceof Error) message = message.stack.replace(/^\S*?Error:/, "ERROR:");
|
||||
print_error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// A file glob function that only supports "*" and "?" wildcards in the basename.
|
||||
// Example: "foo/bar/*baz??.*.js"
|
||||
// Argument `glob` may be a string or an array of strings.
|
||||
// Returns an array of strings. Garbage in, garbage out.
|
||||
function simple_glob(glob) {
|
||||
if (Array.isArray(glob)) {
|
||||
return [].concat.apply([], glob.map(simple_glob));
|
||||
}
|
||||
if (glob && glob.match(/[*?]/)) {
|
||||
var dir = path.dirname(glob);
|
||||
try {
|
||||
var entries = fs.readdirSync(dir);
|
||||
} catch (ex) {}
|
||||
if (entries) {
|
||||
var pattern = "^" + path.basename(glob)
|
||||
.replace(/[.+^$[\]\\(){}]/g, "\\$&")
|
||||
.replace(/\*/g, "[^/\\\\]*")
|
||||
.replace(/\?/g, "[^/\\\\]") + "$";
|
||||
var mod = process.platform === "win32" ? "i" : "";
|
||||
var rx = new RegExp(pattern, mod);
|
||||
var results = entries.filter(function(name) {
|
||||
return rx.test(name);
|
||||
}).map(function(name) {
|
||||
return path.join(dir, name);
|
||||
});
|
||||
if (results.length) return results;
|
||||
}
|
||||
}
|
||||
return [ glob ];
|
||||
}
|
||||
|
||||
function read_file(path, default_value) {
|
||||
try {
|
||||
return fs.readFileSync(path, "utf8");
|
||||
} catch (ex) {
|
||||
if ((ex.code == "ENOENT" || ex.code == "ENAMETOOLONG") && default_value != null) return default_value;
|
||||
fatal(ex);
|
||||
}
|
||||
}
|
||||
|
||||
function parse_js(flag) {
|
||||
return function(value, options) {
|
||||
options = options || {};
|
||||
try {
|
||||
walk(parse(value, { expression: true }), node => {
|
||||
if (node instanceof AST_Assign) {
|
||||
var name = node.left.print_to_string();
|
||||
var value = node.right;
|
||||
if (flag) {
|
||||
options[name] = value;
|
||||
} else if (value instanceof AST_Array) {
|
||||
options[name] = value.elements.map(to_string);
|
||||
} else if (value instanceof AST_RegExp) {
|
||||
value = value.value;
|
||||
options[name] = new RegExp(value.source, value.flags);
|
||||
} else {
|
||||
options[name] = to_string(value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_Symbol || node instanceof AST_PropAccess) {
|
||||
var name = node.print_to_string();
|
||||
options[name] = true;
|
||||
return true;
|
||||
}
|
||||
if (!(node instanceof AST_Sequence)) throw node;
|
||||
|
||||
function to_string(value) {
|
||||
return value instanceof AST_Constant ? value.getValue() : value.print_to_string({
|
||||
quote_keys: true
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch(ex) {
|
||||
if (flag) {
|
||||
fatal("Error parsing arguments for '" + flag + "': " + value);
|
||||
} else {
|
||||
options[value] = null;
|
||||
}
|
||||
}
|
||||
return options;
|
||||
};
|
||||
}
|
||||
|
||||
function symdef(def) {
|
||||
var ret = (1e6 + def.id) + " " + def.name;
|
||||
if (def.mangled_name) ret += " " + def.mangled_name;
|
||||
return ret;
|
||||
}
|
||||
|
||||
function collect_from_map(map, callback) {
|
||||
var result = [];
|
||||
map.forEach(function (def) {
|
||||
result.push(callback(def));
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function format_object(obj) {
|
||||
var lines = [];
|
||||
var padding = "";
|
||||
Object.keys(obj).map(function(name) {
|
||||
if (padding.length < name.length) padding = Array(name.length + 1).join(" ");
|
||||
return [ name, JSON.stringify(obj[name]) ];
|
||||
}).forEach(function(tokens) {
|
||||
lines.push(" " + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]);
|
||||
});
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function print_error(msg) {
|
||||
process.stderr.write(msg);
|
||||
process.stderr.write("\n");
|
||||
}
|
||||
|
||||
function describe_ast() {
|
||||
var out = OutputStream({ beautify: true });
|
||||
function doitem(ctor) {
|
||||
out.print("AST_" + ctor.TYPE);
|
||||
const props = ctor.SELF_PROPS.filter(prop => !/^\$/.test(prop));
|
||||
|
||||
if (props.length > 0) {
|
||||
out.space();
|
||||
out.with_parens(function() {
|
||||
props.forEach(function(prop, i) {
|
||||
if (i) out.space();
|
||||
out.print(prop);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (ctor.documentation) {
|
||||
out.space();
|
||||
out.print_string(ctor.documentation);
|
||||
}
|
||||
|
||||
if (ctor.SUBCLASSES.length > 0) {
|
||||
out.space();
|
||||
out.with_block(function() {
|
||||
ctor.SUBCLASSES.forEach(function(ctor) {
|
||||
out.indent();
|
||||
doitem(ctor);
|
||||
out.newline();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
doitem(AST_Node);
|
||||
return out + "\n";
|
||||
}
|
||||
}
|
||||
+344
@@ -0,0 +1,344 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
import {
|
||||
AST_Array,
|
||||
AST_Arrow,
|
||||
AST_BlockStatement,
|
||||
AST_Call,
|
||||
AST_Class,
|
||||
AST_Const,
|
||||
AST_Constant,
|
||||
AST_DefClass,
|
||||
AST_Defun,
|
||||
AST_EmptyStatement,
|
||||
AST_Export,
|
||||
AST_False,
|
||||
AST_Function,
|
||||
AST_Import,
|
||||
AST_Infinity,
|
||||
AST_LabeledStatement,
|
||||
AST_Lambda,
|
||||
AST_Let,
|
||||
AST_LoopControl,
|
||||
AST_NaN,
|
||||
AST_Node,
|
||||
AST_Null,
|
||||
AST_Number,
|
||||
AST_Object,
|
||||
AST_ObjectKeyVal,
|
||||
AST_PropAccess,
|
||||
AST_RegExp,
|
||||
AST_Scope,
|
||||
AST_Sequence,
|
||||
AST_SimpleStatement,
|
||||
AST_Statement,
|
||||
AST_String,
|
||||
AST_SymbolRef,
|
||||
AST_True,
|
||||
AST_UnaryPrefix,
|
||||
AST_Undefined,
|
||||
|
||||
TreeWalker,
|
||||
walk,
|
||||
walk_abort,
|
||||
walk_parent,
|
||||
} from "../ast.js";
|
||||
import { make_node, regexp_source_fix, string_template, makePredicate } from "../utils/index.js";
|
||||
import { first_in_statement } from "../utils/first_in_statement.js";
|
||||
import { has_flag, TOP } from "./compressor-flags.js";
|
||||
|
||||
export function merge_sequence(array, node) {
|
||||
if (node instanceof AST_Sequence) {
|
||||
array.push(...node.expressions);
|
||||
} else {
|
||||
array.push(node);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
export function make_sequence(orig, expressions) {
|
||||
if (expressions.length == 1) return expressions[0];
|
||||
if (expressions.length == 0) throw new Error("trying to create a sequence with length zero!");
|
||||
return make_node(AST_Sequence, orig, {
|
||||
expressions: expressions.reduce(merge_sequence, [])
|
||||
});
|
||||
}
|
||||
|
||||
export function make_node_from_constant(val, orig) {
|
||||
switch (typeof val) {
|
||||
case "string":
|
||||
return make_node(AST_String, orig, {
|
||||
value: val
|
||||
});
|
||||
case "number":
|
||||
if (isNaN(val)) return make_node(AST_NaN, orig);
|
||||
if (isFinite(val)) {
|
||||
return 1 / val < 0 ? make_node(AST_UnaryPrefix, orig, {
|
||||
operator: "-",
|
||||
expression: make_node(AST_Number, orig, { value: -val })
|
||||
}) : make_node(AST_Number, orig, { value: val });
|
||||
}
|
||||
return val < 0 ? make_node(AST_UnaryPrefix, orig, {
|
||||
operator: "-",
|
||||
expression: make_node(AST_Infinity, orig)
|
||||
}) : make_node(AST_Infinity, orig);
|
||||
case "boolean":
|
||||
return make_node(val ? AST_True : AST_False, orig);
|
||||
case "undefined":
|
||||
return make_node(AST_Undefined, orig);
|
||||
default:
|
||||
if (val === null) {
|
||||
return make_node(AST_Null, orig, { value: null });
|
||||
}
|
||||
if (val instanceof RegExp) {
|
||||
return make_node(AST_RegExp, orig, {
|
||||
value: {
|
||||
source: regexp_source_fix(val.source),
|
||||
flags: val.flags
|
||||
}
|
||||
});
|
||||
}
|
||||
throw new Error(string_template("Can't handle constant of type: {type}", {
|
||||
type: typeof val
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export function best_of_expression(ast1, ast2) {
|
||||
return ast1.size() > ast2.size() ? ast2 : ast1;
|
||||
}
|
||||
|
||||
export function best_of_statement(ast1, ast2) {
|
||||
return best_of_expression(
|
||||
make_node(AST_SimpleStatement, ast1, {
|
||||
body: ast1
|
||||
}),
|
||||
make_node(AST_SimpleStatement, ast2, {
|
||||
body: ast2
|
||||
})
|
||||
).body;
|
||||
}
|
||||
|
||||
/** Find which node is smaller, and return that */
|
||||
export function best_of(compressor, ast1, ast2) {
|
||||
if (first_in_statement(compressor)) {
|
||||
return best_of_statement(ast1, ast2);
|
||||
} else {
|
||||
return best_of_expression(ast1, ast2);
|
||||
}
|
||||
}
|
||||
|
||||
/** Simplify an object property's key, if possible */
|
||||
export function get_simple_key(key) {
|
||||
if (key instanceof AST_Constant) {
|
||||
return key.getValue();
|
||||
}
|
||||
if (key instanceof AST_UnaryPrefix
|
||||
&& key.operator == "void"
|
||||
&& key.expression instanceof AST_Constant) {
|
||||
return;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
export function read_property(obj, key) {
|
||||
key = get_simple_key(key);
|
||||
if (key instanceof AST_Node) return;
|
||||
|
||||
var value;
|
||||
if (obj instanceof AST_Array) {
|
||||
var elements = obj.elements;
|
||||
if (key == "length") return make_node_from_constant(elements.length, obj);
|
||||
if (typeof key == "number" && key in elements) value = elements[key];
|
||||
} else if (obj instanceof AST_Object) {
|
||||
key = "" + key;
|
||||
var props = obj.properties;
|
||||
for (var i = props.length; --i >= 0;) {
|
||||
var prop = props[i];
|
||||
if (!(prop instanceof AST_ObjectKeyVal)) return;
|
||||
if (!value && props[i].key === key) value = props[i].value;
|
||||
}
|
||||
}
|
||||
|
||||
return value instanceof AST_SymbolRef && value.fixed_value() || value;
|
||||
}
|
||||
|
||||
export function has_break_or_continue(loop, parent) {
|
||||
var found = false;
|
||||
var tw = new TreeWalker(function(node) {
|
||||
if (found || node instanceof AST_Scope) return true;
|
||||
if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === loop) {
|
||||
return found = true;
|
||||
}
|
||||
});
|
||||
if (parent instanceof AST_LabeledStatement) tw.push(parent);
|
||||
tw.push(loop);
|
||||
loop.body.walk(tw);
|
||||
return found;
|
||||
}
|
||||
|
||||
// we shouldn't compress (1,func)(something) to
|
||||
// func(something) because that changes the meaning of
|
||||
// the func (becomes lexical instead of global).
|
||||
export function maintain_this_binding(parent, orig, val) {
|
||||
if (
|
||||
parent instanceof AST_UnaryPrefix && parent.operator == "delete"
|
||||
|| parent instanceof AST_Call && parent.expression === orig
|
||||
&& (
|
||||
val instanceof AST_PropAccess
|
||||
|| val instanceof AST_SymbolRef && val.name == "eval"
|
||||
)
|
||||
) {
|
||||
const zero = make_node(AST_Number, orig, { value: 0 });
|
||||
return make_sequence(orig, [ zero, val ]);
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
export function is_func_expr(node) {
|
||||
return node instanceof AST_Arrow || node instanceof AST_Function;
|
||||
}
|
||||
|
||||
export function is_iife_call(node) {
|
||||
// Used to determine whether the node can benefit from negation.
|
||||
// Not the case with arrow functions (you need an extra set of parens).
|
||||
if (node.TYPE != "Call") return false;
|
||||
return node.expression instanceof AST_Function || is_iife_call(node.expression);
|
||||
}
|
||||
|
||||
export function is_empty(thing) {
|
||||
if (thing === null) return true;
|
||||
if (thing instanceof AST_EmptyStatement) return true;
|
||||
if (thing instanceof AST_BlockStatement) return thing.body.length == 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
export const identifier_atom = makePredicate("Infinity NaN undefined");
|
||||
export function is_identifier_atom(node) {
|
||||
return node instanceof AST_Infinity
|
||||
|| node instanceof AST_NaN
|
||||
|| node instanceof AST_Undefined;
|
||||
}
|
||||
|
||||
/** Check if this is a SymbolRef node which has one def of a certain AST type */
|
||||
export function is_ref_of(ref, type) {
|
||||
if (!(ref instanceof AST_SymbolRef)) return false;
|
||||
var orig = ref.definition().orig;
|
||||
for (var i = orig.length; --i >= 0;) {
|
||||
if (orig[i] instanceof type) return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Can we turn { block contents... } into just the block contents ?
|
||||
// Not if one of these is inside.
|
||||
export function can_be_evicted_from_block(node) {
|
||||
return !(
|
||||
node instanceof AST_DefClass ||
|
||||
node instanceof AST_Defun ||
|
||||
node instanceof AST_Let ||
|
||||
node instanceof AST_Const ||
|
||||
node instanceof AST_Export ||
|
||||
node instanceof AST_Import
|
||||
);
|
||||
}
|
||||
|
||||
export function as_statement_array(thing) {
|
||||
if (thing === null) return [];
|
||||
if (thing instanceof AST_BlockStatement) return thing.body;
|
||||
if (thing instanceof AST_EmptyStatement) return [];
|
||||
if (thing instanceof AST_Statement) return [ thing ];
|
||||
throw new Error("Can't convert thing to statement array");
|
||||
}
|
||||
|
||||
export function is_reachable(scope_node, defs) {
|
||||
const find_ref = node => {
|
||||
if (node instanceof AST_SymbolRef && defs.includes(node.definition())) {
|
||||
return walk_abort;
|
||||
}
|
||||
};
|
||||
|
||||
return walk_parent(scope_node, (node, info) => {
|
||||
if (node instanceof AST_Scope && node !== scope_node) {
|
||||
var parent = info.parent();
|
||||
|
||||
if (
|
||||
parent instanceof AST_Call
|
||||
&& parent.expression === node
|
||||
// Async/Generators aren't guaranteed to sync evaluate all of
|
||||
// their body steps, so it's possible they close over the variable.
|
||||
&& !(node.async || node.is_generator)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (walk(node, find_ref)) return walk_abort;
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Check if a ref refers to the name of a function/class it's defined within */
|
||||
export function is_recursive_ref(compressor, def) {
|
||||
var node;
|
||||
for (var i = 0; node = compressor.parent(i); i++) {
|
||||
if (node instanceof AST_Lambda || node instanceof AST_Class) {
|
||||
var name = node.name;
|
||||
if (name && name.definition() === def) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO this only works with AST_Defun, shouldn't it work for other ways of defining functions?
|
||||
export function retain_top_func(fn, compressor) {
|
||||
return compressor.top_retain
|
||||
&& fn instanceof AST_Defun
|
||||
&& has_flag(fn, TOP)
|
||||
&& fn.name
|
||||
&& compressor.top_retain(fn.name);
|
||||
}
|
||||
Generated
Vendored
+63
@@ -0,0 +1,63 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
// bitfield flags to be stored in node.flags.
|
||||
// These are set and unset during compression, and store information in the node without requiring multiple fields.
|
||||
export const UNUSED = 0b00000001;
|
||||
export const TRUTHY = 0b00000010;
|
||||
export const FALSY = 0b00000100;
|
||||
export const UNDEFINED = 0b00001000;
|
||||
export const INLINED = 0b00010000;
|
||||
|
||||
// Nodes to which values are ever written. Used when keep_assign is part of the unused option string.
|
||||
export const WRITE_ONLY = 0b00100000;
|
||||
|
||||
// information specific to a single compression pass
|
||||
export const SQUEEZED = 0b0000000100000000;
|
||||
export const OPTIMIZED = 0b0000001000000000;
|
||||
export const TOP = 0b0000010000000000;
|
||||
export const CLEAR_BETWEEN_PASSES = SQUEEZED | OPTIMIZED | TOP;
|
||||
|
||||
export const has_flag = (node, flag) => node.flags & flag;
|
||||
export const set_flag = (node, flag) => { node.flags |= flag; };
|
||||
export const clear_flag = (node, flag) => { node.flags &= ~flag; };
|
||||
Generated
Vendored
+350
@@ -0,0 +1,350 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
import {
|
||||
AST_Accessor,
|
||||
AST_Array,
|
||||
AST_Arrow,
|
||||
AST_Assign,
|
||||
AST_Binary,
|
||||
AST_Call,
|
||||
AST_Chain,
|
||||
AST_Class,
|
||||
AST_ClassProperty,
|
||||
AST_ConciseMethod,
|
||||
AST_Conditional,
|
||||
AST_Constant,
|
||||
AST_Dot,
|
||||
AST_Expansion,
|
||||
AST_Function,
|
||||
AST_Node,
|
||||
AST_Number,
|
||||
AST_Object,
|
||||
AST_ObjectGetter,
|
||||
AST_ObjectKeyVal,
|
||||
AST_ObjectProperty,
|
||||
AST_ObjectSetter,
|
||||
AST_PropAccess,
|
||||
AST_Scope,
|
||||
AST_Sequence,
|
||||
AST_Sub,
|
||||
AST_SymbolRef,
|
||||
AST_TemplateSegment,
|
||||
AST_TemplateString,
|
||||
AST_This,
|
||||
AST_Unary,
|
||||
} from "../ast.js";
|
||||
import { make_node, return_null, return_this } from "../utils/index.js";
|
||||
import { first_in_statement } from "../utils/first_in_statement.js";
|
||||
|
||||
import { pure_prop_access_globals } from "./native-objects.js";
|
||||
import { lazy_op, unary_side_effects, is_nullish_shortcircuited } from "./inference.js";
|
||||
import { WRITE_ONLY, set_flag, clear_flag } from "./compressor-flags.js";
|
||||
import { make_sequence, is_func_expr, is_iife_call } from "./common.js";
|
||||
|
||||
// AST_Node#drop_side_effect_free() gets called when we don't care about the value,
|
||||
// only about side effects. We'll be defining this method for each node type in this module
|
||||
//
|
||||
// Examples:
|
||||
// foo++ -> foo++
|
||||
// 1 + func() -> func()
|
||||
// 10 -> (nothing)
|
||||
// knownPureFunc(foo++) -> foo++
|
||||
|
||||
function def_drop_side_effect_free(node, func) {
|
||||
node.DEFMETHOD("drop_side_effect_free", func);
|
||||
}
|
||||
|
||||
// Drop side-effect-free elements from an array of expressions.
|
||||
// Returns an array of expressions with side-effects or null
|
||||
// if all elements were dropped. Note: original array may be
|
||||
// returned if nothing changed.
|
||||
function trim(nodes, compressor, first_in_statement) {
|
||||
var len = nodes.length;
|
||||
if (!len) return null;
|
||||
|
||||
var ret = [], changed = false;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var node = nodes[i].drop_side_effect_free(compressor, first_in_statement);
|
||||
changed |= node !== nodes[i];
|
||||
if (node) {
|
||||
ret.push(node);
|
||||
first_in_statement = false;
|
||||
}
|
||||
}
|
||||
return changed ? ret.length ? ret : null : nodes;
|
||||
}
|
||||
|
||||
def_drop_side_effect_free(AST_Node, return_this);
|
||||
def_drop_side_effect_free(AST_Constant, return_null);
|
||||
def_drop_side_effect_free(AST_This, return_null);
|
||||
|
||||
def_drop_side_effect_free(AST_Call, function (compressor, first_in_statement) {
|
||||
if (is_nullish_shortcircuited(this, compressor)) {
|
||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
}
|
||||
|
||||
if (!this.is_callee_pure(compressor)) {
|
||||
if (this.expression.is_call_pure(compressor)) {
|
||||
var exprs = this.args.slice();
|
||||
exprs.unshift(this.expression.expression);
|
||||
exprs = trim(exprs, compressor, first_in_statement);
|
||||
return exprs && make_sequence(this, exprs);
|
||||
}
|
||||
if (is_func_expr(this.expression)
|
||||
&& (!this.expression.name || !this.expression.name.definition().references.length)) {
|
||||
var node = this.clone();
|
||||
node.expression.process_expression(false, compressor);
|
||||
return node;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
var args = trim(this.args, compressor, first_in_statement);
|
||||
return args && make_sequence(this, args);
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Accessor, return_null);
|
||||
|
||||
def_drop_side_effect_free(AST_Function, return_null);
|
||||
|
||||
def_drop_side_effect_free(AST_Arrow, return_null);
|
||||
|
||||
def_drop_side_effect_free(AST_Class, function (compressor) {
|
||||
const with_effects = [];
|
||||
const trimmed_extends = this.extends && this.extends.drop_side_effect_free(compressor);
|
||||
if (trimmed_extends)
|
||||
with_effects.push(trimmed_extends);
|
||||
for (const prop of this.properties) {
|
||||
const trimmed_prop = prop.drop_side_effect_free(compressor);
|
||||
if (trimmed_prop)
|
||||
with_effects.push(trimmed_prop);
|
||||
}
|
||||
if (!with_effects.length)
|
||||
return null;
|
||||
return make_sequence(this, with_effects);
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Binary, function (compressor, first_in_statement) {
|
||||
var right = this.right.drop_side_effect_free(compressor);
|
||||
if (!right)
|
||||
return this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (lazy_op.has(this.operator)) {
|
||||
if (right === this.right)
|
||||
return this;
|
||||
var node = this.clone();
|
||||
node.right = right;
|
||||
return node;
|
||||
} else {
|
||||
var left = this.left.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (!left)
|
||||
return this.right.drop_side_effect_free(compressor, first_in_statement);
|
||||
return make_sequence(this, [left, right]);
|
||||
}
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Assign, function (compressor) {
|
||||
if (this.logical)
|
||||
return this;
|
||||
|
||||
var left = this.left;
|
||||
if (left.has_side_effects(compressor)
|
||||
|| compressor.has_directive("use strict")
|
||||
&& left instanceof AST_PropAccess
|
||||
&& left.expression.is_constant()) {
|
||||
return this;
|
||||
}
|
||||
set_flag(this, WRITE_ONLY);
|
||||
while (left instanceof AST_PropAccess) {
|
||||
left = left.expression;
|
||||
}
|
||||
if (left.is_constant_expression(compressor.find_parent(AST_Scope))) {
|
||||
return this.right.drop_side_effect_free(compressor);
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Conditional, function (compressor) {
|
||||
var consequent = this.consequent.drop_side_effect_free(compressor);
|
||||
var alternative = this.alternative.drop_side_effect_free(compressor);
|
||||
if (consequent === this.consequent && alternative === this.alternative)
|
||||
return this;
|
||||
if (!consequent)
|
||||
return alternative ? make_node(AST_Binary, this, {
|
||||
operator: "||",
|
||||
left: this.condition,
|
||||
right: alternative
|
||||
}) : this.condition.drop_side_effect_free(compressor);
|
||||
if (!alternative)
|
||||
return make_node(AST_Binary, this, {
|
||||
operator: "&&",
|
||||
left: this.condition,
|
||||
right: consequent
|
||||
});
|
||||
var node = this.clone();
|
||||
node.consequent = consequent;
|
||||
node.alternative = alternative;
|
||||
return node;
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Unary, function (compressor, first_in_statement) {
|
||||
if (unary_side_effects.has(this.operator)) {
|
||||
if (!this.expression.has_side_effects(compressor)) {
|
||||
set_flag(this, WRITE_ONLY);
|
||||
} else {
|
||||
clear_flag(this, WRITE_ONLY);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
|
||||
return null;
|
||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (first_in_statement && expression && is_iife_call(expression)) {
|
||||
if (expression === this.expression && this.operator == "!")
|
||||
return this;
|
||||
return expression.negate(compressor, first_in_statement);
|
||||
}
|
||||
return expression;
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_SymbolRef, function (compressor) {
|
||||
const safe_access = this.is_declared(compressor)
|
||||
|| pure_prop_access_globals.has(this.name);
|
||||
return safe_access ? null : this;
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Object, function (compressor, first_in_statement) {
|
||||
var values = trim(this.properties, compressor, first_in_statement);
|
||||
return values && make_sequence(this, values);
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_ObjectProperty, function (compressor, first_in_statement) {
|
||||
const computed_key = this instanceof AST_ObjectKeyVal && this.key instanceof AST_Node;
|
||||
const key = computed_key && this.key.drop_side_effect_free(compressor, first_in_statement);
|
||||
const value = this.value && this.value.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (key && value) {
|
||||
return make_sequence(this, [key, value]);
|
||||
}
|
||||
return key || value;
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_ClassProperty, function (compressor) {
|
||||
const key = this.computed_key() && this.key.drop_side_effect_free(compressor);
|
||||
|
||||
const value = this.static && this.value
|
||||
&& this.value.drop_side_effect_free(compressor);
|
||||
|
||||
if (key && value)
|
||||
return make_sequence(this, [key, value]);
|
||||
return key || value || null;
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_ConciseMethod, function () {
|
||||
return this.computed_key() ? this.key : null;
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_ObjectGetter, function () {
|
||||
return this.computed_key() ? this.key : null;
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_ObjectSetter, function () {
|
||||
return this.computed_key() ? this.key : null;
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Array, function (compressor, first_in_statement) {
|
||||
var values = trim(this.elements, compressor, first_in_statement);
|
||||
return values && make_sequence(this, values);
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Dot, function (compressor, first_in_statement) {
|
||||
if (is_nullish_shortcircuited(this, compressor)) {
|
||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
}
|
||||
if (this.expression.may_throw_on_access(compressor)) return this;
|
||||
|
||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Sub, function (compressor, first_in_statement) {
|
||||
if (is_nullish_shortcircuited(this, compressor)) {
|
||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
}
|
||||
if (this.expression.may_throw_on_access(compressor)) return this;
|
||||
|
||||
var expression = this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
if (!expression)
|
||||
return this.property.drop_side_effect_free(compressor, first_in_statement);
|
||||
var property = this.property.drop_side_effect_free(compressor);
|
||||
if (!property)
|
||||
return expression;
|
||||
return make_sequence(this, [expression, property]);
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Chain, function (compressor, first_in_statement) {
|
||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Sequence, function (compressor) {
|
||||
var last = this.tail_node();
|
||||
var expr = last.drop_side_effect_free(compressor);
|
||||
if (expr === last)
|
||||
return this;
|
||||
var expressions = this.expressions.slice(0, -1);
|
||||
if (expr)
|
||||
expressions.push(expr);
|
||||
if (!expressions.length) {
|
||||
return make_node(AST_Number, this, { value: 0 });
|
||||
}
|
||||
return make_sequence(this, expressions);
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_Expansion, function (compressor, first_in_statement) {
|
||||
return this.expression.drop_side_effect_free(compressor, first_in_statement);
|
||||
});
|
||||
|
||||
def_drop_side_effect_free(AST_TemplateSegment, return_null);
|
||||
|
||||
def_drop_side_effect_free(AST_TemplateString, function (compressor) {
|
||||
var values = trim(this.segments, compressor, first_in_statement);
|
||||
return values && make_sequence(this, values);
|
||||
});
|
||||
+462
@@ -0,0 +1,462 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
import {
|
||||
HOP,
|
||||
makePredicate,
|
||||
return_this,
|
||||
string_template,
|
||||
regexp_source_fix,
|
||||
regexp_is_safe,
|
||||
} from "../utils/index.js";
|
||||
import {
|
||||
AST_Array,
|
||||
AST_BigInt,
|
||||
AST_Binary,
|
||||
AST_Call,
|
||||
AST_Chain,
|
||||
AST_Class,
|
||||
AST_Conditional,
|
||||
AST_Constant,
|
||||
AST_Dot,
|
||||
AST_Expansion,
|
||||
AST_Function,
|
||||
AST_Lambda,
|
||||
AST_New,
|
||||
AST_Node,
|
||||
AST_Object,
|
||||
AST_PropAccess,
|
||||
AST_RegExp,
|
||||
AST_Statement,
|
||||
AST_Symbol,
|
||||
AST_SymbolRef,
|
||||
AST_TemplateString,
|
||||
AST_UnaryPrefix,
|
||||
AST_With,
|
||||
} from "../ast.js";
|
||||
import { is_undeclared_ref} from "./inference.js";
|
||||
import { is_pure_native_value, is_pure_native_fn, is_pure_native_method } from "./native-objects.js";
|
||||
|
||||
// methods to evaluate a constant expression
|
||||
|
||||
function def_eval(node, func) {
|
||||
node.DEFMETHOD("_eval", func);
|
||||
}
|
||||
|
||||
// Used to propagate a nullish short-circuit signal upwards through the chain.
|
||||
export const nullish = Symbol("This AST_Chain is nullish");
|
||||
|
||||
// If the node has been successfully reduced to a constant,
|
||||
// then its value is returned; otherwise the element itself
|
||||
// is returned.
|
||||
// They can be distinguished as constant value is never a
|
||||
// descendant of AST_Node.
|
||||
AST_Node.DEFMETHOD("evaluate", function (compressor) {
|
||||
if (!compressor.option("evaluate"))
|
||||
return this;
|
||||
var val = this._eval(compressor, 1);
|
||||
if (!val || val instanceof RegExp)
|
||||
return val;
|
||||
if (typeof val == "function" || typeof val == "object" || val == nullish)
|
||||
return this;
|
||||
return val;
|
||||
});
|
||||
|
||||
var unaryPrefix = makePredicate("! ~ - + void");
|
||||
AST_Node.DEFMETHOD("is_constant", function () {
|
||||
// Accomodate when compress option evaluate=false
|
||||
// as well as the common constant expressions !0 and -1
|
||||
if (this instanceof AST_Constant) {
|
||||
return !(this instanceof AST_RegExp);
|
||||
} else {
|
||||
return this instanceof AST_UnaryPrefix
|
||||
&& this.expression instanceof AST_Constant
|
||||
&& unaryPrefix.has(this.operator);
|
||||
}
|
||||
});
|
||||
|
||||
def_eval(AST_Statement, function () {
|
||||
throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
|
||||
});
|
||||
|
||||
def_eval(AST_Lambda, return_this);
|
||||
def_eval(AST_Class, return_this);
|
||||
def_eval(AST_Node, return_this);
|
||||
def_eval(AST_Constant, function () {
|
||||
return this.getValue();
|
||||
});
|
||||
|
||||
def_eval(AST_BigInt, return_this);
|
||||
|
||||
def_eval(AST_RegExp, function (compressor) {
|
||||
let evaluated = compressor.evaluated_regexps.get(this.value);
|
||||
if (evaluated === undefined && regexp_is_safe(this.value.source)) {
|
||||
try {
|
||||
const { source, flags } = this.value;
|
||||
evaluated = new RegExp(source, flags);
|
||||
} catch (e) {
|
||||
evaluated = null;
|
||||
}
|
||||
compressor.evaluated_regexps.set(this.value, evaluated);
|
||||
}
|
||||
return evaluated || this;
|
||||
});
|
||||
|
||||
def_eval(AST_TemplateString, function () {
|
||||
if (this.segments.length !== 1) return this;
|
||||
return this.segments[0].value;
|
||||
});
|
||||
|
||||
def_eval(AST_Function, function (compressor) {
|
||||
if (compressor.option("unsafe")) {
|
||||
var fn = function () { };
|
||||
fn.node = this;
|
||||
fn.toString = () => this.print_to_string();
|
||||
return fn;
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
def_eval(AST_Array, function (compressor, depth) {
|
||||
if (compressor.option("unsafe")) {
|
||||
var elements = [];
|
||||
for (var i = 0, len = this.elements.length; i < len; i++) {
|
||||
var element = this.elements[i];
|
||||
var value = element._eval(compressor, depth);
|
||||
if (element === value)
|
||||
return this;
|
||||
elements.push(value);
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
def_eval(AST_Object, function (compressor, depth) {
|
||||
if (compressor.option("unsafe")) {
|
||||
var val = {};
|
||||
for (var i = 0, len = this.properties.length; i < len; i++) {
|
||||
var prop = this.properties[i];
|
||||
if (prop instanceof AST_Expansion)
|
||||
return this;
|
||||
var key = prop.key;
|
||||
if (key instanceof AST_Symbol) {
|
||||
key = key.name;
|
||||
} else if (key instanceof AST_Node) {
|
||||
key = key._eval(compressor, depth);
|
||||
if (key === prop.key)
|
||||
return this;
|
||||
}
|
||||
if (typeof Object.prototype[key] === "function") {
|
||||
return this;
|
||||
}
|
||||
if (prop.value instanceof AST_Function)
|
||||
continue;
|
||||
val[key] = prop.value._eval(compressor, depth);
|
||||
if (val[key] === prop.value)
|
||||
return this;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
var non_converting_unary = makePredicate("! typeof void");
|
||||
def_eval(AST_UnaryPrefix, function (compressor, depth) {
|
||||
var e = this.expression;
|
||||
// Function would be evaluated to an array and so typeof would
|
||||
// incorrectly return 'object'. Hence making is a special case.
|
||||
if (compressor.option("typeofs")
|
||||
&& this.operator == "typeof"
|
||||
&& (e instanceof AST_Lambda
|
||||
|| e instanceof AST_SymbolRef
|
||||
&& e.fixed_value() instanceof AST_Lambda)) {
|
||||
return typeof function () { };
|
||||
}
|
||||
if (!non_converting_unary.has(this.operator))
|
||||
depth++;
|
||||
e = e._eval(compressor, depth);
|
||||
if (e === this.expression)
|
||||
return this;
|
||||
switch (this.operator) {
|
||||
case "!": return !e;
|
||||
case "typeof":
|
||||
// typeof <RegExp> returns "object" or "function" on different platforms
|
||||
// so cannot evaluate reliably
|
||||
if (e instanceof RegExp)
|
||||
return this;
|
||||
return typeof e;
|
||||
case "void": return void e;
|
||||
case "~": return ~e;
|
||||
case "-": return -e;
|
||||
case "+": return +e;
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
var non_converting_binary = makePredicate("&& || ?? === !==");
|
||||
const identity_comparison = makePredicate("== != === !==");
|
||||
const has_identity = value => typeof value === "object"
|
||||
|| typeof value === "function"
|
||||
|| typeof value === "symbol";
|
||||
|
||||
def_eval(AST_Binary, function (compressor, depth) {
|
||||
if (!non_converting_binary.has(this.operator))
|
||||
depth++;
|
||||
|
||||
var left = this.left._eval(compressor, depth);
|
||||
if (left === this.left)
|
||||
return this;
|
||||
var right = this.right._eval(compressor, depth);
|
||||
if (right === this.right)
|
||||
return this;
|
||||
var result;
|
||||
|
||||
if (left != null
|
||||
&& right != null
|
||||
&& identity_comparison.has(this.operator)
|
||||
&& has_identity(left)
|
||||
&& has_identity(right)
|
||||
&& typeof left === typeof right) {
|
||||
// Do not compare by reference
|
||||
return this;
|
||||
}
|
||||
|
||||
switch (this.operator) {
|
||||
case "&&": result = left && right; break;
|
||||
case "||": result = left || right; break;
|
||||
case "??": result = left != null ? left : right; break;
|
||||
case "|": result = left | right; break;
|
||||
case "&": result = left & right; break;
|
||||
case "^": result = left ^ right; break;
|
||||
case "+": result = left + right; break;
|
||||
case "*": result = left * right; break;
|
||||
case "**": result = Math.pow(left, right); break;
|
||||
case "/": result = left / right; break;
|
||||
case "%": result = left % right; break;
|
||||
case "-": result = left - right; break;
|
||||
case "<<": result = left << right; break;
|
||||
case ">>": result = left >> right; break;
|
||||
case ">>>": result = left >>> right; break;
|
||||
case "==": result = left == right; break;
|
||||
case "===": result = left === right; break;
|
||||
case "!=": result = left != right; break;
|
||||
case "!==": result = left !== right; break;
|
||||
case "<": result = left < right; break;
|
||||
case "<=": result = left <= right; break;
|
||||
case ">": result = left > right; break;
|
||||
case ">=": result = left >= right; break;
|
||||
default:
|
||||
return this;
|
||||
}
|
||||
if (isNaN(result) && compressor.find_parent(AST_With)) {
|
||||
// leave original expression as is
|
||||
return this;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
def_eval(AST_Conditional, function (compressor, depth) {
|
||||
var condition = this.condition._eval(compressor, depth);
|
||||
if (condition === this.condition)
|
||||
return this;
|
||||
var node = condition ? this.consequent : this.alternative;
|
||||
var value = node._eval(compressor, depth);
|
||||
return value === node ? this : value;
|
||||
});
|
||||
|
||||
// Set of AST_SymbolRef which are currently being evaluated.
|
||||
// Avoids infinite recursion of ._eval()
|
||||
const reentrant_ref_eval = new Set();
|
||||
def_eval(AST_SymbolRef, function (compressor, depth) {
|
||||
if (reentrant_ref_eval.has(this))
|
||||
return this;
|
||||
|
||||
var fixed = this.fixed_value();
|
||||
if (!fixed)
|
||||
return this;
|
||||
|
||||
reentrant_ref_eval.add(this);
|
||||
const value = fixed._eval(compressor, depth);
|
||||
reentrant_ref_eval.delete(this);
|
||||
|
||||
if (value === fixed)
|
||||
return this;
|
||||
|
||||
if (value && typeof value == "object") {
|
||||
var escaped = this.definition().escaped;
|
||||
if (escaped && depth > escaped)
|
||||
return this;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
const global_objs = { Array, Math, Number, Object, String };
|
||||
|
||||
const regexp_flags = new Set([
|
||||
"dotAll",
|
||||
"global",
|
||||
"ignoreCase",
|
||||
"multiline",
|
||||
"sticky",
|
||||
"unicode",
|
||||
]);
|
||||
|
||||
def_eval(AST_PropAccess, function (compressor, depth) {
|
||||
let obj = this.expression._eval(compressor, depth + 1);
|
||||
if (obj === nullish || (this.optional && obj == null)) return nullish;
|
||||
if (compressor.option("unsafe")) {
|
||||
var key = this.property;
|
||||
if (key instanceof AST_Node) {
|
||||
key = key._eval(compressor, depth);
|
||||
if (key === this.property)
|
||||
return this;
|
||||
}
|
||||
var exp = this.expression;
|
||||
if (is_undeclared_ref(exp)) {
|
||||
|
||||
var aa;
|
||||
var first_arg = exp.name === "hasOwnProperty"
|
||||
&& key === "call"
|
||||
&& (aa = compressor.parent() && compressor.parent().args)
|
||||
&& (aa && aa[0]
|
||||
&& aa[0].evaluate(compressor));
|
||||
|
||||
first_arg = first_arg instanceof AST_Dot ? first_arg.expression : first_arg;
|
||||
|
||||
if (first_arg == null || first_arg.thedef && first_arg.thedef.undeclared) {
|
||||
return this.clone();
|
||||
}
|
||||
if (!is_pure_native_value(exp.name, key))
|
||||
return this;
|
||||
obj = global_objs[exp.name];
|
||||
} else {
|
||||
if (obj instanceof RegExp) {
|
||||
if (key == "source") {
|
||||
return regexp_source_fix(obj.source);
|
||||
} else if (key == "flags" || regexp_flags.has(key)) {
|
||||
return obj[key];
|
||||
}
|
||||
}
|
||||
if (!obj || obj === exp || !HOP(obj, key))
|
||||
return this;
|
||||
|
||||
if (typeof obj == "function")
|
||||
switch (key) {
|
||||
case "name":
|
||||
return obj.node.name ? obj.node.name.name : "";
|
||||
case "length":
|
||||
return obj.node.length_property();
|
||||
default:
|
||||
return this;
|
||||
}
|
||||
}
|
||||
return obj[key];
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
def_eval(AST_Chain, function (compressor, depth) {
|
||||
const evaluated = this.expression._eval(compressor, depth);
|
||||
return evaluated === nullish
|
||||
? undefined
|
||||
: evaluated === this.expression
|
||||
? this
|
||||
: evaluated;
|
||||
});
|
||||
|
||||
def_eval(AST_Call, function (compressor, depth) {
|
||||
var exp = this.expression;
|
||||
|
||||
const callee = exp._eval(compressor, depth);
|
||||
if (callee === nullish || (this.optional && callee == null)) return nullish;
|
||||
|
||||
if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
|
||||
var key = exp.property;
|
||||
if (key instanceof AST_Node) {
|
||||
key = key._eval(compressor, depth);
|
||||
if (key === exp.property)
|
||||
return this;
|
||||
}
|
||||
var val;
|
||||
var e = exp.expression;
|
||||
if (is_undeclared_ref(e)) {
|
||||
var first_arg = e.name === "hasOwnProperty" &&
|
||||
key === "call" &&
|
||||
(this.args[0] && this.args[0].evaluate(compressor));
|
||||
|
||||
first_arg = first_arg instanceof AST_Dot ? first_arg.expression : first_arg;
|
||||
|
||||
if ((first_arg == null || first_arg.thedef && first_arg.thedef.undeclared)) {
|
||||
return this.clone();
|
||||
}
|
||||
if (!is_pure_native_fn(e.name, key)) return this;
|
||||
val = global_objs[e.name];
|
||||
} else {
|
||||
val = e._eval(compressor, depth + 1);
|
||||
if (val === e || !val)
|
||||
return this;
|
||||
if (!is_pure_native_method(val.constructor.name, key))
|
||||
return this;
|
||||
}
|
||||
var args = [];
|
||||
for (var i = 0, len = this.args.length; i < len; i++) {
|
||||
var arg = this.args[i];
|
||||
var value = arg._eval(compressor, depth);
|
||||
if (arg === value)
|
||||
return this;
|
||||
if (arg instanceof AST_Lambda)
|
||||
return this;
|
||||
args.push(value);
|
||||
}
|
||||
try {
|
||||
return val[key].apply(val, args);
|
||||
} catch (ex) {
|
||||
// We don't really care
|
||||
}
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
// Also a subclass of AST_Call
|
||||
def_eval(AST_New, return_this);
|
||||
+4152
File diff suppressed because it is too large
Load Diff
+948
@@ -0,0 +1,948 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
import {
|
||||
AST_Array,
|
||||
AST_Arrow,
|
||||
AST_Assign,
|
||||
AST_Binary,
|
||||
AST_Block,
|
||||
AST_BlockStatement,
|
||||
AST_Call,
|
||||
AST_Case,
|
||||
AST_Chain,
|
||||
AST_Class,
|
||||
AST_ClassProperty,
|
||||
AST_ConciseMethod,
|
||||
AST_Conditional,
|
||||
AST_Constant,
|
||||
AST_Definitions,
|
||||
AST_Dot,
|
||||
AST_EmptyStatement,
|
||||
AST_Expansion,
|
||||
AST_False,
|
||||
AST_Function,
|
||||
AST_If,
|
||||
AST_Import,
|
||||
AST_Jump,
|
||||
AST_LabeledStatement,
|
||||
AST_Lambda,
|
||||
AST_New,
|
||||
AST_Node,
|
||||
AST_Null,
|
||||
AST_Number,
|
||||
AST_Object,
|
||||
AST_ObjectGetter,
|
||||
AST_ObjectKeyVal,
|
||||
AST_ObjectProperty,
|
||||
AST_ObjectSetter,
|
||||
AST_PropAccess,
|
||||
AST_RegExp,
|
||||
AST_Return,
|
||||
AST_Sequence,
|
||||
AST_SimpleStatement,
|
||||
AST_Statement,
|
||||
AST_String,
|
||||
AST_Sub,
|
||||
AST_Switch,
|
||||
AST_SwitchBranch,
|
||||
AST_SymbolClassProperty,
|
||||
AST_SymbolDeclaration,
|
||||
AST_SymbolRef,
|
||||
AST_TemplateSegment,
|
||||
AST_TemplateString,
|
||||
AST_This,
|
||||
AST_Toplevel,
|
||||
AST_True,
|
||||
AST_Try,
|
||||
AST_Unary,
|
||||
AST_UnaryPostfix,
|
||||
AST_UnaryPrefix,
|
||||
AST_Undefined,
|
||||
AST_VarDef,
|
||||
|
||||
TreeTransformer,
|
||||
walk,
|
||||
walk_abort,
|
||||
|
||||
_PURE
|
||||
} from "../ast.js";
|
||||
import {
|
||||
makePredicate,
|
||||
return_true,
|
||||
return_false,
|
||||
return_null,
|
||||
return_this,
|
||||
make_node,
|
||||
member,
|
||||
noop,
|
||||
has_annotation,
|
||||
HOP
|
||||
} from "../utils/index.js";
|
||||
import { make_node_from_constant, make_sequence, best_of_expression, read_property } from "./common.js";
|
||||
|
||||
import { INLINED, UNDEFINED, has_flag } from "./compressor-flags.js";
|
||||
import { pure_prop_access_globals, is_pure_native_fn, is_pure_native_method } from "./native-objects.js";
|
||||
|
||||
// Functions and methods to infer certain facts about expressions
|
||||
// It's not always possible to be 100% sure about something just by static analysis,
|
||||
// so `true` means yes, and `false` means maybe
|
||||
|
||||
export const is_undeclared_ref = (node) =>
|
||||
node instanceof AST_SymbolRef && node.definition().undeclared;
|
||||
|
||||
export const lazy_op = makePredicate("&& || ??");
|
||||
export const unary_side_effects = makePredicate("delete ++ --");
|
||||
|
||||
// methods to determine whether an expression has a boolean result type
|
||||
(function(def_is_boolean) {
|
||||
const unary_bool = makePredicate("! delete");
|
||||
const binary_bool = makePredicate("in instanceof == != === !== < <= >= >");
|
||||
def_is_boolean(AST_Node, return_false);
|
||||
def_is_boolean(AST_UnaryPrefix, function() {
|
||||
return unary_bool.has(this.operator);
|
||||
});
|
||||
def_is_boolean(AST_Binary, function() {
|
||||
return binary_bool.has(this.operator)
|
||||
|| lazy_op.has(this.operator)
|
||||
&& this.left.is_boolean()
|
||||
&& this.right.is_boolean();
|
||||
});
|
||||
def_is_boolean(AST_Conditional, function() {
|
||||
return this.consequent.is_boolean() && this.alternative.is_boolean();
|
||||
});
|
||||
def_is_boolean(AST_Assign, function() {
|
||||
return this.operator == "=" && this.right.is_boolean();
|
||||
});
|
||||
def_is_boolean(AST_Sequence, function() {
|
||||
return this.tail_node().is_boolean();
|
||||
});
|
||||
def_is_boolean(AST_True, return_true);
|
||||
def_is_boolean(AST_False, return_true);
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_boolean", func);
|
||||
});
|
||||
|
||||
// methods to determine if an expression has a numeric result type
|
||||
(function(def_is_number) {
|
||||
def_is_number(AST_Node, return_false);
|
||||
def_is_number(AST_Number, return_true);
|
||||
const unary = makePredicate("+ - ~ ++ --");
|
||||
def_is_number(AST_Unary, function() {
|
||||
return unary.has(this.operator);
|
||||
});
|
||||
const numeric_ops = makePredicate("- * / % & | ^ << >> >>>");
|
||||
def_is_number(AST_Binary, function(compressor) {
|
||||
return numeric_ops.has(this.operator) || this.operator == "+"
|
||||
&& this.left.is_number(compressor)
|
||||
&& this.right.is_number(compressor);
|
||||
});
|
||||
def_is_number(AST_Assign, function(compressor) {
|
||||
return numeric_ops.has(this.operator.slice(0, -1))
|
||||
|| this.operator == "=" && this.right.is_number(compressor);
|
||||
});
|
||||
def_is_number(AST_Sequence, function(compressor) {
|
||||
return this.tail_node().is_number(compressor);
|
||||
});
|
||||
def_is_number(AST_Conditional, function(compressor) {
|
||||
return this.consequent.is_number(compressor) && this.alternative.is_number(compressor);
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_number", func);
|
||||
});
|
||||
|
||||
// methods to determine if an expression has a string result type
|
||||
(function(def_is_string) {
|
||||
def_is_string(AST_Node, return_false);
|
||||
def_is_string(AST_String, return_true);
|
||||
def_is_string(AST_TemplateString, return_true);
|
||||
def_is_string(AST_UnaryPrefix, function() {
|
||||
return this.operator == "typeof";
|
||||
});
|
||||
def_is_string(AST_Binary, function(compressor) {
|
||||
return this.operator == "+" &&
|
||||
(this.left.is_string(compressor) || this.right.is_string(compressor));
|
||||
});
|
||||
def_is_string(AST_Assign, function(compressor) {
|
||||
return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor);
|
||||
});
|
||||
def_is_string(AST_Sequence, function(compressor) {
|
||||
return this.tail_node().is_string(compressor);
|
||||
});
|
||||
def_is_string(AST_Conditional, function(compressor) {
|
||||
return this.consequent.is_string(compressor) && this.alternative.is_string(compressor);
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_string", func);
|
||||
});
|
||||
|
||||
export function is_undefined(node, compressor) {
|
||||
return (
|
||||
has_flag(node, UNDEFINED)
|
||||
|| node instanceof AST_Undefined
|
||||
|| node instanceof AST_UnaryPrefix
|
||||
&& node.operator == "void"
|
||||
&& !node.expression.has_side_effects(compressor)
|
||||
);
|
||||
}
|
||||
|
||||
// Is the node explicitly null or undefined.
|
||||
function is_null_or_undefined(node, compressor) {
|
||||
let fixed;
|
||||
return (
|
||||
node instanceof AST_Null
|
||||
|| is_undefined(node, compressor)
|
||||
|| (
|
||||
node instanceof AST_SymbolRef
|
||||
&& (fixed = node.definition().fixed) instanceof AST_Node
|
||||
&& is_nullish(fixed, compressor)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Find out if this expression is optionally chained from a base-point that we
|
||||
// can statically analyze as null or undefined.
|
||||
export function is_nullish_shortcircuited(node, compressor) {
|
||||
if (node instanceof AST_PropAccess || node instanceof AST_Call) {
|
||||
return (
|
||||
(node.optional && is_null_or_undefined(node.expression, compressor))
|
||||
|| is_nullish_shortcircuited(node.expression, compressor)
|
||||
);
|
||||
}
|
||||
if (node instanceof AST_Chain) return is_nullish_shortcircuited(node.expression, compressor);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find out if something is == null, or can short circuit into nullish.
|
||||
// Used to optimize ?. and ??
|
||||
export function is_nullish(node, compressor) {
|
||||
if (is_null_or_undefined(node, compressor)) return true;
|
||||
return is_nullish_shortcircuited(node, compressor);
|
||||
}
|
||||
|
||||
// Determine if expression might cause side effects
|
||||
// If there's a possibility that a node may change something when it's executed, this returns true
|
||||
(function(def_has_side_effects) {
|
||||
def_has_side_effects(AST_Node, return_true);
|
||||
|
||||
def_has_side_effects(AST_EmptyStatement, return_false);
|
||||
def_has_side_effects(AST_Constant, return_false);
|
||||
def_has_side_effects(AST_This, return_false);
|
||||
|
||||
function any(list, compressor) {
|
||||
for (var i = list.length; --i >= 0;)
|
||||
if (list[i].has_side_effects(compressor))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
def_has_side_effects(AST_Block, function(compressor) {
|
||||
return any(this.body, compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Call, function(compressor) {
|
||||
if (
|
||||
!this.is_callee_pure(compressor)
|
||||
&& (!this.expression.is_call_pure(compressor)
|
||||
|| this.expression.has_side_effects(compressor))
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return any(this.args, compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Switch, function(compressor) {
|
||||
return this.expression.has_side_effects(compressor)
|
||||
|| any(this.body, compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Case, function(compressor) {
|
||||
return this.expression.has_side_effects(compressor)
|
||||
|| any(this.body, compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Try, function(compressor) {
|
||||
return any(this.body, compressor)
|
||||
|| this.bcatch && this.bcatch.has_side_effects(compressor)
|
||||
|| this.bfinally && this.bfinally.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_If, function(compressor) {
|
||||
return this.condition.has_side_effects(compressor)
|
||||
|| this.body && this.body.has_side_effects(compressor)
|
||||
|| this.alternative && this.alternative.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_LabeledStatement, function(compressor) {
|
||||
return this.body.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_SimpleStatement, function(compressor) {
|
||||
return this.body.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Lambda, return_false);
|
||||
def_has_side_effects(AST_Class, function (compressor) {
|
||||
if (this.extends && this.extends.has_side_effects(compressor)) {
|
||||
return true;
|
||||
}
|
||||
return any(this.properties, compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Binary, function(compressor) {
|
||||
return this.left.has_side_effects(compressor)
|
||||
|| this.right.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Assign, return_true);
|
||||
def_has_side_effects(AST_Conditional, function(compressor) {
|
||||
return this.condition.has_side_effects(compressor)
|
||||
|| this.consequent.has_side_effects(compressor)
|
||||
|| this.alternative.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Unary, function(compressor) {
|
||||
return unary_side_effects.has(this.operator)
|
||||
|| this.expression.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_SymbolRef, function(compressor) {
|
||||
return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name);
|
||||
});
|
||||
def_has_side_effects(AST_SymbolClassProperty, return_false);
|
||||
def_has_side_effects(AST_SymbolDeclaration, return_false);
|
||||
def_has_side_effects(AST_Object, function(compressor) {
|
||||
return any(this.properties, compressor);
|
||||
});
|
||||
def_has_side_effects(AST_ObjectProperty, function(compressor) {
|
||||
return (
|
||||
this.computed_key() && this.key.has_side_effects(compressor)
|
||||
|| this.value && this.value.has_side_effects(compressor)
|
||||
);
|
||||
});
|
||||
def_has_side_effects(AST_ClassProperty, function(compressor) {
|
||||
return (
|
||||
this.computed_key() && this.key.has_side_effects(compressor)
|
||||
|| this.static && this.value && this.value.has_side_effects(compressor)
|
||||
);
|
||||
});
|
||||
def_has_side_effects(AST_ConciseMethod, function(compressor) {
|
||||
return this.computed_key() && this.key.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_ObjectGetter, function(compressor) {
|
||||
return this.computed_key() && this.key.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_ObjectSetter, function(compressor) {
|
||||
return this.computed_key() && this.key.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Array, function(compressor) {
|
||||
return any(this.elements, compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Dot, function(compressor) {
|
||||
if (is_nullish(this, compressor)) return false;
|
||||
return !this.optional && this.expression.may_throw_on_access(compressor)
|
||||
|| this.expression.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Sub, function(compressor) {
|
||||
if (is_nullish(this, compressor)) return false;
|
||||
|
||||
return !this.optional && this.expression.may_throw_on_access(compressor)
|
||||
|| this.expression.has_side_effects(compressor)
|
||||
|| this.property.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Chain, function (compressor) {
|
||||
return this.expression.has_side_effects(compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Sequence, function(compressor) {
|
||||
return any(this.expressions, compressor);
|
||||
});
|
||||
def_has_side_effects(AST_Definitions, function(compressor) {
|
||||
return any(this.definitions, compressor);
|
||||
});
|
||||
def_has_side_effects(AST_VarDef, function() {
|
||||
return this.value;
|
||||
});
|
||||
def_has_side_effects(AST_TemplateSegment, return_false);
|
||||
def_has_side_effects(AST_TemplateString, function(compressor) {
|
||||
return any(this.segments, compressor);
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("has_side_effects", func);
|
||||
});
|
||||
|
||||
// determine if expression may throw
|
||||
(function(def_may_throw) {
|
||||
def_may_throw(AST_Node, return_true);
|
||||
|
||||
def_may_throw(AST_Constant, return_false);
|
||||
def_may_throw(AST_EmptyStatement, return_false);
|
||||
def_may_throw(AST_Lambda, return_false);
|
||||
def_may_throw(AST_SymbolDeclaration, return_false);
|
||||
def_may_throw(AST_This, return_false);
|
||||
|
||||
function any(list, compressor) {
|
||||
for (var i = list.length; --i >= 0;)
|
||||
if (list[i].may_throw(compressor))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
def_may_throw(AST_Class, function(compressor) {
|
||||
if (this.extends && this.extends.may_throw(compressor)) return true;
|
||||
return any(this.properties, compressor);
|
||||
});
|
||||
|
||||
def_may_throw(AST_Array, function(compressor) {
|
||||
return any(this.elements, compressor);
|
||||
});
|
||||
def_may_throw(AST_Assign, function(compressor) {
|
||||
if (this.right.may_throw(compressor)) return true;
|
||||
if (!compressor.has_directive("use strict")
|
||||
&& this.operator == "="
|
||||
&& this.left instanceof AST_SymbolRef) {
|
||||
return false;
|
||||
}
|
||||
return this.left.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Binary, function(compressor) {
|
||||
return this.left.may_throw(compressor)
|
||||
|| this.right.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Block, function(compressor) {
|
||||
return any(this.body, compressor);
|
||||
});
|
||||
def_may_throw(AST_Call, function(compressor) {
|
||||
if (is_nullish(this, compressor)) return false;
|
||||
if (any(this.args, compressor)) return true;
|
||||
if (this.is_callee_pure(compressor)) return false;
|
||||
if (this.expression.may_throw(compressor)) return true;
|
||||
return !(this.expression instanceof AST_Lambda)
|
||||
|| any(this.expression.body, compressor);
|
||||
});
|
||||
def_may_throw(AST_Case, function(compressor) {
|
||||
return this.expression.may_throw(compressor)
|
||||
|| any(this.body, compressor);
|
||||
});
|
||||
def_may_throw(AST_Conditional, function(compressor) {
|
||||
return this.condition.may_throw(compressor)
|
||||
|| this.consequent.may_throw(compressor)
|
||||
|| this.alternative.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Definitions, function(compressor) {
|
||||
return any(this.definitions, compressor);
|
||||
});
|
||||
def_may_throw(AST_If, function(compressor) {
|
||||
return this.condition.may_throw(compressor)
|
||||
|| this.body && this.body.may_throw(compressor)
|
||||
|| this.alternative && this.alternative.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_LabeledStatement, function(compressor) {
|
||||
return this.body.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Object, function(compressor) {
|
||||
return any(this.properties, compressor);
|
||||
});
|
||||
def_may_throw(AST_ObjectProperty, function(compressor) {
|
||||
// TODO key may throw too
|
||||
return this.value ? this.value.may_throw(compressor) : false;
|
||||
});
|
||||
def_may_throw(AST_ClassProperty, function(compressor) {
|
||||
return (
|
||||
this.computed_key() && this.key.may_throw(compressor)
|
||||
|| this.static && this.value && this.value.may_throw(compressor)
|
||||
);
|
||||
});
|
||||
def_may_throw(AST_ConciseMethod, function(compressor) {
|
||||
return this.computed_key() && this.key.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_ObjectGetter, function(compressor) {
|
||||
return this.computed_key() && this.key.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_ObjectSetter, function(compressor) {
|
||||
return this.computed_key() && this.key.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Return, function(compressor) {
|
||||
return this.value && this.value.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Sequence, function(compressor) {
|
||||
return any(this.expressions, compressor);
|
||||
});
|
||||
def_may_throw(AST_SimpleStatement, function(compressor) {
|
||||
return this.body.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Dot, function(compressor) {
|
||||
if (is_nullish(this, compressor)) return false;
|
||||
return !this.optional && this.expression.may_throw_on_access(compressor)
|
||||
|| this.expression.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Sub, function(compressor) {
|
||||
if (is_nullish(this, compressor)) return false;
|
||||
return !this.optional && this.expression.may_throw_on_access(compressor)
|
||||
|| this.expression.may_throw(compressor)
|
||||
|| this.property.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Chain, function(compressor) {
|
||||
return this.expression.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Switch, function(compressor) {
|
||||
return this.expression.may_throw(compressor)
|
||||
|| any(this.body, compressor);
|
||||
});
|
||||
def_may_throw(AST_SymbolRef, function(compressor) {
|
||||
return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name);
|
||||
});
|
||||
def_may_throw(AST_SymbolClassProperty, return_false);
|
||||
def_may_throw(AST_Try, function(compressor) {
|
||||
return this.bcatch ? this.bcatch.may_throw(compressor) : any(this.body, compressor)
|
||||
|| this.bfinally && this.bfinally.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_Unary, function(compressor) {
|
||||
if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef)
|
||||
return false;
|
||||
return this.expression.may_throw(compressor);
|
||||
});
|
||||
def_may_throw(AST_VarDef, function(compressor) {
|
||||
if (!this.value) return false;
|
||||
return this.value.may_throw(compressor);
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("may_throw", func);
|
||||
});
|
||||
|
||||
// determine if expression is constant
|
||||
(function(def_is_constant_expression) {
|
||||
function all_refs_local(scope) {
|
||||
let result = true;
|
||||
walk(this, node => {
|
||||
if (node instanceof AST_SymbolRef) {
|
||||
if (has_flag(this, INLINED)) {
|
||||
result = false;
|
||||
return walk_abort;
|
||||
}
|
||||
var def = node.definition();
|
||||
if (
|
||||
member(def, this.enclosed)
|
||||
&& !this.variables.has(def.name)
|
||||
) {
|
||||
if (scope) {
|
||||
var scope_def = scope.find_variable(node);
|
||||
if (def.undeclared ? !scope_def : scope_def === def) {
|
||||
result = "f";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
result = false;
|
||||
return walk_abort;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (node instanceof AST_This && this instanceof AST_Arrow) {
|
||||
// TODO check arguments too!
|
||||
result = false;
|
||||
return walk_abort;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
def_is_constant_expression(AST_Node, return_false);
|
||||
def_is_constant_expression(AST_Constant, return_true);
|
||||
def_is_constant_expression(AST_Class, function(scope) {
|
||||
if (this.extends && !this.extends.is_constant_expression(scope)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const prop of this.properties) {
|
||||
if (prop.computed_key() && !prop.key.is_constant_expression(scope)) {
|
||||
return false;
|
||||
}
|
||||
if (prop.static && prop.value && !prop.value.is_constant_expression(scope)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return all_refs_local.call(this, scope);
|
||||
});
|
||||
def_is_constant_expression(AST_Lambda, all_refs_local);
|
||||
def_is_constant_expression(AST_Unary, function() {
|
||||
return this.expression.is_constant_expression();
|
||||
});
|
||||
def_is_constant_expression(AST_Binary, function() {
|
||||
return this.left.is_constant_expression()
|
||||
&& this.right.is_constant_expression();
|
||||
});
|
||||
def_is_constant_expression(AST_Array, function() {
|
||||
return this.elements.every((l) => l.is_constant_expression());
|
||||
});
|
||||
def_is_constant_expression(AST_Object, function() {
|
||||
return this.properties.every((l) => l.is_constant_expression());
|
||||
});
|
||||
def_is_constant_expression(AST_ObjectProperty, function() {
|
||||
return !!(!(this.key instanceof AST_Node) && this.value && this.value.is_constant_expression());
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("is_constant_expression", func);
|
||||
});
|
||||
|
||||
|
||||
// may_throw_on_access()
|
||||
// returns true if this node may be null, undefined or contain `AST_Accessor`
|
||||
(function(def_may_throw_on_access) {
|
||||
AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) {
|
||||
return !compressor.option("pure_getters")
|
||||
|| this._dot_throw(compressor);
|
||||
});
|
||||
|
||||
function is_strict(compressor) {
|
||||
return /strict/.test(compressor.option("pure_getters"));
|
||||
}
|
||||
|
||||
def_may_throw_on_access(AST_Node, is_strict);
|
||||
def_may_throw_on_access(AST_Null, return_true);
|
||||
def_may_throw_on_access(AST_Undefined, return_true);
|
||||
def_may_throw_on_access(AST_Constant, return_false);
|
||||
def_may_throw_on_access(AST_Array, return_false);
|
||||
def_may_throw_on_access(AST_Object, function(compressor) {
|
||||
if (!is_strict(compressor)) return false;
|
||||
for (var i = this.properties.length; --i >=0;)
|
||||
if (this.properties[i]._dot_throw(compressor)) return true;
|
||||
return false;
|
||||
});
|
||||
// Do not be as strict with classes as we are with objects.
|
||||
// Hopefully the community is not going to abuse static getters and setters.
|
||||
// https://github.com/terser/terser/issues/724#issuecomment-643655656
|
||||
def_may_throw_on_access(AST_Class, return_false);
|
||||
def_may_throw_on_access(AST_ObjectProperty, return_false);
|
||||
def_may_throw_on_access(AST_ObjectGetter, return_true);
|
||||
def_may_throw_on_access(AST_Expansion, function(compressor) {
|
||||
return this.expression._dot_throw(compressor);
|
||||
});
|
||||
def_may_throw_on_access(AST_Function, return_false);
|
||||
def_may_throw_on_access(AST_Arrow, return_false);
|
||||
def_may_throw_on_access(AST_UnaryPostfix, return_false);
|
||||
def_may_throw_on_access(AST_UnaryPrefix, function() {
|
||||
return this.operator == "void";
|
||||
});
|
||||
def_may_throw_on_access(AST_Binary, function(compressor) {
|
||||
return (this.operator == "&&" || this.operator == "||" || this.operator == "??")
|
||||
&& (this.left._dot_throw(compressor) || this.right._dot_throw(compressor));
|
||||
});
|
||||
def_may_throw_on_access(AST_Assign, function(compressor) {
|
||||
if (this.logical) return true;
|
||||
|
||||
return this.operator == "="
|
||||
&& this.right._dot_throw(compressor);
|
||||
});
|
||||
def_may_throw_on_access(AST_Conditional, function(compressor) {
|
||||
return this.consequent._dot_throw(compressor)
|
||||
|| this.alternative._dot_throw(compressor);
|
||||
});
|
||||
def_may_throw_on_access(AST_Dot, function(compressor) {
|
||||
if (!is_strict(compressor)) return false;
|
||||
|
||||
if (this.property == "prototype") {
|
||||
return !(
|
||||
this.expression instanceof AST_Function
|
||||
|| this.expression instanceof AST_Class
|
||||
);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
def_may_throw_on_access(AST_Chain, function(compressor) {
|
||||
return this.expression._dot_throw(compressor);
|
||||
});
|
||||
def_may_throw_on_access(AST_Sequence, function(compressor) {
|
||||
return this.tail_node()._dot_throw(compressor);
|
||||
});
|
||||
def_may_throw_on_access(AST_SymbolRef, function(compressor) {
|
||||
if (this.name === "arguments") return false;
|
||||
if (has_flag(this, UNDEFINED)) return true;
|
||||
if (!is_strict(compressor)) return false;
|
||||
if (is_undeclared_ref(this) && this.is_declared(compressor)) return false;
|
||||
if (this.is_immutable()) return false;
|
||||
var fixed = this.fixed_value();
|
||||
return !fixed || fixed._dot_throw(compressor);
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("_dot_throw", func);
|
||||
});
|
||||
|
||||
export function is_lhs(node, parent) {
|
||||
if (parent instanceof AST_Unary && unary_side_effects.has(parent.operator)) return parent.expression;
|
||||
if (parent instanceof AST_Assign && parent.left === node) return node;
|
||||
}
|
||||
|
||||
(function(def_find_defs) {
|
||||
function to_node(value, orig) {
|
||||
if (value instanceof AST_Node) {
|
||||
if (!(value instanceof AST_Constant)) {
|
||||
// Value may be a function, an array including functions and even a complex assign / block expression,
|
||||
// so it should never be shared in different places.
|
||||
// Otherwise wrong information may be used in the compression phase
|
||||
value = value.clone(true);
|
||||
}
|
||||
return make_node(value.CTOR, orig, value);
|
||||
}
|
||||
if (Array.isArray(value)) return make_node(AST_Array, orig, {
|
||||
elements: value.map(function(value) {
|
||||
return to_node(value, orig);
|
||||
})
|
||||
});
|
||||
if (value && typeof value == "object") {
|
||||
var props = [];
|
||||
for (var key in value) if (HOP(value, key)) {
|
||||
props.push(make_node(AST_ObjectKeyVal, orig, {
|
||||
key: key,
|
||||
value: to_node(value[key], orig)
|
||||
}));
|
||||
}
|
||||
return make_node(AST_Object, orig, {
|
||||
properties: props
|
||||
});
|
||||
}
|
||||
return make_node_from_constant(value, orig);
|
||||
}
|
||||
|
||||
AST_Toplevel.DEFMETHOD("resolve_defines", function(compressor) {
|
||||
if (!compressor.option("global_defs")) return this;
|
||||
this.figure_out_scope({ ie8: compressor.option("ie8") });
|
||||
return this.transform(new TreeTransformer(function(node) {
|
||||
var def = node._find_defs(compressor, "");
|
||||
if (!def) return;
|
||||
var level = 0, child = node, parent;
|
||||
while (parent = this.parent(level++)) {
|
||||
if (!(parent instanceof AST_PropAccess)) break;
|
||||
if (parent.expression !== child) break;
|
||||
child = parent;
|
||||
}
|
||||
if (is_lhs(child, parent)) {
|
||||
return;
|
||||
}
|
||||
return def;
|
||||
}));
|
||||
});
|
||||
def_find_defs(AST_Node, noop);
|
||||
def_find_defs(AST_Chain, function(compressor, suffix) {
|
||||
return this.expression._find_defs(compressor, suffix);
|
||||
});
|
||||
def_find_defs(AST_Dot, function(compressor, suffix) {
|
||||
return this.expression._find_defs(compressor, "." + this.property + suffix);
|
||||
});
|
||||
def_find_defs(AST_SymbolDeclaration, function() {
|
||||
if (!this.global()) return;
|
||||
});
|
||||
def_find_defs(AST_SymbolRef, function(compressor, suffix) {
|
||||
if (!this.global()) return;
|
||||
var defines = compressor.option("global_defs");
|
||||
var name = this.name + suffix;
|
||||
if (HOP(defines, name)) return to_node(defines[name], this);
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("_find_defs", func);
|
||||
});
|
||||
|
||||
// method to negate an expression
|
||||
(function(def_negate) {
|
||||
function basic_negation(exp) {
|
||||
return make_node(AST_UnaryPrefix, exp, {
|
||||
operator: "!",
|
||||
expression: exp
|
||||
});
|
||||
}
|
||||
function best(orig, alt, first_in_statement) {
|
||||
var negated = basic_negation(orig);
|
||||
if (first_in_statement) {
|
||||
var stat = make_node(AST_SimpleStatement, alt, {
|
||||
body: alt
|
||||
});
|
||||
return best_of_expression(negated, stat) === stat ? alt : negated;
|
||||
}
|
||||
return best_of_expression(negated, alt);
|
||||
}
|
||||
def_negate(AST_Node, function() {
|
||||
return basic_negation(this);
|
||||
});
|
||||
def_negate(AST_Statement, function() {
|
||||
throw new Error("Cannot negate a statement");
|
||||
});
|
||||
def_negate(AST_Function, function() {
|
||||
return basic_negation(this);
|
||||
});
|
||||
def_negate(AST_Arrow, function() {
|
||||
return basic_negation(this);
|
||||
});
|
||||
def_negate(AST_UnaryPrefix, function() {
|
||||
if (this.operator == "!")
|
||||
return this.expression;
|
||||
return basic_negation(this);
|
||||
});
|
||||
def_negate(AST_Sequence, function(compressor) {
|
||||
var expressions = this.expressions.slice();
|
||||
expressions.push(expressions.pop().negate(compressor));
|
||||
return make_sequence(this, expressions);
|
||||
});
|
||||
def_negate(AST_Conditional, function(compressor, first_in_statement) {
|
||||
var self = this.clone();
|
||||
self.consequent = self.consequent.negate(compressor);
|
||||
self.alternative = self.alternative.negate(compressor);
|
||||
return best(this, self, first_in_statement);
|
||||
});
|
||||
def_negate(AST_Binary, function(compressor, first_in_statement) {
|
||||
var self = this.clone(), op = this.operator;
|
||||
if (compressor.option("unsafe_comps")) {
|
||||
switch (op) {
|
||||
case "<=" : self.operator = ">" ; return self;
|
||||
case "<" : self.operator = ">=" ; return self;
|
||||
case ">=" : self.operator = "<" ; return self;
|
||||
case ">" : self.operator = "<=" ; return self;
|
||||
}
|
||||
}
|
||||
switch (op) {
|
||||
case "==" : self.operator = "!="; return self;
|
||||
case "!=" : self.operator = "=="; return self;
|
||||
case "===": self.operator = "!=="; return self;
|
||||
case "!==": self.operator = "==="; return self;
|
||||
case "&&":
|
||||
self.operator = "||";
|
||||
self.left = self.left.negate(compressor, first_in_statement);
|
||||
self.right = self.right.negate(compressor);
|
||||
return best(this, self, first_in_statement);
|
||||
case "||":
|
||||
self.operator = "&&";
|
||||
self.left = self.left.negate(compressor, first_in_statement);
|
||||
self.right = self.right.negate(compressor);
|
||||
return best(this, self, first_in_statement);
|
||||
}
|
||||
return basic_negation(this);
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("negate", function(compressor, first_in_statement) {
|
||||
return func.call(this, compressor, first_in_statement);
|
||||
});
|
||||
});
|
||||
|
||||
// Is the callee of this function pure?
|
||||
var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError");
|
||||
AST_Call.DEFMETHOD("is_callee_pure", function(compressor) {
|
||||
if (compressor.option("unsafe")) {
|
||||
var expr = this.expression;
|
||||
var first_arg = (this.args && this.args[0] && this.args[0].evaluate(compressor));
|
||||
if (
|
||||
expr.expression && expr.expression.name === "hasOwnProperty" &&
|
||||
(first_arg == null || first_arg.thedef && first_arg.thedef.undeclared)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (is_undeclared_ref(expr) && global_pure_fns.has(expr.name)) return true;
|
||||
if (
|
||||
expr instanceof AST_Dot
|
||||
&& is_undeclared_ref(expr.expression)
|
||||
&& is_pure_native_fn(expr.expression.name, expr.property)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return !!has_annotation(this, _PURE) || !compressor.pure_funcs(this);
|
||||
});
|
||||
|
||||
// If I call this, is it a pure function?
|
||||
AST_Node.DEFMETHOD("is_call_pure", return_false);
|
||||
AST_Dot.DEFMETHOD("is_call_pure", function(compressor) {
|
||||
if (!compressor.option("unsafe")) return;
|
||||
const expr = this.expression;
|
||||
|
||||
let native_obj;
|
||||
if (expr instanceof AST_Array) {
|
||||
native_obj = "Array";
|
||||
} else if (expr.is_boolean()) {
|
||||
native_obj = "Boolean";
|
||||
} else if (expr.is_number(compressor)) {
|
||||
native_obj = "Number";
|
||||
} else if (expr instanceof AST_RegExp) {
|
||||
native_obj = "RegExp";
|
||||
} else if (expr.is_string(compressor)) {
|
||||
native_obj = "String";
|
||||
} else if (!this.may_throw_on_access(compressor)) {
|
||||
native_obj = "Object";
|
||||
}
|
||||
return native_obj != null && is_pure_native_method(native_obj, this.property);
|
||||
});
|
||||
|
||||
// tell me if a statement aborts
|
||||
export const aborts = (thing) => thing && thing.aborts();
|
||||
|
||||
(function(def_aborts) {
|
||||
def_aborts(AST_Statement, return_null);
|
||||
def_aborts(AST_Jump, return_this);
|
||||
function block_aborts() {
|
||||
for (var i = 0; i < this.body.length; i++) {
|
||||
if (aborts(this.body[i])) {
|
||||
return this.body[i];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
def_aborts(AST_Import, function() { return null; });
|
||||
def_aborts(AST_BlockStatement, block_aborts);
|
||||
def_aborts(AST_SwitchBranch, block_aborts);
|
||||
def_aborts(AST_If, function() {
|
||||
return this.alternative && aborts(this.body) && aborts(this.alternative) && this;
|
||||
});
|
||||
})(function(node, func) {
|
||||
node.DEFMETHOD("aborts", func);
|
||||
});
|
||||
|
||||
export function is_modified(compressor, tw, node, value, level, immutable) {
|
||||
var parent = tw.parent(level);
|
||||
var lhs = is_lhs(node, parent);
|
||||
if (lhs) return lhs;
|
||||
if (!immutable
|
||||
&& parent instanceof AST_Call
|
||||
&& parent.expression === node
|
||||
&& !(value instanceof AST_Arrow)
|
||||
&& !(value instanceof AST_Class)
|
||||
&& !parent.is_callee_pure(compressor)
|
||||
&& (!(value instanceof AST_Function)
|
||||
|| !(parent instanceof AST_New) && value.contains_this())) {
|
||||
return true;
|
||||
}
|
||||
if (parent instanceof AST_Array) {
|
||||
return is_modified(compressor, tw, parent, parent, level + 1);
|
||||
}
|
||||
if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
|
||||
var obj = tw.parent(level + 1);
|
||||
return is_modified(compressor, tw, obj, obj, level + 2);
|
||||
}
|
||||
if (parent instanceof AST_PropAccess && parent.expression === node) {
|
||||
var prop = read_property(value, parent.property);
|
||||
return !immutable && is_modified(compressor, tw, parent, prop, level + 1);
|
||||
}
|
||||
}
|
||||
+641
@@ -0,0 +1,641 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
import {
|
||||
AST_Array,
|
||||
AST_Assign,
|
||||
AST_Block,
|
||||
AST_Call,
|
||||
AST_Catch,
|
||||
AST_Class,
|
||||
AST_ClassExpression,
|
||||
AST_DefaultAssign,
|
||||
AST_DefClass,
|
||||
AST_Defun,
|
||||
AST_Destructuring,
|
||||
AST_EmptyStatement,
|
||||
AST_Expansion,
|
||||
AST_Export,
|
||||
AST_Function,
|
||||
AST_Infinity,
|
||||
AST_IterationStatement,
|
||||
AST_Lambda,
|
||||
AST_NaN,
|
||||
AST_Node,
|
||||
AST_Number,
|
||||
AST_Object,
|
||||
AST_ObjectKeyVal,
|
||||
AST_PropAccess,
|
||||
AST_Return,
|
||||
AST_Scope,
|
||||
AST_SimpleStatement,
|
||||
AST_Statement,
|
||||
AST_SymbolDefun,
|
||||
AST_SymbolFunarg,
|
||||
AST_SymbolLambda,
|
||||
AST_SymbolRef,
|
||||
AST_SymbolVar,
|
||||
AST_This,
|
||||
AST_Toplevel,
|
||||
AST_UnaryPrefix,
|
||||
AST_Undefined,
|
||||
AST_Var,
|
||||
AST_VarDef,
|
||||
AST_With,
|
||||
|
||||
walk,
|
||||
|
||||
_INLINE,
|
||||
_NOINLINE,
|
||||
_PURE
|
||||
} from "../ast.js";
|
||||
import { make_node, has_annotation } from "../utils/index.js";
|
||||
import "../size.js";
|
||||
|
||||
import "./evaluate.js";
|
||||
import "./drop-side-effect-free.js";
|
||||
import "./reduce-vars.js";
|
||||
import { is_undeclared_ref, is_lhs } from "./inference.js";
|
||||
import {
|
||||
SQUEEZED,
|
||||
INLINED,
|
||||
UNUSED,
|
||||
|
||||
has_flag,
|
||||
set_flag,
|
||||
} from "./compressor-flags.js";
|
||||
import {
|
||||
make_sequence,
|
||||
best_of,
|
||||
make_node_from_constant,
|
||||
identifier_atom,
|
||||
is_empty,
|
||||
is_func_expr,
|
||||
is_iife_call,
|
||||
is_reachable,
|
||||
is_recursive_ref,
|
||||
retain_top_func,
|
||||
} from "./common.js";
|
||||
|
||||
|
||||
function within_array_or_object_literal(compressor) {
|
||||
var node, level = 0;
|
||||
while (node = compressor.parent(level++)) {
|
||||
if (node instanceof AST_Statement) return false;
|
||||
if (node instanceof AST_Array
|
||||
|| node instanceof AST_ObjectKeyVal
|
||||
|| node instanceof AST_Object) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function scope_encloses_variables_in_this_scope(scope, pulled_scope) {
|
||||
for (const enclosed of pulled_scope.enclosed) {
|
||||
if (pulled_scope.variables.has(enclosed.name)) {
|
||||
continue;
|
||||
}
|
||||
const looked_up = scope.find_variable(enclosed.name);
|
||||
if (looked_up) {
|
||||
if (looked_up === enclosed) continue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function inline_into_symbolref(self, compressor) {
|
||||
if (
|
||||
!compressor.option("ie8")
|
||||
&& is_undeclared_ref(self)
|
||||
&& !compressor.find_parent(AST_With)
|
||||
) {
|
||||
switch (self.name) {
|
||||
case "undefined":
|
||||
return make_node(AST_Undefined, self).optimize(compressor);
|
||||
case "NaN":
|
||||
return make_node(AST_NaN, self).optimize(compressor);
|
||||
case "Infinity":
|
||||
return make_node(AST_Infinity, self).optimize(compressor);
|
||||
}
|
||||
}
|
||||
|
||||
const parent = compressor.parent();
|
||||
if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) {
|
||||
const def = self.definition();
|
||||
const nearest_scope = compressor.find_scope();
|
||||
if (compressor.top_retain && def.global && compressor.top_retain(def)) {
|
||||
def.fixed = false;
|
||||
def.single_use = false;
|
||||
return self;
|
||||
}
|
||||
|
||||
let fixed = self.fixed_value();
|
||||
let single_use = def.single_use
|
||||
&& !(parent instanceof AST_Call
|
||||
&& (parent.is_callee_pure(compressor))
|
||||
|| has_annotation(parent, _NOINLINE))
|
||||
&& !(parent instanceof AST_Export
|
||||
&& fixed instanceof AST_Lambda
|
||||
&& fixed.name);
|
||||
|
||||
if (single_use && fixed instanceof AST_Node) {
|
||||
single_use =
|
||||
!fixed.has_side_effects(compressor)
|
||||
&& !fixed.may_throw(compressor);
|
||||
}
|
||||
|
||||
if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) {
|
||||
if (retain_top_func(fixed, compressor)) {
|
||||
single_use = false;
|
||||
} else if (def.scope !== self.scope
|
||||
&& (def.escaped == 1
|
||||
|| has_flag(fixed, INLINED)
|
||||
|| within_array_or_object_literal(compressor)
|
||||
|| !compressor.option("reduce_funcs"))) {
|
||||
single_use = false;
|
||||
} else if (is_recursive_ref(compressor, def)) {
|
||||
single_use = false;
|
||||
} else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) {
|
||||
single_use = fixed.is_constant_expression(self.scope);
|
||||
if (single_use == "f") {
|
||||
var scope = self.scope;
|
||||
do {
|
||||
if (scope instanceof AST_Defun || is_func_expr(scope)) {
|
||||
set_flag(scope, INLINED);
|
||||
}
|
||||
} while (scope = scope.parent_scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (single_use && fixed instanceof AST_Lambda) {
|
||||
single_use =
|
||||
def.scope === self.scope
|
||||
&& !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
|
||||
|| parent instanceof AST_Call
|
||||
&& parent.expression === self
|
||||
&& !scope_encloses_variables_in_this_scope(nearest_scope, fixed)
|
||||
&& !(fixed.name && fixed.name.definition().recursive_refs > 0);
|
||||
}
|
||||
|
||||
if (single_use && fixed) {
|
||||
if (fixed instanceof AST_DefClass) {
|
||||
set_flag(fixed, SQUEEZED);
|
||||
fixed = make_node(AST_ClassExpression, fixed, fixed);
|
||||
}
|
||||
if (fixed instanceof AST_Defun) {
|
||||
set_flag(fixed, SQUEEZED);
|
||||
fixed = make_node(AST_Function, fixed, fixed);
|
||||
}
|
||||
if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) {
|
||||
const defun_def = fixed.name.definition();
|
||||
let lambda_def = fixed.variables.get(fixed.name.name);
|
||||
let name = lambda_def && lambda_def.orig[0];
|
||||
if (!(name instanceof AST_SymbolLambda)) {
|
||||
name = make_node(AST_SymbolLambda, fixed.name, fixed.name);
|
||||
name.scope = fixed;
|
||||
fixed.name = name;
|
||||
lambda_def = fixed.def_function(name);
|
||||
}
|
||||
walk(fixed, node => {
|
||||
if (node instanceof AST_SymbolRef && node.definition() === defun_def) {
|
||||
node.thedef = lambda_def;
|
||||
lambda_def.references.push(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (
|
||||
(fixed instanceof AST_Lambda || fixed instanceof AST_Class)
|
||||
&& fixed.parent_scope !== nearest_scope
|
||||
) {
|
||||
fixed = fixed.clone(true, compressor.get_toplevel());
|
||||
|
||||
nearest_scope.add_child_scope(fixed);
|
||||
}
|
||||
return fixed.optimize(compressor);
|
||||
}
|
||||
|
||||
// multiple uses
|
||||
if (fixed) {
|
||||
let replace;
|
||||
|
||||
if (fixed instanceof AST_This) {
|
||||
if (!(def.orig[0] instanceof AST_SymbolFunarg)
|
||||
&& def.references.every((ref) =>
|
||||
def.scope === ref.scope
|
||||
)) {
|
||||
replace = fixed;
|
||||
}
|
||||
} else {
|
||||
var ev = fixed.evaluate(compressor);
|
||||
if (
|
||||
ev !== fixed
|
||||
&& (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))
|
||||
) {
|
||||
replace = make_node_from_constant(ev, fixed);
|
||||
}
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
const name_length = self.size(compressor);
|
||||
const replace_size = replace.size(compressor);
|
||||
|
||||
let overhead = 0;
|
||||
if (compressor.option("unused") && !compressor.exposed(def)) {
|
||||
overhead =
|
||||
(name_length + 2 + replace_size) /
|
||||
(def.references.length - def.assignments);
|
||||
}
|
||||
|
||||
if (replace_size <= name_length + overhead) {
|
||||
return replace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
export function inline_into_call(self, fn, compressor) {
|
||||
var exp = self.expression;
|
||||
var simple_args = self.args.every((arg) => !(arg instanceof AST_Expansion));
|
||||
|
||||
if (compressor.option("reduce_vars")
|
||||
&& fn instanceof AST_SymbolRef
|
||||
&& !has_annotation(self, _NOINLINE)
|
||||
) {
|
||||
const fixed = fn.fixed_value();
|
||||
if (!retain_top_func(fixed, compressor)) {
|
||||
fn = fixed;
|
||||
}
|
||||
}
|
||||
|
||||
var is_func = fn instanceof AST_Lambda;
|
||||
|
||||
var stat = is_func && fn.body[0];
|
||||
var is_regular_func = is_func && !fn.is_generator && !fn.async;
|
||||
var can_inline = is_regular_func && compressor.option("inline") && !self.is_callee_pure(compressor);
|
||||
if (can_inline && stat instanceof AST_Return) {
|
||||
let returned = stat.value;
|
||||
if (!returned || returned.is_constant_expression()) {
|
||||
if (returned) {
|
||||
returned = returned.clone(true);
|
||||
} else {
|
||||
returned = make_node(AST_Undefined, self);
|
||||
}
|
||||
const args = self.args.concat(returned);
|
||||
return make_sequence(self, args).optimize(compressor);
|
||||
}
|
||||
|
||||
// optimize identity function
|
||||
if (
|
||||
fn.argnames.length === 1
|
||||
&& (fn.argnames[0] instanceof AST_SymbolFunarg)
|
||||
&& self.args.length < 2
|
||||
&& returned instanceof AST_SymbolRef
|
||||
&& returned.name === fn.argnames[0].name
|
||||
) {
|
||||
const replacement =
|
||||
(self.args[0] || make_node(AST_Undefined)).optimize(compressor);
|
||||
|
||||
let parent;
|
||||
if (
|
||||
replacement instanceof AST_PropAccess
|
||||
&& (parent = compressor.parent()) instanceof AST_Call
|
||||
&& parent.expression === self
|
||||
) {
|
||||
// identity function was being used to remove `this`, like in
|
||||
//
|
||||
// id(bag.no_this)(...)
|
||||
//
|
||||
// Replace with a larger but more effish (0, bag.no_this) wrapper.
|
||||
|
||||
return make_sequence(self, [
|
||||
make_node(AST_Number, self, { value: 0 }),
|
||||
replacement
|
||||
]);
|
||||
}
|
||||
// replace call with first argument or undefined if none passed
|
||||
return replacement;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_inline) {
|
||||
var scope, in_loop, level = -1;
|
||||
let def;
|
||||
let returned_value;
|
||||
let nearest_scope;
|
||||
if (simple_args
|
||||
&& !fn.uses_arguments
|
||||
&& !(compressor.parent() instanceof AST_Class)
|
||||
&& !(fn.name && fn instanceof AST_Function)
|
||||
&& (returned_value = can_flatten_body(stat))
|
||||
&& (exp === fn
|
||||
|| has_annotation(self, _INLINE)
|
||||
|| compressor.option("unused")
|
||||
&& (def = exp.definition()).references.length == 1
|
||||
&& !is_recursive_ref(compressor, def)
|
||||
&& fn.is_constant_expression(exp.scope))
|
||||
&& !has_annotation(self, _PURE | _NOINLINE)
|
||||
&& !fn.contains_this()
|
||||
&& can_inject_symbols()
|
||||
&& (nearest_scope = compressor.find_scope())
|
||||
&& !scope_encloses_variables_in_this_scope(nearest_scope, fn)
|
||||
&& !(function in_default_assign() {
|
||||
// Due to the fact function parameters have their own scope
|
||||
// which can't use `var something` in the function body within,
|
||||
// we simply don't inline into DefaultAssign.
|
||||
let i = 0;
|
||||
let p;
|
||||
while ((p = compressor.parent(i++))) {
|
||||
if (p instanceof AST_DefaultAssign) return true;
|
||||
if (p instanceof AST_Block) break;
|
||||
}
|
||||
return false;
|
||||
})()
|
||||
&& !(scope instanceof AST_Class)
|
||||
) {
|
||||
set_flag(fn, SQUEEZED);
|
||||
nearest_scope.add_child_scope(fn);
|
||||
return make_sequence(self, flatten_fn(returned_value)).optimize(compressor);
|
||||
}
|
||||
}
|
||||
|
||||
if (can_inline && has_annotation(self, _INLINE)) {
|
||||
set_flag(fn, SQUEEZED);
|
||||
fn = make_node(fn.CTOR === AST_Defun ? AST_Function : fn.CTOR, fn, fn);
|
||||
fn = fn.clone(true);
|
||||
fn.figure_out_scope({}, {
|
||||
parent_scope: compressor.find_scope(),
|
||||
toplevel: compressor.get_toplevel()
|
||||
});
|
||||
|
||||
return make_node(AST_Call, self, {
|
||||
expression: fn,
|
||||
args: self.args,
|
||||
}).optimize(compressor);
|
||||
}
|
||||
|
||||
const can_drop_this_call = is_regular_func && compressor.option("side_effects") && fn.body.every(is_empty);
|
||||
if (can_drop_this_call) {
|
||||
var args = self.args.concat(make_node(AST_Undefined, self));
|
||||
return make_sequence(self, args).optimize(compressor);
|
||||
}
|
||||
|
||||
if (compressor.option("negate_iife")
|
||||
&& compressor.parent() instanceof AST_SimpleStatement
|
||||
&& is_iife_call(self)) {
|
||||
return self.negate(compressor, true);
|
||||
}
|
||||
|
||||
var ev = self.evaluate(compressor);
|
||||
if (ev !== self) {
|
||||
ev = make_node_from_constant(ev, self).optimize(compressor);
|
||||
return best_of(compressor, ev, self);
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
function return_value(stat) {
|
||||
if (!stat) return make_node(AST_Undefined, self);
|
||||
if (stat instanceof AST_Return) {
|
||||
if (!stat.value) return make_node(AST_Undefined, self);
|
||||
return stat.value.clone(true);
|
||||
}
|
||||
if (stat instanceof AST_SimpleStatement) {
|
||||
return make_node(AST_UnaryPrefix, stat, {
|
||||
operator: "void",
|
||||
expression: stat.body.clone(true)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function can_flatten_body(stat) {
|
||||
var body = fn.body;
|
||||
var len = body.length;
|
||||
if (compressor.option("inline") < 3) {
|
||||
return len == 1 && return_value(stat);
|
||||
}
|
||||
stat = null;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var line = body[i];
|
||||
if (line instanceof AST_Var) {
|
||||
if (stat && !line.definitions.every((var_def) =>
|
||||
!var_def.value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
} else if (stat) {
|
||||
return false;
|
||||
} else if (!(line instanceof AST_EmptyStatement)) {
|
||||
stat = line;
|
||||
}
|
||||
}
|
||||
return return_value(stat);
|
||||
}
|
||||
|
||||
function can_inject_args(block_scoped, safe_to_inject) {
|
||||
for (var i = 0, len = fn.argnames.length; i < len; i++) {
|
||||
var arg = fn.argnames[i];
|
||||
if (arg instanceof AST_DefaultAssign) {
|
||||
if (has_flag(arg.left, UNUSED)) continue;
|
||||
return false;
|
||||
}
|
||||
if (arg instanceof AST_Destructuring) return false;
|
||||
if (arg instanceof AST_Expansion) {
|
||||
if (has_flag(arg.expression, UNUSED)) continue;
|
||||
return false;
|
||||
}
|
||||
if (has_flag(arg, UNUSED)) continue;
|
||||
if (!safe_to_inject
|
||||
|| block_scoped.has(arg.name)
|
||||
|| identifier_atom.has(arg.name)
|
||||
|| scope.conflicting_def(arg.name)) {
|
||||
return false;
|
||||
}
|
||||
if (in_loop) in_loop.push(arg.definition());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function can_inject_vars(block_scoped, safe_to_inject) {
|
||||
var len = fn.body.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var stat = fn.body[i];
|
||||
if (!(stat instanceof AST_Var)) continue;
|
||||
if (!safe_to_inject) return false;
|
||||
for (var j = stat.definitions.length; --j >= 0;) {
|
||||
var name = stat.definitions[j].name;
|
||||
if (name instanceof AST_Destructuring
|
||||
|| block_scoped.has(name.name)
|
||||
|| identifier_atom.has(name.name)
|
||||
|| scope.conflicting_def(name.name)) {
|
||||
return false;
|
||||
}
|
||||
if (in_loop) in_loop.push(name.definition());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function can_inject_symbols() {
|
||||
var block_scoped = new Set();
|
||||
do {
|
||||
scope = compressor.parent(++level);
|
||||
if (scope.is_block_scope() && scope.block_scope) {
|
||||
// TODO this is sometimes undefined during compression.
|
||||
// But it should always have a value!
|
||||
scope.block_scope.variables.forEach(function (variable) {
|
||||
block_scoped.add(variable.name);
|
||||
});
|
||||
}
|
||||
if (scope instanceof AST_Catch) {
|
||||
// TODO can we delete? AST_Catch is a block scope.
|
||||
if (scope.argname) {
|
||||
block_scoped.add(scope.argname.name);
|
||||
}
|
||||
} else if (scope instanceof AST_IterationStatement) {
|
||||
in_loop = [];
|
||||
} else if (scope instanceof AST_SymbolRef) {
|
||||
if (scope.fixed_value() instanceof AST_Scope) return false;
|
||||
}
|
||||
} while (!(scope instanceof AST_Scope));
|
||||
|
||||
var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars;
|
||||
var inline = compressor.option("inline");
|
||||
if (!can_inject_vars(block_scoped, inline >= 3 && safe_to_inject)) return false;
|
||||
if (!can_inject_args(block_scoped, inline >= 2 && safe_to_inject)) return false;
|
||||
return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop);
|
||||
}
|
||||
|
||||
function append_var(decls, expressions, name, value) {
|
||||
var def = name.definition();
|
||||
|
||||
// Name already exists, only when a function argument had the same name
|
||||
const already_appended = scope.variables.has(name.name);
|
||||
if (!already_appended) {
|
||||
scope.variables.set(name.name, def);
|
||||
scope.enclosed.push(def);
|
||||
decls.push(make_node(AST_VarDef, name, {
|
||||
name: name,
|
||||
value: null
|
||||
}));
|
||||
}
|
||||
|
||||
var sym = make_node(AST_SymbolRef, name, name);
|
||||
def.references.push(sym);
|
||||
if (value) expressions.push(make_node(AST_Assign, self, {
|
||||
operator: "=",
|
||||
logical: false,
|
||||
left: sym,
|
||||
right: value.clone()
|
||||
}));
|
||||
}
|
||||
|
||||
function flatten_args(decls, expressions) {
|
||||
var len = fn.argnames.length;
|
||||
for (var i = self.args.length; --i >= len;) {
|
||||
expressions.push(self.args[i]);
|
||||
}
|
||||
for (i = len; --i >= 0;) {
|
||||
var name = fn.argnames[i];
|
||||
var value = self.args[i];
|
||||
if (has_flag(name, UNUSED) || !name.name || scope.conflicting_def(name.name)) {
|
||||
if (value) expressions.push(value);
|
||||
} else {
|
||||
var symbol = make_node(AST_SymbolVar, name, name);
|
||||
name.definition().orig.push(symbol);
|
||||
if (!value && in_loop) value = make_node(AST_Undefined, self);
|
||||
append_var(decls, expressions, symbol, value);
|
||||
}
|
||||
}
|
||||
decls.reverse();
|
||||
expressions.reverse();
|
||||
}
|
||||
|
||||
function flatten_vars(decls, expressions) {
|
||||
var pos = expressions.length;
|
||||
for (var i = 0, lines = fn.body.length; i < lines; i++) {
|
||||
var stat = fn.body[i];
|
||||
if (!(stat instanceof AST_Var)) continue;
|
||||
for (var j = 0, defs = stat.definitions.length; j < defs; j++) {
|
||||
var var_def = stat.definitions[j];
|
||||
var name = var_def.name;
|
||||
append_var(decls, expressions, name, var_def.value);
|
||||
if (in_loop && fn.argnames.every((argname) =>
|
||||
argname.name != name.name
|
||||
)) {
|
||||
var def = fn.variables.get(name.name);
|
||||
var sym = make_node(AST_SymbolRef, name, name);
|
||||
def.references.push(sym);
|
||||
expressions.splice(pos++, 0, make_node(AST_Assign, var_def, {
|
||||
operator: "=",
|
||||
logical: false,
|
||||
left: sym,
|
||||
right: make_node(AST_Undefined, name)
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function flatten_fn(returned_value) {
|
||||
var decls = [];
|
||||
var expressions = [];
|
||||
flatten_args(decls, expressions);
|
||||
flatten_vars(decls, expressions);
|
||||
expressions.push(returned_value);
|
||||
|
||||
if (decls.length) {
|
||||
const i = scope.body.indexOf(compressor.parent(level - 1)) + 1;
|
||||
scope.body.splice(i, 0, make_node(AST_Var, fn, {
|
||||
definitions: decls
|
||||
}));
|
||||
}
|
||||
|
||||
return expressions.map(exp => exp.clone(true));
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+184
@@ -0,0 +1,184 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
import { makePredicate } from "../utils/index.js";
|
||||
|
||||
// Lists of native methods, useful for `unsafe` option which assumes they exist.
|
||||
// Note: Lots of methods and functions are missing here, in case they aren't pure
|
||||
// or not available in all JS environments.
|
||||
|
||||
function make_nested_lookup(obj) {
|
||||
const out = new Map();
|
||||
for (var key of Object.keys(obj)) {
|
||||
out.set(key, makePredicate(obj[key]));
|
||||
}
|
||||
|
||||
const does_have = (global_name, fname) => {
|
||||
const inner_map = out.get(global_name);
|
||||
return inner_map != null && inner_map.has(fname);
|
||||
};
|
||||
return does_have;
|
||||
}
|
||||
|
||||
// Objects which are safe to access without throwing or causing a side effect.
|
||||
// Usually we'd check the `unsafe` option first but these are way too common for that
|
||||
export const pure_prop_access_globals = new Set([
|
||||
"Number",
|
||||
"String",
|
||||
"Array",
|
||||
"Object",
|
||||
"Function",
|
||||
"Promise",
|
||||
]);
|
||||
|
||||
const object_methods = [
|
||||
"constructor",
|
||||
"toString",
|
||||
"valueOf",
|
||||
];
|
||||
|
||||
export const is_pure_native_method = make_nested_lookup({
|
||||
Array: [
|
||||
"indexOf",
|
||||
"join",
|
||||
"lastIndexOf",
|
||||
"slice",
|
||||
...object_methods,
|
||||
],
|
||||
Boolean: object_methods,
|
||||
Function: object_methods,
|
||||
Number: [
|
||||
"toExponential",
|
||||
"toFixed",
|
||||
"toPrecision",
|
||||
...object_methods,
|
||||
],
|
||||
Object: object_methods,
|
||||
RegExp: [
|
||||
"test",
|
||||
...object_methods,
|
||||
],
|
||||
String: [
|
||||
"charAt",
|
||||
"charCodeAt",
|
||||
"concat",
|
||||
"indexOf",
|
||||
"italics",
|
||||
"lastIndexOf",
|
||||
"match",
|
||||
"replace",
|
||||
"search",
|
||||
"slice",
|
||||
"split",
|
||||
"substr",
|
||||
"substring",
|
||||
"toLowerCase",
|
||||
"toUpperCase",
|
||||
"trim",
|
||||
...object_methods,
|
||||
],
|
||||
});
|
||||
|
||||
export const is_pure_native_fn = make_nested_lookup({
|
||||
Array: [
|
||||
"isArray",
|
||||
],
|
||||
Math: [
|
||||
"abs",
|
||||
"acos",
|
||||
"asin",
|
||||
"atan",
|
||||
"ceil",
|
||||
"cos",
|
||||
"exp",
|
||||
"floor",
|
||||
"log",
|
||||
"round",
|
||||
"sin",
|
||||
"sqrt",
|
||||
"tan",
|
||||
"atan2",
|
||||
"pow",
|
||||
"max",
|
||||
"min",
|
||||
],
|
||||
Number: [
|
||||
"isFinite",
|
||||
"isNaN",
|
||||
],
|
||||
Object: [
|
||||
"create",
|
||||
"getOwnPropertyDescriptor",
|
||||
"getOwnPropertyNames",
|
||||
"getPrototypeOf",
|
||||
"isExtensible",
|
||||
"isFrozen",
|
||||
"isSealed",
|
||||
"hasOwn",
|
||||
"keys",
|
||||
],
|
||||
String: [
|
||||
"fromCharCode",
|
||||
],
|
||||
});
|
||||
|
||||
// Known numeric values which come with JS environments
|
||||
export const is_pure_native_value = make_nested_lookup({
|
||||
Math: [
|
||||
"E",
|
||||
"LN10",
|
||||
"LN2",
|
||||
"LOG2E",
|
||||
"LOG10E",
|
||||
"PI",
|
||||
"SQRT1_2",
|
||||
"SQRT2",
|
||||
],
|
||||
Number: [
|
||||
"MAX_VALUE",
|
||||
"MIN_VALUE",
|
||||
"NaN",
|
||||
"NEGATIVE_INFINITY",
|
||||
"POSITIVE_INFINITY",
|
||||
],
|
||||
});
|
||||
Generated
Vendored
+675
@@ -0,0 +1,675 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
import {
|
||||
AST_Accessor,
|
||||
AST_Array,
|
||||
AST_Assign,
|
||||
AST_Await,
|
||||
AST_Binary,
|
||||
AST_Block,
|
||||
AST_Call,
|
||||
AST_Case,
|
||||
AST_Chain,
|
||||
AST_Class,
|
||||
AST_ClassExpression,
|
||||
AST_Conditional,
|
||||
AST_Default,
|
||||
AST_Defun,
|
||||
AST_Destructuring,
|
||||
AST_Do,
|
||||
AST_Exit,
|
||||
AST_Expansion,
|
||||
AST_For,
|
||||
AST_ForIn,
|
||||
AST_If,
|
||||
AST_LabeledStatement,
|
||||
AST_Lambda,
|
||||
AST_New,
|
||||
AST_Node,
|
||||
AST_Number,
|
||||
AST_ObjectKeyVal,
|
||||
AST_PropAccess,
|
||||
AST_Sequence,
|
||||
AST_SimpleStatement,
|
||||
AST_Symbol,
|
||||
AST_SymbolCatch,
|
||||
AST_SymbolConst,
|
||||
AST_SymbolDefun,
|
||||
AST_SymbolFunarg,
|
||||
AST_SymbolLambda,
|
||||
AST_SymbolRef,
|
||||
AST_This,
|
||||
AST_Toplevel,
|
||||
AST_Try,
|
||||
AST_Unary,
|
||||
AST_UnaryPrefix,
|
||||
AST_Undefined,
|
||||
AST_VarDef,
|
||||
AST_While,
|
||||
AST_Yield,
|
||||
|
||||
walk,
|
||||
walk_body,
|
||||
|
||||
_INLINE,
|
||||
_NOINLINE,
|
||||
_PURE
|
||||
} from "../ast.js";
|
||||
import { HOP, make_node, noop } from "../utils/index.js";
|
||||
|
||||
import { lazy_op, is_modified } from "./inference.js";
|
||||
import { INLINED, clear_flag } from "./compressor-flags.js";
|
||||
import { read_property, has_break_or_continue, is_recursive_ref } from "./common.js";
|
||||
|
||||
// Define the method AST_Node#reduce_vars, which goes through the AST in
|
||||
// execution order to perform basic flow analysis
|
||||
|
||||
function def_reduce_vars(node, func) {
|
||||
node.DEFMETHOD("reduce_vars", func);
|
||||
}
|
||||
|
||||
def_reduce_vars(AST_Node, noop);
|
||||
|
||||
function reset_def(compressor, def) {
|
||||
def.assignments = 0;
|
||||
def.chained = false;
|
||||
def.direct_access = false;
|
||||
def.escaped = 0;
|
||||
def.recursive_refs = 0;
|
||||
def.references = [];
|
||||
def.single_use = undefined;
|
||||
if (def.scope.pinned()) {
|
||||
def.fixed = false;
|
||||
} else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) {
|
||||
def.fixed = def.init;
|
||||
} else {
|
||||
def.fixed = false;
|
||||
}
|
||||
}
|
||||
|
||||
function reset_variables(tw, compressor, node) {
|
||||
node.variables.forEach(function(def) {
|
||||
reset_def(compressor, def);
|
||||
if (def.fixed === null) {
|
||||
tw.defs_to_safe_ids.set(def.id, tw.safe_ids);
|
||||
mark(tw, def, true);
|
||||
} else if (def.fixed) {
|
||||
tw.loop_ids.set(def.id, tw.in_loop);
|
||||
mark(tw, def, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function reset_block_variables(compressor, node) {
|
||||
if (node.block_scope) node.block_scope.variables.forEach((def) => {
|
||||
reset_def(compressor, def);
|
||||
});
|
||||
}
|
||||
|
||||
function push(tw) {
|
||||
tw.safe_ids = Object.create(tw.safe_ids);
|
||||
}
|
||||
|
||||
function pop(tw) {
|
||||
tw.safe_ids = Object.getPrototypeOf(tw.safe_ids);
|
||||
}
|
||||
|
||||
function mark(tw, def, safe) {
|
||||
tw.safe_ids[def.id] = safe;
|
||||
}
|
||||
|
||||
function safe_to_read(tw, def) {
|
||||
if (def.single_use == "m") return false;
|
||||
if (tw.safe_ids[def.id]) {
|
||||
if (def.fixed == null) {
|
||||
var orig = def.orig[0];
|
||||
if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false;
|
||||
def.fixed = make_node(AST_Undefined, orig);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return def.fixed instanceof AST_Defun;
|
||||
}
|
||||
|
||||
function safe_to_assign(tw, def, scope, value) {
|
||||
if (def.fixed === undefined) return true;
|
||||
let def_safe_ids;
|
||||
if (def.fixed === null
|
||||
&& (def_safe_ids = tw.defs_to_safe_ids.get(def.id))
|
||||
) {
|
||||
def_safe_ids[def.id] = false;
|
||||
tw.defs_to_safe_ids.delete(def.id);
|
||||
return true;
|
||||
}
|
||||
if (!HOP(tw.safe_ids, def.id)) return false;
|
||||
if (!safe_to_read(tw, def)) return false;
|
||||
if (def.fixed === false) return false;
|
||||
if (def.fixed != null && (!value || def.references.length > def.assignments)) return false;
|
||||
if (def.fixed instanceof AST_Defun) {
|
||||
return value instanceof AST_Node && def.fixed.parent_scope === scope;
|
||||
}
|
||||
return def.orig.every((sym) => {
|
||||
return !(sym instanceof AST_SymbolConst
|
||||
|| sym instanceof AST_SymbolDefun
|
||||
|| sym instanceof AST_SymbolLambda);
|
||||
});
|
||||
}
|
||||
|
||||
function ref_once(tw, compressor, def) {
|
||||
return compressor.option("unused")
|
||||
&& !def.scope.pinned()
|
||||
&& def.references.length - def.recursive_refs == 1
|
||||
&& tw.loop_ids.get(def.id) === tw.in_loop;
|
||||
}
|
||||
|
||||
function is_immutable(value) {
|
||||
if (!value) return false;
|
||||
return value.is_constant()
|
||||
|| value instanceof AST_Lambda
|
||||
|| value instanceof AST_This;
|
||||
}
|
||||
|
||||
// A definition "escapes" when its value can leave the point of use.
|
||||
// Example: `a = b || c`
|
||||
// In this example, "b" and "c" are escaping, because they're going into "a"
|
||||
//
|
||||
// def.escaped is != 0 when it escapes.
|
||||
//
|
||||
// When greater than 1, it means that N chained properties will be read off
|
||||
// of that def before an escape occurs. This is useful for evaluating
|
||||
// property accesses, where you need to know when to stop.
|
||||
function mark_escaped(tw, d, scope, node, value, level = 0, depth = 1) {
|
||||
var parent = tw.parent(level);
|
||||
if (value) {
|
||||
if (value.is_constant()) return;
|
||||
if (value instanceof AST_ClassExpression) return;
|
||||
}
|
||||
|
||||
if (
|
||||
parent instanceof AST_Assign && (parent.operator === "=" || parent.logical) && node === parent.right
|
||||
|| parent instanceof AST_Call && (node !== parent.expression || parent instanceof AST_New)
|
||||
|| parent instanceof AST_Exit && node === parent.value && node.scope !== d.scope
|
||||
|| parent instanceof AST_VarDef && node === parent.value
|
||||
|| parent instanceof AST_Yield && node === parent.value && node.scope !== d.scope
|
||||
) {
|
||||
if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1;
|
||||
if (!d.escaped || d.escaped > depth) d.escaped = depth;
|
||||
return;
|
||||
} else if (
|
||||
parent instanceof AST_Array
|
||||
|| parent instanceof AST_Await
|
||||
|| parent instanceof AST_Binary && lazy_op.has(parent.operator)
|
||||
|| parent instanceof AST_Conditional && node !== parent.condition
|
||||
|| parent instanceof AST_Expansion
|
||||
|| parent instanceof AST_Sequence && node === parent.tail_node()
|
||||
) {
|
||||
mark_escaped(tw, d, scope, parent, parent, level + 1, depth);
|
||||
} else if (parent instanceof AST_ObjectKeyVal && node === parent.value) {
|
||||
var obj = tw.parent(level + 1);
|
||||
|
||||
mark_escaped(tw, d, scope, obj, obj, level + 2, depth);
|
||||
} else if (parent instanceof AST_PropAccess && node === parent.expression) {
|
||||
value = read_property(value, parent.property);
|
||||
|
||||
mark_escaped(tw, d, scope, parent, value, level + 1, depth + 1);
|
||||
if (value) return;
|
||||
}
|
||||
|
||||
if (level > 0) return;
|
||||
if (parent instanceof AST_Sequence && node !== parent.tail_node()) return;
|
||||
if (parent instanceof AST_SimpleStatement) return;
|
||||
|
||||
d.direct_access = true;
|
||||
}
|
||||
|
||||
const suppress = node => walk(node, node => {
|
||||
if (!(node instanceof AST_Symbol)) return;
|
||||
var d = node.definition();
|
||||
if (!d) return;
|
||||
if (node instanceof AST_SymbolRef) d.references.push(node);
|
||||
d.fixed = false;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Accessor, function(tw, descend, compressor) {
|
||||
push(tw);
|
||||
reset_variables(tw, compressor, this);
|
||||
descend();
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Assign, function(tw, descend, compressor) {
|
||||
var node = this;
|
||||
if (node.left instanceof AST_Destructuring) {
|
||||
suppress(node.left);
|
||||
return;
|
||||
}
|
||||
|
||||
const finish_walk = () => {
|
||||
if (node.logical) {
|
||||
node.left.walk(tw);
|
||||
|
||||
push(tw);
|
||||
node.right.walk(tw);
|
||||
pop(tw);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var sym = node.left;
|
||||
if (!(sym instanceof AST_SymbolRef)) return finish_walk();
|
||||
|
||||
var def = sym.definition();
|
||||
var safe = safe_to_assign(tw, def, sym.scope, node.right);
|
||||
def.assignments++;
|
||||
if (!safe) return finish_walk();
|
||||
|
||||
var fixed = def.fixed;
|
||||
if (!fixed && node.operator != "=" && !node.logical) return finish_walk();
|
||||
|
||||
var eq = node.operator == "=";
|
||||
var value = eq ? node.right : node;
|
||||
if (is_modified(compressor, tw, node, value, 0)) return finish_walk();
|
||||
|
||||
def.references.push(sym);
|
||||
|
||||
if (!node.logical) {
|
||||
if (!eq) def.chained = true;
|
||||
|
||||
def.fixed = eq ? function() {
|
||||
return node.right;
|
||||
} : function() {
|
||||
return make_node(AST_Binary, node, {
|
||||
operator: node.operator.slice(0, -1),
|
||||
left: fixed instanceof AST_Node ? fixed : fixed(),
|
||||
right: node.right
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
if (node.logical) {
|
||||
mark(tw, def, false);
|
||||
push(tw);
|
||||
node.right.walk(tw);
|
||||
pop(tw);
|
||||
return true;
|
||||
}
|
||||
|
||||
mark(tw, def, false);
|
||||
node.right.walk(tw);
|
||||
mark(tw, def, true);
|
||||
|
||||
mark_escaped(tw, def, sym.scope, node, value, 0, 1);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Binary, function(tw) {
|
||||
if (!lazy_op.has(this.operator)) return;
|
||||
this.left.walk(tw);
|
||||
push(tw);
|
||||
this.right.walk(tw);
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Block, function(tw, descend, compressor) {
|
||||
reset_block_variables(compressor, this);
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Case, function(tw) {
|
||||
push(tw);
|
||||
this.expression.walk(tw);
|
||||
pop(tw);
|
||||
push(tw);
|
||||
walk_body(this, tw);
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Class, function(tw, descend) {
|
||||
clear_flag(this, INLINED);
|
||||
push(tw);
|
||||
descend();
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Conditional, function(tw) {
|
||||
this.condition.walk(tw);
|
||||
push(tw);
|
||||
this.consequent.walk(tw);
|
||||
pop(tw);
|
||||
push(tw);
|
||||
this.alternative.walk(tw);
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Chain, function(tw, descend) {
|
||||
// Chains' conditions apply left-to-right, cumulatively.
|
||||
// If we walk normally we don't go in that order because we would pop before pushing again
|
||||
// Solution: AST_PropAccess and AST_Call push when they are optional, and never pop.
|
||||
// Then we pop everything when they are done being walked.
|
||||
const safe_ids = tw.safe_ids;
|
||||
|
||||
descend();
|
||||
|
||||
// Unroll back to start
|
||||
tw.safe_ids = safe_ids;
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Call, function (tw) {
|
||||
this.expression.walk(tw);
|
||||
|
||||
if (this.optional) {
|
||||
// Never pop -- it's popped at AST_Chain above
|
||||
push(tw);
|
||||
}
|
||||
|
||||
for (const arg of this.args) arg.walk(tw);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_PropAccess, function (tw) {
|
||||
if (!this.optional) return;
|
||||
|
||||
this.expression.walk(tw);
|
||||
|
||||
// Never pop -- it's popped at AST_Chain above
|
||||
push(tw);
|
||||
|
||||
if (this.property instanceof AST_Node) this.property.walk(tw);
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Default, function(tw, descend) {
|
||||
push(tw);
|
||||
descend();
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
|
||||
function mark_lambda(tw, descend, compressor) {
|
||||
clear_flag(this, INLINED);
|
||||
push(tw);
|
||||
reset_variables(tw, compressor, this);
|
||||
if (this.uses_arguments) {
|
||||
descend();
|
||||
pop(tw);
|
||||
return;
|
||||
}
|
||||
var iife;
|
||||
if (!this.name
|
||||
&& (iife = tw.parent()) instanceof AST_Call
|
||||
&& iife.expression === this
|
||||
&& !iife.args.some(arg => arg instanceof AST_Expansion)
|
||||
&& this.argnames.every(arg_name => arg_name instanceof AST_Symbol)
|
||||
) {
|
||||
// Virtually turn IIFE parameters into variable definitions:
|
||||
// (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})()
|
||||
// So existing transformation rules can work on them.
|
||||
this.argnames.forEach((arg, i) => {
|
||||
if (!arg.definition) return;
|
||||
var d = arg.definition();
|
||||
// Avoid setting fixed when there's more than one origin for a variable value
|
||||
if (d.orig.length > 1) return;
|
||||
if (d.fixed === undefined && (!this.uses_arguments || tw.has_directive("use strict"))) {
|
||||
d.fixed = function() {
|
||||
return iife.args[i] || make_node(AST_Undefined, iife);
|
||||
};
|
||||
tw.loop_ids.set(d.id, tw.in_loop);
|
||||
mark(tw, d, true);
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
descend();
|
||||
pop(tw);
|
||||
return true;
|
||||
}
|
||||
|
||||
def_reduce_vars(AST_Lambda, mark_lambda);
|
||||
|
||||
def_reduce_vars(AST_Do, function(tw, descend, compressor) {
|
||||
reset_block_variables(compressor, this);
|
||||
const saved_loop = tw.in_loop;
|
||||
tw.in_loop = this;
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
if (has_break_or_continue(this)) {
|
||||
pop(tw);
|
||||
push(tw);
|
||||
}
|
||||
this.condition.walk(tw);
|
||||
pop(tw);
|
||||
tw.in_loop = saved_loop;
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_For, function(tw, descend, compressor) {
|
||||
reset_block_variables(compressor, this);
|
||||
if (this.init) this.init.walk(tw);
|
||||
const saved_loop = tw.in_loop;
|
||||
tw.in_loop = this;
|
||||
push(tw);
|
||||
if (this.condition) this.condition.walk(tw);
|
||||
this.body.walk(tw);
|
||||
if (this.step) {
|
||||
if (has_break_or_continue(this)) {
|
||||
pop(tw);
|
||||
push(tw);
|
||||
}
|
||||
this.step.walk(tw);
|
||||
}
|
||||
pop(tw);
|
||||
tw.in_loop = saved_loop;
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_ForIn, function(tw, descend, compressor) {
|
||||
reset_block_variables(compressor, this);
|
||||
suppress(this.init);
|
||||
this.object.walk(tw);
|
||||
const saved_loop = tw.in_loop;
|
||||
tw.in_loop = this;
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
pop(tw);
|
||||
tw.in_loop = saved_loop;
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_If, function(tw) {
|
||||
this.condition.walk(tw);
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
pop(tw);
|
||||
if (this.alternative) {
|
||||
push(tw);
|
||||
this.alternative.walk(tw);
|
||||
pop(tw);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_LabeledStatement, function(tw) {
|
||||
push(tw);
|
||||
this.body.walk(tw);
|
||||
pop(tw);
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_SymbolCatch, function() {
|
||||
this.definition().fixed = false;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_SymbolRef, function(tw, descend, compressor) {
|
||||
var d = this.definition();
|
||||
d.references.push(this);
|
||||
if (d.references.length == 1
|
||||
&& !d.fixed
|
||||
&& d.orig[0] instanceof AST_SymbolDefun) {
|
||||
tw.loop_ids.set(d.id, tw.in_loop);
|
||||
}
|
||||
var fixed_value;
|
||||
if (d.fixed === undefined || !safe_to_read(tw, d)) {
|
||||
d.fixed = false;
|
||||
} else if (d.fixed) {
|
||||
fixed_value = this.fixed_value();
|
||||
if (
|
||||
fixed_value instanceof AST_Lambda
|
||||
&& is_recursive_ref(tw, d)
|
||||
) {
|
||||
d.recursive_refs++;
|
||||
} else if (fixed_value
|
||||
&& !compressor.exposed(d)
|
||||
&& ref_once(tw, compressor, d)
|
||||
) {
|
||||
d.single_use =
|
||||
fixed_value instanceof AST_Lambda && !fixed_value.pinned()
|
||||
|| fixed_value instanceof AST_Class
|
||||
|| d.scope === this.scope && fixed_value.is_constant_expression();
|
||||
} else {
|
||||
d.single_use = false;
|
||||
}
|
||||
if (is_modified(compressor, tw, this, fixed_value, 0, is_immutable(fixed_value))) {
|
||||
if (d.single_use) {
|
||||
d.single_use = "m";
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
mark_escaped(tw, d, this.scope, this, fixed_value, 0, 1);
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Toplevel, function(tw, descend, compressor) {
|
||||
this.globals.forEach(function(def) {
|
||||
reset_def(compressor, def);
|
||||
});
|
||||
reset_variables(tw, compressor, this);
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Try, function(tw, descend, compressor) {
|
||||
reset_block_variables(compressor, this);
|
||||
push(tw);
|
||||
walk_body(this, tw);
|
||||
pop(tw);
|
||||
if (this.bcatch) {
|
||||
push(tw);
|
||||
this.bcatch.walk(tw);
|
||||
pop(tw);
|
||||
}
|
||||
if (this.bfinally) this.bfinally.walk(tw);
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_Unary, function(tw) {
|
||||
var node = this;
|
||||
if (node.operator !== "++" && node.operator !== "--") return;
|
||||
var exp = node.expression;
|
||||
if (!(exp instanceof AST_SymbolRef)) return;
|
||||
var def = exp.definition();
|
||||
var safe = safe_to_assign(tw, def, exp.scope, true);
|
||||
def.assignments++;
|
||||
if (!safe) return;
|
||||
var fixed = def.fixed;
|
||||
if (!fixed) return;
|
||||
def.references.push(exp);
|
||||
def.chained = true;
|
||||
def.fixed = function() {
|
||||
return make_node(AST_Binary, node, {
|
||||
operator: node.operator.slice(0, -1),
|
||||
left: make_node(AST_UnaryPrefix, node, {
|
||||
operator: "+",
|
||||
expression: fixed instanceof AST_Node ? fixed : fixed()
|
||||
}),
|
||||
right: make_node(AST_Number, node, {
|
||||
value: 1
|
||||
})
|
||||
});
|
||||
};
|
||||
mark(tw, def, true);
|
||||
return true;
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_VarDef, function(tw, descend) {
|
||||
var node = this;
|
||||
if (node.name instanceof AST_Destructuring) {
|
||||
suppress(node.name);
|
||||
return;
|
||||
}
|
||||
var d = node.name.definition();
|
||||
if (node.value) {
|
||||
if (safe_to_assign(tw, d, node.name.scope, node.value)) {
|
||||
d.fixed = function() {
|
||||
return node.value;
|
||||
};
|
||||
tw.loop_ids.set(d.id, tw.in_loop);
|
||||
mark(tw, d, false);
|
||||
descend();
|
||||
mark(tw, d, true);
|
||||
return true;
|
||||
} else {
|
||||
d.fixed = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
def_reduce_vars(AST_While, function(tw, descend, compressor) {
|
||||
reset_block_variables(compressor, this);
|
||||
const saved_loop = tw.in_loop;
|
||||
tw.in_loop = this;
|
||||
push(tw);
|
||||
descend();
|
||||
pop(tw);
|
||||
tw.in_loop = saved_loop;
|
||||
return true;
|
||||
});
|
||||
Generated
Vendored
+1461
File diff suppressed because it is too large
Load Diff
+287
@@ -0,0 +1,287 @@
|
||||
import {
|
||||
AST_Array,
|
||||
AST_Atom,
|
||||
AST_Await,
|
||||
AST_BigInt,
|
||||
AST_Binary,
|
||||
AST_Block,
|
||||
AST_Call,
|
||||
AST_Catch,
|
||||
AST_Chain,
|
||||
AST_Class,
|
||||
AST_ClassProperty,
|
||||
AST_ConciseMethod,
|
||||
AST_Conditional,
|
||||
AST_Debugger,
|
||||
AST_Definitions,
|
||||
AST_Destructuring,
|
||||
AST_Directive,
|
||||
AST_Do,
|
||||
AST_Dot,
|
||||
AST_DotHash,
|
||||
AST_EmptyStatement,
|
||||
AST_Expansion,
|
||||
AST_Export,
|
||||
AST_Finally,
|
||||
AST_For,
|
||||
AST_ForIn,
|
||||
AST_ForOf,
|
||||
AST_If,
|
||||
AST_Import,
|
||||
AST_ImportMeta,
|
||||
AST_Jump,
|
||||
AST_LabeledStatement,
|
||||
AST_Lambda,
|
||||
AST_LoopControl,
|
||||
AST_NameMapping,
|
||||
AST_NewTarget,
|
||||
AST_Node,
|
||||
AST_Number,
|
||||
AST_Object,
|
||||
AST_ObjectGetter,
|
||||
AST_ObjectKeyVal,
|
||||
AST_ObjectProperty,
|
||||
AST_ObjectSetter,
|
||||
AST_PrefixedTemplateString,
|
||||
AST_PropAccess,
|
||||
AST_RegExp,
|
||||
AST_Sequence,
|
||||
AST_SimpleStatement,
|
||||
AST_String,
|
||||
AST_Super,
|
||||
AST_Switch,
|
||||
AST_SwitchBranch,
|
||||
AST_Symbol,
|
||||
AST_TemplateSegment,
|
||||
AST_TemplateString,
|
||||
AST_This,
|
||||
AST_Toplevel,
|
||||
AST_Try,
|
||||
AST_Unary,
|
||||
AST_VarDef,
|
||||
AST_While,
|
||||
AST_With,
|
||||
AST_Yield
|
||||
} from "./ast.js";
|
||||
|
||||
const shallow_cmp = (node1, node2) => {
|
||||
return (
|
||||
node1 === null && node2 === null
|
||||
|| node1.TYPE === node2.TYPE && node1.shallow_cmp(node2)
|
||||
);
|
||||
};
|
||||
|
||||
export const equivalent_to = (tree1, tree2) => {
|
||||
if (!shallow_cmp(tree1, tree2)) return false;
|
||||
const walk_1_state = [tree1];
|
||||
const walk_2_state = [tree2];
|
||||
|
||||
const walk_1_push = walk_1_state.push.bind(walk_1_state);
|
||||
const walk_2_push = walk_2_state.push.bind(walk_2_state);
|
||||
|
||||
while (walk_1_state.length && walk_2_state.length) {
|
||||
const node_1 = walk_1_state.pop();
|
||||
const node_2 = walk_2_state.pop();
|
||||
|
||||
if (!shallow_cmp(node_1, node_2)) return false;
|
||||
|
||||
node_1._children_backwards(walk_1_push);
|
||||
node_2._children_backwards(walk_2_push);
|
||||
|
||||
if (walk_1_state.length !== walk_2_state.length) {
|
||||
// Different number of children
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return walk_1_state.length == 0 && walk_2_state.length == 0;
|
||||
};
|
||||
|
||||
const pass_through = () => true;
|
||||
|
||||
AST_Node.prototype.shallow_cmp = function () {
|
||||
throw new Error("did not find a shallow_cmp function for " + this.constructor.name);
|
||||
};
|
||||
|
||||
AST_Debugger.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Directive.prototype.shallow_cmp = function(other) {
|
||||
return this.value === other.value;
|
||||
};
|
||||
|
||||
AST_SimpleStatement.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Block.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_EmptyStatement.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_LabeledStatement.prototype.shallow_cmp = function(other) {
|
||||
return this.label.name === other.label.name;
|
||||
};
|
||||
|
||||
AST_Do.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_While.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_For.prototype.shallow_cmp = function(other) {
|
||||
return (this.init == null ? other.init == null : this.init === other.init) && (this.condition == null ? other.condition == null : this.condition === other.condition) && (this.step == null ? other.step == null : this.step === other.step);
|
||||
};
|
||||
|
||||
AST_ForIn.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_ForOf.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_With.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Toplevel.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Expansion.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Lambda.prototype.shallow_cmp = function(other) {
|
||||
return this.is_generator === other.is_generator && this.async === other.async;
|
||||
};
|
||||
|
||||
AST_Destructuring.prototype.shallow_cmp = function(other) {
|
||||
return this.is_array === other.is_array;
|
||||
};
|
||||
|
||||
AST_PrefixedTemplateString.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_TemplateString.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_TemplateSegment.prototype.shallow_cmp = function(other) {
|
||||
return this.value === other.value;
|
||||
};
|
||||
|
||||
AST_Jump.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_LoopControl.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Await.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Yield.prototype.shallow_cmp = function(other) {
|
||||
return this.is_star === other.is_star;
|
||||
};
|
||||
|
||||
AST_If.prototype.shallow_cmp = function(other) {
|
||||
return this.alternative == null ? other.alternative == null : this.alternative === other.alternative;
|
||||
};
|
||||
|
||||
AST_Switch.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_SwitchBranch.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Try.prototype.shallow_cmp = function(other) {
|
||||
return (this.bcatch == null ? other.bcatch == null : this.bcatch === other.bcatch) && (this.bfinally == null ? other.bfinally == null : this.bfinally === other.bfinally);
|
||||
};
|
||||
|
||||
AST_Catch.prototype.shallow_cmp = function(other) {
|
||||
return this.argname == null ? other.argname == null : this.argname === other.argname;
|
||||
};
|
||||
|
||||
AST_Finally.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Definitions.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_VarDef.prototype.shallow_cmp = function(other) {
|
||||
return this.value == null ? other.value == null : this.value === other.value;
|
||||
};
|
||||
|
||||
AST_NameMapping.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Import.prototype.shallow_cmp = function(other) {
|
||||
return (this.imported_name == null ? other.imported_name == null : this.imported_name === other.imported_name) && (this.imported_names == null ? other.imported_names == null : this.imported_names === other.imported_names);
|
||||
};
|
||||
|
||||
AST_ImportMeta.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Export.prototype.shallow_cmp = function(other) {
|
||||
return (this.exported_definition == null ? other.exported_definition == null : this.exported_definition === other.exported_definition) && (this.exported_value == null ? other.exported_value == null : this.exported_value === other.exported_value) && (this.exported_names == null ? other.exported_names == null : this.exported_names === other.exported_names) && this.module_name === other.module_name && this.is_default === other.is_default;
|
||||
};
|
||||
|
||||
AST_Call.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Sequence.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_PropAccess.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Chain.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Dot.prototype.shallow_cmp = function(other) {
|
||||
return this.property === other.property;
|
||||
};
|
||||
|
||||
AST_DotHash.prototype.shallow_cmp = function(other) {
|
||||
return this.property === other.property;
|
||||
};
|
||||
|
||||
AST_Unary.prototype.shallow_cmp = function(other) {
|
||||
return this.operator === other.operator;
|
||||
};
|
||||
|
||||
AST_Binary.prototype.shallow_cmp = function(other) {
|
||||
return this.operator === other.operator;
|
||||
};
|
||||
|
||||
AST_Conditional.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Array.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Object.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_ObjectProperty.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_ObjectKeyVal.prototype.shallow_cmp = function(other) {
|
||||
return this.key === other.key;
|
||||
};
|
||||
|
||||
AST_ObjectSetter.prototype.shallow_cmp = function(other) {
|
||||
return this.static === other.static;
|
||||
};
|
||||
|
||||
AST_ObjectGetter.prototype.shallow_cmp = function(other) {
|
||||
return this.static === other.static;
|
||||
};
|
||||
|
||||
AST_ConciseMethod.prototype.shallow_cmp = function(other) {
|
||||
return this.static === other.static && this.is_generator === other.is_generator && this.async === other.async;
|
||||
};
|
||||
|
||||
AST_Class.prototype.shallow_cmp = function(other) {
|
||||
return (this.name == null ? other.name == null : this.name === other.name) && (this.extends == null ? other.extends == null : this.extends === other.extends);
|
||||
};
|
||||
|
||||
AST_ClassProperty.prototype.shallow_cmp = function(other) {
|
||||
return this.static === other.static;
|
||||
};
|
||||
|
||||
AST_Symbol.prototype.shallow_cmp = function(other) {
|
||||
return this.name === other.name;
|
||||
};
|
||||
|
||||
AST_NewTarget.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_This.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_Super.prototype.shallow_cmp = pass_through;
|
||||
|
||||
AST_String.prototype.shallow_cmp = function(other) {
|
||||
return this.value === other.value;
|
||||
};
|
||||
|
||||
AST_Number.prototype.shallow_cmp = function(other) {
|
||||
return this.value === other.value;
|
||||
};
|
||||
|
||||
AST_BigInt.prototype.shallow_cmp = function(other) {
|
||||
return this.value === other.value;
|
||||
};
|
||||
|
||||
AST_RegExp.prototype.shallow_cmp = function (other) {
|
||||
return (
|
||||
this.value.flags === other.value.flags
|
||||
&& this.value.source === other.value.source
|
||||
);
|
||||
};
|
||||
|
||||
AST_Atom.prototype.shallow_cmp = pass_through;
|
||||
+368
@@ -0,0 +1,368 @@
|
||||
"use strict";
|
||||
/* eslint-env browser, es6, node */
|
||||
|
||||
import {
|
||||
defaults,
|
||||
map_from_object,
|
||||
map_to_object,
|
||||
HOP,
|
||||
} from "./utils/index.js";
|
||||
import { AST_Toplevel, AST_Node, walk, AST_Scope } from "./ast.js";
|
||||
import { parse } from "./parse.js";
|
||||
import { OutputStream } from "./output.js";
|
||||
import { Compressor } from "./compress/index.js";
|
||||
import { base54 } from "./scope.js";
|
||||
import { SourceMap } from "./sourcemap.js";
|
||||
import {
|
||||
mangle_properties,
|
||||
mangle_private_properties,
|
||||
reserve_quoted_keys,
|
||||
} from "./propmangle.js";
|
||||
|
||||
var to_ascii = typeof atob == "undefined" ? function(b64) {
|
||||
return Buffer.from(b64, "base64").toString();
|
||||
} : atob;
|
||||
var to_base64 = typeof btoa == "undefined" ? function(str) {
|
||||
return Buffer.from(str).toString("base64");
|
||||
} : btoa;
|
||||
|
||||
function read_source_map(code) {
|
||||
var match = /(?:^|[^.])\/\/# sourceMappingURL=data:application\/json(;[\w=-]*)?;base64,([+/0-9A-Za-z]*=*)\s*$/.exec(code);
|
||||
if (!match) {
|
||||
console.warn("inline source map not found");
|
||||
return null;
|
||||
}
|
||||
return to_ascii(match[2]);
|
||||
}
|
||||
|
||||
function set_shorthand(name, options, keys) {
|
||||
if (options[name]) {
|
||||
keys.forEach(function(key) {
|
||||
if (options[key]) {
|
||||
if (typeof options[key] != "object") options[key] = {};
|
||||
if (!(name in options[key])) options[key][name] = options[name];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function init_cache(cache) {
|
||||
if (!cache) return;
|
||||
if (!("props" in cache)) {
|
||||
cache.props = new Map();
|
||||
} else if (!(cache.props instanceof Map)) {
|
||||
cache.props = map_from_object(cache.props);
|
||||
}
|
||||
}
|
||||
|
||||
function cache_to_json(cache) {
|
||||
return {
|
||||
props: map_to_object(cache.props)
|
||||
};
|
||||
}
|
||||
|
||||
function log_input(files, options, fs, debug_folder) {
|
||||
if (!(fs && fs.writeFileSync && fs.mkdirSync)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
fs.mkdirSync(debug_folder);
|
||||
} catch (e) {
|
||||
if (e.code !== "EEXIST") throw e;
|
||||
}
|
||||
|
||||
const log_path = `${debug_folder}/terser-debug-${(Math.random() * 9999999) | 0}.log`;
|
||||
|
||||
options = options || {};
|
||||
|
||||
const options_str = JSON.stringify(options, (_key, thing) => {
|
||||
if (typeof thing === "function") return "[Function " + thing.toString() + "]";
|
||||
if (thing instanceof RegExp) return "[RegExp " + thing.toString() + "]";
|
||||
return thing;
|
||||
}, 4);
|
||||
|
||||
const files_str = (file) => {
|
||||
if (typeof file === "object" && options.parse && options.parse.spidermonkey) {
|
||||
return JSON.stringify(file, null, 2);
|
||||
} else if (typeof file === "object") {
|
||||
return Object.keys(file)
|
||||
.map((key) => key + ": " + files_str(file[key]))
|
||||
.join("\n\n");
|
||||
} else if (typeof file === "string") {
|
||||
return "```\n" + file + "\n```";
|
||||
} else {
|
||||
return file; // What do?
|
||||
}
|
||||
};
|
||||
|
||||
fs.writeFileSync(log_path, "Options: \n" + options_str + "\n\nInput files:\n\n" + files_str(files) + "\n");
|
||||
}
|
||||
|
||||
async function minify(files, options, _fs_module) {
|
||||
if (
|
||||
_fs_module
|
||||
&& typeof process === "object"
|
||||
&& process.env
|
||||
&& typeof process.env.TERSER_DEBUG_DIR === "string"
|
||||
) {
|
||||
log_input(files, options, _fs_module, process.env.TERSER_DEBUG_DIR);
|
||||
}
|
||||
|
||||
options = defaults(options, {
|
||||
compress: {},
|
||||
ecma: undefined,
|
||||
enclose: false,
|
||||
ie8: false,
|
||||
keep_classnames: undefined,
|
||||
keep_fnames: false,
|
||||
mangle: {},
|
||||
module: false,
|
||||
nameCache: null,
|
||||
output: null,
|
||||
format: null,
|
||||
parse: {},
|
||||
rename: undefined,
|
||||
safari10: false,
|
||||
sourceMap: false,
|
||||
spidermonkey: false,
|
||||
timings: false,
|
||||
toplevel: false,
|
||||
warnings: false,
|
||||
wrap: false,
|
||||
}, true);
|
||||
|
||||
var timings = options.timings && {
|
||||
start: Date.now()
|
||||
};
|
||||
if (options.keep_classnames === undefined) {
|
||||
options.keep_classnames = options.keep_fnames;
|
||||
}
|
||||
if (options.rename === undefined) {
|
||||
options.rename = options.compress && options.mangle;
|
||||
}
|
||||
if (options.output && options.format) {
|
||||
throw new Error("Please only specify either output or format option, preferrably format.");
|
||||
}
|
||||
options.format = options.format || options.output || {};
|
||||
set_shorthand("ecma", options, [ "parse", "compress", "format" ]);
|
||||
set_shorthand("ie8", options, [ "compress", "mangle", "format" ]);
|
||||
set_shorthand("keep_classnames", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("keep_fnames", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("module", options, [ "parse", "compress", "mangle" ]);
|
||||
set_shorthand("safari10", options, [ "mangle", "format" ]);
|
||||
set_shorthand("toplevel", options, [ "compress", "mangle" ]);
|
||||
set_shorthand("warnings", options, [ "compress" ]); // legacy
|
||||
var quoted_props;
|
||||
if (options.mangle) {
|
||||
options.mangle = defaults(options.mangle, {
|
||||
cache: options.nameCache && (options.nameCache.vars || {}),
|
||||
eval: false,
|
||||
ie8: false,
|
||||
keep_classnames: false,
|
||||
keep_fnames: false,
|
||||
module: false,
|
||||
nth_identifier: base54,
|
||||
properties: false,
|
||||
reserved: [],
|
||||
safari10: false,
|
||||
toplevel: false,
|
||||
}, true);
|
||||
if (options.mangle.properties) {
|
||||
if (typeof options.mangle.properties != "object") {
|
||||
options.mangle.properties = {};
|
||||
}
|
||||
if (options.mangle.properties.keep_quoted) {
|
||||
quoted_props = options.mangle.properties.reserved;
|
||||
if (!Array.isArray(quoted_props)) quoted_props = [];
|
||||
options.mangle.properties.reserved = quoted_props;
|
||||
}
|
||||
if (options.nameCache && !("cache" in options.mangle.properties)) {
|
||||
options.mangle.properties.cache = options.nameCache.props || {};
|
||||
}
|
||||
}
|
||||
init_cache(options.mangle.cache);
|
||||
init_cache(options.mangle.properties.cache);
|
||||
}
|
||||
if (options.sourceMap) {
|
||||
options.sourceMap = defaults(options.sourceMap, {
|
||||
asObject: false,
|
||||
content: null,
|
||||
filename: null,
|
||||
includeSources: false,
|
||||
root: null,
|
||||
url: null,
|
||||
}, true);
|
||||
}
|
||||
|
||||
// -- Parse phase --
|
||||
if (timings) timings.parse = Date.now();
|
||||
var toplevel;
|
||||
if (files instanceof AST_Toplevel) {
|
||||
toplevel = files;
|
||||
} else {
|
||||
if (typeof files == "string" || (options.parse.spidermonkey && !Array.isArray(files))) {
|
||||
files = [ files ];
|
||||
}
|
||||
options.parse = options.parse || {};
|
||||
options.parse.toplevel = null;
|
||||
|
||||
if (options.parse.spidermonkey) {
|
||||
options.parse.toplevel = AST_Node.from_mozilla_ast(Object.keys(files).reduce(function(toplevel, name) {
|
||||
if (!toplevel) return files[name];
|
||||
toplevel.body = toplevel.body.concat(files[name].body);
|
||||
return toplevel;
|
||||
}, null));
|
||||
} else {
|
||||
delete options.parse.spidermonkey;
|
||||
|
||||
for (var name in files) if (HOP(files, name)) {
|
||||
options.parse.filename = name;
|
||||
options.parse.toplevel = parse(files[name], options.parse);
|
||||
if (options.sourceMap && options.sourceMap.content == "inline") {
|
||||
if (Object.keys(files).length > 1)
|
||||
throw new Error("inline source map only works with singular input");
|
||||
options.sourceMap.content = read_source_map(files[name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toplevel = options.parse.toplevel;
|
||||
}
|
||||
if (quoted_props && options.mangle.properties.keep_quoted !== "strict") {
|
||||
reserve_quoted_keys(toplevel, quoted_props);
|
||||
}
|
||||
if (options.wrap) {
|
||||
toplevel = toplevel.wrap_commonjs(options.wrap);
|
||||
}
|
||||
if (options.enclose) {
|
||||
toplevel = toplevel.wrap_enclose(options.enclose);
|
||||
}
|
||||
if (timings) timings.rename = Date.now();
|
||||
// disable rename on harmony due to expand_names bug in for-of loops
|
||||
// https://github.com/mishoo/UglifyJS2/issues/2794
|
||||
if (0 && options.rename) {
|
||||
toplevel.figure_out_scope(options.mangle);
|
||||
toplevel.expand_names(options.mangle);
|
||||
}
|
||||
|
||||
// -- Compress phase --
|
||||
if (timings) timings.compress = Date.now();
|
||||
if (options.compress) {
|
||||
toplevel = new Compressor(options.compress, {
|
||||
mangle_options: options.mangle
|
||||
}).compress(toplevel);
|
||||
}
|
||||
|
||||
// -- Mangle phase --
|
||||
if (timings) timings.scope = Date.now();
|
||||
if (options.mangle) toplevel.figure_out_scope(options.mangle);
|
||||
if (timings) timings.mangle = Date.now();
|
||||
if (options.mangle) {
|
||||
toplevel.compute_char_frequency(options.mangle);
|
||||
toplevel.mangle_names(options.mangle);
|
||||
toplevel = mangle_private_properties(toplevel, options.mangle);
|
||||
}
|
||||
if (timings) timings.properties = Date.now();
|
||||
if (options.mangle && options.mangle.properties) {
|
||||
toplevel = mangle_properties(toplevel, options.mangle.properties);
|
||||
}
|
||||
|
||||
// Format phase
|
||||
if (timings) timings.format = Date.now();
|
||||
var result = {};
|
||||
if (options.format.ast) {
|
||||
result.ast = toplevel;
|
||||
}
|
||||
if (options.format.spidermonkey) {
|
||||
result.ast = toplevel.to_mozilla_ast();
|
||||
}
|
||||
if (!HOP(options.format, "code") || options.format.code) {
|
||||
if (!options.format.ast) {
|
||||
// Destroy stuff to save RAM. (unless the deprecated `ast` option is on)
|
||||
options.format._destroy_ast = true;
|
||||
|
||||
walk(toplevel, node => {
|
||||
if (node instanceof AST_Scope) {
|
||||
node.variables = undefined;
|
||||
node.enclosed = undefined;
|
||||
node.parent_scope = undefined;
|
||||
}
|
||||
if (node.block_scope) {
|
||||
node.block_scope.variables = undefined;
|
||||
node.block_scope.enclosed = undefined;
|
||||
node.parent_scope = undefined;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (options.sourceMap) {
|
||||
if (options.sourceMap.includeSources && files instanceof AST_Toplevel) {
|
||||
throw new Error("original source content unavailable");
|
||||
}
|
||||
options.format.source_map = await SourceMap({
|
||||
file: options.sourceMap.filename,
|
||||
orig: options.sourceMap.content,
|
||||
root: options.sourceMap.root,
|
||||
files: options.sourceMap.includeSources ? files : null,
|
||||
});
|
||||
}
|
||||
delete options.format.ast;
|
||||
delete options.format.code;
|
||||
delete options.format.spidermonkey;
|
||||
var stream = OutputStream(options.format);
|
||||
toplevel.print(stream);
|
||||
result.code = stream.get();
|
||||
if (options.sourceMap) {
|
||||
Object.defineProperty(result, "map", {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get() {
|
||||
const map = options.format.source_map.getEncoded();
|
||||
return (result.map = options.sourceMap.asObject ? map : JSON.stringify(map));
|
||||
},
|
||||
set(value) {
|
||||
Object.defineProperty(result, "map", {
|
||||
value,
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
result.decoded_map = options.format.source_map.getDecoded();
|
||||
if (options.sourceMap.url == "inline") {
|
||||
var sourceMap = typeof result.map === "object" ? JSON.stringify(result.map) : result.map;
|
||||
result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(sourceMap);
|
||||
} else if (options.sourceMap.url) {
|
||||
result.code += "\n//# sourceMappingURL=" + options.sourceMap.url;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (options.nameCache && options.mangle) {
|
||||
if (options.mangle.cache) options.nameCache.vars = cache_to_json(options.mangle.cache);
|
||||
if (options.mangle.properties && options.mangle.properties.cache) {
|
||||
options.nameCache.props = cache_to_json(options.mangle.properties.cache);
|
||||
}
|
||||
}
|
||||
if (options.format && options.format.source_map) {
|
||||
options.format.source_map.destroy();
|
||||
}
|
||||
if (timings) {
|
||||
timings.end = Date.now();
|
||||
result.timings = {
|
||||
parse: 1e-3 * (timings.rename - timings.parse),
|
||||
rename: 1e-3 * (timings.compress - timings.rename),
|
||||
compress: 1e-3 * (timings.scope - timings.compress),
|
||||
scope: 1e-3 * (timings.mangle - timings.scope),
|
||||
mangle: 1e-3 * (timings.properties - timings.mangle),
|
||||
properties: 1e-3 * (timings.format - timings.properties),
|
||||
format: 1e-3 * (timings.end - timings.format),
|
||||
total: 1e-3 * (timings.end - timings.start)
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export {
|
||||
minify,
|
||||
to_ascii,
|
||||
};
|
||||
+1769
File diff suppressed because it is too large
Load Diff
+2366
File diff suppressed because it is too large
Load Diff
+3365
File diff suppressed because one or more lines are too long
+376
@@ -0,0 +1,376 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
"use strict";
|
||||
/* global global, self */
|
||||
|
||||
import {
|
||||
defaults,
|
||||
push_uniq,
|
||||
} from "./utils/index.js";
|
||||
import { base54 } from "./scope.js";
|
||||
import {
|
||||
AST_Binary,
|
||||
AST_Call,
|
||||
AST_ClassPrivateProperty,
|
||||
AST_Conditional,
|
||||
AST_Dot,
|
||||
AST_DotHash,
|
||||
AST_ObjectKeyVal,
|
||||
AST_ObjectProperty,
|
||||
AST_PrivateMethod,
|
||||
AST_PrivateGetter,
|
||||
AST_PrivateSetter,
|
||||
AST_Sequence,
|
||||
AST_String,
|
||||
AST_Sub,
|
||||
TreeTransformer,
|
||||
TreeWalker,
|
||||
} from "./ast.js";
|
||||
import { domprops } from "../tools/domprops.js";
|
||||
|
||||
function find_builtins(reserved) {
|
||||
domprops.forEach(add);
|
||||
|
||||
// Compatibility fix for some standard defined globals not defined on every js environment
|
||||
var new_globals = ["Symbol", "Map", "Promise", "Proxy", "Reflect", "Set", "WeakMap", "WeakSet"];
|
||||
var objects = {};
|
||||
var global_ref = typeof global === "object" ? global : self;
|
||||
|
||||
new_globals.forEach(function (new_global) {
|
||||
objects[new_global] = global_ref[new_global] || function() {};
|
||||
});
|
||||
|
||||
[
|
||||
"null",
|
||||
"true",
|
||||
"false",
|
||||
"NaN",
|
||||
"Infinity",
|
||||
"-Infinity",
|
||||
"undefined",
|
||||
].forEach(add);
|
||||
[ Object, Array, Function, Number,
|
||||
String, Boolean, Error, Math,
|
||||
Date, RegExp, objects.Symbol, ArrayBuffer,
|
||||
DataView, decodeURI, decodeURIComponent,
|
||||
encodeURI, encodeURIComponent, eval, EvalError,
|
||||
Float32Array, Float64Array, Int8Array, Int16Array,
|
||||
Int32Array, isFinite, isNaN, JSON, objects.Map, parseFloat,
|
||||
parseInt, objects.Promise, objects.Proxy, RangeError, ReferenceError,
|
||||
objects.Reflect, objects.Set, SyntaxError, TypeError, Uint8Array,
|
||||
Uint8ClampedArray, Uint16Array, Uint32Array, URIError,
|
||||
objects.WeakMap, objects.WeakSet
|
||||
].forEach(function(ctor) {
|
||||
Object.getOwnPropertyNames(ctor).map(add);
|
||||
if (ctor.prototype) {
|
||||
Object.getOwnPropertyNames(ctor.prototype).map(add);
|
||||
}
|
||||
});
|
||||
function add(name) {
|
||||
reserved.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
function reserve_quoted_keys(ast, reserved) {
|
||||
function add(name) {
|
||||
push_uniq(reserved, name);
|
||||
}
|
||||
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_ObjectKeyVal && node.quote) {
|
||||
add(node.key);
|
||||
} else if (node instanceof AST_ObjectProperty && node.quote) {
|
||||
add(node.key.name);
|
||||
} else if (node instanceof AST_Sub) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
function addStrings(node, add) {
|
||||
node.walk(new TreeWalker(function(node) {
|
||||
if (node instanceof AST_Sequence) {
|
||||
addStrings(node.tail_node(), add);
|
||||
} else if (node instanceof AST_String) {
|
||||
add(node.value);
|
||||
} else if (node instanceof AST_Conditional) {
|
||||
addStrings(node.consequent, add);
|
||||
addStrings(node.alternative, add);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
function mangle_private_properties(ast, options) {
|
||||
var cprivate = -1;
|
||||
var private_cache = new Map();
|
||||
var nth_identifier = options.nth_identifier || base54;
|
||||
|
||||
ast = ast.transform(new TreeTransformer(function(node) {
|
||||
if (
|
||||
node instanceof AST_ClassPrivateProperty
|
||||
|| node instanceof AST_PrivateMethod
|
||||
|| node instanceof AST_PrivateGetter
|
||||
|| node instanceof AST_PrivateSetter
|
||||
) {
|
||||
node.key.name = mangle_private(node.key.name);
|
||||
} else if (node instanceof AST_DotHash) {
|
||||
node.property = mangle_private(node.property);
|
||||
}
|
||||
}));
|
||||
return ast;
|
||||
|
||||
function mangle_private(name) {
|
||||
let mangled = private_cache.get(name);
|
||||
if (!mangled) {
|
||||
mangled = nth_identifier.get(++cprivate);
|
||||
private_cache.set(name, mangled);
|
||||
}
|
||||
|
||||
return mangled;
|
||||
}
|
||||
}
|
||||
|
||||
function mangle_properties(ast, options) {
|
||||
options = defaults(options, {
|
||||
builtins: false,
|
||||
cache: null,
|
||||
debug: false,
|
||||
keep_quoted: false,
|
||||
nth_identifier: base54,
|
||||
only_cache: false,
|
||||
regex: null,
|
||||
reserved: null,
|
||||
undeclared: false,
|
||||
}, true);
|
||||
|
||||
var nth_identifier = options.nth_identifier;
|
||||
|
||||
var reserved_option = options.reserved;
|
||||
if (!Array.isArray(reserved_option)) reserved_option = [reserved_option];
|
||||
var reserved = new Set(reserved_option);
|
||||
if (!options.builtins) find_builtins(reserved);
|
||||
|
||||
var cname = -1;
|
||||
|
||||
var cache;
|
||||
if (options.cache) {
|
||||
cache = options.cache.props;
|
||||
} else {
|
||||
cache = new Map();
|
||||
}
|
||||
|
||||
var regex = options.regex && new RegExp(options.regex);
|
||||
|
||||
// note debug is either false (disabled), or a string of the debug suffix to use (enabled).
|
||||
// note debug may be enabled as an empty string, which is falsey. Also treat passing 'true'
|
||||
// the same as passing an empty string.
|
||||
var debug = options.debug !== false;
|
||||
var debug_name_suffix;
|
||||
if (debug) {
|
||||
debug_name_suffix = (options.debug === true ? "" : options.debug);
|
||||
}
|
||||
|
||||
var names_to_mangle = new Set();
|
||||
var unmangleable = new Set();
|
||||
// Track each already-mangled name to prevent nth_identifier from generating
|
||||
// the same name.
|
||||
cache.forEach((mangled_name) => unmangleable.add(mangled_name));
|
||||
|
||||
var keep_quoted = !!options.keep_quoted;
|
||||
|
||||
// step 1: find candidates to mangle
|
||||
ast.walk(new TreeWalker(function(node) {
|
||||
if (
|
||||
node instanceof AST_ClassPrivateProperty
|
||||
|| node instanceof AST_PrivateMethod
|
||||
|| node instanceof AST_PrivateGetter
|
||||
|| node instanceof AST_PrivateSetter
|
||||
|| node instanceof AST_DotHash
|
||||
) {
|
||||
// handled by mangle_private_properties
|
||||
} else if (node instanceof AST_ObjectKeyVal) {
|
||||
if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
|
||||
add(node.key);
|
||||
}
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
// setter or getter, since KeyVal is handled above
|
||||
if (!keep_quoted || !node.quote) {
|
||||
add(node.key.name);
|
||||
}
|
||||
} else if (node instanceof AST_Dot) {
|
||||
var declared = !!options.undeclared;
|
||||
if (!declared) {
|
||||
var root = node;
|
||||
while (root.expression) {
|
||||
root = root.expression;
|
||||
}
|
||||
declared = !(root.thedef && root.thedef.undeclared);
|
||||
}
|
||||
if (declared &&
|
||||
(!keep_quoted || !node.quote)) {
|
||||
add(node.property);
|
||||
}
|
||||
} else if (node instanceof AST_Sub) {
|
||||
if (!keep_quoted) {
|
||||
addStrings(node.property, add);
|
||||
}
|
||||
} else if (node instanceof AST_Call
|
||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||
addStrings(node.args[1], add);
|
||||
} else if (node instanceof AST_Binary && node.operator === "in") {
|
||||
addStrings(node.left, add);
|
||||
}
|
||||
}));
|
||||
|
||||
// step 2: transform the tree, renaming properties
|
||||
return ast.transform(new TreeTransformer(function(node) {
|
||||
if (
|
||||
node instanceof AST_ClassPrivateProperty
|
||||
|| node instanceof AST_PrivateMethod
|
||||
|| node instanceof AST_PrivateGetter
|
||||
|| node instanceof AST_PrivateSetter
|
||||
|| node instanceof AST_DotHash
|
||||
) {
|
||||
// handled by mangle_private_properties
|
||||
} else if (node instanceof AST_ObjectKeyVal) {
|
||||
if (typeof node.key == "string" && (!keep_quoted || !node.quote)) {
|
||||
node.key = mangle(node.key);
|
||||
}
|
||||
} else if (node instanceof AST_ObjectProperty) {
|
||||
// setter, getter, method or class field
|
||||
if (!keep_quoted || !node.quote) {
|
||||
node.key.name = mangle(node.key.name);
|
||||
}
|
||||
} else if (node instanceof AST_Dot) {
|
||||
if (!keep_quoted || !node.quote) {
|
||||
node.property = mangle(node.property);
|
||||
}
|
||||
} else if (!keep_quoted && node instanceof AST_Sub) {
|
||||
node.property = mangleStrings(node.property);
|
||||
} else if (node instanceof AST_Call
|
||||
&& node.expression.print_to_string() == "Object.defineProperty") {
|
||||
node.args[1] = mangleStrings(node.args[1]);
|
||||
} else if (node instanceof AST_Binary && node.operator === "in") {
|
||||
node.left = mangleStrings(node.left);
|
||||
}
|
||||
}));
|
||||
|
||||
// only function declarations after this line
|
||||
|
||||
function can_mangle(name) {
|
||||
if (unmangleable.has(name)) return false;
|
||||
if (reserved.has(name)) return false;
|
||||
if (options.only_cache) {
|
||||
return cache.has(name);
|
||||
}
|
||||
if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function should_mangle(name) {
|
||||
if (regex && !regex.test(name)) return false;
|
||||
if (reserved.has(name)) return false;
|
||||
return cache.has(name)
|
||||
|| names_to_mangle.has(name);
|
||||
}
|
||||
|
||||
function add(name) {
|
||||
if (can_mangle(name))
|
||||
names_to_mangle.add(name);
|
||||
|
||||
if (!should_mangle(name)) {
|
||||
unmangleable.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
function mangle(name) {
|
||||
if (!should_mangle(name)) {
|
||||
return name;
|
||||
}
|
||||
|
||||
var mangled = cache.get(name);
|
||||
if (!mangled) {
|
||||
if (debug) {
|
||||
// debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_.
|
||||
var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_";
|
||||
|
||||
if (can_mangle(debug_mangled)) {
|
||||
mangled = debug_mangled;
|
||||
}
|
||||
}
|
||||
|
||||
// either debug mode is off, or it is on and we could not use the mangled name
|
||||
if (!mangled) {
|
||||
do {
|
||||
mangled = nth_identifier.get(++cname);
|
||||
} while (!can_mangle(mangled));
|
||||
}
|
||||
|
||||
cache.set(name, mangled);
|
||||
}
|
||||
return mangled;
|
||||
}
|
||||
|
||||
function mangleStrings(node) {
|
||||
return node.transform(new TreeTransformer(function(node) {
|
||||
if (node instanceof AST_Sequence) {
|
||||
var last = node.expressions.length - 1;
|
||||
node.expressions[last] = mangleStrings(node.expressions[last]);
|
||||
} else if (node instanceof AST_String) {
|
||||
node.value = mangle(node.value);
|
||||
} else if (node instanceof AST_Conditional) {
|
||||
node.consequent = mangleStrings(node.consequent);
|
||||
node.alternative = mangleStrings(node.alternative);
|
||||
}
|
||||
return node;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
reserve_quoted_keys,
|
||||
mangle_properties,
|
||||
mangle_private_properties,
|
||||
};
|
||||
+1042
File diff suppressed because it is too large
Load Diff
+488
@@ -0,0 +1,488 @@
|
||||
import {
|
||||
AST_Accessor,
|
||||
AST_Array,
|
||||
AST_Arrow,
|
||||
AST_Await,
|
||||
AST_BigInt,
|
||||
AST_Binary,
|
||||
AST_Block,
|
||||
AST_Break,
|
||||
AST_Call,
|
||||
AST_Case,
|
||||
AST_Class,
|
||||
AST_ClassPrivateProperty,
|
||||
AST_ClassProperty,
|
||||
AST_ConciseMethod,
|
||||
AST_Conditional,
|
||||
AST_Const,
|
||||
AST_Continue,
|
||||
AST_Debugger,
|
||||
AST_Default,
|
||||
AST_Defun,
|
||||
AST_Destructuring,
|
||||
AST_Directive,
|
||||
AST_Do,
|
||||
AST_Dot,
|
||||
AST_DotHash,
|
||||
AST_EmptyStatement,
|
||||
AST_Expansion,
|
||||
AST_Export,
|
||||
AST_False,
|
||||
AST_For,
|
||||
AST_ForIn,
|
||||
AST_Function,
|
||||
AST_Hole,
|
||||
AST_If,
|
||||
AST_Import,
|
||||
AST_ImportMeta,
|
||||
AST_Infinity,
|
||||
AST_LabeledStatement,
|
||||
AST_Let,
|
||||
AST_NameMapping,
|
||||
AST_NaN,
|
||||
AST_New,
|
||||
AST_NewTarget,
|
||||
AST_Node,
|
||||
AST_Null,
|
||||
AST_Number,
|
||||
AST_Object,
|
||||
AST_ObjectKeyVal,
|
||||
AST_ObjectGetter,
|
||||
AST_ObjectSetter,
|
||||
AST_PrivateGetter,
|
||||
AST_PrivateMethod,
|
||||
AST_PrivateSetter,
|
||||
AST_RegExp,
|
||||
AST_Return,
|
||||
AST_Sequence,
|
||||
AST_String,
|
||||
AST_Sub,
|
||||
AST_Super,
|
||||
AST_Switch,
|
||||
AST_Symbol,
|
||||
AST_SymbolClassProperty,
|
||||
AST_SymbolExportForeign,
|
||||
AST_SymbolImportForeign,
|
||||
AST_SymbolRef,
|
||||
AST_SymbolDeclaration,
|
||||
AST_TemplateSegment,
|
||||
AST_TemplateString,
|
||||
AST_This,
|
||||
AST_Throw,
|
||||
AST_Toplevel,
|
||||
AST_True,
|
||||
AST_Try,
|
||||
AST_Catch,
|
||||
AST_Finally,
|
||||
AST_Unary,
|
||||
AST_Undefined,
|
||||
AST_Var,
|
||||
AST_VarDef,
|
||||
AST_While,
|
||||
AST_With,
|
||||
AST_Yield,
|
||||
walk_parent
|
||||
} from "./ast.js";
|
||||
import { first_in_statement } from "./utils/first_in_statement.js";
|
||||
|
||||
let mangle_options = undefined;
|
||||
AST_Node.prototype.size = function (compressor, stack) {
|
||||
mangle_options = compressor && compressor.mangle_options;
|
||||
|
||||
let size = 0;
|
||||
walk_parent(this, (node, info) => {
|
||||
size += node._size(info);
|
||||
|
||||
// Braceless arrow functions have fake "return" statements
|
||||
if (node instanceof AST_Arrow && node.is_braceless()) {
|
||||
size += node.body[0].value._size(info);
|
||||
return true;
|
||||
}
|
||||
}, stack || (compressor && compressor.stack));
|
||||
|
||||
// just to save a bit of memory
|
||||
mangle_options = undefined;
|
||||
|
||||
return size;
|
||||
};
|
||||
|
||||
AST_Node.prototype._size = () => 0;
|
||||
|
||||
AST_Debugger.prototype._size = () => 8;
|
||||
|
||||
AST_Directive.prototype._size = function () {
|
||||
// TODO string encoding stuff
|
||||
return 2 + this.value.length;
|
||||
};
|
||||
|
||||
/** Count commas/semicolons necessary to show a list of expressions/statements */
|
||||
const list_overhead = (array) => array.length && array.length - 1;
|
||||
|
||||
AST_Block.prototype._size = function () {
|
||||
return 2 + list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_Toplevel.prototype._size = function() {
|
||||
return list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_EmptyStatement.prototype._size = () => 1;
|
||||
|
||||
AST_LabeledStatement.prototype._size = () => 2; // x:
|
||||
|
||||
AST_Do.prototype._size = () => 9;
|
||||
|
||||
AST_While.prototype._size = () => 7;
|
||||
|
||||
AST_For.prototype._size = () => 8;
|
||||
|
||||
AST_ForIn.prototype._size = () => 8;
|
||||
// AST_ForOf inherits ^
|
||||
|
||||
AST_With.prototype._size = () => 6;
|
||||
|
||||
AST_Expansion.prototype._size = () => 3;
|
||||
|
||||
const lambda_modifiers = func =>
|
||||
(func.is_generator ? 1 : 0) + (func.async ? 6 : 0);
|
||||
|
||||
AST_Accessor.prototype._size = function () {
|
||||
return lambda_modifiers(this) + 4 + list_overhead(this.argnames) + list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_Function.prototype._size = function (info) {
|
||||
const first = !!first_in_statement(info);
|
||||
return (first * 2) + lambda_modifiers(this) + 12 + list_overhead(this.argnames) + list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_Defun.prototype._size = function () {
|
||||
return lambda_modifiers(this) + 13 + list_overhead(this.argnames) + list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_Arrow.prototype._size = function () {
|
||||
let args_and_arrow = 2 + list_overhead(this.argnames);
|
||||
|
||||
if (
|
||||
!(
|
||||
this.argnames.length === 1
|
||||
&& this.argnames[0] instanceof AST_Symbol
|
||||
)
|
||||
) {
|
||||
args_and_arrow += 2; // parens around the args
|
||||
}
|
||||
|
||||
const body_overhead = this.is_braceless() ? 0 : list_overhead(this.body) + 2;
|
||||
|
||||
return lambda_modifiers(this) + args_and_arrow + body_overhead;
|
||||
};
|
||||
|
||||
AST_Destructuring.prototype._size = () => 2;
|
||||
|
||||
AST_TemplateString.prototype._size = function () {
|
||||
return 2 + (Math.floor(this.segments.length / 2) * 3); /* "${}" */
|
||||
};
|
||||
|
||||
AST_TemplateSegment.prototype._size = function () {
|
||||
return this.value.length;
|
||||
};
|
||||
|
||||
AST_Return.prototype._size = function () {
|
||||
return this.value ? 7 : 6;
|
||||
};
|
||||
|
||||
AST_Throw.prototype._size = () => 6;
|
||||
|
||||
AST_Break.prototype._size = function () {
|
||||
return this.label ? 6 : 5;
|
||||
};
|
||||
|
||||
AST_Continue.prototype._size = function () {
|
||||
return this.label ? 9 : 8;
|
||||
};
|
||||
|
||||
AST_If.prototype._size = () => 4;
|
||||
|
||||
AST_Switch.prototype._size = function () {
|
||||
return 8 + list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_Case.prototype._size = function () {
|
||||
return 5 + list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_Default.prototype._size = function () {
|
||||
return 8 + list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_Try.prototype._size = function () {
|
||||
return 3 + list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_Catch.prototype._size = function () {
|
||||
let size = 7 + list_overhead(this.body);
|
||||
if (this.argname) {
|
||||
size += 2;
|
||||
}
|
||||
return size;
|
||||
};
|
||||
|
||||
AST_Finally.prototype._size = function () {
|
||||
return 7 + list_overhead(this.body);
|
||||
};
|
||||
|
||||
AST_Var.prototype._size = function () {
|
||||
return 4 + list_overhead(this.definitions);
|
||||
};
|
||||
|
||||
AST_Let.prototype._size = function () {
|
||||
return 4 + list_overhead(this.definitions);
|
||||
};
|
||||
|
||||
AST_Const.prototype._size = function () {
|
||||
return 6 + list_overhead(this.definitions);
|
||||
};
|
||||
|
||||
AST_VarDef.prototype._size = function () {
|
||||
return this.value ? 1 : 0;
|
||||
};
|
||||
|
||||
AST_NameMapping.prototype._size = function () {
|
||||
// foreign name isn't mangled
|
||||
return this.name ? 4 : 0;
|
||||
};
|
||||
|
||||
AST_Import.prototype._size = function () {
|
||||
// import
|
||||
let size = 6;
|
||||
|
||||
if (this.imported_name) size += 1;
|
||||
|
||||
// from
|
||||
if (this.imported_name || this.imported_names) size += 5;
|
||||
|
||||
// braces, and the commas
|
||||
if (this.imported_names) {
|
||||
size += 2 + list_overhead(this.imported_names);
|
||||
}
|
||||
|
||||
return size;
|
||||
};
|
||||
|
||||
AST_ImportMeta.prototype._size = () => 11;
|
||||
|
||||
AST_Export.prototype._size = function () {
|
||||
let size = 7 + (this.is_default ? 8 : 0);
|
||||
|
||||
if (this.exported_value) {
|
||||
size += this.exported_value._size();
|
||||
}
|
||||
|
||||
if (this.exported_names) {
|
||||
// Braces and commas
|
||||
size += 2 + list_overhead(this.exported_names);
|
||||
}
|
||||
|
||||
if (this.module_name) {
|
||||
// "from "
|
||||
size += 5;
|
||||
}
|
||||
|
||||
return size;
|
||||
};
|
||||
|
||||
AST_Call.prototype._size = function () {
|
||||
if (this.optional) {
|
||||
return 4 + list_overhead(this.args);
|
||||
}
|
||||
return 2 + list_overhead(this.args);
|
||||
};
|
||||
|
||||
AST_New.prototype._size = function () {
|
||||
return 6 + list_overhead(this.args);
|
||||
};
|
||||
|
||||
AST_Sequence.prototype._size = function () {
|
||||
return list_overhead(this.expressions);
|
||||
};
|
||||
|
||||
AST_Dot.prototype._size = function () {
|
||||
if (this.optional) {
|
||||
return this.property.length + 2;
|
||||
}
|
||||
return this.property.length + 1;
|
||||
};
|
||||
|
||||
AST_DotHash.prototype._size = function () {
|
||||
if (this.optional) {
|
||||
return this.property.length + 3;
|
||||
}
|
||||
return this.property.length + 2;
|
||||
};
|
||||
|
||||
AST_Sub.prototype._size = function () {
|
||||
return this.optional ? 4 : 2;
|
||||
};
|
||||
|
||||
AST_Unary.prototype._size = function () {
|
||||
if (this.operator === "typeof") return 7;
|
||||
if (this.operator === "void") return 5;
|
||||
return this.operator.length;
|
||||
};
|
||||
|
||||
AST_Binary.prototype._size = function (info) {
|
||||
if (this.operator === "in") return 4;
|
||||
|
||||
let size = this.operator.length;
|
||||
|
||||
if (
|
||||
(this.operator === "+" || this.operator === "-")
|
||||
&& this.right instanceof AST_Unary && this.right.operator === this.operator
|
||||
) {
|
||||
// 1+ +a > needs space between the +
|
||||
size += 1;
|
||||
}
|
||||
|
||||
if (this.needs_parens(info)) {
|
||||
size += 2;
|
||||
}
|
||||
|
||||
return size;
|
||||
};
|
||||
|
||||
AST_Conditional.prototype._size = () => 3;
|
||||
|
||||
AST_Array.prototype._size = function () {
|
||||
return 2 + list_overhead(this.elements);
|
||||
};
|
||||
|
||||
AST_Object.prototype._size = function (info) {
|
||||
let base = 2;
|
||||
if (first_in_statement(info)) {
|
||||
base += 2; // parens
|
||||
}
|
||||
return base + list_overhead(this.properties);
|
||||
};
|
||||
|
||||
/*#__INLINE__*/
|
||||
const key_size = key =>
|
||||
typeof key === "string" ? key.length : 0;
|
||||
|
||||
AST_ObjectKeyVal.prototype._size = function () {
|
||||
return key_size(this.key) + 1;
|
||||
};
|
||||
|
||||
/*#__INLINE__*/
|
||||
const static_size = is_static => is_static ? 7 : 0;
|
||||
|
||||
AST_ObjectGetter.prototype._size = function () {
|
||||
return 5 + static_size(this.static) + key_size(this.key);
|
||||
};
|
||||
|
||||
AST_ObjectSetter.prototype._size = function () {
|
||||
return 5 + static_size(this.static) + key_size(this.key);
|
||||
};
|
||||
|
||||
AST_ConciseMethod.prototype._size = function () {
|
||||
return static_size(this.static) + key_size(this.key) + lambda_modifiers(this);
|
||||
};
|
||||
|
||||
AST_PrivateMethod.prototype._size = function () {
|
||||
return AST_ConciseMethod.prototype._size.call(this) + 1;
|
||||
};
|
||||
|
||||
AST_PrivateGetter.prototype._size = AST_PrivateSetter.prototype._size = function () {
|
||||
return AST_ConciseMethod.prototype._size.call(this) + 4;
|
||||
};
|
||||
|
||||
AST_Class.prototype._size = function () {
|
||||
return (
|
||||
(this.name ? 8 : 7)
|
||||
+ (this.extends ? 8 : 0)
|
||||
);
|
||||
};
|
||||
|
||||
AST_ClassProperty.prototype._size = function () {
|
||||
return (
|
||||
static_size(this.static)
|
||||
+ (typeof this.key === "string" ? this.key.length + 2 : 0)
|
||||
+ (this.value ? 1 : 0)
|
||||
);
|
||||
};
|
||||
|
||||
AST_ClassPrivateProperty.prototype._size = function () {
|
||||
return AST_ClassProperty.prototype._size.call(this) + 1;
|
||||
};
|
||||
|
||||
AST_Symbol.prototype._size = function () {
|
||||
return !mangle_options || this.definition().unmangleable(mangle_options)
|
||||
? this.name.length
|
||||
: 1;
|
||||
};
|
||||
|
||||
// TODO take propmangle into account
|
||||
AST_SymbolClassProperty.prototype._size = function () {
|
||||
return this.name.length;
|
||||
};
|
||||
|
||||
AST_SymbolRef.prototype._size = AST_SymbolDeclaration.prototype._size = function () {
|
||||
const { name, thedef } = this;
|
||||
|
||||
if (thedef && thedef.global) return name.length;
|
||||
|
||||
if (name === "arguments") return 9;
|
||||
|
||||
return AST_Symbol.prototype._size.call(this);
|
||||
};
|
||||
|
||||
AST_NewTarget.prototype._size = () => 10;
|
||||
|
||||
AST_SymbolImportForeign.prototype._size = function () {
|
||||
return this.name.length;
|
||||
};
|
||||
|
||||
AST_SymbolExportForeign.prototype._size = function () {
|
||||
return this.name.length;
|
||||
};
|
||||
|
||||
AST_This.prototype._size = () => 4;
|
||||
|
||||
AST_Super.prototype._size = () => 5;
|
||||
|
||||
AST_String.prototype._size = function () {
|
||||
return this.value.length + 2;
|
||||
};
|
||||
|
||||
AST_Number.prototype._size = function () {
|
||||
const { value } = this;
|
||||
if (value === 0) return 1;
|
||||
if (value > 0 && Math.floor(value) === value) {
|
||||
return Math.floor(Math.log10(value) + 1);
|
||||
}
|
||||
return value.toString().length;
|
||||
};
|
||||
|
||||
AST_BigInt.prototype._size = function () {
|
||||
return this.value.length;
|
||||
};
|
||||
|
||||
AST_RegExp.prototype._size = function () {
|
||||
return this.value.toString().length;
|
||||
};
|
||||
|
||||
AST_Null.prototype._size = () => 4;
|
||||
|
||||
AST_NaN.prototype._size = () => 3;
|
||||
|
||||
AST_Undefined.prototype._size = () => 6; // "void 0"
|
||||
|
||||
AST_Hole.prototype._size = () => 0; // comma is taken into account by list_overhead()
|
||||
|
||||
AST_Infinity.prototype._size = () => 8;
|
||||
|
||||
AST_True.prototype._size = () => 4;
|
||||
|
||||
AST_False.prototype._size = () => 5;
|
||||
|
||||
AST_Await.prototype._size = () => 6;
|
||||
|
||||
AST_Yield.prototype._size = () => 6;
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import {SourceMapConsumer, SourceMapGenerator} from "@jridgewell/source-map";
|
||||
import {defaults, HOP} from "./utils/index.js";
|
||||
|
||||
// a small wrapper around source-map and @jridgewell/source-map
|
||||
async function SourceMap(options) {
|
||||
options = defaults(options, {
|
||||
file : null,
|
||||
root : null,
|
||||
orig : null,
|
||||
files: {},
|
||||
});
|
||||
|
||||
var orig_map;
|
||||
var generator = new SourceMapGenerator({
|
||||
file : options.file,
|
||||
sourceRoot : options.root
|
||||
});
|
||||
|
||||
let sourcesContent = {__proto__: null};
|
||||
let files = options.files;
|
||||
for (var name in files) if (HOP(files, name)) {
|
||||
sourcesContent[name] = files[name];
|
||||
}
|
||||
if (options.orig) {
|
||||
// We support both @jridgewell/source-map (which has a sync
|
||||
// SourceMapConsumer) and source-map (which has an async
|
||||
// SourceMapConsumer).
|
||||
orig_map = await new SourceMapConsumer(options.orig);
|
||||
if (orig_map.sourcesContent) {
|
||||
orig_map.sources.forEach(function(source, i) {
|
||||
var content = orig_map.sourcesContent[i];
|
||||
if (content) {
|
||||
sourcesContent[source] = content;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
|
||||
let generatedPos = { line: gen_line, column: gen_col };
|
||||
|
||||
if (orig_map) {
|
||||
var info = orig_map.originalPositionFor({
|
||||
line: orig_line,
|
||||
column: orig_col
|
||||
});
|
||||
if (info.source === null) {
|
||||
generator.addMapping({
|
||||
generated: generatedPos,
|
||||
original: null,
|
||||
source: null,
|
||||
name: null
|
||||
});
|
||||
return;
|
||||
}
|
||||
source = info.source;
|
||||
orig_line = info.line;
|
||||
orig_col = info.column;
|
||||
name = info.name || name;
|
||||
}
|
||||
generator.addMapping({
|
||||
generated : generatedPos,
|
||||
original : { line: orig_line, column: orig_col },
|
||||
source : source,
|
||||
name : name
|
||||
});
|
||||
generator.setSourceContent(source, sourcesContent[source]);
|
||||
}
|
||||
|
||||
function clean(map) {
|
||||
const allNull = map.sourcesContent && map.sourcesContent.every(c => c == null);
|
||||
if (allNull) delete map.sourcesContent;
|
||||
if (map.file === undefined) delete map.file;
|
||||
if (map.sourceRoot === undefined) delete map.sourceRoot;
|
||||
return map;
|
||||
}
|
||||
|
||||
function getDecoded() {
|
||||
if (!generator.toDecodedMap) return null;
|
||||
return clean(generator.toDecodedMap());
|
||||
}
|
||||
|
||||
function getEncoded() {
|
||||
return clean(generator.toJSON());
|
||||
}
|
||||
|
||||
function destroy() {
|
||||
// @jridgewell/source-map's SourceMapConsumer does not need to be
|
||||
// manually freed.
|
||||
if (orig_map && orig_map.destroy) orig_map.destroy();
|
||||
}
|
||||
|
||||
return {
|
||||
add,
|
||||
getDecoded,
|
||||
getEncoded,
|
||||
destroy,
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
SourceMap,
|
||||
};
|
||||
+318
@@ -0,0 +1,318 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
import {
|
||||
AST_Array,
|
||||
AST_Await,
|
||||
AST_Binary,
|
||||
AST_Block,
|
||||
AST_Call,
|
||||
AST_Case,
|
||||
AST_Catch,
|
||||
AST_Chain,
|
||||
AST_Class,
|
||||
AST_Conditional,
|
||||
AST_Definitions,
|
||||
AST_Destructuring,
|
||||
AST_Do,
|
||||
AST_Exit,
|
||||
AST_Expansion,
|
||||
AST_Export,
|
||||
AST_For,
|
||||
AST_ForIn,
|
||||
AST_If,
|
||||
AST_Import,
|
||||
AST_LabeledStatement,
|
||||
AST_Lambda,
|
||||
AST_LoopControl,
|
||||
AST_NameMapping,
|
||||
AST_Node,
|
||||
AST_Number,
|
||||
AST_Object,
|
||||
AST_ObjectProperty,
|
||||
AST_PrefixedTemplateString,
|
||||
AST_PropAccess,
|
||||
AST_Sequence,
|
||||
AST_SimpleStatement,
|
||||
AST_Sub,
|
||||
AST_Switch,
|
||||
AST_TemplateString,
|
||||
AST_Try,
|
||||
AST_Unary,
|
||||
AST_VarDef,
|
||||
AST_While,
|
||||
AST_With,
|
||||
AST_Yield,
|
||||
} from "./ast.js";
|
||||
import {
|
||||
MAP,
|
||||
noop,
|
||||
} from "./utils/index.js";
|
||||
|
||||
function def_transform(node, descend) {
|
||||
node.DEFMETHOD("transform", function(tw, in_list) {
|
||||
let transformed = undefined;
|
||||
tw.push(this);
|
||||
if (tw.before) transformed = tw.before(this, descend, in_list);
|
||||
if (transformed === undefined) {
|
||||
transformed = this;
|
||||
descend(transformed, tw);
|
||||
if (tw.after) {
|
||||
const after_ret = tw.after(transformed, in_list);
|
||||
if (after_ret !== undefined) transformed = after_ret;
|
||||
}
|
||||
}
|
||||
tw.pop();
|
||||
return transformed;
|
||||
});
|
||||
}
|
||||
|
||||
function do_list(list, tw) {
|
||||
return MAP(list, function(node) {
|
||||
return node.transform(tw, true);
|
||||
});
|
||||
}
|
||||
|
||||
def_transform(AST_Node, noop);
|
||||
|
||||
def_transform(AST_LabeledStatement, function(self, tw) {
|
||||
self.label = self.label.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_SimpleStatement, function(self, tw) {
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Block, function(self, tw) {
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Do, function(self, tw) {
|
||||
self.body = self.body.transform(tw);
|
||||
self.condition = self.condition.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_While, function(self, tw) {
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_For, function(self, tw) {
|
||||
if (self.init) self.init = self.init.transform(tw);
|
||||
if (self.condition) self.condition = self.condition.transform(tw);
|
||||
if (self.step) self.step = self.step.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_ForIn, function(self, tw) {
|
||||
self.init = self.init.transform(tw);
|
||||
self.object = self.object.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_With, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Exit, function(self, tw) {
|
||||
if (self.value) self.value = self.value.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_LoopControl, function(self, tw) {
|
||||
if (self.label) self.label = self.label.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_If, function(self, tw) {
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.body = self.body.transform(tw);
|
||||
if (self.alternative) self.alternative = self.alternative.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Switch, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Case, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Try, function(self, tw) {
|
||||
self.body = do_list(self.body, tw);
|
||||
if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
|
||||
if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Catch, function(self, tw) {
|
||||
if (self.argname) self.argname = self.argname.transform(tw);
|
||||
self.body = do_list(self.body, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Definitions, function(self, tw) {
|
||||
self.definitions = do_list(self.definitions, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_VarDef, function(self, tw) {
|
||||
self.name = self.name.transform(tw);
|
||||
if (self.value) self.value = self.value.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Destructuring, function(self, tw) {
|
||||
self.names = do_list(self.names, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Lambda, function(self, tw) {
|
||||
if (self.name) self.name = self.name.transform(tw);
|
||||
self.argnames = do_list(self.argnames, tw);
|
||||
if (self.body instanceof AST_Node) {
|
||||
self.body = self.body.transform(tw);
|
||||
} else {
|
||||
self.body = do_list(self.body, tw);
|
||||
}
|
||||
});
|
||||
|
||||
def_transform(AST_Call, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.args = do_list(self.args, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Sequence, function(self, tw) {
|
||||
const result = do_list(self.expressions, tw);
|
||||
self.expressions = result.length
|
||||
? result
|
||||
: [new AST_Number({ value: 0 })];
|
||||
});
|
||||
|
||||
def_transform(AST_PropAccess, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Sub, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
self.property = self.property.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Chain, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Yield, function(self, tw) {
|
||||
if (self.expression) self.expression = self.expression.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Await, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Unary, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Binary, function(self, tw) {
|
||||
self.left = self.left.transform(tw);
|
||||
self.right = self.right.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Conditional, function(self, tw) {
|
||||
self.condition = self.condition.transform(tw);
|
||||
self.consequent = self.consequent.transform(tw);
|
||||
self.alternative = self.alternative.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Array, function(self, tw) {
|
||||
self.elements = do_list(self.elements, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Object, function(self, tw) {
|
||||
self.properties = do_list(self.properties, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_ObjectProperty, function(self, tw) {
|
||||
if (self.key instanceof AST_Node) {
|
||||
self.key = self.key.transform(tw);
|
||||
}
|
||||
if (self.value) self.value = self.value.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Class, function(self, tw) {
|
||||
if (self.name) self.name = self.name.transform(tw);
|
||||
if (self.extends) self.extends = self.extends.transform(tw);
|
||||
self.properties = do_list(self.properties, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Expansion, function(self, tw) {
|
||||
self.expression = self.expression.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_NameMapping, function(self, tw) {
|
||||
self.foreign_name = self.foreign_name.transform(tw);
|
||||
self.name = self.name.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Import, function(self, tw) {
|
||||
if (self.imported_name) self.imported_name = self.imported_name.transform(tw);
|
||||
if (self.imported_names) do_list(self.imported_names, tw);
|
||||
self.module_name = self.module_name.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_Export, function(self, tw) {
|
||||
if (self.exported_definition) self.exported_definition = self.exported_definition.transform(tw);
|
||||
if (self.exported_value) self.exported_value = self.exported_value.transform(tw);
|
||||
if (self.exported_names) do_list(self.exported_names, tw);
|
||||
if (self.module_name) self.module_name = self.module_name.transform(tw);
|
||||
});
|
||||
|
||||
def_transform(AST_TemplateString, function(self, tw) {
|
||||
self.segments = do_list(self.segments, tw);
|
||||
});
|
||||
|
||||
def_transform(AST_PrefixedTemplateString, function(self, tw) {
|
||||
self.prefix = self.prefix.transform(tw);
|
||||
self.template_string = self.template_string.transform(tw);
|
||||
});
|
||||
|
||||
Generated
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
AST_Binary,
|
||||
AST_Conditional,
|
||||
AST_Dot,
|
||||
AST_Object,
|
||||
AST_Sequence,
|
||||
AST_Statement,
|
||||
AST_Sub,
|
||||
AST_UnaryPostfix,
|
||||
AST_PrefixedTemplateString
|
||||
} from "../ast.js";
|
||||
|
||||
// return true if the node at the top of the stack (that means the
|
||||
// innermost node in the current output) is lexically the first in
|
||||
// a statement.
|
||||
function first_in_statement(stack) {
|
||||
let node = stack.parent(-1);
|
||||
for (let i = 0, p; p = stack.parent(i); i++) {
|
||||
if (p instanceof AST_Statement && p.body === node)
|
||||
return true;
|
||||
if ((p instanceof AST_Sequence && p.expressions[0] === node) ||
|
||||
(p.TYPE === "Call" && p.expression === node) ||
|
||||
(p instanceof AST_PrefixedTemplateString && p.prefix === node) ||
|
||||
(p instanceof AST_Dot && p.expression === node) ||
|
||||
(p instanceof AST_Sub && p.expression === node) ||
|
||||
(p instanceof AST_Conditional && p.condition === node) ||
|
||||
(p instanceof AST_Binary && p.left === node) ||
|
||||
(p instanceof AST_UnaryPostfix && p.expression === node)
|
||||
) {
|
||||
node = p;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns whether the leftmost item in the expression is an object
|
||||
function left_is_object(node) {
|
||||
if (node instanceof AST_Object) return true;
|
||||
if (node instanceof AST_Sequence) return left_is_object(node.expressions[0]);
|
||||
if (node.TYPE === "Call") return left_is_object(node.expression);
|
||||
if (node instanceof AST_PrefixedTemplateString) return left_is_object(node.prefix);
|
||||
if (node instanceof AST_Dot || node instanceof AST_Sub) return left_is_object(node.expression);
|
||||
if (node instanceof AST_Conditional) return left_is_object(node.condition);
|
||||
if (node instanceof AST_Binary) return left_is_object(node.left);
|
||||
if (node instanceof AST_UnaryPostfix) return left_is_object(node.expression);
|
||||
return false;
|
||||
}
|
||||
|
||||
export { first_in_statement, left_is_object };
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
"use strict";
|
||||
|
||||
function characters(str) {
|
||||
return str.split("");
|
||||
}
|
||||
|
||||
function member(name, array) {
|
||||
return array.includes(name);
|
||||
}
|
||||
|
||||
class DefaultsError extends Error {
|
||||
constructor(msg, defs) {
|
||||
super();
|
||||
|
||||
this.name = "DefaultsError";
|
||||
this.message = msg;
|
||||
this.defs = defs;
|
||||
}
|
||||
}
|
||||
|
||||
function defaults(args, defs, croak) {
|
||||
if (args === true) {
|
||||
args = {};
|
||||
} else if (args != null && typeof args === "object") {
|
||||
args = {...args};
|
||||
}
|
||||
|
||||
const ret = args || {};
|
||||
|
||||
if (croak) for (const i in ret) if (HOP(ret, i) && !HOP(defs, i)) {
|
||||
throw new DefaultsError("`" + i + "` is not a supported option", defs);
|
||||
}
|
||||
|
||||
for (const i in defs) if (HOP(defs, i)) {
|
||||
if (!args || !HOP(args, i)) {
|
||||
ret[i] = defs[i];
|
||||
} else if (i === "ecma") {
|
||||
let ecma = args[i] | 0;
|
||||
if (ecma > 5 && ecma < 2015) ecma += 2009;
|
||||
ret[i] = ecma;
|
||||
} else {
|
||||
ret[i] = (args && HOP(args, i)) ? args[i] : defs[i];
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
function return_false() { return false; }
|
||||
function return_true() { return true; }
|
||||
function return_this() { return this; }
|
||||
function return_null() { return null; }
|
||||
|
||||
var MAP = (function() {
|
||||
function MAP(a, f, backwards) {
|
||||
var ret = [], top = [], i;
|
||||
function doit() {
|
||||
var val = f(a[i], i);
|
||||
var is_last = val instanceof Last;
|
||||
if (is_last) val = val.v;
|
||||
if (val instanceof AtTop) {
|
||||
val = val.v;
|
||||
if (val instanceof Splice) {
|
||||
top.push.apply(top, backwards ? val.v.slice().reverse() : val.v);
|
||||
} else {
|
||||
top.push(val);
|
||||
}
|
||||
} else if (val !== skip) {
|
||||
if (val instanceof Splice) {
|
||||
ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v);
|
||||
} else {
|
||||
ret.push(val);
|
||||
}
|
||||
}
|
||||
return is_last;
|
||||
}
|
||||
if (Array.isArray(a)) {
|
||||
if (backwards) {
|
||||
for (i = a.length; --i >= 0;) if (doit()) break;
|
||||
ret.reverse();
|
||||
top.reverse();
|
||||
} else {
|
||||
for (i = 0; i < a.length; ++i) if (doit()) break;
|
||||
}
|
||||
} else {
|
||||
for (i in a) if (HOP(a, i)) if (doit()) break;
|
||||
}
|
||||
return top.concat(ret);
|
||||
}
|
||||
MAP.at_top = function(val) { return new AtTop(val); };
|
||||
MAP.splice = function(val) { return new Splice(val); };
|
||||
MAP.last = function(val) { return new Last(val); };
|
||||
var skip = MAP.skip = {};
|
||||
function AtTop(val) { this.v = val; }
|
||||
function Splice(val) { this.v = val; }
|
||||
function Last(val) { this.v = val; }
|
||||
return MAP;
|
||||
})();
|
||||
|
||||
function make_node(ctor, orig, props) {
|
||||
if (!props) props = {};
|
||||
if (orig) {
|
||||
if (!props.start) props.start = orig.start;
|
||||
if (!props.end) props.end = orig.end;
|
||||
}
|
||||
return new ctor(props);
|
||||
}
|
||||
|
||||
function push_uniq(array, el) {
|
||||
if (!array.includes(el))
|
||||
array.push(el);
|
||||
}
|
||||
|
||||
function string_template(text, props) {
|
||||
return text.replace(/{(.+?)}/g, function(str, p) {
|
||||
return props && props[p];
|
||||
});
|
||||
}
|
||||
|
||||
function remove(array, el) {
|
||||
for (var i = array.length; --i >= 0;) {
|
||||
if (array[i] === el) array.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
function mergeSort(array, cmp) {
|
||||
if (array.length < 2) return array.slice();
|
||||
function merge(a, b) {
|
||||
var r = [], ai = 0, bi = 0, i = 0;
|
||||
while (ai < a.length && bi < b.length) {
|
||||
cmp(a[ai], b[bi]) <= 0
|
||||
? r[i++] = a[ai++]
|
||||
: r[i++] = b[bi++];
|
||||
}
|
||||
if (ai < a.length) r.push.apply(r, a.slice(ai));
|
||||
if (bi < b.length) r.push.apply(r, b.slice(bi));
|
||||
return r;
|
||||
}
|
||||
function _ms(a) {
|
||||
if (a.length <= 1)
|
||||
return a;
|
||||
var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m);
|
||||
left = _ms(left);
|
||||
right = _ms(right);
|
||||
return merge(left, right);
|
||||
}
|
||||
return _ms(array);
|
||||
}
|
||||
|
||||
function makePredicate(words) {
|
||||
if (!Array.isArray(words)) words = words.split(" ");
|
||||
|
||||
return new Set(words.sort());
|
||||
}
|
||||
|
||||
function map_add(map, key, value) {
|
||||
if (map.has(key)) {
|
||||
map.get(key).push(value);
|
||||
} else {
|
||||
map.set(key, [ value ]);
|
||||
}
|
||||
}
|
||||
|
||||
function map_from_object(obj) {
|
||||
var map = new Map();
|
||||
for (var key in obj) {
|
||||
if (HOP(obj, key) && key.charAt(0) === "$") {
|
||||
map.set(key.substr(1), obj[key]);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
function map_to_object(map) {
|
||||
var obj = Object.create(null);
|
||||
map.forEach(function (value, key) {
|
||||
obj["$" + key] = value;
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
function HOP(obj, prop) {
|
||||
return Object.prototype.hasOwnProperty.call(obj, prop);
|
||||
}
|
||||
|
||||
function keep_name(keep_setting, name) {
|
||||
return keep_setting === true
|
||||
|| (keep_setting instanceof RegExp && keep_setting.test(name));
|
||||
}
|
||||
|
||||
var lineTerminatorEscape = {
|
||||
"\0": "0",
|
||||
"\n": "n",
|
||||
"\r": "r",
|
||||
"\u2028": "u2028",
|
||||
"\u2029": "u2029",
|
||||
};
|
||||
function regexp_source_fix(source) {
|
||||
// V8 does not escape line terminators in regexp patterns in node 12
|
||||
// We'll also remove literal \0
|
||||
return source.replace(/[\0\n\r\u2028\u2029]/g, function (match, offset) {
|
||||
var escaped = source[offset - 1] == "\\"
|
||||
&& (source[offset - 2] != "\\"
|
||||
|| /(?:^|[^\\])(?:\\{2})*$/.test(source.slice(0, offset - 1)));
|
||||
return (escaped ? "" : "\\") + lineTerminatorEscape[match];
|
||||
});
|
||||
}
|
||||
|
||||
// Subset of regexps that is not going to cause regexp based DDOS
|
||||
// https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
|
||||
const re_safe_regexp = /^[\\/|\0\s\w^$.[\]()]*$/;
|
||||
|
||||
/** Check if the regexp is safe for Terser to create without risking a RegExp DOS */
|
||||
export const regexp_is_safe = (source) => re_safe_regexp.test(source);
|
||||
|
||||
const all_flags = "dgimsuy";
|
||||
function sort_regexp_flags(flags) {
|
||||
const existing_flags = new Set(flags.split(""));
|
||||
let out = "";
|
||||
for (const flag of all_flags) {
|
||||
if (existing_flags.has(flag)) {
|
||||
out += flag;
|
||||
existing_flags.delete(flag);
|
||||
}
|
||||
}
|
||||
if (existing_flags.size) {
|
||||
// Flags Terser doesn't know about
|
||||
existing_flags.forEach(flag => { out += flag; });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function has_annotation(node, annotation) {
|
||||
return node._annotations & annotation;
|
||||
}
|
||||
|
||||
function set_annotation(node, annotation) {
|
||||
node._annotations |= annotation;
|
||||
}
|
||||
|
||||
export {
|
||||
characters,
|
||||
defaults,
|
||||
HOP,
|
||||
keep_name,
|
||||
make_node,
|
||||
makePredicate,
|
||||
map_add,
|
||||
map_from_object,
|
||||
map_to_object,
|
||||
MAP,
|
||||
member,
|
||||
mergeSort,
|
||||
noop,
|
||||
push_uniq,
|
||||
regexp_source_fix,
|
||||
remove,
|
||||
return_false,
|
||||
return_null,
|
||||
return_this,
|
||||
return_true,
|
||||
sort_regexp_flags,
|
||||
string_template,
|
||||
has_annotation,
|
||||
set_annotation
|
||||
};
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import "./lib/transform.js";
|
||||
import "./lib/mozilla-ast.js";
|
||||
import { minify } from "./lib/minify.js";
|
||||
|
||||
export { minify } from "./lib/minify.js";
|
||||
export { run_cli as _run_cli } from "./lib/cli.js";
|
||||
|
||||
export async function _default_options() {
|
||||
const defs = {};
|
||||
|
||||
Object.keys(infer_options({ 0: 0 })).forEach((component) => {
|
||||
const options = infer_options({
|
||||
[component]: {0: 0}
|
||||
});
|
||||
|
||||
if (options) defs[component] = options;
|
||||
});
|
||||
return defs;
|
||||
}
|
||||
|
||||
async function infer_options(options) {
|
||||
try {
|
||||
await minify("", options);
|
||||
} catch (error) {
|
||||
return error.defs;
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"terser@5.14.2",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "terser@5.14.2",
|
||||
"_id": "terser@5.14.2",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==",
|
||||
"_location": "/terser-webpack-plugin/terser",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "terser@5.14.2",
|
||||
"name": "terser",
|
||||
"escapedName": "terser",
|
||||
"rawSpec": "5.14.2",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "5.14.2"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/terser-webpack-plugin"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz",
|
||||
"_spec": "5.14.2",
|
||||
"_where": "/home/node/nuxt",
|
||||
"author": {
|
||||
"name": "Mihai Bazon",
|
||||
"email": "mihai.bazon@gmail.com",
|
||||
"url": "http://lisperator.net/"
|
||||
},
|
||||
"bin": {
|
||||
"terser": "bin/terser"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/terser/terser/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.2",
|
||||
"acorn": "^8.5.0",
|
||||
"commander": "^2.20.0",
|
||||
"source-map-support": "~0.5.20"
|
||||
},
|
||||
"description": "JavaScript parser, mangler/compressor and beautifier toolkit for ES6+",
|
||||
"devDependencies": {
|
||||
"@ls-lint/ls-lint": "^1.10.0",
|
||||
"astring": "^1.7.5",
|
||||
"eslint": "^7.32.0",
|
||||
"eslump": "^3.0.0",
|
||||
"esm": "^3.2.25",
|
||||
"mocha": "^9.2.0",
|
||||
"pre-commit": "^1.2.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "2.56.3",
|
||||
"semver": "^7.3.4",
|
||||
"source-map": "~0.8.0-beta.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 2020
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"es2020": true
|
||||
},
|
||||
"globals": {
|
||||
"describe": false,
|
||||
"it": false,
|
||||
"require": false,
|
||||
"before": false,
|
||||
"after": false,
|
||||
"global": false,
|
||||
"process": false
|
||||
},
|
||||
"rules": {
|
||||
"brace-style": [
|
||||
"error",
|
||||
"1tbs",
|
||||
{
|
||||
"allowSingleLine": true
|
||||
}
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"double",
|
||||
"avoid-escape"
|
||||
],
|
||||
"no-debugger": "error",
|
||||
"no-undef": "error",
|
||||
"no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"varsIgnorePattern": "^_"
|
||||
}
|
||||
],
|
||||
"no-tabs": "error",
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
"no-extra-semi": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"space-before-blocks": [
|
||||
"error",
|
||||
"always"
|
||||
]
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
".": [
|
||||
{
|
||||
"types": "./tools/terser.d.ts",
|
||||
"import": "./main.js",
|
||||
"require": "./dist/bundle.min.js"
|
||||
},
|
||||
"./dist/bundle.min.js"
|
||||
],
|
||||
"./package": "./package.json",
|
||||
"./package.json": "./package.json",
|
||||
"./bin/terser": "./bin/terser"
|
||||
},
|
||||
"files": [
|
||||
"bin",
|
||||
"dist",
|
||||
"lib",
|
||||
"tools",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
"CHANGELOG.md",
|
||||
"PATRONS.md",
|
||||
"main.js"
|
||||
],
|
||||
"homepage": "https://terser.org",
|
||||
"keywords": [
|
||||
"uglify",
|
||||
"terser",
|
||||
"uglify-es",
|
||||
"uglify-js",
|
||||
"minify",
|
||||
"minifier",
|
||||
"javascript",
|
||||
"ecmascript",
|
||||
"es5",
|
||||
"es6",
|
||||
"es7",
|
||||
"es8",
|
||||
"es2015",
|
||||
"es2016",
|
||||
"es2017",
|
||||
"async",
|
||||
"await"
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"main": "dist/bundle.min.js",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "Fábio Santos",
|
||||
"email": "fabiosantosart@gmail.com"
|
||||
}
|
||||
],
|
||||
"module": "./main.js",
|
||||
"name": "terser",
|
||||
"pre-commit": [
|
||||
"build",
|
||||
"lint-fix",
|
||||
"ls-lint",
|
||||
"test"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/terser/terser.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rimraf dist/bundle* && rollup --config --silent",
|
||||
"lint": "eslint lib",
|
||||
"lint-fix": "eslint --fix lib",
|
||||
"ls-lint": "ls-lint",
|
||||
"postversion": "echo 'Remember to update the changelog!'",
|
||||
"prepare": "npm run build",
|
||||
"test": "node test/compress.js && mocha test/mocha",
|
||||
"test:compress": "node test/compress.js",
|
||||
"test:mocha": "mocha test/mocha"
|
||||
},
|
||||
"type": "module",
|
||||
"types": "tools/terser.d.ts",
|
||||
"version": "5.14.2"
|
||||
}
|
||||
+7783
File diff suppressed because it is too large
Load Diff
+7
@@ -0,0 +1,7 @@
|
||||
// workaround for tty output truncation upon process.exit()
|
||||
// https://github.com/nodejs/node/issues/6456
|
||||
|
||||
[process.stdout, process.stderr].forEach((s) => {
|
||||
s && s.isTTY && s._handle && s._handle.setBlocking &&
|
||||
s._handle.setBlocking(true)
|
||||
});
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<script>(function(){
|
||||
var props = {};
|
||||
|
||||
function addObject(obj) {
|
||||
if (obj == null) return;
|
||||
try {
|
||||
Object.getOwnPropertyNames(obj).forEach(add);
|
||||
} catch(ex) {}
|
||||
if (obj.prototype) {
|
||||
Object.getOwnPropertyNames(obj.prototype).forEach(add);
|
||||
}
|
||||
if (typeof obj == "function") {
|
||||
try {
|
||||
Object.getOwnPropertyNames(new obj).forEach(add);
|
||||
} catch(ex) {}
|
||||
}
|
||||
}
|
||||
|
||||
function add(name) {
|
||||
props[name] = true;
|
||||
}
|
||||
|
||||
Object.getOwnPropertyNames(window).forEach(function(thing){
|
||||
addObject(window[thing]);
|
||||
});
|
||||
|
||||
try {
|
||||
addObject(new Event("click"));
|
||||
addObject(new Event("contextmenu"));
|
||||
addObject(new Event("mouseup"));
|
||||
addObject(new Event("mousedown"));
|
||||
addObject(new Event("keydown"));
|
||||
addObject(new Event("keypress"));
|
||||
addObject(new Event("keyup"));
|
||||
} catch(ex) {}
|
||||
|
||||
var ta = document.createElement("textarea");
|
||||
ta.style.width = "100%";
|
||||
ta.style.height = "20em";
|
||||
ta.style.boxSizing = "border-box";
|
||||
ta.value = 'export var domprops = ' + JSON.stringify(Object.keys(props).sort(cmp), null, 4);
|
||||
document.body.appendChild(ta);
|
||||
|
||||
function cmp(a, b) {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
}
|
||||
})();</script>
|
||||
</body>
|
||||
</html>
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
/// <reference lib="es2015" />
|
||||
|
||||
import { SectionedSourceMapInput, EncodedSourceMap, DecodedSourceMap } from '@jridgewell/source-map';
|
||||
|
||||
export type ECMA = 5 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020;
|
||||
|
||||
export interface ParseOptions {
|
||||
bare_returns?: boolean;
|
||||
/** @deprecated legacy option. Currently, all supported EcmaScript is valid to parse. */
|
||||
ecma?: ECMA;
|
||||
html5_comments?: boolean;
|
||||
shebang?: boolean;
|
||||
}
|
||||
|
||||
export interface CompressOptions {
|
||||
arguments?: boolean;
|
||||
arrows?: boolean;
|
||||
booleans_as_integers?: boolean;
|
||||
booleans?: boolean;
|
||||
collapse_vars?: boolean;
|
||||
comparisons?: boolean;
|
||||
computed_props?: boolean;
|
||||
conditionals?: boolean;
|
||||
dead_code?: boolean;
|
||||
defaults?: boolean;
|
||||
directives?: boolean;
|
||||
drop_console?: boolean;
|
||||
drop_debugger?: boolean;
|
||||
ecma?: ECMA;
|
||||
evaluate?: boolean;
|
||||
expression?: boolean;
|
||||
global_defs?: object;
|
||||
hoist_funs?: boolean;
|
||||
hoist_props?: boolean;
|
||||
hoist_vars?: boolean;
|
||||
ie8?: boolean;
|
||||
if_return?: boolean;
|
||||
inline?: boolean | InlineFunctions;
|
||||
join_vars?: boolean;
|
||||
keep_classnames?: boolean | RegExp;
|
||||
keep_fargs?: boolean;
|
||||
keep_fnames?: boolean | RegExp;
|
||||
keep_infinity?: boolean;
|
||||
loops?: boolean;
|
||||
module?: boolean;
|
||||
negate_iife?: boolean;
|
||||
passes?: number;
|
||||
properties?: boolean;
|
||||
pure_funcs?: string[];
|
||||
pure_getters?: boolean | 'strict';
|
||||
reduce_funcs?: boolean;
|
||||
reduce_vars?: boolean;
|
||||
sequences?: boolean | number;
|
||||
side_effects?: boolean;
|
||||
switches?: boolean;
|
||||
toplevel?: boolean;
|
||||
top_retain?: null | string | string[] | RegExp;
|
||||
typeofs?: boolean;
|
||||
unsafe_arrows?: boolean;
|
||||
unsafe?: boolean;
|
||||
unsafe_comps?: boolean;
|
||||
unsafe_Function?: boolean;
|
||||
unsafe_math?: boolean;
|
||||
unsafe_symbols?: boolean;
|
||||
unsafe_methods?: boolean;
|
||||
unsafe_proto?: boolean;
|
||||
unsafe_regexp?: boolean;
|
||||
unsafe_undefined?: boolean;
|
||||
unused?: boolean;
|
||||
}
|
||||
|
||||
export enum InlineFunctions {
|
||||
Disabled = 0,
|
||||
SimpleFunctions = 1,
|
||||
WithArguments = 2,
|
||||
WithArgumentsAndVariables = 3
|
||||
}
|
||||
|
||||
export interface MangleOptions {
|
||||
eval?: boolean;
|
||||
keep_classnames?: boolean | RegExp;
|
||||
keep_fnames?: boolean | RegExp;
|
||||
module?: boolean;
|
||||
nth_identifier?: SimpleIdentifierMangler | WeightedIdentifierMangler;
|
||||
properties?: boolean | ManglePropertiesOptions;
|
||||
reserved?: string[];
|
||||
safari10?: boolean;
|
||||
toplevel?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* An identifier mangler for which the output is invariant with respect to the source code.
|
||||
*/
|
||||
export interface SimpleIdentifierMangler {
|
||||
/**
|
||||
* Obtains the nth most favored (usually shortest) identifier to rename a variable to.
|
||||
* The mangler will increment n and retry until the return value is not in use in scope, and is not a reserved word.
|
||||
* This function is expected to be stable; Evaluating get(n) === get(n) should always return true.
|
||||
* @param n The ordinal of the identifier.
|
||||
*/
|
||||
get(n: number): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An identifier mangler that leverages character frequency analysis to determine identifier precedence.
|
||||
*/
|
||||
export interface WeightedIdentifierMangler extends SimpleIdentifierMangler {
|
||||
/**
|
||||
* Modifies the internal weighting of the input characters by the specified delta.
|
||||
* Will be invoked on the entire printed AST, and then deduct mangleable identifiers.
|
||||
* @param chars The characters to modify the weighting of.
|
||||
* @param delta The numeric weight to add to the characters.
|
||||
*/
|
||||
consider(chars: string, delta: number): number;
|
||||
/**
|
||||
* Resets character weights.
|
||||
*/
|
||||
reset(): void;
|
||||
/**
|
||||
* Sorts identifiers by character frequency, in preparation for calls to get(n).
|
||||
*/
|
||||
sort(): void;
|
||||
}
|
||||
|
||||
export interface ManglePropertiesOptions {
|
||||
builtins?: boolean;
|
||||
debug?: boolean;
|
||||
keep_quoted?: boolean | 'strict';
|
||||
nth_identifier?: SimpleIdentifierMangler | WeightedIdentifierMangler;
|
||||
regex?: RegExp | string;
|
||||
reserved?: string[];
|
||||
}
|
||||
|
||||
export interface FormatOptions {
|
||||
ascii_only?: boolean;
|
||||
/** @deprecated Not implemented anymore */
|
||||
beautify?: boolean;
|
||||
braces?: boolean;
|
||||
comments?: boolean | 'all' | 'some' | RegExp | ( (node: any, comment: {
|
||||
value: string,
|
||||
type: 'comment1' | 'comment2' | 'comment3' | 'comment4',
|
||||
pos: number,
|
||||
line: number,
|
||||
col: number,
|
||||
}) => boolean );
|
||||
ecma?: ECMA;
|
||||
ie8?: boolean;
|
||||
keep_numbers?: boolean;
|
||||
indent_level?: number;
|
||||
indent_start?: number;
|
||||
inline_script?: boolean;
|
||||
keep_quoted_props?: boolean;
|
||||
max_line_len?: number | false;
|
||||
preamble?: string;
|
||||
preserve_annotations?: boolean;
|
||||
quote_keys?: boolean;
|
||||
quote_style?: OutputQuoteStyle;
|
||||
safari10?: boolean;
|
||||
semicolons?: boolean;
|
||||
shebang?: boolean;
|
||||
shorthand?: boolean;
|
||||
source_map?: SourceMapOptions;
|
||||
webkit?: boolean;
|
||||
width?: number;
|
||||
wrap_iife?: boolean;
|
||||
wrap_func_args?: boolean;
|
||||
}
|
||||
|
||||
export enum OutputQuoteStyle {
|
||||
PreferDouble = 0,
|
||||
AlwaysSingle = 1,
|
||||
AlwaysDouble = 2,
|
||||
AlwaysOriginal = 3
|
||||
}
|
||||
|
||||
export interface MinifyOptions {
|
||||
compress?: boolean | CompressOptions;
|
||||
ecma?: ECMA;
|
||||
enclose?: boolean | string;
|
||||
ie8?: boolean;
|
||||
keep_classnames?: boolean | RegExp;
|
||||
keep_fnames?: boolean | RegExp;
|
||||
mangle?: boolean | MangleOptions;
|
||||
module?: boolean;
|
||||
nameCache?: object;
|
||||
format?: FormatOptions;
|
||||
/** @deprecated */
|
||||
output?: FormatOptions;
|
||||
parse?: ParseOptions;
|
||||
safari10?: boolean;
|
||||
sourceMap?: boolean | SourceMapOptions;
|
||||
toplevel?: boolean;
|
||||
}
|
||||
|
||||
export interface MinifyOutput {
|
||||
code?: string;
|
||||
map?: EncodedSourceMap | string;
|
||||
decoded_map?: DecodedSourceMap | null;
|
||||
}
|
||||
|
||||
export interface SourceMapOptions {
|
||||
/** Source map object, 'inline' or source map file content */
|
||||
content?: SectionedSourceMapInput | string;
|
||||
includeSources?: boolean;
|
||||
filename?: string;
|
||||
root?: string;
|
||||
url?: string | 'inline';
|
||||
}
|
||||
|
||||
export function minify(files: string | string[] | { [file: string]: string }, options?: MinifyOptions): Promise<MinifyOutput>;
|
||||
+52
-43
@@ -1,36 +1,42 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"terser-webpack-plugin@2.3.7",
|
||||
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
|
||||
"terser-webpack-plugin@4.2.3",
|
||||
"/home/node/nuxt"
|
||||
]
|
||||
],
|
||||
"_from": "terser-webpack-plugin@2.3.7",
|
||||
"_id": "terser-webpack-plugin@2.3.7",
|
||||
"_from": "terser-webpack-plugin@4.2.3",
|
||||
"_id": "terser-webpack-plugin@4.2.3",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-xzYyaHUNhzgaAdBsXxk2Yvo/x1NJdslUaussK3fdpBbvttm1iIwU+c26dj9UxJcwk2c5UWt5F55MUTIA8BE7Dg==",
|
||||
"_integrity": "sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==",
|
||||
"_location": "/terser-webpack-plugin",
|
||||
"_phantomChildren": {
|
||||
"@jridgewell/source-map": "0.3.2",
|
||||
"@types/json-schema": "7.0.11",
|
||||
"ajv": "6.12.6",
|
||||
"ajv-keywords": "3.5.2",
|
||||
"commander": "2.20.3",
|
||||
"commondir": "1.0.1",
|
||||
"p-limit": "2.3.0",
|
||||
"randombytes": "2.1.0"
|
||||
"p-try": "2.2.0",
|
||||
"source-map-support": "0.5.21",
|
||||
"yocto-queue": "0.1.0"
|
||||
},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "terser-webpack-plugin@2.3.7",
|
||||
"raw": "terser-webpack-plugin@4.2.3",
|
||||
"name": "terser-webpack-plugin",
|
||||
"escapedName": "terser-webpack-plugin",
|
||||
"rawSpec": "2.3.7",
|
||||
"rawSpec": "4.2.3",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "2.3.7"
|
||||
"fetchSpec": "4.2.3"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/@nuxt/webpack"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.7.tgz",
|
||||
"_spec": "2.3.7",
|
||||
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
|
||||
"_resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz",
|
||||
"_spec": "4.2.3",
|
||||
"_where": "/home/node/nuxt",
|
||||
"author": {
|
||||
"name": "webpack Contrib Team"
|
||||
},
|
||||
@@ -38,44 +44,47 @@
|
||||
"url": "https://github.com/webpack-contrib/terser-webpack-plugin/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"cacache": "^13.0.1",
|
||||
"cacache": "^15.0.5",
|
||||
"find-cache-dir": "^3.3.1",
|
||||
"jest-worker": "^25.4.0",
|
||||
"p-limit": "^2.3.0",
|
||||
"schema-utils": "^2.6.6",
|
||||
"serialize-javascript": "^3.1.0",
|
||||
"jest-worker": "^26.5.0",
|
||||
"p-limit": "^3.0.2",
|
||||
"schema-utils": "^3.0.0",
|
||||
"serialize-javascript": "^5.0.1",
|
||||
"source-map": "^0.6.1",
|
||||
"terser": "^4.6.12",
|
||||
"terser": "^5.3.4",
|
||||
"webpack-sources": "^1.4.3"
|
||||
},
|
||||
"description": "Terser plugin for webpack",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.8.4",
|
||||
"@babel/core": "^7.9.0",
|
||||
"@babel/preset-env": "^7.9.5",
|
||||
"@commitlint/cli": "^8.3.5",
|
||||
"@commitlint/config-conventional": "^8.3.4",
|
||||
"@webpack-contrib/defaults": "^6.2.0",
|
||||
"@babel/cli": "^7.11.6",
|
||||
"@babel/core": "^7.11.6",
|
||||
"@babel/preset-env": "^7.11.5",
|
||||
"@commitlint/cli": "^11.0.0",
|
||||
"@commitlint/config-conventional": "^11.0.0",
|
||||
"@webpack-contrib/defaults": "^6.3.0",
|
||||
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
|
||||
"babel-jest": "^25.4.0",
|
||||
"cross-env": "^6.0.3",
|
||||
"del": "^5.1.0",
|
||||
"del-cli": "^3.0.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"husky": "^4.2.5",
|
||||
"jest": "^25.4.0",
|
||||
"lint-staged": "^10.1.7",
|
||||
"memfs": "^3.1.2",
|
||||
"babel-jest": "^26.5.2",
|
||||
"copy-webpack-plugin": "^6.2.0",
|
||||
"cross-env": "^7.0.2",
|
||||
"del": "^6.0.0",
|
||||
"del-cli": "^3.0.1",
|
||||
"eslint": "^7.10.0",
|
||||
"eslint-config-prettier": "^6.12.0",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"file-loader": "^6.1.0",
|
||||
"husky": "^4.3.0",
|
||||
"jest": "^26.5.2",
|
||||
"lint-staged": "^10.4.0",
|
||||
"memfs": "^3.2.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prettier": "^1.19.1",
|
||||
"standard-version": "^7.1.0",
|
||||
"uglify-js": "^3.9.1",
|
||||
"webpack": "^4.43.0"
|
||||
"prettier": "^2.1.2",
|
||||
"standard-version": "^9.0.0",
|
||||
"uglify-js": "^3.11.1",
|
||||
"webpack": "^4.44.2",
|
||||
"worker-loader": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.9.0"
|
||||
"node": ">= 10.13.0"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
@@ -119,7 +128,7 @@
|
||||
"defaults": "webpack-defaults",
|
||||
"lint": "npm-run-all -l -p \"lint:**\"",
|
||||
"lint:js": "eslint --cache .",
|
||||
"lint:prettier": "prettier \"{**/*,*}.{js,json,md,yml,css,ts}\" --list-different",
|
||||
"lint:prettier": "prettier --list-different .",
|
||||
"prebuild": "npm run clean",
|
||||
"prepare": "npm run build",
|
||||
"pretest": "npm run lint",
|
||||
@@ -131,5 +140,5 @@
|
||||
"test:only": "cross-env NODE_ENV=test jest",
|
||||
"test:watch": "npm run test:only -- --watch"
|
||||
},
|
||||
"version": "2.3.7"
|
||||
"version": "4.2.3"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user