chore: tidy up messages (#11327)

* start reorganising messages

* tidy up

* more

* more

* more

* alphabetise

* consolidate

* more

* more

* more

* more

* more

* more

* alphabetise

* more

* this is no longer needed

* no longer necessary

* more

* more

* fix

* regenerate messages

* more

* more

* tighten up rune validation

* more

* fix

* more

* tweak a11y messages

* add server errors

* overhaul runtime errors

* regenerate messages

* unused

* lint

* more

* more

* Update packages/svelte/messages/compile-errors/script.md

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>

* Update packages/svelte/messages/client-warnings/warnings.md

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>

* fix

---------

Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com>
pull/11333/head
Rich Harris 2 months ago committed by GitHub
parent 6ad5cd4461
commit 8e17428316
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -7,7 +7,9 @@ packages/svelte/src/compiler/errors.js
packages/svelte/src/compiler/warnings.js
packages/svelte/src/internal/client/errors.js
packages/svelte/src/internal/client/warnings.js
packages/svelte/src/internal/shared/errors.js
packages/svelte/src/internal/shared/warnings.js
packages/svelte/src/internal/server/errors.js
packages/svelte/tests/**/*.svelte
packages/svelte/tests/**/_expected*
packages/svelte/tests/**/_actual*

@ -1,3 +0,0 @@
## effect_update_depth_exceeded
> Maximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops

@ -0,0 +1,67 @@
## bind_invalid_checkbox_value
> Using `bind:value` together with a checkbox input is not allowed. Use `bind:checked` instead
## bind_invalid_export
> Component %component% has an export named `%key%` that a consumer component is trying to access using `bind:%key%`, which is disallowed. Instead, use `bind:this` (e.g. `<%name% bind:this={component} />`) and then access the property on the bound component instance (e.g. `component.%key%`)
## bind_not_bindable
> A component is attempting to bind to a non-bindable property `%key%` belonging to %component% (i.e. `<%name% bind:%key%={...}>`). To mark a property as bindable: `let { %key% = $bindable() } = $props()`
## each_key_duplicate
> Keyed each block has duplicate key at indexes %a% and %b%
> Keyed each block has duplicate key `%value%` at indexes %a% and %b%
## effect_in_teardown
> `%rune%` cannot be used inside an effect cleanup function
## effect_orphan
> `%rune%` can only be used inside an effect (e.g. during component initialisation)
## effect_update_depth_exceeded
> Maximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops
## hydration_missing_marker_close
> Missing hydration closing marker
## hydration_missing_marker_open
> Missing hydration opening marker
## lifecycle_legacy_only
> `%name%(...)` cannot be used in runes mode
## props_invalid_value
> Cannot do `bind:%key%={undefined}` when `%key%` has a fallback value
## props_rest_readonly
> Rest element properties of `$props()` such as `%property%` are readonly
## rune_outside_svelte
> The `%rune%` rune is only available inside `.svelte` and `.svelte.js/ts` files
## state_prototype_fixed
> Cannot set prototype of `$state` object
## state_unsafe_mutation
> Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. This can lead to unexpected errors and possibly cause infinite loops.
>
> If the object is not meant to be reactive, declare it without `$state`
## svelte_component_invalid_this_value
> The `this={...}` property of a `<svelte:component>` must be a Svelte component, if defined

@ -1,7 +0,0 @@
## lifecycle_outside_component
> `%name%(...)` can only be used during component initialisation
## lifecycle_legacy_only
> `%name%(...)` cannot be used in runes mode

@ -1,3 +1,11 @@
## hydration_attribute_changed
> The `%attribute%` attribute on `%html%` changed its value between server and client renders. The client value, `%value%`, will be ignored in favour of the server value
## hydration_mismatch
> Hydration failed because the initial UI does not match what was rendered on the server
## lifecycle_double_unmount
> Tried to unmount a component that was not mounted

@ -1,59 +0,0 @@
## empty_attribute_shorthand
> Attribute shorthand cannot be empty
## duplicate_attribute
> Attributes need to be unique
## invalid_event_attribute_value
> Event attribute must be a JavaScript expression, not a string
## invalid_attribute_name
> '%name%' is not a valid attribute name
## animation_invalid_placement
> An element that uses the `animate:` directive must be the only child of a keyed `{#each ...}` block
## animation_missing_key
> An element that uses the `animate:` directive must be the only child of a keyed `{#each ...}` block. Did you forget to add a key to your each block?
## animation_duplicate
> An element can only have one 'animate' directive
## invalid_event_modifier
> Valid event modifiers are %list%
## invalid_component_event_modifier
> Event modifiers other than 'once' can only be used on DOM elements
## invalid_event_modifier_combination
> The '%modifier1%' and '%modifier2%' modifiers cannot be used together
## transition_duplicate
> Cannot use multiple `%type%:` directives on a single element
## transition_conflict
> Cannot use `%type%:` alongside existing `%existing%:` directive
## invalid_let_directive_placement
> `let:` directive at invalid position
## invalid_style_directive_modifier
> Invalid 'style:' modifier. Valid modifiers are: 'important'
## invalid_sequence_expression
> Sequence expressions are not allowed as attribute/directive values in runes mode, unless wrapped in parentheses

@ -1,33 +0,0 @@
## invalid_binding_expression
> Can only bind to an Identifier or MemberExpression
## invalid_binding_value
> Can only bind to state or props
## bind_invalid_target
> `bind:%name%` can only be used with %elements%
## bind_invalid
> `bind:%name%` is not a valid binding
> `bind:%name%` is not a valid binding. %explanation%
## invalid_type_attribute
> 'type' attribute must be a static text value if input uses two-way binding
## invalid_multiple_attribute
> 'multiple' attribute must be static if select uses two-way binding
## missing_contenteditable_attribute
> 'contenteditable' attribute is required for textContent, innerHTML and innerText two-way bindings
## dynamic_contenteditable_attribute
> 'contenteditable' attribute cannot be dynamic if element uses two-way binding

@ -1,7 +0,0 @@
## invalid_compiler_option
> Invalid compiler option: %msg%
## removed_compiler_option
> Invalid compiler option: %msg%

@ -1,3 +0,0 @@
## invalid_component_directive
> This type of directive is not valid on components

@ -1,3 +0,0 @@
## invalid_const_placement
> {@const} must be the immediate child of {#snippet}, {#if}, {:else if}, {:else}, {#each}, {:then}, {:catch}, <svelte:fragment> or <Component>

@ -1,27 +0,0 @@
## invalid_textarea_content
> A `<textarea>` can have either a value attribute or (equivalently) child content, but not both
## invalid_void_content
> Void elements cannot have children or closing tags
## invalid_element_content
> <%name%> cannot have children
## invalid_tag_name
> Expected valid tag name
## invalid_node_placement
> %thing% is invalid inside <%parent%>
## illegal_title_attribute
> `<title>` cannot have attributes nor directives
## invalid_title_content
> `<title>` can only contain text and {tags}

@ -1,3 +0,0 @@
## cyclical_reactive_declaration
> Cyclical dependency detected: %cycle%

@ -0,0 +1,11 @@
## options_invalid_value
> Invalid compiler option: %details%
## options_removed
> Invalid compiler option: %details%
## options_unrecognised
> Unrecognised compiler option %keypath%

@ -1,147 +0,0 @@
## unclosed_element
> `<%name%>` was left open
## unclosed_block
> Block was left open
## unexpected_block_close
> Unexpected block closing tag
## unexpected_eof
> Unexpected end of input
## js_parse_error
> %message%
## expected_token
> Expected token %token%
## unexpected_reserved_word
> '%word%' is a reserved word in JavaScript and cannot be used here
## missing_whitespace
> Expected whitespace
## expected_pattern
> Expected identifier or destructure pattern
## invalid_script_context
> If the context attribute is supplied, its value must be "module"
## invalid_elseif
> 'elseif' should be 'else if'
## invalid_continuing_block_placement
> {:...} block is invalid at this position (did you forget to close the preceeding element or block?)
## invalid_block_missing_parent
> %child% block must be a child of %parent%
## duplicate_block_part
> %name% cannot appear more than once within a block
## expected_block_type
> Expected 'if', 'each', 'await', 'key' or 'snippet'
## expected_identifier
> Expected an identifier
## invalid_debug
> {@debug ...} arguments must be identifiers, not arbitrary expressions
## invalid_const
> {@const ...} must be an assignment
## invalid_block_placement
> {#%name% ...} block cannot be %location%
## invalid_tag_placement
> {@%name% ...} tag cannot be %location%
## missing_attribute_value
> Expected attribute value
## unclosed_attribute_value
> Expected closing %delimiter% character
## invalid_directive_value
> Directive value must be a JavaScript expression enclosed in curly braces
## empty_directive_name
> %type% name cannot be empty
## invalid_closing_tag
> </%name%> attempted to close an element that was not open
## invalid_closing_tag_after_autoclose
> </%name%> attempted to close element that was already automatically closed by <%reason%> (cannot nest <%reason%> inside <%name%>)
## invalid_dollar_binding
> The $ name is reserved, and cannot be used for variables and imports
## invalid_dollar_prefix
> The $ prefix is reserved, and cannot be used for variables and imports
## invalid_dollar_global
> The $ name is reserved. To reference a global variable called $, use globalThis.$
## illegal_subscription
> Cannot reference store value inside `<script context="module">`
## duplicate_style_element
> A component can have a single top-level `<style>` element
## duplicate_script_element
> A component can have a single top-level `<script>` element and/or a single top-level `<script context="module">` element
## invalid_render_expression
> {@render ...} tags can only contain call expressions
## invalid_render_arguments
> expected at most one argument
## invalid_render_call
> Calling a snippet function using apply, bind or call is not allowed
## invalid_render_spread_argument
> cannot use spread arguments in {@render ...} tags
## invalid_snippet_rest_parameter
> snippets do not support rest parameters; use an array instead

@ -1,95 +0,0 @@
## invalid_legacy_props
> Cannot use `$$props` in runes mode
## invalid_legacy_rest_props
> Cannot use `$$restProps` in runes mode
## invalid_legacy_reactive_statement
> `$:` is not allowed in runes mode, use `$derived` or `$effect` instead
## invalid_legacy_export
> Cannot use `export let` in runes mode — use $props instead
## invalid_rune_usage
> Cannot use %rune% rune in non-runes mode
## invalid_state_export
> Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties
## invalid_derived_export
> Cannot export derived state from a module. To expose the current derived value, export a function returning its value
## invalid_props_id
> `$props()` can only be used with an object destructuring pattern
## invalid_props_pattern
> `$props()` assignment must not contain nested properties or computed keys
## invalid_props_location
> `$props()` can only be used at the top level of components as a variable declaration initializer
## invalid_bindable_location
> `$bindable()` can only be used inside a `$props()` declaration
## invalid_state_location
> `%rune%(...)` can only be used as a variable declaration initializer or a class field
## invalid_effect_location
> `$effect()` can only be used as an expression statement
## invalid_host_location
> `$host()` can only be used inside custom element component instances
## invalid_assignment
> Cannot assign to %thing%
## invalid_binding
> Cannot bind to %thing%
## invalid_rune_args
> `%rune%` cannot be called with arguments
## invalid_rune_args_length
> `%rune%` must be called with %args%
## invalid_runes_mode_import
> %name% cannot be used in runes mode
## duplicate_props_rune
> Cannot use `$props()` more than once
## invalid_each_assignment
> Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`)
## invalid_snippet_assignment
> Cannot reassign or bind to snippet parameter
## invalid_derived_call
> `$derived.call(...)` has been replaced with `$derived.by(...)`
## conflicting_property_name
> Cannot have a property and a component export with the same name

@ -0,0 +1,135 @@
## bindable_invalid_location
> `$bindable()` can only be used inside a `$props()` declaration
## constant_assignment
> Cannot assign to %thing%
## constant_binding
> Cannot bind to %thing%
## declaration_duplicate
> `%name%` has already been declared
## declaration_duplicate_module_import
> Cannot declare same variable name which is imported inside `<script context="module">`
## derived_invalid_export
> Cannot export derived state from a module. To expose the current derived value, export a function returning its value
## dollar_binding_invalid
> The $ name is reserved, and cannot be used for variables and imports
## dollar_prefix_invalid
> The $ prefix is reserved, and cannot be used for variables and imports
## each_item_invalid_assignment
> Cannot reassign or bind to each block argument in runes mode. Use the array and index variables instead (e.g. `array[i] = value` instead of `entry = value`)
## effect_invalid_placement
> `$effect()` can only be used as an expression statement
## global_reference_invalid
> `%name%` is an illegal variable name. To reference a global variable called `%name%`, use `globalThis.%name%`
## host_invalid_placement
> `$host()` can only be used inside custom element component instances
## legacy_export_invalid
> Cannot use `export let` in runes mode — use `$props()` instead
## legacy_props_invalid
> Cannot use `$$props` in runes mode
## legacy_reactive_statement_invalid
> `$:` is not allowed in runes mode, use `$derived` or `$effect` instead
## legacy_rest_props_invalid
> Cannot use `$$restProps` in runes mode
## module_illegal_default_export
> A component cannot have a default export
## props_duplicate
> Cannot use `$props()` more than once
## props_invalid_identifier
> `$props()` can only be used with an object destructuring pattern
## props_invalid_pattern
> `$props()` assignment must not contain nested properties or computed keys
## props_invalid_placement
> `$props()` can only be used at the top level of components as a variable declaration initializer
## reactive_declaration_cycle
> Cyclical dependency detected: %cycle%
## rune_invalid_arguments
> `%rune%` cannot be called with arguments
## rune_invalid_arguments_length
> `%rune%` must be called with %args%
## rune_invalid_computed_property
> Cannot access a computed property of a rune
## rune_invalid_name
> `%name%` is not a valid rune
## rune_invalid_usage
> Cannot use `%rune%` rune in non-runes mode
## rune_missing_parentheses
> Cannot use rune without parentheses
## runes_mode_invalid_import
> %name% cannot be used in runes mode
## snippet_parameter_assignment
> Cannot reassign or bind to snippet parameter
## state_invalid_export
> Cannot export state from a module if it is reassigned. Either export a function returning the state value or only mutate the state value's properties
## state_invalid_placement
> `%rune%(...)` can only be used as a variable declaration initializer or a class field
## store_invalid_scoped_subscription
> Cannot subscribe to stores that are not declared at the top level of the component
## store_invalid_subscription
> Cannot reference store value inside `<script context="module">`

@ -1,31 +0,0 @@
## invalid_slot_element_attribute
> `<slot>` can only receive attributes and (optionally) let directives
## invalid_slot_attribute
> slot attribute must be a static value
## invalid_slot_name_default
> `default` is a reserved word — it cannot be used as a slot name
## invalid_slot_name
> slot attribute must be a static value
## invalid_slot_placement
> Element with a slot='...' attribute must be a child of a component or a descendant of a custom element
## duplicate_slot_name
> Duplicate slot name '%name%' in <%component%>
## invalid_default_slot_content
> Found default slot content alongside an explicit slot="default"
## conflicting_children_snippet
> Cannot use explicit children snippet at the same time as implicit children content. Remove either the non-whitespace content or the children snippet block

@ -1,99 +0,0 @@
## invalid_svelte_option_attribute
> `<svelte:options>` can only receive static attributes
## invalid_svelte_option_namespace
> Unsupported `<svelte:option>` value for "namespace". Valid values are "html", "svg" or "foreign"
## tag_option_deprecated
> "tag" option is deprecated — use "customElement" instead
## invalid_svelte_option_runes
> Unsupported `<svelte:option>` value for "runes". Valid values are true or false
## invalid_svelte_option_accessors
> Unsupported `<svelte:option>` value for "accessors". Valid values are true or false
## invalid_svelte_option_preserveWhitespace
> Unsupported `<svelte:option>` value for "preserveWhitespace". Valid values are true or false
## invalid_svelte_option_immutable
> Unsupported `<svelte:option>` value for "immutable". Valid values are true or false
## invalid_tag_property
> Tag name must be two or more words joined by the "-" character
## invalid_svelte_option_customElement
> "customElement" must be a string literal defining a valid custom element name or an object of the form { tag: string; shadow?: "open" | "none"; props?: { [key: string]: { attribute?: string; reflect?: boolean; type: .. } } }
## invalid_customElement_props_attribute
> "props" must be a statically analyzable object literal of the form "{ [key: string]: { attribute?: string; reflect?: boolean; type?: "String" | "Boolean" | "Number" | "Array" | "Object" }"
## invalid_customElement_shadow_attribute
> "shadow" must be either "open" or "none"
## unknown_svelte_option_attribute
> `<svelte:options>` unknown attribute '%name%'
## illegal_svelte_head_attribute
> `<svelte:head>` cannot have attributes nor directives
## invalid_svelte_fragment_attribute
> `<svelte:fragment>` can only have a slot attribute and (optionally) a let: directive
## invalid_svelte_fragment_slot
> `<svelte:fragment>` slot attribute must have a static value
## invalid_svelte_fragment_placement
> `<svelte:fragment>` must be the direct child of a component
## invalid_svelte_element_placement
> <%name%> tags cannot be inside elements or blocks
## duplicate_svelte_element
> A component can only have one <%name%> element
## invalid_self_placement
> `<svelte:self>` components can only exist inside {#if} blocks, {#each} blocks, {#snippet} blocks or slots passed to components
## missing_svelte_element_definition
> `<svelte:element>` must have a 'this' attribute
## missing_svelte_component_definition
> `<svelte:component>` must have a 'this' attribute
## invalid_svelte_element_definition
> Invalid element definition — must be an {expression}
## invalid_svelte_component_definition
> Invalid component definition — must be an {expression}
## invalid_svelte_tag
> Valid `<svelte:...>` tag names are %list%
## conflicting_slot_usage
> Cannot use `<slot>` syntax and `{@render ...}` tags in the same component. Migrate towards `{@render ...}` tags completely.

@ -1,51 +1,47 @@
## invalid_css_empty_declaration
## css_empty_declaration
> Declaration cannot be empty
## invalid_css_global_block_list
## css_expected_identifier
> A :global {...} block cannot be part of a selector list with more than one item
## invalid_css_global_block_modifier
> A :global {...} block cannot modify an existing selector
> Expected a valid CSS identifier
## invalid_css_global_block_combinator
## css_global_block_invalid_combinator
> A :global {...} block cannot follow a %name% combinator
## invalid_css_global_block_declaration
## css_global_block_invalid_declaration
> A :global {...} block can only contain rules, not declarations
## invalid_css_global_placement
## css_global_block_invalid_list
> :global(...) can be at the start or end of a selector sequence, but not in the middle
> A :global {...} block cannot be part of a selector list with more than one item
## invalid_css_global_selector
## css_global_block_invalid_modifier
> :global(...) must contain exactly one selector
> A :global {...} block cannot modify an existing selector
## invalid_css_global_selector_list
## css_global_invalid_placement
> :global(...) must not contain type or universal selectors when used in a compound selector
> :global(...) can be at the start or end of a selector sequence, but not in the middle
## invalid_css_type_selector_placement
## css_global_invalid_selector
> :global(...) must not be followed with a type selector
> :global(...) must contain exactly one selector
## invalid_css_selector
## css_global_invalid_selector_list
> Invalid selector
> :global(...) must not contain type or universal selectors when used in a compound selector
## invalid_css_identifier
## css_nesting_selector_invalid_placement
> Expected a valid CSS identifier
> Nesting selectors can only be used inside a rule
## invalid_nesting_selector
## css_selector_invalid
> Nesting selectors can only be used inside a rule
> Invalid selector
## invalid_css_declaration
## css_type_selector_invalid_placement
> Declaration cannot be empty
> :global(...) must not be followed with a type selector

@ -0,0 +1,365 @@
## animation_duplicate
> An element can only have one 'animate' directive
## animation_invalid_placement
> An element that uses the `animate:` directive must be the only child of a keyed `{#each ...}` block
## animation_missing_key
> An element that uses the `animate:` directive must be the only child of a keyed `{#each ...}` block. Did you forget to add a key to your each block?
## attribute_contenteditable_dynamic
> 'contenteditable' attribute cannot be dynamic if element uses two-way binding
## attribute_contenteditable_missing
> 'contenteditable' attribute is required for textContent, innerHTML and innerText two-way bindings
## attribute_duplicate
> Attributes need to be unique
## attribute_empty_shorthand
> Attribute shorthand cannot be empty
## attribute_invalid_event_handler
> Event attribute must be a JavaScript expression, not a string
## attribute_invalid_multiple
> 'multiple' attribute must be static if select uses two-way binding
## attribute_invalid_name
> '%name%' is not a valid attribute name
## attribute_invalid_sequence_expression
> Sequence expressions are not allowed as attribute/directive values in runes mode, unless wrapped in parentheses
## attribute_invalid_type
> 'type' attribute must be a static text value if input uses two-way binding
## bind_invalid_expression
> Can only bind to an Identifier or MemberExpression
## bind_invalid_name
> `bind:%name%` is not a valid binding
> `bind:%name%` is not a valid binding. %explanation%
## bind_invalid_target
> `bind:%name%` can only be used with %elements%
## bind_invalid_value
> Can only bind to state or props
## block_duplicate_clause
> %name% cannot appear more than once within a block
## block_invalid_continuation_placement
> {:...} block is invalid at this position (did you forget to close the preceeding element or block?)
## block_invalid_elseif
> 'elseif' should be 'else if'
## block_invalid_placement
> {#%name% ...} block cannot be %location%
## block_unclosed
> Block was left open
## block_unexpected_close
> Unexpected block closing tag
## component_invalid_directive
> This type of directive is not valid on components
## const_tag_invalid_expression
> {@const ...} must be an assignment
## const_tag_invalid_placement
> `{@const}` must be the immediate child of `{#snippet}`, `{#if}`, `{:else if}`, `{:else}`, `{#each}`, `{:then}`, `{:catch}`, `<svelte:fragment>` or `<Component>`
## debug_tag_invalid_arguments
> {@debug ...} arguments must be identifiers, not arbitrary expressions
## directive_invalid_value
> Directive value must be a JavaScript expression enclosed in curly braces
## directive_missing_name
> `%type%` name cannot be empty
## element_invalid_closing_tag
> `</%name%>` attempted to close an element that was not open
## element_invalid_closing_tag_autoclosed
> `</%name%>` attempted to close element that was already automatically closed by `<%reason%>` (cannot nest `<%reason%>` inside `<%name%>`)
## element_invalid_tag_name
> Expected valid tag name
## element_unclosed
> `<%name%>` was left open
## event_handler_invalid_component_modifier
> Event modifiers other than 'once' can only be used on DOM elements
## event_handler_invalid_modifier
> Valid event modifiers are %list%
## event_handler_invalid_modifier_combination
> The '%modifier1%' and '%modifier2%' modifiers cannot be used together
## expected_attribute_value
> Expected attribute value
## expected_block_type
> Expected 'if', 'each', 'await', 'key' or 'snippet'
## expected_identifier
> Expected an identifier
## expected_pattern
> Expected identifier or destructure pattern
## expected_token
> Expected token %token%
## expected_whitespace
> Expected whitespace
## js_parse_error
> %message%
## let_directive_invalid_placement
> `let:` directive at invalid position
## node_invalid_placement
> %thing% is invalid inside <%parent%>
## render_tag_invalid_call_expression
> Calling a snippet function using apply, bind or call is not allowed
## render_tag_invalid_expression
> `{@render ...}` tags can only contain call expressions
## render_tag_invalid_spread_argument
> cannot use spread arguments in `{@render ...}` tags
## script_duplicate
> A component can have a single top-level `<script>` element and/or a single top-level `<script context="module">` element
## script_invalid_context
> If the context attribute is supplied, its value must be "module"
## slot_attribute_duplicate
> Duplicate slot name '%name%' in <%component%>
## slot_attribute_invalid
> slot attribute must be a static value
## slot_attribute_invalid_placement
> Element with a slot='...' attribute must be a child of a component or a descendant of a custom element
## slot_default_duplicate
> Found default slot content alongside an explicit slot="default"
## slot_element_invalid_attribute
> `<slot>` can only receive attributes and (optionally) let directives
## slot_element_invalid_name
> slot attribute must be a static value
## slot_element_invalid_name_default
> `default` is a reserved word — it cannot be used as a slot name
## slot_snippet_conflict
> Cannot use `<slot>` syntax and `{@render ...}` tags in the same component. Migrate towards `{@render ...}` tags completely.
## snippet_conflict
> Cannot use explicit children snippet at the same time as implicit children content. Remove either the non-whitespace content or the children snippet block
## snippet_invalid_rest_parameter
> snippets do not support rest parameters; use an array instead
## style_directive_invalid_modifier
> `style:` directive can only use the `important` modifier
## style_duplicate
> A component can have a single top-level `<style>` element
## svelte_component_invalid_this
> Invalid component definition — must be an `{expression}`
## svelte_component_missing_this
> `<svelte:component>` must have a 'this' attribute
## svelte_element_invalid_this
> Invalid element definition — must be an `{expression}`
## svelte_element_missing_this
> `<svelte:element>` must have a 'this' attribute
## svelte_fragment_invalid_attribute
> `<svelte:fragment>` can only have a slot attribute and (optionally) a let: directive
## svelte_fragment_invalid_placement
> `<svelte:fragment>` must be the direct child of a component
## svelte_fragment_invalid_slot
> `<svelte:fragment>` slot attribute must have a static value
## svelte_head_illegal_attribute
> `<svelte:head>` cannot have attributes nor directives
## svelte_meta_duplicate
> A component can only have one `<%name%>` element
## svelte_meta_invalid_content
> <%name%> cannot have children
## svelte_meta_invalid_placement
> `<%name%>` tags cannot be inside elements or blocks
## svelte_meta_invalid_tag
> Valid `<svelte:...>` tag names are %list%
## svelte_options_deprecated_tag
> "tag" option is deprecated — use "customElement" instead
## svelte_options_invalid_attribute
> `<svelte:options>` can only receive static attributes
## svelte_options_invalid_attribute_value
> Valid values are %list%
## svelte_options_invalid_customelement
> "customElement" must be a string literal defining a valid custom element name or an object of the form { tag: string; shadow?: "open" | "none"; props?: { [key: string]: { attribute?: string; reflect?: boolean; type: .. } } }
## svelte_options_invalid_customelement_props
> "props" must be a statically analyzable object literal of the form "{ [key: string]: { attribute?: string; reflect?: boolean; type?: "String" | "Boolean" | "Number" | "Array" | "Object" }"
## svelte_options_invalid_customelement_shadow
> "shadow" must be either "open" or "none"
## svelte_options_invalid_tagname
> Tag name must be two or more words joined by the "-" character
## svelte_options_unknown_attribute
> `<svelte:options>` unknown attribute '%name%'
## svelte_self_invalid_placement
> `<svelte:self>` components can only exist inside `{#if}` blocks, `{#each}` blocks, `{#snippet}` blocks or slots passed to components
## tag_invalid_placement
> {@%name% ...} tag cannot be %location%
## textarea_invalid_content
> A `<textarea>` can have either a value attribute or (equivalently) child content, but not both
## title_illegal_attribute
> `<title>` cannot have attributes nor directives
## title_invalid_content
> `<title>` can only contain text and {tags}
## transition_conflict
> Cannot use `%type%:` alongside existing `%existing%:` directive
## transition_duplicate
> Cannot use multiple `%type%:` directives on a single element
## unexpected_eof
> Unexpected end of input
## unexpected_reserved_word
> '%word%' is a reserved word in JavaScript and cannot be used here
## void_element_invalid_content
> Void elements cannot have children or closing tags

@ -1,19 +0,0 @@
## illegal_global
> `%name%` is an illegal variable name. To reference a global variable called `%name%`, use `globalThis.%name%`
## duplicate_declaration
> `%name%` has already been declared
## default_export
> A component cannot have a default export
## illegal_variable_declaration
> Cannot declare same variable name which is imported inside `<script context="module">`
## illegal_store_subscription
> Cannot subscribe to stores that are not declared at the top level of the component

@ -1,167 +1,167 @@
## a11y_aria_attributes
## a11y_accesskey
> <%name%> should not have aria-* attributes
> Avoid using accesskey
## a11y_unknown_aria_attribute
## a11y_aria_activedescendant_has_tabindex
> Unknown aria attribute 'aria-%attribute%'
> An element with an aria-activedescendant attribute should have a tabindex value
> Unknown aria attribute 'aria-%attribute%'. Did you mean '%suggestion%'?
## a11y_aria_attributes
## a11y_hidden
> `<%name%>` should not have aria-* attributes
> <%name%> element should not be hidden
## a11y_autocomplete_valid
## a11y_incorrect_aria_attribute_type_boolean
> '%value%' is an invalid value for 'autocomplete' on `<input type="%type%">`
> The value of '%attribute%' must be either 'true' or 'false'
## a11y_autofocus
## a11y_incorrect_aria_attribute_type_integer
> Avoid using autofocus
> The value of '%attribute%' must be an integer
## a11y_click_events_have_key_events
## a11y_incorrect_aria_attribute_type_id
> Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as `<button type="button">` or `<a>` might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.
> The value of '%attribute%' must be a string that represents a DOM element ID
## a11y_distracting_elements
## a11y_incorrect_aria_attribute_type_idlist
> Avoid `<%name%>` elements
> The value of '%attribute%' must be a space-separated list of strings that represent DOM element IDs
## a11y_figcaption_index
## a11y_incorrect_aria_attribute_type_tristate
> `<figcaption>` must be first or last child of `<figure>`
> The value of '%attribute%' must be exactly one of true, false, or mixed
## a11y_figcaption_parent
## a11y_incorrect_aria_attribute_type_token
> `<figcaption>` must be an immediate child of `<figure>`
> The value of '%attribute%' must be exactly one of %values%
## a11y_hidden
## a11y_incorrect_aria_attribute_type_tokenlist
> `<%name%>` element should not be hidden
> The value of '%attribute%' must be a space-separated list of one or more of %values%
## a11y_img_redundant_alt
> Screenreaders already announce `<img>` elements as an image.
## a11y_incorrect_aria_attribute_type
> The value of '%attribute%' must be of type %type%
## a11y_aria_activedescendant_has_tabindex
## a11y_incorrect_aria_attribute_type_boolean
> Elements with attribute aria-activedescendant should have tabindex value
> The value of '%attribute%' must be either 'true' or 'false'
## a11y_misplaced_role
## a11y_incorrect_aria_attribute_type_id
> <%name%> should not have role attribute
> The value of '%attribute%' must be a string that represents a DOM element ID
## a11y_no_abstract_role
## a11y_incorrect_aria_attribute_type_idlist
> Abstract role '%role%' is forbidden
> The value of '%attribute%' must be a space-separated list of strings that represent DOM element IDs
## a11y_unknown_role
## a11y_incorrect_aria_attribute_type_integer
> Unknown role '%role%'
> The value of '%attribute%' must be an integer
> Unknown role '%role%'. Did you mean '%suggestion%'?
## a11y_incorrect_aria_attribute_type_token
## a11y_no_redundant_roles
> The value of '%attribute%' must be exactly one of %values%
> Redundant role '%role%'
## a11y_incorrect_aria_attribute_type_tokenlist
## a11y_role_has_required_aria_props
> The value of '%attribute%' must be a space-separated list of one or more of %values%
> Elements with the ARIA role "%role%" must have the following attributes defined: %props%
## a11y_incorrect_aria_attribute_type_tristate
> The value of '%attribute%' must be exactly one of true, false, or mixed
## a11y_interactive_supports_focus
> Elements with the '%role%' interactive role must have a tabindex value.
## a11y_no_interactive_element_to_noninteractive_role
## a11y_invalid_attribute
> <%element%> cannot have role '%role%'
> '%href_value%' is not a valid %href_attribute% attribute
## a11y_no_noninteractive_element_to_interactive_role
## a11y_label_has_associated_control
> Non-interactive element <%element%> cannot have interactive role '%role%'
> A form label must be associated with a control.
## a11y_accesskey
## a11y_media_has_caption
> Avoid using accesskey
> `<video>` elements must have a `<track kind="captions">`
## a11y_autofocus
## a11y_misplaced_role
> Avoid using autofocus
> `<%name%>` should not have role attribute
## a11y_misplaced_scope
> The scope attribute should only be used with <th> elements
> The scope attribute should only be used with `<th>` elements
## a11y_positive_tabindex
## a11y_missing_attribute
> Avoid tabindex values above zero
> `<%name%>` element should have %article% %sequence% attribute
## a11y_click_events_have_key_events
## a11y_missing_content
> Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type="button"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.
> `<%name%>` element should have child content
## a11y_no_noninteractive_tabindex
## a11y_mouse_events_have_key_events
> noninteractive element cannot have nonnegative tabIndex value
> '%event%' event must be accompanied by '%accompanied_by%' event
## a11y_role_supports_aria_props
## a11y_no_abstract_role
> The attribute '%attribute%' is not supported by the role '%role%'
> Abstract role '%role%' is forbidden
## a11y_role_supports_aria_props_implicit
## a11y_no_interactive_element_to_noninteractive_role
> The attribute '%attribute%' is not supported by the role '%role%'. This role is implicit on the element <%name%>
> `<%element%>` cannot have role '%role%'
## a11y_no_noninteractive_element_interactions
> Non-interactive element <%element%> should not be assigned mouse or keyboard event listeners.
## a11y_no_static_element_interactions
> <%element%> with a %handler% handler must have an ARIA role
> Non-interactive element `<%element%>` should not be assigned mouse or keyboard event listeners.
## a11y_invalid_attribute
## a11y_no_noninteractive_element_to_interactive_role
> '%href_value%' is not a valid %href_attribute% attribute
> Non-interactive element `<%element%>` cannot have interactive role '%role%'
## a11y_missing_attribute
## a11y_no_noninteractive_tabindex
> <%name%> element should have %article% %sequence% attribute
> noninteractive element cannot have nonnegative tabIndex value
## a11y_autocomplete_valid
## a11y_no_redundant_roles
> The value '%value%' is not supported by the attribute 'autocomplete' on element <input type="%type%">
> Redundant role '%role%'
## a11y_img_redundant_alt
## a11y_no_static_element_interactions
> Screenreaders already announce <img> elements as an image.
> `<%element%>` with a %handler% handler must have an ARIA role
## a11y_label_has_associated_control
## a11y_positive_tabindex
> A form label must be associated with a control.
> Avoid tabindex values above zero
## a11y_media_has_caption
## a11y_role_has_required_aria_props
> <video> elements must have a <track kind="captions">
> Elements with the ARIA role "%role%" must have the following attributes defined: %props%
## a11y_distracting_elements
## a11y_role_supports_aria_props
> Avoid <%name%> elements
> The attribute '%attribute%' is not supported by the role '%role%'
## a11y_figcaption_parent
## a11y_role_supports_aria_props_implicit
> `<figcaption>` must be an immediate child of `<figure>`
> The attribute '%attribute%' is not supported by the role '%role%'. This role is implicit on the element `<%name%>`
## a11y_figcaption_index
## a11y_unknown_aria_attribute
> `<figcaption>` must be first or last child of `<figure>`
> Unknown aria attribute 'aria-%attribute%'
## a11y_mouse_events_have_key_events
> Unknown aria attribute 'aria-%attribute%'. Did you mean '%suggestion%'?
> '%event%' event must be accompanied by '%accompanied_by%' event
## a11y_unknown_role
## a11y_missing_content
> Unknown role '%role%'
> <%name%> element should have child content
> Unknown role '%role%'. Did you mean '%suggestion%'?

@ -1,15 +0,0 @@
## avoid_is
> The "is" attribute is not supported cross-browser and should be avoided
## global_event_reference
> You are referencing globalThis.%name%. Did you forget to declare a variable with that name?
## illegal_attribute_character
> Attributes should not contain ':' characters to prevent ambiguity with Svelte directives
## invalid_html_attribute
> '%wrong%' is not a valid HTML attribute. Did you mean '%right%'?

@ -1,3 +0,0 @@
## empty_block
> Empty block

@ -1,3 +0,0 @@
## component_name_lowercase
> <%name%> will be treated as an HTML element unless it begins with a capital letter

@ -1,3 +0,0 @@
## css_unused_selector
> Unused CSS selector "%name%"

@ -1,19 +0,0 @@
## no_reactive_declaration
> Reactive declarations only exist at the top level of the instance script
## module_script_reactive_declaration
> All dependencies of the reactive declaration are declared in a module script and will not be reactive
## unused_export_let
> Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%`
## deprecated_slot_element
> Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.
## deprecated_event_handler
> Using on:%name% to listen to the %name% event is is deprecated. Use the event attribute on%name% instead.

@ -1,3 +0,0 @@
## invalid_self_closing_tag
> Self-closing HTML tags for non-void elements are ambiguous — use <%name% ...></%name%> rather than <%name% ... />

@ -10,10 +10,6 @@
> The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?
## options_renamed_ssr_dom
> `generate: "dom"` and `generate: "ssr"` options have been renamed to "client" and "server" respectively
## options_removed_enable_sourcemap
> The `enableSourcemap` option has been removed. Source maps are always generated now, and tooling can choose to ignore them
@ -25,3 +21,7 @@
## options_removed_loop_guard_timeout
> The `loopGuardTimeout` option has been removed
## options_renamed_ssr_dom
> `generate: "dom"` and `generate: "ssr"` options have been renamed to "client" and "server" respectively

@ -1,7 +0,0 @@
## avoid_inline_class
> Avoid 'new class' — instead, declare the class at the top level scope
## avoid_nested_class
> Avoid declaring classes below the top level scope

@ -1,19 +0,0 @@
## store_with_rune_name
> It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity
## non_state_reference
> `%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
## derived_iife
> Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`
## invalid_props_declaration
> Component properties are declared using `$props()` in runes mode. Did you forget to call the function?
## invalid_bindable_declaration
> Bindable component properties are declared using `$bindable()` in runes mode. Did you forget to call the function?

@ -0,0 +1,35 @@
## derived_iife
> Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`
## export_let_unused
> Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%`
## non_reactive_update
> `%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
## perf_avoid_inline_class
> Avoid 'new class' — instead, declare the class at the top level scope
## perf_avoid_nested_class
> Avoid declaring classes below the top level scope
## reactive_declaration_invalid_placement
> Reactive declarations only exist at the top level of the instance script
## reactive_declaration_module_script
> All dependencies of the reactive declaration are declared in a module script and will not be reactive
## state_referenced_locally
> State referenced in its own scope will never update. Did you mean to reference it inside a closure?
## store_rune_conflict
> It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity

@ -1,7 +0,0 @@
## static_state_reference
> State referenced in its own scope will never update. Did you mean to reference it inside a closure?
## invalid_rest_eachblock_binding
> The rest operator (...) will create a new object and binding '%name%' with the original object will not work

@ -0,0 +1,3 @@
## css_unused_selector
> Unused CSS selector "%name%"

@ -0,0 +1,39 @@
## attribute_avoid_is
> The "is" attribute is not supported cross-browser and should be avoided
## attribute_global_event_reference
> You are referencing `globalThis.%name%`. Did you forget to declare a variable with that name?
## attribute_illegal_colon
> Attributes should not contain ':' characters to prevent ambiguity with Svelte directives
## attribute_invalid_property_name
> '%wrong%' is not a valid HTML attribute. Did you mean '%right%'?
## bind_invalid_each_rest
> The rest operator (...) will create a new object and binding '%name%' with the original object will not work
## block_empty
> Empty block
## component_name_lowercase
> `<%name%>` will be treated as an HTML element unless it begins with a capital letter
## element_invalid_self_closing_tag
> Self-closing HTML tags for non-void elements are ambiguous — use `<%name% ...></%name%>` rather than `<%name% ... />`
## event_directive_deprecated
> Using `on:%name%` to listen to the %name% event is deprecated. Use the event attribute `on%name%` instead.
## slot_element_deprecated
> Using `<slot>` to render parent content is deprecated. Use `{@render ...}` tags instead.

@ -0,0 +1,3 @@
## lifecycle_function_unavailable
> `%name%(...)` is not available on the server

@ -0,0 +1,19 @@
## lifecycle_outside_component
> `%name%(...)` can only be used during component initialisation
## render_tag_invalid_argument
> The argument to `{@render ...}` must be a snippet function, not a component or some other kind of function. If you want to dynamically render one snippet or another, use `$derived` and pass its result to `{@render ...}`
## snippet_used_as_component
> A snippet must be rendered with `{@render ...}`
## store_invalid_shape
> `%name%` is not a store with a `subscribe` method
## svelte_element_invalid_this_value
> The `this` prop on `<svelte:element>` must be a string, if defined

@ -1,3 +1,3 @@
## dynamic_void_element_content
> `<svelte:element this="%tag%">` is a void element — it cannot have content
> `<svelte:element this="%tag%">` is a void element — it cannot have content

@ -18,6 +18,8 @@ for (const category of fs.readdirSync('messages')) {
.readFileSync(`messages/${category}/${file}`, 'utf-8')
.replace(/\r\n/g, '\n');
const sorted = [];
for (const match of markdown.matchAll(/## ([\w]+)\n\n([^]+?)(?=$|\n\n## )/g)) {
const [_, code, text] = match;
@ -25,6 +27,8 @@ for (const category of fs.readdirSync('messages')) {
throw new Error(`Duplicate message code ${category}/${code}`);
}
sorted.push({ code, _ });
const sections = text.trim().split('\n\n');
let details = null;
if (!sections[sections.length - 1].startsWith('> ')) {
@ -41,6 +45,12 @@ for (const category of fs.readdirSync('messages')) {
details
};
}
sorted.sort((a, b) => (a.code < b.code ? -1 : 1));
fs.writeFileSync(
`messages/${category}/${file}`,
sorted.map((x) => x._.trim()).join('\n\n') + '\n'
);
}
}
@ -289,4 +299,6 @@ transform('compile-warnings', 'src/compiler/warnings.js');
transform('client-warnings', 'src/internal/client/warnings.js');
transform('client-errors', 'src/internal/client/errors.js');
transform('server-errors', 'src/internal/server/errors.js');
transform('shared-errors', 'src/internal/shared/errors.js');
transform('shared-warnings', 'src/internal/shared/warnings.js');

@ -0,0 +1,10 @@
/**
* MESSAGE
* @param {string} PARAMETER
* @returns {never}
*/
export function CODE(PARAMETER) {
const error = new Error(`${'CODE'}\n${MESSAGE}`);
error.name = 'Svelte error';
throw error;
}

@ -0,0 +1,17 @@
import { DEV } from 'esm-env';
/**
* MESSAGE
* @param {string} PARAMETER
* @returns {never}
*/
export function CODE(PARAMETER) {
if (DEV) {
const error = new Error(`${'CODE'}\n${MESSAGE}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error('CODE');
}
}

File diff suppressed because it is too large Load Diff

@ -92,10 +92,10 @@ export class Parser {
if (current.type === 'RegularElement') {
current.end = current.start + 1;
e.unclosed_element(current, current.name);
e.element_unclosed(current, current.name);
} else {
current.end = current.start + 1;
e.unclosed_block(current);
e.block_unclosed(current);
}
}
@ -263,7 +263,7 @@ export class Parser {
require_whitespace() {
if (!regex_whitespace.test(this.template[this.index])) {
e.missing_whitespace(this.index);
e.expected_whitespace(this.index);
}
this.allow_whitespace();

@ -22,18 +22,18 @@ export default function read_options(node) {
for (const attribute of node.attributes) {
if (attribute.type !== 'Attribute') {
e.invalid_svelte_option_attribute(attribute);
e.svelte_options_invalid_attribute(attribute);
}
const { name } = attribute;
switch (name) {
case 'runes': {
component_options.runes = get_boolean_value(attribute, e.invalid_svelte_option_runes);
component_options.runes = get_boolean_value(attribute);
break;
}
case 'tag': {
e.tag_option_deprecated(attribute);
e.svelte_options_deprecated_tag(attribute);
break; // eslint doesn't know this is unnecessary
}
case 'customElement': {
@ -42,9 +42,9 @@ export default function read_options(node) {
const { value } = attribute;
if (value === true) {
e.invalid_svelte_option_customElement(attribute);
e.svelte_options_invalid_customelement(attribute);
} else if (value[0].type === 'Text') {
const tag = get_static_value(attribute, () => e.invalid_tag_property(attribute));
const tag = get_static_value(attribute);
validate_tag(attribute, tag);
ce.tag = tag;
component_options.customElement = ce;
@ -55,7 +55,7 @@ export default function read_options(node) {
if (value[0].expression.type === 'Literal' && value[0].expression.value === null) {
break;
}
e.invalid_svelte_option_customElement(attribute);
e.svelte_options_invalid_customelement(attribute);
}
/** @type {Array<[string, any]>} */
@ -66,7 +66,7 @@ export default function read_options(node) {
property.computed ||
property.key.type !== 'Identifier'
) {
e.invalid_svelte_option_customElement(attribute);
e.svelte_options_invalid_customelement(attribute);
}
properties.push([property.key.name, property.value]);
}
@ -77,13 +77,13 @@ export default function read_options(node) {
validate_tag(tag, tag_value);
ce.tag = tag_value;
} else {
e.invalid_svelte_option_customElement(attribute);
e.svelte_options_invalid_customelement(attribute);
}
const props = properties.find(([name]) => name === 'props')?.[1];
if (props) {
if (props.type !== 'ObjectExpression') {
e.invalid_customElement_props_attribute(attribute);
e.svelte_options_invalid_customelement_props(attribute);
}
ce.props = {};
for (const property of /** @type {import('estree').ObjectExpression} */ (props)
@ -94,7 +94,7 @@ export default function read_options(node) {
property.key.type !== 'Identifier' ||
property.value.type !== 'ObjectExpression'
) {
e.invalid_customElement_props_attribute(attribute);
e.svelte_options_invalid_customelement_props(attribute);
}
ce.props[property.key.name] = {};
for (const prop of property.value.properties) {
@ -104,7 +104,7 @@ export default function read_options(node) {
prop.key.type !== 'Identifier' ||
prop.value.type !== 'Literal'
) {
e.invalid_customElement_props_attribute(attribute);
e.svelte_options_invalid_customelement_props(attribute);
}
if (prop.key.name === 'type') {
@ -113,21 +113,21 @@ export default function read_options(node) {
/** @type {string} */ (prop.value.value)
) === -1
) {
e.invalid_customElement_props_attribute(attribute);
e.svelte_options_invalid_customelement_props(attribute);
}
ce.props[property.key.name].type = /** @type {any} */ (prop.value.value);
} else if (prop.key.name === 'reflect') {
if (typeof prop.value.value !== 'boolean') {
e.invalid_customElement_props_attribute(attribute);
e.svelte_options_invalid_customelement_props(attribute);
}
ce.props[property.key.name].reflect = prop.value.value;
} else if (prop.key.name === 'attribute') {
if (typeof prop.value.value !== 'string') {
e.invalid_customElement_props_attribute(attribute);
e.svelte_options_invalid_customelement_props(attribute);
}
ce.props[property.key.name].attribute = prop.value.value;
} else {
e.invalid_customElement_props_attribute(attribute);
e.svelte_options_invalid_customelement_props(attribute);
}
}
}
@ -137,7 +137,7 @@ export default function read_options(node) {
if (shadow) {
const shadowdom = shadow?.value;
if (shadowdom !== 'open' && shadowdom !== 'none') {
e.invalid_customElement_shadow_attribute(shadow);
e.svelte_options_invalid_customelement_shadow(shadow);
}
ce.shadow = shadowdom;
}
@ -151,46 +151,32 @@ export default function read_options(node) {
break;
}
case 'namespace': {
const value = get_static_value(attribute, () =>
e.invalid_svelte_option_namespace(attribute)
);
if (typeof value !== 'string') {
e.invalid_svelte_option_namespace(attribute);
}
const value = get_static_value(attribute);
if (value === namespace_svg) {
component_options.namespace = 'svg';
} else if (value === 'html' || value === 'svg' || value === 'foreign') {
component_options.namespace = value;
} else {
e.invalid_svelte_option_namespace(attribute);
e.svelte_options_invalid_attribute_value(attribute, `"html", "svg" or "foreign"`);
}
break;
}
case 'immutable': {
component_options.immutable = get_boolean_value(
attribute,
e.invalid_svelte_option_immutable
);
component_options.immutable = get_boolean_value(attribute);
break;
}
case 'preserveWhitespace': {
component_options.preserveWhitespace = get_boolean_value(
attribute,
e.invalid_svelte_option_preserveWhitespace
);
component_options.preserveWhitespace = get_boolean_value(attribute);
break;
}
case 'accessors': {
component_options.accessors = get_boolean_value(
attribute,
e.invalid_svelte_option_accessors
);
component_options.accessors = get_boolean_value(attribute);
break;
}
default:
e.unknown_svelte_option_attribute(attribute, name);
e.svelte_options_unknown_attribute(attribute, name);
}
}
@ -199,45 +185,43 @@ export default function read_options(node) {
/**
* @param {any} attribute
* @param {(attribute: any) => never} error
*/
function get_static_value(attribute, error) {
function get_static_value(attribute) {
const { value } = attribute;
const chunk = value[0];
if (!chunk) return true;
if (value.length > 1) {
error(attribute);
return null;
}
if (chunk.type === 'Text') return chunk.data;
if (chunk.expression.type !== 'Literal') {
error(attribute);
return null;
}
return chunk.expression.value;
}
/**
* @param {any} attribute
* @param {(attribute: any) => never} error
*/
function get_boolean_value(attribute, error) {
const value = get_static_value(attribute, () => error(attribute));
function get_boolean_value(attribute) {
const value = get_static_value(attribute);
if (typeof value !== 'boolean') {
error(attribute);
e.svelte_options_invalid_attribute_value(attribute, 'true or false');
}
return value;
}
/**
* @param {any} attribute
* @param {string} tag
* @param {string | null} tag
* @returns {asserts tag is string}
*/
function validate_tag(attribute, tag) {
if (typeof tag !== 'string' && tag !== null) {
e.invalid_tag_property(attribute);
if (typeof tag !== 'string') {
e.svelte_options_invalid_tagname(attribute);
}
if (tag && !regex_valid_tag_name.test(tag)) {
e.invalid_tag_property(attribute);
e.svelte_options_invalid_tagname(attribute);
}
// TODO do we still need this?
// if (tag && !component.compile_options.customElement) {

@ -16,13 +16,13 @@ function get_context(attributes) {
if (!context) return 'default';
if (context.value.length !== 1 || context.value[0].type !== 'Text') {
e.invalid_script_context(context.start);
e.script_invalid_context(context.start);
}
const value = context.value[0].data;
if (value !== 'module') {
e.invalid_script_context(context.start);
e.script_invalid_context(context.start);
}
return value;
@ -38,7 +38,7 @@ export function read_script(parser, start, attributes) {
const script_start = parser.index;
const data = parser.read_until(regex_closing_script_tag);
if (parser.index >= parser.template.length) {
e.unclosed_element(parser.template.length, 'script');
e.element_unclosed(parser.template.length, 'script');
}
const source =

@ -352,7 +352,7 @@ function read_selector(parser, inside_pseudo_class = false) {
if (combinator) {
if (relative_selector.selectors.length === 0) {
if (!inside_pseudo_class) {
e.invalid_css_selector(start);
e.css_selector_invalid(start);
}
} else {
relative_selector.end = index;
@ -365,7 +365,7 @@ function read_selector(parser, inside_pseudo_class = false) {
parser.allow_whitespace();
if (parser.match(',') || (inside_pseudo_class ? parser.match(')') : parser.match('{'))) {
e.invalid_css_selector(parser.index);
e.css_selector_invalid(parser.index);
}
}
}
@ -471,12 +471,13 @@ function read_declaration(parser) {
const property = parser.read_until(REGEX_WHITESPACE_OR_COLON);
parser.allow_whitespace();
parser.eat(':');
let index = parser.index;
parser.allow_whitespace();
const value = read_value(parser);
if (!value && !property.startsWith('--')) {
e.invalid_css_declaration(parser.index);
e.css_empty_declaration({ start, end: index });
}
const end = parser.index;
@ -577,7 +578,7 @@ function read_identifier(parser) {
let identifier = '';
if (parser.match('--') || parser.match_regex(REGEX_LEADING_HYPHEN_OR_DIGIT)) {
e.invalid_css_identifier(start);
e.css_expected_identifier(start);
}
let escaped = false;
@ -602,7 +603,7 @@ function read_identifier(parser) {
}
if (identifier === '') {
e.invalid_css_identifier(start);
e.css_expected_identifier(start);
}
return identifier;

@ -101,18 +101,18 @@ export default function tag(parser) {
['svelte:options', 'svelte:window', 'svelte:body', 'svelte:document'].includes(name) &&
/** @type {import('#compiler').ElementLike} */ (parent).fragment.nodes.length
) {
e.invalid_element_content(
e.svelte_meta_invalid_content(
/** @type {import('#compiler').ElementLike} */ (parent).fragment.nodes[0].start,
name
);
}
} else {
if (name in parser.meta_tags) {
e.duplicate_svelte_element(start, name);
e.svelte_meta_duplicate(start, name);
}
if (parent.type !== 'Root') {
e.invalid_svelte_element_placement(start, name);
e.svelte_meta_invalid_placement(start, name);
}
parser.meta_tags[name] = true;
@ -164,7 +164,7 @@ export default function tag(parser) {
if (is_closing_tag) {
if (is_void(name)) {
e.invalid_void_content(start);
e.void_element_invalid_content(start);
}
parser.eat('>', true);
@ -173,9 +173,9 @@ export default function tag(parser) {
while (/** @type {import('#compiler').RegularElement} */ (parent).name !== name) {
if (parent.type !== 'RegularElement') {
if (parser.last_auto_closed_tag && parser.last_auto_closed_tag.tag === name) {
e.invalid_closing_tag_after_autoclose(start, name, parser.last_auto_closed_tag.reason);
e.element_invalid_closing_tag_autoclosed(start, name, parser.last_auto_closed_tag.reason);
} else {
e.invalid_closing_tag(start, name);
e.element_invalid_closing_tag(start, name);
}
}
@ -216,7 +216,7 @@ export default function tag(parser) {
while ((attribute = read(parser))) {
if (attribute.type === 'Attribute' || attribute.type === 'BindDirective') {
if (unique_names.includes(attribute.name)) {
e.duplicate_attribute(attribute.start);
e.attribute_duplicate(attribute.start);
// <svelte:element bind:this this=..> is allowed
} else if (attribute.name !== 'this') {
unique_names.push(attribute.name);
@ -233,7 +233,7 @@ export default function tag(parser) {
(attr) => attr.type === 'Attribute' && attr.name === 'this'
);
if (index === -1) {
e.missing_svelte_component_definition(start);
e.svelte_component_missing_this(start);
}
const definition = /** @type {import('#compiler').Attribute} */ (
@ -244,7 +244,7 @@ export default function tag(parser) {
definition.value.length !== 1 ||
definition.value[0].type === 'Text'
) {
e.invalid_svelte_component_definition(definition.start);
e.svelte_component_invalid_this(definition.start);
}
element.expression = definition.value[0].expression;
@ -256,14 +256,14 @@ export default function tag(parser) {
(attr) => attr.type === 'Attribute' && attr.name === 'this'
);
if (index === -1) {
e.missing_svelte_element_definition(start);
e.svelte_element_missing_this(start);
}
const definition = /** @type {import('#compiler').Attribute} */ (
element.attributes.splice(index, 1)[0]
);
if (definition.value === true || definition.value.length !== 1) {
e.invalid_svelte_element_definition(definition.start);
e.svelte_element_invalid_this(definition.start);
}
const chunk = definition.value[0];
element.tag =
@ -302,17 +302,17 @@ export default function tag(parser) {
}
if (content.context === 'module') {
if (current.module) e.duplicate_script_element(start);
if (current.module) e.script_duplicate(start);
current.module = content;
} else {
if (current.instance) e.duplicate_script_element(start);
if (current.instance) e.script_duplicate(start);
current.instance = content;
}
} else {
const content = read_style(parser, start, element.attributes);
content.content.comment = prev_comment;
if (current.css) e.duplicate_style_element(start);
if (current.css) e.style_duplicate(start);
current.css = content;
}
return;
@ -387,7 +387,7 @@ function read_tag_name(parser) {
}
if (!legal) {
e.invalid_self_placement(start);
e.svelte_self_invalid_placement(start);
}
return 'svelte:self';
@ -404,11 +404,11 @@ function read_tag_name(parser) {
if (name.startsWith('svelte:')) {
const list = `${valid_meta_tags.slice(0, -1).join(', ')} or ${valid_meta_tags[valid_meta_tags.length - 1]}`;
e.invalid_svelte_tag(start, list);
e.svelte_meta_invalid_tag(start, list);
}
if (!valid_tag_name.test(name)) {
e.invalid_tag_name(start);
e.element_invalid_tag_name(start);
}
return name;
@ -436,7 +436,7 @@ function read_static_attribute(parser) {
parser.allow_whitespace();
let raw = parser.match_regex(regex_attribute_value);
if (!raw) {
e.missing_attribute_value(parser.index);
e.expected_attribute_value(parser.index);
}
parser.index += raw.length;
@ -500,7 +500,7 @@ function read_attribute(parser) {
const name = parser.read_identifier();
if (name === null) {
e.empty_attribute_shorthand(start);
e.attribute_empty_shorthand(start);
}
parser.allow_whitespace();
@ -552,7 +552,7 @@ function read_attribute(parser) {
const [directive_name, ...modifiers] = name.slice(colon_index + 1).split('|');
if (directive_name === '') {
e.empty_directive_name(start + colon_index + 1, type);
e.directive_missing_name({ start, end: start + colon_index + 1 }, name);
}
if (type === 'StyleDirective') {
@ -577,7 +577,7 @@ function read_attribute(parser) {
const attribute_contains_text =
/** @type {any[]} */ (value).length > 1 || first_value.type === 'Text';
if (attribute_contains_text) {
e.invalid_directive_value(/** @type {number} */ (first_value.start));
e.directive_invalid_value(/** @type {number} */ (first_value.start));
} else {
expression = first_value.expression;
}
@ -678,14 +678,14 @@ function read_attribute_value(parser) {
const pos = error.position?.[0];
if (pos !== undefined && parser.template.slice(pos - 1, pos + 1) === '/>') {
parser.index = pos;
e.unclosed_attribute_value(pos, quote_mark || '}');
e.expected_token(pos, quote_mark || '}');
}
}
throw error;
}
if (value.length === 0 && !quote_mark) {
e.missing_attribute_value(parser.index);
e.expected_attribute_value(parser.index);
}
if (quote_mark) parser.index += 1;
@ -732,12 +732,12 @@ function read_sequence(parser, done, location) {
const index = parser.index - 1;
parser.eat('#');
const name = parser.read_until(/[^a-z]/);
e.invalid_block_placement(index, name, location);
e.block_invalid_placement(index, name, location);
} else if (parser.match('@')) {
const index = parser.index - 1;
parser.eat('@');
const name = parser.read_until(/[^a-z]/);
e.invalid_tag_placement(index, name, location);
e.tag_invalid_placement(index, name, location);
}
flush(parser.index - 1);

@ -331,7 +331,7 @@ function next(parser) {
if (block.type === 'IfBlock') {
if (!parser.eat('else')) e.expected_token(start, '{:else} or {:else if}');
if (parser.eat('if')) e.invalid_elseif(start);
if (parser.eat('if')) e.block_invalid_elseif(start);
parser.allow_whitespace();
@ -389,7 +389,7 @@ function next(parser) {
if (block.type === 'AwaitBlock') {
if (parser.eat('then')) {
if (block.then) {
e.duplicate_block_part(start, '{:then}');
e.block_duplicate_clause(start, '{:then}');
}
if (!parser.eat('}')) {
@ -408,7 +408,7 @@ function next(parser) {
if (parser.eat('catch')) {
if (block.catch) {
e.duplicate_block_part(start, '{:catch}');
e.block_duplicate_clause(start, '{:catch}');
}
if (!parser.eat('}')) {
@ -428,7 +428,7 @@ function next(parser) {
e.expected_token(start, '{:then ...} or {:catch ...}');
}
e.invalid_continuing_block_placement(start);
e.block_invalid_continuation_placement(start);
}
/** @param {import('../index.js').Parser} parser */
@ -466,11 +466,11 @@ function close(parser) {
case 'RegularElement':
// TODO handle implicitly closed elements
e.unexpected_block_close(start);
e.block_unexpected_close(start);
break;
default:
e.unexpected_block_close(start);
e.block_unexpected_close(start);
}
parser.allow_whitespace();
@ -522,7 +522,7 @@ function special(parser) {
identifiers.forEach(
/** @param {any} node */ (node) => {
if (node.type !== 'Identifier') {
e.invalid_debug(/** @type {number} */ (node.start));
e.debug_tag_invalid_arguments(/** @type {number} */ (node.start));
}
}
);
@ -583,7 +583,7 @@ function special(parser) {
expression.expression.type !== 'CallExpression' ||
!expression.expression.optional)
) {
e.invalid_render_expression(expression);
e.render_tag_invalid_expression(expression);
}
parser.allow_whitespace();

@ -98,26 +98,26 @@ const validation_visitors = {
Rule(node, context) {
if (node.metadata.is_global_block) {
if (node.prelude.children.length > 1) {
e.invalid_css_global_block_list(node.prelude);
e.css_global_block_invalid_list(node.prelude);
}
const complex_selector = node.prelude.children[0];
const relative_selector = complex_selector.children[complex_selector.children.length - 1];
if (relative_selector.selectors.length > 1) {
e.invalid_css_global_block_modifier(
e.css_global_block_invalid_modifier(
relative_selector.selectors[relative_selector.selectors.length - 1]
);
}
if (relative_selector.combinator && relative_selector.combinator.name !== ' ') {
e.invalid_css_global_block_combinator(relative_selector, relative_selector.combinator.name);
e.css_global_block_invalid_combinator(relative_selector, relative_selector.combinator.name);
}
const declaration = node.block.children.find((child) => child.type === 'Declaration');
if (declaration) {
e.invalid_css_global_block_declaration(declaration);
e.css_global_block_invalid_declaration(declaration);
}
}
@ -132,7 +132,7 @@ const validation_visitors = {
if (a !== b) {
for (let i = a; i <= b; i += 1) {
if (is_global(node.children[i])) {
e.invalid_css_global_placement(node.children[i].selectors[0]);
e.css_global_invalid_placement(node.children[i].selectors[0]);
}
}
}
@ -147,12 +147,12 @@ const validation_visitors = {
const child = selector.args?.children[0].children[0];
// ensure `:global(element)` to be at the first position in a compound selector
if (child?.selectors[0].type === 'TypeSelector' && i !== 0) {
e.invalid_css_global_selector_list(selector);
e.css_global_invalid_selector_list(selector);
}
// ensure `:global(.class)` is not followed by a type selector, eg: `:global(.class)element`
if (relative_selector.selectors[i + 1]?.type === 'TypeSelector') {
e.invalid_css_type_selector_placement(relative_selector.selectors[i + 1]);
e.css_type_selector_invalid_placement(relative_selector.selectors[i + 1]);
}
// ensure `:global(...)`contains a single selector
@ -162,7 +162,7 @@ const validation_visitors = {
selector.args.children.length > 1 &&
(node.children.length > 1 || relative_selector.selectors.length > 1)
) {
e.invalid_css_global_selector(selector);
e.css_global_invalid_selector(selector);
}
}
}
@ -171,7 +171,7 @@ const validation_visitors = {
NestingSelector(node, context) {
const rule = /** @type {import('#compiler').Css.Rule} */ (context.state.rule);
if (!rule.metadata.parent_rule) {
e.invalid_nesting_selector(node);
e.css_nesting_selector_invalid_placement(node);
}
}
};

@ -230,7 +230,7 @@ export function analyze_module(ast, options) {
for (const [name, references] of scope.references) {
if (name[0] !== '$' || ReservedKeywords.includes(name)) continue;
if (name === '$' || name[1] === '$') {
e.illegal_global(references[0].node, name);
e.global_reference_invalid(references[0].node, name);
}
}
@ -271,7 +271,7 @@ export function analyze_component(root, source, options) {
for (const [name, references] of module.scope.references) {
if (name[0] !== '$' || ReservedKeywords.includes(name)) continue;
if (name === '$' || name[1] === '$') {
e.illegal_global(references[0].node, name);
e.global_reference_invalid(references[0].node, name);
}
const store_name = name.slice(1);
@ -311,16 +311,16 @@ export function analyze_component(root, source, options) {
}
if (is_nested_store_subscription_node) {
e.illegal_store_subscription(is_nested_store_subscription_node);
e.store_invalid_scoped_subscription(is_nested_store_subscription_node);
}
if (options.runes !== false) {
if (declaration === null && /[a-z]/.test(store_name[0])) {
e.illegal_global(references[0].node, name);
e.global_reference_invalid(references[0].node, name);
} else if (declaration !== null && Runes.includes(/** @type {any} */ (name))) {
for (const { node, path } of references) {
if (path.at(-1)?.type === 'CallExpression') {
w.store_with_rune_name(node, store_name);
w.store_rune_conflict(node, store_name);
}
}
}
@ -335,7 +335,7 @@ export function analyze_component(root, source, options) {
// const state = $state(0) is valid
get_rune(/** @type {import('estree').Node} */ (path.at(-1)), module.scope) === null
) {
e.illegal_subscription(node);
e.store_invalid_subscription(node);
}
}
}
@ -414,12 +414,12 @@ export function analyze_component(root, source, options) {
if (analysis.runes) {
const props_refs = module.scope.references.get('$$props');
if (props_refs) {
e.invalid_legacy_props(props_refs[0].node);
e.legacy_props_invalid(props_refs[0].node);
}
const rest_props_refs = module.scope.references.get('$$restProps');
if (rest_props_refs) {
e.invalid_legacy_rest_props(rest_props_refs[0].node);
e.legacy_rest_props_invalid(rest_props_refs[0].node);
}
for (const { ast, scope, scopes } of [module, instance, template]) {
@ -444,20 +444,6 @@ export function analyze_component(root, source, options) {
merge(set_scope(scopes), validation_runes, runes_scope_tweaker, common_visitors)
);
}
if (analysis.exports.length > 0) {
for (const [_, binding] of instance.scope.declarations) {
if (binding.kind === 'prop' || binding.kind === 'bindable_prop') {
if (
analysis.exports.some(
({ alias, name }) => (binding.prop_alias ?? binding.node.name) === (alias ?? name)
)
) {
e.conflicting_property_name(binding.node);
}
}
}
}
} else {
instance.scope.declare(b.id('$$props'), 'bindable_prop', 'synthetic');
instance.scope.declare(b.id('$$restProps'), 'rest_prop', 'synthetic');
@ -498,7 +484,7 @@ export function analyze_component(root, source, options) {
(r) => r.node !== binding.node && r.path.at(-1)?.type !== 'ExportSpecifier'
);
if (!references.length && !instance.scope.declarations.has(`$${name}`)) {
w.unused_export_let(binding.node, name);
w.export_let_unused(binding.node, name);
}
}
}
@ -507,7 +493,7 @@ export function analyze_component(root, source, options) {
}
if (analysis.uses_render_tags && (analysis.uses_slots || analysis.slot_names.size > 0)) {
e.conflicting_slot_usage(analysis.slot_names.values().next().value);
e.slot_snippet_conflict(analysis.slot_names.values().next().value);
}
// warn on any nonstate declarations that are a) reassigned and b) referenced in the template
@ -538,7 +524,7 @@ export function analyze_component(root, source, options) {
type === 'AwaitBlock' ||
type === 'KeyBlock'
) {
w.non_state_reference(binding.node, name);
w.non_reactive_update(binding.node, name);
continue outer;
}
}
@ -546,7 +532,7 @@ export function analyze_component(root, source, options) {
}
}
w.non_state_reference(binding.node, name);
w.non_reactive_update(binding.node, name);
continue outer;
}
}
@ -688,7 +674,7 @@ const legacy_scope_tweaker = {
(d) => d.scope === state.analysis.module.scope && d.declaration_kind !== 'const'
)
) {
w.module_script_reactive_declaration(node);
w.reactive_declaration_module_script(node);
}
if (
@ -1210,7 +1196,7 @@ const common_visitors = {
binding.kind === 'derived') &&
context.state.function_depth === binding.scope.function_depth
) {
w.static_state_reference(node);
w.state_referenced_locally(node);
}
}
},
@ -1493,7 +1479,7 @@ function order_reactive_statements(unsorted_reactive_declarations) {
const cycle = check_graph_for_cycles(edges);
if (cycle?.length) {
const declaration = /** @type {Tuple[]} */ (lookup.get(cycle[0]))[0];
e.cyclical_reactive_declaration(declaration[0], cycle.join(' → '));
e.reactive_declaration_cycle(declaration[0], cycle.join(' → '));
}
// We use a map and take advantage of the fact that the spec says insertion order is preserved when iterating

@ -1,3 +1,4 @@
import is_reference from 'is-reference';
import {
disallowed_paragraph_contents,
interactive_elements,
@ -18,6 +19,7 @@ import { binding_properties } from '../bindings.js';
import {
ContentEditableBindings,
EventModifiers,
Runes,
SVGElements,
VoidElements
} from '../constants.js';
@ -44,14 +46,14 @@ function validate_component(node, context) {
attribute.type !== 'OnDirective' &&
attribute.type !== 'BindDirective'
) {
e.invalid_component_directive(attribute);
e.component_invalid_directive(attribute);
}
if (
attribute.type === 'OnDirective' &&
(attribute.modifiers.length > 1 || attribute.modifiers.some((m) => m !== 'once'))
) {
e.invalid_component_event_modifier(attribute);
e.event_handler_invalid_component_modifier(attribute);
}
if (attribute.type === 'Attribute') {
@ -62,7 +64,7 @@ function validate_component(node, context) {
while (--i > 0) {
const char = context.state.analysis.source[i];
if (char === '(') break; // parenthesized sequence expressions are ok
if (char === '{') e.invalid_sequence_expression(expression);
if (char === '{') e.attribute_invalid_sequence_expression(expression);
}
}
}
@ -111,18 +113,18 @@ function validate_element(node, context) {
while (--i > 0) {
const char = context.state.analysis.source[i];
if (char === '(') break; // parenthesized sequence expressions are ok
if (char === '{') e.invalid_sequence_expression(expression);
if (char === '{') e.attribute_invalid_sequence_expression(expression);
}
}
}
if (regex_illegal_attribute_character.test(attribute.name)) {
e.invalid_attribute_name(attribute, attribute.name);
e.attribute_invalid_name(attribute, attribute.name);
}
if (attribute.name.startsWith('on') && attribute.name.length > 2) {
if (!is_expression) {
e.invalid_event_attribute_value(attribute);
e.attribute_invalid_event_handler(attribute);
}
const value = attribute.value[0].expression;
@ -131,7 +133,7 @@ function validate_element(node, context) {
value.name === attribute.name &&
!context.state.scope.get(value.name)
) {
w.global_event_reference(attribute, attribute.name);
w.attribute_global_event_reference(attribute, attribute.name);
}
}
@ -141,12 +143,12 @@ function validate_element(node, context) {
}
if (attribute.name === 'is' && context.state.options.namespace !== 'foreign') {
w.avoid_is(attribute);
w.attribute_avoid_is(attribute);
}
const correct_name = react_attributes.get(attribute.name);
if (correct_name) {
w.invalid_html_attribute(attribute, attribute.name, correct_name);
w.attribute_invalid_property_name(attribute, attribute.name, correct_name);
}
validate_attribute_name(attribute);
@ -196,7 +198,7 @@ function validate_element(node, context) {
for (const modifier of attribute.modifiers) {
if (!EventModifiers.includes(modifier)) {
const list = `${EventModifiers.slice(0, -1).join(', ')} or ${EventModifiers.at(-1)}`;
e.invalid_event_modifier(attribute, list);
e.event_handler_invalid_modifier(attribute, list);
}
if (modifier === 'passive') {
has_passive_modifier = true;
@ -204,7 +206,11 @@ function validate_element(node, context) {
conflicting_passive_modifier = modifier;
}
if (has_passive_modifier && conflicting_passive_modifier) {
e.invalid_event_modifier_combination(attribute, 'passive', conflicting_passive_modifier);
e.event_handler_invalid_modifier_combination(
attribute,
'passive',
conflicting_passive_modifier
);
}
}
}
@ -221,7 +227,7 @@ function validate_attribute_name(attribute) {
!attribute.name.startsWith('xlink:') &&
!attribute.name.startsWith('xml:')
) {
w.illegal_attribute_character(attribute);
w.attribute_illegal_colon(attribute);
}
}
@ -249,7 +255,7 @@ function validate_slot_attribute(context, attribute) {
if (owner) {
if (!is_text_attribute(attribute)) {
e.invalid_slot_attribute(attribute);
e.slot_attribute_invalid(attribute);
}
if (
@ -258,13 +264,13 @@ function validate_slot_attribute(context, attribute) {
owner.type === 'SvelteSelf'
) {
if (owner !== context.path.at(-2)) {
e.invalid_slot_placement(attribute);
e.slot_attribute_invalid_placement(attribute);
}
const name = attribute.value[0].data;
if (context.state.component_slots.has(name)) {
e.duplicate_slot_name(attribute, name, owner.name);
e.slot_attribute_duplicate(attribute, name, owner.name);
}
context.state.component_slots.add(name);
@ -281,12 +287,12 @@ function validate_slot_attribute(context, attribute) {
}
}
e.invalid_default_slot_content(node);
e.slot_default_duplicate(node);
}
}
}
} else {
e.invalid_slot_placement(attribute);
e.slot_attribute_invalid_placement(attribute);
}
}
@ -299,7 +305,7 @@ function validate_block_not_empty(node, context) {
// Assumption: If the block has zero elements, someone's in the middle of typing it out,
// so don't warn in that case because it would be distracting.
if (node.nodes.length === 1 && node.nodes[0].type === 'Text' && !node.nodes[0].raw.trim()) {
w.empty_block(node.nodes[0]);
w.block_empty(node.nodes[0]);
}
}
@ -317,7 +323,7 @@ const validation = {
const left = object(assignee);
if (left === null) {
e.invalid_binding_expression(node);
e.bind_invalid_expression(node);
}
const binding = context.state.scope.get(left.name);
@ -337,19 +343,19 @@ const validation = {
binding.kind !== 'store_sub' &&
!binding.mutated)
) {
e.invalid_binding_value(node.expression);
e.bind_invalid_value(node.expression);
}
if (binding.kind === 'derived') {
e.invalid_binding(node.expression, 'derived state');
e.constant_binding(node.expression, 'derived state');
}
if (context.state.analysis.runes && binding.kind === 'each') {
e.invalid_each_assignment(node);
e.each_item_invalid_assignment(node);
}
if (binding.kind === 'snippet') {
e.invalid_snippet_assignment(node);
e.snippet_parameter_assignment(node);
}
}
@ -360,7 +366,7 @@ const validation = {
}
if (binding?.kind === 'each' && binding.metadata?.inside_rest) {
w.invalid_rest_eachblock_binding(binding.node, binding.node.name);
w.bind_invalid_each_rest(binding.node, binding.node.name);
}
const parent = context.path.at(-1);
@ -373,7 +379,7 @@ const validation = {
parent?.type === 'SvelteBody'
) {
if (context.state.options.namespace === 'foreign' && node.name !== 'this') {
e.bind_invalid(node, node.name, 'Foreign elements only support `bind:this`');
e.bind_invalid_name(node, node.name, 'Foreign elements only support `bind:this`');
}
if (node.name in binding_properties) {
@ -392,7 +398,7 @@ const validation = {
);
if (type && !is_text_attribute(type)) {
if (node.name !== 'value' || type.value === true) {
e.invalid_type_attribute(type);
e.attribute_invalid_type(type);
}
return; // bind:value can handle dynamic `type` attributes
}
@ -415,7 +421,7 @@ const validation = {
a.value !== true
);
if (multiple) {
e.invalid_multiple_attribute(multiple);
e.attribute_invalid_multiple(multiple);
}
}
@ -432,9 +438,9 @@ const validation = {
parent.attributes.find((a) => a.type === 'Attribute' && a.name === 'contenteditable')
);
if (!contenteditable) {
e.missing_contenteditable_attribute(node);
e.attribute_contenteditable_missing(node);
} else if (!is_text_attribute(contenteditable) && contenteditable.value !== true) {
e.dynamic_contenteditable_attribute(contenteditable);
e.attribute_contenteditable_dynamic(contenteditable);
}
}
} else {
@ -442,15 +448,15 @@ const validation = {
if (match) {
const property = binding_properties[match];
if (!property.valid_elements || property.valid_elements.includes(parent.name)) {
e.bind_invalid(node, node.name, `Did you mean '${match}'?`);
e.bind_invalid_name(node, node.name, `Did you mean '${match}'?`);
}
}
e.bind_invalid(node, node.name);
e.bind_invalid_name(node, node.name);
}
}
},
ExportDefaultDeclaration(node) {
e.default_export(node);
e.module_illegal_default_export(node);
},
ConstTag(node, context) {
const parent = context.path.at(-1);
@ -467,7 +473,7 @@ const validation = {
((grand_parent?.type !== 'RegularElement' && grand_parent?.type !== 'SvelteElement') ||
!grand_parent.attributes.some((a) => a.type === 'Attribute' && a.name === 'slot')))
) {
e.invalid_const_placement(node);
e.const_tag_invalid_placement(node);
}
},
ImportDeclaration(node, context) {
@ -478,7 +484,7 @@ const validation = {
specifier.imported.name === 'beforeUpdate' ||
specifier.imported.name === 'afterUpdate'
) {
e.invalid_runes_mode_import(specifier, specifier.imported.name);
e.runes_mode_invalid_import(specifier, specifier.imported.name);
}
}
}
@ -496,14 +502,14 @@ const validation = {
parent.type !== 'SvelteSelf' &&
parent.type !== 'SvelteFragment')
) {
e.invalid_let_directive_placement(node);
e.let_directive_invalid_placement(node);
}
},
RegularElement(node, context) {
if (node.name === 'textarea' && node.fragment.nodes.length > 0) {
for (const attribute of node.attributes) {
if (attribute.type === 'Attribute' && attribute.name === 'value') {
e.invalid_textarea_content(node);
e.textarea_invalid_content(node);
}
}
}
@ -521,7 +527,7 @@ const validation = {
if (context.state.parent_element) {
if (!is_tag_valid_with_parent(node.name, context.state.parent_element)) {
e.invalid_node_placement(node, `<${node.name}>`, context.state.parent_element);
e.node_invalid_placement(node, `<${node.name}>`, context.state.parent_element);
}
}
@ -533,7 +539,7 @@ const validation = {
parent.name === node.name &&
interactive_elements.has(parent.name)
) {
e.invalid_node_placement(node, `<${node.name}>`, parent.name);
e.node_invalid_placement(node, `<${node.name}>`, parent.name);
}
}
}
@ -542,7 +548,7 @@ const validation = {
const path = context.path;
for (let parent of path) {
if (parent.type === 'RegularElement' && parent.name === 'p') {
e.invalid_node_placement(node, `<${node.name}>`, parent.name);
e.node_invalid_placement(node, `<${node.name}>`, parent.name);
}
}
}
@ -553,7 +559,7 @@ const validation = {
!VoidElements.includes(node.name) &&
!SVGElements.includes(node.name)
) {
w.invalid_self_closing_tag(node, node.name);
w.element_invalid_self_closing_tag(node, node.name);
}
context.next({
@ -567,7 +573,7 @@ const validation = {
const raw_args = unwrap_optional(node.expression).arguments;
for (const arg of raw_args) {
if (arg.type === 'SpreadElement') {
e.invalid_render_spread_argument(arg);
e.render_tag_invalid_spread_argument(arg);
}
}
@ -577,7 +583,7 @@ const validation = {
callee.property.type === 'Identifier' &&
['bind', 'apply', 'call'].includes(callee.property.name)
) {
e.invalid_render_call(node);
e.render_tag_invalid_call_expression(node);
}
const is_inside_textarea = context.path.find((n) => {
@ -589,7 +595,7 @@ const validation = {
);
});
if (is_inside_textarea) {
e.invalid_tag_placement(
e.tag_invalid_placement(
node,
'inside <textarea> or <svelte:element this="textarea">',
'render'
@ -630,19 +636,19 @@ const validation = {
(node) => node.type !== 'SnippetBlock' && (node.type !== 'Text' || node.data.trim())
)
) {
e.conflicting_children_snippet(node);
e.snippet_conflict(node);
}
}
},
StyleDirective(node) {
if (node.modifiers.length > 1 || (node.modifiers.length && node.modifiers[0] !== 'important')) {
e.invalid_style_directive_modifier(node);
e.style_directive_invalid_modifier(node);
}
},
SvelteHead(node) {
const attribute = node.attributes[0];
if (attribute) {
e.illegal_svelte_head_attribute(attribute);
e.svelte_head_illegal_attribute(attribute);
}
},
SvelteElement(node, context) {
@ -655,7 +661,7 @@ const validation = {
SvelteFragment(node, context) {
const parent = context.path.at(-2);
if (parent?.type !== 'Component' && parent?.type !== 'SvelteComponent') {
e.invalid_svelte_fragment_placement(node);
e.svelte_fragment_invalid_placement(node);
}
for (const attribute of node.attributes) {
@ -664,7 +670,7 @@ const validation = {
validate_slot_attribute(context, attribute);
}
} else if (attribute.type !== 'LetDirective') {
e.invalid_svelte_fragment_attribute(attribute);
e.svelte_fragment_invalid_attribute(attribute);
}
}
},
@ -673,15 +679,15 @@ const validation = {
if (attribute.type === 'Attribute') {
if (attribute.name === 'name') {
if (!is_text_attribute(attribute)) {
e.invalid_slot_name(attribute);
e.slot_element_invalid_name(attribute);
}
const slot_name = attribute.value[0].data;
if (slot_name === 'default') {
e.invalid_slot_name_default(attribute);
e.slot_element_invalid_name_default(attribute);
}
}
} else if (attribute.type !== 'SpreadAttribute' && attribute.type !== 'LetDirective') {
e.invalid_slot_element_attribute(attribute);
e.slot_element_invalid_attribute(attribute);
}
}
},
@ -692,19 +698,19 @@ const validation = {
if (!node.parent) return;
if (context.state.parent_element && regex_not_whitespace.test(node.data)) {
if (!is_tag_valid_with_parent('#text', context.state.parent_element)) {
e.invalid_node_placement(node, 'Text node', context.state.parent_element);
e.node_invalid_placement(node, 'Text node', context.state.parent_element);
}
}
},
TitleElement(node) {
const attribute = node.attributes[0];
if (attribute) {
e.illegal_title_attribute(attribute);
e.title_illegal_attribute(attribute);
}
const child = node.fragment.nodes.find((n) => n.type !== 'Text' && n.type !== 'ExpressionTag');
if (child) {
e.invalid_title_content(child);
e.title_invalid_content(child);
}
},
UpdateExpression(node, context) {
@ -714,7 +720,7 @@ const validation = {
if (!node.parent) return;
if (context.state.parent_element) {
if (!is_tag_valid_with_parent('#text', context.state.parent_element)) {
e.invalid_node_placement(node, '{expression}', context.state.parent_element);
e.node_invalid_placement(node, '{expression}', context.state.parent_element);
}
}
}
@ -735,7 +741,7 @@ export const validation_legacy = merge(validation, a11y_validators, {
}
if (state.scope.get(callee.name)?.kind !== 'store_sub') {
e.invalid_rune_usage(node.init, callee.name);
e.rune_invalid_usage(node.init, callee.name);
}
},
AssignmentExpression(node, { state, path }) {
@ -749,7 +755,7 @@ export const validation_legacy = merge(validation, a11y_validators, {
(state.ast_type !== 'instance' ||
/** @type {import('#compiler').SvelteNode} */ (path.at(-1)).type !== 'Program')
) {
w.no_reactive_declaration(node);
w.reactive_declaration_invalid_placement(node);
}
},
UpdateExpression(node, { state }) {
@ -768,11 +774,11 @@ function validate_export(node, scope, name) {
if (!binding) return;
if (binding.kind === 'derived') {
e.invalid_derived_export(node);
e.derived_invalid_export(node);
}
if ((binding.kind === 'state' || binding.kind === 'frozen_state') && binding.reassigned) {
e.invalid_state_export(node);
e.state_invalid_export(node);
}
}
@ -790,7 +796,7 @@ function validate_call_expression(node, scope, path) {
if (rune === '$props') {
if (parent.type === 'VariableDeclarator') return;
e.invalid_props_location(node);
e.props_invalid_placement(node);
}
if (rune === '$bindable') {
@ -803,7 +809,7 @@ function validate_call_expression(node, scope, path) {
return;
}
}
e.invalid_bindable_location(node);
e.bindable_invalid_location(node);
}
if (
@ -814,46 +820,46 @@ function validate_call_expression(node, scope, path) {
) {
if (parent.type === 'VariableDeclarator') return;
if (parent.type === 'PropertyDefinition' && !parent.static && !parent.computed) return;
e.invalid_state_location(node, rune);
e.state_invalid_placement(node, rune);
}
if (rune === '$effect' || rune === '$effect.pre') {
if (parent.type !== 'ExpressionStatement') {
e.invalid_effect_location(node);
e.effect_invalid_placement(node);
}
if (node.arguments.length !== 1) {
e.invalid_rune_args_length(node, rune, 'exactly one argument');
e.rune_invalid_arguments_length(node, rune, 'exactly one argument');
}
}
if (rune === '$effect.active') {
if (node.arguments.length !== 0) {
e.invalid_rune_args(node, rune);
e.rune_invalid_arguments(node, rune);
}
}
if (rune === '$effect.root') {
if (node.arguments.length !== 1) {
e.invalid_rune_args_length(node, rune, 'exactly one argument');
e.rune_invalid_arguments_length(node, rune, 'exactly one argument');
}
}
if (rune === '$inspect') {
if (node.arguments.length < 1) {
e.invalid_rune_args_length(node, rune, 'one or more arguments');
e.rune_invalid_arguments_length(node, rune, 'one or more arguments');
}
}
if (rune === '$inspect().with') {
if (node.arguments.length !== 1) {
e.invalid_rune_args_length(node, rune, 'exactly one argument');
e.rune_invalid_arguments_length(node, rune, 'exactly one argument');
}
}
if (rune === '$state.snapshot') {
if (node.arguments.length !== 1) {
e.invalid_rune_args_length(node, rune, 'exactly one argument');
e.rune_invalid_arguments_length(node, rune, 'exactly one argument');
}
}
}
@ -869,7 +875,7 @@ function ensure_no_module_import_conflict(node, state) {
state.scope === state.analysis.instance.scope &&
state.analysis.module.scope.get(id.name)?.declaration_kind === 'import'
) {
e.illegal_variable_declaration(node.id);
e.declaration_duplicate_module_import(node.id);
}
}
}
@ -895,7 +901,7 @@ export const validation_runes_js = {
},
CallExpression(node, { state, path }) {
if (get_rune(node, state.scope) === '$host') {
e.invalid_host_location(node);
e.host_invalid_placement(node);
}
validate_call_expression(node, state.scope, path);
},
@ -908,13 +914,13 @@ export const validation_runes_js = {
const args = /** @type {import('estree').CallExpression} */ (init).arguments;
if ((rune === '$derived' || rune === '$derived.by') && args.length !== 1) {
e.invalid_rune_args_length(node, rune, 'exactly one argument');
e.rune_invalid_arguments_length(node, rune, 'exactly one argument');
} else if (rune === '$state' && args.length > 1) {
e.invalid_rune_args_length(node, rune, 'zero or one arguments');
e.rune_invalid_arguments_length(node, rune, 'zero or one arguments');
} else if (rune === '$props') {
e.invalid_props_location(node);
e.props_invalid_placement(node);
} else if (rune === '$bindable') {
e.invalid_bindable_location(node);
e.bindable_invalid_location(node);
}
},
AssignmentExpression(node, { state }) {
@ -952,12 +958,12 @@ export const validation_runes_js = {
const allowed_depth = context.state.ast_type === 'module' ? 0 : 1;
if (context.state.scope.function_depth > allowed_depth) {
w.avoid_nested_class(node);
w.perf_avoid_nested_class(node);
}
},
NewExpression(node, context) {
if (node.callee.type === 'ClassExpression' && context.state.scope.function_depth > 0) {
w.avoid_inline_class(node);
w.perf_avoid_inline_class(node);
}
}
};
@ -998,9 +1004,9 @@ function validate_no_const_assignment(node, argument, scope, is_binding) {
const thing = 'constant';
if (is_binding) {
e.invalid_binding(node, thing);
e.constant_binding(node, thing);
} else {
e.invalid_assignment(node, thing);
e.constant_assignment(node, thing);
}
}
}
@ -1019,16 +1025,16 @@ function validate_assignment(node, argument, state) {
if (state.analysis.runes) {
if (binding?.kind === 'derived') {
e.invalid_assignment(node, 'derived state');
e.constant_assignment(node, 'derived state');
}
if (binding?.kind === 'each') {
e.invalid_each_assignment(node);
e.each_item_invalid_assignment(node);
}
}
if (binding?.kind === 'snippet') {
e.invalid_snippet_assignment(node);
e.snippet_parameter_assignment(node);
}
}
@ -1044,15 +1050,46 @@ function validate_assignment(node, argument, state) {
if (object.type === 'ThisExpression' && property?.type === 'PrivateIdentifier') {
if (state.private_derived_state.includes(property.name)) {
e.invalid_assignment(node, 'derived state');
e.constant_assignment(node, 'derived state');
}
}
}
export const validation_runes = merge(validation, a11y_validators, {
Identifier(node, { path, state }) {
let i = path.length;
let parent = /** @type {import('estree').Expression} */ (path[--i]);
if (
Runes.includes(/** @type {Runes[number]} */ (node.name)) &&
is_reference(node, parent) &&
state.scope.get(node.name) === null &&
state.scope.get(node.name.slice(1)) === null
) {
/** @type {import('estree').Expression} */
let current = node;
let name = node.name;
while (parent.type === 'MemberExpression') {
if (parent.computed) e.rune_invalid_computed_property(parent);
name += `.${/** @type {import('estree').Identifier} */ (parent.property).name}`;
current = parent;
parent = /** @type {import('estree').Expression} */ (path[--i]);
if (!Runes.includes(/** @type {Runes[number]} */ (name))) {
e.rune_invalid_name(parent, name);
}
}
if (parent.type !== 'CallExpression') {
e.rune_missing_parentheses(current);
}
}
},
LabeledStatement(node, { path }) {
if (node.label.name !== '$' || path.at(-1)?.type !== 'Program') return;
e.invalid_legacy_reactive_statement(node);
e.legacy_reactive_statement_invalid(node);
},
ExportNamedDeclaration(node, { state, next }) {
if (state.ast_type === 'module') {
@ -1070,7 +1107,7 @@ export const validation_runes = merge(validation, a11y_validators, {
if (node.declaration?.type !== 'VariableDeclaration') return;
if (node.declaration.kind !== 'let') return;
if (state.analysis.instance.scope !== state.scope) return;
e.invalid_legacy_export(node);
e.legacy_export_invalid(node);
}
},
ExportSpecifier(node, { state }) {
@ -1081,12 +1118,12 @@ export const validation_runes = merge(validation, a11y_validators, {
CallExpression(node, { state, path }) {
const rune = get_rune(node, state.scope);
if (rune === '$bindable' && node.arguments.length > 1) {
e.invalid_rune_args_length(node, '$bindable', 'zero or one arguments');
e.rune_invalid_arguments_length(node, '$bindable', 'zero or one arguments');
} else if (rune === '$host') {
if (node.arguments.length > 0) {
e.invalid_rune_args(node, '$host');
e.rune_invalid_arguments(node, '$host');
} else if (state.ast_type === 'module' || !state.analysis.custom_element) {
e.invalid_host_location(node);
e.host_invalid_placement(node);
}
}
@ -1098,7 +1135,7 @@ export const validation_runes = merge(validation, a11y_validators, {
context.type === 'Identifier' &&
(context.name === '$state' || context.name === '$derived')
) {
e.invalid_state_location(node, context.name);
e.state_invalid_placement(node, context.name);
}
next({ ...state });
},
@ -1108,50 +1145,45 @@ export const validation_runes = merge(validation, a11y_validators, {
const init = node.init;
const rune = get_rune(init, state.scope);
if (rune === null) {
if (init?.type === 'Identifier' && init.name === '$props' && !state.scope.get('props')) {
w.invalid_props_declaration(node);
}
return;
}
if (rune === null) return;
const args = /** @type {import('estree').CallExpression} */ (init).arguments;
// TODO some of this is duplicated with above, seems off
if ((rune === '$derived' || rune === '$derived.by') && args.length !== 1) {
e.invalid_rune_args_length(node, rune, 'exactly one argument');
e.rune_invalid_arguments_length(node, rune, 'exactly one argument');
} else if (rune === '$state' && args.length > 1) {
e.invalid_rune_args_length(node, rune, 'zero or one arguments');
e.rune_invalid_arguments_length(node, rune, 'zero or one arguments');
} else if (rune === '$props') {
if (state.has_props_rune) {
e.duplicate_props_rune(node);
e.props_duplicate(node);
}
state.has_props_rune = true;
if (args.length > 0) {
e.invalid_rune_args(node, rune);
e.rune_invalid_arguments(node, rune);
}
if (node.id.type !== 'ObjectPattern') {
e.invalid_props_id(node);
e.props_invalid_identifier(node);
}
if (state.scope !== state.analysis.instance.scope) {
e.invalid_props_location(node);
e.props_invalid_placement(node);
}
for (const property of node.id.properties) {
if (property.type === 'Property') {
if (property.computed) {
e.invalid_props_pattern(property);
e.props_invalid_pattern(property);
}
const value =
property.value.type === 'AssignmentPattern' ? property.value.left : property.value;
if (value.type !== 'Identifier') {
e.invalid_props_pattern(property);
e.props_invalid_pattern(property);
}
}
}
@ -1167,25 +1199,16 @@ export const validation_runes = merge(validation, a11y_validators, {
}
}
},
AssignmentPattern(node, { state }) {
if (
node.right.type === 'Identifier' &&
node.right.name === '$bindable' &&
!state.scope.get('bindable')
) {
w.invalid_bindable_declaration(node);
}
},
SlotElement(node, { state }) {
if (!state.analysis.custom_element) {
w.deprecated_slot_element(node);
w.slot_element_deprecated(node);
}
},
OnDirective(node, { path }) {
const parent_type = path.at(-1)?.type;
// Don't warn on component events; these might not be under the author's control so the warning would be unactionable
if (parent_type === 'RegularElement' || parent_type === 'SvelteElement') {
w.deprecated_event_handler(node, node.name);
w.event_directive_deprecated(node, node.name);
}
},
// TODO this is a code smell. need to refactor this stuff

@ -70,7 +70,7 @@ export class Scope {
*/
declare(node, kind, declaration_kind, initial = null) {
if (node.name === '$') {
e.invalid_dollar_binding(node);
e.dollar_binding_invalid(node);
}
if (
@ -80,7 +80,7 @@ export class Scope {
declaration_kind !== 'rest_param' &&
this.function_depth <= 1
) {
e.invalid_dollar_prefix(node);
e.dollar_prefix_invalid(node);
}
if (this.parent) {
@ -95,7 +95,7 @@ export class Scope {
if (this.declarations.has(node.name)) {
// This also errors on var/function types, but that's arguably a good thing
e.duplicate_declaration(node, node.name);
e.declaration_duplicate(node, node.name);
}
/** @type {import('#compiler').Binding} */
@ -767,7 +767,6 @@ export function get_rune(node, scope) {
joined = n.name + joined;
if (joined === '$derived.call') e.invalid_derived_call(node);
if (!Runes.includes(/** @type {any} */ (joined))) return null;
const binding = scope.get(n.name);

@ -133,7 +133,7 @@ export const validate_component_options =
function removed(msg) {
return (input) => {
if (input !== undefined) {
e.removed_compiler_option(null, msg);
e.options_removed(null, msg);
}
return /** @type {any} */ (undefined);
};
@ -191,10 +191,7 @@ function object(children, allow_unknown = false) {
if (allow_unknown) {
output[key] = input[key];
} else {
e.invalid_compiler_option(
null,
`Unexpected option ${keypath ? `${keypath}.${key}` : key}`
);
e.options_unrecognised(null, `${keypath ? `${keypath}.${key}` : key}`);
}
}
}
@ -297,5 +294,5 @@ function fun(fallback) {
/** @param {string} msg */
function throw_error(msg) {
e.invalid_compiler_option(null, msg);
e.options_invalid_value(null, msg);
}

@ -41,96 +41,96 @@ function w(node, code, message) {
}
/**
* <%name%> should not have aria-* attributes
* Avoid using accesskey
* @param {null | NodeLike} node
* @param {string} name
*/
export function a11y_aria_attributes(node, name) {
w(node, "a11y_aria_attributes", `<${name}> should not have aria-* attributes`);
export function a11y_accesskey(node) {
w(node, "a11y_accesskey", "Avoid using accesskey");
}
/**
* Unknown aria attribute 'aria-%attribute%'. Did you mean '%suggestion%'?
* An element with an aria-activedescendant attribute should have a tabindex value
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string | undefined | null} [suggestion]
*/
export function a11y_unknown_aria_attribute(node, attribute, suggestion) {
w(node, "a11y_unknown_aria_attribute", suggestion ? `Unknown aria attribute 'aria-${attribute}'. Did you mean '${suggestion}'?` : `Unknown aria attribute 'aria-${attribute}'`);
export function a11y_aria_activedescendant_has_tabindex(node) {
w(node, "a11y_aria_activedescendant_has_tabindex", "An element with an aria-activedescendant attribute should have a tabindex value");
}
/**
* <%name%> element should not be hidden
* `<%name%>` should not have aria-* attributes
* @param {null | NodeLike} node
* @param {string} name
*/
export function a11y_hidden(node, name) {
w(node, "a11y_hidden", `<${name}> element should not be hidden`);
export function a11y_aria_attributes(node, name) {
w(node, "a11y_aria_attributes", `\`<${name}>\` should not have aria-* attributes`);
}
/**
* The value of '%attribute%' must be either 'true' or 'false'
* '%value%' is an invalid value for 'autocomplete' on `<input type="%type%">`
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} value
* @param {string} type
*/
export function a11y_incorrect_aria_attribute_type_boolean(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_boolean", `The value of '${attribute}' must be either 'true' or 'false'`);
export function a11y_autocomplete_valid(node, value, type) {
w(node, "a11y_autocomplete_valid", `'${value}' is an invalid value for 'autocomplete' on \`<input type="${type}">\``);
}
/**
* The value of '%attribute%' must be an integer
* Avoid using autofocus
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_integer(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_integer", `The value of '${attribute}' must be an integer`);
export function a11y_autofocus(node) {
w(node, "a11y_autofocus", "Avoid using autofocus");
}
/**
* The value of '%attribute%' must be a string that represents a DOM element ID
* Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as `<button type="button">` or `<a>` might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_id(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_id", `The value of '${attribute}' must be a string that represents a DOM element ID`);
export function a11y_click_events_have_key_events(node) {
w(node, "a11y_click_events_have_key_events", "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as `<button type=\"button\">` or `<a>` might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.");
}
/**
* The value of '%attribute%' must be a space-separated list of strings that represent DOM element IDs
* Avoid `<%name%>` elements
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} name
*/
export function a11y_incorrect_aria_attribute_type_idlist(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_idlist", `The value of '${attribute}' must be a space-separated list of strings that represent DOM element IDs`);
export function a11y_distracting_elements(node, name) {
w(node, "a11y_distracting_elements", `Avoid \`<${name}>\` elements`);
}
/**
* The value of '%attribute%' must be exactly one of true, false, or mixed
* `<figcaption>` must be first or last child of `<figure>`
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_tristate(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_tristate", `The value of '${attribute}' must be exactly one of true, false, or mixed`);
export function a11y_figcaption_index(node) {
w(node, "a11y_figcaption_index", "`<figcaption>` must be first or last child of `<figure>`");
}
/**
* The value of '%attribute%' must be exactly one of %values%
* `<figcaption>` must be an immediate child of `<figure>`
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} values
*/
export function a11y_incorrect_aria_attribute_type_token(node, attribute, values) {
w(node, "a11y_incorrect_aria_attribute_type_token", `The value of '${attribute}' must be exactly one of ${values}`);
export function a11y_figcaption_parent(node) {
w(node, "a11y_figcaption_parent", "`<figcaption>` must be an immediate child of `<figure>`");
}
/**
* The value of '%attribute%' must be a space-separated list of one or more of %values%
* `<%name%>` element should not be hidden
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} values
* @param {string} name
*/
export function a11y_incorrect_aria_attribute_type_tokenlist(node, attribute, values) {
w(node, "a11y_incorrect_aria_attribute_type_tokenlist", `The value of '${attribute}' must be a space-separated list of one or more of ${values}`);
export function a11y_hidden(node, name) {
w(node, "a11y_hidden", `\`<${name}>\` element should not be hidden`);
}
/**
* Screenreaders already announce `<img>` elements as an image.
* @param {null | NodeLike} node
*/
export function a11y_img_redundant_alt(node) {
w(node, "a11y_img_redundant_alt", "Screenreaders already announce `<img>` elements as an image.");
}
/**
@ -144,58 +144,68 @@ export function a11y_incorrect_aria_attribute_type(node, attribute, type) {
}
/**
* Elements with attribute aria-activedescendant should have tabindex value
* The value of '%attribute%' must be either 'true' or 'false'
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_aria_activedescendant_has_tabindex(node) {
w(node, "a11y_aria_activedescendant_has_tabindex", "Elements with attribute aria-activedescendant should have tabindex value");
export function a11y_incorrect_aria_attribute_type_boolean(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_boolean", `The value of '${attribute}' must be either 'true' or 'false'`);
}
/**
* <%name%> should not have role attribute
* The value of '%attribute%' must be a string that represents a DOM element ID
* @param {null | NodeLike} node
* @param {string} name
* @param {string} attribute
*/
export function a11y_misplaced_role(node, name) {
w(node, "a11y_misplaced_role", `<${name}> should not have role attribute`);
export function a11y_incorrect_aria_attribute_type_id(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_id", `The value of '${attribute}' must be a string that represents a DOM element ID`);
}
/**
* Abstract role '%role%' is forbidden
* The value of '%attribute%' must be a space-separated list of strings that represent DOM element IDs
* @param {null | NodeLike} node
* @param {string} role
* @param {string} attribute
*/
export function a11y_no_abstract_role(node, role) {
w(node, "a11y_no_abstract_role", `Abstract role '${role}' is forbidden`);
export function a11y_incorrect_aria_attribute_type_idlist(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_idlist", `The value of '${attribute}' must be a space-separated list of strings that represent DOM element IDs`);
}
/**
* Unknown role '%role%'. Did you mean '%suggestion%'?
* The value of '%attribute%' must be an integer
* @param {null | NodeLike} node
* @param {string} role
* @param {string | undefined | null} [suggestion]
* @param {string} attribute
*/
export function a11y_unknown_role(node, role, suggestion) {
w(node, "a11y_unknown_role", suggestion ? `Unknown role '${role}'. Did you mean '${suggestion}'?` : `Unknown role '${role}'`);
export function a11y_incorrect_aria_attribute_type_integer(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_integer", `The value of '${attribute}' must be an integer`);
}
/**
* Redundant role '%role%'
* The value of '%attribute%' must be exactly one of %values%
* @param {null | NodeLike} node
* @param {string} role
* @param {string} attribute
* @param {string} values
*/
export function a11y_no_redundant_roles(node, role) {
w(node, "a11y_no_redundant_roles", `Redundant role '${role}'`);
export function a11y_incorrect_aria_attribute_type_token(node, attribute, values) {
w(node, "a11y_incorrect_aria_attribute_type_token", `The value of '${attribute}' must be exactly one of ${values}`);
}
/**
* Elements with the ARIA role "%role%" must have the following attributes defined: %props%
* The value of '%attribute%' must be a space-separated list of one or more of %values%
* @param {null | NodeLike} node
* @param {string} role
* @param {string} props
* @param {string} attribute
* @param {string} values
*/
export function a11y_role_has_required_aria_props(node, role, props) {
w(node, "a11y_role_has_required_aria_props", `Elements with the ARIA role "${role}" must have the following attributes defined: ${props}`);
export function a11y_incorrect_aria_attribute_type_tokenlist(node, attribute, values) {
w(node, "a11y_incorrect_aria_attribute_type_tokenlist", `The value of '${attribute}' must be a space-separated list of one or more of ${values}`);
}
/**
* The value of '%attribute%' must be exactly one of true, false, or mixed
* @param {null | NodeLike} node
* @param {string} attribute
*/
export function a11y_incorrect_aria_attribute_type_tristate(node, attribute) {
w(node, "a11y_incorrect_aria_attribute_type_tristate", `The value of '${attribute}' must be exactly one of true, false, or mixed`);
}
/**
@ -208,287 +218,264 @@ export function a11y_interactive_supports_focus(node, role) {
}
/**
* <%element%> cannot have role '%role%'
* '%href_value%' is not a valid %href_attribute% attribute
* @param {null | NodeLike} node
* @param {string} element
* @param {string} role
* @param {string} href_value
* @param {string} href_attribute
*/
export function a11y_no_interactive_element_to_noninteractive_role(node, element, role) {
w(node, "a11y_no_interactive_element_to_noninteractive_role", `<${element}> cannot have role '${role}'`);
export function a11y_invalid_attribute(node, href_value, href_attribute) {
w(node, "a11y_invalid_attribute", `'${href_value}' is not a valid ${href_attribute} attribute`);
}
/**
* Non-interactive element <%element%> cannot have interactive role '%role%'
* A form label must be associated with a control.
* @param {null | NodeLike} node
* @param {string} element
* @param {string} role
*/
export function a11y_no_noninteractive_element_to_interactive_role(node, element, role) {
w(node, "a11y_no_noninteractive_element_to_interactive_role", `Non-interactive element <${element}> cannot have interactive role '${role}'`);
export function a11y_label_has_associated_control(node) {
w(node, "a11y_label_has_associated_control", "A form label must be associated with a control.");
}
/**
* Avoid using accesskey
* `<video>` elements must have a `<track kind="captions">`
* @param {null | NodeLike} node
*/
export function a11y_accesskey(node) {
w(node, "a11y_accesskey", "Avoid using accesskey");
export function a11y_media_has_caption(node) {
w(node, "a11y_media_has_caption", "`<video>` elements must have a `<track kind=\"captions\">`");
}
/**
* Avoid using autofocus
* `<%name%>` should not have role attribute
* @param {null | NodeLike} node
* @param {string} name
*/
export function a11y_autofocus(node) {
w(node, "a11y_autofocus", "Avoid using autofocus");
export function a11y_misplaced_role(node, name) {
w(node, "a11y_misplaced_role", `\`<${name}>\` should not have role attribute`);
}
/**
* The scope attribute should only be used with <th> elements
* The scope attribute should only be used with `<th>` elements
* @param {null | NodeLike} node
*/
export function a11y_misplaced_scope(node) {
w(node, "a11y_misplaced_scope", "The scope attribute should only be used with <th> elements");
w(node, "a11y_misplaced_scope", "The scope attribute should only be used with `<th>` elements");
}
/**
* Avoid tabindex values above zero
* `<%name%>` element should have %article% %sequence% attribute
* @param {null | NodeLike} node
* @param {string} name
* @param {string} article
* @param {string} sequence
*/
export function a11y_positive_tabindex(node) {
w(node, "a11y_positive_tabindex", "Avoid tabindex values above zero");
export function a11y_missing_attribute(node, name, article, sequence) {
w(node, "a11y_missing_attribute", `\`<${name}>\` element should have ${article} ${sequence} attribute`);
}
/**
* Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type="button"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.
* `<%name%>` element should have child content
* @param {null | NodeLike} node
* @param {string} name
*/
export function a11y_click_events_have_key_events(node) {
w(node, "a11y_click_events_have_key_events", "Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type=\"button\"> or <a> might be more appropriate. See https://svelte.dev/docs/accessibility-warnings#a11y-click-events-have-key-events for more details.");
export function a11y_missing_content(node, name) {
w(node, "a11y_missing_content", `\`<${name}>\` element should have child content`);
}
/**
* noninteractive element cannot have nonnegative tabIndex value
* '%event%' event must be accompanied by '%accompanied_by%' event
* @param {null | NodeLike} node
* @param {string} event
* @param {string} accompanied_by
*/
export function a11y_no_noninteractive_tabindex(node) {
w(node, "a11y_no_noninteractive_tabindex", "noninteractive element cannot have nonnegative tabIndex value");
export function a11y_mouse_events_have_key_events(node, event, accompanied_by) {
w(node, "a11y_mouse_events_have_key_events", `'${event}' event must be accompanied by '${accompanied_by}' event`);
}
/**
* The attribute '%attribute%' is not supported by the role '%role%'
* Abstract role '%role%' is forbidden
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} role
*/
export function a11y_role_supports_aria_props(node, attribute, role) {
w(node, "a11y_role_supports_aria_props", `The attribute '${attribute}' is not supported by the role '${role}'`);
export function a11y_no_abstract_role(node, role) {
w(node, "a11y_no_abstract_role", `Abstract role '${role}' is forbidden`);
}
/**
* The attribute '%attribute%' is not supported by the role '%role%'. This role is implicit on the element <%name%>
* `<%element%>` cannot have role '%role%'
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} element
* @param {string} role
* @param {string} name
*/
export function a11y_role_supports_aria_props_implicit(node, attribute, role, name) {
w(node, "a11y_role_supports_aria_props_implicit", `The attribute '${attribute}' is not supported by the role '${role}'. This role is implicit on the element <${name}>`);
export function a11y_no_interactive_element_to_noninteractive_role(node, element, role) {
w(node, "a11y_no_interactive_element_to_noninteractive_role", `\`<${element}>\` cannot have role '${role}'`);
}
/**
* Non-interactive element <%element%> should not be assigned mouse or keyboard event listeners.
* Non-interactive element `<%element%>` should not be assigned mouse or keyboard event listeners.
* @param {null | NodeLike} node
* @param {string} element
*/
export function a11y_no_noninteractive_element_interactions(node, element) {
w(node, "a11y_no_noninteractive_element_interactions", `Non-interactive element <${element}> should not be assigned mouse or keyboard event listeners.`);
w(node, "a11y_no_noninteractive_element_interactions", `Non-interactive element \`<${element}>\` should not be assigned mouse or keyboard event listeners.`);
}
/**
* <%element%> with a %handler% handler must have an ARIA role
* Non-interactive element `<%element%>` cannot have interactive role '%role%'
* @param {null | NodeLike} node
* @param {string} element
* @param {string} handler
* @param {string} role
*/
export function a11y_no_static_element_interactions(node, element, handler) {
w(node, "a11y_no_static_element_interactions", `<${element}> with a ${handler} handler must have an ARIA role`);
export function a11y_no_noninteractive_element_to_interactive_role(node, element, role) {
w(node, "a11y_no_noninteractive_element_to_interactive_role", `Non-interactive element \`<${element}>\` cannot have interactive role '${role}'`);
}
/**
* '%href_value%' is not a valid %href_attribute% attribute
* noninteractive element cannot have nonnegative tabIndex value
* @param {null | NodeLike} node
* @param {string} href_value
* @param {string} href_attribute
*/
export function a11y_invalid_attribute(node, href_value, href_attribute) {
w(node, "a11y_invalid_attribute", `'${href_value}' is not a valid ${href_attribute} attribute`);
export function a11y_no_noninteractive_tabindex(node) {
w(node, "a11y_no_noninteractive_tabindex", "noninteractive element cannot have nonnegative tabIndex value");
}
/**
* <%name%> element should have %article% %sequence% attribute
* Redundant role '%role%'
* @param {null | NodeLike} node
* @param {string} name
* @param {string} article
* @param {string} sequence
* @param {string} role
*/
export function a11y_missing_attribute(node, name, article, sequence) {
w(node, "a11y_missing_attribute", `<${name}> element should have ${article} ${sequence} attribute`);
export function a11y_no_redundant_roles(node, role) {
w(node, "a11y_no_redundant_roles", `Redundant role '${role}'`);
}
/**
* The value '%value%' is not supported by the attribute 'autocomplete' on element <input type="%type%">
* `<%element%>` with a %handler% handler must have an ARIA role
* @param {null | NodeLike} node
* @param {string} value
* @param {string} type
* @param {string} element
* @param {string} handler
*/
export function a11y_autocomplete_valid(node, value, type) {
w(node, "a11y_autocomplete_valid", `The value '${value}' is not supported by the attribute 'autocomplete' on element <input type="${type}">`);
export function a11y_no_static_element_interactions(node, element, handler) {
w(node, "a11y_no_static_element_interactions", `\`<${element}>\` with a ${handler} handler must have an ARIA role`);
}
/**
* Screenreaders already announce <img> elements as an image.
* Avoid tabindex values above zero
* @param {null | NodeLike} node
*/
export function a11y_img_redundant_alt(node) {
w(node, "a11y_img_redundant_alt", "Screenreaders already announce <img> elements as an image.");
export function a11y_positive_tabindex(node) {
w(node, "a11y_positive_tabindex", "Avoid tabindex values above zero");
}
/**
* A form label must be associated with a control.
* Elements with the ARIA role "%role%" must have the following attributes defined: %props%
* @param {null | NodeLike} node
* @param {string} role
* @param {string} props
*/
export function a11y_label_has_associated_control(node) {
w(node, "a11y_label_has_associated_control", "A form label must be associated with a control.");
export function a11y_role_has_required_aria_props(node, role, props) {
w(node, "a11y_role_has_required_aria_props", `Elements with the ARIA role "${role}" must have the following attributes defined: ${props}`);
}
/**
* <video> elements must have a <track kind="captions">
* The attribute '%attribute%' is not supported by the role '%role%'
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} role
*/
export function a11y_media_has_caption(node) {
w(node, "a11y_media_has_caption", "<video> elements must have a <track kind=\"captions\">");
export function a11y_role_supports_aria_props(node, attribute, role) {
w(node, "a11y_role_supports_aria_props", `The attribute '${attribute}' is not supported by the role '${role}'`);
}
/**
* Avoid <%name%> elements
* The attribute '%attribute%' is not supported by the role '%role%'. This role is implicit on the element `<%name%>`
* @param {null | NodeLike} node
* @param {string} attribute
* @param {string} role
* @param {string} name
*/
export function a11y_distracting_elements(node, name) {
w(node, "a11y_distracting_elements", `Avoid <${name}> elements`);
}
/**
* `<figcaption>` must be an immediate child of `<figure>`
* @param {null | NodeLike} node
*/
export function a11y_figcaption_parent(node) {
w(node, "a11y_figcaption_parent", "`<figcaption>` must be an immediate child of `<figure>`");
}
/**
* `<figcaption>` must be first or last child of `<figure>`
* @param {null | NodeLike} node
*/
export function a11y_figcaption_index(node) {
w(node, "a11y_figcaption_index", "`<figcaption>` must be first or last child of `<figure>`");
export function a11y_role_supports_aria_props_implicit(node, attribute, role, name) {
w(node, "a11y_role_supports_aria_props_implicit", `The attribute '${attribute}' is not supported by the role '${role}'. This role is implicit on the element \`<${name}>\``);
}
/**
* '%event%' event must be accompanied by '%accompanied_by%' event
* Unknown aria attribute 'aria-%attribute%'. Did you mean '%suggestion%'?
* @param {null | NodeLike} node
* @param {string} event
* @param {string} accompanied_by
* @param {string} attribute
* @param {string | undefined | null} [suggestion]
*/
export function a11y_mouse_events_have_key_events(node, event, accompanied_by) {
w(node, "a11y_mouse_events_have_key_events", `'${event}' event must be accompanied by '${accompanied_by}' event`);
export function a11y_unknown_aria_attribute(node, attribute, suggestion) {
w(node, "a11y_unknown_aria_attribute", suggestion ? `Unknown aria attribute 'aria-${attribute}'. Did you mean '${suggestion}'?` : `Unknown aria attribute 'aria-${attribute}'`);
}
/**
* <%name%> element should have child content
* Unknown role '%role%'. Did you mean '%suggestion%'?
* @param {null | NodeLike} node
* @param {string} name
* @param {string} role
* @param {string | undefined | null} [suggestion]
*/
export function a11y_missing_content(node, name) {
w(node, "a11y_missing_content", `<${name}> element should have child content`);
export function a11y_unknown_role(node, role, suggestion) {
w(node, "a11y_unknown_role", suggestion ? `Unknown role '${role}'. Did you mean '${suggestion}'?` : `Unknown role '${role}'`);
}
/**
* The "is" attribute is not supported cross-browser and should be avoided
* The `accessors` option has been deprecated. It will have no effect in runes mode
* @param {null | NodeLike} node
*/
export function avoid_is(node) {
w(node, "avoid_is", "The \"is\" attribute is not supported cross-browser and should be avoided");
export function options_deprecated_accessors(node) {
w(node, "options_deprecated_accessors", "The `accessors` option has been deprecated. It will have no effect in runes mode");
}
/**
* You are referencing globalThis.%name%. Did you forget to declare a variable with that name?
* The `immutable` option has been deprecated. It will have no effect in runes mode
* @param {null | NodeLike} node
* @param {string} name
*/
export function global_event_reference(node, name) {
w(node, "global_event_reference", `You are referencing globalThis.${name}. Did you forget to declare a variable with that name?`);
export function options_deprecated_immutable(node) {
w(node, "options_deprecated_immutable", "The `immutable` option has been deprecated. It will have no effect in runes mode");
}
/**
* Attributes should not contain ':' characters to prevent ambiguity with Svelte directives
* The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?
* @param {null | NodeLike} node
*/
export function illegal_attribute_character(node) {
w(node, "illegal_attribute_character", "Attributes should not contain ':' characters to prevent ambiguity with Svelte directives");
}
/**
* '%wrong%' is not a valid HTML attribute. Did you mean '%right%'?
* @param {null | NodeLike} node
* @param {string} wrong
* @param {string} right
*/
export function invalid_html_attribute(node, wrong, right) {
w(node, "invalid_html_attribute", `'${wrong}' is not a valid HTML attribute. Did you mean '${right}'?`);
export function options_missing_custom_element(node) {
w(node, "options_missing_custom_element", "The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?");
}
/**
* Empty block
* The `enableSourcemap` option has been removed. Source maps are always generated now, and tooling can choose to ignore them
* @param {null | NodeLike} node
*/
export function empty_block(node) {
w(node, "empty_block", "Empty block");
export function options_removed_enable_sourcemap(node) {
w(node, "options_removed_enable_sourcemap", "The `enableSourcemap` option has been removed. Source maps are always generated now, and tooling can choose to ignore them");
}
/**
* <%name%> will be treated as an HTML element unless it begins with a capital letter
* The `hydratable` option has been removed. Svelte components are always hydratable now
* @param {null | NodeLike} node
* @param {string} name
*/
export function component_name_lowercase(node, name) {
w(node, "component_name_lowercase", `<${name}> will be treated as an HTML element unless it begins with a capital letter`);
export function options_removed_hydratable(node) {
w(node, "options_removed_hydratable", "The `hydratable` option has been removed. Svelte components are always hydratable now");
}
/**
* Unused CSS selector "%name%"
* The `loopGuardTimeout` option has been removed
* @param {null | NodeLike} node
* @param {string} name
*/
export function css_unused_selector(node, name) {
w(node, "css_unused_selector", `Unused CSS selector "${name}"`);
export function options_removed_loop_guard_timeout(node) {
w(node, "options_removed_loop_guard_timeout", "The `loopGuardTimeout` option has been removed");
}
/**
* Reactive declarations only exist at the top level of the instance script
* `generate: "dom"` and `generate: "ssr"` options have been renamed to "client" and "server" respectively
* @param {null | NodeLike} node
*/
export function no_reactive_declaration(node) {
w(node, "no_reactive_declaration", "Reactive declarations only exist at the top level of the instance script");
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");
}
/**
* All dependencies of the reactive declaration are declared in a module script and will not be reactive
* Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`
* @param {null | NodeLike} node
*/
export function module_script_reactive_declaration(node) {
w(node, "module_script_reactive_declaration", "All dependencies of the reactive declaration are declared in a module script and will not be reactive");
export function derived_iife(node) {
w(node, "derived_iife", "Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`");
}
/**
@ -496,163 +483,160 @@ export function module_script_reactive_declaration(node) {
* @param {null | NodeLike} node
* @param {string} name
*/
export function unused_export_let(node, name) {
w(node, "unused_export_let", `Component has unused export property '${name}'. If it is for external reference only, please consider using \`export const ${name}\``);
export function export_let_unused(node, name) {
w(node, "export_let_unused", `Component has unused export property '${name}'. If it is for external reference only, please consider using \`export const ${name}\``);
}
/**
* Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.
* @param {null | NodeLike} node
*/
export function deprecated_slot_element(node) {
w(node, "deprecated_slot_element", "Using <slot> to render parent content is deprecated. Use {@render ...} tags instead.");
}
/**
* Using on:%name% to listen to the %name% event is is deprecated. Use the event attribute on%name% instead.
* `%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
* @param {null | NodeLike} node
* @param {string} name
*/
export function deprecated_event_handler(node, name) {
w(node, "deprecated_event_handler", `Using on:${name} to listen to the ${name} event is is deprecated. Use the event attribute on${name} instead.`);
export function non_reactive_update(node, name) {
w(node, "non_reactive_update", `\`${name}\` is updated, but is not declared with \`$state(...)\`. Changing its value will not correctly trigger updates`);
}
/**
* Self-closing HTML tags for non-void elements are ambiguous use <%name% ...></%name%> rather than <%name% ... />
* Avoid 'new class' instead, declare the class at the top level scope
* @param {null | NodeLike} node
* @param {string} name
*/
export function invalid_self_closing_tag(node, name) {
w(node, "invalid_self_closing_tag", `Self-closing HTML tags for non-void elements are ambiguous — use <${name} ...></${name}> rather than <${name} ... />`);
export function perf_avoid_inline_class(node) {
w(node, "perf_avoid_inline_class", "Avoid 'new class' — instead, declare the class at the top level scope");
}
/**
* The `accessors` option has been deprecated. It will have no effect in runes mode
* Avoid declaring classes below the top level scope
* @param {null | NodeLike} node
*/
export function options_deprecated_accessors(node) {
w(node, "options_deprecated_accessors", "The `accessors` option has been deprecated. It will have no effect in runes mode");
export function perf_avoid_nested_class(node) {
w(node, "perf_avoid_nested_class", "Avoid declaring classes below the top level scope");
}
/**
* The `immutable` option has been deprecated. It will have no effect in runes mode
* Reactive declarations only exist at the top level of the instance script
* @param {null | NodeLike} node
*/
export function options_deprecated_immutable(node) {
w(node, "options_deprecated_immutable", "The `immutable` option has been deprecated. It will have no effect in runes mode");
export function reactive_declaration_invalid_placement(node) {
w(node, "reactive_declaration_invalid_placement", "Reactive declarations only exist at the top level of the instance script");
}
/**
* The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?
* All dependencies of the reactive declaration are declared in a module script and will not be reactive
* @param {null | NodeLike} node
*/
export function options_missing_custom_element(node) {
w(node, "options_missing_custom_element", "The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option?");
export function reactive_declaration_module_script(node) {
w(node, "reactive_declaration_module_script", "All dependencies of the reactive declaration are declared in a module script and will not be reactive");
}
/**
* `generate: "dom"` and `generate: "ssr"` options have been renamed to "client" and "server" respectively
* State referenced in its own scope will never update. Did you mean to reference it inside a closure?
* @param {null | NodeLike} node
*/
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");
export function state_referenced_locally(node) {
w(node, "state_referenced_locally", "State referenced in its own scope will never update. Did you mean to reference it inside a closure?");
}
/**
* The `enableSourcemap` option has been removed. Source maps are always generated now, and tooling can choose to ignore them
* It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity
* @param {null | NodeLike} node
* @param {string} name
*/
export function options_removed_enable_sourcemap(node) {
w(node, "options_removed_enable_sourcemap", "The `enableSourcemap` option has been removed. Source maps are always generated now, and tooling can choose to ignore them");
export function store_rune_conflict(node, name) {
w(node, "store_rune_conflict", `It looks like you're using the \`$${name}\` rune, but there is a local binding called \`${name}\`. Referencing a local variable with a \`$\` prefix will create a store subscription. Please rename \`${name}\` to avoid the ambiguity`);
}
/**
* The `hydratable` option has been removed. Svelte components are always hydratable now
* Unused CSS selector "%name%"
* @param {null | NodeLike} node
* @param {string} name
*/
export function options_removed_hydratable(node) {
w(node, "options_removed_hydratable", "The `hydratable` option has been removed. Svelte components are always hydratable now");
export function css_unused_selector(node, name) {
w(node, "css_unused_selector", `Unused CSS selector "${name}"`);
}
/**
* The `loopGuardTimeout` option has been removed
* The "is" attribute is not supported cross-browser and should be avoided
* @param {null | NodeLike} node
*/
export function options_removed_loop_guard_timeout(node) {
w(node, "options_removed_loop_guard_timeout", "The `loopGuardTimeout` option has been removed");
export function attribute_avoid_is(node) {
w(node, "attribute_avoid_is", "The \"is\" attribute is not supported cross-browser and should be avoided");
}
/**
* Avoid 'new class' instead, declare the class at the top level scope
* You are referencing `globalThis.%name%`. Did you forget to declare a variable with that name?
* @param {null | NodeLike} node
* @param {string} name
*/
export function avoid_inline_class(node) {
w(node, "avoid_inline_class", "Avoid 'new class' — instead, declare the class at the top level scope");
export function attribute_global_event_reference(node, name) {
w(node, "attribute_global_event_reference", `You are referencing \`globalThis.${name}\`. Did you forget to declare a variable with that name?`);
}
/**
* Avoid declaring classes below the top level scope
* Attributes should not contain ':' characters to prevent ambiguity with Svelte directives
* @param {null | NodeLike} node
*/
export function avoid_nested_class(node) {
w(node, "avoid_nested_class", "Avoid declaring classes below the top level scope");
export function attribute_illegal_colon(node) {
w(node, "attribute_illegal_colon", "Attributes should not contain ':' characters to prevent ambiguity with Svelte directives");
}
/**
* It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity
* '%wrong%' is not a valid HTML attribute. Did you mean '%right%'?
* @param {null | NodeLike} node
* @param {string} name
* @param {string} wrong
* @param {string} right
*/
export function store_with_rune_name(node, name) {
w(node, "store_with_rune_name", `It looks like you're using the \`$${name}\` rune, but there is a local binding called \`${name}\`. Referencing a local variable with a \`$\` prefix will create a store subscription. Please rename \`${name}\` to avoid the ambiguity`);
export function attribute_invalid_property_name(node, wrong, right) {
w(node, "attribute_invalid_property_name", `'${wrong}' is not a valid HTML attribute. Did you mean '${right}'?`);
}
/**
* `%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates
* The rest operator (...) will create a new object and binding '%name%' with the original object will not work
* @param {null | NodeLike} node
* @param {string} name
*/
export function non_state_reference(node, name) {
w(node, "non_state_reference", `\`${name}\` is updated, but is not declared with \`$state(...)\`. Changing its value will not correctly trigger updates`);
export function bind_invalid_each_rest(node, name) {
w(node, "bind_invalid_each_rest", `The rest operator (...) will create a new object and binding '${name}' with the original object will not work`);
}
/**
* Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`
* Empty block
* @param {null | NodeLike} node
*/
export function derived_iife(node) {
w(node, "derived_iife", "Use `$derived.by(() => {...})` instead of `$derived((() => {...})())`");
export function block_empty(node) {
w(node, "block_empty", "Empty block");
}
/**
* Component properties are declared using `$props()` in runes mode. Did you forget to call the function?
* `<%name%>` will be treated as an HTML element unless it begins with a capital letter
* @param {null | NodeLike} node
* @param {string} name
*/
export function invalid_props_declaration(node) {
w(node, "invalid_props_declaration", "Component properties are declared using `$props()` in runes mode. Did you forget to call the function?");
export function component_name_lowercase(node, name) {
w(node, "component_name_lowercase", `\`<${name}>\` will be treated as an HTML element unless it begins with a capital letter`);
}
/**
* Bindable component properties are declared using `$bindable()` in runes mode. Did you forget to call the function?
* Self-closing HTML tags for non-void elements are ambiguous use `<%name% ...></%name%>` rather than `<%name% ... />`
* @param {null | NodeLike} node
* @param {string} name
*/
export function invalid_bindable_declaration(node) {
w(node, "invalid_bindable_declaration", "Bindable component properties are declared using `$bindable()` in runes mode. Did you forget to call the function?");
export function element_invalid_self_closing_tag(node, name) {
w(node, "element_invalid_self_closing_tag", `Self-closing HTML tags for non-void elements are ambiguous — use \`<${name} ...></${name}>\` rather than \`<${name} ... />\``);
}
/**
* State referenced in its own scope will never update. Did you mean to reference it inside a closure?
* Using `on:%name%` to listen to the %name% event is deprecated. Use the event attribute `on%name%` instead.
* @param {null | NodeLike} node
* @param {string} name
*/
export function static_state_reference(node) {
w(node, "static_state_reference", "State referenced in its own scope will never update. Did you mean to reference it inside a closure?");
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.`);
}
/**
* The rest operator (...) will create a new object and binding '%name%' with the original object will not work
* Using `<slot>` to render parent content is deprecated. Use `{@render ...}` tags instead.
* @param {null | NodeLike} node
* @param {string} name
*/
export function invalid_rest_eachblock_binding(node, name) {
w(node, "invalid_rest_eachblock_binding", `The rest operator (...) will create a new object and binding '${name}' with the original object will not work`);
export function slot_element_deprecated(node) {
w(node, "slot_element_deprecated", "Using `<slot>` to render parent content is deprecated. Use `{@render ...}` tags instead.");
}

@ -2,6 +2,7 @@ import { current_component_context, flush_sync, untrack } from './internal/clien
import { is_array } from './internal/client/utils.js';
import { user_effect } from './internal/client/index.js';
import * as e from './internal/client/errors.js';
import { lifecycle_outside_component } from './internal/shared/errors.js';
/**
* The `onMount` function schedules a callback to run as soon as the component has been mounted to the DOM.
@ -19,7 +20,7 @@ import * as e from './internal/client/errors.js';
*/
export function onMount(fn) {
if (current_component_context === null) {
e.lifecycle_outside_component('onMount');
lifecycle_outside_component('onMount');
}
if (current_component_context.l !== null) {
@ -44,7 +45,7 @@ export function onMount(fn) {
*/
export function onDestroy(fn) {
if (current_component_context === null) {
e.lifecycle_outside_component('onDestroy');
lifecycle_outside_component('onDestroy');
}
onMount(() => () => untrack(fn));
@ -88,7 +89,7 @@ function create_custom_event(type, detail, { bubbles = false, cancelable = false
export function createEventDispatcher() {
const component_context = current_component_context;
if (component_context === null) {
e.lifecycle_outside_component('createEventDispatcher');
lifecycle_outside_component('createEventDispatcher');
}
return (type, detail, options) => {
@ -127,11 +128,11 @@ export function createEventDispatcher() {
*/
export function beforeUpdate(fn) {
if (current_component_context === null) {
e.lifecycle_outside_component('beforeUpdate');
lifecycle_outside_component('beforeUpdate');
}
if (current_component_context.l === null) {
throw new Error('beforeUpdate cannot be used in runes mode');
e.lifecycle_legacy_only('beforeUpdate');
}
init_update_callbacks(current_component_context).b.push(fn);
@ -151,7 +152,7 @@ export function beforeUpdate(fn) {
*/
export function afterUpdate(fn) {
if (current_component_context === null) {
e.lifecycle_outside_component('afterUpdate');
lifecycle_outside_component('afterUpdate');
}
if (current_component_context.l === null) {

@ -1,5 +1,6 @@
import { current_component } from './internal/server/context.js';
import { noop } from './internal/shared/utils.js';
import * as e from './internal/server/errors.js';
/** @param {() => void} fn */
export function onDestroy(fn) {
@ -20,15 +21,15 @@ export function createEventDispatcher() {
}
export function mount() {
throw new Error('mount(...) is not available on the server');
e.lifecycle_function_unavailable('mount');
}
export function hydrate() {
throw new Error('hydrate(...) is not available on the server');
e.lifecycle_function_unavailable('hydrate');
}
export function unmount() {
throw new Error('unmount(...) is not available on the server');
e.lifecycle_function_unavailable('unmount');
}
export async function tick() {}

@ -6,6 +6,7 @@ import { delegate } from './events.js';
import { autofocus } from './misc.js';
import { effect } from '../../reactivity/effects.js';
import { run } from '../../../shared/utils.js';
import * as w from '../../warnings.js';
/**
* The value/checked attribute in the template actually corresponds to the defaultValue property, so we need
@ -263,13 +264,10 @@ function check_src_in_dev_hydration(element, attribute, value) {
if (attribute === 'srcset' && srcset_url_equal(element, value)) return;
if (src_url_equal(element.getAttribute(attribute) ?? '', value ?? '')) return;
// eslint-disable-next-line no-console
console.error(
`Detected a ${attribute} attribute value change during hydration. This will not be repaired during hydration, ` +
`the ${attribute} value that came from the server will be used. Related element:`,
element,
' Differing value:',
value
w.hydration_attribute_changed(
attribute,
element.outerHTML.replace(element.innerHTML, '...'),
String(value)
);
}

@ -2,6 +2,7 @@ import { DEV } from 'esm-env';
import { render_effect, effect } from '../../../reactivity/effects.js';
import { stringify } from '../../../render.js';
import { listen_to_event_and_reset_event } from './shared.js';
import * as e from '../../../errors.js';
/**
* @param {HTMLInputElement} input
@ -12,9 +13,8 @@ import { listen_to_event_and_reset_event } from './shared.js';
export function bind_value(input, get_value, update) {
listen_to_event_and_reset_event(input, 'input', () => {
if (DEV && input.type === 'checkbox') {
throw new Error(
'Using bind:value together with a checkbox input is not allowed. Use bind:checked instead'
);
// TODO should this happen in prod too?
e.bind_invalid_checkbox_value();
}
update(is_numberlike_input(input) ? to_number(input.value) : input.value);
@ -22,9 +22,8 @@ export function bind_value(input, get_value, update) {
render_effect(() => {
if (DEV && input.type === 'checkbox') {
throw new Error(
'Using bind:value together with a checkbox input is not allowed. Use bind:checked instead'
);
// TODO should this happen in prod too?
e.bind_invalid_checkbox_value();
}
var value = get_value();

@ -1,4 +1,5 @@
import { HYDRATION_END, HYDRATION_START } from '../../../constants.js';
import * as e from '../errors.js';
/**
* Use this variable to guard everything related to hydration code so it can be treeshaken out
@ -66,5 +67,5 @@ export function hydrate_anchor(node) {
nodes.push(current);
}
throw new Error('Expected a closing hydration marker');
e.hydration_missing_marker_close();
}

@ -2,6 +2,113 @@
import { DEV } from 'esm-env';
/**
* Using `bind:value` together with a checkbox input is not allowed. Use `bind:checked` instead
* @returns {never}
*/
export function bind_invalid_checkbox_value() {
if (DEV) {
const error = new Error(`${"bind_invalid_checkbox_value"}\n${"Using `bind:value` together with a checkbox input is not allowed. Use `bind:checked` instead"}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("bind_invalid_checkbox_value");
}
}
/**
* Component %component% has an export named `%key%` that a consumer component is trying to access using `bind:%key%`, which is disallowed. Instead, use `bind:this` (e.g. `<%name% bind:this={component} />`) and then access the property on the bound component instance (e.g. `component.%key%`)
* @param {string} component
* @param {string} key
* @param {string} name
* @returns {never}
*/
export function bind_invalid_export(component, key, name) {
if (DEV) {
const error = new Error(`${"bind_invalid_export"}\n${`Component ${component} has an export named \`${key}\` that a consumer component is trying to access using \`bind:${key}\`, which is disallowed. Instead, use \`bind:this\` (e.g. \`<${name} bind:this={component} />\`) and then access the property on the bound component instance (e.g. \`component.${key}\`)`}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("bind_invalid_export");
}
}
/**
* A component is attempting to bind to a non-bindable property `%key%` belonging to %component% (i.e. `<%name% bind:%key%={...}>`). To mark a property as bindable: `let { %key% = $bindable() } = $props()`
* @param {string} key
* @param {string} component
* @param {string} name
* @returns {never}
*/
export function bind_not_bindable(key, component, name) {
if (DEV) {
const error = new Error(`${"bind_not_bindable"}\n${`A component is attempting to bind to a non-bindable property \`${key}\` belonging to ${component} (i.e. \`<${name} bind:${key}={...}>\`). To mark a property as bindable: \`let { ${key} = $bindable() } = $props()\``}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("bind_not_bindable");
}
}
/**
* Keyed each block has duplicate key `%value%` at indexes %a% and %b%
* @param {string} a
* @param {string} b
* @param {string | undefined | null} [value]
* @returns {never}
*/
export function each_key_duplicate(a, b, value) {
if (DEV) {
const error = new Error(`${"each_key_duplicate"}\n${value ? `Keyed each block has duplicate key \`${value}\` at indexes ${a} and ${b}` : `Keyed each block has duplicate key at indexes ${a} and ${b}`}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("each_key_duplicate");
}
}
/**
* `%rune%` cannot be used inside an effect cleanup function
* @param {string} rune
* @returns {never}
*/
export function effect_in_teardown(rune) {
if (DEV) {
const error = new Error(`${"effect_in_teardown"}\n${`\`${rune}\` cannot be used inside an effect cleanup function`}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("effect_in_teardown");
}
}
/**
* `%rune%` can only be used inside an effect (e.g. during component initialisation)
* @param {string} rune
* @returns {never}
*/
export function effect_orphan(rune) {
if (DEV) {
const error = new Error(`${"effect_orphan"}\n${`\`${rune}\` can only be used inside an effect (e.g. during component initialisation)`}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("effect_orphan");
}
}
/**
* Maximum update depth exceeded. This can happen when a reactive block or effect repeatedly sets a new value. Svelte limits the number of nested updates to prevent infinite loops
* @returns {never}
@ -19,19 +126,34 @@ export function effect_update_depth_exceeded() {
}
/**
* `%name%(...)` can only be used during component initialisation
* @param {string} name
* Missing hydration closing marker
* @returns {never}
*/
export function lifecycle_outside_component(name) {
export function hydration_missing_marker_close() {
if (DEV) {
const error = new Error(`${"lifecycle_outside_component"}\n${`\`${name}(...)\` can only be used during component initialisation`}`);
const error = new Error(`${"hydration_missing_marker_close"}\n${"Missing hydration closing marker"}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("lifecycle_outside_component");
throw new Error("hydration_missing_marker_close");
}
}
/**
* Missing hydration opening marker
* @returns {never}
*/
export function hydration_missing_marker_open() {
if (DEV) {
const error = new Error(`${"hydration_missing_marker_open"}\n${"Missing hydration opening marker"}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("hydration_missing_marker_open");
}
}
@ -50,4 +172,105 @@ export function lifecycle_legacy_only(name) {
// TODO print a link to the documentation
throw new Error("lifecycle_legacy_only");
}
}
/**
* Cannot do `bind:%key%={undefined}` when `%key%` has a fallback value
* @param {string} key
* @returns {never}
*/
export function props_invalid_value(key) {
if (DEV) {
const error = new Error(`${"props_invalid_value"}\n${`Cannot do \`bind:${key}={undefined}\` when \`${key}\` has a fallback value`}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("props_invalid_value");
}
}
/**
* Rest element properties of `$props()` such as `%property%` are readonly
* @param {string} property
* @returns {never}
*/
export function props_rest_readonly(property) {
if (DEV) {
const error = new Error(`${"props_rest_readonly"}\n${`Rest element properties of \`$props()\` such as \`${property}\` are readonly`}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("props_rest_readonly");
}
}
/**
* The `%rune%` rune is only available inside `.svelte` and `.svelte.js/ts` files
* @param {string} rune
* @returns {never}
*/
export function rune_outside_svelte(rune) {
if (DEV) {
const error = new Error(`${"rune_outside_svelte"}\n${`The \`${rune}\` rune is only available inside \`.svelte\` and \`.svelte.js/ts\` files`}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("rune_outside_svelte");
}
}
/**
* Cannot set prototype of `$state` object
* @returns {never}
*/
export function state_prototype_fixed() {
if (DEV) {
const error = new Error(`${"state_prototype_fixed"}\n${"Cannot set prototype of `$state` object"}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("state_prototype_fixed");
}
}
/**
* Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. This can lead to unexpected errors and possibly cause infinite loops.
* >
* If the object is not meant to be reactive, declare it without `$state`
* @returns {never}
*/
export function state_unsafe_mutation() {
if (DEV) {
const error = new Error(`${"state_unsafe_mutation"}\n${"Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. This can lead to unexpected errors and possibly cause infinite loops.\n>\nIf the object is not meant to be reactive, declare it without `$state`"}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("state_unsafe_mutation");
}
}
/**
* The `this={...}` property of a `<svelte:component>` must be a Svelte component, if defined
* @returns {never}
*/
export function svelte_component_invalid_this_value() {
if (DEV) {
const error = new Error(`${"svelte_component_invalid_this_value"}\n${"The `this={...}` property of a `<svelte:component>` must be a Svelte component, if defined"}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("svelte_component_invalid_this_value");
}
}

@ -128,8 +128,7 @@ export {
export {
validate_dynamic_component,
validate_each_keys,
validate_prop_bindings,
validate_store
validate_prop_bindings
} from './validate.js';
export { raf } from './timing.js';
export { proxy, snapshot } from './proxy.js';
@ -147,5 +146,6 @@ export {
validate_component,
validate_dynamic_element_tag,
validate_snippet,
validate_store,
validate_void_dynamic_element
} from '../shared/validate.js';

@ -20,6 +20,7 @@ import { check_ownership, widen_ownership } from './dev/ownership.js';
import { mutable_source, source, set } from './reactivity/sources.js';
import { STATE_SYMBOL } from './constants.js';
import { UNINITIALIZED } from '../../constants.js';
import * as e from './errors.js';
/**
* @template T
@ -334,6 +335,6 @@ const state_proxy_handler = {
if (DEV) {
state_proxy_handler.setPrototypeOf = () => {
throw new Error('Cannot set prototype of $state object');
e.state_prototype_fixed();
};
}

@ -1,4 +1,3 @@
import { DEV } from 'esm-env';
import {
check_dirtiness,
current_component_context,
@ -30,6 +29,7 @@ import {
} from '../constants.js';
import { set } from './sources.js';
import { remove } from '../dom/reconciler.js';
import * as e from '../errors.js';
/**
* @param {import('#client').Effect | null} effect
@ -38,19 +38,11 @@ import { remove } from '../dom/reconciler.js';
*/
export function validate_effect(effect, rune) {
if (effect === null) {
throw new Error(
'ERR_SVELTE_ORPHAN_EFFECT' +
(DEV
? `: ${rune} can only be used inside an effect (e.g. during component initialisation)`
: '')
);
e.effect_orphan(rune);
}
if (is_destroying_effect) {
throw new Error(
'ERR_SVELTE_EFFECT_IN_TEARDOWN' +
(DEV ? `: ${rune} cannot be used inside an effect cleanup function.` : '')
);
e.effect_in_teardown(rune);
}
}

@ -11,6 +11,7 @@ import { derived } from './deriveds.js';
import { get, is_signals_recorded, untrack } from '../runtime.js';
import { safe_equals } from './equality.js';
import { inspect_fn } from '../dev/inspect.js';
import * as e from '../errors.js';
/**
* @param {((value?: number) => number)} fn
@ -46,9 +47,8 @@ const rest_props_handler = {
},
set(target, key) {
if (DEV) {
throw new Error(
`Rest element properties of $props() such as ${target.name}.${String(key)} are readonly`
);
// TODO should this happen in prod too?
e.props_rest_readonly(`${target.name}.${String(key)}`);
}
return false;
@ -169,13 +169,7 @@ export function prop(props, key, flags, fallback) {
if (prop_value === undefined && fallback !== undefined) {
if (setter && runes) {
// TODO consolidate all these random runtime errors
throw new Error(
'ERR_SVELTE_BINDING_FALLBACK' +
(DEV
? `: Cannot pass undefined to bind:${key} because the property contains a fallback value. Pass a different value than undefined to ${key}.`
: '')
);
e.props_invalid_value(key);
}
prop_value = get_fallback();

@ -19,6 +19,7 @@ import {
import { equals, safe_equals } from './equality.js';
import { CLEAN, DERIVED, DIRTY, BRANCH_EFFECT } from '../constants.js';
import { UNINITIALIZED } from '../../../constants.js';
import * as e from '../errors.js';
/**
* @template V
@ -91,14 +92,7 @@ export function set(signal, value) {
is_runes() &&
(current_reaction.f & DERIVED) !== 0
) {
throw new Error(
'ERR_SVELTE_UNSAFE_MUTATION' +
(DEV
? ": Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. " +
'This can lead to unexpected errors and possibly cause infinite loops.\n\nIf this mutation is not meant ' +
'to be reactive do not use the "$state" rune for that declaration.'
: '')
);
e.state_unsafe_mutation();
}
if (!signal.equals(value)) {

@ -20,6 +20,7 @@ import { array_from } from './utils.js';
import { handle_event_propagation } from './dom/elements/events.js';
import { reset_head_anchor } from './dom/blocks/svelte-head.js';
import * as w from './warnings.js';
import * as e from './errors.js';
/** @type {Set<string>} */
export const all_registered_events = new Set();
@ -143,7 +144,7 @@ export function hydrate(component, options) {
}
if (!node) {
throw new Error('Missing hydration marker');
e.hydration_missing_marker_open();
}
const anchor = hydrate_anchor(node);
@ -158,14 +159,7 @@ export function hydrate(component, options) {
}, false);
} catch (error) {
if (!hydrated && options.recover !== false) {
// eslint-disable-next-line no-console
console.error(
'ERR_SVELTE_HYDRATION_MISMATCH' +
(DEV
? ': Hydration failed because the initial UI does not match what was rendered on the server.'
: ''),
error
);
w.hydration_mismatch();
clear_text_content(target);

@ -23,6 +23,7 @@ import { mutate, set, source } from './reactivity/sources.js';
import { update_derived } from './reactivity/deriveds.js';
import { inspect_captured_signals, inspect_fn, set_inspect_fn } from './dev/inspect.js';
import * as e from './errors.js';
import { lifecycle_outside_component } from '../shared/errors.js';
const FLUSH_MICROTASK = 0;
const FLUSH_SYNC = 1;
@ -952,7 +953,7 @@ export function getAllContexts() {
*/
function get_or_init_context_map(name) {
if (current_component_context === null) {
e.lifecycle_outside_component(name);
lifecycle_outside_component(name);
}
return (current_component_context.c ??= new Map(
@ -1185,13 +1186,13 @@ if (DEV) {
let value; // let's hope noone modifies this global, but belts and braces
Object.defineProperty(globalThis, rune, {
configurable: true,
// eslint-disable-next-line getter-return
get: () => {
if (value !== undefined) {
return value;
}
throw new Error(
`The ${rune} rune is only available inside .svelte and .svelte.js/ts files`
);
e.rune_outside_svelte(rune);
},
set: (v) => {
value = v;

@ -1,5 +1,6 @@
import { untrack } from './runtime.js';
import { get_descriptor, is_array } from './utils.js';
import * as e from './errors.js';
/** regex of all html void element names */
const void_element_names =
@ -10,35 +11,27 @@ function is_void(tag) {
return void_element_names.test(tag) || tag.toLowerCase() === '!doctype';
}
/**
* @param {any} store
* @param {string} name
*/
export function validate_store(store, name) {
if (store != null && typeof store.subscribe !== 'function') {
throw new Error(`'${name}' is not a store with a 'subscribe' method`);
}
}
/**
* @param {() => any} component_fn
* @returns {any}
*/
export function validate_dynamic_component(component_fn) {
const error_message = 'this={...} of <svelte:component> should specify a Svelte component.';
try {
const instance = component_fn();
if (instance !== undefined && typeof instance !== 'object') {
throw new Error(error_message);
e.svelte_component_invalid_this_value();
}
return instance;
} catch (err) {
const { message } = /** @type {Error} */ (err);
if (typeof message === 'string' && message.indexOf('is not a function') !== -1) {
throw new Error(error_message);
} else {
throw err;
e.svelte_component_invalid_this_value();
}
throw err;
}
}
@ -59,29 +52,19 @@ export function validate_each_keys(collection, key_fn) {
for (let i = 0; i < length; i++) {
const key = key_fn(array[i], i);
if (keys.has(key)) {
throw new Error(
`Cannot have duplicate keys in a keyed each: Keys at index ${keys.get(
key
)} and ${i} with value '${array[i]}' are duplicates`
);
const a = String(keys.get(key));
const b = String(i);
/** @type {string | null} */
let k = String(array[i]);
if (k.startsWith('[object ')) k = null;
e.each_key_duplicate(a, b, k);
}
keys.set(key, i);
}
}
/**
* @param {number} timeout
* @returns {() => void}
* */
export function loop_guard(timeout) {
const start = Date.now();
return () => {
if (Date.now() - start > timeout) {
throw new Error('Infinite loop detected');
}
};
}
/**
* @param {Record<string, any>} $$props
* @param {string[]} bindable
@ -95,17 +78,11 @@ export function validate_prop_bindings($$props, bindable, exports, component) {
if (setter) {
if (exports.includes(key)) {
throw new Error(
`Component ${component.filename} has an export named ${key} that a consumer component is trying to access using bind:${key}, which is disallowed. ` +
`Instead, use bind:this (e.g. <${name} bind:this={component} />) ` +
`and then access the property on the bound component instance (e.g. component.${key}).`
);
e.bind_invalid_export(component.filename, key, name);
}
if (!bindable.includes(key)) {
throw new Error(
`A component is binding to property ${key} of ${name}.svelte (i.e. <${name} bind:${key} />). This is disallowed because the property was not declared as bindable inside ${component.filename}. ` +
`To mark a property as bindable, use the $bindable() rune in ${name}.svelte like this: \`let { ${key} = $bindable() } = $props()\``
);
e.bind_not_bindable(key, component.filename, name);
}
}
}

@ -5,6 +5,33 @@ import { DEV } from 'esm-env';
var bold = 'font-weight: bold';
var normal = 'font-weight: normal';
/**
* The `%attribute%` attribute on `%html%` changed its value between server and client renders. The client value, `%value%`, will be ignored in favour of the server value
* @param {string} attribute
* @param {string} html
* @param {string} value
*/
export function hydration_attribute_changed(attribute, html, value) {
if (DEV) {
console.warn(`%c[svelte] ${"hydration_attribute_changed"}\n%c${`The \`${attribute}\` attribute on \`${html}\` changed its value between server and client renders. The client value, \`${value}\`, will be ignored in favour of the server value`}`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("hydration_attribute_changed");
}
}
/**
* Hydration failed because the initial UI does not match what was rendered on the server
*/
export function hydration_mismatch() {
if (DEV) {
console.warn(`%c[svelte] ${"hydration_mismatch"}\n%c${"Hydration failed because the initial UI does not match what was rendered on the server"}`, bold, normal);
} else {
// TODO print a link to the documentation
console.warn("hydration_mismatch");
}
}
/**
* Tried to unmount a component that was not mounted
*/

@ -1,5 +1,6 @@
import { DEV } from 'esm-env';
import { on_destroy } from './index.js';
import * as e from '../shared/errors.js';
/** @type {import('#server').Component | null} */
export var current_component = null;
@ -10,7 +11,7 @@ export var current_component = null;
* @returns {T}
*/
export function getContext(key) {
const context_map = getAllContexts();
const context_map = get_or_init_context_map('getContext');
const result = /** @type {T} */ (context_map.get(key));
return result;
@ -23,7 +24,7 @@ export function getContext(key) {
* @returns {T}
*/
export function setContext(key, context) {
getAllContexts().set(key, context);
get_or_init_context_map('setContext').set(key, context);
return context;
}
@ -32,21 +33,24 @@ export function setContext(key, context) {
* @returns {boolean}
*/
export function hasContext(key) {
return getAllContexts().has(key);
return get_or_init_context_map('hasContext').has(key);
}
/** @returns {Map<any, any>} */
export function getAllContexts() {
const context = current_component;
return get_or_init_context_map('getAllContexts');
}
if (context === null) {
throw new Error(
'ERR_SVELTE_ORPHAN_CONTEXT' +
(DEV ? 'Context can only be used during component initialisation.' : '')
);
/**
* @param {string} name
* @returns {Map<unknown, unknown>}
*/
function get_or_init_context_map(name) {
if (current_component === null) {
e.lifecycle_outside_component(name);
}
return (context.c ??= new Map(get_parent_context(context) || undefined));
return (current_component.c ??= new Map(get_parent_context(current_component) || undefined));
}
export function push() {

@ -0,0 +1,13 @@
/* This file is generated by scripts/process-messages/index.js. Do not edit! */
/**
* `%name%(...)` is not available on the server
* @param {string} name
* @returns {never}
*/
export function lifecycle_function_unavailable(name) {
const error = new Error(`${"lifecycle_function_unavailable"}\n${`\`${name}(...)\` is not available on the server`}`);
error.name = 'Svelte error';
throw error;
}

@ -11,6 +11,7 @@ import {
import { DEV } from 'esm-env';
import { current_component, pop, push } from './context.js';
import { BLOCK_CLOSE, BLOCK_OPEN } from './hydration.js';
import { validate_store } from '../shared/validate.js';
/**
* @typedef {{
@ -443,16 +444,6 @@ export function store_get(store_values, store_name, store) {
return store_values[store_name][2];
}
/**
* @param {any} store
* @param {string} name
*/
export function validate_store(store, name) {
if (store != null && typeof store.subscribe !== 'function') {
throw new Error(`'${name}' is not a store with a 'subscribe' method`);
}
}
/**
* Sets the new value of a store and returns that value.
* @template V
@ -631,19 +622,6 @@ export function ensure_array_like(array_like_or_iterator) {
: Array.from(array_like_or_iterator);
}
/**
* @param {number} timeout
* @returns {() => void}
* */
export function loop_guard(timeout) {
const start = Date.now();
return () => {
if (Date.now() - start > timeout) {
throw new Error('Infinite loop detected');
}
};
}
/**
* @param {any[]} args
* @param {Function} [inspect]

@ -0,0 +1,85 @@
/* This file is generated by scripts/process-messages/index.js. Do not edit! */
import { DEV } from 'esm-env';
/**
* `%name%(...)` can only be used during component initialisation
* @param {string} name
* @returns {never}
*/
export function lifecycle_outside_component(name) {
if (DEV) {
const error = new Error(`${"lifecycle_outside_component"}\n${`\`${name}(...)\` can only be used during component initialisation`}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("lifecycle_outside_component");
}
}
/**
* The argument to `{@render ...}` must be a snippet function, not a component or some other kind of function. If you want to dynamically render one snippet or another, use `$derived` and pass its result to `{@render ...}`
* @returns {never}
*/
export function render_tag_invalid_argument() {
if (DEV) {
const error = new Error(`${"render_tag_invalid_argument"}\n${"The argument to `{@render ...}` must be a snippet function, not a component or some other kind of function. If you want to dynamically render one snippet or another, use `$derived` and pass its result to `{@render ...}`"}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("render_tag_invalid_argument");
}
}
/**
* A snippet must be rendered with `{@render ...}`
* @returns {never}
*/
export function snippet_used_as_component() {
if (DEV) {
const error = new Error(`${"snippet_used_as_component"}\n${"A snippet must be rendered with `{@render ...}`"}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("snippet_used_as_component");
}
}
/**
* `%name%` is not a store with a `subscribe` method
* @param {string} name
* @returns {never}
*/
export function store_invalid_shape(name) {
if (DEV) {
const error = new Error(`${"store_invalid_shape"}\n${`\`${name}\` is not a store with a \`subscribe\` method`}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("store_invalid_shape");
}
}
/**
* The `this` prop on `<svelte:element>` must be a string, if defined
* @returns {never}
*/
export function svelte_element_invalid_this_value() {
if (DEV) {
const error = new Error(`${"svelte_element_invalid_this_value"}\n${"The `this` prop on `<svelte:element>` must be a string, if defined"}`);
error.name = 'Svelte error';
throw error;
} else {
// TODO print a link to the documentation
throw new Error("svelte_element_invalid_this_value");
}
}

@ -1,5 +1,6 @@
import { is_void } from '../../compiler/phases/1-parse/utils/names.js';
import * as w from './warnings.js';
import * as e from './errors.js';
const snippet_symbol = Symbol.for('svelte.snippet');
@ -17,11 +18,9 @@ export function add_snippet_symbol(fn) {
*/
export function validate_snippet(snippet_fn) {
if (snippet_fn && snippet_fn[snippet_symbol] !== true) {
throw new Error(
'The argument to `{@render ...}` must be a snippet function, not a component or some other kind of function. ' +
'If you want to dynamically render one snippet or another, use `$derived` and pass its result to `{@render ...}`.'
);
e.render_tag_invalid_argument();
}
return snippet_fn;
}
@ -31,8 +30,9 @@ export function validate_snippet(snippet_fn) {
*/
export function validate_component(component_fn) {
if (component_fn?.[snippet_symbol] === true) {
throw new Error('A snippet must be rendered with `{@render ...}`');
e.snippet_used_as_component();
}
return component_fn;
}
@ -52,6 +52,16 @@ export function validate_dynamic_element_tag(tag_fn) {
const tag = tag_fn();
const is_string = typeof tag === 'string';
if (tag && !is_string) {
throw new Error('<svelte:element> expects "this" attribute to be a string.');
e.svelte_element_invalid_this_value();
}
}
/**
* @param {any} store
* @param {string} name
*/
export function validate_store(store, name) {
if (store != null && typeof store.subscribe !== 'function') {
e.store_invalid_shape(name);
}
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'missing_attribute_value',
code: 'expected_attribute_value',
message: 'Expected attribute value',
position: [12, 12]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_sequence_expression',
code: 'attribute_invalid_sequence_expression',
message:
'Sequence expressions are not allowed as attribute/directive values in runes mode, unless wrapped in parentheses',
position: [124, 131]

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_sequence_expression',
code: 'attribute_invalid_sequence_expression',
message:
'Sequence expressions are not allowed as attribute/directive values in runes mode, unless wrapped in parentheses',
position: [163, 170]

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate_attribute',
code: 'attribute_duplicate',
message: 'Attributes need to be unique',
position: [17, 17]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate_attribute',
code: 'attribute_duplicate',
message: 'Attributes need to be unique',
position: [17, 17]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate_attribute',
code: 'attribute_duplicate',
message: 'Attributes need to be unique',
position: [17, 17]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_continuing_block_placement',
code: 'block_invalid_continuation_placement',
message:
'{:...} block is invalid at this position (did you forget to close the preceeding element or block?)',
position: [1, 1]

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_state_location',
code: 'state_invalid_placement',
message:
'`$state(...)` can only be used as a variable declaration initializer or a class field',
position: [33, 41]

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate_slot_name',
code: 'slot_attribute_duplicate',
message: "Duplicate slot name 'foo' in <Nested>"
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate_slot_name',
code: 'slot_attribute_duplicate',
message: "Duplicate slot name 'foo' in <Nested>"
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_default_slot_content',
code: 'slot_default_duplicate',
message: 'Found default slot content alongside an explicit slot="default"'
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate_slot_name',
code: 'slot_attribute_duplicate',
message: "Duplicate slot name 'foo' in <Nested>"
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate_slot_name',
code: 'slot_attribute_duplicate',
message: "Duplicate slot name 'foo' in <Nested>"
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'duplicate_slot_name',
code: 'slot_attribute_duplicate',
message: "Duplicate slot name 'foo' in <Nested>"
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_slot_placement',
code: 'slot_attribute_invalid_placement',
message:
"Element with a slot='...' attribute must be a child of a component or a descendant of a custom element"
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_slot_placement',
code: 'slot_attribute_invalid_placement',
message:
"Element with a slot='...' attribute must be a child of a component or a descendant of a custom element"
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_slot_placement',
code: 'slot_attribute_invalid_placement',
message:
"Element with a slot='...' attribute must be a child of a component or a descendant of a custom element"
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_css_global_block_combinator',
code: 'css_global_block_invalid_combinator',
message: 'A :global {...} block cannot follow a > combinator',
position: [12, 21]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_css_global_block_declaration',
code: 'css_global_block_invalid_declaration',
message: 'A :global {...} block can only contain rules, not declarations',
position: [24, 34]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_css_global_block_modifier',
code: 'css_global_block_invalid_modifier',
message: 'A :global {...} block cannot modify an existing selector',
position: [14, 21]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_css_global_block_list',
code: 'css_global_block_invalid_list',
message: 'A :global {...} block cannot be part of a selector list with more than one item',
position: [9, 31]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_css_identifier',
code: 'css_expected_identifier',
message: 'Expected a valid CSS identifier',
position: [25, 25]
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_dollar_binding',
code: 'dollar_binding_invalid',
message: 'The $ name is reserved, and cannot be used for variables and imports'
}
});

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'illegal_global',
code: 'global_reference_invalid',
message:
'`$` is an illegal variable name. To reference a global variable called `$`, use `globalThis.$`'
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'illegal_global',
code: 'global_reference_invalid',
message:
'`$` is an illegal variable name. To reference a global variable called `$`, use `globalThis.$`'
}

@ -2,7 +2,7 @@ import { test } from '../../test';
export default test({
error: {
code: 'invalid_dollar_binding',
code: 'dollar_binding_invalid',
message: 'The $ name is reserved, and cannot be used for variables and imports'
}
});

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save