references from the parser: is-reference goes, what the compiler builds is judged by position

goodbye-acorn
Nic 23 hours ago
parent 77f9de99aa
commit 2abd971127

@ -174,7 +174,7 @@
"dependencies": { "dependencies": {
"@jridgewell/remapping": "^2.3.5", "@jridgewell/remapping": "^2.3.5",
"@jridgewell/sourcemap-codec": "^1.6.0", "@jridgewell/sourcemap-codec": "^1.6.0",
"@teasel/parser": "link:../../../teasel/bindings/node", "@teasel/parser": "link:../../../teasel/package",
"@types/estree": "^1.0.9", "@types/estree": "^1.0.9",
"aria-query": "5.3.1", "aria-query": "5.3.1",
"axobject-query": "^4.1.0", "axobject-query": "^4.1.0",
@ -182,7 +182,6 @@
"devalue": "^5.9.2", "devalue": "^5.9.2",
"esm-env": "^1.2.1", "esm-env": "^1.2.1",
"esrap": "^2.3.6", "esrap": "^2.3.6",
"is-reference": "^3.0.3",
"locate-character": "^3.0.0", "locate-character": "^3.0.0",
"magic-string": "^0.30.11", "magic-string": "^0.30.11",
"zimmerframe": "^1.1.2" "zimmerframe": "^1.1.2"

@ -3,6 +3,7 @@
/** @import * as ESTree from 'estree' */ /** @import * as ESTree from 'estree' */
import { Source, isIdentifierStart, isIdentifierChar } from '@teasel/parser'; import { Source, isIdentifierStart, isIdentifierChar } from '@teasel/parser';
import fragment from './state/fragment.js'; import fragment from './state/fragment.js';
import { value_names } from '../../utils/ast.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';
@ -96,6 +97,7 @@ export class Parser {
typescript: this.ts && (erase ? 'erase' : true), typescript: this.ts && (erase ? 'erase' : true),
comments: true, comments: true,
locations: true, locations: true,
scopes: true,
// a script may export what the component declares elsewhere // a script may export what the component declares elsewhere
allowUndeclaredExports: true allowUndeclaredExports: true
}); });
@ -259,7 +261,8 @@ export class Parser {
} }
} }
return { /** @type {ESTree.Identifier & { start: number, end: number, loc: { start: Location, end: Location } }} */
const identifier = {
type: 'Identifier', type: 'Identifier',
name, name,
start, start,
@ -269,6 +272,8 @@ export class Parser {
end: state.locator(end) end: state.locator(end)
} }
}; };
value_names.add(identifier);
return identifier;
} }
/** @param {string} delimiter */ /** @param {string} delimiter */

@ -18,7 +18,8 @@ export function parse(source, comments, typescript) {
sourceType: 'module', sourceType: 'module',
typescript, typescript,
comments: true, comments: true,
locations: true locations: true,
scopes: true
}); });
} catch (err) { } catch (err) {
return handle_parse_error(err); return handle_parse_error(err);
@ -26,6 +27,8 @@ export function parse(source, comments, typescript) {
add_comments(source, comments, /** @type {teasel.Comment[]} */ (ast.comments)); add_comments(source, comments, /** @type {teasel.Comment[]} */ (ast.comments));
delete ast.comments; delete ast.comments;
delete ast.scopes;
delete ast.bindings;
return ast; return ast;
} }
@ -51,6 +54,8 @@ export function parse_script(parser, start, end) {
/** @type {teasel.Comment[]} */ (ast.comments) /** @type {teasel.Comment[]} */ (ast.comments)
); );
delete ast.comments; delete ast.comments;
delete ast.scopes;
delete ast.bindings;
unsupported(ast.typescript); unsupported(ast.typescript);
delete ast.typescript; delete ast.typescript;

@ -11,7 +11,7 @@ import * as e from '../../../errors.js';
import * as w from '../../../warnings.js'; import * as w from '../../../warnings.js';
import { create_fragment } from '../utils/create.js'; import { create_fragment } from '../utils/create.js';
import { create_attribute, ExpressionMetadata, is_element_node } from '../../nodes.js'; import { create_attribute, ExpressionMetadata, is_element_node } from '../../nodes.js';
import { get_attribute_expression, is_expression_attribute } from '../../../utils/ast.js'; import { get_attribute_expression, is_expression_attribute, value_names } from '../../../utils/ast.js';
import { closing_tag_omitted } from '../../../../html-tree-validation.js'; import { closing_tag_omitted } from '../../../../html-tree-validation.js';
import { list } from '../../../utils/string.js'; import { list } from '../../../utils/string.js';
import { locator } from '../../../state.js'; import { locator } from '../../../state.js';
@ -712,6 +712,7 @@ function read_attribute(parser) {
type: 'Identifier', type: 'Identifier',
name: directive.name name: directive.name
}); });
value_names.add(/** @type {Identifier} */ (directive.expression));
} }
return directive; return directive;
@ -949,7 +950,8 @@ function read_tag(parser, attribute = false) {
const name = read_tag_name(parser, attribute); const name = read_tag_name(parser, attribute);
const end = parser.index; const end = parser.index;
return { /** @type {Identifier & { start: number, end: number, loc: SourceLocation }} */
const identifier = {
type: 'Identifier', type: 'Identifier',
name, name,
start, start,
@ -959,6 +961,8 @@ function read_tag(parser, attribute = false) {
end: locator(end) end: locator(end)
} }
}; };
value_names.add(identifier);
return identifier;
} }
/** @param {Parser} parser */ /** @param {Parser} parser */

@ -9,6 +9,7 @@ import * as w from '../../warnings.js';
import { import {
extract_identifiers, extract_identifiers,
has_await_expression, has_await_expression,
is_reference,
object, object,
unwrap_pattern unwrap_pattern
} from '../../utils/ast.js'; } from '../../utils/ast.js';
@ -83,7 +84,6 @@ import { TransitionDirective } from './visitors/TransitionDirective.js';
import { UpdateExpression } from './visitors/UpdateExpression.js'; import { UpdateExpression } from './visitors/UpdateExpression.js';
import { UseDirective } from './visitors/UseDirective.js'; 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 { mark_subtree_dynamic } from './visitors/shared/fragment.js'; import { mark_subtree_dynamic } from './visitors/shared/fragment.js';
import * as state from '../../state.js'; import * as state from '../../state.js';
@ -657,9 +657,7 @@ export function analyze_component(root, source, options) {
// @ts-expect-error // @ts-expect-error
_: set_scope, _: set_scope,
Identifier(node, context) { Identifier(node, context) {
const parent = /** @type {ESTree.Expression} */ (context.path.at(-1)); if (is_reference(node, context.path.at(-1))) {
if (is_reference(node, parent)) {
const binding = context.state.scope.get(node.name); const binding = context.state.scope.get(node.name);
if ( if (
@ -981,8 +979,7 @@ function calculate_blockers(instance, analysis) {
}, },
ImportDeclaration(node) {}, ImportDeclaration(node) {},
Identifier(node, context) { Identifier(node, context) {
const parent = /** @type {ESTree.Node} */ (context.path.at(-1)); if (is_reference(node, context.path.at(-1))) {
if (is_reference(node, parent)) {
const binding = context.state.scope.get(node.name); const binding = context.state.scope.get(node.name);
if (binding) { if (binding) {
touched.add(binding); touched.add(binding);
@ -1059,8 +1056,7 @@ function calculate_blockers(instance, analysis) {
touch(node, context.state.scope, writes, writes_seen); touch(node, context.state.scope, writes, writes_seen);
}, },
Identifier(node, context) { Identifier(node, context) {
const parent = /** @type {ESTree.Node} */ (context.path.at(-1)); if (is_reference(node, context.path.at(-1))) {
if (is_reference(node, parent)) {
const binding = context.state.scope.get(node.name); const binding = context.state.scope.get(node.name);
if (binding) { if (binding) {
reads.add(binding); reads.add(binding);

@ -1,7 +1,7 @@
/** @import { Expression, Identifier } from 'estree' */ /** @import { Expression, Identifier } from 'estree' */
/** @import { Context } from '../types' */ /** @import { Context } from '../types' */
import is_reference from 'is-reference';
import { should_proxy } from '../../3-transform/client/utils.js'; import { should_proxy } from '../../3-transform/client/utils.js';
import { is_reference } from '../../../utils/ast.js';
import * as e from '../../../errors.js'; import * as e from '../../../errors.js';
import * as w from '../../../warnings.js'; import * as w from '../../../warnings.js';
import { is_rune } from '../../../../utils.js'; import { is_rune } from '../../../../utils.js';

@ -1,7 +1,7 @@
/** @import { Identifier, Node } from 'estree' */ /** @import { Identifier, Node } from 'estree' */
/** @import { Context } from '../types' */ /** @import { Context } from '../types' */
import is_reference from 'is-reference';
import * as b from '#compiler/builders'; import * as b from '#compiler/builders';
import { is_reference } from '../../../../utils/ast.js';
import { build_getter } from '../utils.js'; import { build_getter } from '../utils.js';
/** /**

@ -2,11 +2,10 @@
/** @import { AST } from '#compiler' */ /** @import { AST } from '#compiler' */
/** @import { ComponentClientTransformState, ComponentContext, Context } from '../../types' */ /** @import { ComponentClientTransformState, ComponentContext, Context } from '../../types' */
import { walk } from 'zimmerframe'; import { walk } from 'zimmerframe';
import { object } from '../../../../../utils/ast.js'; import { is_reference, object } from '../../../../../utils/ast.js';
import * as b from '#compiler/builders'; import * as b from '#compiler/builders';
import { sanitize_template_string } from '../../../../../utils/sanitize_template_string.js'; import { sanitize_template_string } from '../../../../../utils/sanitize_template_string.js';
import { regex_is_valid_identifier } from '../../../../patterns.js'; import { regex_is_valid_identifier } from '../../../../patterns.js';
import is_reference from 'is-reference';
import { dev, is_ignored, locator, component_name } from '../../../../../state.js'; import { dev, is_ignored, locator, component_name } from '../../../../../state.js';
import { async_thunk, build_getter, is_state_source } from '../../utils.js'; import { async_thunk, build_getter, is_state_source } from '../../utils.js';
import { ExpressionMetadata } from '../../../../nodes.js'; import { ExpressionMetadata } from '../../../../nodes.js';
@ -266,8 +265,7 @@ export function build_bind_this(expression, value, { state, visit }) {
if (seen.includes(node.name)) return; if (seen.includes(node.name)) return;
seen.push(node.name); seen.push(node.name);
const parent = /** @type {Expression} */ (path.at(-1)); if (!is_reference(node, path.at(-1))) return;
if (!is_reference(node, parent)) return;
const binding = state.scope.get(node.name); const binding = state.scope.get(node.name);
if (!binding) return; if (!binding) return;

@ -1,7 +1,7 @@
/** @import { Identifier, Node } from 'estree' */ /** @import { Identifier } from 'estree' */
/** @import { Context } from '../types.js' */ /** @import { Context } from '../types.js' */
import is_reference from 'is-reference';
import * as b from '#compiler/builders'; import * as b from '#compiler/builders';
import { is_reference } from '../../../../utils/ast.js';
import { build_getter } from './shared/utils.js'; import { build_getter } from './shared/utils.js';
/** /**
@ -9,7 +9,7 @@ import { build_getter } from './shared/utils.js';
* @param {Context} context * @param {Context} context
*/ */
export function Identifier(node, context) { export function Identifier(node, context) {
if (is_reference(node, /** @type {Node} */ (context.path.at(-1)))) { if (is_reference(node, context.path.at(-1))) {
if (node.name === '$$props') { if (node.name === '$$props') {
return b.id('$$sanitized_props'); return b.id('$$sanitized_props');
} }

@ -8,9 +8,8 @@ import {
} from '../patterns.js'; } from '../patterns.js';
import * as e from '../../errors.js'; import * as e from '../../errors.js';
import { walk } from 'zimmerframe'; import { walk } from 'zimmerframe';
import { extract_identifiers } from '../../utils/ast.js'; import { extract_identifiers, is_reference } from '../../utils/ast.js';
import check_graph_for_cycles from '../2-analyze/utils/check_graph_for_cycles.js'; import check_graph_for_cycles from '../2-analyze/utils/check_graph_for_cycles.js';
import is_reference from 'is-reference';
import { set_scope } from '../scope.js'; import { set_scope } from '../scope.js';
/** /**
@ -46,9 +45,7 @@ function sort_const_tags(nodes, state) {
// @ts-expect-error don't know, don't care // @ts-expect-error don't know, don't care
_: set_scope, _: set_scope,
Identifier(node, context) { Identifier(node, context) {
const parent = /** @type {Expression} */ (context.path.at(-1)); if (is_reference(node, context.path.at(-1))) {
if (is_reference(node, parent)) {
const binding = context.state.scope.get(node.name); const binding = context.state.scope.get(node.name);
if (binding) deps.add(binding); if (binding) deps.add(binding);
} }

@ -1,7 +1,6 @@
/** @import { BinaryOperator, ClassDeclaration, Expression, FunctionDeclaration, Identifier, ImportDeclaration, MemberExpression, LogicalOperator, Node, Pattern, UnaryOperator, VariableDeclarator, Super, SimpleLiteral, FunctionExpression, ArrowFunctionExpression } from 'estree' */ /** @import { BinaryOperator, ClassDeclaration, Expression, FunctionDeclaration, Identifier, ImportDeclaration, MemberExpression, LogicalOperator, Node, Pattern, UnaryOperator, VariableDeclarator, Super, SimpleLiteral, FunctionExpression, ArrowFunctionExpression } from 'estree' */
/** @import { Context, Visitor } from 'zimmerframe' */ /** @import { Context, Visitor } from 'zimmerframe' */
/** @import { AST, BindingKind, DeclarationKind } from '#compiler' */ /** @import { AST, BindingKind, DeclarationKind } from '#compiler' */
import is_reference from 'is-reference';
import { walk } from 'zimmerframe'; import { walk } from 'zimmerframe';
import { ExpressionMetadata } from './nodes.js'; import { ExpressionMetadata } from './nodes.js';
import * as b from '#compiler/builders'; import * as b from '#compiler/builders';
@ -9,6 +8,7 @@ import * as e from '../errors.js';
import { import {
extract_identifiers, extract_identifiers,
extract_identifiers_from_destructuring, extract_identifiers_from_destructuring,
is_reference,
object, object,
unwrap_pattern unwrap_pattern
} from '../utils/ast.js'; } from '../utils/ast.js';
@ -1046,17 +1046,8 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
context.next(); context.next();
}, },
// references
Identifier(node, { path, state }) { Identifier(node, { path, state }) {
const parent = path.at(-1); if (is_reference(node, path.at(-1))) {
if (
parent &&
is_reference(node, /** @type {Node} */ (parent)) &&
// TSTypeAnnotation, TSInterfaceDeclaration etc - these are normally already filtered out,
// but for the migration they aren't, so we need to filter them out here
// TODO -> once migration script is gone we can remove this check
!parent.type.startsWith('TS')
) {
references.push([state.scope, { node, path: path.slice() }]); references.push([state.scope, { node, path: path.slice() }]);
} }
}, },

@ -1,6 +1,7 @@
/** @import { AST, Scope } from '#compiler' */ /** @import { AST, Scope } from '#compiler' */
/** @import * as ESTree from 'estree' */ /** @import * as ESTree from 'estree' */
import { walk } from 'zimmerframe'; import { walk } from 'zimmerframe';
import { bindingOf } from '@teasel/parser';
import * as b from '#compiler/builders'; import * as b from '#compiler/builders';
/** /**
@ -634,3 +635,36 @@ export function has_await_expression(node) {
export function save(expression) { export function save(expression) {
return b.call(b.await(b.call('$.save', expression))); return b.call(b.await(b.call('$.save', expression)));
} }
/** @type {WeakSet<ESTree.Identifier>} the identifiers the parser makes itself for names in template syntax */
export const value_names = new WeakSet();
/**
* Whether an identifier names a value. The parser answers for what it parsed and marks what it
* made; an identifier the compiler built is judged by where it sits.
* @param {ESTree.Identifier} node
* @param {ESTree.Node | AST.SvelteNode | null | undefined} parent
*/
export function is_reference(node, parent) {
const binding = bindingOf(node);
if (binding !== undefined || value_names.has(node)) return true;
if (!parent) return true;
switch (parent.type) {
case 'MemberExpression':
return parent.computed || node === parent.object;
case 'MethodDefinition':
return parent.computed;
case 'PropertyDefinition':
case 'Property':
return parent.computed || node === parent.value;
case 'ExportSpecifier':
case 'ImportSpecifier':
return node === parent.local;
case 'LabeledStatement':
case 'BreakStatement':
case 'ContinueStatement':
return false;
default:
return !parent.type.startsWith('TS');
}
}

@ -75,8 +75,8 @@ importers:
specifier: ^1.6.0 specifier: ^1.6.0
version: 1.6.0 version: 1.6.0
'@teasel/parser': '@teasel/parser':
specifier: link:../../../teasel/bindings/node specifier: link:../../../teasel/package
version: link:../../../teasel/bindings/node version: link:../../../teasel/package
'@types/estree': '@types/estree':
specifier: ^1.0.9 specifier: ^1.0.9
version: 1.0.9 version: 1.0.9
@ -98,9 +98,6 @@ importers:
esrap: esrap:
specifier: ^2.3.6 specifier: ^2.3.6
version: 2.3.6(@typescript-eslint/types@8.59.4) version: 2.3.6(@typescript-eslint/types@8.59.4)
is-reference:
specifier: ^3.0.3
version: 3.0.3
locate-character: locate-character:
specifier: ^3.0.0 specifier: ^3.0.0
version: 3.0.0 version: 3.0.0
@ -1642,9 +1639,6 @@ packages:
is-reference@1.2.1: is-reference@1.2.1:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
is-reference@3.0.3:
resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==}
is-subdir@1.2.0: is-subdir@1.2.0:
resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==}
engines: {node: '>=4'} engines: {node: '>=4'}
@ -3854,10 +3848,6 @@ snapshots:
dependencies: dependencies:
'@types/estree': 1.0.9 '@types/estree': 1.0.9
is-reference@3.0.3:
dependencies:
'@types/estree': 1.0.9
is-subdir@1.2.0: is-subdir@1.2.0:
dependencies: dependencies:
better-path-resolve: 1.0.0 better-path-resolve: 1.0.0

Loading…
Cancel
Save