From 40be734f949ff1c9fc236c9c7e87669726ceb179 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Wed, 21 May 2025 20:04:00 -0400 Subject: [PATCH] put locations on template, instead of on the side --- .../3-transform/client/transform-client.js | 3 +- .../client/transform-template/index.js | 38 +++++++++++-------- .../client/transform-template/template.js | 10 +++-- .../client/transform-template/types.d.ts | 2 + .../phases/3-transform/client/types.d.ts | 5 +-- .../3-transform/client/visitors/Fragment.js | 1 - .../client/visitors/RegularElement.js | 27 ++----------- .../client/visitors/shared/component.js | 13 ++----- .../src/internal/client/dev/elements.js | 2 +- .../svelte/src/internal/client/types.d.ts | 4 ++ .../svelte/src/internal/shared/types.d.ts | 4 -- 11 files changed, 45 insertions(+), 64 deletions(-) diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js index 6abea2c2c9..e2e006c14b 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-client.js @@ -170,8 +170,7 @@ export function client_component(analysis, options) { update: /** @type {any} */ (null), expressions: /** @type {any} */ (null), after_update: /** @type {any} */ (null), - template: /** @type {any} */ (null), - locations: /** @type {any} */ (null) + template: /** @type {any} */ (null) }; const module = /** @type {ESTree.Program} */ ( diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js index ec18ad30c8..7225bcfc62 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/index.js @@ -1,7 +1,8 @@ -/** @import { ComponentClientTransformState } from '../types.js' */ +/** @import { Location } from 'locate-character' */ /** @import { Namespace } from '#compiler' */ -/** @import { SourceLocation } from '#shared' */ -import { dev } from '../../../../state.js'; +/** @import { ComponentClientTransformState } from '../types.js' */ +/** @import { Node } from './types.js' */ +import { dev, locator } from '../../../../state.js'; import * as b from '../../../../utils/builders.js'; import { template_to_functions } from './to-functions.js'; import { template_to_string } from './to-string.js'; @@ -28,20 +29,27 @@ function get_template_function(namespace, state) { } /** - * @param {SourceLocation[]} locations + * @param {Node[]} nodes */ -function build_locations(locations) { - return b.array( - locations.map((loc) => { - const expression = b.array([b.literal(loc[0]), b.literal(loc[1])]); +function build_locations(nodes) { + const array = b.array([]); - if (loc.length === 3) { - expression.elements.push(build_locations(loc[2])); - } + for (const node of nodes) { + if (node.type !== 'element') continue; - return expression; - }) - ); + const { line, column } = /** @type {Location} */ (locator(node.start)); + + const expression = b.array([b.literal(line), b.literal(column)]); + const children = build_locations(node.children); + + if (children.elements.length > 0) { + expression.elements.push(children); + } + + array.elements.push(expression); + } + + return array; } /** @@ -66,7 +74,7 @@ export function transform_template(state, namespace, flags) { '$.add_locations', call, b.member(b.id(state.analysis.name), '$.FILENAME', true), - build_locations(state.locations) + build_locations(state.template.nodes) ); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/template.js b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/template.js index 9596449dec..3a706ee897 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/template.js @@ -22,13 +22,17 @@ export class Template { #fragment = this.nodes; - /** @param {string} name */ - create_element(name) { + /** + * @param {string} name + * @param {number} start + */ + create_element(name, start) { this.#element = { type: 'element', name, attributes: {}, - children: [] + children: [], + start }; this.#fragment.push(this.#element); diff --git a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/types.d.ts index dad8356ed7..92a55e79c5 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/transform-template/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/transform-template/types.d.ts @@ -5,6 +5,8 @@ export interface Element { name: string; attributes: Record; children: Node[]; + /** used for populating __svelte_meta */ + start: number; } export interface Text { diff --git a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts index bea0eaa93e..2388ee1b00 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts +++ b/packages/svelte/src/compiler/phases/3-transform/client/types.d.ts @@ -3,16 +3,14 @@ import type { Statement, LabeledStatement, Identifier, - PrivateIdentifier, Expression, AssignmentExpression, UpdateExpression, VariableDeclaration } from 'estree'; -import type { AST, Namespace, StateField, ValidatedCompileOptions } from '#compiler'; +import type { AST, Namespace, ValidatedCompileOptions } from '#compiler'; import type { TransformState } from '../types.js'; import type { ComponentAnalysis } from '../../types.js'; -import type { SourceLocation } from '#shared'; import type { Template } from './transform-template/template.js'; export interface ClientTransformState extends TransformState { @@ -55,7 +53,6 @@ export interface ComponentClientTransformState extends ClientTransformState { readonly expressions: Expression[]; /** The HTML template string */ readonly template: Template; - readonly locations: SourceLocation[]; readonly metadata: { namespace: Namespace; bound_contenteditable: boolean; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js index 151258bbc0..938a8736ac 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/Fragment.js @@ -67,7 +67,6 @@ export function Fragment(node, context) { expressions: [], after_update: [], template: new Template(), - locations: [], transform: { ...context.state.transform }, metadata: { namespace, diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js index 6c5ae08d21..714d2964b9 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/RegularElement.js @@ -1,17 +1,14 @@ /** @import { ArrayExpression, Expression, ExpressionStatement, Identifier, MemberExpression, ObjectExpression } from 'estree' */ /** @import { AST } from '#compiler' */ -/** @import { SourceLocation } from '#shared' */ /** @import { ComponentClientTransformState, ComponentContext } from '../types' */ /** @import { Scope } from '../../../scope' */ import { cannot_be_set_statically, is_boolean_attribute, is_dom_property, - is_load_error_element, - is_void + is_load_error_element } from '../../../../../utils.js'; -import { escape_html } from '../../../../../escaping.js'; -import { dev, is_ignored, locator } from '../../../../state.js'; +import { is_ignored } from '../../../../state.js'; import { is_event_attribute, is_text_attribute } from '../../../../utils/ast.js'; import * as b from '#compiler/builders'; import { is_custom_element_node } from '../../../nodes.js'; @@ -39,20 +36,9 @@ import { visit_event_attribute } from './shared/events.js'; * @param {ComponentContext} context */ export function RegularElement(node, context) { - /** @type {SourceLocation} */ - let location = [-1, -1]; - - if (dev) { - const loc = locator(node.start); - if (loc) { - location[0] = loc.line; - location[1] = loc.column; - context.state.locations.push(location); - } - } + context.state.template.create_element(node.name, node.start); if (node.name === 'noscript') { - context.state.template.create_element('noscript'); return; } @@ -68,8 +54,6 @@ export function RegularElement(node, context) { context.state.template.contains_script_tag ||= node.name === 'script'; - context.state.template.create_element(node.name); - /** @type {Array} */ const attributes = []; @@ -345,7 +329,6 @@ export function RegularElement(node, context) { const state = { ...context.state, metadata, - locations: [], scope: /** @type {Scope} */ (context.state.scopes.get(node.fragment)), preserve_whitespace: context.state.preserve_whitespace || node.name === 'pre' || node.name === 'textarea' @@ -439,10 +422,6 @@ export function RegularElement(node, context) { context.state.update.push(b.stmt(b.assignment('=', dir, dir))); } - if (state.locations.length > 0) { - // @ts-expect-error - location.push(state.locations); - } context.state.template.pop_element(); } diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js index cf60e92e26..f430200774 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/shared/component.js @@ -1,7 +1,7 @@ /** @import { BlockStatement, Expression, ExpressionStatement, Identifier, MemberExpression, Pattern, Property, SequenceExpression, Statement } from 'estree' */ /** @import { AST } from '#compiler' */ /** @import { ComponentContext } from '../../types.js' */ -import { dev, is_ignored, locator } from '../../../../../state.js'; +import { dev, is_ignored } from '../../../../../state.js'; import { get_attribute_chunks, object } from '../../../../../utils/ast.js'; import * as b from '#compiler/builders'; import { build_bind_this, memoize_expression, validate_binding } from '../shared/utils.js'; @@ -440,19 +440,12 @@ export function build_component(node, component_name, context, anchor = context. } if (Object.keys(custom_css_props).length > 0) { - if (dev) { - const loc = locator(node.start); - if (loc) { - context.state.locations.push([loc.line, loc.column]); - } - } - if (context.state.metadata.namespace === 'svg') { // this boils down to - context.state.template.create_element('g'); + context.state.template.create_element('g', node.start); } else { // this boils down to - context.state.template.create_element('svelte-css-wrapper'); + context.state.template.create_element('svelte-css-wrapper', node.start); context.state.template.set_prop('style', 'display: contents'); } diff --git a/packages/svelte/src/internal/client/dev/elements.js b/packages/svelte/src/internal/client/dev/elements.js index bf75e6e5cc..62ac09d784 100644 --- a/packages/svelte/src/internal/client/dev/elements.js +++ b/packages/svelte/src/internal/client/dev/elements.js @@ -1,4 +1,4 @@ -/** @import { SourceLocation } from '#shared' */ +/** @import { SourceLocation } from '#client' */ import { HYDRATION_END, HYDRATION_START, HYDRATION_START_ELSE } from '../../../constants.js'; import { hydrating } from '../dom/hydration.js'; diff --git a/packages/svelte/src/internal/client/types.d.ts b/packages/svelte/src/internal/client/types.d.ts index b46bdf2013..9703c2aac1 100644 --- a/packages/svelte/src/internal/client/types.d.ts +++ b/packages/svelte/src/internal/client/types.d.ts @@ -183,4 +183,8 @@ export type ProxyStateObject> = T & { [STATE_SYMBOL]: T; }; +export type SourceLocation = + | [line: number, column: number] + | [line: number, column: number, SourceLocation[]]; + export * from './reactivity/types'; diff --git a/packages/svelte/src/internal/shared/types.d.ts b/packages/svelte/src/internal/shared/types.d.ts index a97a61af67..4deeb76b2f 100644 --- a/packages/svelte/src/internal/shared/types.d.ts +++ b/packages/svelte/src/internal/shared/types.d.ts @@ -3,10 +3,6 @@ export type Store = { set(value: V): void; }; -export type SourceLocation = - | [line: number, column: number] - | [line: number, column: number, SourceLocation[]]; - export type Getters = { [K in keyof T]: () => T[K]; };