htmlnano 2.1.0 → 2.1.2

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/index.d.ts CHANGED
@@ -5,6 +5,7 @@ import type { Config as SvgoOptimizeOptions } from "svgo";
5
5
 
6
6
  export interface HtmlnanoOptions {
7
7
  skipConfigLoading?: boolean;
8
+ skipInternalWarnings?: boolean;
8
9
  collapseAttributeWhitespace?: boolean;
9
10
  collapseBooleanAttributes?: {
10
11
  amphtml?: boolean;
@@ -22,7 +23,7 @@ export interface HtmlnanoOptions {
22
23
  minifySvg?: SvgoOptimizeOptions | boolean;
23
24
  normalizeAttributeValues?: boolean;
24
25
  removeAttributeQuotes?: boolean;
25
- removeComments?: boolean | "safe" | "all" | RegExp | (() => boolean);
26
+ removeComments?: boolean | "safe" | "all" | RegExp | ((comment: string) => boolean);
26
27
  removeEmptyAttributes?: boolean;
27
28
  removeRedundantAttributes?: boolean;
28
29
  removeOptionalTags?: boolean;
package/lib/helpers.cjs CHANGED
@@ -11,7 +11,7 @@ exports.isEventHandler = isEventHandler;
11
11
  exports.isStyleNode = isStyleNode;
12
12
  exports.optionalImport = optionalImport;
13
13
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
14
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
14
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
15
15
  function __transformExtension(filepath, extMapping) {
16
16
  if (!filepath.startsWith('./') && !filepath.startsWith('../')) {
17
17
  // Package import
@@ -52,7 +52,8 @@ function isComment(content) {
52
52
  return false;
53
53
  }
54
54
  function isConditionalComment(content) {
55
- return (content || '').trim().startsWith('<!--[if');
55
+ const clean = (content || '').trim();
56
+ return clean.startsWith('<!--[if') || clean === '<!--<![endif]-->';
56
57
  }
57
58
  function isStyleNode(node) {
58
59
  return node.tag === 'style' && !isAmpBoilerplate(node) && 'content' in node && node.content.length > 0;
package/lib/helpers.mjs CHANGED
@@ -24,7 +24,8 @@ export function isComment(content) {
24
24
  }
25
25
 
26
26
  export function isConditionalComment(content) {
27
- return (content || '').trim().startsWith('<!--[if');
27
+ const clean = (content || '').trim();
28
+ return clean.startsWith('<!--[if') || clean === '<!--<![endif]-->';
28
29
  }
29
30
 
30
31
  export function isStyleNode(node) {
package/lib/htmlnano.cjs CHANGED
@@ -10,7 +10,7 @@ var _cosmiconfig = require("cosmiconfig");
10
10
  var _safe = _interopRequireDefault(require("./presets/safe.cjs"));
11
11
  var _ampSafe = _interopRequireDefault(require("./presets/ampSafe.cjs"));
12
12
  var _max = _interopRequireDefault(require("./presets/max.cjs"));
13
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
14
  function __transformExtension(filepath, extMapping) {
15
15
  if (!filepath.startsWith('./') && !filepath.startsWith('../')) {
16
16
  // Package import
@@ -33,7 +33,7 @@ function __transformExtension(filepath, extMapping) {
33
33
  return filepath;
34
34
  }
35
35
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
36
- function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
36
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
37
37
  const presets = {
38
38
  safe: _safe.default,
39
39
  ampSafe: _ampSafe.default,
@@ -121,7 +121,9 @@ function htmlnano(optionsRun, presetRun) {
121
121
  }));
122
122
  } catch (e) {
123
123
  if (e.code === 'MODULE_NOT_FOUND' || e.code === 'ERR_MODULE_NOT_FOUND') {
124
- console.warn(`You have to install "${dependency}" in order to use htmlnano's "${moduleName}" module`);
124
+ if (!options.skipInternalWarnings) {
125
+ console.warn(`You have to install "${dependency}" in order to use htmlnano's "${moduleName}" module`);
126
+ }
125
127
  } else {
126
128
  throw e;
127
129
  }
package/lib/htmlnano.mjs CHANGED
@@ -98,7 +98,9 @@ function htmlnano(optionsRun, presetRun) {
98
98
  await import(dependency);
99
99
  } catch (e) {
100
100
  if (e.code === 'MODULE_NOT_FOUND' || e.code === 'ERR_MODULE_NOT_FOUND') {
101
- console.warn(`You have to install "${dependency}" in order to use htmlnano's "${moduleName}" module`);
101
+ if (!options.skipInternalWarnings){
102
+ console.warn(`You have to install "${dependency}" in order to use htmlnano's "${moduleName}" module`);
103
+ }
102
104
  } else {
103
105
  throw e;
104
106
  }
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.default = minifyConditionalComments;
7
7
  var _htmlnano = _interopRequireDefault(require("../htmlnano.cjs"));
8
8
  var _helpers = require("../helpers.cjs");
9
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
10
  // Spec: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/ms537512(v=vs.85)
11
11
  const CONDITIONAL_COMMENT_REGEXP = /(<!--\[if\s+?[^<>[\]]+?]>)([\s\S]+?)(<!\[endif\]-->)/gm;
12
12
 
@@ -98,14 +98,14 @@ async function minifyUrls(tree, options, moduleOptions) {
98
98
  if (isSrcsetAttribute(node.tag, attrNameLower)) {
99
99
  if (srcset) {
100
100
  try {
101
- const parsedSrcset = srcset.parse(attrValue, {
101
+ const parsedSrcset = srcset.parseSrcset(attrValue, {
102
102
  strict: true
103
103
  });
104
- node.attrs[attrName] = srcset.stringify(parsedSrcset.map(srcset => {
104
+ node.attrs[attrName] = srcset.stringifySrcset(parsedSrcset.map(item => {
105
105
  if (relateUrlInstance) {
106
- srcset.url = relateUrlInstance.relate(srcset.url);
106
+ item.url = relateUrlInstance.relate(item.url);
107
107
  }
108
- return srcset;
108
+ return item;
109
109
  }));
110
110
  } catch (e) {
111
111
  // srcset will throw an Error for invalid srcset.
@@ -175,14 +175,14 @@ export default async function minifyUrls(tree, options, moduleOptions) {
175
175
  if (isSrcsetAttribute(node.tag, attrNameLower)) {
176
176
  if (srcset) {
177
177
  try {
178
- const parsedSrcset = srcset.parse(attrValue, { strict: true });
178
+ const parsedSrcset = srcset.parseSrcset(attrValue, { strict: true });
179
179
 
180
- node.attrs[attrName] = srcset.stringify(parsedSrcset.map(srcset => {
180
+ node.attrs[attrName] = srcset.stringifySrcset(parsedSrcset.map(item => {
181
181
  if (relateUrlInstance) {
182
- srcset.url = relateUrlInstance.relate(srcset.url);
182
+ item.url = relateUrlInstance.relate(item.url);
183
183
  }
184
184
 
185
- return srcset;
185
+ return item;
186
186
  }));
187
187
  } catch (e) {
188
188
  // srcset will throw an Error for invalid srcset.
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = sortAttributes;
7
- var _timsort = require("timsort");
8
7
  const validOptions = new Set(['frequency', 'alphabetical']);
9
8
  const processModuleOptions = options => {
10
9
  if (options === true) return 'alphabetical';
@@ -14,7 +13,6 @@ class AttributeTokenChain {
14
13
  constructor() {
15
14
  this.freqData = new Map(); // <attr, frequency>[]
16
15
  }
17
-
18
16
  addFromNodeAttrs(nodeAttrs) {
19
17
  Object.keys(nodeAttrs).forEach(attrName => {
20
18
  const attrNameLower = attrName.toLowerCase();
@@ -27,7 +25,7 @@ class AttributeTokenChain {
27
25
  }
28
26
  createSortOrder() {
29
27
  let _sortOrder = [...this.freqData.entries()];
30
- (0, _timsort.sort)(_sortOrder, (a, b) => b[1] - a[1]);
28
+ _sortOrder.sort((a, b) => b[1] - a[1]);
31
29
  this.sortOrder = _sortOrder.map(i => i[0]);
32
30
  }
33
31
  sortFromNodeAttrs(nodeAttrs) {
@@ -1,5 +1,3 @@
1
- import { sort as timSort } from 'timsort';
2
-
3
1
  const validOptions = new Set(['frequency', 'alphabetical']);
4
2
 
5
3
  const processModuleOptions = options => {
@@ -27,7 +25,7 @@ class AttributeTokenChain {
27
25
 
28
26
  createSortOrder() {
29
27
  let _sortOrder = [...this.freqData.entries()];
30
- timSort(_sortOrder, (a, b) => b[1] - a[1]);
28
+ _sortOrder.sort((a, b) => b[1] - a[1]);
31
29
 
32
30
  this.sortOrder = _sortOrder.map(i => i[0]);
33
31
  }
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = collapseAttributeWhitespace;
7
- var _timsort = require("timsort");
8
7
  var _collapseAttributeWhitespace = require("./collapseAttributeWhitespace.cjs");
9
8
  // class, rel, ping
10
9
 
@@ -17,7 +16,6 @@ class AttributeTokenChain {
17
16
  constructor() {
18
17
  this.freqData = new Map(); // <attrValue, frequency>[]
19
18
  }
20
-
21
19
  addFromNodeAttrsArray(attrValuesArray) {
22
20
  attrValuesArray.forEach(attrValue => {
23
21
  if (this.freqData.has(attrValue)) {
@@ -29,7 +27,7 @@ class AttributeTokenChain {
29
27
  }
30
28
  createSortOrder() {
31
29
  let _sortOrder = [...this.freqData.entries()];
32
- (0, _timsort.sort)(_sortOrder, (a, b) => b[1] - a[1]);
30
+ _sortOrder.sort((a, b) => b[1] - a[1]);
33
31
  this.sortOrder = _sortOrder.map(i => i[0]);
34
32
  }
35
33
  sortFromNodeAttrsArray(attrValuesArray) {
@@ -1,5 +1,4 @@
1
1
  // class, rel, ping
2
- import { sort as timSort } from 'timsort';
3
2
  import { attributesWithLists } from './collapseAttributeWhitespace.mjs';
4
3
 
5
4
  const validOptions = new Set(['frequency', 'alphabetical']);
@@ -26,7 +25,7 @@ class AttributeTokenChain {
26
25
 
27
26
  createSortOrder() {
28
27
  let _sortOrder = [...this.freqData.entries()];
29
- timSort(_sortOrder, (a, b) => b[1] - a[1]);
28
+ _sortOrder.sort((a, b) => b[1] - a[1]);
30
29
 
31
30
  this.sortOrder = _sortOrder.map(i => i[0]);
32
31
  }
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _safe = _interopRequireDefault(require("./safe.cjs"));
8
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
9
  /**
10
10
  * A safe preset for AMP pages (https://www.ampproject.org)
11
11
  */
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _safe = _interopRequireDefault(require("./safe.cjs"));
8
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
9
9
  /**
10
10
  * Maximal minification (might break some pages)
11
11
  */
package/package.json CHANGED
@@ -1,19 +1,22 @@
1
1
  {
2
2
  "name": "htmlnano",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Modular HTML minifier, built on top of the PostHTML",
5
5
  "main": "index.cjs",
6
6
  "module": "index.mjs",
7
7
  "source": "index.mjs",
8
8
  "exports": {
9
9
  ".": {
10
+ "types": "./index.d.ts",
10
11
  "require": "./index.cjs",
11
12
  "import": "./index.mjs"
12
13
  },
13
14
  "./index.mjs": {
15
+ "types": "./index.d.mts",
14
16
  "import": "./index.mjs"
15
17
  },
16
18
  "./index.cjs": {
19
+ "types": "./index.d.cts",
17
20
  "require": "./index.cjs"
18
21
  }
19
22
  },
@@ -59,38 +62,37 @@
59
62
  ]
60
63
  },
61
64
  "dependencies": {
62
- "cosmiconfig": "^8.0.0",
63
- "posthtml": "^0.16.5",
64
- "timsort": "^0.3.0"
65
+ "cosmiconfig": "^9.0.0",
66
+ "posthtml": "^0.16.5"
65
67
  },
66
68
  "devDependencies": {
69
+ "@aminya/babel-plugin-replace-import-extension": "1.2.0",
67
70
  "@babel/cli": "^7.15.7",
68
71
  "@babel/core": "^7.15.5",
69
72
  "@babel/eslint-parser": "^7.17.0",
70
73
  "@babel/preset-env": "^7.15.6",
71
74
  "@babel/register": "^7.15.3",
72
- "@aminya/babel-plugin-replace-import-extension": "1.2.0",
73
- "cssnano": "^6.0.0",
75
+ "cssnano": "^7.0.0",
74
76
  "eslint": "^8.12.0",
75
77
  "eslint-plugin-import": "^2.28.1",
76
78
  "eslint-plugin-path-import-extension": "^0.9.0",
77
79
  "expect": "^29.0.0",
78
- "mocha": "^10.1.0",
80
+ "mocha": "^11.0.1",
79
81
  "postcss": "^8.3.11",
80
- "purgecss": "^5.0.0",
82
+ "purgecss": "^7.0.2",
81
83
  "relateurl": "^0.2.7",
82
- "rimraf": "^5.0.0",
83
- "srcset": "4.0.0",
84
+ "rimraf": "^6.0.0",
85
+ "srcset": "5.0.1",
84
86
  "svgo": "^3.0.2",
85
87
  "terser": "^5.21.0",
86
88
  "uncss": "^0.17.3"
87
89
  },
88
90
  "peerDependencies": {
89
- "cssnano": "^6.0.0",
91
+ "cssnano": "^7.0.0",
90
92
  "postcss": "^8.3.11",
91
- "purgecss": "^5.0.0",
93
+ "purgecss": "^7.0.2",
92
94
  "relateurl": "^0.2.7",
93
- "srcset": "4.0.0",
95
+ "srcset": "5.0.1",
94
96
  "svgo": "^3.0.2",
95
97
  "terser": "^5.10.0",
96
98
  "uncss": "^0.17.3"
package/test.js CHANGED
@@ -1,39 +1,13 @@
1
+ const fs = require('fs');
2
+
1
3
  const htmlnano = require('.');
2
4
  // const posthtml = require('posthtml');
3
- const safePreset = require('./lib/presets/safe');
4
- // const options = {
5
- // minifySvg: false,
6
- // minifyJs: false,
7
- // };
8
- // // posthtml, posthtml-render, and posthtml-parse options
9
- // const postHtmlOptions = {
10
- // sync: true, // https://github.com/posthtml/posthtml#usage
11
- // lowerCaseTags: true, // https://github.com/posthtml/posthtml-parser#options
12
- // quoteAllAttributes: false, // https://github.com/posthtml/posthtml-render#options
13
- // };
5
+ const preset = require('./lib/presets/max.cjs');
6
+
14
7
 
15
- // const html = `
16
- // <!doctype html>
17
- // <html lang="en">
18
- // <head>
19
- // <meta charset="utf-8">
20
- // <title></title>
21
- // <script class="fob">alert(1)</script>
22
- // <script>alert(2)</script>
23
- // </head>
24
- // <body>
25
- // <script>alert(3)</script>
26
- // <script>alert(4)</script>
27
- // </body>
28
- // </html>
29
- // `;
8
+ const html = fs.readFileSync('./test.html', 'utf8');
30
9
 
31
- const options = {
32
- minifySvg: safePreset.minifySvg,
33
- };
34
- const html = `
35
- <input type="text" class="form-control" name="testInput" autofocus="" autocomplete="off" id="testId"><a id="testId" href="#" class="testClass"></a><img width="20" src="../images/image.png" height="40" alt="image" class="cls" id="id2">
36
- `;
10
+ const startTime = Date.now();
37
11
 
38
12
  htmlnano
39
13
  // "preset" arg might be skipped (see "Presets" section below for more info)
@@ -41,7 +15,8 @@ htmlnano
41
15
  .process(html)
42
16
  .then(function (result) {
43
17
  // result.html is minified
44
- console.log(result.html);
18
+ // console.log(result.html);
19
+ console.log(`Time taken: ${Date.now() - startTime}ms`);
45
20
  })
46
21
  .catch(function (err) {
47
22
  console.error(err);