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
@@ -1,229 +0,0 @@
1
- import { optionalImport } from '../helpers.mjs';
2
-
3
- // Adopts from https://github.com/kangax/html-minifier/blob/51ce10f4daedb1de483ffbcccecc41be1c873da2/src/htmlminifier.js#L209-L221
4
- const tagsHaveUriValuesForAttributes = new Set([
5
- 'a',
6
- 'area',
7
- 'link',
8
- 'base',
9
- 'object',
10
- 'blockquote',
11
- 'q',
12
- 'del',
13
- 'ins',
14
- 'form',
15
- 'input',
16
- 'head',
17
- 'audio',
18
- 'embed',
19
- 'iframe',
20
- 'img',
21
- 'script',
22
- 'track',
23
- 'video',
24
- ]);
25
-
26
- const tagsHasHrefAttributes = new Set([
27
- 'a',
28
- 'area',
29
- 'link',
30
- 'base'
31
- ]);
32
-
33
- const attributesOfImgTagHasUriValues = new Set([
34
- 'src',
35
- 'longdesc',
36
- 'usemap'
37
- ]);
38
-
39
- const attributesOfObjectTagHasUriValues = new Set([
40
- 'classid',
41
- 'codebase',
42
- 'data',
43
- 'usemap'
44
- ]);
45
-
46
- const tagsHasCiteAttributes = new Set([
47
- 'blockquote',
48
- 'q',
49
- 'ins',
50
- 'del'
51
- ]);
52
-
53
- const tagsHasSrcAttributes = new Set([
54
- 'audio',
55
- 'embed',
56
- 'iframe',
57
- 'img',
58
- 'input',
59
- 'script',
60
- 'track',
61
- 'video',
62
- /**
63
- * https://html.spec.whatwg.org/#attr-source-src
64
- *
65
- * Although most of browsers recommend not to use "src" in <source>,
66
- * but technically it does comply with HTML Standard.
67
- */
68
- 'source'
69
- ]);
70
-
71
- const isUriTypeAttribute = (tag, attr) => {
72
- return (
73
- tagsHasHrefAttributes.has(tag) && attr === 'href' ||
74
- tag === 'img' && attributesOfImgTagHasUriValues.has(attr) ||
75
- tag === 'object' && attributesOfObjectTagHasUriValues.has(attr) ||
76
- tagsHasCiteAttributes.has(tag) && attr === 'cite' ||
77
- tag === 'form' && attr === 'action' ||
78
- tag === 'input' && attr === 'usemap' ||
79
- tag === 'head' && attr === 'profile' ||
80
- tag === 'script' && attr === 'for' ||
81
- tagsHasSrcAttributes.has(tag) && attr === 'src'
82
- );
83
- };
84
-
85
- const isSrcsetAttribute = (tag, attr) => {
86
- return (
87
- tag === 'source' && attr === 'srcset' ||
88
- tag === 'img' && attr === 'srcset' ||
89
- tag === 'link' && attr === 'imagesrcset'
90
- );
91
- };
92
-
93
- const processModuleOptions = options => {
94
- // FIXME!
95
- // relateurl@1.0.0-alpha only supports URL while stable version (0.2.7) only supports string
96
- // should convert input into URL instance after relateurl@1 is stable
97
- if (typeof options === 'string') return options;
98
- if (options instanceof URL) return options.toString();
99
-
100
- return false;
101
- };
102
-
103
- const isLinkRelCanonical = ({ tag, attrs }) => {
104
- // Return false early for non-"link" tag
105
- if (tag !== 'link') return false;
106
-
107
- for (const [attrName, attrValue] of Object.entries(attrs)) {
108
- if (attrName.toLowerCase() === 'rel' && attrValue === 'canonical') return true;
109
- }
110
-
111
- return false;
112
- };
113
-
114
- const JAVASCRIPT_URL_PROTOCOL = 'javascript:';
115
-
116
- let relateUrlInstance;
117
- let STORED_URL_BASE;
118
-
119
- /** Convert absolute url into relative url */
120
- export default async function minifyUrls(tree, options, moduleOptions) {
121
- const RelateUrl = await optionalImport('relateurl');
122
- const srcset = await optionalImport('srcset');
123
- const terser = await optionalImport('terser');
124
-
125
- let promises = [];
126
-
127
- const urlBase = processModuleOptions(moduleOptions);
128
-
129
- // Invalid configuration, return tree directly
130
- if (!urlBase) return tree;
131
-
132
- /** Bring up a reusable RelateUrl instances (only once)
133
- *
134
- * STORED_URL_BASE is used to invalidate RelateUrl instances,
135
- * avoiding require.cache acrossing multiple htmlnano instance with different configuration,
136
- * e.g. unit tests cases.
137
- */
138
- if (!relateUrlInstance || STORED_URL_BASE !== urlBase) {
139
- if (RelateUrl) {
140
- relateUrlInstance = new RelateUrl(urlBase);
141
- }
142
- STORED_URL_BASE = urlBase;
143
- }
144
-
145
- tree.walk(node => {
146
- if (!node.attrs) return node;
147
-
148
- if (!node.tag) return node;
149
-
150
- if (!tagsHaveUriValuesForAttributes.has(node.tag)) return node;
151
-
152
- // Prevent link[rel=canonical] being processed
153
- // Can't be excluded by isUriTypeAttribute()
154
- if (isLinkRelCanonical(node)) return node;
155
-
156
- for (const [attrName, attrValue] of Object.entries(node.attrs)) {
157
- const attrNameLower = attrName.toLowerCase();
158
-
159
- if (isUriTypeAttribute(node.tag, attrNameLower)) {
160
- if (isJavaScriptUrl(attrValue)) {
161
- promises.push(minifyJavaScriptUrl(node, attrName, terser));
162
- } else {
163
- if (relateUrlInstance) {
164
- // FIXME!
165
- // relateurl@1.0.0-alpha only supports URL while stable version (0.2.7) only supports string
166
- // the WHATWG URL API is very strict while attrValue might not be a valid URL
167
- // new URL should be used, and relateUrl#relate should be wrapped in try...catch after relateurl@1 is stable
168
- node.attrs[attrName] = relateUrlInstance.relate(attrValue);
169
- }
170
- }
171
-
172
- continue;
173
- }
174
-
175
- if (isSrcsetAttribute(node.tag, attrNameLower)) {
176
- if (srcset) {
177
- try {
178
- const parsedSrcset = srcset.parseSrcset(attrValue, { strict: true });
179
-
180
- node.attrs[attrName] = srcset.stringifySrcset(parsedSrcset.map(item => {
181
- if (relateUrlInstance) {
182
- item.url = relateUrlInstance.relate(item.url);
183
- }
184
-
185
- return item;
186
- }));
187
- } catch (e) {
188
- // srcset will throw an Error for invalid srcset.
189
- }
190
- }
191
-
192
- continue;
193
- }
194
- }
195
-
196
- return node;
197
- });
198
-
199
- if (promises.length > 0) return Promise.all(promises).then(() => tree);
200
- return Promise.resolve(tree);
201
- }
202
-
203
- function isJavaScriptUrl(url) {
204
- return typeof url === 'string' && url.toLowerCase().startsWith(JAVASCRIPT_URL_PROTOCOL);
205
- }
206
-
207
- const jsWrapperStart = 'function a(){';
208
- const jsWrapperEnd = '}a();';
209
-
210
- function minifyJavaScriptUrl(node, attrName, terser) {
211
- if (!terser) return Promise.resolve();
212
-
213
- let result = node.attrs[attrName];
214
- if (result) {
215
- result = jsWrapperStart + result.slice(JAVASCRIPT_URL_PROTOCOL.length) + jsWrapperEnd;
216
-
217
- return terser
218
- .minify(result, {}) // Default Option is good enough
219
- .then(({ code }) => {
220
- const minifiedJs = code.substring(
221
- jsWrapperStart.length,
222
- code.length - jsWrapperEnd.length
223
- );
224
- node.attrs[attrName] = JAVASCRIPT_URL_PROTOCOL + minifiedJs;
225
- });
226
- }
227
-
228
- return Promise.resolve();
229
- }
@@ -1,120 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.onAttrs = onAttrs;
7
- const caseInsensitiveAttributes = {
8
- autocomplete: ['form'],
9
- charset: ['meta', 'script'],
10
- contenteditable: null,
11
- crossorigin: ['audio', 'img', 'link', 'script', 'video'],
12
- dir: null,
13
- draggable: null,
14
- dropzone: null,
15
- formmethod: ['button', 'input'],
16
- inputmode: ['input', 'textarea'],
17
- kind: ['track'],
18
- method: ['form'],
19
- preload: ['audio', 'video'],
20
- referrerpolicy: null,
21
- sandbox: ['iframe'],
22
- spellcheck: null,
23
- scope: ['th'],
24
- shape: ['area'],
25
- sizes: ['link'],
26
- step: ['input'],
27
- translate: null,
28
- type: ['a', 'link', 'button', 'embed', 'object', 'script', 'source', 'style', 'input', 'menu', 'menuitem'],
29
- wrap: ['textarea']
30
- };
31
-
32
- // https://html.spec.whatwg.org/#invalid-value-default
33
- /** @typedef { [key: string]: { tag: null | string[], default: string, valid: string[] } } */
34
- const invalidValueDefault = {
35
- crossorigin: {
36
- tag: null,
37
- default: 'anonymous',
38
- valid: ['', 'anonymous', 'use-credentials']
39
- },
40
- // https://html.spec.whatwg.org/#referrer-policy-attributes
41
- // The attribute's invalid value default and missing value default are both the empty string state.
42
- referrerpolicy: {
43
- tag: null,
44
- default: '',
45
- valid: ['', 'url', 'origin', 'no-referrer', 'no-referrer-when-downgrade', 'same-origin', 'origin-when-cross-origin', 'strict-origin-when-cross-origin', 'unsafe-url']
46
- },
47
- // https://html.spec.whatwg.org/#lazy-loading-attributes
48
- loading: {
49
- tag: ['img', 'iframe'],
50
- default: 'eager',
51
- valid: ['lazy', 'eager']
52
- },
53
- // https://html.spec.whatwg.org/#the-img-element
54
- // https://html.spec.whatwg.org/#image-decoding-hint
55
- decoding: {
56
- tag: ['img'],
57
- default: 'auto',
58
- valid: ['auto', 'sync', 'async']
59
- },
60
- // https://html.spec.whatwg.org/#the-track-element
61
- kind: {
62
- tag: ['track'],
63
- default: 'metadata',
64
- valid: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata']
65
- },
66
- type: {
67
- tag: ['button'],
68
- default: 'submit',
69
- valid: ['submit', 'reset', 'button']
70
- },
71
- wrap: {
72
- tag: ['textarea'],
73
- default: 'soft',
74
- valid: ['soft', 'hard']
75
- },
76
- // https://html.spec.whatwg.org/#the-hidden-attribute
77
- hidden: {
78
- tag: null,
79
- default: 'hidden',
80
- valid: ['hidden', 'until-found']
81
- },
82
- // https://html.spec.whatwg.org/#autocapitalization
83
- autocapitalize: {
84
- tag: null,
85
- default: 'sentences',
86
- valid: ['none', 'off', 'on', 'sentences', 'words', 'characters']
87
- },
88
- // https://html.spec.whatwg.org/#the-marquee-element
89
- behavior: {
90
- tag: ['marquee'],
91
- default: 'scroll',
92
- valid: ['scroll', 'slide', 'alternate']
93
- },
94
- direction: {
95
- tag: ['marquee'],
96
- default: 'left',
97
- valid: ['left', 'right', 'up', 'down']
98
- }
99
- };
100
- function onAttrs() {
101
- return (attrs, node) => {
102
- const newAttrs = attrs;
103
- Object.entries(attrs).forEach(([attrName, attrValue]) => {
104
- let newAttrValue = attrValue;
105
- if (Object.hasOwnProperty.call(caseInsensitiveAttributes, attrName) && (caseInsensitiveAttributes[attrName] === null || caseInsensitiveAttributes[attrName].includes(node.tag))) {
106
- newAttrValue = typeof attrValue.toLowerCase === 'function' ? attrValue.toLowerCase() : attrValue;
107
- }
108
- if (Object.hasOwnProperty.call(invalidValueDefault, attrName)) {
109
- const meta = invalidValueDefault[attrName];
110
- if (meta.tag === null || node && node.tag && meta.tag.includes(node.tag)) {
111
- if (!meta.valid.includes(newAttrValue)) {
112
- newAttrValue = meta.default;
113
- }
114
- }
115
- }
116
- newAttrs[attrName] = newAttrValue;
117
- });
118
- return newAttrs;
119
- };
120
- }
@@ -1,140 +0,0 @@
1
- const caseInsensitiveAttributes = {
2
- autocomplete: ['form'],
3
- charset: ['meta', 'script'],
4
- contenteditable: null,
5
- crossorigin: ['audio', 'img', 'link', 'script', 'video'],
6
- dir: null,
7
- draggable: null,
8
- dropzone: null,
9
- formmethod: ['button', 'input'],
10
- inputmode: ['input', 'textarea'],
11
- kind: ['track'],
12
- method: ['form'],
13
- preload: ['audio', 'video'],
14
- referrerpolicy: null,
15
- sandbox: ['iframe'],
16
- spellcheck: null,
17
- scope: ['th'],
18
- shape: ['area'],
19
- sizes: ['link'],
20
- step: ['input'],
21
- translate: null,
22
- type: [
23
- 'a',
24
- 'link',
25
- 'button',
26
- 'embed',
27
- 'object',
28
- 'script',
29
- 'source',
30
- 'style',
31
- 'input',
32
- 'menu',
33
- 'menuitem'
34
- ],
35
- wrap: ['textarea']
36
- };
37
-
38
- // https://html.spec.whatwg.org/#invalid-value-default
39
- /** @typedef { [key: string]: { tag: null | string[], default: string, valid: string[] } } */
40
- const invalidValueDefault = {
41
- crossorigin: {
42
- tag: null,
43
- default: 'anonymous',
44
- valid: ['', 'anonymous', 'use-credentials']
45
- },
46
- // https://html.spec.whatwg.org/#referrer-policy-attributes
47
- // The attribute's invalid value default and missing value default are both the empty string state.
48
- referrerpolicy: {
49
- tag: null,
50
- default: '',
51
- valid: ['', 'url', 'origin', 'no-referrer', 'no-referrer-when-downgrade', 'same-origin', 'origin-when-cross-origin', 'strict-origin-when-cross-origin', 'unsafe-url']
52
- },
53
- // https://html.spec.whatwg.org/#lazy-loading-attributes
54
- loading: {
55
- tag: ['img', 'iframe'],
56
- default: 'eager',
57
- valid: ['lazy', 'eager']
58
- },
59
- // https://html.spec.whatwg.org/#the-img-element
60
- // https://html.spec.whatwg.org/#image-decoding-hint
61
- decoding: {
62
- tag: ['img'],
63
- default: 'auto',
64
- valid: ['auto', 'sync', 'async']
65
- },
66
- // https://html.spec.whatwg.org/#the-track-element
67
- kind: {
68
- tag: ['track'],
69
- default: 'metadata',
70
- valid: ['subtitles', 'captions', 'descriptions', 'chapters', 'metadata']
71
- },
72
- type: {
73
- tag: ['button'],
74
- default: 'submit',
75
- valid: ['submit', 'reset', 'button']
76
- },
77
- wrap: {
78
- tag: ['textarea'],
79
- default: 'soft',
80
- valid: ['soft', 'hard']
81
- },
82
- // https://html.spec.whatwg.org/#the-hidden-attribute
83
- hidden: {
84
- tag: null,
85
- default: 'hidden',
86
- valid: ['hidden', 'until-found']
87
- },
88
- // https://html.spec.whatwg.org/#autocapitalization
89
- autocapitalize: {
90
- tag: null,
91
- default: 'sentences',
92
- valid: ['none', 'off', 'on', 'sentences', 'words', 'characters']
93
- },
94
- // https://html.spec.whatwg.org/#the-marquee-element
95
- behavior: {
96
- tag: ['marquee'],
97
- default: 'scroll',
98
- valid: ['scroll', 'slide', 'alternate']
99
- },
100
- direction: {
101
- tag: ['marquee'],
102
- default: 'left',
103
- valid: ['left', 'right', 'up', 'down']
104
- }
105
- };
106
-
107
- export function onAttrs() {
108
- return (attrs, node) => {
109
- const newAttrs = attrs;
110
-
111
- Object.entries(attrs).forEach(([attrName, attrValue]) => {
112
- let newAttrValue = attrValue;
113
-
114
- if (
115
- Object.hasOwnProperty.call(caseInsensitiveAttributes, attrName)
116
- && (
117
- caseInsensitiveAttributes[attrName] === null
118
- || caseInsensitiveAttributes[attrName].includes(node.tag)
119
- )
120
- ) {
121
- newAttrValue = typeof attrValue.toLowerCase === 'function' ? attrValue.toLowerCase() : attrValue;
122
- }
123
-
124
- if (
125
- Object.hasOwnProperty.call(invalidValueDefault, attrName)
126
- ) {
127
- const meta = invalidValueDefault[attrName];
128
- if (meta.tag === null || (node && node.tag && meta.tag.includes(node.tag))) {
129
- if (!meta.valid.includes(newAttrValue)) {
130
- newAttrValue = meta.default;
131
- }
132
- }
133
- }
134
-
135
- newAttrs[attrName] = newAttrValue;
136
- });
137
-
138
- return newAttrs;
139
- };
140
- }
@@ -1,17 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = removeAttributeQuotes;
7
- // Specification: https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
8
- // See also: https://github.com/posthtml/posthtml-render/pull/30
9
- // See also: https://github.com/posthtml/htmlnano/issues/6#issuecomment-707105334
10
-
11
- /** Disable quoteAllAttributes while not overriding the configuration */
12
- function removeAttributeQuotes(tree) {
13
- if (tree.options && typeof tree.options.quoteAllAttributes === 'undefined') {
14
- tree.options.quoteAllAttributes = false;
15
- }
16
- return tree;
17
- }
@@ -1,12 +0,0 @@
1
- // Specification: https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
2
- // See also: https://github.com/posthtml/posthtml-render/pull/30
3
- // See also: https://github.com/posthtml/htmlnano/issues/6#issuecomment-707105334
4
-
5
- /** Disable quoteAllAttributes while not overriding the configuration */
6
- export default function removeAttributeQuotes(tree) {
7
- if (tree.options && typeof tree.options.quoteAllAttributes === 'undefined') {
8
- tree.options.quoteAllAttributes = false;
9
- }
10
-
11
- return tree;
12
- }
@@ -1,86 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.onContent = onContent;
7
- exports.onNode = onNode;
8
- var _helpers = require("../helpers.cjs");
9
- const MATCH_EXCERPT_REGEXP = /<!-- ?more ?-->/i;
10
-
11
- /** Removes HTML comments */
12
- function onNode(options, removeType) {
13
- if (removeType !== 'all' && removeType !== 'safe' && !isMatcher(removeType)) {
14
- removeType = 'safe';
15
- }
16
- return node => {
17
- if (isCommentToRemove(node, removeType)) {
18
- return '';
19
- }
20
- return node;
21
- };
22
- }
23
- function onContent(options, removeType) {
24
- if (removeType !== 'all' && removeType !== 'safe' && !isMatcher(removeType)) {
25
- removeType = 'safe';
26
- }
27
- return contents => {
28
- return contents.filter(content => !isCommentToRemove(content, removeType));
29
- };
30
- }
31
- function isCommentToRemove(text, removeType) {
32
- if (typeof text !== 'string') {
33
- return false;
34
- }
35
- if (!(0, _helpers.isComment)(text)) {
36
- // Not HTML comment
37
- return false;
38
- }
39
- if (removeType === 'safe') {
40
- const isNoindex = text === '<!--noindex-->' || text === '<!--/noindex-->';
41
- // Don't remove noindex comments.
42
- // See: https://yandex.com/support/webmaster/controlling-robot/html.xml
43
- if (isNoindex) {
44
- return false;
45
- }
46
- const isServerSideExclude = text === '<!--sse-->' || text === '<!--/sse-->';
47
- // Don't remove sse comments.
48
- // See: https://support.cloudflare.com/hc/en-us/articles/200170036-What-does-Server-Side-Excludes-SSE-do-
49
- if (isServerSideExclude) {
50
- return false;
51
- }
52
-
53
- // https://en.wikipedia.org/wiki/Conditional_comment
54
- if ((0, _helpers.isConditionalComment)(text)) {
55
- return false;
56
- }
57
-
58
- // Hexo: https://hexo.io/docs/tag-plugins#Post-Excerpt
59
- // Hugo: https://gohugo.io/content-management/summaries/#manual-summary-splitting
60
- // WordPress: https://wordpress.com/support/wordpress-editor/blocks/more-block/2/
61
- // Jekyll: https://jekyllrb.com/docs/posts/#post-excerpts
62
- const isCMSExcerptComment = MATCH_EXCERPT_REGEXP.test(text);
63
- if (isCMSExcerptComment) {
64
- return false;
65
- }
66
- }
67
- if (isMatcher(removeType)) {
68
- return isMatch(text, removeType);
69
- }
70
- return true;
71
- }
72
- function isMatch(input, matcher) {
73
- if (matcher instanceof RegExp) {
74
- return matcher.test(input);
75
- }
76
- if (typeof matcher === 'function') {
77
- return Boolean(matcher(input));
78
- }
79
- return false;
80
- }
81
- function isMatcher(matcher) {
82
- if (matcher instanceof RegExp || typeof matcher === 'function') {
83
- return true;
84
- }
85
- return false;
86
- }
@@ -1,72 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.onAttrs = onAttrs;
7
- var _helpers = require("../helpers.cjs");
8
- const safeToRemoveAttrs = {
9
- id: null,
10
- class: null,
11
- style: null,
12
- title: null,
13
- lang: null,
14
- dir: null,
15
- abbr: ['th'],
16
- accept: ['input'],
17
- 'accept-charset': ['form'],
18
- charset: ['meta', 'script'],
19
- action: ['form'],
20
- cols: ['textarea'],
21
- colspan: ['td', 'th'],
22
- coords: ['area'],
23
- dirname: ['input', 'textarea'],
24
- dropzone: null,
25
- headers: ['td', 'th'],
26
- form: ['button', 'fieldset', 'input', 'keygen', 'object', 'output', 'select', 'textarea'],
27
- formaction: ['button', 'input'],
28
- height: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video'],
29
- high: 'meter',
30
- href: 'link',
31
- list: 'input',
32
- low: 'meter',
33
- manifest: 'html',
34
- max: ['meter', 'progress'],
35
- maxLength: ['input', 'textarea'],
36
- menu: 'button',
37
- min: 'meter',
38
- minLength: ['input', 'textarea'],
39
- name: ['button', 'fieldset', 'input', 'keygen', 'output', 'select', 'textarea', 'form', 'map', 'meta', 'param', 'slot'],
40
- pattern: ['input'],
41
- ping: ['a', 'area'],
42
- placeholder: ['input', 'textarea'],
43
- poster: ['video'],
44
- rel: ['a', 'area', 'link'],
45
- rows: 'textarea',
46
- rowspan: ['td', 'th'],
47
- size: ['input', 'select'],
48
- span: ['col', 'colgroup'],
49
- src: ['audio', 'embed', 'iframe', 'img', 'input', 'script', 'source', 'track', 'video'],
50
- start: 'ol',
51
- tabindex: null,
52
- type: ['a', 'link', 'button', 'embed', 'object', 'script', 'source', 'style', 'input', 'menu', 'menuitem', 'ol'],
53
- value: ['button', 'input', 'li'],
54
- width: ['canvas', 'embed', 'iframe', 'img', 'input', 'object', 'video']
55
- };
56
- function onAttrs() {
57
- return (attrs, node) => {
58
- const newAttrs = {
59
- ...attrs
60
- };
61
- Object.entries(attrs).forEach(([attrName, attrValue]) => {
62
- if ((0, _helpers.isEventHandler)(attrName) || Object.hasOwnProperty.call(safeToRemoveAttrs, attrName) && (safeToRemoveAttrs[attrName] === null || safeToRemoveAttrs[attrName].includes(node.tag))) {
63
- if (typeof attrValue === 'string') {
64
- if (attrValue === '' || attrValue.trim() === '') {
65
- delete newAttrs[attrName];
66
- }
67
- }
68
- }
69
- });
70
- return newAttrs;
71
- };
72
- }