html-minifier-next 4.16.3 → 4.17.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 +110 -70
- package/cli.js +27 -25
- package/dist/htmlminifier.cjs +264 -138
- package/dist/htmlminifier.esm.bundle.js +264 -138
- package/dist/types/htmlminifier.d.ts.map +1 -1
- package/dist/types/htmlparser.d.ts.map +1 -1
- package/dist/types/lib/attributes.d.ts +1 -1
- package/dist/types/lib/attributes.d.ts.map +1 -1
- package/dist/types/lib/constants.d.ts +16 -15
- package/dist/types/lib/constants.d.ts.map +1 -1
- package/dist/types/lib/content.d.ts.map +1 -1
- package/dist/types/lib/options.d.ts +2 -2
- package/dist/types/lib/whitespace.d.ts +1 -1
- package/dist/types/lib/whitespace.d.ts.map +1 -1
- package/dist/types/presets.d.ts +1 -1
- package/package.json +13 -8
- package/src/htmlminifier.js +49 -47
- package/src/htmlparser.js +44 -13
- package/src/lib/attributes.js +72 -30
- package/src/lib/constants.js +46 -39
- package/src/lib/content.js +0 -1
- package/src/lib/elements.js +15 -15
- package/src/lib/options.js +9 -9
- package/src/lib/svg.js +14 -14
- package/src/lib/whitespace.js +53 -4
- package/src/presets.js +4 -4
- package/src/tokenchain.js +2 -2
- package/src/lib/index.js +0 -20
- package/src/utils.js +0 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"AA41CO,8BAJI,MAAM,YACN,eAAe,GACb,OAAO,CAAC,MAAM,CAAC,CAe3B;;;;;;;;;;;;UAhwCS,MAAM;YACN,MAAM;YACN,MAAM;mBACN,MAAM;iBACN,MAAM;kBACN,MAAM;;;;;;;;;;;;;4BAQN,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,qBAAqB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;wBAMjG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO;;;;;;;;oBAMhH,OAAO;;;;;;;;;kCAON,OAAO;;;;;;;;gCAQR,OAAO;;;;;;;;kCAOP,OAAO;;;;;;;;yBAOP,OAAO;;;;;;;;2BAOP,OAAO;;;;;;;;4BAOP,OAAO;;;;;;;2BAOP,OAAO;;;;;;;;uBAMP,MAAM,EAAE;;;;;;yBAOR,MAAM;;;;;;yBAKN,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE;;;;;;;4BAKlB,MAAM,EAAE;;;;;;;oCAMR,MAAM;;;;;;;qBAMN,OAAO;;;;;;;YAMP,OAAO;;;;;;;;2BAMP,MAAM,EAAE;;;;;;;;;4BAOR,MAAM,EAAE;;;;;;;+BAQR,OAAO;;;;;;;2BAMP,SAAS,CAAC,MAAM,CAAC;;;;;;uBAMjB,OAAO;;;;;;;;UAKP,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI;;;;;;;;qBAO1B,MAAM;;;;;;;oBAON,MAAM;;;;;;;;;;gBAMN,OAAO,GAAG,OAAO,CAAC,OAAO,cAAc,EAAE,gBAAgB,CAAC,OAAO,cAAc,EAAE,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;;;;;eAS9J,OAAO,GAAG,OAAO,QAAQ,EAAE,aAAa,GAAG;QAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAC,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;iBAa3J,OAAO,GAAG,MAAM,GAAG,OAAO,WAAW,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;;gBAS7F,OAAO,GAAG;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAC;;;;;;;;WAUhF,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM;;;;;;;+BAOxB,OAAO;;;;;;;;;;oBAMP,OAAO;;;;;;;;yBASP,OAAO;;;;;;;gCAOP,OAAO;;;;;;;;iCAMP,OAAO;;;;;;;;;;qBAOP,MAAM,EAAE;;;;;;;qBASR,IAAI,GAAG,GAAG;;;;;;;4BAMV,OAAO;;;;;;;;qBAMP,OAAO;;;;;;;;;4BAOP,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;;;;;;;;0BAQtD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;gCAOP,MAAM,EAAE;;;;;;;;yBAyBR,OAAO;;;;;;;;gCAOP,OAAO;;;;;;;iCAOP,OAAO;;;;;;;oCAMP,OAAO;;;;;;;;;;0BAMP,OAAO;;;;;;;;;qBASP,OAAO,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,IAAI,CAAC;;;;;;;;;oBAQzD,OAAO,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;;;;;;;;0BAQrC,OAAO;;;;;;;sBAOP,OAAO;;wBAnekC,cAAc;0BAAd,cAAc;+BAAd,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"htmlparser.d.ts","sourceRoot":"","sources":["../../src/htmlparser.js"],"names":[],"mappings":"AA+CA,4BAAoE;AA8EpE;IACE,qCAGC;IAFC,UAAgB;IAChB,aAAsB;IAGxB,
|
|
1
|
+
{"version":3,"file":"htmlparser.d.ts","sourceRoot":"","sources":["../../src/htmlparser.js"],"names":[],"mappings":"AA+CA,4BAAoE;AA8EpE;IACE,qCAGC;IAFC,UAAgB;IAChB,aAAsB;IAGxB,uBA+fC;CACF"}
|
|
@@ -8,7 +8,7 @@ export function isScriptTypeAttribute(attrValue?: string): boolean;
|
|
|
8
8
|
export function keepScriptTypeAttribute(attrValue?: string): boolean;
|
|
9
9
|
export function isExecutableScript(tag: any, attrs: any): boolean;
|
|
10
10
|
export function isStyleLinkTypeAttribute(attrValue?: string): boolean;
|
|
11
|
-
export function
|
|
11
|
+
export function isStyleElement(tag: any, attrs: any): boolean;
|
|
12
12
|
export function isBooleanAttribute(attrName: any, attrValue: any): boolean;
|
|
13
13
|
export function isUriTypeAttribute(attrName: any, tag: any): boolean;
|
|
14
14
|
export function isNumberTypeAttribute(attrName: any, tag: any): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../src/lib/attributes.js"],"names":[],"mappings":"AA0BA,yDAEC;AAED,mEAOC;AAED,uEAWC;AAED,8DAGC;AAED,4EAOC;AAED,
|
|
1
|
+
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../src/lib/attributes.js"],"names":[],"mappings":"AA0BA,yDAEC;AAED,mEAOC;AAED,uEAWC;AAED,8DAGC;AAED,4EAOC;AAED,mGAuCC;AAED,mEAGC;AAED,qEAGC;AAED,kEAWC;AAED,sEAGC;AAED,8DAWC;AAED,2EAEC;AAED,qEAaC;AAED,wEAUC;AAED,sEAUC;AAED,2EAEC;AAED,2DAEC;AAED,8DAUC;AAED,uEAUC;AAED,oGASC;AAED,4DAOC;AAID,0IAgJC;AAsBD;;;;GAwCC;AAED,6GAuHC"}
|
|
@@ -19,6 +19,7 @@ export const RE_NUMERIC_VALUE: RegExp;
|
|
|
19
19
|
export const inlineElementsToKeepWhitespaceAround: Set<string>;
|
|
20
20
|
export const inlineElementsToKeepWhitespaceWithin: Set<string>;
|
|
21
21
|
export const inlineElementsToKeepWhitespace: Set<string>;
|
|
22
|
+
export const formControlElements: Set<string>;
|
|
22
23
|
export namespace generalDefaults {
|
|
23
24
|
let autocorrect: string;
|
|
24
25
|
let fetchpriority: string;
|
|
@@ -78,24 +79,24 @@ export const keepScriptsMimetypes: Set<string>;
|
|
|
78
79
|
export const jsonScriptTypes: Set<string>;
|
|
79
80
|
export const isSimpleBoolean: Set<string>;
|
|
80
81
|
export const isBooleanValue: Set<string>;
|
|
81
|
-
export const
|
|
82
|
+
export const srcsetElements: Set<string>;
|
|
82
83
|
export const optionalStartTags: Set<string>;
|
|
83
84
|
export const optionalEndTags: Set<string>;
|
|
84
|
-
export const
|
|
85
|
-
export const
|
|
86
|
-
export const
|
|
87
|
-
export const
|
|
85
|
+
export const headerElements: Set<string>;
|
|
86
|
+
export const descriptionElements: Set<string>;
|
|
87
|
+
export const pBlockElements: Set<string>;
|
|
88
|
+
export const pInlineElements: Set<string>;
|
|
88
89
|
export const rubyEndTagOmission: Set<string>;
|
|
89
90
|
export const rubyRtcEndTagOmission: Set<string>;
|
|
90
|
-
export const
|
|
91
|
-
export const
|
|
92
|
-
export const
|
|
93
|
-
export const
|
|
94
|
-
export const
|
|
95
|
-
export const
|
|
96
|
-
export const
|
|
97
|
-
export const
|
|
98
|
-
export const
|
|
91
|
+
export const optionElements: Set<string>;
|
|
92
|
+
export const tableContentElements: Set<string>;
|
|
93
|
+
export const tableSectionElements: Set<string>;
|
|
94
|
+
export const cellElements: Set<string>;
|
|
95
|
+
export const topLevelElements: Set<string>;
|
|
96
|
+
export const compactElements: Set<string>;
|
|
97
|
+
export const looseElements: Set<string>;
|
|
98
|
+
export const trailingElements: Set<string>;
|
|
99
|
+
export const htmlElements: Set<string>;
|
|
99
100
|
export const reEmptyAttribute: RegExp;
|
|
100
|
-
export const
|
|
101
|
+
export const specialContentElements: Set<string>;
|
|
101
102
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.js"],"names":[],"mappings":"AAEA,iCAAoC;AACpC,+BAAkC;AAClC,oCAA2C;AAC3C,2CAAmD;AACnD,wCAA8C;AAC9C,4CAAkD;AAClD,4CAA2C;AAC3C,4CAA0D;AAC1D,2CAA8C;AAC9C,+CAA0D;AAC1D,2CAAmC;AACnC,mCAA4C;AAC5C,wCAAwqB;AACxqB,kCAA0B;AAC1B,sCAAuC;AACvC,yCAA4C;AAC5C,qCAAuD;AACvD,sCAAmE;AAKnE,+DAAgb;AAGhb,+DAA6O;AAG7O,yDAAmF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.js"],"names":[],"mappings":"AAEA,iCAAoC;AACpC,+BAAkC;AAClC,oCAA2C;AAC3C,2CAAmD;AACnD,wCAA8C;AAC9C,4CAAkD;AAClD,4CAA2C;AAC3C,4CAA0D;AAC1D,2CAA8C;AAC9C,+CAA0D;AAC1D,2CAAmC;AACnC,mCAA4C;AAC5C,wCAAwqB;AACxqB,kCAA0B;AAC1B,sCAAuC;AACvC,yCAA4C;AAC5C,qCAAuD;AACvD,sCAAmE;AAKnE,+DAAgb;AAGhb,+DAA6O;AAG7O,yDAAmF;AAGnF,8CAA8G;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0C9G,qDAWG;AAEH,+CAEG;AAcH,0CAUG;AApBH,0CAAwhB;AAExhB,yCAAkD;AAIlD,yCAAkD;AAuBlD,4CAAiF;AAEjF,0CAAoM;AAEpM,yCAA4F;AAE5F,8CAAkD;AAElD,yCAAiT;AAEjT,0CAA0F;AAE1F,6CAA8D;AAE9D,gDAAqD;AAErD,yCAAuD;AAEvD,+CAAyD;AAEzD,+CAAkE;AAElE,uCAA2C;AAE3C,2CAA2D;AAE3D,0CAAkD;AAElD,wCAA+D;AAE/D,2CAAkD;AAElD,uCAAmxC;AAInxC,sCAEsD;AAItD,iDAA4D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/lib/content.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../src/lib/content.js"],"names":[],"mappings":"AAYA,mDASC;AAED,qDAWC;AAED,mGAMC;AAID,yDAWC;AAED,uDAWC;AAED,yGAiBC"}
|
|
@@ -2,8 +2,8 @@ export function shouldMinifyInnerHTML(options: any): boolean;
|
|
|
2
2
|
/**
|
|
3
3
|
* @param {Partial<MinifierOptions>} inputOptions - User-provided options
|
|
4
4
|
* @param {Object} deps - Dependencies from htmlminifier.js
|
|
5
|
-
* @param {Function} deps.getLightningCSS - Function to lazily load
|
|
6
|
-
* @param {Function} deps.getTerser - Function to lazily load
|
|
5
|
+
* @param {Function} deps.getLightningCSS - Function to lazily load Lightning CSS
|
|
6
|
+
* @param {Function} deps.getTerser - Function to lazily load Terser
|
|
7
7
|
* @param {Function} deps.getSwc - Function to lazily load @swc/core
|
|
8
8
|
* @param {LRU} deps.cssMinifyCache - CSS minification cache
|
|
9
9
|
* @param {LRU} deps.jsMinifyCache - JS minification cache
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export function trimWhitespace(str: any): any;
|
|
2
2
|
export function collapseWhitespaceAll(str: any): any;
|
|
3
3
|
export function collapseWhitespace(str: any, options: any, trimLeft: any, trimRight: any, collapseAll: any): any;
|
|
4
|
-
export function collapseWhitespaceSmart(str: any, prevTag: any, nextTag: any, options: any, inlineElements: any, inlineTextSet: any): any;
|
|
4
|
+
export function collapseWhitespaceSmart(str: any, prevTag: any, nextTag: any, prevAttrs: any, nextAttrs: any, options: any, inlineElements: any, inlineTextSet: any): any;
|
|
5
5
|
export function canCollapseWhitespace(tag: any): boolean;
|
|
6
6
|
export function canTrimWhitespace(tag: any): boolean;
|
|
7
7
|
//# sourceMappingURL=whitespace.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whitespace.d.ts","sourceRoot":"","sources":["../../../src/lib/whitespace.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"whitespace.d.ts","sourceRoot":"","sources":["../../../src/lib/whitespace.js"],"names":[],"mappings":"AAiBA,8CAOC;AAID,qDAgBC;AAID,iHAyDC;AAID,0KAwEC;AAID,yDAEC;AAED,qDAEC"}
|
package/dist/types/presets.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Get preset configuration by name
|
|
3
|
-
* @param {string} name - Preset name (
|
|
3
|
+
* @param {string} name - Preset name (“conservative” or “comprehensive”)
|
|
4
4
|
* @returns {object|null} Preset options object or null if not found
|
|
5
5
|
*/
|
|
6
6
|
export function getPreset(name: string): object | null;
|
package/package.json
CHANGED
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"@rollup/plugin-terser": "^0.4.4",
|
|
24
24
|
"@swc/core": "^1.15.7",
|
|
25
25
|
"eslint": "^9.39.2",
|
|
26
|
-
"rollup": "^4.
|
|
26
|
+
"rollup": "^4.54.0",
|
|
27
27
|
"rollup-plugin-polyfill-node": "^0.13.0",
|
|
28
28
|
"typescript": "^5.9.3",
|
|
29
|
-
"vite": "^7.
|
|
29
|
+
"vite": "^7.3.0"
|
|
30
30
|
},
|
|
31
31
|
"exports": {
|
|
32
32
|
".": {
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"dist/",
|
|
43
43
|
"src/"
|
|
44
44
|
],
|
|
45
|
+
"funding": "https://github.com/j9t/html-minifier-next?sponsor=1",
|
|
45
46
|
"homepage": "https://j9t.github.io/html-minifier-next/",
|
|
46
47
|
"keywords": [
|
|
47
48
|
"cli",
|
|
@@ -51,6 +52,7 @@
|
|
|
51
52
|
"html",
|
|
52
53
|
"htmlmin",
|
|
53
54
|
"javascript",
|
|
55
|
+
"js",
|
|
54
56
|
"min",
|
|
55
57
|
"minification",
|
|
56
58
|
"minifier",
|
|
@@ -59,8 +61,8 @@
|
|
|
59
61
|
"optimizer",
|
|
60
62
|
"pack",
|
|
61
63
|
"packer",
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
+
"svg",
|
|
65
|
+
"swc",
|
|
64
66
|
"terser",
|
|
65
67
|
"uglifier",
|
|
66
68
|
"uglify"
|
|
@@ -68,7 +70,6 @@
|
|
|
68
70
|
"license": "MIT",
|
|
69
71
|
"main": "./dist/htmlminifier.cjs",
|
|
70
72
|
"module": "./src/htmlminifier.js",
|
|
71
|
-
"types": "./dist/types/htmlminifier.d.ts",
|
|
72
73
|
"name": "html-minifier-next",
|
|
73
74
|
"peerDependencies": {
|
|
74
75
|
"@swc/core": "^1.15.7"
|
|
@@ -78,13 +79,16 @@
|
|
|
78
79
|
"optional": true
|
|
79
80
|
}
|
|
80
81
|
},
|
|
81
|
-
"repository":
|
|
82
|
+
"repository": {
|
|
83
|
+
"type": "git",
|
|
84
|
+
"url": "git+https://github.com/j9t/html-minifier-next.git"
|
|
85
|
+
},
|
|
82
86
|
"scripts": {
|
|
83
|
-
"prebuild": "node --eval='require(`fs`).rmSync(`dist`,{recursive:true,force:true})'",
|
|
84
87
|
"build": "tsc && rollup -c",
|
|
85
88
|
"build:docs": "vite build --base /html-minifier-next/ --outDir build",
|
|
86
89
|
"deploy": "npm run build && npm run build:docs",
|
|
87
90
|
"lint": "eslint .",
|
|
91
|
+
"prebuild": "node --eval='require(`fs`).rmSync(`dist`,{recursive:true,force:true})'",
|
|
88
92
|
"prepack": "npm run build",
|
|
89
93
|
"prepare": "git config core.hooksPath .githooks || true",
|
|
90
94
|
"serve": "npm run build && vite",
|
|
@@ -93,5 +97,6 @@
|
|
|
93
97
|
"test:watch": "node --test --watch tests/*.spec.js"
|
|
94
98
|
},
|
|
95
99
|
"type": "module",
|
|
96
|
-
"
|
|
100
|
+
"types": "./dist/types/htmlminifier.d.ts",
|
|
101
|
+
"version": "4.17.0"
|
|
97
102
|
}
|
package/src/htmlminifier.js
CHANGED
|
@@ -12,15 +12,15 @@ import {
|
|
|
12
12
|
RE_ESCAPE_LT,
|
|
13
13
|
inlineElementsToKeepWhitespaceAround,
|
|
14
14
|
inlineElementsToKeepWhitespaceWithin,
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
specialContentElements,
|
|
16
|
+
htmlElements,
|
|
17
17
|
optionalStartTags,
|
|
18
18
|
optionalEndTags,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
topLevelElements,
|
|
20
|
+
compactElements,
|
|
21
|
+
looseElements,
|
|
22
|
+
trailingElements,
|
|
23
|
+
pInlineElements
|
|
24
24
|
} from './lib/constants.js';
|
|
25
25
|
|
|
26
26
|
import {
|
|
@@ -28,15 +28,15 @@ import {
|
|
|
28
28
|
collapseWhitespaceAll,
|
|
29
29
|
collapseWhitespace,
|
|
30
30
|
collapseWhitespaceSmart,
|
|
31
|
-
canCollapseWhitespace,
|
|
32
|
-
canTrimWhitespace
|
|
31
|
+
canCollapseWhitespace as defaultCanCollapseWhitespace,
|
|
32
|
+
canTrimWhitespace as defaultCanTrimWhitespace
|
|
33
33
|
} from './lib/whitespace.js';
|
|
34
34
|
|
|
35
35
|
import {
|
|
36
36
|
isConditionalComment,
|
|
37
37
|
isIgnoredComment,
|
|
38
38
|
isExecutableScript,
|
|
39
|
-
|
|
39
|
+
isStyleElement,
|
|
40
40
|
normalizeAttr,
|
|
41
41
|
buildAttr
|
|
42
42
|
} from './lib/attributes.js';
|
|
@@ -517,7 +517,7 @@ async function createSortFns(value, options, uidIgnore, uidAttr, ignoredMarkupCh
|
|
|
517
517
|
}
|
|
518
518
|
|
|
519
519
|
// Pre-compile regex patterns for reuse (performance optimization)
|
|
520
|
-
// These must be declared before scan() since scan uses them
|
|
520
|
+
// These must be declared before `scan()` since scan uses them
|
|
521
521
|
const whitespaceSplitPatternScan = /[ \t\n\f\r]+/;
|
|
522
522
|
const whitespaceSplitPatternSort = /[ \n\f\r]+/;
|
|
523
523
|
|
|
@@ -549,9 +549,9 @@ async function createSortFns(value, options, uidIgnore, uidAttr, ignoredMarkupCh
|
|
|
549
549
|
chars: async function (text) {
|
|
550
550
|
// Only recursively scan HTML content, not JSON-LD or other non-HTML script types
|
|
551
551
|
// `scan()` is for analyzing HTML attribute order, not for parsing JSON
|
|
552
|
-
if (options.processScripts &&
|
|
553
|
-
|
|
554
|
-
|
|
552
|
+
if (options.processScripts && specialContentElements.has(currentTag) &&
|
|
553
|
+
options.processScripts.indexOf(currentType) > -1 &&
|
|
554
|
+
currentType === 'text/html') {
|
|
555
555
|
await scan(text);
|
|
556
556
|
}
|
|
557
557
|
},
|
|
@@ -574,7 +574,7 @@ async function createSortFns(value, options, uidIgnore, uidAttr, ignoredMarkupCh
|
|
|
574
574
|
// For the first pass, create a copy of options and disable aggressive minification.
|
|
575
575
|
// Keep attribute transformations (like `removeStyleLinkTypeAttributes`) for accurate analysis.
|
|
576
576
|
// This is safe because `createSortFns` is called before custom fragment UID markers (`uidAttr`) are added.
|
|
577
|
-
// Note: `htmlmin:ignore` UID markers (uidIgnore) already exist and are expanded for analysis.
|
|
577
|
+
// Note: `htmlmin:ignore` UID markers (`uidIgnore`) already exist and are expanded for analysis.
|
|
578
578
|
const firstPassOptions = Object.assign({}, options, {
|
|
579
579
|
// Disable sorting for the analysis pass
|
|
580
580
|
sortAttributes: false,
|
|
@@ -593,7 +593,7 @@ async function createSortFns(value, options, uidIgnore, uidAttr, ignoredMarkupCh
|
|
|
593
593
|
});
|
|
594
594
|
|
|
595
595
|
// Temporarily enable `continueOnParseError` for the `scan()` function call below.
|
|
596
|
-
// Note: `firstPassOptions` already has `continueOnParseError: true` for the minifyHTML call.
|
|
596
|
+
// Note: `firstPassOptions` already has `continueOnParseError: true` for the `minifyHTML` call.
|
|
597
597
|
const originalContinueOnParseError = options.continueOnParseError;
|
|
598
598
|
options.continueOnParseError = true;
|
|
599
599
|
|
|
@@ -606,7 +606,7 @@ async function createSortFns(value, options, uidIgnore, uidAttr, ignoredMarkupCh
|
|
|
606
606
|
: null;
|
|
607
607
|
|
|
608
608
|
try {
|
|
609
|
-
// Expand UID tokens back to original content for frequency analysis
|
|
609
|
+
// Expand UID tokens back to the original content for frequency analysis
|
|
610
610
|
let expandedValue = value;
|
|
611
611
|
if (uidReplacePattern) {
|
|
612
612
|
expandedValue = value.replace(uidReplacePattern, function (match, index) {
|
|
@@ -655,7 +655,7 @@ async function createSortFns(value, options, uidIgnore, uidAttr, ignoredMarkupCh
|
|
|
655
655
|
attrOrderCache.set(cacheKey, sortedNames);
|
|
656
656
|
}
|
|
657
657
|
|
|
658
|
-
// Apply the sorted order to attrs
|
|
658
|
+
// Apply the sorted order to `attrs`
|
|
659
659
|
const attrMap = Object.create(null);
|
|
660
660
|
names.forEach(function (name, index) {
|
|
661
661
|
(attrMap[name] || (attrMap[name] = [])).push(attrs[index]);
|
|
@@ -742,7 +742,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
742
742
|
const customElementsInput = options.inlineCustomElements ?? [];
|
|
743
743
|
const customElementsArr = Array.isArray(customElementsInput) ? customElementsInput : Array.from(customElementsInput);
|
|
744
744
|
const normalizedCustomElements = customElementsArr.map(name => options.name(name));
|
|
745
|
-
// Fast path: Reuse base
|
|
745
|
+
// Fast path: Reuse base sets if no custom elements
|
|
746
746
|
const inlineTextSet = normalizedCustomElements.length
|
|
747
747
|
? new Set([...inlineElementsToKeepWhitespaceWithin, ...normalizedCustomElements])
|
|
748
748
|
: inlineElementsToKeepWhitespaceWithin;
|
|
@@ -762,7 +762,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
762
762
|
}
|
|
763
763
|
|
|
764
764
|
// Temporarily replace ignored chunks with comments, so that we don’t have to worry what’s there.
|
|
765
|
-
// For all we care there might be completely-horribly-broken-alien-non-html-
|
|
765
|
+
// For all we care there might be completely-horribly-broken-alien-non-html-emoji-cthulhu-filled content
|
|
766
766
|
value = value.replace(/<!-- htmlmin:ignore -->([\s\S]*?)<!-- htmlmin:ignore -->/g, function (match, group1) {
|
|
767
767
|
if (!uidIgnore) {
|
|
768
768
|
uidIgnore = uniqueId(value);
|
|
@@ -783,7 +783,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
783
783
|
// Create sort functions after `htmlmin:ignore` processing but before custom fragment UID markers
|
|
784
784
|
// This allows proper frequency analysis with access to ignored content via UID tokens
|
|
785
785
|
if ((options.sortAttributes && typeof options.sortAttributes !== 'function') ||
|
|
786
|
-
|
|
786
|
+
(options.sortClassName && typeof options.sortClassName !== 'function')) {
|
|
787
787
|
await createSortFns(value, options, uidIgnore, null, ignoredMarkupChunks);
|
|
788
788
|
}
|
|
789
789
|
|
|
@@ -845,12 +845,12 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
845
845
|
});
|
|
846
846
|
}
|
|
847
847
|
|
|
848
|
-
function
|
|
849
|
-
return options.canCollapseWhitespace(tag, attrs,
|
|
848
|
+
function canCollapseWhitespace(tag, attrs) {
|
|
849
|
+
return options.canCollapseWhitespace(tag, attrs, defaultCanCollapseWhitespace);
|
|
850
850
|
}
|
|
851
851
|
|
|
852
|
-
function
|
|
853
|
-
return options.canTrimWhitespace(tag, attrs,
|
|
852
|
+
function canTrimWhitespace(tag, attrs) {
|
|
853
|
+
return options.canTrimWhitespace(tag, attrs, defaultCanTrimWhitespace);
|
|
854
854
|
}
|
|
855
855
|
|
|
856
856
|
function removeStartTag() {
|
|
@@ -871,12 +871,12 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
871
871
|
|
|
872
872
|
// Look for trailing whitespaces, bypass any inline tags
|
|
873
873
|
function trimTrailingWhitespace(index, nextTag) {
|
|
874
|
-
for (let endTag = null; index >= 0 &&
|
|
874
|
+
for (let endTag = null; index >= 0 && canTrimWhitespace(endTag); index--) {
|
|
875
875
|
const str = buffer[index];
|
|
876
876
|
const match = str.match(/^<\/([\w:-]+)>$/);
|
|
877
877
|
if (match) {
|
|
878
878
|
endTag = match[1];
|
|
879
|
-
} else if (/>$/.test(str) || (buffer[index] = collapseWhitespaceSmart(str, null, nextTag, options, inlineElements, inlineTextSet))) {
|
|
879
|
+
} else if (/>$/.test(str) || (buffer[index] = collapseWhitespaceSmart(str, null, nextTag, [], [], options, inlineElements, inlineTextSet))) {
|
|
880
880
|
break;
|
|
881
881
|
}
|
|
882
882
|
}
|
|
@@ -925,10 +925,10 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
925
925
|
|
|
926
926
|
let optional = options.removeOptionalTags;
|
|
927
927
|
if (optional) {
|
|
928
|
-
const htmlTag =
|
|
928
|
+
const htmlTag = htmlElements.has(tag);
|
|
929
929
|
// `<html>` may be omitted if first thing inside is not a comment
|
|
930
930
|
// `<head>` may be omitted if first thing inside is an element
|
|
931
|
-
// `<body>` may be omitted if first thing inside is not space, comment, `<meta>`, `<link>`, `<script>`,
|
|
931
|
+
// `<body>` may be omitted if first thing inside is not space, comment, `<meta>`, `<link>`, `<script>`, `<style>`, or `<template>`
|
|
932
932
|
// `<colgroup>` may be omitted if first thing inside is `<col>`
|
|
933
933
|
// `<tbody>` may be omitted if first thing inside is `<tr>`
|
|
934
934
|
if (htmlTag && canRemoveParentTag(optionalStartTag, tag)) {
|
|
@@ -945,16 +945,16 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
945
945
|
optionalEndTag = '';
|
|
946
946
|
}
|
|
947
947
|
|
|
948
|
-
// Set whitespace flags for nested tags (e.g.,
|
|
948
|
+
// Set whitespace flags for nested tags (e.g., `<code>` within a `<pre>`)
|
|
949
949
|
if (options.collapseWhitespace) {
|
|
950
950
|
if (!stackNoTrimWhitespace.length) {
|
|
951
951
|
squashTrailingWhitespace(tag);
|
|
952
952
|
}
|
|
953
953
|
if (!unary) {
|
|
954
|
-
if (!
|
|
954
|
+
if (!canTrimWhitespace(tag, attrs) || stackNoTrimWhitespace.length) {
|
|
955
955
|
stackNoTrimWhitespace.push(tag);
|
|
956
956
|
}
|
|
957
|
-
if (!
|
|
957
|
+
if (!canCollapseWhitespace(tag, attrs) || stackNoCollapseWhitespace.length) {
|
|
958
958
|
stackNoCollapseWhitespace.push(tag);
|
|
959
959
|
}
|
|
960
960
|
}
|
|
@@ -1010,7 +1010,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1010
1010
|
squashTrailingWhitespace('/' + tag);
|
|
1011
1011
|
}
|
|
1012
1012
|
if (stackNoCollapseWhitespace.length &&
|
|
1013
|
-
|
|
1013
|
+
tag === stackNoCollapseWhitespace[stackNoCollapseWhitespace.length - 1]) {
|
|
1014
1014
|
stackNoCollapseWhitespace.pop();
|
|
1015
1015
|
}
|
|
1016
1016
|
}
|
|
@@ -1023,7 +1023,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1023
1023
|
|
|
1024
1024
|
if (options.removeOptionalTags) {
|
|
1025
1025
|
// `<html>`, `<head>` or `<body>` may be omitted if the element is empty
|
|
1026
|
-
if (isElementEmpty &&
|
|
1026
|
+
if (isElementEmpty && topLevelElements.has(optionalStartTag)) {
|
|
1027
1027
|
removeStartTag();
|
|
1028
1028
|
}
|
|
1029
1029
|
optionalStartTag = '';
|
|
@@ -1031,7 +1031,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1031
1031
|
// `</head>` may be omitted if not followed by space or comment
|
|
1032
1032
|
// `</p>` may be omitted if no more content in non-`</a>` parent
|
|
1033
1033
|
// except for `</dt>` or `</thead>`, end tags may be omitted if no more content in parent element
|
|
1034
|
-
if (tag && optionalEndTag && !
|
|
1034
|
+
if (tag && optionalEndTag && !trailingElements.has(optionalEndTag) && (optionalEndTag !== 'p' || !pInlineElements.has(tag))) {
|
|
1035
1035
|
removeEndTag();
|
|
1036
1036
|
}
|
|
1037
1037
|
optionalEndTag = optionalEndTags.has(tag) ? tag : '';
|
|
@@ -1078,10 +1078,12 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1078
1078
|
}
|
|
1079
1079
|
}
|
|
1080
1080
|
},
|
|
1081
|
-
chars: async function (text, prevTag, nextTag) {
|
|
1081
|
+
chars: async function (text, prevTag, nextTag, prevAttrs, nextAttrs) {
|
|
1082
1082
|
prevTag = prevTag === '' ? 'comment' : prevTag;
|
|
1083
1083
|
nextTag = nextTag === '' ? 'comment' : nextTag;
|
|
1084
|
-
|
|
1084
|
+
prevAttrs = prevAttrs || [];
|
|
1085
|
+
nextAttrs = nextAttrs || [];
|
|
1086
|
+
if (options.decodeEntities && text && !specialContentElements.has(currentTag)) {
|
|
1085
1087
|
if (text.indexOf('&') !== -1) {
|
|
1086
1088
|
text = decodeHTML(text);
|
|
1087
1089
|
}
|
|
@@ -1117,7 +1119,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1117
1119
|
}
|
|
1118
1120
|
}
|
|
1119
1121
|
if (prevTag || nextTag) {
|
|
1120
|
-
text = collapseWhitespaceSmart(text, prevTag, nextTag, options, inlineElements, inlineTextSet);
|
|
1122
|
+
text = collapseWhitespaceSmart(text, prevTag, nextTag, prevAttrs, nextAttrs, options, inlineElements, inlineTextSet);
|
|
1121
1123
|
} else {
|
|
1122
1124
|
text = collapseWhitespace(text, options, true, true);
|
|
1123
1125
|
}
|
|
@@ -1129,13 +1131,13 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1129
1131
|
text = collapseWhitespace(text, options, false, false, true);
|
|
1130
1132
|
}
|
|
1131
1133
|
}
|
|
1132
|
-
if (
|
|
1134
|
+
if (specialContentElements.has(currentTag) && (options.processScripts || hasJsonScriptType(currentAttrs))) {
|
|
1133
1135
|
text = await processScript(text, options, currentAttrs, minifyHTML);
|
|
1134
1136
|
}
|
|
1135
1137
|
if (isExecutableScript(currentTag, currentAttrs)) {
|
|
1136
1138
|
text = await options.minifyJS(text);
|
|
1137
1139
|
}
|
|
1138
|
-
if (
|
|
1140
|
+
if (isStyleElement(currentTag, currentAttrs)) {
|
|
1139
1141
|
text = await options.minifyCSS(text);
|
|
1140
1142
|
}
|
|
1141
1143
|
if (options.removeOptionalTags && text) {
|
|
@@ -1147,7 +1149,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1147
1149
|
optionalStartTag = '';
|
|
1148
1150
|
// `</html>` or `</body>` may be omitted if not followed by comment
|
|
1149
1151
|
// `</head>`, `</colgroup>`, or `</caption>` may be omitted if not followed by space or comment
|
|
1150
|
-
if (
|
|
1152
|
+
if (compactElements.has(optionalEndTag) || (looseElements.has(optionalEndTag) && !/^\s/.test(text))) {
|
|
1151
1153
|
removeEndTag();
|
|
1152
1154
|
}
|
|
1153
1155
|
// Don’t reset optionalEndTag if text is only whitespace and will be collapsed (not conservatively)
|
|
@@ -1156,11 +1158,11 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1156
1158
|
}
|
|
1157
1159
|
}
|
|
1158
1160
|
charsPrevTag = /^\s*$/.test(text) ? prevTag : 'comment';
|
|
1159
|
-
if (options.decodeEntities && text && !
|
|
1161
|
+
if (options.decodeEntities && text && !specialContentElements.has(currentTag)) {
|
|
1160
1162
|
// Escape any `&` symbols that start either:
|
|
1161
|
-
// 1) a legacy
|
|
1163
|
+
// 1) a legacy-named character reference (i.e., one that doesn’t end with `;`)
|
|
1162
1164
|
// 2) or any other character reference (i.e., one that does end with `;`)
|
|
1163
|
-
// Note that `&` can be escaped as `&`, without the
|
|
1165
|
+
// Note that `&` can be escaped as `&`, without the semicolon.
|
|
1164
1166
|
// https://mathiasbynens.be/notes/ambiguous-ampersands
|
|
1165
1167
|
if (text.indexOf('&') !== -1) {
|
|
1166
1168
|
text = text.replace(RE_LEGACY_ENTITIES, '&$1');
|
|
@@ -1225,7 +1227,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1225
1227
|
|
|
1226
1228
|
// Only collapse whitespace if both blocks contain HTML (start with `<`)
|
|
1227
1229
|
// Don’t collapse if either contains plain text, as that would change meaning
|
|
1228
|
-
// Note: This check will match HTML comments (`<!-- … -->`), but the tag
|
|
1230
|
+
// Note: This check will match HTML comments (`<!-- … -->`), but the tag name
|
|
1229
1231
|
// regex below requires starting with a letter, so comments are intentionally
|
|
1230
1232
|
// excluded by the `currentTagMatch && prevTagMatch` guard
|
|
1231
1233
|
if (currentContent && prevContent && /^\s*</.test(currentContent) && /^\s*</.test(prevContent)) {
|
|
@@ -1286,11 +1288,11 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1286
1288
|
if (options.removeOptionalTags) {
|
|
1287
1289
|
// `<html>` may be omitted if first thing inside is not a comment
|
|
1288
1290
|
// `<head>` or `<body>` may be omitted if empty
|
|
1289
|
-
if (
|
|
1291
|
+
if (topLevelElements.has(optionalStartTag)) {
|
|
1290
1292
|
removeStartTag();
|
|
1291
1293
|
}
|
|
1292
1294
|
// except for `</dt>` or `</thead>`, end tags may be omitted if no more content in parent element
|
|
1293
|
-
if (optionalEndTag && !
|
|
1295
|
+
if (optionalEndTag && !trailingElements.has(optionalEndTag)) {
|
|
1294
1296
|
removeEndTag();
|
|
1295
1297
|
}
|
|
1296
1298
|
}
|