chore: remove stack-based module boundaries (#15711)

pull/15712/head
Rich Harris 5 months ago committed by GitHub
parent 93110a3246
commit c23f15134e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -21,7 +21,7 @@ A component is attempting to bind to a non-bindable property `%key%` belonging t
### component_api_changed
```
%parent% called `%method%` on an instance of %component%, which is no longer valid in Svelte 5
Calling `%method%` on a component instance (of %component%) is no longer valid in Svelte 5
```
See the [migration guide](/docs/svelte/v5-migration-guide#Components-are-no-longer-classes) for more information.

@ -12,7 +12,7 @@
## component_api_changed
> %parent% called `%method%` on an instance of %component%, which is no longer valid in Svelte 5
> Calling `%method%` on a component instance (of %component%) is no longer valid in Svelte 5
See the [migration guide](/docs/svelte/v5-migration-guide#Components-are-no-longer-classes) for more information.

@ -536,9 +536,6 @@ export function client_component(analysis, options) {
b.assignment('=', b.member(b.id(analysis.name), '$.FILENAME', true), b.literal(filename))
)
);
body.unshift(b.stmt(b.call(b.id('$.mark_module_start'))));
body.push(b.stmt(b.call(b.id('$.mark_module_end'), b.id(analysis.name))));
}
if (!analysis.runes) {

@ -1,7 +1,6 @@
import * as e from '../errors.js';
import { component_context } from '../context.js';
import { FILENAME } from '../../../constants.js';
import { get_component } from './ownership.js';
/** @param {Function & { [FILENAME]: string }} target */
export function check_target(target) {
@ -15,9 +14,7 @@ export function legacy_api() {
/** @param {string} method */
function error(method) {
// @ts-expect-error
const parent = get_component()?.[FILENAME] ?? 'Something';
e.component_api_changed(parent, method, component[FILENAME]);
e.component_api_changed(method, component[FILENAME]);
}
return {

@ -7,103 +7,6 @@ import { component_context } from '../context.js';
import * as w from '../warnings.js';
import { sanitize_location } from '../../../utils.js';
/** @type {Record<string, Array<{ start: Location, end: Location, component: Function }>>} */
const boundaries = {};
const chrome_pattern = /at (?:.+ \()?(.+):(\d+):(\d+)\)?$/;
const firefox_pattern = /@(.+):(\d+):(\d+)$/;
function get_stack() {
const stack = new Error().stack;
if (!stack) return null;
const entries = [];
for (const line of stack.split('\n')) {
let match = chrome_pattern.exec(line) ?? firefox_pattern.exec(line);
if (match) {
entries.push({
file: match[1],
line: +match[2],
column: +match[3]
});
}
}
return entries;
}
/**
* Determines which `.svelte` component is responsible for a given state change
* @returns {Function | null}
*/
export function get_component() {
// first 4 lines are svelte internals; adjust this number if we change the internal call stack
const stack = get_stack()?.slice(4);
if (!stack) return null;
for (let i = 0; i < stack.length; i++) {
const entry = stack[i];
const modules = boundaries[entry.file];
if (!modules) {
// If the first entry is not a component, that means the modification very likely happened
// within a .svelte.js file, possibly triggered by a component. Since these files are not part
// of the bondaries/component context heuristic, we need to bail in this case, else we would
// have false positives when the .svelte.ts file provides a state creator function, encapsulating
// the state and its mutations, and is being called from a component other than the one who
// called the state creator function.
if (i === 0) return null;
continue;
}
for (const module of modules) {
if (module.end == null) {
return null;
}
if (module.start.line < entry.line && module.end.line > entry.line) {
return module.component;
}
}
}
return null;
}
/**
* Together with `mark_module_end`, this function establishes the boundaries of a `.svelte` file,
* such that subsequent calls to `get_component` can tell us which component is responsible
* for a given state change
*/
export function mark_module_start() {
const start = get_stack()?.[2];
if (start) {
(boundaries[start.file] ??= []).push({
start,
// @ts-expect-error
end: null,
// @ts-expect-error we add the component at the end, since HMR will overwrite the function
component: null
});
}
}
/**
* @param {Function} component
*/
export function mark_module_end(component) {
const end = get_stack()?.[2];
if (end) {
const boundaries_file = boundaries[end.file];
const boundary = boundaries_file[boundaries_file.length - 1];
boundary.end = end;
boundary.component = component;
}
}
/**
* Sets up a validator that
* - traverses the path of a prop to find out if it is allowed to be mutated

@ -54,15 +54,14 @@ export function bind_not_bindable(key, component, name) {
}
/**
* %parent% called `%method%` on an instance of %component%, which is no longer valid in Svelte 5
* @param {string} parent
* Calling `%method%` on a component instance (of %component%) is no longer valid in Svelte 5
* @param {string} method
* @param {string} component
* @returns {never}
*/
export function component_api_changed(parent, method, component) {
export function component_api_changed(method, component) {
if (DEV) {
const error = new Error(`component_api_changed\n${parent} called \`${method}\` on an instance of ${component}, which is no longer valid in Svelte 5\nhttps://svelte.dev/e/component_api_changed`);
const error = new Error(`component_api_changed\nCalling \`${method}\` on a component instance (of ${component}) is no longer valid in Svelte 5\nhttps://svelte.dev/e/component_api_changed`);
error.name = 'Svelte error';
throw error;

@ -4,7 +4,7 @@ export { assign, assign_and, assign_or, assign_nullish } from './dev/assign.js';
export { cleanup_styles } from './dev/css.js';
export { add_locations } from './dev/elements.js';
export { hmr } from './dev/hmr.js';
export { mark_module_start, mark_module_end, 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 { trace } from './dev/tracing.js';
export { inspect } from './dev/inspect.js';

Loading…
Cancel
Save