htmlnano 0.2.7 → 0.2.8

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.
@@ -3,28 +3,141 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports["default"] = collapseAttributeWhitespace;
6
+ exports.default = collapseAttributeWhitespace;
7
+
8
+ var _timsort = require("timsort");
7
9
 
8
10
  var _collapseAttributeWhitespace = require("./collapseAttributeWhitespace");
9
11
 
12
+ // class, rel, ping
13
+ const validOptions = new Set(['frequency', 'alphabetical']);
14
+
15
+ const processModuleOptions = options => {
16
+ if (options === true) return 'alphabetical';
17
+ return validOptions.has(options) ? options : false;
18
+ };
19
+
20
+ class AttributeTokenChain {
21
+ constructor() {
22
+ this.freqData = new Map(); // <attrValue, frequency>[]
23
+ }
24
+
25
+ addFromNodeAttrsArray(attrValuesArray) {
26
+ attrValuesArray.forEach(attrValue => {
27
+ if (this.freqData.has(attrValue)) {
28
+ this.freqData.set(attrValue, this.freqData.get(attrValue) + 1);
29
+ } else {
30
+ this.freqData.set(attrValue, 1);
31
+ }
32
+ });
33
+ }
34
+
35
+ createSortOrder() {
36
+ let _sortOrder = [];
37
+
38
+ for (const item of this.freqData.entries()) {
39
+ _sortOrder.push(item);
40
+ }
41
+
42
+ (0, _timsort.sort)(_sortOrder, (a, b) => b[1] - a[1]);
43
+ this.sortOrder = _sortOrder.map(i => i[0]);
44
+ }
45
+
46
+ sortFromNodeAttrsArray(attrValuesArray) {
47
+ const resultArray = [];
48
+
49
+ if (!this.sortOrder) {
50
+ this.createSortOrder();
51
+ }
52
+
53
+ this.sortOrder.forEach(k => {
54
+ if (attrValuesArray.includes(k)) {
55
+ resultArray.push(k);
56
+ }
57
+ });
58
+ return resultArray;
59
+ }
60
+
61
+ }
10
62
  /** Sort values inside list-like attributes (e.g. class, rel) */
11
- function collapseAttributeWhitespace(tree) {
12
- tree.walk(function (node) {
63
+
64
+
65
+ function collapseAttributeWhitespace(tree, options, moduleOptions) {
66
+ const sortType = processModuleOptions(moduleOptions);
67
+
68
+ if (sortType === 'alphabetical') {
69
+ return sortAttributesWithListsInAlphabeticalOrder(tree);
70
+ }
71
+
72
+ if (sortType === 'frequency') {
73
+ return sortAttributesWithListsByFrequency(tree);
74
+ } // Invalid configuration
75
+
76
+
77
+ return tree;
78
+ }
79
+
80
+ function sortAttributesWithListsInAlphabeticalOrder(tree) {
81
+ tree.walk(node => {
13
82
  if (!node.attrs) {
14
83
  return node;
15
84
  }
16
85
 
17
- Object.keys(node.attrs).forEach(function (attrName) {
18
- var attrNameLower = attrName.toLowerCase();
86
+ Object.keys(node.attrs).forEach(attrName => {
87
+ const attrNameLower = attrName.toLowerCase();
19
88
 
20
89
  if (!_collapseAttributeWhitespace.attributesWithLists.has(attrNameLower)) {
21
90
  return;
22
91
  }
23
92
 
24
- var attrValues = node.attrs[attrName].split(/\s/);
25
- node.attrs[attrName] = attrValues.sort().join(' ');
93
+ const attrValues = node.attrs[attrName].split(/\s/);
94
+ node.attrs[attrName] = attrValues.sort((a, b) => {
95
+ return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
96
+ }).join(' ');
26
97
  });
27
98
  return node;
28
99
  });
29
100
  return tree;
101
+ }
102
+
103
+ function sortAttributesWithListsByFrequency(tree) {
104
+ const tokenChainObj = {}; // <attrNameLower: AttributeTokenChain>[]
105
+ // Traverse through tree to get frequency
106
+
107
+ tree.walk(node => {
108
+ if (!node.attrs) {
109
+ return node;
110
+ }
111
+
112
+ Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
113
+ const attrNameLower = attrName.toLowerCase();
114
+
115
+ if (!_collapseAttributeWhitespace.attributesWithLists.has(attrNameLower)) {
116
+ return;
117
+ }
118
+
119
+ tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new AttributeTokenChain();
120
+ tokenChainObj[attrNameLower].addFromNodeAttrsArray(attrValues.split(/\s/));
121
+ });
122
+ return node;
123
+ }); // Traverse through tree again, this time sort the attribute values
124
+
125
+ tree.walk(node => {
126
+ if (!node.attrs) {
127
+ return node;
128
+ }
129
+
130
+ Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
131
+ const attrNameLower = attrName.toLowerCase();
132
+
133
+ if (!_collapseAttributeWhitespace.attributesWithLists.has(attrNameLower)) {
134
+ return;
135
+ }
136
+
137
+ if (tokenChainObj[attrNameLower]) {
138
+ node.attrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(attrValues.split(/\s/)).join(' ');
139
+ }
140
+ });
141
+ return node;
142
+ });
30
143
  }
@@ -3,74 +3,24 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports["default"] = void 0;
6
+ exports.default = void 0;
7
7
 
8
8
  var _safe = _interopRequireDefault(require("./safe"));
9
9
 
10
10
  function _interopRequireDefault(obj) {
11
11
  return obj && obj.__esModule ? obj : {
12
- "default": obj
12
+ default: obj
13
13
  };
14
14
  }
15
-
16
- function ownKeys(object, enumerableOnly) {
17
- var keys = Object.keys(object);
18
-
19
- if (Object.getOwnPropertySymbols) {
20
- var symbols = Object.getOwnPropertySymbols(object);
21
- if (enumerableOnly) symbols = symbols.filter(function (sym) {
22
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
23
- });
24
- keys.push.apply(keys, symbols);
25
- }
26
-
27
- return keys;
28
- }
29
-
30
- function _objectSpread(target) {
31
- for (var i = 1; i < arguments.length; i++) {
32
- var source = arguments[i] != null ? arguments[i] : {};
33
-
34
- if (i % 2) {
35
- ownKeys(Object(source), true).forEach(function (key) {
36
- _defineProperty(target, key, source[key]);
37
- });
38
- } else if (Object.getOwnPropertyDescriptors) {
39
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
40
- } else {
41
- ownKeys(Object(source)).forEach(function (key) {
42
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
43
- });
44
- }
45
- }
46
-
47
- return target;
48
- }
49
-
50
- function _defineProperty(obj, key, value) {
51
- if (key in obj) {
52
- Object.defineProperty(obj, key, {
53
- value: value,
54
- enumerable: true,
55
- configurable: true,
56
- writable: true
57
- });
58
- } else {
59
- obj[key] = value;
60
- }
61
-
62
- return obj;
63
- }
64
15
  /**
65
16
  * A safe preset for AMP pages (https://www.ampproject.org)
66
17
  */
67
18
 
68
19
 
69
- var _default = _objectSpread(_objectSpread({}, _safe["default"]), {}, {
20
+ var _default = { ..._safe.default,
70
21
  collapseBooleanAttributes: {
71
22
  amphtml: true
72
23
  },
73
24
  minifyJs: false
74
- });
75
-
76
- exports["default"] = _default;
25
+ };
26
+ exports.default = _default;
@@ -3,70 +3,21 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports["default"] = void 0;
6
+ exports.default = void 0;
7
7
 
8
8
  var _safe = _interopRequireDefault(require("./safe"));
9
9
 
10
10
  function _interopRequireDefault(obj) {
11
11
  return obj && obj.__esModule ? obj : {
12
- "default": obj
12
+ default: obj
13
13
  };
14
14
  }
15
-
16
- function ownKeys(object, enumerableOnly) {
17
- var keys = Object.keys(object);
18
-
19
- if (Object.getOwnPropertySymbols) {
20
- var symbols = Object.getOwnPropertySymbols(object);
21
- if (enumerableOnly) symbols = symbols.filter(function (sym) {
22
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
23
- });
24
- keys.push.apply(keys, symbols);
25
- }
26
-
27
- return keys;
28
- }
29
-
30
- function _objectSpread(target) {
31
- for (var i = 1; i < arguments.length; i++) {
32
- var source = arguments[i] != null ? arguments[i] : {};
33
-
34
- if (i % 2) {
35
- ownKeys(Object(source), true).forEach(function (key) {
36
- _defineProperty(target, key, source[key]);
37
- });
38
- } else if (Object.getOwnPropertyDescriptors) {
39
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
40
- } else {
41
- ownKeys(Object(source)).forEach(function (key) {
42
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
43
- });
44
- }
45
- }
46
-
47
- return target;
48
- }
49
-
50
- function _defineProperty(obj, key, value) {
51
- if (key in obj) {
52
- Object.defineProperty(obj, key, {
53
- value: value,
54
- enumerable: true,
55
- configurable: true,
56
- writable: true
57
- });
58
- } else {
59
- obj[key] = value;
60
- }
61
-
62
- return obj;
63
- }
64
15
  /**
65
16
  * Maximal minification (might break some pages)
66
17
  */
67
18
 
68
19
 
69
- var _default = _objectSpread(_objectSpread({}, _safe["default"]), {}, {
20
+ var _default = { ..._safe.default,
70
21
  collapseWhitespace: 'all',
71
22
  removeComments: 'all',
72
23
  removeAttributeQuotes: true,
@@ -75,7 +26,8 @@ var _default = _objectSpread(_objectSpread({}, _safe["default"]), {}, {
75
26
  minifyCss: {
76
27
  preset: 'default'
77
28
  },
78
- minifySvg: {}
79
- });
80
-
81
- exports["default"] = _default;
29
+ minifySvg: {},
30
+ minifyConditionalComments: true,
31
+ removeOptionalTags: true
32
+ };
33
+ exports.default = _default;
@@ -3,12 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports["default"] = void 0;
6
+ exports.default = void 0;
7
7
  /**
8
8
  * Minify HTML in a safe way without breaking anything.
9
9
  */
10
10
 
11
11
  var _default = {
12
+ sortAttributes: false,
12
13
  collapseAttributeWhitespace: true,
13
14
  collapseBooleanAttributes: {
14
15
  amphtml: false
@@ -31,11 +32,13 @@ var _default = {
31
32
  convertShapeToPath: false
32
33
  }]
33
34
  },
35
+ minifyConditionalComments: false,
34
36
  removeEmptyAttributes: true,
35
37
  removeRedundantAttributes: false,
36
38
  removeComments: 'safe',
37
39
  removeAttributeQuotes: false,
38
- sortAttributesWithLists: true,
39
- minifyUrls: false
40
+ sortAttributesWithLists: 'alphabetical',
41
+ minifyUrls: false,
42
+ removeOptionalTags: false
40
43
  };
41
- exports["default"] = _default;
44
+ exports.default = _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "htmlnano",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Modular HTML minifier, built on top of the PostHTML",
5
5
  "main": "index.js",
6
6
  "author": "Kirill Maltsev <maltsevkirill@gmail.com>",
@@ -28,17 +28,26 @@
28
28
  ],
29
29
  "babel": {
30
30
  "presets": [
31
- "@babel/env"
31
+ [
32
+ "@babel/env",
33
+ {
34
+ "targets": {
35
+ "node": 10
36
+ }
37
+ }
38
+ ]
32
39
  ]
33
40
  },
34
41
  "dependencies": {
35
42
  "cssnano": "^4.1.10",
36
43
  "posthtml": "^0.13.4",
37
- "posthtml-render": "^1.2.2",
44
+ "posthtml-render": "^1.3.0",
38
45
  "purgecss": "^2.3.0",
39
46
  "relateurl": "^0.2.7",
47
+ "srcset": "^3.0.0",
40
48
  "svgo": "^1.3.2",
41
49
  "terser": "^4.8.0",
50
+ "timsort": "^0.3.0",
42
51
  "uncss": "^0.17.3"
43
52
  },
44
53
  "devDependencies": {
@@ -47,10 +56,10 @@
47
56
  "@babel/preset-env": "^7.12.1",
48
57
  "@babel/register": "^7.12.1",
49
58
  "babel-eslint": "^10.1.0",
50
- "eslint": "^7.4.0",
51
- "expect": "^26.1.0",
52
- "mocha": "^8.2.0",
53
- "release-it": "^14.1.0",
59
+ "eslint": "^7.13.0",
60
+ "expect": "^26.6.2",
61
+ "mocha": "^8.2.1",
62
+ "release-it": "^14.2.1",
54
63
  "rimraf": "^3.0.2"
55
64
  },
56
65
  "repository": {