chore: dedupe `getLocator` calls (#11600)

...by introducing global compiler state that is reset between iterations
pull/11606/head
Rich Harris 8 months ago committed by GitHub
parent 5cb432b7bd
commit ac7709f65c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,29 +1,7 @@
import { getLocator } from 'locate-character'; import { filename, locator, warnings } from './state.js';
/** @typedef {{ start?: number, end?: number }} NodeLike */ /** @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 {null | NodeLike} node
* @param {string} code * @param {string} code

@ -1,4 +1,3 @@
import { getLocator } from 'locate-character';
import { walk as zimmerframe_walk } from 'zimmerframe'; import { walk as zimmerframe_walk } from 'zimmerframe';
import { CompileError } from './errors.js'; import { CompileError } from './errors.js';
import { convert } from './legacy.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 { analyze_component, analyze_module } from './phases/2-analyze/index.js';
import { transform_component, transform_module } from './phases/3-transform/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 { 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'; 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) { export function compile(source, options) {
try { try {
const warnings = reset_warnings({ source, filename: options.filename }); state.reset({ source, filename: options.filename });
const validated = validate_component_options(options, ''); const validated = validate_component_options(options, '');
let parsed = _parse(source); let parsed = _parse(source);
@ -44,9 +44,7 @@ export function compile(source, options) {
} }
const analysis = analyze_component(parsed, source, combined_options); const analysis = analyze_component(parsed, source, combined_options);
const result = transform_component(analysis, source, combined_options); const result = transform_component(analysis, source, combined_options);
result.warnings = warnings;
result.ast = to_public_ast(source, parsed, options.modernAst); result.ast = to_public_ast(source, parsed, options.modernAst);
return result; return result;
} catch (e) { } catch (e) {
@ -68,11 +66,11 @@ export function compile(source, options) {
*/ */
export function compileModule(source, options) { export function compileModule(source, options) {
try { try {
const warnings = reset_warnings({ source, filename: options.filename }); state.reset({ source, filename: options.filename });
const validated = validate_module_options(options, ''); const validated = validate_module_options(options, '');
const analysis = analyze_module(parse_acorn(source, false), validated); const analysis = analyze_module(parse_acorn(source, false), validated);
const result = transform_module(analysis, source, validated); const result = transform_module(analysis, source, validated);
result.warnings = warnings;
return result; return result;
} catch (e) { } catch (e) {
if (e instanceof CompileError) { if (e instanceof CompileError) {
@ -92,10 +90,8 @@ function handle_compile_error(error, filename, source) {
error.filename = filename; error.filename = filename;
if (error.position) { if (error.position) {
// TODO this is reused with warnings — DRY out const start = state.locator(error.position[0]);
const locator = getLocator(source, { offsetLine: 1 }); const end = state.locator(error.position[1]);
const start = locator(error.position[0]);
const end = locator(error.position[1]);
error.start = start; error.start = start;
error.end = end; error.end = end;
@ -142,6 +138,8 @@ function handle_compile_error(error, filename, source) {
* @returns {import('#compiler').Root | import('./types/legacy-nodes.js').LegacyRoot} * @returns {import('#compiler').Root | import('./types/legacy-nodes.js').LegacyRoot}
*/ */
export function parse(source, options = {}) { export function parse(source, options = {}) {
state.reset({ source, filename: options.filename });
/** @type {import('#compiler').Root} */ /** @type {import('#compiler').Root} */
let ast; let ast;
try { try {

@ -4,7 +4,7 @@ import { parse } from '../phases/1-parse/index.js';
import { analyze_component } from '../phases/2-analyze/index.js'; import { analyze_component } from '../phases/2-analyze/index.js';
import { validate_component_options } from '../validate-options.js'; import { validate_component_options } from '../validate-options.js';
import { get_rune } from '../phases/scope.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 { extract_identifiers } from '../utils/ast.js';
import { regex_is_valid_identifier } from '../phases/patterns.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) { export function migrate(source) {
try { try {
reset_warnings({ source, filename: 'migrate.svelte' }); reset({ source, filename: 'migrate.svelte' });
let parsed = parse(source); let parsed = parse(source);

@ -7,7 +7,7 @@ import full_char_code_at from './utils/full_char_code_at.js';
import * as e from '../../errors.js'; import * as e from '../../errors.js';
import { create_fragment } from './utils/create.js'; import { create_fragment } from './utils/create.js';
import read_options from './read/options.js'; import read_options from './read/options.js';
import { getLocator } from 'locate-character'; import { locator } from '../../state.js';
const regex_position_indicator = / \(\d+:\d+\)$/; const regex_position_indicator = / \(\d+:\d+\)$/;
@ -42,8 +42,6 @@ export class Parser {
/** @type {LastAutoClosedTag | undefined} */ /** @type {LastAutoClosedTag | undefined} */
last_auto_closed_tag; last_auto_closed_tag;
locate;
/** @param {string} template */ /** @param {string} template */
constructor(template) { constructor(template) {
if (typeof template !== 'string') { if (typeof template !== 'string') {
@ -51,7 +49,6 @@ export class Parser {
} }
this.template = template.trimEnd(); this.template = template.trimEnd();
this.locate = getLocator(this.template, { offsetLine: 1 });
let match_lang; 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() { current() {
return this.stack[this.stack.length - 1]; return this.stack[this.stack.length - 1];
} }

@ -10,6 +10,7 @@ import {
import { parse_expression_at } from '../acorn.js'; import { parse_expression_at } from '../acorn.js';
import { regex_not_newline_characters } from '../../patterns.js'; import { regex_not_newline_characters } from '../../patterns.js';
import * as e from '../../../errors.js'; import * as e from '../../../errors.js';
import { locator } from '../../../state.js';
/** /**
* @param {import('../index.js').Parser} parser * @param {import('../index.js').Parser} parser
@ -29,7 +30,10 @@ export default function read_pattern(parser, optional_allowed = false) {
type: 'Identifier', type: 'Identifier',
name, name,
start, 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, end: parser.index,
typeAnnotation: annotation typeAnnotation: annotation
}; };

@ -8,7 +8,6 @@ import { javascript_visitors_runes } from './visitors/javascript-runes.js';
import { javascript_visitors_legacy } from './visitors/javascript-legacy.js'; import { javascript_visitors_legacy } from './visitors/javascript-legacy.js';
import { serialize_get_binding } from './utils.js'; import { serialize_get_binding } from './utils.js';
import { render_stylesheet } from '../css/index.js'; import { render_stylesheet } from '../css/index.js';
import { getLocator } from 'locate-character';
/** /**
* This function ensures visitor sets don't accidentally clobber each other * 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, scopes: analysis.template.scopes,
hoisted: [b.import_all('$', 'svelte/internal/client')], hoisted: [b.import_all('$', 'svelte/internal/client')],
node: /** @type {any} */ (null), // populated by the root node 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 // these should be set by create_block - if they're called outside, it's a bug
get before_init() { get before_init() {
/** @type {any[]} */ /** @type {any[]} */

@ -33,10 +33,6 @@ export interface ComponentClientTransformState extends ClientTransformState {
readonly options: ValidatedCompileOptions; readonly options: ValidatedCompileOptions;
readonly hoisted: Array<Statement | ModuleDeclaration>; readonly hoisted: Array<Statement | ModuleDeclaration>;
readonly events: Set<string>; readonly events: Set<string>;
readonly source_locator: (
search: string | number,
index?: number | undefined
) => Location | undefined;
/** Stuff that happens before the render effect(s) */ /** Stuff that happens before the render effect(s) */
readonly before_init: Statement[]; readonly before_init: Statement[];

@ -38,6 +38,7 @@ import { regex_is_valid_identifier } from '../../../patterns.js';
import { javascript_visitors_runes } from './javascript-runes.js'; import { javascript_visitors_runes } from './javascript-runes.js';
import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js'; import { sanitize_template_string } from '../../../../utils/sanitize_template_string.js';
import { walk } from 'zimmerframe'; import { walk } from 'zimmerframe';
import { locator } from '../../../../state.js';
/** /**
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} element * @param {import('#compiler').RegularElement | import('#compiler').SvelteElement} element
@ -1841,7 +1842,7 @@ export const template_visitors = {
let location = [-1, -1]; let location = [-1, -1];
if (context.state.options.dev) { if (context.state.options.dev) {
const loc = context.state.source_locator(node.start); const loc = locator(node.start);
if (loc) { if (loc) {
location[0] = loc.line; location[0] = loc.line;
location[1] = loc.column; 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( context.state.init.push(
b.stmt( b.stmt(

@ -2,9 +2,9 @@ import { print } from 'esrap';
import { VERSION } from '../../../version.js'; import { VERSION } from '../../../version.js';
import { server_component, server_module } from './server/transform-server.js'; import { server_component, server_module } from './server/transform-server.js';
import { client_component, client_module } from './client/transform-client.js'; import { client_component, client_module } from './client/transform-client.js';
import { getLocator } from 'locate-character';
import { render_stylesheet } from './css/index.js'; import { render_stylesheet } from './css/index.js';
import { merge_with_preprocessor_map, get_source_name } from '../../utils/mapped_code.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 * @param {import('../types').ComponentAnalysis} analysis
@ -17,7 +17,7 @@ export function transform_component(analysis, source, options) {
return { return {
js: /** @type {any} */ (null), js: /** @type {any} */ (null),
css: null, css: null,
warnings: /** @type {any} */ (null), // set afterwards warnings: state.warnings, // set afterwards
metadata: { metadata: {
runes: analysis.runes runes: analysis.runes
}, },
@ -46,7 +46,7 @@ export function transform_component(analysis, source, options) {
return { return {
js, js,
css, css,
warnings: /** @type {any} */ (null), // set afterwards. TODO apply preprocessor sourcemap warnings: state.warnings, // set afterwards. TODO apply preprocessor sourcemap
metadata: { metadata: {
runes: analysis.runes runes: analysis.runes
}, },
@ -65,7 +65,7 @@ export function transform_module(analysis, source, options) {
return { return {
js: /** @type {any} */ (null), js: /** @type {any} */ (null),
css: null, css: null,
warnings: /** @type {any} */ (null), // set afterwards warnings: state.warnings, // set afterwards
metadata: { metadata: {
runes: true runes: true
}, },
@ -94,7 +94,7 @@ export function transform_module(analysis, source, options) {
metadata: { metadata: {
runes: true runes: true
}, },
warnings: /** @type {any} */ (null), // set afterwards warnings: state.warnings, // set afterwards
ast: /** @type {any} */ (null) // set afterwards ast: /** @type {any} */ (null) // set afterwards
}; };
} }

@ -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 = [];
}

@ -1,27 +1,8 @@
/* This file is generated by scripts/process-messages/index.js. Do not edit! */ /* 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 */ /** @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 {null | NodeLike} node
* @param {string} code * @param {string} code

Loading…
Cancel
Save