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;
|
|
@@ -85,6 +129,8 @@ type HtmlnanoModule<Options = any> = {
|
|
|
85
129
|
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
86
130
|
};
|
|
87
131
|
|
|
88
|
-
|
|
132
|
+
type SortAttributesOption = 'alphabetical' | 'frequency';
|
|
133
|
+
|
|
134
|
+
declare const mod: HtmlnanoModule<boolean | SortAttributesOption>;
|
|
89
135
|
|
|
90
136
|
export { mod as default };
|
|
@@ -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;
|
|
@@ -85,6 +129,8 @@ type HtmlnanoModule<Options = any> = {
|
|
|
85
129
|
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
86
130
|
};
|
|
87
131
|
|
|
88
|
-
|
|
132
|
+
type SortAttributesOption = 'alphabetical' | 'frequency';
|
|
133
|
+
|
|
134
|
+
declare const mod: HtmlnanoModule<boolean | SortAttributesOption>;
|
|
89
135
|
|
|
90
136
|
export { mod as default };
|
|
@@ -2,35 +2,36 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
2
2
|
|
|
3
3
|
var collapseAttributeWhitespace_js = require('./collapseAttributeWhitespace.js');
|
|
4
4
|
|
|
5
|
-
// class, rel, ping
|
|
6
5
|
const validOptions = new Set([
|
|
7
6
|
'frequency',
|
|
8
7
|
'alphabetical'
|
|
9
8
|
]);
|
|
10
|
-
|
|
9
|
+
function resolveSortType(options) {
|
|
11
10
|
if (options === true) return 'alphabetical';
|
|
12
11
|
if (options === false) return false;
|
|
13
12
|
return validOptions.has(options) ? options : false;
|
|
14
|
-
}
|
|
15
|
-
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// class, rel, ping
|
|
16
|
+
class ListAttributeTokenChain {
|
|
16
17
|
addFromNodeAttrsArray(attrValuesArray) {
|
|
17
18
|
attrValuesArray.forEach((attrValue)=>{
|
|
18
19
|
if (!attrValue) {
|
|
19
20
|
return;
|
|
20
21
|
}
|
|
21
|
-
if (this.
|
|
22
|
-
this.
|
|
22
|
+
if (this.tokenCounts.has(attrValue)) {
|
|
23
|
+
this.tokenCounts.set(attrValue, this.tokenCounts.get(attrValue) + 1);
|
|
23
24
|
} else {
|
|
24
|
-
this.
|
|
25
|
+
this.tokenCounts.set(attrValue, 1);
|
|
25
26
|
}
|
|
26
27
|
});
|
|
27
28
|
}
|
|
28
29
|
createSortOrder() {
|
|
29
|
-
const
|
|
30
|
-
...this.
|
|
30
|
+
const nextSortOrder = [
|
|
31
|
+
...this.tokenCounts.entries()
|
|
31
32
|
];
|
|
32
|
-
|
|
33
|
-
this.
|
|
33
|
+
nextSortOrder.sort((a, b)=>b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
34
|
+
this.sortedTokens = nextSortOrder.map((i)=>i[0]);
|
|
34
35
|
}
|
|
35
36
|
sortFromNodeAttrsArray(attrValuesArray) {
|
|
36
37
|
const resultArray = [];
|
|
@@ -42,10 +43,10 @@ class AttributeTokenChain {
|
|
|
42
43
|
}
|
|
43
44
|
tokenCounts.set(attrValue, ((_tokenCounts_get = tokenCounts.get(attrValue)) != null ? _tokenCounts_get : 0) + 1);
|
|
44
45
|
});
|
|
45
|
-
if (!this.
|
|
46
|
+
if (!this.sortedTokens) {
|
|
46
47
|
this.createSortOrder();
|
|
47
48
|
}
|
|
48
|
-
this.
|
|
49
|
+
this.sortedTokens.forEach((k)=>{
|
|
49
50
|
const count = tokenCounts.get(k);
|
|
50
51
|
if (!count) {
|
|
51
52
|
return;
|
|
@@ -57,13 +58,13 @@ class AttributeTokenChain {
|
|
|
57
58
|
return resultArray;
|
|
58
59
|
}
|
|
59
60
|
constructor(){
|
|
60
|
-
/** <attr, frequency> */ this.
|
|
61
|
-
this.
|
|
61
|
+
/** <attr, frequency> */ this.tokenCounts = new Map();
|
|
62
|
+
this.sortedTokens = null;
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
/** Sort values inside list-like attributes (e.g. class, rel) */ const mod = {
|
|
65
66
|
default (tree, options, moduleOptions) {
|
|
66
|
-
const sortType =
|
|
67
|
+
const sortType = resolveSortType(moduleOptions);
|
|
67
68
|
if (sortType === 'alphabetical') {
|
|
68
69
|
return sortAttributesWithListsInAlphabeticalOrder(tree);
|
|
69
70
|
}
|
|
@@ -75,64 +76,50 @@ class AttributeTokenChain {
|
|
|
75
76
|
}
|
|
76
77
|
};
|
|
77
78
|
const splitListAttributeValues = (attrValue)=>attrValue.split(/\s+/).filter(Boolean);
|
|
78
|
-
function
|
|
79
|
+
function walkListAttributes(tree, walkFn) {
|
|
79
80
|
tree.walk((node)=>{
|
|
80
81
|
if (!node.attrs) {
|
|
81
82
|
return node;
|
|
82
83
|
}
|
|
83
84
|
const tagName = node.tag ? node.tag.toLowerCase() : undefined;
|
|
84
|
-
Object.
|
|
85
|
+
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
85
86
|
const attrNameLower = attrName.toLowerCase();
|
|
86
|
-
if (!collapseAttributeWhitespace_js.isListAttribute(attrNameLower, tagName)) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const attrValues = splitListAttributeValues(node.attrs[attrName]);
|
|
90
|
-
if (attrValues.length < 2) {
|
|
87
|
+
if (!collapseAttributeWhitespace_js.isListAttribute(attrNameLower, tagName) || typeof attrValues !== 'string') {
|
|
91
88
|
return;
|
|
92
89
|
}
|
|
93
|
-
node.attrs
|
|
94
|
-
// @ts-expect-error -- deliberately use minus operator to sort things
|
|
95
|
-
return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
|
|
96
|
-
}).join(' ');
|
|
90
|
+
walkFn(node.attrs, attrName, attrValues);
|
|
97
91
|
});
|
|
98
92
|
return node;
|
|
99
93
|
});
|
|
94
|
+
}
|
|
95
|
+
function sortAttributesWithListsInAlphabeticalOrder(tree) {
|
|
96
|
+
walkListAttributes(tree, (nodeAttrs, attrName, attrValues)=>{
|
|
97
|
+
const values = splitListAttributeValues(attrValues);
|
|
98
|
+
if (values.length < 2) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
nodeAttrs[attrName] = values.sort((a, b)=>{
|
|
102
|
+
// @ts-expect-error -- deliberately use minus operator to sort things
|
|
103
|
+
return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
|
|
104
|
+
}).join(' ');
|
|
105
|
+
});
|
|
100
106
|
return tree;
|
|
101
107
|
}
|
|
102
108
|
function sortAttributesWithListsByFrequency(tree) {
|
|
103
|
-
const tokenChainObj = {};
|
|
109
|
+
const tokenChainObj = {};
|
|
104
110
|
// Traverse through tree to get frequency
|
|
105
|
-
tree
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const tagName = node.tag ? node.tag.toLowerCase() : undefined;
|
|
110
|
-
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
111
|
-
const attrNameLower = attrName.toLowerCase();
|
|
112
|
-
if (!collapseAttributeWhitespace_js.isListAttribute(attrNameLower, tagName)) {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new AttributeTokenChain();
|
|
116
|
-
tokenChainObj[attrNameLower].addFromNodeAttrsArray(splitListAttributeValues(attrValues));
|
|
117
|
-
});
|
|
118
|
-
return node;
|
|
111
|
+
walkListAttributes(tree, (_nodeAttrs, attrName, attrValues)=>{
|
|
112
|
+
const attrNameLower = attrName.toLowerCase();
|
|
113
|
+
tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new ListAttributeTokenChain();
|
|
114
|
+
tokenChainObj[attrNameLower].addFromNodeAttrsArray(splitListAttributeValues(attrValues));
|
|
119
115
|
});
|
|
120
116
|
// Traverse through tree again, this time sort the attribute values
|
|
121
|
-
tree
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
walkListAttributes(tree, (nodeAttrs, attrName, attrValues)=>{
|
|
118
|
+
const attrNameLower = attrName.toLowerCase();
|
|
119
|
+
if (!tokenChainObj[attrNameLower]) {
|
|
120
|
+
return;
|
|
124
121
|
}
|
|
125
|
-
|
|
126
|
-
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
127
|
-
const attrNameLower = attrName.toLowerCase();
|
|
128
|
-
if (!collapseAttributeWhitespace_js.isListAttribute(attrNameLower, tagName)) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
if (tokenChainObj[attrNameLower]) {
|
|
132
|
-
node.attrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(splitListAttributeValues(attrValues)).join(' ');
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
return node;
|
|
122
|
+
nodeAttrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(splitListAttributeValues(attrValues)).join(' ');
|
|
136
123
|
});
|
|
137
124
|
return tree;
|
|
138
125
|
}
|
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
import { isListAttribute } from './collapseAttributeWhitespace.mjs';
|
|
2
2
|
|
|
3
|
-
// class, rel, ping
|
|
4
3
|
const validOptions = new Set([
|
|
5
4
|
'frequency',
|
|
6
5
|
'alphabetical'
|
|
7
6
|
]);
|
|
8
|
-
|
|
7
|
+
function resolveSortType(options) {
|
|
9
8
|
if (options === true) return 'alphabetical';
|
|
10
9
|
if (options === false) return false;
|
|
11
10
|
return validOptions.has(options) ? options : false;
|
|
12
|
-
}
|
|
13
|
-
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// class, rel, ping
|
|
14
|
+
class ListAttributeTokenChain {
|
|
14
15
|
addFromNodeAttrsArray(attrValuesArray) {
|
|
15
16
|
attrValuesArray.forEach((attrValue)=>{
|
|
16
17
|
if (!attrValue) {
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
|
-
if (this.
|
|
20
|
-
this.
|
|
20
|
+
if (this.tokenCounts.has(attrValue)) {
|
|
21
|
+
this.tokenCounts.set(attrValue, this.tokenCounts.get(attrValue) + 1);
|
|
21
22
|
} else {
|
|
22
|
-
this.
|
|
23
|
+
this.tokenCounts.set(attrValue, 1);
|
|
23
24
|
}
|
|
24
25
|
});
|
|
25
26
|
}
|
|
26
27
|
createSortOrder() {
|
|
27
|
-
const
|
|
28
|
-
...this.
|
|
28
|
+
const nextSortOrder = [
|
|
29
|
+
...this.tokenCounts.entries()
|
|
29
30
|
];
|
|
30
|
-
|
|
31
|
-
this.
|
|
31
|
+
nextSortOrder.sort((a, b)=>b[1] - a[1] || a[0].localeCompare(b[0]));
|
|
32
|
+
this.sortedTokens = nextSortOrder.map((i)=>i[0]);
|
|
32
33
|
}
|
|
33
34
|
sortFromNodeAttrsArray(attrValuesArray) {
|
|
34
35
|
const resultArray = [];
|
|
@@ -40,10 +41,10 @@ class AttributeTokenChain {
|
|
|
40
41
|
}
|
|
41
42
|
tokenCounts.set(attrValue, ((_tokenCounts_get = tokenCounts.get(attrValue)) != null ? _tokenCounts_get : 0) + 1);
|
|
42
43
|
});
|
|
43
|
-
if (!this.
|
|
44
|
+
if (!this.sortedTokens) {
|
|
44
45
|
this.createSortOrder();
|
|
45
46
|
}
|
|
46
|
-
this.
|
|
47
|
+
this.sortedTokens.forEach((k)=>{
|
|
47
48
|
const count = tokenCounts.get(k);
|
|
48
49
|
if (!count) {
|
|
49
50
|
return;
|
|
@@ -55,13 +56,13 @@ class AttributeTokenChain {
|
|
|
55
56
|
return resultArray;
|
|
56
57
|
}
|
|
57
58
|
constructor(){
|
|
58
|
-
/** <attr, frequency> */ this.
|
|
59
|
-
this.
|
|
59
|
+
/** <attr, frequency> */ this.tokenCounts = new Map();
|
|
60
|
+
this.sortedTokens = null;
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
63
|
/** Sort values inside list-like attributes (e.g. class, rel) */ const mod = {
|
|
63
64
|
default (tree, options, moduleOptions) {
|
|
64
|
-
const sortType =
|
|
65
|
+
const sortType = resolveSortType(moduleOptions);
|
|
65
66
|
if (sortType === 'alphabetical') {
|
|
66
67
|
return sortAttributesWithListsInAlphabeticalOrder(tree);
|
|
67
68
|
}
|
|
@@ -73,64 +74,50 @@ class AttributeTokenChain {
|
|
|
73
74
|
}
|
|
74
75
|
};
|
|
75
76
|
const splitListAttributeValues = (attrValue)=>attrValue.split(/\s+/).filter(Boolean);
|
|
76
|
-
function
|
|
77
|
+
function walkListAttributes(tree, walkFn) {
|
|
77
78
|
tree.walk((node)=>{
|
|
78
79
|
if (!node.attrs) {
|
|
79
80
|
return node;
|
|
80
81
|
}
|
|
81
82
|
const tagName = node.tag ? node.tag.toLowerCase() : undefined;
|
|
82
|
-
Object.
|
|
83
|
+
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
83
84
|
const attrNameLower = attrName.toLowerCase();
|
|
84
|
-
if (!isListAttribute(attrNameLower, tagName)) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const attrValues = splitListAttributeValues(node.attrs[attrName]);
|
|
88
|
-
if (attrValues.length < 2) {
|
|
85
|
+
if (!isListAttribute(attrNameLower, tagName) || typeof attrValues !== 'string') {
|
|
89
86
|
return;
|
|
90
87
|
}
|
|
91
|
-
node.attrs
|
|
92
|
-
// @ts-expect-error -- deliberately use minus operator to sort things
|
|
93
|
-
return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
|
|
94
|
-
}).join(' ');
|
|
88
|
+
walkFn(node.attrs, attrName, attrValues);
|
|
95
89
|
});
|
|
96
90
|
return node;
|
|
97
91
|
});
|
|
92
|
+
}
|
|
93
|
+
function sortAttributesWithListsInAlphabeticalOrder(tree) {
|
|
94
|
+
walkListAttributes(tree, (nodeAttrs, attrName, attrValues)=>{
|
|
95
|
+
const values = splitListAttributeValues(attrValues);
|
|
96
|
+
if (values.length < 2) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
nodeAttrs[attrName] = values.sort((a, b)=>{
|
|
100
|
+
// @ts-expect-error -- deliberately use minus operator to sort things
|
|
101
|
+
return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
|
|
102
|
+
}).join(' ');
|
|
103
|
+
});
|
|
98
104
|
return tree;
|
|
99
105
|
}
|
|
100
106
|
function sortAttributesWithListsByFrequency(tree) {
|
|
101
|
-
const tokenChainObj = {};
|
|
107
|
+
const tokenChainObj = {};
|
|
102
108
|
// Traverse through tree to get frequency
|
|
103
|
-
tree
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const tagName = node.tag ? node.tag.toLowerCase() : undefined;
|
|
108
|
-
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
109
|
-
const attrNameLower = attrName.toLowerCase();
|
|
110
|
-
if (!isListAttribute(attrNameLower, tagName)) {
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new AttributeTokenChain();
|
|
114
|
-
tokenChainObj[attrNameLower].addFromNodeAttrsArray(splitListAttributeValues(attrValues));
|
|
115
|
-
});
|
|
116
|
-
return node;
|
|
109
|
+
walkListAttributes(tree, (_nodeAttrs, attrName, attrValues)=>{
|
|
110
|
+
const attrNameLower = attrName.toLowerCase();
|
|
111
|
+
tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new ListAttributeTokenChain();
|
|
112
|
+
tokenChainObj[attrNameLower].addFromNodeAttrsArray(splitListAttributeValues(attrValues));
|
|
117
113
|
});
|
|
118
114
|
// Traverse through tree again, this time sort the attribute values
|
|
119
|
-
tree
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
walkListAttributes(tree, (nodeAttrs, attrName, attrValues)=>{
|
|
116
|
+
const attrNameLower = attrName.toLowerCase();
|
|
117
|
+
if (!tokenChainObj[attrNameLower]) {
|
|
118
|
+
return;
|
|
122
119
|
}
|
|
123
|
-
|
|
124
|
-
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
125
|
-
const attrNameLower = attrName.toLowerCase();
|
|
126
|
-
if (!isListAttribute(attrNameLower, tagName)) {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
if (tokenChainObj[attrNameLower]) {
|
|
130
|
-
node.attrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(splitListAttributeValues(attrValues)).join(' ');
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
return node;
|
|
120
|
+
nodeAttrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(splitListAttributeValues(attrValues)).join(' ');
|
|
134
121
|
});
|
|
135
122
|
return tree;
|
|
136
123
|
}
|