html-minifier 3.5.15 → 3.5.16

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
@@ -22,19 +22,19 @@ How does HTMLMinifier compare to other solutions — [HTML Minifier from Will Pe
22
22
 
23
23
  | Site | Original size *(KB)* | HTMLMinifier | minimize | Will Peavy | htmlcompressor.com |
24
24
  | ---------------------------------------------------------------------------- |:--------------------:| ------------:| --------:| ----------:| ------------------:|
25
- | [Google](https://www.google.com/) | 45 | **42** | 45 | 47 | 45 |
26
- | [Twitter](https://twitter.com/) | 122 | **89** | 115 | 134 | 115 |
27
- | [HTMLMinifier](https://github.com/kangax/html-minifier) | 142 | **110** | 119 | 123 | 118 |
28
- | [New York Times](https://www.nytimes.com/) | 221 | **152** | 172 | 168 | 156 |
29
- | [Stack Overflow](https://stackoverflow.com/) | 247 | **193** | 202 | 210 | 200 |
25
+ | [Google](https://www.google.com/) | 50 | **45** | 49 | 51 | 49 |
26
+ | [Twitter](https://twitter.com/) | 128 | **94** | 121 | 140 | 121 |
27
+ | [HTMLMinifier](https://github.com/kangax/html-minifier) | 144 | **112** | 120 | 125 | 120 |
28
+ | [New York Times](https://www.nytimes.com/) | 212 | **145** | 164 | 159 | 148 |
29
+ | [Stack Overflow](https://stackoverflow.com/) | 249 | **194** | 203 | 212 | 201 |
30
30
  | [Bootstrap CSS](https://getbootstrap.com/docs/3.3/css/) | 272 | **260** | 269 | 229 | 269 |
31
- | [BBC](https://www.bbc.co.uk/) | 283 | **228** | 275 | 278 | 262 |
32
- | [Amazon](https://www.amazon.co.uk/) | 370 | **315** | 356 | 367 | n/a |
33
- | [Wikipedia](https://en.wikipedia.org/wiki/President_of_the_United_States) | 474 | **442** | 458 | 473 | 457 |
34
- | [NBC](https://www.nbc.com/) | 666 | **627** | 663 | 665 | n/a |
31
+ | [BBC](https://www.bbc.co.uk/) | 295 | **237** | 287 | 290 | 272 |
32
+ | [Amazon](https://www.amazon.co.uk/) | 391 | **336** | 377 | 389 | n/a |
33
+ | [Wikipedia](https://en.wikipedia.org/wiki/President_of_the_United_States) | 474 | **442** | 458 | 474 | 458 |
34
+ | [NBC](https://www.nbc.com/) | 689 | **647** | 685 | 687 | n/a |
35
35
  | [Eloquent Javascript](https://eloquentjavascript.net/1st_edition/print.html) | 870 | **815** | 840 | 864 | n/a |
36
- | [ES6 table](https://kangax.github.io/compat-table/es6/) | 4916 | **4189** | 4652 | n/a | n/a |
37
- | [ES6 draft](https://tc39.github.io/ecma262/) | 6099 | **5435** | 5597 | n/a | n/a |
36
+ | [ES6 table](https://kangax.github.io/compat-table/es6/) | 5014 | **4273** | 4745 | n/a | n/a |
37
+ | [ES6 draft](https://tc39.github.io/ecma262/) | 6101 | **5437** | 5599 | n/a | n/a |
38
38
 
39
39
  ## Options Quick Reference
40
40
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "html-minifier",
3
3
  "description": "Highly configurable, well-tested, JavaScript-based HTML minifier.",
4
- "version": "3.5.15",
4
+ "version": "3.5.16",
5
5
  "keywords": [
6
6
  "cli",
7
7
  "compress",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "benchmarkDependencies": {
74
74
  "brotli": "1.3.x",
75
- "chalk": "2.3.x",
75
+ "chalk": "2.4.x",
76
76
  "cli-table": "0.3.x",
77
77
  "lzma": "2.3.x",
78
78
  "minimize": "2.2.x",
@@ -9,10 +9,7 @@ var UglifyJS = require('uglify-js');
9
9
  var utils = require('./utils');
10
10
 
11
11
  function trimWhitespace(str) {
12
- if (typeof str !== 'string') {
13
- return str;
14
- }
15
- return str.replace(/^[ \n\r\t\f]+/, '').replace(/[ \n\r\t\f]+$/, '');
12
+ return str && str.replace(/^[ \n\r\t\f]+/, '').replace(/[ \n\r\t\f]+$/, '');
16
13
  }
17
14
 
18
15
  function collapseWhitespaceAll(str) {
@@ -258,7 +255,7 @@ function isSrcset(attrName, tag) {
258
255
  }
259
256
 
260
257
  function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
261
- if (attrValue && isEventAttribute(attrName, options)) {
258
+ if (isEventAttribute(attrName, options)) {
262
259
  attrValue = trimWhitespace(attrValue).replace(/^javascript:\s*/i, '');
263
260
  return options.minifyJS(attrValue, true);
264
261
  }
@@ -314,7 +311,7 @@ function cleanAttributeValue(tag, attrName, attrValue, options, attrs) {
314
311
  return (+numString).toString();
315
312
  });
316
313
  }
317
- else if (attrValue && options.customAttrCollapse && options.customAttrCollapse.test(attrName)) {
314
+ else if (options.customAttrCollapse && options.customAttrCollapse.test(attrName)) {
318
315
  attrValue = attrValue.replace(/\n+|\r+|\s{2,}/g, '');
319
316
  }
320
317
  else if (tag === 'script' && attrName === 'type') {
@@ -522,7 +519,7 @@ function canTrimWhitespace(tag) {
522
519
  }
523
520
 
524
521
  function normalizeAttr(attr, attrs, tag, options) {
525
- var attrName = options.caseSensitive ? attr.name : attr.name.toLowerCase(),
522
+ var attrName = options.name(attr.name),
526
523
  attrValue = attr.value;
527
524
 
528
525
  if (options.decodeEntities && attrValue) {
@@ -538,7 +535,9 @@ function normalizeAttr(attr, attrs, tag, options) {
538
535
  return;
539
536
  }
540
537
 
541
- attrValue = cleanAttributeValue(tag, attrName, attrValue, options, attrs);
538
+ if (attrValue) {
539
+ attrValue = cleanAttributeValue(tag, attrName, attrValue, options, attrs);
540
+ }
542
541
 
543
542
  if (options.removeEmptyAttributes &&
544
543
  canDeleteEmptyAttribute(tag, attrName, attrValue, options)) {
@@ -615,6 +614,9 @@ function identity(value) {
615
614
 
616
615
  function processOptions(values) {
617
616
  var options = {
617
+ name: function(name) {
618
+ return name.toLowerCase();
619
+ },
618
620
  canCollapseWhitespace: canCollapseWhitespace,
619
621
  canTrimWhitespace: canTrimWhitespace,
620
622
  html5: true,
@@ -631,7 +633,12 @@ function processOptions(values) {
631
633
  };
632
634
  Object.keys(values).forEach(function(key) {
633
635
  var value = values[key];
634
- if (key === 'log') {
636
+ if (key === 'caseSensitive') {
637
+ if (value) {
638
+ options.name = identity;
639
+ }
640
+ }
641
+ else if (key === 'log') {
635
642
  if (typeof value === 'function') {
636
643
  options.log = value;
637
644
  }
@@ -732,7 +739,7 @@ function createSortFns(value, options, uidIgnore, uidAttr) {
732
739
 
733
740
  function attrNames(attrs) {
734
741
  return attrs.map(function(attr) {
735
- return options.caseSensitive ? attr.name : attr.name.toLowerCase();
742
+ return options.name(attr.name);
736
743
  });
737
744
  }
738
745
 
@@ -756,7 +763,7 @@ function createSortFns(value, options, uidIgnore, uidAttr) {
756
763
  }
757
764
  for (var i = 0, len = attrs.length; i < len; i++) {
758
765
  var attr = attrs[i];
759
- if (classChain && (options.caseSensitive ? attr.name : attr.name.toLowerCase()) === 'class') {
766
+ if (classChain && attr.value && options.name(attr.name) === 'class') {
760
767
  classChain.add(trimWhitespace(attr.value).split(/[ \t\n\f\r]+/).filter(shouldSkipUIDs));
761
768
  }
762
769
  else if (options.processScripts && attr.name.toLowerCase() === 'type') {
@@ -946,16 +953,13 @@ function minify(value, options, partialMarkup) {
946
953
  html5: options.html5,
947
954
 
948
955
  start: function(tag, attrs, unary, unarySlash, autoGenerated) {
949
- var lowerTag = tag.toLowerCase();
950
-
951
- if (lowerTag === 'svg') {
956
+ if (tag.toLowerCase() === 'svg') {
952
957
  options = Object.create(options);
953
- options.keepClosingSlash = true;
954
958
  options.caseSensitive = true;
959
+ options.keepClosingSlash = true;
960
+ options.name = identity;
955
961
  }
956
-
957
- tag = options.caseSensitive ? tag : lowerTag;
958
-
962
+ tag = options.name(tag);
959
963
  currentTag = tag;
960
964
  charsPrevTag = tag;
961
965
  if (!inlineTextTags(tag)) {
@@ -1035,11 +1039,10 @@ function minify(value, options, partialMarkup) {
1035
1039
  }
1036
1040
  },
1037
1041
  end: function(tag, attrs, autoGenerated) {
1038
- var lowerTag = tag.toLowerCase();
1039
- if (lowerTag === 'svg') {
1042
+ if (tag.toLowerCase() === 'svg') {
1040
1043
  options = Object.getPrototypeOf(options);
1041
1044
  }
1042
- tag = options.caseSensitive ? tag : lowerTag;
1045
+ tag = options.name(tag);
1043
1046
 
1044
1047
  // check if current tag is in a whitespace stack
1045
1048
  if (options.collapseWhitespace) {
@@ -1271,20 +1274,29 @@ function joinResultSegments(results, options) {
1271
1274
  var str;
1272
1275
  var maxLineLength = options.maxLineLength;
1273
1276
  if (maxLineLength) {
1274
- var token;
1275
- var lines = [];
1276
- var line = '';
1277
- for (var i = 0, len = results.length; i < len; i++) {
1278
- token = results[i];
1279
- if (line.length + token.length < maxLineLength) {
1280
- line += token;
1277
+ var line = '', lines = [];
1278
+ while (results.length) {
1279
+ var len = line.length;
1280
+ var end = results[0].indexOf('\n');
1281
+ if (end < 0) {
1282
+ line += results.shift();
1281
1283
  }
1282
1284
  else {
1283
- lines.push(line.replace(/^\n/, ''));
1284
- line = token;
1285
+ line += results[0].slice(0, end);
1286
+ results[0] = results[0].slice(end + 1);
1285
1287
  }
1288
+ if (len > 0 && line.length >= maxLineLength) {
1289
+ lines.push(line.slice(0, len));
1290
+ line = line.slice(len);
1291
+ }
1292
+ else if (end >= 0) {
1293
+ lines.push(line);
1294
+ line = '';
1295
+ }
1296
+ }
1297
+ if (line) {
1298
+ lines.push(line);
1286
1299
  }
1287
- lines.push(line);
1288
1300
 
1289
1301
  str = lines.join('\n');
1290
1302
  }
package/src/htmlparser.js CHANGED
@@ -267,12 +267,36 @@ function HTMLParser(html, handler) {
267
267
  }
268
268
  }
269
269
 
270
+ function closeIfFound(tagName) {
271
+ if (findTag(tagName) >= 0) {
272
+ parseEndTag('', tagName);
273
+ return true;
274
+ }
275
+ }
276
+
270
277
  function handleStartTag(match) {
271
278
  var tagName = match.tagName;
272
279
  var unarySlash = match.unarySlash;
273
280
 
274
- if (handler.html5 && lastTag === 'p' && nonPhrasing(tagName)) {
275
- parseEndTag('', lastTag);
281
+ if (handler.html5) {
282
+ if (lastTag === 'p' && nonPhrasing(tagName)) {
283
+ parseEndTag('', lastTag);
284
+ }
285
+ else if (tagName === 'tbody') {
286
+ closeIfFound('thead');
287
+ }
288
+ else if (tagName === 'tfoot') {
289
+ if (!closeIfFound('tbody')) {
290
+ closeIfFound('thead');
291
+ }
292
+ }
293
+ if (tagName === 'col' && findTag('colgroup') < 0) {
294
+ lastTag = 'colgroup';
295
+ stack.push({ tag: lastTag, attrs: [] });
296
+ if (handler.start) {
297
+ handler.start(lastTag, [], false, '');
298
+ }
299
+ }
276
300
  }
277
301
 
278
302
  if (!handler.html5 && !inline(tagName)) {
@@ -353,17 +377,23 @@ function HTMLParser(html, handler) {
353
377
  }
354
378
  }
355
379
 
380
+ function findTag(tagName) {
381
+ var pos;
382
+ var needle = tagName.toLowerCase();
383
+ for (pos = stack.length - 1; pos >= 0; pos--) {
384
+ if (stack[pos].tag.toLowerCase() === needle) {
385
+ break;
386
+ }
387
+ }
388
+ return pos;
389
+ }
390
+
356
391
  function parseEndTag(tag, tagName) {
357
392
  var pos;
358
393
 
359
394
  // Find the closest opened tag of the same type
360
395
  if (tagName) {
361
- var needle = tagName.toLowerCase();
362
- for (pos = stack.length - 1; pos >= 0; pos--) {
363
- if (stack[pos].tag.toLowerCase() === needle) {
364
- break;
365
- }
366
- }
396
+ pos = findTag(tagName);
367
397
  }
368
398
  // If no tag name is provided, clean shop
369
399
  else {