Merge branch 'main' into fix-ordering

pull/12591/head
Rich Harris 2 years ago committed by GitHub
commit 2712ab9151
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: tweak element_invalid_self_closing_tag to exclude namespace

@ -1,3 +1,5 @@
/** @import { Comment, Program } from 'estree' */
/** @import { Node } from 'acorn' */
import * as acorn from 'acorn';
import { walk } from 'zimmerframe';
import { tsPlugin } from 'acorn-typescript';
@ -23,7 +25,7 @@ export function parse(source, typescript) {
if (typescript) amend(source, ast);
add_comments(ast);
return /** @type {import('estree').Program} */ (ast);
return /** @type {Program} */ (ast);
}
/**
@ -57,7 +59,7 @@ export function parse_expression_at(source, typescript, index) {
*/
function get_comment_handlers(source) {
/**
* @typedef {import('estree').Comment & {
* @typedef {Comment & {
* start: number;
* end: number;
* }} CommentWithLocation
@ -149,7 +151,7 @@ function get_comment_handlers(source) {
/**
* Tidy up some stuff left behind by acorn-typescript
* @param {string} source
* @param {import('acorn').Node} node
* @param {Node} node
*/
function amend(source, node) {
return walk(node, null, {

@ -1,10 +1,12 @@
/** @import { Expression } from 'estree' */
/** @import { Parser } from '../index.js' */
import { parse_expression_at } from '../acorn.js';
import { regex_whitespace } from '../../patterns.js';
import * as e from '../../../errors.js';
/**
* @param {import('../index.js').Parser} parser
* @returns {import('estree').Expression}
* @param {Parser} parser
* @returns {Expression}
*/
export default function read_expression(parser) {
try {
@ -35,7 +37,7 @@ export default function read_expression(parser) {
parser.index = index;
return /** @type {import('estree').Expression} */ (node);
return /** @type {Expression} */ (node);
} catch (err) {
parser.acorn_error(err);
}

@ -1,5 +1,6 @@
/** @import { Parser } from '../index.js' */
/** @import { Expression } from 'estree' */
/** @import * as Compiler from '#compiler' */
/** @import { Parser } from '../index.js' */
import { is_void } from '../../../../constants.js';
import read_expression from '../read/expression.js';
import { read_script } from '../read/script.js';
@ -589,7 +590,7 @@ function read_attribute(parser) {
const first_value = value === true ? undefined : Array.isArray(value) ? value[0] : value;
/** @type {import('estree').Expression | null} */
/** @type {Expression | null} */
let expression = null;
if (first_value) {

@ -1,3 +1,6 @@
/** @import { ArrowFunctionExpression, Expression, Identifier } from 'estree' */
/** @import { AwaitBlock, ConstTag, DebugTag, EachBlock, ExpressionTag, HtmlTag, IfBlock, KeyBlock, RenderTag, SnippetBlock } from '#compiler' */
/** @import { Parser } from '../index.js' */
import read_pattern from '../read/context.js';
import read_expression from '../read/expression.js';
import * as e from '../../../errors.js';
@ -7,7 +10,7 @@ import { parse_expression_at } from '../acorn.js';
const regex_whitespace_with_closing_curly_brace = /^\s*}/;
/** @param {import('../index.js').Parser} parser */
/** @param {Parser} parser */
export default function tag(parser) {
const start = parser.index;
parser.index += 1;
@ -29,7 +32,7 @@ export default function tag(parser) {
parser.allow_whitespace();
parser.eat('}', true);
/** @type {ReturnType<typeof parser.append<import('#compiler').ExpressionTag>>} */
/** @type {ReturnType<typeof parser.append<ExpressionTag>>} */
parser.append({
type: 'ExpressionTag',
start,
@ -42,7 +45,7 @@ export default function tag(parser) {
});
}
/** @param {import('../index.js').Parser} parser */
/** @param {Parser} parser */
function open(parser) {
let start = parser.index - 2;
while (parser.template[start] !== '{') start -= 1;
@ -50,7 +53,7 @@ function open(parser) {
if (parser.eat('if')) {
parser.require_whitespace();
/** @type {ReturnType<typeof parser.append<import('#compiler').IfBlock>>} */
/** @type {ReturnType<typeof parser.append<IfBlock>>} */
const block = parser.append({
type: 'IfBlock',
elseif: false,
@ -76,7 +79,7 @@ function open(parser) {
const template = parser.template;
let end = parser.template.length;
/** @type {import('estree').Expression | undefined} */
/** @type {Expression | undefined} */
let expression;
// we have to do this loop because `{#each x as { y = z }}` fails to parse —
@ -119,7 +122,7 @@ function open(parser) {
expression = walk(expression, null, {
// @ts-expect-error
TSAsExpression(node, context) {
if (node.end === /** @type {import('estree').Expression} */ (expression).end) {
if (node.end === /** @type {Expression} */ (expression).end) {
assertion = node;
end = node.expression.end;
return node.expression;
@ -171,7 +174,7 @@ function open(parser) {
parser.eat('}', true);
/** @type {ReturnType<typeof parser.append<import('#compiler').EachBlock>>} */
/** @type {ReturnType<typeof parser.append<EachBlock>>} */
const block = parser.append({
type: 'EachBlock',
start,
@ -195,7 +198,7 @@ function open(parser) {
const expression = read_expression(parser);
parser.allow_whitespace();
/** @type {ReturnType<typeof parser.append<import('#compiler').AwaitBlock>>} */
/** @type {ReturnType<typeof parser.append<AwaitBlock>>} */
const block = parser.append({
type: 'AwaitBlock',
start,
@ -249,7 +252,7 @@ function open(parser) {
parser.eat('}', true);
/** @type {ReturnType<typeof parser.append<import('#compiler').KeyBlock>>} */
/** @type {ReturnType<typeof parser.append<KeyBlock>>} */
const block = parser.append({
type: 'KeyBlock',
start,
@ -293,14 +296,14 @@ function open(parser) {
const prelude = parser.template.slice(0, params_start).replace(/\S/g, ' ');
const params = parser.template.slice(params_start, parser.index);
let function_expression = /** @type {import('estree').ArrowFunctionExpression} */ (
let function_expression = /** @type {ArrowFunctionExpression} */ (
parse_expression_at(prelude + `${params} => {}`, parser.ts, params_start)
);
parser.allow_whitespace();
parser.eat('}', true);
/** @type {ReturnType<typeof parser.append<import('#compiler').SnippetBlock>>} */
/** @type {ReturnType<typeof parser.append<SnippetBlock>>} */
const block = parser.append({
type: 'SnippetBlock',
start,
@ -323,7 +326,7 @@ function open(parser) {
e.expected_block_type(parser.index);
}
/** @param {import('../index.js').Parser} parser */
/** @param {Parser} parser */
function next(parser) {
const start = parser.index - 1;
@ -352,7 +355,7 @@ function next(parser) {
let elseif_start = start - 1;
while (parser.template[elseif_start] !== '{') elseif_start -= 1;
/** @type {ReturnType<typeof parser.append<import('#compiler').IfBlock>>} */
/** @type {ReturnType<typeof parser.append<IfBlock>>} */
const child = parser.append({
start: elseif_start,
end: -1,
@ -434,7 +437,7 @@ function next(parser) {
e.block_invalid_continuation_placement(start);
}
/** @param {import('../index.js').Parser} parser */
/** @param {Parser} parser */
function close(parser) {
const start = parser.index - 1;
@ -448,7 +451,7 @@ function close(parser) {
while (block.elseif) {
block.end = parser.index;
parser.stack.pop();
block = /** @type {import('#compiler').IfBlock} */ (parser.current());
block = /** @type {IfBlock} */ (parser.current());
}
block.end = parser.index;
parser.pop();
@ -482,7 +485,7 @@ function close(parser) {
parser.pop();
}
/** @param {import('../index.js').Parser} parser */
/** @param {Parser} parser */
function special(parser) {
let start = parser.index;
while (parser.template[start] !== '{') start -= 1;
@ -496,7 +499,7 @@ function special(parser) {
parser.allow_whitespace();
parser.eat('}', true);
/** @type {ReturnType<typeof parser.append<import('#compiler').HtmlTag>>} */
/** @type {ReturnType<typeof parser.append<HtmlTag>>} */
parser.append({
type: 'HtmlTag',
start,
@ -508,7 +511,7 @@ function special(parser) {
}
if (parser.eat('debug')) {
/** @type {import('estree').Identifier[]} */
/** @type {Identifier[]} */
let identifiers;
// Implies {@debug} which indicates "debug all"
@ -519,8 +522,8 @@ function special(parser) {
identifiers =
expression.type === 'SequenceExpression'
? /** @type {import('estree').Identifier[]} */ (expression.expressions)
: [/** @type {import('estree').Identifier} */ (expression)];
? /** @type {Identifier[]} */ (expression.expressions)
: [/** @type {Identifier} */ (expression)];
identifiers.forEach(
/** @param {any} node */ (node) => {
@ -534,7 +537,7 @@ function special(parser) {
parser.eat('}', true);
}
/** @type {ReturnType<typeof parser.append<import('#compiler').DebugTag>>} */
/** @type {ReturnType<typeof parser.append<DebugTag>>} */
parser.append({
type: 'DebugTag',
start,
@ -567,7 +570,7 @@ function special(parser) {
parser.eat('}', true);
/** @type {ReturnType<typeof parser.append<import('#compiler').ConstTag>>} */
/** @type {ReturnType<typeof parser.append<ConstTag>>} */
parser.append({
type: 'ConstTag',
start,
@ -598,7 +601,7 @@ function special(parser) {
parser.allow_whitespace();
parser.eat('}', true);
/** @type {ReturnType<typeof parser.append<import('#compiler').RenderTag>>} */
/** @type {ReturnType<typeof parser.append<RenderTag>>} */
parser.append({
type: 'RenderTag',
start,

@ -1,3 +1,7 @@
/** @import { ArrowFunctionExpression, CallExpression, Expression, FunctionDeclaration, FunctionExpression, Identifier, LabeledStatement, Literal, Node, Program, Super } from 'estree' */
/** @import { Attribute, BindDirective, Binding, DelegatedEvent, RegularElement, Root, Script, SvelteNode, Text, ValidatedCompileOptions, ValidatedModuleCompileOptions } from '#compiler' */
/** @import { AnalysisState, Context, LegacyAnalysisState, Visitors } from './types' */
/** @import { Analysis, ComponentAnalysis, Js, ReactiveStatement, Template } from '../types' */
import is_reference from 'is-reference';
import { walk } from 'zimmerframe';
import * as e from '../../errors.js';
@ -37,14 +41,14 @@ import { ignore_map, ignore_stack, pop_ignore, push_ignore } from '../../state.j
import { equal } from '../../utils/assert.js';
/**
* @param {import('#compiler').Script | null} script
* @param {Script | null} script
* @param {ScopeRoot} root
* @param {boolean} allow_reactive_declarations
* @param {Scope | null} parent
* @returns {import('../types.js').Js}
* @returns {Js}
*/
function js(script, root, allow_reactive_declarations, parent) {
/** @type {import('estree').Program} */
/** @type {Program} */
const ast = script?.content ?? {
type: 'Program',
sourceType: 'module',
@ -75,9 +79,9 @@ function get_component_name(filename) {
/**
* Checks if given event attribute can be delegated/hoisted and returns the corresponding info if so
* @param {string} event_name
* @param {import('estree').Expression | null} handler
* @param {import('./types').Context} context
* @returns {null | import('#compiler').DelegatedEvent}
* @param {Expression | null} handler
* @param {Context} context
* @returns {null | DelegatedEvent}
*/
function get_delegated_event(event_name, handler, context) {
// Handle delegated event handlers. Bail-out if not a delegated event.
@ -91,9 +95,9 @@ function get_delegated_event(event_name, handler, context) {
return null;
}
/** @type {import('#compiler').DelegatedEvent} */
/** @type {DelegatedEvent} */
const non_hoistable = { type: 'non-hoistable' };
/** @type {import('estree').FunctionExpression | import('estree').FunctionDeclaration | import('estree').ArrowFunctionExpression | null} */
/** @type {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression | null} */
let target_function = null;
let binding = null;
@ -119,20 +123,20 @@ function get_delegated_event(event_name, handler, context) {
const grandparent = path.at(-2);
/** @type {import('#compiler').RegularElement | null} */
/** @type {RegularElement | null} */
let element = null;
/** @type {string | null} */
let event_name = null;
if (parent.type === 'OnDirective') {
element = /** @type {import('#compiler').RegularElement} */ (grandparent);
element = /** @type {RegularElement} */ (grandparent);
event_name = parent.name;
} else if (
parent.type === 'ExpressionTag' &&
grandparent?.type === 'Attribute' &&
is_event_attribute(grandparent)
) {
element = /** @type {import('#compiler').RegularElement} */ (path.at(-3));
const attribute = /** @type {import('#compiler').Attribute} */ (grandparent);
element = /** @type {RegularElement} */ (path.at(-3));
const attribute = /** @type {Attribute} */ (grandparent);
event_name = get_attribute_event_name(attribute.name);
}
@ -224,9 +228,9 @@ function get_delegated_event(event_name, handler, context) {
}
/**
* @param {import('estree').Program} ast
* @param {import('#compiler').ValidatedModuleCompileOptions} options
* @returns {import('../types.js').Analysis}
* @param {Program} ast
* @param {ValidatedModuleCompileOptions} options
* @returns {Analysis}
*/
export function analyze_module(ast, options) {
const { scope, scopes } = create_scopes(ast, new ScopeRoot(), false, null);
@ -239,7 +243,7 @@ export function analyze_module(ast, options) {
}
walk(
/** @type {import('estree').Node} */ (ast),
/** @type {Node} */ (ast),
{ scope, analysis: { runes: true } },
// @ts-expect-error TODO clean this mess up
merge(set_scope(scopes), validation_runes_js, runes_scope_js_tweaker)
@ -255,10 +259,10 @@ export function analyze_module(ast, options) {
}
/**
* @param {import('#compiler').Root} root
* @param {Root} root
* @param {string} source
* @param {import('#compiler').ValidatedCompileOptions} options
* @returns {import('../types.js').ComponentAnalysis}
* @param {ValidatedCompileOptions} options
* @returns {ComponentAnalysis}
*/
export function analyze_component(root, source, options) {
const scope_root = new ScopeRoot();
@ -268,7 +272,7 @@ export function analyze_component(root, source, options) {
const { scope, scopes } = create_scopes(root.fragment, scope_root, false, instance.scope);
/** @type {import('../types.js').Template} */
/** @type {Template} */
const template = { ast: root.fragment, scope, scopes };
// create synthetic bindings for store subscriptions
@ -339,7 +343,7 @@ export function analyze_component(root, source, options) {
/** @type {number} */ (node.start) > /** @type {number} */ (module.ast.start) &&
/** @type {number} */ (node.end) < /** @type {number} */ (module.ast.end) &&
// const state = $state(0) is valid
get_rune(/** @type {import('estree').Node} */ (path.at(-1)), module.scope) === null
get_rune(/** @type {Node} */ (path.at(-1)), module.scope) === null
) {
e.store_invalid_subscription(node);
}
@ -360,7 +364,7 @@ export function analyze_component(root, source, options) {
Array.from(module.scope.references).some(([name]) => Runes.includes(/** @type {any} */ (name)));
// TODO remove all the ?? stuff, we don't need it now that we're validating the config
/** @type {import('../types.js').ComponentAnalysis} */
/** @type {ComponentAnalysis} */
const analysis = {
name: module.scope.generate(options.name ?? component_name),
root: scope_root,
@ -434,7 +438,7 @@ export function analyze_component(root, source, options) {
}
for (const { ast, scope, scopes } of [module, instance, template]) {
/** @type {import('./types').AnalysisState} */
/** @type {AnalysisState} */
const state = {
scope,
analysis,
@ -450,7 +454,7 @@ export function analyze_component(root, source, options) {
};
walk(
/** @type {import('#compiler').SvelteNode} */ (ast),
/** @type {SvelteNode} */ (ast),
state,
merge(set_scope(scopes), validation_runes, runes_scope_tweaker, common_visitors)
);
@ -474,7 +478,7 @@ export function analyze_component(root, source, options) {
// bind:this doesn't need to be a state reference if it will never change
if (
type === 'BindDirective' &&
/** @type {import('#compiler').BindDirective} */ (path[i]).name === 'this'
/** @type {BindDirective} */ (path[i]).name === 'this'
) {
for (let j = i - 1; j >= 0; j -= 1) {
const type = path[j].type;
@ -503,7 +507,7 @@ export function analyze_component(root, source, options) {
instance.scope.declare(b.id('$$restProps'), 'rest_prop', 'synthetic');
for (const { ast, scope, scopes } of [module, instance, template]) {
/** @type {import('./types').LegacyAnalysisState} */
/** @type {LegacyAnalysisState} */
const state = {
scope,
analysis,
@ -522,7 +526,7 @@ export function analyze_component(root, source, options) {
};
walk(
/** @type {import('#compiler').SvelteNode} */ (ast),
/** @type {SvelteNode} */ (ast),
state,
// @ts-expect-error TODO
merge(set_scope(scopes), validation_legacy, legacy_scope_tweaker, common_visitors)
@ -583,7 +587,7 @@ export function analyze_component(root, source, options) {
// TODO this happens during the analysis phase, which shouldn't know anything about client vs server
if (element.type === 'SvelteElement' && options.generate === 'client') continue;
/** @type {import('#compiler').Attribute | undefined} */
/** @type {Attribute | undefined} */
let class_attribute = undefined;
for (const attribute of element.attributes) {
@ -602,7 +606,7 @@ export function analyze_component(root, source, options) {
if (is_text_attribute(class_attribute)) {
class_attribute.value[0].data += ` ${analysis.css.hash}`;
} else {
/** @type {import('#compiler').Text} */
/** @type {Text} */
const css_text = {
type: 'Text',
data: ` ${analysis.css.hash}`,
@ -642,19 +646,19 @@ export function analyze_component(root, source, options) {
return analysis;
}
/** @type {import('./types').Visitors<import('./types').LegacyAnalysisState>} */
/** @type {Visitors<LegacyAnalysisState>} */
const legacy_scope_tweaker = {
LabeledStatement(node, { next, path, state }) {
if (
state.ast_type !== 'instance' ||
node.label.name !== '$' ||
/** @type {import('#compiler').SvelteNode} */ (path.at(-1)).type !== 'Program'
/** @type {SvelteNode} */ (path.at(-1)).type !== 'Program'
) {
return next();
}
// Find all dependencies of this `$: {...}` statement
/** @type {import('../types.js').ReactiveStatement} */
/** @type {ReactiveStatement} */
const reactive_statement = {
assignments: new Set(),
dependencies: []
@ -669,14 +673,14 @@ const legacy_scope_tweaker = {
if (binding === null) continue;
for (const { node, path } of nodes) {
/** @type {import('estree').Expression} */
/** @type {Expression} */
let left = node;
let i = path.length - 1;
let parent = /** @type {import('estree').Expression} */ (path.at(i));
let parent = /** @type {Expression} */ (path.at(i));
while (parent.type === 'MemberExpression') {
left = parent;
parent = /** @type {import('estree').Expression} */ (path.at(--i));
parent = /** @type {Expression} */ (path.at(--i));
}
if (
@ -757,7 +761,7 @@ const legacy_scope_tweaker = {
next();
},
Identifier(node, { state, path }) {
const parent = /** @type {import('estree').Node} */ (path.at(-1));
const parent = /** @type {Node} */ (path.at(-1));
if (is_reference(node, parent)) {
if (node.name === '$$props') {
state.analysis.uses_props = true;
@ -834,9 +838,7 @@ const legacy_scope_tweaker = {
if (!node.declaration) {
for (const specifier of node.specifiers) {
const binding = /** @type {import('#compiler').Binding} */ (
state.scope.get(specifier.local.name)
);
const binding = /** @type {Binding} */ (state.scope.get(specifier.local.name));
if (
binding !== null &&
(binding.kind === 'state' ||
@ -863,7 +865,7 @@ const legacy_scope_tweaker = {
node.declaration.type === 'ClassDeclaration'
) {
state.analysis.exports.push({
name: /** @type {import('estree').Identifier} */ (node.declaration.id).name,
name: /** @type {Identifier} */ (node.declaration.id).name,
alias: null
});
return next();
@ -881,7 +883,7 @@ const legacy_scope_tweaker = {
for (const declarator of node.declaration.declarations) {
for (const id of extract_identifiers(declarator.id)) {
const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(id.name));
const binding = /** @type {Binding} */ (state.scope.get(id.name));
binding.kind = 'bindable_prop';
}
}
@ -899,7 +901,7 @@ const legacy_scope_tweaker = {
}
};
/** @type {import('zimmerframe').Visitors<import('#compiler').SvelteNode, { scope: Scope, analysis: { runes: true } }>} */
/** @type {Visitors} */
const runes_scope_js_tweaker = {
VariableDeclarator(node, { state }) {
if (node.init?.type !== 'CallExpression') return;
@ -919,14 +921,14 @@ const runes_scope_js_tweaker = {
for (const path of extract_paths(node.id)) {
// @ts-ignore this fails in CI for some insane reason
const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(path.node.name));
const binding = /** @type {Binding} */ (state.scope.get(path.node.name));
binding.kind =
rune === '$state' ? 'state' : rune === '$state.frozen' ? 'frozen_state' : 'derived';
}
}
};
/** @type {import('./types').Visitors} */
/** @type {Visitors} */
const runes_scope_tweaker = {
CallExpression(node, { state, next }) {
const rune = get_rune(node, state.scope);
@ -956,7 +958,7 @@ const runes_scope_tweaker = {
for (const path of extract_paths(node.id)) {
// @ts-ignore this fails in CI for some insane reason
const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(path.node.name));
const binding = /** @type {Binding} */ (state.scope.get(path.node.name));
binding.kind =
rune === '$state'
? 'state'
@ -973,7 +975,7 @@ const runes_scope_tweaker = {
state.analysis.needs_props = true;
if (node.id.type === 'Identifier') {
const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(node.id.name));
const binding = /** @type {Binding} */ (state.scope.get(node.id.name));
binding.initial = null; // else would be $props()
binding.kind = 'rest_prop';
} else {
@ -984,15 +986,15 @@ const runes_scope_tweaker = {
const name =
property.value.type === 'AssignmentPattern'
? /** @type {import('estree').Identifier} */ (property.value.left).name
: /** @type {import('estree').Identifier} */ (property.value).name;
? /** @type {Identifier} */ (property.value.left).name
: /** @type {Identifier} */ (property.value).name;
const alias =
property.key.type === 'Identifier'
? property.key.name
: String(/** @type {import('estree').Literal} */ (property.key).value);
: String(/** @type {Literal} */ (property.key).value);
let initial = property.value.type === 'AssignmentPattern' ? property.value.right : null;
const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(name));
const binding = /** @type {Binding} */ (state.scope.get(name));
binding.prop_alias = alias;
// rewire initial from $props() to the actual initial value, stripping $bindable() if necessary
@ -1001,9 +1003,7 @@ const runes_scope_tweaker = {
initial.callee.type === 'Identifier' &&
initial.callee.name === '$bindable'
) {
binding.initial = /** @type {import('estree').Expression | null} */ (
initial.arguments[0] ?? null
);
binding.initial = /** @type {Expression | null} */ (initial.arguments[0] ?? null);
binding.kind = 'bindable_prop';
} else {
binding.initial = initial;
@ -1033,7 +1033,7 @@ const runes_scope_tweaker = {
node.declaration.type === 'ClassDeclaration'
) {
state.analysis.exports.push({
name: /** @type {import('estree').Identifier} */ (node.declaration.id).name,
name: /** @type {Identifier} */ (node.declaration.id).name,
alias: null
});
return next();
@ -1050,8 +1050,8 @@ const runes_scope_tweaker = {
};
/**
* @param {import('estree').CallExpression} node
* @param {import('./types').Context} context
* @param {CallExpression} node
* @param {Context} context
* @returns {boolean}
*/
function is_known_safe_call(node, context) {
@ -1075,8 +1075,8 @@ function is_known_safe_call(node, context) {
}
/**
* @param {import('estree').ArrowFunctionExpression | import('estree').FunctionExpression | import('estree').FunctionDeclaration} node
* @param {import('./types').Context} context
* @param {ArrowFunctionExpression | FunctionExpression | FunctionDeclaration} node
* @param {Context} context
*/
const function_visitor = (node, context) => {
// TODO retire this in favour of a more general solution based on bindings
@ -1096,7 +1096,7 @@ const function_visitor = (node, context) => {
/**
* A 'safe' identifier means that the `foo` in `foo.bar` or `foo()` will not
* call functions that require component context to exist
* @param {import('estree').Expression | import('estree').Super} expression
* @param {Expression | Super} expression
* @param {Scope} scope
*/
function is_safe_identifier(expression, scope) {
@ -1120,7 +1120,7 @@ function is_safe_identifier(expression, scope) {
);
}
/** @type {import('./types').Visitors} */
/** @type {Visitors} */
const common_visitors = {
_(node, { state, next, path }) {
ignore_map.set(node, structuredClone(ignore_stack));
@ -1243,7 +1243,7 @@ const common_visitors = {
context.next({ ...context.state, expression: node });
},
Identifier(node, context) {
const parent = /** @type {import('estree').Node} */ (context.path.at(-1));
const parent = /** @type {Node} */ (context.path.at(-1));
if (!is_reference(node, parent)) return;
if (node.name === '$$slots') {
@ -1270,8 +1270,7 @@ const common_visitors = {
// TODO it would be better to just bail out when we hit the ExportSpecifier node but that's
// not currently possibly because of our visitor merging, which I desperately want to nuke
const is_export_specifier =
/** @type {import('#compiler').SvelteNode} */ (context.path.at(-1)).type ===
'ExportSpecifier';
/** @type {SvelteNode} */ (context.path.at(-1)).type === 'ExportSpecifier';
if (
context.state.analysis.runes &&
@ -1472,8 +1471,8 @@ const common_visitors = {
node.attributes.push(
create_attribute(
'value',
/** @type {import('#compiler').Text} */ (node.fragment.nodes.at(0)).start,
/** @type {import('#compiler').Text} */ (node.fragment.nodes.at(-1)).end,
/** @type {Text} */ (node.fragment.nodes.at(0)).start,
/** @type {Text} */ (node.fragment.nodes.at(-1)).end,
// @ts-ignore
node.fragment.nodes
)
@ -1552,7 +1551,7 @@ const common_visitors = {
};
/**
* @param {import('#compiler').RegularElement} node
* @param {RegularElement} node
*/
function determine_element_spread(node) {
let has_spread = false;
@ -1578,10 +1577,10 @@ function get_attribute_event_name(event_name) {
}
/**
* @param {Map<import('estree').LabeledStatement, import('../types.js').ReactiveStatement>} unsorted_reactive_declarations
* @param {Map<LabeledStatement, ReactiveStatement>} unsorted_reactive_declarations
*/
function order_reactive_statements(unsorted_reactive_declarations) {
/** @typedef {[import('estree').LabeledStatement, import('../types.js').ReactiveStatement]} Tuple */
/** @typedef {[LabeledStatement, ReactiveStatement]} Tuple */
/** @type {Map<string, Array<Tuple>>} */
const lookup = new Map();
@ -1614,13 +1613,13 @@ function order_reactive_statements(unsorted_reactive_declarations) {
}
// We use a map and take advantage of the fact that the spec says insertion order is preserved when iterating
/** @type {Map<import('estree').LabeledStatement, import('../types.js').ReactiveStatement>} */
/** @type {Map<LabeledStatement, ReactiveStatement>} */
const reactive_declarations = new Map();
/**
*
* @param {import('estree').LabeledStatement} node
* @param {import('../types.js').ReactiveStatement} declaration
* @param {LabeledStatement} node
* @param {ReactiveStatement} declaration
* @returns
*/
const add_declaration = (node, declaration) => {

@ -1,3 +1,7 @@
/** @import { AssignmentExpression, CallExpression, Expression, Identifier, Node, Pattern, PrivateIdentifier, Super, UpdateExpression, VariableDeclarator } from 'estree' */
/** @import { Attribute, Component, ElementLike, Fragment, RegularElement, SvelteComponent, SvelteElement, SvelteNode, SvelteSelf, TransitionDirective } from '#compiler' */
/** @import { NodeLike } from '../../errors.js' */
/** @import { AnalysisState, Context, Visitors } from './types.js' */
import is_reference from 'is-reference';
import {
disallowed_paragraph_contents,
@ -35,8 +39,8 @@ import { merge } from '../visitors.js';
import { a11y_validators } from './a11y.js';
/**
* @param {import('#compiler').Attribute} attribute
* @param {import('#compiler').ElementLike} parent
* @param {Attribute} attribute
* @param {ElementLike} parent
*/
function validate_attribute(attribute, parent) {
if (
@ -63,8 +67,8 @@ function validate_attribute(attribute, parent) {
}
/**
* @param {import('#compiler').Component | import('#compiler').SvelteComponent | import('#compiler').SvelteSelf} node
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, import('./types.js').AnalysisState>} context
* @param {Component | SvelteComponent | SvelteSelf} node
* @param {Context} context
*/
function validate_component(node, context) {
for (const attribute of node.attributes) {
@ -123,16 +127,16 @@ const react_attributes = new Map([
]);
/**
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} node
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, import('./types.js').AnalysisState>} context
* @param {RegularElement | SvelteElement} node
* @param {Context} context
*/
function validate_element(node, context) {
let has_animate_directive = false;
/** @type {import('#compiler').TransitionDirective | null} */
/** @type {TransitionDirective | null} */
let in_transition = null;
/** @type {import('#compiler').TransitionDirective | null} */
/** @type {TransitionDirective | null} */
let out_transition = null;
for (const attribute of node.attributes) {
@ -175,7 +179,7 @@ function validate_element(node, context) {
}
if (attribute.name === 'slot') {
/** @type {import('#compiler').RegularElement | import('#compiler').SvelteElement | import('#compiler').Component | import('#compiler').SvelteComponent | import('#compiler').SvelteSelf | undefined} */
/** @type {RegularElement | SvelteElement | Component | SvelteComponent | SvelteSelf | undefined} */
validate_slot_attribute(context, attribute);
}
@ -212,7 +216,7 @@ function validate_element(node, context) {
has_animate_directive = true;
}
} else if (attribute.type === 'TransitionDirective') {
const existing = /** @type {import('#compiler').TransitionDirective | null} */ (
const existing = /** @type {TransitionDirective | null} */ (
(attribute.intro && in_transition) || (attribute.outro && out_transition)
);
@ -255,7 +259,7 @@ function validate_element(node, context) {
}
/**
* @param {import('#compiler').Attribute} attribute
* @param {Attribute} attribute
*/
function validate_attribute_name(attribute) {
if (
@ -269,8 +273,8 @@ function validate_attribute_name(attribute) {
}
/**
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, import('./types.js').AnalysisState>} context
* @param {import('#compiler').Attribute} attribute
* @param {Context} context
* @param {Attribute} attribute
* @param {boolean} is_component
*/
function validate_slot_attribute(context, attribute, is_component = false) {
@ -343,8 +347,8 @@ function validate_slot_attribute(context, attribute, is_component = false) {
}
/**
* @param {import('#compiler').Fragment | null | undefined} node
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, import('./types.js').AnalysisState>} context
* @param {Fragment | null | undefined} node
* @param {Context} context
*/
function validate_block_not_empty(node, context) {
if (!node) return;
@ -356,7 +360,7 @@ function validate_block_not_empty(node, context) {
}
/**
* @type {import('zimmerframe').Visitors<import('#compiler').SvelteNode, import('./types.js').AnalysisState>}
* @type {Visitors}
*/
const validation = {
MemberExpression(node, context) {
@ -465,7 +469,7 @@ const validation = {
}
if (parent.name === 'input' && node.name !== 'this') {
const type = /** @type {import('#compiler').Attribute | undefined} */ (
const type = /** @type {Attribute | undefined} */ (
parent.attributes.find((a) => a.type === 'Attribute' && a.name === 'type')
);
if (type && !is_text_attribute(type)) {
@ -506,7 +510,7 @@ const validation = {
}
if (ContentEditableBindings.includes(node.name)) {
const contenteditable = /** @type {import('#compiler').Attribute} */ (
const contenteditable = /** @type {Attribute} */ (
parent.attributes.find((a) => a.type === 'Attribute' && a.name === 'contenteditable')
);
if (!contenteditable) {
@ -636,11 +640,14 @@ const validation = {
}
}
// Strip off any namespace from the beginning of the node name.
const node_name = node.name.replace(/[a-zA-Z-]*:/g, '');
if (
context.state.analysis.source[node.end - 2] === '/' &&
context.state.options.namespace !== 'foreign' &&
!VoidElements.includes(node.name) &&
!SVGElements.includes(node.name)
!VoidElements.includes(node_name) &&
!SVGElements.includes(node_name)
) {
w.element_invalid_self_closing_tag(node, node.name);
}
@ -843,8 +850,7 @@ export const validation_legacy = merge(validation, a11y_validators, {
LabeledStatement(node, { path, state }) {
if (
node.label.name === '$' &&
(state.ast_type !== 'instance' ||
/** @type {import('#compiler').SvelteNode} */ (path.at(-1)).type !== 'Program')
(state.ast_type !== 'instance' || /** @type {SvelteNode} */ (path.at(-1)).type !== 'Program')
) {
w.reactive_declaration_invalid_placement(node);
}
@ -856,8 +862,8 @@ export const validation_legacy = merge(validation, a11y_validators, {
/**
*
* @param {import('estree').Node} node
* @param {import('../scope').Scope} scope
* @param {Node} node
* @param {Scope} scope
* @param {string} name
*/
function validate_export(node, scope, name) {
@ -874,16 +880,16 @@ function validate_export(node, scope, name) {
}
/**
* @param {import('estree').CallExpression} node
* @param {CallExpression} node
* @param {Scope} scope
* @param {import('#compiler').SvelteNode[]} path
* @param {SvelteNode[]} path
* @returns
*/
function validate_call_expression(node, scope, path) {
const rune = get_rune(node, scope);
if (rune === null) return;
const parent = /** @type {import('#compiler').SvelteNode} */ (get_parent(path, -1));
const parent = /** @type {SvelteNode} */ (get_parent(path, -1));
if (rune === '$props') {
if (parent.type === 'VariableDeclarator') return;
@ -962,8 +968,8 @@ function validate_call_expression(node, scope, path) {
}
/**
* @param {import('estree').VariableDeclarator} node
* @param {import('./types.js').AnalysisState} state
* @param {VariableDeclarator} node
* @param {AnalysisState} state
*/
function ensure_no_module_import_conflict(node, state) {
const ids = extract_identifiers(node.id);
@ -978,7 +984,7 @@ function ensure_no_module_import_conflict(node, state) {
}
/**
* @type {import('zimmerframe').Visitors<import('#compiler').SvelteNode, import('./types.js').AnalysisState>}
* @type {Visitors}
*/
export const validation_runes_js = {
ImportDeclaration(node) {
@ -1013,7 +1019,7 @@ export const validation_runes_js = {
if (rune === null) return;
const args = /** @type {import('estree').CallExpression} */ (init).arguments;
const args = /** @type {CallExpression} */ (init).arguments;
if ((rune === '$derived' || rune === '$derived.by') && args.length !== 1) {
e.rune_invalid_arguments_length(node, rune, 'exactly one argument');
@ -1070,7 +1076,7 @@ export const validation_runes_js = {
},
Identifier(node, { path, state }) {
let i = path.length;
let parent = /** @type {import('estree').Expression} */ (path[--i]);
let parent = /** @type {Expression} */ (path[--i]);
if (
Runes.includes(/** @type {Runes[number]} */ (node.name)) &&
@ -1078,16 +1084,16 @@ export const validation_runes_js = {
state.scope.get(node.name) === null &&
state.scope.get(node.name.slice(1)) === null
) {
/** @type {import('estree').Expression} */
/** @type {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}`;
name += `.${/** @type {Identifier} */ (parent.property).name}`;
current = parent;
parent = /** @type {import('estree').Expression} */ (path[--i]);
parent = /** @type {Expression} */ (path[--i]);
if (!Runes.includes(/** @type {Runes[number]} */ (name))) {
if (name === '$effect.active') {
@ -1106,8 +1112,8 @@ export const validation_runes_js = {
};
/**
* @param {import('../../errors.js').NodeLike} node
* @param {import('estree').Pattern | import('estree').Expression} argument
* @param {NodeLike} node
* @param {Pattern | Expression} argument
* @param {Scope} scope
* @param {boolean} is_binding
*/
@ -1153,7 +1159,7 @@ function validate_no_const_assignment(node, argument, scope, is_binding) {
* Validates that the opening of a control flow block is `{` immediately followed by the expected character.
* In legacy mode whitespace is allowed inbetween. TODO remove once legacy mode is gone and move this into parser instead.
* @param {{start: number; end: number}} node
* @param {import('./types.js').AnalysisState} state
* @param {AnalysisState} state
* @param {string} expected
*/
function validate_opening_tag(node, state, expected) {
@ -1164,9 +1170,9 @@ function validate_opening_tag(node, state, expected) {
}
/**
* @param {import('estree').AssignmentExpression | import('estree').UpdateExpression} node
* @param {import('estree').Pattern | import('estree').Expression} argument
* @param {import('./types.js').AnalysisState} state
* @param {AssignmentExpression | UpdateExpression} node
* @param {Pattern | Expression} argument
* @param {AnalysisState} state
*/
function validate_assignment(node, argument, state) {
validate_no_const_assignment(node, argument, state.scope, false);
@ -1189,9 +1195,9 @@ function validate_assignment(node, argument, state) {
}
}
let object = /** @type {import('estree').Expression | import('estree').Super} */ (argument);
let object = /** @type {Expression | Super} */ (argument);
/** @type {import('estree').Expression | import('estree').PrivateIdentifier | null} */
/** @type {Expression | PrivateIdentifier | null} */
let property = null;
while (object.type === 'MemberExpression') {
@ -1319,7 +1325,7 @@ export const validation_runes = merge(validation, a11y_validators, {
if (rune === null) return;
const args = /** @type {import('estree').CallExpression} */ (init).arguments;
const args = /** @type {CallExpression} */ (init).arguments;
// TODO some of this is duplicated with above, seems off
if ((rune === '$derived' || rune === '$derived.by') && args.length !== 1) {

@ -1,3 +1,7 @@
/** @import { ArrowFunctionExpression, AssignmentExpression, BinaryOperator, Expression, FunctionDeclaration, FunctionExpression, Identifier, MemberExpression, Node, Pattern, PrivateIdentifier, Statement } from 'estree' */
/** @import { Binding, SvelteNode } from '#compiler' */
/** @import { ClientTransformState, ComponentClientTransformState, ComponentContext } from './types.js' */
/** @import { Scope } from '../../scope.js' */
import * as b from '../../../utils/builders.js';
import {
extract_identifiers,
@ -14,21 +18,21 @@ import {
} from '../../../../constants.js';
/**
* @template {import('./types').ClientTransformState} State
* @param {import('estree').AssignmentExpression} node
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, State>} context
* @template {ClientTransformState} State
* @param {AssignmentExpression} node
* @param {import('zimmerframe').Context<SvelteNode, State>} context
* @returns
*/
export function get_assignment_value(node, { state, visit }) {
if (node.left.type === 'Identifier') {
const operator = node.operator;
return operator === '='
? /** @type {import('estree').Expression} */ (visit(node.right))
? /** @type {Expression} */ (visit(node.right))
: // turn something like x += 1 into x = x + 1
b.binary(
/** @type {import('estree').BinaryOperator} */ (operator.slice(0, -1)),
/** @type {BinaryOperator} */ (operator.slice(0, -1)),
serialize_get_binding(node.left, state),
/** @type {import('estree').Expression} */ (visit(node.right))
/** @type {Expression} */ (visit(node.right))
);
} else if (
node.left.type === 'MemberExpression' &&
@ -38,21 +42,21 @@ export function get_assignment_value(node, { state, visit }) {
) {
const operator = node.operator;
return operator === '='
? /** @type {import('estree').Expression} */ (visit(node.right))
? /** @type {Expression} */ (visit(node.right))
: // turn something like x += 1 into x = x + 1
b.binary(
/** @type {import('estree').BinaryOperator} */ (operator.slice(0, -1)),
/** @type {import('estree').Expression} */ (visit(node.left)),
/** @type {import('estree').Expression} */ (visit(node.right))
/** @type {BinaryOperator} */ (operator.slice(0, -1)),
/** @type {Expression} */ (visit(node.left)),
/** @type {Expression} */ (visit(node.right))
);
} else {
return /** @type {import('estree').Expression} */ (visit(node.right));
return /** @type {Expression} */ (visit(node.right));
}
}
/**
* @param {import('#compiler').Binding} binding
* @param {import('./types').ClientTransformState} state
* @param {Binding} binding
* @param {ClientTransformState} state
* @returns {boolean}
*/
export function is_state_source(binding, state) {
@ -63,9 +67,9 @@ export function is_state_source(binding, state) {
}
/**
* @param {import('estree').Identifier} node
* @param {import('./types').ClientTransformState} state
* @returns {import('estree').Expression}
* @param {Identifier} node
* @param {ClientTransformState} state
* @returns {Expression}
*/
export function serialize_get_binding(node, state) {
const binding = state.scope.get(node.name);
@ -117,13 +121,13 @@ export function serialize_get_binding(node, state) {
}
/**
* @template {import('./types').ClientTransformState} State
* @param {import('estree').AssignmentExpression} node
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, State>} context
* @template {ClientTransformState} State
* @param {AssignmentExpression} node
* @param {import('zimmerframe').Context<SvelteNode, State>} context
* @param {() => any} fallback
* @param {boolean | null} [prefix] - If the assignment is a transformed update expression, set this. Else `null`
* @param {{skip_proxy_and_freeze?: boolean}} [options]
* @returns {import('estree').Expression}
* @returns {Expression}
*/
export function serialize_set_binding(node, context, fallback, prefix, options) {
const { state, visit } = context;
@ -137,10 +141,10 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
// Turn assignment into an IIFE, so that `$.set` calls etc don't produce invalid code
const tmp_id = context.state.scope.generate('tmp');
/** @type {import('estree').AssignmentExpression[]} */
/** @type {AssignmentExpression[]} */
const original_assignments = [];
/** @type {import('estree').Expression[]} */
/** @type {Expression[]} */
const assignments = [];
const paths = extract_paths(assignee);
@ -159,7 +163,7 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
return fallback();
}
const rhs_expression = /** @type {import('estree').Expression} */ (visit(node.right));
const rhs_expression = /** @type {Expression} */ (visit(node.right));
const iife_is_async =
is_expression_async(rhs_expression) ||
@ -271,8 +275,8 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
'$$_import_' + binding.node.name,
b.assignment(
node.operator,
/** @type {import('estree').Pattern} */ (visit(node.left)),
/** @type {import('estree').Expression} */ (visit(node.right))
/** @type {Pattern} */ (visit(node.left)),
/** @type {Expression} */ (visit(node.right))
)
);
}
@ -299,10 +303,7 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
if (left === node.left) {
const is_initial_proxy =
binding.initial !== null &&
should_proxy_or_freeze(
/**@type {import("estree").Expression}*/ (binding.initial),
context.state.scope
);
should_proxy_or_freeze(/**@type {Expression}*/ (binding.initial), context.state.scope);
if ((binding.kind === 'prop' || binding.kind === 'bindable_prop') && !is_initial_proxy) {
return b.call(left, value);
} else if (is_store) {
@ -359,38 +360,31 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
// keep consistency with how store $ shorthand reads work in Svelte 4.
/**
*
* @param {import("estree").Expression | import("estree").Pattern} node
* @returns {import("estree").Expression}
* @param {Expression | Pattern} node
* @returns {Expression}
*/
function visit_node(node) {
if (node.type === 'MemberExpression') {
return {
...node,
object: visit_node(/** @type {import("estree").Expression} */ (node.object)),
property: /** @type {import("estree").MemberExpression} */ (visit(node)).property
object: visit_node(/** @type {Expression} */ (node.object)),
property: /** @type {MemberExpression} */ (visit(node)).property
};
}
if (node.type === 'Identifier') {
const binding = state.scope.get(node.name);
if (binding !== null && binding.kind === 'store_sub') {
return b.call(
'$.untrack',
b.thunk(/** @type {import('estree').Expression} */ (visit(node)))
);
return b.call('$.untrack', b.thunk(/** @type {Expression} */ (visit(node))));
}
}
return /** @type {import("estree").Expression} */ (visit(node));
return /** @type {Expression} */ (visit(node));
}
return b.call(
'$.mutate_store',
serialize_get_binding(b.id(left_name), state),
b.assignment(
node.operator,
/** @type {import("estree").Pattern}} */ (visit_node(node.left)),
value
),
b.assignment(node.operator, /** @type {Pattern}} */ (visit_node(node.left)), value),
b.call('$.untrack', b.id('$' + left_name))
);
} else if (
@ -401,22 +395,14 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
if (binding.kind === 'bindable_prop') {
return b.call(
left,
b.assignment(
node.operator,
/** @type {import('estree').Pattern} */ (visit(node.left)),
value
),
b.assignment(node.operator, /** @type {Pattern} */ (visit(node.left)), value),
b.true
);
} else {
return b.call(
'$.mutate',
b.id(left_name),
b.assignment(
node.operator,
/** @type {import('estree').Pattern} */ (visit(node.left)),
value
)
b.assignment(node.operator, /** @type {Pattern} */ (visit(node.left)), value)
);
}
} else if (
@ -426,14 +412,14 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
) {
return b.update(
node.operator === '+=' ? '++' : '--',
/** @type {import('estree').Expression} */ (visit(node.left)),
/** @type {Expression} */ (visit(node.left)),
prefix
);
} else {
return b.assignment(
node.operator,
/** @type {import('estree').Pattern} */ (visit(node.left)),
/** @type {import('estree').Expression} */ (visit(node.right))
/** @type {Pattern} */ (visit(node.left)),
/** @type {Expression} */ (visit(node.right))
);
}
}
@ -447,9 +433,9 @@ export function serialize_set_binding(node, context, fallback, prefix, options)
}
/**
* @param {import('estree').Expression} value
* @param {import('estree').PrivateIdentifier | string} proxy_reference
* @param {import('./types').ClientTransformState} state
* @param {Expression} value
* @param {PrivateIdentifier | string} proxy_reference
* @param {ClientTransformState} state
*/
export function serialize_proxy_reassignment(value, proxy_reference, state) {
return state.options.dev
@ -465,8 +451,8 @@ export function serialize_proxy_reassignment(value, proxy_reference, state) {
}
/**
* @param {import('estree').ArrowFunctionExpression | import('estree').FunctionExpression} node
* @param {import('./types').ComponentContext} context
* @param {ArrowFunctionExpression | FunctionExpression} node
* @param {ComponentContext} context
*/
export const function_visitor = (node, context) => {
const metadata = node.metadata;
@ -474,7 +460,7 @@ export const function_visitor = (node, context) => {
let state = context.state;
if (node.type === 'FunctionExpression') {
const parent = /** @type {import('estree').Node} */ (context.path.at(-1));
const parent = /** @type {Node} */ (context.path.at(-1));
const in_constructor = parent.type === 'MethodDefinition' && parent.kind === 'constructor';
state = { ...context.state, in_constructor };
@ -485,7 +471,7 @@ export const function_visitor = (node, context) => {
if (metadata?.hoistable === true) {
const params = serialize_hoistable_params(node, context);
return /** @type {import('estree').FunctionExpression} */ ({
return /** @type {FunctionExpression} */ ({
...node,
params,
body: context.visit(node.body, state)
@ -496,19 +482,19 @@ export const function_visitor = (node, context) => {
};
/**
* @param {import('estree').FunctionDeclaration | import('estree').FunctionExpression | import('estree').ArrowFunctionExpression} node
* @param {import('./types').ComponentContext} context
* @returns {import('estree').Pattern[]}
* @param {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression} node
* @param {ComponentContext} context
* @returns {Pattern[]}
*/
function get_hoistable_params(node, context) {
const scope = context.state.scope;
/** @type {import('estree').Identifier[]} */
/** @type {Identifier[]} */
const params = [];
/**
* We only want to push if it's not already present to avoid name clashing
* @param {import('estree').Identifier} id
* @param {Identifier} id
*/
function push_unique(id) {
if (!params.find((param) => param.name === id.name)) {
@ -523,9 +509,7 @@ function get_hoistable_params(node, context) {
if (binding.kind === 'store_sub') {
// We need both the subscription for getting the value and the store for updating
push_unique(b.id(binding.node.name));
binding = /** @type {import('#compiler').Binding} */ (
scope.get(binding.node.name.slice(1))
);
binding = /** @type {Binding} */ (scope.get(binding.node.name.slice(1)));
}
const expression = context.state.getters[reference];
@ -566,15 +550,15 @@ function get_hoistable_params(node, context) {
}
/**
* @param {import('estree').FunctionDeclaration | import('estree').FunctionExpression | import('estree').ArrowFunctionExpression} node
* @param {import('./types').ComponentContext} context
* @returns {import('estree').Pattern[]}
* @param {FunctionDeclaration | FunctionExpression | ArrowFunctionExpression} node
* @param {ComponentContext} context
* @returns {Pattern[]}
*/
export function serialize_hoistable_params(node, context) {
const hoistable_params = get_hoistable_params(node, context);
node.metadata.hoistable_params = hoistable_params;
/** @type {import('estree').Pattern[]} */
/** @type {Pattern[]} */
const params = [];
if (node.params.length === 0) {
@ -584,7 +568,7 @@ export function serialize_hoistable_params(node, context) {
}
} else {
for (const param of node.params) {
params.push(/** @type {import('estree').Pattern} */ (context.visit(param)));
params.push(/** @type {Pattern} */ (context.visit(param)));
}
}
@ -593,14 +577,14 @@ export function serialize_hoistable_params(node, context) {
}
/**
* @param {import('#compiler').Binding} binding
* @param {import('./types').ComponentClientTransformState} state
* @param {Binding} binding
* @param {ComponentClientTransformState} state
* @param {string} name
* @param {import('estree').Expression | null} [initial]
* @param {Expression | null} [initial]
* @returns
*/
export function get_prop_source(binding, state, name, initial) {
/** @type {import('estree').Expression[]} */
/** @type {Expression[]} */
const args = [b.id('$$props'), b.literal(name)];
let flags = 0;
@ -622,7 +606,7 @@ export function get_prop_source(binding, state, name, initial) {
flags |= PROPS_IS_UPDATED;
}
/** @type {import('estree').Expression | undefined} */
/** @type {Expression | undefined} */
let arg;
if (initial) {
@ -654,8 +638,8 @@ export function get_prop_source(binding, state, name, initial) {
/**
*
* @param {import('#compiler').Binding} binding
* @param {import('./types').ClientTransformState} state
* @param {Binding} binding
* @param {ClientTransformState} state
* @returns
*/
export function is_prop_source(binding, state) {
@ -672,8 +656,8 @@ export function is_prop_source(binding, state) {
}
/**
* @param {import('estree').Expression} node
* @param {import("../../scope.js").Scope | null} scope
* @param {Expression} node
* @param {Scope | null} scope
*/
export function should_proxy_or_freeze(node, scope) {
if (
@ -710,8 +694,8 @@ export function should_proxy_or_freeze(node, scope) {
* Port over the location information from the source to the target identifier.
* but keep the target as-is (i.e. a new id is created).
* This ensures esrap can generate accurate source maps.
* @param {import('estree').Identifier} target
* @param {import('estree').Identifier} source
* @param {Identifier} target
* @param {Identifier} source
*/
export function with_loc(target, source) {
if (source.loc) {
@ -721,16 +705,16 @@ export function with_loc(target, source) {
}
/**
* @param {import("estree").Pattern} node
* @param {import("zimmerframe").Context<import("#compiler").SvelteNode, import("./types").ComponentClientTransformState>} context
* @returns {{ id: import("estree").Pattern, declarations: null | import("estree").Statement[] }}
* @param {Pattern} node
* @param {import('zimmerframe').Context<SvelteNode, ComponentClientTransformState>} context
* @returns {{ id: Pattern, declarations: null | Statement[] }}
*/
export function create_derived_block_argument(node, context) {
if (node.type === 'Identifier') {
return { id: node, declarations: null };
}
const pattern = /** @type {import('estree').Pattern} */ (context.visit(node));
const pattern = /** @type {Pattern} */ (context.visit(node));
const identifiers = extract_identifiers(node);
const id = b.id('$$source');
@ -754,8 +738,8 @@ export function create_derived_block_argument(node, context) {
/**
* Svelte legacy mode should use safe equals in most places, runes mode shouldn't
* @param {import('./types.js').ComponentClientTransformState} state
* @param {import('estree').Expression} arg
* @param {ComponentClientTransformState} state
* @param {Expression} arg
*/
export function create_derived(state, arg) {
return b.call(state.analysis.runes ? '$.derived' : '$.derived_safe_equal', arg);

@ -1,11 +1,13 @@
/** @import { Expression, Node, Pattern, Statement } from 'estree' */
/** @import { Visitors } from '../types' */
import is_reference from 'is-reference';
import { serialize_get_binding, serialize_set_binding } from '../utils.js';
import * as b from '../../../../utils/builders.js';
/** @type {import('../types').Visitors} */
/** @type {Visitors} */
export const global_visitors = {
Identifier(node, { path, state }) {
if (is_reference(node, /** @type {import('estree').Node} */ (path.at(-1)))) {
if (is_reference(node, /** @type {Node} */ (path.at(-1)))) {
if (node.name === '$$props') {
return b.id('$$sanitized_props');
}
@ -74,7 +76,7 @@ export const global_visitors = {
binding?.kind === 'bindable_prop' ||
is_store
) {
/** @type {import('estree').Expression[]} */
/** @type {Expression[]} */
const args = [];
let fn = '$.update';
@ -105,7 +107,7 @@ export const global_visitors = {
let fn = '$.update';
if (node.prefix) fn += '_pre';
/** @type {import('estree').Expression[]} */
/** @type {Expression[]} */
const args = [argument];
if (node.operator === '--') {
args.push(b.literal(-1));
@ -116,7 +118,7 @@ export const global_visitors = {
// turn it into an IIFEE assignment expression: i++ -> (() => { const $$value = i; i+=1; return $$value; })
const assignment = b.assignment(
node.operator === '++' ? '+=' : '-=',
/** @type {import('estree').Pattern} */ (argument),
/** @type {Pattern} */ (argument),
b.literal(1)
);
const serialized_assignment = serialize_set_binding(
@ -125,14 +127,14 @@ export const global_visitors = {
() => assignment,
node.prefix
);
const value = /** @type {import('estree').Expression} */ (visit(argument));
const value = /** @type {Expression} */ (visit(argument));
if (serialized_assignment === assignment) {
// No change to output -> nothing to transform -> we can keep the original update expression
return next();
} else if (context.state.analysis.runes) {
return serialized_assignment;
} else {
/** @type {import('estree').Statement[]} */
/** @type {Statement[]} */
let statements;
if (node.prefix) {
statements = [b.stmt(serialized_assignment), b.return(value)];

@ -1,3 +1,6 @@
/** @import { CallExpression, Expression, Identifier, Literal, MethodDefinition, PrivateIdentifier, PropertyDefinition, VariableDeclarator } from 'estree' */
/** @import { Binding } from '#compiler' */
/** @import { ComponentVisitors, StateField } from '../types.js' */
import { get_rune } from '../../../scope.js';
import { is_hoistable_function, transform_inspect_rune } from '../../utils.js';
import * as b from '../../../../utils/builders.js';
@ -12,13 +15,13 @@ import {
import { extract_paths } from '../../../../utils/ast.js';
import { regex_invalid_identifier_chars } from '../../../patterns.js';
/** @type {import('../types.js').ComponentVisitors} */
/** @type {ComponentVisitors} */
export const javascript_visitors_runes = {
ClassBody(node, { state, visit }) {
/** @type {Map<string, import('../types.js').StateField>} */
/** @type {Map<string, StateField>} */
const public_state = new Map();
/** @type {Map<string, import('../types.js').StateField>} */
/** @type {Map<string, StateField>} */
const private_state = new Map();
/** @type {string[]} */
@ -46,7 +49,7 @@ export const javascript_visitors_runes = {
rune === '$derived' ||
rune === '$derived.by'
) {
/** @type {import('../types.js').StateField} */
/** @type {StateField} */
const field = {
kind:
rune === '$state'
@ -81,7 +84,7 @@ export const javascript_visitors_runes = {
field.id = b.private_id(deconflicted);
}
/** @type {Array<import('estree').MethodDefinition | import('estree').PropertyDefinition>} */
/** @type {Array<MethodDefinition | PropertyDefinition>} */
const body = [];
const child_state = { ...state, public_state, private_state };
@ -104,7 +107,7 @@ export const javascript_visitors_runes = {
let value = null;
if (definition.value.arguments.length > 0) {
const init = /** @type {import('estree').Expression} **/ (
const init = /** @type {Expression} **/ (
visit(definition.value.arguments[0], child_state)
);
@ -182,7 +185,7 @@ export const javascript_visitors_runes = {
}
}
body.push(/** @type {import('estree').MethodDefinition} **/ (visit(definition, child_state)));
body.push(/** @type {MethodDefinition} **/ (visit(definition, child_state)));
}
if (state.options.dev && public_state.size > 0) {
@ -225,15 +228,11 @@ export const javascript_visitors_runes = {
if (init != null && is_hoistable_function(init)) {
const hoistable_function = visit(init);
state.hoisted.push(
b.declaration(
'const',
declarator.id,
/** @type {import('estree').Expression} */ (hoistable_function)
)
b.declaration('const', declarator.id, /** @type {Expression} */ (hoistable_function))
);
continue;
}
declarations.push(/** @type {import('estree').VariableDeclarator} */ (visit(declarator)));
declarations.push(/** @type {VariableDeclarator} */ (visit(declarator)));
continue;
}
@ -246,7 +245,7 @@ export const javascript_visitors_runes = {
}
if (declarator.id.type === 'Identifier') {
/** @type {import('estree').Expression[]} */
/** @type {Expression[]} */
const args = [b.id('$$props'), b.array(seen.map((name) => b.literal(name)))];
if (state.options.dev) {
@ -260,9 +259,7 @@ export const javascript_visitors_runes = {
for (const property of declarator.id.properties) {
if (property.type === 'Property') {
const key = /** @type {import('estree').Identifier | import('estree').Literal} */ (
property.key
);
const key = /** @type {Identifier | Literal} */ (property.key);
const name = key.type === 'Identifier' ? key.name : /** @type {string} */ (key.value);
seen.push(name);
@ -270,10 +267,8 @@ export const javascript_visitors_runes = {
let id =
property.value.type === 'AssignmentPattern' ? property.value.left : property.value;
assert.equal(id.type, 'Identifier');
const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(id.name));
let initial =
binding.initial &&
/** @type {import('estree').Expression} */ (visit(binding.initial));
const binding = /** @type {Binding} */ (state.scope.get(id.name));
let initial = binding.initial && /** @type {Expression} */ (visit(binding.initial));
// We're adding proxy here on demand and not within the prop runtime function so that
// people not using proxied state anywhere in their code don't have to pay the additional bundle size cost
if (
@ -289,14 +284,12 @@ export const javascript_visitors_runes = {
}
} else {
// RestElement
/** @type {import('estree').Expression[]} */
/** @type {Expression[]} */
const args = [b.id('$$props'), b.array(seen.map((name) => b.literal(name)))];
if (state.options.dev) {
// include rest name, so we can provide informative error messages
args.push(
b.literal(/** @type {import('estree').Identifier} */ (property.argument).name)
);
args.push(b.literal(/** @type {Identifier} */ (property.argument).name));
}
declarations.push(b.declarator(property.argument, b.call('$.rest_props', ...args)));
@ -308,19 +301,17 @@ export const javascript_visitors_runes = {
continue;
}
const args = /** @type {import('estree').CallExpression} */ (init).arguments;
const args = /** @type {CallExpression} */ (init).arguments;
const value =
args.length === 0
? b.id('undefined')
: /** @type {import('estree').Expression} */ (visit(args[0]));
args.length === 0 ? b.id('undefined') : /** @type {Expression} */ (visit(args[0]));
if (rune === '$state' || rune === '$state.frozen') {
/**
* @param {import('estree').Identifier} id
* @param {import('estree').Expression} value
* @param {Identifier} id
* @param {Expression} value
*/
const create_state_declarator = (id, value) => {
const binding = /** @type {import('#compiler').Binding} */ (state.scope.get(id.name));
const binding = /** @type {Binding} */ (state.scope.get(id.name));
if (should_proxy_or_freeze(value, state.scope)) {
value = b.call(rune === '$state' ? '$.proxy' : '$.freeze', value);
}
@ -341,9 +332,7 @@ export const javascript_visitors_runes = {
b.declarator(b.id(tmp), value),
...paths.map((path) => {
const value = path.expression?.(b.id(tmp));
const binding = state.scope.get(
/** @type {import('estree').Identifier} */ (path.node).name
);
const binding = state.scope.get(/** @type {Identifier} */ (path.node).name);
return b.declarator(
path.node,
binding?.kind === 'state' || binding?.kind === 'frozen_state'
@ -426,7 +415,7 @@ export const javascript_visitors_runes = {
const func = context.visit(node.expression.arguments[0]);
return {
...node,
expression: b.call('$.user_effect', /** @type {import('estree').Expression} */ (func))
expression: b.call('$.user_effect', /** @type {Expression} */ (func))
};
}
@ -441,7 +430,7 @@ export const javascript_visitors_runes = {
const func = context.visit(node.expression.arguments[0]);
return {
...node,
expression: b.call('$.user_pre_effect', /** @type {import('estree').Expression} */ (func))
expression: b.call('$.user_pre_effect', /** @type {Expression} */ (func))
};
}
}
@ -460,24 +449,19 @@ export const javascript_visitors_runes = {
}
if (rune === '$state.snapshot') {
return b.call(
'$.snapshot',
/** @type {import('estree').Expression} */ (context.visit(node.arguments[0]))
);
return b.call('$.snapshot', /** @type {Expression} */ (context.visit(node.arguments[0])));
}
if (rune === '$state.is') {
return b.call(
'$.is',
/** @type {import('estree').Expression} */ (context.visit(node.arguments[0])),
/** @type {import('estree').Expression} */ (context.visit(node.arguments[1]))
/** @type {Expression} */ (context.visit(node.arguments[0])),
/** @type {Expression} */ (context.visit(node.arguments[1]))
);
}
if (rune === '$effect.root') {
const args = /** @type {import('estree').Expression[]} */ (
node.arguments.map((arg) => context.visit(arg))
);
const args = /** @type {Expression[]} */ (node.arguments.map((arg) => context.visit(arg)));
return b.call('$.effect_root', ...args);
}
@ -494,8 +478,8 @@ export const javascript_visitors_runes = {
if (operator === '===' || operator === '!==') {
return b.call(
'$.strict_equals',
/** @type {import('estree').Expression} */ (visit(node.left)),
/** @type {import('estree').Expression} */ (visit(node.right)),
/** @type {Expression} */ (visit(node.left)),
/** @type {Expression} */ (visit(node.right)),
operator === '!==' && b.literal(false)
);
}
@ -503,8 +487,8 @@ export const javascript_visitors_runes = {
if (operator === '==' || operator === '!=') {
return b.call(
'$.equals',
/** @type {import('estree').Expression} */ (visit(node.left)),
/** @type {import('estree').Expression} */ (visit(node.right)),
/** @type {Expression} */ (visit(node.left)),
/** @type {Expression} */ (visit(node.right)),
operator === '!=' && b.literal(false)
);
}
@ -515,7 +499,7 @@ export const javascript_visitors_runes = {
};
/**
* @param {import('estree').Identifier | import('estree').PrivateIdentifier | import('estree').Literal} node
* @param {Identifier | PrivateIdentifier | Literal} node
*/
function get_name(node) {
if (node.type === 'Literal') {

@ -1,5 +1,8 @@
/** @import { BlockStatement, CallExpression, Expression, ExpressionStatement, Identifier, Literal, MemberExpression, ObjectExpression, Pattern, Property, Statement, Super, TemplateElement, TemplateLiteral } from 'estree' */
/** @import { BindDirective, RegularElement } from '#compiler' */
/** @import { Attribute, BindDirective, Binding, ClassDirective, Component, DelegatedEvent, EachBlock, ExpressionTag, Namespace, OnDirective, RegularElement, SpreadAttribute, StyleDirective, SvelteComponent, SvelteElement, SvelteNode, SvelteSelf, TemplateNode, Text } from '#compiler' */
/** @import { SourceLocation } from '#shared' */
/** @import { Scope } from '../../../scope.js' */
/** @import { ComponentClientTransformState, ComponentContext, ComponentVisitors } from '../types.js' */
import {
extract_identifiers,
extract_paths,
@ -54,9 +57,9 @@ import { locator } from '../../../../state.js';
import is_reference from 'is-reference';
/**
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} element
* @param {import('#compiler').Attribute} attribute
* @param {{ state: { metadata: { namespace: import('#compiler').Namespace }}}} context
* @param {RegularElement | SvelteElement} element
* @param {Attribute} attribute
* @param {{ state: { metadata: { namespace: Namespace }}}} context
*/
function get_attribute_name(element, attribute, context) {
let name = attribute.name;
@ -76,9 +79,9 @@ function get_attribute_name(element, attribute, context) {
/**
* Serializes each style directive into something like `$.set_style(element, style_property, value)`
* and adds it either to init or update, depending on whether or not the value or the attributes are dynamic.
* @param {import('#compiler').StyleDirective[]} style_directives
* @param {StyleDirective[]} style_directives
* @param {Identifier} element_id
* @param {import('../types.js').ComponentContext} context
* @param {ComponentContext} context
* @param {boolean} is_attributes_reactive
*/
function serialize_style_directives(style_directives, element_id, context, is_attributes_reactive) {
@ -138,9 +141,9 @@ function parse_directive_name(name) {
/**
* Serializes each class directive into something like `$.class_toogle(element, class_name, value)`
* and adds it either to init or update, depending on whether or not the value or the attributes are dynamic.
* @param {import('#compiler').ClassDirective[]} class_directives
* @param {ClassDirective[]} class_directives
* @param {Identifier} element_id
* @param {import('../types.js').ComponentContext} context
* @param {ComponentContext} context
* @param {boolean} is_attributes_reactive
*/
function serialize_class_directives(class_directives, element_id, context, is_attributes_reactive) {
@ -161,11 +164,11 @@ function serialize_class_directives(class_directives, element_id, context, is_at
}
/**
* @param {import('#compiler').Binding[]} references
* @param {import('../types.js').ComponentContext} context
* @param {Binding[]} references
* @param {ComponentContext} context
*/
function serialize_transitive_dependencies(references, context) {
/** @type {Set<import('#compiler').Binding>} */
/** @type {Set<Binding>} */
const dependencies = new Set();
for (const ref of references) {
@ -179,9 +182,9 @@ function serialize_transitive_dependencies(references, context) {
}
/**
* @param {import('#compiler').Binding} binding
* @param {Set<import('#compiler').Binding>} seen
* @returns {import('#compiler').Binding[]}
* @param {Binding} binding
* @param {Set<Binding>} seen
* @returns {Binding[]}
*/
function collect_transitive_dependencies(binding, seen = new Set()) {
if (binding.kind !== 'legacy_reactive') return [];
@ -201,8 +204,8 @@ function collect_transitive_dependencies(binding, seen = new Set()) {
/**
* Special case: if we have a value binding on a select element, we need to set up synchronization
* between the value binding and inner signals, for indirect updates
* @param {import('#compiler').BindDirective} value_binding
* @param {import('../types.js').ComponentContext} context
* @param {BindDirective} value_binding
* @param {ComponentContext} context
*/
function setup_select_synchronization(value_binding, context) {
if (context.state.analysis.runes) return;
@ -253,9 +256,9 @@ function setup_select_synchronization(value_binding, context) {
}
/**
* @param {Array<import('#compiler').Attribute | import('#compiler').SpreadAttribute>} attributes
* @param {import('../types.js').ComponentContext} context
* @param {import('#compiler').RegularElement} element
* @param {Array<Attribute | SpreadAttribute>} attributes
* @param {ComponentContext} context
* @param {RegularElement} element
* @param {Identifier} element_id
* @param {boolean} needs_select_handling
*/
@ -358,8 +361,8 @@ function serialize_element_spread_attributes(
/**
* Serializes dynamic element attribute assignments.
* Returns the `true` if spread is deemed reactive.
* @param {Array<import('#compiler').Attribute | import('#compiler').SpreadAttribute>} attributes
* @param {import('../types.js').ComponentContext} context
* @param {Array<Attribute | SpreadAttribute>} attributes
* @param {ComponentContext} context
* @param {Identifier} element_id
* @returns {boolean}
*/
@ -472,10 +475,10 @@ function serialize_dynamic_element_attributes(attributes, context, element_id) {
* });
* ```
* Returns true if attribute is deemed reactive, false otherwise.
* @param {import('#compiler').RegularElement} element
* @param {RegularElement} element
* @param {Identifier} node_id
* @param {import('#compiler').Attribute} attribute
* @param {import('../types.js').ComponentContext} context
* @param {Attribute} attribute
* @param {ComponentContext} context
* @returns {boolean}
*/
function serialize_element_attribute_update_assignment(element, node_id, attribute, context) {
@ -542,8 +545,8 @@ function serialize_element_attribute_update_assignment(element, node_id, attribu
/**
* Like `serialize_element_attribute_update_assignment` but without any special attribute treatment.
* @param {Identifier} node_id
* @param {import('#compiler').Attribute} attribute
* @param {import('../types.js').ComponentContext} context
* @param {Attribute} attribute
* @param {ComponentContext} context
* @returns {boolean}
*/
function serialize_custom_element_attribute_update_assignment(node_id, attribute, context) {
@ -572,8 +575,8 @@ function serialize_custom_element_attribute_update_assignment(node_id, attribute
* Returns true if attribute is deemed reactive, false otherwise.
* @param {string} element
* @param {Identifier} node_id
* @param {import('#compiler').Attribute} attribute
* @param {import('../types.js').ComponentContext} context
* @param {Attribute} attribute
* @param {ComponentContext} context
* @returns {boolean}
*/
function serialize_element_special_value_attribute(element, node_id, attribute, context) {
@ -632,7 +635,7 @@ function serialize_element_special_value_attribute(element, node_id, attribute,
}
/**
* @param {import('../types.js').ComponentClientTransformState} state
* @param {ComponentClientTransformState} state
* @param {string} id
* @param {Expression | undefined} init
* @param {Expression} value
@ -646,18 +649,16 @@ function serialize_update_assignment(state, id, init, value, update) {
}
/**
* @param {import('../types.js').ComponentContext} context
* @param {ComponentContext} context
*/
function collect_parent_each_blocks(context) {
return /** @type {import('#compiler').EachBlock[]} */ (
context.path.filter((node) => node.type === 'EachBlock')
);
return /** @type {EachBlock[]} */ (context.path.filter((node) => node.type === 'EachBlock'));
}
/**
* @param {import('#compiler').Component | import('#compiler').SvelteComponent | import('#compiler').SvelteSelf} node
* @param {Component | SvelteComponent | SvelteSelf} node
* @param {string} component_name
* @param {import('../types.js').ComponentContext} context
* @param {ComponentContext} context
* @param {Expression} anchor
* @returns {Statement}
*/
@ -668,7 +669,7 @@ function serialize_inline_component(node, component_name, context, anchor = cont
/** @type {ExpressionStatement[]} */
const lets = [];
/** @type {Record<string, import('#compiler').TemplateNode[]>} */
/** @type {Record<string, TemplateNode[]>} */
const children = {};
/** @type {Record<string, Expression[]>} */
@ -681,7 +682,7 @@ function serialize_inline_component(node, component_name, context, anchor = cont
let bind_this = null;
/**
* @type {import("estree").ExpressionStatement[]}
* @type {ExpressionStatement[]}
*/
const binding_initializers = [];
@ -844,14 +845,14 @@ function serialize_inline_component(node, component_name, context, anchor = cont
let slot_name = 'default';
if (is_element_node(child)) {
const attribute = /** @type {import('#compiler').Attribute | undefined} */ (
const attribute = /** @type {Attribute | undefined} */ (
child.attributes.find(
(attribute) => attribute.type === 'Attribute' && attribute.name === 'slot'
)
);
if (attribute !== undefined) {
slot_name = /** @type {import('#compiler').Text[]} */ (attribute.value)[0].data;
slot_name = /** @type {Text[]} */ (attribute.value)[0].data;
}
}
@ -995,7 +996,7 @@ function serialize_inline_component(node, component_name, context, anchor = cont
* Serializes `bind:this` for components and elements.
* @param {Identifier | MemberExpression} expression
* @param {Expression} value
* @param {import('zimmerframe').Context<import('#compiler').SvelteNode, import('../types.js').ComponentClientTransformState>} context
* @param {import('zimmerframe').Context<SvelteNode, ComponentClientTransformState>} context
*/
function serialize_bind_this(expression, value, { state, visit }) {
/** @type {Identifier[]} */
@ -1059,7 +1060,7 @@ function serialize_bind_this(expression, value, { state, visit }) {
}
/**
* @param {import('#shared').SourceLocation[]} locations
* @param {SourceLocation[]} locations
*/
function serialize_locations(locations) {
return b.array(
@ -1077,8 +1078,8 @@ function serialize_locations(locations) {
/**
*
* @param {import('#compiler').Namespace} namespace
* @param {import('../types.js').ComponentClientTransformState} state
* @param {Namespace} namespace
* @param {ComponentClientTransformState} state
* @returns
*/
function get_template_function(namespace, state) {
@ -1116,9 +1117,9 @@ function serialize_render_stmt(update) {
/**
* Serializes the event handler function of the `on:` directive
* @param {Pick<import('#compiler').OnDirective, 'name' | 'modifiers' | 'expression'>} node
* @param {Pick<OnDirective, 'name' | 'modifiers' | 'expression'>} node
* @param {null | { contains_call_expression: boolean; dynamic: boolean; } | null} metadata
* @param {import('../types.js').ComponentContext} context
* @param {ComponentContext} context
*/
function serialize_event_handler(node, metadata, { state, visit }) {
/** @type {Expression} */
@ -1225,9 +1226,9 @@ function serialize_event_handler(node, metadata, { state, visit }) {
/**
* Serializes an event handler function of the `on:` directive or an attribute starting with `on`
* @param {{name: string;modifiers: string[];expression: Expression | null;delegated?: import('#compiler').DelegatedEvent | null;}} node
* @param {{name: string;modifiers: string[];expression: Expression | null;delegated?: DelegatedEvent | null;}} node
* @param {null | { contains_call_expression: boolean; dynamic: boolean; }} metadata
* @param {import('../types.js').ComponentContext} context
* @param {ComponentContext} context
*/
function serialize_event(node, metadata, context) {
const state = context.state;
@ -1312,7 +1313,7 @@ function serialize_event(node, metadata, context) {
);
}
const parent = /** @type {import('#compiler').SvelteNode} */ (context.path.at(-1));
const parent = /** @type {SvelteNode} */ (context.path.at(-1));
const has_action_directive =
parent.type === 'RegularElement' && parent.attributes.find((a) => a.type === 'UseDirective');
const statement = b.stmt(
@ -1332,8 +1333,8 @@ function serialize_event(node, metadata, context) {
}
/**
* @param {import('#compiler').Attribute & { value: import('#compiler').ExpressionTag | [import('#compiler').ExpressionTag] }} node
* @param {import('../types').ComponentContext} context
* @param {Attribute & { value: ExpressionTag | [ExpressionTag] }} node
* @param {ComponentContext} context
*/
function serialize_event_attribute(node, context) {
/** @type {string[]} */
@ -1361,15 +1362,15 @@ function serialize_event_attribute(node, context) {
* Processes an array of template nodes, joining sibling text/expression nodes
* (e.g. `{a} b {c}`) into a single update function. Along the way it creates
* corresponding template node references these updates are applied to.
* @param {import('#compiler').SvelteNode[]} nodes
* @param {SvelteNode[]} nodes
* @param {(is_text: boolean) => Expression} expression
* @param {boolean} is_element
* @param {import('../types.js').ComponentContext} context
* @param {ComponentContext} context
*/
function process_children(nodes, expression, is_element, { visit, state }) {
const within_bound_contenteditable = state.metadata.bound_contenteditable;
/** @typedef {Array<import('#compiler').Text | import('#compiler').ExpressionTag>} Sequence */
/** @typedef {Array<Text | ExpressionTag>} Sequence */
/** @type {Sequence} */
let sequence = [];
@ -1495,7 +1496,7 @@ function process_children(nodes, expression, is_element, { visit, state }) {
/**
* @param {Expression} expression
* @param {import('../types.js').ComponentClientTransformState} state
* @param {ComponentClientTransformState} state
* @param {string} name
*/
function get_node_id(expression, state, name) {
@ -1510,8 +1511,8 @@ function get_node_id(expression, state, name) {
}
/**
* @param {import('#compiler').Attribute['value']} value
* @param {import('../types').ComponentContext} context
* @param {Attribute['value']} value
* @param {ComponentContext} context
* @returns {[contains_call_expression: boolean, Expression]}
*/
function serialize_attribute_value(value, context) {
@ -1536,9 +1537,9 @@ function serialize_attribute_value(value, context) {
}
/**
* @param {Array<import('#compiler').Text | import('#compiler').ExpressionTag>} values
* @param {(node: import('#compiler').SvelteNode, state: any) => any} visit
* @param {import("../types.js").ComponentClientTransformState} state
* @param {Array<Text | ExpressionTag>} values
* @param {(node: SvelteNode, state: any) => any} visit
* @param {ComponentClientTransformState} state
* @returns {[boolean, TemplateLiteral]}
*/
function serialize_template_literal(values, visit, state) {
@ -1598,7 +1599,7 @@ function serialize_template_literal(values, visit, state) {
return [contains_call_expression, b.template(quasis, expressions)];
}
/** @type {import('../types').ComponentVisitors} */
/** @type {ComponentVisitors} */
export const template_visitors = {
Fragment(node, context) {
// Creates a new block which looks roughly like this:
@ -1644,7 +1645,7 @@ export const template_visitors = {
/** @type {Statement | undefined} */
let close = undefined;
/** @type {import('../types').ComponentClientTransformState} */
/** @type {ComponentClientTransformState} */
const state = {
...context.state,
before_init: [],
@ -1692,7 +1693,7 @@ export const template_visitors = {
};
if (is_single_element) {
const element = /** @type {import('#compiler').RegularElement} */ (trimmed[0]);
const element = /** @type {RegularElement} */ (trimmed[0]);
const id = b.id(context.state.scope.generate(element.name));
@ -1967,7 +1968,7 @@ export const template_visitors = {
state.after_update.push(b.stmt(b.call('$.transition', ...args)));
},
RegularElement(node, context) {
/** @type {import('#shared').SourceLocation} */
/** @type {SourceLocation} */
let location = [-1, -1];
if (context.state.options.dev) {
@ -1995,13 +1996,13 @@ export const template_visitors = {
context.state.template.push(`<${node.name}`);
/** @type {Array<import('#compiler').Attribute | import('#compiler').SpreadAttribute>} */
/** @type {Array<Attribute | SpreadAttribute>} */
const attributes = [];
/** @type {import('#compiler').ClassDirective[]} */
/** @type {ClassDirective[]} */
const class_directives = [];
/** @type {import('#compiler').StyleDirective[]} */
/** @type {StyleDirective[]} */
const style_directives = [];
/** @type {ExpressionStatement[]} */
@ -2011,7 +2012,7 @@ export const template_visitors = {
let needs_input_reset = false;
let needs_content_reset = false;
/** @type {import('#compiler').BindDirective | null} */
/** @type {BindDirective | null} */
let value_binding = null;
/** If true, needs `__value` for inputs */
@ -2133,7 +2134,7 @@ export const template_visitors = {
);
is_attributes_reactive = true;
} else {
for (const attribute of /** @type {import('#compiler').Attribute[]} */ (attributes)) {
for (const attribute of /** @type {Attribute[]} */ (attributes)) {
if (is_event_attribute(attribute)) {
if (
(attribute.name === 'onload' || attribute.name === 'onerror') &&
@ -2195,17 +2196,15 @@ export const template_visitors = {
context.state.template.push('>');
/** @type {import('#shared').SourceLocation[]} */
/** @type {SourceLocation[]} */
const child_locations = [];
/** @type {import('../types').ComponentClientTransformState} */
/** @type {ComponentClientTransformState} */
const state = {
...context.state,
metadata: child_metadata,
locations: child_locations,
scope: /** @type {import('../../../scope').Scope} */ (
context.state.scopes.get(node.fragment)
),
scope: /** @type {Scope} */ (context.state.scopes.get(node.fragment)),
preserve_whitespace:
context.state.preserve_whitespace ||
((node.name === 'pre' || node.name === 'textarea') &&
@ -2288,16 +2287,16 @@ export const template_visitors = {
SvelteElement(node, context) {
context.state.template.push(`<!>`);
/** @type {Array<import('#compiler').Attribute | import('#compiler').SpreadAttribute>} */
/** @type {Array<Attribute | SpreadAttribute>} */
const attributes = [];
/** @type {import('#compiler').Attribute['value'] | undefined} */
/** @type {Attribute['value'] | undefined} */
let dynamic_namespace = undefined;
/** @type {import('#compiler').ClassDirective[]} */
/** @type {ClassDirective[]} */
const class_directives = [];
/** @type {import('#compiler').StyleDirective[]} */
/** @type {StyleDirective[]} */
const style_directives = [];
/** @type {ExpressionStatement[]} */
@ -2307,7 +2306,7 @@ export const template_visitors = {
// They'll then be added to the function parameter of $.element
const element_id = b.id(context.state.scope.generate('$$element'));
/** @type {import('../types').ComponentContext} */
/** @type {ComponentContext} */
const inner_context = {
...context,
state: {
@ -2495,7 +2494,7 @@ export const template_visitors = {
/**
* @param {Pattern} expression_for_id
* @returns {import('#compiler').Binding['mutation']}
* @returns {Binding['mutation']}
*/
const create_mutation = (expression_for_id) => {
return (assignment, context) => {
@ -2540,8 +2539,8 @@ export const template_visitors = {
? each_node_meta.index
: b.id(node.index);
const item = each_node_meta.item;
const binding = /** @type {import('#compiler').Binding} */ (context.state.scope.get(item.name));
const getter = (/** @type {import("estree").Identifier} */ id) => {
const binding = /** @type {Binding} */ (context.state.scope.get(item.name));
const getter = (/** @type {Identifier} */ id) => {
const item_with_loc = with_loc(item, id);
return b.call('$.unwrap', item_with_loc);
};
@ -2571,7 +2570,7 @@ export const template_visitors = {
for (const path of paths) {
const name = /** @type {Identifier} */ (path.node).name;
const binding = /** @type {import('#compiler').Binding} */ (context.state.scope.get(name));
const binding = /** @type {Binding} */ (context.state.scope.get(name));
const needs_derived = path.has_default_value; // to ensure that default value is only called once
const fn = b.thunk(
/** @type {Expression} */ (context.visit(path.expression?.(unwrapped), child_state))
@ -2793,7 +2792,7 @@ export const template_visitors = {
for (const path of paths) {
const name = /** @type {Identifier} */ (path.node).name;
const binding = /** @type {import('#compiler').Binding} */ (context.state.scope.get(name));
const binding = /** @type {Binding} */ (context.state.scope.get(name));
const needs_derived = path.has_default_value; // to ensure that default value is only called once
const fn = b.thunk(
/** @type {Expression} */ (
@ -3052,7 +3051,7 @@ export const template_visitors = {
const parent = path.at(-1);
if (parent?.type === 'RegularElement') {
const value = /** @type {any[]} */ (
/** @type {import('#compiler').Attribute} */ (
/** @type {Attribute} */ (
parent.attributes.find(
(a) =>
a.type === 'Attribute' &&
@ -3274,7 +3273,7 @@ export const template_visitors = {
b.assignment(
'=',
b.member(b.id('$.document'), b.id('title')),
b.literal(/** @type {import('#compiler').Text} */ (node.fragment.nodes[0]).data)
b.literal(/** @type {Text} */ (node.fragment.nodes[0]).data)
)
)
);
@ -3313,7 +3312,7 @@ export const template_visitors = {
};
/**
* @param {import('../types.js').ComponentClientTransformState} state
* @param {ComponentClientTransformState} state
* @param {BindDirective} binding
* @param {MemberExpression} expression
*/

@ -1,3 +1,6 @@
/** @import { ComponentContext, ComponentContextLegacy } from '#client' */
/** @import { EventDispatcher } from './index.js' */
/** @import { NotFunction } from './internal/types.js' */
import { current_component_context, flush_sync, untrack } from './internal/client/runtime.js';
import { is_array } from './internal/shared/utils.js';
import { user_effect } from './internal/client/index.js';
@ -15,7 +18,7 @@ import { lifecycle_outside_component } from './internal/shared/errors.js';
*
* https://svelte.dev/docs/svelte#onmount
* @template T
* @param {() => import('./internal/types').NotFunction<T> | Promise<import('./internal/types').NotFunction<T>> | (() => any)} fn
* @param {() => NotFunction<T> | Promise<NotFunction<T>> | (() => any)} fn
* @returns {void}
*/
export function onMount(fn) {
@ -84,7 +87,7 @@ function create_custom_event(type, detail, { bubbles = false, cancelable = false
* https://svelte.dev/docs/svelte#createeventdispatcher
* @deprecated Use callback props and/or the `$host()` rune instead see https://svelte-5-preview.vercel.app/docs/deprecations#createeventdispatcher
* @template {Record<string, any>} [EventMap = any]
* @returns {import('./index.js').EventDispatcher<EventMap>}
* @returns {EventDispatcher<EventMap>}
*/
export function createEventDispatcher() {
const component_context = current_component_context;
@ -164,10 +167,10 @@ export function afterUpdate(fn) {
/**
* Legacy-mode: Init callbacks object for onMount/beforeUpdate/afterUpdate
* @param {import('#client').ComponentContext} context
* @param {ComponentContext} context
*/
function init_update_callbacks(context) {
var l = /** @type {import('#client').ComponentContextLegacy} */ (context).l;
var l = /** @type {ComponentContextLegacy} */ (context).l;
return (l.u ??= { a: [], b: [], m: [] });
}

@ -1,10 +1,11 @@
/** @import { Component } from '#server' */
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) {
var context = /** @type {import('#server').Component} */ (current_component);
var context = /** @type {Component} */ (current_component);
(context.d ??= []).push(fn);
}

@ -1,4 +1,4 @@
/** @import { TemplateNode } from '#client' */
/** @import { EachItem, EachState, Effect, EffectNodes, MaybeSource, Source, TemplateNode, TransitionManager, Value } from '#client' */
import {
EACH_INDEX_REACTIVE,
EACH_IS_ANIMATED,
@ -36,11 +36,11 @@ import { current_effect } from '../../runtime.js';
/**
* The row of a keyed each block that is currently updating. We track this
* so that `animate:` directives have something to attach themselves to
* @type {import('#client').EachItem | null}
* @type {EachItem | null}
*/
export let current_each_item = null;
/** @param {import('#client').EachItem | null} item */
/** @param {EachItem | null} item */
export function set_current_each_item(item) {
current_each_item = item;
}
@ -56,13 +56,13 @@ export function index(_, i) {
/**
* Pause multiple effects simultaneously, and coordinate their
* subsequent destruction. Used in each blocks
* @param {import('#client').EachState} state
* @param {import('#client').EachItem[]} items
* @param {EachState} state
* @param {EachItem[]} items
* @param {null | Node} controlled_anchor
* @param {Map<any, import("#client").EachItem>} items_map
* @param {Map<any, EachItem>} items_map
*/
function pause_effects(state, items, controlled_anchor, items_map) {
/** @type {import('#client').TransitionManager[]} */
/** @type {TransitionManager[]} */
var transitions = [];
var length = items.length;
@ -101,14 +101,14 @@ function pause_effects(state, items, controlled_anchor, items_map) {
* @param {number} flags
* @param {() => V[]} get_collection
* @param {(value: V, index: number) => any} get_key
* @param {(anchor: Node, item: import('#client').MaybeSource<V>, index: import('#client').MaybeSource<number>) => void} render_fn
* @param {(anchor: Node, item: MaybeSource<V>, index: MaybeSource<number>) => void} render_fn
* @param {null | ((anchor: Node) => void)} fallback_fn
* @returns {void}
*/
export function each(node, flags, get_collection, get_key, render_fn, fallback_fn = null) {
var anchor = node;
/** @type {import('#client').EachState} */
/** @type {EachState} */
var state = { flags, items: new Map(), first: null };
var is_controlled = (flags & EACH_IS_CONTROLLED) !== 0;
@ -125,7 +125,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
hydrate_next();
}
/** @type {import('#client').Effect | null} */
/** @type {Effect | null} */
var fallback = null;
block(() => {
@ -174,10 +174,10 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
// this is separate to the previous block because `hydrating` might change
if (hydrating) {
/** @type {import('#client').EachItem | null} */
/** @type {EachItem | null} */
var prev = null;
/** @type {import('#client').EachItem} */
/** @type {EachItem} */
var item;
for (var i = 0; i < length; i++) {
@ -239,9 +239,9 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
/**
* @template V
* @param {Array<V>} array
* @param {import('#client').EachState} state
* @param {EachState} state
* @param {Element | Comment | Text} anchor
* @param {(anchor: Node, item: import('#client').MaybeSource<V>, index: number | import('#client').Source<number>) => void} render_fn
* @param {(anchor: Node, item: MaybeSource<V>, index: number | Source<number>) => void} render_fn
* @param {number} flags
* @param {(value: V, index: number) => any} get_key
* @returns {void}
@ -255,19 +255,19 @@ function reconcile(array, state, anchor, render_fn, flags, get_key) {
var first = state.first;
var current = first;
/** @type {Set<import('#client').EachItem>} */
/** @type {Set<EachItem>} */
var seen = new Set();
/** @type {import('#client').EachItem | null} */
/** @type {EachItem | null} */
var prev = null;
/** @type {Set<import('#client').EachItem>} */
/** @type {Set<EachItem>} */
var to_animate = new Set();
/** @type {import('#client').EachItem[]} */
/** @type {EachItem[]} */
var matched = [];
/** @type {import('#client').EachItem[]} */
/** @type {EachItem[]} */
var stashed = [];
/** @type {V} */
@ -276,7 +276,7 @@ function reconcile(array, state, anchor, render_fn, flags, get_key) {
/** @type {any} */
var key;
/** @type {import('#client').EachItem | undefined} */
/** @type {EachItem | undefined} */
var item;
/** @type {number} */
@ -301,9 +301,7 @@ function reconcile(array, state, anchor, render_fn, flags, get_key) {
item = items.get(key);
if (item === undefined) {
var child_anchor = current
? /** @type {import('#client').EffectNodes} */ (current.e.nodes).start
: anchor;
var child_anchor = current ? /** @type {EffectNodes} */ (current.e.nodes).start : anchor;
prev = create_item(
child_anchor,
@ -436,12 +434,12 @@ function reconcile(array, state, anchor, render_fn, flags, get_key) {
});
}
/** @type {import('#client').Effect} */ (current_effect).first = state.first && state.first.e;
/** @type {import('#client').Effect} */ (current_effect).last = prev && prev.e;
/** @type {Effect} */ (current_effect).first = state.first && state.first.e;
/** @type {Effect} */ (current_effect).last = prev && prev.e;
}
/**
* @param {import('#client').EachItem} item
* @param {EachItem} item
* @param {any} value
* @param {number} index
* @param {number} type
@ -453,7 +451,7 @@ function update_item(item, value, index, type) {
}
if ((type & EACH_INDEX_REACTIVE) !== 0) {
set(/** @type {import('#client').Value<number>} */ (item.i), index);
set(/** @type {Value<number>} */ (item.i), index);
} else {
item.i = index;
}
@ -462,15 +460,15 @@ function update_item(item, value, index, type) {
/**
* @template V
* @param {Node} anchor
* @param {import('#client').EachState} state
* @param {import('#client').EachItem | null} prev
* @param {import('#client').EachItem | null} next
* @param {EachState} state
* @param {EachItem | null} prev
* @param {EachItem | null} next
* @param {V} value
* @param {unknown} key
* @param {number} index
* @param {(anchor: Node, item: V | import('#client').Source<V>, index: number | import('#client').Value<number>) => void} render_fn
* @param {(anchor: Node, item: V | Source<V>, index: number | Value<number>) => void} render_fn
* @param {number} flags
* @returns {import('#client').EachItem}
* @returns {EachItem}
*/
function create_item(anchor, state, prev, next, value, key, index, render_fn, flags) {
var previous_each_item = current_each_item;
@ -482,7 +480,7 @@ function create_item(anchor, state, prev, next, value, key, index, render_fn, fl
var v = reactive ? (mutable ? mutable_source(value) : source(value)) : value;
var i = (flags & EACH_INDEX_REACTIVE) === 0 ? index : source(index);
/** @type {import('#client').EachItem} */
/** @type {EachItem} */
var item = {
i,
v,
@ -519,29 +517,27 @@ function create_item(anchor, state, prev, next, value, key, index, render_fn, fl
}
/**
* @param {import('#client').EachItem} item
* @param {import('#client').EachItem | null} next
* @param {EachItem} item
* @param {EachItem | null} next
* @param {Text | Element | Comment} anchor
*/
function move(item, next, anchor) {
var end = item.next
? /** @type {import('#client').EffectNodes} */ (item.next.e.nodes).start
: anchor;
var end = item.next ? /** @type {EffectNodes} */ (item.next.e.nodes).start : anchor;
var dest = next ? /** @type {import('#client').EffectNodes} */ (next.e.nodes).start : anchor;
var node = /** @type {import('#client').EffectNodes} */ (item.e.nodes).start;
var dest = next ? /** @type {EffectNodes} */ (next.e.nodes).start : anchor;
var node = /** @type {EffectNodes} */ (item.e.nodes).start;
while (node !== end) {
var next_node = /** @type {import('#client').TemplateNode} */ (node.nextSibling);
var next_node = /** @type {TemplateNode} */ (node.nextSibling);
dest.before(node);
node = next_node;
}
}
/**
* @param {import('#client').EachState} state
* @param {import('#client').EachItem | null} prev
* @param {import('#client').EachItem | null} next
* @param {EachState} state
* @param {EachItem | null} prev
* @param {EachItem | null} next
*/
function link(state, prev, next) {
if (prev === null) {

@ -1,4 +1,4 @@
/** @import { TemplateNode } from '#client' */
/** @import { Effect, TemplateNode } from '#client' */
import { EFFECT_TRANSPARENT } from '../../constants.js';
import {
hydrate_next,
@ -14,8 +14,8 @@ import { HYDRATION_START_ELSE } from '../../../../constants.js';
/**
* @param {TemplateNode} node
* @param {() => boolean} get_condition
* @param {(anchor: Node) => import('#client').Dom} consequent_fn
* @param {null | ((anchor: Node) => import('#client').Dom)} [alternate_fn]
* @param {(anchor: Node) => void} consequent_fn
* @param {null | ((anchor: Node) => void)} [alternate_fn]
* @param {boolean} [elseif] True if this is an `{:else if ...}` block rather than an `{#if ...}`, as that affects which transitions are considered 'local'
* @returns {void}
*/
@ -26,10 +26,10 @@ export function if_block(node, get_condition, consequent_fn, alternate_fn = null
var anchor = node;
/** @type {import('#client').Effect | null} */
/** @type {Effect | null} */
var consequent_effect = null;
/** @type {import('#client').Effect | null} */
/** @type {Effect | null} */
var alternate_effect = null;
/** @type {boolean | null} */

@ -1,3 +1,4 @@
/** @import { AnimateFn, Animation, AnimationConfig, EachItem, Effect, Task, TransitionFn, TransitionManager } from '#client' */
import { noop, is_function } from '../../../shared/utils.js';
import { effect } from '../../reactivity/effects.js';
import { current_effect, untrack } from '../../runtime.js';
@ -60,11 +61,11 @@ const linear = (t) => t;
* and attaches it to the block, so that moves can be animated following reconciliation.
* @template P
* @param {Element} element
* @param {() => import('#client').AnimateFn<P | undefined>} get_fn
* @param {() => AnimateFn<P | undefined>} get_fn
* @param {(() => P) | null} get_params
*/
export function animation(element, get_fn, get_params) {
var item = /** @type {import('#client').EachItem} */ (current_each_item);
var item = /** @type {EachItem} */ (current_each_item);
/** @type {DOMRect} */
var from;
@ -72,7 +73,7 @@ export function animation(element, get_fn, get_params) {
/** @type {DOMRect} */
var to;
/** @type {import('#client').Animation | undefined} */
/** @type {Animation | undefined} */
var animation;
/** @type {null | { position: string, width: string, height: string, transform: string }} */
@ -167,7 +168,7 @@ export function animation(element, get_fn, get_params) {
* @template P
* @param {number} flags
* @param {HTMLElement} element
* @param {() => import('#client').TransitionFn<P | undefined>} get_fn
* @param {() => TransitionFn<P | undefined>} get_fn
* @param {(() => P) | null} get_params
* @returns {void}
*/
@ -180,15 +181,15 @@ export function transition(flags, element, get_fn, get_params) {
/** @type {'in' | 'out' | 'both'} */
var direction = is_both ? 'both' : is_intro ? 'in' : 'out';
/** @type {import('#client').AnimationConfig | ((opts: { direction: 'in' | 'out' }) => import('#client').AnimationConfig) | undefined} */
/** @type {AnimationConfig | ((opts: { direction: 'in' | 'out' }) => AnimationConfig) | undefined} */
var current_options;
var inert = element.inert;
/** @type {import('#client').Animation | undefined} */
/** @type {Animation | undefined} */
var intro;
/** @type {import('#client').Animation | undefined} */
/** @type {Animation | undefined} */
var outro;
/** @type {(() => void) | undefined} */
@ -201,7 +202,7 @@ export function transition(flags, element, get_fn, get_params) {
return (current_options ??= get_fn()(element, get_params?.(), { direction }));
}
/** @type {import('#client').TransitionManager} */
/** @type {TransitionManager} */
var transition = {
is_global,
in() {
@ -271,7 +272,7 @@ export function transition(flags, element, get_fn, get_params) {
}
};
var e = /** @type {import('#client').Effect} */ (current_effect);
var e = /** @type {Effect} */ (current_effect);
(e.transitions ??= []).push(transition);
@ -282,7 +283,7 @@ export function transition(flags, element, get_fn, get_params) {
let run = is_global;
if (!run) {
var block = /** @type {import('#client').Effect | null} */ (e.parent);
var block = /** @type {Effect | null} */ (e.parent);
// skip over transparent blocks (e.g. snippets, else-if blocks)
while (block && (block.f & EFFECT_TRANSPARENT) !== 0) {
@ -305,12 +306,12 @@ export function transition(flags, element, get_fn, get_params) {
/**
* Animates an element, according to the provided configuration
* @param {Element} element
* @param {import('#client').AnimationConfig | ((opts: { direction: 'in' | 'out' }) => import('#client').AnimationConfig)} options
* @param {import('#client').Animation | undefined} counterpart The corresponding intro/outro to this outro/intro
* @param {AnimationConfig | ((opts: { direction: 'in' | 'out' }) => AnimationConfig)} options
* @param {Animation | undefined} counterpart The corresponding intro/outro to this outro/intro
* @param {number} t2 The target `t` value `1` for intro, `0` for outro
* @param {(() => void) | undefined} on_finish Called after successfully completing the animation
* @param {(() => void) | undefined} on_abort Called if the animation is aborted
* @returns {import('#client').Animation}
* @returns {Animation}
*/
function animate(element, options, counterpart, t2, on_finish, on_abort) {
var is_intro = t2 === 1;
@ -319,7 +320,7 @@ function animate(element, options, counterpart, t2, on_finish, on_abort) {
// In the case of a deferred transition (such as `crossfade`), `option` will be
// a function rather than an `AnimationConfig`. We need to call this function
// once DOM has been updated...
/** @type {import('#client').Animation} */
/** @type {Animation} */
var a;
queue_micro_task(() => {
@ -358,10 +359,10 @@ function animate(element, options, counterpart, t2, on_finish, on_abort) {
var duration = options.duration * Math.abs(delta);
var end = start + duration;
/** @type {Animation} */
/** @type {globalThis.Animation} */
var animation;
/** @type {import('#client').Task} */
/** @type {Task} */
var task;
if (css) {

@ -1,3 +1,4 @@
/** @import { ProxyMetadata, ProxyStateObject, Source } from '#client' */
import { DEV } from 'esm-env';
import { get, current_component_context, untrack, current_effect } from './runtime.js';
import {
@ -18,9 +19,9 @@ import * as e from './errors.js';
/**
* @template T
* @param {T} value
* @param {import('#client').ProxyMetadata | null} [parent]
* @param {import('#client').Source<T>} [prev] dev mode only
* @returns {import('#client').ProxyStateObject<T> | T}
* @param {ProxyMetadata | null} [parent]
* @param {Source<T>} [prev] dev mode only
* @returns {ProxyStateObject<T> | T}
*/
export function proxy(value, parent = null, prev) {
if (
@ -31,7 +32,7 @@ export function proxy(value, parent = null, prev) {
) {
// If we have an existing proxy, return it...
if (STATE_SYMBOL in value) {
const metadata = /** @type {import('#client').ProxyMetadata<T>} */ (value[STATE_SYMBOL]);
const metadata = /** @type {ProxyMetadata<T>} */ (value[STATE_SYMBOL]);
// ...unless the proxy belonged to a different object, because
// someone copied the state symbol using `Reflect.ownKeys(...)`
@ -53,7 +54,7 @@ export function proxy(value, parent = null, prev) {
const proxy = new Proxy(value, state_proxy_handler);
define_property(value, STATE_SYMBOL, {
value: /** @type {import('#client').ProxyMetadata} */ ({
value: /** @type {ProxyMetadata} */ ({
s: new Map(),
v: source(0),
a: is_array(value),
@ -94,18 +95,18 @@ export function proxy(value, parent = null, prev) {
}
/**
* @param {import('#client').Source<number>} signal
* @param {Source<number>} signal
* @param {1 | -1} [d]
*/
function update_version(signal, d = 1) {
set(signal, signal.v + d);
}
/** @type {ProxyHandler<import('#client').ProxyStateObject<any>>} */
/** @type {ProxyHandler<ProxyStateObject<any>>} */
const state_proxy_handler = {
defineProperty(target, prop, descriptor) {
if (descriptor.value) {
/** @type {import('#client').ProxyMetadata} */
/** @type {ProxyMetadata} */
const metadata = target[STATE_SYMBOL];
const s = metadata.s.get(prop);
@ -116,7 +117,7 @@ const state_proxy_handler = {
},
deleteProperty(target, prop) {
/** @type {import('#client').ProxyMetadata} */
/** @type {ProxyMetadata} */
const metadata = target[STATE_SYMBOL];
const s = metadata.s.get(prop);
const is_array = metadata.a;
@ -149,7 +150,7 @@ const state_proxy_handler = {
return Reflect.get(target, STATE_SYMBOL);
}
/** @type {import('#client').ProxyMetadata} */
/** @type {ProxyMetadata} */
const metadata = target[STATE_SYMBOL];
let s = metadata.s.get(prop);
@ -170,7 +171,7 @@ const state_proxy_handler = {
getOwnPropertyDescriptor(target, prop) {
const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
if (descriptor && 'value' in descriptor) {
/** @type {import('#client').ProxyMetadata} */
/** @type {ProxyMetadata} */
const metadata = target[STATE_SYMBOL];
const s = metadata.s.get(prop);
@ -186,7 +187,7 @@ const state_proxy_handler = {
if (prop === STATE_SYMBOL) {
return true;
}
/** @type {import('#client').ProxyMetadata} */
/** @type {ProxyMetadata} */
const metadata = target[STATE_SYMBOL];
const has = Reflect.has(target, prop);
@ -208,7 +209,7 @@ const state_proxy_handler = {
},
set(target, prop, value, receiver) {
/** @type {import('#client').ProxyMetadata} */
/** @type {ProxyMetadata} */
const metadata = target[STATE_SYMBOL];
let s = metadata.s.get(prop);
// If we haven't yet created a source for this property, we need to ensure
@ -227,7 +228,7 @@ const state_proxy_handler = {
const not_has = !(prop in target);
if (DEV) {
/** @type {import('#client').ProxyMetadata | undefined} */
/** @type {ProxyMetadata | undefined} */
const prop_metadata = value?.[STATE_SYMBOL];
if (prop_metadata && prop_metadata?.parent !== metadata) {
widen_ownership(metadata, prop_metadata);
@ -271,7 +272,7 @@ const state_proxy_handler = {
},
ownKeys(target) {
/** @type {import('#client').ProxyMetadata} */
/** @type {ProxyMetadata} */
const metadata = target[STATE_SYMBOL];
get(metadata.v);

@ -1,3 +1,4 @@
/** @import { Derived } from '#client' */
import { CLEAN, DERIVED, DESTROYED, DIRTY, MAYBE_DIRTY, UNOWNED } from '../constants.js';
import {
current_reaction,
@ -16,14 +17,14 @@ export let updating_derived = false;
/**
* @template V
* @param {() => V} fn
* @returns {import('#client').Derived<V>}
* @returns {Derived<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function derived(fn) {
let flags = DERIVED | DIRTY;
if (current_effect === null) flags |= UNOWNED;
/** @type {import('#client').Derived<V>} */
/** @type {Derived<V>} */
const signal = {
deps: null,
deriveds: null,
@ -38,7 +39,7 @@ export function derived(fn) {
};
if (current_reaction !== null && (current_reaction.f & DERIVED) !== 0) {
var current_derived = /** @type {import('#client').Derived} */ (current_reaction);
var current_derived = /** @type {Derived} */ (current_reaction);
if (current_derived.deriveds === null) {
current_derived.deriveds = [signal];
} else {
@ -52,7 +53,7 @@ export function derived(fn) {
/**
* @template V
* @param {() => V} fn
* @returns {import('#client').Derived<V>}
* @returns {Derived<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function derived_safe_equal(fn) {
@ -62,7 +63,7 @@ export function derived_safe_equal(fn) {
}
/**
* @param {import('#client').Derived} derived
* @param {Derived} derived
* @returns {void}
*/
function destroy_derived_children(derived) {
@ -79,7 +80,7 @@ function destroy_derived_children(derived) {
}
/**
* @param {import('#client').Derived} derived
* @param {Derived} derived
* @returns {void}
*/
export function update_derived(derived) {
@ -103,7 +104,7 @@ export function update_derived(derived) {
}
/**
* @param {import('#client').Derived} signal
* @param {Derived} signal
* @returns {void}
*/
export function destroy_derived(signal) {

@ -1,3 +1,4 @@
/** @import { ComponentContext, ComponentContextLegacy, Effect, Reaction, TemplateNode, TransitionManager } from '#client' */
import {
check_dirtiness,
current_component_context,
@ -57,8 +58,8 @@ export function validate_effect(rune) {
}
/**
* @param {import("#client").Effect} effect
* @param {import("#client").Reaction} parent_effect
* @param {Effect} effect
* @param {Reaction} parent_effect
*/
export function push_effect(effect, parent_effect) {
var parent_last = parent_effect.last;
@ -76,12 +77,12 @@ export function push_effect(effect, parent_effect) {
* @param {null | (() => void | (() => void))} fn
* @param {boolean} sync
* @param {boolean} push
* @returns {import('#client').Effect}
* @returns {Effect}
*/
function create_effect(type, fn, sync, push = true) {
var is_root = (type & ROOT_EFFECT) !== 0;
/** @type {import('#client').Effect} */
/** @type {Effect} */
var effect = {
ctx: current_component_context,
deps: null,
@ -187,7 +188,7 @@ export function user_effect(fn) {
}
if (defer) {
var context = /** @type {import('#client').ComponentContext} */ (current_component_context);
var context = /** @type {ComponentContext} */ (current_component_context);
(context.e ??= []).push(fn);
} else {
var signal = effect(fn);
@ -198,7 +199,7 @@ export function user_effect(fn) {
/**
* Internal representation of `$effect.pre(...)`
* @param {() => void | (() => void)} fn
* @returns {import('#client').Effect}
* @returns {Effect}
*/
export function user_pre_effect(fn) {
validate_effect('$effect.pre');
@ -229,7 +230,7 @@ export function effect_root(fn) {
/**
* @param {() => void | (() => void)} fn
* @returns {import('#client').Effect}
* @returns {Effect}
*/
export function effect(fn) {
return create_effect(EFFECT, fn, false);
@ -241,9 +242,9 @@ export function effect(fn) {
* @param {() => void | (() => void)} fn
*/
export function legacy_pre_effect(deps, fn) {
var context = /** @type {import('#client').ComponentContextLegacy} */ (current_component_context);
var context = /** @type {ComponentContextLegacy} */ (current_component_context);
/** @type {{ effect: null | import('#client').Effect, ran: boolean }} */
/** @type {{ effect: null | Effect, ran: boolean }} */
var token = { effect: null, ran: false };
context.l.r1.push(token);
@ -261,7 +262,7 @@ export function legacy_pre_effect(deps, fn) {
}
export function legacy_pre_effect_reset() {
var context = /** @type {import('#client').ComponentContextLegacy} */ (current_component_context);
var context = /** @type {ComponentContextLegacy} */ (current_component_context);
render_effect(() => {
if (!get(context.l.r2)) return;
@ -283,7 +284,7 @@ export function legacy_pre_effect_reset() {
/**
* @param {() => void | (() => void)} fn
* @returns {import('#client').Effect}
* @returns {Effect}
*/
export function render_effect(fn) {
return create_effect(RENDER_EFFECT, fn, true);
@ -291,7 +292,7 @@ export function render_effect(fn) {
/**
* @param {() => void | (() => void)} fn
* @returns {import('#client').Effect}
* @returns {Effect}
*/
export function template_effect(fn) {
if (DEV) {
@ -319,7 +320,7 @@ export function branch(fn, push = true) {
}
/**
* @param {import("#client").Effect} effect
* @param {Effect} effect
*/
export function execute_effect_teardown(effect) {
var teardown = effect.teardown;
@ -338,7 +339,7 @@ export function execute_effect_teardown(effect) {
}
/**
* @param {import('#client').Effect} effect
* @param {Effect} effect
* @param {boolean} [remove_dom]
* @returns {void}
*/
@ -346,14 +347,13 @@ export function destroy_effect(effect, remove_dom = true) {
var removed = false;
if ((remove_dom || (effect.f & HEAD_EFFECT) !== 0) && effect.nodes !== null) {
/** @type {import('#client').TemplateNode | null} */
/** @type {TemplateNode | null} */
var node = effect.nodes.start;
var end = effect.nodes.end;
while (node !== null) {
/** @type {import('#client').TemplateNode | null} */
var next =
node === end ? null : /** @type {import('#client').TemplateNode} */ (node.nextSibling);
/** @type {TemplateNode | null} */
var next = node === end ? null : /** @type {TemplateNode} */ (node.nextSibling);
node.remove();
node = next;
@ -396,7 +396,7 @@ export function destroy_effect(effect, remove_dom = true) {
/**
* Detach an effect from the effect tree, freeing up memory and
* reducing the amount of work that happens on subsequent traversals
* @param {import('#client').Effect} effect
* @param {Effect} effect
*/
export function unlink_effect(effect) {
var parent = effect.parent;
@ -418,11 +418,11 @@ export function unlink_effect(effect) {
* It stays around (in memory, and in the DOM) until outro transitions have
* completed, and if the state change is reversed then we _resume_ it.
* A paused effect does not update, and the DOM subtree becomes inert.
* @param {import('#client').Effect} effect
* @param {Effect} effect
* @param {() => void} [callback]
*/
export function pause_effect(effect, callback) {
/** @type {import('#client').TransitionManager[]} */
/** @type {TransitionManager[]} */
var transitions = [];
pause_children(effect, transitions, true);
@ -434,7 +434,7 @@ export function pause_effect(effect, callback) {
}
/**
* @param {import('#client').TransitionManager[]} transitions
* @param {TransitionManager[]} transitions
* @param {() => void} fn
*/
export function run_out_transitions(transitions, fn) {
@ -450,8 +450,8 @@ export function run_out_transitions(transitions, fn) {
}
/**
* @param {import('#client').Effect} effect
* @param {import('#client').TransitionManager[]} transitions
* @param {Effect} effect
* @param {TransitionManager[]} transitions
* @param {boolean} local
*/
export function pause_children(effect, transitions, local) {
@ -482,14 +482,14 @@ export function pause_children(effect, transitions, local) {
/**
* The opposite of `pause_effect`. We call this if (for example)
* `x` becomes falsy then truthy: `{#if x}...{/if}`
* @param {import('#client').Effect} effect
* @param {Effect} effect
*/
export function resume_effect(effect) {
resume_children(effect, true);
}
/**
* @param {import('#client').Effect} effect
* @param {Effect} effect
* @param {boolean} local
*/
function resume_children(effect, local) {

@ -1,3 +1,4 @@
/** @import { Derived, Effect, Source, Value } from '#client' */
import { DEV } from 'esm-env';
import {
current_component_context,
@ -31,7 +32,7 @@ let inspect_effects = new Set();
/**
* @template V
* @param {V} v
* @returns {import('#client').Source<V>}
* @returns {Source<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function source(v) {
@ -47,7 +48,7 @@ export function source(v) {
/**
* @template V
* @param {V} initial_value
* @returns {import('#client').Source<V>}
* @returns {Source<V>}
*/
/*#__NO_SIDE_EFFECTS__*/
export function mutable_source(initial_value) {
@ -65,7 +66,7 @@ export function mutable_source(initial_value) {
/**
* @template V
* @param {import('#client').Value<V>} source
* @param {Value<V>} source
* @param {V} value
*/
export function mutate(source, value) {
@ -78,7 +79,7 @@ export function mutate(source, value) {
/**
* @template V
* @param {import('#client').Source<V>} source
* @param {Source<V>} source
* @param {V} value
* @returns {V}
*/
@ -129,7 +130,7 @@ export function set(source, value) {
}
/**
* @param {import('#client').Value} signal
* @param {Value} signal
* @param {number} status should be DIRTY or MAYBE_DIRTY
* @returns {void}
*/
@ -161,9 +162,9 @@ function mark_reactions(signal, status) {
// If the signal a) was previously clean or b) is an unowned derived, then mark it
if ((flags & (CLEAN | UNOWNED)) !== 0) {
if ((flags & DERIVED) !== 0) {
mark_reactions(/** @type {import('#client').Derived} */ (reaction), MAYBE_DIRTY);
mark_reactions(/** @type {Derived} */ (reaction), MAYBE_DIRTY);
} else {
schedule_effect(/** @type {import('#client').Effect} */ (reaction));
schedule_effect(/** @type {Effect} */ (reaction));
}
}
}

@ -1,3 +1,5 @@
/** @import { ComponentContext, Effect, EffectNodes, TemplateNode } from '#client' */
/** @import { Component, ComponentType, SvelteComponent } from '../../index.js' */
import { DEV } from 'esm-env';
import { clear_text_content, empty, init_operations } from './dom/operations.js';
import {
@ -59,7 +61,7 @@ export function set_text(text, value) {
*
* @template {Record<string, any>} Props
* @template {Record<string, any>} Exports
* @param {import('../../index.js').ComponentType<import('../../index.js').SvelteComponent<Props>> | import('../../index.js').Component<Props, Exports, any>} component
* @param {ComponentType<SvelteComponent<Props>> | Component<Props, Exports, any>} component
* @param {{} extends Props ? {
* target: Document | Element | ShadowRoot;
* anchor?: Node;
@ -88,7 +90,7 @@ export function mount(component, options) {
*
* @template {Record<string, any>} Props
* @template {Record<string, any>} Exports
* @param {import('../../index.js').ComponentType<import('../../index.js').SvelteComponent<Props>> | import('../../index.js').Component<Props, Exports, any>} component
* @param {ComponentType<SvelteComponent<Props>> | Component<Props, Exports, any>} component
* @param {{} extends Props ? {
* target: Document | Element | ShadowRoot;
* props?: Props;
@ -115,12 +117,12 @@ export function hydrate(component, options) {
try {
// Don't flush previous effects to ensure order of outer effects stays consistent
return flush_sync(() => {
var anchor = /** @type {import('#client').TemplateNode} */ (target.firstChild);
var anchor = /** @type {TemplateNode} */ (target.firstChild);
while (
anchor &&
(anchor.nodeType !== 8 || /** @type {Comment} */ (anchor).data !== HYDRATION_START)
) {
anchor = /** @type {import('#client').TemplateNode} */ (anchor.nextSibling);
anchor = /** @type {TemplateNode} */ (anchor.nextSibling);
}
if (!anchor) {
@ -141,8 +143,6 @@ export function hydrate(component, options) {
throw HYDRATION_ERROR;
}
// flush_sync will run this callback and then synchronously run any pending effects,
// which don't belong to the hydration phase anymore - therefore reset it here
set_hydrating(false);
return instance;
@ -177,7 +177,7 @@ const document_listeners = new Map();
/**
* @template {Record<string, any>} Exports
* @param {import('../../index.js').ComponentType<import('../../index.js').SvelteComponent<any>> | import('../../index.js').Component<any>} Component
* @param {ComponentType<SvelteComponent<any>> | Component<any>} Component
* @param {{
* target: Document | Element | ShadowRoot;
* anchor: Node;
@ -232,7 +232,7 @@ function _mount(Component, { target, anchor, props = {}, events, context, intro
branch(() => {
if (context) {
push({});
var ctx = /** @type {import('#client').ComponentContext} */ (current_component_context);
var ctx = /** @type {ComponentContext} */ (current_component_context);
ctx.c = context;
}
@ -242,7 +242,7 @@ function _mount(Component, { target, anchor, props = {}, events, context, intro
}
if (hydrating) {
assign_nodes(/** @type {import('#client').TemplateNode} */ (anchor), null);
assign_nodes(/** @type {TemplateNode} */ (anchor), null);
}
should_intro = intro;
@ -251,9 +251,7 @@ function _mount(Component, { target, anchor, props = {}, events, context, intro
should_intro = true;
if (hydrating) {
/** @type {import('#client').Effect & { nodes: import('#client').EffectNodes }} */ (
current_effect
).nodes.end = hydrate_node;
/** @type {Effect & { nodes: EffectNodes }} */ (current_effect).nodes.end = hydrate_node;
}
if (context) {

@ -1,3 +1,4 @@
/** @import { ComponentContext, Derived, Effect, Reaction, Signal, Source, Value } from '#client' */
import { DEV } from 'esm-env';
import { define_property, get_descriptors, get_prototype_of } from '../shared/utils.js';
import {
@ -57,24 +58,24 @@ export function set_is_destroying_effect(value) {
// Handle effect queues
/** @type {import('#client').Effect[]} */
/** @type {Effect[]} */
let current_queued_root_effects = [];
let flush_count = 0;
// Handle signal reactivity tree dependencies and reactions
/** @type {null | import('#client').Reaction} */
/** @type {null | Reaction} */
export let current_reaction = null;
/** @param {null | import('#client').Reaction} reaction */
/** @param {null | Reaction} reaction */
export function set_current_reaction(reaction) {
current_reaction = reaction;
}
/** @type {null | import('#client').Effect} */
/** @type {null | Effect} */
export let current_effect = null;
/** @param {null | import('#client').Effect} effect */
/** @param {null | Effect} effect */
export function set_current_effect(effect) {
current_effect = effect;
}
@ -83,7 +84,7 @@ export function set_current_effect(effect) {
* The dependencies of the reaction that is currently being executed. In many cases,
* the dependencies are unchanged between runs, and so this will be `null` unless
* and until a new dependency is accessed we track this via `skipped_deps`
* @type {null | import('#client').Value[]}
* @type {null | Value[]}
*/
export let new_deps = null;
@ -92,11 +93,11 @@ let skipped_deps = 0;
/**
* Tracks writes that the effect it's executed in doesn't listen to yet,
* so that the dependency can be added to the effect later on if it then reads it
* @type {null | import('#client').Source[]}
* @type {null | Source[]}
*/
export let current_untracked_writes = null;
/** @param {null | import('#client').Source[]} value */
/** @param {null | Source[]} value */
export function set_current_untracked_writes(value) {
current_untracked_writes = value;
}
@ -112,10 +113,10 @@ export let is_signals_recorded = false;
let captured_signals = new Set();
// Handling runtime component context
/** @type {import('#client').ComponentContext | null} */
/** @type {ComponentContext | null} */
export let current_component_context = null;
/** @param {import('#client').ComponentContext | null} context */
/** @param {ComponentContext | null} context */
export function set_current_component_context(context) {
current_component_context = context;
}
@ -128,11 +129,11 @@ export function set_current_component_context(context) {
* <Bar /> <!-- context == Foo.svelte, function == App.svelte -->
* </Foo>
* ```
* @type {import('#client').ComponentContext['function']}
* @type {ComponentContext['function']}
*/
export let dev_current_component_function = null;
/** @param {import('#client').ComponentContext['function']} fn */
/** @param {ComponentContext['function']} fn */
export function set_dev_current_component_function(fn) {
dev_current_component_function = fn;
}
@ -149,7 +150,7 @@ export function is_runes() {
/**
* Determines whether a derived or effect is dirty.
* If it is MAYBE_DIRTY, will set the status to CLEAN
* @param {import('#client').Reaction} reaction
* @param {Reaction} reaction
* @returns {boolean}
*/
export function check_dirtiness(reaction) {
@ -177,8 +178,8 @@ export function check_dirtiness(reaction) {
for (i = 0; i < dependencies.length; i++) {
var dependency = dependencies[i];
if (check_dirtiness(/** @type {import('#client').Derived} */ (dependency))) {
update_derived(/** @type {import('#client').Derived} */ (dependency));
if (check_dirtiness(/** @type {Derived} */ (dependency))) {
update_derived(/** @type {Derived} */ (dependency));
}
if (dependency.version > reaction.version) {
@ -205,8 +206,8 @@ export function check_dirtiness(reaction) {
/**
* @param {Error} error
* @param {import("#client").Effect} effect
* @param {import("#client").ComponentContext | null} component_context
* @param {Effect} effect
* @param {ComponentContext | null} component_context
*/
function handle_error(error, effect, component_context) {
// Given we don't yet have error boundaries, we will just always throw.
@ -222,7 +223,7 @@ function handle_error(error, effect, component_context) {
component_stack.push(effect_name);
}
/** @type {import("#client").ComponentContext | null} */
/** @type {ComponentContext | null} */
let current_context = component_context;
while (current_context !== null) {
@ -266,7 +267,7 @@ function handle_error(error, effect, component_context) {
/**
* @template V
* @param {import('#client').Reaction} reaction
* @param {Reaction} reaction
* @returns {V}
*/
export function update_reaction(reaction) {
@ -276,7 +277,7 @@ export function update_reaction(reaction) {
var previous_reaction = current_reaction;
var previous_skip_reaction = current_skip_reaction;
new_deps = /** @type {null | import('#client').Value[]} */ (null);
new_deps = /** @type {null | Value[]} */ (null);
skipped_deps = 0;
current_untracked_writes = null;
current_reaction = (reaction.f & (BRANCH_EFFECT | ROOT_EFFECT)) === 0 ? reaction : null;
@ -349,8 +350,8 @@ export function update_reaction(reaction) {
/**
* @template V
* @param {import('#client').Reaction} signal
* @param {import('#client').Value<V>} dependency
* @param {Reaction} signal
* @param {Value<V>} dependency
* @returns {void}
*/
function remove_reaction(signal, dependency) {
@ -378,12 +379,12 @@ function remove_reaction(signal, dependency) {
if ((dependency.f & (UNOWNED | DISCONNECTED)) === 0) {
dependency.f ^= DISCONNECTED;
}
remove_reactions(/** @type {import('#client').Derived} **/ (dependency), 0);
remove_reactions(/** @type {Derived} **/ (dependency), 0);
}
}
/**
* @param {import('#client').Reaction} signal
* @param {Reaction} signal
* @param {number} start_index
* @returns {void}
*/
@ -408,7 +409,7 @@ export function remove_reactions(signal, start_index) {
}
/**
* @param {import('#client').Reaction} signal
* @param {Reaction} signal
* @param {boolean} remove_dom
* @returns {void}
*/
@ -424,7 +425,7 @@ export function destroy_effect_children(signal, remove_dom = false) {
}
/**
* @param {import('#client').Effect} effect
* @param {Effect} effect
* @returns {void}
*/
export function update_effect(effect) {
@ -480,7 +481,7 @@ function infinite_loop_guard() {
}
/**
* @param {Array<import('#client').Effect>} root_effects
* @param {Array<Effect>} root_effects
* @returns {void}
*/
function flush_queued_root_effects(root_effects) {
@ -501,7 +502,7 @@ function flush_queued_root_effects(root_effects) {
if (effect.first === null && (effect.f & BRANCH_EFFECT) === 0) {
flush_queued_effects([effect]);
} else {
/** @type {import('#client').Effect[]} */
/** @type {Effect[]} */
var collected_effects = [];
process_effects(effect, collected_effects);
@ -514,7 +515,7 @@ function flush_queued_root_effects(root_effects) {
}
/**
* @param {Array<import('#client').Effect>} effects
* @param {Array<Effect>} effects
* @returns {void}
*/
function flush_queued_effects(effects) {
@ -559,7 +560,7 @@ function process_deferred() {
}
/**
* @param {import('#client').Effect} signal
* @param {Effect} signal
* @returns {void}
*/
export function schedule_effect(signal) {
@ -592,8 +593,8 @@ export function schedule_effect(signal) {
* bitwise flag passed in only. The collected effects array will be populated with all the user
* effects to be flushed.
*
* @param {import('#client').Effect} effect
* @param {import('#client').Effect[]} collected_effects
* @param {Effect} effect
* @param {Effect[]} collected_effects
* @returns {void}
*/
function process_effects(effect, collected_effects) {
@ -680,7 +681,7 @@ export function flush_sync(fn, flush_previous = true) {
try {
infinite_loop_guard();
/** @type {import('#client').Effect[]} */
/** @type {Effect[]} */
const root_effects = [];
current_scheduler_mode = FLUSH_SYNC;
@ -720,7 +721,7 @@ export async function tick() {
/**
* @template V
* @param {import('#client').Value<V>} signal
* @param {Value<V>} signal
* @returns {V}
*/
export function get(signal) {
@ -768,7 +769,7 @@ export function get(signal) {
}
if ((flags & DERIVED) !== 0) {
var derived = /** @type {import('#client').Derived} */ (signal);
var derived = /** @type {Derived} */ (signal);
if (check_dirtiness(derived)) {
update_derived(derived);
@ -804,7 +805,7 @@ export function invalidate_inner_signals(fn) {
for (signal of captured) {
// Go one level up because derived signals created as part of props in legacy mode
if ((signal.f & LEGACY_DERIVED_PROP) !== 0) {
for (const dep of /** @type {import('#client').Derived} */ (signal).deps || []) {
for (const dep of /** @type {Derived} */ (signal).deps || []) {
if ((dep.f & DERIVED) === 0) {
mutate(dep, null /* doesnt matter */);
}
@ -836,7 +837,7 @@ export function untrack(fn) {
const STATUS_MASK = ~(DIRTY | MAYBE_DIRTY | CLEAN);
/**
* @param {import('#client').Signal} signal
* @param {Signal} signal
* @param {number} status
* @returns {void}
*/
@ -846,14 +847,12 @@ export function set_signal_status(signal, status) {
/**
* @template V
* @param {V | import('#client').Value<V>} val
* @returns {val is import('#client').Value<V>}
* @param {V | Value<V>} val
* @returns {val is Value<V>}
*/
export function is_signal(val) {
return (
typeof val === 'object' &&
val !== null &&
typeof (/** @type {import('#client').Value<V>} */ (val).f) === 'number'
typeof val === 'object' && val !== null && typeof (/** @type {Value<V>} */ (val).f) === 'number'
);
}
@ -871,8 +870,7 @@ export function getContext(key) {
const result = /** @type {T} */ (context_map.get(key));
if (DEV) {
const fn = /** @type {import('#client').ComponentContext} */ (current_component_context)
.function;
const fn = /** @type {ComponentContext} */ (current_component_context).function;
if (fn) {
add_owner(result, fn, true);
}
@ -952,7 +950,7 @@ function get_or_init_context_map(name) {
}
/**
* @param {import('#client').ComponentContext} component_context
* @param {ComponentContext} component_context
* @returns {Map<unknown, unknown> | null}
*/
function get_parent_context(component_context) {
@ -968,7 +966,7 @@ function get_parent_context(component_context) {
}
/**
* @param {import('#client').Value<number>} signal
* @param {Value<number>} signal
* @param {1 | -1} [d]
* @returns {number}
*/
@ -979,7 +977,7 @@ export function update(signal, d = 1) {
}
/**
* @param {import('#client').Value<number>} signal
* @param {Value<number>} signal
* @param {1 | -1} [d]
* @returns {number}
*/
@ -1159,7 +1157,7 @@ export function deep_read(value, visited = new Set()) {
/**
* @template V
* @param {V | import('#client').Value<V>} value
* @param {V | Value<V>} value
* @returns {V}
*/
export function unwrap(value) {

@ -1,3 +1,4 @@
/** @import { Component, Payload } from '#server' */
import {
FILENAME,
disallowed_paragraph_contents,
@ -33,7 +34,7 @@ function stringify(element) {
}
/**
* @param {import('#server').Payload} payload
* @param {Payload} payload
* @param {Element} parent
* @param {Element} child
*/
@ -51,13 +52,13 @@ function print_error(payload, parent, child) {
}
/**
* @param {import('#server').Payload} payload
* @param {Payload} payload
* @param {string} tag
* @param {number} line
* @param {number} column
*/
export function push_element(payload, tag, line, column) {
var filename = /** @type {import('#server').Component} */ (current_component).function[FILENAME];
var filename = /** @type {Component} */ (current_component).function[FILENAME];
var child = { tag, parent, filename, line, column };
if (parent !== null && !is_tag_valid_with_parent(tag, parent.tag)) {

@ -1,3 +1,4 @@
/** @import { ComponentType, SvelteComponent } from 'svelte' */
/** @import { Component, Payload, RenderOutput } from '#server' */
/** @import { Store } from '#shared' */
export { FILENAME, HMR } from '../../constants.js';
@ -103,7 +104,7 @@ export let on_destroy = [];
* Only available on the server and when compiling with the `server` option.
* Takes a component and returns an object with `body` and `head` properties on it, which you can use to populate the HTML when server-rendering your app.
* @template {Record<string, any>} Props
* @param {import('svelte').Component<Props> | import('svelte').ComponentType<import('svelte').SvelteComponent<Props>>} component
* @param {import('svelte').Component<Props> | ComponentType<SvelteComponent<Props>>} component
* @param {{ props?: Omit<Props, '$$slots' | '$$events'>; context?: Map<any, any> }} [options]
* @returns {RenderOutput}
*/

@ -1,3 +1,6 @@
/** @import { Task } from '#client' */
/** @import { SpringOpts, SpringUpdateOpts, TickContext } from './private.js' */
/** @import { Spring } from './public.js' */
import { writable } from '../store/index.js';
import { loop } from '../internal/client/loop.js';
import { raf } from '../internal/client/timing.js';
@ -5,7 +8,7 @@ import { is_date } from './utils.js';
/**
* @template T
* @param {import('./private').TickContext<T>} ctx
* @param {TickContext<T>} ctx
* @param {T} last_value
* @param {T} current_value
* @param {T} target_value
@ -53,15 +56,15 @@ function tick_spring(ctx, last_value, current_value, target_value) {
* https://svelte.dev/docs/svelte-motion#spring
* @template [T=any]
* @param {T} [value]
* @param {import('./private').SpringOpts} [opts]
* @returns {import('./public.js').Spring<T>}
* @param {SpringOpts} [opts]
* @returns {Spring<T>}
*/
export function spring(value, opts = {}) {
const store = writable(value);
const { stiffness = 0.15, damping = 0.8, precision = 0.01 } = opts;
/** @type {number} */
let last_time;
/** @type {import('../internal/client/types').Task | null} */
/** @type {Task | null} */
let task;
/** @type {object} */
let current_token;
@ -74,7 +77,7 @@ export function spring(value, opts = {}) {
let cancel_task = false;
/**
* @param {T} new_value
* @param {import('./private').SpringUpdateOpts} opts
* @param {SpringUpdateOpts} opts
* @returns {Promise<void>}
*/
function set(new_value, opts = {}) {
@ -101,7 +104,7 @@ export function spring(value, opts = {}) {
return false;
}
inv_mass = Math.min(inv_mass + inv_mass_recovery_rate, 1);
/** @type {import('./private').TickContext<T>} */
/** @type {TickContext<T>} */
const ctx = {
inv_mass,
opts: spring,
@ -120,12 +123,12 @@ export function spring(value, opts = {}) {
});
}
return new Promise((fulfil) => {
/** @type {import('../internal/client/types').Task} */ (task).promise.then(() => {
/** @type {Task} */ (task).promise.then(() => {
if (token === current_token) fulfil();
});
});
}
/** @type {import('./public.js').Spring<T>} */
/** @type {Spring<T>} */
const spring = {
set,
update: (fn, opts) => set(fn(/** @type {T} */ (target_value), /** @type {T} */ (value)), opts),

@ -1,3 +1,4 @@
/** @import { Source } from '#client' */
import { DEV } from 'esm-env';
import { source, set } from '../internal/client/reactivity/sources.js';
import { get } from '../internal/client/runtime.js';
@ -9,7 +10,7 @@ import { increment } from './utils.js';
* @extends {Map<K, V>}
*/
export class SvelteMap extends Map {
/** @type {Map<K, import('#client').Source<number>>} */
/** @type {Map<K, Source<number>>} */
#sources = new Map();
#version = source(0);
#size = source(0);

@ -1,3 +1,4 @@
/** @import { Source } from '#client' */
import { DEV } from 'esm-env';
import { source, set } from '../internal/client/reactivity/sources.js';
import { get } from '../internal/client/runtime.js';
@ -13,7 +14,7 @@ var inited = false;
* @extends {Set<T>}
*/
export class SvelteSet extends Set {
/** @type {Map<T, import('#client').Source<boolean>>} */
/** @type {Map<T, Source<boolean>>} */
#sources = new Map();
#version = source(0);
#size = source(0);

@ -1,3 +1,4 @@
/** @import { Source } from '#client' */
import { set } from '../internal/client/reactivity/sources.js';
/**
@ -30,7 +31,7 @@ function get_this() {
return this;
}
/** @param {import('#client').Source<number>} source */
/** @param {Source<number>} source */
export function increment(source) {
set(source, source.v + 1);
}

@ -1,6 +1,8 @@
<!-- valid -->
<link />
<svg><g /></svg>
<enhanced:img />
<!-- invalid -->
<div />

@ -3,11 +3,11 @@
"code": "element_invalid_self_closing_tag",
"message": "Self-closing HTML tags for non-void elements are ambiguous — use `<div ...></div>` rather than `<div ... />`",
"start": {
"line": 6,
"line": 8,
"column": 0
},
"end": {
"line": 6,
"line": 8,
"column": 7
}
},
@ -15,11 +15,11 @@
"code": "element_invalid_self_closing_tag",
"message": "Self-closing HTML tags for non-void elements are ambiguous — use `<my-thing ...></my-thing>` rather than `<my-thing ... />`",
"start": {
"line": 7,
"line": 9,
"column": 0
},
"end": {
"line": 7,
"line": 9,
"column": 12
}
}

@ -373,8 +373,6 @@ declare module 'svelte' {
* Synchronously flushes any pending state changes and those that result from it.
* */
export function flushSync(fn?: (() => void) | undefined): void;
/** Anything except a function */
type NotFunction<T> = T extends Function ? never : T;
/**
* Create a snippet programmatically
* */
@ -382,6 +380,8 @@ declare module 'svelte' {
render: () => string;
setup?: (element: Element) => void;
}): Snippet<Params>;
/** Anything except a function */
type NotFunction<T> = T extends Function ? never : T;
/**
* Mounts a component to the given target and returns the exports and potentially the props (if compiled with `accessors: true`) of the component.
* Transitions will play during the initial render unless the `intro` option is set to `false`.

Loading…
Cancel
Save