pull/11294/head
Rich Harris 2 years ago
parent abfbd06f35
commit f9f94db4f0

@ -14,29 +14,37 @@ Event attribute must be a JavaScript expression, not a string
'%name%' is not a valid attribute name
## invalid_animation
## animation_invalid_placement
An element that uses the animate directive must be the immediate child of a keyed each block`
: type === 'each-key'
? `An element that uses the animate directive must be used inside a keyed each block. Did you forget to add a key to your each block?`
: `An element that uses the animate directive must be the sole child of a keyed each block
An element that uses the `animate:` directive must be the only child of a keyed `{#each ...}` block
## duplicate_animation
## 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 %modifiers.slice(0, -1).join(', ')% or %modifiers.slice(-1)%`
: `Event modifiers other than 'once' can only be used on DOM elements
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
## duplicate_transition
## transition_duplicate
TODO
Cannot use multiple `%type%:` directives on a single element
## transition_conflict
Cannot use `%type%:` alongside existing `%existing%:` directive
## invalid_let_directive_placement
@ -48,4 +56,4 @@ 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
Sequence expressions are not allowed as attribute/directive values in runes mode, unless wrapped in parentheses

@ -149,7 +149,6 @@ const const_tag = {
/** @satisfies {Errors} */
const errors = {
...internal,
...attributes,
...slots,
...bindings,
...variables,

@ -98,8 +98,8 @@ export function invalid_attribute_name(node, name) {
* @returns {never}
*/
export function invalid_animation(node) {
e(node, "invalid_animation", "An element that uses the animate directive must be the immediate child of a keyed each block`\n\t\t\t: type === 'each-key'\n\t\t\t\t? `An element that uses the animate directive must be used inside a keyed each block. Did you forget to add a key to your each block?`\n\t\t\t\t: `An element that uses the animate directive must be the sole child of a keyed each block");
export function animation_invalid_placement(node) {
e(node, "animation_invalid_placement", "An element that uses the `animate:` directive must be the only child of a keyed `{#each ...}` block");
}
/**
@ -107,8 +107,8 @@ export function invalid_animation(node) {
* @returns {never}
*/
export function duplicate_animation(node) {
e(node, "duplicate_animation", "An element can only have one 'animate' directive");
export function animation_missing_key(node) {
e(node, "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?");
}
/**
@ -116,8 +116,26 @@ export function duplicate_animation(node) {
* @returns {never}
*/
export function invalid_event_modifier(node) {
e(node, "invalid_event_modifier", "Valid event modifiers are %modifiers.slice(0, -1).join(', ')% or %modifiers.slice(-1)%`\n\t\t\t: `Event modifiers other than 'once' can only be used on DOM elements");
export function animation_duplicate(node) {
e(node, "animation_duplicate", "An element can only have one 'animate' directive");
}
/**
* @param {number | NodeLike} node
* @param {string} list
* @returns {never}
*/
export function invalid_event_modifier(node, list) {
e(node, "invalid_event_modifier", `Valid event modifiers are ${list}`);
}
/**
* @param {number | NodeLike} node
* @returns {never}
*/
export function invalid_component_event_modifier(node) {
e(node, "invalid_component_event_modifier", "Event modifiers other than 'once' can only be used on DOM elements");
}
/**
@ -132,11 +150,21 @@ export function invalid_event_modifier_combination(node, modifier1, modifier2) {
/**
* @param {number | NodeLike} node
* @param {string} type
* @returns {never}
*/
export function transition_duplicate(node, type) {
e(node, "transition_duplicate", `Cannot use multiple \`${type}:\` directives on a single element`);
}
/**
* @param {number | NodeLike} node
* @param {string} type
* @param {string} existing
* @returns {never}
*/
export function duplicate_transition(node) {
e(node, "duplicate_transition", "TODO");
export function transition_conflict(node, type, existing) {
e(node, "transition_conflict", `Cannot use \`${type}:\` alongside existing \`${existing}:\` directive`);
}
/**
@ -397,7 +425,7 @@ export function invalid_css_declaration(node) {
* @returns {never}
*/
export function invalid_textarea_content(node) {
e(node, "invalid_textarea_content", "A <textarea> can have either a value attribute or (equivalently) child content, but not both");
e(node, "invalid_textarea_content", "A `<textarea>` can have either a value attribute or (equivalently) child content, but not both");
}
/**
@ -424,7 +452,7 @@ export function invalid_element_content(node, name) {
* @returns {never}
*/
export function invalid_tag_name(node) {
e(node, "invalid_tag_name", "TODO");
e(node, "invalid_tag_name", "Expected valid tag name");
}
/**
@ -443,7 +471,7 @@ export function invalid_node_placement(node, thing, parent) {
* @returns {never}
*/
export function illegal_title_attribute(node) {
e(node, "illegal_title_attribute", "TODO");
e(node, "illegal_title_attribute", "`<title>` cannot have attributes nor directives");
}
/**
@ -452,7 +480,7 @@ export function illegal_title_attribute(node) {
* @returns {never}
*/
export function invalid_title_content(node) {
e(node, "invalid_title_content", "TODO");
e(node, "invalid_title_content", "`<title>` can only contain text and {tags}");
}
/**
@ -945,15 +973,6 @@ export function invalid_binding(node, thing) {
e(node, "invalid_binding", `Invalid assignment to ${thing}`);
}
/**
* @param {number | NodeLike} node
* @returns {never}
*/
export function invalid_const_assignment(node) {
e(node, "invalid_const_assignment", "Invalid %is_binding ? 'binding' : 'assignment'% to const variable%\nshow_details\n? ' ($derived values, let: directives, :then/:catch variables and @const declarations count as const)'\n: ''\n%");
}
/**
* @param {number | NodeLike} node
* @param {string} rune

@ -5,7 +5,6 @@ import read_expression from '../read/expression.js';
import { read_script } from '../read/script.js';
import read_style from '../read/style.js';
import { closing_tag_omitted, decode_character_references } from '../utils/html.js';
import { error } from '../../../errors-tmp.js';
import * as e from '../../../errors.js';
import { create_fragment } from '../utils/create.js';
import { create_attribute } from '../../nodes.js';
@ -220,7 +219,7 @@ export default function tag(parser) {
while ((attribute = read(parser))) {
if (attribute.type === 'Attribute' || attribute.type === 'BindDirective') {
if (unique_names.includes(attribute.name)) {
error(attribute.start, 'duplicate-attribute');
e.duplicate_attribute(attribute.start);
// <svelte:element bind:this this=..> is allowed
} else if (attribute.name !== 'this') {
unique_names.push(attribute.name);
@ -507,7 +506,7 @@ function read_attribute(parser) {
const name = parser.read_identifier();
if (name === null) {
error(start, 'empty-attribute-shorthand');
e.empty_attribute_shorthand(start);
}
parser.allow_whitespace();

@ -52,7 +52,7 @@ function validate_component(node, context) {
attribute.type === 'OnDirective' &&
(attribute.modifiers.length > 1 || attribute.modifiers.some((m) => m !== 'once'))
) {
error(attribute, 'invalid-event-modifier');
e.invalid_component_event_modifier(attribute);
}
if (attribute.type === 'Attribute') {
@ -63,7 +63,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 === '{') error(expression, 'invalid-sequence-expression');
if (char === '{') e.invalid_sequence_expression(expression);
}
}
}
@ -94,8 +94,12 @@ const react_attributes = new Map([
*/
function validate_element(node, context) {
let has_animate_directive = false;
let has_in_transition = false;
let has_out_transition = false;
/** @type {import('#compiler').TransitionDirective | null} */
let in_transition = null;
/** @type {import('#compiler').TransitionDirective | null} */
let out_transition = null;
for (const attribute of node.attributes) {
if (attribute.type === 'Attribute') {
@ -108,18 +112,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 === '{') error(expression, 'invalid-sequence-expression');
if (char === '{') e.invalid_sequence_expression(expression);
}
}
}
if (regex_illegal_attribute_character.test(attribute.name)) {
error(attribute, 'invalid-attribute-name', attribute.name);
e.invalid_attribute_name(attribute, attribute.name);
}
if (attribute.name.startsWith('on') && attribute.name.length > 2) {
if (!is_expression) {
error(attribute, 'invalid-event-attribute-value');
e.invalid_event_attribute_value(attribute);
}
const value = attribute.value[0].expression;
@ -163,9 +167,9 @@ function validate_element(node, context) {
} else if (attribute.type === 'AnimateDirective') {
const parent = context.path.at(-2);
if (parent?.type !== 'EachBlock') {
error(attribute, 'invalid-animation', 'no-each');
e.animation_invalid_placement(attribute);
} else if (!parent.key) {
error(attribute, 'invalid-animation', 'each-key');
e.animation_missing_key(attribute);
} else if (
parent.body.nodes.filter(
(n) =>
@ -174,34 +178,36 @@ function validate_element(node, context) {
(n.type !== 'Text' || n.data.trim() !== '')
).length > 1
) {
error(attribute, 'invalid-animation', 'child');
e.animation_invalid_placement(attribute);
}
if (has_animate_directive) {
error(attribute, 'duplicate-animation');
e.animation_duplicate(attribute);
} else {
has_animate_directive = true;
}
} else if (attribute.type === 'TransitionDirective') {
if ((attribute.outro && has_out_transition) || (attribute.intro && has_in_transition)) {
/** @param {boolean} _in @param {boolean} _out */
const type = (_in, _out) => (_in && _out ? 'transition' : _in ? 'in' : 'out');
error(
attribute,
'duplicate-transition',
type(has_in_transition, has_out_transition),
type(attribute.intro, attribute.outro)
);
const existing = /** @type {import('#compiler').TransitionDirective | null} */ (
attribute.intro ? in_transition : out_transition
);
if (existing !== null) {
if (attribute.name === existing.name) {
e.transition_duplicate(attribute, attribute.name);
} else {
e.transition_conflict(attribute, attribute.name, existing.name);
}
}
has_in_transition = has_in_transition || attribute.intro;
has_out_transition = has_out_transition || attribute.outro;
if (attribute.intro) in_transition = attribute;
if (attribute.outro) out_transition = attribute;
} else if (attribute.type === 'OnDirective') {
let has_passive_modifier = false;
let conflicting_passive_modifier = '';
for (const modifier of attribute.modifiers) {
if (!EventModifiers.includes(modifier)) {
error(attribute, 'invalid-event-modifier', EventModifiers);
const list = `${EventModifiers.slice(0, 1)} or ${EventModifiers.at(-1)}`;
e.invalid_event_modifier(attribute, list);
}
if (modifier === 'passive') {
has_passive_modifier = true;
@ -209,12 +215,7 @@ function validate_element(node, context) {
conflicting_passive_modifier = modifier;
}
if (has_passive_modifier && conflicting_passive_modifier) {
error(
attribute,
'invalid-event-modifier-combination',
'passive',
conflicting_passive_modifier
);
e.invalid_event_modifier_combination(attribute, 'passive', conflicting_passive_modifier);
}
}
}
@ -521,7 +522,7 @@ const validation = {
parent.type !== 'SvelteSelf' &&
parent.type !== 'SvelteFragment')
) {
error(node, 'invalid-let-directive-placement');
e.invalid_let_directive_placement(node);
}
},
RegularElement(node, context) {
@ -673,7 +674,7 @@ const validation = {
},
StyleDirective(node) {
if (node.modifiers.length > 1 || (node.modifiers.length && node.modifiers[0] !== 'important')) {
error(node, 'invalid-style-directive-modifier');
e.invalid_style_directive_modifier(node);
}
},
SvelteHead(node) {

Loading…
Cancel
Save