diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js index 05efd22e5f..5ca9adb98b 100644 --- a/packages/svelte/src/compiler/migrate/index.js +++ b/packages/svelte/src/compiler/migrate/index.js @@ -18,7 +18,7 @@ import { import { migrate_svelte_ignore } from '../utils/extract_svelte_ignore.js'; import { validate_component_options } from '../validate-options.js'; import { is_reserved, is_svg, is_void } from '../../utils.js'; -import { regex_is_valid_identifier } from '../../regexes.js'; +import { regex_is_valid_identifier } from '../phases/patterns.js'; const regex_style_tags = /(]+>)([\S\s]*?)(<\/style>)/g; const style_placeholder = '/*$$__STYLE_CONTENT__$$*/'; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js index f22838a3f1..da3e164ad8 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js @@ -89,7 +89,11 @@ export function VariableDeclaration(node, context) { binding.kind === 'bindable_prop' && should_proxy(initial, context.state.scope) ) { - initial = b.call('$.proxy', initial, dev && b.literal(id.name)); + initial = b.call('$.proxy', initial); + + if (dev) { + initial = b.call('$.tag_proxy', initial, b.literal(id.name)); + } } if (is_prop_source(binding, context.state)) { @@ -132,7 +136,11 @@ export function VariableDeclaration(node, context) { const is_proxy = should_proxy(value, context.state.scope); if (rune === '$state' && is_proxy) { - value = b.call('$.proxy', value, dev && b.literal(id.name)); + value = b.call('$.proxy', value); + + if (dev) { + value = b.call('$.tag_proxy', value, b.literal(id.name)); + } } if (is_state) { diff --git a/packages/svelte/src/internal/client/dev/tracing.js b/packages/svelte/src/internal/client/dev/tracing.js index e424ebed6a..1506b023b1 100644 --- a/packages/svelte/src/internal/client/dev/tracing.js +++ b/packages/svelte/src/internal/client/dev/tracing.js @@ -2,7 +2,7 @@ import { UNINITIALIZED } from '../../../constants.js'; import { snapshot } from '../../shared/clone.js'; import { define_property } from '../../shared/utils.js'; -import { DERIVED, STATE_SYMBOL } from '#client/constants'; +import { DERIVED, PROXY_PATH_SYMBOL, STATE_SYMBOL } from '#client/constants'; import { effect_tracking } from '../reactivity/effects.js'; import { active_reaction, captured_signals, set_captured_signals, untrack } from '../runtime.js'; @@ -190,6 +190,16 @@ export function tag(source, name) { return source; } +/** + * @param {unknown} value + * @param {string} label + */ +export function tag_proxy(value, label) { + // @ts-expect-error + value?.[PROXY_PATH_SYMBOL]?.(label); + return value; +} + /** * @param {unknown} value */ diff --git a/packages/svelte/src/internal/client/index.js b/packages/svelte/src/internal/client/index.js index 8e4d36d44d..60f9af9120 100644 --- a/packages/svelte/src/internal/client/index.js +++ b/packages/svelte/src/internal/client/index.js @@ -7,7 +7,7 @@ export { add_locations } from './dev/elements.js'; export { hmr } from './dev/hmr.js'; export { create_ownership_validator } from './dev/ownership.js'; export { check_target, legacy_api } from './dev/legacy.js'; -export { trace, tag } from './dev/tracing.js'; +export { trace, tag, tag_proxy } from './dev/tracing.js'; export { inspect } from './dev/inspect.js'; export { validate_snippet_args } from './dev/validation.js'; export { await_block as await } from './dom/blocks/await.js'; diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js index a9d2eedc1c..bf4340ce30 100644 --- a/packages/svelte/src/internal/client/proxy.js +++ b/packages/svelte/src/internal/client/proxy.js @@ -12,7 +12,7 @@ import { state as source, set } from './reactivity/sources.js'; import { PROXY_PATH_SYMBOL, STATE_SYMBOL } from '#client/constants'; import { UNINITIALIZED } from '../../constants.js'; import * as e from './errors.js'; -import { get_stack, tag } from './dev/tracing.js'; +import { get_stack, tag, tag_proxy } from './dev/tracing.js'; import { tracing_mode_flag } from '../flags/index.js'; // TODO move all regexes into shared module? @@ -21,10 +21,9 @@ const regex_is_valid_identifier = /^[a-zA-Z_$][a-zA-Z_$0-9]*$/; /** * @template T * @param {T} value - * @param {string} [path] * @returns {T} */ -export function proxy(value, path) { +export function proxy(value) { // if non-proxyable, or is already a proxy, return `value` if (typeof value !== 'object' || value === null || STATE_SYMBOL in value) { return value; @@ -39,7 +38,7 @@ export function proxy(value, path) { /** @type {Map>} */ var sources = new Map(); var is_proxied_array = is_array(value); - var version = DEV ? tag(source(0), `${path} version`) : source(0); + var version = source(0); var stack = DEV && tracing_mode_flag ? get_stack('CreatedAt') : null; var reaction = active_reaction; @@ -62,10 +61,12 @@ export function proxy(value, path) { if (is_proxied_array) { // We need to create the length source eagerly to ensure that // mutations to the array are properly synced with our proxy - const length_source = source(/** @type {any[]} */ (value).length, stack); - sources.set('length', DEV ? tag(length_source, to_trace_name('length')) : length_source); + sources.set('length', source(/** @type {any[]} */ (value).length, stack)); } + /** Used in dev for $inspect.trace() */ + var path = ''; + /** @param {string | symbol} prop */ function to_trace_name(prop) { if (typeof prop === 'symbol') return `${path}[Symbol(${prop.description ?? ''})]`; @@ -84,7 +85,7 @@ export function proxy(value, path) { var label = to_trace_name(prop); tag(source, label); - source.v?.[PROXY_PATH_SYMBOL]?.(label); + tag_proxy(source.v, label); } } @@ -107,13 +108,18 @@ export function proxy(value, path) { if (s === undefined) { s = with_parent(() => source(descriptor.value, stack)); - s = DEV && typeof prop === 'string' ? tag(s, to_trace_name(prop)) : s; sources.set(prop, s); + + if (DEV && typeof prop === 'string') { + tag(s, to_trace_name(prop)); + } } else { - set( - s, - with_parent(() => proxy(descriptor.value, to_trace_name(prop))) - ); + var p = with_parent(() => proxy(descriptor.value)); + set(s, p); + + if (DEV) { + tag_proxy(p, to_trace_name(prop)); + } } return true; @@ -125,8 +131,12 @@ export function proxy(value, path) { if (s === undefined) { if (prop in target) { const s = with_parent(() => source(UNINITIALIZED, stack)); - sources.set(prop, DEV ? tag(s, to_trace_name(prop)) : s); + sources.set(prop, s); update_version(version); + + if (DEV) { + tag(s, to_trace_name(prop)); + } } } else { // When working with arrays, we need to also ensure we update the length when removing @@ -160,10 +170,19 @@ export function proxy(value, path) { // create a source, but only if it's an own property and not a prototype property if (s === undefined && (!exists || get_descriptor(target, prop)?.writable)) { - s = with_parent(() => - source(proxy(exists ? target[prop] : UNINITIALIZED, to_trace_name(prop)), stack) - ); - s = DEV ? tag(s, to_trace_name(prop)) : s; + s = with_parent(() => { + var p = proxy(exists ? target[prop] : UNINITIALIZED); + var s = source(p, stack); + + if (DEV) { + var label = to_trace_name(prop); + tag(s, label); + tag_proxy(p, label); + } + + return s; + }); + sources.set(prop, s); } @@ -211,10 +230,19 @@ export function proxy(value, path) { (active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) ) { if (s === undefined) { - s = with_parent(() => - source(has ? proxy(target[prop], to_trace_name(prop)) : UNINITIALIZED, stack) - ); - s = DEV ? tag(s, to_trace_name(prop)) : s; + s = with_parent(() => { + var p = has ? proxy(target[prop]) : UNINITIALIZED; + var s = source(p, stack); + + if (DEV) { + var label = to_trace_name(prop); + tag(s, label); + tag_proxy(p, label); + } + + return s; + }); + sources.set(prop, s); } @@ -255,12 +283,12 @@ export function proxy(value, path) { if (s === undefined) { if (!has || get_descriptor(target, prop)?.writable) { s = with_parent(() => source(undefined, stack)); - var p = with_parent(() => proxy(value, to_trace_name(prop))); + var p = with_parent(() => proxy(value)); if (DEV) { var label = to_trace_name(prop); tag(s, label); - p?.[PROXY_PATH_SYMBOL]?.(label); + tag_proxy(p, label); } set(s, p); @@ -269,11 +297,10 @@ export function proxy(value, path) { } else { has = s.v !== UNINITIALIZED; - p = with_parent(() => proxy(value, to_trace_name(prop))); + p = with_parent(() => proxy(value)); if (DEV) { - label = to_trace_name(prop); - p?.[PROXY_PATH_SYMBOL]?.(label); + tag_proxy(p, to_trace_name(prop)); } set(s, p);