pull/10464/head
Rich Harris 3 years ago
parent f05319fb11
commit 17eae456b8

@ -439,7 +439,16 @@ export function client_component(source, analysis, options) {
if (options.dev && state.options.filename) {
body.unshift(b.stmt(b.call(b.id('$.push_module'), b.literal(state.options.filename))));
body.push(b.stmt(b.call(b.id('$.pop_module'), b.literal(state.options.filename))));
body.push(
b.stmt(
b.assignment(
'=',
b.member(b.id(analysis.name), b.id('filename')),
b.literal(state.options.filename)
)
)
);
body.push(b.stmt(b.call(b.id('$.pop_module'))));
}
return {

@ -763,6 +763,8 @@ function serialize_inline_component(node, component_name, context) {
/** @type {import('estree').Identifier | import('estree').MemberExpression | null} */
let bind_this = null;
const binding_initializers = [];
/**
* If this component has a slot property, it is a named slot within another component. In this case
* the slot scope applies to the component itself, too, and not just its children.
@ -850,14 +852,21 @@ function serialize_inline_component(node, component_name, context) {
if (attribute.name === 'this') {
bind_this = attribute.expression;
} else {
push_prop(
b.get(attribute.name, [
b.return(
/** @type {import('estree').Expression} */ (context.visit(attribute.expression))
const expression = /** @type {import('estree').Expression} */ (
context.visit(attribute.expression)
);
binding_initializers.push(
b.stmt(
b.call(
b.id('$.pre_effect'),
b.thunk(b.call(b.id('$.add_owner'), expression, b.id(component_name)))
)
])
)
);
push_prop(b.get(attribute.name, [b.return(expression)]));
const assignment = b.assignment('=', attribute.expression, b.id('$$value'));
push_prop(
b.set(attribute.name, [
@ -997,14 +1006,11 @@ function serialize_inline_component(node, component_name, context) {
);
}
/** @type {import('estree').Statement} */
let statement = b.stmt(fn(context.state.node));
const statements = [...snippet_declarations, ...binding_initializers];
if (snippet_declarations.length > 0) {
statement = b.block([...snippet_declarations, statement]);
}
statements.push(b.stmt(fn(context.state.node)));
return statement;
return statements.length > 1 ? b.block(statements) : statements[0];
}
/**

@ -1,5 +1,7 @@
/** @typedef {{ file: string, line: number, column: number }} Location */
import { deep_read, set_current_owner, set_current_owner_override, untrack } from './runtime.js';
/** @type {Record<string, Array<{ start: Location, end: Location, filename: string }>>} */
const boundaries = {};
@ -61,10 +63,7 @@ export function push_module(filename) {
}
}
/**
* @param {string} filename
*/
export function pop_module(filename) {
export function pop_module() {
const end = get_stack()?.[1];
if (end) {
@ -72,3 +71,16 @@ export function pop_module(filename) {
boundaries[end.file].at(-1).end = end;
}
}
/**
*
* @param {any} object
* @param {any} owner
*/
export function add_owner(object, owner) {
untrack(() => {
set_current_owner_override(owner.filename);
deep_read(object);
set_current_owner_override(null);
});
}

@ -8,7 +8,10 @@ import {
updating_derived,
UNINITIALIZED,
mutable_source,
batch_inspect
batch_inspect,
set_current_owner,
current_component_context,
current_owner
} from './runtime.js';
import {
array_prototype,
@ -54,7 +57,7 @@ export function proxy(value, immutable = true) {
i: immutable,
p: proxy,
t: value,
o: DEV ? get_module() : ''
o: DEV && (current_owner ?? current_component_context?.f)
}),
writable: true,
enumerable: false
@ -178,12 +181,18 @@ const state_proxy_handler = {
(effect_active() || updating_derived) &&
(!(prop in target) || get_descriptor(target, prop)?.writable)
) {
console.log('setting current owner', metadata.o);
const previous_owner = current_owner;
if (!current_owner) set_current_owner(metadata.o);
s = (metadata.i ? source : mutable_source)(proxy(target[prop], metadata.i));
set_current_owner(previous_owner);
metadata.s.set(prop, s);
}
if (s !== undefined) {
// set_current_owner(metadata.o);
const value = get(s);
// set_current_owner(null);
return value === UNINITIALIZED ? undefined : value;
}
@ -251,13 +260,6 @@ const state_proxy_handler = {
// @ts-ignore
target[prop] = value;
if (DEV) {
const site = get_module();
if (site !== metadata.o) {
console.error(`mutating state outside the component where it was created: ${site}`);
}
}
if (not_has) {
// If we have mutated an array directly, we might need to
// signal that length has also changed. Do it before updating metadata

@ -19,6 +19,7 @@ import {
} from '../../constants.js';
import { STATE_SYMBOL, unstate } from './proxy.js';
import { EACH_BLOCK, IF_BLOCK } from './block.js';
import { get_module } from './dev.js';
export const SOURCE = 1;
export const DERIVED = 1 << 1;
@ -106,6 +107,26 @@ export let current_component_context = null;
export let updating_derived = false;
/** @type {string | null} */
export let current_owner = null;
/**
* @param {string | null} owner
*/
export function set_current_owner(owner) {
current_owner = owner;
}
/** @type {string | null} */
export let current_owner_override = null;
/**
* @param {string | null} owner
*/
export function set_current_owner_override(owner) {
current_owner_override = owner;
}
/**
* @param {null | import('./types.js').ComponentContext} context
* @returns {boolean}
@ -913,11 +934,17 @@ export function unsubscribe_on_destroy(stores) {
* @returns {V}
*/
export function get(signal) {
// @ts-expect-error
if (DEV && signal.inspect && inspect_fn) {
/** @type {import('./types.js').SignalDebug} */ (signal).inspect.add(inspect_fn);
if (DEV) {
if (signal.o && (current_owner_override || current_owner)) {
signal.o.add(current_owner_override || current_owner);
}
// @ts-expect-error
inspect_captured_signals.push(signal);
if (signal.inspect && inspect_fn) {
/** @type {import('./types.js').SignalDebug} */ (signal).inspect.add(inspect_fn);
// @ts-expect-error
inspect_captured_signals.push(signal);
}
}
const flags = signal.f;
@ -983,6 +1010,13 @@ export function get(signal) {
* @returns {V}
*/
export function set(signal, value) {
if (DEV && 'o' in signal) {
const site = get_module();
if (site && !signal.o.has(site)) {
console.error(`mutating state outside the component where it was created: ${site}`);
}
}
set_signal_value(signal, value);
return value;
}
@ -1295,6 +1329,13 @@ export function source(initial_value) {
* @param {import('./types.js').Signal} signal
*/
function bind_signal_to_component_context(signal) {
if (DEV) {
const owner = current_owner ?? current_component_context?.f;
if (owner) {
(signal.o ??= new Set()).add(owner);
}
}
if (current_component_context === null || !current_component_context.r) return;
const signals = current_component_context.d;
@ -1858,7 +1899,6 @@ function on_destroy(fn) {
*/
export function push(props, runes = false) {
current_component_context = {
// accessors
a: null,
// context
c: null,
@ -1875,7 +1915,9 @@ export function push(props, runes = false) {
// runes
r: runes,
// update_callbacks
u: null
u: null,
// filename
f: (DEV && get_module()) || ''
};
}
@ -1956,7 +1998,7 @@ export function init() {
* @param {Set<any>} visited
* @returns {void}
*/
function deep_read(value, visited = new Set()) {
export function deep_read(value, visited = new Set()) {
if (typeof value === 'object' && value !== null && !visited.has(value)) {
visited.add(value);
for (let key in value) {

@ -61,6 +61,8 @@ export type ComponentContext = {
/** onMount callbacks */
m: Array<() => any>;
};
/** filename */
f: string;
};
// We keep two shapes rather than a single monomorphic shape to improve the memory usage.
@ -77,6 +79,8 @@ export type SourceSignal<V = unknown> = {
f: SignalFlags;
/** value: The latest value for this signal */
v: V;
/** owners: The components that can write to this signal */
o: Set<string>;
};
export type SourceSignalDebug = {

Loading…
Cancel
Save