import type * as AST from 'estree'; import type * as ESTreeJSX from 'estree-jsx'; import type { TSESTree } from '@typescript-eslint/types'; import type { NAMESPACE_URI } from '../../runtime/internal/client/constants.js'; import type { Parse } from '#parser'; import type * as ESRap from 'esrap'; import type { RippleCompileError, CompileOptions } from 'ripple/compiler'; import type { Position } from 'acorn'; import type { RequireAllOrNone } from '#helpers'; export type NameSpace = keyof typeof NAMESPACE_URI; interface BaseNodeMetaData { scoped?: boolean; path: AST.Node[]; has_template?: boolean; source_name?: string | '#server' | '#style'; is_capitalized?: boolean; has_await?: boolean; commentContainerId?: number; parenthesized?: boolean; elementLeadingComments?: AST.Comment[]; inside_component_top_level?: boolean; returns?: AST.ReturnStatement[]; has_return?: boolean; is_reactive?: boolean; lone_return?: boolean; forceMapping?: boolean; lazy_id?: string; } interface FunctionMetaData extends BaseNodeMetaData { // needed for volar tokens to recognize component functions is_component?: boolean; is_method?: boolean; tracked?: boolean; } // Strip parent, loc, and range from TSESTree nodes to match @sveltejs/acorn-typescript output // acorn-typescript uses start/end instead of range, and loc is optional type AcornTSNode = Omit & { start?: number; end?: number; loc?: AST.SourceLocation; range?: AST.BaseNode['range']; metadata: BaseNodeMetaData; leadingComments?: AST.Comment[] | undefined; trailingComments?: AST.Comment[] | undefined; }; interface FunctionLikeTS { returnType?: AST.TSTypeAnnotation; typeParameters?: AST.TSTypeParameterDeclaration; typeAnnotation?: AST.TSTypeAnnotation; } // Ripple augmentation for ESTree function nodes declare module 'estree' { interface FunctionDeclaration extends FunctionLikeTS { metadata: FunctionMetaData; } interface FunctionExpression extends FunctionLikeTS { metadata: FunctionMetaData; } interface ArrowFunctionExpression extends FunctionLikeTS { metadata: FunctionMetaData; } interface NewExpression { metadata: BaseNodeMetaData & { skipNewMapping?: boolean; }; } type Accessibility = 'public' | 'protected' | 'private'; // missing in acorn-typescript types interface MethodDefinition { typeParameters?: TSTypeParameterDeclaration; accessibility?: Accessibility; } interface PropertyDefinition { accessibility?: Accessibility; readonly?: boolean; optional?: boolean; } interface ClassDeclaration { typeParameters?: AST.TSTypeParameterDeclaration; superTypeParameters?: AST.TSTypeParameterInstantiation; implements?: AST.TSClassImplements[]; } interface ClassExpression { typeParameters?: AST.TSTypeParameterDeclaration; superTypeParameters?: AST.TSTypeParameterInstantiation; implements?: AST.TSClassImplements[]; } interface Identifier extends AST.TrackedNode { metadata: BaseNodeMetaData & { // needed for volar tokens to recognize component functions is_component?: boolean; }; typeAnnotation?: TSTypeAnnotation | undefined; decorators: TSESTree.Decorator[]; optional: boolean; } // Lazy destructuring patterns (&{...} and &[...]) interface ObjectPattern { lazy?: boolean; } interface ArrayPattern { lazy?: boolean; } // We mark the whole node as marked when member is @[expression] // Otherwise, we only mark Identifier nodes interface MemberExpression {} interface SimpleLiteral extends AST.LiteralNode {} interface RegExpLiteral extends AST.LiteralNode {} interface BigIntLiteral extends AST.LiteralNode {} interface TrackedNode { tracked?: boolean; } interface LiteralNode { was_expression?: boolean; } // Include TypeScript node types and Ripple-specific nodes in NodeMap interface NodeMap { Component: Component; TsxCompat: TsxCompat; RippleExpression: RippleExpression; Html: Html; Element: Element; Text: TextNode; ServerBlock: ServerBlock; ServerBlockStatement: ServerBlockStatement; ServerIdentifier: ServerIdentifier; StyleIdentifier: StyleIdentifier; Attribute: Attribute; RefAttribute: RefAttribute; SpreadAttribute: SpreadAttribute; ParenthesizedExpression: ParenthesizedExpression; ScriptContent: ScriptContent; } interface ExpressionMap { StyleIdentifier: StyleIdentifier; ServerIdentifier: ServerIdentifier; Text: TextNode; JSXEmptyExpression: ESTreeJSX.JSXEmptyExpression; ParenthesizedExpression: ParenthesizedExpression; TSAsExpression: TSAsExpression; } // Missing estree type interface ParenthesizedExpression extends AST.BaseNode { type: 'ParenthesizedExpression'; expression: AST.Expression; metadata: BaseNodeMetaData & { skipParenthesisMapping?: boolean; }; } interface Comment { context?: Parse.CommentMetaData | null; } // For now only ObjectExpression needs printInline // Needed to avoid ts pragma comments being on the wrong line that // does not affect the next line as in the source code interface ObjectExpression { metadata: BaseNodeMetaData & { printInline?: boolean; }; } /** * Custom Comment interface with location information */ type CommentWithLocation = AST.Comment & NodeWithLocation; interface TryStatement { pending?: AST.BlockStatement | null; } interface ForOfStatement { index?: AST.Identifier | null; key?: AST.Expression | null; } interface ServerIdentifier extends AST.BaseExpression { type: 'ServerIdentifier'; } interface StyleIdentifier extends AST.BaseExpression { type: 'StyleIdentifier'; } interface ImportDeclaration { importKind: TSESTree.ImportDeclaration['importKind']; } interface ImportSpecifier { importKind: TSESTree.ImportSpecifier['importKind']; } interface ExportNamedDeclaration { exportKind: TSESTree.ExportNamedDeclaration['exportKind']; } interface BaseNodeWithoutComments { // Adding start, end for now as always there // later might change to optional // And only define on certain nodes // BaseNode inherits from this interface start?: number; end?: number; } interface BaseNode { is_controlled?: boolean; // This is for Pattern but it's a type alias // So it's just easy to extend BaseNode even though // typeAnnotation, typeArguments do not apply to all nodes typeAnnotation?: TSTypeAnnotation; typeArguments?: TSTypeParameterInstantiation; // even though technically metadata starts out as undefined // metadata is always populated by the `_` visitor // which runs for every node before other visitors // so taking a practical approach and making it required // to avoid lots of typecasting or checking for undefined metadata: BaseNodeMetaData; comments?: Comment[]; } interface NodeWithLocation { start: number; end: number; loc: AST.SourceLocation; } interface NodeWithMaybeComments { innerComments?: AST.Comment[] | undefined; leadingComments?: AST.Comment[] | undefined; trailingComments?: AST.Comment[] | undefined; } /** * Ripple custom interfaces and types section */ interface Component extends AST.BaseNode { type: 'Component'; // null is for anonymous components {component: () => {}} id: AST.Identifier | null; params: AST.Pattern[]; body: AST.Node[]; css: CSS.StyleSheet | null; metadata: BaseNodeMetaData & { topScopedClasses?: TopScopedClasses; styleClasses?: StyleClasses; styleIdentifierPresent?: boolean; }; default: boolean; typeParameters?: AST.TSTypeParameterDeclaration; } interface TsxCompat extends AST.BaseNode { type: 'TsxCompat'; kind: string; attributes: Array; children: ESTreeJSX.JSXElement['children']; selfClosing?: boolean; unclosed?: boolean; openingElement: ESTreeJSX.JSXOpeningElement; closingElement: ESTreeJSX.JSXClosingElement; } interface Html extends AST.BaseNode { type: 'Html'; expression: AST.Expression; } export interface RippleExpression extends AST.BaseExpression { type: 'RippleExpression'; expression: AST.Expression; loc?: AST.SourceLocation; } interface Element extends AST.BaseNode { type: 'Element'; // MemberExpression for namespaced or dynamic elements id: AST.Identifier | AST.MemberExpression; attributes: RippleAttribute[]; children: AST.Node[]; selfClosing?: boolean; unclosed?: boolean; loc: SourceLocation; metadata: BaseNodeMetaData & { ts_name?: string; // for