Skip to content

Commit a45ad5d

Browse files
authored
chore: dedupe void element lists (#12690)
* chore: dedupe void element lists * fix
1 parent 44a1324 commit a45ad5d

File tree

9 files changed

+40
-71
lines changed

9 files changed

+40
-71
lines changed

packages/svelte/src/compiler/phases/1-parse/state/element.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/** @import { Expression } from 'estree' */
22
/** @import * as Compiler from '#compiler' */
33
/** @import { Parser } from '../index.js' */
4-
import { is_void } from '../../../../constants.js';
4+
import { is_void } from '../../../../utils.js';
55
import read_expression from '../read/expression.js';
66
import { read_script } from '../read/script.js';
77
import read_style from '../read/style.js';

packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
/** @import { RegularElement } from '#compiler' */
22
/** @import { Context } from '../types' */
3+
import { is_void } from '../../../../utils.js';
34
import {
45
is_tag_valid_with_ancestor,
56
is_tag_valid_with_parent
67
} from '../../../../html-tree-validation.js';
78
import * as e from '../../../errors.js';
89
import * as w from '../../../warnings.js';
9-
import { MathMLElements, SVGElements, VoidElements } from '../../constants.js';
10+
import { MathMLElements, SVGElements } from '../../constants.js';
1011
import { create_attribute } from '../../nodes.js';
1112
import { regex_starts_with_newline } from '../../patterns.js';
1213
import { check_element } from './shared/a11y.js';
@@ -157,7 +158,7 @@ export function RegularElement(node, context) {
157158
if (
158159
context.state.analysis.source[node.end - 2] === '/' &&
159160
context.state.options.namespace !== 'foreign' &&
160-
!VoidElements.includes(node_name) &&
161+
!is_void(node_name) &&
161162
!SVGElements.includes(node_name)
162163
) {
163164
w.element_invalid_self_closing_tag(node, node.name);

packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
/** @import { ComponentClientTransformState, ComponentContext } from '../types' */
55
/** @import { Scope } from '../../../scope' */
66
import { DOMBooleanAttributes } from '../../../../../constants.js';
7+
import { is_void } from '../../../../../utils.js';
78
import { escape_html } from '../../../../../escaping.js';
89
import { dev, is_ignored, locator } from '../../../../state.js';
910
import {
@@ -12,7 +13,7 @@ import {
1213
is_text_attribute
1314
} from '../../../../utils/ast.js';
1415
import * as b from '../../../../utils/builders.js';
15-
import { DOMProperties, LoadErrorElements, VoidElements } from '../../../constants.js';
16+
import { DOMProperties, LoadErrorElements } from '../../../constants.js';
1617
import { is_custom_element_node } from '../../../nodes.js';
1718
import { clean_nodes, determine_namespace_for_children } from '../../utils.js';
1819
import { serialize_get_binding } from '../utils.js';
@@ -358,7 +359,7 @@ export function RegularElement(node, context) {
358359
location.push(child_locations);
359360
}
360361

361-
if (!VoidElements.includes(node.name)) {
362+
if (!is_void(node.name)) {
362363
context.state.template.push(`</${node.name}>`);
363364
}
364365
}

packages/svelte/src/compiler/phases/3-transform/server/visitors/RegularElement.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
/** @import { RegularElement, Text } from '#compiler' */
33
/** @import { ComponentContext, ComponentServerTransformState } from '../types.js' */
44
/** @import { Scope } from '../../../scope.js' */
5+
import { is_void } from '../../../../../utils.js';
56
import { dev, locator } from '../../../../state.js';
67
import * as b from '../../../../utils/builders.js';
7-
import { VoidElements } from '../../../constants.js';
88
import { clean_nodes, determine_namespace_for_children } from '../../utils.js';
99
import { serialize_element_attributes } from './shared/element.js';
1010
import { process_children, serialize_template } from './shared/utils.js';
@@ -95,7 +95,7 @@ export function RegularElement(node, context) {
9595
);
9696
}
9797

98-
if (!VoidElements.includes(node.name) || namespace === 'foreign') {
98+
if (!is_void(node.name) || namespace === 'foreign') {
9999
state.template.push(b.literal(`</${node.name}>`));
100100
}
101101

packages/svelte/src/compiler/phases/constants.js

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,6 @@ export const DOMProperties = [
88
...DOMBooleanAttributes
99
];
1010

11-
export const VoidElements = [
12-
'area',
13-
'base',
14-
'br',
15-
'col',
16-
'embed',
17-
'hr',
18-
'img',
19-
'input',
20-
'keygen',
21-
'link',
22-
'menuitem',
23-
'meta',
24-
'param',
25-
'source',
26-
'track',
27-
'wbr'
28-
];
29-
3011
export const PassiveEvents = ['wheel', 'touchstart', 'touchmove', 'touchend', 'touchcancel'];
3112

3213
export const Runes = /** @type {const} */ ([

packages/svelte/src/constants.js

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -180,25 +180,6 @@ export const reserved = [
180180
'yield'
181181
];
182182

183-
const void_element_names = [
184-
'area',
185-
'base',
186-
'br',
187-
'col',
188-
'command',
189-
'embed',
190-
'hr',
191-
'img',
192-
'input',
193-
'keygen',
194-
'link',
195-
'meta',
196-
'param',
197-
'source',
198-
'track',
199-
'wbr'
200-
];
201-
202183
// we use a list of ignorable runtime warnings because not every runtime warning
203184
// can be ignored and we want to keep the validation for svelte-ignore in place
204185
export const IGNORABLE_RUNTIME_WARNINGS = /** @type {const} */ ([
@@ -209,8 +190,3 @@ export const IGNORABLE_RUNTIME_WARNINGS = /** @type {const} */ ([
209190
'ownership_invalid_binding',
210191
'ownership_invalid_mutation'
211192
]);
212-
213-
/** @param {string} name */
214-
export function is_void(name) {
215-
return void_element_names.includes(name) || name.toLowerCase() === '!doctype';
216-
}

packages/svelte/src/internal/server/index.js

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,19 @@ import {
1111
ELEMENT_PRESERVE_ATTRIBUTE_CASE,
1212
ELEMENT_IS_NAMESPACED
1313
} from '../../constants.js';
14+
1415
import { escape_html } from '../../escaping.js';
1516
import { DEV } from 'esm-env';
1617
import { current_component, pop, push } from './context.js';
1718
import { EMPTY_COMMENT, BLOCK_CLOSE, BLOCK_OPEN } from './hydration.js';
1819
import { validate_store } from '../shared/validate.js';
20+
import { is_void } from '../../utils.js';
1921

2022
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
2123
// https://infra.spec.whatwg.org/#noncharacter
2224
const INVALID_ATTR_NAME_CHAR_REGEX =
2325
/[\s'">/=\u{FDD0}-\u{FDEF}\u{FFFE}\u{FFFF}\u{1FFFE}\u{1FFFF}\u{2FFFE}\u{2FFFF}\u{3FFFE}\u{3FFFF}\u{4FFFE}\u{4FFFF}\u{5FFFE}\u{5FFFF}\u{6FFFE}\u{6FFFF}\u{7FFFE}\u{7FFFF}\u{8FFFE}\u{8FFFF}\u{9FFFE}\u{9FFFF}\u{AFFFE}\u{AFFFF}\u{BFFFE}\u{BFFFF}\u{CFFFE}\u{CFFFF}\u{DFFFE}\u{DFFFF}\u{EFFFE}\u{EFFFF}\u{FFFFE}\u{FFFFF}\u{10FFFE}\u{10FFFF}]/u;
2426

25-
export const VoidElements = new Set([
26-
'area',
27-
'base',
28-
'br',
29-
'col',
30-
'embed',
31-
'hr',
32-
'img',
33-
'input',
34-
'keygen',
35-
'link',
36-
'menuitem',
37-
'meta',
38-
'param',
39-
'source',
40-
'track',
41-
'wbr'
42-
]);
43-
4427
/**
4528
* @param {Payload} to_copy
4629
* @returns {Payload}
@@ -82,7 +65,7 @@ export function element(payload, tag, attributes_fn = noop, children_fn = noop)
8265
attributes_fn();
8366
payload.out += `>`;
8467

85-
if (!VoidElements.has(tag)) {
68+
if (!is_void(tag)) {
8669
children_fn();
8770
if (!RawTextElements.includes(tag)) {
8871
payload.out += EMPTY_COMMENT;

packages/svelte/src/internal/shared/validate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/** @import { TemplateNode } from '#client' */
22
/** @import { Getters } from '#shared' */
3-
import { is_void } from '../../constants.js';
3+
import { is_void } from '../../utils.js';
44
import * as w from './warnings.js';
55
import * as e from './errors.js';
66

packages/svelte/src/utils.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,30 @@ export function hash(str) {
1212
while (i--) hash = ((hash << 5) - hash) ^ str.charCodeAt(i);
1313
return (hash >>> 0).toString(36);
1414
}
15+
16+
const VOID_ELEMENT_NAMES = [
17+
'area',
18+
'base',
19+
'br',
20+
'col',
21+
'command',
22+
'embed',
23+
'hr',
24+
'img',
25+
'input',
26+
'keygen',
27+
'link',
28+
'meta',
29+
'param',
30+
'source',
31+
'track',
32+
'wbr'
33+
];
34+
35+
/**
36+
* Returns `true` if `name` is of a void element
37+
* @param {string} name
38+
*/
39+
export function is_void(name) {
40+
return VOID_ELEMENT_NAMES.includes(name) || name.toLowerCase() === '!doctype';
41+
}

0 commit comments

Comments
 (0)