chore: move stuff from `analysis` into global compiler state (#16268)

* break out locator stuff from the rest of global state

* move some stuff around

* tighten up

* make runes globally available

* make component_name globally available

* unused
pull/16140/merge
Rich Harris 3 months ago committed by GitHub
parent b673145659
commit eb530c82c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -20,9 +20,8 @@ export { default as preprocess } from './preprocess/index.js';
*/ */
export function compile(source, options) { export function compile(source, options) {
source = remove_bom(source); source = remove_bom(source);
state.reset_warning_filter(options.warningFilter); state.reset_warnings(options.warningFilter);
const validated = validate_component_options(options, ''); const validated = validate_component_options(options, '');
state.reset(source, validated);
let parsed = _parse(source); let parsed = _parse(source);
@ -64,9 +63,8 @@ export function compile(source, options) {
*/ */
export function compileModule(source, options) { export function compileModule(source, options) {
source = remove_bom(source); source = remove_bom(source);
state.reset_warning_filter(options.warningFilter); state.reset_warnings(options.warningFilter);
const validated = validate_module_options(options, ''); const validated = validate_module_options(options, '');
state.reset(source, validated);
const analysis = analyze_module(source, validated); const analysis = analyze_module(source, validated);
return transform_module(analysis, source, validated); return transform_module(analysis, source, validated);
@ -96,6 +94,7 @@ export function compileModule(source, options) {
* @returns {Record<string, any>} * @returns {Record<string, any>}
*/ */
// TODO 6.0 remove unused `filename`
/** /**
* The parse function parses a component, returning only its abstract syntax tree. * The parse function parses a component, returning only its abstract syntax tree.
* *
@ -104,14 +103,15 @@ export function compileModule(source, options) {
* *
* The `loose` option, available since 5.13.0, tries to always return an AST even if the input will not successfully compile. * The `loose` option, available since 5.13.0, tries to always return an AST even if the input will not successfully compile.
* *
* The `filename` option is unused and will be removed in Svelte 6.0.
*
* @param {string} source * @param {string} source
* @param {{ filename?: string; rootDir?: string; modern?: boolean; loose?: boolean }} [options] * @param {{ filename?: string; rootDir?: string; modern?: boolean; loose?: boolean }} [options]
* @returns {AST.Root | LegacyRoot} * @returns {AST.Root | LegacyRoot}
*/ */
export function parse(source, { filename, rootDir, modern, loose } = {}) { export function parse(source, { modern, loose } = {}) {
source = remove_bom(source); source = remove_bom(source);
state.reset_warning_filter(() => false); state.reset_warnings(() => false);
state.reset(source, { filename: filename ?? '(unknown)', rootDir });
const ast = _parse(source, loose); const ast = _parse(source, loose);
return to_public_ast(source, ast, modern); return to_public_ast(source, ast, modern);

@ -9,7 +9,7 @@ import { parse } from '../phases/1-parse/index.js';
import { regex_valid_component_name } from '../phases/1-parse/state/element.js'; import { regex_valid_component_name } from '../phases/1-parse/state/element.js';
import { analyze_component } from '../phases/2-analyze/index.js'; import { analyze_component } from '../phases/2-analyze/index.js';
import { get_rune } from '../phases/scope.js'; import { get_rune } from '../phases/scope.js';
import { reset, reset_warning_filter } from '../state.js'; import { reset, reset_warnings } from '../state.js';
import { import {
extract_identifiers, extract_identifiers,
extract_all_identifiers_from_expression, extract_all_identifiers_from_expression,
@ -134,8 +134,7 @@ export function migrate(source, { filename, use_ts } = {}) {
return start + style_placeholder + end; return start + style_placeholder + end;
}); });
reset_warning_filter(() => false); reset_warnings(() => false);
reset(source, { filename: filename ?? '(unknown)' });
let parsed = parse(source); let parsed = parse(source);

@ -9,6 +9,7 @@ import { create_fragment } from './utils/create.js';
import read_options from './read/options.js'; import read_options from './read/options.js';
import { is_reserved } from '../../../utils.js'; import { is_reserved } from '../../../utils.js';
import { disallow_children } from '../2-analyze/visitors/shared/special-element.js'; import { disallow_children } from '../2-analyze/visitors/shared/special-element.js';
import * as state from '../../state.js';
const regex_position_indicator = / \(\d+:\d+\)$/; const regex_position_indicator = / \(\d+:\d+\)$/;
@ -301,6 +302,8 @@ export class Parser {
* @returns {AST.Root} * @returns {AST.Root}
*/ */
export function parse(template, loose = false) { export function parse(template, loose = false) {
state.set_source(template);
const parser = new Parser(template, loose); const parser = new Parser(template, loose);
return parser.root; return parser.root;
} }

@ -76,6 +76,7 @@ import { UseDirective } from './visitors/UseDirective.js';
import { VariableDeclarator } from './visitors/VariableDeclarator.js'; import { VariableDeclarator } from './visitors/VariableDeclarator.js';
import is_reference from 'is-reference'; import is_reference from 'is-reference';
import { mark_subtree_dynamic } from './visitors/shared/fragment.js'; import { mark_subtree_dynamic } from './visitors/shared/fragment.js';
import * as state from '../../state.js';
/** /**
* @type {Visitors} * @type {Visitors}
@ -240,6 +241,7 @@ export function analyze_module(source, options) {
/** @type {AST.JSComment[]} */ /** @type {AST.JSComment[]} */
const comments = []; const comments = [];
state.set_source(source);
const ast = parse(source, comments, false, false); const ast = parse(source, comments, false, false);
const { scope, scopes } = create_scopes(ast, new ScopeRoot(), false, null); const { scope, scopes } = create_scopes(ast, new ScopeRoot(), false, null);
@ -269,6 +271,13 @@ export function analyze_module(source, options) {
classes: new Map() classes: new Map()
}; };
state.reset({
dev: options.dev,
filename: options.filename,
rootDir: options.rootDir,
runes: true
});
walk( walk(
/** @type {Node} */ (ast), /** @type {Node} */ (ast),
{ {
@ -506,6 +515,14 @@ export function analyze_component(root, source, options) {
snippets: new Set() snippets: new Set()
}; };
state.reset({
component_name: analysis.name,
dev: options.dev,
filename: options.filename,
rootDir: options.rootDir,
runes: true
});
if (!runes) { if (!runes) {
// every exported `let` or `var` declaration becomes a prop, everything else becomes an export // every exported `let` or `var` declaration becomes a prop, everything else becomes an export
for (const node of instance.ast.body) { for (const node of instance.ast.body) {

@ -34,7 +34,9 @@ export interface ReactiveStatement {
*/ */
export interface Analysis { export interface Analysis {
module: Js; module: Js;
/** @deprecated use `component_name` from `state.js` instead */
name: string; // TODO should this be filename? it's used in `compileModule` as well as `compile` name: string; // TODO should this be filename? it's used in `compileModule` as well as `compile`
/** @deprecated use `runes` from `state.js` instead */
runes: boolean; runes: boolean;
immutable: boolean; immutable: boolean;
tracing: boolean; tracing: boolean;
@ -90,6 +92,7 @@ export interface ComponentAnalysis extends Analysis {
keyframes: string[]; keyframes: string[];
has_global: boolean; has_global: boolean;
}; };
/** @deprecated use `source` from `state.js` instead */
source: string; source: string;
undefined_exports: Map<string, Node>; undefined_exports: Map<string, Node>;
/** /**

@ -16,6 +16,8 @@ export let warnings = [];
*/ */
export let filename; export let filename;
export let component_name = '<unknown>';
/** /**
* The original source code * The original source code
* @type {string} * @type {string}
@ -28,8 +30,16 @@ export let source;
*/ */
export let dev; export let dev;
export let runes = false;
export let locator = getLocator('', { offsetLine: 1 }); export let locator = getLocator('', { offsetLine: 1 });
/** @param {string} value */
export function set_source(value) {
source = value;
locator = getLocator(source, { offsetLine: 1 });
}
/** /**
* @param {AST.SvelteNode & { start?: number | undefined }} node * @param {AST.SvelteNode & { start?: number | undefined }} node
*/ */
@ -71,8 +81,9 @@ export function pop_ignore() {
* *
* @param {(warning: Warning) => boolean} fn * @param {(warning: Warning) => boolean} fn
*/ */
export function reset_warning_filter(fn = () => true) { export function reset_warnings(fn = () => true) {
warning_filter = fn; warning_filter = fn;
warnings = [];
} }
/** /**
@ -85,23 +96,27 @@ export function is_ignored(node, code) {
} }
/** /**
* @param {string} _source * @param {{
* @param {{ dev?: boolean; filename: string; rootDir?: string }} options * dev: boolean;
* filename: string;
* component_name?: string;
* rootDir?: string;
* runes: boolean;
* }} state
*/ */
export function reset(_source, options) { export function reset(state) {
source = _source; const root_dir = state.rootDir?.replace(/\\/g, '/');
const root_dir = options.rootDir?.replace(/\\/g, '/'); filename = state.filename.replace(/\\/g, '/');
filename = options.filename.replace(/\\/g, '/');
dev = !!options.dev; dev = state.dev;
runes = state.runes;
component_name = state.component_name ?? '(unknown)';
if (typeof root_dir === 'string' && filename.startsWith(root_dir)) { if (typeof root_dir === 'string' && filename.startsWith(root_dir)) {
// make filename relative to rootDir // make filename relative to rootDir
filename = filename.replace(root_dir, '').replace(/^[/\\]/, ''); filename = filename.replace(root_dir, '').replace(/^[/\\]/, '');
} }
locator = getLocator(source, { offsetLine: 1 });
warnings = [];
ignore_stack = []; ignore_stack = [];
ignore_map.clear(); ignore_map.clear();
} }

Loading…
Cancel
Save