Skip to content

Commit 91272d7

Browse files
feat: add source name logging to $inspect.trace (#16060)
* init * improve symbol logging * doh * remove proxy path name when reassigned to a source * try this * fix * oops * fix * "unown" proxy when in another source declaration * fix * tag proxy version * proxy bindable props * tag iterables used in destructuring * add changeset, fix failing tests * add comments, minor tweak * lint * somehow forgot to add support for class fields * more class fields * tag_source -> tag, since it applies to deriveds as well * private class fields * this condition is impossible * explicit type narrowing lets us avoid coercion * simplify * unused * tweak * oops, never meant to commit that * minor tweaks * fix private field tagging, only get `declaration` once * fix state declarations in constructors * fix * tag `svelte/reactivity`, `svelte/motion` sources in DEV * try fixing lint * fix intellisense formatting * actually fix lint * replace tag_if_necessary with conditional tagging * avoid [[object Object]] in labels * remove PROXY_REMOVE_PATH * simplify a bit * simplify * tweak * tweak implementation * tweak implementation * tweak implementation * hoist * tweak * fix * WIP (reduce number of with_parent calls, move towards possibility of combining tag and tag_proxy) * DRY out * tweak labels * remove PROXY_REMOVE_PATH (#16126) * remove PROXY_REMOVE_PATH * simplify a bit * simplify * tweak * tweak implementation * tweak implementation * tweak implementation * hoist * tweak * fix * WIP (reduce number of with_parent calls, move towards possibility of combining tag and tag_proxy) * DRY out * come on this was just lazy * fix tests --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 17629a6 commit 91272d7

File tree

23 files changed

+409
-152
lines changed

23 files changed

+409
-152
lines changed

.changeset/big-teachers-agree.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': minor
3+
---
4+
5+
feat: add source name logging to `$inspect.trace`

packages/svelte/src/compiler/phases/3-transform/client/visitors/AssignmentExpression.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,20 @@ function build_assignment(operator, left, right, context) {
6767
in_constructor: rune !== '$derived' && rune !== '$derived.by'
6868
};
6969

70-
return b.assignment(
71-
operator,
72-
b.member(b.this, field.key),
73-
/** @type {Expression} */ (context.visit(right, child_state))
74-
);
70+
let value = /** @type {Expression} */ (context.visit(right, child_state));
71+
72+
if (dev) {
73+
const declaration = context.path.findLast(
74+
(parent) => parent.type === 'ClassDeclaration' || parent.type === 'ClassExpression'
75+
);
76+
value = b.call(
77+
'$.tag',
78+
value,
79+
b.literal(`${declaration?.id?.name ?? '[class]'}.${name}`)
80+
);
81+
}
82+
83+
return b.assignment(operator, b.member(b.this, field.key), value);
7584
}
7685
}
7786

packages/svelte/src/compiler/phases/3-transform/client/visitors/ClassBody.js

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
/** @import { CallExpression, ClassBody, MethodDefinition, PropertyDefinition, StaticBlock } from 'estree' */
1+
/** @import { CallExpression, ClassBody, ClassDeclaration, ClassExpression, MethodDefinition, PropertyDefinition, StaticBlock } from 'estree' */
22
/** @import { StateField } from '#compiler' */
33
/** @import { Context } from '../types' */
44
import * as b from '#compiler/builders';
5+
import { dev } from '../../../../state.js';
6+
import { get_parent } from '../../../../utils/ast.js';
57
import { get_name } from '../../../nodes.js';
68

79
/**
@@ -50,6 +52,10 @@ export function ClassBody(node, context) {
5052
}
5153
}
5254

55+
const declaration = /** @type {ClassDeclaration | ClassExpression} */ (
56+
get_parent(context.path, -1)
57+
);
58+
5359
// Replace parts of the class body
5460
for (const definition of node.body) {
5561
if (definition.type !== 'PropertyDefinition') {
@@ -68,17 +74,26 @@ export function ClassBody(node, context) {
6874
}
6975

7076
if (name[0] === '#') {
71-
body.push(/** @type {PropertyDefinition} */ (context.visit(definition, child_state)));
77+
let value = definition.value
78+
? /** @type {CallExpression} */ (context.visit(definition.value, child_state))
79+
: undefined;
80+
81+
if (dev) {
82+
value = b.call('$.tag', value, b.literal(`${declaration.id?.name ?? '[class]'}.${name}`));
83+
}
84+
85+
body.push(b.prop_def(definition.key, value));
7286
} else if (field.node === definition) {
73-
const member = b.member(b.this, field.key);
87+
let call = /** @type {CallExpression} */ (context.visit(field.value, child_state));
7488

89+
if (dev) {
90+
call = b.call('$.tag', call, b.literal(`${declaration.id?.name ?? '[class]'}.${name}`));
91+
}
92+
const member = b.member(b.this, field.key);
7593
const should_proxy = field.type === '$state' && true; // TODO
7694

7795
body.push(
78-
b.prop_def(
79-
field.key,
80-
/** @type {CallExpression} */ (context.visit(field.value, child_state))
81-
),
96+
b.prop_def(field.key, call),
8297

8398
b.method('get', definition.key, [], [b.return(b.call('$.get', member))]),
8499

packages/svelte/src/compiler/phases/3-transform/client/visitors/VariableDeclaration.js

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ export function VariableDeclaration(node, context) {
9090
should_proxy(initial, context.state.scope)
9191
) {
9292
initial = b.call('$.proxy', initial);
93+
94+
if (dev) {
95+
initial = b.call('$.tag_proxy', initial, b.literal(id.name));
96+
}
9397
}
9498

9599
if (is_prop_source(binding, context.state)) {
@@ -128,12 +132,25 @@ export function VariableDeclaration(node, context) {
128132
const binding = /** @type {import('#compiler').Binding} */ (
129133
context.state.scope.get(id.name)
130134
);
131-
if (rune === '$state' && should_proxy(value, context.state.scope)) {
135+
const is_state = is_state_source(binding, context.state.analysis);
136+
const is_proxy = should_proxy(value, context.state.scope);
137+
138+
if (rune === '$state' && is_proxy) {
132139
value = b.call('$.proxy', value);
140+
141+
if (dev && !is_state) {
142+
value = b.call('$.tag_proxy', value, b.literal(id.name));
143+
}
133144
}
134-
if (is_state_source(binding, context.state.analysis)) {
145+
146+
if (is_state) {
135147
value = b.call('$.state', value);
148+
149+
if (dev) {
150+
value = b.call('$.tag', value, b.literal(id.name));
151+
}
136152
}
153+
137154
return value;
138155
};
139156

@@ -154,7 +171,11 @@ export function VariableDeclaration(node, context) {
154171
context.state.transform[id.name] = { read: get_value };
155172

156173
const expression = /** @type {Expression} */ (context.visit(b.thunk(value)));
157-
return b.declarator(id, b.call('$.derived', expression));
174+
const call = b.call('$.derived', expression);
175+
return b.declarator(
176+
id,
177+
dev ? b.call('$.tag', call, b.literal('[$state iterable]')) : call
178+
);
158179
}),
159180
...paths.map((path) => {
160181
const value = /** @type {Expression} */ (context.visit(path.expression));
@@ -176,8 +197,13 @@ export function VariableDeclaration(node, context) {
176197
if (declarator.id.type === 'Identifier') {
177198
let expression = /** @type {Expression} */ (context.visit(value));
178199
if (rune === '$derived') expression = b.thunk(expression);
179-
180-
declarations.push(b.declarator(declarator.id, b.call('$.derived', expression)));
200+
const call = b.call('$.derived', expression);
201+
declarations.push(
202+
b.declarator(
203+
declarator.id,
204+
dev ? b.call('$.tag', call, b.literal(declarator.id.name)) : call
205+
)
206+
);
181207
} else {
182208
const init = /** @type {CallExpression} */ (declarator.init);
183209

@@ -189,8 +215,10 @@ export function VariableDeclaration(node, context) {
189215

190216
let expression = /** @type {Expression} */ (context.visit(value));
191217
if (rune === '$derived') expression = b.thunk(expression);
192-
193-
declarations.push(b.declarator(id, b.call('$.derived', expression)));
218+
const call = b.call('$.derived', expression);
219+
declarations.push(
220+
b.declarator(id, dev ? b.call('$.tag', call, b.literal('[$derived iterable]')) : call)
221+
);
194222
}
195223

196224
const { inserts, paths } = extract_paths(declarator.id, rhs);
@@ -200,12 +228,23 @@ export function VariableDeclaration(node, context) {
200228
context.state.transform[id.name] = { read: get_value };
201229

202230
const expression = /** @type {Expression} */ (context.visit(b.thunk(value)));
203-
declarations.push(b.declarator(id, b.call('$.derived', expression)));
231+
const call = b.call('$.derived', expression);
232+
declarations.push(
233+
b.declarator(id, dev ? b.call('$.tag', call, b.literal('[$derived iterable]')) : call)
234+
);
204235
}
205236

206237
for (const path of paths) {
207238
const expression = /** @type {Expression} */ (context.visit(path.expression));
208-
declarations.push(b.declarator(path.node, b.call('$.derived', b.thunk(expression))));
239+
const call = b.call('$.derived', b.thunk(expression));
240+
declarations.push(
241+
b.declarator(
242+
path.node,
243+
dev
244+
? b.call('$.tag', call, b.literal(/** @type {Identifier} */ (path.node).name))
245+
: call
246+
)
247+
);
209248
}
210249
}
211250

packages/svelte/src/internal/client/constants.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ export const EFFECT_IS_UPDATING = 1 << 21;
2525
export const STATE_SYMBOL = Symbol('$state');
2626
export const LEGACY_PROPS = Symbol('legacy props');
2727
export const LOADING_ATTR_SYMBOL = Symbol('');
28+
export const PROXY_PATH_SYMBOL = Symbol('proxy path');

packages/svelte/src/internal/client/dev/tracing.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { UNINITIALIZED } from '../../../constants.js';
33
import { snapshot } from '../../shared/clone.js';
44
import { define_property } from '../../shared/utils.js';
5-
import { DERIVED, STATE_SYMBOL } from '#client/constants';
5+
import { DERIVED, PROXY_PATH_SYMBOL, STATE_SYMBOL } from '#client/constants';
66
import { effect_tracking } from '../reactivity/effects.js';
77
import { active_reaction, captured_signals, set_captured_signals, untrack } from '../runtime.js';
88

@@ -43,11 +43,15 @@ function log_entry(signal, entry) {
4343
const type = (signal.f & DERIVED) !== 0 ? '$derived' : '$state';
4444
const current_reaction = /** @type {Reaction} */ (active_reaction);
4545
const dirty = signal.wv > current_reaction.wv || current_reaction.wv === 0;
46+
const style = dirty
47+
? 'color: CornflowerBlue; font-weight: bold'
48+
: 'color: grey; font-weight: normal';
4649

4750
// eslint-disable-next-line no-console
4851
console.groupCollapsed(
49-
`%c${type}`,
50-
dirty ? 'color: CornflowerBlue; font-weight: bold' : 'color: grey; font-weight: bold',
52+
signal.label ? `%c${type}%c ${signal.label}` : `%c${type}%c`,
53+
style,
54+
dirty ? 'font-weight: normal' : style,
5155
typeof value === 'object' && value !== null && STATE_SYMBOL in value
5256
? snapshot(value, true)
5357
: value
@@ -177,3 +181,34 @@ export function get_stack(label) {
177181
}
178182
return error;
179183
}
184+
185+
/**
186+
* @param {Value} source
187+
* @param {string} label
188+
*/
189+
export function tag(source, label) {
190+
source.label = label;
191+
tag_proxy(source.v, label);
192+
193+
return source;
194+
}
195+
196+
/**
197+
* @param {unknown} value
198+
* @param {string} label
199+
*/
200+
export function tag_proxy(value, label) {
201+
// @ts-expect-error
202+
value?.[PROXY_PATH_SYMBOL]?.(label);
203+
return value;
204+
}
205+
206+
/**
207+
* @param {unknown} value
208+
*/
209+
export function label(value) {
210+
if (typeof value === 'symbol') return `Symbol(${value.description})`;
211+
if (typeof value === 'function') return '<function>';
212+
if (typeof value === 'object' && value) return '<object>';
213+
return String(value);
214+
}

packages/svelte/src/internal/client/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export { add_locations } from './dev/elements.js';
77
export { hmr } from './dev/hmr.js';
88
export { create_ownership_validator } from './dev/ownership.js';
99
export { check_target, legacy_api } from './dev/legacy.js';
10-
export { trace } from './dev/tracing.js';
10+
export { trace, tag, tag_proxy } from './dev/tracing.js';
1111
export { inspect } from './dev/inspect.js';
1212
export { validate_snippet_args } from './dev/validation.js';
1313
export { await_block as await } from './dom/blocks/await.js';

0 commit comments

Comments
 (0)