html-minifier-next 4.9.1 → 4.10.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 +25 -19
- package/dist/htmlminifier.cjs +191 -94
- package/dist/htmlminifier.esm.bundle.js +191 -94
- package/dist/types/htmlminifier.d.ts.map +1 -1
- package/dist/types/htmlparser.d.ts.map +1 -1
- package/dist/types/tokenchain.d.ts +1 -0
- package/dist/types/tokenchain.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/htmlminifier.js +5 -1
- package/src/htmlparser.js +89 -50
- package/src/tokenchain.js +77 -34
|
@@ -5147,18 +5147,6 @@ function requireLib () {
|
|
|
5147
5147
|
var libExports = requireLib();
|
|
5148
5148
|
var RelateURL = /*@__PURE__*/getDefaultExportFromCjs(libExports);
|
|
5149
5149
|
|
|
5150
|
-
async function replaceAsync(str, regex, asyncFn) {
|
|
5151
|
-
const promises = [];
|
|
5152
|
-
|
|
5153
|
-
str.replace(regex, (match, ...args) => {
|
|
5154
|
-
const promise = asyncFn(match, ...args);
|
|
5155
|
-
promises.push(promise);
|
|
5156
|
-
});
|
|
5157
|
-
|
|
5158
|
-
const data = await Promise.all(promises);
|
|
5159
|
-
return str.replace(regex, () => data.shift());
|
|
5160
|
-
}
|
|
5161
|
-
|
|
5162
5150
|
/*!
|
|
5163
5151
|
* HTML Parser By John Resig (ejohn.org)
|
|
5164
5152
|
* Modified by Juriy “kangax” Zaytsev
|
|
@@ -5166,6 +5154,15 @@ async function replaceAsync(str, regex, asyncFn) {
|
|
|
5166
5154
|
* http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
|
|
5167
5155
|
*/
|
|
5168
5156
|
|
|
5157
|
+
/*
|
|
5158
|
+
* // Use like so:
|
|
5159
|
+
* HTMLParser(htmlString, {
|
|
5160
|
+
* start: function(tag, attrs, unary) {},
|
|
5161
|
+
* end: function(tag) {},
|
|
5162
|
+
* chars: function(text) {},
|
|
5163
|
+
* comment: function(text) {}
|
|
5164
|
+
* });
|
|
5165
|
+
*/
|
|
5169
5166
|
|
|
5170
5167
|
class CaseInsensitiveSet extends Set {
|
|
5171
5168
|
has(str) {
|
|
@@ -5234,6 +5231,9 @@ const preCompiledStackedTags = {
|
|
|
5234
5231
|
'noscript': /([\s\S]*?)<\/noscript[^>]*>/i
|
|
5235
5232
|
};
|
|
5236
5233
|
|
|
5234
|
+
// Cache for compiled attribute regexes per handler configuration
|
|
5235
|
+
const attrRegexCache = new WeakMap();
|
|
5236
|
+
|
|
5237
5237
|
function attrForHandler(handler) {
|
|
5238
5238
|
let pattern = singleAttrIdentifier.source +
|
|
5239
5239
|
'(?:\\s*(' + joinSingleAttrAssigns(handler) + ')' +
|
|
@@ -5271,22 +5271,47 @@ class HTMLParser {
|
|
|
5271
5271
|
}
|
|
5272
5272
|
|
|
5273
5273
|
async parse() {
|
|
5274
|
-
let html = this.html;
|
|
5275
5274
|
const handler = this.handler;
|
|
5275
|
+
const fullHtml = this.html;
|
|
5276
|
+
const fullLength = fullHtml.length;
|
|
5276
5277
|
|
|
5277
5278
|
const stack = []; let lastTag;
|
|
5278
|
-
|
|
5279
|
-
let
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
|
|
5285
|
-
|
|
5279
|
+
// Use cached attribute regex if available
|
|
5280
|
+
let attribute = attrRegexCache.get(handler);
|
|
5281
|
+
if (!attribute) {
|
|
5282
|
+
attribute = attrForHandler(handler);
|
|
5283
|
+
attrRegexCache.set(handler, attribute);
|
|
5284
|
+
}
|
|
5285
|
+
let prevTag = undefined, nextTag = undefined;
|
|
5286
|
+
|
|
5287
|
+
// Index-based parsing
|
|
5288
|
+
let pos = 0;
|
|
5289
|
+
let lastPos;
|
|
5290
|
+
|
|
5291
|
+
// Helper to get remaining HTML from current position
|
|
5292
|
+
const remaining = () => fullHtml.slice(pos);
|
|
5293
|
+
|
|
5294
|
+
// Helper to advance position
|
|
5295
|
+
const advance = (n) => { pos += n; };
|
|
5296
|
+
|
|
5297
|
+
// Lazy line/column calculation—only compute on actual errors
|
|
5298
|
+
const getLineColumn = (position) => {
|
|
5299
|
+
let line = 1;
|
|
5300
|
+
let column = 1;
|
|
5301
|
+
for (let i = 0; i < position; i++) {
|
|
5302
|
+
if (fullHtml[i] === '\n') {
|
|
5303
|
+
line++;
|
|
5304
|
+
column = 1;
|
|
5305
|
+
} else {
|
|
5306
|
+
column++;
|
|
5307
|
+
}
|
|
5308
|
+
}
|
|
5309
|
+
return { line, column };
|
|
5286
5310
|
};
|
|
5287
5311
|
|
|
5288
|
-
while (
|
|
5289
|
-
|
|
5312
|
+
while (pos < fullLength) {
|
|
5313
|
+
lastPos = pos;
|
|
5314
|
+
const html = remaining();
|
|
5290
5315
|
// Make sure we’re not in a `script` or `style` element
|
|
5291
5316
|
if (!lastTag || !special.has(lastTag)) {
|
|
5292
5317
|
let textEnd = html.indexOf('<');
|
|
@@ -5299,7 +5324,7 @@ class HTMLParser {
|
|
|
5299
5324
|
if (handler.comment) {
|
|
5300
5325
|
await handler.comment(html.substring(4, commentEnd));
|
|
5301
5326
|
}
|
|
5302
|
-
|
|
5327
|
+
advance(commentEnd + 3);
|
|
5303
5328
|
prevTag = '';
|
|
5304
5329
|
continue;
|
|
5305
5330
|
}
|
|
@@ -5313,7 +5338,7 @@ class HTMLParser {
|
|
|
5313
5338
|
if (handler.comment) {
|
|
5314
5339
|
await handler.comment(html.substring(2, conditionalEnd + 1), true /* non-standard */);
|
|
5315
5340
|
}
|
|
5316
|
-
|
|
5341
|
+
advance(conditionalEnd + 2);
|
|
5317
5342
|
prevTag = '';
|
|
5318
5343
|
continue;
|
|
5319
5344
|
}
|
|
@@ -5325,7 +5350,7 @@ class HTMLParser {
|
|
|
5325
5350
|
if (handler.doctype) {
|
|
5326
5351
|
handler.doctype(doctypeMatch[0]);
|
|
5327
5352
|
}
|
|
5328
|
-
|
|
5353
|
+
advance(doctypeMatch[0].length);
|
|
5329
5354
|
prevTag = '';
|
|
5330
5355
|
continue;
|
|
5331
5356
|
}
|
|
@@ -5333,8 +5358,8 @@ class HTMLParser {
|
|
|
5333
5358
|
// End tag
|
|
5334
5359
|
const endTagMatch = html.match(endTag);
|
|
5335
5360
|
if (endTagMatch) {
|
|
5336
|
-
|
|
5337
|
-
await
|
|
5361
|
+
advance(endTagMatch[0].length);
|
|
5362
|
+
await parseEndTag(endTagMatch[0], endTagMatch[1]);
|
|
5338
5363
|
prevTag = '/' + endTagMatch[1].toLowerCase();
|
|
5339
5364
|
continue;
|
|
5340
5365
|
}
|
|
@@ -5342,7 +5367,7 @@ class HTMLParser {
|
|
|
5342
5367
|
// Start tag
|
|
5343
5368
|
const startTagMatch = parseStartTag(html);
|
|
5344
5369
|
if (startTagMatch) {
|
|
5345
|
-
|
|
5370
|
+
advance(startTagMatch.advance);
|
|
5346
5371
|
await handleStartTag(startTagMatch);
|
|
5347
5372
|
prevTag = startTagMatch.tagName.toLowerCase();
|
|
5348
5373
|
continue;
|
|
@@ -5357,18 +5382,19 @@ class HTMLParser {
|
|
|
5357
5382
|
let text;
|
|
5358
5383
|
if (textEnd >= 0) {
|
|
5359
5384
|
text = html.substring(0, textEnd);
|
|
5360
|
-
|
|
5385
|
+
advance(textEnd);
|
|
5361
5386
|
} else {
|
|
5362
5387
|
text = html;
|
|
5363
|
-
html
|
|
5388
|
+
advance(html.length);
|
|
5364
5389
|
}
|
|
5365
5390
|
|
|
5366
5391
|
// Next tag
|
|
5367
|
-
|
|
5392
|
+
const nextHtml = remaining();
|
|
5393
|
+
let nextTagMatch = parseStartTag(nextHtml);
|
|
5368
5394
|
if (nextTagMatch) {
|
|
5369
5395
|
nextTag = nextTagMatch.tagName;
|
|
5370
5396
|
} else {
|
|
5371
|
-
nextTagMatch =
|
|
5397
|
+
nextTagMatch = nextHtml.match(endTag);
|
|
5372
5398
|
if (nextTagMatch) {
|
|
5373
5399
|
nextTag = '/' + nextTagMatch[1];
|
|
5374
5400
|
} else {
|
|
@@ -5385,45 +5411,50 @@ class HTMLParser {
|
|
|
5385
5411
|
// Use pre-compiled regex for common tags (`script`, `style`, `noscript`) to avoid regex creation overhead
|
|
5386
5412
|
const reStackedTag = preCompiledStackedTags[stackedTag] || reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)</' + stackedTag + '[^>]*>', 'i'));
|
|
5387
5413
|
|
|
5388
|
-
|
|
5414
|
+
const m = reStackedTag.exec(html);
|
|
5415
|
+
if (m) {
|
|
5416
|
+
let text = m[1];
|
|
5389
5417
|
if (stackedTag !== 'script' && stackedTag !== 'style' && stackedTag !== 'noscript') {
|
|
5390
5418
|
text = text
|
|
5391
5419
|
.replace(/<!--([\s\S]*?)-->/g, '$1')
|
|
5392
5420
|
.replace(/<!\[CDATA\[([\s\S]*?)]]>/g, '$1');
|
|
5393
5421
|
}
|
|
5394
|
-
|
|
5395
5422
|
if (handler.chars) {
|
|
5396
5423
|
await handler.chars(text);
|
|
5397
5424
|
}
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5425
|
+
// Advance HTML past the matched special tag content and its closing tag
|
|
5426
|
+
advance(m.index + m[0].length);
|
|
5427
|
+
await parseEndTag('</' + stackedTag + '>', stackedTag);
|
|
5428
|
+
} else {
|
|
5429
|
+
// No closing tag found; to avoid infinite loop, break similarly to previous behavior
|
|
5430
|
+
if (handler.continueOnParseError && handler.chars && html) {
|
|
5431
|
+
await handler.chars(html[0], prevTag, '');
|
|
5432
|
+
advance(1);
|
|
5433
|
+
} else {
|
|
5434
|
+
break;
|
|
5435
|
+
}
|
|
5436
|
+
}
|
|
5403
5437
|
}
|
|
5404
5438
|
|
|
5405
|
-
if (
|
|
5439
|
+
if (pos === lastPos) {
|
|
5406
5440
|
if (handler.continueOnParseError) {
|
|
5407
5441
|
// Skip the problematic character and continue
|
|
5408
5442
|
if (handler.chars) {
|
|
5409
|
-
await handler.chars(
|
|
5443
|
+
await handler.chars(fullHtml[pos], prevTag, '');
|
|
5410
5444
|
}
|
|
5411
|
-
|
|
5412
|
-
position++;
|
|
5445
|
+
advance(1);
|
|
5413
5446
|
prevTag = '';
|
|
5414
5447
|
continue;
|
|
5415
5448
|
}
|
|
5416
|
-
const loc = getLineColumn(
|
|
5417
|
-
// Include some context before the error position so the snippet contains
|
|
5418
|
-
// the offending markup plus preceding characters (e.g. "invalid<tag").
|
|
5449
|
+
const loc = getLineColumn(pos);
|
|
5450
|
+
// Include some context before the error position so the snippet contains the offending markup plus preceding characters (e.g., “invalid<tag”)
|
|
5419
5451
|
const CONTEXT_BEFORE = 50;
|
|
5420
|
-
const startPos = Math.max(0,
|
|
5421
|
-
const snippet =
|
|
5452
|
+
const startPos = Math.max(0, pos - CONTEXT_BEFORE);
|
|
5453
|
+
const snippet = fullHtml.slice(startPos, startPos + 200).replace(/\n/g, ' ');
|
|
5422
5454
|
throw new Error(
|
|
5423
|
-
`Parse error at line ${loc.line}, column ${loc.column}:\n${snippet}${
|
|
5455
|
+
`Parse error at line ${loc.line}, column ${loc.column}:\n${snippet}${fullHtml.length > startPos + 200 ? '…' : ''}`
|
|
5424
5456
|
);
|
|
5425
5457
|
}
|
|
5426
|
-
position = this.html.length - html.length;
|
|
5427
5458
|
}
|
|
5428
5459
|
|
|
5429
5460
|
if (!handler.partialMarkup) {
|
|
@@ -5436,9 +5467,11 @@ class HTMLParser {
|
|
|
5436
5467
|
if (start) {
|
|
5437
5468
|
const match = {
|
|
5438
5469
|
tagName: start[1],
|
|
5439
|
-
attrs: []
|
|
5470
|
+
attrs: [],
|
|
5471
|
+
advance: 0
|
|
5440
5472
|
};
|
|
5441
|
-
|
|
5473
|
+
let consumed = start[0].length;
|
|
5474
|
+
input = input.slice(consumed);
|
|
5442
5475
|
let end, attr;
|
|
5443
5476
|
|
|
5444
5477
|
// Safety limit: max length of input to check for attributes
|
|
@@ -5488,7 +5521,9 @@ class HTMLParser {
|
|
|
5488
5521
|
} else {
|
|
5489
5522
|
attr[baseIndex + 3] = value; // Single-quoted value
|
|
5490
5523
|
}
|
|
5491
|
-
|
|
5524
|
+
const attrLen = fullAttr.length;
|
|
5525
|
+
input = input.slice(attrLen);
|
|
5526
|
+
consumed += attrLen;
|
|
5492
5527
|
match.attrs.push(attr);
|
|
5493
5528
|
continue;
|
|
5494
5529
|
}
|
|
@@ -5505,7 +5540,9 @@ class HTMLParser {
|
|
|
5505
5540
|
break;
|
|
5506
5541
|
}
|
|
5507
5542
|
|
|
5508
|
-
|
|
5543
|
+
const attrLen = attr[0].length;
|
|
5544
|
+
input = input.slice(attrLen);
|
|
5545
|
+
consumed += attrLen;
|
|
5509
5546
|
match.attrs.push(attr);
|
|
5510
5547
|
}
|
|
5511
5548
|
|
|
@@ -5513,7 +5550,8 @@ class HTMLParser {
|
|
|
5513
5550
|
end = input.match(startTagClose);
|
|
5514
5551
|
if (end) {
|
|
5515
5552
|
match.unarySlash = end[1];
|
|
5516
|
-
|
|
5553
|
+
consumed += end[0].length;
|
|
5554
|
+
match.advance = consumed;
|
|
5517
5555
|
return match;
|
|
5518
5556
|
}
|
|
5519
5557
|
}
|
|
@@ -5523,7 +5561,7 @@ class HTMLParser {
|
|
|
5523
5561
|
let pos;
|
|
5524
5562
|
const needle = tagName.toLowerCase();
|
|
5525
5563
|
for (pos = stack.length - 1; pos >= 0; pos--) {
|
|
5526
|
-
const currentTag = stack[pos].
|
|
5564
|
+
const currentTag = stack[pos].lowerTag;
|
|
5527
5565
|
if (currentTag === needle) {
|
|
5528
5566
|
return pos;
|
|
5529
5567
|
}
|
|
@@ -5577,7 +5615,7 @@ class HTMLParser {
|
|
|
5577
5615
|
}
|
|
5578
5616
|
if (tagName === 'col' && findTag('colgroup') < 0) {
|
|
5579
5617
|
lastTag = 'colgroup';
|
|
5580
|
-
stack.push({ tag: lastTag, attrs: [] });
|
|
5618
|
+
stack.push({ tag: lastTag, lowerTag: 'colgroup', attrs: [] });
|
|
5581
5619
|
if (handler.start) {
|
|
5582
5620
|
await handler.start(lastTag, [], false, '');
|
|
5583
5621
|
}
|
|
@@ -5656,7 +5694,7 @@ class HTMLParser {
|
|
|
5656
5694
|
});
|
|
5657
5695
|
|
|
5658
5696
|
if (!unary) {
|
|
5659
|
-
stack.push({ tag: tagName, attrs });
|
|
5697
|
+
stack.push({ tag: tagName, lowerTag: tagName.toLowerCase(), attrs });
|
|
5660
5698
|
lastTag = tagName;
|
|
5661
5699
|
unarySlash = '';
|
|
5662
5700
|
}
|
|
@@ -5670,7 +5708,7 @@ class HTMLParser {
|
|
|
5670
5708
|
let pos;
|
|
5671
5709
|
const needle = tagName.toLowerCase();
|
|
5672
5710
|
for (pos = stack.length - 1; pos >= 0; pos--) {
|
|
5673
|
-
if (stack[pos].
|
|
5711
|
+
if (stack[pos].lowerTag === needle) {
|
|
5674
5712
|
break;
|
|
5675
5713
|
}
|
|
5676
5714
|
}
|
|
@@ -5722,21 +5760,40 @@ class HTMLParser {
|
|
|
5722
5760
|
class Sorter {
|
|
5723
5761
|
sort(tokens, fromIndex = 0) {
|
|
5724
5762
|
for (let i = 0, len = this.keys.length; i < len; i++) {
|
|
5725
|
-
const
|
|
5726
|
-
|
|
5763
|
+
const token = this.keys[i];
|
|
5764
|
+
|
|
5765
|
+
// Build position map for this token to avoid repeated `indexOf`
|
|
5766
|
+
const positions = [];
|
|
5767
|
+
for (let j = fromIndex; j < tokens.length; j++) {
|
|
5768
|
+
if (tokens[j] === token) {
|
|
5769
|
+
positions.push(j);
|
|
5770
|
+
}
|
|
5771
|
+
}
|
|
5727
5772
|
|
|
5728
|
-
|
|
5773
|
+
if (positions.length > 0) {
|
|
5774
|
+
// Build new array with tokens in sorted order instead of splicing
|
|
5775
|
+
const result = [];
|
|
5729
5776
|
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5777
|
+
// Add all instances of the current token first
|
|
5778
|
+
for (let j = 0; j < positions.length; j++) {
|
|
5779
|
+
result.push(token);
|
|
5780
|
+
}
|
|
5781
|
+
|
|
5782
|
+
// Add other tokens, skipping positions where current token was
|
|
5783
|
+
const posSet = new Set(positions);
|
|
5784
|
+
for (let j = fromIndex; j < tokens.length; j++) {
|
|
5785
|
+
if (!posSet.has(j)) {
|
|
5786
|
+
result.push(tokens[j]);
|
|
5735
5787
|
}
|
|
5736
|
-
|
|
5737
|
-
} while ((index = tokens.indexOf(token, fromIndex)) !== -1);
|
|
5788
|
+
}
|
|
5738
5789
|
|
|
5739
|
-
|
|
5790
|
+
// Copy sorted portion back to tokens array
|
|
5791
|
+
for (let j = 0; j < result.length; j++) {
|
|
5792
|
+
tokens[fromIndex + j] = result[j];
|
|
5793
|
+
}
|
|
5794
|
+
|
|
5795
|
+
const newFromIndex = fromIndex + positions.length;
|
|
5796
|
+
return this.sorterMap.get(token).sort(tokens, newFromIndex);
|
|
5740
5797
|
}
|
|
5741
5798
|
}
|
|
5742
5799
|
return tokens;
|
|
@@ -5744,48 +5801,84 @@ class Sorter {
|
|
|
5744
5801
|
}
|
|
5745
5802
|
|
|
5746
5803
|
class TokenChain {
|
|
5804
|
+
constructor() {
|
|
5805
|
+
// Use Map instead of object properties for better performance
|
|
5806
|
+
this.map = new Map();
|
|
5807
|
+
}
|
|
5808
|
+
|
|
5747
5809
|
add(tokens) {
|
|
5748
5810
|
tokens.forEach((token) => {
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
this[key] = [];
|
|
5752
|
-
this[key].processed = 0;
|
|
5811
|
+
if (!this.map.has(token)) {
|
|
5812
|
+
this.map.set(token, { arrays: [], processed: 0 });
|
|
5753
5813
|
}
|
|
5754
|
-
this
|
|
5814
|
+
this.map.get(token).arrays.push(tokens);
|
|
5755
5815
|
});
|
|
5756
5816
|
}
|
|
5757
5817
|
|
|
5758
5818
|
createSorter() {
|
|
5759
5819
|
const sorter = new Sorter();
|
|
5820
|
+
sorter.sorterMap = new Map();
|
|
5821
|
+
|
|
5822
|
+
// Convert Map entries to array and sort
|
|
5823
|
+
const entries = Array.from(this.map.entries()).sort((a, b) => {
|
|
5824
|
+
const m = a[1].arrays.length;
|
|
5825
|
+
const n = b[1].arrays.length;
|
|
5826
|
+
// Sort by length descending (larger first)
|
|
5827
|
+
const lengthDiff = n - m;
|
|
5828
|
+
if (lengthDiff !== 0) return lengthDiff;
|
|
5829
|
+
// If lengths equal, sort by key ascending
|
|
5830
|
+
return a[0].localeCompare(b[0]);
|
|
5831
|
+
});
|
|
5760
5832
|
|
|
5761
|
-
sorter.keys =
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
}).filter((key) => {
|
|
5766
|
-
if (this[key].processed < this[key].length) {
|
|
5767
|
-
const token = key.slice(1);
|
|
5833
|
+
sorter.keys = [];
|
|
5834
|
+
|
|
5835
|
+
entries.forEach(([token, data]) => {
|
|
5836
|
+
if (data.processed < data.arrays.length) {
|
|
5768
5837
|
const chain = new TokenChain();
|
|
5769
5838
|
|
|
5770
|
-
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5839
|
+
data.arrays.forEach((tokens) => {
|
|
5840
|
+
// Build new array without the current token instead of splicing
|
|
5841
|
+
const filtered = [];
|
|
5842
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
5843
|
+
if (tokens[i] !== token) {
|
|
5844
|
+
filtered.push(tokens[i]);
|
|
5845
|
+
}
|
|
5774
5846
|
}
|
|
5775
|
-
|
|
5776
|
-
|
|
5847
|
+
|
|
5848
|
+
// Mark remaining tokens as processed
|
|
5849
|
+
filtered.forEach((t) => {
|
|
5850
|
+
const tData = this.map.get(t);
|
|
5851
|
+
if (tData) {
|
|
5852
|
+
tData.processed++;
|
|
5853
|
+
}
|
|
5777
5854
|
});
|
|
5778
|
-
|
|
5855
|
+
|
|
5856
|
+
if (filtered.length > 0) {
|
|
5857
|
+
chain.add(filtered);
|
|
5858
|
+
}
|
|
5779
5859
|
});
|
|
5780
|
-
|
|
5781
|
-
|
|
5860
|
+
|
|
5861
|
+
sorter.keys.push(token);
|
|
5862
|
+
sorter.sorterMap.set(token, chain.createSorter());
|
|
5782
5863
|
}
|
|
5783
|
-
return false;
|
|
5784
5864
|
});
|
|
5865
|
+
|
|
5785
5866
|
return sorter;
|
|
5786
5867
|
}
|
|
5787
5868
|
}
|
|
5788
5869
|
|
|
5870
|
+
async function replaceAsync(str, regex, asyncFn) {
|
|
5871
|
+
const promises = [];
|
|
5872
|
+
|
|
5873
|
+
str.replace(regex, (match, ...args) => {
|
|
5874
|
+
const promise = asyncFn(match, ...args);
|
|
5875
|
+
promises.push(promise);
|
|
5876
|
+
});
|
|
5877
|
+
|
|
5878
|
+
const data = await Promise.all(promises);
|
|
5879
|
+
return str.replace(regex, () => data.shift());
|
|
5880
|
+
}
|
|
5881
|
+
|
|
5789
5882
|
/**
|
|
5790
5883
|
* Preset configurations for HTML Minifier Next
|
|
5791
5884
|
*
|
|
@@ -7436,7 +7529,9 @@ async function createSortFns(value, options, uidIgnore, uidAttr) {
|
|
|
7436
7529
|
currentType === 'text/html') {
|
|
7437
7530
|
await scan(text);
|
|
7438
7531
|
}
|
|
7439
|
-
}
|
|
7532
|
+
},
|
|
7533
|
+
// We never need `nextTag` information in this scan
|
|
7534
|
+
wantsNextTag: false
|
|
7440
7535
|
});
|
|
7441
7536
|
|
|
7442
7537
|
await parser.parse();
|
|
@@ -7672,6 +7767,8 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
7672
7767
|
customAttrAssign: options.customAttrAssign,
|
|
7673
7768
|
customAttrSurround: options.customAttrSurround,
|
|
7674
7769
|
html5: options.html5,
|
|
7770
|
+
// Compute `nextTag` only when whitespace collapse features require it
|
|
7771
|
+
wantsNextTag: !!(options.collapseWhitespace || options.collapseInlineTagWhitespace || options.conservativeCollapse),
|
|
7675
7772
|
|
|
7676
7773
|
start: async function (tag, attrs, unary, unarySlash, autoGenerated) {
|
|
7677
7774
|
if (tag.toLowerCase() === 'svg') {
|
|
@@ -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":"AAovEO,8BAJI,MAAM,YACN,eAAe,GACb,OAAO,CAAC,MAAM,CAAC,CAQ3B;;;;;;;;;;;;UA3tES,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;;;;;;;;gCAOP,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,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;;;iBASzG,OAAO,GAAG,MAAM,GAAG,OAAO,WAAW,EAAE,OAAO,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;;;;;;;;WAS7F,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;;wBAnYkC,cAAc;0BAAd,cAAc;+BAAd,cAAc"}
|
|
@@ -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":"AA8CA,4BAAoE;AAuEpE;IACE,qCAGC;IAFC,UAAgB;IAChB,aAAsB;IAGxB,uBAoeC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokenchain.d.ts","sourceRoot":"","sources":["../../src/tokenchain.js"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"tokenchain.d.ts","sourceRoot":"","sources":["../../src/tokenchain.js"],"names":[],"mappings":";AA2CA;IAGI,mBAAoB;IAGtB,uBAOC;IAED,uBAiDC;CACF;AA5GD;IACE,2CAuCC;CACF"}
|
package/package.json
CHANGED
|
@@ -15,17 +15,17 @@
|
|
|
15
15
|
},
|
|
16
16
|
"description": "Super-configurable, well-tested, JavaScript-based HTML minifier (enhanced successor of HTML Minifier)",
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@commitlint/cli": "^20.
|
|
18
|
+
"@commitlint/cli": "^20.2.0",
|
|
19
19
|
"@eslint/js": "^9.39.1",
|
|
20
20
|
"@rollup/plugin-commonjs": "^29.0.0",
|
|
21
21
|
"@rollup/plugin-json": "^6.1.0",
|
|
22
22
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
23
23
|
"@rollup/plugin-terser": "^0.4.4",
|
|
24
24
|
"eslint": "^9.39.1",
|
|
25
|
-
"rollup": "^4.53.
|
|
25
|
+
"rollup": "^4.53.3",
|
|
26
26
|
"rollup-plugin-polyfill-node": "^0.13.0",
|
|
27
27
|
"typescript": "^5.9.3",
|
|
28
|
-
"vite": "^7.2.
|
|
28
|
+
"vite": "^7.2.7"
|
|
29
29
|
},
|
|
30
30
|
"exports": {
|
|
31
31
|
".": {
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"test:watch": "node --test --watch tests/*.spec.js"
|
|
85
85
|
},
|
|
86
86
|
"type": "module",
|
|
87
|
-
"version": "4.
|
|
87
|
+
"version": "4.10.0"
|
|
88
88
|
}
|
package/src/htmlminifier.js
CHANGED
|
@@ -1588,7 +1588,9 @@ async function createSortFns(value, options, uidIgnore, uidAttr) {
|
|
|
1588
1588
|
currentType === 'text/html') {
|
|
1589
1589
|
await scan(text);
|
|
1590
1590
|
}
|
|
1591
|
-
}
|
|
1591
|
+
},
|
|
1592
|
+
// We never need `nextTag` information in this scan
|
|
1593
|
+
wantsNextTag: false
|
|
1592
1594
|
});
|
|
1593
1595
|
|
|
1594
1596
|
await parser.parse();
|
|
@@ -1824,6 +1826,8 @@ async function minifyHTML(value, options, partialMarkup) {
|
|
|
1824
1826
|
customAttrAssign: options.customAttrAssign,
|
|
1825
1827
|
customAttrSurround: options.customAttrSurround,
|
|
1826
1828
|
html5: options.html5,
|
|
1829
|
+
// Compute `nextTag` only when whitespace collapse features require it
|
|
1830
|
+
wantsNextTag: !!(options.collapseWhitespace || options.collapseInlineTagWhitespace || options.conservativeCollapse),
|
|
1827
1831
|
|
|
1828
1832
|
start: async function (tag, attrs, unary, unarySlash, autoGenerated) {
|
|
1829
1833
|
if (tag.toLowerCase() === 'svg') {
|