feat: move dev-time component properties to private symbols (#12461)

* add a FILENAME symbol

* feat: move dev-time component properties to private symbols

* lint
pull/12463/head
Rich Harris 1 year ago committed by GitHub
parent e196bb2140
commit 07b0db83c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
feat: move dev-time component properties to private symbols'

@ -418,7 +418,7 @@ export function client_component(source, analysis, options) {
if (options.hmr) {
const accept_fn_body = [
b.stmt(b.call('$.set', b.id('s'), b.member(b.id('module.default'), b.id('original'))))
b.stmt(b.call('$.set', b.id('s'), b.member(b.id('module.default'), b.id('$.ORIGINAL'), true)))
];
if (analysis.css.hash) {
@ -446,7 +446,11 @@ export function client_component(source, analysis, options) {
// Assign the original component to the wrapper so we can use it on hot reload patching,
// else we would call the HMR function two times
b.stmt(
b.assignment('=', b.member(b.id(analysis.name), b.id('original')), b.id('$$original'))
b.assignment(
'=',
b.member(b.id(analysis.name), b.id('$.ORIGINAL'), true),
b.id('$$original')
)
),
b.stmt(b.call('import.meta.hot.accept', b.arrow([b.id('module')], b.block(accept_fn_body))))
]);
@ -458,10 +462,14 @@ export function client_component(source, analysis, options) {
if (options.dev) {
if (filename) {
// add `App.filename = 'App.svelte'` so that we can print useful messages later
// add `App[$.FILENAME] = 'App.svelte'` so that we can print useful messages later
body.unshift(
b.stmt(
b.assignment('=', b.member(b.id(analysis.name), b.id('filename')), b.literal(filename))
b.assignment(
'=',
b.member(b.id(analysis.name), b.id('$.FILENAME'), true),
b.literal(filename)
)
)
);
}

@ -1640,7 +1640,7 @@ export const template_visitors = {
call = b.call(
'$.add_locations',
call,
b.member(b.id(context.state.analysis.name), b.id('filename')),
b.member(b.id(context.state.analysis.name), b.id('$.FILENAME'), true),
serialize_locations(state.locations)
);
}

@ -2249,10 +2249,14 @@ export function server_component(analysis, options) {
}
if (options.dev && filename) {
// add `App.filename = 'App.svelte'` so that we can print useful messages later
// add `App[$.FILENAME] = 'App.svelte'` so that we can print useful messages later
body.unshift(
b.stmt(
b.assignment('=', b.member(b.id(analysis.name), b.id('filename')), b.literal(filename))
b.assignment(
'=',
b.member(b.id(analysis.name), b.id('$.FILENAME'), true),
b.literal(filename)
)
)
);
}

@ -30,6 +30,10 @@ export const ELEMENT_PRESERVE_ATTRIBUTE_CASE = 1 << 1;
export const UNINITIALIZED = Symbol();
// Dev-time component properties
export const FILENAME = Symbol('filename');
export const ORIGINAL = Symbol('original');
/** List of elements that require raw contents and should not have SSR comments put in them */
export const RawTextElements = ['textarea', 'script', 'style', 'title'];

@ -1,11 +1,12 @@
import * as e from '../errors.js';
import { current_component_context } from '../runtime.js';
import { FILENAME } from '../../../constants.js';
import { get_component } from './ownership.js';
/** @param {Function & { filename: string }} target */
/** @param {Function & { [FILENAME]: string }} target */
export function check_target(target) {
if (target) {
e.component_api_invalid_new(target.filename ?? 'a component', target.name);
e.component_api_invalid_new(target[FILENAME] ?? 'a component', target.name);
}
}
@ -15,8 +16,8 @@ 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);
const parent = get_component()?.[FILENAME] ?? 'Something';
e.component_api_changed(parent, method, component[FILENAME]);
}
return {

@ -6,6 +6,7 @@ import { render_effect, user_pre_effect } from '../reactivity/effects.js';
import { dev_current_component_function } from '../runtime.js';
import { get_prototype_of } from '../../shared/utils.js';
import * as w from '../warnings.js';
import { FILENAME } from '../../../constants.js';
/** @type {Record<string, Array<{ start: Location, end: Location, component: Function }>>} */
const boundaries = {};
@ -115,8 +116,8 @@ export function add_owner(object, owner, global = false) {
if (metadata && !has_owner(metadata, component)) {
let original = get_owner(metadata);
if (owner.filename !== component.filename) {
w.ownership_invalid_binding(component.filename, owner.filename, original.filename);
if (owner[FILENAME] !== component[FILENAME]) {
w.ownership_invalid_binding(component[FILENAME], owner[FILENAME], original[FILENAME]);
}
}
}
@ -236,9 +237,9 @@ export function check_ownership(metadata) {
let original = get_owner(metadata);
// @ts-expect-error
if (original.filename !== component.filename) {
if (original[FILENAME] !== component[FILENAME]) {
// @ts-expect-error
w.ownership_invalid_mutation(component.filename, original.filename);
w.ownership_invalid_mutation(component[FILENAME], original[FILENAME]);
} else {
w.ownership_invalid_mutation();
}

@ -1,5 +1,5 @@
/** @import { Effect, TemplateNode } from '#client' */
import { HYDRATION_ERROR } from '../../../../constants.js';
import { FILENAME, HYDRATION_ERROR } from '../../../../constants.js';
import { block, branch, destroy_effect } from '../../reactivity/effects.js';
import { hydrate_next, hydrate_node, hydrating, set_hydrate_node } from '../hydration.js';
import { create_fragment_from_html } from '../reconciler.js';
@ -23,8 +23,8 @@ function check_hash(element, server_hash, value) {
const loc = element.__svelte_meta?.loc;
if (loc) {
location = `near ${loc.file}:${loc.line}:${loc.column}`;
} else if (dev_current_component_function?.filename) {
location = `in ${dev_current_component_function.filename}`;
} else if (dev_current_component_function?.[FILENAME]) {
location = `in ${dev_current_component_function[FILENAME]}`;
}
w.hydration_html_changed(

@ -1,5 +1,5 @@
/** @import { Effect, EffectNodes, TemplateNode } from '#client' */
import { namespace_svg } from '../../../../constants.js';
import { FILENAME, namespace_svg } from '../../../../constants.js';
import {
hydrate_next,
hydrate_node,
@ -38,7 +38,7 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio
hydrate_next();
}
var filename = DEV && location && current_component_context?.function.filename;
var filename = DEV && location && current_component_context?.function[FILENAME];
/** @type {string | null} */
var tag;

@ -1,3 +1,4 @@
export { FILENAME, ORIGINAL } from '../../constants.js';
export { add_locations } from './dev/elements.js';
export { hmr } from './dev/hmr.js';
export {

@ -29,6 +29,7 @@ import { mutate, set, source } from './reactivity/sources.js';
import { update_derived } from './reactivity/deriveds.js';
import * as e from './errors.js';
import { lifecycle_outside_component } from '../shared/errors.js';
import { FILENAME } from '../../constants.js';
const FLUSH_MICROTASK = 0;
const FLUSH_SYNC = 1;
@ -226,7 +227,7 @@ function handle_error(error, effect, component_context) {
while (current_context !== null) {
/** @type {string} */
var filename = current_context.function?.filename;
var filename = current_context.function?.[FILENAME];
if (filename) {
const file = filename.split('/').pop();

@ -1,6 +1,7 @@
import { untrack } from './runtime.js';
import { get_descriptor, is_array } from '../shared/utils.js';
import * as e from './errors.js';
import { FILENAME } from '../../constants.js';
/** regex of all html void element names */
const void_element_names =
@ -70,7 +71,7 @@ export function validate_each_keys(collection, key_fn) {
* @param {Record<string, any>} $$props
* @param {string[]} bindable
* @param {string[]} exports
* @param {Function & { filename: string }} component
* @param {Function & { [FILENAME]: string }} component
*/
export function validate_prop_bindings($$props, bindable, exports, component) {
for (const key in $$props) {
@ -79,11 +80,11 @@ export function validate_prop_bindings($$props, bindable, exports, component) {
if (setter) {
if (exports.includes(key)) {
e.bind_invalid_export(component.filename, key, name);
e.bind_invalid_export(component[FILENAME], key, name);
}
if (!bindable.includes(key)) {
e.bind_not_bindable(key, component.filename, name);
e.bind_not_bindable(key, component[FILENAME], name);
}
}
}

@ -1,4 +1,5 @@
import {
FILENAME,
disallowed_paragraph_contents,
interactive_elements,
is_tag_valid_with_parent
@ -56,7 +57,7 @@ function print_error(payload, parent, child) {
* @param {number} column
*/
export function push_element(payload, tag, line, column) {
var filename = /** @type {import('#server').Component} */ (current_component).function.filename;
var filename = /** @type {import('#server').Component} */ (current_component).function[FILENAME];
var child = { tag, parent, filename, line, column };
if (parent !== null && !is_tag_valid_with_parent(tag, parent.tag)) {

@ -1,5 +1,6 @@
/** @import { Component, Payload, RenderOutput } from '#server' */
/** @import { Store } from '#shared' */
export { FILENAME, ORIGINAL } from '../../constants.js';
import { is_promise, noop } from '../shared/utils.js';
import { subscribe_to_store } from '../../store/utils.js';
import {

@ -16,10 +16,10 @@ if (import.meta.hot) {
Hmr = $.hmr(s);
Hmr.filename = filename;
Hmr.original = $$original;
Hmr[$.ORIGINAL] = $$original;
import.meta.hot.accept((module) => {
$.set(s, module.default.original);
$.set(s, module.default[$.ORIGINAL]);
});
}

Loading…
Cancel
Save