html-minifier 1.3.1 → 1.4.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/README.md CHANGED
@@ -21,24 +21,23 @@ How does HTMLMinifier compare to other solutions — [HTML Minifier from Will Pe
21
21
  | Site | Original size *(KB)* | HTMLMinifier | minimize | Will Peavy | htmlcompressor.com |
22
22
  | --------------------------------------------------------------------------- |:--------------------:| ------------:| --------:| ----------:| ------------------:|
23
23
  | [HTMLMinifier page](https://github.com/kangax/html-minifier) | 49 | **37** | 42 | 44 | 43 |
24
- | [NBC](http://www.nbc.com/) | 91 | **74** | 84 | 86 | 85 |
25
- | [ES6 table](http://kangax.github.io/es5-compat-table/es6/) | 118 | **80** | 93 | 95 | 94 |
24
+ | [NBC](http://www.nbc.com/) | 91 | **74** | 84 | 85 | 85 |
25
+ | [ES6 table](http://kangax.github.io/es5-compat-table/es6/) | 118 | **80** | 93 | 93 | 94 |
26
26
  | [New York Times](http://www.nytimes.com/) | 131 | **101** | 122 | 125 | 120 |
27
27
  | [Google](https://www.google.com/) | 133 | **128** | 132 | 135 | 131 |
28
28
  | [MSN](http://www.msn.com/) | 157 | **130** | 138 | 145 | 138 |
29
- | [Stackoverflow](http://stackoverflow.com/) | 200 | **159** | 165 | 174 | 166 |
30
- | [Amazon](http://www.amazon.com/) | 246 | **204** | 234 | 230 | 219 |
29
+ | [Stackoverflow](http://stackoverflow.com/) | 200 | **159** | 165 | 173 | 166 |
30
+ | [Amazon](http://www.amazon.com/) | 246 | **203** | 234 | 230 | 219 |
31
+ | [Bootstrap CSS](http://getbootstrap.com/css/) | 277 | **268** | 274 | 232 | 277 |
31
32
  | [Wikipedia](https://en.wikipedia.org/wiki/President_of_the_United_States) | 401 | **367** | 388 | 400 | n/a |
32
33
  | [Eloquent Javascript](http://eloquentjavascript.net/1st_edition/print.html) | 870 | **827** | 840 | 864 | n/a |
33
- | [ES6 draft](https://tc39.github.io/ecma262/) | 3678 | **2990** | 3079 | 3204 | n/a |
34
+ | [ES6 draft](https://tc39.github.io/ecma262/) | 3678 | **2991** | 3079 | 3183 | n/a |
34
35
 
35
36
  ## Options Quick Reference
36
37
 
37
38
  | Option | Description | Default |
38
39
  |--------------------------------|-----------------|---------|
39
40
  | `removeComments` | [Strip HTML comments](http://perfectionkills.com/experimenting-with-html-minifier/#remove_comments) | `false` |
40
- | `removeCommentsFromCDATA` | [Strip HTML comments from scripts and styles](http://perfectionkills.com/experimenting-with-html-minifier/#remove_comments_from_scripts_and_styles) | `false` |
41
- | `removeCDATASectionsFromCDATA` | [Remove CDATA sections from script and style elements](http://perfectionkills.com/experimenting-with-html-minifier/#remove_cdata_sections) | `false` |
42
41
  | `collapseWhitespace` | [Collapse white space that contributes to text nodes in a document tree.](http://perfectionkills.com/experimenting-with-html-minifier/#collapse_whitespace) | `false` |
43
42
  | `conservativeCollapse` | Always collapse to 1 space (never remove it entirely). Must be used in conjunction with `collapseWhitespace=true` | `false` |
44
43
  | `collapseInlineTagWhitespace` | Don't leave any spaces between `display:inline;` elements when collapsing. Must be used in conjunction with `collapseWhitespace=true` | `false` |
package/cli.js CHANGED
@@ -34,11 +34,10 @@ var path = require('path');
34
34
  var fs = require('fs');
35
35
  var appName = require('./package.json').name;
36
36
  var appVersion = require('./package.json').version;
37
- var minify = require('./dist/htmlminifier.min.js').minify;
38
- var HTMLLint = require('./dist/htmlminifier.min.js').HTMLLint;
37
+ var minify = require('.').minify;
38
+ var HTMLLint = require('./src/htmllint').HTMLLint;
39
39
  var minifyOptions = {};
40
- var input = null;
41
- var output = null;
40
+ var output;
42
41
 
43
42
  cli.width = 100;
44
43
  cli.option_width = 40;
@@ -55,38 +54,40 @@ usage += ' on the command line you must escape those such as --ignore-custom-
55
54
  cli.setUsage(usage);
56
55
 
57
56
  var mainOptions = {
58
- removeComments: [[false, 'Strip HTML comments']],
59
- removeCommentsFromCDATA: [[false, 'Strip HTML comments from scripts and styles']],
60
- removeCDATASectionsFromCDATA: [[false, 'Remove CDATA sections from script and style elements']],
57
+ caseSensitive: [[false, 'Treat attributes in case sensitive manner (useful for SVG; e.g. viewBox)']],
58
+ collapseBooleanAttributes: [[false, 'Omit attribute values from boolean attributes']],
59
+ collapseInlineTagWhitespace: [[false, 'Collapse white space around inline tag']],
61
60
  collapseWhitespace: [[false, 'Collapse white space that contributes to text nodes in a document tree.']],
62
61
  conservativeCollapse: [[false, 'Always collapse to 1 space (never remove it entirely)']],
62
+ customAttrAssign: [[false, 'Arrays of regex\'es that allow to support custom attribute assign expressions (e.g. \'<div flex?="{{mode != cover}}"></div>\')', 'string'], 'json-regex'],
63
+ customAttrCollapse: [[false, 'Regex that specifies custom attribute to strip newlines from (e.g. /ng\-class/)', 'string'], 'string-regex'],
64
+ 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'],
65
+ customEventAttributes: [[false, 'Arrays of regex\'es that allow to support custom event attributes for minifyJS (e.g. ng-click)', 'string'], 'json-regex'],
66
+ html5: [[false, 'Parse input according to HTML5 specifications']],
67
+ ignoreCustomComments: [[false, 'Array of regex\'es that allow to ignore certain comments, when matched', 'string'], 'json-regex'],
68
+ ignoreCustomFragments: [[false, 'Array of regex\'es that allow to ignore certain fragments, when matched (e.g. <?php ... ?>, {{ ... }})', 'string'], 'json-regex'],
69
+ includeAutoGeneratedTags: [[false, 'Insert tags generated by HTML parser'], true],
70
+ keepClosingSlash: [[false, 'Keep the trailing slash on singleton elements']],
71
+ lint: [[false, 'Toggle linting']],
72
+ maxLineLength: [[false, 'Max line length', 'number'], true],
73
+ minifyCSS: [[false, 'Minify CSS in style elements and style attributes (uses clean-css)']],
74
+ minifyJS: [[false, 'Minify Javascript in script elements and on* attributes (uses UglifyJS)']],
75
+ minifyURLs: [[false, 'Minify URLs in various attributes (uses relateurl)', 'string'], 'site-url'],
63
76
  preserveLineBreaks: [[false, 'Always collapse to 1 line break (never remove it entirely) when whitespace between tags include a line break.']],
64
- collapseInlineTagWhitespace: [[false, 'Collapse white space around inline tag']],
65
- collapseBooleanAttributes: [[false, 'Omit attribute values from boolean attributes']],
66
- removeTagWhitespace: [[false, 'Remove space between attributes whenever possible.']],
67
- removeAttributeQuotes: [[false, 'Remove quotes around attributes when possible.']],
68
- removeRedundantAttributes: [[false, 'Remove attributes when value matches default.']],
69
77
  preventAttributesEscaping: [[false, 'Prevents the escaping of the values of attributes.']],
70
- useShortDoctype: [[false, 'Replaces the doctype with the short (HTML5) doctype']],
78
+ processConditionalComments: [[false, 'Process contents of conditional comments through minifier']],
79
+ 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'],
80
+ quoteCharacter: [[false, 'Type of quote to use for attribute values (\' or ")', 'string'], true],
81
+ removeAttributeQuotes: [[false, 'Remove quotes around attributes when possible.']],
82
+ removeComments: [[false, 'Strip HTML comments']],
71
83
  removeEmptyAttributes: [[false, 'Remove all attributes with whitespace-only values']],
84
+ removeEmptyElements: [[false, 'Remove all elements with empty contents']],
85
+ removeOptionalTags: [[false, 'Remove unrequired tags']],
86
+ removeRedundantAttributes: [[false, 'Remove attributes when value matches default.']],
72
87
  removeScriptTypeAttributes: [[false, 'Remove type="text/javascript" from script tags. Other type attribute values are left intact.']],
73
88
  removeStyleLinkTypeAttributes: [[false, 'Remove type="text/css" from style and link tags. Other type attribute values are left intact.']],
74
- removeOptionalTags: [[false, 'Remove unrequired tags']],
75
- removeEmptyElements: [[false, 'Remove all elements with empty contents']],
76
- lint: [[false, 'Toggle linting']],
77
- keepClosingSlash: [[false, 'Keep the trailing slash on singleton elements']],
78
- caseSensitive: [[false, 'Treat attributes in case sensitive manner (useful for SVG; e.g. viewBox)']],
79
- minifyJS: [[false, 'Minify Javascript in script elements and on* attributes (uses UglifyJS)']],
80
- minifyCSS: [[false, 'Minify CSS in style elements and style attributes (uses clean-css)']],
81
- minifyURLs: [[false, 'Minify URLs in various attributes (uses relateurl)', 'string'], 'site-url'],
82
- ignoreCustomComments: [[false, 'Array of regex\'es that allow to ignore certain comments, when matched', 'string'], 'json-regex'],
83
- ignoreCustomFragments: [[false, 'Array of regex\'es that allow to ignore certain fragments, when matched (e.g. <?php ... ?>, {{ ... }})', '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'],
85
- maxLineLength: [[false, 'Max line length', 'number'], true],
86
- customEventAttributes: [[false, 'Arrays of regex\'es that allow to support custom event attributes for minifyJS (e.g. ng-click)', 'string'], 'json-regex'],
87
- customAttrAssign: [[false, 'Arrays of regex\'es that allow to support custom attribute assign expressions (e.g. \'<div flex?="{{mode != cover}}"></div>\')', 'string'], 'json-regex'],
88
- 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'],
89
- customAttrCollapse: [[false, 'Regex that specifies custom attribute to strip newlines from (e.g. /ng\-class/)', 'string'], 'string-regex']
89
+ removeTagWhitespace: [[false, 'Remove space between attributes whenever possible.']],
90
+ useShortDoctype: [[false, 'Replaces the doctype with the short (HTML5) doctype']]
90
91
  };
91
92
 
92
93
  var cliOptions = {
@@ -133,27 +134,19 @@ cli.main(function(args, options) {
133
134
  }
134
135
  }
135
136
 
136
- function parseJSONOption(value, options) {
137
- var opts = options || {};
137
+ function parseJSONOption(value, regexArray) {
138
138
  if (value !== null) {
139
139
  var jsonArray;
140
140
  try {
141
141
  jsonArray = JSON.parse(value);
142
- if (opts.regexArray) {
143
- jsonArray = jsonArray.map(function (regexString) {
144
- return stringToRegExp(regexString);
145
- });
142
+ if (regexArray) {
143
+ jsonArray = jsonArray.map(stringToRegExp);
146
144
  }
147
145
  }
148
146
  catch (e) {
149
147
  cli.fatal('Could not parse JSON value \'' + value + '\'');
150
148
  }
151
- if (jsonArray instanceof Array) {
152
- return jsonArray;
153
- }
154
- else {
155
- return [value];
156
- }
149
+ return Array.isArray(jsonArray) ? jsonArray : [value];
157
150
  }
158
151
  }
159
152
 
@@ -175,19 +168,17 @@ cli.main(function(args, options) {
175
168
 
176
169
  if (minified !== null) {
177
170
  // Write the output
178
- try {
179
- // eslint-disable-next-line eqeqeq
180
- if (output != null) {
171
+ if (output) {
172
+ try {
181
173
  fs.writeFileSync(path.resolve(output), minified);
182
174
  }
183
- else {
184
- process.stdout.write(minified);
175
+ catch (e) {
176
+ status = 4;
177
+ cli.error('Cannot write to ' + output);
185
178
  }
186
179
  }
187
- catch (e) {
188
- status = 4;
189
- console.log(output);
190
- cli.error('Cannot write to output');
180
+ else {
181
+ process.stdout.write(minified);
191
182
  }
192
183
  }
193
184
 
@@ -235,40 +226,51 @@ cli.main(function(args, options) {
235
226
  }
236
227
 
237
228
  if (options['config-file']) {
238
- var fileOptions;
239
- var fileOptionsPath = path.resolve(options['config-file']);
229
+ var configPath = path.resolve(options['config-file']);
240
230
  try {
241
- fileOptions = fs.readFileSync(fileOptionsPath, { encoding: 'utf8' });
242
- }
243
- catch (e) {
244
- cli.fatal('The specified config file doesn’t exist or is unreadable:\n' + fileOptionsPath);
245
- }
246
- try {
247
- fileOptions = JSON.parse(fileOptions);
231
+ var configData;
232
+ try {
233
+ configData = fs.readFileSync(configPath, { encoding: 'utf8' });
234
+ }
235
+ catch (e) {
236
+ cli.fatal('The specified config file doesn’t exist or is unreadable:\n' + configPath);
237
+ }
238
+ configData = JSON.parse(configData);
239
+ mainOptionKeys.forEach(function(key) {
240
+ var value = configData[key];
241
+ if (value !== undefined) {
242
+ switch (mainOptions[key][1]) {
243
+ case 'json-regex':
244
+ minifyOptions[key] = value.map(stringToRegExp);
245
+ break;
246
+ case 'string-regex':
247
+ minifyOptions[key] = stringToRegExp(value);
248
+ break;
249
+ default:
250
+ minifyOptions[key] = value;
251
+ }
252
+ }
253
+ });
248
254
  }
249
255
  catch (je) {
250
256
  try {
251
- fileOptions = require(fileOptionsPath);
257
+ minifyOptions = require(configPath);
252
258
  }
253
259
  catch (ne) {
254
- cli.fatal('Cannot read the specified config file. \nAs JSON: ' + je.message + '\nAs module: ' + ne.message);
260
+ cli.fatal('Cannot read the specified config file.\nAs JSON: ' + je.message + '\nAs module: ' + ne.message);
255
261
  }
256
262
  }
257
-
258
- if (fileOptions && typeof fileOptions === 'object') {
259
- minifyOptions = fileOptions;
260
- }
261
263
  }
262
264
  mainOptionKeys.forEach(function(key) {
263
265
  var paramKey = changeCase.paramCase(key);
264
266
  var value = options[paramKey];
265
- if (options[paramKey] !== null) {
267
+ if (value !== null) {
266
268
  switch (mainOptions[key][1]) {
267
269
  case 'json':
268
270
  minifyOptions[key] = parseJSONOption(value);
269
271
  break;
270
272
  case 'json-regex':
271
- minifyOptions[key] = parseJSONOption(value, { regexArray: true });
273
+ minifyOptions[key] = parseJSONOption(value, true);
272
274
  break;
273
275
  case 'string-regex':
274
276
  minifyOptions[key] = stringToRegExp(value);
@@ -289,10 +291,6 @@ cli.main(function(args, options) {
289
291
  minifyOptions.lint = new HTMLLint();
290
292
  }
291
293
 
292
- if (args.length) {
293
- input = args;
294
- }
295
-
296
294
  if (options['input-dir'] || options['output-dir']) {
297
295
  var inputDir = options['input-dir'];
298
296
  var outputDir = options['output-dir'];
@@ -330,11 +328,10 @@ cli.main(function(args, options) {
330
328
  output = options.output;
331
329
  }
332
330
 
333
- if (input !== null) { // Minifying one or more files specified on the CMD line
334
-
331
+ if (args.length) { // Minifying one or more files specified on the CMD line
335
332
  var original = '';
336
333
 
337
- input.forEach(function(afile) {
334
+ args.forEach(function(afile) {
338
335
  try {
339
336
  original += fs.readFileSync(afile, 'utf8');
340
337
  }
@@ -345,11 +342,10 @@ cli.main(function(args, options) {
345
342
  });
346
343
 
347
344
  cli.exit(runMinify(original, output));
348
-
349
345
  }
350
346
  else { // Minifying input coming from STDIN
351
347
  process.stdin.pipe(concat({ encoding: 'string' }, function(content) {
352
- runMinify(content, output);
348
+ cli.exit(runMinify(content, output));
353
349
  }));
354
350
  }
355
351
  });