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.
@@ -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
- const attribute = attrForHandler(handler);
5279
- let last, prevTag = undefined, nextTag = undefined;
5280
-
5281
- // Track position for better error messages
5282
- let position = 0;
5283
- const getLineColumn = (pos) => {
5284
- const lines = this.html.slice(0, pos).split('\n');
5285
- return { line: lines.length, column: lines[lines.length - 1].length + 1 };
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 (html) {
5289
- last = html;
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
- html = html.substring(commentEnd + 3);
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
- html = html.substring(conditionalEnd + 2);
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
- html = html.substring(doctypeMatch[0].length);
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
- html = html.substring(endTagMatch[0].length);
5337
- await replaceAsync(endTagMatch[0], endTag, parseEndTag);
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
- html = startTagMatch.rest;
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
- html = html.substring(textEnd);
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
- let nextTagMatch = parseStartTag(html);
5392
+ const nextHtml = remaining();
5393
+ let nextTagMatch = parseStartTag(nextHtml);
5368
5394
  if (nextTagMatch) {
5369
5395
  nextTag = nextTagMatch.tagName;
5370
5396
  } else {
5371
- nextTagMatch = html.match(endTag);
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
- html = await replaceAsync(html, reStackedTag, async (_, text) => {
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
- return '';
5400
- });
5401
-
5402
- await parseEndTag('</' + stackedTag + '>', stackedTag);
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 (html === last) {
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(html[0], prevTag, '');
5443
+ await handler.chars(fullHtml[pos], prevTag, '');
5410
5444
  }
5411
- html = html.substring(1);
5412
- position++;
5445
+ advance(1);
5413
5446
  prevTag = '';
5414
5447
  continue;
5415
5448
  }
5416
- const loc = getLineColumn(position);
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, position - CONTEXT_BEFORE);
5421
- const snippet = this.html.slice(startPos, startPos + 200).replace(/\n/g, ' ');
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}${this.html.length > startPos + 200 ? '…' : ''}`
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
- input = input.slice(start[0].length);
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
- input = input.slice(fullAttr.length);
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
- input = input.slice(attr[0].length);
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
- match.rest = input.slice(end[0].length);
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].tag.toLowerCase();
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].tag.toLowerCase() === needle) {
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 key = this.keys[i];
5726
- const token = key.slice(1);
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
- let index = tokens.indexOf(token, fromIndex);
5773
+ if (positions.length > 0) {
5774
+ // Build new array with tokens in sorted order instead of splicing
5775
+ const result = [];
5729
5776
 
5730
- if (index !== -1) {
5731
- do {
5732
- if (index !== fromIndex) {
5733
- tokens.splice(index, 1);
5734
- tokens.splice(fromIndex, 0, token);
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
- fromIndex++;
5737
- } while ((index = tokens.indexOf(token, fromIndex)) !== -1);
5788
+ }
5738
5789
 
5739
- return this[key].sort(tokens, fromIndex);
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
- const key = '$' + token;
5750
- if (!this[key]) {
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[key].push(tokens);
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 = Object.keys(this).sort((j, k) => {
5762
- const m = this[j].length;
5763
- const n = this[k].length;
5764
- return m < n ? 1 : m > n ? -1 : j < k ? -1 : j > k ? 1 : 0;
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
- this[key].forEach((tokens) => {
5771
- let index;
5772
- while ((index = tokens.indexOf(token)) !== -1) {
5773
- tokens.splice(index, 1);
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
- tokens.forEach((token) => {
5776
- this['$' + token].processed++;
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
- chain.add(tokens.slice(0));
5855
+
5856
+ if (filtered.length > 0) {
5857
+ chain.add(filtered);
5858
+ }
5779
5859
  });
5780
- sorter[key] = chain.createSorter();
5781
- return true;
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":"AAgvEO,8BAJI,MAAM,YACN,eAAe,GACb,OAAO,CAAC,MAAM,CAAC,CAQ3B;;;;;;;;;;;;UAvtES,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
+ {"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":"AAgDA,4BAAoE;AAoEpE;IACE,qCAGC;IAFC,UAAgB;IAChB,aAAsB;IAGxB,uBA8bC;CACF"}
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,5 +1,6 @@
1
1
  export default TokenChain;
2
2
  declare class TokenChain {
3
+ map: Map<any, any>;
3
4
  add(tokens: any): void;
4
5
  createSorter(): Sorter;
5
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tokenchain.d.ts","sourceRoot":"","sources":["../../src/tokenchain.js"],"names":[],"mappings":";AAwBA;IACE,uBASC;IAED,uBA4BC;CACF;AAjED;IACE,2CAoBC;CACF"}
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.1.0",
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.2",
25
+ "rollup": "^4.53.3",
26
26
  "rollup-plugin-polyfill-node": "^0.13.0",
27
27
  "typescript": "^5.9.3",
28
- "vite": "^7.2.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.9.1"
87
+ "version": "4.10.0"
88
88
  }
@@ -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') {