Skip to content

Commit

Permalink
feat: Expose more AST types from "svelte/compiler" (#14601)
Browse files Browse the repository at this point in the history
* add missing `SvelteBoundary` in `ElementLike`

* make union of AST types public and exportable with `AST` namespace

* apply AST types change to codebase

* changeset

* manually generate types

* Add `AttributeLike` type

* export namespace `Css` inside `AST`

* manually generate types again

* exported `Css` -> `CSS`

* `Css` -> `AST.CSS`

* fix Prettier issue

* Apply suggestions from code review

---------

Co-authored-by: Rich Harris <[email protected]>
  • Loading branch information
xeho91 and Rich-Harris authored Dec 12, 2024
1 parent 2e0dcd7 commit 61a0da8
Show file tree
Hide file tree
Showing 50 changed files with 343 additions and 303 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-papayas-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': minor
---

feat: expose more AST types from `"svelte/compiler"`
6 changes: 3 additions & 3 deletions packages/svelte/src/compiler/legacy.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @import { Expression } from 'estree' */
/** @import { AST, SvelteNode, TemplateNode } from '#compiler' */
/** @import { AST } from '#compiler' */
/** @import * as Legacy from './types/legacy-nodes.js' */
import { walk } from 'zimmerframe';
import {
Expand All @@ -11,7 +11,7 @@ import { extract_svelte_ignore } from './utils/extract_svelte_ignore.js';

/**
* Some of the legacy Svelte AST nodes remove whitespace from the start and end of their children.
* @param {TemplateNode[]} nodes
* @param {AST.TemplateNode[]} nodes
*/
function remove_surrounding_whitespace_nodes(nodes) {
const first = nodes.at(0);
Expand Down Expand Up @@ -40,7 +40,7 @@ function remove_surrounding_whitespace_nodes(nodes) {
* @returns {Legacy.LegacyRoot}
*/
export function convert(source, ast) {
const root = /** @type {SvelteNode | Legacy.LegacySvelteNode} */ (ast);
const root = /** @type {AST.SvelteNode | Legacy.LegacySvelteNode} */ (ast);

return /** @type {Legacy.LegacyRoot} */ (
walk(root, null, {
Expand Down
10 changes: 5 additions & 5 deletions packages/svelte/src/compiler/migrate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/** @import { Visitors } from 'zimmerframe' */
/** @import { ComponentAnalysis } from '../phases/types.js' */
/** @import { Scope, ScopeRoot } from '../phases/scope.js' */
/** @import { AST, Binding, SvelteNode, ValidatedCompileOptions } from '#compiler' */
/** @import { AST, Binding, ValidatedCompileOptions } from '#compiler' */
import MagicString from 'magic-string';
import { walk } from 'zimmerframe';
import { parse } from '../phases/1-parse/index.js';
Expand Down Expand Up @@ -479,7 +479,7 @@ export function migrate(source, { filename, use_ts } = {}) {
* }} State
*/

/** @type {Visitors<SvelteNode, State>} */
/** @type {Visitors<AST.SvelteNode, State>} */
const instance_script = {
_(node, { state, next }) {
// @ts-expect-error
Expand Down Expand Up @@ -1050,7 +1050,7 @@ function trim_block(state, start, end) {
}
}

/** @type {Visitors<SvelteNode, State>} */
/** @type {Visitors<AST.SvelteNode, State>} */
const template = {
Identifier(node, { state, path }) {
handle_identifier(node, state, path);
Expand Down Expand Up @@ -1410,7 +1410,7 @@ const template = {

/**
* @param {AST.RegularElement | AST.SvelteElement | AST.SvelteComponent | AST.Component | AST.SlotElement | AST.SvelteFragment} node
* @param {SvelteNode[]} path
* @param {AST.SvelteNode[]} path
* @param {State} state
*/
function migrate_slot_usage(node, path, state) {
Expand Down Expand Up @@ -1580,7 +1580,7 @@ function migrate_slot_usage(node, path, state) {
/**
* @param {VariableDeclarator} declarator
* @param {State} state
* @param {SvelteNode[]} path
* @param {AST.SvelteNode[]} path
*/
function extract_type_and_comment(declarator, state, path) {
const str = state.str;
Expand Down
4 changes: 2 additions & 2 deletions packages/svelte/src/compiler/phases/1-parse/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import { AST, TemplateNode } from '#compiler' */
/** @import { AST } from '#compiler' */
// @ts-expect-error acorn type definitions are borked in the release we use
import { isIdentifierStart, isIdentifierChar } from 'acorn';
import fragment from './state/fragment.js';
Expand Down Expand Up @@ -28,7 +28,7 @@ export class Parser {
/** Whether we're parsing in TypeScript mode */
ts = false;

/** @type {TemplateNode[]} */
/** @type {AST.TemplateNode[]} */
stack = [];

/** @type {AST.Fragment[]} */
Expand Down
4 changes: 2 additions & 2 deletions packages/svelte/src/compiler/phases/1-parse/read/script.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @import { Program } from 'estree' */
/** @import { AST, Directive } from '#compiler' */
/** @import { AST } from '#compiler' */
/** @import { Parser } from '../index.js' */
import * as acorn from '../acorn.js';
import { regex_not_newline_characters } from '../../patterns.js';
Expand All @@ -16,7 +16,7 @@ const ALLOWED_ATTRIBUTES = ['context', 'generics', 'lang', 'module'];
/**
* @param {Parser} parser
* @param {number} start
* @param {Array<AST.Attribute | AST.SpreadAttribute | Directive>} attributes
* @param {Array<AST.Attribute | AST.SpreadAttribute | AST.Directive>} attributes
* @returns {AST.Script}
*/
export function read_script(parser, start, attributes) {
Expand Down
40 changes: 20 additions & 20 deletions packages/svelte/src/compiler/phases/1-parse/read/style.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import { AST, Css, Directive } from '#compiler' */
/** @import { AST } from '#compiler' */
/** @import { Parser } from '../index.js' */
import * as e from '../../../errors.js';

Expand All @@ -18,8 +18,8 @@ const REGEX_HTML_COMMENT_CLOSE = /-->/;
/**
* @param {Parser} parser
* @param {number} start
* @param {Array<AST.Attribute | AST.SpreadAttribute | Directive>} attributes
* @returns {Css.StyleSheet}
* @param {Array<AST.Attribute | AST.SpreadAttribute | AST.Directive>} attributes
* @returns {AST.CSS.StyleSheet}
*/
export default function read_style(parser, start, attributes) {
const content_start = parser.index;
Expand Down Expand Up @@ -49,7 +49,7 @@ export default function read_style(parser, start, attributes) {
* @returns {any[]}
*/
function read_body(parser, close) {
/** @type {Array<Css.Rule | Css.Atrule>} */
/** @type {Array<AST.CSS.Rule | AST.CSS.Atrule>} */
const children = [];

while (parser.index < parser.template.length) {
Expand All @@ -71,7 +71,7 @@ function read_body(parser, close) {

/**
* @param {Parser} parser
* @returns {Css.Atrule}
* @returns {AST.CSS.Atrule}
*/
function read_at_rule(parser) {
const start = parser.index;
Expand All @@ -81,7 +81,7 @@ function read_at_rule(parser) {

const prelude = read_value(parser);

/** @type {Css.Block | null} */
/** @type {AST.CSS.Block | null} */
let block = null;

if (parser.match('{')) {
Expand All @@ -104,7 +104,7 @@ function read_at_rule(parser) {

/**
* @param {Parser} parser
* @returns {Css.Rule}
* @returns {AST.CSS.Rule}
*/
function read_rule(parser) {
const start = parser.index;
Expand All @@ -126,10 +126,10 @@ function read_rule(parser) {
/**
* @param {Parser} parser
* @param {boolean} [inside_pseudo_class]
* @returns {Css.SelectorList}
* @returns {AST.CSS.SelectorList}
*/
function read_selector_list(parser, inside_pseudo_class = false) {
/** @type {Css.ComplexSelector[]} */
/** @type {AST.CSS.ComplexSelector[]} */
const children = [];

allow_comment_or_whitespace(parser);
Expand Down Expand Up @@ -162,18 +162,18 @@ function read_selector_list(parser, inside_pseudo_class = false) {
/**
* @param {Parser} parser
* @param {boolean} [inside_pseudo_class]
* @returns {Css.ComplexSelector}
* @returns {AST.CSS.ComplexSelector}
*/
function read_selector(parser, inside_pseudo_class = false) {
const list_start = parser.index;

/** @type {Css.RelativeSelector[]} */
/** @type {AST.CSS.RelativeSelector[]} */
const children = [];

/**
* @param {Css.Combinator | null} combinator
* @param {AST.CSS.Combinator | null} combinator
* @param {number} start
* @returns {Css.RelativeSelector}
* @returns {AST.CSS.RelativeSelector}
*/
function create_selector(combinator, start) {
return {
Expand All @@ -190,7 +190,7 @@ function read_selector(parser, inside_pseudo_class = false) {
};
}

/** @type {Css.RelativeSelector} */
/** @type {AST.CSS.RelativeSelector} */
let relative_selector = create_selector(null, parser.index);

while (parser.index < parser.template.length) {
Expand Down Expand Up @@ -247,7 +247,7 @@ function read_selector(parser, inside_pseudo_class = false) {
} else if (parser.eat(':')) {
const name = read_identifier(parser);

/** @type {null | Css.SelectorList} */
/** @type {null | AST.CSS.SelectorList} */
let args = null;

if (parser.eat('(')) {
Expand Down Expand Up @@ -372,7 +372,7 @@ function read_selector(parser, inside_pseudo_class = false) {

/**
* @param {Parser} parser
* @returns {Css.Combinator | null}
* @returns {AST.CSS.Combinator | null}
*/
function read_combinator(parser) {
const start = parser.index;
Expand Down Expand Up @@ -407,14 +407,14 @@ function read_combinator(parser) {

/**
* @param {Parser} parser
* @returns {Css.Block}
* @returns {AST.CSS.Block}
*/
function read_block(parser) {
const start = parser.index;

parser.eat('{', true);

/** @type {Array<Css.Declaration | Css.Rule | Css.Atrule>} */
/** @type {Array<AST.CSS.Declaration | AST.CSS.Rule | AST.CSS.Atrule>} */
const children = [];

while (parser.index < parser.template.length) {
Expand All @@ -441,7 +441,7 @@ function read_block(parser) {
* Reads a declaration, rule or at-rule
*
* @param {Parser} parser
* @returns {Css.Declaration | Css.Rule | Css.Atrule}
* @returns {AST.CSS.Declaration | AST.CSS.Rule | AST.CSS.Atrule}
*/
function read_block_item(parser) {
if (parser.match('@')) {
Expand All @@ -460,7 +460,7 @@ function read_block_item(parser) {

/**
* @param {Parser} parser
* @returns {Css.Declaration}
* @returns {AST.CSS.Declaration}
*/
function read_declaration(parser) {
const start = parser.index;
Expand Down
18 changes: 9 additions & 9 deletions packages/svelte/src/compiler/phases/1-parse/state/element.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/** @import { Expression } from 'estree' */
/** @import { AST, Directive, ElementLike, TemplateNode } from '#compiler' */
/** @import { AST } from '#compiler' */
/** @import { Parser } from '../index.js' */
import { is_void } from '../../../../utils.js';
import read_expression from '../read/expression.js';
Expand Down Expand Up @@ -28,7 +28,7 @@ export const regex_valid_component_name =
// (must start with uppercase letter if no dots, can contain dots)
/^(?:\p{Lu}[$\u200c\u200d\p{ID_Continue}.]*|\p{ID_Start}[$\u200c\u200d\p{ID_Continue}]*(?:\.[$\u200c\u200d\p{ID_Continue}]+)+)$/u;

/** @type {Map<string, ElementLike['type']>} */
/** @type {Map<string, AST.ElementLike['type']>} */
const root_only_meta_tags = new Map([
['svelte:head', 'SvelteHead'],
['svelte:options', 'SvelteOptions'],
Expand All @@ -37,7 +37,7 @@ const root_only_meta_tags = new Map([
['svelte:body', 'SvelteBody']
]);

/** @type {Map<string, ElementLike['type']>} */
/** @type {Map<string, AST.ElementLike['type']>} */
const meta_tags = new Map([
...root_only_meta_tags,
['svelte:element', 'SvelteElement'],
Expand Down Expand Up @@ -137,7 +137,7 @@ export default function element(parser) {
? 'SlotElement'
: 'RegularElement';

/** @type {ElementLike} */
/** @type {AST.ElementLike} */
const element =
type === 'RegularElement'
? {
Expand All @@ -155,7 +155,7 @@ export default function element(parser) {
path: []
}
}
: /** @type {ElementLike} */ ({
: /** @type {AST.ElementLike} */ ({
type,
start,
end: -1,
Expand Down Expand Up @@ -358,7 +358,7 @@ export default function element(parser) {
}
}

/** @param {TemplateNode[]} stack */
/** @param {AST.TemplateNode[]} stack */
function parent_is_head(stack) {
let i = stack.length;
while (i--) {
Expand All @@ -369,7 +369,7 @@ function parent_is_head(stack) {
return false;
}

/** @param {TemplateNode[]} stack */
/** @param {AST.TemplateNode[]} stack */
function parent_is_shadowroot_template(stack) {
// https://developer.chrome.com/docs/css-ui/declarative-shadow-dom#building_a_declarative_shadow_root
let i = stack.length;
Expand Down Expand Up @@ -433,7 +433,7 @@ function read_static_attribute(parser) {

/**
* @param {Parser} parser
* @returns {AST.Attribute | AST.SpreadAttribute | Directive | null}
* @returns {AST.Attribute | AST.SpreadAttribute | AST.Directive | null}
*/
function read_attribute(parser) {
const start = parser.index;
Expand Down Expand Up @@ -564,7 +564,7 @@ function read_attribute(parser) {
}
}

/** @type {Directive} */
/** @type {AST.Directive} */
const directive = {
start,
end,
Expand Down
Loading

0 comments on commit 61a0da8

Please sign in to comment.