html-minifier-next 7.2.0 → 7.4.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.
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.js"],"names":[],"mappings":"AAEA;;;GAGG;AACH,qCAHW,OAAO,GACL,MAAM,CAYlB;AAID;IACE,4BAIC;IAHC,cAAkB;IAClB,mCAAmC;IACnC,KADW,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CACX;IAEtB,0BAA0B;IAC1B,SADY,MAAM,WASjB;IACD;;;OAGG;IACH,SAHW,MAAM,SACN,OAAO,QASjB;IACD,0BAA0B;IAC1B,YADY,MAAM,QACmB;CACtC;AAID,0BAA0B;AAC1B,iCADY,MAAM,UAQjB;AAID,4BAA4B;AAC5B,gCADY,MAAM,UAOjB;AAID,4BAA4B;AAC5B,gCADY,MAAM,UAGjB;AAED;;;GAGG;AACH,kCAHW,OAAO,GACL,KAAK,IAAI,WAAW,CAAC,GAAG,CAAC,CAIrC;AAED,4BAA4B;AAC5B,iCADY,MAAM,UAGjB;AAID;;;;;;GAMG;AACH,kCALW,MAAM,SACN,MAAM,sBAEJ,OAAO,CAAC,MAAM,CAAC,CAc3B;AAID,qCAAqC;AACrC,mCADY,MAAM,GAAG,MAAM,sBAW1B"}
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,CAc3B;AAID,qCAAqC;AACrC,iBAAS,WAAW,CAAC,KAAK,EADd,MAAM,GAAG,MACK,sBAUzB;AAID,OAAO,EAAE,eAAe,EAAE,CAAC;AAC3B,OAAO,EAAE,GAAG,EAAE,CAAC;AACf,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,CAAC;AACpB,OAAO,EAAE,UAAU,EAAE,CAAC;AACtB,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -1,7 +1,7 @@
1
1
  /** @param {string} str */
2
- export function trimWhitespace(str: string): string;
2
+ declare const trimWhitespace: (str: string) => string;
3
3
  /** @param {string} str */
4
- export function collapseWhitespaceAll(str: string): string;
4
+ declare function collapseWhitespaceAll(str: string): string;
5
5
  /**
6
6
  * @param {string} str
7
7
  * @param {{preserveLineBreaks?: boolean | undefined, conservativeCollapse?: boolean | undefined}} options
@@ -9,7 +9,7 @@ export function collapseWhitespaceAll(str: string): string;
9
9
  * @param {boolean} trimRight
10
10
  * @param {boolean} [collapseAll]
11
11
  */
12
- export function collapseWhitespace(str: string, options: {
12
+ declare function collapseWhitespace(str: string, options: {
13
13
  preserveLineBreaks?: boolean | undefined;
14
14
  conservativeCollapse?: boolean | undefined;
15
15
  }, trimLeft: boolean, trimRight: boolean, collapseAll?: boolean): string;
@@ -23,7 +23,7 @@ export function collapseWhitespace(str: string, options: {
23
23
  * @param {Set<string>} inlineElements
24
24
  * @param {Set<string>} inlineTextSet
25
25
  */
26
- export function collapseWhitespaceSmart(str: string, prevTag: string, nextTag: string, prevAttrs: Array<{
26
+ declare function collapseWhitespaceSmart(str: string, prevTag: string, nextTag: string, prevAttrs: Array<{
27
27
  name: string;
28
28
  value?: string;
29
29
  }>, nextAttrs: Array<{
@@ -35,7 +35,8 @@ export function collapseWhitespaceSmart(str: string, prevTag: string, nextTag: s
35
35
  collapseInlineTagWhitespace?: boolean;
36
36
  }, inlineElements: Set<string>, inlineTextSet: Set<string>): string;
37
37
  /** @param {string} tag */
38
- export function canCollapseWhitespace(tag: string): boolean;
38
+ declare function canCollapseWhitespace(tag: string): boolean;
39
39
  /** @param {string} tag */
40
- export function canTrimWhitespace(tag: string): boolean;
40
+ declare function canTrimWhitespace(tag: string): boolean;
41
+ export { trimWhitespace, collapseWhitespaceAll, collapseWhitespace, collapseWhitespaceSmart, canCollapseWhitespace, canTrimWhitespace };
41
42
  //# sourceMappingURL=whitespace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"whitespace.d.ts","sourceRoot":"","sources":["../../../src/lib/whitespace.js"],"names":[],"mappings":"AAeA,0BAA0B;AAC1B,oCADY,MAAM,UAQjB;AAID,0BAA0B;AAC1B,2CADY,MAAM,UAiBjB;AAID;;;;;;GAMG;AACH,wCANW,MAAM,WACN;IAAC,kBAAkB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,oBAAoB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAC,YACtF,OAAO,aACP,OAAO,gBACP,OAAO,UAuFjB;AAID;;;;;;;;;GASG;AACH,6CATW,MAAM,WACN,MAAM,WACN,MAAM,aACN,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,CAAC,aACrC,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAC,CAAC,WACrC;IAAC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAAC,2BAA2B,CAAC,EAAE,OAAO,CAAA;CAAC,kBACrG,GAAG,CAAC,MAAM,CAAC,iBACX,GAAG,CAAC,MAAM,CAAC,UA0ErB;AAOD,0BAA0B;AAC1B,2CADY,MAAM,WAGjB;AAED,0BAA0B;AAC1B,uCADY,MAAM,WAGjB"}
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;AAID;;;;;;;;;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,UAwEnH;AAOD,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"}
@@ -1,47 +1,49 @@
1
+ /**
2
+ * Preset configurations
3
+ *
4
+ * Presets provide curated option sets for common use cases:
5
+ * - `conservative`: Safe minification suitable for most projects
6
+ * - `comprehensive`: Aggressive minification for maximum file size reduction
7
+ */
8
+ export declare const presets: {
9
+ conservative: {
10
+ caseSensitive: boolean;
11
+ collapseBooleanAttributes: boolean;
12
+ collapseWhitespace: boolean;
13
+ conservativeCollapse: boolean;
14
+ preserveLineBreaks: boolean;
15
+ removeComments: boolean;
16
+ removeDefaultTypeAttributes: boolean;
17
+ useShortDoctype: boolean;
18
+ };
19
+ comprehensive: {
20
+ collapseAttributeWhitespace: boolean;
21
+ collapseBooleanAttributes: boolean;
22
+ collapseWhitespace: boolean;
23
+ decodeEntities: boolean;
24
+ mergeScripts: boolean;
25
+ minifyCSS: boolean;
26
+ minifyJS: boolean;
27
+ minifySVG: boolean;
28
+ minifyURLs: boolean;
29
+ removeAttributeQuotes: boolean;
30
+ removeComments: boolean;
31
+ removeDefaultTypeAttributes: boolean;
32
+ removeEmptyAttributes: boolean;
33
+ removeOptionalTags: boolean;
34
+ removeRedundantAttributes: boolean;
35
+ useShortDoctype: boolean;
36
+ };
37
+ };
1
38
  /**
2
39
  * Get preset configuration by name
3
40
  * @param {string} name - Preset name (“conservative” or “comprehensive”)
4
41
  * @returns {object|null} Preset options object or null if not found
5
42
  */
6
- export function getPreset(name: string): object | null;
43
+ export declare function getPreset(name: string): object | null;
7
44
  /**
8
45
  * Get list of available preset names
9
46
  * @returns {string[]} Array of preset names
10
47
  */
11
- export function getPresetNames(): string[];
12
- export namespace presets {
13
- namespace conservative {
14
- let caseSensitive: boolean;
15
- let collapseBooleanAttributes: boolean;
16
- let collapseWhitespace: boolean;
17
- let conservativeCollapse: boolean;
18
- let preserveLineBreaks: boolean;
19
- let removeComments: boolean;
20
- let removeDefaultTypeAttributes: boolean;
21
- let useShortDoctype: boolean;
22
- }
23
- namespace comprehensive {
24
- export let collapseAttributeWhitespace: boolean;
25
- let collapseBooleanAttributes_1: boolean;
26
- export { collapseBooleanAttributes_1 as collapseBooleanAttributes };
27
- let collapseWhitespace_1: boolean;
28
- export { collapseWhitespace_1 as collapseWhitespace };
29
- export let decodeEntities: boolean;
30
- export let mergeScripts: boolean;
31
- export let minifyCSS: boolean;
32
- export let minifyJS: boolean;
33
- export let minifySVG: boolean;
34
- export let minifyURLs: boolean;
35
- export let removeAttributeQuotes: boolean;
36
- let removeComments_1: boolean;
37
- export { removeComments_1 as removeComments };
38
- let removeDefaultTypeAttributes_1: boolean;
39
- export { removeDefaultTypeAttributes_1 as removeDefaultTypeAttributes };
40
- export let removeEmptyAttributes: boolean;
41
- export let removeOptionalTags: boolean;
42
- export let removeRedundantAttributes: boolean;
43
- let useShortDoctype_1: boolean;
44
- export { useShortDoctype_1 as useShortDoctype };
45
- }
46
- }
48
+ export declare function getPresetNames(): string[];
47
49
  //# sourceMappingURL=presets.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/presets.js"],"names":[],"mappings":"AAuCA;;;;GAIG;AACH,gCAHW,MAAM,GACJ,MAAM,GAAC,IAAI,CAMvB;AAED;;;GAGG;AACH,kCAFa,MAAM,EAAE,CAIpB"}
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/presets.js"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,OAAO;IAClB,YAAY;QACV,aAAa;QACb,yBAAyB;QACzB,kBAAkB;QAClB,oBAAoB;QACpB,kBAAkB;QAClB,cAAc;QACd,2BAA2B;QAC3B,eAAe;;IAEjB,aAAa;QACX,2BAA2B;QAC3B,yBAAyB;QACzB,kBAAkB;QAClB,cAAc;QACd,YAAY;QACZ,SAAS;QACT,QAAQ;QACR,SAAS;QACT,UAAU;QACV,qBAAqB;QACrB,cAAc;QACd,2BAA2B;QAC3B,qBAAqB;QACrB,kBAAkB;QAClB,yBAAyB;QACzB,eAAe;;CAElB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAHnB,MAGmB,GAFjB,MAAM,GAAC,IAAI,CAMvB;AAED;;;GAGG;AACH,wBAAgB,cAAc,IAFjB,MAAM,EAAE,CAIpB"}
@@ -1,19 +1,9 @@
1
- export default TokenChain;
2
- declare class TokenChain {
3
- /** @type {Map<string, {arrays: string[][], processed: number}>} */
4
- map: Map<string, {
5
- arrays: string[][];
6
- processed: number;
7
- }>;
8
- /** @param {string[]} tokens */
9
- add(tokens: string[]): void;
10
- createSorter(): Sorter;
11
- }
12
1
  declare class Sorter {
13
2
  /** @type {string[]} */
14
3
  keys: string[];
15
4
  /** @type {Map<string, Sorter>} */
16
5
  sorterMap: Map<string, Sorter>;
6
+ constructor();
17
7
  /**
18
8
  * @param {string[]} tokens
19
9
  * @param {number} fromIndex
@@ -21,4 +11,16 @@ declare class Sorter {
21
11
  */
22
12
  sort(tokens: string[], fromIndex?: number): string[];
23
13
  }
14
+ declare class TokenChain {
15
+ /** @type {Map<string, {arrays: string[][], processed: number}>} */
16
+ map: Map<string, {
17
+ arrays: string[][];
18
+ processed: number;
19
+ }>;
20
+ constructor();
21
+ /** @param {string[]} tokens */
22
+ add(tokens: string[]): void;
23
+ createSorter(): Sorter;
24
+ }
25
+ export default TokenChain;
24
26
  //# sourceMappingURL=tokenchain.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokenchain.d.ts","sourceRoot":"","sources":["../../src/tokenchain.js"],"names":[],"mappings":";AA+CA;IAEI,mEAAmE;IACnE,KADW,GAAG,CAAC,MAAM,EAAE;QAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAC,CAC3C;IAGtB,+BAA+B;IAC/B,YADY,MAAM,EAAE,QAUnB;IAED,uBA+CC;CACF;AAjHD;IAEI,uBAAuB;IACvB,MADW,MAAM,EAAE,CACL;IACd,kCAAkC;IAClC,WADW,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CACJ;IAG5B;;;;OAIG;IACH,aAJW,MAAM,EAAE,cACR,MAAM,GACJ,MAAM,EAAE,CAiCpB;CACF"}
1
+ {"version":3,"file":"tokenchain.d.ts","sourceRoot":"","sources":["../../src/tokenchain.js"],"names":[],"mappings":"AAAA,cAAM,MAAM;IAER,uBAAuB;IAClB,IAAI,EADE,MAAM,EAAE;IAEnB,kCAAkC;IAC7B,SAAS,EADH,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAHhC,cAKC;IAED;;;;OAIG;IACH,IAAI,CAAC,MAAM,EAJA,MAAM,EAIN,EAAE,SAAS,GAHX,MAGe,GAFb,MAAM,EAAE,CAiCpB;CACF;AAED,cAAM,UAAU;IAEZ,mEAAmE;IAC9D,GAAG,EADG,GAAG,CAAC,MAAM,EAAE;QAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAC;IADjE,cAGC;IAED,+BAA+B;IAC/B,GAAG,CAAC,MAAM,EADE,MAAM,EACR,QAST;IAED,YAAY,WA+CX;CACF;eAEc,UAAU"}
package/package.json CHANGED
@@ -9,21 +9,21 @@
9
9
  "commander": "^15.0.0",
10
10
  "entities": "^8.0.0",
11
11
  "lightningcss": "^1.32.0",
12
- "svgo": "^4.0.1",
13
- "terser": "^5.47.1"
12
+ "svgo": "^4.0.2",
13
+ "terser": "^5.49.0"
14
14
  },
15
15
  "description": "Super-configurable and well-tested web page minifier (enhanced successor to HTML Minifier)",
16
16
  "devDependencies": {
17
- "@commitlint/cli": "^21.2.0",
17
+ "@commitlint/cli": "^21.2.1",
18
18
  "@eslint/js": "^10.0.1",
19
- "@swc/core": "^1.15.41",
20
- "@types/node": "^26.1.0",
21
- "eslint": "^10.6.0",
22
- "typescript": "^6.0.3",
23
- "vite": "^8.0.16"
19
+ "@swc/core": "^1.15.43",
20
+ "@types/node": "^26.1.1",
21
+ "eslint": "^10.7.0",
22
+ "typescript": "^7.0.2",
23
+ "vite": "^8.1.5"
24
24
  },
25
25
  "engines": {
26
- "node": ">=22"
26
+ "node": ">=22.13"
27
27
  },
28
28
  "exports": {
29
29
  ".": {
@@ -34,9 +34,9 @@
34
34
  },
35
35
  "files": [
36
36
  "cli.js",
37
+ "dist/types",
37
38
  "html-minifier-next.schema.json",
38
- "dist/types/",
39
- "src/"
39
+ "src"
40
40
  ],
41
41
  "funding": "https://github.com/j9t/html-minifier-next?sponsor=1",
42
42
  "homepage": "https://j9t.github.io/html-minifier-next/",
@@ -93,5 +93,5 @@
93
93
  "test:watch": "node --test --watch tests/*.spec.js"
94
94
  },
95
95
  "type": "module",
96
- "version": "7.2.0"
96
+ "version": "7.4.0"
97
97
  }
@@ -529,6 +529,22 @@ let jsMinifyCache = null;
529
529
  /** @type {LRU | null} */
530
530
  let svgMinifyCache = null;
531
531
 
532
+ /**
533
+ * @typedef {Object} CacheStats
534
+ * Hit/miss statistics and current occupancy for a single minification cache.
535
+ *
536
+ * @prop {number} gets Number of lookups attempted against the cache.
537
+ * @prop {number} hits Number of lookups that found a cached entry.
538
+ * @prop {number} size Number of entries currently held in the cache.
539
+ * @prop {number} limit Maximum number of entries the cache can hold.
540
+ */
541
+
542
+ /**
543
+ * @param {LRU | null} cache
544
+ * @returns {CacheStats}
545
+ */
546
+ const cacheStatsOrEmpty = (cache) => cache ? cache.stats() : { gets: 0, hits: 0, size: 0, limit: 0 };
547
+
532
548
  // Pre-compiled patterns for script merging (avoid repeated allocation in hot path)
533
549
  const RE_SCRIPT_ATTRS = /([^\s=]+)(?:=(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g;
534
550
  const RE_SCRIPT_OPEN = /<script(?=[\s>])/gi; // Finds tag start; use `findTagEnd()` for the actual closing `>`
@@ -1893,6 +1909,23 @@ function initCaches(options) {
1893
1909
  return { cssMinifyCache, jsMinifyCache, svgMinifyCache };
1894
1910
  }
1895
1911
 
1912
+ /**
1913
+ * Get hit/miss statistics for the CSS, JavaScript, and SVG minification caches.
1914
+ *
1915
+ * Each cache is created lazily on the first `minify()` call (see `initCaches`); before
1916
+ * that first call, or for a cache never exercised (e.g., `minifyCSS` disabled), its
1917
+ * entry reports all-zero stats.
1918
+ *
1919
+ * @returns {{ css: CacheStats, js: CacheStats, svg: CacheStats }}
1920
+ */
1921
+ export function getCacheStats() {
1922
+ return {
1923
+ css: cacheStatsOrEmpty(cssMinifyCache),
1924
+ js: cacheStatsOrEmpty(jsMinifyCache),
1925
+ svg: cacheStatsOrEmpty(svgMinifyCache)
1926
+ };
1927
+ }
1928
+
1896
1929
  /**
1897
1930
  * @param {string} value
1898
1931
  * @param {MinifierOptions} [options]
@@ -1926,4 +1959,4 @@ export const minify = async function (value, options) {
1926
1959
 
1927
1960
  export { presets, getPreset, getPresetNames };
1928
1961
 
1929
- export default { minify, presets, getPreset, getPresetNames };
1962
+ export default { minify, presets, getPreset, getPresetNames, getCacheStats };
@@ -1,5 +1,5 @@
1
1
  import { createUrlMinifier } from './urls.js';
2
- import { LRU, stableStringify, hashContent, identity, lowercase, replaceAsync, parseRegExp } from './utils.js';
2
+ import { LRU, MAX_CACHE_ENTRY_SIZE, stableStringify, hashContent, identity, lowercase, replaceAsync, parseRegExp } from './utils.js';
3
3
  import { RE_TRAILING_SEMICOLON } from './constants.js';
4
4
  import { canCollapseWhitespace, canTrimWhitespace } from './whitespace.js';
5
5
  import { wrapCSS, unwrapCSS } from './content.js';
@@ -183,15 +183,20 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
183
183
  // Cache key: Content + type + options signature; large inputs are hashed to avoid huge Map keys
184
184
  const inputCSS = wrapCSS(text, type);
185
185
  const cssSig = stableStringify({ type, opts: lightningCssOptions, cont: !!options.continueOnMinifyError });
186
- const cssKey = inputCSS.length > 2048
187
- ? (hashContent(inputCSS) + '|' + type + '|' + cssSig)
188
- : (inputCSS + '|' + type + '|' + cssSig);
186
+ const isCacheable = inputCSS.length <= MAX_CACHE_ENTRY_SIZE;
187
+ const cssKey = isCacheable
188
+ ? (inputCSS.length > 2048
189
+ ? (hashContent(inputCSS) + '|' + type + '|' + cssSig)
190
+ : (inputCSS + '|' + type + '|' + cssSig))
191
+ : undefined;
189
192
 
190
193
  try {
191
- const cached = /** @type {string | Promise<string> | undefined} */ (cssCache.get(cssKey));
192
- if (cached !== undefined) {
193
- // Support both resolved values and in-flight promises
194
- return await cached;
194
+ if (cssKey !== undefined) {
195
+ const cached = /** @type {string | Promise<string> | undefined} */ (cssCache.get(cssKey));
196
+ if (cached !== undefined) {
197
+ // Support both resolved values and in-flight promises
198
+ return await cached;
199
+ }
195
200
  }
196
201
 
197
202
  // In-flight promise caching: Prevent duplicate concurrent minifications
@@ -224,12 +229,12 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
224
229
  return (text.trim() && !outputCSS.trim() && (looksLikeTemplate || hasUID)) ? text : outputCSS;
225
230
  })();
226
231
 
227
- cssCache.set(cssKey, inFlight);
232
+ if (cssKey !== undefined) cssCache.set(cssKey, inFlight);
228
233
  const resolved = await inFlight;
229
- cssCache.set(cssKey, resolved);
234
+ if (cssKey !== undefined) cssCache.set(cssKey, resolved);
230
235
  return resolved;
231
236
  } catch (err) {
232
- cssCache.delete(cssKey);
237
+ if (cssKey !== undefined) cssCache.delete(cssKey);
233
238
  if (!options.continueOnMinifyError) {
234
239
  throw err;
235
240
  }
@@ -293,19 +298,22 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
293
298
  // Hybrid strategy: Always use Terser for inline JS (needs bare returns support)
294
299
  // Use user’s chosen engine for script blocks
295
300
  const useEngine = inline ? 'terser' : engine;
296
-
297
301
  let jsKey;
302
+ const isCacheable = code.length <= MAX_CACHE_ENTRY_SIZE;
303
+
298
304
  try {
299
305
  // Select pre-computed signature based on engine
300
306
  const optsSig = useEngine === 'terser' ? terserSig : swcSig;
301
307
 
302
- // For large inputs, hash the full content to avoid storing huge strings as Map keys
303
- jsKey = (code.length > 2048 ? (hashContent(code) + '|') : (code + '|'))
304
- + (inline ? '1' : '0') + '|' + (isModule ? 'm' : '') + '|' + useEngine + '|' + optsSig;
308
+ if (isCacheable) {
309
+ // For large inputs, hash the full content to avoid storing huge strings as Map keys
310
+ jsKey = (code.length > 2048 ? (hashContent(code) + '|') : (code + '|'))
311
+ + (inline ? '1' : '0') + '|' + (isModule ? 'm' : '') + '|' + useEngine + '|' + optsSig;
305
312
 
306
- const cached = /** @type {string | Promise<string> | undefined} */ (jsCache.get(jsKey));
307
- if (cached !== undefined) {
308
- return await cached;
313
+ const cached = /** @type {string | Promise<string> | undefined} */ (jsCache.get(jsKey));
314
+ if (cached !== undefined) {
315
+ return await cached;
316
+ }
309
317
  }
310
318
 
311
319
  const inFlight = (async () => {
@@ -337,12 +345,12 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
337
345
  throw new Error(`Unknown JS minifier engine: ${useEngine}`);
338
346
  })();
339
347
 
340
- jsCache.set(jsKey, inFlight);
348
+ if (jsKey !== undefined) jsCache.set(jsKey, inFlight);
341
349
  const resolved = await inFlight;
342
- jsCache.set(jsKey, resolved);
350
+ if (jsKey !== undefined) jsCache.set(jsKey, resolved);
343
351
  return resolved;
344
352
  } catch (err) {
345
- if (jsKey) jsCache.delete(jsKey);
353
+ if (jsKey !== undefined) jsCache.delete(jsKey);
346
354
  if (!options.continueOnMinifyError) {
347
355
  throw err;
348
356
  }
@@ -416,15 +424,19 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
416
424
  return svgContent;
417
425
  }
418
426
 
419
- // Cache key: Large inputs are hashed to avoid huge Map keys
420
- const svgKey = svgContent.length > 2048
421
- ? (hashContent(svgContent) + '|' + svgSig)
422
- : (svgContent + '|' + svgSig);
427
+ const isCacheable = svgContent.length <= MAX_CACHE_ENTRY_SIZE;
428
+ const svgKey = isCacheable
429
+ ? (svgContent.length > 2048
430
+ ? (hashContent(svgContent) + '|' + svgSig)
431
+ : (svgContent + '|' + svgSig))
432
+ : undefined;
423
433
 
424
434
  try {
425
- const cached = /** @type {string | Promise<string> | undefined} */ (svgCache.get(svgKey));
426
- if (cached !== undefined) {
427
- return await cached;
435
+ if (svgKey !== undefined) {
436
+ const cached = /** @type {string | Promise<string> | undefined} */ (svgCache.get(svgKey));
437
+ if (cached !== undefined) {
438
+ return await cached;
439
+ }
428
440
  }
429
441
 
430
442
  const inFlight = (async () => {
@@ -433,12 +445,12 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
433
445
  return result.data;
434
446
  })();
435
447
 
436
- svgCache.set(svgKey, inFlight);
448
+ if (svgKey !== undefined) svgCache.set(svgKey, inFlight);
437
449
  const resolved = await inFlight;
438
- svgCache.set(svgKey, resolved);
450
+ if (svgKey !== undefined) svgCache.set(svgKey, resolved);
439
451
  return resolved;
440
452
  } catch (err) {
441
- svgCache.delete(svgKey);
453
+ if (svgKey !== undefined) svgCache.delete(svgKey);
442
454
  if (!options.continueOnMinifyError) {
443
455
  throw err;
444
456
  }
package/src/lib/urls.js CHANGED
@@ -79,7 +79,7 @@ function removeDirectoryIndex(pathname) {
79
79
  /**
80
80
  * Create a URL minifier function for the given site context
81
81
  * @param {string} site - The site base URL (used to compute relative URLs)
82
- * @returns {function(string): string} Minifier function that returns the shortest URL
82
+ * @returns {(url: string) => string} Minifier function that returns the shortest URL
83
83
  */
84
84
  export function createUrlMinifier(site) {
85
85
  let baseUrl;
package/src/lib/utils.js CHANGED
@@ -21,12 +21,16 @@ function stableStringify(obj) {
21
21
  class LRU {
22
22
  constructor(limit = 200) {
23
23
  this.limit = limit;
24
+ this.gets = 0;
25
+ this.hits = 0;
24
26
  /** @type {Map<string, unknown>} */
25
27
  this.map = new Map();
26
28
  }
27
29
  /** @param {string} key */
28
30
  get(key) {
31
+ this.gets++;
29
32
  if (this.map.has(key)) {
33
+ this.hits++;
30
34
  const v = this.map.get(key);
31
35
  this.map.delete(key);
32
36
  this.map.set(key, v);
@@ -48,8 +52,17 @@ class LRU {
48
52
  }
49
53
  /** @param {string} key */
50
54
  delete(key) { this.map.delete(key); }
55
+ /** @returns {{ gets: number, hits: number, size: number, limit: number }} */
56
+ stats() {
57
+ return { gets: this.gets, hits: this.hits, size: this.map.size, limit: this.limit };
58
+ }
51
59
  }
52
60
 
61
+ // Content longer than this (in UTF-16 code units, roughly bytes for typical CSS/JS/SVG) is
62
+ // minified normally but never stored in a minification cache—caps worst-case cache memory
63
+ // (entry count × this size) without affecting realistically sized inline content
64
+ const MAX_CACHE_ENTRY_SIZE = 1024 * 1024; // 1 MB
65
+
53
66
  // FNV-1a 32-bit hash for large-input cache keys
54
67
 
55
68
  /** @param {string} str */
@@ -135,6 +148,7 @@ function parseRegExp(value) {
135
148
 
136
149
  export { stableStringify };
137
150
  export { LRU };
151
+ export { MAX_CACHE_ENTRY_SIZE };
138
152
  export { hashContent };
139
153
  export { uniqueId };
140
154
  export { identity };