html-minifier-next 6.2.11 → 7.1.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 +19 -21
- package/cli.js +21 -27
- package/dist/types/htmlminifier.d.ts +20 -43
- package/dist/types/htmlminifier.d.ts.map +1 -1
- package/dist/types/lib/attributes.d.ts +19 -12
- package/dist/types/lib/attributes.d.ts.map +1 -1
- package/dist/types/lib/content.d.ts +8 -10
- package/dist/types/lib/content.d.ts.map +1 -1
- package/dist/types/lib/elements.d.ts +6 -11
- package/dist/types/lib/elements.d.ts.map +1 -1
- package/dist/types/lib/option-definitions.d.ts +11 -17
- package/dist/types/lib/options.d.ts +50 -6
- package/dist/types/lib/options.d.ts.map +1 -1
- package/dist/types/lib/utils.d.ts +5 -2
- package/dist/types/lib/utils.d.ts.map +1 -1
- package/dist/types/presets.d.ts +3 -6
- package/dist/types/presets.d.ts.map +1 -1
- package/package.json +16 -23
- package/src/htmlminifier.js +65 -66
- package/src/htmlparser.js +1 -1
- package/src/lib/attributes.js +45 -17
- package/src/lib/content.js +5 -3
- package/src/lib/elements.js +3 -8
- package/src/lib/option-definitions.js +4 -8
- package/src/lib/options.js +67 -22
- package/src/lib/utils.js +4 -1
- package/src/lib/whitespace.js +1 -1
- package/src/presets.js +2 -4
- package/dist/htmlminifier.cjs +0 -5142
package/src/lib/attributes.js
CHANGED
|
@@ -19,6 +19,8 @@ import { trimWhitespace, collapseWhitespaceAll } from './whitespace.js';
|
|
|
19
19
|
import { shouldMinifyInnerHTML } from './options.js';
|
|
20
20
|
import { identity, isThenable } from './utils.js';
|
|
21
21
|
|
|
22
|
+
/** @import { ProcessedOptions } from './options.js' */
|
|
23
|
+
|
|
22
24
|
// Type definitions
|
|
23
25
|
|
|
24
26
|
/**
|
|
@@ -41,11 +43,9 @@ async function getDecodeHTMLStrict() {
|
|
|
41
43
|
|
|
42
44
|
/**
|
|
43
45
|
* @param {string} text
|
|
44
|
-
* @param {
|
|
46
|
+
* @param {ProcessedOptions} options
|
|
45
47
|
*/
|
|
46
48
|
function isIgnoredComment(text, options) {
|
|
47
|
-
// @@ Optimize: `Array.isArray(options.ignoreCustomComments)` runs on every comment node; it could be eliminated once `parseRegExpArray` is tightened to coerce non-arrays to `[]` at setup time
|
|
48
|
-
if (!Array.isArray(options.ignoreCustomComments)) return false;
|
|
49
49
|
for (const pattern of options.ignoreCustomComments) {
|
|
50
50
|
if (pattern.test(text)) {
|
|
51
51
|
return true;
|
|
@@ -303,7 +303,8 @@ function isMediaQuery(tag, attrs, attrName) {
|
|
|
303
303
|
* @param {string} tag
|
|
304
304
|
*/
|
|
305
305
|
function isSrcset(attrName, tag) {
|
|
306
|
-
return attrName === 'srcset' && srcsetElements.has(tag)
|
|
306
|
+
return (attrName === 'srcset' && srcsetElements.has(tag)) ||
|
|
307
|
+
(attrName === 'imagesrcset' && tag === 'link');
|
|
307
308
|
}
|
|
308
309
|
|
|
309
310
|
/**
|
|
@@ -380,7 +381,7 @@ const valueWhitespaceExemptElements = new Set(['button', 'data', 'input', 'optio
|
|
|
380
381
|
* @param {string} tag
|
|
381
382
|
* @param {string} attrName
|
|
382
383
|
* @param {string} attrValue
|
|
383
|
-
* @param {
|
|
384
|
+
* @param {ProcessedOptions} options
|
|
384
385
|
* @param {HTMLAttribute[]} attrs
|
|
385
386
|
* @param {Function} minifyHTMLSelf
|
|
386
387
|
*/
|
|
@@ -432,7 +433,8 @@ function cleanAttributeValue(tag, attrName, attrValue, options, attrs, minifyHTM
|
|
|
432
433
|
if (attrName === 'class') {
|
|
433
434
|
attrValue = trimWhitespace(attrValue);
|
|
434
435
|
if (options.sortClassNames) {
|
|
435
|
-
|
|
436
|
+
// By the time attributes are processed, `createSortFns` has replaced any truthy non-function value
|
|
437
|
+
attrValue = /** @type {(value: string) => string} */ (options.sortClassNames)(attrValue);
|
|
436
438
|
} else {
|
|
437
439
|
attrValue = collapseWhitespaceAll(attrValue);
|
|
438
440
|
}
|
|
@@ -491,8 +493,34 @@ function cleanAttributeValue(tag, attrName, attrValue, options, attrs, minifyHTM
|
|
|
491
493
|
}
|
|
492
494
|
|
|
493
495
|
if (isSrcset(attrName, tag)) {
|
|
494
|
-
//
|
|
495
|
-
|
|
496
|
+
// Split into image candidate strings following the spec parsing algorithm
|
|
497
|
+
// (https://html.spec.whatwg.org/multipage/images.html#parsing-a-srcset-attribute);
|
|
498
|
+
// a naive split on commas would corrupt URLs that contain commas
|
|
499
|
+
const value = trimWhitespace(attrValue);
|
|
500
|
+
/** @type {string[]} */
|
|
501
|
+
const candidates = [];
|
|
502
|
+
let pos = 0;
|
|
503
|
+
while (pos < value.length) {
|
|
504
|
+
// Skip whitespace and separator commas
|
|
505
|
+
while (pos < value.length && /[\s,]/.test(value.charAt(pos))) pos++;
|
|
506
|
+
if (pos >= value.length) break;
|
|
507
|
+
const start = pos;
|
|
508
|
+
// URL: a run of non-whitespace characters (which may contain commas)
|
|
509
|
+
while (pos < value.length && !/\s/.test(value.charAt(pos))) pos++;
|
|
510
|
+
if (value.charAt(pos - 1) === ',') {
|
|
511
|
+
// Trailing comma(s) end the candidate—a URL without descriptor
|
|
512
|
+
candidates.push(value.slice(start, pos).replace(/,+$/, ''));
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
// Descriptor: everything up to the next comma outside parentheses
|
|
516
|
+
let inParens = false;
|
|
517
|
+
while (pos < value.length && (inParens || value.charAt(pos) !== ',')) {
|
|
518
|
+
if (value.charAt(pos) === '(') inParens = true;
|
|
519
|
+
else if (value.charAt(pos) === ')') inParens = false;
|
|
520
|
+
pos++;
|
|
521
|
+
}
|
|
522
|
+
candidates.push(trimWhitespace(value.slice(start, pos)));
|
|
523
|
+
}
|
|
496
524
|
const processed = candidates.map(candidate => {
|
|
497
525
|
let url = candidate;
|
|
498
526
|
let descriptor = '';
|
|
@@ -602,7 +630,7 @@ function chooseAttributeQuote(attrValue, options) {
|
|
|
602
630
|
* @param {HTMLAttribute} attr
|
|
603
631
|
* @param {HTMLAttribute[]} attrs
|
|
604
632
|
* @param {string} tag
|
|
605
|
-
* @param {
|
|
633
|
+
* @param {ProcessedOptions} options
|
|
606
634
|
* @param {Function} minifyHTML
|
|
607
635
|
*/
|
|
608
636
|
function normalizeAttr(attr, attrs, tag, options, minifyHTML) {
|
|
@@ -626,16 +654,16 @@ function normalizeAttr(attr, attrs, tag, options, minifyHTML) {
|
|
|
626
654
|
* @param {HTMLAttribute} attr
|
|
627
655
|
* @param {HTMLAttribute[]} attrs
|
|
628
656
|
* @param {string} tag
|
|
629
|
-
* @param {
|
|
657
|
+
* @param {ProcessedOptions} options
|
|
630
658
|
* @param {Function} minifyHTML
|
|
631
659
|
*/
|
|
632
660
|
function normalizeAttrContinue(attrName, attrValue, attr, attrs, tag, options, minifyHTML) {
|
|
633
661
|
if ((options.removeRedundantAttributes &&
|
|
634
662
|
isAttributeRedundant(tag, attrName, attrValue ?? '', attrs)) ||
|
|
635
|
-
(options.
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
663
|
+
(options.removeDefaultTypeAttributes && attrName === 'type' && (
|
|
664
|
+
((tag === 'style' || tag === 'link') && isStyleLinkTypeAttribute(attrValue)) ||
|
|
665
|
+
(tag === 'script' && isScriptTypeAttribute(attrValue) && !keepScriptTypeAttribute(attrValue))
|
|
666
|
+
))) {
|
|
639
667
|
return;
|
|
640
668
|
}
|
|
641
669
|
|
|
@@ -656,7 +684,7 @@ function normalizeAttrContinue(attrName, attrValue, attr, attrs, tag, options, m
|
|
|
656
684
|
* @param {string | undefined} attrValue
|
|
657
685
|
* @param {HTMLAttribute} attr
|
|
658
686
|
* @param {string} tag
|
|
659
|
-
* @param {
|
|
687
|
+
* @param {ProcessedOptions} options
|
|
660
688
|
*/
|
|
661
689
|
function normalizeAttrFinish(attrName, attrValue, attr, tag, options) {
|
|
662
690
|
if (options.removeEmptyAttributes &&
|
|
@@ -676,9 +704,9 @@ function normalizeAttrFinish(attrName, attrValue, attr, tag, options) {
|
|
|
676
704
|
}
|
|
677
705
|
|
|
678
706
|
/**
|
|
679
|
-
* @param {{name: string, value
|
|
707
|
+
* @param {{name: string, value: string | undefined, attr: HTMLAttribute}} normalized
|
|
680
708
|
* @param {string | boolean | undefined} hasUnarySlash
|
|
681
|
-
* @param {
|
|
709
|
+
* @param {ProcessedOptions} options
|
|
682
710
|
* @param {boolean} isLast
|
|
683
711
|
* @param {string | undefined} uidAttr
|
|
684
712
|
*/
|
package/src/lib/content.js
CHANGED
|
@@ -3,13 +3,15 @@ import {
|
|
|
3
3
|
} from './constants.js';
|
|
4
4
|
import { trimWhitespace } from './whitespace.js';
|
|
5
5
|
|
|
6
|
+
/** @import { ProcessedOptions } from './options.js' */
|
|
7
|
+
|
|
6
8
|
// CSS processing
|
|
7
9
|
|
|
8
10
|
// Wrap CSS declarations for inline styles and media queries
|
|
9
11
|
// This ensures proper context for CSS minification
|
|
10
12
|
/**
|
|
11
13
|
* @param {string} text
|
|
12
|
-
* @param {string} type
|
|
14
|
+
* @param {string} [type]
|
|
13
15
|
*/
|
|
14
16
|
function wrapCSS(text, type) {
|
|
15
17
|
switch (type) {
|
|
@@ -24,7 +26,7 @@ function wrapCSS(text, type) {
|
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* @param {string} text
|
|
27
|
-
* @param {string} type
|
|
29
|
+
* @param {string} [type]
|
|
28
30
|
*/
|
|
29
31
|
function unwrapCSS(text, type) {
|
|
30
32
|
let matches;
|
|
@@ -73,7 +75,7 @@ function hasJsonScriptType(attrs) {
|
|
|
73
75
|
|
|
74
76
|
/**
|
|
75
77
|
* @param {string} text
|
|
76
|
-
* @param {
|
|
78
|
+
* @param {ProcessedOptions} options
|
|
77
79
|
* @param {Array<{name: string, value?: string | undefined}>} currentAttrs
|
|
78
80
|
* @param {Function} minifyHTML
|
|
79
81
|
*/
|
package/src/lib/elements.js
CHANGED
|
@@ -12,12 +12,7 @@ import {
|
|
|
12
12
|
import { hasAttrName } from './attributes.js';
|
|
13
13
|
|
|
14
14
|
/** @import { HTMLAttribute } from './attributes.js' */
|
|
15
|
-
|
|
16
|
-
// Type definitions
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @typedef {{ name: (str: string) => string, log?: Function }} MinifierOptions
|
|
20
|
-
*/
|
|
15
|
+
/** @import { ProcessedOptions } from './options.js' */
|
|
21
16
|
|
|
22
17
|
// Tag omission rules
|
|
23
18
|
|
|
@@ -143,7 +138,7 @@ function canRemoveElement(tag, attrs) {
|
|
|
143
138
|
|
|
144
139
|
/**
|
|
145
140
|
* @param {string} str - Tag name or HTML-like element spec (e.g., “td” or “<span aria-hidden='true'>”)
|
|
146
|
-
* @param {
|
|
141
|
+
* @param {ProcessedOptions} options - Options object for name normalization
|
|
147
142
|
* @returns {{tag: string, attrs: Object.<string, string|undefined>|null}|null} Parsed spec or null if invalid
|
|
148
143
|
*/
|
|
149
144
|
function parseElementSpec(str, options) {
|
|
@@ -196,7 +191,7 @@ function parseElementSpec(str, options) {
|
|
|
196
191
|
|
|
197
192
|
/**
|
|
198
193
|
* @param {string[]} input - Array of element specifications from `removeEmptyElementsExcept` option
|
|
199
|
-
* @param {
|
|
194
|
+
* @param {ProcessedOptions} options - Options object for parsing
|
|
200
195
|
* @returns {Array<{tag: string, attrs: Object.<string, string|undefined>|null}>} Array of parsed element specs
|
|
201
196
|
*/
|
|
202
197
|
function parseRemoveEmptyElementsExcept(input, options) {
|
|
@@ -138,6 +138,10 @@ const optionDefinitions = {
|
|
|
138
138
|
description: 'Strip HTML comments',
|
|
139
139
|
type: 'boolean'
|
|
140
140
|
},
|
|
141
|
+
removeDefaultTypeAttributes: {
|
|
142
|
+
description: 'Remove default `type` attributes from `style`/`link` (e.g., `type="text/css"`) and `script` (e.g., `type="text/javascript"`) elements; other `type` attribute values are left intact',
|
|
143
|
+
type: 'boolean'
|
|
144
|
+
},
|
|
141
145
|
removeEmptyAttributes: {
|
|
142
146
|
description: 'Remove all attributes with whitespace-only values',
|
|
143
147
|
type: 'boolean'
|
|
@@ -158,14 +162,6 @@ const optionDefinitions = {
|
|
|
158
162
|
description: 'Remove attributes when value matches default',
|
|
159
163
|
type: 'boolean'
|
|
160
164
|
},
|
|
161
|
-
removeScriptTypeAttributes: {
|
|
162
|
-
description: 'Remove `type="text/javascript"` from `script` elements; other `type` attribute values are left intact',
|
|
163
|
-
type: 'boolean'
|
|
164
|
-
},
|
|
165
|
-
removeStyleLinkTypeAttributes: {
|
|
166
|
-
description: 'Remove `type="text/css"` from `style` and `link` elements; other `type` attribute values are left intact',
|
|
167
|
-
type: 'boolean'
|
|
168
|
-
},
|
|
169
165
|
removeTagWhitespace: {
|
|
170
166
|
description: 'Remove space between attributes whenever possible; note that this will result in invalid HTML',
|
|
171
167
|
type: 'boolean'
|
package/src/lib/options.js
CHANGED
|
@@ -4,19 +4,39 @@ import { RE_TRAILING_SEMICOLON } from './constants.js';
|
|
|
4
4
|
import { canCollapseWhitespace, canTrimWhitespace } from './whitespace.js';
|
|
5
5
|
import { wrapCSS, unwrapCSS } from './content.js';
|
|
6
6
|
import { getPreset, getPresetNames } from '../presets.js';
|
|
7
|
-
import { optionDefaults } from './option-definitions.js';
|
|
7
|
+
import { optionDefinitions, optionDefaults } from './option-definitions.js';
|
|
8
|
+
|
|
9
|
+
/** @import { MinifierOptions, HTMLAttribute } from '../htmlminifier.js' */
|
|
8
10
|
|
|
9
11
|
// Type definitions
|
|
10
12
|
|
|
11
13
|
/**
|
|
12
|
-
*
|
|
14
|
+
* Options object produced by `processOptions` and consumed by `minifyHTML` and
|
|
15
|
+
* the `lib/` helpers; normalization guarantees that the function-valued options
|
|
16
|
+
* below are always present (defaulting to identity/built-in functions), and
|
|
17
|
+
* minification adds writable internal state on top of the public options
|
|
18
|
+
* (set on prototype-chain forks during SVG/MathML namespace transitions)
|
|
19
|
+
*
|
|
20
|
+
* @typedef {Omit<MinifierOptions, 'preset' | 'canCollapseWhitespace' | 'canTrimWhitespace' | 'ignoreCustomComments' | 'log' | 'minifyCSS' | 'minifyJS' | 'minifyURLs' | 'minifySVG'> & {
|
|
21
|
+
* name: (name: string) => string,
|
|
22
|
+
* log: (message: any) => unknown,
|
|
23
|
+
* ignoreCustomComments: RegExp[],
|
|
24
|
+
* canCollapseWhitespace: (tag: string, attrs: HTMLAttribute[], defaultFn: (tag: string) => boolean) => boolean,
|
|
25
|
+
* canTrimWhitespace: (tag: string, attrs: HTMLAttribute[], defaultFn: (tag: string) => boolean) => boolean,
|
|
26
|
+
* minifyCSS: (text: string, type?: string) => string | Promise<string>,
|
|
27
|
+
* minifyJS: (text: string, inline?: boolean, isModule?: boolean) => string | Promise<string>,
|
|
28
|
+
* minifyURLs: (text: string) => string | Promise<string>,
|
|
29
|
+
* minifySVG: ((svgContent: string) => string | Promise<string>) | null,
|
|
30
|
+
* nameParent?: (name: string) => string,
|
|
31
|
+
* nameHTML?: (name: string) => string,
|
|
32
|
+
* insideSVG?: boolean,
|
|
33
|
+
* insideForeignContent?: boolean
|
|
34
|
+
* }} ProcessedOptions
|
|
13
35
|
*/
|
|
14
36
|
|
|
15
|
-
// @@ Extract a `ProcessedOptions` typedef (with `name`, `log`, `canCollapseWhitespace`, `canTrimWhitespace`,`minifyCSS`, `minifyJS`, `minifyURLs` typed as required, non-optional) to replace the current `Record<string, any>` escape hatch and eliminate the `/** @type {Function} */` casts in htmlminifier.js
|
|
16
|
-
|
|
17
37
|
// Helper functions
|
|
18
38
|
|
|
19
|
-
/** @param {
|
|
39
|
+
/** @param {ProcessedOptions} options */
|
|
20
40
|
function shouldMinifyInnerHTML(options) {
|
|
21
41
|
return Boolean(
|
|
22
42
|
options.collapseWhitespace ||
|
|
@@ -29,15 +49,23 @@ function shouldMinifyInnerHTML(options) {
|
|
|
29
49
|
);
|
|
30
50
|
}
|
|
31
51
|
|
|
52
|
+
// User-facing option keys that are valid but not listed in `optionDefinitions`
|
|
53
|
+
const optionKeysExtra = new Set(['preset', 'log', 'canCollapseWhitespace', 'canTrimWhitespace', 'cacheCSS', 'cacheJS', 'cacheSVG']);
|
|
54
|
+
|
|
55
|
+
// Unknown option keys and preset names already warned about—warn once per
|
|
56
|
+
// key per process, so repeated `minify` calls (e.g., batch runs) don’t flood STDERR
|
|
57
|
+
const optionKeysWarned = new Set();
|
|
58
|
+
const presetNamesWarned = new Set();
|
|
59
|
+
|
|
32
60
|
// Main options processor
|
|
33
61
|
|
|
34
62
|
/**
|
|
35
63
|
* @param {MinifierOptions} inputOptions - User-provided options
|
|
36
64
|
* @param {{getLightningCSS?: Function | undefined, getTerser?: Function | undefined, getSwc?: Function | undefined, getSvgo?: Function | undefined, cssMinifyCache?: LRU | undefined, jsMinifyCache?: LRU | undefined, svgMinifyCache?: LRU | undefined}} [deps] - Dependencies from htmlminifier.js
|
|
37
|
-
* @returns {
|
|
65
|
+
* @returns {ProcessedOptions} Normalized options with defaults applied
|
|
38
66
|
*/
|
|
39
67
|
const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getSvgo, cssMinifyCache, jsMinifyCache, svgMinifyCache } = {}) => {
|
|
40
|
-
/** @type {
|
|
68
|
+
/** @type {ProcessedOptions} */
|
|
41
69
|
const options = {
|
|
42
70
|
name: lowercase,
|
|
43
71
|
canCollapseWhitespace,
|
|
@@ -67,6 +95,18 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
67
95
|
});
|
|
68
96
|
};
|
|
69
97
|
|
|
98
|
+
// Route warnings through the user-provided `log` hook so API consumers can
|
|
99
|
+
// capture or suppress them consistently; fall back to `console.warn`
|
|
100
|
+
const warn = typeof inputOptions.log === 'function' ? inputOptions.log : console.warn;
|
|
101
|
+
|
|
102
|
+
// Warn about unrecognized options—catches typos as well as options removed in earlier versions
|
|
103
|
+
Object.keys(inputOptions).forEach(function (key) {
|
|
104
|
+
if (!Object.hasOwn(optionDefinitions, key) && !optionKeysExtra.has(key) && !optionKeysWarned.has(key)) {
|
|
105
|
+
optionKeysWarned.add(key);
|
|
106
|
+
warn(`HTML Minifier Next: Ignoring unknown or deprecated option “${key}” (see README for available options)`);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
70
110
|
// Merge preset with user options so all values go through normalization
|
|
71
111
|
// User options take precedence over preset values
|
|
72
112
|
let effectiveInput = inputOptions;
|
|
@@ -74,17 +114,22 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
74
114
|
const preset = getPreset(inputOptions.preset);
|
|
75
115
|
if (preset) {
|
|
76
116
|
effectiveInput = { ...preset, ...inputOptions };
|
|
77
|
-
} else {
|
|
117
|
+
} else if (!presetNamesWarned.has(inputOptions.preset)) {
|
|
118
|
+
presetNamesWarned.add(inputOptions.preset);
|
|
78
119
|
const available = getPresetNames().join(', ');
|
|
79
|
-
|
|
120
|
+
warn(`HTML Minifier Next: Unknown preset “${inputOptions.preset}”; available presets: ${available}`);
|
|
80
121
|
}
|
|
81
122
|
}
|
|
82
123
|
|
|
124
|
+
// Escape hatch for the loop below, which reads and assigns user-provided values by dynamic key
|
|
125
|
+
const optionsDynamic = /** @type {Record<string, any>} */ (options);
|
|
126
|
+
|
|
83
127
|
Object.keys(effectiveInput).forEach(function (key) {
|
|
84
|
-
const option = effectiveInput[key];
|
|
128
|
+
const option = /** @type {Record<string, any>} */ (effectiveInput)[key];
|
|
85
129
|
|
|
86
|
-
// Skip preset
|
|
87
|
-
|
|
130
|
+
// Skip `preset` (already processed) and unrecognized keys (warned about above)—
|
|
131
|
+
// the latter also keeps internal keys from being overridden
|
|
132
|
+
if (key === 'preset' || (!Object.hasOwn(optionDefinitions, key) && !optionKeysExtra.has(key))) {
|
|
88
133
|
return;
|
|
89
134
|
}
|
|
90
135
|
|
|
@@ -106,7 +151,7 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
106
151
|
const cssLoader = getLightningCSS;
|
|
107
152
|
const cssCache = cssMinifyCache;
|
|
108
153
|
|
|
109
|
-
options.minifyCSS = async function (/** @type {string} */ text, /** @type {string} */ type) {
|
|
154
|
+
options.minifyCSS = async function (/** @type {string} */ text, /** @type {string | undefined} */ type) {
|
|
110
155
|
// Fast path: Nothing to minify
|
|
111
156
|
if (!text || !text.trim()) {
|
|
112
157
|
return text;
|
|
@@ -143,7 +188,7 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
143
188
|
: (inputCSS + '|' + type + '|' + cssSig);
|
|
144
189
|
|
|
145
190
|
try {
|
|
146
|
-
const cached = cssCache.get(cssKey);
|
|
191
|
+
const cached = /** @type {string | Promise<string> | undefined} */ (cssCache.get(cssKey));
|
|
147
192
|
if (cached !== undefined) {
|
|
148
193
|
// Support both resolved values and in-flight promises
|
|
149
194
|
return await cached;
|
|
@@ -236,7 +281,7 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
236
281
|
cont: !!options.continueOnMinifyError
|
|
237
282
|
});
|
|
238
283
|
|
|
239
|
-
options.minifyJS = async function (/** @type {string} */ text, /** @type {boolean} */ inline, /** @type {boolean} */ isModule) {
|
|
284
|
+
options.minifyJS = async function (/** @type {string} */ text, /** @type {boolean | undefined} */ inline, /** @type {boolean | undefined} */ isModule) {
|
|
240
285
|
const start = text.match(/^\s*<!--.*/);
|
|
241
286
|
const code = start ? text.slice(start[0].length).replace(/\n\s*-->\s*$/, '') : text;
|
|
242
287
|
|
|
@@ -258,7 +303,7 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
258
303
|
jsKey = (code.length > 2048 ? (hashContent(code) + '|') : (code + '|'))
|
|
259
304
|
+ (inline ? '1' : '0') + '|' + (isModule ? 'm' : '') + '|' + useEngine + '|' + optsSig;
|
|
260
305
|
|
|
261
|
-
const cached = jsCache.get(jsKey);
|
|
306
|
+
const cached = /** @type {string | Promise<string> | undefined} */ (jsCache.get(jsKey));
|
|
262
307
|
if (cached !== undefined) {
|
|
263
308
|
return await cached;
|
|
264
309
|
}
|
|
@@ -331,7 +376,7 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
331
376
|
}
|
|
332
377
|
|
|
333
378
|
// Check cache
|
|
334
|
-
const cached = instanceCache.get(text);
|
|
379
|
+
const cached = /** @type {string | undefined} */ (instanceCache.get(text));
|
|
335
380
|
if (cached !== undefined) {
|
|
336
381
|
return cached;
|
|
337
382
|
}
|
|
@@ -377,7 +422,7 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
377
422
|
: (svgContent + '|' + svgSig);
|
|
378
423
|
|
|
379
424
|
try {
|
|
380
|
-
const cached = svgCache.get(svgKey);
|
|
425
|
+
const cached = /** @type {string | Promise<string> | undefined} */ (svgCache.get(svgKey));
|
|
381
426
|
if (cached !== undefined) {
|
|
382
427
|
return await cached;
|
|
383
428
|
}
|
|
@@ -403,15 +448,15 @@ const processOptions = (inputOptions, { getLightningCSS, getTerser, getSwc, getS
|
|
|
403
448
|
};
|
|
404
449
|
} else if (key === 'customAttrCollapse') {
|
|
405
450
|
// Single regex pattern
|
|
406
|
-
|
|
451
|
+
optionsDynamic[key] = parseRegExp(option);
|
|
407
452
|
} else if (key === 'customAttrSurround') {
|
|
408
453
|
// Nested array of RegExp pairs: `[[openRegExp, closeRegExp], …]`
|
|
409
|
-
|
|
454
|
+
optionsDynamic[key] = parseNestedRegExpArray(option);
|
|
410
455
|
} else if (['customAttrAssign', 'customEventAttributes', 'ignoreCustomComments', 'ignoreCustomFragments'].includes(key)) {
|
|
411
456
|
// Array of regex patterns
|
|
412
|
-
|
|
457
|
+
optionsDynamic[key] = parseRegExpArray(option);
|
|
413
458
|
} else {
|
|
414
|
-
|
|
459
|
+
optionsDynamic[key] = option;
|
|
415
460
|
}
|
|
416
461
|
});
|
|
417
462
|
return options;
|
package/src/lib/utils.js
CHANGED
|
@@ -80,7 +80,10 @@ function identity(value) {
|
|
|
80
80
|
return value;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
/**
|
|
83
|
+
/**
|
|
84
|
+
* @param {unknown} value
|
|
85
|
+
* @returns {value is PromiseLike<any>}
|
|
86
|
+
*/
|
|
84
87
|
function isThenable(value) {
|
|
85
88
|
return value != null && typeof value === 'object' && typeof /** @type {any} */ (value).then === 'function';
|
|
86
89
|
}
|
package/src/lib/whitespace.js
CHANGED
|
@@ -39,7 +39,7 @@ function collapseWhitespaceAll(str) {
|
|
|
39
39
|
// Fast path: No no-break space, common case—just collapse to single space
|
|
40
40
|
// This avoids the nested regex for the majority of cases
|
|
41
41
|
if (spaces.indexOf('\xA0') === -1) return ' ';
|
|
42
|
-
// For no-break space handling, use the
|
|
42
|
+
// For no-break space handling, use the nested regex
|
|
43
43
|
return spaces.replace(RE_NBSP_LEADING_GROUP, '$1 ');
|
|
44
44
|
});
|
|
45
45
|
}
|
package/src/presets.js
CHANGED
|
@@ -14,8 +14,7 @@ export const presets = {
|
|
|
14
14
|
conservativeCollapse: true,
|
|
15
15
|
preserveLineBreaks: true,
|
|
16
16
|
removeComments: true,
|
|
17
|
-
|
|
18
|
-
removeStyleLinkTypeAttributes: true,
|
|
17
|
+
removeDefaultTypeAttributes: true,
|
|
19
18
|
useShortDoctype: true
|
|
20
19
|
},
|
|
21
20
|
comprehensive: {
|
|
@@ -30,11 +29,10 @@ export const presets = {
|
|
|
30
29
|
minifyURLs: true,
|
|
31
30
|
removeAttributeQuotes: true,
|
|
32
31
|
removeComments: true,
|
|
32
|
+
removeDefaultTypeAttributes: true,
|
|
33
33
|
removeEmptyAttributes: true,
|
|
34
34
|
removeOptionalTags: true,
|
|
35
35
|
removeRedundantAttributes: true,
|
|
36
|
-
removeScriptTypeAttributes: true,
|
|
37
|
-
removeStyleLinkTypeAttributes: true,
|
|
38
36
|
useShortDoctype: true
|
|
39
37
|
}
|
|
40
38
|
};
|