diff --git a/.changeset/itchy-beans-melt.md b/.changeset/itchy-beans-melt.md new file mode 100644 index 0000000000..e6a58d02ff --- /dev/null +++ b/.changeset/itchy-beans-melt.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +chore: fix compiler errors test suite diff --git a/.changeset/lazy-masks-sit.md b/.changeset/lazy-masks-sit.md new file mode 100644 index 0000000000..553bbf4a6f --- /dev/null +++ b/.changeset/lazy-masks-sit.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: ensure transitions properly cancel on completion diff --git a/.changeset/spicy-plums-admire.md b/.changeset/spicy-plums-admire.md new file mode 100644 index 0000000000..9ba9e5313c --- /dev/null +++ b/.changeset/spicy-plums-admire.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: apply event attribute validation to elements only diff --git a/.changeset/sweet-mangos-beg.md b/.changeset/sweet-mangos-beg.md new file mode 100644 index 0000000000..3a0adfc03c --- /dev/null +++ b/.changeset/sweet-mangos-beg.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: handle css nth-selector syntax diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js index 2a2d969475..8d01f4ac97 100644 --- a/packages/svelte/src/compiler/errors.js +++ b/packages/svelte/src/compiler/errors.js @@ -24,9 +24,11 @@ const internal = { const parse = { /** @param {string} name */ 'unclosed-element': (name) => `<${name}> was left open`, - 'unclosed-block': () => `block was left open`, + 'unclosed-block': () => `Block was left open`, 'unexpected-block-close': () => `Unexpected block closing tag`, - 'unexpected-eof': () => `Unexpected end of input`, + /** @param {string} [expected] */ + 'unexpected-eof': (expected) => + `Unexpected end of input` + (expected ? ` (expected ${expected})` : ''), /** @param {string} message */ 'js-parse-error': (message) => message, /** @param {string} token */ @@ -39,17 +41,15 @@ const parse = { 'invalid-script-context': () => `If the context attribute is supplied, its value must be "module"`, 'invalid-elseif': () => `'elseif' should be 'else if'`, - /** - * @param {string} child - * @param {string} parent - */ - 'invalid-block-parent': (child, parent) => - `Expected to close ${parent} before seeing ${child} block`, + 'invalid-continuing-block-placement': () => + `{:...} block is invalid at this position (did you forget to close the preceeding element or block?)`, /** * @param {string} child * @param {string} parent */ 'invalid-block-missing-parent': (child, parent) => `${child} block must be a child of ${parent}`, + /** @param {string} name */ + 'duplicate-block-part': (name) => `${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`, @@ -98,12 +98,9 @@ const css = { 'invalid-css-empty-declaration': () => `Declaration cannot be empty`, 'invalid-css-global-placement': () => `:global(...) can be at the start or end of a selector sequence, but not in the middle`, - 'invalid-css-global-selector': () => `:global(...) must contain exactly one selector`, - 'invalid-css-global-selector-list': () => `:global(...) cannot be used to modify a selector, or be modified by another selector`, - 'invalid-css-selector': () => `Invalid selector`, 'invalid-css-identifier': () => 'Expected a valid CSS identifier' }; diff --git a/packages/svelte/src/compiler/phases/1-parse/index.js b/packages/svelte/src/compiler/phases/1-parse/index.js index 5199ad5960..6b7642c251 100644 --- a/packages/svelte/src/compiler/phases/1-parse/index.js +++ b/packages/svelte/src/compiler/phases/1-parse/index.js @@ -77,8 +77,10 @@ export class Parser { const current = this.current(); if (current.type === 'RegularElement') { + current.end = current.start + 1; error(current, 'unclosed-element', current.name); } else { + current.end = current.start + 1; error(current, 'unclosed-block'); } } @@ -145,7 +147,7 @@ export class Parser { if (required) { if (this.index === this.template.length) { - error(this.index, 'unexpected-eof'); + error(this.index, 'unexpected-eof', str); } else { error(this.index, 'expected-token', str); } diff --git a/packages/svelte/src/compiler/phases/1-parse/read/style.js b/packages/svelte/src/compiler/phases/1-parse/read/style.js index 5197f10329..9f59e8205e 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/style.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/style.js @@ -6,6 +6,7 @@ const REGEX_ATTRIBUTE_FLAGS = /^[a-zA-Z]+/; // only `i` and `s` are valid today, const REGEX_COMBINATOR_WHITESPACE = /^\s*(\+|~|>|\|\|)\s*/; const REGEX_COMBINATOR = /^(\+|~|>|\|\|)/; const REGEX_PERCENTAGE = /^\d+(\.\d+)?%/; +const REGEX_NTH_OF = /^(even|odd|(-?[0-9]?n?(\s*\+\s*[0-9]+)?))(\s+of\s+)?/; const REGEX_WHITESPACE_OR_COLON = /[\s:]/; const REGEX_BRACE_OR_SEMICOLON = /[{;]/; const REGEX_LEADING_HYPHEN_OR_DIGIT = /-?\d/; @@ -234,6 +235,8 @@ function read_selector(parser, inside_pseudo_class = false) { if (parser.eat('(')) { args = read_selector_list(parser, true); parser.eat(')', true); + } else if (name === 'global') { + error(parser.index, 'invalid-css-global-selector'); } children.push({ @@ -291,6 +294,13 @@ function read_selector(parser, inside_pseudo_class = false) { start, end: parser.index }); + } else if (parser.match_regex(REGEX_NTH_OF)) { + children.push({ + type: 'Nth', + value: /** @type {string} */ (parser.read(REGEX_NTH_OF)), + start, + end: parser.index + }); } else { let name = read_identifier(parser); if (parser.match('|')) { diff --git a/packages/svelte/src/compiler/phases/1-parse/state/element.js b/packages/svelte/src/compiler/phases/1-parse/state/element.js index a5e2a2a82a..019e29c944 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/element.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/element.js @@ -202,11 +202,13 @@ export default function tag(parser) { let attribute; while ((attribute = read(parser))) { - if ( - (attribute.type === 'Attribute' || attribute.type === 'BindDirective') && - unique_names.includes(attribute.name) - ) { - error(attribute.start, 'duplicate-attribute'); + if (attribute.type === 'Attribute' || attribute.type === 'BindDirective') { + if (unique_names.includes(attribute.name)) { + error(attribute.start, 'duplicate-attribute'); + // is allowed + } else if (attribute.name !== 'this') { + unique_names.push(attribute.name); + } } element.attributes.push(attribute); @@ -635,13 +637,14 @@ function read_attribute_value(parser) { 'in attribute value' ); } catch (/** @type {any} e */ e) { - if (e.code === 'parse-error') { + if (e.code === 'js-parse-error') { // if the attribute value didn't close + self-closing tag // eg: `` // acorn may throw a `Unterminated regular expression` because of `/>` - if (parser.template.slice(e.pos - 1, e.pos + 1) === '/>') { - parser.index = e.pos; - error(e.pos, 'unclosed-attribute-value', quote_mark || '}'); + const pos = e.position?.[0]; + if (pos !== undefined && parser.template.slice(pos - 1, pos + 1) === '/>') { + parser.index = pos; + error(pos, 'unclosed-attribute-value', quote_mark || '}'); } } throw e; diff --git a/packages/svelte/src/compiler/phases/1-parse/state/tag.js b/packages/svelte/src/compiler/phases/1-parse/state/tag.js index 36a66ac59f..ebfebb73b1 100644 --- a/packages/svelte/src/compiler/phases/1-parse/state/tag.js +++ b/packages/svelte/src/compiler/phases/1-parse/state/tag.js @@ -315,7 +315,7 @@ function next(parser) { const block = parser.current(); // TODO type should not be TemplateNode, that's much too broad if (block.type === 'IfBlock') { - if (!parser.eat('else')) error(start, 'expected-token', 'else'); + if (!parser.eat('else')) error(start, 'expected-token', '{:else} or {:else if}'); if (parser.eat('if')) error(start, 'invalid-elseif'); parser.allow_whitespace(); @@ -359,7 +359,7 @@ function next(parser) { } if (block.type === 'EachBlock') { - if (!parser.eat('else')) error(start, 'expected-token', 'else'); + if (!parser.eat('else')) error(start, 'expected-token', '{:else}'); parser.allow_whitespace(); parser.eat('}', true); @@ -375,7 +375,7 @@ function next(parser) { if (block.type === 'AwaitBlock') { if (parser.eat('then')) { if (block.then) { - error(start, 'TODO', 'duplicate then'); + error(start, 'duplicate-block-part', '{:then}'); } if (!parser.eat('}')) { @@ -394,7 +394,7 @@ function next(parser) { if (parser.eat('catch')) { if (block.catch) { - error(start, 'TODO', 'duplicate catch'); + error(start, 'duplicate-block-part', '{:catch}'); } if (!parser.eat('}')) { @@ -413,6 +413,8 @@ function next(parser) { error(start, 'expected-token', '{:then ...} or {:catch ...}'); } + + error(start, 'invalid-continuing-block-placement'); } /** @param {import('../index.js').Parser} parser */ diff --git a/packages/svelte/src/compiler/phases/2-analyze/css/Selector.js b/packages/svelte/src/compiler/phases/2-analyze/css/Selector.js index fcddaf2df6..b0942d6572 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/css/Selector.js +++ b/packages/svelte/src/compiler/phases/2-analyze/css/Selector.js @@ -306,7 +306,7 @@ function block_might_apply_to_node(block, node) { while (i--) { const selector = block.selectors[i]; - if (selector.type === 'Percentage') continue; + if (selector.type === 'Percentage' || selector.type === 'Nth') continue; const name = selector.name.replace(regex_backslash_and_following_character, '$1'); diff --git a/packages/svelte/src/compiler/phases/2-analyze/validation.js b/packages/svelte/src/compiler/phases/2-analyze/validation.js index 2323282893..3be08c75fb 100644 --- a/packages/svelte/src/compiler/phases/2-analyze/validation.js +++ b/packages/svelte/src/compiler/phases/2-analyze/validation.js @@ -65,12 +65,24 @@ function validate_element(node, context) { error(attribute, 'invalid-attribute-name', attribute.name); } - if (attribute.name === 'is' && context.state.options.namespace !== 'foreign') { - warn(context.state.analysis.warnings, attribute, context.path, 'avoid-is'); - } else if (attribute.name === 'slot') { + if (attribute.name.startsWith('on') && attribute.name.length > 2) { + if ( + attribute.value === true || + is_text_attribute(attribute) || + attribute.value.length > 1 + ) { + error(attribute, 'invalid-event-attribute-value'); + } + } + + if (attribute.name === 'slot') { /** @type {import('#compiler').RegularElement | import('#compiler').SvelteElement | import('#compiler').Component | import('#compiler').SvelteComponent | import('#compiler').SvelteSelf | undefined} */ validate_slot_attribute(context, attribute); } + + if (attribute.name === 'is' && context.state.options.namespace !== 'foreign') { + warn(context.state.analysis.warnings, attribute, context.path, 'avoid-is'); + } } else if (attribute.type === 'AnimateDirective') { const parent = context.path.at(-2); if (parent?.type !== 'EachBlock') { @@ -316,13 +328,6 @@ function is_tag_valid_with_parent(tag, parent_tag) { * @type {import('zimmerframe').Visitors} */ export const validation = { - Attribute(node) { - if (node.name.startsWith('on') && node.name.length > 2) { - if (node.value === true || is_text_attribute(node) || node.value.length > 1) { - error(node, 'invalid-event-attribute-value'); - } - } - }, BindDirective(node, context) { validate_no_const_assignment(node, node.expression, context.state.scope, true); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/utils.js b/packages/svelte/src/compiler/phases/3-transform/client/utils.js index d6700add11..0227313214 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/utils.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/utils.js @@ -1,6 +1,7 @@ import * as b from '../../../utils/builders.js'; import { extract_paths, is_simple_expression } from '../../../utils/ast.js'; import { error } from '../../../errors.js'; +import { PROPS_CALL_DEFAULT_VALUE, PROPS_IS_IMMUTABLE } from '../../../../constants.js'; /** * @template {import('./types').ClientTransformState} State @@ -359,29 +360,43 @@ export function get_props_method(binding, state, name, default_value) { (state.analysis.immutable ? binding.reassigned : binding.mutated); if (needs_source) { - args.push(b.literal(state.analysis.immutable)); - } + let flags = 0; - if (default_value) { - // To avoid eagerly evaluating the right-hand-side, we wrap it in a thunk if necessary - if (is_simple_expression(default_value)) { - args.push(default_value); - } else { - if ( - default_value.type === 'CallExpression' && - default_value.callee.type === 'Identifier' && - default_value.arguments.length === 0 - ) { - args.push(default_value.callee); + /** @type {import('estree').Expression | undefined} */ + let arg; + + if (state.analysis.immutable) { + flags |= PROPS_IS_IMMUTABLE; + } + + if (default_value) { + // To avoid eagerly evaluating the right-hand-side, we wrap it in a thunk if necessary + if (is_simple_expression(default_value)) { + arg = default_value; } else { - args.push(b.thunk(default_value)); + if ( + default_value.type === 'CallExpression' && + default_value.callee.type === 'Identifier' && + default_value.arguments.length === 0 + ) { + arg = default_value.callee; + } else { + arg = b.thunk(default_value); + } + + flags |= PROPS_CALL_DEFAULT_VALUE; } + } - args.push(b.true); + if (flags || arg) { + args.push(b.literal(flags)); + if (arg) args.push(arg); } + + return b.call('$.prop_source', ...args); } - return b.call(needs_source ? '$.prop_source' : '$.prop', ...args); + return b.call('$.prop', ...args); } /** diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index feb9174187..fb43ec654b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -795,32 +795,17 @@ function serialize_inline_component(node, component_name, context) { push_prop( b.get(attribute.name, [ b.return( - b.call( - '$.exposable', - b.thunk( - /** @type {import('estree').Expression} */ (context.visit(attribute.expression)) - ) - ) + /** @type {import('estree').Expression} */ (context.visit(attribute.expression)) ) ]) ); - // If the binding is just a reference to a top level state variable - // we don't need a setter as the inner component can write to the signal directly - const binding = - attribute.expression.type !== 'Identifier' - ? null - : context.state.scope.get(attribute.expression.name); - if ( - binding === null || - (binding.kind !== 'state' && binding.kind !== 'prop' && binding.kind !== 'rest_prop') - ) { - const assignment = b.assignment('=', attribute.expression, b.id('$$value')); - push_prop( - b.set(attribute.name, [ - b.stmt(serialize_set_binding(assignment, context, () => context.visit(assignment))) - ]) - ); - } + + const assignment = b.assignment('=', attribute.expression, b.id('$$value')); + push_prop( + b.set(attribute.name, [ + b.stmt(serialize_set_binding(assignment, context, () => context.visit(assignment))) + ]) + ); } } } diff --git a/packages/svelte/src/compiler/types/css.d.ts b/packages/svelte/src/compiler/types/css.d.ts index 7d936207ac..49a3fc5143 100644 --- a/packages/svelte/src/compiler/types/css.d.ts +++ b/packages/svelte/src/compiler/types/css.d.ts @@ -67,6 +67,11 @@ export interface Percentage extends BaseNode { value: string; } +export interface Nth extends BaseNode { + type: 'Nth'; + value: string; +} + export type SimpleSelector = | TypeSelector | IdSelector @@ -74,7 +79,8 @@ export type SimpleSelector = | AttributeSelector | PseudoElementSelector | PseudoClassSelector - | Percentage; + | Percentage + | Nth; export interface Combinator extends BaseNode { type: 'Combinator'; diff --git a/packages/svelte/src/constants.js b/packages/svelte/src/constants.js index 6b7cc123f5..d5daaf700b 100644 --- a/packages/svelte/src/constants.js +++ b/packages/svelte/src/constants.js @@ -5,6 +5,9 @@ export const EACH_IS_CONTROLLED = 1 << 3; export const EACH_IS_ANIMATED = 1 << 4; export const EACH_IS_IMMUTABLE = 1 << 6; +export const PROPS_IS_IMMUTABLE = 1; +export const PROPS_CALL_DEFAULT_VALUE = 1 << 1; + /** List of Element events that will be delegated */ export const DelegatedEvents = [ 'beforeinput', diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index e3ebafe854..d1fa227c6d 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -34,7 +34,6 @@ import { untrack, effect, flushSync, - expose, safe_not_equal, current_block, source, @@ -1202,10 +1201,7 @@ export function bind_prop(props, prop, value) { /** @param {V | null} value */ const update = (value) => { const current_props = unwrap(props); - const signal = expose(() => current_props[prop]); - if (is_signal(signal)) { - set(signal, value); - } else if (get_descriptor(current_props, prop)?.set !== undefined) { + if (get_descriptor(current_props, prop)?.set !== undefined) { current_props[prop] = value; } }; diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 2d3e5204c7..29f1b733dd 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -1,7 +1,8 @@ import { DEV } from 'esm-env'; import { subscribe_to_store } from '../../store/utils.js'; import { EMPTY_FUNC, run_all } from '../common.js'; -import { get_descriptors, is_array } from './utils.js'; +import { get_descriptor, get_descriptors, is_array } from './utils.js'; +import { PROPS_CALL_DEFAULT_VALUE, PROPS_IS_IMMUTABLE } from '../../constants.js'; export const SOURCE = 1; export const DERIVED = 1 << 1; @@ -30,8 +31,7 @@ let current_scheduler_mode = FLUSH_MICROTASK; // Used for handling scheduling let is_micro_task_queued = false; let is_task_queued = false; -// Used for exposing signals -let is_signal_exposed = false; + // Handle effect queues /** @type {import('./types.js').EffectSignal[]} */ @@ -63,8 +63,6 @@ export let current_untracking = false; /** Exists to opt out of the mutation validation for stores which may be set for the first time during a derivation */ let ignore_mutation_validation = false; -/** @type {null | import('./types.js').Signal} */ -let current_captured_signal = null; // If we are working with a get() chain that has no active container, // to prevent memory leaks, we skip adding the consumer. let current_skip_consumer = false; @@ -800,23 +798,6 @@ export function unsubscribe_on_destroy(stores) { }); } -/** - * Wraps a function and marks execution context so that the last signal read from can be captured - * using the `expose` function. - * @template V - * @param {() => V} fn - * @returns {V} - */ -export function exposable(fn) { - const previous_is_signal_exposed = is_signal_exposed; - try { - is_signal_exposed = true; - return fn(); - } finally { - is_signal_exposed = previous_is_signal_exposed; - } -} - /** * @template V * @param {import('./types.js').Signal} signal @@ -836,10 +817,6 @@ export function get(signal) { return signal.v; } - if (is_signal_exposed && current_should_capture_signal) { - current_captured_signal = signal; - } - if (is_signals_recorded) { captured_signals.add(signal); } @@ -906,31 +883,6 @@ export function set_sync(signal, value) { flushSync(() => set(signal, value)); } -/** - * Invokes a function and captures the last signal that is read during the invocation - * if that signal is read within the `exposable` function context. - * If a signal is captured, it returns the signal instead of the read value. - * @template V - * @param {() => V} possible_signal_fn - * @returns {any} - */ -export function expose(possible_signal_fn) { - const previous_captured_signal = current_captured_signal; - const previous_should_capture_signal = current_should_capture_signal; - current_captured_signal = null; - current_should_capture_signal = true; - try { - const value = possible_signal_fn(); - if (current_captured_signal === null) { - return value; - } - return current_captured_signal; - } finally { - current_captured_signal = previous_captured_signal; - current_should_capture_signal = previous_should_capture_signal; - } -} - /** * Invokes a function and captures all signals that are read during the invocation, * then invalidates them. @@ -1463,35 +1415,19 @@ export function is_store(val) { * @template V * @param {import('./types.js').MaybeSignal>} props_obj * @param {string} key - * @param {boolean} immutable + * @param {number} flags * @param {V | (() => V)} [default_value] - * @param {boolean} [call_default_value] * @returns {import('./types.js').Signal | (() => V)} */ -export function prop_source(props_obj, key, immutable, default_value, call_default_value) { +export function prop_source(props_obj, key, flags, default_value) { + const call_default_value = (flags & PROPS_CALL_DEFAULT_VALUE) !== 0; + const immutable = (flags & PROPS_IS_IMMUTABLE) !== 0; + const props = is_signal(props_obj) ? get(props_obj) : props_obj; - const possible_signal = /** @type {import('./types.js').MaybeSignal} */ ( - expose(() => props[key]) - ); - const update_bound_prop = Object.getOwnPropertyDescriptor(props, key)?.set; + const update_bound_prop = get_descriptor(props, key)?.set; let value = props[key]; const should_set_default_value = value === undefined && default_value !== undefined; - if ( - is_signal(possible_signal) && - possible_signal.v === value && - update_bound_prop === undefined - ) { - if (should_set_default_value) { - set( - possible_signal, - // @ts-expect-error would need a cumbersome method overload to type this - call_default_value ? default_value() : default_value - ); - } - return possible_signal; - } - if (should_set_default_value) { value = // @ts-expect-error would need a cumbersome method overload to type this @@ -1534,7 +1470,7 @@ export function prop_source(props_obj, key, immutable, default_value, call_defau } }); - if (is_signal(possible_signal) && update_bound_prop !== undefined) { + if (update_bound_prop !== undefined) { let ignore_first = !should_set_default_value; sync_effect(() => { // Before if to ensure signal dependency is registered @@ -1548,11 +1484,9 @@ export function prop_source(props_obj, key, immutable, default_value, call_defau return; } - if (not_equal(immutable, propagating_value, possible_signal.v)) { - ignore_next1 = true; - did_update_to_defined = true; - untrack(() => update_bound_prop(propagating_value)); - } + ignore_next1 = true; + did_update_to_defined = true; + untrack(() => update_bound_prop(propagating_value)); }); } diff --git a/packages/svelte/src/internal/client/transitions.js b/packages/svelte/src/internal/client/transitions.js index 27db05fdd2..d55dbbba56 100644 --- a/packages/svelte/src/internal/client/transitions.js +++ b/packages/svelte/src/internal/client/transitions.js @@ -177,9 +177,12 @@ class TickAnimation { } cancel() { - const t = this.#reversed ? 1 : 0; active_tick_animations.delete(this); - this.#tick_fn(t, 1 - t); + const current = this.#current / this.#duration; + if (current > 0 && current < 1) { + const t = this.#reversed ? 1 : 0; + this.#tick_fn(t, 1 - t); + } } finish() { @@ -322,7 +325,7 @@ function create_transition(dom, init, direction, effect) { animation.onfinish = () => { const is_outro = curr_direction === 'out'; - /** @type {Animation | TickAnimation} */ (animation).pause(); + /** @type {Animation | TickAnimation} */ (animation).cancel(); if (is_outro) { run_all(subs); subs = []; diff --git a/packages/svelte/src/internal/index.js b/packages/svelte/src/internal/index.js index 955e05e01f..000def896e 100644 --- a/packages/svelte/src/internal/index.js +++ b/packages/svelte/src/internal/index.js @@ -4,8 +4,6 @@ export { set, set_sync, invalidate_inner_signals, - expose, - exposable, source, mutable_source, derived, diff --git a/packages/svelte/tests/animation-helpers.js b/packages/svelte/tests/animation-helpers.js index 8855d813bd..21635a05bd 100644 --- a/packages/svelte/tests/animation-helpers.js +++ b/packages/svelte/tests/animation-helpers.js @@ -102,16 +102,18 @@ class Animation { } finish() { + this.onfinish(); this.currentTime = this.#reversed ? 0 : this.#duration; if (this.#reversed) { raf.animations.delete(this); } - this.onfinish(); } cancel() { - this._applyKeyFrame(this.#reversed ? this.#keyframes.length - 1 : 0); - raf.animations.delete(this); + this.#paused = true; + if (this.currentTime > 0 && this.currentTime < this.#duration) { + this._applyKeyFrame(this.#reversed ? this.#keyframes.length - 1 : 0); + } } pause() { diff --git a/packages/svelte/tests/compiler-errors/samples/attribute-empty/_config.js b/packages/svelte/tests/compiler-errors/samples/attribute-empty/_config.js index 5823dca910..248fc1107e 100644 --- a/packages/svelte/tests/compiler-errors/samples/attribute-empty/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/attribute-empty/_config.js @@ -3,7 +3,7 @@ import { test } from '../../test'; export default test({ error: { code: 'missing-attribute-value', - message: 'Expected value for the attribute', + message: 'Expected attribute value', position: [12, 12] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/attribute-empty/input.svelte b/packages/svelte/tests/compiler-errors/samples/attribute-empty/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/attribute-empty/input.svelte rename to packages/svelte/tests/compiler-errors/samples/attribute-empty/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/attribute-unique-binding/input.svelte b/packages/svelte/tests/compiler-errors/samples/attribute-unique-binding/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/attribute-unique-binding/input.svelte rename to packages/svelte/tests/compiler-errors/samples/attribute-unique-binding/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/attribute-unique-shorthand/input.svelte b/packages/svelte/tests/compiler-errors/samples/attribute-unique-shorthand/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/attribute-unique-shorthand/input.svelte rename to packages/svelte/tests/compiler-errors/samples/attribute-unique-shorthand/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/attribute-unique/input.svelte b/packages/svelte/tests/compiler-errors/samples/attribute-unique/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/attribute-unique/input.svelte rename to packages/svelte/tests/compiler-errors/samples/attribute-unique/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/catch-before-closing/_config.js b/packages/svelte/tests/compiler-errors/samples/catch-before-closing/_config.js index 5fb8c58c2a..1a50076da4 100644 --- a/packages/svelte/tests/compiler-errors/samples/catch-before-closing/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/catch-before-closing/_config.js @@ -2,8 +2,8 @@ import { test } from '../../test'; export default test({ error: { - code: 'invalid-catch-placement', - message: 'Expected to close {#each} block before seeing {:catch} block', - position: [41, 41] + code: 'expected-token', + message: 'Expected token {:else}', + position: [35, 35] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/catch-before-closing/input.svelte b/packages/svelte/tests/compiler-errors/samples/catch-before-closing/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/catch-before-closing/input.svelte rename to packages/svelte/tests/compiler-errors/samples/catch-before-closing/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/catch-without-await/_config.js b/packages/svelte/tests/compiler-errors/samples/catch-without-await/_config.js index 63f3b5e3cd..64c85f85c9 100644 --- a/packages/svelte/tests/compiler-errors/samples/catch-without-await/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/catch-without-await/_config.js @@ -2,8 +2,9 @@ import { test } from '../../test'; export default test({ error: { - code: 'invalid-catch-placement', - message: 'Cannot have an {:catch} block outside an {#await ...} block', - position: [7, 7] + code: 'invalid-continuing-block-placement', + message: + '{:...} block is invalid at this position (did you forget to close the preceeding element or block?)', + position: [1, 1] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/catch-without-await/input.svelte b/packages/svelte/tests/compiler-errors/samples/catch-without-await/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/catch-without-await/input.svelte rename to packages/svelte/tests/compiler-errors/samples/catch-without-await/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/class-state-field-static/_config.js b/packages/svelte/tests/compiler-errors/samples/class-state-field-static/_config.js index b6dca4e40d..27991ba427 100644 --- a/packages/svelte/tests/compiler-errors/samples/class-state-field-static/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/class-state-field-static/_config.js @@ -4,6 +4,6 @@ export default test({ error: { code: 'invalid-state-location', message: '$state() can only be used as a variable declaration initializer or a class field', - position: process.platform === 'win32' ? [35, 43] : [33, 41] + position: [33, 41] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/comment-unclosed/_config.js b/packages/svelte/tests/compiler-errors/samples/comment-unclosed/_config.js index 166a9df9b7..7c00375ad6 100644 --- a/packages/svelte/tests/compiler-errors/samples/comment-unclosed/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/comment-unclosed/_config.js @@ -2,8 +2,8 @@ import { test } from '../../test'; export default test({ error: { - code: 'unclosed-comment', - message: 'comment was left open, expected -->', + code: 'unexpected-eof', + message: 'Unexpected end of input (expected -->)', position: [24, 24] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/comment-unclosed/input.svelte b/packages/svelte/tests/compiler-errors/samples/comment-unclosed/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/comment-unclosed/input.svelte rename to packages/svelte/tests/compiler-errors/samples/comment-unclosed/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-without-selector/_config.js b/packages/svelte/tests/compiler-errors/samples/css-global-without-selector/_config.js index c8e598d4a8..549ad3ebe2 100644 --- a/packages/svelte/tests/compiler-errors/samples/css-global-without-selector/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/css-global-without-selector/_config.js @@ -2,8 +2,8 @@ import { test } from '../../test'; export default test({ error: { - code: 'css-syntax-error', - message: ':global() must contain a selector', - position: [9, 9] + code: 'invalid-css-global-selector', + message: ':global(...) must contain exactly one selector', + position: [16, 16] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/css-global-without-selector/input.svelte b/packages/svelte/tests/compiler-errors/samples/css-global-without-selector/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/css-global-without-selector/input.svelte rename to packages/svelte/tests/compiler-errors/samples/css-global-without-selector/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/css/_config.js b/packages/svelte/tests/compiler-errors/samples/css/_config.js index d1a7e346f9..9705cde6b5 100644 --- a/packages/svelte/tests/compiler-errors/samples/css/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/css/_config.js @@ -2,8 +2,8 @@ import { test } from '../../test'; export default test({ error: { - code: 'css-syntax-error', - message: '"{" is expected', - position: [24, 24] + code: 'invalid-css-identifier', + message: 'Expected a valid CSS identifier', + position: [25, 25] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/css/input.svelte b/packages/svelte/tests/compiler-errors/samples/css/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/css/input.svelte rename to packages/svelte/tests/compiler-errors/samples/css/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/dollar-binding-global-js/main.js b/packages/svelte/tests/compiler-errors/samples/dollar-binding-global-js/main.svelte.js similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/dollar-binding-global-js/main.js rename to packages/svelte/tests/compiler-errors/samples/dollar-binding-global-js/main.svelte.js diff --git a/packages/svelte/tests/compiler-errors/samples/else-before-closing-2/_config.js b/packages/svelte/tests/compiler-errors/samples/else-before-closing-2/_config.js index 7b1d43bf1d..dc9aff145c 100644 --- a/packages/svelte/tests/compiler-errors/samples/else-before-closing-2/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/else-before-closing-2/_config.js @@ -2,8 +2,8 @@ import { test } from '../../test'; export default test({ error: { - code: 'invalid-else-placement', - message: 'Expected to close {#await} block before seeing {:else} block', - position: [29, 29] + code: 'expected-token', + message: 'Expected token {:then ...} or {:catch ...}', + position: [24, 24] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/else-before-closing-2/input.svelte b/packages/svelte/tests/compiler-errors/samples/else-before-closing-2/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/else-before-closing-2/input.svelte rename to packages/svelte/tests/compiler-errors/samples/else-before-closing-2/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/else-before-closing-3/_config.js b/packages/svelte/tests/compiler-errors/samples/else-before-closing-3/_config.js index ab7281cee5..80a2a136db 100644 --- a/packages/svelte/tests/compiler-errors/samples/else-before-closing-3/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/else-before-closing-3/_config.js @@ -2,8 +2,9 @@ import { test } from '../../test'; export default test({ error: { - code: 'invalid-else-placement', - message: 'Cannot have an {:else} block outside an {#if ...} or {#each ...} block', - position: [11, 11] + code: 'invalid-continuing-block-placement', + message: + '{:...} block is invalid at this position (did you forget to close the preceeding element or block?)', + position: [6, 6] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/else-before-closing-3/input.svelte b/packages/svelte/tests/compiler-errors/samples/else-before-closing-3/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/else-before-closing-3/input.svelte rename to packages/svelte/tests/compiler-errors/samples/else-before-closing-3/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/else-before-closing/_config.js b/packages/svelte/tests/compiler-errors/samples/else-before-closing/_config.js index 31635f2124..87c1296f49 100644 --- a/packages/svelte/tests/compiler-errors/samples/else-before-closing/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/else-before-closing/_config.js @@ -2,8 +2,9 @@ import { test } from '../../test'; export default test({ error: { - code: 'invalid-else-placement', - message: 'Expected to close
  • tag before seeing {:else} block', - position: [23, 23] + code: 'invalid-continuing-block-placement', + message: + '{:...} block is invalid at this position (did you forget to close the preceeding element or block?)', + position: [18, 18] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/else-before-closing/input.svelte b/packages/svelte/tests/compiler-errors/samples/else-before-closing/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/else-before-closing/input.svelte rename to packages/svelte/tests/compiler-errors/samples/else-before-closing/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/else-if-before-closing-2/_config.js b/packages/svelte/tests/compiler-errors/samples/else-if-before-closing-2/_config.js index 10ed037ede..4b4059cf3b 100644 --- a/packages/svelte/tests/compiler-errors/samples/else-if-before-closing-2/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/else-if-before-closing-2/_config.js @@ -2,8 +2,9 @@ import { test } from '../../test'; export default test({ error: { - code: 'invalid-elseif-placement', - message: 'Expected to close

    tag before seeing {:else if ...} block', - position: [25, 25] + code: 'invalid-continuing-block-placement', + message: + '{:...} block is invalid at this position (did you forget to close the preceeding element or block?)', + position: [17, 17] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/else-if-before-closing-2/input.svelte b/packages/svelte/tests/compiler-errors/samples/else-if-before-closing-2/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/else-if-before-closing-2/input.svelte rename to packages/svelte/tests/compiler-errors/samples/else-if-before-closing-2/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/else-if-before-closing/_config.js b/packages/svelte/tests/compiler-errors/samples/else-if-before-closing/_config.js index 70823c9959..ae20d2da8c 100644 --- a/packages/svelte/tests/compiler-errors/samples/else-if-before-closing/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/else-if-before-closing/_config.js @@ -2,8 +2,8 @@ import { test } from '../../test'; export default test({ error: { - code: 'invalid-elseif-placement', - message: 'Expected to close {#await} block before seeing {:else if ...} block', - position: [34, 34] + code: 'expected-token', + message: 'Expected token {:then ...} or {:catch ...}', + position: [26, 26] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/else-if-before-closing/input.svelte b/packages/svelte/tests/compiler-errors/samples/else-if-before-closing/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/else-if-before-closing/input.svelte rename to packages/svelte/tests/compiler-errors/samples/else-if-before-closing/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/else-if-without-if/_config.js b/packages/svelte/tests/compiler-errors/samples/else-if-without-if/_config.js index cb8e35c41d..04d8342f20 100644 --- a/packages/svelte/tests/compiler-errors/samples/else-if-without-if/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/else-if-without-if/_config.js @@ -2,8 +2,8 @@ import { test } from '../../test'; export default test({ error: { - code: 'invalid-elseif-placement', - message: 'Cannot have an {:else if ...} block outside an {#if ...} block', - position: [35, 35] + code: 'expected-token', + message: 'Expected token {:then ...} or {:catch ...}', + position: [27, 27] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/else-if-without-if/input.svelte b/packages/svelte/tests/compiler-errors/samples/else-if-without-if/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/else-if-without-if/input.svelte rename to packages/svelte/tests/compiler-errors/samples/else-if-without-if/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/empty-attribute-shorthand/input.svelte b/packages/svelte/tests/compiler-errors/samples/empty-attribute-shorthand/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/empty-attribute-shorthand/input.svelte rename to packages/svelte/tests/compiler-errors/samples/empty-attribute-shorthand/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/empty-classname-binding/_config.js b/packages/svelte/tests/compiler-errors/samples/empty-classname-binding/_config.js index 0051e827a5..bd1d1d7682 100644 --- a/packages/svelte/tests/compiler-errors/samples/empty-classname-binding/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/empty-classname-binding/_config.js @@ -3,7 +3,7 @@ import { test } from '../../test'; export default test({ error: { code: 'empty-directive-name', - message: 'Class name cannot be empty', + message: 'ClassDirective name cannot be empty', position: [10, 10] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/empty-classname-binding/input.svelte b/packages/svelte/tests/compiler-errors/samples/empty-classname-binding/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/empty-classname-binding/input.svelte rename to packages/svelte/tests/compiler-errors/samples/empty-classname-binding/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/empty-directive-name/_config.js b/packages/svelte/tests/compiler-errors/samples/empty-directive-name/_config.js index 7f6d0f1d0f..48a0eb32c4 100644 --- a/packages/svelte/tests/compiler-errors/samples/empty-directive-name/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/empty-directive-name/_config.js @@ -3,7 +3,7 @@ import { test } from '../../test'; export default test({ error: { code: 'empty-directive-name', - message: 'Action name cannot be empty', + message: 'UseDirective name cannot be empty', position: [8, 8] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/empty-directive-name/input.svelte b/packages/svelte/tests/compiler-errors/samples/empty-directive-name/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/empty-directive-name/input.svelte rename to packages/svelte/tests/compiler-errors/samples/empty-directive-name/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/export-derived-state/_config.js b/packages/svelte/tests/compiler-errors/samples/export-derived-state/_config.js index 801d1d8a30..1c171d19c0 100644 --- a/packages/svelte/tests/compiler-errors/samples/export-derived-state/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/export-derived-state/_config.js @@ -4,6 +4,6 @@ export default test({ error: { code: 'invalid-derived-export', message: 'Cannot export derived state', - position: process.platform === 'win32' ? [26, 68] : [24, 66] + position: [24, 66] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/export-state/_config.js b/packages/svelte/tests/compiler-errors/samples/export-state/_config.js index 755b891586..5ddb2a859a 100644 --- a/packages/svelte/tests/compiler-errors/samples/export-state/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/export-state/_config.js @@ -4,6 +4,6 @@ export default test({ error: { code: 'invalid-state-export', message: 'Cannot export state if it is reassigned', - position: process.platform === 'win32' ? [50, 90] : [46, 86] + position: [46, 86] } }); diff --git a/packages/svelte/tests/compiler-errors/samples/illegal-expression/_config.js b/packages/svelte/tests/compiler-errors/samples/illegal-expression/_config.js index 659679c345..887f11e882 100644 --- a/packages/svelte/tests/compiler-errors/samples/illegal-expression/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/illegal-expression/_config.js @@ -2,7 +2,7 @@ import { test } from '../../test'; export default test({ error: { - code: 'parse-error', + code: 'js-parse-error', message: 'Assigning to rvalue', position: [1, 1] } diff --git a/packages/svelte/tests/compiler-errors/samples/illegal-expression/input.svelte b/packages/svelte/tests/compiler-errors/samples/illegal-expression/main.svelte similarity index 100% rename from packages/svelte/tests/compiler-errors/samples/illegal-expression/input.svelte rename to packages/svelte/tests/compiler-errors/samples/illegal-expression/main.svelte diff --git a/packages/svelte/tests/compiler-errors/samples/multiple-styles/_config.js b/packages/svelte/tests/compiler-errors/samples/multiple-styles/_config.js index da3e69fc1e..50cf2583af 100644 --- a/packages/svelte/tests/compiler-errors/samples/multiple-styles/_config.js +++ b/packages/svelte/tests/compiler-errors/samples/multiple-styles/_config.js @@ -2,8 +2,8 @@ import { test } from '../../test'; export default test({ error: { - code: 'duplicate-style', - message: 'You can only have one top-level + +

    Broken

    diff --git a/packages/svelte/tests/parser-modern/samples/css-nth-syntax/output.json b/packages/svelte/tests/parser-modern/samples/css-nth-syntax/output.json new file mode 100644 index 0000000000..1cea48b17c --- /dev/null +++ b/packages/svelte/tests/parser-modern/samples/css-nth-syntax/output.json @@ -0,0 +1,520 @@ +{ + "css": { + "type": "Style", + "start": 0, + "end": 467, + "attributes": [], + "children": [ + { + "type": "Rule", + "prelude": { + "type": "SelectorList", + "start": 60, + "end": 80, + "children": [ + { + "type": "Selector", + "start": 60, + "end": 80, + "children": [ + { + "type": "TypeSelector", + "name": "h1", + "start": 60, + "end": 62 + }, + { + "type": "PseudoClassSelector", + "name": "nth-of-type", + "args": { + "type": "SelectorList", + "start": 75, + "end": 79, + "children": [ + { + "type": "Selector", + "start": 75, + "end": 79, + "children": [ + { + "type": "Nth", + "value": "2n+1", + "start": 75, + "end": 79 + } + ] + } + ] + }, + "start": 62, + "end": 80 + } + ] + } + ] + }, + "block": { + "type": "Block", + "start": 80, + "end": 112, + "children": [ + { + "type": "Declaration", + "start": 90, + "end": 105, + "property": "background", + "value": "red" + } + ] + }, + "start": 60, + "end": 112 + }, + { + "type": "Rule", + "prelude": { + "type": "SelectorList", + "start": 117, + "end": 153, + "children": [ + { + "type": "Selector", + "start": 117, + "end": 153, + "children": [ + { + "type": "TypeSelector", + "name": "h1", + "start": 117, + "end": 119 + }, + { + "type": "PseudoClassSelector", + "name": "nth-child", + "args": { + "type": "SelectorList", + "start": 130, + "end": 152, + "children": [ + { + "type": "Selector", + "start": 130, + "end": 152, + "children": [ + { + "type": "Nth", + "value": "-n + 3 of ", + "start": 130, + "end": 140 + }, + { + "type": "TypeSelector", + "name": "li", + "start": 140, + "end": 142 + }, + { + "type": "ClassSelector", + "name": "important", + "start": 142, + "end": 152 + } + ] + } + ] + }, + "start": 119, + "end": 153 + } + ] + } + ] + }, + "block": { + "type": "Block", + "start": 154, + "end": 186, + "children": [ + { + "type": "Declaration", + "start": 164, + "end": 179, + "property": "background", + "value": "red" + } + ] + }, + "start": 117, + "end": 186 + }, + { + "type": "Rule", + "prelude": { + "type": "SelectorList", + "start": 191, + "end": 206, + "children": [ + { + "type": "Selector", + "start": 191, + "end": 206, + "children": [ + { + "type": "TypeSelector", + "name": "h1", + "start": 191, + "end": 193 + }, + { + "type": "PseudoClassSelector", + "name": "nth-child", + "args": { + "type": "SelectorList", + "start": 204, + "end": 205, + "children": [ + { + "type": "Selector", + "start": 204, + "end": 205, + "children": [ + { + "type": "Nth", + "value": "1", + "start": 204, + "end": 205 + } + ] + } + ] + }, + "start": 193, + "end": 206 + } + ] + } + ] + }, + "block": { + "type": "Block", + "start": 207, + "end": 239, + "children": [ + { + "type": "Declaration", + "start": 217, + "end": 232, + "property": "background", + "value": "red" + } + ] + }, + "start": 191, + "end": 239 + }, + { + "type": "Rule", + "prelude": { + "type": "SelectorList", + "start": 244, + "end": 259, + "children": [ + { + "type": "Selector", + "start": 244, + "end": 259, + "children": [ + { + "type": "TypeSelector", + "name": "h1", + "start": 244, + "end": 246 + }, + { + "type": "PseudoClassSelector", + "name": "nth-child", + "args": { + "type": "SelectorList", + "start": 257, + "end": 258, + "children": [ + { + "type": "Selector", + "start": 257, + "end": 258, + "children": [ + { + "type": "TypeSelector", + "name": "p", + "start": 257, + "end": 258 + } + ] + } + ] + }, + "start": 246, + "end": 259 + } + ] + } + ] + }, + "block": { + "type": "Block", + "start": 260, + "end": 292, + "children": [ + { + "type": "Declaration", + "start": 270, + "end": 285, + "property": "background", + "value": "red" + } + ] + }, + "start": 244, + "end": 292 + }, + { + "type": "Rule", + "prelude": { + "type": "SelectorList", + "start": 297, + "end": 314, + "children": [ + { + "type": "Selector", + "start": 297, + "end": 314, + "children": [ + { + "type": "TypeSelector", + "name": "h1", + "start": 297, + "end": 299 + }, + { + "type": "PseudoClassSelector", + "name": "nth-child", + "args": { + "type": "SelectorList", + "start": 310, + "end": 313, + "children": [ + { + "type": "Selector", + "start": 310, + "end": 313, + "children": [ + { + "type": "Nth", + "value": "n+7", + "start": 310, + "end": 313 + } + ] + } + ] + }, + "start": 299, + "end": 314 + } + ] + } + ] + }, + "block": { + "type": "Block", + "start": 315, + "end": 347, + "children": [ + { + "type": "Declaration", + "start": 325, + "end": 340, + "property": "background", + "value": "red" + } + ] + }, + "start": 297, + "end": 347 + }, + { + "type": "Rule", + "prelude": { + "type": "SelectorList", + "start": 352, + "end": 370, + "children": [ + { + "type": "Selector", + "start": 352, + "end": 370, + "children": [ + { + "type": "TypeSelector", + "name": "h1", + "start": 352, + "end": 354 + }, + { + "type": "PseudoClassSelector", + "name": "nth-child", + "args": { + "type": "SelectorList", + "start": 365, + "end": 369, + "children": [ + { + "type": "Selector", + "start": 365, + "end": 369, + "children": [ + { + "type": "Nth", + "value": "even", + "start": 365, + "end": 369 + } + ] + } + ] + }, + "start": 354, + "end": 370 + } + ] + } + ] + }, + "block": { + "type": "Block", + "start": 371, + "end": 403, + "children": [ + { + "type": "Declaration", + "start": 381, + "end": 396, + "property": "background", + "value": "red" + } + ] + }, + "start": 352, + "end": 403 + }, + { + "type": "Rule", + "prelude": { + "type": "SelectorList", + "start": 408, + "end": 425, + "children": [ + { + "type": "Selector", + "start": 408, + "end": 425, + "children": [ + { + "type": "TypeSelector", + "name": "h1", + "start": 408, + "end": 410 + }, + { + "type": "PseudoClassSelector", + "name": "nth-child", + "args": { + "type": "SelectorList", + "start": 421, + "end": 424, + "children": [ + { + "type": "Selector", + "start": 421, + "end": 424, + "children": [ + { + "type": "Nth", + "value": "odd", + "start": 421, + "end": 424 + } + ] + } + ] + }, + "start": 410, + "end": 425 + } + ] + } + ] + }, + "block": { + "type": "Block", + "start": 426, + "end": 458, + "children": [ + { + "type": "Declaration", + "start": 436, + "end": 451, + "property": "background", + "value": "red" + } + ] + }, + "start": 408, + "end": 458 + } + ], + "content": { + "start": 7, + "end": 459, + "styles": "\n /* test that all these are parsed correctly */\n\th1:nth-of-type(2n+1){\n background: red;\n }\n h1:nth-child(-n + 3 of li.important) {\n background: red;\n }\n h1:nth-child(1) {\n background: red;\n }\n h1:nth-child(p) {\n background: red;\n }\n h1:nth-child(n+7) {\n background: red;\n }\n h1:nth-child(even) {\n background: red;\n }\n h1:nth-child(odd) {\n background: red;\n }\n" + } + }, + "js": [], + "start": 469, + "end": 484, + "type": "Root", + "fragment": { + "type": "Fragment", + "nodes": [ + { + "type": "Text", + "start": 467, + "end": 469, + "raw": "\n\n", + "data": "\n\n" + }, + { + "type": "RegularElement", + "start": 469, + "end": 484, + "name": "h1", + "attributes": [], + "fragment": { + "type": "Fragment", + "nodes": [ + { + "type": "Text", + "start": 473, + "end": 479, + "raw": "Broken", + "data": "Broken" + } + ], + "transparent": true + } + } + ], + "transparent": false + }, + "options": null +} diff --git a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js index 99295575ea..55ccb739aa 100644 --- a/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js @@ -6,7 +6,7 @@ import * as $ from "svelte/internal"; export default function Svelte_element($$anchor, $$props) { $.push($$props, true); - let tag = $.prop_source($$props, "tag", true, 'hr'); + let tag = $.prop_source($$props, "tag", 1, 'hr'); /* Init */ var fragment = $.comment($$anchor); var node = $.child_frag(fragment); diff --git a/packages/svelte/tests/validator/samples/event-attribute/errors.json b/packages/svelte/tests/validator/samples/event-attribute/errors.json new file mode 100644 index 0000000000..28a8f9f11a --- /dev/null +++ b/packages/svelte/tests/validator/samples/event-attribute/errors.json @@ -0,0 +1,14 @@ +[ + { + "message": "Event attribute must be a JavaScript expression, not a string", + "code": "invalid-event-attribute-value", + "start": { + "line": 4, + "column": 8 + }, + "end": { + "line": 4, + "column": 21 + } + } +] diff --git a/packages/svelte/tests/validator/samples/event-attribute/input.svelte b/packages/svelte/tests/validator/samples/event-attribute/input.svelte new file mode 100644 index 0000000000..2ab0e39823 --- /dev/null +++ b/packages/svelte/tests/validator/samples/event-attribute/input.svelte @@ -0,0 +1,4 @@ + + + +