htmlnano 2.1.2 → 2.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -12
- package/dist/_modules/collapseAttributeWhitespace.d.mts +57 -0
- package/dist/_modules/collapseAttributeWhitespace.d.ts +57 -0
- package/dist/_modules/collapseAttributeWhitespace.js +296 -0
- package/dist/_modules/collapseAttributeWhitespace.mjs +293 -0
- package/dist/_modules/collapseBooleanAttributes.d.mts +60 -0
- package/dist/_modules/collapseBooleanAttributes.d.ts +60 -0
- package/dist/_modules/collapseBooleanAttributes.js +159 -0
- package/{lib/modules → dist/_modules}/collapseBooleanAttributes.mjs +39 -57
- package/dist/_modules/collapseWhitespace.d.mts +57 -0
- package/dist/_modules/collapseWhitespace.d.ts +57 -0
- package/dist/_modules/collapseWhitespace.js +172 -0
- package/dist/_modules/collapseWhitespace.mjs +170 -0
- package/dist/_modules/custom.d.mts +57 -0
- package/dist/_modules/custom.d.ts +57 -0
- package/dist/_modules/custom.js +22 -0
- package/dist/_modules/custom.mjs +20 -0
- package/dist/_modules/deduplicateAttributeValues.d.mts +56 -0
- package/dist/_modules/deduplicateAttributeValues.d.ts +56 -0
- package/dist/_modules/deduplicateAttributeValues.js +38 -0
- package/dist/_modules/deduplicateAttributeValues.mjs +36 -0
- package/dist/_modules/example.d.mts +59 -0
- package/dist/_modules/example.d.ts +59 -0
- package/dist/_modules/example.js +67 -0
- package/dist/_modules/example.mjs +65 -0
- package/dist/_modules/mergeScripts.d.mts +56 -0
- package/dist/_modules/mergeScripts.d.ts +56 -0
- package/dist/_modules/mergeScripts.js +53 -0
- package/dist/_modules/mergeScripts.mjs +51 -0
- package/dist/_modules/mergeStyles.d.mts +56 -0
- package/dist/_modules/mergeStyles.d.ts +56 -0
- package/dist/_modules/mergeStyles.js +42 -0
- package/dist/_modules/mergeStyles.mjs +40 -0
- package/dist/_modules/minifyConditionalComments.d.mts +56 -0
- package/dist/_modules/minifyConditionalComments.d.ts +56 -0
- package/dist/_modules/minifyConditionalComments.js +54 -0
- package/{lib/modules → dist/_modules}/minifyConditionalComments.mjs +21 -22
- package/dist/_modules/minifyCss.d.mts +56 -0
- package/dist/_modules/minifyCss.d.ts +56 -0
- package/dist/_modules/minifyCss.js +84 -0
- package/dist/_modules/minifyCss.mjs +82 -0
- package/dist/_modules/minifyJs.d.mts +56 -0
- package/dist/_modules/minifyJs.d.ts +56 -0
- package/dist/_modules/minifyJs.js +108 -0
- package/dist/_modules/minifyJs.mjs +106 -0
- package/dist/_modules/minifyJson.d.mts +56 -0
- package/dist/_modules/minifyJson.d.ts +56 -0
- package/dist/_modules/minifyJson.js +35 -0
- package/dist/_modules/minifyJson.mjs +33 -0
- package/dist/_modules/minifySvg.d.mts +56 -0
- package/dist/_modules/minifySvg.d.ts +56 -0
- package/dist/_modules/minifySvg.js +40 -0
- package/dist/_modules/minifySvg.mjs +38 -0
- package/dist/_modules/minifyUrls.d.mts +56 -0
- package/dist/_modules/minifyUrls.d.ts +56 -0
- package/dist/_modules/minifyUrls.js +180 -0
- package/dist/_modules/minifyUrls.mjs +178 -0
- package/dist/_modules/normalizeAttributeValues.d.mts +56 -0
- package/dist/_modules/normalizeAttributeValues.d.ts +56 -0
- package/dist/_modules/normalizeAttributeValues.js +234 -0
- package/dist/_modules/normalizeAttributeValues.mjs +232 -0
- package/dist/_modules/removeAttributeQuotes.d.mts +56 -0
- package/dist/_modules/removeAttributeQuotes.d.ts +56 -0
- package/dist/_modules/removeAttributeQuotes.js +15 -0
- package/dist/_modules/removeAttributeQuotes.mjs +13 -0
- package/dist/_modules/removeComments.d.mts +58 -0
- package/dist/_modules/removeComments.d.ts +58 -0
- package/dist/_modules/removeComments.js +83 -0
- package/{lib/modules → dist/_modules}/removeComments.mjs +24 -35
- package/dist/_modules/removeEmptyAttributes.d.mts +56 -0
- package/dist/_modules/removeEmptyAttributes.d.ts +56 -0
- package/dist/_modules/removeEmptyAttributes.js +197 -0
- package/dist/_modules/removeEmptyAttributes.mjs +195 -0
- package/dist/_modules/removeOptionalTags.d.mts +56 -0
- package/dist/_modules/removeOptionalTags.d.ts +56 -0
- package/dist/_modules/removeOptionalTags.js +190 -0
- package/{lib/modules → dist/_modules}/removeOptionalTags.mjs +54 -91
- package/dist/_modules/removeRedundantAttributes.d.mts +57 -0
- package/dist/_modules/removeRedundantAttributes.d.ts +57 -0
- package/dist/_modules/removeRedundantAttributes.js +128 -0
- package/{lib/modules → dist/_modules}/removeRedundantAttributes.mjs +43 -59
- package/dist/_modules/removeUnusedCss.d.mts +60 -0
- package/dist/_modules/removeUnusedCss.d.ts +60 -0
- package/dist/_modules/removeUnusedCss.js +134 -0
- package/dist/_modules/removeUnusedCss.mjs +132 -0
- package/dist/_modules/sortAttributes.d.mts +57 -0
- package/dist/_modules/sortAttributes.d.ts +57 -0
- package/dist/_modules/sortAttributes.js +102 -0
- package/{lib/modules → dist/_modules}/sortAttributes.mjs +39 -58
- package/dist/_modules/sortAttributesWithLists.d.mts +56 -0
- package/dist/_modules/sortAttributesWithLists.d.ts +56 -0
- package/dist/_modules/sortAttributesWithLists.js +118 -0
- package/{lib/modules → dist/_modules}/sortAttributesWithLists.mjs +41 -59
- package/dist/helpers.js +72 -0
- package/dist/helpers.mjs +63 -0
- package/dist/index.js +223 -0
- package/dist/index.mjs +209 -0
- package/dist/presets/ampSafe.js +19 -0
- package/{lib → dist}/presets/ampSafe.mjs +6 -4
- package/dist/presets/max.js +28 -0
- package/{lib → dist}/presets/max.mjs +6 -4
- package/dist/presets/safe.js +60 -0
- package/{lib → dist}/presets/safe.mjs +13 -20
- package/package.json +48 -56
- package/.eslintignore +0 -3
- package/CHANGELOG.md +0 -409
- package/docs/README.md +0 -33
- package/docs/babel.config.js +0 -3
- package/docs/docs/010-introduction.md +0 -22
- package/docs/docs/020-usage.md +0 -117
- package/docs/docs/030-config.md +0 -21
- package/docs/docs/040-presets.md +0 -75
- package/docs/docs/050-modules.md +0 -855
- package/docs/docs/060-contribute.md +0 -16
- package/docs/docusaurus.config.js +0 -65
- package/docs/netlify.toml +0 -4
- package/docs/package-lock.json +0 -21630
- package/docs/package.json +0 -40
- package/docs/sidebars.js +0 -26
- package/docs/versioned_docs/version-1.1.1/010-introduction.md +0 -22
- package/docs/versioned_docs/version-1.1.1/020-usage.md +0 -77
- package/docs/versioned_docs/version-1.1.1/030-config.md +0 -21
- package/docs/versioned_docs/version-1.1.1/040-presets.md +0 -75
- package/docs/versioned_docs/version-1.1.1/050-modules.md +0 -785
- package/docs/versioned_docs/version-1.1.1/060-contribute.md +0 -16
- package/docs/versioned_docs/version-2.0.0/010-introduction.md +0 -22
- package/docs/versioned_docs/version-2.0.0/020-usage.md +0 -77
- package/docs/versioned_docs/version-2.0.0/030-config.md +0 -21
- package/docs/versioned_docs/version-2.0.0/040-presets.md +0 -75
- package/docs/versioned_docs/version-2.0.0/050-modules.md +0 -838
- package/docs/versioned_docs/version-2.0.0/060-contribute.md +0 -16
- package/docs/versioned_sidebars/version-1.1.1-sidebars.json +0 -8
- package/docs/versioned_sidebars/version-2.0.0-sidebars.json +0 -8
- package/docs/versions.json +0 -4
- package/index.cjs +0 -11
- package/index.d.cts +0 -3
- package/index.d.mts +0 -3
- package/index.d.ts +0 -94
- package/index.mjs +0 -2
- package/lib/helpers.cjs +0 -79
- package/lib/helpers.mjs +0 -53
- package/lib/htmlnano.cjs +0 -202
- package/lib/htmlnano.mjs +0 -198
- package/lib/modules/collapseAttributeWhitespace.cjs +0 -86
- package/lib/modules/collapseAttributeWhitespace.mjs +0 -104
- package/lib/modules/collapseBooleanAttributes.cjs +0 -62
- package/lib/modules/collapseWhitespace.cjs +0 -100
- package/lib/modules/collapseWhitespace.mjs +0 -132
- package/lib/modules/custom.cjs +0 -19
- package/lib/modules/custom.mjs +0 -16
- package/lib/modules/deduplicateAttributeValues.cjs +0 -38
- package/lib/modules/deduplicateAttributeValues.mjs +0 -40
- package/lib/modules/example.cjs +0 -85
- package/lib/modules/example.mjs +0 -75
- package/lib/modules/mergeScripts.cjs +0 -54
- package/lib/modules/mergeScripts.mjs +0 -56
- package/lib/modules/mergeStyles.cjs +0 -38
- package/lib/modules/mergeStyles.mjs +0 -36
- package/lib/modules/minifyConditionalComments.cjs +0 -47
- package/lib/modules/minifyCss.cjs +0 -73
- package/lib/modules/minifyCss.mjs +0 -88
- package/lib/modules/minifyJs.cjs +0 -103
- package/lib/modules/minifyJs.mjs +0 -121
- package/lib/modules/minifyJson.cjs +0 -24
- package/lib/modules/minifyJson.mjs +0 -21
- package/lib/modules/minifySvg.cjs +0 -37
- package/lib/modules/minifySvg.mjs +0 -30
- package/lib/modules/minifyUrls.cjs +0 -141
- package/lib/modules/minifyUrls.mjs +0 -229
- package/lib/modules/normalizeAttributeValues.cjs +0 -120
- package/lib/modules/normalizeAttributeValues.mjs +0 -140
- package/lib/modules/removeAttributeQuotes.cjs +0 -17
- package/lib/modules/removeAttributeQuotes.mjs +0 -12
- package/lib/modules/removeComments.cjs +0 -86
- package/lib/modules/removeEmptyAttributes.cjs +0 -72
- package/lib/modules/removeEmptyAttributes.mjs +0 -121
- package/lib/modules/removeOptionalTags.cjs +0 -183
- package/lib/modules/removeRedundantAttributes.cjs +0 -112
- package/lib/modules/removeUnusedCss.cjs +0 -113
- package/lib/modules/removeUnusedCss.mjs +0 -122
- package/lib/modules/sortAttributes.cjs +0 -98
- package/lib/modules/sortAttributesWithLists.cjs +0 -114
- package/lib/presets/ampSafe.cjs +0 -18
- package/lib/presets/max.cjs +0 -27
- package/lib/presets/safe.cjs +0 -65
- package/test.js +0 -23
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { isEventHandler } from '../helpers.mjs';
|
|
2
|
+
|
|
3
|
+
const safeToRemoveAttrs = {
|
|
4
|
+
id: null,
|
|
5
|
+
class: null,
|
|
6
|
+
style: null,
|
|
7
|
+
title: null,
|
|
8
|
+
lang: null,
|
|
9
|
+
dir: null,
|
|
10
|
+
abbr: [
|
|
11
|
+
'th'
|
|
12
|
+
],
|
|
13
|
+
accept: [
|
|
14
|
+
'input'
|
|
15
|
+
],
|
|
16
|
+
'accept-charset': [
|
|
17
|
+
'form'
|
|
18
|
+
],
|
|
19
|
+
charset: [
|
|
20
|
+
'meta',
|
|
21
|
+
'script'
|
|
22
|
+
],
|
|
23
|
+
action: [
|
|
24
|
+
'form'
|
|
25
|
+
],
|
|
26
|
+
cols: [
|
|
27
|
+
'textarea'
|
|
28
|
+
],
|
|
29
|
+
colspan: [
|
|
30
|
+
'td',
|
|
31
|
+
'th'
|
|
32
|
+
],
|
|
33
|
+
coords: [
|
|
34
|
+
'area'
|
|
35
|
+
],
|
|
36
|
+
dirname: [
|
|
37
|
+
'input',
|
|
38
|
+
'textarea'
|
|
39
|
+
],
|
|
40
|
+
dropzone: null,
|
|
41
|
+
headers: [
|
|
42
|
+
'td',
|
|
43
|
+
'th'
|
|
44
|
+
],
|
|
45
|
+
form: [
|
|
46
|
+
'button',
|
|
47
|
+
'fieldset',
|
|
48
|
+
'input',
|
|
49
|
+
'keygen',
|
|
50
|
+
'object',
|
|
51
|
+
'output',
|
|
52
|
+
'select',
|
|
53
|
+
'textarea'
|
|
54
|
+
],
|
|
55
|
+
formaction: [
|
|
56
|
+
'button',
|
|
57
|
+
'input'
|
|
58
|
+
],
|
|
59
|
+
height: [
|
|
60
|
+
'canvas',
|
|
61
|
+
'embed',
|
|
62
|
+
'iframe',
|
|
63
|
+
'img',
|
|
64
|
+
'input',
|
|
65
|
+
'object',
|
|
66
|
+
'video'
|
|
67
|
+
],
|
|
68
|
+
high: 'meter',
|
|
69
|
+
href: 'link',
|
|
70
|
+
list: 'input',
|
|
71
|
+
low: 'meter',
|
|
72
|
+
manifest: 'html',
|
|
73
|
+
max: [
|
|
74
|
+
'meter',
|
|
75
|
+
'progress'
|
|
76
|
+
],
|
|
77
|
+
maxLength: [
|
|
78
|
+
'input',
|
|
79
|
+
'textarea'
|
|
80
|
+
],
|
|
81
|
+
menu: 'button',
|
|
82
|
+
min: 'meter',
|
|
83
|
+
minLength: [
|
|
84
|
+
'input',
|
|
85
|
+
'textarea'
|
|
86
|
+
],
|
|
87
|
+
name: [
|
|
88
|
+
'button',
|
|
89
|
+
'fieldset',
|
|
90
|
+
'input',
|
|
91
|
+
'keygen',
|
|
92
|
+
'output',
|
|
93
|
+
'select',
|
|
94
|
+
'textarea',
|
|
95
|
+
'form',
|
|
96
|
+
'map',
|
|
97
|
+
'meta',
|
|
98
|
+
'param',
|
|
99
|
+
'slot'
|
|
100
|
+
],
|
|
101
|
+
pattern: [
|
|
102
|
+
'input'
|
|
103
|
+
],
|
|
104
|
+
ping: [
|
|
105
|
+
'a',
|
|
106
|
+
'area'
|
|
107
|
+
],
|
|
108
|
+
placeholder: [
|
|
109
|
+
'input',
|
|
110
|
+
'textarea'
|
|
111
|
+
],
|
|
112
|
+
poster: [
|
|
113
|
+
'video'
|
|
114
|
+
],
|
|
115
|
+
rel: [
|
|
116
|
+
'a',
|
|
117
|
+
'area',
|
|
118
|
+
'link'
|
|
119
|
+
],
|
|
120
|
+
rows: 'textarea',
|
|
121
|
+
rowspan: [
|
|
122
|
+
'td',
|
|
123
|
+
'th'
|
|
124
|
+
],
|
|
125
|
+
size: [
|
|
126
|
+
'input',
|
|
127
|
+
'select'
|
|
128
|
+
],
|
|
129
|
+
span: [
|
|
130
|
+
'col',
|
|
131
|
+
'colgroup'
|
|
132
|
+
],
|
|
133
|
+
src: [
|
|
134
|
+
'audio',
|
|
135
|
+
'embed',
|
|
136
|
+
'iframe',
|
|
137
|
+
'img',
|
|
138
|
+
'input',
|
|
139
|
+
'script',
|
|
140
|
+
'source',
|
|
141
|
+
'track',
|
|
142
|
+
'video'
|
|
143
|
+
],
|
|
144
|
+
start: 'ol',
|
|
145
|
+
tabindex: null,
|
|
146
|
+
type: [
|
|
147
|
+
'a',
|
|
148
|
+
'link',
|
|
149
|
+
'button',
|
|
150
|
+
'embed',
|
|
151
|
+
'object',
|
|
152
|
+
'script',
|
|
153
|
+
'source',
|
|
154
|
+
'style',
|
|
155
|
+
'input',
|
|
156
|
+
'menu',
|
|
157
|
+
'menuitem',
|
|
158
|
+
'ol'
|
|
159
|
+
],
|
|
160
|
+
value: [
|
|
161
|
+
'button',
|
|
162
|
+
'input',
|
|
163
|
+
'li'
|
|
164
|
+
],
|
|
165
|
+
width: [
|
|
166
|
+
'canvas',
|
|
167
|
+
'embed',
|
|
168
|
+
'iframe',
|
|
169
|
+
'img',
|
|
170
|
+
'input',
|
|
171
|
+
'object',
|
|
172
|
+
'video'
|
|
173
|
+
]
|
|
174
|
+
};
|
|
175
|
+
const mod = {
|
|
176
|
+
onAttrs () {
|
|
177
|
+
return (attrs, node)=>{
|
|
178
|
+
const newAttrs = {
|
|
179
|
+
...attrs
|
|
180
|
+
};
|
|
181
|
+
Object.entries(attrs).forEach(([attrName, attrValue])=>{
|
|
182
|
+
if (isEventHandler(attrName) || Object.hasOwnProperty.call(safeToRemoveAttrs, attrName) && (safeToRemoveAttrs[attrName] === null || typeof node.tag === 'string' && safeToRemoveAttrs[attrName].includes(node.tag))) {
|
|
183
|
+
if (typeof attrValue === 'string') {
|
|
184
|
+
if (attrValue === '' || attrValue.trim() === '') {
|
|
185
|
+
delete newAttrs[attrName];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return newAttrs;
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export { mod as default };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import PostHTML from 'posthtml';
|
|
2
|
+
import { MinifyOptions } from 'terser';
|
|
3
|
+
import { Options } from 'cssnano';
|
|
4
|
+
import { Config } from 'svgo';
|
|
5
|
+
|
|
6
|
+
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
|
+
options?: {
|
|
8
|
+
quoteAllAttributes?: boolean | undefined;
|
|
9
|
+
} | undefined;
|
|
10
|
+
render(): string;
|
|
11
|
+
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
|
+
};
|
|
13
|
+
type MaybeArray<T> = T | Array<T>;
|
|
14
|
+
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
15
|
+
interface HtmlnanoOptions {
|
|
16
|
+
skipConfigLoading?: boolean;
|
|
17
|
+
skipInternalWarnings?: boolean;
|
|
18
|
+
collapseAttributeWhitespace?: boolean;
|
|
19
|
+
collapseBooleanAttributes?: {
|
|
20
|
+
amphtml?: boolean;
|
|
21
|
+
};
|
|
22
|
+
collapseWhitespace?: 'conservative' | 'all' | 'aggressive';
|
|
23
|
+
custom?: MaybeArray<(tree: PostHTMLTreeLike, options?: any) => (PostHTML.Node | PostHTMLTreeLike)>;
|
|
24
|
+
deduplicateAttributeValues?: boolean;
|
|
25
|
+
minifyUrls?: URL | string | false;
|
|
26
|
+
mergeStyles?: boolean;
|
|
27
|
+
mergeScripts?: boolean;
|
|
28
|
+
minifyCss?: Options | boolean;
|
|
29
|
+
minifyConditionalComments?: boolean;
|
|
30
|
+
minifyJs?: MinifyOptions | boolean;
|
|
31
|
+
minifyJson?: boolean;
|
|
32
|
+
minifySvg?: Config | boolean;
|
|
33
|
+
normalizeAttributeValues?: boolean;
|
|
34
|
+
removeAttributeQuotes?: boolean;
|
|
35
|
+
removeComments?: boolean | 'safe' | 'all' | RegExp | ((comment: string) => boolean);
|
|
36
|
+
removeEmptyAttributes?: boolean;
|
|
37
|
+
removeRedundantAttributes?: boolean;
|
|
38
|
+
removeOptionalTags?: boolean;
|
|
39
|
+
removeUnusedCss?: boolean;
|
|
40
|
+
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
41
|
+
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
42
|
+
}
|
|
43
|
+
type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
|
|
44
|
+
type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
|
|
45
|
+
type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
|
|
46
|
+
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
|
|
47
|
+
type HtmlnanoModule<Options = any> = {
|
|
48
|
+
onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
|
|
49
|
+
onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
|
|
50
|
+
onNode?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleNodeHandler;
|
|
51
|
+
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
declare const mod: HtmlnanoModule;
|
|
55
|
+
|
|
56
|
+
export { mod as default };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import PostHTML from 'posthtml';
|
|
2
|
+
import { MinifyOptions } from 'terser';
|
|
3
|
+
import { Options } from 'cssnano';
|
|
4
|
+
import { Config } from 'svgo';
|
|
5
|
+
|
|
6
|
+
type PostHTMLTreeLike = [PostHTML.Node] & PostHTML.NodeAPI & {
|
|
7
|
+
options?: {
|
|
8
|
+
quoteAllAttributes?: boolean | undefined;
|
|
9
|
+
} | undefined;
|
|
10
|
+
render(): string;
|
|
11
|
+
render(node: PostHTML.Node | PostHTMLTreeLike, renderOptions?: any): string;
|
|
12
|
+
};
|
|
13
|
+
type MaybeArray<T> = T | Array<T>;
|
|
14
|
+
type PostHTMLNodeLike = PostHTML.Node | string;
|
|
15
|
+
interface HtmlnanoOptions {
|
|
16
|
+
skipConfigLoading?: boolean;
|
|
17
|
+
skipInternalWarnings?: boolean;
|
|
18
|
+
collapseAttributeWhitespace?: boolean;
|
|
19
|
+
collapseBooleanAttributes?: {
|
|
20
|
+
amphtml?: boolean;
|
|
21
|
+
};
|
|
22
|
+
collapseWhitespace?: 'conservative' | 'all' | 'aggressive';
|
|
23
|
+
custom?: MaybeArray<(tree: PostHTMLTreeLike, options?: any) => (PostHTML.Node | PostHTMLTreeLike)>;
|
|
24
|
+
deduplicateAttributeValues?: boolean;
|
|
25
|
+
minifyUrls?: URL | string | false;
|
|
26
|
+
mergeStyles?: boolean;
|
|
27
|
+
mergeScripts?: boolean;
|
|
28
|
+
minifyCss?: Options | boolean;
|
|
29
|
+
minifyConditionalComments?: boolean;
|
|
30
|
+
minifyJs?: MinifyOptions | boolean;
|
|
31
|
+
minifyJson?: boolean;
|
|
32
|
+
minifySvg?: Config | boolean;
|
|
33
|
+
normalizeAttributeValues?: boolean;
|
|
34
|
+
removeAttributeQuotes?: boolean;
|
|
35
|
+
removeComments?: boolean | 'safe' | 'all' | RegExp | ((comment: string) => boolean);
|
|
36
|
+
removeEmptyAttributes?: boolean;
|
|
37
|
+
removeRedundantAttributes?: boolean;
|
|
38
|
+
removeOptionalTags?: boolean;
|
|
39
|
+
removeUnusedCss?: boolean;
|
|
40
|
+
sortAttributes?: boolean | 'alphabetical' | 'frequency';
|
|
41
|
+
sortAttributesWithLists?: boolean | 'alphabetical' | 'frequency';
|
|
42
|
+
}
|
|
43
|
+
type HtmlnanoModuleAttrsHandler = (attrs: Record<string, string | boolean | void>, node: PostHTML.Node) => Record<string, string | boolean | void>;
|
|
44
|
+
type HtmlnanoModuleContentHandler = (content: Array<PostHTMLNodeLike>, node: PostHTML.Node) => MaybeArray<PostHTMLNodeLike>;
|
|
45
|
+
type HtmlnanoModuleNodeHandler = (node: PostHTMLNodeLike) => PostHTML.Node | string;
|
|
46
|
+
type OptionalOptions<T> = T extends boolean | string | Function | number | null | undefined ? T : T extends object ? Partial<T> : T;
|
|
47
|
+
type HtmlnanoModule<Options = any> = {
|
|
48
|
+
onAttrs?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleAttrsHandler;
|
|
49
|
+
onContent?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleContentHandler;
|
|
50
|
+
onNode?: (options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => HtmlnanoModuleNodeHandler;
|
|
51
|
+
default?: (tree: PostHTMLTreeLike, options: Partial<HtmlnanoOptions>, moduleOptions: OptionalOptions<Options>) => PostHTMLTreeLike | Promise<PostHTMLTreeLike>;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
declare const mod: HtmlnanoModule;
|
|
55
|
+
|
|
56
|
+
export { mod as default };
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
+
|
|
3
|
+
var helpers_js = require('../helpers.js');
|
|
4
|
+
|
|
5
|
+
const startWithWhitespacePattern = /^\s+/;
|
|
6
|
+
const bodyStartTagCantBeOmittedWithFirstChildTags = new Set([
|
|
7
|
+
'meta',
|
|
8
|
+
'link',
|
|
9
|
+
'script',
|
|
10
|
+
'style'
|
|
11
|
+
]);
|
|
12
|
+
const tbodyStartTagCantBeOmittedWithPrecededTags = new Set([
|
|
13
|
+
'tbody',
|
|
14
|
+
'thead',
|
|
15
|
+
'tfoot'
|
|
16
|
+
]);
|
|
17
|
+
const tbodyEndTagCantBeOmittedWithFollowedTags = new Set([
|
|
18
|
+
'tbody',
|
|
19
|
+
'tfoot'
|
|
20
|
+
]);
|
|
21
|
+
function isEmptyTextNode(node) {
|
|
22
|
+
if (typeof node === 'string' && node.trim() === '') {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
function isEmptyNode(node) {
|
|
28
|
+
if (!node.content) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
if (node.content.length) {
|
|
32
|
+
return !node.content.filter((n)=>typeof n === 'string' && isEmptyTextNode(n) ? false : true).length;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
function getFirstChildTag(node, nonEmpty = true) {
|
|
37
|
+
if (node.content && node.content.length) {
|
|
38
|
+
if (nonEmpty) {
|
|
39
|
+
for (const childNode of node.content){
|
|
40
|
+
if (typeof childNode !== 'string') return childNode;
|
|
41
|
+
if (!isEmptyTextNode(childNode)) return childNode;
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
return node.content[0] || null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function getPrevNode(tree, currentNodeIndex, nonEmpty = false) {
|
|
50
|
+
if (nonEmpty) {
|
|
51
|
+
for(let i = currentNodeIndex - 1; i >= 0; i--){
|
|
52
|
+
const node = tree[i];
|
|
53
|
+
if (typeof node !== 'string' && node.tag) return node;
|
|
54
|
+
if (!isEmptyTextNode(node)) return node;
|
|
55
|
+
}
|
|
56
|
+
} else {
|
|
57
|
+
return tree[currentNodeIndex - 1] || null;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function getNextNode(tree, currentNodeIndex, nonEmpty = false) {
|
|
62
|
+
if (nonEmpty) {
|
|
63
|
+
for(let i = currentNodeIndex + 1; i < tree.length; i++){
|
|
64
|
+
const node = tree[i];
|
|
65
|
+
if (typeof node !== 'string') return node;
|
|
66
|
+
if (!isEmptyTextNode(node)) return node;
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
return tree[currentNodeIndex + 1] || null;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
function removeOptionalTags(tree) {
|
|
74
|
+
tree.forEach((node, index)=>{
|
|
75
|
+
if (typeof node === 'string') return node;
|
|
76
|
+
if (!node.tag) return node;
|
|
77
|
+
if (node.attrs && Object.keys(node.attrs).length) return node;
|
|
78
|
+
// const prevNode = getPrevNode(tree, index);
|
|
79
|
+
const prevNonEmptyNode = getPrevNode(tree, index, true);
|
|
80
|
+
const nextNode = getNextNode(tree, index);
|
|
81
|
+
const nextNonEmptyNode = getNextNode(tree, index, true);
|
|
82
|
+
const firstChildNode = getFirstChildTag(node, false);
|
|
83
|
+
const firstNonEmptyChildNode = getFirstChildTag(node);
|
|
84
|
+
/**
|
|
85
|
+
* An "html" element's start tag may be omitted if the first thing inside the "html" element is not a comment.
|
|
86
|
+
* An "html" element's end tag may be omitted if the "html" element is not IMMEDIATELY followed by a comment.
|
|
87
|
+
*/ if (node.tag === 'html') {
|
|
88
|
+
let isHtmlStartTagCanBeOmitted = true;
|
|
89
|
+
let isHtmlEndTagCanBeOmitted = true;
|
|
90
|
+
if (typeof firstNonEmptyChildNode === 'string' && helpers_js.isComment(firstNonEmptyChildNode)) {
|
|
91
|
+
isHtmlStartTagCanBeOmitted = false;
|
|
92
|
+
}
|
|
93
|
+
if (typeof nextNonEmptyNode === 'string' && helpers_js.isComment(nextNonEmptyNode)) {
|
|
94
|
+
isHtmlEndTagCanBeOmitted = false;
|
|
95
|
+
}
|
|
96
|
+
if (isHtmlStartTagCanBeOmitted && isHtmlEndTagCanBeOmitted) {
|
|
97
|
+
// @ts-expect-error -- deliberately set tag to false
|
|
98
|
+
node.tag = false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* A "head" element's start tag may be omitted if the element is empty, or if the first thing inside the "head" element is an element.
|
|
103
|
+
* A "head" element's end tag may be omitted if the "head" element is not IMMEDIATELY followed by ASCII whitespace or a comment.
|
|
104
|
+
*/ if (node.tag === 'head') {
|
|
105
|
+
let isHeadStartTagCanBeOmitted = false;
|
|
106
|
+
let isHeadEndTagCanBeOmitted = true;
|
|
107
|
+
if (isEmptyNode(node) || firstNonEmptyChildNode && typeof firstNonEmptyChildNode === 'object' && firstNonEmptyChildNode.tag) {
|
|
108
|
+
isHeadStartTagCanBeOmitted = true;
|
|
109
|
+
}
|
|
110
|
+
if (nextNode && typeof nextNode === 'string' && startWithWhitespacePattern.test(nextNode) || nextNonEmptyNode && typeof nextNonEmptyNode === 'string' && helpers_js.isComment(nextNode)) {
|
|
111
|
+
isHeadEndTagCanBeOmitted = false;
|
|
112
|
+
}
|
|
113
|
+
if (isHeadStartTagCanBeOmitted && isHeadEndTagCanBeOmitted) {
|
|
114
|
+
// @ts-expect-error -- deliberately set tag to false
|
|
115
|
+
node.tag = false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A "body" element's start tag may be omitted if the element is empty, or if the first thing inside the "body" element is not ASCII whitespace or a comment, except if the first thing inside the "body" element is a "meta", "link", "script", "style", or "template" element.
|
|
120
|
+
* A "body" element's end tag may be omitted if the "body" element is not IMMEDIATELY followed by a comment.
|
|
121
|
+
*/ if (node.tag === 'body') {
|
|
122
|
+
let isBodyStartTagCanBeOmitted = true;
|
|
123
|
+
let isBodyEndTagCanBeOmitted = true;
|
|
124
|
+
if (typeof firstChildNode === 'string' && startWithWhitespacePattern.test(firstChildNode) || typeof firstNonEmptyChildNode === 'string' && helpers_js.isComment(firstNonEmptyChildNode)) {
|
|
125
|
+
isBodyStartTagCanBeOmitted = false;
|
|
126
|
+
}
|
|
127
|
+
if (firstNonEmptyChildNode && typeof firstNonEmptyChildNode === 'object' && firstNonEmptyChildNode.tag && bodyStartTagCantBeOmittedWithFirstChildTags.has(firstNonEmptyChildNode.tag)) {
|
|
128
|
+
isBodyStartTagCanBeOmitted = false;
|
|
129
|
+
}
|
|
130
|
+
if (nextNode && typeof nextNode === 'string' && helpers_js.isComment(nextNode)) {
|
|
131
|
+
isBodyEndTagCanBeOmitted = false;
|
|
132
|
+
}
|
|
133
|
+
if (isBodyStartTagCanBeOmitted && isBodyEndTagCanBeOmitted) {
|
|
134
|
+
// @ts-expect-error -- deliberately set tag to false
|
|
135
|
+
node.tag = false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* A "colgroup" element's start tag may be omitted if the first thing inside the "colgroup" element is a "col" element, and if the element is not IMMEDIATELY preceded by another "colgroup" element. It can't be omitted if the element is empty.
|
|
140
|
+
* A "colgroup" element's end tag may be omitted if the "colgroup" element is not IMMEDIATELY followed by ASCII whitespace or a comment.
|
|
141
|
+
*/ if (node.tag === 'colgroup') {
|
|
142
|
+
let isColgroupStartTagCanBeOmitted = false;
|
|
143
|
+
let isColgroupEndTagCanBeOmitted = true;
|
|
144
|
+
if (firstNonEmptyChildNode && typeof firstNonEmptyChildNode === 'object' && firstNonEmptyChildNode.tag && firstNonEmptyChildNode.tag === 'col') {
|
|
145
|
+
isColgroupStartTagCanBeOmitted = true;
|
|
146
|
+
}
|
|
147
|
+
if (prevNonEmptyNode && typeof prevNonEmptyNode === 'object' && prevNonEmptyNode.tag && prevNonEmptyNode.tag === 'colgroup') {
|
|
148
|
+
isColgroupStartTagCanBeOmitted = false;
|
|
149
|
+
}
|
|
150
|
+
if (nextNode && typeof nextNode === 'string' && startWithWhitespacePattern.test(nextNode) || nextNonEmptyNode && typeof nextNonEmptyNode === 'string' && helpers_js.isComment(nextNonEmptyNode)) {
|
|
151
|
+
isColgroupEndTagCanBeOmitted = false;
|
|
152
|
+
}
|
|
153
|
+
if (isColgroupStartTagCanBeOmitted && isColgroupEndTagCanBeOmitted) {
|
|
154
|
+
// @ts-expect-error -- deliberately set tag to false
|
|
155
|
+
node.tag = false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* A "tbody" element's start tag may be omitted if the first thing inside the "tbody" element is a "tr" element, and if the element is not immediately preceded by another "tbody", "thead" or "tfoot" element. It can't be omitted if the element is empty.
|
|
160
|
+
* A "tbody" element's end tag may be omitted if the "tbody" element is not IMMEDIATELY followed by a "tbody" or "tfoot" element.
|
|
161
|
+
*/ if (node.tag === 'tbody') {
|
|
162
|
+
let isTbodyStartTagCanBeOmitted = false;
|
|
163
|
+
let isTbodyEndTagCanBeOmitted = true;
|
|
164
|
+
if (firstNonEmptyChildNode && typeof firstNonEmptyChildNode === 'object' && firstNonEmptyChildNode.tag && firstNonEmptyChildNode.tag === 'tr') {
|
|
165
|
+
isTbodyStartTagCanBeOmitted = true;
|
|
166
|
+
}
|
|
167
|
+
if (prevNonEmptyNode && typeof prevNonEmptyNode === 'object' && prevNonEmptyNode.tag && tbodyStartTagCantBeOmittedWithPrecededTags.has(prevNonEmptyNode.tag)) {
|
|
168
|
+
isTbodyStartTagCanBeOmitted = false;
|
|
169
|
+
}
|
|
170
|
+
if (nextNonEmptyNode && typeof nextNonEmptyNode === 'object' && nextNonEmptyNode.tag && tbodyEndTagCantBeOmittedWithFollowedTags.has(nextNonEmptyNode.tag)) {
|
|
171
|
+
isTbodyEndTagCanBeOmitted = false;
|
|
172
|
+
}
|
|
173
|
+
if (isTbodyStartTagCanBeOmitted && isTbodyEndTagCanBeOmitted) {
|
|
174
|
+
// @ts-expect-error -- deliberately set tag to false
|
|
175
|
+
node.tag = false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (node.content && node.content.length) {
|
|
179
|
+
removeOptionalTags(node.content);
|
|
180
|
+
}
|
|
181
|
+
return node;
|
|
182
|
+
});
|
|
183
|
+
return tree;
|
|
184
|
+
}
|
|
185
|
+
// Specification https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
|
|
186
|
+
/** Remove optional tag in the DOM */ const mod = {
|
|
187
|
+
default: removeOptionalTags
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
exports.default = mod;
|