htmlnano 3.1.0 → 3.2.1
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 +37 -23
- package/dist/_modules/collapseAttributeWhitespace.d.mts +58 -14
- package/dist/_modules/collapseAttributeWhitespace.d.ts +58 -14
- package/dist/_modules/collapseBooleanAttributes.d.mts +58 -14
- package/dist/_modules/collapseBooleanAttributes.d.ts +58 -14
- package/dist/_modules/collapseWhitespace.d.mts +58 -14
- package/dist/_modules/collapseWhitespace.d.ts +58 -14
- package/dist/_modules/custom.d.mts +58 -14
- package/dist/_modules/custom.d.ts +58 -14
- package/dist/_modules/deduplicateAttributeValues.d.mts +58 -14
- package/dist/_modules/deduplicateAttributeValues.d.ts +58 -14
- package/dist/_modules/example.d.mts +58 -14
- package/dist/_modules/example.d.ts +58 -14
- package/dist/_modules/mergeScripts.d.mts +58 -14
- package/dist/_modules/mergeScripts.d.ts +58 -14
- package/dist/_modules/mergeScripts.js +30 -23
- package/dist/_modules/mergeScripts.mjs +30 -23
- package/dist/_modules/mergeStyles.d.mts +58 -14
- package/dist/_modules/mergeStyles.d.ts +58 -14
- package/dist/_modules/mergeStyles.js +26 -21
- package/dist/_modules/mergeStyles.mjs +26 -21
- package/dist/_modules/minifyAttributes.d.mts +58 -14
- package/dist/_modules/minifyAttributes.d.ts +58 -14
- package/dist/_modules/minifyAttributes.js +2 -2
- package/dist/_modules/minifyAttributes.mjs +2 -2
- package/dist/_modules/minifyConditionalComments.d.mts +58 -14
- package/dist/_modules/minifyConditionalComments.d.ts +58 -14
- package/dist/_modules/minifyCss.d.mts +61 -14
- package/dist/_modules/minifyCss.d.ts +61 -14
- package/dist/_modules/minifyCss.js +79 -12
- package/dist/_modules/minifyCss.mjs +79 -13
- package/dist/_modules/minifyHtmlTemplate.d.mts +58 -14
- package/dist/_modules/minifyHtmlTemplate.d.ts +58 -14
- package/dist/_modules/minifyJs.d.mts +58 -13
- package/dist/_modules/minifyJs.d.ts +58 -13
- package/dist/_modules/minifyJs.js +12 -0
- package/dist/_modules/minifyJs.mjs +12 -0
- package/dist/_modules/minifyJson.d.mts +58 -14
- package/dist/_modules/minifyJson.d.ts +58 -14
- package/dist/_modules/minifyJson.js +1 -1
- package/dist/_modules/minifyJson.mjs +1 -1
- package/dist/_modules/minifySvg.d.mts +58 -13
- package/dist/_modules/minifySvg.d.ts +58 -13
- package/dist/_modules/minifySvg.js +2 -2
- package/dist/_modules/minifySvg.mjs +2 -2
- package/dist/_modules/minifyUrls.d.mts +58 -14
- package/dist/_modules/minifyUrls.d.ts +58 -14
- package/dist/_modules/minifyUrls.js +2 -2
- package/dist/_modules/minifyUrls.mjs +2 -2
- package/dist/_modules/normalizeAttributeValues.d.mts +58 -14
- package/dist/_modules/normalizeAttributeValues.d.ts +58 -14
- package/dist/_modules/removeAttributeQuotes.d.mts +58 -14
- package/dist/_modules/removeAttributeQuotes.d.ts +58 -14
- package/dist/_modules/removeComments.d.mts +58 -14
- package/dist/_modules/removeComments.d.ts +58 -14
- package/dist/_modules/removeComments.js +1 -1
- package/dist/_modules/removeComments.mjs +1 -1
- package/dist/_modules/removeEmptyAttributes.d.mts +58 -14
- package/dist/_modules/removeEmptyAttributes.d.ts +58 -14
- package/dist/_modules/removeEmptyElements.d.mts +58 -14
- package/dist/_modules/removeEmptyElements.d.ts +58 -14
- package/dist/_modules/removeOptionalTags.d.mts +58 -14
- package/dist/_modules/removeOptionalTags.d.ts +58 -14
- package/dist/_modules/removeRedundantAttributes.d.mts +58 -14
- package/dist/_modules/removeRedundantAttributes.d.ts +58 -14
- package/dist/_modules/removeUnusedCss.d.mts +58 -14
- package/dist/_modules/removeUnusedCss.d.ts +58 -14
- package/dist/_modules/removeUnusedCss.js +3 -2
- package/dist/_modules/removeUnusedCss.mjs +3 -2
- package/dist/_modules/sortAttributes.d.mts +61 -16
- package/dist/_modules/sortAttributes.d.ts +61 -16
- package/dist/_modules/sortAttributes.js +5 -9
- package/dist/_modules/sortAttributes.mjs +5 -9
- package/dist/_modules/sortAttributesWithLists.d.mts +61 -15
- package/dist/_modules/sortAttributesWithLists.d.ts +61 -15
- package/dist/_modules/sortAttributesWithLists.js +43 -56
- package/dist/_modules/sortAttributesWithLists.mjs +43 -56
- package/dist/index.d.ts +59 -15
- package/dist/index.js +7 -6
- package/dist/index.mjs +7 -6
- package/dist/presets/ampSafe.d.ts +57 -12
- package/dist/presets/max.d.ts +57 -12
- package/dist/presets/max.js +9 -5
- package/dist/presets/max.mjs +9 -5
- package/dist/presets/safe.d.ts +57 -12
- package/dist/presets/safe.js +1 -1
- package/dist/presets/safe.mjs +1 -1
- package/package.json +20 -14
|
@@ -1,25 +1,70 @@
|
|
|
1
1
|
import PostHTML from 'posthtml';
|
|
2
|
-
import { MinifyOptions } from 'terser';
|
|
3
|
-
import { Options } from 'cssnano';
|
|
4
|
-
import { Config } from 'svgo';
|
|
5
|
-
import { UserDefinedOptions } from 'purgecss';
|
|
6
2
|
|
|
7
|
-
type
|
|
3
|
+
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
4
|
+
type PostHTMLTreeLike = [PostHTMLNodeLike] & PostHTML.NodeAPI & {
|
|
8
5
|
options?: {
|
|
9
6
|
quoteAllAttributes?: boolean | undefined;
|
|
10
7
|
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
8
|
replaceQuote?: boolean | undefined;
|
|
12
9
|
} | undefined;
|
|
13
10
|
render(): string;
|
|
14
|
-
render(node:
|
|
11
|
+
render(node: PostHTMLNodeLike | PostHTMLTreeLike, renderOptions?: any): string;
|
|
15
12
|
};
|
|
16
13
|
type MaybeArray<T> = T | Array<T>;
|
|
17
|
-
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
14
|
type HtmlnanoTemplateRule = {
|
|
19
15
|
tag: string;
|
|
20
16
|
attrs?: Record<string, string | boolean | void>;
|
|
21
17
|
};
|
|
22
18
|
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
19
|
+
type HtmlnanoMinifyCssOptions = object;
|
|
20
|
+
type HtmlnanoMinifyJsOptions = object;
|
|
21
|
+
type HtmlnanoMinifySvgOptions = object;
|
|
22
|
+
type HtmlnanoPurgeCssPattern = string | RegExp;
|
|
23
|
+
type HtmlnanoPurgeCssExtractorResultDetailed = {
|
|
24
|
+
attributes: {
|
|
25
|
+
names: string[];
|
|
26
|
+
values: string[];
|
|
27
|
+
};
|
|
28
|
+
classes: string[];
|
|
29
|
+
ids: string[];
|
|
30
|
+
tags: string[];
|
|
31
|
+
undetermined: string[];
|
|
32
|
+
};
|
|
33
|
+
type HtmlnanoPurgeCssExtractorResult = HtmlnanoPurgeCssExtractorResultDetailed | string[];
|
|
34
|
+
type HtmlnanoPurgeCssDefaultExtractor = (content: string) => HtmlnanoPurgeCssExtractorResult;
|
|
35
|
+
type HtmlnanoPurgeCssSourceMapOptions = {
|
|
36
|
+
absolute?: boolean;
|
|
37
|
+
annotation?: boolean | string;
|
|
38
|
+
from?: string;
|
|
39
|
+
inline?: boolean;
|
|
40
|
+
prev?: boolean | object | string;
|
|
41
|
+
sourcesContent?: boolean;
|
|
42
|
+
to?: string;
|
|
43
|
+
};
|
|
44
|
+
type HtmlnanoPurgeCssSafelist = HtmlnanoPurgeCssPattern[] | {
|
|
45
|
+
standard?: HtmlnanoPurgeCssPattern[];
|
|
46
|
+
deep?: RegExp[];
|
|
47
|
+
greedy?: RegExp[];
|
|
48
|
+
variables?: HtmlnanoPurgeCssPattern[];
|
|
49
|
+
keyframes?: HtmlnanoPurgeCssPattern[];
|
|
50
|
+
};
|
|
51
|
+
interface HtmlnanoPurgeCssOptions {
|
|
52
|
+
tool: 'purgeCSS';
|
|
53
|
+
defaultExtractor?: HtmlnanoPurgeCssDefaultExtractor;
|
|
54
|
+
fontFace?: boolean;
|
|
55
|
+
keyframes?: boolean;
|
|
56
|
+
output?: string;
|
|
57
|
+
rejected?: boolean;
|
|
58
|
+
rejectedCss?: boolean;
|
|
59
|
+
sourceMap?: boolean | HtmlnanoPurgeCssSourceMapOptions;
|
|
60
|
+
stdin?: boolean;
|
|
61
|
+
stdout?: boolean;
|
|
62
|
+
variables?: boolean;
|
|
63
|
+
safelist?: HtmlnanoPurgeCssSafelist;
|
|
64
|
+
blocklist?: HtmlnanoPurgeCssPattern[];
|
|
65
|
+
skippedContentGlobs?: string[];
|
|
66
|
+
dynamicAttributes?: string[];
|
|
67
|
+
}
|
|
23
68
|
interface HtmlnanoOptions {
|
|
24
69
|
skipConfigLoading?: boolean;
|
|
25
70
|
configPath?: string;
|
|
@@ -34,16 +79,16 @@ interface HtmlnanoOptions {
|
|
|
34
79
|
minifyUrls?: URL | string | false;
|
|
35
80
|
mergeStyles?: boolean;
|
|
36
81
|
mergeScripts?: boolean;
|
|
37
|
-
minifyCss?:
|
|
82
|
+
minifyCss?: HtmlnanoMinifyCssOptions | boolean;
|
|
38
83
|
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
39
84
|
minifyConditionalComments?: boolean;
|
|
40
|
-
minifyJs?:
|
|
85
|
+
minifyJs?: HtmlnanoMinifyJsOptions | boolean;
|
|
41
86
|
minifyJson?: boolean;
|
|
42
87
|
minifyAttributes?: boolean | {
|
|
43
88
|
metaContent?: boolean;
|
|
44
89
|
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
90
|
};
|
|
46
|
-
minifySvg?:
|
|
91
|
+
minifySvg?: HtmlnanoMinifySvgOptions | boolean;
|
|
47
92
|
normalizeAttributeValues?: boolean;
|
|
48
93
|
removeAttributeQuotes?: boolean | {
|
|
49
94
|
force?: boolean;
|
|
@@ -55,9 +100,8 @@ interface HtmlnanoOptions {
|
|
|
55
100
|
};
|
|
56
101
|
removeRedundantAttributes?: boolean;
|
|
57
102
|
removeOptionalTags?: boolean;
|
|
58
|
-
removeUnusedCss?: boolean |
|
|
59
|
-
tool
|
|
60
|
-
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
103
|
+
removeUnusedCss?: boolean | HtmlnanoPurgeCssOptions | {
|
|
104
|
+
tool?: 'uncss';
|
|
61
105
|
banner?: boolean;
|
|
62
106
|
csspath?: string;
|
|
63
107
|
htmlroot?: string;
|
|
@@ -77,7 +121,7 @@ interface HtmlnanoOptions {
|
|
|
77
121
|
type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
|
|
78
122
|
type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
|
|
79
123
|
type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
|
|
80
|
-
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
|
|
124
|
+
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends Array<infer Item> ? Array<Item> : T extends object ? Partial<T> : T;
|
|
81
125
|
type HtmlnanoModule<Options = any> = {
|
|
82
126
|
onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
|
|
83
127
|
onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
|
|
@@ -1,25 +1,70 @@
|
|
|
1
1
|
import PostHTML from 'posthtml';
|
|
2
|
-
import { MinifyOptions } from 'terser';
|
|
3
|
-
import { Options } from 'cssnano';
|
|
4
|
-
import { Config } from 'svgo';
|
|
5
|
-
import { UserDefinedOptions } from 'purgecss';
|
|
6
2
|
|
|
7
|
-
type
|
|
3
|
+
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
4
|
+
type PostHTMLTreeLike = [PostHTMLNodeLike] & PostHTML.NodeAPI & {
|
|
8
5
|
options?: {
|
|
9
6
|
quoteAllAttributes?: boolean | undefined;
|
|
10
7
|
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
8
|
replaceQuote?: boolean | undefined;
|
|
12
9
|
} | undefined;
|
|
13
10
|
render(): string;
|
|
14
|
-
render(node:
|
|
11
|
+
render(node: PostHTMLNodeLike | PostHTMLTreeLike, renderOptions?: any): string;
|
|
15
12
|
};
|
|
16
13
|
type MaybeArray<T> = T | Array<T>;
|
|
17
|
-
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
14
|
type HtmlnanoTemplateRule = {
|
|
19
15
|
tag: string;
|
|
20
16
|
attrs?: Record<string, string | boolean | void>;
|
|
21
17
|
};
|
|
22
18
|
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
19
|
+
type HtmlnanoMinifyCssOptions = object;
|
|
20
|
+
type HtmlnanoMinifyJsOptions = object;
|
|
21
|
+
type HtmlnanoMinifySvgOptions = object;
|
|
22
|
+
type HtmlnanoPurgeCssPattern = string | RegExp;
|
|
23
|
+
type HtmlnanoPurgeCssExtractorResultDetailed = {
|
|
24
|
+
attributes: {
|
|
25
|
+
names: string[];
|
|
26
|
+
values: string[];
|
|
27
|
+
};
|
|
28
|
+
classes: string[];
|
|
29
|
+
ids: string[];
|
|
30
|
+
tags: string[];
|
|
31
|
+
undetermined: string[];
|
|
32
|
+
};
|
|
33
|
+
type HtmlnanoPurgeCssExtractorResult = HtmlnanoPurgeCssExtractorResultDetailed | string[];
|
|
34
|
+
type HtmlnanoPurgeCssDefaultExtractor = (content: string) => HtmlnanoPurgeCssExtractorResult;
|
|
35
|
+
type HtmlnanoPurgeCssSourceMapOptions = {
|
|
36
|
+
absolute?: boolean;
|
|
37
|
+
annotation?: boolean | string;
|
|
38
|
+
from?: string;
|
|
39
|
+
inline?: boolean;
|
|
40
|
+
prev?: boolean | object | string;
|
|
41
|
+
sourcesContent?: boolean;
|
|
42
|
+
to?: string;
|
|
43
|
+
};
|
|
44
|
+
type HtmlnanoPurgeCssSafelist = HtmlnanoPurgeCssPattern[] | {
|
|
45
|
+
standard?: HtmlnanoPurgeCssPattern[];
|
|
46
|
+
deep?: RegExp[];
|
|
47
|
+
greedy?: RegExp[];
|
|
48
|
+
variables?: HtmlnanoPurgeCssPattern[];
|
|
49
|
+
keyframes?: HtmlnanoPurgeCssPattern[];
|
|
50
|
+
};
|
|
51
|
+
interface HtmlnanoPurgeCssOptions {
|
|
52
|
+
tool: 'purgeCSS';
|
|
53
|
+
defaultExtractor?: HtmlnanoPurgeCssDefaultExtractor;
|
|
54
|
+
fontFace?: boolean;
|
|
55
|
+
keyframes?: boolean;
|
|
56
|
+
output?: string;
|
|
57
|
+
rejected?: boolean;
|
|
58
|
+
rejectedCss?: boolean;
|
|
59
|
+
sourceMap?: boolean | HtmlnanoPurgeCssSourceMapOptions;
|
|
60
|
+
stdin?: boolean;
|
|
61
|
+
stdout?: boolean;
|
|
62
|
+
variables?: boolean;
|
|
63
|
+
safelist?: HtmlnanoPurgeCssSafelist;
|
|
64
|
+
blocklist?: HtmlnanoPurgeCssPattern[];
|
|
65
|
+
skippedContentGlobs?: string[];
|
|
66
|
+
dynamicAttributes?: string[];
|
|
67
|
+
}
|
|
23
68
|
interface HtmlnanoOptions {
|
|
24
69
|
skipConfigLoading?: boolean;
|
|
25
70
|
configPath?: string;
|
|
@@ -34,16 +79,16 @@ interface HtmlnanoOptions {
|
|
|
34
79
|
minifyUrls?: URL | string | false;
|
|
35
80
|
mergeStyles?: boolean;
|
|
36
81
|
mergeScripts?: boolean;
|
|
37
|
-
minifyCss?:
|
|
82
|
+
minifyCss?: HtmlnanoMinifyCssOptions | boolean;
|
|
38
83
|
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
39
84
|
minifyConditionalComments?: boolean;
|
|
40
|
-
minifyJs?:
|
|
85
|
+
minifyJs?: HtmlnanoMinifyJsOptions | boolean;
|
|
41
86
|
minifyJson?: boolean;
|
|
42
87
|
minifyAttributes?: boolean | {
|
|
43
88
|
metaContent?: boolean;
|
|
44
89
|
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
90
|
};
|
|
46
|
-
minifySvg?:
|
|
91
|
+
minifySvg?: HtmlnanoMinifySvgOptions | boolean;
|
|
47
92
|
normalizeAttributeValues?: boolean;
|
|
48
93
|
removeAttributeQuotes?: boolean | {
|
|
49
94
|
force?: boolean;
|
|
@@ -55,9 +100,8 @@ interface HtmlnanoOptions {
|
|
|
55
100
|
};
|
|
56
101
|
removeRedundantAttributes?: boolean;
|
|
57
102
|
removeOptionalTags?: boolean;
|
|
58
|
-
removeUnusedCss?: boolean |
|
|
59
|
-
tool
|
|
60
|
-
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
103
|
+
removeUnusedCss?: boolean | HtmlnanoPurgeCssOptions | {
|
|
104
|
+
tool?: 'uncss';
|
|
61
105
|
banner?: boolean;
|
|
62
106
|
csspath?: string;
|
|
63
107
|
htmlroot?: string;
|
|
@@ -77,7 +121,7 @@ interface HtmlnanoOptions {
|
|
|
77
121
|
type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
|
|
78
122
|
type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
|
|
79
123
|
type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
|
|
80
|
-
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
|
|
124
|
+
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends Array<infer Item> ? Array<Item> : T extends object ? Partial<T> : T;
|
|
81
125
|
type HtmlnanoModule<Options = any> = {
|
|
82
126
|
onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
|
|
83
127
|
onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
|
|
@@ -2,10 +2,31 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
2
2
|
|
|
3
3
|
var helpers_js = require('../helpers.js');
|
|
4
4
|
|
|
5
|
+
function normalizeAttrsForKey(attrs, config) {
|
|
6
|
+
const normalized = {
|
|
7
|
+
...config.baseAttrs
|
|
8
|
+
};
|
|
9
|
+
for (const [key, value] of Object.entries(attrs || {})){
|
|
10
|
+
if (config.skippedAttrs.has(key) || value === undefined) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (config.booleanAttrs.has(key)) {
|
|
14
|
+
normalized[key] = true;
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
normalized[key] = value;
|
|
18
|
+
}
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
|
|
5
22
|
const booleanAttrs = new Set([
|
|
6
23
|
'amp-custom',
|
|
7
24
|
'disabled'
|
|
8
25
|
]);
|
|
26
|
+
const skippedAttrs = new Set([
|
|
27
|
+
'type',
|
|
28
|
+
'media'
|
|
29
|
+
]);
|
|
9
30
|
function normalizeStyleType(attrs) {
|
|
10
31
|
if (!attrs || typeof attrs.type !== 'string') {
|
|
11
32
|
return 'text/css';
|
|
@@ -21,21 +42,10 @@ function normalizeStyleMedia(attrs) {
|
|
|
21
42
|
return media ? media.replace(/\s+/g, ' ').toLowerCase() : 'all';
|
|
22
43
|
}
|
|
23
44
|
function normalizeStyleAttrsForKey(attrs) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
if (value === undefined) {
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
if (booleanAttrs.has(key)) {
|
|
33
|
-
normalized[key] = true;
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
normalized[key] = value;
|
|
37
|
-
}
|
|
38
|
-
return normalized;
|
|
45
|
+
return normalizeAttrsForKey(attrs, {
|
|
46
|
+
booleanAttrs,
|
|
47
|
+
skippedAttrs
|
|
48
|
+
});
|
|
39
49
|
}
|
|
40
50
|
function buildStyleKey(attrs) {
|
|
41
51
|
const keyObject = {
|
|
@@ -43,12 +53,7 @@ function buildStyleKey(attrs) {
|
|
|
43
53
|
media: normalizeStyleMedia(attrs),
|
|
44
54
|
...normalizeStyleAttrsForKey(attrs)
|
|
45
55
|
};
|
|
46
|
-
|
|
47
|
-
const sortedKeyObject = {};
|
|
48
|
-
for (const key of sortedKeys){
|
|
49
|
-
sortedKeyObject[key] = keyObject[key];
|
|
50
|
-
}
|
|
51
|
-
return JSON.stringify(sortedKeyObject);
|
|
56
|
+
return JSON.stringify(Object.fromEntries(Object.entries(keyObject).sort()));
|
|
52
57
|
}
|
|
53
58
|
function extractStyleTextContent(node) {
|
|
54
59
|
if (typeof node.content === 'string') {
|
|
@@ -1,9 +1,30 @@
|
|
|
1
1
|
import { isAmpBoilerplate, extractTextContentFromNode } from '../helpers.mjs';
|
|
2
2
|
|
|
3
|
+
function normalizeAttrsForKey(attrs, config) {
|
|
4
|
+
const normalized = {
|
|
5
|
+
...config.baseAttrs
|
|
6
|
+
};
|
|
7
|
+
for (const [key, value] of Object.entries(attrs || {})){
|
|
8
|
+
if (config.skippedAttrs.has(key) || value === undefined) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
if (config.booleanAttrs.has(key)) {
|
|
12
|
+
normalized[key] = true;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
normalized[key] = value;
|
|
16
|
+
}
|
|
17
|
+
return normalized;
|
|
18
|
+
}
|
|
19
|
+
|
|
3
20
|
const booleanAttrs = new Set([
|
|
4
21
|
'amp-custom',
|
|
5
22
|
'disabled'
|
|
6
23
|
]);
|
|
24
|
+
const skippedAttrs = new Set([
|
|
25
|
+
'type',
|
|
26
|
+
'media'
|
|
27
|
+
]);
|
|
7
28
|
function normalizeStyleType(attrs) {
|
|
8
29
|
if (!attrs || typeof attrs.type !== 'string') {
|
|
9
30
|
return 'text/css';
|
|
@@ -19,21 +40,10 @@ function normalizeStyleMedia(attrs) {
|
|
|
19
40
|
return media ? media.replace(/\s+/g, ' ').toLowerCase() : 'all';
|
|
20
41
|
}
|
|
21
42
|
function normalizeStyleAttrsForKey(attrs) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
if (value === undefined) {
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
if (booleanAttrs.has(key)) {
|
|
31
|
-
normalized[key] = true;
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
normalized[key] = value;
|
|
35
|
-
}
|
|
36
|
-
return normalized;
|
|
43
|
+
return normalizeAttrsForKey(attrs, {
|
|
44
|
+
booleanAttrs,
|
|
45
|
+
skippedAttrs
|
|
46
|
+
});
|
|
37
47
|
}
|
|
38
48
|
function buildStyleKey(attrs) {
|
|
39
49
|
const keyObject = {
|
|
@@ -41,12 +51,7 @@ function buildStyleKey(attrs) {
|
|
|
41
51
|
media: normalizeStyleMedia(attrs),
|
|
42
52
|
...normalizeStyleAttrsForKey(attrs)
|
|
43
53
|
};
|
|
44
|
-
|
|
45
|
-
const sortedKeyObject = {};
|
|
46
|
-
for (const key of sortedKeys){
|
|
47
|
-
sortedKeyObject[key] = keyObject[key];
|
|
48
|
-
}
|
|
49
|
-
return JSON.stringify(sortedKeyObject);
|
|
54
|
+
return JSON.stringify(Object.fromEntries(Object.entries(keyObject).sort()));
|
|
50
55
|
}
|
|
51
56
|
function extractStyleTextContent(node) {
|
|
52
57
|
if (typeof node.content === 'string') {
|
|
@@ -1,25 +1,70 @@
|
|
|
1
1
|
import PostHTML from 'posthtml';
|
|
2
|
-
import { MinifyOptions } from 'terser';
|
|
3
|
-
import { Options } from 'cssnano';
|
|
4
|
-
import { Config } from 'svgo';
|
|
5
|
-
import { UserDefinedOptions } from 'purgecss';
|
|
6
2
|
|
|
7
|
-
type
|
|
3
|
+
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
4
|
+
type PostHTMLTreeLike = [PostHTMLNodeLike] & PostHTML.NodeAPI & {
|
|
8
5
|
options?: {
|
|
9
6
|
quoteAllAttributes?: boolean | undefined;
|
|
10
7
|
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
8
|
replaceQuote?: boolean | undefined;
|
|
12
9
|
} | undefined;
|
|
13
10
|
render(): string;
|
|
14
|
-
render(node:
|
|
11
|
+
render(node: PostHTMLNodeLike | PostHTMLTreeLike, renderOptions?: any): string;
|
|
15
12
|
};
|
|
16
13
|
type MaybeArray<T> = T | Array<T>;
|
|
17
|
-
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
14
|
type HtmlnanoTemplateRule = {
|
|
19
15
|
tag: string;
|
|
20
16
|
attrs?: Record<string, string | boolean | void>;
|
|
21
17
|
};
|
|
22
18
|
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
19
|
+
type HtmlnanoMinifyCssOptions = object;
|
|
20
|
+
type HtmlnanoMinifyJsOptions = object;
|
|
21
|
+
type HtmlnanoMinifySvgOptions = object;
|
|
22
|
+
type HtmlnanoPurgeCssPattern = string | RegExp;
|
|
23
|
+
type HtmlnanoPurgeCssExtractorResultDetailed = {
|
|
24
|
+
attributes: {
|
|
25
|
+
names: string[];
|
|
26
|
+
values: string[];
|
|
27
|
+
};
|
|
28
|
+
classes: string[];
|
|
29
|
+
ids: string[];
|
|
30
|
+
tags: string[];
|
|
31
|
+
undetermined: string[];
|
|
32
|
+
};
|
|
33
|
+
type HtmlnanoPurgeCssExtractorResult = HtmlnanoPurgeCssExtractorResultDetailed | string[];
|
|
34
|
+
type HtmlnanoPurgeCssDefaultExtractor = (content: string) => HtmlnanoPurgeCssExtractorResult;
|
|
35
|
+
type HtmlnanoPurgeCssSourceMapOptions = {
|
|
36
|
+
absolute?: boolean;
|
|
37
|
+
annotation?: boolean | string;
|
|
38
|
+
from?: string;
|
|
39
|
+
inline?: boolean;
|
|
40
|
+
prev?: boolean | object | string;
|
|
41
|
+
sourcesContent?: boolean;
|
|
42
|
+
to?: string;
|
|
43
|
+
};
|
|
44
|
+
type HtmlnanoPurgeCssSafelist = HtmlnanoPurgeCssPattern[] | {
|
|
45
|
+
standard?: HtmlnanoPurgeCssPattern[];
|
|
46
|
+
deep?: RegExp[];
|
|
47
|
+
greedy?: RegExp[];
|
|
48
|
+
variables?: HtmlnanoPurgeCssPattern[];
|
|
49
|
+
keyframes?: HtmlnanoPurgeCssPattern[];
|
|
50
|
+
};
|
|
51
|
+
interface HtmlnanoPurgeCssOptions {
|
|
52
|
+
tool: 'purgeCSS';
|
|
53
|
+
defaultExtractor?: HtmlnanoPurgeCssDefaultExtractor;
|
|
54
|
+
fontFace?: boolean;
|
|
55
|
+
keyframes?: boolean;
|
|
56
|
+
output?: string;
|
|
57
|
+
rejected?: boolean;
|
|
58
|
+
rejectedCss?: boolean;
|
|
59
|
+
sourceMap?: boolean | HtmlnanoPurgeCssSourceMapOptions;
|
|
60
|
+
stdin?: boolean;
|
|
61
|
+
stdout?: boolean;
|
|
62
|
+
variables?: boolean;
|
|
63
|
+
safelist?: HtmlnanoPurgeCssSafelist;
|
|
64
|
+
blocklist?: HtmlnanoPurgeCssPattern[];
|
|
65
|
+
skippedContentGlobs?: string[];
|
|
66
|
+
dynamicAttributes?: string[];
|
|
67
|
+
}
|
|
23
68
|
interface HtmlnanoOptions {
|
|
24
69
|
skipConfigLoading?: boolean;
|
|
25
70
|
configPath?: string;
|
|
@@ -34,16 +79,16 @@ interface HtmlnanoOptions {
|
|
|
34
79
|
minifyUrls?: URL | string | false;
|
|
35
80
|
mergeStyles?: boolean;
|
|
36
81
|
mergeScripts?: boolean;
|
|
37
|
-
minifyCss?:
|
|
82
|
+
minifyCss?: HtmlnanoMinifyCssOptions | boolean;
|
|
38
83
|
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
39
84
|
minifyConditionalComments?: boolean;
|
|
40
|
-
minifyJs?:
|
|
85
|
+
minifyJs?: HtmlnanoMinifyJsOptions | boolean;
|
|
41
86
|
minifyJson?: boolean;
|
|
42
87
|
minifyAttributes?: boolean | {
|
|
43
88
|
metaContent?: boolean;
|
|
44
89
|
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
90
|
};
|
|
46
|
-
minifySvg?:
|
|
91
|
+
minifySvg?: HtmlnanoMinifySvgOptions | boolean;
|
|
47
92
|
normalizeAttributeValues?: boolean;
|
|
48
93
|
removeAttributeQuotes?: boolean | {
|
|
49
94
|
force?: boolean;
|
|
@@ -55,9 +100,8 @@ interface HtmlnanoOptions {
|
|
|
55
100
|
};
|
|
56
101
|
removeRedundantAttributes?: boolean;
|
|
57
102
|
removeOptionalTags?: boolean;
|
|
58
|
-
removeUnusedCss?: boolean |
|
|
59
|
-
tool
|
|
60
|
-
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
103
|
+
removeUnusedCss?: boolean | HtmlnanoPurgeCssOptions | {
|
|
104
|
+
tool?: 'uncss';
|
|
61
105
|
banner?: boolean;
|
|
62
106
|
csspath?: string;
|
|
63
107
|
htmlroot?: string;
|
|
@@ -77,7 +121,7 @@ interface HtmlnanoOptions {
|
|
|
77
121
|
type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
|
|
78
122
|
type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
|
|
79
123
|
type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
|
|
80
|
-
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
|
|
124
|
+
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends Array<infer Item> ? Array<Item> : T extends object ? Partial<T> : T;
|
|
81
125
|
type HtmlnanoModule<Options = any> = {
|
|
82
126
|
onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
|
|
83
127
|
onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
|
|
@@ -1,25 +1,70 @@
|
|
|
1
1
|
import PostHTML from 'posthtml';
|
|
2
|
-
import { MinifyOptions } from 'terser';
|
|
3
|
-
import { Options } from 'cssnano';
|
|
4
|
-
import { Config } from 'svgo';
|
|
5
|
-
import { UserDefinedOptions } from 'purgecss';
|
|
6
2
|
|
|
7
|
-
type
|
|
3
|
+
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
4
|
+
type PostHTMLTreeLike = [PostHTMLNodeLike] & PostHTML.NodeAPI & {
|
|
8
5
|
options?: {
|
|
9
6
|
quoteAllAttributes?: boolean | undefined;
|
|
10
7
|
quoteStyle?: 0 | 1 | 2 | undefined;
|
|
11
8
|
replaceQuote?: boolean | undefined;
|
|
12
9
|
} | undefined;
|
|
13
10
|
render(): string;
|
|
14
|
-
render(node:
|
|
11
|
+
render(node: PostHTMLNodeLike | PostHTMLTreeLike, renderOptions?: any): string;
|
|
15
12
|
};
|
|
16
13
|
type MaybeArray<T> = T | Array<T>;
|
|
17
|
-
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
18
14
|
type HtmlnanoTemplateRule = {
|
|
19
15
|
tag: string;
|
|
20
16
|
attrs?: Record<string, string | boolean | void>;
|
|
21
17
|
};
|
|
22
18
|
type MinifyHtmlTemplateOptions = boolean | HtmlnanoTemplateRule[];
|
|
19
|
+
type HtmlnanoMinifyCssOptions = object;
|
|
20
|
+
type HtmlnanoMinifyJsOptions = object;
|
|
21
|
+
type HtmlnanoMinifySvgOptions = object;
|
|
22
|
+
type HtmlnanoPurgeCssPattern = string | RegExp;
|
|
23
|
+
type HtmlnanoPurgeCssExtractorResultDetailed = {
|
|
24
|
+
attributes: {
|
|
25
|
+
names: string[];
|
|
26
|
+
values: string[];
|
|
27
|
+
};
|
|
28
|
+
classes: string[];
|
|
29
|
+
ids: string[];
|
|
30
|
+
tags: string[];
|
|
31
|
+
undetermined: string[];
|
|
32
|
+
};
|
|
33
|
+
type HtmlnanoPurgeCssExtractorResult = HtmlnanoPurgeCssExtractorResultDetailed | string[];
|
|
34
|
+
type HtmlnanoPurgeCssDefaultExtractor = (content: string) => HtmlnanoPurgeCssExtractorResult;
|
|
35
|
+
type HtmlnanoPurgeCssSourceMapOptions = {
|
|
36
|
+
absolute?: boolean;
|
|
37
|
+
annotation?: boolean | string;
|
|
38
|
+
from?: string;
|
|
39
|
+
inline?: boolean;
|
|
40
|
+
prev?: boolean | object | string;
|
|
41
|
+
sourcesContent?: boolean;
|
|
42
|
+
to?: string;
|
|
43
|
+
};
|
|
44
|
+
type HtmlnanoPurgeCssSafelist = HtmlnanoPurgeCssPattern[] | {
|
|
45
|
+
standard?: HtmlnanoPurgeCssPattern[];
|
|
46
|
+
deep?: RegExp[];
|
|
47
|
+
greedy?: RegExp[];
|
|
48
|
+
variables?: HtmlnanoPurgeCssPattern[];
|
|
49
|
+
keyframes?: HtmlnanoPurgeCssPattern[];
|
|
50
|
+
};
|
|
51
|
+
interface HtmlnanoPurgeCssOptions {
|
|
52
|
+
tool: 'purgeCSS';
|
|
53
|
+
defaultExtractor?: HtmlnanoPurgeCssDefaultExtractor;
|
|
54
|
+
fontFace?: boolean;
|
|
55
|
+
keyframes?: boolean;
|
|
56
|
+
output?: string;
|
|
57
|
+
rejected?: boolean;
|
|
58
|
+
rejectedCss?: boolean;
|
|
59
|
+
sourceMap?: boolean | HtmlnanoPurgeCssSourceMapOptions;
|
|
60
|
+
stdin?: boolean;
|
|
61
|
+
stdout?: boolean;
|
|
62
|
+
variables?: boolean;
|
|
63
|
+
safelist?: HtmlnanoPurgeCssSafelist;
|
|
64
|
+
blocklist?: HtmlnanoPurgeCssPattern[];
|
|
65
|
+
skippedContentGlobs?: string[];
|
|
66
|
+
dynamicAttributes?: string[];
|
|
67
|
+
}
|
|
23
68
|
interface HtmlnanoOptions {
|
|
24
69
|
skipConfigLoading?: boolean;
|
|
25
70
|
configPath?: string;
|
|
@@ -34,16 +79,16 @@ interface HtmlnanoOptions {
|
|
|
34
79
|
minifyUrls?: URL | string | false;
|
|
35
80
|
mergeStyles?: boolean;
|
|
36
81
|
mergeScripts?: boolean;
|
|
37
|
-
minifyCss?:
|
|
82
|
+
minifyCss?: HtmlnanoMinifyCssOptions | boolean;
|
|
38
83
|
minifyHtmlTemplate?: MinifyHtmlTemplateOptions;
|
|
39
84
|
minifyConditionalComments?: boolean;
|
|
40
|
-
minifyJs?:
|
|
85
|
+
minifyJs?: HtmlnanoMinifyJsOptions | boolean;
|
|
41
86
|
minifyJson?: boolean;
|
|
42
87
|
minifyAttributes?: boolean | {
|
|
43
88
|
metaContent?: boolean;
|
|
44
89
|
redundantWhitespaces?: 'safe' | 'agressive' | false;
|
|
45
90
|
};
|
|
46
|
-
minifySvg?:
|
|
91
|
+
minifySvg?: HtmlnanoMinifySvgOptions | boolean;
|
|
47
92
|
normalizeAttributeValues?: boolean;
|
|
48
93
|
removeAttributeQuotes?: boolean | {
|
|
49
94
|
force?: boolean;
|
|
@@ -55,9 +100,8 @@ interface HtmlnanoOptions {
|
|
|
55
100
|
};
|
|
56
101
|
removeRedundantAttributes?: boolean;
|
|
57
102
|
removeOptionalTags?: boolean;
|
|
58
|
-
removeUnusedCss?: boolean |
|
|
59
|
-
tool
|
|
60
|
-
} & Omit<UserDefinedOptions, 'content' | 'css' | 'extractors'>) | {
|
|
103
|
+
removeUnusedCss?: boolean | HtmlnanoPurgeCssOptions | {
|
|
104
|
+
tool?: 'uncss';
|
|
61
105
|
banner?: boolean;
|
|
62
106
|
csspath?: string;
|
|
63
107
|
htmlroot?: string;
|
|
@@ -77,7 +121,7 @@ interface HtmlnanoOptions {
|
|
|
77
121
|
type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
|
|
78
122
|
type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
|
|
79
123
|
type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
|
|
80
|
-
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
|
|
124
|
+
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends Array<infer Item> ? Array<Item> : T extends object ? Partial<T> : T;
|
|
81
125
|
type HtmlnanoModule<Options = any> = {
|
|
82
126
|
onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
|
|
83
127
|
onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
|
|
@@ -132,7 +132,8 @@ const mod = {
|
|
|
132
132
|
onAttrs (_options, moduleOptions) {
|
|
133
133
|
const normalizedOptions = normalizeOptions(moduleOptions);
|
|
134
134
|
return (attrs, node)=>{
|
|
135
|
-
|
|
135
|
+
const tagName = typeof node.tag === 'string' ? node.tag.toLowerCase() : undefined;
|
|
136
|
+
if (normalizedOptions.metaContent && isMetaRefresh(attrs, tagName)) {
|
|
136
137
|
const content = attrs.content;
|
|
137
138
|
if (typeof content === 'string') {
|
|
138
139
|
const minified = minifyMetaRefreshValue(content);
|
|
@@ -142,7 +143,6 @@ const mod = {
|
|
|
142
143
|
}
|
|
143
144
|
}
|
|
144
145
|
if (normalizedOptions.redundantWhitespaces) {
|
|
145
|
-
const tagName = node.tag ? node.tag.toLowerCase() : undefined;
|
|
146
146
|
Object.entries(attrs).forEach(([attrName, attrValue])=>{
|
|
147
147
|
if (typeof attrValue !== 'string') return;
|
|
148
148
|
const minified = minifyAttributeWhitespace(normalizedOptions.redundantWhitespaces, attrName, attrValue, tagName);
|
|
@@ -130,7 +130,8 @@ const mod = {
|
|
|
130
130
|
onAttrs (_options, moduleOptions) {
|
|
131
131
|
const normalizedOptions = normalizeOptions(moduleOptions);
|
|
132
132
|
return (attrs, node)=>{
|
|
133
|
-
|
|
133
|
+
const tagName = typeof node.tag === 'string' ? node.tag.toLowerCase() : undefined;
|
|
134
|
+
if (normalizedOptions.metaContent && isMetaRefresh(attrs, tagName)) {
|
|
134
135
|
const content = attrs.content;
|
|
135
136
|
if (typeof content === 'string') {
|
|
136
137
|
const minified = minifyMetaRefreshValue(content);
|
|
@@ -140,7 +141,6 @@ const mod = {
|
|
|
140
141
|
}
|
|
141
142
|
}
|
|
142
143
|
if (normalizedOptions.redundantWhitespaces) {
|
|
143
|
-
const tagName = node.tag ? node.tag.toLowerCase() : undefined;
|
|
144
144
|
Object.entries(attrs).forEach(([attrName, attrValue])=>{
|
|
145
145
|
if (typeof attrValue !== 'string') return;
|
|
146
146
|
const minified = minifyAttributeWhitespace(normalizedOptions.redundantWhitespaces, attrName, attrValue, tagName);
|