html-minifier-next 8.1.1 → 8.2.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 +1 -1
- package/dist/types/htmlminifier.d.ts +3 -1
- package/dist/types/htmlminifier.d.ts.map +1 -1
- package/dist/types/htmlparser.d.ts +1 -0
- package/dist/types/htmlparser.d.ts.map +1 -1
- package/dist/types/lib/attributes.d.ts.map +1 -1
- package/dist/types/lib/constants.d.ts +6 -1
- package/dist/types/lib/constants.d.ts.map +1 -1
- package/dist/types/lib/options.d.ts +2 -0
- package/dist/types/lib/options.d.ts.map +1 -1
- package/dist/types/lib/utils.d.ts +2 -1
- package/dist/types/lib/utils.d.ts.map +1 -1
- package/dist/types/lib/whitespace.d.ts.map +1 -1
- package/html-minifier-next.schema.json +1 -1
- package/package.json +3 -3
- package/src/htmlminifier.js +68 -16
- package/src/htmlparser.js +174 -73
- package/src/lib/attributes.js +2 -0
- package/src/lib/constants.js +34 -1
- package/src/lib/option-definitions.js +1 -1
- package/src/lib/options.js +1 -0
- package/src/lib/utils.js +4 -3
- package/src/lib/whitespace.js +4 -2
package/README.md
CHANGED
|
@@ -149,7 +149,7 @@ Options can be used in config files (camelCase) or via CLI flags (kebab-case wit
|
|
|
149
149
|
| `ignoreCustomFragments`<br>`--ignore-custom-fragments` | Array of regexes that allow to ignore certain fragments, when matched (e.g., `<?php … ?>`, `{{ … }}`, etc.) | `[ /<%[\s\S]*?%>/, /<\?[\s\S]*?\?>/ ]` |
|
|
150
150
|
| `includeAutoGeneratedTags`<br>`--include-auto-generated-tags` | Insert elements generated by HTML parser | `false` |
|
|
151
151
|
| `inlineCustomElements`<br>`--inline-custom-elements` | Array of names of custom elements which are inline, for whitespace handling | `[]` |
|
|
152
|
-
| `keepClosingSlash`<br>`--keep-closing-slash` | Keep the trailing slash on void elements | `false` |
|
|
152
|
+
| `keepClosingSlash`<br>`--keep-closing-slash` | Keep the trailing slash on void elements and other start tags that carry one, and read it as closing the element | `false` |
|
|
153
153
|
| `maxInputLength`<br>`--max-input-length` | Maximum input length to prevent ReDoS attacks (disabled by default) | `undefined` |
|
|
154
154
|
| `maxLineLength`<br>`--max-line-length` | Specify a maximum line length; compressed output will be split by newlines at valid HTML split-points | `undefined` |
|
|
155
155
|
| `mergeScripts`<br>`--merge-scripts` | Merge consecutive inline `script` elements into one (only merges compatible scripts with same `type`, matching `async`/`defer`/`nomodule`/`nonce`) | `false` |
|
|
@@ -191,7 +191,9 @@ export type MinifierOptions = {
|
|
|
191
191
|
*/
|
|
192
192
|
inlineCustomElements?: ArrayLike<string>;
|
|
193
193
|
/**
|
|
194
|
-
*
|
|
194
|
+
* Keep the trailing slash on void elements and other start tags that carry one, and read it
|
|
195
|
+
* as closing the element. The default drops the slash and ignores it, as HTML does; in SVG
|
|
196
|
+
* and MathML a slash closes the element either way.
|
|
195
197
|
*
|
|
196
198
|
* Default: `false`
|
|
197
199
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,7 @@ export type HTMLParserHandler = {
|
|
|
7
7
|
continueOnParseError?: boolean | undefined;
|
|
8
8
|
partialMarkup?: boolean | undefined;
|
|
9
9
|
wantsNextTag?: boolean | undefined;
|
|
10
|
+
selfClosingSlash?: boolean | undefined;
|
|
10
11
|
customAttrSurround?: RegExp[][] | undefined;
|
|
11
12
|
customAttrAssign?: RegExp[] | undefined;
|
|
12
13
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"htmlparser.d.ts","sourceRoot":"","sources":["../../src/htmlparser.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"htmlparser.d.ts","sourceRoot":"","sources":["../../src/htmlparser.js"],"names":[],"mappings":"AAeG,YAYG,iBAAiB,GAZV;IACR,KAAK,CAAC,WAAW;IACjB,GAAG,CAAC,WAAW;IACf,KAAK,CAAC,WAAW;IACjB,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,WAAW;IACnB,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3C,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACpC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,kBAAkB,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,SAAS,CAAC;IAC5C,gBAAgB,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;CACxC,CAAmB;AA0CvB,eAAO,MAAM,MAAM,QAA8C,CAAC;AAoJlE,qBAAa,UAAU;IAMd,IAAI;IACJ,OAAO;IANd;;;OAGG;IACH,YAAY,IAAI,EAHL,MAGK,EAAE,OAAO,EAFd,iBAEc,EAGxB;IAEK,KAAK,kBA4uBV;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../src/lib/attributes.js"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"attributes.d.ts","sourceRoot":"","sources":["../../../src/lib/attributes.js"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,8 @@ declare const RE_TRAILING_SEMICOLON: RegExp;
|
|
|
13
13
|
declare const RE_AMP_ENTITY: RegExp;
|
|
14
14
|
declare const RE_LEGACY_ENTITIES: RegExp;
|
|
15
15
|
declare const RE_ESCAPE_LT: RegExp;
|
|
16
|
+
declare const RE_ESCAPE_LT_RAW_TEXT: Record<string, RegExp>;
|
|
17
|
+
declare const RE_HTML_ENCODING: RegExp;
|
|
16
18
|
declare const RE_ATTR_WS_CHECK: RegExp;
|
|
17
19
|
declare const RE_ATTR_WS_COLLAPSE: RegExp;
|
|
18
20
|
declare const RE_ATTR_WS_TRIM: RegExp;
|
|
@@ -97,5 +99,8 @@ declare const looseElements: Set<string>;
|
|
|
97
99
|
declare const trailingElements: Set<string>;
|
|
98
100
|
declare const htmlElements: Set<string>;
|
|
99
101
|
declare const specialContentElements: Set<string>;
|
|
100
|
-
|
|
102
|
+
declare const genericRawTextElements: Set<string>;
|
|
103
|
+
declare const escapableRawTextElements: Set<string>;
|
|
104
|
+
declare const rawTextElements: Set<string>;
|
|
105
|
+
export { RE_WS_START, RE_WS_END, RE_WS_ONLY, RE_WS_NBSP_END, RE_ALL_WS_NBSP, RE_NBSP_LEADING_GROUP, RE_NBSP_LEAD_GROUP, RE_NBSP_TRAILING_GROUP, RE_NBSP_TRAILING_STRIP, RE_EVENT_ATTR_DEFAULT, RE_CAN_REMOVE_ATTR_QUOTES, RE_TRAILING_SEMICOLON, RE_AMP_ENTITY, RE_LEGACY_ENTITIES, RE_ESCAPE_LT, RE_ESCAPE_LT_RAW_TEXT, RE_HTML_ENCODING, RE_ATTR_WS_CHECK, RE_ATTR_WS_COLLAPSE, RE_ATTR_WS_TRIM, RE_STYLE_ELEMENT, RE_EMPTY_ATTRIBUTE, inlineElementsToKeepWhitespaceAround, inlineElementsToKeepWhitespaceWithin, inlineElementsToKeepWhitespace, formControlElements, generalDefaults, tagDefaults, executableScriptsMimetypes, keepScriptsMimetypes, jsonScriptTypes, isSimpleBoolean, isBooleanValue, collapsibleValues, srcsetElements, optionalStartTags, optionalEndTags, headerElements, descriptionElements, pBlockElements, pInlineElements, rubyEndTagOmission, rubyRtcEndTagOmission, optionElements, tableContentElements, tableSectionElements, cellElements, topLevelElements, compactElements, looseElements, trailingElements, htmlElements, specialContentElements, genericRawTextElements, escapableRawTextElements, rawTextElements };
|
|
101
106
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.js"],"names":[],"mappings":"AAEA,QAAA,MAAM,WAAW,QAAkB,CAAC;AACpC,QAAA,MAAM,SAAS,QAAkB,CAAC;AAClC,QAAA,MAAM,UAAU,QAAmB,CAAC;AACpC,QAAA,MAAM,cAAc,QAAqB,CAAC;AAC1C,QAAA,MAAM,cAAc,QAAsB,CAAC;AAC3C,QAAA,MAAM,qBAAqB,QAAuB,CAAC;AACnD,QAAA,MAAM,kBAAkB,QAAqB,CAAC;AAC9C,QAAA,MAAM,sBAAsB,QAAqB,CAAC;AAClD,QAAA,MAAM,sBAAsB,QAAc,CAAC;AAC3C,QAAA,MAAM,qBAAqB,QAAkB,CAAC;AAC9C,QAAA,MAAM,yBAAyB,QAA0B,CAAC;AAC1D,QAAA,MAAM,qBAAqB,QAAO,CAAC;AACnC,QAAA,MAAM,aAAa,QAAwB,CAAC;AAC5C,QAAA,MAAM,kBAAkB,QAA+oB,CAAC;AACxqB,QAAA,MAAM,YAAY,QAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/constants.js"],"names":[],"mappings":"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"}
|
|
@@ -25,6 +25,7 @@ export type ProcessedOptions = Omit<MinifierOptions, 'preset' | 'canCollapseWhit
|
|
|
25
25
|
cssContext?: CSSContext;
|
|
26
26
|
nameParent?: (name: string) => string;
|
|
27
27
|
nameHTML?: (name: string) => string;
|
|
28
|
+
keepClosingSlashHTML?: boolean;
|
|
28
29
|
insideSVG?: boolean;
|
|
29
30
|
insideForeignContent?: boolean;
|
|
30
31
|
};
|
|
@@ -63,6 +64,7 @@ export type ProcessedOptions = Omit<MinifierOptions, 'preset' | 'canCollapseWhit
|
|
|
63
64
|
* cssContext?: CSSContext,
|
|
64
65
|
* nameParent?: (name: string) => string,
|
|
65
66
|
* nameHTML?: (name: string) => string,
|
|
67
|
+
* keepClosingSlashHTML?: boolean,
|
|
66
68
|
* insideSVG?: boolean,
|
|
67
69
|
* insideForeignContent?: boolean
|
|
68
70
|
* }} ProcessedOptions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../src/lib/options.js"],"names":[],"mappings":"AACA,OAAO,EAAE,GAAG,EAAwI,MAAM,YAAY,CAAC;AAQnK,OAAQ,KAAA,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AASrE,YAA4D,UAAU,GAA5D;IAAC,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAAC,CAAY;AAOtE,YAA6C,SAAS,GAA5C;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAC,CAAW;AAUtD,
|
|
1
|
+
{"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../../src/lib/options.js"],"names":[],"mappings":"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"}
|
|
@@ -89,8 +89,9 @@ declare function describeQuantifierRisk(pattern: RegExp | string): string | null
|
|
|
89
89
|
* over quoted attribute values (which may contain `>`).
|
|
90
90
|
* @param {string} html
|
|
91
91
|
* @param {number} pos - Start position (just after the tag name)
|
|
92
|
+
* @param {number} [limit] - Position to stop the search at (exclusive)
|
|
92
93
|
* @returns {number} Index of the closing `>`, or -1 if not found
|
|
93
94
|
*/
|
|
94
|
-
declare function findTagEnd(html: string, pos: number): number;
|
|
95
|
+
declare function findTagEnd(html: string, pos: number, limit?: number): number;
|
|
95
96
|
export { stableStringify, findTagEnd, LRU, MAX_CACHE_ENTRY_SIZE, hashContent, uniqueId, identity, isThenable, lowercase, replaceAsync, parseRegExp, embedSource, lostFlag, describeQuantifierRisk };
|
|
96
97
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.js"],"names":[],"mappings":"AAEA;;;GAGG;AACH,iBAAS,eAAe,CAAC,GAAG,EAHjB,OAGiB,GAFf,MAAM,CAYlB;AAID,cAAM,GAAG;IAEA,KAAK;IACL,IAAI;IACJ,IAAI;IACT,mCAAmC;IAC9B,GAAG,EADG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAJjC,YAAY,KAAK,SAAM,EAMtB;IACD,0BAA0B;IAC1B,GAAG,CAAC,GAAG,EADK,MACL,WAUN;IACD;;;OAGG;IACH,GAAG,CAAC,GAAG,EAHI,MAGJ,EAAE,KAAK,EAFH,OAEG,QAOb;IACD,0BAA0B;IAC1B,MAAM,CAAC,GAAG,EADE,MACF,QAA2B;IACrC,6EAA6E;IAC7E,KAAK,IADS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAGxE;CACF;AAKD,QAAA,MAAM,oBAAoB,QAAc,CAAC;AAIzC,0BAA0B;AAC1B,iBAAS,WAAW,CAAC,GAAG,EADZ,MACY,UAOvB;AAID,4BAA4B;AAC5B,iBAAS,QAAQ,CAAC,KAAK,EADX,MACW,UAMtB;AAID,4BAA4B;AAC5B,iBAAS,QAAQ,CAAC,KAAK,EADX,MACW,UAEtB;AAED;;;GAGG;AACH,iBAAS,UAAU,CAAC,KAAK,EAHd,OAGc,GAFZ,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,CAIrC;AAED,4BAA4B;AAC5B,iBAAS,SAAS,CAAC,KAAK,EADZ,MACY,UAEvB;AAID;;;;;;GAMG;AACH,iBAAe,YAAY,CAAC,GAAG,EALpB,MAKoB,EAAE,KAAK,EAJ3B,MAI2B,EAAE,OAAO,UAAA,GAFlC,OAAO,CAAC,MAAM,CAAC,CAe3B;AAID,qCAAqC;AACrC,iBAAS,WAAW,CAAC,KAAK,EADd,MAAM,GAAG,MACK,sBAUzB;AAyYD;;;;;;;;;GASG;AACH,iBAAS,QAAQ,CAAC,OAAO,EAJd,MAIc,GAHZ,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAqDlC;AAED;;;;;;;;;GASG;AACH,iBAAS,WAAW,CAAC,OAAO,EAHjB,MAGiB,GAFf,MAAM,CAOlB;AAGE,YAA6D,MAAM,GAAzD;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,IAAI,CAAA;CAAC,CAE7D;AAqKD;;;;;GAKG;AACH,iBAAS,sBAAsB,CAAC,OAAO,EAL5B,MAAM,GAAG,MAKmB,GAH1B,MAAM,GAAG,IAAI,CAqBzB;AAED
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.js"],"names":[],"mappings":"AAEA;;;GAGG;AACH,iBAAS,eAAe,CAAC,GAAG,EAHjB,OAGiB,GAFf,MAAM,CAYlB;AAID,cAAM,GAAG;IAEA,KAAK;IACL,IAAI;IACJ,IAAI;IACT,mCAAmC;IAC9B,GAAG,EADG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAJjC,YAAY,KAAK,SAAM,EAMtB;IACD,0BAA0B;IAC1B,GAAG,CAAC,GAAG,EADK,MACL,WAUN;IACD;;;OAGG;IACH,GAAG,CAAC,GAAG,EAHI,MAGJ,EAAE,KAAK,EAFH,OAEG,QAOb;IACD,0BAA0B;IAC1B,MAAM,CAAC,GAAG,EADE,MACF,QAA2B;IACrC,6EAA6E;IAC7E,KAAK,IADS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAGxE;CACF;AAKD,QAAA,MAAM,oBAAoB,QAAc,CAAC;AAIzC,0BAA0B;AAC1B,iBAAS,WAAW,CAAC,GAAG,EADZ,MACY,UAOvB;AAID,4BAA4B;AAC5B,iBAAS,QAAQ,CAAC,KAAK,EADX,MACW,UAMtB;AAID,4BAA4B;AAC5B,iBAAS,QAAQ,CAAC,KAAK,EADX,MACW,UAEtB;AAED;;;GAGG;AACH,iBAAS,UAAU,CAAC,KAAK,EAHd,OAGc,GAFZ,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,CAIrC;AAED,4BAA4B;AAC5B,iBAAS,SAAS,CAAC,KAAK,EADZ,MACY,UAEvB;AAID;;;;;;GAMG;AACH,iBAAe,YAAY,CAAC,GAAG,EALpB,MAKoB,EAAE,KAAK,EAJ3B,MAI2B,EAAE,OAAO,UAAA,GAFlC,OAAO,CAAC,MAAM,CAAC,CAe3B;AAID,qCAAqC;AACrC,iBAAS,WAAW,CAAC,KAAK,EADd,MAAM,GAAG,MACK,sBAUzB;AAyYD;;;;;;;;;GASG;AACH,iBAAS,QAAQ,CAAC,OAAO,EAJd,MAIc,GAHZ,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAqDlC;AAED;;;;;;;;;GASG;AACH,iBAAS,WAAW,CAAC,OAAO,EAHjB,MAGiB,GAFf,MAAM,CAOlB;AAGE,YAA6D,MAAM,GAAzD;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,IAAI,CAAA;CAAC,CAE7D;AAqKD;;;;;GAKG;AACH,iBAAS,sBAAsB,CAAC,OAAO,EAL5B,MAAM,GAAG,MAKmB,GAH1B,MAAM,GAAG,IAAI,CAqBzB;AAED;;;;;;;GAOG;AACH,iBAAS,UAAU,CAAC,IAAI,EALb,MAKa,EAAE,GAAG,EAJlB,MAIkB,EAAE,KAAK,AAHjC,CACA,EADQ,MAGuC,GAFrC,MAAM,CAelB;AAID,OAAO,EACL,eAAe,EACf,UAAU,EACV,GAAG,EACH,oBAAoB,EACpB,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,WAAW,EACX,QAAQ,EACR,sBAAsB,EACvB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whitespace.d.ts","sourceRoot":"","sources":["../../../src/lib/whitespace.js"],"names":[],"mappings":"AAeA,0BAA0B;AAC1B,QAAA,MAAM,cAAc,QADR,MAAM,WAQjB,CAAC;AAIF,0BAA0B;AAC1B,iBAAS,qBAAqB,CAAC,GAAG,EADtB,MACsB,UAgBjC;AAID;;;;;;GAMG;AACH,iBAAS,kBAAkB,CAAC,GAAG,EANpB,MAMoB,EAAE,OAAO,EAL7B;IAAC,kBAAkB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAKxD,EAAE,QAAQ,EAJvC,OAIuC,EAAE,SAAS,EAHlD,OAGkD,EAAE,WAAW,AAFvE,CAA8B,EAAtB,OAEuE,UAqFjF;AAoBD;;;;;;;;;GASG;AACH,iBAAS,uBAAuB,CAAC,GAAG,EATzB,MASyB,EAAE,OAAO,EARlC,MAQkC,EAAE,OAAO,EAP3C,MAO2C,EAAE,SAAS,EANtD,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,CAMkB,EAAE,SAAS,EALjE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,CAK6B,EAAE,OAAO,EAJ1E;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAAC,2BAA2B,CAAC,EAAE,OAAO,CAAA;CAI1B,EAAE,cAAc,EAH1F,GAAG,CAAC,MAAM,CAGgF,EAAE,aAAa,EAFzG,GAAG,CAAC,MAAM,CAE+F,UAiEnH;
|
|
1
|
+
{"version":3,"file":"whitespace.d.ts","sourceRoot":"","sources":["../../../src/lib/whitespace.js"],"names":[],"mappings":"AAeA,0BAA0B;AAC1B,QAAA,MAAM,cAAc,QADR,MAAM,WAQjB,CAAC;AAIF,0BAA0B;AAC1B,iBAAS,qBAAqB,CAAC,GAAG,EADtB,MACsB,UAgBjC;AAID;;;;;;GAMG;AACH,iBAAS,kBAAkB,CAAC,GAAG,EANpB,MAMoB,EAAE,OAAO,EAL7B;IAAC,kBAAkB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAKxD,EAAE,QAAQ,EAJvC,OAIuC,EAAE,SAAS,EAHlD,OAGkD,EAAE,WAAW,AAFvE,CAA8B,EAAtB,OAEuE,UAqFjF;AAoBD;;;;;;;;;GASG;AACH,iBAAS,uBAAuB,CAAC,GAAG,EATzB,MASyB,EAAE,OAAO,EARlC,MAQkC,EAAE,OAAO,EAP3C,MAO2C,EAAE,SAAS,EANtD,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,CAMkB,EAAE,SAAS,EALjE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,CAK6B,EAAE,OAAO,EAJ1E;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAAC,2BAA2B,CAAC,EAAE,OAAO,CAAA;CAI1B,EAAE,cAAc,EAH1F,GAAG,CAAC,MAAM,CAGgF,EAAE,aAAa,EAFzG,GAAG,CAAC,MAAM,CAE+F,UAiEnH;AASD,0BAA0B;AAC1B,iBAAS,qBAAqB,CAAC,GAAG,EADtB,MACsB,WAEjC;AAED,0BAA0B;AAC1B,iBAAS,iBAAiB,CAAC,GAAG,EADlB,MACkB,WAE7B;AAID,OAAO,EACL,cAAc,EACd,qBAAqB,EACrB,kBAAkB,EAClB,uBAAuB,EACvB,qBAAqB,EACrB,iBAAiB,EAClB,CAAC"}
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
}
|
|
157
157
|
},
|
|
158
158
|
"keepClosingSlash": {
|
|
159
|
-
"description": "Keep the trailing slash on void elements",
|
|
159
|
+
"description": "Keep the trailing slash on void elements and other start tags that carry one, and read it as closing the element",
|
|
160
160
|
"type": "boolean"
|
|
161
161
|
},
|
|
162
162
|
"maxInputLength": {
|
package/package.json
CHANGED
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@commitlint/cli": "^21.2.2",
|
|
18
18
|
"@eslint/js": "^10.0.1",
|
|
19
|
-
"@swc/core": "^1.16.
|
|
19
|
+
"@swc/core": "^1.16.1",
|
|
20
20
|
"@types/node": "^26.2.0",
|
|
21
|
-
"eslint": "^10.
|
|
21
|
+
"eslint": "^10.9.1",
|
|
22
22
|
"globals": "^17.11.0",
|
|
23
23
|
"typescript": "^7.0.2",
|
|
24
24
|
"vite": "^8.2.1"
|
|
@@ -95,5 +95,5 @@
|
|
|
95
95
|
},
|
|
96
96
|
"type": "module",
|
|
97
97
|
"types": "dist/types/htmlminifier.d.ts",
|
|
98
|
-
"version": "8.
|
|
98
|
+
"version": "8.2.0"
|
|
99
99
|
}
|
package/src/htmlminifier.js
CHANGED
|
@@ -8,6 +8,8 @@ import { collectUsedSymbols } from './lib/unused-css.js';
|
|
|
8
8
|
import {
|
|
9
9
|
RE_LEGACY_ENTITIES,
|
|
10
10
|
RE_ESCAPE_LT,
|
|
11
|
+
RE_ESCAPE_LT_RAW_TEXT,
|
|
12
|
+
RE_HTML_ENCODING,
|
|
11
13
|
RE_WS_START,
|
|
12
14
|
RE_WS_END,
|
|
13
15
|
RE_WS_ONLY,
|
|
@@ -16,6 +18,7 @@ import {
|
|
|
16
18
|
inlineElementsToKeepWhitespaceAround,
|
|
17
19
|
inlineElementsToKeepWhitespaceWithin,
|
|
18
20
|
specialContentElements,
|
|
21
|
+
rawTextElements,
|
|
19
22
|
htmlElements,
|
|
20
23
|
optionalStartTags,
|
|
21
24
|
optionalEndTags,
|
|
@@ -244,7 +247,9 @@ import { toFragment, replaceCustomFragments } from './lib/fragments.js';
|
|
|
244
247
|
* Default: `[]`
|
|
245
248
|
*
|
|
246
249
|
* @prop {boolean} [keepClosingSlash]
|
|
247
|
-
*
|
|
250
|
+
* Keep the trailing slash on void elements and other start tags that carry one, and read it
|
|
251
|
+
* as closing the element. The default drops the slash and ignores it, as HTML does; in SVG
|
|
252
|
+
* and MathML a slash closes the element either way.
|
|
248
253
|
*
|
|
249
254
|
* Default: `false`
|
|
250
255
|
*
|
|
@@ -586,8 +591,6 @@ const RE_HTML_COMMENT_START = /^\s*<!--/;
|
|
|
586
591
|
const RE_CLOSING_TAG_START = /^\s*<\/([a-zA-Z][\w:-]*)/;
|
|
587
592
|
const RE_LAST_HTML_TAG = /[\s\S]*<(\/?[a-zA-Z][\w:-]*)/;
|
|
588
593
|
|
|
589
|
-
// HTML encoding types for annotation-xml (MathML)
|
|
590
|
-
const RE_HTML_ENCODING = /^(text\/html|application\/xhtml\+xml)$/i;
|
|
591
594
|
|
|
592
595
|
// Probe for SVG/MathML elements—when the input has none (the common case),
|
|
593
596
|
// the per-tag foreign-content machinery can be skipped entirely
|
|
@@ -764,7 +767,7 @@ async function createSortFns(value, options, uidIgnore, uidAttr, ignoredMarkupCh
|
|
|
764
767
|
/** @type {string | undefined} */
|
|
765
768
|
let currentType;
|
|
766
769
|
const parser = new HTMLParser(input, {
|
|
767
|
-
start: function (/** @type {string} */ tag, /** @type {HTMLAttribute[]} */ attrs) {
|
|
770
|
+
start: function (/** @type {string} */ tag, /** @type {HTMLAttribute[]} */ attrs, /** @type {boolean} */ unary) {
|
|
768
771
|
if (attrChains) {
|
|
769
772
|
if (!attrChains[tag]) {
|
|
770
773
|
attrChains[tag] = new TokenChain();
|
|
@@ -781,6 +784,11 @@ async function createSortFns(value, options, uidIgnore, uidAttr, ignoredMarkupCh
|
|
|
781
784
|
currentType = attr.value;
|
|
782
785
|
}
|
|
783
786
|
}
|
|
787
|
+
// As on the main path: What a unary tag holds ends with the tag, so no text can belong to it
|
|
788
|
+
if (unary) {
|
|
789
|
+
currentTag = '';
|
|
790
|
+
currentType = undefined;
|
|
791
|
+
}
|
|
784
792
|
},
|
|
785
793
|
end: function () {
|
|
786
794
|
currentTag = '';
|
|
@@ -797,7 +805,8 @@ async function createSortFns(value, options, uidIgnore, uidAttr, ignoredMarkupCh
|
|
|
797
805
|
// No need for `nextTag` information in this scan
|
|
798
806
|
wantsNextTag: false,
|
|
799
807
|
// Continue on parse errors during analysis pass
|
|
800
|
-
continueOnParseError: options.continueOnParseError
|
|
808
|
+
continueOnParseError: options.continueOnParseError,
|
|
809
|
+
selfClosingSlash: options.keepClosingSlash
|
|
801
810
|
});
|
|
802
811
|
|
|
803
812
|
try {
|
|
@@ -1123,6 +1132,14 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1123
1132
|
buffer.length = Math.max(0, index);
|
|
1124
1133
|
}
|
|
1125
1134
|
|
|
1135
|
+
// Whether the element being parsed holds text rather than markup. The namespace decides
|
|
1136
|
+
// this, not the name alone: `script` and `style` hold text wherever they stand, the rest
|
|
1137
|
+
// only as HTML elements—an SVG or MathML `title` holds markup like any foreign element
|
|
1138
|
+
function holdsRawText() {
|
|
1139
|
+
return specialContentElements.has(currentTag) ||
|
|
1140
|
+
(rawTextElements.has(currentTag) && !options.insideForeignContent);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1126
1143
|
// Whether whitespace-only text between tags survives minification
|
|
1127
1144
|
function keepsWhitespace() {
|
|
1128
1145
|
return !options.collapseWhitespace || Boolean(options.conservativeCollapse) || Boolean(options.preserveLineBreaks);
|
|
@@ -1348,7 +1365,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1348
1365
|
}
|
|
1349
1366
|
}
|
|
1350
1367
|
charsPrevTag = /^\s*$/.test(text) ? textPrevTag : 'comment';
|
|
1351
|
-
if (options.decodeEntities && text && !
|
|
1368
|
+
if (options.decodeEntities && text && !holdsRawText()) {
|
|
1352
1369
|
// Escape any `&` symbols that start either:
|
|
1353
1370
|
// 1. a legacy-named character reference (i.e., one that doesn’t end with `;`)
|
|
1354
1371
|
// 2. or any other character reference (i.e., one that does end with `;`)
|
|
@@ -1358,7 +1375,10 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1358
1375
|
text = text.replace(RE_LEGACY_ENTITIES, '&$1');
|
|
1359
1376
|
}
|
|
1360
1377
|
if (text.indexOf('<') !== -1) {
|
|
1361
|
-
text
|
|
1378
|
+
// Escapable raw text ends at its own end tag alone, so only that one needs escaping;
|
|
1379
|
+
// in foreign content the same element holds markup, where every `<` does
|
|
1380
|
+
const escapeLt = (options.insideForeignContent ? undefined : RE_ESCAPE_LT_RAW_TEXT[currentTag]) ?? RE_ESCAPE_LT;
|
|
1381
|
+
text = text.replace(escapeLt, '<');
|
|
1362
1382
|
}
|
|
1363
1383
|
}
|
|
1364
1384
|
if (uidPattern && options.collapseWhitespace && stackNoTrimWhitespace.length) {
|
|
@@ -1502,43 +1522,61 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1502
1522
|
customAttrSurround: options.customAttrSurround,
|
|
1503
1523
|
// Compute `nextTag` only when whitespace collapse features require it
|
|
1504
1524
|
wantsNextTag: !!(options.collapseWhitespace || options.collapseInlineTagWhitespace || options.conservativeCollapse),
|
|
1525
|
+
// `keepClosingSlash` calls the slash meaningful, which decides how the input is read as well
|
|
1526
|
+
selfClosingSlash: options.keepClosingSlash,
|
|
1505
1527
|
|
|
1506
1528
|
start: async function (/** @type {string} */ tag, /** @type {HTMLAttribute[]} */ attrs, /** @type {boolean} */ unary, /** @type {string} */ unarySlash, /** @type {boolean} */ autoGenerated) {
|
|
1507
1529
|
// `lowerTag` stays '' when no foreign content is around—the SVG/MathML
|
|
1508
1530
|
// checks below can then never match, and no per-tag lowercasing is needed
|
|
1509
1531
|
let lowerTag = '';
|
|
1510
1532
|
let useNameParentForTag = false;
|
|
1533
|
+
// The context the start tag sits in, which the branches below leave behind
|
|
1534
|
+
const optionsParent = options;
|
|
1535
|
+
let pushedContext = false;
|
|
1511
1536
|
if (hasForeignContext) {
|
|
1512
1537
|
lowerTag = tag.toLowerCase();
|
|
1513
1538
|
if (lowerTag === 'svg' || lowerTag === 'math') {
|
|
1514
1539
|
// Preserve the surrounding HTML context’s name function (e.g., `identity`
|
|
1515
|
-
// under `caseSensitive`) so `foreignObject`/`annotation-xml`
|
|
1540
|
+
// under `caseSensitive`) and slash handling so `foreignObject`/`annotation-xml`
|
|
1541
|
+
// can restore them
|
|
1516
1542
|
const nameHTML = options.name;
|
|
1543
|
+
const keepClosingSlashHTML = Boolean(options.keepClosingSlash);
|
|
1517
1544
|
options = Object.create(options);
|
|
1518
1545
|
options.caseSensitive = true;
|
|
1519
1546
|
options.keepClosingSlash = true;
|
|
1520
1547
|
options.name = identity;
|
|
1521
1548
|
options.nameHTML = nameHTML;
|
|
1522
|
-
options.
|
|
1549
|
+
options.keepClosingSlashHTML = keepClosingSlashHTML;
|
|
1550
|
+
// SVGO reads an SVG block whole, nested MathML included, so what the block is stays true inside it
|
|
1551
|
+
options.insideSVG = lowerTag === 'svg' || Boolean(options.insideSVG);
|
|
1523
1552
|
options.insideForeignContent = true;
|
|
1524
1553
|
// Disable HTML-specific options that produce invalid XML:
|
|
1525
1554
|
// SVG with `minifySVG` enabled is passed to SVGO, which requires valid XML input;
|
|
1526
1555
|
// MathML is never processed by SVGO, so these restrictions never apply to it
|
|
1527
1556
|
if (lowerTag === 'svg' && options.minifySVG) {
|
|
1528
1557
|
options.removeAttributeQuotes = false;
|
|
1558
|
+
// @@ Encode a bare `&` for SVGO as well—it costs the block its optimization
|
|
1559
|
+
// (though not its validity; early fix could encode `&` where it’s unambiguous)
|
|
1529
1560
|
options.decodeEntities = false;
|
|
1561
|
+
// Omitting a start and end tag both would keep the block well-formed, which this misses
|
|
1562
|
+
options.removeOptionalTags = false;
|
|
1563
|
+
options.collapseBooleanAttributes = false;
|
|
1564
|
+
options.includeAutoGeneratedTags = true;
|
|
1530
1565
|
}
|
|
1531
1566
|
options.removeTagWhitespace = false;
|
|
1567
|
+
pushedContext = true;
|
|
1532
1568
|
}
|
|
1533
1569
|
// `foreignObject` in SVG and `annotation-xml` in MathML contain HTML content
|
|
1534
|
-
//
|
|
1570
|
+
// (the element itself is in SVG/MathML namespace, only its children are HTML);
|
|
1571
|
+
// a repeated attribute is dropped after the first, so the first `encoding` decides
|
|
1535
1572
|
if (options.insideForeignContent && (lowerTag === 'foreignobject' ||
|
|
1536
|
-
(lowerTag === 'annotation-xml' &&
|
|
1537
|
-
|
|
1573
|
+
(lowerTag === 'annotation-xml' && RE_HTML_ENCODING.test(
|
|
1574
|
+
attrs.find((/** @type {HTMLAttribute} */ a) => a.name.toLowerCase() === 'encoding')?.value ?? '')))) {
|
|
1538
1575
|
const nameParent = options.name;
|
|
1539
1576
|
options = Object.create(options);
|
|
1540
1577
|
options.caseSensitive = false;
|
|
1541
|
-
|
|
1578
|
+
// What the parser read the slash as, so that the two agree here as they do in HTML
|
|
1579
|
+
options.keepClosingSlash = options.keepClosingSlashHTML ?? false;
|
|
1542
1580
|
options.nameParent = nameParent; // Preserve for the element tag itself
|
|
1543
1581
|
options.name = options.nameHTML ?? lowercase;
|
|
1544
1582
|
options.insideForeignContent = false;
|
|
@@ -1546,6 +1584,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1546
1584
|
// stay disabled (inherited from SVG context) because the entire SVG block
|
|
1547
1585
|
// must be valid XML for SVGO processing
|
|
1548
1586
|
useNameParentForTag = true;
|
|
1587
|
+
pushedContext = true;
|
|
1549
1588
|
}
|
|
1550
1589
|
}
|
|
1551
1590
|
// `nameParent` is always set when `useNameParentForTag` is true; the extra check only narrows the type
|
|
@@ -1600,7 +1639,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1600
1639
|
}
|
|
1601
1640
|
|
|
1602
1641
|
// Track SVG subtree for SVGO block processing
|
|
1603
|
-
if (lowerTag === 'svg' && options.minifySVG) {
|
|
1642
|
+
if (lowerTag === 'svg' && options.minifySVG && !unary) {
|
|
1604
1643
|
if (svgDepth === 0) {
|
|
1605
1644
|
svgBufferStartIndex = buffer.length; // Record position before <svg> is pushed
|
|
1606
1645
|
}
|
|
@@ -1608,7 +1647,10 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1608
1647
|
}
|
|
1609
1648
|
|
|
1610
1649
|
const openTag = '<' + tag;
|
|
1611
|
-
|
|
1650
|
+
// SVGO reads the whole SVG block as XML, where an element closes itself or not, so
|
|
1651
|
+
// every unary element in there is written with a slash
|
|
1652
|
+
const needsXMLSlash = unary && Boolean(options.insideSVG) && Boolean(options.minifySVG);
|
|
1653
|
+
const hasUnarySlash = needsXMLSlash || (unarySlash && (useNameParentForTag ? optionsParent : options).keepClosingSlash);
|
|
1612
1654
|
|
|
1613
1655
|
buffer.push(openTag);
|
|
1614
1656
|
|
|
@@ -1662,6 +1704,16 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1662
1704
|
optionalStartTag = '';
|
|
1663
1705
|
currentTag = '';
|
|
1664
1706
|
}
|
|
1707
|
+
|
|
1708
|
+
// `end` restores what a start tag pushed, and a unary tag never reaches it
|
|
1709
|
+
if (unary && pushedContext) {
|
|
1710
|
+
options = optionsParent;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
// What a unary tag holds ends with the tag, so no text can belong to it
|
|
1714
|
+
if (unary) {
|
|
1715
|
+
currentTag = '';
|
|
1716
|
+
}
|
|
1665
1717
|
},
|
|
1666
1718
|
end: function (/** @type {string} */ tag, /** @type {HTMLAttribute[]} */ attrs, /** @type {boolean} */ autoGenerated) {
|
|
1667
1719
|
// As in `start`: `lowerTag` stays '' when no foreign content is around
|
|
@@ -1778,7 +1830,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1778
1830
|
textNextAttrs = nextAttrs || [];
|
|
1779
1831
|
|
|
1780
1832
|
// Detect whether any async work is actually needed for this text node
|
|
1781
|
-
const needsDecode = options.decodeEntities && text && !
|
|
1833
|
+
const needsDecode = options.decodeEntities && text && !holdsRawText() && text.indexOf('&') !== -1;
|
|
1782
1834
|
const needsProcessScript = specialContentElements.has(currentTag) && (options.processScripts || hasJsonScriptType(currentAttrs));
|
|
1783
1835
|
const needsMinifyJS = options.minifyJS !== identity && isExecutableScript(currentTag, currentAttrs);
|
|
1784
1836
|
const isModuleScript = needsMinifyJS && currentAttrs.some(
|
package/src/htmlparser.js
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { isThenable, embedSource } from './lib/utils.js';
|
|
8
|
+
import { isThenable, embedSource, findTagEnd } from './lib/utils.js';
|
|
9
|
+
import { escapableRawTextElements, genericRawTextElements, RE_HTML_ENCODING } from './lib/constants.js';
|
|
9
10
|
|
|
10
11
|
/** @import { HTMLAttribute } from './lib/attributes.js' */
|
|
11
12
|
|
|
@@ -21,6 +22,7 @@ import { isThenable, embedSource } from './lib/utils.js';
|
|
|
21
22
|
* continueOnParseError?: boolean | undefined,
|
|
22
23
|
* partialMarkup?: boolean | undefined,
|
|
23
24
|
* wantsNextTag?: boolean | undefined,
|
|
25
|
+
* selfClosingSlash?: boolean | undefined,
|
|
24
26
|
* customAttrSurround?: RegExp[][] | undefined,
|
|
25
27
|
* customAttrAssign?: RegExp[] | undefined
|
|
26
28
|
* }} HTMLParserHandler
|
|
@@ -64,6 +66,7 @@ const qnameCapture = (function () {
|
|
|
64
66
|
return '((?:' + ncname + '\\:)?' + ncname + ')';
|
|
65
67
|
})();
|
|
66
68
|
const startTagOpen = new RegExp('^<' + qnameCapture);
|
|
69
|
+
const endTagOpen = new RegExp('^</' + qnameCapture);
|
|
67
70
|
export const endTag = new RegExp('^</' + qnameCapture + '[^>]*>');
|
|
68
71
|
|
|
69
72
|
let IS_REGEX_CAPTURING_BROKEN = false;
|
|
@@ -84,45 +87,70 @@ const fillAttrs = new Set(['checked', 'compact', 'declare', 'defer', 'disabled',
|
|
|
84
87
|
// Special elements (can contain anything)
|
|
85
88
|
const special = new Set(['script', 'style']);
|
|
86
89
|
|
|
90
|
+
// Elements whose children are HTML rather than foreign content, each only in
|
|
91
|
+
// the namespace it belongs to (`annotation-xml` is one, too, but only for some
|
|
92
|
+
// `encoding` values, so it is checked separately)
|
|
93
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#html-integration-point
|
|
94
|
+
const svgIntegrationPoints = new Set(['foreignobject', 'desc', 'title']);
|
|
95
|
+
const mathIntegrationPoints = new Set(['mi', 'mo', 'mn', 'ms', 'mtext']);
|
|
96
|
+
|
|
87
97
|
// HTML elements, https://html.spec.whatwg.org/multipage/indices.html#elements-3
|
|
88
98
|
// Phrasing content, https://html.spec.whatwg.org/multipage/dom.html#phrasing-content
|
|
89
|
-
const nonPhrasing = new Set(['address', 'article', 'aside', 'base', 'blockquote', 'body', 'caption', 'col', 'colgroup', 'dd', 'details', 'dialog', 'div', 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'legend', 'li', 'menuitem', 'meta', 'ol', 'optgroup', 'option', 'param', 'rp', 'rt', 'source', 'style', 'summary', 'tbody', 'td', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul']);
|
|
90
|
-
|
|
91
|
-
const reCache = {};
|
|
99
|
+
const nonPhrasing = new Set(['address', 'article', 'aside', 'base', 'blockquote', 'body', 'caption', 'center', 'col', 'colgroup', 'dd', 'details', 'dialog', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'legend', 'li', 'listing', 'main', 'menu', 'menuitem', 'meta', 'nav', 'ol', 'optgroup', 'option', 'param', 'plaintext', 'pre', 'rp', 'rt', 'search', 'section', 'source', 'style', 'summary', 'table', 'tbody', 'td', 'tfoot', 'th', 'thead', 'title', 'tr', 'track', 'ul', 'xmp']);
|
|
92
100
|
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
const
|
|
96
|
-
'
|
|
97
|
-
'style': /([\s\S]*?)<\/style[^>]*>/i,
|
|
98
|
-
'noscript': /([\s\S]*?)<\/noscript[^>]*>/i
|
|
99
|
-
};
|
|
101
|
+
// A tag name ends at whitespace, a slash, or the closing bracket, so `</scriptx>` names a
|
|
102
|
+
// different element and does not end this one
|
|
103
|
+
const endsTagName = (/** @type {string} */ character) =>
|
|
104
|
+
character === '' || character === '/' || character === '>' || /\s/.test(character);
|
|
100
105
|
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
/**
|
|
107
|
+
* @param {string} text - The input the tag stands in
|
|
108
|
+
* @param {number} nameEnd - Position right after the tag name
|
|
109
|
+
* @returns {number} Position of the `>` that ends the tag, or -1 where none follows
|
|
110
|
+
*/
|
|
111
|
+
function findEndTagClose(text, nameEnd) {
|
|
112
|
+
const close = text.indexOf('>', nameEnd);
|
|
113
|
+
if (close === -1) {
|
|
114
|
+
return -1;
|
|
115
|
+
}
|
|
116
|
+
// A quoted attribute value can hold a `>` that does not end the tag it stands in, so a
|
|
117
|
+
// quote ahead of that bracket calls for a scan that knows about quoting. It stops at the
|
|
118
|
+
// next `<`, which no tag reaches past: The scans of consecutive tags then never overlap,
|
|
119
|
+
// and an unquoted value that spans one leaves the first bracket as the end, as before.
|
|
120
|
+
for (let index = nameEnd; index < close; index++) {
|
|
121
|
+
const character = text[index];
|
|
122
|
+
if (character === '"' || character === "'") {
|
|
123
|
+
const nextOpen = text.indexOf('<', nameEnd);
|
|
124
|
+
const quoted = findTagEnd(text, nameEnd, nextOpen === -1 ? text.length : nextOpen);
|
|
125
|
+
return quoted === -1 ? close : quoted;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return close;
|
|
129
|
+
}
|
|
103
130
|
|
|
104
|
-
// O(n) helper: Strip all occurrences of `open…close` delimiters, keeping inner content
|
|
105
|
-
// Used instead of a regex replace to avoid O(n²) behavior on adversarial inputs
|
|
106
131
|
/**
|
|
107
|
-
* @param {string}
|
|
108
|
-
* @param {string}
|
|
109
|
-
* @
|
|
132
|
+
* @param {string} text - The input from the start of the content on
|
|
133
|
+
* @param {string} tag - Lowercase element name
|
|
134
|
+
* @returns {{content: string, length: number} | null} What the element holds and how far it
|
|
135
|
+
* reaches, or `null` where no end tag of its own follows
|
|
110
136
|
*/
|
|
111
|
-
function
|
|
112
|
-
|
|
113
|
-
let
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
i = end + close.length;
|
|
137
|
+
function findRawTextEnd(text, tag) {
|
|
138
|
+
const nameEnd = tag.length + 2;
|
|
139
|
+
for (let candidate = text.indexOf('</'); candidate !== -1; candidate = text.indexOf('</', candidate + 2)) {
|
|
140
|
+
if (text.slice(candidate + 2, candidate + nameEnd).toLowerCase() !== tag || !endsTagName(text.charAt(candidate + nameEnd))) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
// What follows the name is not part of it, and the tag ends at the next bracket outside
|
|
144
|
+
// its attribute values—where none follows, no later end tag can be complete, either
|
|
145
|
+
const end = findEndTagClose(text, candidate + nameEnd);
|
|
146
|
+
return end === -1 ? null : { content: text.slice(0, candidate), length: end + 1 };
|
|
122
147
|
}
|
|
123
|
-
return
|
|
148
|
+
return null;
|
|
124
149
|
}
|
|
125
150
|
|
|
151
|
+
// Cache for compiled attribute regexes per handler configuration
|
|
152
|
+
const attrRegexCache = new WeakMap();
|
|
153
|
+
|
|
126
154
|
/** @param {HTMLParserHandler} handler */
|
|
127
155
|
function buildAttrRegex(handler) {
|
|
128
156
|
const unquotedValue = handler.continueOnParseError ? singleAttrValueLenientUnquoted : singleAttrValues[2];
|
|
@@ -202,7 +230,7 @@ export class HTMLParser {
|
|
|
202
230
|
const fullHtml = this.html;
|
|
203
231
|
const fullLength = fullHtml.length;
|
|
204
232
|
|
|
205
|
-
/** @type {Array<{tag: string, lowerTag: string, attrs: HTMLAttribute[]}>} */
|
|
233
|
+
/** @type {Array<{tag: string, lowerTag: string, attrs: HTMLAttribute[], namespace: string}>} */
|
|
206
234
|
const stack = [];
|
|
207
235
|
/** @type {string} */
|
|
208
236
|
let lastTag = '';
|
|
@@ -225,7 +253,7 @@ export class HTMLParser {
|
|
|
225
253
|
const startTagOpenY = new RegExp(startTagOpen.source.slice(1), 'y');
|
|
226
254
|
// `\s*` with sticky flag is O(n) at worst—no retry from different positions possible
|
|
227
255
|
const startTagCloseY = /\s*(\/?)>/y;
|
|
228
|
-
const
|
|
256
|
+
const endTagOpenY = new RegExp(endTagOpen.source.slice(1), 'y');
|
|
229
257
|
const doctypeY = /<!DOCTYPE[^<>]+>/iy;
|
|
230
258
|
const commentTestY = /<!--/y;
|
|
231
259
|
const conditionalTestY = /<!\[/y;
|
|
@@ -238,11 +266,11 @@ export class HTMLParser {
|
|
|
238
266
|
let pos = 0;
|
|
239
267
|
let lastPos;
|
|
240
268
|
|
|
241
|
-
// An end tag always ends at a `>`; without one, the
|
|
242
|
-
//
|
|
243
|
-
// (e.g., `</aaaa…` with no `>`). Track the next `>` monotonically
|
|
244
|
-
// advances, so the aggregate scan work stays O(n)—and skip the
|
|
245
|
-
// lies ahead, where
|
|
269
|
+
// An end tag always ends at a `>`; without one ahead, matching the name only to find
|
|
270
|
+
// no bracket behind it repeats the name run at every position, which costs O(n²) on a
|
|
271
|
+
// long unclosed name (e.g., `</aaaa…` with no `>`). Track the next `>` monotonically—
|
|
272
|
+
// `pos` only advances, so the aggregate scan work stays O(n)—and skip the match when
|
|
273
|
+
// none lies ahead, where the tag could not be complete anyway.
|
|
246
274
|
let nextGtPos = fullHtml.indexOf('>');
|
|
247
275
|
const hasCloseAtOrAfter = (/** @type {number} */ p) => {
|
|
248
276
|
if (nextGtPos !== -1 && nextGtPos < p) {
|
|
@@ -251,6 +279,13 @@ export class HTMLParser {
|
|
|
251
279
|
return nextGtPos !== -1;
|
|
252
280
|
};
|
|
253
281
|
|
|
282
|
+
// A `-->` that the opener at `pos` does not find is not there for any later one, either,
|
|
283
|
+
// and the same holds for the `]>` of a downlevel-revealed conditional comment. `pos`
|
|
284
|
+
// only advances, so remembering the search that came up empty keeps the aggregate work
|
|
285
|
+
// O(n), where searching again at every opener rescans the rest of the input each time.
|
|
286
|
+
let commentEndAhead = true;
|
|
287
|
+
let conditionalEndAhead = true;
|
|
288
|
+
|
|
254
289
|
// Helper to advance position
|
|
255
290
|
const advance = (/** @type {number} */ n) => { pos += n; };
|
|
256
291
|
|
|
@@ -274,11 +309,55 @@ export class HTMLParser {
|
|
|
274
309
|
return fullHtml.slice(startPos);
|
|
275
310
|
};
|
|
276
311
|
|
|
312
|
+
// `annotation-xml` holds HTML only where its `encoding` says so; with any other value,
|
|
313
|
+
// and with none, its content stays MathML
|
|
314
|
+
const annotationHoldsHTML = (/** @type {{attrs?: HTMLAttribute[]}} */ entry) => {
|
|
315
|
+
for (const attr of entry.attrs ?? []) {
|
|
316
|
+
if (attr.name.toLowerCase() === 'encoding') {
|
|
317
|
+
return RE_HTML_ENCODING.test(attr.value ?? '');
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return false;
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
// Escapable raw text is an HTML rule, so what decides it is the namespace the element sits
|
|
324
|
+
// in. Walking down from the root resolves that: `<svg>`/`<math>` lead out of HTML, an
|
|
325
|
+
// integration point leads back in, and a name counts only in the namespace it belongs to
|
|
326
|
+
// (`title` is one in SVG but not in MathML, `annotation-xml` one in MathML but not in SVG)
|
|
327
|
+
/** @param {{lowerTag: string, namespace: string, attrs?: HTMLAttribute[]} | undefined} entry */
|
|
328
|
+
const namespaceInside = (entry) => {
|
|
329
|
+
if (!entry) {
|
|
330
|
+
return '';
|
|
331
|
+
}
|
|
332
|
+
const { namespace, lowerTag } = entry;
|
|
333
|
+
if (!namespace) {
|
|
334
|
+
return lowerTag === 'svg' || lowerTag === 'math' ? lowerTag : '';
|
|
335
|
+
}
|
|
336
|
+
if (namespace === 'svg') {
|
|
337
|
+
return svgIntegrationPoints.has(lowerTag) ? '' : namespace;
|
|
338
|
+
}
|
|
339
|
+
return mathIntegrationPoints.has(lowerTag) || (lowerTag === 'annotation-xml' && annotationHoldsHTML(entry)) ? '' : namespace;
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// The element itself never decides this: `<svg><title>` is SVG, what it holds is HTML
|
|
343
|
+
const inForeignContent = () => Boolean(stack[stack.length - 1]?.namespace);
|
|
344
|
+
|
|
345
|
+
// The same question for a start tag, which is not on the stack yet: The element enters the
|
|
346
|
+
// namespace its parent holds, except that `svg` and `math` lead out of HTML themselves
|
|
347
|
+
const startsForeignContent = (/** @type {string} */ lowerTag) =>
|
|
348
|
+
Boolean(namespaceInside(stack[stack.length - 1])) || lowerTag === 'svg' || lowerTag === 'math';
|
|
349
|
+
|
|
350
|
+
// Whether the content of the element being parsed is read as text rather than markup
|
|
351
|
+
// (`script` and `style` hold text in every namespace; the rest do so as HTML elements only)
|
|
352
|
+
const holdsRawText = (/** @type {string} */ tag) =>
|
|
353
|
+
special.has(tag) ||
|
|
354
|
+
((genericRawTextElements.has(tag) || escapableRawTextElements.has(tag)) && !inForeignContent());
|
|
355
|
+
|
|
277
356
|
while (pos < fullLength) {
|
|
278
357
|
lastPos = pos;
|
|
279
358
|
|
|
280
|
-
// Make sure not to be in
|
|
281
|
-
if (!lastTagLower || !
|
|
359
|
+
// Make sure not to be in an element whose content is text, not markup
|
|
360
|
+
if (!lastTagLower || !holdsRawText(lastTagLower)) {
|
|
282
361
|
const textEnd = fullHtml.indexOf('<', pos);
|
|
283
362
|
|
|
284
363
|
if (textEnd === pos) {
|
|
@@ -298,9 +377,9 @@ export class HTMLParser {
|
|
|
298
377
|
const endTagMatch = cachedNextEndTag.match;
|
|
299
378
|
cachedNextStartTag = null;
|
|
300
379
|
cachedNextEndTag = null;
|
|
301
|
-
advance(
|
|
302
|
-
await parseEndTag(endTagMatch
|
|
303
|
-
prevTag = '/' +
|
|
380
|
+
advance(endTagMatch.text.length);
|
|
381
|
+
await parseEndTag(endTagMatch.text, endTagMatch.name);
|
|
382
|
+
prevTag = '/' + endTagMatch.name.toLowerCase();
|
|
304
383
|
prevAttrs = [];
|
|
305
384
|
continue;
|
|
306
385
|
}
|
|
@@ -310,7 +389,8 @@ export class HTMLParser {
|
|
|
310
389
|
// Comment
|
|
311
390
|
commentTestY.lastIndex = pos;
|
|
312
391
|
if (commentTestY.test(fullHtml)) {
|
|
313
|
-
const commentEnd = fullHtml.indexOf('-->', pos + 4);
|
|
392
|
+
const commentEnd = commentEndAhead ? fullHtml.indexOf('-->', pos + 4) : -1;
|
|
393
|
+
if (commentEnd === -1) commentEndAhead = false;
|
|
314
394
|
|
|
315
395
|
if (commentEnd >= 0) {
|
|
316
396
|
if (handler.comment) {
|
|
@@ -327,7 +407,8 @@ export class HTMLParser {
|
|
|
327
407
|
// https://web.archive.org/web/20241201212701/https://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
|
|
328
408
|
conditionalTestY.lastIndex = pos;
|
|
329
409
|
if (conditionalTestY.test(fullHtml)) {
|
|
330
|
-
const conditionalEnd = fullHtml.indexOf(']>', pos + 3);
|
|
410
|
+
const conditionalEnd = conditionalEndAhead ? fullHtml.indexOf(']>', pos + 3) : -1;
|
|
411
|
+
if (conditionalEnd === -1) conditionalEndAhead = false;
|
|
331
412
|
|
|
332
413
|
if (conditionalEnd >= 0) {
|
|
333
414
|
if (handler.comment) {
|
|
@@ -354,15 +435,14 @@ export class HTMLParser {
|
|
|
354
435
|
continue;
|
|
355
436
|
}
|
|
356
437
|
|
|
357
|
-
// End tag—skip when no `>` lies ahead: The
|
|
358
|
-
//
|
|
438
|
+
// End tag—skip when no `>` lies ahead: The tag cannot be complete, and matching
|
|
439
|
+
// its name at every position would cost O(n²) on a long unclosed name
|
|
359
440
|
if (hasCloseAtOrAfter(pos)) {
|
|
360
|
-
|
|
361
|
-
const endTagMatch = endTagY.exec(fullHtml);
|
|
441
|
+
const endTagMatch = matchEndTag(pos);
|
|
362
442
|
if (endTagMatch) {
|
|
363
|
-
advance(
|
|
364
|
-
await parseEndTag(endTagMatch
|
|
365
|
-
prevTag = '/' +
|
|
443
|
+
advance(endTagMatch.text.length);
|
|
444
|
+
await parseEndTag(endTagMatch.text, endTagMatch.name);
|
|
445
|
+
prevTag = '/' + endTagMatch.name.toLowerCase();
|
|
366
446
|
prevAttrs = [];
|
|
367
447
|
continue;
|
|
368
448
|
}
|
|
@@ -401,10 +481,9 @@ export class HTMLParser {
|
|
|
401
481
|
nextAttrs = extractAttrInfo(nextStartTagMatch.attrs);
|
|
402
482
|
cachedNextStartTag = { match: nextStartTagMatch, pos };
|
|
403
483
|
} else if (hasCloseAtOrAfter(pos)) {
|
|
404
|
-
|
|
405
|
-
const nextEndTagMatch = endTagY.exec(fullHtml);
|
|
484
|
+
const nextEndTagMatch = matchEndTag(pos);
|
|
406
485
|
if (nextEndTagMatch) {
|
|
407
|
-
nextTag = '/' + nextEndTagMatch
|
|
486
|
+
nextTag = '/' + nextEndTagMatch.name;
|
|
408
487
|
nextAttrs = [];
|
|
409
488
|
cachedNextEndTag = { match: nextEndTagMatch, pos };
|
|
410
489
|
} else {
|
|
@@ -425,32 +504,36 @@ export class HTMLParser {
|
|
|
425
504
|
prevAttrs = [];
|
|
426
505
|
} else {
|
|
427
506
|
const stackedTag = lastTagLower;
|
|
428
|
-
|
|
429
|
-
const reStackedTag = /** @type {Record<string, RegExp>} */ (preCompiledStackedTags)[stackedTag] || /** @type {Record<string, RegExp>} */ (reCache)[stackedTag] || (/** @type {Record<string, RegExp>} */ (reCache)[stackedTag] = new RegExp('([\\s\\S]*?)\\x3c/' + stackedTag + '[^>]*>', 'i'));
|
|
507
|
+
const isEscapableRawText = escapableRawTextElements.has(stackedTag);
|
|
430
508
|
|
|
431
509
|
const remaining = sliceFromPos(pos);
|
|
432
|
-
const
|
|
433
|
-
if (
|
|
434
|
-
|
|
435
|
-
if (stackedTag !== 'script' && stackedTag !== 'style' && stackedTag !== 'noscript') {
|
|
436
|
-
text = stripDelimited(stripDelimited(text, '<!--', '-->'), '<![CDATA[', ']]>');
|
|
437
|
-
}
|
|
510
|
+
const rawText = findRawTextEnd(remaining, stackedTag);
|
|
511
|
+
if (rawText) {
|
|
512
|
+
const text = rawText.content;
|
|
438
513
|
if (handler.chars) {
|
|
439
|
-
|
|
514
|
+
// Escapable raw text is a text node like any other, so the handler gets the tags
|
|
515
|
+
// around it—it collapses and trims whitespace by what stands next to the text
|
|
516
|
+
const result = isEscapableRawText
|
|
517
|
+
? handler.chars(text, stackedTag, '/' + stackedTag, prevAttrs, [])
|
|
518
|
+
: handler.chars(text);
|
|
440
519
|
if (isThenable(result)) await result;
|
|
441
520
|
}
|
|
442
521
|
// Advance HTML past the matched special tag content and its closing tag
|
|
443
|
-
advance(
|
|
522
|
+
advance(rawText.length);
|
|
444
523
|
await parseEndTag('</' + stackedTag + '>', stackedTag);
|
|
524
|
+
// What follows stands after that end tag, not after the start tag still named here—
|
|
525
|
+
// whitespace next to `textarea` stays verbatim only while the element is open
|
|
526
|
+
prevTag = '/' + stackedTag;
|
|
527
|
+
prevAttrs = [];
|
|
445
528
|
} else {
|
|
446
|
-
//
|
|
447
|
-
if (handler.
|
|
448
|
-
const result =
|
|
529
|
+
// Without an end tag of its own, the element holds the rest of the input as text
|
|
530
|
+
if (handler.chars && remaining) {
|
|
531
|
+
const result = isEscapableRawText
|
|
532
|
+
? handler.chars(remaining, stackedTag, '', prevAttrs, [])
|
|
533
|
+
: handler.chars(remaining);
|
|
449
534
|
if (isThenable(result)) await result;
|
|
450
|
-
advance(1);
|
|
451
|
-
} else {
|
|
452
|
-
break;
|
|
453
535
|
}
|
|
536
|
+
advance(remaining.length);
|
|
454
537
|
}
|
|
455
538
|
}
|
|
456
539
|
|
|
@@ -497,6 +580,21 @@ export class HTMLParser {
|
|
|
497
580
|
}).filter(attr => attr.name)); // Filter out invalid entries
|
|
498
581
|
}
|
|
499
582
|
|
|
583
|
+
/**
|
|
584
|
+
* @param {number} startPos
|
|
585
|
+
* @returns {{text: string, name: string} | null} The end tag standing there, or `null`
|
|
586
|
+
* where none is complete
|
|
587
|
+
*/
|
|
588
|
+
function matchEndTag(startPos) {
|
|
589
|
+
endTagOpenY.lastIndex = startPos;
|
|
590
|
+
const open = endTagOpenY.exec(fullHtml);
|
|
591
|
+
if (!open) {
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
const close = findEndTagClose(fullHtml, startPos + open[0].length);
|
|
595
|
+
return close === -1 ? null : { text: fullHtml.slice(startPos, close + 1), name: open[1] ?? '' };
|
|
596
|
+
}
|
|
597
|
+
|
|
500
598
|
function parseStartTag(/** @type {number} */ startPos) {
|
|
501
599
|
startTagOpenY.lastIndex = startPos;
|
|
502
600
|
const start = startTagOpenY.exec(fullHtml);
|
|
@@ -730,7 +828,7 @@ export class HTMLParser {
|
|
|
730
828
|
if (lowerTagName === 'col' && findTagInCurrentTable('colgroup') < 0) {
|
|
731
829
|
lastTag = 'colgroup';
|
|
732
830
|
lastTagLower = 'colgroup';
|
|
733
|
-
stack.push({ tag: lastTag, lowerTag: 'colgroup', attrs: [] });
|
|
831
|
+
stack.push({ tag: lastTag, lowerTag: 'colgroup', attrs: [], namespace: namespaceInside(stack[stack.length - 1]) });
|
|
734
832
|
if (handler.start) {
|
|
735
833
|
await handler.start(lastTag, [], false, '', true);
|
|
736
834
|
}
|
|
@@ -748,7 +846,10 @@ export class HTMLParser {
|
|
|
748
846
|
await parseEndTag('', lastTag);
|
|
749
847
|
}
|
|
750
848
|
|
|
751
|
-
|
|
849
|
+
// HTML ignores the slash on a start tag—only in SVG and MathML does it close the
|
|
850
|
+
// element, which `selfClosingSlash` extends back to every element
|
|
851
|
+
const selfClosed = !!unarySlash && (handler.selfClosingSlash || startsForeignContent(lowerTagName));
|
|
852
|
+
const unary = empty.has(lowerTagName) || (lowerTagName === 'html' && lastTagLower === 'head') || selfClosed;
|
|
752
853
|
|
|
753
854
|
const attrs = /** @type {HTMLAttribute[]} */ (match.attrs.map(function (/** @type {Array<string | undefined>} */ args) {
|
|
754
855
|
/** @type {string | undefined} */
|
|
@@ -806,7 +907,7 @@ export class HTMLParser {
|
|
|
806
907
|
}));
|
|
807
908
|
|
|
808
909
|
if (!unary) {
|
|
809
|
-
stack.push({ tag: tagName, lowerTag: lowerTagName, attrs });
|
|
910
|
+
stack.push({ tag: tagName, lowerTag: lowerTagName, attrs, namespace: namespaceInside(stack[stack.length - 1]) });
|
|
810
911
|
lastTag = tagName;
|
|
811
912
|
lastTagLower = lowerTagName;
|
|
812
913
|
unarySlash = '';
|
package/src/lib/attributes.js
CHANGED
|
@@ -781,6 +781,8 @@ function buildAttr(normalized, hasUnarySlash, options, isLast, uidAttr) {
|
|
|
781
781
|
(options.removeAttributeQuotes && ((uidAttr ? attrValue.indexOf(uidAttr) !== -1 : false) || !canRemoveAttributeQuotes(attrValue))) ||
|
|
782
782
|
// If `removeAttributeQuotes` is not enabled, preserve original quote style or add quotes if value requires them
|
|
783
783
|
(!options.removeAttributeQuotes && (attrQuote !== '' || !canRemoveAttributeQuotes(attrValue) ||
|
|
784
|
+
// SVGO reads the whole SVG block as XML, where every attribute value carries quotes
|
|
785
|
+
(Boolean(options.insideSVG) && Boolean(options.minifySVG)) ||
|
|
784
786
|
// Special case: With `removeTagWhitespace`, unquoted values that aren’t last will have space added,
|
|
785
787
|
// which can create ambiguous/invalid HTML—add quotes to be safe
|
|
786
788
|
(options.removeTagWhitespace && attrQuote === '' && !isLast)))
|
package/src/lib/constants.js
CHANGED
|
@@ -15,6 +15,17 @@ const RE_TRAILING_SEMICOLON = /;$/;
|
|
|
15
15
|
const RE_AMP_ENTITY = /&(#?[0-9a-zA-Z]+;)/g;
|
|
16
16
|
const RE_LEGACY_ENTITIES = /&((?:Iacute|aacute|uacute|plusmn|Otilde|otilde|agrave|Agrave|Yacute|yacute|Oslash|oslash|atilde|Atilde|brvbar|ccedil|Ccedil|Ograve|curren|divide|eacute|Eacute|ograve|Oacute|egrave|Egrave|Ugrave|frac12|frac14|frac34|ugrave|oacute|iacute|Ntilde|ntilde|Uacute|middot|igrave|Igrave|iquest|Aacute|cedil|laquo|micro|iexcl|Icirc|icirc|acirc|Ucirc|Ecirc|ocirc|Ocirc|ecirc|ucirc|Aring|aring|AElig|aelig|acute|pound|raquo|Acirc|times|THORN|szlig|thorn|COPY|auml|ordf|ordm|Uuml|macr|uuml|Auml|ouml|Ouml|para|nbsp|euml|quot|QUOT|Euml|yuml|cent|sect|copy|sup1|sup2|sup3|iuml|Iuml|ETH|shy|reg|not|yen|amp|AMP|REG|uml|eth|deg|gt|GT|LT|lt)(?!;)|(?:#?[0-9a-zA-Z]+;))/g;
|
|
17
17
|
const RE_ESCAPE_LT = /</g;
|
|
18
|
+
// In escapable raw text only the element’s own end tag ends the element, so nothing else
|
|
19
|
+
// that `decodeEntities` decoded to a `<` needs escaping there
|
|
20
|
+
// (the record has no prototype, so a tag named after an inherited property—`constructor`,
|
|
21
|
+
// `__proto__`—finds nothing here and falls back to escaping every `<`)
|
|
22
|
+
const RE_ESCAPE_LT_RAW_TEXT = /** @type {Record<string, RegExp>} */ (Object.assign(Object.create(null), {
|
|
23
|
+
textarea: /<(?=\/textarea[\s/>])/gi,
|
|
24
|
+
title: /<(?=\/title[\s/>])/gi
|
|
25
|
+
}));
|
|
26
|
+
// Encodings that make an `annotation-xml` element hold HTML rather than MathML
|
|
27
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#html-integration-point
|
|
28
|
+
const RE_HTML_ENCODING = /^(text\/html|application\/xhtml\+xml)$/i;
|
|
18
29
|
const RE_ATTR_WS_CHECK = /[ \n\r\t\f]/;
|
|
19
30
|
const RE_ATTR_WS_COLLAPSE = /[ \n\r\t\f]+/g;
|
|
20
31
|
const RE_ATTR_WS_TRIM = /^[ \n\r\t\f]+|[ \n\r\t\f]+$/g;
|
|
@@ -172,6 +183,23 @@ const htmlElements = new Set(['a', 'abbr', 'acronym', 'address', 'applet', 'area
|
|
|
172
183
|
|
|
173
184
|
const specialContentElements = new Set(['script', 'style']);
|
|
174
185
|
|
|
186
|
+
// Elements the parser reads as raw text as well, though only `script` and `style` are raw text
|
|
187
|
+
// elements by name—these are HTML’s alone, where `script` and `style` hold text in SVG, too
|
|
188
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#generic-raw-text-element-parsing-algorithm
|
|
189
|
+
//
|
|
190
|
+
// (`noscript`, `noframes`, and `noembed` are raw text, too, but stay markup here: What they
|
|
191
|
+
// hold is markup to the UA that displays it—one without scripting or frames—so minifying it
|
|
192
|
+
// as markup keeps what that UA sees)
|
|
193
|
+
const genericRawTextElements = new Set(['iframe', 'xmp']);
|
|
194
|
+
|
|
195
|
+
// Escapable raw text elements, whose content is text rather than markup
|
|
196
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#elements-2
|
|
197
|
+
const escapableRawTextElements = new Set(['textarea', 'title']);
|
|
198
|
+
|
|
199
|
+
// Raw text is read without resolving character references, so its text keeps them—unlike that
|
|
200
|
+
// of `textarea` and `title`, where they are resolved as they are anywhere else
|
|
201
|
+
const rawTextElements = new Set([...specialContentElements, ...genericRawTextElements]);
|
|
202
|
+
|
|
175
203
|
// Exports
|
|
176
204
|
|
|
177
205
|
export {
|
|
@@ -191,6 +219,8 @@ export {
|
|
|
191
219
|
RE_AMP_ENTITY,
|
|
192
220
|
RE_LEGACY_ENTITIES,
|
|
193
221
|
RE_ESCAPE_LT,
|
|
222
|
+
RE_ESCAPE_LT_RAW_TEXT,
|
|
223
|
+
RE_HTML_ENCODING,
|
|
194
224
|
RE_ATTR_WS_CHECK,
|
|
195
225
|
RE_ATTR_WS_COLLAPSE,
|
|
196
226
|
RE_ATTR_WS_TRIM,
|
|
@@ -240,5 +270,8 @@ export {
|
|
|
240
270
|
htmlElements,
|
|
241
271
|
|
|
242
272
|
// Special content elements
|
|
243
|
-
specialContentElements
|
|
273
|
+
specialContentElements,
|
|
274
|
+
genericRawTextElements,
|
|
275
|
+
escapableRawTextElements,
|
|
276
|
+
rawTextElements
|
|
244
277
|
};
|
|
@@ -91,7 +91,7 @@ const optionDefinitions = {
|
|
|
91
91
|
type: 'jsonArray'
|
|
92
92
|
},
|
|
93
93
|
keepClosingSlash: {
|
|
94
|
-
description: 'Keep the trailing slash on void elements',
|
|
94
|
+
description: 'Keep the trailing slash on void elements and other start tags that carry one, and read it as closing the element',
|
|
95
95
|
type: 'boolean'
|
|
96
96
|
},
|
|
97
97
|
maxInputLength: {
|
package/src/lib/options.js
CHANGED
|
@@ -47,6 +47,7 @@ import { optionDefinitions, optionDefaults } from './option-definitions.js';
|
|
|
47
47
|
* cssContext?: CSSContext,
|
|
48
48
|
* nameParent?: (name: string) => string,
|
|
49
49
|
* nameHTML?: (name: string) => string,
|
|
50
|
+
* keepClosingSlashHTML?: boolean,
|
|
50
51
|
* insideSVG?: boolean,
|
|
51
52
|
* insideForeignContent?: boolean
|
|
52
53
|
* }} ProcessedOptions
|
package/src/lib/utils.js
CHANGED
|
@@ -814,17 +814,18 @@ function describeQuantifierRisk(pattern) {
|
|
|
814
814
|
* over quoted attribute values (which may contain `>`).
|
|
815
815
|
* @param {string} html
|
|
816
816
|
* @param {number} pos - Start position (just after the tag name)
|
|
817
|
+
* @param {number} [limit] - Position to stop the search at (exclusive)
|
|
817
818
|
* @returns {number} Index of the closing `>`, or -1 if not found
|
|
818
819
|
*/
|
|
819
|
-
function findTagEnd(html, pos) {
|
|
820
|
+
function findTagEnd(html, pos, limit = html.length) {
|
|
820
821
|
let i = pos;
|
|
821
|
-
while (i <
|
|
822
|
+
while (i < limit) {
|
|
822
823
|
const ch = html[i];
|
|
823
824
|
if (ch === '>') return i;
|
|
824
825
|
if (ch === '"' || ch === "'") {
|
|
825
826
|
const q = ch;
|
|
826
827
|
i++;
|
|
827
|
-
while (i <
|
|
828
|
+
while (i < limit && html[i] !== q) i++;
|
|
828
829
|
}
|
|
829
830
|
i++;
|
|
830
831
|
}
|
package/src/lib/whitespace.js
CHANGED
|
@@ -237,8 +237,10 @@ function collapseWhitespaceSmart(str, prevTag, nextTag, prevAttrs, nextAttrs, op
|
|
|
237
237
|
|
|
238
238
|
// Collapse/trim whitespace for given tag
|
|
239
239
|
|
|
240
|
-
|
|
241
|
-
|
|
240
|
+
// `xmp`, `listing`, and `plaintext` render preformatted, as `pre` does
|
|
241
|
+
// https://html.spec.whatwg.org/multipage/rendering.html#the-page
|
|
242
|
+
const noCollapseWhitespaceTags = new Set(['script', 'style', 'pre', 'textarea', 'xmp', 'listing', 'plaintext']);
|
|
243
|
+
const noTrimWhitespaceTags = new Set(['pre', 'textarea', 'xmp', 'listing', 'plaintext']);
|
|
242
244
|
|
|
243
245
|
/** @param {string} tag */
|
|
244
246
|
function canCollapseWhitespace(tag) {
|