htmlnano 2.1.1 → 2.1.3
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 +53 -12
- package/dist/_modules/collapseAttributeWhitespace.d.mts +57 -0
- package/dist/_modules/collapseAttributeWhitespace.d.ts +57 -0
- package/dist/_modules/collapseAttributeWhitespace.js +296 -0
- package/dist/_modules/collapseAttributeWhitespace.mjs +293 -0
- package/dist/_modules/collapseBooleanAttributes.d.mts +60 -0
- package/dist/_modules/collapseBooleanAttributes.d.ts +60 -0
- package/dist/_modules/collapseBooleanAttributes.js +159 -0
- package/{lib/modules → dist/_modules}/collapseBooleanAttributes.mjs +39 -57
- package/dist/_modules/collapseWhitespace.d.mts +57 -0
- package/dist/_modules/collapseWhitespace.d.ts +57 -0
- package/dist/_modules/collapseWhitespace.js +172 -0
- package/dist/_modules/collapseWhitespace.mjs +170 -0
- package/dist/_modules/custom.d.mts +57 -0
- package/dist/_modules/custom.d.ts +57 -0
- package/dist/_modules/custom.js +22 -0
- package/dist/_modules/custom.mjs +20 -0
- package/dist/_modules/deduplicateAttributeValues.d.mts +56 -0
- package/dist/_modules/deduplicateAttributeValues.d.ts +56 -0
- package/dist/_modules/deduplicateAttributeValues.js +38 -0
- package/dist/_modules/deduplicateAttributeValues.mjs +36 -0
- package/dist/_modules/example.d.mts +59 -0
- package/dist/_modules/example.d.ts +59 -0
- package/dist/_modules/example.js +67 -0
- package/dist/_modules/example.mjs +65 -0
- package/dist/_modules/mergeScripts.d.mts +56 -0
- package/dist/_modules/mergeScripts.d.ts +56 -0
- package/dist/_modules/mergeScripts.js +53 -0
- package/dist/_modules/mergeScripts.mjs +51 -0
- package/dist/_modules/mergeStyles.d.mts +56 -0
- package/dist/_modules/mergeStyles.d.ts +56 -0
- package/dist/_modules/mergeStyles.js +42 -0
- package/dist/_modules/mergeStyles.mjs +40 -0
- package/dist/_modules/minifyConditionalComments.d.mts +56 -0
- package/dist/_modules/minifyConditionalComments.d.ts +56 -0
- package/dist/_modules/minifyConditionalComments.js +54 -0
- package/{lib/modules → dist/_modules}/minifyConditionalComments.mjs +21 -22
- package/dist/_modules/minifyCss.d.mts +56 -0
- package/dist/_modules/minifyCss.d.ts +56 -0
- package/dist/_modules/minifyCss.js +84 -0
- package/dist/_modules/minifyCss.mjs +82 -0
- package/dist/_modules/minifyJs.d.mts +56 -0
- package/dist/_modules/minifyJs.d.ts +56 -0
- package/dist/_modules/minifyJs.js +108 -0
- package/dist/_modules/minifyJs.mjs +106 -0
- package/dist/_modules/minifyJson.d.mts +56 -0
- package/dist/_modules/minifyJson.d.ts +56 -0
- package/dist/_modules/minifyJson.js +35 -0
- package/dist/_modules/minifyJson.mjs +33 -0
- package/dist/_modules/minifySvg.d.mts +56 -0
- package/dist/_modules/minifySvg.d.ts +56 -0
- package/dist/_modules/minifySvg.js +40 -0
- package/dist/_modules/minifySvg.mjs +38 -0
- package/dist/_modules/minifyUrls.d.mts +56 -0
- package/dist/_modules/minifyUrls.d.ts +56 -0
- package/dist/_modules/minifyUrls.js +180 -0
- package/dist/_modules/minifyUrls.mjs +178 -0
- package/dist/_modules/normalizeAttributeValues.d.mts +56 -0
- package/dist/_modules/normalizeAttributeValues.d.ts +56 -0
- package/dist/_modules/normalizeAttributeValues.js +234 -0
- package/dist/_modules/normalizeAttributeValues.mjs +232 -0
- package/dist/_modules/removeAttributeQuotes.d.mts +56 -0
- package/dist/_modules/removeAttributeQuotes.d.ts +56 -0
- package/dist/_modules/removeAttributeQuotes.js +15 -0
- package/dist/_modules/removeAttributeQuotes.mjs +13 -0
- package/dist/_modules/removeComments.d.mts +58 -0
- package/dist/_modules/removeComments.d.ts +58 -0
- package/dist/_modules/removeComments.js +83 -0
- package/{lib/modules → dist/_modules}/removeComments.mjs +24 -35
- package/dist/_modules/removeEmptyAttributes.d.mts +56 -0
- package/dist/_modules/removeEmptyAttributes.d.ts +56 -0
- package/dist/_modules/removeEmptyAttributes.js +197 -0
- package/dist/_modules/removeEmptyAttributes.mjs +195 -0
- package/dist/_modules/removeOptionalTags.d.mts +56 -0
- package/dist/_modules/removeOptionalTags.d.ts +56 -0
- package/dist/_modules/removeOptionalTags.js +190 -0
- package/{lib/modules → dist/_modules}/removeOptionalTags.mjs +54 -91
- package/dist/_modules/removeRedundantAttributes.d.mts +57 -0
- package/dist/_modules/removeRedundantAttributes.d.ts +57 -0
- package/dist/_modules/removeRedundantAttributes.js +128 -0
- package/{lib/modules → dist/_modules}/removeRedundantAttributes.mjs +43 -59
- package/dist/_modules/removeUnusedCss.d.mts +60 -0
- package/dist/_modules/removeUnusedCss.d.ts +60 -0
- package/dist/_modules/removeUnusedCss.js +134 -0
- package/dist/_modules/removeUnusedCss.mjs +132 -0
- package/dist/_modules/sortAttributes.d.mts +57 -0
- package/dist/_modules/sortAttributes.d.ts +57 -0
- package/dist/_modules/sortAttributes.js +102 -0
- package/{lib/modules → dist/_modules}/sortAttributes.mjs +39 -60
- package/dist/_modules/sortAttributesWithLists.d.mts +56 -0
- package/dist/_modules/sortAttributesWithLists.d.ts +56 -0
- package/dist/_modules/sortAttributesWithLists.js +118 -0
- package/{lib/modules → dist/_modules}/sortAttributesWithLists.mjs +41 -60
- package/dist/helpers.js +72 -0
- package/dist/helpers.mjs +63 -0
- package/dist/index.js +223 -0
- package/dist/index.mjs +209 -0
- package/dist/presets/ampSafe.js +19 -0
- package/{lib → dist}/presets/ampSafe.mjs +6 -4
- package/dist/presets/max.js +28 -0
- package/{lib → dist}/presets/max.mjs +6 -4
- package/dist/presets/safe.js +60 -0
- package/{lib → dist}/presets/safe.mjs +13 -20
- package/package.json +53 -59
- package/.eslintignore +0 -3
- package/CHANGELOG.md +0 -398
- package/docs/README.md +0 -33
- package/docs/babel.config.js +0 -3
- package/docs/docs/010-introduction.md +0 -22
- package/docs/docs/020-usage.md +0 -117
- package/docs/docs/030-config.md +0 -21
- package/docs/docs/040-presets.md +0 -75
- package/docs/docs/050-modules.md +0 -855
- package/docs/docs/060-contribute.md +0 -16
- package/docs/docusaurus.config.js +0 -65
- package/docs/netlify.toml +0 -4
- package/docs/package-lock.json +0 -21796
- package/docs/package.json +0 -40
- package/docs/sidebars.js +0 -26
- package/docs/versioned_docs/version-1.1.1/010-introduction.md +0 -22
- package/docs/versioned_docs/version-1.1.1/020-usage.md +0 -77
- package/docs/versioned_docs/version-1.1.1/030-config.md +0 -21
- package/docs/versioned_docs/version-1.1.1/040-presets.md +0 -75
- package/docs/versioned_docs/version-1.1.1/050-modules.md +0 -785
- package/docs/versioned_docs/version-1.1.1/060-contribute.md +0 -16
- package/docs/versioned_docs/version-2.0.0/010-introduction.md +0 -22
- package/docs/versioned_docs/version-2.0.0/020-usage.md +0 -77
- package/docs/versioned_docs/version-2.0.0/030-config.md +0 -21
- package/docs/versioned_docs/version-2.0.0/040-presets.md +0 -75
- package/docs/versioned_docs/version-2.0.0/050-modules.md +0 -838
- package/docs/versioned_docs/version-2.0.0/060-contribute.md +0 -16
- package/docs/versioned_sidebars/version-1.1.1-sidebars.json +0 -8
- package/docs/versioned_sidebars/version-2.0.0-sidebars.json +0 -8
- package/docs/versions.json +0 -4
- package/index.cjs +0 -11
- package/index.d.cts +0 -3
- package/index.d.mts +0 -3
- package/index.d.ts +0 -93
- package/index.mjs +0 -2
- package/lib/helpers.cjs +0 -79
- package/lib/helpers.mjs +0 -53
- package/lib/htmlnano.cjs +0 -200
- package/lib/htmlnano.mjs +0 -196
- package/lib/modules/collapseAttributeWhitespace.cjs +0 -86
- package/lib/modules/collapseAttributeWhitespace.mjs +0 -104
- package/lib/modules/collapseBooleanAttributes.cjs +0 -62
- package/lib/modules/collapseWhitespace.cjs +0 -100
- package/lib/modules/collapseWhitespace.mjs +0 -132
- package/lib/modules/custom.cjs +0 -19
- package/lib/modules/custom.mjs +0 -16
- package/lib/modules/deduplicateAttributeValues.cjs +0 -38
- package/lib/modules/deduplicateAttributeValues.mjs +0 -40
- package/lib/modules/example.cjs +0 -85
- package/lib/modules/example.mjs +0 -75
- package/lib/modules/mergeScripts.cjs +0 -54
- package/lib/modules/mergeScripts.mjs +0 -56
- package/lib/modules/mergeStyles.cjs +0 -38
- package/lib/modules/mergeStyles.mjs +0 -36
- package/lib/modules/minifyConditionalComments.cjs +0 -47
- package/lib/modules/minifyCss.cjs +0 -73
- package/lib/modules/minifyCss.mjs +0 -88
- package/lib/modules/minifyJs.cjs +0 -103
- package/lib/modules/minifyJs.mjs +0 -121
- package/lib/modules/minifyJson.cjs +0 -24
- package/lib/modules/minifyJson.mjs +0 -21
- package/lib/modules/minifySvg.cjs +0 -37
- package/lib/modules/minifySvg.mjs +0 -30
- package/lib/modules/minifyUrls.cjs +0 -141
- package/lib/modules/minifyUrls.mjs +0 -229
- package/lib/modules/normalizeAttributeValues.cjs +0 -120
- package/lib/modules/normalizeAttributeValues.mjs +0 -140
- package/lib/modules/removeAttributeQuotes.cjs +0 -17
- package/lib/modules/removeAttributeQuotes.mjs +0 -12
- package/lib/modules/removeComments.cjs +0 -86
- package/lib/modules/removeEmptyAttributes.cjs +0 -72
- package/lib/modules/removeEmptyAttributes.mjs +0 -121
- package/lib/modules/removeOptionalTags.cjs +0 -183
- package/lib/modules/removeRedundantAttributes.cjs +0 -112
- package/lib/modules/removeUnusedCss.cjs +0 -113
- package/lib/modules/removeUnusedCss.mjs +0 -122
- package/lib/modules/sortAttributes.cjs +0 -99
- package/lib/modules/sortAttributesWithLists.cjs +0 -115
- package/lib/presets/ampSafe.cjs +0 -18
- package/lib/presets/max.cjs +0 -27
- package/lib/presets/safe.cjs +0 -65
- package/test.js +0 -48
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
|
|
3
|
+
const validOptions = new Set([
|
|
4
|
+
'frequency',
|
|
5
|
+
'alphabetical'
|
|
6
|
+
]);
|
|
7
|
+
const processModuleOptions = (options)=>{
|
|
8
|
+
if (options === true) return 'alphabetical';
|
|
9
|
+
if (options === false) return false;
|
|
10
|
+
return validOptions.has(options) ? options : false;
|
|
11
|
+
};
|
|
12
|
+
class AttributeTokenChain {
|
|
13
|
+
addFromNodeAttrs(nodeAttrs) {
|
|
14
|
+
Object.keys(nodeAttrs).forEach((attrName)=>{
|
|
15
|
+
const attrNameLower = attrName.toLowerCase();
|
|
16
|
+
if (this.freqData.has(attrNameLower)) {
|
|
17
|
+
this.freqData.set(attrNameLower, this.freqData.get(attrNameLower) + 1);
|
|
18
|
+
} else {
|
|
19
|
+
this.freqData.set(attrNameLower, 1);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
createSortOrder() {
|
|
24
|
+
const _sortOrder = [
|
|
25
|
+
...this.freqData.entries()
|
|
26
|
+
];
|
|
27
|
+
_sortOrder.sort((a, b)=>b[1] - a[1]);
|
|
28
|
+
this.sortOrder = _sortOrder.map((i)=>i[0]);
|
|
29
|
+
}
|
|
30
|
+
sortFromNodeAttrs(nodeAttrs) {
|
|
31
|
+
const newAttrs = {};
|
|
32
|
+
// Convert node.attrs attrName into lower case.
|
|
33
|
+
const loweredNodeAttrs = {};
|
|
34
|
+
Object.entries(nodeAttrs).forEach(([attrName, attrValue])=>{
|
|
35
|
+
loweredNodeAttrs[attrName.toLowerCase()] = attrValue;
|
|
36
|
+
});
|
|
37
|
+
if (!this.sortOrder) {
|
|
38
|
+
this.createSortOrder();
|
|
39
|
+
}
|
|
40
|
+
this.sortOrder.forEach((attrNameLower)=>{
|
|
41
|
+
// The attrName inside "sortOrder" has been lowered
|
|
42
|
+
if (loweredNodeAttrs[attrNameLower] != null) {
|
|
43
|
+
newAttrs[attrNameLower] = loweredNodeAttrs[attrNameLower];
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return newAttrs;
|
|
47
|
+
}
|
|
48
|
+
constructor(){
|
|
49
|
+
/** <attr, frequency> */ this.freqData = new Map();
|
|
50
|
+
this.sortOrder = null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Sort attibutes */ const mod = {
|
|
54
|
+
default (tree, options, moduleOptions) {
|
|
55
|
+
const sortType = processModuleOptions(moduleOptions);
|
|
56
|
+
if (sortType === 'alphabetical') {
|
|
57
|
+
return sortAttributesInAlphabeticalOrder(tree);
|
|
58
|
+
}
|
|
59
|
+
if (sortType === 'frequency') {
|
|
60
|
+
return sortAttributesByFrequency(tree);
|
|
61
|
+
}
|
|
62
|
+
// Invalid configuration
|
|
63
|
+
return tree;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
function sortAttributesInAlphabeticalOrder(tree) {
|
|
67
|
+
tree.walk((node)=>{
|
|
68
|
+
if (!node.attrs) {
|
|
69
|
+
return node;
|
|
70
|
+
}
|
|
71
|
+
const newAttrs = {};
|
|
72
|
+
Object.keys(node.attrs)// @ts-expect-error -- deliberately use minus operator to sort things
|
|
73
|
+
.sort((a, b)=>typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b).forEach((attr)=>{
|
|
74
|
+
newAttrs[attr] = node.attrs[attr];
|
|
75
|
+
});
|
|
76
|
+
node.attrs = newAttrs;
|
|
77
|
+
return node;
|
|
78
|
+
});
|
|
79
|
+
return tree;
|
|
80
|
+
}
|
|
81
|
+
function sortAttributesByFrequency(tree) {
|
|
82
|
+
const tokenchain = new AttributeTokenChain();
|
|
83
|
+
// Traverse through tree to get frequency
|
|
84
|
+
tree.walk((node)=>{
|
|
85
|
+
if (!node.attrs) {
|
|
86
|
+
return node;
|
|
87
|
+
}
|
|
88
|
+
tokenchain.addFromNodeAttrs(node.attrs);
|
|
89
|
+
return node;
|
|
90
|
+
});
|
|
91
|
+
// Traverse through tree again, this time sort the attributes
|
|
92
|
+
tree.walk((node)=>{
|
|
93
|
+
if (!node.attrs) {
|
|
94
|
+
return node;
|
|
95
|
+
}
|
|
96
|
+
node.attrs = tokenchain.sortFromNodeAttrs(node.attrs);
|
|
97
|
+
return node;
|
|
98
|
+
});
|
|
99
|
+
return tree;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
exports.default = mod;
|
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const processModuleOptions = options
|
|
1
|
+
const validOptions = new Set([
|
|
2
|
+
'frequency',
|
|
3
|
+
'alphabetical'
|
|
4
|
+
]);
|
|
5
|
+
const processModuleOptions = (options)=>{
|
|
6
6
|
if (options === true) return 'alphabetical';
|
|
7
|
-
|
|
7
|
+
if (options === false) return false;
|
|
8
8
|
return validOptions.has(options) ? options : false;
|
|
9
9
|
};
|
|
10
|
-
|
|
11
10
|
class AttributeTokenChain {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.freqData = new Map(); // <attr, frequency>[]
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
addFromNodeAttrs(nodeAttrs) {
|
|
17
|
-
Object.keys(nodeAttrs).forEach(attrName
|
|
12
|
+
Object.keys(nodeAttrs).forEach((attrName)=>{
|
|
18
13
|
const attrNameLower = attrName.toLowerCase();
|
|
19
|
-
|
|
20
14
|
if (this.freqData.has(attrNameLower)) {
|
|
21
15
|
this.freqData.set(attrNameLower, this.freqData.get(attrNameLower) + 1);
|
|
22
16
|
} else {
|
|
@@ -24,98 +18,83 @@ class AttributeTokenChain {
|
|
|
24
18
|
}
|
|
25
19
|
});
|
|
26
20
|
}
|
|
27
|
-
|
|
28
21
|
createSortOrder() {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
const _sortOrder = [
|
|
23
|
+
...this.freqData.entries()
|
|
24
|
+
];
|
|
25
|
+
_sortOrder.sort((a, b)=>b[1] - a[1]);
|
|
26
|
+
this.sortOrder = _sortOrder.map((i)=>i[0]);
|
|
33
27
|
}
|
|
34
|
-
|
|
35
28
|
sortFromNodeAttrs(nodeAttrs) {
|
|
36
29
|
const newAttrs = {};
|
|
37
|
-
|
|
38
30
|
// Convert node.attrs attrName into lower case.
|
|
39
31
|
const loweredNodeAttrs = {};
|
|
40
|
-
Object.entries(nodeAttrs).forEach(([attrName, attrValue])
|
|
32
|
+
Object.entries(nodeAttrs).forEach(([attrName, attrValue])=>{
|
|
41
33
|
loweredNodeAttrs[attrName.toLowerCase()] = attrValue;
|
|
42
34
|
});
|
|
43
|
-
|
|
44
35
|
if (!this.sortOrder) {
|
|
45
36
|
this.createSortOrder();
|
|
46
37
|
}
|
|
47
|
-
|
|
48
|
-
this.sortOrder.forEach(attrNameLower => {
|
|
38
|
+
this.sortOrder.forEach((attrNameLower)=>{
|
|
49
39
|
// The attrName inside "sortOrder" has been lowered
|
|
50
40
|
if (loweredNodeAttrs[attrNameLower] != null) {
|
|
51
41
|
newAttrs[attrNameLower] = loweredNodeAttrs[attrNameLower];
|
|
52
42
|
}
|
|
53
43
|
});
|
|
54
|
-
|
|
55
44
|
return newAttrs;
|
|
56
45
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
export default function sortAttributes(tree, options, moduleOptions) {
|
|
61
|
-
const sortType = processModuleOptions(moduleOptions);
|
|
62
|
-
|
|
63
|
-
if (sortType === 'alphabetical') {
|
|
64
|
-
return sortAttributesInAlphabeticalOrder(tree);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (sortType === 'frequency') {
|
|
68
|
-
return sortAttributesByFrequency(tree);
|
|
46
|
+
constructor(){
|
|
47
|
+
/** <attr, frequency> */ this.freqData = new Map();
|
|
48
|
+
this.sortOrder = null;
|
|
69
49
|
}
|
|
70
|
-
|
|
71
|
-
// Invalid configuration
|
|
72
|
-
return tree;
|
|
73
50
|
}
|
|
74
|
-
|
|
51
|
+
/** Sort attibutes */ const mod = {
|
|
52
|
+
default (tree, options, moduleOptions) {
|
|
53
|
+
const sortType = processModuleOptions(moduleOptions);
|
|
54
|
+
if (sortType === 'alphabetical') {
|
|
55
|
+
return sortAttributesInAlphabeticalOrder(tree);
|
|
56
|
+
}
|
|
57
|
+
if (sortType === 'frequency') {
|
|
58
|
+
return sortAttributesByFrequency(tree);
|
|
59
|
+
}
|
|
60
|
+
// Invalid configuration
|
|
61
|
+
return tree;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
75
64
|
function sortAttributesInAlphabeticalOrder(tree) {
|
|
76
|
-
tree.walk(node
|
|
65
|
+
tree.walk((node)=>{
|
|
77
66
|
if (!node.attrs) {
|
|
78
67
|
return node;
|
|
79
68
|
}
|
|
80
|
-
|
|
81
69
|
const newAttrs = {};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
70
|
+
Object.keys(node.attrs)// @ts-expect-error -- deliberately use minus operator to sort things
|
|
71
|
+
.sort((a, b)=>typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b).forEach((attr)=>{
|
|
72
|
+
newAttrs[attr] = node.attrs[attr];
|
|
73
|
+
});
|
|
87
74
|
node.attrs = newAttrs;
|
|
88
|
-
|
|
89
75
|
return node;
|
|
90
76
|
});
|
|
91
|
-
|
|
92
77
|
return tree;
|
|
93
78
|
}
|
|
94
|
-
|
|
95
79
|
function sortAttributesByFrequency(tree) {
|
|
96
80
|
const tokenchain = new AttributeTokenChain();
|
|
97
|
-
|
|
98
81
|
// Traverse through tree to get frequency
|
|
99
|
-
tree.walk(node
|
|
82
|
+
tree.walk((node)=>{
|
|
100
83
|
if (!node.attrs) {
|
|
101
84
|
return node;
|
|
102
85
|
}
|
|
103
|
-
|
|
104
86
|
tokenchain.addFromNodeAttrs(node.attrs);
|
|
105
|
-
|
|
106
87
|
return node;
|
|
107
88
|
});
|
|
108
|
-
|
|
109
89
|
// Traverse through tree again, this time sort the attributes
|
|
110
|
-
tree.walk(node
|
|
90
|
+
tree.walk((node)=>{
|
|
111
91
|
if (!node.attrs) {
|
|
112
92
|
return node;
|
|
113
93
|
}
|
|
114
|
-
|
|
115
94
|
node.attrs = tokenchain.sortFromNodeAttrs(node.attrs);
|
|
116
|
-
|
|
117
95
|
return node;
|
|
118
96
|
});
|
|
119
|
-
|
|
120
97
|
return tree;
|
|
121
98
|
}
|
|
99
|
+
|
|
100
|
+
export { mod as default };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import PostHTML from 'posthtml';
|
|
2
|
+
import { MinifyOptions } from 'terser';
|
|
3
|
+
import { Options } from 'cssnano';
|
|
4
|
+
import { Config } from 'svgo';
|
|
5
|
+
|
|
6
|
+
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
|
+
options?: {
|
|
8
|
+
quoteAllAttributes?: boolean | undefined;
|
|
9
|
+
} | undefined;
|
|
10
|
+
render(): string;
|
|
11
|
+
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
|
+
};
|
|
13
|
+
type MaybeArray<T> = T | Array<T>;
|
|
14
|
+
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
15
|
+
interface HtmlnanoOptions {
|
|
16
|
+
skipConfigLoading?: boolean;
|
|
17
|
+
skipInternalWarnings?: boolean;
|
|
18
|
+
collapseAttributeWhitespace?: boolean;
|
|
19
|
+
collapseBooleanAttributes?: {
|
|
20
|
+
amphtml?: boolean;
|
|
21
|
+
};
|
|
22
|
+
collapseWhitespace?: 'conservative' | 'all' | 'aggressive';
|
|
23
|
+
custom?: MaybeArray<(tree: PostHTMLTreeLike, options?: any) => (PostHTML.Node | PostHTMLTreeLike)>;
|
|
24
|
+
deduplicateAttributeValues?: boolean;
|
|
25
|
+
minifyUrls?: URL | string | false;
|
|
26
|
+
mergeStyles?: boolean;
|
|
27
|
+
mergeScripts?: boolean;
|
|
28
|
+
minifyCss?: Options | boolean;
|
|
29
|
+
minifyConditionalComments?: boolean;
|
|
30
|
+
minifyJs?: MinifyOptions | boolean;
|
|
31
|
+
minifyJson?: boolean;
|
|
32
|
+
minifySvg?: Config | boolean;
|
|
33
|
+
normalizeAttributeValues?: boolean;
|
|
34
|
+
removeAttributeQuotes?: boolean;
|
|
35
|
+
removeComments?: boolean | 'safe' | 'all' | RegExp | ((comment: string) => boolean);
|
|
36
|
+
removeEmptyAttributes?: boolean;
|
|
37
|
+
removeRedundantAttributes?: boolean;
|
|
38
|
+
removeOptionalTags?: boolean;
|
|
39
|
+
removeUnusedCss?: boolean;
|
|
40
|
+
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
41
|
+
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
42
|
+
}
|
|
43
|
+
type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
|
|
44
|
+
type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
|
|
45
|
+
type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
|
|
46
|
+
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
|
|
47
|
+
type HtmlnanoModule<Options = any> = {
|
|
48
|
+
onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
|
|
49
|
+
onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
|
|
50
|
+
onNode?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleNodeHandler;
|
|
51
|
+
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
declare const mod: HtmlnanoModule<boolean | 'alphabetical' | 'frequency'>;
|
|
55
|
+
|
|
56
|
+
export { mod as default };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import PostHTML from 'posthtml';
|
|
2
|
+
import { MinifyOptions } from 'terser';
|
|
3
|
+
import { Options } from 'cssnano';
|
|
4
|
+
import { Config } from 'svgo';
|
|
5
|
+
|
|
6
|
+
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
|
+
options?: {
|
|
8
|
+
quoteAllAttributes?: boolean | undefined;
|
|
9
|
+
} | undefined;
|
|
10
|
+
render(): string;
|
|
11
|
+
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
|
+
};
|
|
13
|
+
type MaybeArray<T> = T | Array<T>;
|
|
14
|
+
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
15
|
+
interface HtmlnanoOptions {
|
|
16
|
+
skipConfigLoading?: boolean;
|
|
17
|
+
skipInternalWarnings?: boolean;
|
|
18
|
+
collapseAttributeWhitespace?: boolean;
|
|
19
|
+
collapseBooleanAttributes?: {
|
|
20
|
+
amphtml?: boolean;
|
|
21
|
+
};
|
|
22
|
+
collapseWhitespace?: 'conservative' | 'all' | 'aggressive';
|
|
23
|
+
custom?: MaybeArray<(tree: PostHTMLTreeLike, options?: any) => (PostHTML.Node | PostHTMLTreeLike)>;
|
|
24
|
+
deduplicateAttributeValues?: boolean;
|
|
25
|
+
minifyUrls?: URL | string | false;
|
|
26
|
+
mergeStyles?: boolean;
|
|
27
|
+
mergeScripts?: boolean;
|
|
28
|
+
minifyCss?: Options | boolean;
|
|
29
|
+
minifyConditionalComments?: boolean;
|
|
30
|
+
minifyJs?: MinifyOptions | boolean;
|
|
31
|
+
minifyJson?: boolean;
|
|
32
|
+
minifySvg?: Config | boolean;
|
|
33
|
+
normalizeAttributeValues?: boolean;
|
|
34
|
+
removeAttributeQuotes?: boolean;
|
|
35
|
+
removeComments?: boolean | 'safe' | 'all' | RegExp | ((comment: string) => boolean);
|
|
36
|
+
removeEmptyAttributes?: boolean;
|
|
37
|
+
removeRedundantAttributes?: boolean;
|
|
38
|
+
removeOptionalTags?: boolean;
|
|
39
|
+
removeUnusedCss?: boolean;
|
|
40
|
+
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
41
|
+
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
42
|
+
}
|
|
43
|
+
type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
|
|
44
|
+
type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
|
|
45
|
+
type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
|
|
46
|
+
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
|
|
47
|
+
type HtmlnanoModule<Options = any> = {
|
|
48
|
+
onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
|
|
49
|
+
onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
|
|
50
|
+
onNode?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleNodeHandler;
|
|
51
|
+
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
declare const mod: HtmlnanoModule<boolean | 'alphabetical' | 'frequency'>;
|
|
55
|
+
|
|
56
|
+
export { mod as default };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
|
|
3
|
+
var collapseAttributeWhitespace_js = require('./collapseAttributeWhitespace.js');
|
|
4
|
+
|
|
5
|
+
// class, rel, ping
|
|
6
|
+
const validOptions = new Set([
|
|
7
|
+
'frequency',
|
|
8
|
+
'alphabetical'
|
|
9
|
+
]);
|
|
10
|
+
const processModuleOptions = (options)=>{
|
|
11
|
+
if (options === true) return 'alphabetical';
|
|
12
|
+
if (options === false) return false;
|
|
13
|
+
return validOptions.has(options) ? options : false;
|
|
14
|
+
};
|
|
15
|
+
class AttributeTokenChain {
|
|
16
|
+
addFromNodeAttrsArray(attrValuesArray) {
|
|
17
|
+
attrValuesArray.forEach((attrValue)=>{
|
|
18
|
+
if (this.freqData.has(attrValue)) {
|
|
19
|
+
this.freqData.set(attrValue, this.freqData.get(attrValue) + 1);
|
|
20
|
+
} else {
|
|
21
|
+
this.freqData.set(attrValue, 1);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
createSortOrder() {
|
|
26
|
+
const _sortOrder = [
|
|
27
|
+
...this.freqData.entries()
|
|
28
|
+
];
|
|
29
|
+
_sortOrder.sort((a, b)=>b[1] - a[1]);
|
|
30
|
+
this.sortOrder = _sortOrder.map((i)=>i[0]);
|
|
31
|
+
}
|
|
32
|
+
sortFromNodeAttrsArray(attrValuesArray) {
|
|
33
|
+
const resultArray = [];
|
|
34
|
+
if (!this.sortOrder) {
|
|
35
|
+
this.createSortOrder();
|
|
36
|
+
}
|
|
37
|
+
this.sortOrder.forEach((k)=>{
|
|
38
|
+
if (attrValuesArray.includes(k)) {
|
|
39
|
+
resultArray.push(k);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return resultArray;
|
|
43
|
+
}
|
|
44
|
+
constructor(){
|
|
45
|
+
/** <attr, frequency> */ this.freqData = new Map();
|
|
46
|
+
this.sortOrder = null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Sort values inside list-like attributes (e.g. class, rel) */ const mod = {
|
|
50
|
+
default (tree, options, moduleOptions) {
|
|
51
|
+
const sortType = processModuleOptions(moduleOptions);
|
|
52
|
+
if (sortType === 'alphabetical') {
|
|
53
|
+
return sortAttributesWithListsInAlphabeticalOrder(tree);
|
|
54
|
+
}
|
|
55
|
+
if (sortType === 'frequency') {
|
|
56
|
+
return sortAttributesWithListsByFrequency(tree);
|
|
57
|
+
}
|
|
58
|
+
// Invalid configuration
|
|
59
|
+
return tree;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function sortAttributesWithListsInAlphabeticalOrder(tree) {
|
|
63
|
+
tree.walk((node)=>{
|
|
64
|
+
if (!node.attrs) {
|
|
65
|
+
return node;
|
|
66
|
+
}
|
|
67
|
+
Object.keys(node.attrs).forEach((attrName)=>{
|
|
68
|
+
const attrNameLower = attrName.toLowerCase();
|
|
69
|
+
if (!collapseAttributeWhitespace_js.attributesWithLists.has(attrNameLower)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const attrValues = node.attrs[attrName].split(/\s/);
|
|
73
|
+
node.attrs[attrName] = attrValues.sort((a, b)=>{
|
|
74
|
+
// @ts-expect-error -- deliberately use minus operator to sort things
|
|
75
|
+
return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
|
|
76
|
+
}).join(' ');
|
|
77
|
+
});
|
|
78
|
+
return node;
|
|
79
|
+
});
|
|
80
|
+
return tree;
|
|
81
|
+
}
|
|
82
|
+
function sortAttributesWithListsByFrequency(tree) {
|
|
83
|
+
const tokenChainObj = {}; // <attrNameLower: AttributeTokenChain>[]
|
|
84
|
+
// Traverse through tree to get frequency
|
|
85
|
+
tree.walk((node)=>{
|
|
86
|
+
if (!node.attrs) {
|
|
87
|
+
return node;
|
|
88
|
+
}
|
|
89
|
+
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
90
|
+
const attrNameLower = attrName.toLowerCase();
|
|
91
|
+
if (!collapseAttributeWhitespace_js.attributesWithLists.has(attrNameLower)) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new AttributeTokenChain();
|
|
95
|
+
tokenChainObj[attrNameLower].addFromNodeAttrsArray(attrValues.split(/\s/));
|
|
96
|
+
});
|
|
97
|
+
return node;
|
|
98
|
+
});
|
|
99
|
+
// Traverse through tree again, this time sort the attribute values
|
|
100
|
+
tree.walk((node)=>{
|
|
101
|
+
if (!node.attrs) {
|
|
102
|
+
return node;
|
|
103
|
+
}
|
|
104
|
+
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
105
|
+
const attrNameLower = attrName.toLowerCase();
|
|
106
|
+
if (!collapseAttributeWhitespace_js.attributesWithLists.has(attrNameLower)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (tokenChainObj[attrNameLower]) {
|
|
110
|
+
node.attrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(attrValues.split(/\s/)).join(' ');
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
return node;
|
|
114
|
+
});
|
|
115
|
+
return tree;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
exports.default = mod;
|
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
// class, rel, ping
|
|
2
|
-
import { sort as timSort } from 'timsort';
|
|
3
1
|
import { attributesWithLists } from './collapseAttributeWhitespace.mjs';
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
const
|
|
3
|
+
// class, rel, ping
|
|
4
|
+
const validOptions = new Set([
|
|
5
|
+
'frequency',
|
|
6
|
+
'alphabetical'
|
|
7
|
+
]);
|
|
8
|
+
const processModuleOptions = (options)=>{
|
|
7
9
|
if (options === true) return 'alphabetical';
|
|
8
|
-
|
|
10
|
+
if (options === false) return false;
|
|
9
11
|
return validOptions.has(options) ? options : false;
|
|
10
12
|
};
|
|
11
|
-
|
|
12
13
|
class AttributeTokenChain {
|
|
13
|
-
constructor() {
|
|
14
|
-
this.freqData = new Map(); // <attrValue, frequency>[]
|
|
15
|
-
}
|
|
16
|
-
|
|
17
14
|
addFromNodeAttrsArray(attrValuesArray) {
|
|
18
|
-
attrValuesArray.forEach(attrValue
|
|
15
|
+
attrValuesArray.forEach((attrValue)=>{
|
|
19
16
|
if (this.freqData.has(attrValue)) {
|
|
20
17
|
this.freqData.set(attrValue, this.freqData.get(attrValue) + 1);
|
|
21
18
|
} else {
|
|
@@ -23,113 +20,97 @@ class AttributeTokenChain {
|
|
|
23
20
|
}
|
|
24
21
|
});
|
|
25
22
|
}
|
|
26
|
-
|
|
27
23
|
createSortOrder() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
const _sortOrder = [
|
|
25
|
+
...this.freqData.entries()
|
|
26
|
+
];
|
|
27
|
+
_sortOrder.sort((a, b)=>b[1] - a[1]);
|
|
28
|
+
this.sortOrder = _sortOrder.map((i)=>i[0]);
|
|
32
29
|
}
|
|
33
|
-
|
|
34
30
|
sortFromNodeAttrsArray(attrValuesArray) {
|
|
35
31
|
const resultArray = [];
|
|
36
|
-
|
|
37
32
|
if (!this.sortOrder) {
|
|
38
33
|
this.createSortOrder();
|
|
39
34
|
}
|
|
40
|
-
|
|
41
|
-
this.sortOrder.forEach(k => {
|
|
35
|
+
this.sortOrder.forEach((k)=>{
|
|
42
36
|
if (attrValuesArray.includes(k)) {
|
|
43
37
|
resultArray.push(k);
|
|
44
38
|
}
|
|
45
39
|
});
|
|
46
|
-
|
|
47
40
|
return resultArray;
|
|
48
41
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
export default function collapseAttributeWhitespace(tree, options, moduleOptions) {
|
|
53
|
-
const sortType = processModuleOptions(moduleOptions);
|
|
54
|
-
|
|
55
|
-
if (sortType === 'alphabetical') {
|
|
56
|
-
return sortAttributesWithListsInAlphabeticalOrder(tree);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (sortType === 'frequency') {
|
|
60
|
-
return sortAttributesWithListsByFrequency(tree);
|
|
42
|
+
constructor(){
|
|
43
|
+
/** <attr, frequency> */ this.freqData = new Map();
|
|
44
|
+
this.sortOrder = null;
|
|
61
45
|
}
|
|
62
|
-
|
|
63
|
-
// Invalid configuration
|
|
64
|
-
return tree;
|
|
65
46
|
}
|
|
66
|
-
|
|
47
|
+
/** Sort values inside list-like attributes (e.g. class, rel) */ const mod = {
|
|
48
|
+
default (tree, options, moduleOptions) {
|
|
49
|
+
const sortType = processModuleOptions(moduleOptions);
|
|
50
|
+
if (sortType === 'alphabetical') {
|
|
51
|
+
return sortAttributesWithListsInAlphabeticalOrder(tree);
|
|
52
|
+
}
|
|
53
|
+
if (sortType === 'frequency') {
|
|
54
|
+
return sortAttributesWithListsByFrequency(tree);
|
|
55
|
+
}
|
|
56
|
+
// Invalid configuration
|
|
57
|
+
return tree;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
67
60
|
function sortAttributesWithListsInAlphabeticalOrder(tree) {
|
|
68
|
-
tree.walk(node
|
|
61
|
+
tree.walk((node)=>{
|
|
69
62
|
if (!node.attrs) {
|
|
70
63
|
return node;
|
|
71
64
|
}
|
|
72
|
-
|
|
73
|
-
Object.keys(node.attrs).forEach(attrName => {
|
|
65
|
+
Object.keys(node.attrs).forEach((attrName)=>{
|
|
74
66
|
const attrNameLower = attrName.toLowerCase();
|
|
75
67
|
if (!attributesWithLists.has(attrNameLower)) {
|
|
76
68
|
return;
|
|
77
69
|
}
|
|
78
|
-
|
|
79
70
|
const attrValues = node.attrs[attrName].split(/\s/);
|
|
80
|
-
|
|
81
|
-
|
|
71
|
+
node.attrs[attrName] = attrValues.sort((a, b)=>{
|
|
72
|
+
// @ts-expect-error -- deliberately use minus operator to sort things
|
|
82
73
|
return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
|
|
83
74
|
}).join(' ');
|
|
84
75
|
});
|
|
85
|
-
|
|
86
76
|
return node;
|
|
87
77
|
});
|
|
88
|
-
|
|
89
78
|
return tree;
|
|
90
79
|
}
|
|
91
|
-
|
|
92
80
|
function sortAttributesWithListsByFrequency(tree) {
|
|
93
81
|
const tokenChainObj = {}; // <attrNameLower: AttributeTokenChain>[]
|
|
94
|
-
|
|
95
82
|
// Traverse through tree to get frequency
|
|
96
|
-
tree.walk(node
|
|
83
|
+
tree.walk((node)=>{
|
|
97
84
|
if (!node.attrs) {
|
|
98
85
|
return node;
|
|
99
86
|
}
|
|
100
|
-
|
|
101
|
-
Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
|
|
87
|
+
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
102
88
|
const attrNameLower = attrName.toLowerCase();
|
|
103
|
-
|
|
104
89
|
if (!attributesWithLists.has(attrNameLower)) {
|
|
105
90
|
return;
|
|
106
91
|
}
|
|
107
|
-
|
|
108
92
|
tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new AttributeTokenChain();
|
|
109
93
|
tokenChainObj[attrNameLower].addFromNodeAttrsArray(attrValues.split(/\s/));
|
|
110
94
|
});
|
|
111
|
-
|
|
112
95
|
return node;
|
|
113
96
|
});
|
|
114
|
-
|
|
115
97
|
// Traverse through tree again, this time sort the attribute values
|
|
116
|
-
tree.walk(node
|
|
98
|
+
tree.walk((node)=>{
|
|
117
99
|
if (!node.attrs) {
|
|
118
100
|
return node;
|
|
119
101
|
}
|
|
120
|
-
|
|
121
|
-
Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
|
|
102
|
+
Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
|
|
122
103
|
const attrNameLower = attrName.toLowerCase();
|
|
123
|
-
|
|
124
104
|
if (!attributesWithLists.has(attrNameLower)) {
|
|
125
105
|
return;
|
|
126
106
|
}
|
|
127
|
-
|
|
128
107
|
if (tokenChainObj[attrNameLower]) {
|
|
129
108
|
node.attrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(attrValues.split(/\s/)).join(' ');
|
|
130
109
|
}
|
|
131
110
|
});
|
|
132
|
-
|
|
133
111
|
return node;
|
|
134
112
|
});
|
|
113
|
+
return tree;
|
|
135
114
|
}
|
|
115
|
+
|
|
116
|
+
export { mod as default };
|