html-minifier 0.6.9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/LICENSE +1 -1
- package/README.md +42 -13
- package/cli.js +120 -93
- package/dist/htmlminifier.js +135 -50
- package/dist/htmlminifier.min.js +4 -4
- package/package.json +21 -22
- package/src/htmllint.js +168 -0
- package/src/htmlminifier.js +834 -0
- package/src/htmlparser.js +560 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [0.7.0](https://github.com/kangax/html-minifier/compare/v0.6.9...v0.7.0)
|
|
2
|
+
|
|
3
|
+
* TODO
|
|
4
|
+
|
|
5
|
+
## [0.6.9](https://github.com/kangax/html-minifier/compare/v0.6.8...v0.6.9)
|
|
6
|
+
|
|
7
|
+
* TODO
|
|
8
|
+
|
|
9
|
+
## [0.6.8](https://github.com/kangax/html-minifier/compare/v0.6.7...v0.6.8)
|
|
10
|
+
|
|
11
|
+
* TODO
|
|
12
|
+
|
|
1
13
|
## [0.6.7](https://github.com/kangax/html-minifier/compare/v0.6.6...v0.6.7)
|
|
2
14
|
|
|
3
15
|
* Preserve empty script with `src` attribute
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
[](https://www.npmjs.com/package/html-minifier)
|
|
2
|
+
[](https://travis-ci.org/kangax/html-minifier)
|
|
3
|
+
[](https://david-dm.org/kangax/html-minifier)
|
|
4
|
+
[](https://david-dm.org/kangax/html-minifier#info=devDependencies)
|
|
5
5
|
|
|
6
|
-
[HTMLMinifier](http://kangax.github.io/html-minifier/) is a highly
|
|
6
|
+
[HTMLMinifier](http://kangax.github.io/html-minifier/) is a highly **configurable**, **well-tested**, Javascript-based HTML minifier, with lint-like capabilities.
|
|
7
7
|
|
|
8
8
|
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).
|
|
9
9
|
|
|
@@ -13,13 +13,13 @@ Also see corresponding [Ruby wrapper](https://github.com/stereobooster/html_mini
|
|
|
13
13
|
|
|
14
14
|
How does HTMLMinifier compare to [another solution](http://www.willpeavy.com/minifier/) — HTML Minifier from Will Peavy (1st result in [google search for "html minifier"](https://www.google.com/#q=html+minifier)) as well as htmlcompressor.com?
|
|
15
15
|
|
|
16
|
-
| Site
|
|
16
|
+
| Site | Original size _(KB)_ | HTMLMinifier _(KB)_ | Will Peavy _(KB)_ | htmlcompressor.com _(KB)_ |
|
|
17
17
|
| --------------------------------------------------------------------------- |:-----------:| ----------------:| ------------:| ----------------:|
|
|
18
18
|
| [HTMLMinifier page](https://github.com/kangax/html-minifier) | 48.8 | <b>37.3</b> | 43.3 | 41.9 |
|
|
19
19
|
| [ES6 table](http://kangax.github.io/es5-compat-table/es6/) | 117.9 | <b>79.9</b> | 92 | 91.9 |
|
|
20
20
|
| [MSN](http://msn.com) | 156.6 | <b>133</b> | 145 | 138.3 |
|
|
21
21
|
| [Stackoverflow](http://stackoverflow.com) | 200.4 | <b>159.5</b> | 168.3 | 163.3 |
|
|
22
|
-
| [Amazon](http://amazon.com) | 245.9 | <b>206.3</b> | 225 |
|
|
22
|
+
| [Amazon](http://amazon.com) | 245.9 | <b>206.3</b> | 225 | 218.5 |
|
|
23
23
|
| [Wikipedia](http://en.wikipedia.org/wiki/President_of_the_United_States) | 401.4 | <b>380.6</b> | 396.3 | n/a |
|
|
24
24
|
| [Eloquent Javascript](http://eloquentjavascript.net/print.html) | 869.5 | <b>830</b> | 872 | n/a |
|
|
25
25
|
|
|
@@ -34,10 +34,11 @@ How does HTMLMinifier compare to [another solution](http://www.willpeavy.com/min
|
|
|
34
34
|
| `removeCDATASectionsFromCDATA` | [Remove CDATA sections from script and style elements](http://perfectionkills.com/experimenting-with-html-minifier/#remove_cdata_sections) | `false` |
|
|
35
35
|
| `collapseWhitespace` | [Collapse white space that contributes to text nodes in a document tree.](http://perfectionkills.com/experimenting-with-html-minifier/#collapse_whitespace) | `false` |
|
|
36
36
|
| `conservativeCollapse` | Always collapse to 1 space (never remove it entirely). Must be used in conjunction with `collapseWhitespace=true` | `false` |
|
|
37
|
-
| `preserveLineBreaks`
|
|
37
|
+
| `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` |
|
|
38
38
|
| `collapseBooleanAttributes` | [Omit attribute values from boolean attributes](http://perfectionkills.com/experimenting-with-html-minifier/#collapse_boolean_attributes) | `false` |
|
|
39
39
|
| `removeAttributeQuotes` | [Remove quotes around attributes when possible.](http://perfectionkills.com/experimenting-with-html-minifier/#remove_attribute_quotes) | `false` |
|
|
40
40
|
| `removeRedundantAttributes` | [Remove attributes when value matches default.](http://perfectionkills.com/experimenting-with-html-minifier/#remove_redundant_attributes) | `false` |
|
|
41
|
+
| `preventAttributesEscaping` | Prevents the escaping of the values of attributes. | `false` |
|
|
41
42
|
| `useShortDoctype` | [Replaces the doctype with the short (HTML5) doctype](http://perfectionkills.com/experimenting-with-html-minifier/#use_short_doctype) | `false` |
|
|
42
43
|
| `removeEmptyAttributes` | [Remove all attributes with whitespace-only values](http://perfectionkills.com/experimenting-with-html-minifier/#remove_empty_or_blank_attributes) | `false` |
|
|
43
44
|
| `removeScriptTypeAttributes` | Remove `type="text/javascript"` from `script` tags. Other `type` attribute values are left intact. | `false` |
|
|
@@ -47,7 +48,7 @@ How does HTMLMinifier compare to [another solution](http://www.willpeavy.com/min
|
|
|
47
48
|
| `removeEmptyElements` | [Remove all elements with empty contents](http://perfectionkills.com/experimenting-with-html-minifier/#remove_empty_elements) | `false` |
|
|
48
49
|
| `lint` | [Toggle linting](http://perfectionkills.com/experimenting-with-html-minifier/#validate_input_through_html_lint) | `false` |
|
|
49
50
|
| `keepClosingSlash` | Keep the trailing slash on singleton elements | `false` |
|
|
50
|
-
| `caseSensitive` | Treat attributes in case sensitive manner (useful for
|
|
51
|
+
| `caseSensitive` | Treat attributes in case sensitive manner (useful for custom HTML tags.) | `false` |
|
|
51
52
|
| `minifyJS` | Minify Javascript in script elements and on* attributes (uses [UglifyJS](https://github.com/mishoo/UglifyJS2)) | `false` (could be `true`, `false`, `Object` (options)) |
|
|
52
53
|
| `minifyCSS` | Minify CSS in style elements and style attributes (uses [clean-css](https://github.com/GoalSmashers/clean-css)) | `false` (could be `true`, `false`, `Object` (options)) |
|
|
53
54
|
| `minifyURLs` | Minify URLs in various attributes (uses [relateurl](https://github.com/stevenvachon/relateurl)) | `false` (could be `Object` (options)) |
|
|
@@ -57,9 +58,37 @@ How does HTMLMinifier compare to [another solution](http://www.willpeavy.com/min
|
|
|
57
58
|
| `customAttrAssign` | Arrays of regex'es that allow to support custom attribute assign expressions (e.g. `'<div flex?="{{mode != cover}}"></div>'`) | `[ ]` |
|
|
58
59
|
| `customAttrSurround` | Arrays of regex'es that allow to support custom attribute surround expressions (e.g. `<input {{#if value}}checked="checked"{{/if}}>`) | `[ ]` |
|
|
59
60
|
| `customAttrCollapse` | Regex that specifies custom attribute to strip newlines from (e.g. `/ng\-class/`) | |
|
|
61
|
+
| `quoteCharacter` | Type of quote to use for attribute values (' or ") | " |
|
|
60
62
|
|
|
63
|
+
## Special cases
|
|
61
64
|
|
|
62
|
-
|
|
65
|
+
### Ignoring chunks of markup.
|
|
66
|
+
|
|
67
|
+
If you have chunks of markup you would like preserved, you can wrap them `<!-- htmlmin:ignore -->`.
|
|
68
|
+
|
|
69
|
+
### Preserving SVG tags
|
|
70
|
+
|
|
71
|
+
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.
|
|
72
|
+
|
|
73
|
+
### Working with invalid markup
|
|
74
|
+
|
|
75
|
+
HTMLMinifier **can't work with invalid or partial chunks of markup**. This is because it parses markup into a tree struture, then modifies it (removing anything that was specified for removal, ignoring anything that was specified to be ingored, etc.), then it creates a markup out of that tree and returns it.
|
|
76
|
+
|
|
77
|
+
Input markup (e.g. `<p id="">foo`)
|
|
78
|
+
|
|
79
|
+
↓
|
|
80
|
+
|
|
81
|
+
Internal representation of markup in a form of tree (e.g. `{tag: "p", attr: "id", children: ["foo"] }`)
|
|
82
|
+
|
|
83
|
+
↓
|
|
84
|
+
|
|
85
|
+
Transformation of internal representation (e.g. removal of "id" attribute)
|
|
86
|
+
|
|
87
|
+
↓
|
|
88
|
+
|
|
89
|
+
Output of resulting markup (e.g. `<p>foo</p>`)
|
|
90
|
+
|
|
91
|
+
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.
|
|
63
92
|
|
|
64
93
|
## Installation Instructions
|
|
65
94
|
|
|
@@ -84,7 +113,7 @@ npm link .
|
|
|
84
113
|
|
|
85
114
|
For command line usage please see `html-minifier --help`
|
|
86
115
|
|
|
87
|
-
|
|
116
|
+
### Node.js
|
|
88
117
|
|
|
89
118
|
```js
|
|
90
119
|
var minify = require('html-minifier').minify;
|
|
@@ -94,8 +123,8 @@ var result = minify('<p title="blah" id="moo">foo</p>', {
|
|
|
94
123
|
result; // '<p title=blah id=moo>foo</p>'
|
|
95
124
|
```
|
|
96
125
|
|
|
97
|
-
Running benchmarks
|
|
98
|
-
|
|
126
|
+
## Running benchmarks
|
|
127
|
+
|
|
99
128
|
Benchmarks for minified HTML:
|
|
100
129
|
```
|
|
101
130
|
node benchmark.js
|
package/cli.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* The MIT License (MIT)
|
|
6
6
|
*
|
|
7
|
-
* Copyright (c) 2014 Zoltan Frombach
|
|
7
|
+
* Copyright (c) 2014-2015 Zoltan Frombach
|
|
8
8
|
*
|
|
9
9
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
10
10
|
* this software and associated documentation files (the "Software"), to deal in
|
|
@@ -25,15 +25,19 @@
|
|
|
25
25
|
*
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
|
+
/* globals JSON:true */
|
|
29
|
+
|
|
28
30
|
'use strict';
|
|
29
31
|
|
|
30
32
|
var cli = require('cli');
|
|
33
|
+
var concat = require('concat-stream');
|
|
31
34
|
var changeCase = require('change-case');
|
|
32
35
|
var path = require('path');
|
|
33
36
|
var fs = require('fs');
|
|
34
37
|
var appName = require('./package.json').name;
|
|
35
38
|
var appVersion = require('./package.json').version;
|
|
36
39
|
var minify = require('./dist/htmlminifier.min.js').minify;
|
|
40
|
+
var HTMLLint = require('./dist/htmlminifier.min.js').HTMLLint;
|
|
37
41
|
var minifyOptions = {};
|
|
38
42
|
var input = null;
|
|
39
43
|
var output = null;
|
|
@@ -62,9 +66,13 @@ var mainOptions = {
|
|
|
62
66
|
collapseBooleanAttributes: [[false, 'Omit attribute values from boolean attributes']],
|
|
63
67
|
removeAttributeQuotes: [[false, 'Remove quotes around attributes when possible.']],
|
|
64
68
|
removeRedundantAttributes: [[false, 'Remove attributes when value matches default.']],
|
|
69
|
+
preventAttributesEscaping: [[false, 'Prevents the escaping of the values of attributes.']],
|
|
65
70
|
useShortDoctype: [[false, 'Replaces the doctype with the short (HTML5) doctype']],
|
|
66
71
|
removeEmptyAttributes: [[false, 'Remove all attributes with whitespace-only values']],
|
|
72
|
+
removeScriptTypeAttributes: [[false, 'Remove type="text/javascript" from script tags. Other type attribute values are left intact.']],
|
|
73
|
+
removeStyleLinkTypeAttributes: [[false, 'Remove type="text/css" from style and link tags. Other type attribute values are left intact.']],
|
|
67
74
|
removeOptionalTags: [[false, 'Remove unrequired tags']],
|
|
75
|
+
removeIgnored: [[false, 'Remove all tags starting and ending with <%, %>, <?, ?>']],
|
|
68
76
|
removeEmptyElements: [[false, 'Remove all elements with empty contents']],
|
|
69
77
|
lint: [[false, 'Toggle linting']],
|
|
70
78
|
keepClosingSlash: [[false, 'Keep the trailing slash on singleton elements']],
|
|
@@ -72,9 +80,12 @@ var mainOptions = {
|
|
|
72
80
|
minifyJS: [[false, 'Minify Javascript in script elements and on* attributes (uses UglifyJS)']],
|
|
73
81
|
minifyCSS: [[false, 'Minify CSS in style elements and style attributes (uses clean-css)']],
|
|
74
82
|
minifyURLs: [[false, 'Minify URLs in various attributes (uses relateurl)']],
|
|
75
|
-
ignoreCustomComments: [[false, 'Array of regex\'es that allow to ignore certain comments, when matched', 'string'], 'json'],
|
|
76
|
-
processScripts: [[false, 'Array of strings corresponding to types of script elements to process through minifier (e.g. "text/ng-template", "text/x-handlebars-template", etc.)', 'string'], 'json'],
|
|
77
|
-
maxLineLength: [[false, 'Max line length', 'number'], true]
|
|
83
|
+
ignoreCustomComments: [[false, 'Array of regex\'es that allow to ignore certain comments, when matched', 'string'], 'json-regex'],
|
|
84
|
+
processScripts: [[false, 'Array of strings corresponding to types of script elements to process through minifier (e.g. "text/ng-template", "text/x-handlebars-template", etc.)', 'string'], 'json-regex'],
|
|
85
|
+
maxLineLength: [[false, 'Max line length', 'number'], true],
|
|
86
|
+
customAttrAssign: [[false, 'Arrays of regex\'es that allow to support custom attribute assign expressions (e.g. \'<div flex?="{{mode != cover}}"></div>\')', 'string'], 'json-regex'],
|
|
87
|
+
customAttrSurround: [[false, 'Arrays of regex\'es that allow to support custom attribute surround expressions (e.g. <input {{#if value}}checked="checked"{{/if}}>)', 'string'], 'json-regex'],
|
|
88
|
+
customAttrCollapse: [[false, 'Regex that specifies custom attribute to strip newlines from (e.g. /ng\-class/)', 'string'], 'string-regex']
|
|
78
89
|
};
|
|
79
90
|
|
|
80
91
|
var cliOptions = {
|
|
@@ -92,8 +103,94 @@ cli.parse(cliOptions);
|
|
|
92
103
|
|
|
93
104
|
cli.main(function(args, options) {
|
|
94
105
|
|
|
106
|
+
function stringToRegExp(value) {
|
|
107
|
+
// JSON does not support regexes, so, e.g., JSON.parse() will not create
|
|
108
|
+
// a RegExp from the JSON value `[ "/matchString/" ]`, which is
|
|
109
|
+
// technically just an array containing a string that begins and end with
|
|
110
|
+
// a forward slash. To get a RegExp from a JSON string, it must be
|
|
111
|
+
// constructed explicitly in JavaScript.
|
|
112
|
+
//
|
|
113
|
+
// The likelihood of actually wanting to match text that is enclosed in
|
|
114
|
+
// forward slashes is probably quite rare, so if forward slashes were
|
|
115
|
+
// included in an argument that requires a regex, the user most likely
|
|
116
|
+
// thought they were part of the syntax for specifying a regex.
|
|
117
|
+
//
|
|
118
|
+
// In the unlikely case that forward slashes are indeed desired in the
|
|
119
|
+
// search string, the user would need to enclose the expression in a
|
|
120
|
+
// second set of slashes:
|
|
121
|
+
//
|
|
122
|
+
// --customAttrSrround "[\"//matchString//\"]"
|
|
123
|
+
//
|
|
124
|
+
if (value) {
|
|
125
|
+
var stripSlashes = /^\/(.*)\/$/.exec(value);
|
|
126
|
+
if (stripSlashes) {
|
|
127
|
+
value = stripSlashes[1];
|
|
128
|
+
}
|
|
129
|
+
return new RegExp(value);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function parseJSONOption(value, options) {
|
|
134
|
+
var opts = options || {};
|
|
135
|
+
if (value !== null) {
|
|
136
|
+
var jsonArray;
|
|
137
|
+
try {
|
|
138
|
+
jsonArray = JSON.parse(value);
|
|
139
|
+
if (opts.regexArray) {
|
|
140
|
+
jsonArray = jsonArray.map(function (regexString) {
|
|
141
|
+
return stringToRegExp(regexString);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
cli.fatal('Could not parse JSON value \'' + value + '\'');
|
|
147
|
+
}
|
|
148
|
+
if (jsonArray instanceof Array) {
|
|
149
|
+
return jsonArray;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
return [value];
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function runMinify(original) {
|
|
158
|
+
var status = 0;
|
|
159
|
+
var minified = null;
|
|
160
|
+
try {
|
|
161
|
+
minified = minify(original, minifyOptions);
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
status = 3;
|
|
165
|
+
cli.error('Minification error');
|
|
166
|
+
process.stderr.write(e);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (minifyOptions.lint) {
|
|
170
|
+
minifyOptions.lint.populate();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (minified !== null) {
|
|
174
|
+
// Write the output
|
|
175
|
+
try {
|
|
176
|
+
if (output !== null) {
|
|
177
|
+
fs.writeFileSync(path.resolve(output), minified);
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
process.stdout.write(minified);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch (e) {
|
|
184
|
+
status = 4;
|
|
185
|
+
cli.error('Cannot write to output');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
cli.exit(status);
|
|
190
|
+
}
|
|
191
|
+
|
|
95
192
|
if (options.version) {
|
|
96
|
-
|
|
193
|
+
cli.output(appName + ' v' + appVersion);
|
|
97
194
|
cli.exit(0);
|
|
98
195
|
}
|
|
99
196
|
|
|
@@ -105,8 +202,7 @@ cli.main(function(args, options) {
|
|
|
105
202
|
}
|
|
106
203
|
}
|
|
107
204
|
catch (e) {
|
|
108
|
-
|
|
109
|
-
cli.exit(1);
|
|
205
|
+
cli.fatal('Cannot read the specified config file');
|
|
110
206
|
}
|
|
111
207
|
}
|
|
112
208
|
|
|
@@ -118,6 +214,12 @@ cli.main(function(args, options) {
|
|
|
118
214
|
case 'json':
|
|
119
215
|
minifyOptions[key] = parseJSONOption(value);
|
|
120
216
|
break;
|
|
217
|
+
case 'json-regex':
|
|
218
|
+
minifyOptions[key] = parseJSONOption(value, { regexArray: true });
|
|
219
|
+
break;
|
|
220
|
+
case 'string-regex':
|
|
221
|
+
minifyOptions[key] = stringToRegExp(value);
|
|
222
|
+
break;
|
|
121
223
|
case true:
|
|
122
224
|
minifyOptions[key] = value;
|
|
123
225
|
break;
|
|
@@ -127,6 +229,10 @@ cli.main(function(args, options) {
|
|
|
127
229
|
}
|
|
128
230
|
});
|
|
129
231
|
|
|
232
|
+
if (minifyOptions.lint === true) {
|
|
233
|
+
minifyOptions.lint = new HTMLLint();
|
|
234
|
+
}
|
|
235
|
+
|
|
130
236
|
if (args.length) {
|
|
131
237
|
input = args;
|
|
132
238
|
}
|
|
@@ -135,104 +241,25 @@ cli.main(function(args, options) {
|
|
|
135
241
|
output = options.output;
|
|
136
242
|
}
|
|
137
243
|
|
|
138
|
-
var original = '';
|
|
139
|
-
var status = 0;
|
|
140
|
-
|
|
141
244
|
if (input !== null) { // Minifying one or more files specified on the CMD line
|
|
142
245
|
|
|
246
|
+
var original = '';
|
|
247
|
+
|
|
143
248
|
input.forEach(function(afile) {
|
|
144
249
|
try {
|
|
145
250
|
original += fs.readFileSync(afile, 'utf8');
|
|
146
251
|
}
|
|
147
252
|
catch (e) {
|
|
148
|
-
|
|
149
|
-
|
|
253
|
+
cli.error('Cannot read file ' + afile);
|
|
254
|
+
cli.exit(2);
|
|
150
255
|
}
|
|
151
256
|
});
|
|
152
257
|
|
|
153
|
-
|
|
154
|
-
else { // Minifying input coming from STDIN
|
|
155
|
-
|
|
156
|
-
var BUFSIZE = 4096;
|
|
157
|
-
var buf = new Buffer(BUFSIZE);
|
|
158
|
-
var bytesRead;
|
|
159
|
-
|
|
160
|
-
while (true) { // Loop as long as stdin input is available.
|
|
161
|
-
bytesRead = 0;
|
|
162
|
-
try {
|
|
163
|
-
bytesRead = fs.readSync(process.stdin.fd, buf, 0, BUFSIZE);
|
|
164
|
-
}
|
|
165
|
-
catch (e) {
|
|
166
|
-
if (e.code === 'EAGAIN') { // 'resource temporarily unavailable'
|
|
167
|
-
// Happens on OS X 10.8.3 (not Windows 7!), if there's no
|
|
168
|
-
// stdin input - typically when invoking a script without any
|
|
169
|
-
// input (for interactive stdin input).
|
|
170
|
-
// If you were to just continue, you'd create a tight loop.
|
|
171
|
-
process.stderr.write('ERROR: interactive stdin input not supported');
|
|
172
|
-
cli.exit(2);
|
|
173
|
-
}
|
|
174
|
-
else if (e.code === 'EOF') {
|
|
175
|
-
// Happens on Windows 7, but not OS X 10.8.3:
|
|
176
|
-
// simply signals the end of *piped* stdin input.
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
throw e; // unexpected exception
|
|
180
|
-
}
|
|
181
|
-
if (bytesRead === 0) {
|
|
182
|
-
// No more stdin input available.
|
|
183
|
-
// OS X 10.8.3: regardless of input method, this is how the end
|
|
184
|
-
// of input is signaled.
|
|
185
|
-
// Windows 7: this is how the end of input is signaled for
|
|
186
|
-
// *interactive* stdin input.
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
original += buf.toString('utf8', 0, bytesRead);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function parseJSONOption(value) {
|
|
195
|
-
if (value !== null) {
|
|
196
|
-
var jsonArray;
|
|
197
|
-
try {
|
|
198
|
-
jsonArray = JSON.parse(value);
|
|
199
|
-
}
|
|
200
|
-
catch (e) {}
|
|
201
|
-
if (jsonArray instanceof Array) {
|
|
202
|
-
return jsonArray;
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
return [value];
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
258
|
+
runMinify(original);
|
|
209
259
|
|
|
210
|
-
// Run minify
|
|
211
|
-
var minified = null;
|
|
212
|
-
try {
|
|
213
|
-
minified = minify(original, minifyOptions);
|
|
214
|
-
}
|
|
215
|
-
catch (e) {
|
|
216
|
-
status = 3;
|
|
217
|
-
process.stderr.write('Error: Minification error');
|
|
218
260
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// Write the output
|
|
222
|
-
try {
|
|
223
|
-
if (output !== null) {
|
|
224
|
-
fs.writeFileSync(path.resolve(output), minified);
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
process.stdout.write(minified);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
catch (e) {
|
|
231
|
-
status = 4;
|
|
232
|
-
process.stderr.write('Error: Cannot write to output');
|
|
233
|
-
}
|
|
261
|
+
else { // Minifying input coming from STDIN
|
|
262
|
+
process.stdin.pipe(concat({ encoding: 'string' }, runMinify));
|
|
234
263
|
}
|
|
235
264
|
|
|
236
|
-
cli.exit(status);
|
|
237
|
-
|
|
238
265
|
});
|