htmlnano 3.0.0 → 3.2.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 +40 -25
- package/dist/_modules/collapseAttributeWhitespace.d.mts +41 -5
- package/dist/_modules/collapseAttributeWhitespace.d.ts +41 -5
- package/dist/_modules/collapseAttributeWhitespace.js +69 -16
- package/dist/_modules/collapseAttributeWhitespace.mjs +67 -17
- package/dist/_modules/collapseBooleanAttributes.d.mts +36 -3
- package/dist/_modules/collapseBooleanAttributes.d.ts +36 -3
- package/dist/_modules/collapseBooleanAttributes.js +18 -11
- package/dist/_modules/collapseBooleanAttributes.mjs +18 -11
- package/dist/_modules/collapseWhitespace.d.mts +36 -3
- package/dist/_modules/collapseWhitespace.d.ts +36 -3
- package/dist/_modules/collapseWhitespace.js +25 -2
- package/dist/_modules/collapseWhitespace.mjs +25 -2
- package/dist/_modules/custom.d.mts +36 -3
- package/dist/_modules/custom.d.ts +36 -3
- package/dist/_modules/deduplicateAttributeValues.d.mts +36 -3
- package/dist/_modules/deduplicateAttributeValues.d.ts +36 -3
- package/dist/_modules/deduplicateAttributeValues.js +20 -5
- package/dist/_modules/deduplicateAttributeValues.mjs +21 -6
- package/dist/_modules/example.d.mts +36 -3
- package/dist/_modules/example.d.ts +36 -3
- package/dist/_modules/mergeScripts.d.mts +36 -3
- package/dist/_modules/mergeScripts.d.ts +36 -3
- package/dist/_modules/mergeScripts.js +111 -24
- package/dist/_modules/mergeScripts.mjs +111 -24
- package/dist/_modules/mergeStyles.d.mts +36 -3
- package/dist/_modules/mergeStyles.d.ts +36 -3
- package/dist/_modules/mergeStyles.js +66 -4
- package/dist/_modules/mergeStyles.mjs +66 -4
- package/dist/_modules/minifyAttributes.d.mts +95 -0
- package/dist/_modules/minifyAttributes.d.ts +95 -0
- package/dist/_modules/minifyAttributes.js +159 -0
- package/dist/_modules/minifyAttributes.mjs +157 -0
- package/dist/_modules/minifyConditionalComments.d.mts +36 -3
- package/dist/_modules/minifyConditionalComments.d.ts +36 -3
- package/dist/_modules/minifyConditionalComments.js +37 -19
- package/dist/_modules/minifyConditionalComments.mjs +37 -19
- package/dist/_modules/minifyCss.d.mts +36 -3
- package/dist/_modules/minifyCss.d.ts +36 -3
- package/dist/_modules/minifyCss.js +13 -27
- package/dist/_modules/minifyCss.mjs +14 -28
- package/dist/_modules/minifyHtmlTemplate.d.mts +91 -0
- package/dist/_modules/minifyHtmlTemplate.d.ts +91 -0
- package/dist/_modules/minifyHtmlTemplate.js +231 -0
- package/dist/_modules/minifyHtmlTemplate.mjs +228 -0
- package/dist/_modules/minifyJs.d.mts +36 -3
- package/dist/_modules/minifyJs.d.ts +36 -3
- package/dist/_modules/minifyJs.js +106 -5
- package/dist/_modules/minifyJs.mjs +107 -6
- package/dist/_modules/minifyJson.d.mts +36 -3
- package/dist/_modules/minifyJson.d.ts +36 -3
- package/dist/_modules/minifyJson.js +8 -11
- package/dist/_modules/minifyJson.mjs +8 -11
- package/dist/_modules/minifySvg.d.mts +36 -3
- package/dist/_modules/minifySvg.d.ts +36 -3
- package/dist/_modules/minifySvg.js +35 -4
- package/dist/_modules/minifySvg.mjs +35 -4
- package/dist/_modules/minifyUrls.d.mts +37 -4
- package/dist/_modules/minifyUrls.d.ts +37 -4
- package/dist/_modules/minifyUrls.js +52 -27
- package/dist/_modules/minifyUrls.mjs +52 -27
- package/dist/_modules/normalizeAttributeValues.d.mts +36 -3
- package/dist/_modules/normalizeAttributeValues.d.ts +36 -3
- package/dist/_modules/normalizeAttributeValues.js +10 -8
- package/dist/_modules/normalizeAttributeValues.mjs +10 -8
- package/dist/_modules/removeAttributeQuotes.d.mts +40 -4
- package/dist/_modules/removeAttributeQuotes.d.ts +40 -4
- package/dist/_modules/removeAttributeQuotes.js +9 -4
- package/dist/_modules/removeAttributeQuotes.mjs +9 -4
- package/dist/_modules/removeComments.d.mts +37 -4
- package/dist/_modules/removeComments.d.ts +37 -4
- package/dist/_modules/removeComments.js +44 -12
- package/dist/_modules/removeComments.mjs +44 -12
- package/dist/_modules/removeEmptyAttributes.d.mts +36 -3
- package/dist/_modules/removeEmptyAttributes.d.ts +36 -3
- package/dist/_modules/removeEmptyAttributes.js +37 -16
- package/dist/_modules/removeEmptyAttributes.mjs +37 -16
- package/dist/_modules/removeEmptyElements.d.mts +95 -0
- package/dist/_modules/removeEmptyElements.d.ts +95 -0
- package/dist/_modules/removeEmptyElements.js +90 -0
- package/dist/_modules/removeEmptyElements.mjs +88 -0
- package/dist/_modules/removeOptionalTags.d.mts +36 -3
- package/dist/_modules/removeOptionalTags.d.ts +36 -3
- package/dist/_modules/removeOptionalTags.js +39 -28
- package/dist/_modules/removeOptionalTags.mjs +39 -28
- package/dist/_modules/removeRedundantAttributes.d.mts +36 -3
- package/dist/_modules/removeRedundantAttributes.d.ts +36 -3
- package/dist/_modules/removeRedundantAttributes.js +43 -28
- package/dist/_modules/removeRedundantAttributes.mjs +43 -28
- package/dist/_modules/removeUnusedCss.d.mts +37 -3
- package/dist/_modules/removeUnusedCss.d.ts +37 -3
- package/dist/_modules/removeUnusedCss.js +40 -14
- package/dist/_modules/removeUnusedCss.mjs +41 -15
- package/dist/_modules/sortAttributes.d.mts +39 -5
- package/dist/_modules/sortAttributes.d.ts +39 -5
- package/dist/_modules/sortAttributes.js +27 -8
- package/dist/_modules/sortAttributes.mjs +27 -8
- package/dist/_modules/sortAttributesWithLists.d.mts +39 -4
- package/dist/_modules/sortAttributesWithLists.d.ts +39 -4
- package/dist/_modules/sortAttributesWithLists.js +61 -52
- package/dist/_modules/sortAttributesWithLists.mjs +62 -53
- package/dist/helpers.d.ts +8 -1
- package/dist/helpers.js +48 -0
- package/dist/helpers.mjs +45 -1
- package/dist/index.d.ts +37 -4
- package/dist/index.js +13 -0
- package/dist/index.mjs +13 -0
- package/dist/presets/ampSafe.d.ts +36 -3
- package/dist/presets/max.d.ts +36 -3
- package/dist/presets/max.js +13 -5
- package/dist/presets/max.mjs +13 -5
- package/dist/presets/safe.d.ts +36 -3
- package/dist/presets/safe.js +6 -0
- package/dist/presets/safe.mjs +6 -0
- package/package.json +27 -15
|
@@ -213,15 +213,17 @@ const mod = {
|
|
|
213
213
|
const newAttrs = attrs;
|
|
214
214
|
Object.entries(attrs).forEach(([attrName, attrValue])=>{
|
|
215
215
|
let newAttrValue = attrValue;
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
const hasCaseInsensitive = Object.hasOwnProperty.call(caseInsensitiveAttributes, attrName) && (caseInsensitiveAttributes[attrName] === null || node.tag && caseInsensitiveAttributes[attrName].includes(node.tag));
|
|
217
|
+
const hasInvalidValueDefault = Object.hasOwnProperty.call(invalidValueDefault, attrName);
|
|
218
|
+
const invalidMeta = hasInvalidValueDefault ? invalidValueDefault[attrName] : undefined;
|
|
219
|
+
const appliesInvalidValueDefault = Boolean(invalidMeta && (invalidMeta.tag === null || node && node.tag && invalidMeta.tag.includes(node.tag)));
|
|
220
|
+
const shouldNormalizeCase = hasCaseInsensitive || appliesInvalidValueDefault;
|
|
221
|
+
if (typeof attrValue === 'string' && shouldNormalizeCase) {
|
|
222
|
+
newAttrValue = attrValue.trim().toLowerCase();
|
|
218
223
|
}
|
|
219
|
-
if (
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (typeof newAttrValue !== 'string' || !meta.valid.includes(newAttrValue)) {
|
|
223
|
-
newAttrValue = meta.default;
|
|
224
|
-
}
|
|
224
|
+
if (appliesInvalidValueDefault && invalidMeta) {
|
|
225
|
+
if (typeof newAttrValue !== 'string' || !invalidMeta.valid.includes(newAttrValue)) {
|
|
226
|
+
newAttrValue = invalidMeta.default;
|
|
225
227
|
}
|
|
226
228
|
}
|
|
227
229
|
newAttrs[attrName] = newAttrValue;
|
|
@@ -211,15 +211,17 @@ const mod = {
|
|
|
211
211
|
const newAttrs = attrs;
|
|
212
212
|
Object.entries(attrs).forEach(([attrName, attrValue])=>{
|
|
213
213
|
let newAttrValue = attrValue;
|
|
214
|
-
|
|
215
|
-
|
|
214
|
+
const hasCaseInsensitive = Object.hasOwnProperty.call(caseInsensitiveAttributes, attrName) && (caseInsensitiveAttributes[attrName] === null || node.tag && caseInsensitiveAttributes[attrName].includes(node.tag));
|
|
215
|
+
const hasInvalidValueDefault = Object.hasOwnProperty.call(invalidValueDefault, attrName);
|
|
216
|
+
const invalidMeta = hasInvalidValueDefault ? invalidValueDefault[attrName] : undefined;
|
|
217
|
+
const appliesInvalidValueDefault = Boolean(invalidMeta && (invalidMeta.tag === null || node && node.tag && invalidMeta.tag.includes(node.tag)));
|
|
218
|
+
const shouldNormalizeCase = hasCaseInsensitive || appliesInvalidValueDefault;
|
|
219
|
+
if (typeof attrValue === 'string' && shouldNormalizeCase) {
|
|
220
|
+
newAttrValue = attrValue.trim().toLowerCase();
|
|
216
221
|
}
|
|
217
|
-
if (
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (typeof newAttrValue !== 'string' || !meta.valid.includes(newAttrValue)) {
|
|
221
|
-
newAttrValue = meta.default;
|
|
222
|
-
}
|
|
222
|
+
if (appliesInvalidValueDefault && invalidMeta) {
|
|
223
|
+
if (typeof newAttrValue !== 'string' || !invalidMeta.valid.includes(newAttrValue)) {
|
|
224
|
+
newAttrValue = invalidMeta.default;
|
|
223
225
|
}
|
|
224
226
|
}
|
|
225
227
|
newAttrs[attrName] = newAttrValue;
|
|
@@ -2,16 +2,24 @@ import PostHTML from 'posthtml';
|
|
|
2
2
|
import { MinifyOptions } from 'terser';
|
|
3
3
|
import { Options } from 'cssnano';
|
|
4
4
|
import { Config } from 'svgo';
|
|
5
|
+
import { UserDefinedOptions } from 'purgecss';
|
|
5
6
|
|
|
6
7
|
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
8
|
options?: {
|
|
8
9
|
quoteAllAttributes?: boolean | undefined;
|
|
10
|
+
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
|
+
replaceQuote?: boolean | undefined;
|
|
9
12
|
} | undefined;
|
|
10
13
|
render(): string;
|
|
11
14
|
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
15
|
};
|
|
13
16
|
type MaybeArray<T> = T | Array<T>;
|
|
14
17
|
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
|
+
type HtmlnanoTemplateRule = {
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs?: Record<string, string | boolean | void>;
|
|
21
|
+
};
|
|
22
|
+
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
15
23
|
interface HtmlnanoOptions {
|
|
16
24
|
skipConfigLoading?: boolean;
|
|
17
25
|
configPath?: string;
|
|
@@ -27,17 +35,42 @@ interface HtmlnanoOptions {
|
|
|
27
35
|
mergeStyles?: boolean;
|
|
28
36
|
mergeScripts?: boolean;
|
|
29
37
|
minifyCss?: Options | boolean;
|
|
38
|
+
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
30
39
|
minifyConditionalComments?: boolean;
|
|
31
40
|
minifyJs?: MinifyOptions | boolean;
|
|
32
41
|
minifyJson?: boolean;
|
|
42
|
+
minifyAttributes?: boolean | {
|
|
43
|
+
metaContent?: boolean;
|
|
44
|
+
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
|
+
};
|
|
33
46
|
minifySvg?: Config | boolean;
|
|
34
47
|
normalizeAttributeValues?: boolean;
|
|
35
|
-
removeAttributeQuotes?: boolean
|
|
36
|
-
|
|
48
|
+
removeAttributeQuotes?: boolean | {
|
|
49
|
+
force?: boolean;
|
|
50
|
+
};
|
|
51
|
+
removeComments?: boolean | RegExp | ((comment: string) => boolean) | string;
|
|
37
52
|
removeEmptyAttributes?: boolean;
|
|
53
|
+
removeEmptyElements?: boolean | {
|
|
54
|
+
removeWithAttributes?: boolean;
|
|
55
|
+
};
|
|
38
56
|
removeRedundantAttributes?: boolean;
|
|
39
57
|
removeOptionalTags?: boolean;
|
|
40
|
-
removeUnusedCss?: boolean
|
|
58
|
+
removeUnusedCss?: boolean | ({
|
|
59
|
+
tool: 'purgeCSS';
|
|
60
|
+
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
61
|
+
banner?: boolean;
|
|
62
|
+
csspath?: string;
|
|
63
|
+
htmlroot?: string;
|
|
64
|
+
ignore?: (string | RegExp)[];
|
|
65
|
+
inject?: string;
|
|
66
|
+
jsdom?: object;
|
|
67
|
+
media?: string[];
|
|
68
|
+
report?: boolean;
|
|
69
|
+
strictSSL?: boolean;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
uncssrc?: string;
|
|
72
|
+
userAgent?: string;
|
|
73
|
+
};
|
|
41
74
|
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
42
75
|
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
43
76
|
}
|
|
@@ -52,6 +85,9 @@ type HtmlnanoModule<Options = any> = {
|
|
|
52
85
|
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
53
86
|
};
|
|
54
87
|
|
|
55
|
-
|
|
88
|
+
type RemoveAttributeQuotesOptions = {
|
|
89
|
+
force?: boolean;
|
|
90
|
+
};
|
|
91
|
+
declare const mod: HtmlnanoModule<RemoveAttributeQuotesOptions>;
|
|
56
92
|
|
|
57
93
|
export { mod as default };
|
|
@@ -2,16 +2,24 @@ import PostHTML from 'posthtml';
|
|
|
2
2
|
import { MinifyOptions } from 'terser';
|
|
3
3
|
import { Options } from 'cssnano';
|
|
4
4
|
import { Config } from 'svgo';
|
|
5
|
+
import { UserDefinedOptions } from 'purgecss';
|
|
5
6
|
|
|
6
7
|
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
8
|
options?: {
|
|
8
9
|
quoteAllAttributes?: boolean | undefined;
|
|
10
|
+
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
|
+
replaceQuote?: boolean | undefined;
|
|
9
12
|
} | undefined;
|
|
10
13
|
render(): string;
|
|
11
14
|
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
15
|
};
|
|
13
16
|
type MaybeArray<T> = T | Array<T>;
|
|
14
17
|
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
|
+
type HtmlnanoTemplateRule = {
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs?: Record<string, string | boolean | void>;
|
|
21
|
+
};
|
|
22
|
+
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
15
23
|
interface HtmlnanoOptions {
|
|
16
24
|
skipConfigLoading?: boolean;
|
|
17
25
|
configPath?: string;
|
|
@@ -27,17 +35,42 @@ interface HtmlnanoOptions {
|
|
|
27
35
|
mergeStyles?: boolean;
|
|
28
36
|
mergeScripts?: boolean;
|
|
29
37
|
minifyCss?: Options | boolean;
|
|
38
|
+
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
30
39
|
minifyConditionalComments?: boolean;
|
|
31
40
|
minifyJs?: MinifyOptions | boolean;
|
|
32
41
|
minifyJson?: boolean;
|
|
42
|
+
minifyAttributes?: boolean | {
|
|
43
|
+
metaContent?: boolean;
|
|
44
|
+
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
|
+
};
|
|
33
46
|
minifySvg?: Config | boolean;
|
|
34
47
|
normalizeAttributeValues?: boolean;
|
|
35
|
-
removeAttributeQuotes?: boolean
|
|
36
|
-
|
|
48
|
+
removeAttributeQuotes?: boolean | {
|
|
49
|
+
force?: boolean;
|
|
50
|
+
};
|
|
51
|
+
removeComments?: boolean | RegExp | ((comment: string) => boolean) | string;
|
|
37
52
|
removeEmptyAttributes?: boolean;
|
|
53
|
+
removeEmptyElements?: boolean | {
|
|
54
|
+
removeWithAttributes?: boolean;
|
|
55
|
+
};
|
|
38
56
|
removeRedundantAttributes?: boolean;
|
|
39
57
|
removeOptionalTags?: boolean;
|
|
40
|
-
removeUnusedCss?: boolean
|
|
58
|
+
removeUnusedCss?: boolean | ({
|
|
59
|
+
tool: 'purgeCSS';
|
|
60
|
+
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
61
|
+
banner?: boolean;
|
|
62
|
+
csspath?: string;
|
|
63
|
+
htmlroot?: string;
|
|
64
|
+
ignore?: (string | RegExp)[];
|
|
65
|
+
inject?: string;
|
|
66
|
+
jsdom?: object;
|
|
67
|
+
media?: string[];
|
|
68
|
+
report?: boolean;
|
|
69
|
+
strictSSL?: boolean;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
uncssrc?: string;
|
|
72
|
+
userAgent?: string;
|
|
73
|
+
};
|
|
41
74
|
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
42
75
|
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
43
76
|
}
|
|
@@ -52,6 +85,9 @@ type HtmlnanoModule<Options = any> = {
|
|
|
52
85
|
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
53
86
|
};
|
|
54
87
|
|
|
55
|
-
|
|
88
|
+
type RemoveAttributeQuotesOptions = {
|
|
89
|
+
force?: boolean;
|
|
90
|
+
};
|
|
91
|
+
declare const mod: HtmlnanoModule<RemoveAttributeQuotesOptions>;
|
|
56
92
|
|
|
57
93
|
export { mod as default };
|
|
@@ -2,11 +2,16 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
2
2
|
|
|
3
3
|
// Specification: https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
|
4
4
|
// See also: https://github.com/posthtml/posthtml-render/pull/30
|
|
5
|
-
// See also: https://github.com/
|
|
5
|
+
// See also: https://github.com/maltsev/htmlnano/issues/6#issuecomment-707105334
|
|
6
6
|
/** Disable quoteAllAttributes while not overriding the configuration */ const mod = {
|
|
7
|
-
default: function removeAttributeQuotes(tree) {
|
|
8
|
-
var _tree_options, _quoteAllAttributes;
|
|
9
|
-
|
|
7
|
+
default: function removeAttributeQuotes(tree, _options, moduleOptions) {
|
|
8
|
+
var _tree, _options1, _tree_options, _quoteAllAttributes;
|
|
9
|
+
(_options1 = (_tree = tree).options) != null ? _options1 : _tree.options = {};
|
|
10
|
+
if (moduleOptions && typeof moduleOptions === 'object' && moduleOptions.force) {
|
|
11
|
+
tree.options.quoteAllAttributes = false;
|
|
12
|
+
return tree;
|
|
13
|
+
}
|
|
14
|
+
(_quoteAllAttributes = (_tree_options = tree.options).quoteAllAttributes) != null ? _quoteAllAttributes : _tree_options.quoteAllAttributes = false;
|
|
10
15
|
return tree;
|
|
11
16
|
}
|
|
12
17
|
};
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
// Specification: https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
|
2
2
|
// See also: https://github.com/posthtml/posthtml-render/pull/30
|
|
3
|
-
// See also: https://github.com/
|
|
3
|
+
// See also: https://github.com/maltsev/htmlnano/issues/6#issuecomment-707105334
|
|
4
4
|
/** Disable quoteAllAttributes while not overriding the configuration */ const mod = {
|
|
5
|
-
default: function removeAttributeQuotes(tree) {
|
|
6
|
-
var _tree_options, _quoteAllAttributes;
|
|
7
|
-
|
|
5
|
+
default: function removeAttributeQuotes(tree, _options, moduleOptions) {
|
|
6
|
+
var _tree, _options1, _tree_options, _quoteAllAttributes;
|
|
7
|
+
(_options1 = (_tree = tree).options) != null ? _options1 : _tree.options = {};
|
|
8
|
+
if (moduleOptions && typeof moduleOptions === 'object' && moduleOptions.force) {
|
|
9
|
+
tree.options.quoteAllAttributes = false;
|
|
10
|
+
return tree;
|
|
11
|
+
}
|
|
12
|
+
(_quoteAllAttributes = (_tree_options = tree.options).quoteAllAttributes) != null ? _quoteAllAttributes : _tree_options.quoteAllAttributes = false;
|
|
8
13
|
return tree;
|
|
9
14
|
}
|
|
10
15
|
};
|
|
@@ -2,16 +2,24 @@ import PostHTML from 'posthtml';
|
|
|
2
2
|
import { MinifyOptions } from 'terser';
|
|
3
3
|
import { Options } from 'cssnano';
|
|
4
4
|
import { Config } from 'svgo';
|
|
5
|
+
import { UserDefinedOptions } from 'purgecss';
|
|
5
6
|
|
|
6
7
|
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
8
|
options?: {
|
|
8
9
|
quoteAllAttributes?: boolean | undefined;
|
|
10
|
+
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
|
+
replaceQuote?: boolean | undefined;
|
|
9
12
|
} | undefined;
|
|
10
13
|
render(): string;
|
|
11
14
|
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
15
|
};
|
|
13
16
|
type MaybeArray<T> = T | Array<T>;
|
|
14
17
|
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
|
+
type HtmlnanoTemplateRule = {
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs?: Record<string, string | boolean | void>;
|
|
21
|
+
};
|
|
22
|
+
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
15
23
|
interface HtmlnanoOptions {
|
|
16
24
|
skipConfigLoading?: boolean;
|
|
17
25
|
configPath?: string;
|
|
@@ -27,17 +35,42 @@ interface HtmlnanoOptions {
|
|
|
27
35
|
mergeStyles?: boolean;
|
|
28
36
|
mergeScripts?: boolean;
|
|
29
37
|
minifyCss?: Options | boolean;
|
|
38
|
+
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
30
39
|
minifyConditionalComments?: boolean;
|
|
31
40
|
minifyJs?: MinifyOptions | boolean;
|
|
32
41
|
minifyJson?: boolean;
|
|
42
|
+
minifyAttributes?: boolean | {
|
|
43
|
+
metaContent?: boolean;
|
|
44
|
+
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
|
+
};
|
|
33
46
|
minifySvg?: Config | boolean;
|
|
34
47
|
normalizeAttributeValues?: boolean;
|
|
35
|
-
removeAttributeQuotes?: boolean
|
|
36
|
-
|
|
48
|
+
removeAttributeQuotes?: boolean | {
|
|
49
|
+
force?: boolean;
|
|
50
|
+
};
|
|
51
|
+
removeComments?: boolean | RegExp | ((comment: string) => boolean) | string;
|
|
37
52
|
removeEmptyAttributes?: boolean;
|
|
53
|
+
removeEmptyElements?: boolean | {
|
|
54
|
+
removeWithAttributes?: boolean;
|
|
55
|
+
};
|
|
38
56
|
removeRedundantAttributes?: boolean;
|
|
39
57
|
removeOptionalTags?: boolean;
|
|
40
|
-
removeUnusedCss?: boolean
|
|
58
|
+
removeUnusedCss?: boolean | ({
|
|
59
|
+
tool: 'purgeCSS';
|
|
60
|
+
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
61
|
+
banner?: boolean;
|
|
62
|
+
csspath?: string;
|
|
63
|
+
htmlroot?: string;
|
|
64
|
+
ignore?: (string | RegExp)[];
|
|
65
|
+
inject?: string;
|
|
66
|
+
jsdom?: object;
|
|
67
|
+
media?: string[];
|
|
68
|
+
report?: boolean;
|
|
69
|
+
strictSSL?: boolean;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
uncssrc?: string;
|
|
72
|
+
userAgent?: string;
|
|
73
|
+
};
|
|
41
74
|
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
42
75
|
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
43
76
|
}
|
|
@@ -52,7 +85,7 @@ type HtmlnanoModule<Options = any> = {
|
|
|
52
85
|
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
53
86
|
};
|
|
54
87
|
|
|
55
|
-
type RemoveCommentsOptions = boolean |
|
|
88
|
+
type RemoveCommentsOptions = boolean | RegExp | ((comment: string) => boolean) | string;
|
|
56
89
|
declare const mod: HtmlnanoModule<RemoveCommentsOptions>;
|
|
57
90
|
|
|
58
91
|
export { mod as default };
|
|
@@ -2,16 +2,24 @@ import PostHTML from 'posthtml';
|
|
|
2
2
|
import { MinifyOptions } from 'terser';
|
|
3
3
|
import { Options } from 'cssnano';
|
|
4
4
|
import { Config } from 'svgo';
|
|
5
|
+
import { UserDefinedOptions } from 'purgecss';
|
|
5
6
|
|
|
6
7
|
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
8
|
options?: {
|
|
8
9
|
quoteAllAttributes?: boolean | undefined;
|
|
10
|
+
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
|
+
replaceQuote?: boolean | undefined;
|
|
9
12
|
} | undefined;
|
|
10
13
|
render(): string;
|
|
11
14
|
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
15
|
};
|
|
13
16
|
type MaybeArray<T> = T | Array<T>;
|
|
14
17
|
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
|
+
type HtmlnanoTemplateRule = {
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs?: Record<string, string | boolean | void>;
|
|
21
|
+
};
|
|
22
|
+
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
15
23
|
interface HtmlnanoOptions {
|
|
16
24
|
skipConfigLoading?: boolean;
|
|
17
25
|
configPath?: string;
|
|
@@ -27,17 +35,42 @@ interface HtmlnanoOptions {
|
|
|
27
35
|
mergeStyles?: boolean;
|
|
28
36
|
mergeScripts?: boolean;
|
|
29
37
|
minifyCss?: Options | boolean;
|
|
38
|
+
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
30
39
|
minifyConditionalComments?: boolean;
|
|
31
40
|
minifyJs?: MinifyOptions | boolean;
|
|
32
41
|
minifyJson?: boolean;
|
|
42
|
+
minifyAttributes?: boolean | {
|
|
43
|
+
metaContent?: boolean;
|
|
44
|
+
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
|
+
};
|
|
33
46
|
minifySvg?: Config | boolean;
|
|
34
47
|
normalizeAttributeValues?: boolean;
|
|
35
|
-
removeAttributeQuotes?: boolean
|
|
36
|
-
|
|
48
|
+
removeAttributeQuotes?: boolean | {
|
|
49
|
+
force?: boolean;
|
|
50
|
+
};
|
|
51
|
+
removeComments?: boolean | RegExp | ((comment: string) => boolean) | string;
|
|
37
52
|
removeEmptyAttributes?: boolean;
|
|
53
|
+
removeEmptyElements?: boolean | {
|
|
54
|
+
removeWithAttributes?: boolean;
|
|
55
|
+
};
|
|
38
56
|
removeRedundantAttributes?: boolean;
|
|
39
57
|
removeOptionalTags?: boolean;
|
|
40
|
-
removeUnusedCss?: boolean
|
|
58
|
+
removeUnusedCss?: boolean | ({
|
|
59
|
+
tool: 'purgeCSS';
|
|
60
|
+
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
61
|
+
banner?: boolean;
|
|
62
|
+
csspath?: string;
|
|
63
|
+
htmlroot?: string;
|
|
64
|
+
ignore?: (string | RegExp)[];
|
|
65
|
+
inject?: string;
|
|
66
|
+
jsdom?: object;
|
|
67
|
+
media?: string[];
|
|
68
|
+
report?: boolean;
|
|
69
|
+
strictSSL?: boolean;
|
|
70
|
+
timeout?: number;
|
|
71
|
+
uncssrc?: string;
|
|
72
|
+
userAgent?: string;
|
|
73
|
+
};
|
|
41
74
|
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
42
75
|
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
43
76
|
}
|
|
@@ -52,7 +85,7 @@ type HtmlnanoModule<Options = any> = {
|
|
|
52
85
|
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
53
86
|
};
|
|
54
87
|
|
|
55
|
-
type RemoveCommentsOptions = boolean |
|
|
88
|
+
type RemoveCommentsOptions = boolean | RegExp | ((comment: string) => boolean) | string;
|
|
56
89
|
declare const mod: HtmlnanoModule<RemoveCommentsOptions>;
|
|
57
90
|
|
|
58
91
|
export { mod as default };
|
|
@@ -2,12 +2,12 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
2
2
|
|
|
3
3
|
var helpers_js = require('../helpers.js');
|
|
4
4
|
|
|
5
|
-
const MATCH_EXCERPT_REGEXP =
|
|
5
|
+
const MATCH_EXCERPT_REGEXP = /^\s*more\b/i;
|
|
6
|
+
const MATCH_NOINDEX_REGEXP = /^\s*\/?\s*noindex\s*$/i;
|
|
7
|
+
const MATCH_SSE_REGEXP = /^\s*\/?\s*sse\s*$/i;
|
|
6
8
|
/** Removes HTML comments */ const mod = {
|
|
7
9
|
onNode (_, removeType) {
|
|
8
|
-
|
|
9
|
-
removeType = 'safe';
|
|
10
|
-
}
|
|
10
|
+
removeType = normalizeRemoveType(removeType);
|
|
11
11
|
return (node)=>{
|
|
12
12
|
if (isCommentToRemove(node, removeType)) {
|
|
13
13
|
return '';
|
|
@@ -16,9 +16,7 @@ const MATCH_EXCERPT_REGEXP = /<!-- ?more ?-->/i;
|
|
|
16
16
|
};
|
|
17
17
|
},
|
|
18
18
|
onContent (_, removeType) {
|
|
19
|
-
|
|
20
|
-
removeType = 'safe';
|
|
21
|
-
}
|
|
19
|
+
removeType = normalizeRemoveType(removeType);
|
|
22
20
|
return (contents)=>{
|
|
23
21
|
return contents.filter((content)=>!isCommentToRemove(content, removeType));
|
|
24
22
|
};
|
|
@@ -33,13 +31,13 @@ function isCommentToRemove(text, removeType) {
|
|
|
33
31
|
return false;
|
|
34
32
|
}
|
|
35
33
|
if (removeType === 'safe') {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
//
|
|
34
|
+
const commentBody = getCommentBody(text);
|
|
35
|
+
const isNoindex = commentBody ? MATCH_NOINDEX_REGEXP.test(commentBody) : false;
|
|
36
|
+
// Don't remove noindex comments. It was used by some search engines in the past.
|
|
39
37
|
if (isNoindex) {
|
|
40
38
|
return false;
|
|
41
39
|
}
|
|
42
|
-
const isServerSideExclude =
|
|
40
|
+
const isServerSideExclude = commentBody ? MATCH_SSE_REGEXP.test(commentBody) : false;
|
|
43
41
|
// Don't remove sse comments.
|
|
44
42
|
// See: https://support.cloudflare.com/hc/en-us/articles/200170036-What-does-Server-Side-Excludes-SSE-do-
|
|
45
43
|
if (isServerSideExclude) {
|
|
@@ -53,7 +51,7 @@ function isCommentToRemove(text, removeType) {
|
|
|
53
51
|
// Hugo: https://gohugo.io/content-management/summaries/#manual-summary-splitting
|
|
54
52
|
// WordPress: https://wordpress.com/support/wordpress-editor/blocks/more-block/2/
|
|
55
53
|
// Jekyll: https://jekyllrb.com/docs/posts/#post-excerpts
|
|
56
|
-
const isCMSExcerptComment = MATCH_EXCERPT_REGEXP.test(
|
|
54
|
+
const isCMSExcerptComment = commentBody ? MATCH_EXCERPT_REGEXP.test(commentBody) : false;
|
|
57
55
|
if (isCMSExcerptComment) {
|
|
58
56
|
return false;
|
|
59
57
|
}
|
|
@@ -73,11 +71,45 @@ function isMatch(input, matcher) {
|
|
|
73
71
|
}
|
|
74
72
|
return false;
|
|
75
73
|
}
|
|
74
|
+
function normalizeRemoveType(removeType) {
|
|
75
|
+
if (removeType === 'all' || removeType === 'safe' || isMatcher(removeType)) {
|
|
76
|
+
return removeType;
|
|
77
|
+
}
|
|
78
|
+
if (typeof removeType === 'string') {
|
|
79
|
+
const regexp = parseRegexString(removeType);
|
|
80
|
+
if (regexp) {
|
|
81
|
+
return regexp;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return 'safe';
|
|
85
|
+
}
|
|
76
86
|
function isMatcher(matcher) {
|
|
77
87
|
if (matcher instanceof RegExp || typeof matcher === 'function') {
|
|
78
88
|
return true;
|
|
79
89
|
}
|
|
80
90
|
return false;
|
|
81
91
|
}
|
|
92
|
+
function parseRegexString(value) {
|
|
93
|
+
const literalMatch = value.match(/^\/([\s\S]+)\/([gimsuy]*)$/);
|
|
94
|
+
if (literalMatch) {
|
|
95
|
+
return tryCreateRegExp(literalMatch[1], literalMatch[2]);
|
|
96
|
+
}
|
|
97
|
+
return tryCreateRegExp(value);
|
|
98
|
+
}
|
|
99
|
+
function tryCreateRegExp(pattern, flags) {
|
|
100
|
+
try {
|
|
101
|
+
return new RegExp(pattern, flags);
|
|
102
|
+
} catch (unused) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function getCommentBody(text) {
|
|
107
|
+
const trimmed = text.trim();
|
|
108
|
+
const match = trimmed.match(/^<!--([\s\S]*?)-->$/);
|
|
109
|
+
if (!match) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
return match[1];
|
|
113
|
+
}
|
|
82
114
|
|
|
83
115
|
exports.default = mod;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { isComment, isConditionalComment } from '../helpers.mjs';
|
|
2
2
|
|
|
3
|
-
const MATCH_EXCERPT_REGEXP =
|
|
3
|
+
const MATCH_EXCERPT_REGEXP = /^\s*more\b/i;
|
|
4
|
+
const MATCH_NOINDEX_REGEXP = /^\s*\/?\s*noindex\s*$/i;
|
|
5
|
+
const MATCH_SSE_REGEXP = /^\s*\/?\s*sse\s*$/i;
|
|
4
6
|
/** Removes HTML comments */ const mod = {
|
|
5
7
|
onNode (_, removeType) {
|
|
6
|
-
|
|
7
|
-
removeType = 'safe';
|
|
8
|
-
}
|
|
8
|
+
removeType = normalizeRemoveType(removeType);
|
|
9
9
|
return (node)=>{
|
|
10
10
|
if (isCommentToRemove(node, removeType)) {
|
|
11
11
|
return '';
|
|
@@ -14,9 +14,7 @@ const MATCH_EXCERPT_REGEXP = /<!-- ?more ?-->/i;
|
|
|
14
14
|
};
|
|
15
15
|
},
|
|
16
16
|
onContent (_, removeType) {
|
|
17
|
-
|
|
18
|
-
removeType = 'safe';
|
|
19
|
-
}
|
|
17
|
+
removeType = normalizeRemoveType(removeType);
|
|
20
18
|
return (contents)=>{
|
|
21
19
|
return contents.filter((content)=>!isCommentToRemove(content, removeType));
|
|
22
20
|
};
|
|
@@ -31,13 +29,13 @@ function isCommentToRemove(text, removeType) {
|
|
|
31
29
|
return false;
|
|
32
30
|
}
|
|
33
31
|
if (removeType === 'safe') {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
//
|
|
32
|
+
const commentBody = getCommentBody(text);
|
|
33
|
+
const isNoindex = commentBody ? MATCH_NOINDEX_REGEXP.test(commentBody) : false;
|
|
34
|
+
// Don't remove noindex comments. It was used by some search engines in the past.
|
|
37
35
|
if (isNoindex) {
|
|
38
36
|
return false;
|
|
39
37
|
}
|
|
40
|
-
const isServerSideExclude =
|
|
38
|
+
const isServerSideExclude = commentBody ? MATCH_SSE_REGEXP.test(commentBody) : false;
|
|
41
39
|
// Don't remove sse comments.
|
|
42
40
|
// See: https://support.cloudflare.com/hc/en-us/articles/200170036-What-does-Server-Side-Excludes-SSE-do-
|
|
43
41
|
if (isServerSideExclude) {
|
|
@@ -51,7 +49,7 @@ function isCommentToRemove(text, removeType) {
|
|
|
51
49
|
// Hugo: https://gohugo.io/content-management/summaries/#manual-summary-splitting
|
|
52
50
|
// WordPress: https://wordpress.com/support/wordpress-editor/blocks/more-block/2/
|
|
53
51
|
// Jekyll: https://jekyllrb.com/docs/posts/#post-excerpts
|
|
54
|
-
const isCMSExcerptComment = MATCH_EXCERPT_REGEXP.test(
|
|
52
|
+
const isCMSExcerptComment = commentBody ? MATCH_EXCERPT_REGEXP.test(commentBody) : false;
|
|
55
53
|
if (isCMSExcerptComment) {
|
|
56
54
|
return false;
|
|
57
55
|
}
|
|
@@ -71,11 +69,45 @@ function isMatch(input, matcher) {
|
|
|
71
69
|
}
|
|
72
70
|
return false;
|
|
73
71
|
}
|
|
72
|
+
function normalizeRemoveType(removeType) {
|
|
73
|
+
if (removeType === 'all' || removeType === 'safe' || isMatcher(removeType)) {
|
|
74
|
+
return removeType;
|
|
75
|
+
}
|
|
76
|
+
if (typeof removeType === 'string') {
|
|
77
|
+
const regexp = parseRegexString(removeType);
|
|
78
|
+
if (regexp) {
|
|
79
|
+
return regexp;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return 'safe';
|
|
83
|
+
}
|
|
74
84
|
function isMatcher(matcher) {
|
|
75
85
|
if (matcher instanceof RegExp || typeof matcher === 'function') {
|
|
76
86
|
return true;
|
|
77
87
|
}
|
|
78
88
|
return false;
|
|
79
89
|
}
|
|
90
|
+
function parseRegexString(value) {
|
|
91
|
+
const literalMatch = value.match(/^\/([\s\S]+)\/([gimsuy]*)$/);
|
|
92
|
+
if (literalMatch) {
|
|
93
|
+
return tryCreateRegExp(literalMatch[1], literalMatch[2]);
|
|
94
|
+
}
|
|
95
|
+
return tryCreateRegExp(value);
|
|
96
|
+
}
|
|
97
|
+
function tryCreateRegExp(pattern, flags) {
|
|
98
|
+
try {
|
|
99
|
+
return new RegExp(pattern, flags);
|
|
100
|
+
} catch (unused) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function getCommentBody(text) {
|
|
105
|
+
const trimmed = text.trim();
|
|
106
|
+
const match = trimmed.match(/^<!--([\s\S]*?)-->$/);
|
|
107
|
+
if (!match) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return match[1];
|
|
111
|
+
}
|
|
80
112
|
|
|
81
113
|
export { mod as default };
|