fix: warn when using rest or identifier in custom elements without props option (#16003)

* fix: warn when using rest or identifier in custom elements without props option

* chore: update message

* tweak message

* update tests

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/16010/head
Paolo Ricciuti 3 months ago committed by GitHub
parent 4e3ff0944d
commit 37488fa65c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: warn when using rest or identifier in custom elements without props option

@ -632,6 +632,12 @@ In some situations a selector may target an element that is not 'visible' to the
</style>
```
### custom_element_props_identifier
```
Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.
```
### element_implicitly_closed
```

@ -1,3 +1,7 @@
## custom_element_props_identifier
> Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.
## export_let_unused
> Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%`

@ -4,6 +4,7 @@
import { get_rune } from '../../scope.js';
import { ensure_no_module_import_conflict, validate_identifier_name } from './shared/utils.js';
import * as e from '../../../errors.js';
import * as w from '../../../warnings.js';
import { extract_paths } from '../../../utils/ast.js';
import { equal } from '../../../utils/assert.js';
@ -52,6 +53,19 @@ export function VariableDeclarator(node, context) {
e.props_invalid_identifier(node);
}
if (
context.state.analysis.custom_element &&
context.state.options.customElementOptions?.props == null
) {
let warn_on;
if (
node.id.type === 'Identifier' ||
(warn_on = node.id.properties.find((p) => p.type === 'RestElement')) != null
) {
w.custom_element_props_identifier(warn_on ?? node.id);
}
}
context.state.analysis.needs_props = true;
if (node.id.type === 'Identifier') {

@ -96,6 +96,7 @@ export const codes = [
'options_removed_hydratable',
'options_removed_loop_guard_timeout',
'options_renamed_ssr_dom',
'custom_element_props_identifier',
'export_let_unused',
'legacy_component_creation',
'non_reactive_update',
@ -592,6 +593,14 @@ export function options_renamed_ssr_dom(node) {
w(node, 'options_renamed_ssr_dom', `\`generate: "dom"\` and \`generate: "ssr"\` options have been renamed to "client" and "server" respectively\nhttps://svelte.dev/e/options_renamed_ssr_dom`);
}
/**
* Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.
* @param {null | NodeLike} node
*/
export function custom_element_props_identifier(node) {
w(node, 'custom_element_props_identifier', `Using a rest element or a non-destructured declaration with \`$props()\` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the \`customElement.props\` option.\nhttps://svelte.dev/e/custom_element_props_identifier`);
}
/**
* Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%`
* @param {null | NodeLike} node

@ -0,0 +1,7 @@
<svelte:options customElement={{
props: {}
}} />
<script>
let props = $props();
</script>

@ -0,0 +1,14 @@
[
{
"code": "options_missing_custom_element",
"end": {
"column": 2,
"line": 3
},
"message": "The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?",
"start": {
"column": 16,
"line": 1
}
}
]

@ -0,0 +1,5 @@
<svelte:options customElement={{}} />
<script>
let { ...props } = $props();
</script>

@ -0,0 +1,26 @@
[
{
"code": "options_missing_custom_element",
"end": {
"column": 34,
"line": 1
},
"message": "The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?",
"start": {
"column": 16,
"line": 1
}
},
{
"code": "custom_element_props_identifier",
"end": {
"column": 15,
"line": 4
},
"message": "Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.",
"start": {
"column": 7,
"line": 4
}
}
]

@ -0,0 +1,5 @@
<svelte:options customElement={{}} />
<script>
let props = $props();
</script>

@ -0,0 +1,26 @@
[
{
"code": "options_missing_custom_element",
"end": {
"column": 34,
"line": 1
},
"message": "The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?",
"start": {
"column": 16,
"line": 1
}
},
{
"code": "custom_element_props_identifier",
"end": {
"column": 10,
"line": 4
},
"message": "Using a rest element or a non-destructured declaration with `$props()` means that Svelte can't infer what properties to expose when creating a custom element. Consider destructuring all the props or explicitly specifying the `customElement.props` option.",
"start": {
"column": 5,
"line": 4
}
}
]
Loading…
Cancel
Save