From ac7709f65c4665e32cbea17a28ed79d3613de580 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 14 May 2024 04:18:43 -0400 Subject: [PATCH] chore: dedupe `getLocator` calls (#11600) ...by introducing global compiler state that is reset between iterations --- .../templates/compile-warnings.js | 24 +------------------ packages/svelte/src/compiler/index.js | 20 +++++++--------- packages/svelte/src/compiler/migrate/index.js | 4 ++-- .../src/compiler/phases/1-parse/index.js | 17 +------------ .../compiler/phases/1-parse/read/context.js | 6 ++++- .../3-transform/client/transform-client.js | 2 -- .../phases/3-transform/client/types.d.ts | 4 ---- .../3-transform/client/visitors/template.js | 5 ++-- .../src/compiler/phases/3-transform/index.js | 10 ++++---- packages/svelte/src/compiler/state.js | 23 ++++++++++++++++++ packages/svelte/src/compiler/warnings.js | 21 +--------------- 11 files changed, 50 insertions(+), 86 deletions(-) create mode 100644 packages/svelte/src/compiler/state.js diff --git a/packages/svelte/scripts/process-messages/templates/compile-warnings.js b/packages/svelte/scripts/process-messages/templates/compile-warnings.js index e96558edad..75d0e3603f 100644 --- a/packages/svelte/scripts/process-messages/templates/compile-warnings.js +++ b/packages/svelte/scripts/process-messages/templates/compile-warnings.js @@ -1,29 +1,7 @@ -import { getLocator } from 'locate-character'; +import { filename, locator, warnings } from './state.js'; /** @typedef {{ start?: number, end?: number }} NodeLike */ -/** @type {import('#compiler').Warning[]} */ -let warnings = []; - -/** @type {string | undefined} */ -let filename; - -let locator = getLocator('', { offsetLine: 1 }); - -/** - * @param {{ - * source: string; - * filename: string | undefined; - * }} options - * @returns {import('#compiler').Warning[]} - */ -export function reset_warnings(options) { - filename = options.filename; - locator = getLocator(options.source, { offsetLine: 1 }); - - return (warnings = []); -} - /** * @param {null | NodeLike} node * @param {string} code diff --git a/packages/svelte/src/compiler/index.js b/packages/svelte/src/compiler/index.js index ba312a1a63..d5edba7510 100644 --- a/packages/svelte/src/compiler/index.js +++ b/packages/svelte/src/compiler/index.js @@ -1,4 +1,3 @@ -import { getLocator } from 'locate-character'; import { walk as zimmerframe_walk } from 'zimmerframe'; import { CompileError } from './errors.js'; import { convert } from './legacy.js'; @@ -8,7 +7,7 @@ import { remove_typescript_nodes } from './phases/1-parse/remove_typescript_node import { analyze_component, analyze_module } from './phases/2-analyze/index.js'; import { transform_component, transform_module } from './phases/3-transform/index.js'; import { validate_component_options, validate_module_options } from './validate-options.js'; -import { reset_warnings } from './warnings.js'; +import * as state from './state.js'; export { default as preprocess } from './preprocess/index.js'; /** @@ -21,7 +20,8 @@ export { default as preprocess } from './preprocess/index.js'; */ export function compile(source, options) { try { - const warnings = reset_warnings({ source, filename: options.filename }); + state.reset({ source, filename: options.filename }); + const validated = validate_component_options(options, ''); let parsed = _parse(source); @@ -44,9 +44,7 @@ export function compile(source, options) { } const analysis = analyze_component(parsed, source, combined_options); - const result = transform_component(analysis, source, combined_options); - result.warnings = warnings; result.ast = to_public_ast(source, parsed, options.modernAst); return result; } catch (e) { @@ -68,11 +66,11 @@ export function compile(source, options) { */ export function compileModule(source, options) { try { - const warnings = reset_warnings({ source, filename: options.filename }); + state.reset({ source, filename: options.filename }); + const validated = validate_module_options(options, ''); const analysis = analyze_module(parse_acorn(source, false), validated); const result = transform_module(analysis, source, validated); - result.warnings = warnings; return result; } catch (e) { if (e instanceof CompileError) { @@ -92,10 +90,8 @@ function handle_compile_error(error, filename, source) { error.filename = filename; if (error.position) { - // TODO this is reused with warnings — DRY out - const locator = getLocator(source, { offsetLine: 1 }); - const start = locator(error.position[0]); - const end = locator(error.position[1]); + const start = state.locator(error.position[0]); + const end = state.locator(error.position[1]); error.start = start; error.end = end; @@ -142,6 +138,8 @@ function handle_compile_error(error, filename, source) { * @returns {import('#compiler').Root | import('./types/legacy-nodes.js').LegacyRoot} */ export function parse(source, options = {}) { + state.reset({ source, filename: options.filename }); + /** @type {import('#compiler').Root} */ let ast; try { diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js index e6328c70ba..6f5d2681d9 100644 --- a/packages/svelte/src/compiler/migrate/index.js +++ b/packages/svelte/src/compiler/migrate/index.js @@ -4,7 +4,7 @@ import { parse } from '../phases/1-parse/index.js'; import { analyze_component } from '../phases/2-analyze/index.js'; import { validate_component_options } from '../validate-options.js'; import { get_rune } from '../phases/scope.js'; -import { reset_warnings } from '../warnings.js'; +import { reset } from '../state.js'; import { extract_identifiers } from '../utils/ast.js'; import { regex_is_valid_identifier } from '../phases/patterns.js'; @@ -17,7 +17,7 @@ import { regex_is_valid_identifier } from '../phases/patterns.js'; */ export function migrate(source) { try { - reset_warnings({ source, filename: 'migrate.svelte' }); + reset({ source, filename: 'migrate.svelte' }); let parsed = parse(source); diff --git a/packages/svelte/src/compiler/phases/1-parse/index.js b/packages/svelte/src/compiler/phases/1-parse/index.js index 69889bfce8..7e3b65cc9e 100644 --- a/packages/svelte/src/compiler/phases/1-parse/index.js +++ b/packages/svelte/src/compiler/phases/1-parse/index.js @@ -7,7 +7,7 @@ import full_char_code_at from './utils/full_char_code_at.js'; import * as e from '../../errors.js'; import { create_fragment } from './utils/create.js'; import read_options from './read/options.js'; -import { getLocator } from 'locate-character'; +import { locator } from '../../state.js'; const regex_position_indicator = / \(\d+:\d+\)$/; @@ -42,8 +42,6 @@ export class Parser { /** @type {LastAutoClosedTag | undefined} */ last_auto_closed_tag; - locate; - /** @param {string} template */ constructor(template) { if (typeof template !== 'string') { @@ -51,7 +49,6 @@ export class Parser { } this.template = template.trimEnd(); - this.locate = getLocator(this.template, { offsetLine: 1 }); let match_lang; @@ -137,18 +134,6 @@ export class Parser { } } - /** - * offset -> line/column - * @param {number} start - * @param {number} end - */ - get_location(start, end) { - return { - start: /** @type {import('locate-character').Location_1} */ (this.locate(start)), - end: /** @type {import('locate-character').Location_1} */ (this.locate(end)) - }; - } - current() { return this.stack[this.stack.length - 1]; } diff --git a/packages/svelte/src/compiler/phases/1-parse/read/context.js b/packages/svelte/src/compiler/phases/1-parse/read/context.js index 10cdaa44b7..1188fb8eb4 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/context.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/context.js @@ -10,6 +10,7 @@ import { import { parse_expression_at } from '../acorn.js'; import { regex_not_newline_characters } from '../../patterns.js'; import * as e from '../../../errors.js'; +import { locator } from '../../../state.js'; /** * @param {import('../index.js').Parser} parser @@ -29,7 +30,10 @@ export default function read_pattern(parser, optional_allowed = false) { type: 'Identifier', name, start, - loc: parser.get_location(start, parser.index), + loc: { + start: /** @type {import('locate-character').Location} */ (locator(start)), + end: /** @type {import('locate-character').Location} */ (locator(parser.index)) + }, end: parser.index, typeAnnotation: annotation }; 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 6bcf8aec47..1be8fa7b79 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 @@ -8,7 +8,6 @@ import { javascript_visitors_runes } from './visitors/javascript-runes.js'; import { javascript_visitors_legacy } from './visitors/javascript-legacy.js'; import { serialize_get_binding } from './utils.js'; import { render_stylesheet } from '../css/index.js'; -import { getLocator } from 'locate-character'; /** * This function ensures visitor sets don't accidentally clobber each other @@ -48,7 +47,6 @@ export function client_component(source, analysis, options) { scopes: analysis.template.scopes, hoisted: [b.import_all('$', 'svelte/internal/client')], node: /** @type {any} */ (null), // populated by the root node - source_locator: getLocator(source, { offsetLine: 1 }), // these should be set by create_block - if they're called outside, it's a bug get before_init() { /** @type {any[]} */ 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 13775bb8f4..7ec0dd6c4a 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 @@ -33,10 +33,6 @@ export interface ComponentClientTransformState extends ClientTransformState { readonly options: ValidatedCompileOptions; readonly hoisted: Array; readonly events: Set; - readonly source_locator: ( - search: string | number, - index?: number | undefined - ) => Location | undefined; /** Stuff that happens before the render effect(s) */ readonly before_init: Statement[]; diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js index 8db98930a8..34ffe66a87 100644 --- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js +++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js @@ -38,6 +38,7 @@ import { regex_is_valid_identifier } from '../../../patterns.js'; import { javascript_visitors_runes } from './javascript-runes.js'; import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js'; import { walk } from 'zimmerframe'; +import { locator } from '../../../../state.js'; /** * @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} element @@ -1841,7 +1842,7 @@ export const template_visitors = { let location = [-1, -1]; if (context.state.options.dev) { - const loc = context.state.source_locator(node.start); + const loc = locator(node.start); if (loc) { location[0] = loc.line; location[1] = loc.column; @@ -2192,7 +2193,7 @@ export const template_visitors = { }) ); - const location = context.state.options.dev && context.state.source_locator(node.start); + const location = context.state.options.dev && locator(node.start); context.state.init.push( b.stmt( diff --git a/packages/svelte/src/compiler/phases/3-transform/index.js b/packages/svelte/src/compiler/phases/3-transform/index.js index de246f6a9d..65bd202363 100644 --- a/packages/svelte/src/compiler/phases/3-transform/index.js +++ b/packages/svelte/src/compiler/phases/3-transform/index.js @@ -2,9 +2,9 @@ import { print } from 'esrap'; import { VERSION } from '../../../version.js'; import { server_component, server_module } from './server/transform-server.js'; import { client_component, client_module } from './client/transform-client.js'; -import { getLocator } from 'locate-character'; import { render_stylesheet } from './css/index.js'; import { merge_with_preprocessor_map, get_source_name } from '../../utils/mapped_code.js'; +import * as state from '../../state.js'; /** * @param {import('../types').ComponentAnalysis} analysis @@ -17,7 +17,7 @@ export function transform_component(analysis, source, options) { return { js: /** @type {any} */ (null), css: null, - warnings: /** @type {any} */ (null), // set afterwards + warnings: state.warnings, // set afterwards metadata: { runes: analysis.runes }, @@ -46,7 +46,7 @@ export function transform_component(analysis, source, options) { return { js, css, - warnings: /** @type {any} */ (null), // set afterwards. TODO apply preprocessor sourcemap + warnings: state.warnings, // set afterwards. TODO apply preprocessor sourcemap metadata: { runes: analysis.runes }, @@ -65,7 +65,7 @@ export function transform_module(analysis, source, options) { return { js: /** @type {any} */ (null), css: null, - warnings: /** @type {any} */ (null), // set afterwards + warnings: state.warnings, // set afterwards metadata: { runes: true }, @@ -94,7 +94,7 @@ export function transform_module(analysis, source, options) { metadata: { runes: true }, - warnings: /** @type {any} */ (null), // set afterwards + warnings: state.warnings, // set afterwards ast: /** @type {any} */ (null) // set afterwards }; } diff --git a/packages/svelte/src/compiler/state.js b/packages/svelte/src/compiler/state.js new file mode 100644 index 0000000000..e329f0077b --- /dev/null +++ b/packages/svelte/src/compiler/state.js @@ -0,0 +1,23 @@ +import { getLocator } from 'locate-character'; + +/** @typedef {{ start?: number, end?: number }} NodeLike */ + +/** @type {import('#compiler').Warning[]} */ +export let warnings = []; + +/** @type {string | undefined} */ +export let filename; + +export let locator = getLocator('', { offsetLine: 1 }); + +/** + * @param {{ + * source: string; + * filename: string | undefined; + * }} options + */ +export function reset(options) { + filename = options.filename; + locator = getLocator(options.source, { offsetLine: 1 }); + warnings = []; +} diff --git a/packages/svelte/src/compiler/warnings.js b/packages/svelte/src/compiler/warnings.js index b6c79bcb42..820a220b3d 100644 --- a/packages/svelte/src/compiler/warnings.js +++ b/packages/svelte/src/compiler/warnings.js @@ -1,27 +1,8 @@ /* This file is generated by scripts/process-messages/index.js. Do not edit! */ -import { getLocator } from 'locate-character'; +import { filename, locator, warnings } from './state.js'; /** @typedef {{ start?: number, end?: number }} NodeLike */ -/** @type {import('#compiler').Warning[]} */ -let warnings = []; -/** @type {string | undefined} */ -let filename; -let locator = getLocator('', { offsetLine: 1 }); - -/** - * @param {{ - * source: string; - * filename: string | undefined; - * }} options - * @returns {import('#compiler').Warning[]} - */ -export function reset_warnings(options) { - filename = options.filename; - locator = getLocator(options.source, { offsetLine: 1 }); - return warnings = []; -} - /** * @param {null | NodeLike} node * @param {string} code