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
package/lib/htmlnano.mjs DELETED
@@ -1,198 +0,0 @@
1
- import posthtml from 'posthtml';
2
- import { cosmiconfigSync } from 'cosmiconfig';
3
- import safePreset from './presets/safe.mjs';
4
- import ampSafePreset from './presets/ampSafe.mjs';
5
- import maxPreset from './presets/max.mjs';
6
-
7
- const presets = {
8
- safe: safePreset,
9
- ampSafe: ampSafePreset,
10
- max: maxPreset,
11
- };
12
-
13
- export function loadConfig(options, preset, configPath) {
14
- let { skipConfigLoading = false, ...rest } = options || {};
15
-
16
- if (!skipConfigLoading) {
17
- const explorer = cosmiconfigSync('htmlnano');
18
- const rc = configPath ? explorer.load(configPath) : explorer.search();
19
- if (rc) {
20
- const { preset: presetName } = rc.config;
21
- if (presetName) {
22
- if (!preset && presets[presetName]) {
23
- preset = presets[presetName];
24
- }
25
-
26
- delete rc.config.preset;
27
- }
28
-
29
- if (!options) {
30
- rest = rc.config;
31
- }
32
- }
33
- }
34
-
35
- return [
36
- rest || {},
37
- preset || safePreset,
38
- ];
39
- }
40
-
41
- const optionalDependencies = {
42
- minifyCss: ['cssnano', 'postcss'],
43
- minifyJs: ['terser'],
44
- minifyUrl: ['relateurl', 'srcset', 'terser'],
45
- minifySvg: ['svgo'],
46
- };
47
-
48
-
49
- const modules = {
50
- collapseAttributeWhitespace: () => import('./modules/collapseAttributeWhitespace.mjs'),
51
- collapseBooleanAttributes: () => import('./modules/collapseBooleanAttributes.mjs'),
52
- collapseWhitespace: () => import('./modules/collapseWhitespace.mjs'),
53
- custom: () => import('./modules/custom.mjs'),
54
- deduplicateAttributeValues: () => import('./modules/deduplicateAttributeValues.mjs'),
55
- example: () => import('./modules/example.mjs'),
56
- mergeScripts: () => import('./modules/mergeScripts.mjs'),
57
- mergeStyles: () => import('./modules/mergeStyles.mjs'),
58
- minifyConditionalComments: () => import('./modules/minifyConditionalComments.mjs'),
59
- minifyCss: () => import('./modules/minifyCss.mjs'),
60
- minifyJs: () => import('./modules/minifyJs.mjs'),
61
- minifyJson: () => import('./modules/minifyJson.mjs'),
62
- minifySvg: () => import('./modules/minifySvg.mjs'),
63
- minifyUrls: () => import('./modules/minifyUrls.mjs'),
64
- normalizeAttributeValues: () => import('./modules/normalizeAttributeValues.mjs'),
65
- removeAttributeQuotes: () => import('./modules/removeAttributeQuotes.mjs'),
66
- removeComments: () => import('./modules/removeComments.mjs'),
67
- removeEmptyAttributes: () => import('./modules/removeEmptyAttributes.mjs'),
68
- removeOptionalTags: () => import('./modules/removeOptionalTags.mjs'),
69
- removeRedundantAttributes: () => import('./modules/removeRedundantAttributes.mjs'),
70
- removeUnusedCss: () => import('./modules/removeUnusedCss.mjs'),
71
- sortAttributes: () => import('./modules/sortAttributes.mjs'),
72
- sortAttributesWithLists: () => import('./modules/sortAttributesWithLists.mjs'),
73
- };
74
-
75
- function htmlnano(optionsRun, presetRun) {
76
- let [options, preset] = loadConfig(optionsRun, presetRun);
77
-
78
- return async function minifier(tree) {
79
- const nodeHandlers = [];
80
- const attrsHandlers = [];
81
- const contentsHandlers = [];
82
-
83
- options = { ...preset, ...options };
84
- let promise = Promise.resolve(tree);
85
-
86
- for (const [moduleName, moduleOptions] of Object.entries(options)) {
87
- if (!moduleOptions) {
88
- // The module is disabled
89
- continue;
90
- }
91
-
92
- if (safePreset[moduleName] === undefined) {
93
- throw new Error('Module "' + moduleName + '" is not defined');
94
- }
95
-
96
- (optionalDependencies[moduleName] || []).forEach(async dependency => {
97
- try {
98
- await import(dependency);
99
- } catch (e) {
100
- if (e.code === 'MODULE_NOT_FOUND' || e.code === 'ERR_MODULE_NOT_FOUND') {
101
- if (!options.skipInternalWarnings){
102
- console.warn(`You have to install "${dependency}" in order to use htmlnano's "${moduleName}" module`);
103
- }
104
- } else {
105
- throw e;
106
- }
107
- }
108
- });
109
-
110
- const module = moduleName in modules ?
111
- await (modules[moduleName]()) :
112
- await import(`./modules/${moduleName}.mjs`);
113
-
114
- if (typeof module.onAttrs === 'function') {
115
- attrsHandlers.push(module.onAttrs(options, moduleOptions));
116
- }
117
- if (typeof module.onContent === 'function') {
118
- contentsHandlers.push(module.onContent(options, moduleOptions));
119
- }
120
- if (typeof module.onNode === 'function') {
121
- nodeHandlers.push(module.onNode(options, moduleOptions));
122
- }
123
- if (typeof module.default === 'function') {
124
- promise = promise.then(async tree => await module.default(tree, options, moduleOptions));
125
- }
126
- }
127
-
128
- if (attrsHandlers.length + contentsHandlers.length + nodeHandlers.length === 0) {
129
- return promise;
130
- }
131
-
132
- return promise.then(tree => {
133
- tree.walk(node => {
134
- if (node) {
135
- if (node.attrs && typeof node.attrs === 'object') {
136
- // Convert all attrs' key to lower case
137
- let newAttrsObj = {};
138
- Object.entries(node.attrs).forEach(([attrName, attrValue]) => {
139
- newAttrsObj[attrName.toLowerCase()] = attrValue;
140
- });
141
-
142
- for (const handler of attrsHandlers) {
143
- newAttrsObj = handler(newAttrsObj, node);
144
- }
145
-
146
- node.attrs = newAttrsObj;
147
- }
148
-
149
- if (node.content) {
150
- node.content = typeof node.content === 'string' ? [node.content] : node.content;
151
-
152
- if (Array.isArray(node.content) && node.content.length > 0) {
153
- for (const handler of contentsHandlers) {
154
- const result = handler(node.content, node);
155
- node.content = typeof result === 'string' ? [result] : result;
156
- }
157
- }
158
- }
159
-
160
- for (const handler of nodeHandlers) {
161
- node = handler(node);
162
- }
163
- }
164
-
165
- return node;
166
- });
167
-
168
- return tree;
169
- });
170
- };
171
- }
172
-
173
- htmlnano.getRequiredOptionalDependencies = function (optionsRun, presetRun) {
174
- const [options] = loadConfig(optionsRun, presetRun);
175
-
176
- return [...new Set(Object.keys(options).filter(moduleName => options[moduleName]).map(moduleName => optionalDependencies[moduleName]).flat())];
177
- };
178
-
179
-
180
- htmlnano.process = function (html, options, preset, postHtmlOptions) {
181
- return posthtml([htmlnano(options, preset)])
182
- .process(html, postHtmlOptions);
183
- };
184
-
185
- // https://github.com/webpack-contrib/html-minimizer-webpack-plugin/blob/faca00f2219514bc671c5942685721f0b5dbaa70/src/utils.js#L74
186
- htmlnano.htmlMinimizerWebpackPluginMinify = function htmlNano(input, minimizerOptions = {}) {
187
- const [[, code]] = Object.entries(input);
188
- return htmlnano.process(code, minimizerOptions, presets.safe)
189
- .then(result => {
190
- return {
191
- code: result.html
192
- };
193
- });
194
- };
195
-
196
- htmlnano.presets = presets;
197
-
198
- export default htmlnano;
@@ -1,86 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.attributesWithLists = void 0;
7
- exports.onAttrs = onAttrs;
8
- var _helpers = require("../helpers.cjs");
9
- const attributesWithLists = exports.attributesWithLists = new Set(['class', 'dropzone', 'rel',
10
- // a, area, link
11
- 'ping',
12
- // a, area
13
- 'sandbox',
14
- // iframe
15
- /**
16
- * https://github.com/posthtml/htmlnano/issues/180
17
- * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-sizes
18
- *
19
- * "sizes" of <img> should not be modified, while "sizes" of <link> will only have one entry in most cases.
20
- */
21
- // 'sizes', // link
22
- 'headers' // td, th
23
- ]);
24
-
25
- /** @type Record<string, string[] | null> */
26
- const attributesWithSingleValue = {
27
- accept: ['input'],
28
- action: ['form'],
29
- accesskey: null,
30
- 'accept-charset': ['form'],
31
- cite: ['blockquote', 'del', 'ins', 'q'],
32
- cols: ['textarea'],
33
- colspan: ['td', 'th'],
34
- data: ['object'],
35
- dropzone: null,
36
- formaction: ['button', 'input'],
37
- height: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
38
- high: ['meter'],
39
- href: ['a', 'area', 'base', 'link'],
40
- itemid: null,
41
- low: ['meter'],
42
- manifest: ['html'],
43
- max: ['meter', 'progress'],
44
- maxlength: ['input', 'textarea'],
45
- media: ['source'],
46
- min: ['meter'],
47
- minlength: ['input', 'textarea'],
48
- optimum: ['meter'],
49
- ping: ['a', 'area'],
50
- poster: ['video'],
51
- profile: ['head'],
52
- rows: ['textarea'],
53
- rowspan: ['td', 'th'],
54
- size: ['input', 'select'],
55
- span: ['col', 'colgroup'],
56
- src: ['audio', 'embed', 'iframe', 'img', 'input', 'script', 'source', 'track', 'video'],
57
- start: ['ol'],
58
- step: ['input'],
59
- style: null,
60
- tabindex: null,
61
- usemap: ['img', 'object'],
62
- value: ['li', 'meter', 'progress'],
63
- width: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video']
64
- };
65
-
66
- /** Collapse whitespaces inside list-like attributes (e.g. class, rel) */
67
- function onAttrs() {
68
- return (attrs, node) => {
69
- const newAttrs = attrs;
70
- Object.entries(attrs).forEach(([attrName, attrValue]) => {
71
- if (typeof attrValue !== 'string') return;
72
- if (attributesWithLists.has(attrName)) {
73
- const newAttrValue = attrValue.replace(/\s+/g, ' ').trim();
74
- newAttrs[attrName] = newAttrValue;
75
- return;
76
- }
77
- if ((0, _helpers.isEventHandler)(attrName) || Object.prototype.hasOwnProperty.call(attributesWithSingleValue, attrName) && (attributesWithSingleValue[attrName] === null || attributesWithSingleValue[attrName].includes(node.tag))) {
78
- newAttrs[attrName] = minifySingleAttributeValue(attrValue);
79
- }
80
- });
81
- return newAttrs;
82
- };
83
- }
84
- function minifySingleAttributeValue(value) {
85
- return typeof value === 'string' ? value.trim() : value;
86
- }
@@ -1,104 +0,0 @@
1
- import { isEventHandler } from '../helpers.mjs';
2
-
3
- export const attributesWithLists = new Set([
4
- 'class',
5
- 'dropzone',
6
- 'rel', // a, area, link
7
- 'ping', // a, area
8
- 'sandbox', // iframe
9
- /**
10
- * https://github.com/posthtml/htmlnano/issues/180
11
- * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-sizes
12
- *
13
- * "sizes" of <img> should not be modified, while "sizes" of <link> will only have one entry in most cases.
14
- */
15
- // 'sizes', // link
16
- 'headers' // td, th
17
- ]);
18
-
19
- /** @type Record<string, string[] | null> */
20
- const attributesWithSingleValue = {
21
- accept: ['input'],
22
- action: ['form'],
23
- accesskey: null,
24
- 'accept-charset': ['form'],
25
- cite: ['blockquote', 'del', 'ins', 'q'],
26
- cols: ['textarea'],
27
- colspan: ['td', 'th'],
28
- data: ['object'],
29
- dropzone: null,
30
- formaction: ['button', 'input'],
31
- height: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
32
- high: ['meter'],
33
- href: ['a', 'area', 'base', 'link'],
34
- itemid: null,
35
- low: ['meter'],
36
- manifest: ['html'],
37
- max: ['meter', 'progress'],
38
- maxlength: ['input', 'textarea'],
39
- media: ['source'],
40
- min: ['meter'],
41
- minlength: ['input', 'textarea'],
42
- optimum: ['meter'],
43
- ping: ['a', 'area'],
44
- poster: ['video'],
45
- profile: ['head'],
46
- rows: ['textarea'],
47
- rowspan: ['td', 'th'],
48
- size: ['input', 'select'],
49
- span: ['col', 'colgroup'],
50
- src: [
51
- 'audio',
52
- 'embed',
53
- 'iframe',
54
- 'img',
55
- 'input',
56
- 'script',
57
- 'source',
58
- 'track',
59
- 'video'
60
- ],
61
- start: ['ol'],
62
- step: ['input'],
63
- style: null,
64
- tabindex: null,
65
- usemap: ['img', 'object'],
66
- value: ['li', 'meter', 'progress'],
67
- width: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video']
68
- };
69
-
70
- /** Collapse whitespaces inside list-like attributes (e.g. class, rel) */
71
- export function onAttrs() {
72
- return (attrs, node) => {
73
- const newAttrs = attrs;
74
-
75
- Object.entries(attrs).forEach(([attrName, attrValue]) => {
76
- if (typeof attrValue !== 'string') return;
77
-
78
- if (attributesWithLists.has(attrName)) {
79
- const newAttrValue = attrValue.replace(/\s+/g, ' ').trim();
80
- newAttrs[attrName] = newAttrValue;
81
- return;
82
- }
83
-
84
- if (
85
- isEventHandler(attrName)
86
- || (
87
- Object.prototype.hasOwnProperty.call(attributesWithSingleValue, attrName)
88
- && (
89
- attributesWithSingleValue[attrName] === null
90
- || attributesWithSingleValue[attrName].includes(node.tag)
91
- )
92
- )
93
- ) {
94
- newAttrs[attrName] = minifySingleAttributeValue(attrValue);
95
- }
96
- });
97
-
98
- return newAttrs;
99
- };
100
- }
101
-
102
- function minifySingleAttributeValue(value) {
103
- return typeof value === 'string' ? value.trim() : value;
104
- }
@@ -1,62 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.onAttrs = onAttrs;
7
- // Source: https://github.com/kangax/html-minifier/issues/63
8
- // https://html.spec.whatwg.org/#boolean-attribute
9
- // https://html.spec.whatwg.org/#attributes-1
10
- const htmlBooleanAttributes = new Set(['allowfullscreen', 'allowpaymentrequest', 'allowtransparency', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', 'default', 'defaultchecked', 'defaultmuted', 'defaultselected', 'defer', 'disabled', 'enabled', 'formnovalidate', 'hidden', 'indeterminate', 'inert', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nohref', 'nomodule', 'noresize', 'noshade', 'novalidate', 'nowrap', 'open', 'pauseonexit', 'playsinline', 'readonly', 'required', 'reversed', 'scoped', 'seamless', 'selected', 'sortable', 'truespeed', 'typemustmatch', 'visible']);
11
- const amphtmlBooleanAttributes = new Set(['⚡', 'amp', '⚡4ads', 'amp4ads', '⚡4email', 'amp4email', 'amp-custom', 'amp-boilerplate', 'amp4ads-boilerplate', 'amp4email-boilerplate', 'allow-blocked-ranges', 'amp-access-hide', 'amp-access-template', 'amp-keyframes', 'animate', 'arrows', 'data-block-on-consent', 'data-enable-refresh', 'data-multi-size', 'date-template', 'disable-double-tap', 'disable-session-states', 'disableremoteplayback', 'dots', 'expand-single-section', 'expanded', 'fallback', 'first', 'fullscreen', 'inline', 'lightbox', 'noaudio', 'noautoplay', 'noloading', 'once', 'open-after-clear', 'open-after-select', 'open-button', 'placeholder', 'preload', 'reset-on-refresh', 'reset-on-resize', 'resizable', 'rotate-to-fullscreen', 'second', 'standalone', 'stereo', 'submit-error', 'submit-success', 'submitting', 'subscriptions-actions', 'subscriptions-dialog']);
12
- const missingValueDefaultEmptyStringAttributes = {
13
- // https://html.spec.whatwg.org/#attr-media-preload
14
- audio: {
15
- preload: 'auto'
16
- },
17
- video: {
18
- preload: 'auto'
19
- }
20
- };
21
- const tagsHasMissingValueDefaultEmptyStringAttributes = new Set(Object.keys(missingValueDefaultEmptyStringAttributes));
22
- function onAttrs(options, moduleOptions) {
23
- return (attrs, node) => {
24
- if (!node.tag) return attrs;
25
- const newAttrs = attrs;
26
- if (tagsHasMissingValueDefaultEmptyStringAttributes.has(node.tag)) {
27
- const tagAttributesCanBeReplacedWithEmptyString = missingValueDefaultEmptyStringAttributes[node.tag];
28
- for (const attributesCanBeReplacedWithEmptyString of Object.keys(tagAttributesCanBeReplacedWithEmptyString)) {
29
- if (Object.prototype.hasOwnProperty.call(attrs, attributesCanBeReplacedWithEmptyString) && attrs[attributesCanBeReplacedWithEmptyString] === tagAttributesCanBeReplacedWithEmptyString[attributesCanBeReplacedWithEmptyString]) {
30
- attrs[attributesCanBeReplacedWithEmptyString] = true;
31
- }
32
- }
33
- }
34
- for (const attrName of Object.keys(attrs)) {
35
- if (attrName === 'visible' && node.tag.startsWith('a-')) {
36
- continue;
37
- }
38
- if (htmlBooleanAttributes.has(attrName)) {
39
- newAttrs[attrName] = true;
40
- }
41
-
42
- // Fast path optimization.
43
- // The rest of tranformations are only for string type attrValue.
44
- if (typeof newAttrs[attrName] !== 'string') continue;
45
- if (moduleOptions.amphtml && amphtmlBooleanAttributes.has(attrName) && attrs[attrName] === '') {
46
- newAttrs[attrName] = true;
47
- }
48
- // https://html.spec.whatwg.org/#a-quick-introduction-to-html
49
- // The value, along with the "=" character, can be omitted altogether if the value is the empty string.
50
- if (attrs[attrName] === '') {
51
- newAttrs[attrName] = true;
52
- }
53
-
54
- // collapse crossorigin attributes
55
- // Specification: https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
56
- if (attrName.toLowerCase() === 'crossorigin' && attrs[attrName] === 'anonymous') {
57
- newAttrs[attrName] = true;
58
- }
59
- }
60
- return newAttrs;
61
- };
62
- }
@@ -1,100 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = collapseWhitespace;
7
- var _helpers = require("../helpers.cjs");
8
- const noWhitespaceCollapseElements = new Set(['script', 'style', 'pre', 'textarea']);
9
- const noTrimWhitespacesArroundElements = new Set([
10
- // non-empty tags that will maintain whitespace around them
11
- 'a', 'abbr', 'acronym', 'b', 'bdi', 'bdo', 'big', 'button', 'cite', 'code', 'del', 'dfn', 'em', 'font', 'i', 'ins', 'kbd', 'label', 'mark', 'math', 'nobr', 'object', 'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'svg', 'textarea', 'time', 'tt', 'u', 'var',
12
- // self-closing tags that will maintain whitespace around them
13
- 'comment', 'img', 'input', 'wbr']);
14
- const noTrimWhitespacesInsideElements = new Set([
15
- // non-empty tags that will maintain whitespace within them
16
- 'a', 'abbr', 'acronym', 'b', 'big', 'del', 'em', 'font', 'i', 'ins', 'kbd', 'mark', 'nobr', 'rp', 's', 'samp', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'time', 'tt', 'u', 'var']);
17
- const startsWithWhitespacePattern = /^\s/;
18
- const endsWithWhitespacePattern = /\s$/;
19
- // See https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace and https://infra.spec.whatwg.org/#ascii-whitespace
20
- const multipleWhitespacePattern = /[\t\n\f\r ]+/g;
21
- const NONE = '';
22
- const SINGLE_SPACE = ' ';
23
- const validOptions = ['all', 'aggressive', 'conservative'];
24
-
25
- /** Collapses redundant whitespaces */
26
- function collapseWhitespace(tree, options, collapseType, parent) {
27
- collapseType = validOptions.includes(collapseType) ? collapseType : 'conservative';
28
- tree.forEach((node, index) => {
29
- const prevNode = tree[index - 1];
30
- const nextNode = tree[index + 1];
31
- if (typeof node === 'string') {
32
- const parentNodeTag = parent && parent.node && parent.node.tag;
33
- const isTopLevel = !parentNodeTag || parentNodeTag === 'html' || parentNodeTag === 'head';
34
- const shouldTrim = collapseType === 'all' || isTopLevel ||
35
- /*
36
- * When collapseType is set to 'aggressive', and the tag is not inside 'noTrimWhitespacesInsideElements'.
37
- * the first & last space inside the tag will be trimmed
38
- */
39
- collapseType === 'aggressive';
40
- node = collapseRedundantWhitespaces(node, collapseType, shouldTrim, parent, prevNode, nextNode);
41
- }
42
- const isAllowCollapseWhitespace = !noWhitespaceCollapseElements.has(node.tag);
43
- if (node.content && node.content.length && isAllowCollapseWhitespace) {
44
- node.content = collapseWhitespace(node.content, options, collapseType, {
45
- node,
46
- prevNode,
47
- nextNode
48
- });
49
- }
50
- tree[index] = node;
51
- });
52
- return tree;
53
- }
54
- function collapseRedundantWhitespaces(text, collapseType, shouldTrim = false, parent, prevNode, nextNode) {
55
- if (!text || text.length === 0) {
56
- return NONE;
57
- }
58
- if (!(0, _helpers.isComment)(text)) {
59
- text = text.replace(multipleWhitespacePattern, SINGLE_SPACE);
60
- }
61
- if (shouldTrim) {
62
- if (collapseType === 'aggressive') {
63
- if (!noTrimWhitespacesInsideElements.has(parent && parent.node && parent.node.tag)) {
64
- if (
65
- // It is the first child node of the parent
66
- !prevNode
67
- // It is not the first child node, and prevNode not a text node, and prevNode is safe to trim around
68
- || prevNode && prevNode.tag && !noTrimWhitespacesArroundElements.has(prevNode.tag)) {
69
- text = text.trimStart();
70
- } else {
71
- // previous node is a "no trim whitespaces arround element"
72
- if (
73
- // but previous node ends with a whitespace
74
- prevNode && prevNode.content && prevNode.content.length && endsWithWhitespacePattern.test(prevNode.content[prevNode.content.length - 1]) && (!nextNode // either the current node is the last child of the parent
75
- ||
76
- // or the next node starts with a white space
77
- nextNode && nextNode.content && nextNode.content.length && !startsWithWhitespacePattern.test(nextNode.content[0]))) {
78
- text = text.trimStart();
79
- }
80
- }
81
- if (!nextNode || nextNode && nextNode.tag && !noTrimWhitespacesArroundElements.has(nextNode.tag)) {
82
- text = text.trimEnd();
83
- }
84
- } else {
85
- // now it is a textNode inside a "no trim whitespaces inside elements" node
86
- if (!prevNode // it the textnode is the first child of the node
87
- && startsWithWhitespacePattern.test(text[0]) // it starts with white space
88
- && typeof parent.prevNode === 'string' // the prev of the node is a textNode as well
89
- && endsWithWhitespacePattern.test(parent.prevNode[parent.prevNode.length - 1]) // that prev is ends with a white
90
- ) {
91
- text = text.trimStart();
92
- }
93
- }
94
- } else {
95
- // collapseType is 'all', trim spaces
96
- text = text.trim();
97
- }
98
- }
99
- return text;
100
- }