diff --git a/CHANGELOG.md b/CHANGELOG.md index cbafadc807..9c910667ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ * Treat slots as if they don't exist when using CSS adjacent and general sibling combinators ([#8284](https://github.com/sveltejs/svelte/issues/8284)) * Fix transitions so that they don't require a `style-src 'unsafe-inline'` Content Security Policy (CSP) ([#6662](https://github.com/sveltejs/svelte/issues/6662)). * Explicitly disallow `var` declarations extending the reactive statement scope ([#6800](https://github.com/sveltejs/svelte/pull/6800)) +* Warn about `:` in attributes and props to prevent ambiguity with Svelte directives ([#6823](https://github.com/sveltejs/svelte/issues/6823)) ## 3.59.1 diff --git a/src/compiler/compile/compiler_warnings.js b/src/compiler/compile/compiler_warnings.js index c20d2e5677..96b68a4228 100644 --- a/src/compiler/compile/compiler_warnings.js +++ b/src/compiler/compile/compiler_warnings.js @@ -301,5 +301,10 @@ export default { code: 'avoid-mouse-events-on-document', message: 'Mouse enter/leave events on the document are not supported in all browsers and should be avoided' + }, + illegal_attribute_character: { + code: 'illegal-attribute-character', + message: + "Attributes should not contain ':' characters to prevent ambiguity with Svelte directives" } }; diff --git a/src/compiler/compile/nodes/Attribute.js b/src/compiler/compile/nodes/Attribute.js index 19efa25dbb..1cfb96dc25 100644 --- a/src/compiler/compile/nodes/Attribute.js +++ b/src/compiler/compile/nodes/Attribute.js @@ -3,6 +3,7 @@ import add_to_set from '../utils/add_to_set.js'; import Node from './shared/Node.js'; import Expression from './shared/Expression.js'; import { x } from 'code-red'; +import compiler_warnings from '../compiler_warnings.js'; /** @extends Node<'Attribute' | 'Spread', import('./Element.js').default> */ export default class Attribute extends Node { @@ -39,6 +40,7 @@ export default class Attribute extends Node { constructor(component, parent, scope, info) { super(component, parent, scope, info); this.scope = scope; + if (info.type === 'Spread') { this.name = null; this.is_spread = true; @@ -64,10 +66,22 @@ export default class Attribute extends Node { } ); } + if (this.dependencies.size > 0) { parent.cannot_use_innerhtml(); parent.not_static_content(); } + + // TODO Svelte 5: Think about moving this into the parser and make it an error + if ( + this.name && + this.name.includes(':') && + !this.name.startsWith('xmlns:') && + !this.name.startsWith('xlink:') && + !this.name.startsWith('xml:') + ) { + component.warn(this, compiler_warnings.illegal_attribute_character); + } } get_dependencies() { if (this.is_spread) return this.expression.dynamic_dependencies(); diff --git a/src/compiler/parse/state/tag.js b/src/compiler/parse/state/tag.js index 603031c08c..c0df00df92 100644 --- a/src/compiler/parse/state/tag.js +++ b/src/compiler/parse/state/tag.js @@ -433,7 +433,6 @@ function get_directive_type(name) { if (name === 'style') return 'StyleDirective'; if (name === 'on') return 'EventHandler'; if (name === 'let') return 'Let'; - if (name === 'ref') return 'Ref'; if (name === 'in' || name === 'out' || name === 'transition') return 'Transition'; } diff --git a/test/validator/samples/illegal-attribute-character/input.svelte b/test/validator/samples/illegal-attribute-character/input.svelte new file mode 100644 index 0000000000..c0ef6849a1 --- /dev/null +++ b/test/validator/samples/illegal-attribute-character/input.svelte @@ -0,0 +1,15 @@ + + +