+1
-1
@@ -5,3 +5,3 @@ { | ||
| "license": "MIT", | ||
| "version": "5.56.0", | ||
| "version": "5.56.1", | ||
| "type": "module", | ||
@@ -8,0 +8,0 @@ "types": "./types/index.d.ts", |
@@ -8,3 +8,2 @@ /** @import { Comment, Program, Statement } from 'estree' */ | ||
| import * as e from '../../errors.js'; | ||
| import { find_matching_bracket } from './utils/bracket.js'; | ||
@@ -110,34 +109,22 @@ const JSParser = acorn.Parser; | ||
| export function parse_statement_at(parser, source, index) { | ||
| const acorn = parser.ts ? TSParser : JSParser; | ||
| let end = find_matching_bracket(source, index, '{'); | ||
| if (end === undefined) e.unexpected_eof(source.length); | ||
| // cast to `any`: acorn's Parser constructor and parseStatement/nextToken aren't in its public types | ||
| const acorn = /** @type {any} */ (parser.ts ? TSParser : JSParser); | ||
| const { onComment, add_comments } = get_comment_handlers(source, parser.root.comments, index); | ||
| while (source[end - 1] === ';') { | ||
| end -= 1; | ||
| } | ||
| const padded_source = `${' '.repeat(index)}${source.slice(index, end)}`; | ||
| const { onComment, add_comments } = get_comment_handlers( | ||
| padded_source, | ||
| parser.root.comments, | ||
| index | ||
| ); | ||
| try { | ||
| const ast = acorn.parse(padded_source, { | ||
| onComment, | ||
| sourceType: 'module', | ||
| ecmaVersion: 16, | ||
| locations: true | ||
| }); | ||
| add_comments(ast); | ||
| const statement = /** @type {Statement} */ ( | ||
| /** @type {unknown} */ (/** @type {Program} */ (ast).body[0]) | ||
| // This is like parseExpressionAt but for statements | ||
| const p = new acorn( | ||
| { onComment, sourceType: 'module', ecmaVersion: 16, locations: true }, | ||
| source, | ||
| index | ||
| ); | ||
| statement.end = Math.min(/** @type {number} */ (statement.end), end); | ||
| p.nextToken(); | ||
| const statement = /** @type {Statement} */ (p.parseStatement(null, true, Object.create(null))); | ||
| add_comments(/** @type {acorn.Node} */ (statement)); | ||
| return statement; | ||
| } catch (e) { | ||
| handle_parse_error(e); | ||
| } catch (err) { | ||
| // A statement that runs to the end of the source (e.g. an unterminated declaration tag) | ||
| // is an EOF, not a stray token; preserve the friendlier `unexpected_eof` diagnostic. | ||
| if (/** @type {any} */ (err).pos === source.length) e.unexpected_eof(source.length); | ||
| handle_parse_error(err); | ||
| } | ||
@@ -144,0 +131,0 @@ } |
@@ -15,5 +15,5 @@ /** @import { ArrowFunctionExpression, Expression, Identifier, Pattern, VariableDeclaration } from 'estree' */ | ||
| const regex_supported_declaration = /(?:let|const)\b/y; | ||
| // All except `type` are reserved keywords and cannot be used as variable names. | ||
| // For type we check if it's not something like `type .x` / `type ()` / `type % 2` / ... | ||
| const regex_unsupported_declaration = /(?:(?:var|interface|enum)\b)|(?:type\s+[^?.(`<[&|%^}])/y; | ||
| const regex_unsupported_declaration = /(?:var|interface|enum)\b/y; | ||
| // `type` is a contextual keyword; this is just a shape hint, confirmed by parsing. | ||
| const regex_maybe_type_declaration = /type\b/y; | ||
@@ -81,6 +81,13 @@ const pointy_bois = { '<': '>' }; | ||
| if (!parser.match_regex(regex_supported_declaration)) { | ||
| if ( | ||
| !parser.match_regex(regex_supported_declaration) && | ||
| // `type` is special, since it is not a reserved keyword and can be used | ||
| // as part of a valid expression. We gotta parse first and then see what it is. | ||
| !parser.match_regex(regex_maybe_type_declaration) | ||
| ) { | ||
| return null; | ||
| } | ||
| const initial_comment_count = parser.root.comments.length; | ||
| /** @type {import('estree').Statement | import('estree').VariableDeclaration} */ | ||
@@ -122,6 +129,12 @@ let declaration; | ||
| if (declaration.type !== 'VariableDeclaration') { | ||
| e.declaration_tag_invalid_type({ | ||
| start: declaration.start ?? start, | ||
| end: declaration.end ?? parser.index | ||
| }); | ||
| if (declaration.type === 'ExpressionStatement') { | ||
| parser.root.comments.length = initial_comment_count; // Else they show up duplicated | ||
| return null; | ||
| } else { | ||
| // This is a TSTypeAliasDeclaration | ||
| e.declaration_tag_invalid_type({ | ||
| start: declaration.start ?? start, | ||
| end: declaration.end ?? parser.index | ||
| }); | ||
| } | ||
| } | ||
@@ -128,0 +141,0 @@ |
@@ -42,3 +42,5 @@ /** @import { Parser } from '../index.js' */ | ||
| function find_regex_end(string, search_start_index) { | ||
| return find_unescaped_char(string, search_start_index, '/'); | ||
| const slash = find_unescaped_char(string, search_start_index, '/'); | ||
| const eol = find_unescaped_char(string, search_start_index, '\n'); | ||
| return slash < eol ? slash : Infinity; | ||
| } | ||
@@ -109,3 +111,7 @@ | ||
| const next_char = template[i + 1]; | ||
| if (!next_char) continue; | ||
| if (!next_char) { | ||
| // `/` is the last character; advance past it so we don't loop forever | ||
| i++; | ||
| continue; | ||
| } | ||
| if (next_char === '/') { | ||
@@ -119,3 +125,8 @@ i = infinity_if_negative(template.indexOf('\n', i + 1)) + '\n'.length; | ||
| } | ||
| i = find_regex_end(template, i + 1) + '/'.length; | ||
| const end = find_regex_end(template, i + 1) + '/'.length; | ||
| if (end === Infinity) { | ||
| i++; | ||
| } else { | ||
| i = end; | ||
| } | ||
| continue; | ||
@@ -122,0 +133,0 @@ } |
@@ -5,3 +5,3 @@ /** @import { AST } from '#compiler' */ | ||
| import * as e from '../../../errors.js'; | ||
| import { validate_opening_tag } from './shared/utils.js'; | ||
| import { extract_identifiers } from '../../../utils/ast.js'; | ||
@@ -13,3 +13,2 @@ /** | ||
| export function DeclarationTag(node, context) { | ||
| validate_opening_tag(node, context.state, node.declaration.kind[0]); | ||
| if (!context.state.analysis.runes && !context.state.analysis.maybe_runes) { | ||
@@ -19,5 +18,19 @@ e.declaration_tag_no_legacy_mode(node); | ||
| const is_top_level = context.path.length === 1 && context.path[0].type === 'Fragment'; | ||
| if (is_top_level) { | ||
| const duplicate = node.declaration.declarations | ||
| .flatMap((declaration) => extract_identifiers(declaration.id)) | ||
| .find((id) => context.state.analysis.instance.scope.declarations.has(id.name)); | ||
| if (duplicate) { | ||
| e.declaration_duplicate(duplicate, duplicate.name); | ||
| } | ||
| } | ||
| context.visit(node.declaration, { | ||
| ...context.state, | ||
| in_declaration_tag: true, | ||
| // the declaration lives in the fragment scope, which is one level deeper than the | ||
| // `function_depth` we're tracking here (`set_scope` doesn't update `function_depth`). | ||
| // align them so that `state_referenced_locally` warnings are calculated correctly | ||
| function_depth: context.state.scope.function_depth, | ||
| expression: node.metadata.expression | ||
@@ -24,0 +37,0 @@ }); |
@@ -28,16 +28,21 @@ /** @import { AST, Binding } from '#compiler' */ | ||
| const can_hoist = | ||
| context.path.length === 1 && | ||
| context.path[0].type === 'Fragment' && | ||
| can_hoist_snippet(context.state.scope, context.state.scopes); | ||
| const is_top_level = context.path.length === 1 && context.path[0].type === 'Fragment'; | ||
| const name = node.expression.name; | ||
| if (is_top_level) { | ||
| const name = node.expression.name; | ||
| if (can_hoist) { | ||
| const binding = /** @type {Binding} */ (context.state.scope.get(name)); | ||
| context.state.analysis.module.scope.declarations.set(name, binding); | ||
| if (context.state.analysis.instance.scope.declarations.has(name)) { | ||
| e.declaration_duplicate(node.expression, name); | ||
| } | ||
| node.metadata.can_hoist = | ||
| is_top_level && can_hoist_snippet(context.state.scope, context.state.scopes); | ||
| if (node.metadata.can_hoist) { | ||
| const name = node.expression.name; | ||
| const binding = /** @type {Binding} */ (context.state.scope.get(name)); | ||
| context.state.analysis.module.scope.declarations.set(name, binding); | ||
| } | ||
| } | ||
| node.metadata.can_hoist = can_hoist; | ||
| const { path } = context; | ||
@@ -44,0 +49,0 @@ const parent = path.at(-2); |
@@ -13,4 +13,6 @@ /** @import { Expression, Identifier, Pattern, Statement, ExpressionStatement, VariableDeclaration } from 'estree' */ | ||
| export function DeclarationTag(node, context) { | ||
| // register the transformers _before_ visiting the declaration, so that | ||
| // later declarators can reference earlier ones (e.g. `{let a = $state(0), b = $derived(a * 2)}`) | ||
| add_state_transformers(context); | ||
| const declaration = /** @type {Statement | undefined} */ (context.visit(node.declaration)); | ||
| add_state_transformers(context); | ||
@@ -17,0 +19,0 @@ if ( |
@@ -346,3 +346,3 @@ /** @import { Expression, Identifier, Node, Statement, BlockStatement, ArrayExpression } from 'estree' */ | ||
| check_blockers(metadata) { | ||
| for (const binding of metadata.dependencies) { | ||
| for (const binding of metadata.references) { | ||
| if (binding.blocker) { | ||
@@ -349,0 +349,0 @@ this.#blockers.add(binding.blocker); |
@@ -206,3 +206,5 @@ /** @import { EachItem, EachOutroGroup, EachState, Effect, EffectNodes, MaybeSource, Source, TemplateNode, TransitionManager, Value } from '#client' */ | ||
| return is_array(collection) ? collection : collection == null ? [] : array_from(collection); | ||
| return /** @type {V[]} */ ( | ||
| is_array(collection) ? collection : collection == null ? [] : array_from(collection) | ||
| ); | ||
| }); | ||
@@ -209,0 +211,0 @@ |
@@ -335,2 +335,11 @@ /** @import { Blocker, Effect } from '#client' */ | ||
| if (element.nodeName === INPUT_TAG && 'type' in next && ('value' in next || '__value' in next)) { | ||
| var type = next.type; | ||
| if (type !== current.type || (type === undefined && element.hasAttribute('type'))) { | ||
| current.type = type; | ||
| set_attribute(element, 'type', type, skip_warning); | ||
| } | ||
| } | ||
| // since key is captured we use const | ||
@@ -337,0 +346,0 @@ for (const key in next) { |
@@ -10,3 +10,2 @@ /** @import { Batch } from '../../../reactivity/batch.js' */ | ||
| import { tick, untrack } from '../../../runtime.js'; | ||
| import { is_runes } from '../../../context.js'; | ||
| import { current_batch, previous_batch } from '../../../reactivity/batch.js'; | ||
@@ -13,0 +12,0 @@ import { async_mode_flag } from '../../../../flags/index.js'; |
@@ -1,2 +0,2 @@ | ||
| /** @import { Blocker, Effect, Value } from '#client' */ | ||
| /** @import { Blocker, Effect, Source, Value } from '#client' */ | ||
| import { DESTROYED, STALE_REACTION } from '#client/constants'; | ||
@@ -41,4 +41,18 @@ import { DEV } from 'esm-env'; | ||
| var deriveds = sync.map(d); | ||
| if (DEV) { | ||
| deriveds.forEach((d, i) => { | ||
| // TODO this is kinda useful for debugging but a lousy implementation — | ||
| // maybe the compiler could pass through the template string | ||
| d.label = sync[i] | ||
| .toString() | ||
| .replace('() => ', '') | ||
| .replaceAll('$.eager(() => ', '$state.eager(') | ||
| .replace(/\$\.get\((.+?)\)/g, (_, id) => id); | ||
| }); | ||
| } | ||
| if (async.length === 0 && pending.length === 0) { | ||
| fn(sync.map(d)); | ||
| fn(deriveds); | ||
| return; | ||
@@ -57,4 +71,6 @@ } | ||
| /** @param {Value[]} values */ | ||
| function finish(values) { | ||
| /** | ||
| * @param {Source[]} async | ||
| */ | ||
| function finish(async) { | ||
| if ((parent.f & DESTROYED) !== 0) { | ||
@@ -67,3 +83,3 @@ return; | ||
| try { | ||
| fn(values); | ||
| fn([...deriveds, ...async]); | ||
| } catch (error) { | ||
@@ -80,6 +96,3 @@ invoke_error_boundary(error, parent); | ||
| if (async.length === 0) { | ||
| /** @type {Promise<any>} */ (blocker_promise) | ||
| .then(() => finish(sync.map(d))) | ||
| .finally(decrement_pending); | ||
| /** @type {Promise<any>} */ (blocker_promise).then(() => finish([])).finally(decrement_pending); | ||
| return; | ||
@@ -91,3 +104,3 @@ } | ||
| Promise.all(async.map((expression) => async_derived(expression))) | ||
| .then((result) => finish([...sync.map(d), ...result])) | ||
| .then(finish) | ||
| .catch((error) => invoke_error_boundary(error, parent)) | ||
@@ -94,0 +107,0 @@ .finally(decrement_pending); |
@@ -390,3 +390,5 @@ /** @import { Blocker, ComponentContext, ComponentContextLegacy, Derived, Effect, TemplateNode, TransitionManager } from '#client' */ | ||
| flatten(blockers, sync, async, (values) => { | ||
| create_effect(RENDER_EFFECT, () => fn(...values.map(get))); | ||
| create_effect(RENDER_EFFECT, () => { | ||
| fn(...values.map(get)); | ||
| }); | ||
| }); | ||
@@ -522,3 +524,3 @@ } | ||
| set_signal_status(effect, DESTROYING); | ||
| effect.f |= DESTROYING; | ||
| destroy_effect_children(effect, remove_dom && !removed); | ||
@@ -525,0 +527,0 @@ remove_reactions(effect, 0); |
@@ -135,7 +135,8 @@ import { DEV } from 'esm-env'; | ||
| set(name, value) { | ||
| var previous = super.getAll(name).join(''); | ||
| var previous = super.getAll(name); | ||
| super.set(name, value); | ||
| // can't use has(name, value), because for something like https://svelte.dev?foo=1&bar=2&foo=3 | ||
| // if you set `foo` to 1, then foo=3 gets deleted whilst `has("foo", "1")` returns true | ||
| if (previous !== super.getAll(name).join('')) { | ||
| var current = super.getAll(name); | ||
| if (previous.length !== current.length || previous.some((value, i) => value !== current[i])) { | ||
| this.#update_url(); | ||
@@ -142,0 +143,0 @@ increment(this.#version); |
+1
-1
@@ -7,3 +7,3 @@ // generated during release, do not modify | ||
| */ | ||
| export const VERSION = '5.56.0'; | ||
| export const VERSION = '5.56.1'; | ||
| export const PUBLIC_VERSION = '5'; |
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
2865981
0.1%64009
0.09%