html-minifier 4.0.0 → 5.0.1
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/LICENSE.txt +23 -0
- package/README.md +851 -110
- package/cli.js +991 -207
- package/dist/types/htmlminifier.d.ts +629 -0
- package/dist/types/htmlminifier.d.ts.map +1 -0
- package/dist/types/htmlparser.d.ts +28 -0
- package/dist/types/htmlparser.d.ts.map +1 -0
- package/dist/types/lib/attributes.d.ts +87 -0
- package/dist/types/lib/attributes.d.ts.map +1 -0
- package/dist/types/lib/constants.d.ts +421 -0
- package/dist/types/lib/constants.d.ts.map +1 -0
- package/dist/types/lib/content.d.ts +44 -0
- package/dist/types/lib/content.d.ts.map +1 -0
- package/dist/types/lib/elements.d.ts +48 -0
- package/dist/types/lib/elements.d.ts.map +1 -0
- package/dist/types/lib/fragments.d.ts +47 -0
- package/dist/types/lib/fragments.d.ts.map +1 -0
- package/dist/types/lib/option-definitions.d.ts +33 -0
- package/dist/types/lib/option-definitions.d.ts.map +1 -0
- package/dist/types/lib/options.d.ts +93 -0
- package/dist/types/lib/options.d.ts.map +1 -0
- package/dist/types/lib/unused-css.d.ts +76 -0
- package/dist/types/lib/unused-css.d.ts.map +1 -0
- package/dist/types/lib/urls.d.ts +15 -0
- package/dist/types/lib/urls.d.ts.map +1 -0
- package/dist/types/lib/utils.d.ts +132 -0
- package/dist/types/lib/utils.d.ts.map +1 -0
- package/dist/types/lib/whitespace.d.ts +97 -0
- package/dist/types/lib/whitespace.d.ts.map +1 -0
- package/dist/types/presets.d.ts +50 -0
- package/dist/types/presets.d.ts.map +1 -0
- package/dist/types/tokenchain.d.ts +36 -0
- package/dist/types/tokenchain.d.ts.map +1 -0
- package/html-minifier.schema.json +322 -0
- package/package.json +71 -60
- package/src/htmlminifier.js +2862 -1106
- package/src/htmlparser.js +1163 -452
- package/src/lib/attributes.js +1196 -0
- package/src/lib/constants.js +521 -0
- package/src/lib/content.js +237 -0
- package/src/lib/elements.js +268 -0
- package/src/lib/file-pool.js +193 -0
- package/src/lib/file-write.js +87 -0
- package/src/lib/fragments.js +340 -0
- package/src/lib/option-definitions.js +246 -0
- package/src/lib/options.js +841 -0
- package/src/lib/unused-css.js +499 -0
- package/src/lib/urls.js +146 -0
- package/src/lib/utils.js +1026 -0
- package/src/lib/whitespace.js +431 -0
- package/src/presets.js +58 -0
- package/src/tokenchain.js +142 -56
- package/LICENSE +0 -22
- package/sample-cli-config-file.conf +0 -40
- package/src/utils.js +0 -18
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regex patterns, element sets, and default configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const RE_WS_START = /^[ \n\r\t\f]+/;
|
|
6
|
+
const RE_WS_END = /[ \n\r\t\f]+$/;
|
|
7
|
+
const RE_WS_ONLY = /^[ \n\r\t\f]+$/;
|
|
8
|
+
const RE_WS_NBSP_END = /[ \n\r\t\f\xA0]$/;
|
|
9
|
+
const RE_ALL_WS_NBSP = /[ \n\r\t\f\xA0]+/g;
|
|
10
|
+
const RE_NBSP_LEADING_GROUP = /(^|\xA0+)[^\xA0]+/g;
|
|
11
|
+
const RE_NBSP_LEAD_GROUP = /(\xA0+)[^\xA0]+/g;
|
|
12
|
+
const RE_NBSP_TRAILING_GROUP = /[^\xA0]+(\xA0+)/g;
|
|
13
|
+
const RE_NBSP_TRAILING_STRIP = /[^\xA0]+$/;
|
|
14
|
+
const RE_EVENT_ATTR_DEFAULT = /^on[a-z]{3,}$/;
|
|
15
|
+
const RE_CAN_REMOVE_ATTR_QUOTES = /^[^ \t\n\f\r"'`=<>]+$/;
|
|
16
|
+
const RE_TRAILING_SEMICOLON = /;$/;
|
|
17
|
+
// Line breaks HTML reads as line feeds when raw
|
|
18
|
+
const RE_CR = /\r/g;
|
|
19
|
+
const RE_LINE_BREAK_CR = /\r\n?/g;
|
|
20
|
+
// Named references HTML resolves without a semicolon
|
|
21
|
+
const LEGACY_REFERENCE_NAMES = 'Iacute|aacute|uacute|plusmn|Otilde|otilde|agrave|Agrave|Yacute|yacute|Oslash|oslash|atilde|Atilde|brvbar|ccedil|Ccedil|Ograve|curren|divide|eacute|Eacute|ograve|Oacute|egrave|Egrave|Ugrave|frac12|frac14|frac34|ugrave|oacute|iacute|Ntilde|ntilde|Uacute|middot|igrave|Igrave|iquest|Aacute|cedil|laquo|micro|iexcl|Icirc|icirc|acirc|Ucirc|Ecirc|ocirc|Ocirc|ecirc|ucirc|Aring|aring|AElig|aelig|acute|pound|raquo|Acirc|times|THORN|szlig|thorn|COPY|auml|ordf|ordm|Uuml|macr|uuml|Auml|ouml|Ouml|para|nbsp|euml|quot|QUOT|Euml|yuml|cent|sect|copy|sup1|sup2|sup3|iuml|Iuml|ETH|shy|reg|not|yen|amp|AMP|REG|uml|eth|deg|gt|GT|LT|lt';
|
|
22
|
+
// Ampersands text would read as starting a reference, for `&` to precede
|
|
23
|
+
const RE_LEGACY_ENTITIES = new RegExp(`&((?:${LEGACY_REFERENCE_NAMES})(?!;)|[0-9a-zA-Z]+;|#[0-9]|#[xX][0-9a-fA-F])`, 'g');
|
|
24
|
+
// Ampersands an attribute value would read as starting a reference (which a legacy name
|
|
25
|
+
// followed by `=` or an alphanumeric does not)
|
|
26
|
+
const RE_AMP_REFERENCE_ATTR = new RegExp(`&(?=(?:${LEGACY_REFERENCE_NAMES})(?![=0-9a-zA-Z])|[0-9a-zA-Z]+;|#[0-9]|#[xX][0-9a-fA-F])`, 'g');
|
|
27
|
+
const RE_ESCAPE_LT = /</g;
|
|
28
|
+
// A `base` element, also as character references may write it, or as a script may name it
|
|
29
|
+
// (e.g., `createElement('base')`)
|
|
30
|
+
const RE_BASE_ELEMENT = /(?:<|<?|�*60;?|�*3c;?)base[\s/>]|(["'`])base\1/i;
|
|
31
|
+
// What decoded text and attribute values hold that XML reads otherwise: markup, and
|
|
32
|
+
// line breaks and tabs XML normalizes (quotes are left to attribute quoting)
|
|
33
|
+
const RE_XML_ESCAPE_TEXT = /[&<\r]|]]>/g;
|
|
34
|
+
const RE_XML_ESCAPE_ATTR = /[&<\t\n\r]/g;
|
|
35
|
+
// In escapable raw text only the element’s own end tag ends the element, so nothing else
|
|
36
|
+
// that `decodeEntities` decoded to a `<` needs escaping there
|
|
37
|
+
// (the record has no prototype, so a tag named after an inherited property—`constructor`,
|
|
38
|
+
// `__proto__`—finds nothing here and falls back to escaping every `<`)
|
|
39
|
+
const RE_ESCAPE_LT_RAW_TEXT = /** @type {Record<string, RegExp>} */ (Object.assign(Object.create(null), {
|
|
40
|
+
textarea: /<(?=\/textarea[\s/>])/gi,
|
|
41
|
+
title: /<(?=\/title[\s/>])/gi
|
|
42
|
+
}));
|
|
43
|
+
// Encodings that make an `annotation-xml` element hold HTML rather than MathML
|
|
44
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#html-integration-point
|
|
45
|
+
const RE_HTML_ENCODING = /^(text\/html|application\/xhtml\+xml)$/i;
|
|
46
|
+
// A doctype’s name, public identifier, and system identifier (quoted),
|
|
47
|
+
// and what follows them, as the tokenizer reads them; unless a system
|
|
48
|
+
// identifier precedes it, anything but `>` sets quirks mode
|
|
49
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#doctype-state
|
|
50
|
+
const RE_DOCTYPE = /^<!doctype[ \n\r\t\f]*([^ \n\r\t\f>]+)[ \n\r\t\f]*(?:public[ \n\r\t\f]*("[^">]*"|'[^'>]*')[ \n\r\t\f]*("[^">]*"|'[^'>]*')?|system[ \n\r\t\f]*("[^">]*"|'[^'>]*'))?([^]*)$/i;
|
|
51
|
+
const RE_ATTR_WS_CHECK = /[ \n\r\t\f]/;
|
|
52
|
+
const RE_ATTR_WS_COLLAPSE = /[ \n\r\t\f]+/g;
|
|
53
|
+
const RE_WS_CHAR = /\s/;
|
|
54
|
+
const RE_STYLE_ELEMENT = /<style[\s/>]/i;
|
|
55
|
+
const RE_EMPTY_ATTRIBUTE = new RegExp(
|
|
56
|
+
'^(?:class|id|style|title|lang|dir|on(?:focus|blur|change|click|dblclick|mouse(' +
|
|
57
|
+
'?:down|up|over|move|out)|key(?:press|down|up)))$');
|
|
58
|
+
|
|
59
|
+
// Inline element sets for whitespace handling
|
|
60
|
+
|
|
61
|
+
// Non-empty elements that will maintain whitespace around them
|
|
62
|
+
const inlineElementsToKeepWhitespaceAround = new Set(['a', 'abbr', 'acronym', 'audio', 'b', 'bdi', 'bdo', 'big', 'button', 'canvas', 'cite', 'code', 'data', 'del', 'dfn', 'em', 'embed', 'font', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'label', 'map', 'mark', 'math', 'meter', 'nobr', 'object', 'output', 'picture', 'progress', 'q', 'rb', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'select', 'selectedcontent', 'slot', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'svg', 'textarea', 'time', 'tt', 'u', 'var', 'video', 'wbr']);
|
|
63
|
+
|
|
64
|
+
// Non-empty elements that will maintain whitespace within them
|
|
65
|
+
const inlineElementsToKeepWhitespaceWithin = new Set(['a', 'abbr', 'acronym', 'b', 'big', 'data', 'del', 'em', 'font', 'i', 'ins', 'kbd', 'map', 'mark', 'nobr', 's', 'samp', 'slot', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'time', 'tt', 'u', 'var']);
|
|
66
|
+
|
|
67
|
+
// Text-level elements that keep whitespace between them and other elements under
|
|
68
|
+
// `collapseInlineTagWhitespace`
|
|
69
|
+
const inlineElementsToKeepWhitespaceBetween = new Set([...inlineElementsToKeepWhitespaceWithin, 'bdi', 'bdo', 'cite', 'code', 'dfn', 'label', 'math', 'q', 'ruby']);
|
|
70
|
+
|
|
71
|
+
// Phrasing elements that don’t render, whose neighbors decide on the whitespace around them
|
|
72
|
+
const inlineElementsTransparent = new Set(['area', 'datalist', 'link', 'meta', 'noscript', 'script', 'style', 'template']);
|
|
73
|
+
const inlineElementsTransparentVoid = new Set(['area', 'link', 'meta']);
|
|
74
|
+
|
|
75
|
+
// What the parser reports as the tag next to text that borders a processing instruction—
|
|
76
|
+
// no tag name can be `?`, and content may be inserted there, so whitespace around it stays
|
|
77
|
+
const processingInstructionTag = '?';
|
|
78
|
+
|
|
79
|
+
// Elements that will always maintain whitespace around them
|
|
80
|
+
const inlineElementsToKeepWhitespace = new Set(['comment', 'embed', 'img', 'input', 'wbr', processingInstructionTag]);
|
|
81
|
+
|
|
82
|
+
// Formatting elements, which browsers reopen after a block that closed them, so their end tags
|
|
83
|
+
// count even when stray, https://html.spec.whatwg.org/multipage/parsing.html#formatting
|
|
84
|
+
const formattingElements = new Set(['a', 'b', 'big', 'code', 'em', 'font', 'i', 'nobr', 's', 'small', 'strike', 'strong', 'tt', 'u']);
|
|
85
|
+
|
|
86
|
+
// Form control elements (for conditional whitespace collapsing)
|
|
87
|
+
const formControlElements = new Set(['input', 'button', 'select', 'textarea', 'output', 'meter', 'progress']);
|
|
88
|
+
|
|
89
|
+
// End-tag spellings (`/a`) of a set of element names
|
|
90
|
+
/** @param {Iterable<string>} names */
|
|
91
|
+
const toEndTags = names => new Set(Array.from(names, name => '/' + name));
|
|
92
|
+
|
|
93
|
+
// Membership under either spelling, for the whitespace checks that ignore the slash;
|
|
94
|
+
// looking a tag up as it comes keeps the hot path from slicing one string per call
|
|
95
|
+
const formControlElementsEither = new Set([...formControlElements, ...toEndTags(formControlElements)]);
|
|
96
|
+
|
|
97
|
+
const inlineElementsToKeepWhitespaceBetweenEnd = toEndTags(inlineElementsToKeepWhitespaceBetween);
|
|
98
|
+
// Spelled as the tags that sit before and after the element: a start tag before it, an end tag
|
|
99
|
+
// (or, for void elements, the start tag) after it
|
|
100
|
+
const inlineElementsTransparentAfter = new Set([...toEndTags(inlineElementsTransparent), ...inlineElementsTransparentVoid]);
|
|
101
|
+
|
|
102
|
+
// Default attribute values (could apply to any element)
|
|
103
|
+
const generalDefaults = {
|
|
104
|
+
autocorrect: 'on',
|
|
105
|
+
fetchpriority: 'auto',
|
|
106
|
+
loading: 'eager',
|
|
107
|
+
popovertargetaction: 'toggle'
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Tag-specific default attribute values
|
|
111
|
+
const tagDefaults = {
|
|
112
|
+
area: { shape: 'rect' },
|
|
113
|
+
button: { type: 'submit' },
|
|
114
|
+
col: { span: '1' },
|
|
115
|
+
colgroup: { span: '1' },
|
|
116
|
+
form: {
|
|
117
|
+
autocomplete: 'on',
|
|
118
|
+
enctype: 'application/x-www-form-urlencoded',
|
|
119
|
+
method: 'get'
|
|
120
|
+
},
|
|
121
|
+
html: { dir: 'ltr' },
|
|
122
|
+
iframe: { scrolling: 'auto' },
|
|
123
|
+
img: { decoding: 'auto' },
|
|
124
|
+
input: {
|
|
125
|
+
colorspace: 'limited-srgb',
|
|
126
|
+
type: 'text'
|
|
127
|
+
},
|
|
128
|
+
link: { media: 'all' },
|
|
129
|
+
marquee: {
|
|
130
|
+
behavior: 'scroll',
|
|
131
|
+
direction: 'left'
|
|
132
|
+
},
|
|
133
|
+
meta: { media: 'all' },
|
|
134
|
+
meter: {
|
|
135
|
+
max: '1',
|
|
136
|
+
min: '0'
|
|
137
|
+
},
|
|
138
|
+
// Not `start` on reversed lists, which count down from their number of items
|
|
139
|
+
ol: {
|
|
140
|
+
start: '1',
|
|
141
|
+
type: '1'
|
|
142
|
+
},
|
|
143
|
+
progress: { max: '1' },
|
|
144
|
+
source: { media: 'all' },
|
|
145
|
+
style: { media: 'all' },
|
|
146
|
+
td: {
|
|
147
|
+
colspan: '1',
|
|
148
|
+
rowspan: '1'
|
|
149
|
+
},
|
|
150
|
+
textarea: {
|
|
151
|
+
cols: '20',
|
|
152
|
+
rows: '2',
|
|
153
|
+
wrap: 'soft'
|
|
154
|
+
},
|
|
155
|
+
th: {
|
|
156
|
+
colspan: '1',
|
|
157
|
+
rowspan: '1',
|
|
158
|
+
scope: 'auto'
|
|
159
|
+
},
|
|
160
|
+
track: { kind: 'subtitles' }
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// SVG and MathML elements whose children HTML reads as HTML, but for MathML `mglyph` and
|
|
164
|
+
// `malignmark` (`foreignObject` and `annotation-xml` get a context of their own)
|
|
165
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#mathml-text-integration-point
|
|
166
|
+
const integrationPointsForeign = {
|
|
167
|
+
svg: new Set(['desc', 'title']),
|
|
168
|
+
math: new Set(['mi', 'mn', 'mo', 'ms', 'mtext'])
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// `meta` element `http-equiv` and `name` values no current browser acts on, in lowercase
|
|
172
|
+
const metaHttpEquivNoEffect = new Set(['cleartype', 'content-script-type', 'content-style-type', 'imagetoolbar', 'msthemecompatible', 'page-enter', 'page-exit', 'pics-label', 'site-enter', 'site-exit', 'window-target', 'x-ua-compatible']);
|
|
173
|
+
const metaNamesNoEffect = new Set(['handheldfriendly', 'ie_rm_off', 'mobileoptimized', 'mssmarttagspreventparsing']);
|
|
174
|
+
|
|
175
|
+
// Elements whose `target` defaults to `_self` where no `base` element sets another
|
|
176
|
+
const targetSelfElements = new Set(['a', 'area', 'form']);
|
|
177
|
+
|
|
178
|
+
const transferFunctionDefaults = { amplitude: '1', exponent: '1', intercept: '0', offset: '0', slope: '1', type: 'identity' };
|
|
179
|
+
|
|
180
|
+
// SVG default attribute values, keyed by element and attribute names in lowercase, with
|
|
181
|
+
// values in lowercase as well; presentation attributes are left out, as they inherit
|
|
182
|
+
const tagDefaultsSVG = {
|
|
183
|
+
animatemotion: { rotate: '0' },
|
|
184
|
+
animatetransform: { type: 'translate' },
|
|
185
|
+
circle: { cx: '0', cy: '0' },
|
|
186
|
+
clippath: { clippathunits: 'userspaceonuse' },
|
|
187
|
+
ellipse: { cx: '0', cy: '0' },
|
|
188
|
+
feblend: { mode: 'normal' },
|
|
189
|
+
fecolormatrix: { type: 'matrix' },
|
|
190
|
+
fecomposite: { k1: '0', k2: '0', k3: '0', k4: '0', operator: 'over' },
|
|
191
|
+
feconvolvematrix: { bias: '0', edgemode: 'duplicate', order: '3', preservealpha: 'false' },
|
|
192
|
+
fediffuselighting: { diffuseconstant: '1', surfacescale: '1' },
|
|
193
|
+
fedisplacementmap: { scale: '0', xchannelselector: 'a', ychannelselector: 'a' },
|
|
194
|
+
fedistantlight: { azimuth: '0', elevation: '0' },
|
|
195
|
+
fedropshadow: { dx: '2', dy: '2', stddeviation: '2' },
|
|
196
|
+
fefunca: transferFunctionDefaults,
|
|
197
|
+
fefuncb: transferFunctionDefaults,
|
|
198
|
+
fefuncg: transferFunctionDefaults,
|
|
199
|
+
fefuncr: transferFunctionDefaults,
|
|
200
|
+
fegaussianblur: { stddeviation: '0' },
|
|
201
|
+
feimage: { preserveaspectratio: 'xmidymid meet' },
|
|
202
|
+
femorphology: { operator: 'erode', radius: '0' },
|
|
203
|
+
feoffset: { dx: '0', dy: '0' },
|
|
204
|
+
fepointlight: { x: '0', y: '0', z: '0' },
|
|
205
|
+
fespecularlighting: { specularconstant: '1', specularexponent: '1', surfacescale: '1' },
|
|
206
|
+
fespotlight: { pointsatx: '0', pointsaty: '0', pointsatz: '0', specularexponent: '1', x: '0', y: '0', z: '0' },
|
|
207
|
+
feturbulence: { basefrequency: '0', numoctaves: '1', seed: '0', stitchtiles: 'nostitch', type: 'turbulence' },
|
|
208
|
+
filter: { filterunits: 'objectboundingbox', height: '120%', primitiveunits: 'userspaceonuse', width: '120%', x: '-10%', y: '-10%' },
|
|
209
|
+
foreignobject: { x: '0', y: '0' },
|
|
210
|
+
image: { preserveaspectratio: 'xmidymid meet', x: '0', y: '0' },
|
|
211
|
+
line: { x1: '0', x2: '0', y1: '0', y2: '0' },
|
|
212
|
+
lineargradient: { gradientunits: 'objectboundingbox', spreadmethod: 'pad', x1: ['0', '0%'], x2: '100%', y1: ['0', '0%'], y2: ['0', '0%'] },
|
|
213
|
+
marker: { markerheight: '3', markerunits: 'strokewidth', markerwidth: '3', orient: '0', preserveaspectratio: 'xmidymid meet', refx: '0', refy: '0' },
|
|
214
|
+
mask: { height: '120%', maskcontentunits: 'userspaceonuse', maskunits: 'objectboundingbox', width: '120%', x: '-10%', y: '-10%' },
|
|
215
|
+
pattern: { height: '0', patterncontentunits: 'userspaceonuse', patternunits: 'objectboundingbox', preserveaspectratio: 'xmidymid meet', width: '0', x: '0', y: '0' },
|
|
216
|
+
radialgradient: { cx: '50%', cy: '50%', fr: ['0', '0%'], gradientunits: 'objectboundingbox', r: '50%', spreadmethod: 'pad' },
|
|
217
|
+
rect: { x: '0', y: '0' },
|
|
218
|
+
stop: { offset: '0' },
|
|
219
|
+
svg: { preserveaspectratio: 'xmidymid meet', version: '1.1', x: '0', y: '0' },
|
|
220
|
+
// Not `refX` and `refY` on `symbol`, which, unset, set no reference point
|
|
221
|
+
symbol: { preserveaspectratio: 'xmidymid meet' },
|
|
222
|
+
// Unlike in `tspan`, where they continue from the text before
|
|
223
|
+
text: { lengthadjust: 'spacing', x: '0', y: '0' },
|
|
224
|
+
textpath: { lengthadjust: 'spacing', method: 'align', spacing: 'exact', startoffset: '0' },
|
|
225
|
+
tspan: { lengthadjust: 'spacing' },
|
|
226
|
+
use: { x: '0', y: '0' },
|
|
227
|
+
view: { preserveaspectratio: 'xmidymid meet' }
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// SVG elements taking what they do not set from the element they refer to
|
|
231
|
+
const svgElementsInheritingByReference = new Set(['filter', 'lineargradient', 'pattern', 'radialgradient']);
|
|
232
|
+
|
|
233
|
+
// The namespaces HTML puts elements in, which `xmlns` may only repeat
|
|
234
|
+
const namespaceHTML = 'http://www.w3.org/1999/xhtml';
|
|
235
|
+
const namespaceSVG = 'http://www.w3.org/2000/svg';
|
|
236
|
+
const namespaceMathML = 'http://www.w3.org/1998/Math/MathML';
|
|
237
|
+
const namespaceXLink = 'http://www.w3.org/1999/xlink';
|
|
238
|
+
|
|
239
|
+
// Script MIME types
|
|
240
|
+
|
|
241
|
+
// https://mathiasbynens.be/demo/javascript-mime-type
|
|
242
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script
|
|
243
|
+
const executableScriptsMimetypes = new Set([
|
|
244
|
+
'text/javascript',
|
|
245
|
+
'text/x-javascript',
|
|
246
|
+
'text/ecmascript',
|
|
247
|
+
'text/x-ecmascript',
|
|
248
|
+
'text/jscript',
|
|
249
|
+
'application/javascript',
|
|
250
|
+
'application/x-javascript',
|
|
251
|
+
'application/ecmascript',
|
|
252
|
+
'application/x-ecmascript',
|
|
253
|
+
'module'
|
|
254
|
+
]);
|
|
255
|
+
|
|
256
|
+
const keepScriptsMimetypes = new Set([
|
|
257
|
+
'module'
|
|
258
|
+
]);
|
|
259
|
+
|
|
260
|
+
// Boolean attribute sets
|
|
261
|
+
|
|
262
|
+
const isSimpleBoolean = new Set(['allowfullscreen', 'async', 'autofocus', 'autoplay', 'checked', 'compact', 'controls', 'declare', 'default', 'defaultchecked', 'defaultmuted', 'defaultselected', 'defer', 'disabled', 'enabled', 'formnovalidate', 'hidden', 'indeterminate', 'inert', 'ismap', 'itemscope', 'loop', 'multiple', 'muted', 'nohref', 'noresize', 'noshade', 'novalidate', 'nowrap', 'open', 'pauseonexit', 'readonly', 'required', 'reversed', 'scoped', 'seamless', 'selected', 'sortable', 'truespeed', 'typemustmatch', 'visible']);
|
|
263
|
+
|
|
264
|
+
const isBooleanValue = new Set(['true', 'false']);
|
|
265
|
+
|
|
266
|
+
// Values that collapse to the bare attribute name:
|
|
267
|
+
// - `crossorigin=""` and `crossorigin="anonymous"` → `crossorigin` (anonymous is the default)
|
|
268
|
+
// - `contenteditable=""` → `contenteditable` (empty string means inherit/true)
|
|
269
|
+
const collapsibleValues = new Map([
|
|
270
|
+
['crossorigin', new Set(['', 'anonymous'])],
|
|
271
|
+
['contenteditable', new Set([''])]
|
|
272
|
+
]);
|
|
273
|
+
|
|
274
|
+
const srcsetElements = new Set(['img', 'source']);
|
|
275
|
+
|
|
276
|
+
const jsonScriptTypes = new Set([
|
|
277
|
+
'application/json',
|
|
278
|
+
'application/ld+json',
|
|
279
|
+
'application/manifest+json',
|
|
280
|
+
'application/vnd.geo+json',
|
|
281
|
+
'application/problem+json',
|
|
282
|
+
'application/merge-patch+json',
|
|
283
|
+
'application/json-patch+json',
|
|
284
|
+
'importmap',
|
|
285
|
+
'speculationrules',
|
|
286
|
+
]);
|
|
287
|
+
|
|
288
|
+
// Tag omission rules from https://html.spec.whatwg.org/multipage/syntax.html#optional-tags
|
|
289
|
+
// with the following extensions:
|
|
290
|
+
// - retain `<body>` if followed by `<noscript>`
|
|
291
|
+
// - `<rb>`, `<rt>`, `<rtc>`, `<rp>` follow the HTML Ruby Markup Extensions draft:
|
|
292
|
+
// https://www.w3.org/TR/html-ruby-extensions/
|
|
293
|
+
// - retain all tags which are adjacent to non-standard HTML tags
|
|
294
|
+
|
|
295
|
+
const optionalStartTags = new Set(['html', 'head', 'body', 'colgroup', 'tbody']);
|
|
296
|
+
|
|
297
|
+
const optionalEndTags = new Set(['html', 'head', 'body', 'li', 'dt', 'dd', 'p', 'rb', 'rt', 'rtc', 'rp', 'optgroup', 'option', 'colgroup', 'caption', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th']);
|
|
298
|
+
|
|
299
|
+
const headerElements = new Set(['meta', 'link', 'script', 'style', 'template', 'noscript']);
|
|
300
|
+
|
|
301
|
+
const descriptionElements = new Set(['dt', 'dd']);
|
|
302
|
+
|
|
303
|
+
const pBlockElements = new Set(['address', 'article', 'aside', 'blockquote', 'details', 'dialog', 'div', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre', 'search', 'section', 'table', 'ul']);
|
|
304
|
+
|
|
305
|
+
// Elements whose end tags close an open `p` in browsers, so that `</p>` may be omitted before them
|
|
306
|
+
const pClosingParents = new Set(['address', 'applet', 'article', 'aside', 'blockquote', 'body', 'button', 'caption', 'center', 'dd', 'details', 'dialog', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'html', 'li', 'listing', 'main', 'marquee', 'menu', 'nav', 'object', 'ol', 'pre', 'search', 'section', 'summary', 'td', 'template', 'th', 'ul']);
|
|
307
|
+
|
|
308
|
+
const rubyEndTagOmission = new Set(['rb', 'rt', 'rtc', 'rp']); // `</rb>`, `</rt>`, `</rp>` can be omitted if followed by `<rb>`, `<rt>`, `<rtc>`, or `<rp>`
|
|
309
|
+
|
|
310
|
+
const rubyRtcEndTagOmission = new Set(['rb', 'rtc']); // `</rtc>` can be omitted if followed by `<rb>` or `<rtc>` (not `<rt>` or `<rp>`)
|
|
311
|
+
|
|
312
|
+
const optionElements = new Set(['option', 'optgroup']);
|
|
313
|
+
|
|
314
|
+
const tableContentElements = new Set(['tbody', 'tfoot']);
|
|
315
|
+
|
|
316
|
+
const tableSectionElements = new Set(['thead', 'tbody', 'tfoot']);
|
|
317
|
+
|
|
318
|
+
const cellElements = new Set(['td', 'th']);
|
|
319
|
+
|
|
320
|
+
const topLevelElements = new Set(['html', 'head', 'body']);
|
|
321
|
+
|
|
322
|
+
const compactElements = new Set(['html', 'body']);
|
|
323
|
+
|
|
324
|
+
const looseElements = new Set(['head', 'colgroup', 'caption']);
|
|
325
|
+
|
|
326
|
+
const trailingElements = new Set(['dt', 'thead']);
|
|
327
|
+
|
|
328
|
+
const htmlElements = new Set(['a', 'abbr', 'acronym', 'address', 'applet', 'area', 'article', 'aside', 'audio', 'b', 'base', 'basefont', 'bdi', 'bdo', 'bgsound', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'command', 'content', 'data', 'datalist', 'dd', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'embed', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'iframe', 'image', 'img', 'input', 'ins', 'isindex', 'kbd', 'keygen', 'label', 'legend', 'li', 'link', 'listing', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meta', 'meter', 'multicol', 'nav', 'nobr', 'noembed', 'noframes', 'noscript', 'object', 'ol', 'optgroup', 'option', 'output', 'p', 'param', 'picture', 'plaintext', 'pre', 'progress', 'q', 'rb', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'script', 'search', 'section', 'select', 'selectedcontent', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr', 'xmp']);
|
|
329
|
+
|
|
330
|
+
// Doctype identifiers that set quirks mode, lowercase for their case-insensitive comparison
|
|
331
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#the-initial-insertion-mode
|
|
332
|
+
|
|
333
|
+
const quirksPublicIds = new Set(['-//w3o//dtd w3 html strict 3.0//en//', '-/w3c/dtd html 4.0 transitional/en', 'html']);
|
|
334
|
+
|
|
335
|
+
const quirksSystemIds = new Set(['http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd']);
|
|
336
|
+
|
|
337
|
+
const quirksPublicIdPrefixes = ['+//silmaril//dtd html pro v0r11 19970101//', '-//as//dtd html 3.0 aswedit + extensions//', '-//advasoft ltd//dtd html 3.0 aswedit + extensions//', '-//ietf//dtd html 2.0 level 1//', '-//ietf//dtd html 2.0 level 2//', '-//ietf//dtd html 2.0 strict level 1//', '-//ietf//dtd html 2.0 strict level 2//', '-//ietf//dtd html 2.0 strict//', '-//ietf//dtd html 2.0//', '-//ietf//dtd html 2.1e//', '-//ietf//dtd html 3.0//', '-//ietf//dtd html 3.2 final//', '-//ietf//dtd html 3.2//', '-//ietf//dtd html 3//', '-//ietf//dtd html level 0//', '-//ietf//dtd html level 1//', '-//ietf//dtd html level 2//', '-//ietf//dtd html level 3//', '-//ietf//dtd html strict level 0//', '-//ietf//dtd html strict level 1//', '-//ietf//dtd html strict level 2//', '-//ietf//dtd html strict level 3//', '-//ietf//dtd html strict//', '-//ietf//dtd html//', '-//metrius//dtd metrius presentational//', '-//microsoft//dtd internet explorer 2.0 html strict//', '-//microsoft//dtd internet explorer 2.0 html//', '-//microsoft//dtd internet explorer 2.0 tables//', '-//microsoft//dtd internet explorer 3.0 html strict//', '-//microsoft//dtd internet explorer 3.0 html//', '-//microsoft//dtd internet explorer 3.0 tables//', '-//netscape comm. corp.//dtd html//', '-//netscape comm. corp.//dtd strict html//', '-//o\'reilly and associates//dtd html 2.0//', '-//o\'reilly and associates//dtd html extended 1.0//', '-//o\'reilly and associates//dtd html extended relaxed 1.0//', '-//sq//dtd html 2.0 hotmetal + extensions//', '-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//', '-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//', '-//spyglass//dtd html 2.0 extended//', '-//sun microsystems corp.//dtd hotjava html//', '-//sun microsystems corp.//dtd hotjava strict html//', '-//w3c//dtd html 3 1995-03-24//', '-//w3c//dtd html 3.2 draft//', '-//w3c//dtd html 3.2 final//', '-//w3c//dtd html 3.2//', '-//w3c//dtd html 3.2s draft//', '-//w3c//dtd html 4.0 frameset//', '-//w3c//dtd html 4.0 transitional//', '-//w3c//dtd html experimental 19960712//', '-//w3c//dtd html experimental 970421//', '-//w3c//dtd w3 html//', '-//w3o//dtd w3 html 3.0//', '-//c.0//', '-//webtechs//dtd mozilla html//'];
|
|
338
|
+
|
|
339
|
+
// Prefixes that set quirks mode only without a system identifier or with an empty one
|
|
340
|
+
// (limited-quirks mode otherwise)
|
|
341
|
+
const quirksPublicIdPrefixesNoSystemId = ['-//w3c//dtd html 4.01 frameset//', '-//w3c//dtd html 4.01 transitional//'];
|
|
342
|
+
|
|
343
|
+
const specialContentElements = new Set(['script', 'style']);
|
|
344
|
+
|
|
345
|
+
// Elements the parser reads as raw text as well, though only `script` and `style` are raw text
|
|
346
|
+
// elements by name—these are HTML’s alone, where `script` and `style` hold text in SVG, too
|
|
347
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#generic-raw-text-element-parsing-algorithm
|
|
348
|
+
//
|
|
349
|
+
// (`noscript`, `noframes`, and `noembed` are raw text, too, but stay markup here: What they
|
|
350
|
+
// hold is markup to the UA that displays it—one without scripting or frames—so minifying it
|
|
351
|
+
// as markup keeps what that UA sees)
|
|
352
|
+
const genericRawTextElements = new Set(['iframe', 'plaintext', 'xmp']);
|
|
353
|
+
|
|
354
|
+
// `plaintext` is the one element among these whose content has no end: The text runs to the
|
|
355
|
+
// end of the document, `</plaintext>` and all, as nothing switches the parser back to markup
|
|
356
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#plaintext-state
|
|
357
|
+
const endlessRawTextElements = new Set(['plaintext']);
|
|
358
|
+
|
|
359
|
+
// Escapable raw text elements, whose content is text rather than markup
|
|
360
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#elements-2
|
|
361
|
+
const escapableRawTextElements = new Set(['textarea', 'title']);
|
|
362
|
+
|
|
363
|
+
// Raw text is read without resolving character references, so its text keeps them—unlike that
|
|
364
|
+
// of `textarea` and `title`, where they are resolved as they are anywhere else
|
|
365
|
+
const rawTextElements = new Set([...specialContentElements, ...genericRawTextElements]);
|
|
366
|
+
|
|
367
|
+
// Marks the error for a minifier that was asked for but isn’t available—a
|
|
368
|
+
// configuration error, and so not one that `continueOnMinifyError` waves through
|
|
369
|
+
const MISSING_DEPENDENCY = 'HM_MISSING_DEPENDENCY';
|
|
370
|
+
|
|
371
|
+
// SVGO’s `preset-default` treats an SVG as a file of its own, but an inline SVG’s
|
|
372
|
+
// IDs, `style` rules, hidden sprites, and empty attributes (`[data-v-…]` hooks, `alt=""`)
|
|
373
|
+
// reach into the rest of the document, so the plugins that assume otherwise stay off,
|
|
374
|
+
// and `minifyStyles` keeps the rules the SVG itself does not use
|
|
375
|
+
const svgoPluginsInline = [{
|
|
376
|
+
name: 'preset-default',
|
|
377
|
+
params: {
|
|
378
|
+
overrides: {
|
|
379
|
+
cleanupIds: false,
|
|
380
|
+
inlineStyles: false,
|
|
381
|
+
minifyStyles: { usage: false },
|
|
382
|
+
removeEmptyAttrs: false,
|
|
383
|
+
removeHiddenElems: false,
|
|
384
|
+
removeUnknownsAndDefaults: { keepRoleAttr: true }
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}];
|
|
388
|
+
|
|
389
|
+
// Mixed-case names the HTML parser gives SVG elements and attributes and MathML attributes, keyed
|
|
390
|
+
// by the lowercase it reads every other name as (no lowercase name is both an element and an
|
|
391
|
+
// attribute of different case, so one table serves both)
|
|
392
|
+
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inforeign
|
|
393
|
+
const namesForeignMixedCase = new Map([
|
|
394
|
+
// SVG elements
|
|
395
|
+
'altGlyph', 'altGlyphDef', 'altGlyphItem', 'animateColor', 'animateMotion', 'animateTransform',
|
|
396
|
+
'clipPath', 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix',
|
|
397
|
+
'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA',
|
|
398
|
+
'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode',
|
|
399
|
+
'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile',
|
|
400
|
+
'feTurbulence', 'foreignObject', 'glyphRef', 'linearGradient', 'radialGradient', 'textPath',
|
|
401
|
+
// SVG attributes
|
|
402
|
+
'attributeName', 'attributeType', 'baseFrequency', 'baseProfile', 'calcMode', 'clipPathUnits',
|
|
403
|
+
'diffuseConstant', 'edgeMode', 'filterUnits', 'gradientTransform', 'gradientUnits',
|
|
404
|
+
'kernelMatrix', 'kernelUnitLength', 'keyPoints', 'keySplines', 'keyTimes', 'lengthAdjust',
|
|
405
|
+
'limitingConeAngle', 'markerHeight', 'markerUnits', 'markerWidth', 'maskContentUnits', 'maskUnits',
|
|
406
|
+
'numOctaves', 'pathLength', 'patternContentUnits', 'patternTransform', 'patternUnits', 'pointsAtX',
|
|
407
|
+
'pointsAtY', 'pointsAtZ', 'preserveAlpha', 'preserveAspectRatio', 'primitiveUnits', 'refX', 'refY',
|
|
408
|
+
'repeatCount', 'repeatDur', 'requiredExtensions', 'requiredFeatures', 'specularConstant',
|
|
409
|
+
'specularExponent', 'spreadMethod', 'startOffset', 'stdDeviation', 'stitchTiles', 'surfaceScale',
|
|
410
|
+
'systemLanguage', 'tableValues', 'targetX', 'targetY', 'textLength', 'viewBox', 'viewTarget',
|
|
411
|
+
'xChannelSelector', 'yChannelSelector', 'zoomAndPan',
|
|
412
|
+
// MathML attributes
|
|
413
|
+
'definitionURL'
|
|
414
|
+
].map(name => [name.toLowerCase(), name]));
|
|
415
|
+
|
|
416
|
+
export {
|
|
417
|
+
// Regex patterns
|
|
418
|
+
RE_WS_START,
|
|
419
|
+
RE_WS_END,
|
|
420
|
+
RE_WS_ONLY,
|
|
421
|
+
RE_WS_NBSP_END,
|
|
422
|
+
RE_ALL_WS_NBSP,
|
|
423
|
+
RE_NBSP_LEADING_GROUP,
|
|
424
|
+
RE_NBSP_LEAD_GROUP,
|
|
425
|
+
RE_NBSP_TRAILING_GROUP,
|
|
426
|
+
RE_NBSP_TRAILING_STRIP,
|
|
427
|
+
RE_EVENT_ATTR_DEFAULT,
|
|
428
|
+
RE_CAN_REMOVE_ATTR_QUOTES,
|
|
429
|
+
RE_TRAILING_SEMICOLON,
|
|
430
|
+
RE_AMP_REFERENCE_ATTR,
|
|
431
|
+
RE_CR,
|
|
432
|
+
RE_LINE_BREAK_CR,
|
|
433
|
+
RE_LEGACY_ENTITIES,
|
|
434
|
+
RE_ESCAPE_LT,
|
|
435
|
+
RE_BASE_ELEMENT,
|
|
436
|
+
RE_ESCAPE_LT_RAW_TEXT,
|
|
437
|
+
RE_XML_ESCAPE_TEXT,
|
|
438
|
+
RE_XML_ESCAPE_ATTR,
|
|
439
|
+
RE_HTML_ENCODING,
|
|
440
|
+
RE_DOCTYPE,
|
|
441
|
+
RE_ATTR_WS_CHECK,
|
|
442
|
+
RE_ATTR_WS_COLLAPSE,
|
|
443
|
+
RE_WS_CHAR,
|
|
444
|
+
RE_STYLE_ELEMENT,
|
|
445
|
+
RE_EMPTY_ATTRIBUTE,
|
|
446
|
+
|
|
447
|
+
// Inline element sets
|
|
448
|
+
formattingElements,
|
|
449
|
+
inlineElementsToKeepWhitespaceAround,
|
|
450
|
+
inlineElementsToKeepWhitespaceWithin,
|
|
451
|
+
inlineElementsToKeepWhitespaceBetween,
|
|
452
|
+
inlineElementsToKeepWhitespaceBetweenEnd,
|
|
453
|
+
inlineElementsTransparent,
|
|
454
|
+
inlineElementsTransparentAfter,
|
|
455
|
+
inlineElementsToKeepWhitespace,
|
|
456
|
+
processingInstructionTag,
|
|
457
|
+
formControlElementsEither,
|
|
458
|
+
toEndTags,
|
|
459
|
+
|
|
460
|
+
// Default values
|
|
461
|
+
generalDefaults,
|
|
462
|
+
tagDefaults,
|
|
463
|
+
metaHttpEquivNoEffect,
|
|
464
|
+
metaNamesNoEffect,
|
|
465
|
+
targetSelfElements,
|
|
466
|
+
integrationPointsForeign,
|
|
467
|
+
tagDefaultsSVG,
|
|
468
|
+
svgElementsInheritingByReference,
|
|
469
|
+
namespaceHTML,
|
|
470
|
+
namespaceSVG,
|
|
471
|
+
namespaceMathML,
|
|
472
|
+
namespaceXLink,
|
|
473
|
+
|
|
474
|
+
// Script/style constants
|
|
475
|
+
executableScriptsMimetypes,
|
|
476
|
+
keepScriptsMimetypes,
|
|
477
|
+
jsonScriptTypes,
|
|
478
|
+
|
|
479
|
+
// Boolean sets
|
|
480
|
+
isSimpleBoolean,
|
|
481
|
+
isBooleanValue,
|
|
482
|
+
collapsibleValues,
|
|
483
|
+
|
|
484
|
+
// Misc
|
|
485
|
+
srcsetElements,
|
|
486
|
+
MISSING_DEPENDENCY,
|
|
487
|
+
namesForeignMixedCase,
|
|
488
|
+
svgoPluginsInline,
|
|
489
|
+
|
|
490
|
+
// Tag omission rules
|
|
491
|
+
optionalStartTags,
|
|
492
|
+
optionalEndTags,
|
|
493
|
+
headerElements,
|
|
494
|
+
descriptionElements,
|
|
495
|
+
pBlockElements,
|
|
496
|
+
pClosingParents,
|
|
497
|
+
rubyEndTagOmission,
|
|
498
|
+
rubyRtcEndTagOmission,
|
|
499
|
+
optionElements,
|
|
500
|
+
tableContentElements,
|
|
501
|
+
tableSectionElements,
|
|
502
|
+
cellElements,
|
|
503
|
+
topLevelElements,
|
|
504
|
+
compactElements,
|
|
505
|
+
looseElements,
|
|
506
|
+
trailingElements,
|
|
507
|
+
htmlElements,
|
|
508
|
+
|
|
509
|
+
// Doctype identifiers
|
|
510
|
+
quirksPublicIds,
|
|
511
|
+
quirksSystemIds,
|
|
512
|
+
quirksPublicIdPrefixes,
|
|
513
|
+
quirksPublicIdPrefixesNoSystemId,
|
|
514
|
+
|
|
515
|
+
// Special content elements
|
|
516
|
+
specialContentElements,
|
|
517
|
+
genericRawTextElements,
|
|
518
|
+
endlessRawTextElements,
|
|
519
|
+
escapableRawTextElements,
|
|
520
|
+
rawTextElements
|
|
521
|
+
};
|