$
This commit is contained in:
22
node_modules/html-minifier-terser/LICENSE
generated
vendored
Normal file
22
node_modules/html-minifier-terser/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2010-2019 Juriy "kangax" Zaytsev
|
||||
|
||||
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.
|
166
node_modules/html-minifier-terser/README.md
generated
vendored
Normal file
166
node_modules/html-minifier-terser/README.md
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
# HTMLMinifier
|
||||
|
||||
[](https://www.npmjs.com/package/html-minifier-terser)
|
||||
[](https://github.com/terser/html-minifier-terser/actions?workflow=CI)
|
||||
|
||||
[HTMLMinifier](https://terser.org/html-minifier-terser/) is a highly **configurable**, **well-tested**, JavaScript-based HTML minifier.
|
||||
|
||||
See [corresponding blog post](http://perfectionkills.com/experimenting-with-html-minifier/) for all the gory details of [how it works](http://perfectionkills.com/experimenting-with-html-minifier/#how_it_works), [description of each option](http://perfectionkills.com/experimenting-with-html-minifier/#options), [testing results](http://perfectionkills.com/experimenting-with-html-minifier/#field_testing) and [conclusions](http://perfectionkills.com/experimenting-with-html-minifier/#cost_and_benefits).
|
||||
|
||||
[Test suite is available online](https://terser.org/html-minifier-terser/tests/).
|
||||
|
||||
Also see corresponding [Ruby wrapper](https://github.com/stereobooster/html_minifier), and for Node.js, [Grunt plugin](https://github.com/gruntjs/grunt-contrib-htmlmin), [Gulp module](https://github.com/jonschlinkert/gulp-htmlmin), [Koa middleware wrapper](https://github.com/koajs/html-minifier) and [Express middleware wrapper](https://github.com/melonmanchan/express-minify-html).
|
||||
|
||||
For lint-like capabilities take a look at [HTMLLint](https://github.com/kangax/html-lint).
|
||||
|
||||
## Minification comparison
|
||||
|
||||
How does HTMLMinifier compare to other solutions — [HTML Minifier from Will Peavy](http://www.willpeavy.com/minifier/) (1st result in [Google search for "html minifier"](https://www.google.com/#q=html+minifier)) as well as [htmlcompressor.com](http://htmlcompressor.com) and [minimize](https://github.com/Swaagie/minimize)?
|
||||
|
||||
| Site | Original size *(KB)* | HTMLMinifier | minimize | Will Peavy | htmlcompressor.com |
|
||||
| ---------------------------------------------------------------------------- |:--------------------:| ------------:| --------:| ----------:| ------------------:|
|
||||
| [Google](https://www.google.com/) | 45 | **41** | 45 | 46 | 45 |
|
||||
| [Stack Overflow](https://stackoverflow.com/) | 115 | **82** | 90 | 92 | 88 |
|
||||
| [HTMLMinifier](https://github.com/kangax/html-minifier) | 132 | **105** | 118 | 123 | 118 |
|
||||
| [Bootstrap CSS](https://getbootstrap.com/docs/3.3/css/) | 271 | **260** | 269 | 229 | 269 |
|
||||
| [Twitter](https://twitter.com/) | 289 | **238** | 282 | 314 | 282 |
|
||||
| [BBC](https://www.bbc.co.uk/) | 298 | **233** | 289 | 291 | 269 |
|
||||
| [Wikipedia](https://en.wikipedia.org/wiki/President_of_the_United_States) | 574 | **468** | 557 | 578 | 557 |
|
||||
| [Amazon](https://www.amazon.co.uk/) | 702 | **343** | 692 | 704 | n/a |
|
||||
| [NBC](https://www.nbc.com/) | 844 | **805** | 843 | 844 | n/a |
|
||||
| [Eloquent Javascript](https://eloquentjavascript.net/1st_edition/print.html) | 870 | **815** | 840 | 864 | n/a |
|
||||
| [New York Times](https://www.nytimes.com/) | 1304 | **1183** | 1301 | 1295 | n/a |
|
||||
| [ES draft](https://tc39.github.io/ecma262/) | 6347 | **5686** | 5863 | n/a | n/a |
|
||||
|
||||
## Options Quick Reference
|
||||
|
||||
Most of the options are disabled by default.
|
||||
|
||||
| Option | Description | Default |
|
||||
|--------------------------------|-----------------|---------|
|
||||
| `caseSensitive` | Treat attributes in case sensitive manner (useful for custom HTML tags) | `false` |
|
||||
| `collapseBooleanAttributes` | [Omit attribute values from boolean attributes](http://perfectionkills.com/experimenting-with-html-minifier/#collapse_boolean_attributes) | `false` |
|
||||
| `collapseInlineTagWhitespace` | Don't leave any spaces between `display:inline;` elements when collapsing. Must be used in conjunction with `collapseWhitespace=true` | `false` |
|
||||
| `collapseWhitespace` | [Collapse white space that contributes to text nodes in a document tree](http://perfectionkills.com/experimenting-with-html-minifier/#collapse_whitespace) | `false` |
|
||||
| `conservativeCollapse` | Always collapse to 1 space (never remove it entirely). Must be used in conjunction with `collapseWhitespace=true` | `false` |
|
||||
| `continueOnParseError` | [Handle parse errors](https://html.spec.whatwg.org/multipage/parsing.html#parse-errors) instead of aborting. | `false` |
|
||||
| `customAttrAssign` | Arrays of regex'es that allow to support custom attribute assign expressions (e.g. `'<div flex?="{{mode != cover}}"></div>'`) | `[ ]` |
|
||||
| `customAttrCollapse` | Regex that specifies custom attribute to strip newlines from (e.g. `/ng-class/`) | |
|
||||
| `customAttrSurround` | Arrays of regex'es that allow to support custom attribute surround expressions (e.g. `<input {{#if value}}checked="checked"{{/if}}>`) | `[ ]` |
|
||||
| `customEventAttributes` | Arrays of regex'es that allow to support custom event attributes for `minifyJS` (e.g. `ng-click`) | `[ /^on[a-z]{3,}$/ ]` |
|
||||
| `decodeEntities` | Use direct Unicode characters whenever possible | `false` |
|
||||
| `html5` | Parse input according to HTML5 specifications | `true` |
|
||||
| `ignoreCustomComments` | Array of regex'es that allow to ignore certain comments, when matched | `[ /^!/, /^\s*#/ ]` |
|
||||
| `ignoreCustomFragments` | Array of regex'es that allow to ignore certain fragments, when matched (e.g. `<?php ... ?>`, `{{ ... }}`, etc.) | `[ /<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/ ]` |
|
||||
| `includeAutoGeneratedTags` | Insert tags generated by HTML parser | `true` |
|
||||
| `keepClosingSlash` | Keep the trailing slash on singleton elements | `false` |
|
||||
| `maxLineLength` | Specify a maximum line length. Compressed output will be split by newlines at valid HTML split-points |
|
||||
| `minifyCSS` | Minify CSS in style elements and style attributes (uses [clean-css](https://github.com/jakubpawlowicz/clean-css)) | `false` (could be `true`, `Object`, `Function(text, type)`) |
|
||||
| `minifyJS` | Minify JavaScript in script elements and event attributes (uses [Terser](https://github.com/terser/terser)) | `false` (could be `true`, `Object`, `Function(text, inline)`) |
|
||||
| `minifyURLs` | Minify URLs in various attributes (uses [relateurl](https://github.com/stevenvachon/relateurl)) | `false` (could be `String`, `Object`, `Function(text)`) |
|
||||
| `noNewlinesBeforeTagClose` | Never add a newline before a tag that closes an element | `false` |
|
||||
| `preserveLineBreaks` | Always collapse to 1 line break (never remove it entirely) when whitespace between tags include a line break. Must be used in conjunction with `collapseWhitespace=true` | `false` |
|
||||
| `preventAttributesEscaping` | Prevents the escaping of the values of attributes | `false` |
|
||||
| `processConditionalComments` | Process contents of conditional comments through minifier | `false` |
|
||||
| `processScripts` | Array of strings corresponding to types of script elements to process through minifier (e.g. `text/ng-template`, `text/x-handlebars-template`, etc.) | `[ ]` |
|
||||
| `quoteCharacter` | Type of quote to use for attribute values (' or ") | |
|
||||
| `removeAttributeQuotes` | [Remove quotes around attributes when possible](http://perfectionkills.com/experimenting-with-html-minifier/#remove_attribute_quotes) | `false` |
|
||||
| `removeComments` | [Strip HTML comments](http://perfectionkills.com/experimenting-with-html-minifier/#remove_comments) | `false` |
|
||||
| `removeEmptyAttributes` | [Remove all attributes with whitespace-only values](http://perfectionkills.com/experimenting-with-html-minifier/#remove_empty_or_blank_attributes) | `false` (could be `true`, `Function(attrName, tag)`) |
|
||||
| `removeEmptyElements` | [Remove all elements with empty contents](http://perfectionkills.com/experimenting-with-html-minifier/#remove_empty_elements) | `false` |
|
||||
| `removeOptionalTags` | [Remove optional tags](http://perfectionkills.com/experimenting-with-html-minifier/#remove_optional_tags) | `false` |
|
||||
| `removeRedundantAttributes` | [Remove attributes when value matches default.](http://perfectionkills.com/experimenting-with-html-minifier/#remove_redundant_attributes) | `false` |
|
||||
| `removeScriptTypeAttributes` | Remove `type="text/javascript"` from `script` tags. Other `type` attribute values are left intact | `false` |
|
||||
| `removeStyleLinkTypeAttributes`| Remove `type="text/css"` from `style` and `link` tags. Other `type` attribute values are left intact | `false` |
|
||||
| `removeTagWhitespace` | Remove space between attributes whenever possible. **Note that this will result in invalid HTML!** | `false` |
|
||||
| `sortAttributes` | [Sort attributes by frequency](#sorting-attributes--style-classes) | `false` |
|
||||
| `sortClassName` | [Sort style classes by frequency](#sorting-attributes--style-classes) | `false` |
|
||||
| `trimCustomFragments` | Trim white space around `ignoreCustomFragments`. | `false` |
|
||||
| `useShortDoctype` | [Replaces the `doctype` with the short (HTML5) doctype](http://perfectionkills.com/experimenting-with-html-minifier/#use_short_doctype) | `false` |
|
||||
|
||||
### Sorting attributes / style classes
|
||||
|
||||
Minifier options like `sortAttributes` and `sortClassName` won't impact the plain-text size of the output. However, they form long repetitive chains of characters that should improve compression ratio of gzip used in HTTP compression.
|
||||
|
||||
## Special cases
|
||||
|
||||
### Ignoring chunks of markup
|
||||
|
||||
If you have chunks of markup you would like preserved, you can wrap them `<!-- htmlmin:ignore -->`.
|
||||
|
||||
### Preserving SVG tags
|
||||
|
||||
SVG tags are automatically recognized, and when they are minified, both case-sensitivity and closing-slashes are preserved, regardless of the minification settings used for the rest of the file.
|
||||
|
||||
### Working with invalid markup
|
||||
|
||||
HTMLMinifier **can't work with invalid or partial chunks of markup**. This is because it parses markup into a tree structure, then modifies it (removing anything that was specified for removal, ignoring anything that was specified to be ignored, etc.), then it creates a markup out of that tree and returns it.
|
||||
|
||||
Input markup (e.g. `<p id="">foo`)
|
||||
|
||||
↓
|
||||
|
||||
Internal representation of markup in a form of tree (e.g. `{ tag: "p", attr: "id", children: ["foo"] }`)
|
||||
|
||||
↓
|
||||
|
||||
Transformation of internal representation (e.g. removal of `id` attribute)
|
||||
|
||||
↓
|
||||
|
||||
Output of resulting markup (e.g. `<p>foo</p>`)
|
||||
|
||||
HTMLMinifier can't know that original markup was only half of the tree; it does its best to try to parse it as a full tree and it loses information about tree being malformed or partial in the beginning. As a result, it can't create a partial/malformed tree at the time of the output.
|
||||
|
||||
## Installation Instructions
|
||||
|
||||
From NPM for use as a command line app:
|
||||
|
||||
```shell
|
||||
npm install html-minifier-terser -g
|
||||
```
|
||||
|
||||
From NPM for programmatic use:
|
||||
|
||||
```shell
|
||||
npm install html-minifier-terser
|
||||
```
|
||||
|
||||
From Git:
|
||||
|
||||
```shell
|
||||
git clone git://github.com/terser/html-minifier-terser.git
|
||||
cd html-minifier-terser
|
||||
npm link .
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Note that almost all options are disabled by default. For command line usage please see `html-minifier-terser --help` for a list of available options. Experiment and find what works best for you and your project.
|
||||
|
||||
- **Sample command line:** `html-minifier-terser --collapse-whitespace --remove-comments --remove-optional-tags --remove-redundant-attributes --remove-script-type-attributes --remove-tag-whitespace --use-short-doctype --minify-css true --minify-js true`
|
||||
|
||||
### Node.js
|
||||
|
||||
```js
|
||||
const { minify } = require('html-minifier-terser');
|
||||
|
||||
const result = await minify('<p title="blah" id="moo">foo</p>', {
|
||||
removeAttributeQuotes: true
|
||||
});
|
||||
result; // '<p title=blah id=moo>foo</p>'
|
||||
```
|
||||
|
||||
## Running benchmarks
|
||||
|
||||
Benchmarks for minified HTML:
|
||||
|
||||
```shell
|
||||
node benchmark.js
|
||||
```
|
||||
|
||||
## Running local server
|
||||
|
||||
```shell
|
||||
npm run serve
|
||||
```
|
315
node_modules/html-minifier-terser/cli.js
generated
vendored
Normal file
315
node_modules/html-minifier-terser/cli.js
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* html-minifier-terser CLI tool
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2016 Zoltan Frombach
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var camelCase = require('camel-case').camelCase;
|
||||
var fs = require('fs');
|
||||
var info = require('./package.json');
|
||||
var minify = require('./' + info.main).minify;
|
||||
var paramCase = require('param-case').paramCase;
|
||||
var path = require('path');
|
||||
var { Command } = require('commander');
|
||||
|
||||
const program = new Command();
|
||||
program.name(info.name);
|
||||
program.version(info.version);
|
||||
|
||||
function fatal(message) {
|
||||
console.error(message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSON does not support regexes, so, e.g., JSON.parse() will not create
|
||||
* a RegExp from the JSON value `[ "/matchString/" ]`, which is
|
||||
* technically just an array containing a string that begins and end with
|
||||
* a forward slash. To get a RegExp from a JSON string, it must be
|
||||
* constructed explicitly in JavaScript.
|
||||
*
|
||||
* The likelihood of actually wanting to match text that is enclosed in
|
||||
* forward slashes is probably quite rare, so if forward slashes were
|
||||
* included in an argument that requires a regex, the user most likely
|
||||
* thought they were part of the syntax for specifying a regex.
|
||||
*
|
||||
* In the unlikely case that forward slashes are indeed desired in the
|
||||
* search string, the user would need to enclose the expression in a
|
||||
* second set of slashes:
|
||||
*
|
||||
* --customAttrSrround "[\"//matchString//\"]"
|
||||
*/
|
||||
function parseRegExp(value) {
|
||||
if (value) {
|
||||
return new RegExp(value.replace(/^\/(.*)\/$/, '$1'));
|
||||
}
|
||||
}
|
||||
|
||||
function parseJSON(value) {
|
||||
if (value) {
|
||||
try {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
catch (e) {
|
||||
if (/^{/.test(value)) {
|
||||
fatal('Could not parse JSON value \'' + value + '\'');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseJSONArray(value) {
|
||||
if (value) {
|
||||
value = parseJSON(value);
|
||||
return Array.isArray(value) ? value : [value];
|
||||
}
|
||||
}
|
||||
|
||||
function parseJSONRegExpArray(value) {
|
||||
value = parseJSONArray(value);
|
||||
return value && value.map(parseRegExp);
|
||||
}
|
||||
|
||||
function parseString(value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
var mainOptions = {
|
||||
caseSensitive: 'Treat attributes in case sensitive manner (useful for SVG; e.g. viewBox)',
|
||||
collapseBooleanAttributes: 'Omit attribute values from boolean attributes',
|
||||
collapseInlineTagWhitespace: 'Collapse white space around inline tag',
|
||||
collapseWhitespace: 'Collapse white space that contributes to text nodes in a document tree.',
|
||||
conservativeCollapse: 'Always collapse to 1 space (never remove it entirely)',
|
||||
continueOnParseError: 'Handle parse errors instead of aborting',
|
||||
customAttrAssign: ['Arrays of regex\'es that allow to support custom attribute assign expressions (e.g. \'<div flex?="{{mode != cover}}"></div>\')', parseJSONRegExpArray],
|
||||
customAttrCollapse: ['Regex that specifies custom attribute to strip newlines from (e.g. /ng-class/)', parseRegExp],
|
||||
customAttrSurround: ['Arrays of regex\'es that allow to support custom attribute surround expressions (e.g. <input {{#if value}}checked="checked"{{/if}}>)', parseJSONRegExpArray],
|
||||
customEventAttributes: ['Arrays of regex\'es that allow to support custom event attributes for minifyJS (e.g. ng-click)', parseJSONRegExpArray],
|
||||
decodeEntities: 'Use direct Unicode characters whenever possible',
|
||||
html5: 'Parse input according to HTML5 specifications',
|
||||
ignoreCustomComments: ['Array of regex\'es that allow to ignore certain comments, when matched', parseJSONRegExpArray],
|
||||
ignoreCustomFragments: ['Array of regex\'es that allow to ignore certain fragments, when matched (e.g. <?php ... ?>, {{ ... }})', parseJSONRegExpArray],
|
||||
includeAutoGeneratedTags: 'Insert tags generated by HTML parser',
|
||||
keepClosingSlash: 'Keep the trailing slash on singleton elements',
|
||||
maxLineLength: ['Max line length', parseInt],
|
||||
minifyCSS: ['Minify CSS in style elements and style attributes (uses clean-css)', parseJSON],
|
||||
minifyJS: ['Minify Javascript in script elements and on* attributes (uses terser)', parseJSON],
|
||||
minifyURLs: ['Minify URLs in various attributes (uses relateurl)', parseJSON],
|
||||
noNewlinesBeforeTagClose: 'Never add a newline before a tag that closes an element',
|
||||
preserveLineBreaks: 'Always collapse to 1 line break (never remove it entirely) when whitespace between tags include a line break.',
|
||||
preventAttributesEscaping: 'Prevents the escaping of the values of attributes.',
|
||||
processConditionalComments: 'Process contents of conditional comments through minifier',
|
||||
processScripts: ['Array of strings corresponding to types of script elements to process through minifier (e.g. "text/ng-template", "text/x-handlebars-template", etc.)', parseJSONArray],
|
||||
quoteCharacter: ['Type of quote to use for attribute values (\' or ")', parseString],
|
||||
removeAttributeQuotes: 'Remove quotes around attributes when possible.',
|
||||
removeComments: 'Strip HTML comments',
|
||||
removeEmptyAttributes: 'Remove all attributes with whitespace-only values',
|
||||
removeEmptyElements: 'Remove all elements with empty contents',
|
||||
removeOptionalTags: 'Remove unrequired tags',
|
||||
removeRedundantAttributes: 'Remove attributes when value matches default.',
|
||||
removeScriptTypeAttributes: 'Removes the following attributes from script tags: text/javascript, text/ecmascript, text/jscript, application/javascript, application/x-javascript, application/ecmascript. Other type attribute values are left intact',
|
||||
removeStyleLinkTypeAttributes: 'Remove type="text/css" from style and link tags. Other type attribute values are left intact.',
|
||||
removeTagWhitespace: 'Remove space between attributes whenever possible',
|
||||
sortAttributes: 'Sort attributes by frequency',
|
||||
sortClassName: 'Sort style classes by frequency',
|
||||
trimCustomFragments: 'Trim white space around ignoreCustomFragments.',
|
||||
useShortDoctype: 'Replaces the doctype with the short (HTML5) doctype'
|
||||
};
|
||||
var mainOptionKeys = Object.keys(mainOptions);
|
||||
mainOptionKeys.forEach(function(key) {
|
||||
var option = mainOptions[key];
|
||||
if (Array.isArray(option)) {
|
||||
key = key === 'minifyURLs' ? '--minify-urls' : '--' + paramCase(key);
|
||||
key += option[1] === parseJSON ? ' [value]' : ' <value>';
|
||||
program.option(key, option[0], option[1]);
|
||||
}
|
||||
else if (~['html5', 'includeAutoGeneratedTags'].indexOf(key)) {
|
||||
program.option('--no-' + paramCase(key), option);
|
||||
}
|
||||
else {
|
||||
program.option('--' + paramCase(key), option);
|
||||
}
|
||||
});
|
||||
program.option('-o --output <file>', 'Specify output file (if not specified STDOUT will be used for output)');
|
||||
|
||||
function readFile(file) {
|
||||
try {
|
||||
return fs.readFileSync(file, { encoding: 'utf8' });
|
||||
}
|
||||
catch (e) {
|
||||
fatal('Cannot read ' + file + '\n' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
var config = {};
|
||||
program.option('-c --config-file <file>', 'Use config file', function(configPath) {
|
||||
var data = readFile(configPath);
|
||||
try {
|
||||
config = JSON.parse(data);
|
||||
}
|
||||
catch (je) {
|
||||
try {
|
||||
config = require(path.resolve(configPath));
|
||||
}
|
||||
catch (ne) {
|
||||
fatal('Cannot read the specified config file.\nAs JSON: ' + je.message + '\nAs module: ' + ne.message);
|
||||
}
|
||||
}
|
||||
mainOptionKeys.forEach(function(key) {
|
||||
if (key in config) {
|
||||
var option = mainOptions[key];
|
||||
if (Array.isArray(option)) {
|
||||
var value = config[key];
|
||||
config[key] = option[1](typeof value === 'string' ? value : JSON.stringify(value));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
program.option('--input-dir <dir>', 'Specify an input directory');
|
||||
program.option('--output-dir <dir>', 'Specify an output directory');
|
||||
program.option('--file-ext <text>', 'Specify an extension to be read, ex: html');
|
||||
var content;
|
||||
program.arguments('[files...]').action(function(files) {
|
||||
content = files.map(readFile).join('');
|
||||
}).parse(process.argv);
|
||||
|
||||
const programOptions = program.opts();
|
||||
|
||||
function createOptions() {
|
||||
var options = {};
|
||||
mainOptionKeys.forEach(function(key) {
|
||||
var param = programOptions[key === 'minifyURLs' ? 'minifyUrls' : camelCase(key)];
|
||||
if (typeof param !== 'undefined') {
|
||||
options[key] = param;
|
||||
}
|
||||
else if (key in config) {
|
||||
options[key] = config[key];
|
||||
}
|
||||
});
|
||||
return options;
|
||||
}
|
||||
|
||||
function mkdir(outputDir, callback) {
|
||||
fs.mkdir(outputDir, function(err) {
|
||||
if (err) {
|
||||
switch (err.code) {
|
||||
case 'ENOENT':
|
||||
return mkdir(path.join(outputDir, '..'), function() {
|
||||
mkdir(outputDir, callback);
|
||||
});
|
||||
case 'EEXIST':
|
||||
break;
|
||||
default:
|
||||
fatal('Cannot create directory ' + outputDir + '\n' + err.message);
|
||||
}
|
||||
}
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function processFile(inputFile, outputFile) {
|
||||
fs.readFile(inputFile, { encoding: 'utf8' }, async function(err, data) {
|
||||
if (err) {
|
||||
fatal('Cannot read ' + inputFile + '\n' + err.message);
|
||||
}
|
||||
var minified;
|
||||
try {
|
||||
minified = await minify(data, createOptions());
|
||||
}
|
||||
catch (e) {
|
||||
fatal('Minification error on ' + inputFile + '\n' + e.message);
|
||||
}
|
||||
fs.writeFile(outputFile, minified, { encoding: 'utf8' }, function(err) {
|
||||
if (err) {
|
||||
fatal('Cannot write ' + outputFile + '\n' + err.message);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function processDirectory(inputDir, outputDir, fileExt) {
|
||||
fs.readdir(inputDir, function(err, files) {
|
||||
if (err) {
|
||||
fatal('Cannot read directory ' + inputDir + '\n' + err.message);
|
||||
}
|
||||
files.forEach(function(file) {
|
||||
var inputFile = path.join(inputDir, file);
|
||||
var outputFile = path.join(outputDir, file);
|
||||
fs.stat(inputFile, function(err, stat) {
|
||||
if (err) {
|
||||
fatal('Cannot read ' + inputFile + '\n' + err.message);
|
||||
}
|
||||
else if (stat.isDirectory()) {
|
||||
processDirectory(inputFile, outputFile, fileExt);
|
||||
}
|
||||
else if (!fileExt || path.extname(file) === '.' + fileExt) {
|
||||
mkdir(outputDir, function() {
|
||||
processFile(inputFile, outputFile);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function writeMinify() {
|
||||
var minified;
|
||||
try {
|
||||
minified = await minify(content, createOptions());
|
||||
}
|
||||
catch (e) {
|
||||
fatal('Minification error:\n' + e.message);
|
||||
}
|
||||
(programOptions.output ? fs.createWriteStream(programOptions.output).on('error', function(e) {
|
||||
fatal('Cannot write ' + programOptions.output + '\n' + e.message);
|
||||
}) : process.stdout).write(minified);
|
||||
}
|
||||
|
||||
var inputDir = programOptions.inputDir;
|
||||
var outputDir = programOptions.outputDir;
|
||||
var fileExt = programOptions.fileExt;
|
||||
if (inputDir || outputDir) {
|
||||
if (!inputDir) {
|
||||
fatal('The option output-dir needs to be used with the option input-dir. If you are working with a single file, use -o.');
|
||||
}
|
||||
else if (!outputDir) {
|
||||
fatal('You need to specify where to write the output files with the option --output-dir');
|
||||
}
|
||||
processDirectory(inputDir, outputDir, fileExt);
|
||||
}
|
||||
// Minifying one or more files specified on the CMD line
|
||||
else if (content) {
|
||||
writeMinify();
|
||||
}
|
||||
// Minifying input coming from STDIN
|
||||
else {
|
||||
content = '';
|
||||
process.stdin.setEncoding('utf8');
|
||||
process.stdin.on('data', function(data) {
|
||||
content += data;
|
||||
}).on('end', writeMinify);
|
||||
}
|
22
node_modules/html-minifier-terser/node_modules/commander/LICENSE
generated
vendored
Normal file
22
node_modules/html-minifier-terser/node_modules/commander/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
|
||||
|
||||
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.
|
1015
node_modules/html-minifier-terser/node_modules/commander/Readme.md
generated
vendored
Normal file
1015
node_modules/html-minifier-terser/node_modules/commander/Readme.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
15
node_modules/html-minifier-terser/node_modules/commander/esm.mjs
generated
vendored
Normal file
15
node_modules/html-minifier-terser/node_modules/commander/esm.mjs
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import commander from './index.js';
|
||||
|
||||
// wrapper to provide named exports for ESM.
|
||||
export const {
|
||||
program,
|
||||
createCommand,
|
||||
createArgument,
|
||||
createOption,
|
||||
CommanderError,
|
||||
InvalidArgumentError,
|
||||
Command,
|
||||
Argument,
|
||||
Option,
|
||||
Help
|
||||
} = commander;
|
27
node_modules/html-minifier-terser/node_modules/commander/index.js
generated
vendored
Normal file
27
node_modules/html-minifier-terser/node_modules/commander/index.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
const { Argument } = require('./lib/argument.js');
|
||||
const { Command } = require('./lib/command.js');
|
||||
const { CommanderError, InvalidArgumentError } = require('./lib/error.js');
|
||||
const { Help } = require('./lib/help.js');
|
||||
const { Option } = require('./lib/option.js');
|
||||
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* Expose the root command.
|
||||
*/
|
||||
|
||||
exports = module.exports = new Command();
|
||||
exports.program = exports; // More explicit access to global command.
|
||||
// Implicit export of createArgument, createCommand, and createOption.
|
||||
|
||||
/**
|
||||
* Expose classes
|
||||
*/
|
||||
|
||||
exports.Argument = Argument;
|
||||
exports.Command = Command;
|
||||
exports.CommanderError = CommanderError;
|
||||
exports.Help = Help;
|
||||
exports.InvalidArgumentError = InvalidArgumentError;
|
||||
exports.InvalidOptionArgumentError = InvalidArgumentError; // Deprecated
|
||||
exports.Option = Option;
|
147
node_modules/html-minifier-terser/node_modules/commander/lib/argument.js
generated
vendored
Normal file
147
node_modules/html-minifier-terser/node_modules/commander/lib/argument.js
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
const { InvalidArgumentError } = require('./error.js');
|
||||
|
||||
// @ts-check
|
||||
|
||||
class Argument {
|
||||
/**
|
||||
* Initialize a new command argument with the given name and description.
|
||||
* The default is that the argument is required, and you can explicitly
|
||||
* indicate this with <> around the name. Put [] around the name for an optional argument.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {string} [description]
|
||||
*/
|
||||
|
||||
constructor(name, description) {
|
||||
this.description = description || '';
|
||||
this.variadic = false;
|
||||
this.parseArg = undefined;
|
||||
this.defaultValue = undefined;
|
||||
this.defaultValueDescription = undefined;
|
||||
this.argChoices = undefined;
|
||||
|
||||
switch (name[0]) {
|
||||
case '<': // e.g. <required>
|
||||
this.required = true;
|
||||
this._name = name.slice(1, -1);
|
||||
break;
|
||||
case '[': // e.g. [optional]
|
||||
this.required = false;
|
||||
this._name = name.slice(1, -1);
|
||||
break;
|
||||
default:
|
||||
this.required = true;
|
||||
this._name = name;
|
||||
break;
|
||||
}
|
||||
|
||||
if (this._name.length > 3 && this._name.slice(-3) === '...') {
|
||||
this.variadic = true;
|
||||
this._name = this._name.slice(0, -3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return argument name.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
|
||||
name() {
|
||||
return this._name;
|
||||
};
|
||||
|
||||
/**
|
||||
* @api private
|
||||
*/
|
||||
|
||||
_concatValue(value, previous) {
|
||||
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
||||
return [value];
|
||||
}
|
||||
|
||||
return previous.concat(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value, and optionally supply the description to be displayed in the help.
|
||||
*
|
||||
* @param {any} value
|
||||
* @param {string} [description]
|
||||
* @return {Argument}
|
||||
*/
|
||||
|
||||
default(value, description) {
|
||||
this.defaultValue = value;
|
||||
this.defaultValueDescription = description;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the custom handler for processing CLI command arguments into argument values.
|
||||
*
|
||||
* @param {Function} [fn]
|
||||
* @return {Argument}
|
||||
*/
|
||||
|
||||
argParser(fn) {
|
||||
this.parseArg = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Only allow option value to be one of choices.
|
||||
*
|
||||
* @param {string[]} values
|
||||
* @return {Argument}
|
||||
*/
|
||||
|
||||
choices(values) {
|
||||
this.argChoices = values;
|
||||
this.parseArg = (arg, previous) => {
|
||||
if (!values.includes(arg)) {
|
||||
throw new InvalidArgumentError(`Allowed choices are ${values.join(', ')}.`);
|
||||
}
|
||||
if (this.variadic) {
|
||||
return this._concatValue(arg, previous);
|
||||
}
|
||||
return arg;
|
||||
};
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Make option-argument required.
|
||||
*/
|
||||
argRequired() {
|
||||
this.required = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make option-argument optional.
|
||||
*/
|
||||
argOptional() {
|
||||
this.required = false;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes an argument and returns its human readable equivalent for help usage.
|
||||
*
|
||||
* @param {Argument} arg
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function humanReadableArgName(arg) {
|
||||
const nameOutput = arg.name() + (arg.variadic === true ? '...' : '');
|
||||
|
||||
return arg.required
|
||||
? '<' + nameOutput + '>'
|
||||
: '[' + nameOutput + ']';
|
||||
}
|
||||
|
||||
exports.Argument = Argument;
|
||||
exports.humanReadableArgName = humanReadableArgName;
|
1944
node_modules/html-minifier-terser/node_modules/commander/lib/command.js
generated
vendored
Normal file
1944
node_modules/html-minifier-terser/node_modules/commander/lib/command.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
45
node_modules/html-minifier-terser/node_modules/commander/lib/error.js
generated
vendored
Normal file
45
node_modules/html-minifier-terser/node_modules/commander/lib/error.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* CommanderError class
|
||||
* @class
|
||||
*/
|
||||
class CommanderError extends Error {
|
||||
/**
|
||||
* Constructs the CommanderError class
|
||||
* @param {number} exitCode suggested exit code which could be used with process.exit
|
||||
* @param {string} code an id string representing the error
|
||||
* @param {string} message human-readable description of the error
|
||||
* @constructor
|
||||
*/
|
||||
constructor(exitCode, code, message) {
|
||||
super(message);
|
||||
// properly capture stack trace in Node.js
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
this.name = this.constructor.name;
|
||||
this.code = code;
|
||||
this.exitCode = exitCode;
|
||||
this.nestedError = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* InvalidArgumentError class
|
||||
* @class
|
||||
*/
|
||||
class InvalidArgumentError extends CommanderError {
|
||||
/**
|
||||
* Constructs the InvalidArgumentError class
|
||||
* @param {string} [message] explanation of why argument is invalid
|
||||
* @constructor
|
||||
*/
|
||||
constructor(message) {
|
||||
super(1, 'commander.invalidArgument', message);
|
||||
// properly capture stack trace in Node.js
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
this.name = this.constructor.name;
|
||||
}
|
||||
}
|
||||
|
||||
exports.CommanderError = CommanderError;
|
||||
exports.InvalidArgumentError = InvalidArgumentError;
|
396
node_modules/html-minifier-terser/node_modules/commander/lib/help.js
generated
vendored
Normal file
396
node_modules/html-minifier-terser/node_modules/commander/lib/help.js
generated
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
const { humanReadableArgName } = require('./argument.js');
|
||||
|
||||
/**
|
||||
* TypeScript import types for JSDoc, used by Visual Studio Code IntelliSense and `npm run typescript-checkJS`
|
||||
* https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#import-types
|
||||
* @typedef { import("./argument.js").Argument } Argument
|
||||
* @typedef { import("./command.js").Command } Command
|
||||
* @typedef { import("./option.js").Option } Option
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
|
||||
// Although this is a class, methods are static in style to allow override using subclass or just functions.
|
||||
class Help {
|
||||
constructor() {
|
||||
this.helpWidth = undefined;
|
||||
this.sortSubcommands = false;
|
||||
this.sortOptions = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @returns {Command[]}
|
||||
*/
|
||||
|
||||
visibleCommands(cmd) {
|
||||
const visibleCommands = cmd.commands.filter(cmd => !cmd._hidden);
|
||||
if (cmd._hasImplicitHelpCommand()) {
|
||||
// Create a command matching the implicit help command.
|
||||
const [, helpName, helpArgs] = cmd._helpCommandnameAndArgs.match(/([^ ]+) *(.*)/);
|
||||
const helpCommand = cmd.createCommand(helpName)
|
||||
.helpOption(false);
|
||||
helpCommand.description(cmd._helpCommandDescription);
|
||||
if (helpArgs) helpCommand.arguments(helpArgs);
|
||||
visibleCommands.push(helpCommand);
|
||||
}
|
||||
if (this.sortSubcommands) {
|
||||
visibleCommands.sort((a, b) => {
|
||||
// @ts-ignore: overloaded return type
|
||||
return a.name().localeCompare(b.name());
|
||||
});
|
||||
}
|
||||
return visibleCommands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @returns {Option[]}
|
||||
*/
|
||||
|
||||
visibleOptions(cmd) {
|
||||
const visibleOptions = cmd.options.filter((option) => !option.hidden);
|
||||
// Implicit help
|
||||
const showShortHelpFlag = cmd._hasHelpOption && cmd._helpShortFlag && !cmd._findOption(cmd._helpShortFlag);
|
||||
const showLongHelpFlag = cmd._hasHelpOption && !cmd._findOption(cmd._helpLongFlag);
|
||||
if (showShortHelpFlag || showLongHelpFlag) {
|
||||
let helpOption;
|
||||
if (!showShortHelpFlag) {
|
||||
helpOption = cmd.createOption(cmd._helpLongFlag, cmd._helpDescription);
|
||||
} else if (!showLongHelpFlag) {
|
||||
helpOption = cmd.createOption(cmd._helpShortFlag, cmd._helpDescription);
|
||||
} else {
|
||||
helpOption = cmd.createOption(cmd._helpFlags, cmd._helpDescription);
|
||||
}
|
||||
visibleOptions.push(helpOption);
|
||||
}
|
||||
if (this.sortOptions) {
|
||||
const getSortKey = (option) => {
|
||||
// WYSIWYG for order displayed in help with short before long, no special handling for negated.
|
||||
return option.short ? option.short.replace(/^-/, '') : option.long.replace(/^--/, '');
|
||||
};
|
||||
visibleOptions.sort((a, b) => {
|
||||
return getSortKey(a).localeCompare(getSortKey(b));
|
||||
});
|
||||
}
|
||||
return visibleOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of the arguments if any have a description.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @returns {Argument[]}
|
||||
*/
|
||||
|
||||
visibleArguments(cmd) {
|
||||
// Side effect! Apply the legacy descriptions before the arguments are displayed.
|
||||
if (cmd._argsDescription) {
|
||||
cmd._args.forEach(argument => {
|
||||
argument.description = argument.description || cmd._argsDescription[argument.name()] || '';
|
||||
});
|
||||
}
|
||||
|
||||
// If there are any arguments with a description then return all the arguments.
|
||||
if (cmd._args.find(argument => argument.description)) {
|
||||
return cmd._args;
|
||||
};
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command term to show in the list of subcommands.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
subcommandTerm(cmd) {
|
||||
// Legacy. Ignores custom usage string, and nested commands.
|
||||
const args = cmd._args.map(arg => humanReadableArgName(arg)).join(' ');
|
||||
return cmd._name +
|
||||
(cmd._aliases[0] ? '|' + cmd._aliases[0] : '') +
|
||||
(cmd.options.length ? ' [options]' : '') + // simplistic check for non-help option
|
||||
(args ? ' ' + args : '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the option term to show in the list of options.
|
||||
*
|
||||
* @param {Option} option
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
optionTerm(option) {
|
||||
return option.flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the argument term to show in the list of arguments.
|
||||
*
|
||||
* @param {Argument} argument
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
argumentTerm(argument) {
|
||||
return argument.name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the longest command term length.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @param {Help} helper
|
||||
* @returns {number}
|
||||
*/
|
||||
|
||||
longestSubcommandTermLength(cmd, helper) {
|
||||
return helper.visibleCommands(cmd).reduce((max, command) => {
|
||||
return Math.max(max, helper.subcommandTerm(command).length);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the longest option term length.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @param {Help} helper
|
||||
* @returns {number}
|
||||
*/
|
||||
|
||||
longestOptionTermLength(cmd, helper) {
|
||||
return helper.visibleOptions(cmd).reduce((max, option) => {
|
||||
return Math.max(max, helper.optionTerm(option).length);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the longest argument term length.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @param {Help} helper
|
||||
* @returns {number}
|
||||
*/
|
||||
|
||||
longestArgumentTermLength(cmd, helper) {
|
||||
return helper.visibleArguments(cmd).reduce((max, argument) => {
|
||||
return Math.max(max, helper.argumentTerm(argument).length);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the command usage to be displayed at the top of the built-in help.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
commandUsage(cmd) {
|
||||
// Usage
|
||||
let cmdName = cmd._name;
|
||||
if (cmd._aliases[0]) {
|
||||
cmdName = cmdName + '|' + cmd._aliases[0];
|
||||
}
|
||||
let parentCmdNames = '';
|
||||
for (let parentCmd = cmd.parent; parentCmd; parentCmd = parentCmd.parent) {
|
||||
parentCmdNames = parentCmd.name() + ' ' + parentCmdNames;
|
||||
}
|
||||
return parentCmdNames + cmdName + ' ' + cmd.usage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the description for the command.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
commandDescription(cmd) {
|
||||
// @ts-ignore: overloaded return type
|
||||
return cmd.description();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command description to show in the list of subcommands.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
subcommandDescription(cmd) {
|
||||
// @ts-ignore: overloaded return type
|
||||
return cmd.description();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the option description to show in the list of options.
|
||||
*
|
||||
* @param {Option} option
|
||||
* @return {string}
|
||||
*/
|
||||
|
||||
optionDescription(option) {
|
||||
const extraInfo = [];
|
||||
// Some of these do not make sense for negated boolean and suppress for backwards compatibility.
|
||||
|
||||
if (option.argChoices && !option.negate) {
|
||||
extraInfo.push(
|
||||
// use stringify to match the display of the default value
|
||||
`choices: ${option.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`);
|
||||
}
|
||||
if (option.defaultValue !== undefined && !option.negate) {
|
||||
extraInfo.push(`default: ${option.defaultValueDescription || JSON.stringify(option.defaultValue)}`);
|
||||
}
|
||||
if (option.envVar !== undefined) {
|
||||
extraInfo.push(`env: ${option.envVar}`);
|
||||
}
|
||||
if (extraInfo.length > 0) {
|
||||
return `${option.description} (${extraInfo.join(', ')})`;
|
||||
}
|
||||
|
||||
return option.description;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the argument description to show in the list of arguments.
|
||||
*
|
||||
* @param {Argument} argument
|
||||
* @return {string}
|
||||
*/
|
||||
|
||||
argumentDescription(argument) {
|
||||
const extraInfo = [];
|
||||
if (argument.argChoices) {
|
||||
extraInfo.push(
|
||||
// use stringify to match the display of the default value
|
||||
`choices: ${argument.argChoices.map((choice) => JSON.stringify(choice)).join(', ')}`);
|
||||
}
|
||||
if (argument.defaultValue !== undefined) {
|
||||
extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
|
||||
}
|
||||
if (extraInfo.length > 0) {
|
||||
const extraDescripton = `(${extraInfo.join(', ')})`;
|
||||
if (argument.description) {
|
||||
return `${argument.description} ${extraDescripton}`;
|
||||
}
|
||||
return extraDescripton;
|
||||
}
|
||||
return argument.description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the built-in help text.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @param {Help} helper
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
formatHelp(cmd, helper) {
|
||||
const termWidth = helper.padWidth(cmd, helper);
|
||||
const helpWidth = helper.helpWidth || 80;
|
||||
const itemIndentWidth = 2;
|
||||
const itemSeparatorWidth = 2; // between term and description
|
||||
function formatItem(term, description) {
|
||||
if (description) {
|
||||
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
|
||||
return helper.wrap(fullText, helpWidth - itemIndentWidth, termWidth + itemSeparatorWidth);
|
||||
}
|
||||
return term;
|
||||
};
|
||||
function formatList(textArray) {
|
||||
return textArray.join('\n').replace(/^/gm, ' '.repeat(itemIndentWidth));
|
||||
}
|
||||
|
||||
// Usage
|
||||
let output = [`Usage: ${helper.commandUsage(cmd)}`, ''];
|
||||
|
||||
// Description
|
||||
const commandDescription = helper.commandDescription(cmd);
|
||||
if (commandDescription.length > 0) {
|
||||
output = output.concat([commandDescription, '']);
|
||||
}
|
||||
|
||||
// Arguments
|
||||
const argumentList = helper.visibleArguments(cmd).map((argument) => {
|
||||
return formatItem(helper.argumentTerm(argument), helper.argumentDescription(argument));
|
||||
});
|
||||
if (argumentList.length > 0) {
|
||||
output = output.concat(['Arguments:', formatList(argumentList), '']);
|
||||
}
|
||||
|
||||
// Options
|
||||
const optionList = helper.visibleOptions(cmd).map((option) => {
|
||||
return formatItem(helper.optionTerm(option), helper.optionDescription(option));
|
||||
});
|
||||
if (optionList.length > 0) {
|
||||
output = output.concat(['Options:', formatList(optionList), '']);
|
||||
}
|
||||
|
||||
// Commands
|
||||
const commandList = helper.visibleCommands(cmd).map((cmd) => {
|
||||
return formatItem(helper.subcommandTerm(cmd), helper.subcommandDescription(cmd));
|
||||
});
|
||||
if (commandList.length > 0) {
|
||||
output = output.concat(['Commands:', formatList(commandList), '']);
|
||||
}
|
||||
|
||||
return output.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the pad width from the maximum term length.
|
||||
*
|
||||
* @param {Command} cmd
|
||||
* @param {Help} helper
|
||||
* @returns {number}
|
||||
*/
|
||||
|
||||
padWidth(cmd, helper) {
|
||||
return Math.max(
|
||||
helper.longestOptionTermLength(cmd, helper),
|
||||
helper.longestSubcommandTermLength(cmd, helper),
|
||||
helper.longestArgumentTermLength(cmd, helper)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrap the given string to width characters per line, with lines after the first indented.
|
||||
* Do not wrap if insufficient room for wrapping (minColumnWidth), or string is manually formatted.
|
||||
*
|
||||
* @param {string} str
|
||||
* @param {number} width
|
||||
* @param {number} indent
|
||||
* @param {number} [minColumnWidth=40]
|
||||
* @return {string}
|
||||
*
|
||||
*/
|
||||
|
||||
wrap(str, width, indent, minColumnWidth = 40) {
|
||||
// Detect manually wrapped and indented strings by searching for line breaks
|
||||
// followed by multiple spaces/tabs.
|
||||
if (str.match(/[\n]\s+/)) return str;
|
||||
// Do not wrap if not enough room for a wrapped column of text (as could end up with a word per line).
|
||||
const columnWidth = width - indent;
|
||||
if (columnWidth < minColumnWidth) return str;
|
||||
|
||||
const leadingStr = str.substr(0, indent);
|
||||
const columnText = str.substr(indent);
|
||||
|
||||
const indentString = ' '.repeat(indent);
|
||||
const regex = new RegExp('.{1,' + (columnWidth - 1) + '}([\\s\u200B]|$)|[^\\s\u200B]+?([\\s\u200B]|$)', 'g');
|
||||
const lines = columnText.match(regex) || [];
|
||||
return leadingStr + lines.map((line, i) => {
|
||||
if (line.slice(-1) === '\n') {
|
||||
line = line.slice(0, line.length - 1);
|
||||
}
|
||||
return ((i > 0) ? indentString : '') + line.trimRight();
|
||||
}).join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
exports.Help = Help;
|
208
node_modules/html-minifier-terser/node_modules/commander/lib/option.js
generated
vendored
Normal file
208
node_modules/html-minifier-terser/node_modules/commander/lib/option.js
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
const { InvalidArgumentError } = require('./error.js');
|
||||
|
||||
// @ts-check
|
||||
|
||||
class Option {
|
||||
/**
|
||||
* Initialize a new `Option` with the given `flags` and `description`.
|
||||
*
|
||||
* @param {string} flags
|
||||
* @param {string} [description]
|
||||
*/
|
||||
|
||||
constructor(flags, description) {
|
||||
this.flags = flags;
|
||||
this.description = description || '';
|
||||
|
||||
this.required = flags.includes('<'); // A value must be supplied when the option is specified.
|
||||
this.optional = flags.includes('['); // A value is optional when the option is specified.
|
||||
// variadic test ignores <value,...> et al which might be used to describe custom splitting of single argument
|
||||
this.variadic = /\w\.\.\.[>\]]$/.test(flags); // The option can take multiple values.
|
||||
this.mandatory = false; // The option must have a value after parsing, which usually means it must be specified on command line.
|
||||
const optionFlags = splitOptionFlags(flags);
|
||||
this.short = optionFlags.shortFlag;
|
||||
this.long = optionFlags.longFlag;
|
||||
this.negate = false;
|
||||
if (this.long) {
|
||||
this.negate = this.long.startsWith('--no-');
|
||||
}
|
||||
this.defaultValue = undefined;
|
||||
this.defaultValueDescription = undefined;
|
||||
this.envVar = undefined;
|
||||
this.parseArg = undefined;
|
||||
this.hidden = false;
|
||||
this.argChoices = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default value, and optionally supply the description to be displayed in the help.
|
||||
*
|
||||
* @param {any} value
|
||||
* @param {string} [description]
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
default(value, description) {
|
||||
this.defaultValue = value;
|
||||
this.defaultValueDescription = description;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set environment variable to check for option value.
|
||||
* Priority order of option values is default < env < cli
|
||||
*
|
||||
* @param {string} name
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
env(name) {
|
||||
this.envVar = name;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the custom handler for processing CLI option arguments into option values.
|
||||
*
|
||||
* @param {Function} [fn]
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
argParser(fn) {
|
||||
this.parseArg = fn;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Whether the option is mandatory and must have a value after parsing.
|
||||
*
|
||||
* @param {boolean} [mandatory=true]
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
makeOptionMandatory(mandatory = true) {
|
||||
this.mandatory = !!mandatory;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide option in help.
|
||||
*
|
||||
* @param {boolean} [hide=true]
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
hideHelp(hide = true) {
|
||||
this.hidden = !!hide;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @api private
|
||||
*/
|
||||
|
||||
_concatValue(value, previous) {
|
||||
if (previous === this.defaultValue || !Array.isArray(previous)) {
|
||||
return [value];
|
||||
}
|
||||
|
||||
return previous.concat(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only allow option value to be one of choices.
|
||||
*
|
||||
* @param {string[]} values
|
||||
* @return {Option}
|
||||
*/
|
||||
|
||||
choices(values) {
|
||||
this.argChoices = values;
|
||||
this.parseArg = (arg, previous) => {
|
||||
if (!values.includes(arg)) {
|
||||
throw new InvalidArgumentError(`Allowed choices are ${values.join(', ')}.`);
|
||||
}
|
||||
if (this.variadic) {
|
||||
return this._concatValue(arg, previous);
|
||||
}
|
||||
return arg;
|
||||
};
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return option name.
|
||||
*
|
||||
* @return {string}
|
||||
*/
|
||||
|
||||
name() {
|
||||
if (this.long) {
|
||||
return this.long.replace(/^--/, '');
|
||||
}
|
||||
return this.short.replace(/^-/, '');
|
||||
};
|
||||
|
||||
/**
|
||||
* Return option name, in a camelcase format that can be used
|
||||
* as a object attribute key.
|
||||
*
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
attributeName() {
|
||||
return camelcase(this.name().replace(/^no-/, ''));
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if `arg` matches the short or long flag.
|
||||
*
|
||||
* @param {string} arg
|
||||
* @return {boolean}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
is(arg) {
|
||||
return this.short === arg || this.long === arg;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert string from kebab-case to camelCase.
|
||||
*
|
||||
* @param {string} str
|
||||
* @return {string}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function camelcase(str) {
|
||||
return str.split('-').reduce((str, word) => {
|
||||
return str + word[0].toUpperCase() + word.slice(1);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the short and long flag out of something like '-m,--mixed <value>'
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function splitOptionFlags(flags) {
|
||||
let shortFlag;
|
||||
let longFlag;
|
||||
// Use original very loose parsing to maintain backwards compatibility for now,
|
||||
// which allowed for example unintended `-sw, --short-word` [sic].
|
||||
const flagParts = flags.split(/[ |,]+/);
|
||||
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1])) shortFlag = flagParts.shift();
|
||||
longFlag = flagParts.shift();
|
||||
// Add support for lone short flag without significantly changing parsing!
|
||||
if (!shortFlag && /^-[^-]$/.test(longFlag)) {
|
||||
shortFlag = longFlag;
|
||||
longFlag = undefined;
|
||||
}
|
||||
return { shortFlag, longFlag };
|
||||
}
|
||||
|
||||
exports.Option = Option;
|
||||
exports.splitOptionFlags = splitOptionFlags;
|
100
node_modules/html-minifier-terser/node_modules/commander/lib/suggestSimilar.js
generated
vendored
Normal file
100
node_modules/html-minifier-terser/node_modules/commander/lib/suggestSimilar.js
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
const maxDistance = 3;
|
||||
|
||||
function editDistance(a, b) {
|
||||
// https://en.wikipedia.org/wiki/Damerau–Levenshtein_distance
|
||||
// Calculating optimal string alignment distance, no substring is edited more than once.
|
||||
// (Simple implementation.)
|
||||
|
||||
// Quick early exit, return worst case.
|
||||
if (Math.abs(a.length - b.length) > maxDistance) return Math.max(a.length, b.length);
|
||||
|
||||
// distance between prefix substrings of a and b
|
||||
const d = [];
|
||||
|
||||
// pure deletions turn a into empty string
|
||||
for (let i = 0; i <= a.length; i++) {
|
||||
d[i] = [i];
|
||||
}
|
||||
// pure insertions turn empty string into b
|
||||
for (let j = 0; j <= b.length; j++) {
|
||||
d[0][j] = j;
|
||||
}
|
||||
|
||||
// fill matrix
|
||||
for (let j = 1; j <= b.length; j++) {
|
||||
for (let i = 1; i <= a.length; i++) {
|
||||
let cost = 1;
|
||||
if (a[i - 1] === b[j - 1]) {
|
||||
cost = 0;
|
||||
} else {
|
||||
cost = 1;
|
||||
}
|
||||
d[i][j] = Math.min(
|
||||
d[i - 1][j] + 1, // deletion
|
||||
d[i][j - 1] + 1, // insertion
|
||||
d[i - 1][j - 1] + cost // substitution
|
||||
);
|
||||
// transposition
|
||||
if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
|
||||
d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return d[a.length][b.length];
|
||||
}
|
||||
|
||||
/**
|
||||
* Find close matches, restricted to same number of edits.
|
||||
*
|
||||
* @param {string} word
|
||||
* @param {string[]} candidates
|
||||
* @returns {string}
|
||||
*/
|
||||
|
||||
function suggestSimilar(word, candidates) {
|
||||
if (!candidates || candidates.length === 0) return '';
|
||||
// remove possible duplicates
|
||||
candidates = Array.from(new Set(candidates));
|
||||
|
||||
const searchingOptions = word.startsWith('--');
|
||||
if (searchingOptions) {
|
||||
word = word.slice(2);
|
||||
candidates = candidates.map(candidate => candidate.slice(2));
|
||||
}
|
||||
|
||||
let similar = [];
|
||||
let bestDistance = maxDistance;
|
||||
const minSimilarity = 0.4;
|
||||
candidates.forEach((candidate) => {
|
||||
if (candidate.length <= 1) return; // no one character guesses
|
||||
|
||||
const distance = editDistance(word, candidate);
|
||||
const length = Math.max(word.length, candidate.length);
|
||||
const similarity = (length - distance) / length;
|
||||
if (similarity > minSimilarity) {
|
||||
if (distance < bestDistance) {
|
||||
// better edit distance, throw away previous worse matches
|
||||
bestDistance = distance;
|
||||
similar = [candidate];
|
||||
} else if (distance === bestDistance) {
|
||||
similar.push(candidate);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
similar.sort((a, b) => a.localeCompare(b));
|
||||
if (searchingOptions) {
|
||||
similar = similar.map(candidate => `--${candidate}`);
|
||||
}
|
||||
|
||||
if (similar.length > 1) {
|
||||
return `\n(Did you mean one of ${similar.join(', ')}?)`;
|
||||
}
|
||||
if (similar.length === 1) {
|
||||
return `\n(Did you mean ${similar[0]}?)`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
exports.suggestSimilar = suggestSimilar;
|
16
node_modules/html-minifier-terser/node_modules/commander/package-support.json
generated
vendored
Normal file
16
node_modules/html-minifier-terser/node_modules/commander/package-support.json
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"versions": [
|
||||
{
|
||||
"version": "*",
|
||||
"target": {
|
||||
"node": "supported"
|
||||
},
|
||||
"response": {
|
||||
"type": "time-permitting"
|
||||
},
|
||||
"backing": {
|
||||
"npm-funding": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
69
node_modules/html-minifier-terser/node_modules/commander/package.json
generated
vendored
Normal file
69
node_modules/html-minifier-terser/node_modules/commander/package.json
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"name": "commander",
|
||||
"version": "8.3.0",
|
||||
"description": "the complete solution for node.js command-line programs",
|
||||
"keywords": [
|
||||
"commander",
|
||||
"command",
|
||||
"option",
|
||||
"parser",
|
||||
"cli",
|
||||
"argument",
|
||||
"args",
|
||||
"argv"
|
||||
],
|
||||
"author": "TJ Holowaychuk <tj@vision-media.ca>",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tj/commander.js.git"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint index.js esm.mjs \"lib/*.js\" \"tests/**/*.js\"",
|
||||
"typescript-lint": "eslint typings/*.ts tests/*.ts",
|
||||
"test": "jest && npm run test-typings",
|
||||
"test-esm": "node --experimental-modules ./tests/esm-imports-test.mjs",
|
||||
"test-typings": "tsd",
|
||||
"typescript-checkJS": "tsc --allowJS --checkJS index.js lib/*.js --noEmit",
|
||||
"test-all": "npm run test && npm run lint && npm run typescript-lint && npm run typescript-checkJS && npm run test-esm"
|
||||
},
|
||||
"main": "./index.js",
|
||||
"files": [
|
||||
"index.js",
|
||||
"lib/*.js",
|
||||
"esm.mjs",
|
||||
"typings/index.d.ts",
|
||||
"package-support.json"
|
||||
],
|
||||
"type": "commonjs",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^26.0.23",
|
||||
"@types/node": "^14.17.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.27.0",
|
||||
"@typescript-eslint/parser": "^4.27.0",
|
||||
"eslint": "^7.29.0",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-plugin-jest": "^24.3.6",
|
||||
"jest": "^27.0.4",
|
||||
"standard": "^16.0.3",
|
||||
"ts-jest": "^27.0.3",
|
||||
"tsd": "^0.17.0",
|
||||
"typescript": "^4.3.4"
|
||||
},
|
||||
"types": "typings/index.d.ts",
|
||||
"jest": {
|
||||
"testEnvironment": "node",
|
||||
"collectCoverage": true,
|
||||
"transform": {
|
||||
"^.+\\.tsx?$": "ts-jest"
|
||||
},
|
||||
"testPathIgnorePatterns": [
|
||||
"/node_modules/"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
},
|
||||
"support": true
|
||||
}
|
774
node_modules/html-minifier-terser/node_modules/commander/typings/index.d.ts
generated
vendored
Normal file
774
node_modules/html-minifier-terser/node_modules/commander/typings/index.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
95
node_modules/html-minifier-terser/package.json
generated
vendored
Normal file
95
node_modules/html-minifier-terser/package.json
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"name": "html-minifier-terser",
|
||||
"description": "Highly configurable, well-tested, JavaScript-based HTML minifier.",
|
||||
"version": "6.1.0",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/terser/html-minifier-terser.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/terser/html-minifier-terser/issues"
|
||||
},
|
||||
"homepage": "https://terser.org/html-minifier-terser/",
|
||||
"author": "Daniel Ruf",
|
||||
"maintainers": [
|
||||
"Daniel Ruf <daniel@daniel-ruf.de",
|
||||
"Alex Lam <alexlamsl@gmail.com>",
|
||||
"Juriy Zaytsev <kangax@gmail.com> (http://perfectionkills.com/)",
|
||||
"Sibiraj <sibiraj.dev>"
|
||||
],
|
||||
"contributors": [
|
||||
"Gilmore Davidson (https://github.com/gilmoreorless)",
|
||||
"Hugo Wetterberg <hugo@wetterberg.nu>",
|
||||
"Zoltan Frombach <tssajo@gmail.com>"
|
||||
],
|
||||
"keywords": [
|
||||
"cli",
|
||||
"compress",
|
||||
"compressor",
|
||||
"css",
|
||||
"html",
|
||||
"htmlmin",
|
||||
"javascript",
|
||||
"min",
|
||||
"minification",
|
||||
"minifier",
|
||||
"minify",
|
||||
"optimize",
|
||||
"optimizer",
|
||||
"pack",
|
||||
"packer",
|
||||
"parse",
|
||||
"parser",
|
||||
"terser",
|
||||
"uglifier",
|
||||
"uglify"
|
||||
],
|
||||
"bin": {
|
||||
"html-minifier-terser": "./cli.js"
|
||||
},
|
||||
"main": "src/htmlminifier.js",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"files": [
|
||||
"src/*.js",
|
||||
"cli.js",
|
||||
"sample-cli-config-file.conf"
|
||||
],
|
||||
"scripts": {
|
||||
"dist": "grunt dist",
|
||||
"test": "grunt test",
|
||||
"prepare": "is-ci || husky install",
|
||||
"serve": "npm run dist && serve . -p 6753"
|
||||
},
|
||||
"dependencies": {
|
||||
"camel-case": "^4.1.2",
|
||||
"clean-css": "^5.2.2",
|
||||
"commander": "^8.3.0",
|
||||
"he": "^1.2.0",
|
||||
"param-case": "^3.0.4",
|
||||
"relateurl": "^0.2.7",
|
||||
"terser": "^5.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"grunt": "^1.4.1",
|
||||
"grunt-browserify": "^6.0.0",
|
||||
"grunt-eslint": "^24.0.0",
|
||||
"grunt-terser": "^2.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"is-ci": "^3.0.1",
|
||||
"lint-staged": "^12.1.2",
|
||||
"node-qunit-puppeteer": "^2.1.0",
|
||||
"qunit": "2.16.0",
|
||||
"serve": "^13.0.2"
|
||||
},
|
||||
"benchmarkDependencies": {
|
||||
"chalk": "^2.4.2",
|
||||
"cli-table3": "^0.5.1",
|
||||
"iltorb": "^2.4.4",
|
||||
"lzma": "^2.3.2",
|
||||
"minimize": "^2.2.0",
|
||||
"progress": "^2.0.3"
|
||||
}
|
||||
}
|
40
node_modules/html-minifier-terser/sample-cli-config-file.conf
generated
vendored
Normal file
40
node_modules/html-minifier-terser/sample-cli-config-file.conf
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"caseSensitive": false,
|
||||
"collapseBooleanAttributes": true,
|
||||
"collapseInlineTagWhitespace": false,
|
||||
"collapseWhitespace": true,
|
||||
"conservativeCollapse": false,
|
||||
"continueOnParseError": true,
|
||||
"customAttrCollapse": ".*",
|
||||
"decodeEntities": true,
|
||||
"html5": true,
|
||||
"ignoreCustomFragments": [
|
||||
"<#[\\s\\S]*?#>",
|
||||
"<%[\\s\\S]*?%>",
|
||||
"<\\?[\\s\\S]*?\\?>"
|
||||
],
|
||||
"includeAutoGeneratedTags": false,
|
||||
"keepClosingSlash": false,
|
||||
"maxLineLength": 0,
|
||||
"minifyCSS": true,
|
||||
"minifyJS": true,
|
||||
"preserveLineBreaks": false,
|
||||
"preventAttributesEscaping": false,
|
||||
"processConditionalComments": true,
|
||||
"processScripts": [
|
||||
"text/html"
|
||||
],
|
||||
"removeAttributeQuotes": true,
|
||||
"removeComments": true,
|
||||
"removeEmptyAttributes": true,
|
||||
"removeEmptyElements": true,
|
||||
"removeOptionalTags": true,
|
||||
"removeRedundantAttributes": true,
|
||||
"removeScriptTypeAttributes": true,
|
||||
"removeStyleLinkTypeAttributes": true,
|
||||
"removeTagWhitespace": true,
|
||||
"sortAttributes": true,
|
||||
"sortClassName": true,
|
||||
"trimCustomFragments": true,
|
||||
"useShortDoctype": true
|
||||
}
|
1368
node_modules/html-minifier-terser/src/htmlminifier.js
generated
vendored
Normal file
1368
node_modules/html-minifier-terser/src/htmlminifier.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
581
node_modules/html-minifier-terser/src/htmlparser.js
generated
vendored
Normal file
581
node_modules/html-minifier-terser/src/htmlparser.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
71
node_modules/html-minifier-terser/src/tokenchain.js
generated
vendored
Normal file
71
node_modules/html-minifier-terser/src/tokenchain.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
'use strict';
|
||||
|
||||
function Sorter() {
|
||||
}
|
||||
|
||||
Sorter.prototype.sort = function(tokens, fromIndex) {
|
||||
fromIndex = fromIndex || 0;
|
||||
for (var i = 0, len = this.keys.length; i < len; i++) {
|
||||
var key = this.keys[i];
|
||||
var token = key.slice(1);
|
||||
var index = tokens.indexOf(token, fromIndex);
|
||||
if (index !== -1) {
|
||||
do {
|
||||
if (index !== fromIndex) {
|
||||
tokens.splice(index, 1);
|
||||
tokens.splice(fromIndex, 0, token);
|
||||
}
|
||||
fromIndex++;
|
||||
} while ((index = tokens.indexOf(token, fromIndex)) !== -1);
|
||||
return this[key].sort(tokens, fromIndex);
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
};
|
||||
|
||||
function TokenChain() {
|
||||
}
|
||||
|
||||
TokenChain.prototype = {
|
||||
add: function(tokens) {
|
||||
var self = this;
|
||||
tokens.forEach(function(token) {
|
||||
var key = '$' + token;
|
||||
if (!self[key]) {
|
||||
self[key] = [];
|
||||
self[key].processed = 0;
|
||||
}
|
||||
self[key].push(tokens);
|
||||
});
|
||||
},
|
||||
createSorter: function() {
|
||||
var self = this;
|
||||
var sorter = new Sorter();
|
||||
sorter.keys = Object.keys(self).sort(function(j, k) {
|
||||
var m = self[j].length;
|
||||
var n = self[k].length;
|
||||
return m < n ? 1 : m > n ? -1 : j < k ? -1 : j > k ? 1 : 0;
|
||||
}).filter(function(key) {
|
||||
if (self[key].processed < self[key].length) {
|
||||
var token = key.slice(1);
|
||||
var chain = new TokenChain();
|
||||
self[key].forEach(function(tokens) {
|
||||
var index;
|
||||
while ((index = tokens.indexOf(token)) !== -1) {
|
||||
tokens.splice(index, 1);
|
||||
}
|
||||
tokens.forEach(function(token) {
|
||||
self['$' + token].processed++;
|
||||
});
|
||||
chain.add(tokens.slice(0));
|
||||
});
|
||||
sorter[key] = chain.createSorter();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return sorter;
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = TokenChain;
|
31
node_modules/html-minifier-terser/src/utils.js
generated
vendored
Normal file
31
node_modules/html-minifier-terser/src/utils.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
function createMap(values, ignoreCase) {
|
||||
var map = {};
|
||||
values.forEach(function(value) {
|
||||
map[value] = 1;
|
||||
});
|
||||
return ignoreCase ? function(value) {
|
||||
return map[value.toLowerCase()] === 1;
|
||||
} : function(value) {
|
||||
return map[value] === 1;
|
||||
};
|
||||
}
|
||||
|
||||
async function replaceAsync(str, regex, asyncFn) {
|
||||
const promises = [];
|
||||
str.replace(regex, (match, ...args) => {
|
||||
const promise = asyncFn(match, ...args);
|
||||
promises.push(promise);
|
||||
});
|
||||
const data = await Promise.all(promises);
|
||||
return str.replace(regex, () => data.shift());
|
||||
}
|
||||
|
||||
|
||||
exports.createMap = createMap;
|
||||
exports.createMapFromString = function(values, ignoreCase) {
|
||||
return createMap(values.split(/,/), ignoreCase);
|
||||
};
|
||||
|
||||
exports.replaceAsync = replaceAsync;
|
Reference in New Issue
Block a user