html-minifier-next 8.5.1 → 8.5.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/README.md +2 -2
- package/dist/types/htmlminifier.d.ts +4 -3
- package/dist/types/htmlminifier.d.ts.map +1 -1
- package/dist/types/htmlparser.d.ts +0 -1
- package/dist/types/htmlparser.d.ts.map +1 -1
- package/html-minifier-next.schema.json +2 -2
- package/package.json +2 -2
- package/src/htmlminifier.js +96 -47
- package/src/htmlparser.js +0 -1
- package/src/lib/option-definitions.js +2 -2
package/README.md
CHANGED
|
@@ -156,13 +156,13 @@ Options can be used in config files (camelCase) or via CLI flags (kebab-case wit
|
|
|
156
156
|
| `inlineCustomElements`<br>`--inline-custom-elements` | Array of names of custom elements which are inline, for whitespace handling—use with `collapseWhitespace` | `[]` |
|
|
157
157
|
| `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` |
|
|
158
158
|
| `maxInputLength`<br>`--max-input-length` | Maximum input length to prevent ReDoS attacks (disabled by default) | `undefined` |
|
|
159
|
-
| `maxLineLength`<br>`--max-line-length` | Specify a maximum line length;
|
|
159
|
+
| `maxLineLength`<br>`--max-line-length` | Specify a maximum line length; output will be split by newlines in tags only (between attributes or before a tag’s `>`), where they can’t change the page, so lines may run longer | `undefined` |
|
|
160
160
|
| `mergeScripts`<br>`--merge-scripts` | Merge consecutive inline `script` elements into one (only merges compatible scripts with same `type`, matching `async`/`defer`/`nomodule`/`nonce`) | `false` |
|
|
161
161
|
| `minifyCSS`<br>`--minify-css` | Minify CSS in `style` elements and attributes (uses [Lightning CSS](https://lightningcss.dev/)) | `false` (could be `true`, `Object`, `Function(text, type)`) |
|
|
162
162
|
| `minifyJS`<br>`--minify-js` | Minify JavaScript in `script` elements and event attributes (uses [Terser](https://terser.org/) or [SWC](https://swc.rs/)) | `false` (could be `true`, `Object`, `Function(text, inline)`) |
|
|
163
163
|
| `minifySVG`<br>`--minify-svg` | Minify SVG elements (uses [SVGO](https://svgo.dev/)) | `false` (could be `true`, `Object`) |
|
|
164
164
|
| `minifyURLs`<br>`--minify-urls` | Minify URLs in various attributes | `false` (could be `true`, `String`, `Object`, `Function(text)`) |
|
|
165
|
-
| `noNewlinesBeforeTagClose`<br>`--no-newlines-before-tag-close` | Never
|
|
165
|
+
| `noNewlinesBeforeTagClose`<br>`--no-newlines-before-tag-close` | Never split a line in a tag that closes an element—use with `maxLineLength` | `false` |
|
|
166
166
|
| `partialMarkup`<br>`--partial-markup` | Treat input as a partial HTML fragment, preserving stray end tags (closing tags without opening tags) and preventing auto-closing of unclosed tags at end of input | `false` |
|
|
167
167
|
| `preserveLineBreaks`<br>`--preserve-line-breaks` | Always collapse to one line break (never remove it entirely) when whitespace between tags includes a line break—use with [`collapseWhitespace`](#combining-whitespace-options) | `false` |
|
|
168
168
|
| `preventAttributesEscaping`<br>`--prevent-attributes-escaping` | Prevents the escaping of the values of attributes | `false` |
|
|
@@ -244,7 +244,8 @@ export type MinifierOptions = {
|
|
|
244
244
|
maxInputLength?: number;
|
|
245
245
|
/**
|
|
246
246
|
* Maximum line length for the output. When set the minifier will wrap
|
|
247
|
-
* output to the given number of characters where possible
|
|
247
|
+
* output to the given number of characters where possible, splitting
|
|
248
|
+
* lines only in tags—between attributes or before a tag’s `>`.
|
|
248
249
|
*
|
|
249
250
|
* Default: No limit
|
|
250
251
|
*/
|
|
@@ -308,8 +309,8 @@ export type MinifierOptions = {
|
|
|
308
309
|
*/
|
|
309
310
|
minifySVG?: boolean | Object;
|
|
310
311
|
/**
|
|
311
|
-
* When wrapping lines,
|
|
312
|
-
*
|
|
312
|
+
* When wrapping lines, never split a line in an end tag (e.g., keeps
|
|
313
|
+
* `</a>` from becoming `</a` and `>` on two lines).
|
|
313
314
|
*
|
|
314
315
|
* Default: `false`
|
|
315
316
|
*/
|
|
@@ -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;AAwE/D,YAAkB,aAAa,GAI/B;IAAe,IAAI,EAAZ,MAAM,CACb;IAAgB,KAAK,AAArB,CACA,EADO,MAAM,CACb;IAAgB,KAAK,AAArB,CACA,EADO,MAAM,CACb;IAAgB,YAAY,AAA5B,CACA,EADO,MAAM,CACb;IAAgB,UAAU,AAA1B,CACA,EADO,MAAM,CACb;IAAgB,WAAW,AAA3B,CAA4B,EAArB,MAAM,CAAe;CAAA,CAAA;AAI5B,YAAkB,eAAe,GAIjC;;;;;;;IAA2G,qBAAqB,AAAhI,CAMA,EANO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,qBAAqB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO,CAMxG;;;;;;;;;;IAAuE,YAAY,AAAnF,CASA,EATO,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,KAAK,OAAO,CAAC,GAAG,IAAI,CASpE;;;;;;;;;IAA8D,WAAW,AAAzE,CAQA,EARO,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,GAAG,IAAI,CAQ3D;;;;;;;;;IAA4C,YAAY,AAAxD,CAQA,EARO,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,IAAI,CAQzC;;;;;;;IAA0H,iBAAiB,AAA3I,CAMA,EANO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,GAAG,SAAS,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,KAAK,OAAO,CAMvH;;;;;;;;;;IAAgB,QAAQ,AAAxB,CASA,EATO,MAAM,CASb;;;;;;;;;;IAAgB,OAAO,AAAvB,CASA,EATO,MAAM,CASb;;;;;;;;;;IAAgB,QAAQ,AAAxB,CASA,EATO,MAAM,CASb;;;;;;;;IAAiB,aAAa,AAA9B,CAOC,EAPM,OAAO,CAOb;;;;;;;;;IAAiB,2BAA2B,AAA5C,CAQD,EARQ,OAAO,CAQf;;;;;;;;IAAiB,yBAAyB,AAA1C,CAOA,EAPO,OAAO,CAOd;;;;;;;;IAAiB,2BAA2B,AAA5C,CAOA,EAPO,OAAO,CAOd;;;;;;;;IAAiB,kBAAkB,AAAnC,CAOA,EAPO,OAAO,CAOd;;;;;;;;IAAiB,oBAAoB,AAArC,CAOA,EAPO,OAAO,CAOd;;;;;;;;IAAiB,qBAAqB,AAAtC,CAOA,EAPO,OAAO,CAOd;;;;;;;IAAiB,oBAAoB,AAArC,CAMA,EANO,OAAO,CAMd;;;;;;;;IAAkB,gBAAgB,AAAlC,CAOA,EAPO,MAAM,EAAE,CAOf;;;;;;IAAgB,kBAAkB,AAAlC,CAKA,EALO,MAAM,CAKb;;;;;;IAA4B,kBAAkB,AAA9C,CAKA,EALO,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAKzB;;;;;;;IAAkB,qBAAqB,AAAvC,CAMA,EANO,MAAM,EAAE,CAMf;;;;;;;;;IAAiB,qBAAqB,AAAtC,CAQA,EARO,OAAO,CAQd;;;;;;;IAAiB,cAAc,AAA/B,CAOA,EAPO,OAAO,CAOd;;;;;;;;IAAkB,oBAAoB,AAAtC,CAOA,EAPO,MAAM,EAAE,CAOf;;;;;;;;;IAAkB,qBAAqB,AAAvC,CAQA,EARO,MAAM,EAAE,CAQf;;;;;;;IAAiB,wBAAwB,AAAzC,CAMA,EANO,OAAO,CAMd;;;;;;;IAA2B,oBAAoB,AAA/C,CAMA,EANO,SAAS,CAAC,MAAM,CAAC,CAMxB;;;;;;;;IAAiB,gBAAgB,AAAjC,CAOA,EAPO,OAAO,CAOd;;;;;;;;IAAoC,GAAG,AAAvC,CAOA,EAPO,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAOjC;;;;;;;;IAAgB,cAAc,AAA9B,CAOA,EAPO,MAAM,CAOb
|
|
1
|
+
{"version":3,"file":"htmlminifier.d.ts","sourceRoot":"","sources":["../../src/htmlminifier.js"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AA6NvB,qBAAa,UAAU;IAMd,IAAI;IACJ,OAAO;IANd;;;OAGG;IACH,YAAY,IAAI,EAHL,MAGK,EAAE,OAAO,EAFd,iBAEc,EAGxB;IAEK,KAAK,kBA2yBV;CACF"}
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
"minimum": 0
|
|
166
166
|
},
|
|
167
167
|
"maxLineLength": {
|
|
168
|
-
"description": "Specify a maximum line length;
|
|
168
|
+
"description": "Specify a maximum line length; output will be split by newlines in tags only (between attributes or before a tag’s `>`), where they can’t change the page, so lines may run longer",
|
|
169
169
|
"type": "integer",
|
|
170
170
|
"minimum": 0
|
|
171
171
|
},
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
]
|
|
204
204
|
},
|
|
205
205
|
"noNewlinesBeforeTagClose": {
|
|
206
|
-
"description": "Never
|
|
206
|
+
"description": "Never split a line in a tag that closes an element—use with `--max-line-length`",
|
|
207
207
|
"type": "boolean"
|
|
208
208
|
},
|
|
209
209
|
"partialMarkup": {
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"@commitlint/cli": "^21.2.2",
|
|
18
18
|
"@eslint/js": "^10.0.1",
|
|
19
19
|
"@swc/core": "^1.16.2",
|
|
20
|
-
"@types/node": "^26.
|
|
20
|
+
"@types/node": "^26.6.1",
|
|
21
21
|
"eslint": "^10.10.0",
|
|
22
22
|
"globals": "^17.12.0",
|
|
23
23
|
"typescript": "^7.0.2",
|
|
@@ -95,5 +95,5 @@
|
|
|
95
95
|
},
|
|
96
96
|
"type": "module",
|
|
97
97
|
"types": "dist/types/htmlminifier.d.ts",
|
|
98
|
-
"version": "8.5.
|
|
98
|
+
"version": "8.5.2"
|
|
99
99
|
}
|
package/src/htmlminifier.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { HTMLParser
|
|
1
|
+
import { HTMLParser } from './htmlparser.js';
|
|
2
2
|
import TokenChain from './tokenchain.js';
|
|
3
3
|
import { presets, getPreset, getPresetNames } from './presets.js';
|
|
4
4
|
|
|
@@ -297,7 +297,8 @@ import { toFragment, replaceCustomFragments } from './lib/fragments.js';
|
|
|
297
297
|
*
|
|
298
298
|
* @prop {number} [maxLineLength]
|
|
299
299
|
* Maximum line length for the output. When set the minifier will wrap
|
|
300
|
-
* output to the given number of characters where possible
|
|
300
|
+
* output to the given number of characters where possible, splitting
|
|
301
|
+
* lines only in tags—between attributes or before a tag’s `>`.
|
|
301
302
|
*
|
|
302
303
|
* Default: No limit
|
|
303
304
|
*
|
|
@@ -350,8 +351,8 @@ import { toFragment, replaceCustomFragments } from './lib/fragments.js';
|
|
|
350
351
|
* Default: `false`
|
|
351
352
|
*
|
|
352
353
|
* @prop {boolean} [noNewlinesBeforeTagClose]
|
|
353
|
-
* When wrapping lines,
|
|
354
|
-
*
|
|
354
|
+
* When wrapping lines, never split a line in an end tag (e.g., keeps
|
|
355
|
+
* `</a>` from becoming `</a` and `>` on two lines).
|
|
355
356
|
*
|
|
356
357
|
* Default: `false`
|
|
357
358
|
*
|
|
@@ -1047,6 +1048,8 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1047
1048
|
|
|
1048
1049
|
/** @type {string[]} */
|
|
1049
1050
|
const buffer = [];
|
|
1051
|
+
// Parallel to `buffer`: whether an entry belongs to a start or end tag, the only place lines may break
|
|
1052
|
+
const bufferTags = options.maxLineLength ? /** @type {boolean[]} */ ([]) : null;
|
|
1050
1053
|
/** @type {string} */
|
|
1051
1054
|
let charsPrevTag = '';
|
|
1052
1055
|
let currentChars = '';
|
|
@@ -1278,12 +1281,22 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1278
1281
|
return options.canTrimWhitespace(tag, attrs, defaultCanTrimWhitespace);
|
|
1279
1282
|
}
|
|
1280
1283
|
|
|
1284
|
+
function bufferPush(/** @type {string} */ entry, /** @type {boolean} */ isTag) {
|
|
1285
|
+
buffer.push(entry);
|
|
1286
|
+
bufferTags?.push(isTag);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
function bufferTruncate(/** @type {number} */ length) {
|
|
1290
|
+
buffer.length = Math.max(0, length);
|
|
1291
|
+
if (bufferTags) bufferTags.length = buffer.length;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1281
1294
|
function removeStartTag() {
|
|
1282
1295
|
let index = buffer.length - 1;
|
|
1283
1296
|
while (index > 0 && !RE_START_TAG.test(buffer[index] ?? '')) {
|
|
1284
1297
|
index--;
|
|
1285
1298
|
}
|
|
1286
|
-
|
|
1299
|
+
bufferTruncate(index);
|
|
1287
1300
|
}
|
|
1288
1301
|
|
|
1289
1302
|
// Whether the element being parsed holds text rather than markup. The namespace decides
|
|
@@ -1339,13 +1352,14 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1339
1352
|
const noTrim = stackNoTrimWhitespace.length > 0;
|
|
1340
1353
|
if (index < buffer.length - 1 && (keepsWhitespace() || noTrim) && RE_END_TAG.test(buffer[index] ?? '')) {
|
|
1341
1354
|
buffer.splice(index, 1);
|
|
1355
|
+
bufferTags?.splice(index, 1);
|
|
1342
1356
|
// Only collapsed whitespace can merge
|
|
1343
1357
|
if (options.collapseWhitespace && !noTrim) {
|
|
1344
1358
|
mergeWhitespaceRuns(index);
|
|
1345
1359
|
}
|
|
1346
1360
|
return;
|
|
1347
1361
|
}
|
|
1348
|
-
|
|
1362
|
+
bufferTruncate(index);
|
|
1349
1363
|
}
|
|
1350
1364
|
|
|
1351
1365
|
// Look for trailing whitespaces, bypass any inline tags
|
|
@@ -1545,7 +1559,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1545
1559
|
if (text) {
|
|
1546
1560
|
hasChars = true;
|
|
1547
1561
|
}
|
|
1548
|
-
|
|
1562
|
+
bufferPush(text, false);
|
|
1549
1563
|
}
|
|
1550
1564
|
|
|
1551
1565
|
// Comment finalization (sync): Optional tag handling, `htmlmin:ignore` whitespace collapsing, buffer push
|
|
@@ -1656,7 +1670,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1656
1670
|
}
|
|
1657
1671
|
}
|
|
1658
1672
|
|
|
1659
|
-
|
|
1673
|
+
bufferPush(comment, false);
|
|
1660
1674
|
}
|
|
1661
1675
|
|
|
1662
1676
|
// Inline scripts are minified one at a time as the parse reaches them, which serializes
|
|
@@ -1839,7 +1853,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1839
1853
|
const needsXMLSlash = unary && Boolean(options.insideSVG) && Boolean(options.minifySVG);
|
|
1840
1854
|
const hasUnarySlash = needsXMLSlash || (unarySlash && (useNameParentForTag ? optionsParent : options).keepClosingSlash);
|
|
1841
1855
|
|
|
1842
|
-
|
|
1856
|
+
bufferPush(openTag, true);
|
|
1843
1857
|
|
|
1844
1858
|
const fragmentJoinsTag = uidAttrExactPattern ? joinFragmentAttrs(attrs) : false;
|
|
1845
1859
|
// Whatever runs into the tag name has to stay first
|
|
@@ -1883,7 +1897,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1883
1897
|
}
|
|
1884
1898
|
if (lastKeptIndex !== -1) {
|
|
1885
1899
|
if (!fragmentJoinsTag) {
|
|
1886
|
-
|
|
1900
|
+
bufferPush(' ', true);
|
|
1887
1901
|
}
|
|
1888
1902
|
for (let i = 0; i <= lastKeptIndex; i++) {
|
|
1889
1903
|
const normalizedAttr = normalizedAttrs[i];
|
|
@@ -1893,7 +1907,11 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1893
1907
|
}
|
|
1894
1908
|
const builtAttr = buildAttr(normalizedAttr, hasUnarySlash, options, i === lastKeptIndex, uidAttr);
|
|
1895
1909
|
// One entry with the tag name, so that no line break can come between them
|
|
1896
|
-
|
|
1910
|
+
if (i === 0 && fragmentJoinsTag) {
|
|
1911
|
+
buffer[buffer.length - 1] += builtAttr;
|
|
1912
|
+
} else {
|
|
1913
|
+
bufferPush(builtAttr, true);
|
|
1914
|
+
}
|
|
1897
1915
|
}
|
|
1898
1916
|
}
|
|
1899
1917
|
} else if (optional && optionalStartTags.has(tag)) {
|
|
@@ -1901,7 +1919,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1901
1919
|
optionalStartTag = tag;
|
|
1902
1920
|
}
|
|
1903
1921
|
|
|
1904
|
-
buffer
|
|
1922
|
+
buffer[buffer.length - 1] += (hasUnarySlash ? '/' : '') + '>';
|
|
1905
1923
|
|
|
1906
1924
|
if (autoGenerated && !options.includeAutoGeneratedTags) {
|
|
1907
1925
|
removeStartTag();
|
|
@@ -2010,7 +2028,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
2010
2028
|
if (autoGenerated && !options.includeAutoGeneratedTags) {
|
|
2011
2029
|
optionalEndTagEmitted = false;
|
|
2012
2030
|
} else {
|
|
2013
|
-
|
|
2031
|
+
bufferPush(endTagText, true);
|
|
2014
2032
|
}
|
|
2015
2033
|
charsPrevTag = '/' + tag;
|
|
2016
2034
|
if (!inlineElements.has(tag)) {
|
|
@@ -2023,7 +2041,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
2023
2041
|
if (autoGenerated && !options.includeAutoGeneratedTags) {
|
|
2024
2042
|
optionalEndTagEmitted = false;
|
|
2025
2043
|
} else {
|
|
2026
|
-
|
|
2044
|
+
bufferPush(endTagText, true);
|
|
2027
2045
|
}
|
|
2028
2046
|
charsPrevTag = '/' + tag;
|
|
2029
2047
|
if (!inlineElements.has(tag)) {
|
|
@@ -2099,10 +2117,10 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
2099
2117
|
commentFinalize(text);
|
|
2100
2118
|
},
|
|
2101
2119
|
doctype: function (/** @type {string} */ doctype) {
|
|
2102
|
-
|
|
2120
|
+
bufferPush(options.useShortDoctype
|
|
2103
2121
|
? '<!doctype' +
|
|
2104
2122
|
(options.removeTagWhitespace ? '' : ' ') + 'html>'
|
|
2105
|
-
: collapseWhitespaceAll(doctype));
|
|
2123
|
+
: collapseWhitespaceAll(doctype), false);
|
|
2106
2124
|
}
|
|
2107
2125
|
});
|
|
2108
2126
|
|
|
@@ -2119,7 +2137,10 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
2119
2137
|
);
|
|
2120
2138
|
for (let i = svgBlocks.length - 1; i >= 0; i--) {
|
|
2121
2139
|
const block = svgBlocks[i];
|
|
2122
|
-
if (block)
|
|
2140
|
+
if (block) {
|
|
2141
|
+
buffer.splice(block.start, block.end - block.start, optimized[i] ?? '');
|
|
2142
|
+
bufferTags?.splice(block.start, block.end - block.start, false);
|
|
2143
|
+
}
|
|
2123
2144
|
}
|
|
2124
2145
|
}
|
|
2125
2146
|
|
|
@@ -2138,7 +2159,7 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
2138
2159
|
squashTrailingWhitespace('br');
|
|
2139
2160
|
}
|
|
2140
2161
|
|
|
2141
|
-
return joinResultSegments(buffer, options, uidPattern
|
|
2162
|
+
return joinResultSegments(buffer, bufferTags ?? [], [uidAttr, uidIgnore].filter(marker => marker !== undefined), options, uidPattern
|
|
2142
2163
|
? function (/** @type {string} */ str) {
|
|
2143
2164
|
return str.replace(/** @type {RegExp} */ (uidPattern), function (/** @type {string} */ match, /** @type {string} */ prefix, /** @type {string} */ index, /** @type {string} */ suffix, /** @type {number} */ offset, /** @type {string} */ string) {
|
|
2144
2165
|
const chunks = ignoredCustomMarkupChunks[+index];
|
|
@@ -2173,46 +2194,74 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
2173
2194
|
|
|
2174
2195
|
/**
|
|
2175
2196
|
* @param {string[]} results
|
|
2197
|
+
* @param {boolean[]} resultTags Whether each result belongs to a start or end tag
|
|
2198
|
+
* @param {string[]} markers Custom fragment and `htmlmin:ignore` placeholder markers
|
|
2176
2199
|
* @param {ProcessedOptions} options
|
|
2177
2200
|
* @param {Function} restoreCustom
|
|
2178
2201
|
* @param {Function} restoreIgnore
|
|
2179
2202
|
*/
|
|
2180
|
-
function joinResultSegments(results, options, restoreCustom, restoreIgnore) {
|
|
2203
|
+
function joinResultSegments(results, resultTags, markers, options, restoreCustom, restoreIgnore) {
|
|
2181
2204
|
let str;
|
|
2182
2205
|
const maxLineLength = options.maxLineLength;
|
|
2183
|
-
const noNewlinesBeforeTagClose = options.noNewlinesBeforeTagClose;
|
|
2184
2206
|
|
|
2185
2207
|
if (maxLineLength) {
|
|
2186
|
-
|
|
2187
|
-
//
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2208
|
+
// Whitespace in tags is the only whitespace that can’t change the output, so lines break
|
|
2209
|
+
// there alone—in place of the space between attributes, or right before a tag’s `>`
|
|
2210
|
+
const noNewlinesBeforeTagClose = options.noNewlinesBeforeTagClose;
|
|
2211
|
+
/** @type {string[]} */
|
|
2212
|
+
const lines = [];
|
|
2213
|
+
let lineLength = 0;
|
|
2214
|
+
// Output since the last break opportunity, and what that opportunity is when not taken;
|
|
2215
|
+
// fragments are restored by chunk, as whitespace around them decides how they come back
|
|
2216
|
+
let chunk = '';
|
|
2217
|
+
/** @type {string | null} */
|
|
2218
|
+
let separator = null;
|
|
2219
|
+
const flush = (/** @type {string | null} */ nextSeparator) => {
|
|
2220
|
+
chunk = restoreIgnore(restoreCustom(chunk));
|
|
2221
|
+
const newline = chunk.indexOf('\n');
|
|
2222
|
+
const head = newline < 0 ? chunk.length : newline;
|
|
2223
|
+
// A line already too long gains nothing from moving a `>` that ends a line of its own
|
|
2224
|
+
const isUseless = separator === '' && head === 1 && lineLength > maxLineLength;
|
|
2225
|
+
if (separator !== null) {
|
|
2226
|
+
if (lineLength > 0 && lineLength + separator.length + head > maxLineLength && !isUseless) {
|
|
2227
|
+
lines.push('\n');
|
|
2228
|
+
lineLength = 0;
|
|
2229
|
+
} else if (separator) {
|
|
2230
|
+
lines.push(separator);
|
|
2231
|
+
lineLength += separator.length;
|
|
2232
|
+
}
|
|
2203
2233
|
}
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2234
|
+
lines.push(chunk);
|
|
2235
|
+
lineLength = newline < 0 ? lineLength + chunk.length : chunk.length - chunk.lastIndexOf('\n') - 1;
|
|
2236
|
+
chunk = '';
|
|
2237
|
+
separator = nextSeparator;
|
|
2238
|
+
};
|
|
2239
|
+
for (let index = 0; index < results.length; index++) {
|
|
2240
|
+
const result = results[index] ?? '';
|
|
2241
|
+
if (!resultTags[index]) {
|
|
2242
|
+
chunk += result;
|
|
2243
|
+
} else if (markers.length && markers.some(marker => result.includes(marker))) {
|
|
2244
|
+
// Whitespace next to a fragment stays as is, as it may belong to it
|
|
2245
|
+
if (!chunk && separator !== null) {
|
|
2246
|
+
chunk = separator;
|
|
2247
|
+
separator = null;
|
|
2248
|
+
}
|
|
2249
|
+
chunk += result;
|
|
2250
|
+
} else if (result.charCodeAt(result.length - 1) === 32 /* space */) {
|
|
2251
|
+
chunk += result.slice(0, -1);
|
|
2252
|
+
flush(' ');
|
|
2253
|
+
} else if (result.charCodeAt(result.length - 1) === 62 /* > */ &&
|
|
2254
|
+
result.charCodeAt(result.length - 2) !== 47 /* / */ &&
|
|
2255
|
+
!(noNewlinesBeforeTagClose && result.startsWith('</'))) {
|
|
2256
|
+
chunk += result.slice(0, -1);
|
|
2257
|
+
flush('');
|
|
2258
|
+
chunk = '>';
|
|
2259
|
+
} else {
|
|
2260
|
+
chunk += result;
|
|
2210
2261
|
}
|
|
2211
2262
|
}
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
}
|
|
2215
|
-
str = lines.join('\n');
|
|
2263
|
+
flush(null);
|
|
2264
|
+
str = lines.join('');
|
|
2216
2265
|
} else {
|
|
2217
2266
|
str = restoreIgnore(restoreCustom(results.join('')));
|
|
2218
2267
|
}
|
package/src/htmlparser.js
CHANGED
|
@@ -67,7 +67,6 @@ const qnameCapture = (function () {
|
|
|
67
67
|
})();
|
|
68
68
|
const startTagOpen = new RegExp('^<' + qnameCapture);
|
|
69
69
|
const endTagOpen = new RegExp('^</' + qnameCapture);
|
|
70
|
-
export const endTag = new RegExp('^</' + qnameCapture + '[^>]*>');
|
|
71
70
|
|
|
72
71
|
let IS_REGEX_CAPTURING_BROKEN = false;
|
|
73
72
|
'x'.replace(/x(.)?/g, function (/** @type {string} */ m, /** @type {string | undefined} */ g) {
|
|
@@ -101,7 +101,7 @@ const optionDefinitions = {
|
|
|
101
101
|
type: 'int'
|
|
102
102
|
},
|
|
103
103
|
maxLineLength: {
|
|
104
|
-
description: 'Specify a maximum line length;
|
|
104
|
+
description: 'Specify a maximum line length; output will be split by newlines in tags only (between attributes or before a tag’s `>`), where they can’t change the page, so lines may run longer',
|
|
105
105
|
type: 'int'
|
|
106
106
|
},
|
|
107
107
|
mergeScripts: {
|
|
@@ -125,7 +125,7 @@ const optionDefinitions = {
|
|
|
125
125
|
type: 'json'
|
|
126
126
|
},
|
|
127
127
|
noNewlinesBeforeTagClose: {
|
|
128
|
-
description: 'Never
|
|
128
|
+
description: 'Never split a line in a tag that closes an element—use with `--max-line-length`',
|
|
129
129
|
type: 'boolean'
|
|
130
130
|
},
|
|
131
131
|
partialMarkup: {
|