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.
Files changed (186) hide show
  1. package/README.md +53 -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 -60
  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 -60
  94. package/dist/helpers.js +72 -0
  95. package/dist/helpers.mjs +63 -0
  96. package/dist/index.js +223 -0
  97. package/dist/index.mjs +209 -0
  98. package/dist/presets/ampSafe.js +19 -0
  99. package/{lib → dist}/presets/ampSafe.mjs +6 -4
  100. package/dist/presets/max.js +28 -0
  101. package/{lib → dist}/presets/max.mjs +6 -4
  102. package/dist/presets/safe.js +60 -0
  103. package/{lib → dist}/presets/safe.mjs +13 -20
  104. package/package.json +53 -59
  105. package/.eslintignore +0 -3
  106. package/CHANGELOG.md +0 -398
  107. package/docs/README.md +0 -33
  108. package/docs/babel.config.js +0 -3
  109. package/docs/docs/010-introduction.md +0 -22
  110. package/docs/docs/020-usage.md +0 -117
  111. package/docs/docs/030-config.md +0 -21
  112. package/docs/docs/040-presets.md +0 -75
  113. package/docs/docs/050-modules.md +0 -855
  114. package/docs/docs/060-contribute.md +0 -16
  115. package/docs/docusaurus.config.js +0 -65
  116. package/docs/netlify.toml +0 -4
  117. package/docs/package-lock.json +0 -21796
  118. package/docs/package.json +0 -40
  119. package/docs/sidebars.js +0 -26
  120. package/docs/versioned_docs/version-1.1.1/010-introduction.md +0 -22
  121. package/docs/versioned_docs/version-1.1.1/020-usage.md +0 -77
  122. package/docs/versioned_docs/version-1.1.1/030-config.md +0 -21
  123. package/docs/versioned_docs/version-1.1.1/040-presets.md +0 -75
  124. package/docs/versioned_docs/version-1.1.1/050-modules.md +0 -785
  125. package/docs/versioned_docs/version-1.1.1/060-contribute.md +0 -16
  126. package/docs/versioned_docs/version-2.0.0/010-introduction.md +0 -22
  127. package/docs/versioned_docs/version-2.0.0/020-usage.md +0 -77
  128. package/docs/versioned_docs/version-2.0.0/030-config.md +0 -21
  129. package/docs/versioned_docs/version-2.0.0/040-presets.md +0 -75
  130. package/docs/versioned_docs/version-2.0.0/050-modules.md +0 -838
  131. package/docs/versioned_docs/version-2.0.0/060-contribute.md +0 -16
  132. package/docs/versioned_sidebars/version-1.1.1-sidebars.json +0 -8
  133. package/docs/versioned_sidebars/version-2.0.0-sidebars.json +0 -8
  134. package/docs/versions.json +0 -4
  135. package/index.cjs +0 -11
  136. package/index.d.cts +0 -3
  137. package/index.d.mts +0 -3
  138. package/index.d.ts +0 -93
  139. package/index.mjs +0 -2
  140. package/lib/helpers.cjs +0 -79
  141. package/lib/helpers.mjs +0 -53
  142. package/lib/htmlnano.cjs +0 -200
  143. package/lib/htmlnano.mjs +0 -196
  144. package/lib/modules/collapseAttributeWhitespace.cjs +0 -86
  145. package/lib/modules/collapseAttributeWhitespace.mjs +0 -104
  146. package/lib/modules/collapseBooleanAttributes.cjs +0 -62
  147. package/lib/modules/collapseWhitespace.cjs +0 -100
  148. package/lib/modules/collapseWhitespace.mjs +0 -132
  149. package/lib/modules/custom.cjs +0 -19
  150. package/lib/modules/custom.mjs +0 -16
  151. package/lib/modules/deduplicateAttributeValues.cjs +0 -38
  152. package/lib/modules/deduplicateAttributeValues.mjs +0 -40
  153. package/lib/modules/example.cjs +0 -85
  154. package/lib/modules/example.mjs +0 -75
  155. package/lib/modules/mergeScripts.cjs +0 -54
  156. package/lib/modules/mergeScripts.mjs +0 -56
  157. package/lib/modules/mergeStyles.cjs +0 -38
  158. package/lib/modules/mergeStyles.mjs +0 -36
  159. package/lib/modules/minifyConditionalComments.cjs +0 -47
  160. package/lib/modules/minifyCss.cjs +0 -73
  161. package/lib/modules/minifyCss.mjs +0 -88
  162. package/lib/modules/minifyJs.cjs +0 -103
  163. package/lib/modules/minifyJs.mjs +0 -121
  164. package/lib/modules/minifyJson.cjs +0 -24
  165. package/lib/modules/minifyJson.mjs +0 -21
  166. package/lib/modules/minifySvg.cjs +0 -37
  167. package/lib/modules/minifySvg.mjs +0 -30
  168. package/lib/modules/minifyUrls.cjs +0 -141
  169. package/lib/modules/minifyUrls.mjs +0 -229
  170. package/lib/modules/normalizeAttributeValues.cjs +0 -120
  171. package/lib/modules/normalizeAttributeValues.mjs +0 -140
  172. package/lib/modules/removeAttributeQuotes.cjs +0 -17
  173. package/lib/modules/removeAttributeQuotes.mjs +0 -12
  174. package/lib/modules/removeComments.cjs +0 -86
  175. package/lib/modules/removeEmptyAttributes.cjs +0 -72
  176. package/lib/modules/removeEmptyAttributes.mjs +0 -121
  177. package/lib/modules/removeOptionalTags.cjs +0 -183
  178. package/lib/modules/removeRedundantAttributes.cjs +0 -112
  179. package/lib/modules/removeUnusedCss.cjs +0 -113
  180. package/lib/modules/removeUnusedCss.mjs +0 -122
  181. package/lib/modules/sortAttributes.cjs +0 -99
  182. package/lib/modules/sortAttributesWithLists.cjs +0 -115
  183. package/lib/presets/ampSafe.cjs +0 -18
  184. package/lib/presets/max.cjs +0 -27
  185. package/lib/presets/safe.cjs +0 -65
  186. package/test.js +0 -48
@@ -48,7 +48,6 @@ const htmlBooleanAttributes = new Set([
48
48
  'typemustmatch',
49
49
  'visible'
50
50
  ]);
51
-
52
51
  const amphtmlBooleanAttributes = new Set([
53
52
  '⚡',
54
53
  'amp',
@@ -56,12 +55,10 @@ const amphtmlBooleanAttributes = new Set([
56
55
  'amp4ads',
57
56
  '⚡4email',
58
57
  'amp4email',
59
-
60
58
  'amp-custom',
61
59
  'amp-boilerplate',
62
60
  'amp4ads-boilerplate',
63
61
  'amp4email-boilerplate',
64
-
65
62
  'allow-blocked-ranges',
66
63
  'amp-access-hide',
67
64
  'amp-access-template',
@@ -105,7 +102,6 @@ const amphtmlBooleanAttributes = new Set([
105
102
  'subscriptions-actions',
106
103
  'subscriptions-dialog'
107
104
  ]);
108
-
109
105
  const missingValueDefaultEmptyStringAttributes = {
110
106
  // https://html.spec.whatwg.org/#attr-media-preload
111
107
  audio: {
@@ -115,61 +111,47 @@ const missingValueDefaultEmptyStringAttributes = {
115
111
  preload: 'auto'
116
112
  }
117
113
  };
118
-
119
114
  const tagsHasMissingValueDefaultEmptyStringAttributes = new Set(Object.keys(missingValueDefaultEmptyStringAttributes));
120
-
121
- export function onAttrs(options, moduleOptions) {
122
- return (attrs, node) => {
123
- if (!node.tag) return attrs;
124
-
125
- const newAttrs = attrs;
126
-
127
- if (tagsHasMissingValueDefaultEmptyStringAttributes.has(node.tag)) {
128
- const tagAttributesCanBeReplacedWithEmptyString = missingValueDefaultEmptyStringAttributes[node.tag];
129
-
130
- for (const attributesCanBeReplacedWithEmptyString of Object.keys(tagAttributesCanBeReplacedWithEmptyString)) {
131
- if (
132
- Object.prototype.hasOwnProperty.call(attrs, attributesCanBeReplacedWithEmptyString)
133
- && attrs[attributesCanBeReplacedWithEmptyString] === tagAttributesCanBeReplacedWithEmptyString[attributesCanBeReplacedWithEmptyString]
134
- ) {
135
- attrs[attributesCanBeReplacedWithEmptyString] = true;
115
+ const mod = {
116
+ onAttrs (options, moduleOptions) {
117
+ return (attrs, node)=>{
118
+ if (!node.tag) return attrs;
119
+ const newAttrs = attrs;
120
+ if (tagsHasMissingValueDefaultEmptyStringAttributes.has(node.tag)) {
121
+ const tagAttributesCanBeReplacedWithEmptyString = missingValueDefaultEmptyStringAttributes[node.tag];
122
+ for (const attributesCanBeReplacedWithEmptyString of Object.keys(tagAttributesCanBeReplacedWithEmptyString)){
123
+ if (attributesCanBeReplacedWithEmptyString in attrs && attributesCanBeReplacedWithEmptyString in tagAttributesCanBeReplacedWithEmptyString && attrs[attributesCanBeReplacedWithEmptyString] === tagAttributesCanBeReplacedWithEmptyString[attributesCanBeReplacedWithEmptyString]) {
124
+ attrs[attributesCanBeReplacedWithEmptyString] = true;
125
+ }
136
126
  }
137
127
  }
138
- }
139
-
140
- for (const attrName of Object.keys(attrs)) {
141
- if (attrName === 'visible' && node.tag.startsWith('a-')) {
142
- continue;
143
- }
144
-
145
- if (htmlBooleanAttributes.has(attrName)) {
146
- newAttrs[attrName] = true;
147
- }
148
-
149
- // Fast path optimization.
150
- // The rest of tranformations are only for string type attrValue.
151
- if (typeof newAttrs[attrName] !== 'string') continue;
152
-
153
- if (moduleOptions.amphtml && amphtmlBooleanAttributes.has(attrName) && attrs[attrName] === '') {
154
- newAttrs[attrName] = true;
155
- }
156
- // https://html.spec.whatwg.org/#a-quick-introduction-to-html
157
- // The value, along with the "=" character, can be omitted altogether if the value is the empty string.
158
- if (attrs[attrName] === '') {
159
- newAttrs[attrName] = true;
160
- }
161
-
162
- // collapse crossorigin attributes
163
- // Specification: https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
164
- if (
165
- attrName.toLowerCase() === 'crossorigin' && (
166
- attrs[attrName] === 'anonymous'
167
- )
168
- ) {
169
- newAttrs[attrName] = true;
128
+ for (const attrName of Object.keys(attrs)){
129
+ if (attrName === 'visible' && node.tag.startsWith('a-')) {
130
+ continue;
131
+ }
132
+ if (htmlBooleanAttributes.has(attrName)) {
133
+ newAttrs[attrName] = true;
134
+ }
135
+ // Fast path optimization.
136
+ // The rest of tranformations are only for string type attrValue.
137
+ if (typeof newAttrs[attrName] !== 'string') continue;
138
+ if (moduleOptions.amphtml && amphtmlBooleanAttributes.has(attrName) && attrs[attrName] === '') {
139
+ newAttrs[attrName] = true;
140
+ }
141
+ // https://html.spec.whatwg.org/#a-quick-introduction-to-html
142
+ // The value, along with the "=" character, can be omitted altogether if the value is the empty string.
143
+ if (attrs[attrName] === '') {
144
+ newAttrs[attrName] = true;
145
+ }
146
+ // collapse crossorigin attributes
147
+ // Specification: https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
148
+ if (attrName.toLowerCase() === 'crossorigin' && attrs[attrName] === 'anonymous') {
149
+ newAttrs[attrName] = true;
150
+ }
170
151
  }
171
- }
152
+ return newAttrs;
153
+ };
154
+ }
155
+ };
172
156
 
173
- return newAttrs;
174
- };
175
- }
157
+ export { mod as default };
@@ -0,0 +1,57 @@
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
+ type CollapseType = 'all' | 'aggressive' | 'conservative';
55
+ declare const mod: HtmlnanoModule<CollapseType>;
56
+
57
+ export { mod as default };
@@ -0,0 +1,57 @@
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
+ type CollapseType = 'all' | 'aggressive' | 'conservative';
55
+ declare const mod: HtmlnanoModule<CollapseType>;
56
+
57
+ export { mod as default };
@@ -0,0 +1,172 @@
1
+ Object.defineProperty(exports, '__esModule', { value: true });
2
+
3
+ var helpers_js = require('../helpers.js');
4
+
5
+ const noWhitespaceCollapseElements = new Set([
6
+ 'script',
7
+ 'style',
8
+ 'pre',
9
+ 'textarea'
10
+ ]);
11
+ const noTrimWhitespacesArroundElements = new Set([
12
+ // non-empty tags that will maintain whitespace around them
13
+ 'a',
14
+ 'abbr',
15
+ 'acronym',
16
+ 'b',
17
+ 'bdi',
18
+ 'bdo',
19
+ 'big',
20
+ 'button',
21
+ 'cite',
22
+ 'code',
23
+ 'del',
24
+ 'dfn',
25
+ 'em',
26
+ 'font',
27
+ 'i',
28
+ 'ins',
29
+ 'kbd',
30
+ 'label',
31
+ 'mark',
32
+ 'math',
33
+ 'nobr',
34
+ 'object',
35
+ 'q',
36
+ 'rp',
37
+ 'rt',
38
+ 'rtc',
39
+ 'ruby',
40
+ 's',
41
+ 'samp',
42
+ 'select',
43
+ 'small',
44
+ 'span',
45
+ 'strike',
46
+ 'strong',
47
+ 'sub',
48
+ 'sup',
49
+ 'svg',
50
+ 'textarea',
51
+ 'time',
52
+ 'tt',
53
+ 'u',
54
+ 'var',
55
+ // self-closing tags that will maintain whitespace around them
56
+ 'comment',
57
+ 'img',
58
+ 'input',
59
+ 'wbr'
60
+ ]);
61
+ const noTrimWhitespacesInsideElements = new Set([
62
+ // non-empty tags that will maintain whitespace within them
63
+ 'a',
64
+ 'abbr',
65
+ 'acronym',
66
+ 'b',
67
+ 'big',
68
+ 'del',
69
+ 'em',
70
+ 'font',
71
+ 'i',
72
+ 'ins',
73
+ 'kbd',
74
+ 'mark',
75
+ 'nobr',
76
+ 'rp',
77
+ 's',
78
+ 'samp',
79
+ 'small',
80
+ 'span',
81
+ 'strike',
82
+ 'strong',
83
+ 'sub',
84
+ 'sup',
85
+ 'time',
86
+ 'tt',
87
+ 'u',
88
+ 'var'
89
+ ]);
90
+ const startsWithWhitespacePattern = /^\s/;
91
+ const endsWithWhitespacePattern = /\s$/;
92
+ // See https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace and https://infra.spec.whatwg.org/#ascii-whitespace
93
+ const multipleWhitespacePattern = /[\t\n\f\r ]+/g;
94
+ const NONE = '';
95
+ const SINGLE_SPACE = ' ';
96
+ const validOptions = [
97
+ 'all',
98
+ 'aggressive',
99
+ 'conservative'
100
+ ];
101
+ function collapseWhitespace(tree, options, collapseType, parent) {
102
+ collapseType = validOptions.includes(collapseType) ? collapseType : 'conservative';
103
+ tree.forEach((node, index)=>{
104
+ const prevNode = tree[index - 1];
105
+ const nextNode = tree[index + 1];
106
+ if (typeof node === 'string') {
107
+ const parentNodeTag = parent == null ? void 0 : parent.node.tag;
108
+ const isTopLevel = parentNodeTag == null || parentNodeTag === 'html' || parentNodeTag === 'head';
109
+ const shouldTrim = isTopLevel || collapseType === 'all' || collapseType === 'aggressive';
110
+ node = collapseRedundantWhitespaces(node, collapseType, shouldTrim, parent, prevNode, nextNode);
111
+ } else if (node.tag) {
112
+ var _node_content;
113
+ const isAllowCollapseWhitespace = !noWhitespaceCollapseElements.has(node.tag);
114
+ if (isAllowCollapseWhitespace && ((_node_content = node.content) == null ? void 0 : _node_content.length)) {
115
+ node.content = collapseWhitespace(node.content, options, collapseType, {
116
+ node,
117
+ prevNode});
118
+ }
119
+ }
120
+ tree[index] = node;
121
+ });
122
+ return tree;
123
+ }
124
+ function collapseRedundantWhitespaces(text, collapseType, shouldTrim = false, parent, prevNode, nextNode) {
125
+ if (!text || text.length === 0) {
126
+ return NONE;
127
+ }
128
+ if (!helpers_js.isComment(text)) {
129
+ text = text.replace(multipleWhitespacePattern, SINGLE_SPACE);
130
+ }
131
+ if (shouldTrim) {
132
+ // either all or top level, trim all
133
+ if (collapseType === 'all' || collapseType === 'conservative') {
134
+ return text.trim();
135
+ }
136
+ if (typeof parent !== 'object' || !(parent == null ? void 0 : parent.node.tag) || !noTrimWhitespacesInsideElements.has(parent.node.tag)) {
137
+ if (// It is the first child node of the parent
138
+ !prevNode || typeof prevNode === 'object' && prevNode.tag && !noTrimWhitespacesArroundElements.has(prevNode.tag)) {
139
+ text = text.trimStart();
140
+ } else {
141
+ // previous node is a "no trim whitespaces arround element"
142
+ if (// but previous node ends with a whitespace
143
+ typeof prevNode === 'object' && prevNode.content) {
144
+ const prevNodeLastContent = prevNode.content[prevNode.content.length - 1];
145
+ if (typeof prevNodeLastContent === 'string' && endsWithWhitespacePattern.test(prevNodeLastContent) && (!nextNode // either the current node is the last child of the parent
146
+ || // or the next node starts with a white space
147
+ typeof nextNode === 'object' && nextNode.content && typeof nextNode.content[0] === 'string' && !startsWithWhitespacePattern.test(nextNode.content[0]))) {
148
+ text = text.trimStart();
149
+ }
150
+ }
151
+ }
152
+ if (!nextNode || typeof nextNode === 'object' && nextNode.tag && !noTrimWhitespacesArroundElements.has(nextNode.tag)) {
153
+ text = text.trimEnd();
154
+ }
155
+ } else {
156
+ // now it is a textNode inside a "no trim whitespaces inside elements" node
157
+ if (!prevNode // it the textnode is the first child of the node
158
+ && startsWithWhitespacePattern.test(text[0]) // it starts with white space
159
+ && typeof (parent == null ? void 0 : parent.prevNode) === 'string' // the prev of the node is a textNode as well
160
+ && endsWithWhitespacePattern.test(parent.prevNode[parent.prevNode.length - 1]) // that prev is ends with a white
161
+ ) {
162
+ text = text.trimStart();
163
+ }
164
+ }
165
+ }
166
+ return text;
167
+ }
168
+ const mod = {
169
+ default: collapseWhitespace
170
+ };
171
+
172
+ exports.default = mod;
@@ -0,0 +1,170 @@
1
+ import { isComment } from '../helpers.mjs';
2
+
3
+ const noWhitespaceCollapseElements = new Set([
4
+ 'script',
5
+ 'style',
6
+ 'pre',
7
+ 'textarea'
8
+ ]);
9
+ const noTrimWhitespacesArroundElements = new Set([
10
+ // non-empty tags that will maintain whitespace around them
11
+ 'a',
12
+ 'abbr',
13
+ 'acronym',
14
+ 'b',
15
+ 'bdi',
16
+ 'bdo',
17
+ 'big',
18
+ 'button',
19
+ 'cite',
20
+ 'code',
21
+ 'del',
22
+ 'dfn',
23
+ 'em',
24
+ 'font',
25
+ 'i',
26
+ 'ins',
27
+ 'kbd',
28
+ 'label',
29
+ 'mark',
30
+ 'math',
31
+ 'nobr',
32
+ 'object',
33
+ 'q',
34
+ 'rp',
35
+ 'rt',
36
+ 'rtc',
37
+ 'ruby',
38
+ 's',
39
+ 'samp',
40
+ 'select',
41
+ 'small',
42
+ 'span',
43
+ 'strike',
44
+ 'strong',
45
+ 'sub',
46
+ 'sup',
47
+ 'svg',
48
+ 'textarea',
49
+ 'time',
50
+ 'tt',
51
+ 'u',
52
+ 'var',
53
+ // self-closing tags that will maintain whitespace around them
54
+ 'comment',
55
+ 'img',
56
+ 'input',
57
+ 'wbr'
58
+ ]);
59
+ const noTrimWhitespacesInsideElements = new Set([
60
+ // non-empty tags that will maintain whitespace within them
61
+ 'a',
62
+ 'abbr',
63
+ 'acronym',
64
+ 'b',
65
+ 'big',
66
+ 'del',
67
+ 'em',
68
+ 'font',
69
+ 'i',
70
+ 'ins',
71
+ 'kbd',
72
+ 'mark',
73
+ 'nobr',
74
+ 'rp',
75
+ 's',
76
+ 'samp',
77
+ 'small',
78
+ 'span',
79
+ 'strike',
80
+ 'strong',
81
+ 'sub',
82
+ 'sup',
83
+ 'time',
84
+ 'tt',
85
+ 'u',
86
+ 'var'
87
+ ]);
88
+ const startsWithWhitespacePattern = /^\s/;
89
+ const endsWithWhitespacePattern = /\s$/;
90
+ // See https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace and https://infra.spec.whatwg.org/#ascii-whitespace
91
+ const multipleWhitespacePattern = /[\t\n\f\r ]+/g;
92
+ const NONE = '';
93
+ const SINGLE_SPACE = ' ';
94
+ const validOptions = [
95
+ 'all',
96
+ 'aggressive',
97
+ 'conservative'
98
+ ];
99
+ function collapseWhitespace(tree, options, collapseType, parent) {
100
+ collapseType = validOptions.includes(collapseType) ? collapseType : 'conservative';
101
+ tree.forEach((node, index)=>{
102
+ const prevNode = tree[index - 1];
103
+ const nextNode = tree[index + 1];
104
+ if (typeof node === 'string') {
105
+ const parentNodeTag = parent == null ? void 0 : parent.node.tag;
106
+ const isTopLevel = parentNodeTag == null || parentNodeTag === 'html' || parentNodeTag === 'head';
107
+ const shouldTrim = isTopLevel || collapseType === 'all' || collapseType === 'aggressive';
108
+ node = collapseRedundantWhitespaces(node, collapseType, shouldTrim, parent, prevNode, nextNode);
109
+ } else if (node.tag) {
110
+ var _node_content;
111
+ const isAllowCollapseWhitespace = !noWhitespaceCollapseElements.has(node.tag);
112
+ if (isAllowCollapseWhitespace && ((_node_content = node.content) == null ? void 0 : _node_content.length)) {
113
+ node.content = collapseWhitespace(node.content, options, collapseType, {
114
+ node,
115
+ prevNode});
116
+ }
117
+ }
118
+ tree[index] = node;
119
+ });
120
+ return tree;
121
+ }
122
+ function collapseRedundantWhitespaces(text, collapseType, shouldTrim = false, parent, prevNode, nextNode) {
123
+ if (!text || text.length === 0) {
124
+ return NONE;
125
+ }
126
+ if (!isComment(text)) {
127
+ text = text.replace(multipleWhitespacePattern, SINGLE_SPACE);
128
+ }
129
+ if (shouldTrim) {
130
+ // either all or top level, trim all
131
+ if (collapseType === 'all' || collapseType === 'conservative') {
132
+ return text.trim();
133
+ }
134
+ if (typeof parent !== 'object' || !(parent == null ? void 0 : parent.node.tag) || !noTrimWhitespacesInsideElements.has(parent.node.tag)) {
135
+ if (// It is the first child node of the parent
136
+ !prevNode || typeof prevNode === 'object' && prevNode.tag && !noTrimWhitespacesArroundElements.has(prevNode.tag)) {
137
+ text = text.trimStart();
138
+ } else {
139
+ // previous node is a "no trim whitespaces arround element"
140
+ if (// but previous node ends with a whitespace
141
+ typeof prevNode === 'object' && prevNode.content) {
142
+ const prevNodeLastContent = prevNode.content[prevNode.content.length - 1];
143
+ if (typeof prevNodeLastContent === 'string' && endsWithWhitespacePattern.test(prevNodeLastContent) && (!nextNode // either the current node is the last child of the parent
144
+ || // or the next node starts with a white space
145
+ typeof nextNode === 'object' && nextNode.content && typeof nextNode.content[0] === 'string' && !startsWithWhitespacePattern.test(nextNode.content[0]))) {
146
+ text = text.trimStart();
147
+ }
148
+ }
149
+ }
150
+ if (!nextNode || typeof nextNode === 'object' && nextNode.tag && !noTrimWhitespacesArroundElements.has(nextNode.tag)) {
151
+ text = text.trimEnd();
152
+ }
153
+ } else {
154
+ // now it is a textNode inside a "no trim whitespaces inside elements" node
155
+ if (!prevNode // it the textnode is the first child of the node
156
+ && startsWithWhitespacePattern.test(text[0]) // it starts with white space
157
+ && typeof (parent == null ? void 0 : parent.prevNode) === 'string' // the prev of the node is a textNode as well
158
+ && endsWithWhitespacePattern.test(parent.prevNode[parent.prevNode.length - 1]) // that prev is ends with a white
159
+ ) {
160
+ text = text.trimStart();
161
+ }
162
+ }
163
+ }
164
+ return text;
165
+ }
166
+ const mod = {
167
+ default: collapseWhitespace
168
+ };
169
+
170
+ export { mod as default };
@@ -0,0 +1,57 @@
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
+ type CustomModule = (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>) => PostHTMLTreeLike;
55
+ declare const mod: HtmlnanoModule<CustomModule[]>;
56
+
57
+ export { mod as default };