Skip to content

Commit efe1df0

Browse files
authored
[fix] Only show lowercase component warning for non-html/svg elements (#7826)
Fixes #5712
1 parent af64ad9 commit efe1df0

File tree

5 files changed

+28
-13
lines changed

5 files changed

+28
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* Improve a11y `label-has-associated-control` check to recusively check for input control ([#5528](https://github.com/sveltejs/svelte/issues/5528))
1717
* Fix class directive updates after half way transition [#7764](https://github.com/sveltejs/svelte/issues/7764)
1818
* Improve parsing speed when encountering large blocks of whitespace [#7675](https://github.com/sveltejs/svelte/issues/7675)
19+
* Only show lowercase component warning for non-html/svg elements [#5712](https://github.com/sveltejs/svelte/issues/5712)
1920

2021
## 3.49.0
2122

src/compiler/compile/nodes/Element.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { is_void } from '../../../shared/utils/names';
1+
import { is_html, is_svg, is_void } from '../../../shared/utils/names';
22
import Node from './shared/Node';
33
import Attribute from './Attribute';
44
import Binding from './Binding';
@@ -26,8 +26,6 @@ import compiler_errors from '../compiler_errors';
2626
import { ARIARoleDefintionKey, roles, aria, ARIAPropertyDefinition, ARIAProperty } from 'aria-query';
2727
import { is_interactive_element, is_non_interactive_roles, is_presentation_role } from '../utils/a11y';
2828

29-
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
30-
3129
const aria_attributes = 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split(' ');
3230
const aria_attribute_set = new Set(aria_attributes);
3331

@@ -166,13 +164,13 @@ function get_namespace(parent: Element, element: Element, explicit_namespace: st
166164
const parent_element = parent.find_nearest(/^Element/);
167165

168166
if (!parent_element) {
169-
return explicit_namespace || (svg.test(element.name)
167+
return explicit_namespace || (is_svg(element.name)
170168
? namespaces.svg
171169
: null);
172170
}
173171

174172
if (parent_element.namespace !== namespaces.foreign) {
175-
if (svg.test(element.name.toLowerCase())) return namespaces.svg;
173+
if (is_svg(element.name.toLowerCase())) return namespaces.svg;
176174
if (parent_element.name.toLowerCase() === 'foreignobject') return null;
177175
}
178176

@@ -373,7 +371,7 @@ export default class Element extends Node {
373371
}
374372

375373
validate() {
376-
if (this.component.var_lookup.has(this.name) && this.component.var_lookup.get(this.name).imported) {
374+
if (this.component.var_lookup.has(this.name) && this.component.var_lookup.get(this.name).imported && !is_svg(this.name) && !is_html(this.name)) {
377375
this.component.warn(this, compiler_warnings.component_name_lowercase(this.name));
378376
}
379377

@@ -827,7 +825,7 @@ export default class Element extends Node {
827825
} else if (dimensions.test(name)) {
828826
if (this.name === 'svg' && (name === 'offsetWidth' || name === 'offsetHeight')) {
829827
return component.error(binding, compiler_errors.invalid_binding_on(binding.name, `<svg>. Use '${name.replace('offset', 'client')}' instead`));
830-
} else if (svg.test(this.name)) {
828+
} else if (is_svg(this.name)) {
831829
return component.error(binding, compiler_errors.invalid_binding_on(binding.name, 'SVG elements'));
832830
} else if (is_void(this.name)) {
833831
return component.error(binding, compiler_errors.invalid_binding_on(binding.name, `void elements like <${this.name}>. Use a wrapper element instead`));

src/shared/utils/names.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
1+
/** regex of all html void element names */
12
const void_element_names = /^(?:area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/;
3+
/** regex of all html element names. svg and math are omitted because they belong to the svg elements namespace */
4+
const html_element_names = /^(?:a|abbr|address|area|article|aside|audio|b|base|bdi|bdo|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|data|datalist|dd|del|details|dfn|dialog|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|head|header|hr|html|i|iframe|img|input|ins|kbd|label|legend|li|link|main|map|mark|meta|meter|nav|noscript|object|ol|optgroup|option|output|p|param|picture|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strong|style|sub|summary|sup|table|tbody|td|template|textarea|tfoot|th|thead|time|title|tr|track|u|ul|var|video|wbr)$/;
5+
/** regex of all svg element names */
6+
const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|svg|switch|symbol|text|textPath|tref|tspan|unknown|use|view|vkern)$/;
27

38
export function is_void(name: string) {
49
return void_element_names.test(name) || name.toLowerCase() === '!doctype';
510
}
11+
12+
export function is_html(name: string) {
13+
return html_element_names.test(name);
14+
}
15+
16+
export function is_svg(name: string) {
17+
return svg.test(name);
18+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<script>
22
import thisShouldWarnMe from './MyComponent.svelte';
3+
import { form } from './form';
34
let i;
5+
form;
46
</script>
57

68
<thisShouldWarnMe />
7-
<i />
9+
<i />
10+
<form />

test/validator/samples/component-name-lowercase/warnings.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22
{
33
"code": "component-name-lowercase",
44
"message": "<thisShouldWarnMe> will be treated as an HTML element unless it begins with a capital letter",
5-
"pos": 82,
5+
"pos": 121,
66
"start": {
7-
"character": 82,
7+
"character": 121,
88
"column": 0,
9-
"line": 6
9+
"line": 8
1010
},
1111
"end": {
12-
"character": 102,
12+
"character": 141,
1313
"column": 20,
14-
"line": 6
14+
"line": 8
1515
}
1616
}
1717
]

0 commit comments

Comments
 (0)