pull/16060/head
ComputerGuy 4 months ago
parent b5fcd112c6
commit 26173de279

@ -128,12 +128,17 @@ export function VariableDeclaration(node, context) {
const binding = /** @type {import('#compiler').Binding} */ ( const binding = /** @type {import('#compiler').Binding} */ (
context.state.scope.get(id.name) context.state.scope.get(id.name)
); );
if (rune === '$state' && should_proxy(value, context.state.scope)) { const is_state = is_state_source(binding, context.state.analysis);
value = b.call('$.proxy', value); const is_proxy = should_proxy(value, context.state.scope);
if (rune === '$state' && is_proxy) {
value = b.call('$.proxy', value, dev ? b.literal(id.name) : undefined);
} }
if (is_state_source(binding, context.state.analysis)) { if (is_state) {
value = b.call('$.state', value); value = b.call('$.state', value);
} }
if (dev && is_state) {
value = b.call('$.tag_source', value, b.literal(id.name));
}
return value; return value;
}; };
@ -154,7 +159,11 @@ export function VariableDeclaration(node, context) {
context.state.transform[id.name] = { read: get_value }; context.state.transform[id.name] = { read: get_value };
const expression = /** @type {Expression} */ (context.visit(b.thunk(value))); const expression = /** @type {Expression} */ (context.visit(b.thunk(value)));
return b.declarator(id, b.call('$.derived', expression)); const call = b.call('$.derived', expression);
return b.declarator(
id,
dev ? b.call('$.tag_source', call, b.literal(id.name)) : call
);
}), }),
...paths.map((path) => { ...paths.map((path) => {
const value = /** @type {Expression} */ (context.visit(path.expression)); const value = /** @type {Expression} */ (context.visit(path.expression));
@ -176,8 +185,13 @@ export function VariableDeclaration(node, context) {
if (declarator.id.type === 'Identifier') { if (declarator.id.type === 'Identifier') {
let expression = /** @type {Expression} */ (context.visit(value)); let expression = /** @type {Expression} */ (context.visit(value));
if (rune === '$derived') expression = b.thunk(expression); if (rune === '$derived') expression = b.thunk(expression);
const call = b.call('$.derived', expression);
declarations.push(b.declarator(declarator.id, b.call('$.derived', expression))); declarations.push(
b.declarator(
declarator.id,
dev ? b.call('$.tag_source', call, b.literal(declarator.id.name)) : call
)
);
} else { } else {
const init = /** @type {CallExpression} */ (declarator.init); const init = /** @type {CallExpression} */ (declarator.init);
@ -205,7 +219,19 @@ export function VariableDeclaration(node, context) {
for (const path of paths) { for (const path of paths) {
const expression = /** @type {Expression} */ (context.visit(path.expression)); const expression = /** @type {Expression} */ (context.visit(path.expression));
declarations.push(b.declarator(path.node, b.call('$.derived', b.thunk(expression)))); const call = b.call('$.derived', b.thunk(expression));
declarations.push(
b.declarator(
path.node,
dev
? b.call(
'$.tag_source',
call,
b.literal(/** @type {Identifier} */ (path.node).name)
)
: call
)
);
} }
} }

@ -25,3 +25,4 @@ export const EFFECT_IS_UPDATING = 1 << 21;
export const STATE_SYMBOL = Symbol('$state'); export const STATE_SYMBOL = Symbol('$state');
export const LEGACY_PROPS = Symbol('legacy props'); export const LEGACY_PROPS = Symbol('legacy props');
export const LOADING_ATTR_SYMBOL = Symbol(''); export const LOADING_ATTR_SYMBOL = Symbol('');
export const PROXY_PATH_SYMBOL = Symbol('proxy path');

@ -43,11 +43,14 @@ function log_entry(signal, entry) {
const type = (signal.f & DERIVED) !== 0 ? '$derived' : '$state'; const type = (signal.f & DERIVED) !== 0 ? '$derived' : '$state';
const current_reaction = /** @type {Reaction} */ (active_reaction); const current_reaction = /** @type {Reaction} */ (active_reaction);
const dirty = signal.wv > current_reaction.wv || current_reaction.wv === 0; const dirty = signal.wv > current_reaction.wv || current_reaction.wv === 0;
const { trace_name: name } = signal;
const style = dirty
? 'color: CornflowerBlue; font-weight: bold'
: 'color: grey; font-weight: bold';
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.groupCollapsed( console.groupCollapsed(
`%c${type}`, typeof name === 'string' ? `%c${name}${type}` : `%c${type}`,
dirty ? 'color: CornflowerBlue; font-weight: bold' : 'color: grey; font-weight: bold', style,
typeof value === 'object' && value !== null && STATE_SYMBOL in value typeof value === 'object' && value !== null && STATE_SYMBOL in value
? snapshot(value, true) ? snapshot(value, true)
: value : value
@ -92,11 +95,9 @@ export function trace(label, fn) {
var previously_tracing_expressions = tracing_expressions; var previously_tracing_expressions = tracing_expressions;
try { try {
tracing_expressions = { entries: new Map(), reaction: active_reaction }; tracing_expressions = { entries: new Map(), reaction: active_reaction };
var start = performance.now(); var start = performance.now();
var value = fn(); var value = fn();
var time = (performance.now() - start).toFixed(2); var time = (performance.now() - start).toFixed(2);
if (!effect_tracking()) { if (!effect_tracking()) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.log(`${label()} %cran outside of an effect (${time}ms)`, 'color: grey'); console.log(`${label()} %cran outside of an effect (${time}ms)`, 'color: grey');
@ -177,3 +178,12 @@ export function get_stack(label) {
} }
return error; return error;
} }
/**
* @param {Value} source
* @param {string} name
*/
export function tag_source(source, name) {
source.trace_name = name;
return source;
}

@ -7,7 +7,7 @@ export { add_locations } from './dev/elements.js';
export { hmr } from './dev/hmr.js'; export { hmr } from './dev/hmr.js';
export { create_ownership_validator } from './dev/ownership.js'; export { create_ownership_validator } from './dev/ownership.js';
export { check_target, legacy_api } from './dev/legacy.js'; export { check_target, legacy_api } from './dev/legacy.js';
export { trace } from './dev/tracing.js'; export { trace, tag_source } from './dev/tracing.js';
export { inspect } from './dev/inspect.js'; export { inspect } from './dev/inspect.js';
export { validate_snippet_args } from './dev/validation.js'; export { validate_snippet_args } from './dev/validation.js';
export { await_block as await } from './dom/blocks/await.js'; export { await_block as await } from './dom/blocks/await.js';

@ -12,15 +12,16 @@ import { state as source, set } from './reactivity/sources.js';
import { STATE_SYMBOL } from '#client/constants'; import { STATE_SYMBOL } from '#client/constants';
import { UNINITIALIZED } from '../../constants.js'; import { UNINITIALIZED } from '../../constants.js';
import * as e from './errors.js'; import * as e from './errors.js';
import { get_stack } from './dev/tracing.js'; import { get_stack, tag_source } from './dev/tracing.js';
import { tracing_mode_flag } from '../flags/index.js'; import { tracing_mode_flag } from '../flags/index.js';
/** /**
* @template T * @template T
* @param {T} value * @param {T} value
* @param {string} [path]
* @returns {T} * @returns {T}
*/ */
export function proxy(value) { export function proxy(value, path) {
// if non-proxyable, or is already a proxy, return `value` // if non-proxyable, or is already a proxy, return `value`
if (typeof value !== 'object' || value === null || STATE_SYMBOL in value) { if (typeof value !== 'object' || value === null || STATE_SYMBOL in value) {
return value; return value;
@ -39,6 +40,16 @@ export function proxy(value) {
var stack = DEV && tracing_mode_flag ? get_stack('CreatedAt') : null; var stack = DEV && tracing_mode_flag ? get_stack('CreatedAt') : null;
var reaction = active_reaction; var reaction = active_reaction;
/** @type {(prop: any) => any} */
var to_trace_name = DEV
? (prop) => {
return typeof prop === 'symbol'
? `${path}[unique symbol]`
: typeof prop === 'number' || Number(prop) === Number(prop)
? `${path}[${prop}]`
: `${path}.${prop}`;
}
: (prop) => undefined;
/** /**
* @template T * @template T
@ -58,7 +69,8 @@ export function proxy(value) {
if (is_proxied_array) { if (is_proxied_array) {
// We need to create the length source eagerly to ensure that // We need to create the length source eagerly to ensure that
// mutations to the array are properly synced with our proxy // mutations to the array are properly synced with our proxy
sources.set('length', source(/** @type {any[]} */ (value).length, stack)); const length_source = source(/** @type {any[]} */ (value).length, stack);
sources.set('length', DEV ? tag_source(length_source, to_trace_name('length')) : length_source);
} }
return new Proxy(/** @type {any} */ (value), { return new Proxy(/** @type {any} */ (value), {
@ -80,11 +92,12 @@ export function proxy(value) {
if (s === undefined) { if (s === undefined) {
s = with_parent(() => source(descriptor.value, stack)); s = with_parent(() => source(descriptor.value, stack));
s = DEV && typeof prop === 'string' ? tag_source(s, to_trace_name(prop)) : s;
sources.set(prop, s); sources.set(prop, s);
} else { } else {
set( set(
s, s,
with_parent(() => proxy(descriptor.value)) with_parent(() => proxy(descriptor.value, to_trace_name(prop)))
); );
} }
@ -96,9 +109,10 @@ export function proxy(value) {
if (s === undefined) { if (s === undefined) {
if (prop in target) { if (prop in target) {
const s = with_parent(() => source(UNINITIALIZED, stack));
sources.set( sources.set(
prop, prop,
with_parent(() => source(UNINITIALIZED, stack)) DEV && typeof prop === 'string' ? tag_source(s, to_trace_name(prop)) : s
); );
update_version(version); update_version(version);
} }
@ -130,7 +144,10 @@ export function proxy(value) {
// create a source, but only if it's an own property and not a prototype property // 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)) { if (s === undefined && (!exists || get_descriptor(target, prop)?.writable)) {
s = with_parent(() => source(proxy(exists ? target[prop] : UNINITIALIZED), stack)); s = with_parent(() =>
source(proxy(exists ? target[prop] : UNINITIALIZED, to_trace_name(prop)), stack)
);
s = DEV && typeof prop === 'string' ? tag_source(s, to_trace_name(prop)) : s;
sources.set(prop, s); sources.set(prop, s);
} }
@ -178,7 +195,10 @@ export function proxy(value) {
(active_effect !== null && (!has || get_descriptor(target, prop)?.writable)) (active_effect !== null && (!has || get_descriptor(target, prop)?.writable))
) { ) {
if (s === undefined) { if (s === undefined) {
s = with_parent(() => source(has ? proxy(target[prop]) : UNINITIALIZED, stack)); s = with_parent(() =>
source(has ? proxy(target[prop], to_trace_name(prop)) : UNINITIALIZED, stack)
);
s = DEV && typeof prop === 'string' ? tag_source(s, to_trace_name(prop)) : s;
sources.set(prop, s); sources.set(prop, s);
} }
@ -206,6 +226,7 @@ export function proxy(value) {
// else a later read of the property would result in a source being created with // else a later read of the property would result in a source being created with
// the value of the original item at that index. // the value of the original item at that index.
other_s = with_parent(() => source(UNINITIALIZED, stack)); other_s = with_parent(() => source(UNINITIALIZED, stack));
other_s = DEV ? tag_source(other_s, to_trace_name(i)) : other_s;
sources.set(i + '', other_s); sources.set(i + '', other_s);
} }
} }
@ -218,9 +239,10 @@ export function proxy(value) {
if (s === undefined) { if (s === undefined) {
if (!has || get_descriptor(target, prop)?.writable) { if (!has || get_descriptor(target, prop)?.writable) {
s = with_parent(() => source(undefined, stack)); s = with_parent(() => source(undefined, stack));
s = DEV && typeof prop === 'string' ? tag_source(s, to_trace_name(prop)) : s;
set( set(
s, s,
with_parent(() => proxy(value)) with_parent(() => proxy(value, to_trace_name(prop)))
); );
sources.set(prop, s); sources.set(prop, s);
} }
@ -228,7 +250,7 @@ export function proxy(value) {
has = s.v !== UNINITIALIZED; has = s.v !== UNINITIALIZED;
set( set(
s, s,
with_parent(() => proxy(value)) with_parent(() => proxy(value, to_trace_name(prop)))
); );
} }

@ -139,7 +139,7 @@ export function set(source, value, should_proxy = false) {
e.state_unsafe_mutation(); e.state_unsafe_mutation();
} }
let new_value = should_proxy ? proxy(value) : value; let new_value = should_proxy ? proxy(value, DEV ? source.trace_name : undefined) : value;
return internal_set(source, new_value); return internal_set(source, new_value);
} }

@ -21,6 +21,7 @@ export interface Value<V = unknown> extends Signal {
updated?: Error | null; updated?: Error | null;
trace_need_increase?: boolean; trace_need_increase?: boolean;
trace_v?: V; trace_v?: V;
trace_name?: string;
debug?: null | (() => void); debug?: null | (() => void);
} }

Loading…
Cancel
Save