htmlnano 2.1.2 → 2.1.4

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.
Files changed (191) hide show
  1. package/README.md +54 -12
  2. package/dist/_modules/collapseAttributeWhitespace.d.mts +57 -0
  3. package/dist/_modules/collapseAttributeWhitespace.d.ts +57 -0
  4. package/dist/_modules/collapseAttributeWhitespace.js +296 -0
  5. package/dist/_modules/collapseAttributeWhitespace.mjs +293 -0
  6. package/dist/_modules/collapseBooleanAttributes.d.mts +60 -0
  7. package/dist/_modules/collapseBooleanAttributes.d.ts +60 -0
  8. package/dist/_modules/collapseBooleanAttributes.js +159 -0
  9. package/{lib/modules → dist/_modules}/collapseBooleanAttributes.mjs +39 -57
  10. package/dist/_modules/collapseWhitespace.d.mts +57 -0
  11. package/dist/_modules/collapseWhitespace.d.ts +57 -0
  12. package/dist/_modules/collapseWhitespace.js +172 -0
  13. package/dist/_modules/collapseWhitespace.mjs +170 -0
  14. package/dist/_modules/custom.d.mts +57 -0
  15. package/dist/_modules/custom.d.ts +57 -0
  16. package/dist/_modules/custom.js +22 -0
  17. package/dist/_modules/custom.mjs +20 -0
  18. package/dist/_modules/deduplicateAttributeValues.d.mts +56 -0
  19. package/dist/_modules/deduplicateAttributeValues.d.ts +56 -0
  20. package/dist/_modules/deduplicateAttributeValues.js +38 -0
  21. package/dist/_modules/deduplicateAttributeValues.mjs +36 -0
  22. package/dist/_modules/example.d.mts +59 -0
  23. package/dist/_modules/example.d.ts +59 -0
  24. package/dist/_modules/example.js +67 -0
  25. package/dist/_modules/example.mjs +65 -0
  26. package/dist/_modules/mergeScripts.d.mts +56 -0
  27. package/dist/_modules/mergeScripts.d.ts +56 -0
  28. package/dist/_modules/mergeScripts.js +53 -0
  29. package/dist/_modules/mergeScripts.mjs +51 -0
  30. package/dist/_modules/mergeStyles.d.mts +56 -0
  31. package/dist/_modules/mergeStyles.d.ts +56 -0
  32. package/dist/_modules/mergeStyles.js +42 -0
  33. package/dist/_modules/mergeStyles.mjs +40 -0
  34. package/dist/_modules/minifyConditionalComments.d.mts +56 -0
  35. package/dist/_modules/minifyConditionalComments.d.ts +56 -0
  36. package/dist/_modules/minifyConditionalComments.js +54 -0
  37. package/{lib/modules → dist/_modules}/minifyConditionalComments.mjs +21 -22
  38. package/dist/_modules/minifyCss.d.mts +56 -0
  39. package/dist/_modules/minifyCss.d.ts +56 -0
  40. package/dist/_modules/minifyCss.js +84 -0
  41. package/dist/_modules/minifyCss.mjs +82 -0
  42. package/dist/_modules/minifyJs.d.mts +56 -0
  43. package/dist/_modules/minifyJs.d.ts +56 -0
  44. package/dist/_modules/minifyJs.js +108 -0
  45. package/dist/_modules/minifyJs.mjs +106 -0
  46. package/dist/_modules/minifyJson.d.mts +56 -0
  47. package/dist/_modules/minifyJson.d.ts +56 -0
  48. package/dist/_modules/minifyJson.js +35 -0
  49. package/dist/_modules/minifyJson.mjs +33 -0
  50. package/dist/_modules/minifySvg.d.mts +56 -0
  51. package/dist/_modules/minifySvg.d.ts +56 -0
  52. package/dist/_modules/minifySvg.js +40 -0
  53. package/dist/_modules/minifySvg.mjs +38 -0
  54. package/dist/_modules/minifyUrls.d.mts +56 -0
  55. package/dist/_modules/minifyUrls.d.ts +56 -0
  56. package/dist/_modules/minifyUrls.js +180 -0
  57. package/dist/_modules/minifyUrls.mjs +178 -0
  58. package/dist/_modules/normalizeAttributeValues.d.mts +56 -0
  59. package/dist/_modules/normalizeAttributeValues.d.ts +56 -0
  60. package/dist/_modules/normalizeAttributeValues.js +234 -0
  61. package/dist/_modules/normalizeAttributeValues.mjs +232 -0
  62. package/dist/_modules/removeAttributeQuotes.d.mts +56 -0
  63. package/dist/_modules/removeAttributeQuotes.d.ts +56 -0
  64. package/dist/_modules/removeAttributeQuotes.js +15 -0
  65. package/dist/_modules/removeAttributeQuotes.mjs +13 -0
  66. package/dist/_modules/removeComments.d.mts +58 -0
  67. package/dist/_modules/removeComments.d.ts +58 -0
  68. package/dist/_modules/removeComments.js +83 -0
  69. package/{lib/modules → dist/_modules}/removeComments.mjs +24 -35
  70. package/dist/_modules/removeEmptyAttributes.d.mts +56 -0
  71. package/dist/_modules/removeEmptyAttributes.d.ts +56 -0
  72. package/dist/_modules/removeEmptyAttributes.js +197 -0
  73. package/dist/_modules/removeEmptyAttributes.mjs +195 -0
  74. package/dist/_modules/removeOptionalTags.d.mts +56 -0
  75. package/dist/_modules/removeOptionalTags.d.ts +56 -0
  76. package/dist/_modules/removeOptionalTags.js +190 -0
  77. package/{lib/modules → dist/_modules}/removeOptionalTags.mjs +54 -91
  78. package/dist/_modules/removeRedundantAttributes.d.mts +57 -0
  79. package/dist/_modules/removeRedundantAttributes.d.ts +57 -0
  80. package/dist/_modules/removeRedundantAttributes.js +128 -0
  81. package/{lib/modules → dist/_modules}/removeRedundantAttributes.mjs +43 -59
  82. package/dist/_modules/removeUnusedCss.d.mts +60 -0
  83. package/dist/_modules/removeUnusedCss.d.ts +60 -0
  84. package/dist/_modules/removeUnusedCss.js +134 -0
  85. package/dist/_modules/removeUnusedCss.mjs +132 -0
  86. package/dist/_modules/sortAttributes.d.mts +57 -0
  87. package/dist/_modules/sortAttributes.d.ts +57 -0
  88. package/dist/_modules/sortAttributes.js +102 -0
  89. package/{lib/modules → dist/_modules}/sortAttributes.mjs +39 -58
  90. package/dist/_modules/sortAttributesWithLists.d.mts +56 -0
  91. package/dist/_modules/sortAttributesWithLists.d.ts +56 -0
  92. package/dist/_modules/sortAttributesWithLists.js +118 -0
  93. package/{lib/modules → dist/_modules}/sortAttributesWithLists.mjs +41 -59
  94. package/dist/helpers.d.ts +16 -0
  95. package/dist/helpers.js +72 -0
  96. package/dist/helpers.mjs +63 -0
  97. package/dist/index.d.ts +79 -0
  98. package/dist/index.js +223 -0
  99. package/dist/index.mjs +209 -0
  100. package/dist/presets/ampSafe.d.ts +47 -0
  101. package/dist/presets/ampSafe.js +19 -0
  102. package/{lib → dist}/presets/ampSafe.mjs +6 -4
  103. package/dist/presets/max.d.ts +47 -0
  104. package/dist/presets/max.js +28 -0
  105. package/{lib → dist}/presets/max.mjs +6 -4
  106. package/dist/presets/safe.d.ts +47 -0
  107. package/dist/presets/safe.js +60 -0
  108. package/{lib → dist}/presets/safe.mjs +13 -20
  109. package/package.json +53 -56
  110. package/.eslintignore +0 -3
  111. package/CHANGELOG.md +0 -409
  112. package/docs/README.md +0 -33
  113. package/docs/babel.config.js +0 -3
  114. package/docs/docs/010-introduction.md +0 -22
  115. package/docs/docs/020-usage.md +0 -117
  116. package/docs/docs/030-config.md +0 -21
  117. package/docs/docs/040-presets.md +0 -75
  118. package/docs/docs/050-modules.md +0 -855
  119. package/docs/docs/060-contribute.md +0 -16
  120. package/docs/docusaurus.config.js +0 -65
  121. package/docs/netlify.toml +0 -4
  122. package/docs/package-lock.json +0 -21630
  123. package/docs/package.json +0 -40
  124. package/docs/sidebars.js +0 -26
  125. package/docs/versioned_docs/version-1.1.1/010-introduction.md +0 -22
  126. package/docs/versioned_docs/version-1.1.1/020-usage.md +0 -77
  127. package/docs/versioned_docs/version-1.1.1/030-config.md +0 -21
  128. package/docs/versioned_docs/version-1.1.1/040-presets.md +0 -75
  129. package/docs/versioned_docs/version-1.1.1/050-modules.md +0 -785
  130. package/docs/versioned_docs/version-1.1.1/060-contribute.md +0 -16
  131. package/docs/versioned_docs/version-2.0.0/010-introduction.md +0 -22
  132. package/docs/versioned_docs/version-2.0.0/020-usage.md +0 -77
  133. package/docs/versioned_docs/version-2.0.0/030-config.md +0 -21
  134. package/docs/versioned_docs/version-2.0.0/040-presets.md +0 -75
  135. package/docs/versioned_docs/version-2.0.0/050-modules.md +0 -838
  136. package/docs/versioned_docs/version-2.0.0/060-contribute.md +0 -16
  137. package/docs/versioned_sidebars/version-1.1.1-sidebars.json +0 -8
  138. package/docs/versioned_sidebars/version-2.0.0-sidebars.json +0 -8
  139. package/docs/versions.json +0 -4
  140. package/index.cjs +0 -11
  141. package/index.d.cts +0 -3
  142. package/index.d.mts +0 -3
  143. package/index.d.ts +0 -94
  144. package/index.mjs +0 -2
  145. package/lib/helpers.cjs +0 -79
  146. package/lib/helpers.mjs +0 -53
  147. package/lib/htmlnano.cjs +0 -202
  148. package/lib/htmlnano.mjs +0 -198
  149. package/lib/modules/collapseAttributeWhitespace.cjs +0 -86
  150. package/lib/modules/collapseAttributeWhitespace.mjs +0 -104
  151. package/lib/modules/collapseBooleanAttributes.cjs +0 -62
  152. package/lib/modules/collapseWhitespace.cjs +0 -100
  153. package/lib/modules/collapseWhitespace.mjs +0 -132
  154. package/lib/modules/custom.cjs +0 -19
  155. package/lib/modules/custom.mjs +0 -16
  156. package/lib/modules/deduplicateAttributeValues.cjs +0 -38
  157. package/lib/modules/deduplicateAttributeValues.mjs +0 -40
  158. package/lib/modules/example.cjs +0 -85
  159. package/lib/modules/example.mjs +0 -75
  160. package/lib/modules/mergeScripts.cjs +0 -54
  161. package/lib/modules/mergeScripts.mjs +0 -56
  162. package/lib/modules/mergeStyles.cjs +0 -38
  163. package/lib/modules/mergeStyles.mjs +0 -36
  164. package/lib/modules/minifyConditionalComments.cjs +0 -47
  165. package/lib/modules/minifyCss.cjs +0 -73
  166. package/lib/modules/minifyCss.mjs +0 -88
  167. package/lib/modules/minifyJs.cjs +0 -103
  168. package/lib/modules/minifyJs.mjs +0 -121
  169. package/lib/modules/minifyJson.cjs +0 -24
  170. package/lib/modules/minifyJson.mjs +0 -21
  171. package/lib/modules/minifySvg.cjs +0 -37
  172. package/lib/modules/minifySvg.mjs +0 -30
  173. package/lib/modules/minifyUrls.cjs +0 -141
  174. package/lib/modules/minifyUrls.mjs +0 -229
  175. package/lib/modules/normalizeAttributeValues.cjs +0 -120
  176. package/lib/modules/normalizeAttributeValues.mjs +0 -140
  177. package/lib/modules/removeAttributeQuotes.cjs +0 -17
  178. package/lib/modules/removeAttributeQuotes.mjs +0 -12
  179. package/lib/modules/removeComments.cjs +0 -86
  180. package/lib/modules/removeEmptyAttributes.cjs +0 -72
  181. package/lib/modules/removeEmptyAttributes.mjs +0 -121
  182. package/lib/modules/removeOptionalTags.cjs +0 -183
  183. package/lib/modules/removeRedundantAttributes.cjs +0 -112
  184. package/lib/modules/removeUnusedCss.cjs +0 -113
  185. package/lib/modules/removeUnusedCss.mjs +0 -122
  186. package/lib/modules/sortAttributes.cjs +0 -98
  187. package/lib/modules/sortAttributesWithLists.cjs +0 -114
  188. package/lib/presets/ampSafe.cjs +0 -18
  189. package/lib/presets/max.cjs +0 -27
  190. package/lib/presets/safe.cjs +0 -65
  191. package/test.js +0 -23
@@ -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,20 +1,16 @@
1
- const validOptions = new Set(['frequency', 'alphabetical']);
2
-
3
- const processModuleOptions = options => {
1
+ const validOptions = new Set([
2
+ 'frequency',
3
+ 'alphabetical'
4
+ ]);
5
+ const processModuleOptions = (options)=>{
4
6
  if (options === true) return 'alphabetical';
5
-
7
+ if (options === false) return false;
6
8
  return validOptions.has(options) ? options : false;
7
9
  };
8
-
9
10
  class AttributeTokenChain {
10
- constructor() {
11
- this.freqData = new Map(); // <attr, frequency>[]
12
- }
13
-
14
11
  addFromNodeAttrs(nodeAttrs) {
15
- Object.keys(nodeAttrs).forEach(attrName => {
12
+ Object.keys(nodeAttrs).forEach((attrName)=>{
16
13
  const attrNameLower = attrName.toLowerCase();
17
-
18
14
  if (this.freqData.has(attrNameLower)) {
19
15
  this.freqData.set(attrNameLower, this.freqData.get(attrNameLower) + 1);
20
16
  } else {
@@ -22,98 +18,83 @@ class AttributeTokenChain {
22
18
  }
23
19
  });
24
20
  }
25
-
26
21
  createSortOrder() {
27
- let _sortOrder = [...this.freqData.entries()];
28
- _sortOrder.sort((a, b) => b[1] - a[1]);
29
-
30
- this.sortOrder = _sortOrder.map(i => i[0]);
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]);
31
27
  }
32
-
33
28
  sortFromNodeAttrs(nodeAttrs) {
34
29
  const newAttrs = {};
35
-
36
30
  // Convert node.attrs attrName into lower case.
37
31
  const loweredNodeAttrs = {};
38
- Object.entries(nodeAttrs).forEach(([attrName, attrValue]) => {
32
+ Object.entries(nodeAttrs).forEach(([attrName, attrValue])=>{
39
33
  loweredNodeAttrs[attrName.toLowerCase()] = attrValue;
40
34
  });
41
-
42
35
  if (!this.sortOrder) {
43
36
  this.createSortOrder();
44
37
  }
45
-
46
- this.sortOrder.forEach(attrNameLower => {
38
+ this.sortOrder.forEach((attrNameLower)=>{
47
39
  // The attrName inside "sortOrder" has been lowered
48
40
  if (loweredNodeAttrs[attrNameLower] != null) {
49
41
  newAttrs[attrNameLower] = loweredNodeAttrs[attrNameLower];
50
42
  }
51
43
  });
52
-
53
44
  return newAttrs;
54
45
  }
55
- }
56
-
57
- /** Sort attibutes */
58
- export default function sortAttributes(tree, options, moduleOptions) {
59
- const sortType = processModuleOptions(moduleOptions);
60
-
61
- if (sortType === 'alphabetical') {
62
- return sortAttributesInAlphabeticalOrder(tree);
63
- }
64
-
65
- if (sortType === 'frequency') {
66
- return sortAttributesByFrequency(tree);
46
+ constructor(){
47
+ /** <attr, frequency> */ this.freqData = new Map();
48
+ this.sortOrder = null;
67
49
  }
68
-
69
- // Invalid configuration
70
- return tree;
71
50
  }
72
-
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
+ };
73
64
  function sortAttributesInAlphabeticalOrder(tree) {
74
- tree.walk(node => {
65
+ tree.walk((node)=>{
75
66
  if (!node.attrs) {
76
67
  return node;
77
68
  }
78
-
79
69
  const newAttrs = {};
80
-
81
- Object.keys(node.attrs)
82
- .sort((a, b) => typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b)
83
- .forEach(attr => newAttrs[attr] = node.attrs[attr]);
84
-
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
+ });
85
74
  node.attrs = newAttrs;
86
-
87
75
  return node;
88
76
  });
89
-
90
77
  return tree;
91
78
  }
92
-
93
79
  function sortAttributesByFrequency(tree) {
94
80
  const tokenchain = new AttributeTokenChain();
95
-
96
81
  // Traverse through tree to get frequency
97
- tree.walk(node => {
82
+ tree.walk((node)=>{
98
83
  if (!node.attrs) {
99
84
  return node;
100
85
  }
101
-
102
86
  tokenchain.addFromNodeAttrs(node.attrs);
103
-
104
87
  return node;
105
88
  });
106
-
107
89
  // Traverse through tree again, this time sort the attributes
108
- tree.walk(node => {
90
+ tree.walk((node)=>{
109
91
  if (!node.attrs) {
110
92
  return node;
111
93
  }
112
-
113
94
  node.attrs = tokenchain.sortFromNodeAttrs(node.attrs);
114
-
115
95
  return node;
116
96
  });
117
-
118
97
  return tree;
119
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,20 +1,18 @@
1
- // class, rel, ping
2
1
  import { attributesWithLists } from './collapseAttributeWhitespace.mjs';
3
2
 
4
- const validOptions = new Set(['frequency', 'alphabetical']);
5
- const processModuleOptions = options => {
3
+ // class, rel, ping
4
+ const validOptions = new Set([
5
+ 'frequency',
6
+ 'alphabetical'
7
+ ]);
8
+ const processModuleOptions = (options)=>{
6
9
  if (options === true) return 'alphabetical';
7
-
10
+ if (options === false) return false;
8
11
  return validOptions.has(options) ? options : false;
9
12
  };
10
-
11
13
  class AttributeTokenChain {
12
- constructor() {
13
- this.freqData = new Map(); // <attrValue, frequency>[]
14
- }
15
-
16
14
  addFromNodeAttrsArray(attrValuesArray) {
17
- attrValuesArray.forEach(attrValue => {
15
+ attrValuesArray.forEach((attrValue)=>{
18
16
  if (this.freqData.has(attrValue)) {
19
17
  this.freqData.set(attrValue, this.freqData.get(attrValue) + 1);
20
18
  } else {
@@ -22,113 +20,97 @@ class AttributeTokenChain {
22
20
  }
23
21
  });
24
22
  }
25
-
26
23
  createSortOrder() {
27
- let _sortOrder = [...this.freqData.entries()];
28
- _sortOrder.sort((a, b) => b[1] - a[1]);
29
-
30
- this.sortOrder = _sortOrder.map(i => i[0]);
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]);
31
29
  }
32
-
33
30
  sortFromNodeAttrsArray(attrValuesArray) {
34
31
  const resultArray = [];
35
-
36
32
  if (!this.sortOrder) {
37
33
  this.createSortOrder();
38
34
  }
39
-
40
- this.sortOrder.forEach(k => {
35
+ this.sortOrder.forEach((k)=>{
41
36
  if (attrValuesArray.includes(k)) {
42
37
  resultArray.push(k);
43
38
  }
44
39
  });
45
-
46
40
  return resultArray;
47
41
  }
48
- }
49
-
50
- /** Sort values inside list-like attributes (e.g. class, rel) */
51
- export default function collapseAttributeWhitespace(tree, options, moduleOptions) {
52
- const sortType = processModuleOptions(moduleOptions);
53
-
54
- if (sortType === 'alphabetical') {
55
- return sortAttributesWithListsInAlphabeticalOrder(tree);
56
- }
57
-
58
- if (sortType === 'frequency') {
59
- return sortAttributesWithListsByFrequency(tree);
42
+ constructor(){
43
+ /** <attr, frequency> */ this.freqData = new Map();
44
+ this.sortOrder = null;
60
45
  }
61
-
62
- // Invalid configuration
63
- return tree;
64
46
  }
65
-
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
+ };
66
60
  function sortAttributesWithListsInAlphabeticalOrder(tree) {
67
- tree.walk(node => {
61
+ tree.walk((node)=>{
68
62
  if (!node.attrs) {
69
63
  return node;
70
64
  }
71
-
72
- Object.keys(node.attrs).forEach(attrName => {
65
+ Object.keys(node.attrs).forEach((attrName)=>{
73
66
  const attrNameLower = attrName.toLowerCase();
74
67
  if (!attributesWithLists.has(attrNameLower)) {
75
68
  return;
76
69
  }
77
-
78
70
  const attrValues = node.attrs[attrName].split(/\s/);
79
-
80
- node.attrs[attrName] = attrValues.sort((a, b) => {
71
+ node.attrs[attrName] = attrValues.sort((a, b)=>{
72
+ // @ts-expect-error -- deliberately use minus operator to sort things
81
73
  return typeof a.localeCompare === 'function' ? a.localeCompare(b) : a - b;
82
74
  }).join(' ');
83
75
  });
84
-
85
76
  return node;
86
77
  });
87
-
88
78
  return tree;
89
79
  }
90
-
91
80
  function sortAttributesWithListsByFrequency(tree) {
92
81
  const tokenChainObj = {}; // <attrNameLower: AttributeTokenChain>[]
93
-
94
82
  // Traverse through tree to get frequency
95
- tree.walk(node => {
83
+ tree.walk((node)=>{
96
84
  if (!node.attrs) {
97
85
  return node;
98
86
  }
99
-
100
- Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
87
+ Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
101
88
  const attrNameLower = attrName.toLowerCase();
102
-
103
89
  if (!attributesWithLists.has(attrNameLower)) {
104
90
  return;
105
91
  }
106
-
107
92
  tokenChainObj[attrNameLower] = tokenChainObj[attrNameLower] || new AttributeTokenChain();
108
93
  tokenChainObj[attrNameLower].addFromNodeAttrsArray(attrValues.split(/\s/));
109
94
  });
110
-
111
95
  return node;
112
96
  });
113
-
114
97
  // Traverse through tree again, this time sort the attribute values
115
- tree.walk(node => {
98
+ tree.walk((node)=>{
116
99
  if (!node.attrs) {
117
100
  return node;
118
101
  }
119
-
120
- Object.entries(node.attrs).forEach(([attrName, attrValues]) => {
102
+ Object.entries(node.attrs).forEach(([attrName, attrValues])=>{
121
103
  const attrNameLower = attrName.toLowerCase();
122
-
123
104
  if (!attributesWithLists.has(attrNameLower)) {
124
105
  return;
125
106
  }
126
-
127
107
  if (tokenChainObj[attrNameLower]) {
128
108
  node.attrs[attrName] = tokenChainObj[attrNameLower].sortFromNodeAttrsArray(attrValues.split(/\s/)).join(' ');
129
109
  }
130
110
  });
131
-
132
111
  return node;
133
112
  });
113
+ return tree;
134
114
  }
115
+
116
+ export { mod as default };
@@ -0,0 +1,16 @@
1
+ import PostHTML from 'posthtml';
2
+
3
+ type PostHTMLNodeLike = PostHTML.Node | string;
4
+
5
+ declare function isAmpBoilerplate(node: PostHTML.Node): boolean;
6
+ declare function isComment(content: PostHTMLNodeLike | null): boolean;
7
+ declare function isConditionalComment(content: string): boolean;
8
+ declare function isStyleNode(node: PostHTML.Node): boolean | undefined;
9
+ declare function extractCssFromStyleNode(node: PostHTML.Node): string | undefined;
10
+ declare function isEventHandler(attributeName: string): boolean | "";
11
+ declare function extractTextContentFromNode(node: PostHTML.Node): string;
12
+ declare function optionalImport<Module = unknown, Default = Module>(moduleName: string): Promise<(Module & {
13
+ default?: Default;
14
+ }) | NonNullable<Default> | null>;
15
+
16
+ export { extractCssFromStyleNode, extractTextContentFromNode, isAmpBoilerplate, isComment, isConditionalComment, isEventHandler, isStyleNode, optionalImport };