diff --git a/.changeset/nine-cobras-stare.md b/.changeset/nine-cobras-stare.md new file mode 100644 index 000000000000..9b48f256e6dc --- /dev/null +++ b/.changeset/nine-cobras-stare.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +feat: warn for lowercase `object.component` rendering \ No newline at end of file diff --git a/packages/svelte/messages/compile-warnings/template.md b/packages/svelte/messages/compile-warnings/template.md index 58a251c729f9..3bd2ff4878ce 100644 --- a/packages/svelte/messages/compile-warnings/template.md +++ b/packages/svelte/messages/compile-warnings/template.md @@ -38,6 +38,10 @@ > Using `on:%name%` to listen to the %name% event is deprecated. Use the event attribute `on%name%` instead +## lowercase_component_rendering + +> Are you trying to render `%component%`? Component names should be uppercase. + ## node_invalid_placement_ssr > %thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js index 5c15f70ba2d5..4c2f696e661b 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js @@ -78,6 +78,16 @@ export function RegularElement(node, context) { } const binding = context.state.scope.get(node.name); + + if (context.state.analysis.runes && node.name.includes('.')) { + const [maybe_object] = node.name.split('.'); + const object_binding = context.state.scope.get(maybe_object); + + if (object_binding) { + w.lowercase_component_rendering(node, node.name); + } + } + if ( binding !== null && binding.declaration_kind === 'import' && diff --git a/packages/svelte/src/compiler/warnings.js b/packages/svelte/src/compiler/warnings.js index facd53cdec92..1e2153cd3760 100644 --- a/packages/svelte/src/compiler/warnings.js +++ b/packages/svelte/src/compiler/warnings.js @@ -115,6 +115,7 @@ export const codes = [ "component_name_lowercase", "element_invalid_self_closing_tag", "event_directive_deprecated", + "lowercase_component_rendering", "node_invalid_placement_ssr", "slot_element_deprecated", "svelte_element_invalid_this" @@ -749,6 +750,15 @@ export function event_directive_deprecated(node, name) { w(node, "event_directive_deprecated", `Using \`on:${name}\` to listen to the ${name} event is deprecated. Use the event attribute \`on${name}\` instead`); } +/** + * Are you trying to render `%component%`? Component names should be uppercase. + * @param {null | NodeLike} node + * @param {string} component + */ +export function lowercase_component_rendering(node, component) { + w(node, "lowercase_component_rendering", `Are you trying to render \`${component}\`? Component names should be uppercase.`); +} + /** * %thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning * @param {null | NodeLike} node diff --git a/packages/svelte/tests/validator/samples/lowercase-component-rendering/input.svelte b/packages/svelte/tests/validator/samples/lowercase-component-rendering/input.svelte new file mode 100644 index 000000000000..042c9d4f0645 --- /dev/null +++ b/packages/svelte/tests/validator/samples/lowercase-component-rendering/input.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/validator/samples/lowercase-component-rendering/warnings.json b/packages/svelte/tests/validator/samples/lowercase-component-rendering/warnings.json new file mode 100644 index 000000000000..742e8bdf5999 --- /dev/null +++ b/packages/svelte/tests/validator/samples/lowercase-component-rendering/warnings.json @@ -0,0 +1,14 @@ +[ + { + "code": "lowercase_component_rendering", + "message": "Are you trying to render `component.component`? Component names should be uppercase.", + "start": { + "line": 5, + "column": 0 + }, + "end": { + "line": 5, + "column": 43 + } + } +]