import { Dict, Nullable, PresentArray, Core, GetContextualFreeOpcode } from "@glimmer/interfaces"; import { EntityParser, EventedTokenizer } from "simple-html-tokenizer"; declare namespace HBS { interface CommonNode { loc: SourceLocation; } interface NodeMap { Program: { input: Program; output: ASTv1.Block; }; MustacheStatement: { input: MustacheStatement; output: ASTv1.MustacheStatement | void; }; Decorator: { input: Decorator; output: never; }; BlockStatement: { input: BlockStatement; output: ASTv1.BlockStatement | void; }; DecoratorBlock: { input: DecoratorBlock; output: never; }; PartialStatement: { input: PartialStatement; output: never; }; PartialBlockStatement: { input: PartialBlockStatement; output: never; }; ContentStatement: { input: ContentStatement; output: void; }; CommentStatement: { input: CommentStatement; output: ASTv1.MustacheCommentStatement | null; }; SubExpression: { input: SubExpression; output: ASTv1.SubExpression; }; PathExpression: { input: PathExpression; output: ASTv1.PathExpression; }; StringLiteral: { input: StringLiteral; output: ASTv1.StringLiteral; }; BooleanLiteral: { input: BooleanLiteral; output: ASTv1.BooleanLiteral; }; NumberLiteral: { input: NumberLiteral; output: ASTv1.NumberLiteral; }; UndefinedLiteral: { input: UndefinedLiteral; output: ASTv1.UndefinedLiteral; }; NullLiteral: { input: NullLiteral; output: ASTv1.NullLiteral; }; } type NodeType = keyof NodeMap; type Node = NodeMap[T]["input"]; type Output = NodeMap[T]["output"]; interface SourceLocation { source: string; start: Position; end: Position; } interface Position { line: number; column: number; } interface Program extends CommonNode { type: "Program"; body: Statement[]; blockParams?: string[]; chained?: boolean; } type Statement = MustacheStatement | BlockStatement | DecoratorBlock | PartialStatement | PartialBlockStatement | ContentStatement | CommentStatement; interface CommonMustache extends CommonNode { path: Expression; params: Expression[]; hash: Hash; escaped: boolean; strip: StripFlags; } interface MustacheStatement extends CommonMustache { type: "MustacheStatement"; } interface Decorator extends CommonMustache { type: "DecoratorStatement"; } interface CommonBlock extends CommonNode { chained: boolean; path: PathExpression | SubExpression; params: Expression[]; hash: Hash; program: Program; inverse: Program; openStrip?: StripFlags; inverseStrip?: StripFlags; closeStrip?: StripFlags; } interface BlockStatement extends CommonBlock { type: "BlockStatement"; } interface DecoratorBlock extends CommonBlock { type: "DecoratorBlock"; } interface PartialStatement extends CommonNode { type: "PartialStatement"; name: PathExpression | SubExpression; params: Expression[]; hash: Hash; indent: string; strip: StripFlags; } interface PartialBlockStatement extends CommonNode { type: "PartialBlockStatement"; name: PathExpression | SubExpression; params: Expression[]; hash: Hash; program: Program; openStrip: StripFlags; closeStrip: StripFlags; } interface ContentStatement extends CommonNode { type: "ContentStatement"; value: string; original: StripFlags; } interface CommentStatement extends CommonNode { type: "CommentStatement"; value: string; strip: StripFlags; } type Expression = SubExpression | PathExpression | Literal; interface SubExpression extends CommonNode { type: "SubExpression"; path: PathExpression | SubExpression; params: Expression[]; hash: Hash; } interface PathExpression extends CommonNode { type: "PathExpression"; data: boolean; depth: number; parts: string[]; original: string; } type Literal = StringLiteral | BooleanLiteral | NumberLiteral | UndefinedLiteral | NullLiteral; interface StringLiteral extends CommonNode { type: "StringLiteral"; value: string; original: string; } interface BooleanLiteral extends CommonNode { type: "BooleanLiteral"; value: boolean; original: boolean; } interface NumberLiteral extends CommonNode { type: "NumberLiteral"; value: number; original: number; } interface UndefinedLiteral extends CommonNode { type: "UndefinedLiteral"; } interface NullLiteral extends CommonNode { type: "NullLiteral"; } interface Hash extends CommonNode { pairs: HashPair[]; } interface HashPair extends CommonNode { key: string; value: Expression; } interface StripFlags { open: boolean; close: boolean; } } declare namespace src { type ParserNodeBuilder = Omit & { start: src.SourceOffset; }; interface StartTag { readonly type: "StartTag"; name: string; nameStart: Nullable; nameEnd: Nullable; readonly attributes: ASTv1.AttrNode[]; readonly modifiers: ASTv1.ElementModifierStatement[]; readonly comments: ASTv1.MustacheCommentStatement[]; readonly params: ASTv1.VarHead[]; selfClosing: boolean; readonly loc: src.SourceSpan; } interface EndTag { readonly type: "EndTag"; name: string; readonly loc: src.SourceSpan; } interface Attribute { name: string; currentPart: ASTv1.TextNode | null; parts: (ASTv1.MustacheStatement | ASTv1.TextNode)[]; isQuoted: boolean; isDynamic: boolean; start: src.SourceOffset; valueSpan: src.SourceSpan; } abstract class Parser { protected elementStack: ASTv1.ParentNode[]; private lines; readonly source: src.Source; currentAttribute: Nullable; currentNode: Nullable | ParserNodeBuilder | ParserNodeBuilder | ParserNodeBuilder>>; tokenizer: EventedTokenizer; constructor(source: src.Source, entityParser?: EntityParser, mode?: "precompile" | "codemod"); offset(): src.SourceOffset; pos({ line, column }: src.SourcePosition): src.SourceOffset; finish(node: ParserNodeBuilder): T; abstract parse(node: HBS.Program, locals: string[]): ASTv1.Template; abstract Program(node: HBS.Program): HBS.Output<"Program">; abstract MustacheStatement(node: HBS.MustacheStatement): HBS.Output<"MustacheStatement">; abstract Decorator(node: HBS.Decorator): HBS.Output<"Decorator">; abstract BlockStatement(node: HBS.BlockStatement): HBS.Output<"BlockStatement">; abstract DecoratorBlock(node: HBS.DecoratorBlock): HBS.Output<"DecoratorBlock">; abstract PartialStatement(node: HBS.PartialStatement): HBS.Output<"PartialStatement">; abstract PartialBlockStatement(node: HBS.PartialBlockStatement): HBS.Output<"PartialBlockStatement">; abstract ContentStatement(node: HBS.ContentStatement): HBS.Output<"ContentStatement">; abstract CommentStatement(node: HBS.CommentStatement): HBS.Output<"CommentStatement">; abstract SubExpression(node: HBS.SubExpression): HBS.Output<"SubExpression">; abstract PathExpression(node: HBS.PathExpression): HBS.Output<"PathExpression">; abstract StringLiteral(node: HBS.StringLiteral): HBS.Output<"StringLiteral">; abstract BooleanLiteral(node: HBS.BooleanLiteral): HBS.Output<"BooleanLiteral">; abstract NumberLiteral(node: HBS.NumberLiteral): HBS.Output<"NumberLiteral">; abstract UndefinedLiteral(node: HBS.UndefinedLiteral): HBS.Output<"UndefinedLiteral">; abstract NullLiteral(node: HBS.NullLiteral): HBS.Output<"NullLiteral">; abstract reset(): void; abstract finishData(): void; abstract tagOpen(): void; abstract beginData(): void; abstract appendToData(char: string): void; abstract beginStartTag(): void; abstract appendToTagName(char: string): void; abstract beginAttribute(): void; abstract appendToAttributeName(char: string): void; abstract beginAttributeValue(quoted: boolean): void; abstract appendToAttributeValue(char: string): void; abstract finishAttributeValue(): void; abstract markTagAsSelfClosing(): void; abstract beginEndTag(): void; abstract finishTag(): void; abstract beginComment(): void; abstract appendToCommentData(char: string): void; abstract finishComment(): void; abstract reportSyntaxError(error: string): void; get currentAttr(): Attribute; get currentTag(): ParserNodeBuilder | ParserNodeBuilder; get currentStartTag(): ParserNodeBuilder; get currentEndTag(): ParserNodeBuilder; get currentComment(): ParserNodeBuilder; get currentData(): ParserNodeBuilder; acceptNode(node: HBS.Node): HBS.Output; currentElement(): ASTv1.ParentNode; sourceForNode(node: HBS.Node, endNode?: { loc: HBS.SourceLocation; }): string; } // ensure stays in sync with typing // ParentNode and ChildKey types are derived from VisitorKeysMap const visitorKeys: { readonly Template: readonly [ "body" ]; readonly Block: readonly [ "body" ]; readonly MustacheStatement: readonly [ "path", "params", "hash" ]; readonly BlockStatement: readonly [ "path", "params", "hash", "program", "inverse" ]; readonly ElementModifierStatement: readonly [ "path", "params", "hash" ]; readonly CommentStatement: readonly [ ]; readonly MustacheCommentStatement: readonly [ ]; readonly ElementNode: readonly [ "attributes", "modifiers", "children", "comments" ]; readonly AttrNode: readonly [ "value" ]; readonly TextNode: readonly [ ]; readonly ConcatStatement: readonly [ "parts" ]; readonly SubExpression: readonly [ "path", "params", "hash" ]; readonly PathExpression: readonly [ ]; readonly StringLiteral: readonly [ ]; readonly BooleanLiteral: readonly [ ]; readonly NumberLiteral: readonly [ ]; readonly NullLiteral: readonly [ ]; readonly UndefinedLiteral: readonly [ ]; readonly Hash: readonly [ "pairs" ]; readonly HashPair: readonly [ "value" ]; }; type VisitorKeysMap = typeof visitorKeys; type VisitorKeys = { [P in keyof VisitorKeysMap]: VisitorKeysMap[P][number]; }; type VisitorKey = VisitorKeys[N["type"]] & keyof N; class WalkerPath { node: N; parent: WalkerPath | null; parentKey: string | null; constructor(node: N, parent?: WalkerPath | null, parentKey?: string | null); get parentNode(): ASTv1.Node | null; parents(): Iterable | null>; } interface FullNodeTraversal { enter?(node: N, path: WalkerPath): void; exit?(node: N, path: WalkerPath): void; keys?: KeysVisitor; } type NodeHandler = (node: N, path: WalkerPath) => void; type NodeTraversal = FullNodeTraversal | NodeHandler; type NodeVisitor = { [P in keyof ASTv1.Nodes]?: NodeTraversal; } & { All?: NodeTraversal; /** * @deprecated use Template or Block instead */ Program?: NodeTraversal; }; interface FullKeyTraversal { enter?(node: N, key: K): void; exit?(node: N, key: K): void; } type KeyHandler> = (node: N, key: K) => void; type KeyTraversal> = FullKeyTraversal | KeyHandler; type KeysVisitor = { [P in VisitorKey]?: KeyTraversal; } & { All?: KeyTraversal>; /** * @deprecated use Template or Block instead */ Program?: KeyTraversal; }; const voidMap: Set; function getVoidTags(): string[]; interface PrinterOptions { entityEncoding: ASTv1.EntityEncodingState; /** * Used to override the mechanism of printing a given AST.Node. * * This will generally only be useful to source -> source codemods * where you would like to specialize/override the way a given node is * printed (e.g. you would like to preserve as much of the original * formatting as possible). * * When the provided override returns undefined, the default built in printing * will be done for the AST.Node. * * @param ast the ast node to be printed * @param options the options specified during the print() invocation */ override?(ast: ASTv1.Node, options: PrinterOptions): void | string; } /** * Examples when true: * - link * - liNK * * Examples when false: * - Link (component) */ function isVoidTag(tag: string): boolean; class Printer { private buffer; private options; constructor(options: PrinterOptions); /* This is used by _all_ methods on this Printer class that add to `this.buffer`, it allows consumers of the printer to use alternate string representations for a given node. The primary use case for this are things like source -> source codemod utilities. For example, ember-template-recast attempts to always preserve the original string formatting in each AST node if no modifications are made to it. */ handledByOverride(node: ASTv1.Node, ensureLeadingWhitespace?: boolean): boolean; Node(node: ASTv1.Node): void; Expression(expression: ASTv1.Expression): void; Literal(literal: ASTv1.Literal): void; TopLevelStatement(statement: ASTv1.TopLevelStatement | ASTv1.Template | ASTv1.AttrNode): void; Template(template: ASTv1.Template): void; Block(block: ASTv1.Block): void; TopLevelStatements(statements: ASTv1.TopLevelStatement[]): void; ElementNode(el: ASTv1.ElementNode): void; OpenElementNode(el: ASTv1.ElementNode): void; CloseElementNode(el: ASTv1.ElementNode): void; AttrNode(attr: ASTv1.AttrNode): void; AttrNodeValue(value: ASTv1.AttrNode["value"]): void; TextNode(text: ASTv1.TextNode, isAttr?: boolean): void; MustacheStatement(mustache: ASTv1.MustacheStatement): void; BlockStatement(block: ASTv1.BlockStatement): void; BlockParams(blockParams: string[]): void; ConcatStatement(concat: ASTv1.ConcatStatement): void; MustacheCommentStatement(comment: ASTv1.MustacheCommentStatement): void; ElementModifierStatement(mod: ASTv1.ElementModifierStatement): void; CommentStatement(comment: ASTv1.CommentStatement): void; PathExpression(path: ASTv1.PathExpression): void; SubExpression(sexp: ASTv1.SubExpression): void; Params(params: ASTv1.Expression[]): void; Hash(hash: ASTv1.Hash): void; HashPair(pair: ASTv1.HashPair): void; StringLiteral(str: ASTv1.StringLiteral): void; BooleanLiteral(bool: ASTv1.BooleanLiteral): void; NumberLiteral(number: ASTv1.NumberLiteral): void; UndefinedLiteral(node: ASTv1.UndefinedLiteral): void; NullLiteral(node: ASTv1.NullLiteral): void; print(node: ASTv1.Node): string; } function build(ast: ASTv1.Node, options?: PrinterOptions): string; const print: typeof build; function traverse(node: ASTv1.Node, visitor: NodeVisitor): void; type NodeCallback = (node: N, walker: Walker) => void; class Walker { order?: unknown; stack: unknown[]; constructor(order?: unknown); visit(node: Nullable, visitor: NodeCallback): void; children(node: N & ASTv1.Node, callback: NodeCallback): void; } // const SOURCE = new Source('', '(tests)'); // Statements type BuilderHead = string | ASTv1.CallableExpression; type TagDescriptor = string | ASTv1.PathExpression | { path: ASTv1.PathExpression; selfClosing?: boolean; } | { name: string; selfClosing?: boolean; }; function buildMustache(path: BuilderHead | ASTv1.Literal, params?: ASTv1.Expression[], hash?: ASTv1.Hash, trusting?: boolean, loc?: SourceLocation, strip?: ASTv1.StripFlags): ASTv1.MustacheStatement; type PossiblyDeprecatedBlock = ASTv1.Block | ASTv1.Template; function buildBlock(path: BuilderHead, params: Nullable, hash: Nullable, _defaultBlock: PossiblyDeprecatedBlock, _elseBlock?: Nullable, loc?: SourceLocation, openStrip?: ASTv1.StripFlags, inverseStrip?: ASTv1.StripFlags, closeStrip?: ASTv1.StripFlags): ASTv1.BlockStatement; function buildElementModifier(path: BuilderHead, params?: ASTv1.Expression[], hash?: ASTv1.Hash, loc?: Nullable): ASTv1.ElementModifierStatement; function buildComment(value: string, loc?: SourceLocation): ASTv1.CommentStatement; function buildMustacheComment(value: string, loc?: SourceLocation): ASTv1.MustacheCommentStatement; function buildConcat(parts: (ASTv1.TextNode | ASTv1.MustacheStatement)[], loc?: SourceLocation): ASTv1.ConcatStatement; // Nodes type ElementParts = [ "attrs", ...AttrSexp[] ] | [ "modifiers", ...ModifierSexp[] ] | [ "body", ...ASTv1.Statement[] ] | [ "comments", ...ElementComment[] ] | [ "as", ...string[] ] | [ "loc", SourceLocation ]; type PathSexp = string | [ "path", string, LocSexp? ]; type ModifierSexp = string | [ PathSexp, LocSexp? ] | [ PathSexp, ASTv1.Expression[], LocSexp? ] | [ PathSexp, ASTv1.Expression[], Dict, LocSexp? ]; type AttrSexp = [ string, ASTv1.AttrNode["value"] | string, LocSexp? ]; type LocSexp = [ "loc", SourceLocation ]; type ElementComment = ASTv1.MustacheCommentStatement | SourceLocation | string; type SexpValue = string | ASTv1.Expression[] | Dict | LocSexp | PathSexp | undefined; interface BuildElementOptions { attrs?: ASTv1.AttrNode[]; modifiers?: ASTv1.ElementModifierStatement[]; children?: ASTv1.Statement[]; comments?: ASTv1.MustacheCommentStatement[]; blockParams?: ASTv1.VarHead[] | string[]; openTag?: SourceLocation; closeTag?: Nullable; loc?: SourceLocation; } function buildElement(tag: TagDescriptor, options?: BuildElementOptions): ASTv1.ElementNode; function buildAttr(name: string, value: ASTv1.AttrValue, loc?: SourceLocation): ASTv1.AttrNode; function buildText(chars?: string, loc?: SourceLocation): ASTv1.TextNode; // Expressions function buildSexpr(path: BuilderHead, params?: ASTv1.Expression[], hash?: ASTv1.Hash, loc?: SourceLocation): ASTv1.SubExpression; function buildThis(loc?: SourceLocation): ASTv1.ThisHead; function buildAtName(name: string, loc?: SourceLocation): ASTv1.AtHead; function buildVar(name: string, loc?: SourceLocation): ASTv1.VarHead; function buildHeadFromString(original: string, loc?: SourceLocation): ASTv1.PathHead; function buildCleanPath(head: ASTv1.PathHead, tail?: string[], loc?: SourceLocation): ASTv1.PathExpression; function buildPath(path: ASTv1.PathExpression | string | { head: string; tail: string[]; }, loc?: SourceLocation): ASTv1.PathExpression; function buildPath(path: BuilderHead, loc?: SourceLocation): ASTv1.CallableExpression; function buildPath(path: BuilderHead | ASTv1.Literal, loc?: SourceLocation): ASTv1.Expression; function buildPath(path: ASTv1.Expression, loc?: SourceLocation): ASTv1.Expression; function buildLiteral(type: T["type"], value: T["value"], loc?: SourceLocation): T; // Miscellaneous function buildHash(pairs?: ASTv1.HashPair[], loc?: SourceLocation): ASTv1.Hash; function buildPair(key: string, value: ASTv1.Expression, loc?: SourceLocation): ASTv1.HashPair; function buildProgram(body?: ASTv1.Statement[], blockParams?: string[], loc?: SourceLocation): ASTv1.Template | ASTv1.Block; function buildBlockItself(body?: ASTv1.Statement[], params?: Array, chained?: boolean, loc?: SourceLocation): ASTv1.Block; function buildTemplate(body?: ASTv1.Statement[], blockParams?: string[], loc?: SourceLocation): ASTv1.Template; function buildPosition(line: number, column: number): SourcePosition; function buildLoc(loc: Nullable): SourceSpan; function buildLoc(startLine: number, startColumn: number, endLine?: number, endColumn?: number, source?: string): SourceSpan; const _default: { mustache: typeof buildMustache; block: typeof buildBlock; comment: typeof buildComment; mustacheComment: typeof buildMustacheComment; element: typeof buildElement; elementModifier: typeof buildElementModifier; attr: typeof buildAttr; text: typeof buildText; sexpr: typeof buildSexpr; concat: typeof buildConcat; hash: typeof buildHash; pair: typeof buildPair; literal: typeof buildLiteral; program: typeof buildProgram; blockItself: typeof buildBlockItself; template: typeof buildTemplate; loc: typeof buildLoc; pos: typeof buildPosition; path: typeof buildPath; fullPath: typeof buildCleanPath; head: typeof buildHeadFromString; at: typeof buildAtName; var: typeof buildVar; this: typeof buildThis; string: (value: string) => ASTv1.StringLiteral; boolean: (value: boolean) => ASTv1.BooleanLiteral; number: (value: number) => ASTv1.NumberLiteral; undefined(): ASTv1.UndefinedLiteral; null(): ASTv1.NullLiteral; }; const publicBuilder: typeof _default; interface PendingError { mustache(span: SourceSpan): never; eof(offset: SourceOffset): never; } abstract class HandlebarsNodeVisitors extends Parser { // Because we interleave the HTML and HBS parsing, sometimes the HTML // tokenizer can run out of tokens when we switch into {{...}} or reached // EOF. There are positions where neither of these are expected, and it would // like to generate an error, but there is no span to attach the error to. // This allows the HTML tokenization to stash an error message and the next // mustache visitor will attach the message to the appropriate span and throw // the error. protected pendingError: Nullable; abstract appendToCommentData(s: string): void; abstract beginAttributeValue(quoted: boolean): void; abstract finishAttributeValue(): void; parse(program: HBS.Program, blockParams: string[]): ASTv1.Template; Program(program: HBS.Program, blockParams?: ASTv1.VarHead[]): ASTv1.Block; private parseProgram; BlockStatement(block: HBS.BlockStatement): ASTv1.BlockStatement | void; MustacheStatement(rawMustache: HBS.MustacheStatement): ASTv1.MustacheStatement | void; appendDynamicAttributeValuePart(part: ASTv1.MustacheStatement): void; finalizeTextPart(): void; startTextPart(): void; ContentStatement(content: HBS.ContentStatement): void; CommentStatement(rawComment: HBS.CommentStatement): Nullable; PartialStatement(partial: HBS.PartialStatement): never; PartialBlockStatement(partialBlock: HBS.PartialBlockStatement): never; Decorator(decorator: HBS.Decorator): never; DecoratorBlock(decoratorBlock: HBS.DecoratorBlock): never; SubExpression(sexpr: HBS.SubExpression): ASTv1.SubExpression; PathExpression(path: HBS.PathExpression): ASTv1.PathExpression; Hash(hash: HBS.Hash): ASTv1.Hash; StringLiteral(string: HBS.StringLiteral): ASTv1.StringLiteral; BooleanLiteral(boolean: HBS.BooleanLiteral): ASTv1.BooleanLiteral; NumberLiteral(number: HBS.NumberLiteral): ASTv1.NumberLiteral; UndefinedLiteral(undef: HBS.UndefinedLiteral): ASTv1.UndefinedLiteral; NullLiteral(nul: HBS.NullLiteral): ASTv1.NullLiteral; } class TokenizerEventHandlers extends HandlebarsNodeVisitors { private tagOpenLine; private tagOpenColumn; reset(): void; // Comment beginComment(): void; appendToCommentData(char: string): void; finishComment(): void; // Data beginData(): void; appendToData(char: string): void; finishData(): void; // Tags - basic tagOpen(): void; beginStartTag(): void; beginEndTag(): void; finishTag(): void; finishStartTag(): void; finishEndTag(isVoid: boolean): void; markTagAsSelfClosing(): void; // Tags - name appendToTagName(char: string): void; // Tags - attributes beginAttribute(): void; appendToAttributeName(char: string): void; beginAttributeValue(isQuoted: boolean): void; appendToAttributeValue(char: string): void; finishAttributeValue(): void; private parsePossibleBlockParams; reportSyntaxError(message: string): void; assembleConcatenatedValue(parts: (ASTv1.MustacheStatement | ASTv1.TextNode)[]): ASTv1.ConcatStatement; validateEndTag(tag: StartTag | EndTag, element: ASTv1.ElementNode, selfClosing: boolean): void; assembleAttributeValue(parts: ASTv1.AttrPart[], isQuoted: boolean, isDynamic: boolean, span: src.SourceSpan): ASTv1.AttrValue; } /** ASTPlugins can make changes to the Glimmer template AST before compilation begins. */ interface ASTPluginBuilder { (env: TEnv): ASTPlugin; } interface ASTPlugin { name: string; visitor: NodeVisitor; } interface ASTPluginEnvironment { meta?: object; syntax: Syntax; } interface HandlebarsParseOptions { srcName?: string; ignoreStandalone?: boolean; } interface TemplateIdFn { (src: string): Nullable; } interface PrecompileOptions extends PreprocessOptions { id?: TemplateIdFn; /** * Additional non-native keywords. * * Local variables (block params or lexical scope) always takes precedence, * but otherwise, suitable free variable candidates (e.g. those are not part * of a path) are matched against this list and turned into keywords. * * In strict mode compilation, keywords suppresses the undefined reference * error and will be resolved by the runtime environment. * * In loose mode, keywords are currently ignored and since all free variables * are already resolved by the runtime environment. */ keywords?: readonly string[]; customizeComponentName?: ((input: string) => string) | undefined; } interface PrecompileOptionsWithLexicalScope extends PrecompileOptions { lexicalScope: (variable: string) => boolean; } interface PreprocessOptions { strictMode?: boolean; locals?: string[]; meta?: { moduleName?: string; }; plugins?: { ast?: ASTPluginBuilder[]; }; parseOptions?: HandlebarsParseOptions; customizeComponentName?: ((input: string) => string) | undefined; /** Useful for specifying a group of options together. When `'codemod'` we disable all whitespace control in handlebars (to preserve as much as possible) and we also avoid any escaping/unescaping of HTML entity codes. */ mode?: "codemod" | "precompile"; } interface Syntax { parse: typeof preprocess; builders: typeof publicBuilder; print: typeof print; traverse: typeof traverse; Walker: typeof Walker; } function preprocess(input: string | src.Source | HBS.Program, options?: PreprocessOptions): ASTv1.Template; class Source { readonly source: string; readonly module: string; static from(source: string, options?: PrecompileOptions): Source; constructor(source: string, module?: string); /** * Validate that the character offset represents a position in the source string. */ check(offset: number): boolean; slice(start: number, end: number): string; offsetFor(line: number, column: number): SourceOffset; spanFor({ start, end }: Readonly): SourceSpan; hbsPosFor(offset: number): Nullable; charPosFor(position: SourcePosition): number | null; } enum OffsetKind { /** * We have already computed the character position of this offset or span. */ CharPosition = "CharPosition", /** * This offset or span was instantiated with a Handlebars SourcePosition or SourceLocation. Its * character position will be computed on demand. */ HbsPosition = "HbsPosition", /** * for (rare) situations where a node is created but there was no source location (e.g. the name * "default" in default blocks when the word "default" never appeared in source). This is used * by the internals when there is a legitimate reason for the internals to synthesize a node * with no location. */ InternalsSynthetic = "InternalsSynthetic", /** * For situations where a node represents zero parts of the source (for example, empty arguments). * In general, we attempt to assign these nodes *some* position (empty arguments can be * positioned immediately after the callee), but it's not always possible */ NonExistent = "NonExistent", /** * For situations where a source location was expected, but it didn't correspond to the node in * the source. This happens if a plugin creates broken locations. */ Broken = "Broken" } /** * This file implements the DSL used by span and offset in places where they need to exhaustively * consider all combinations of states (Handlebars offsets, character offsets and invisible/broken * offsets). * * It's probably overkill, but it makes the code that uses it clear. It could be refactored or * removed. */ const MatchAny = "MATCH_ANY"; type MatchAny = "MATCH_ANY"; type Matches = "Char,Hbs" | "Hbs,Char" | "Hbs,Hbs" | "Char,Char" | "Invisible,Any" | "Any,Invisible"; const IsInvisible = "IS_INVISIBLE"; type IsInvisible = "IS_INVISIBLE"; type Pattern = OffsetKind | IsInvisible | MatchAny; class When { _map: Map; get(pattern: Pattern, or: () => Out): Out; add(pattern: Pattern, out: Out): void; match(kind: OffsetKind): Out[]; } type ExhaustiveCheck = Exclude extends never ? ExhaustiveMatcher : Matcher>; type MatchFn = (left: PositionData, right: PositionData) => Out; interface ExhaustiveMatcher { check(): MatchFn; } function match(callback: (m: Matcher) => ExhaustiveMatcher): MatchFn; class Matcher { _whens: When Out>>; /** * You didn't exhaustively match all possibilities. */ protected check(): MatchFn; private matchFor; // This big block is the bulk of the heavy lifting in this file. It facilitates exhaustiveness // checking so that matchers can ensure they've actually covered all the cases (and TypeScript // will treat it as an exhaustive match). when(left: OffsetKind.CharPosition, right: OffsetKind.HbsPosition, callback: (left: CharPosition, right: HbsPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.HbsPosition, right: OffsetKind.CharPosition, callback: (left: HbsPosition, right: CharPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.HbsPosition, right: OffsetKind.HbsPosition, callback: (left: HbsPosition, right: HbsPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.CharPosition, right: OffsetKind.CharPosition, callback: (left: CharPosition, right: CharPosition) => Out): ExhaustiveCheck; when(left: IsInvisible, right: MatchAny, callback: (left: InvisiblePosition, right: PositionData) => Out): Matcher>; when(left: MatchAny, right: IsInvisible, callback: (left: PositionData, right: InvisiblePosition) => Out): ExhaustiveCheck; when(left: MatchAny, right: MatchAny, callback: (left: PositionData, right: PositionData) => Out): ExhaustiveMatcher; } type SerializedSourceSlice = [ chars: Chars, span: src.SerializedSourceSpan ]; class SourceSlice { static synthetic(chars: S): SourceSlice; static load(source: src.Source, slice: SerializedSourceSlice): SourceSlice; readonly chars: Chars; readonly loc: src.SourceSpan; constructor(options: { loc: src.SourceSpan; chars: Chars; }); getString(): string; serialize(): SerializedSourceSlice; } /** * All spans have these details in common. */ interface SpanData { readonly kind: OffsetKind; /** * Convert this span into a string. If the span is broken, return `''`. */ asString(): string; /** * Gets the module the span was located in. */ getModule(): string; /** * Get the starting position for this span. Try to avoid creating new position objects, as they * cache computations. */ getStart(): AnyPosition; /** * Get the ending position for this span. Try to avoid creating new position objects, as they * cache computations. */ getEnd(): AnyPosition; /** * Compute the `SourceLocation` for this span, returned as an instance of `HbsSpan`. */ toHbsSpan(): HbsSpan | null; /** * For compatibility, whenever the `start` or `end` of a {@see SourceOffset} changes, spans are * notified of the change so they can update themselves. This shouldn't happen outside of AST * plugins. */ locDidUpdate(changes: { start?: SourcePosition; end?: SourcePosition; }): void; /** * Serialize into a {@see SerializedSourceSpan}, which is compact and designed for readability in * context like AST Explorer. If you need a {@see SourceLocation}, use {@see toJSON}. */ serialize(): SerializedSourceSpan; } /** * A `SourceSpan` object represents a span of characters inside of a template source. * * There are three kinds of `SourceSpan` objects: * * - `ConcreteSourceSpan`, which contains byte offsets * - `LazySourceSpan`, which contains `SourceLocation`s from the Handlebars AST, which can be * converted to byte offsets on demand. * - `InvisibleSourceSpan`, which represent source strings that aren't present in the source, * because: * - they were created synthetically * - their location is nonsensical (the span is broken) * - they represent nothing in the source (this currently happens only when a bug in the * upstream Handlebars parser fails to assign a location to empty blocks) * * At a high level, all `SourceSpan` objects provide: * * - byte offsets * - source in column and line format * * And you can do these operations on `SourceSpan`s: * * - collapse it to a `SourceSpan` representing its starting or ending position * - slice out some characters, optionally skipping some characters at the beginning or end * - create a new `SourceSpan` with a different starting or ending offset * * All SourceSpan objects implement `SourceLocation`, for compatibility. All SourceSpan * objects have a `toJSON` that emits `SourceLocation`, also for compatibility. * * For compatibility, subclasses of `AbstractSourceSpan` must implement `locDidUpdate`, which * happens when an AST plugin attempts to modify the `start` or `end` of a span directly. * * The goal is to avoid creating any problems for use-cases like AST Explorer. */ class SourceSpan implements SourceLocation { private data; static get NON_EXISTENT(): SourceSpan; static load(source: Source, serialized: SerializedSourceSpan): SourceSpan; static forHbsLoc(source: Source, loc: SourceLocation): SourceSpan; static forCharPositions(source: Source, startPos: number, endPos: number): SourceSpan; static synthetic(chars: string): SourceSpan; static broken(pos?: SourceLocation): SourceSpan; readonly isInvisible: boolean; constructor(data: SpanData & AnySpan); getStart(): SourceOffset; getEnd(): SourceOffset; get loc(): SourceLocation; get module(): string; /** * Get the starting `SourcePosition` for this `SourceSpan`, lazily computing it if needed. */ get startPosition(): SourcePosition; /** * Get the ending `SourcePosition` for this `SourceSpan`, lazily computing it if needed. */ get endPosition(): SourcePosition; /** * Support converting ASTv1 nodes into a serialized format using JSON.stringify. */ toJSON(): SourceLocation; /** * Create a new span with the current span's end and a new beginning. */ withStart(other: SourceOffset): SourceSpan; /** * Create a new span with the current span's beginning and a new ending. */ withEnd(other: SourceOffset): SourceSpan; asString(): string; /** * Convert this `SourceSpan` into a `SourceSlice`. In debug mode, this method optionally checks * that the byte offsets represented by this `SourceSpan` actually correspond to the expected * string. */ toSlice(expected?: string): SourceSlice; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use startPosition instead */ get start(): SourcePosition; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use withStart instead */ set start(position: SourcePosition); /** * For compatibility with SourceLocation in AST plugins * * @deprecated use endPosition instead */ get end(): SourcePosition; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use withEnd instead */ set end(position: SourcePosition); /** * For compatibility with SourceLocation in AST plugins * * @deprecated use module instead */ get source(): string; collapse(where: "start" | "end"): SourceSpan; extend(other: SourceSpan): SourceSpan; serialize(): SerializedSourceSpan; slice({ skipStart, skipEnd }: { skipStart?: number; skipEnd?: number; }): SourceSpan; sliceStartChars({ skipStart, chars }: { skipStart?: number; chars: number; }): SourceSpan; sliceEndChars({ skipEnd, chars }: { skipEnd?: number; chars: number; }): SourceSpan; } type AnySpan = HbsSpan | CharPositionSpan | InvisibleSpan; class CharPositionSpan implements SpanData { readonly source: Source; readonly charPositions: { start: CharPosition; end: CharPosition; }; readonly kind = OffsetKind.CharPosition; _locPosSpan: HbsSpan | BROKEN | null; constructor(source: Source, charPositions: { start: CharPosition; end: CharPosition; }); wrap(): SourceSpan; asString(): string; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; locDidUpdate(): void; toHbsSpan(): HbsSpan | null; serialize(): SerializedSourceSpan; toCharPosSpan(): CharPositionSpan; } class HbsSpan implements SpanData { readonly source: Source; readonly hbsPositions: { start: HbsPosition; end: HbsPosition; }; readonly kind = OffsetKind.HbsPosition; _charPosSpan: CharPositionSpan | BROKEN | null; // the source location from Handlebars + AST Plugins -- could be wrong _providedHbsLoc: SourceLocation | null; constructor(source: Source, hbsPositions: { start: HbsPosition; end: HbsPosition; }, providedHbsLoc?: SourceLocation | null); serialize(): SerializedConcreteSourceSpan; wrap(): SourceSpan; private updateProvided; locDidUpdate({ start, end }: { start?: SourcePosition; end?: SourcePosition; }): void; asString(): string; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; toHbsLoc(): SourceLocation; toHbsSpan(): HbsSpan; toCharPosSpan(): CharPositionSpan | null; } class InvisibleSpan implements SpanData { readonly kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent; // whatever was provided, possibly broken readonly loc: SourceLocation; // if the span represents a synthetic string readonly string: string | null; constructor(kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent, loc: SourceLocation, string?: string | null); serialize(): SerializedConcreteSourceSpan; wrap(): SourceSpan; asString(): string; locDidUpdate({ start, end }: { start?: SourcePosition; end?: SourcePosition; }): void; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; toCharPosSpan(): InvisibleSpan; toHbsSpan(): null; toHbsLoc(): SourceLocation; } const span: MatchFn; type SerializedConcreteSourceSpan = /** collapsed */ number | /** normal */ [ start: number, size: number ] | /** synthetic */ string; type SerializedSourceSpan = SerializedConcreteSourceSpan | OffsetKind.NonExistent | OffsetKind.Broken; interface SourceLocation { start: SourcePosition; end: SourcePosition; } interface SourcePosition { /** >= 1 */ line: number; /** >= 0 */ column: number; } const UNKNOWN_POSITION: Readonly<{ readonly line: 1; readonly column: 0; }>; const SYNTHETIC_LOCATION: Readonly<{ readonly source: "(synthetic)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; /** @deprecated */ const SYNTHETIC: Readonly<{ readonly source: "(synthetic)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; const TEMPORARY_LOCATION: Readonly<{ readonly source: "(temporary)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; const NON_EXISTENT_LOCATION: Readonly<{ readonly source: "(nonexistent)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; const BROKEN_LOCATION: Readonly<{ readonly source: "(broken)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; type LocatedWithSpan = { offsets: SourceSpan; }; type LocatedWithOptionalSpan = { offsets: SourceSpan | null; }; type LocatedWithPositions = { loc: SourceLocation; }; type LocatedWithOptionalPositions = { loc?: SourceLocation; }; function isLocatedWithPositionsArray(location: LocatedWithOptionalPositions[]): location is PresentArray; function isLocatedWithPositions(location: LocatedWithOptionalPositions): location is LocatedWithPositions; type HasSourceLocation = SourceLocation | LocatedWithPositions | PresentArray; type MaybeHasSourceLocation = null | LocatedWithOptionalPositions | LocatedWithOptionalPositions[]; /** * All positions have these details in common. Most notably, all three kinds of positions can * must be able to attempt to convert themselves into {@see CharPosition}. */ interface PositionData { readonly kind: OffsetKind; toCharPos(): CharPosition | null; toJSON(): SourcePosition; } /** * Used to indicate that an attempt to convert a `SourcePosition` to a character offset failed. It * is separate from `null` so that `null` can be used to indicate that the computation wasn't yet * attempted (and therefore to cache the failure) */ const BROKEN = "BROKEN"; type BROKEN = "BROKEN"; type AnyPosition = HbsPosition | CharPosition | InvisiblePosition; /** * A `SourceOffset` represents a single position in the source. * * There are three kinds of backing data for `SourceOffset` objects: * * - `CharPosition`, which contains a character offset into the raw source string * - `HbsPosition`, which contains a `SourcePosition` from the Handlebars AST, which can be * converted to a `CharPosition` on demand. * - `InvisiblePosition`, which represents a position not in source (@see {InvisiblePosition}) */ class SourceOffset { readonly data: PositionData & AnyPosition; /** * Create a `SourceOffset` from a Handlebars `SourcePosition`. It's stored as-is, and converted * into a character offset on demand, which avoids unnecessarily computing the offset of every * `SourceLocation`, but also means that broken `SourcePosition`s are not always detected. */ static forHbsPos(source: Source, pos: SourcePosition): SourceOffset; /** * Create a `SourceOffset` that corresponds to a broken `SourcePosition`. This means that the * calling code determined (or knows) that the `SourceLocation` doesn't correspond correctly to * any part of the source. */ static broken(pos?: SourcePosition): SourceOffset; constructor(data: PositionData & AnyPosition); /** * Get the character offset for this `SourceOffset`, if possible. */ get offset(): number | null; /** * Compare this offset with another one. * * If both offsets are `HbsPosition`s, they're equivalent as long as their lines and columns are * the same. This avoids computing offsets unnecessarily. * * Otherwise, two `SourceOffset`s are equivalent if their successfully computed character offsets * are the same. */ eql(right: SourceOffset): boolean; /** * Create a span that starts from this source offset and ends with another source offset. Avoid * computing character offsets if both `SourceOffset`s are still lazy. */ until(other: SourceOffset): SourceSpan; /** * Create a `SourceOffset` by moving the character position represented by this source offset * forward or backward (if `by` is negative), if possible. * * If this `SourceOffset` can't compute a valid character offset, `move` returns a broken offset. * * If the resulting character offset is less than 0 or greater than the size of the source, `move` * returns a broken offset. */ move(by: number): SourceOffset; /** * Create a new `SourceSpan` that represents a collapsed range at this source offset. Avoid * computing the character offset if it has not already been computed. */ collapsed(): SourceSpan; /** * Convert this `SourceOffset` into a Handlebars {@see SourcePosition} for compatibility with * existing plugins. */ toJSON(): SourcePosition; } class CharPosition implements PositionData { readonly source: Source; readonly charPos: number; readonly kind = OffsetKind.CharPosition; /** Computed from char offset */ _locPos: HbsPosition | BROKEN | null; constructor(source: Source, charPos: number); /** * This is already a `CharPosition`. * * {@see HbsPosition} for the alternative. */ toCharPos(): CharPosition; /** * Produce a Handlebars {@see SourcePosition} for this `CharPosition`. If this `CharPosition` was * computed using {@see SourceOffset#move}, this will compute the `SourcePosition` for the offset. */ toJSON(): SourcePosition; wrap(): SourceOffset; /** * A `CharPosition` always has an offset it can produce without any additional computation. */ get offset(): number; /** * Convert the current character offset to an `HbsPosition`, if it was not already computed. Once * a `CharPosition` has computed its `HbsPosition`, it will not need to do compute it again, and * the same `CharPosition` is retained when used as one of the ends of a `SourceSpan`, so * computing the `HbsPosition` should be a one-time operation. */ toHbsPos(): HbsPosition | null; } class HbsPosition implements PositionData { readonly source: Source; readonly hbsPos: SourcePosition; readonly kind = OffsetKind.HbsPosition; _charPos: CharPosition | BROKEN | null; constructor(source: Source, hbsPos: SourcePosition, charPos?: number | null); /** * Lazily compute the character offset from the {@see SourcePosition}. Once an `HbsPosition` has * computed its `CharPosition`, it will not need to do compute it again, and the same * `HbsPosition` is retained when used as one of the ends of a `SourceSpan`, so computing the * `CharPosition` should be a one-time operation. */ toCharPos(): CharPosition | null; /** * Return the {@see SourcePosition} that this `HbsPosition` was instantiated with. This operation * does not need to compute anything. */ toJSON(): SourcePosition; wrap(): SourceOffset; /** * This is already an `HbsPosition`. * * {@see CharPosition} for the alternative. */ toHbsPos(): HbsPosition; } class InvisiblePosition implements PositionData { readonly kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent; // whatever was provided, possibly broken readonly pos: SourcePosition; constructor(kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent, pos: SourcePosition); /** * A broken position cannot be turned into a {@see CharacterPosition}. */ toCharPos(): null; /** * The serialization of an `InvisiblePosition is whatever Handlebars {@see SourcePosition} was * originally identified as broken, non-existent or synthetic. * * If an `InvisiblePosition` never had an source offset at all, this method returns * {@see UNKNOWN_POSITION} for compatibility. */ toJSON(): SourcePosition; wrap(): SourceOffset; get offset(): null; } type HasSpan = SourceSpan | LocatedWithSpan | PresentArray; type MaybeHasSpan = SourceSpan | LocatedWithOptionalSpan | LocatedWithOptionalSpan[] | null; type ToSourceOffset = number | SourceOffset; class SpanList { static range(span: PresentArray): SourceSpan; static range(span: HasSourceSpan[], fallback: SourceSpan): SourceSpan; _span: SourceSpan[]; constructor(span?: SourceSpan[]); add(offset: SourceSpan): void; getRangeOffset(fallback: SourceSpan): SourceSpan; } type HasSourceSpan = { loc: SourceSpan; } | SourceSpan | [ HasSourceSpan, ...HasSourceSpan[] ]; function loc(span: HasSourceSpan): SourceSpan; type MaybeHasSourceSpan = { loc: SourceSpan; } | SourceSpan | MaybeHasSourceSpan[]; function hasSpan(span: MaybeHasSourceSpan): span is HasSourceSpan; function maybeLoc(location: MaybeHasSourceSpan, fallback: SourceSpan): SourceSpan; } declare namespace ASTv1 { type ParserNodeBuilder = Omit & { start: src.SourceOffset; }; interface StartTag { readonly type: "StartTag"; name: string; nameStart: Nullable; nameEnd: Nullable; readonly attributes: ASTv1.AttrNode[]; readonly modifiers: ASTv1.ElementModifierStatement[]; readonly comments: ASTv1.MustacheCommentStatement[]; readonly params: ASTv1.VarHead[]; selfClosing: boolean; readonly loc: src.SourceSpan; } interface EndTag { readonly type: "EndTag"; name: string; readonly loc: src.SourceSpan; } interface Attribute { name: string; currentPart: ASTv1.TextNode | null; parts: (ASTv1.MustacheStatement | ASTv1.TextNode)[]; isQuoted: boolean; isDynamic: boolean; start: src.SourceOffset; valueSpan: src.SourceSpan; } abstract class Parser { protected elementStack: ASTv1.ParentNode[]; private lines; readonly source: src.Source; currentAttribute: Nullable; currentNode: Nullable | ParserNodeBuilder | ParserNodeBuilder | ParserNodeBuilder>>; tokenizer: EventedTokenizer; constructor(source: src.Source, entityParser?: EntityParser, mode?: "precompile" | "codemod"); offset(): src.SourceOffset; pos({ line, column }: src.SourcePosition): src.SourceOffset; finish(node: ParserNodeBuilder): T; abstract parse(node: HBS.Program, locals: string[]): ASTv1.Template; abstract Program(node: HBS.Program): HBS.Output<"Program">; abstract MustacheStatement(node: HBS.MustacheStatement): HBS.Output<"MustacheStatement">; abstract Decorator(node: HBS.Decorator): HBS.Output<"Decorator">; abstract BlockStatement(node: HBS.BlockStatement): HBS.Output<"BlockStatement">; abstract DecoratorBlock(node: HBS.DecoratorBlock): HBS.Output<"DecoratorBlock">; abstract PartialStatement(node: HBS.PartialStatement): HBS.Output<"PartialStatement">; abstract PartialBlockStatement(node: HBS.PartialBlockStatement): HBS.Output<"PartialBlockStatement">; abstract ContentStatement(node: HBS.ContentStatement): HBS.Output<"ContentStatement">; abstract CommentStatement(node: HBS.CommentStatement): HBS.Output<"CommentStatement">; abstract SubExpression(node: HBS.SubExpression): HBS.Output<"SubExpression">; abstract PathExpression(node: HBS.PathExpression): HBS.Output<"PathExpression">; abstract StringLiteral(node: HBS.StringLiteral): HBS.Output<"StringLiteral">; abstract BooleanLiteral(node: HBS.BooleanLiteral): HBS.Output<"BooleanLiteral">; abstract NumberLiteral(node: HBS.NumberLiteral): HBS.Output<"NumberLiteral">; abstract UndefinedLiteral(node: HBS.UndefinedLiteral): HBS.Output<"UndefinedLiteral">; abstract NullLiteral(node: HBS.NullLiteral): HBS.Output<"NullLiteral">; abstract reset(): void; abstract finishData(): void; abstract tagOpen(): void; abstract beginData(): void; abstract appendToData(char: string): void; abstract beginStartTag(): void; abstract appendToTagName(char: string): void; abstract beginAttribute(): void; abstract appendToAttributeName(char: string): void; abstract beginAttributeValue(quoted: boolean): void; abstract appendToAttributeValue(char: string): void; abstract finishAttributeValue(): void; abstract markTagAsSelfClosing(): void; abstract beginEndTag(): void; abstract finishTag(): void; abstract beginComment(): void; abstract appendToCommentData(char: string): void; abstract finishComment(): void; abstract reportSyntaxError(error: string): void; get currentAttr(): Attribute; get currentTag(): ParserNodeBuilder | ParserNodeBuilder; get currentStartTag(): ParserNodeBuilder; get currentEndTag(): ParserNodeBuilder; get currentComment(): ParserNodeBuilder; get currentData(): ParserNodeBuilder; acceptNode(node: HBS.Node): HBS.Output; currentElement(): ASTv1.ParentNode; sourceForNode(node: HBS.Node, endNode?: { loc: HBS.SourceLocation; }): string; } // ensure stays in sync with typing // ParentNode and ChildKey types are derived from VisitorKeysMap const visitorKeys: { readonly Template: readonly [ "body" ]; readonly Block: readonly [ "body" ]; readonly MustacheStatement: readonly [ "path", "params", "hash" ]; readonly BlockStatement: readonly [ "path", "params", "hash", "program", "inverse" ]; readonly ElementModifierStatement: readonly [ "path", "params", "hash" ]; readonly CommentStatement: readonly [ ]; readonly MustacheCommentStatement: readonly [ ]; readonly ElementNode: readonly [ "attributes", "modifiers", "children", "comments" ]; readonly AttrNode: readonly [ "value" ]; readonly TextNode: readonly [ ]; readonly ConcatStatement: readonly [ "parts" ]; readonly SubExpression: readonly [ "path", "params", "hash" ]; readonly PathExpression: readonly [ ]; readonly StringLiteral: readonly [ ]; readonly BooleanLiteral: readonly [ ]; readonly NumberLiteral: readonly [ ]; readonly NullLiteral: readonly [ ]; readonly UndefinedLiteral: readonly [ ]; readonly Hash: readonly [ "pairs" ]; readonly HashPair: readonly [ "value" ]; }; type VisitorKeysMap = typeof visitorKeys; type VisitorKeys = { [P in keyof VisitorKeysMap]: VisitorKeysMap[P][number]; }; type VisitorKey = VisitorKeys[N["type"]] & keyof N; class WalkerPath { node: N; parent: WalkerPath | null; parentKey: string | null; constructor(node: N, parent?: WalkerPath | null, parentKey?: string | null); get parentNode(): ASTv1.Node | null; parents(): Iterable | null>; } interface FullNodeTraversal { enter?(node: N, path: WalkerPath): void; exit?(node: N, path: WalkerPath): void; keys?: KeysVisitor; } type NodeHandler = (node: N, path: WalkerPath) => void; type NodeTraversal = FullNodeTraversal | NodeHandler; type NodeVisitor = { [P in keyof ASTv1.Nodes]?: NodeTraversal; } & { All?: NodeTraversal; /** * @deprecated use Template or Block instead */ Program?: NodeTraversal; }; interface FullKeyTraversal { enter?(node: N, key: K): void; exit?(node: N, key: K): void; } type KeyHandler> = (node: N, key: K) => void; type KeyTraversal> = FullKeyTraversal | KeyHandler; type KeysVisitor = { [P in VisitorKey]?: KeyTraversal; } & { All?: KeyTraversal>; /** * @deprecated use Template or Block instead */ Program?: KeyTraversal; }; const voidMap: Set; function getVoidTags(): string[]; interface PrinterOptions { entityEncoding: ASTv1.EntityEncodingState; /** * Used to override the mechanism of printing a given AST.Node. * * This will generally only be useful to source -> source codemods * where you would like to specialize/override the way a given node is * printed (e.g. you would like to preserve as much of the original * formatting as possible). * * When the provided override returns undefined, the default built in printing * will be done for the AST.Node. * * @param ast the ast node to be printed * @param options the options specified during the print() invocation */ override?(ast: ASTv1.Node, options: PrinterOptions): void | string; } /** * Examples when true: * - link * - liNK * * Examples when false: * - Link (component) */ function isVoidTag(tag: string): boolean; class Printer { private buffer; private options; constructor(options: PrinterOptions); /* This is used by _all_ methods on this Printer class that add to `this.buffer`, it allows consumers of the printer to use alternate string representations for a given node. The primary use case for this are things like source -> source codemod utilities. For example, ember-template-recast attempts to always preserve the original string formatting in each AST node if no modifications are made to it. */ handledByOverride(node: ASTv1.Node, ensureLeadingWhitespace?: boolean): boolean; Node(node: ASTv1.Node): void; Expression(expression: ASTv1.Expression): void; Literal(literal: ASTv1.Literal): void; TopLevelStatement(statement: ASTv1.TopLevelStatement | ASTv1.Template | ASTv1.AttrNode): void; Template(template: ASTv1.Template): void; Block(block: ASTv1.Block): void; TopLevelStatements(statements: ASTv1.TopLevelStatement[]): void; ElementNode(el: ASTv1.ElementNode): void; OpenElementNode(el: ASTv1.ElementNode): void; CloseElementNode(el: ASTv1.ElementNode): void; AttrNode(attr: ASTv1.AttrNode): void; AttrNodeValue(value: ASTv1.AttrNode["value"]): void; TextNode(text: ASTv1.TextNode, isAttr?: boolean): void; MustacheStatement(mustache: ASTv1.MustacheStatement): void; BlockStatement(block: ASTv1.BlockStatement): void; BlockParams(blockParams: string[]): void; ConcatStatement(concat: ASTv1.ConcatStatement): void; MustacheCommentStatement(comment: ASTv1.MustacheCommentStatement): void; ElementModifierStatement(mod: ASTv1.ElementModifierStatement): void; CommentStatement(comment: ASTv1.CommentStatement): void; PathExpression(path: ASTv1.PathExpression): void; SubExpression(sexp: ASTv1.SubExpression): void; Params(params: ASTv1.Expression[]): void; Hash(hash: ASTv1.Hash): void; HashPair(pair: ASTv1.HashPair): void; StringLiteral(str: ASTv1.StringLiteral): void; BooleanLiteral(bool: ASTv1.BooleanLiteral): void; NumberLiteral(number: ASTv1.NumberLiteral): void; UndefinedLiteral(node: ASTv1.UndefinedLiteral): void; NullLiteral(node: ASTv1.NullLiteral): void; print(node: ASTv1.Node): string; } function build(ast: ASTv1.Node, options?: PrinterOptions): string; const print: typeof build; function traverse(node: ASTv1.Node, visitor: NodeVisitor): void; type NodeCallback = (node: N, walker: Walker) => void; class Walker { order?: unknown; stack: unknown[]; constructor(order?: unknown); visit(node: Nullable, visitor: NodeCallback): void; children(node: N & ASTv1.Node, callback: NodeCallback): void; } // const SOURCE = new Source('', '(tests)'); // Statements type BuilderHead = string | ASTv1.CallableExpression; type TagDescriptor = string | ASTv1.PathExpression | { path: ASTv1.PathExpression; selfClosing?: boolean; } | { name: string; selfClosing?: boolean; }; function buildMustache(path: BuilderHead | ASTv1.Literal, params?: ASTv1.Expression[], hash?: ASTv1.Hash, trusting?: boolean, loc?: SourceLocation, strip?: ASTv1.StripFlags): ASTv1.MustacheStatement; type PossiblyDeprecatedBlock = ASTv1.Block | ASTv1.Template; function buildBlock(path: BuilderHead, params: Nullable, hash: Nullable, _defaultBlock: PossiblyDeprecatedBlock, _elseBlock?: Nullable, loc?: SourceLocation, openStrip?: ASTv1.StripFlags, inverseStrip?: ASTv1.StripFlags, closeStrip?: ASTv1.StripFlags): ASTv1.BlockStatement; function buildElementModifier(path: BuilderHead, params?: ASTv1.Expression[], hash?: ASTv1.Hash, loc?: Nullable): ASTv1.ElementModifierStatement; function buildComment(value: string, loc?: SourceLocation): ASTv1.CommentStatement; function buildMustacheComment(value: string, loc?: SourceLocation): ASTv1.MustacheCommentStatement; function buildConcat(parts: (ASTv1.TextNode | ASTv1.MustacheStatement)[], loc?: SourceLocation): ASTv1.ConcatStatement; // Nodes type ElementParts = [ "attrs", ...AttrSexp[] ] | [ "modifiers", ...ModifierSexp[] ] | [ "body", ...ASTv1.Statement[] ] | [ "comments", ...ElementComment[] ] | [ "as", ...string[] ] | [ "loc", SourceLocation ]; type PathSexp = string | [ "path", string, LocSexp? ]; type ModifierSexp = string | [ PathSexp, LocSexp? ] | [ PathSexp, ASTv1.Expression[], LocSexp? ] | [ PathSexp, ASTv1.Expression[], Dict, LocSexp? ]; type AttrSexp = [ string, ASTv1.AttrNode["value"] | string, LocSexp? ]; type LocSexp = [ "loc", SourceLocation ]; type ElementComment = ASTv1.MustacheCommentStatement | SourceLocation | string; type SexpValue = string | ASTv1.Expression[] | Dict | LocSexp | PathSexp | undefined; interface BuildElementOptions { attrs?: ASTv1.AttrNode[]; modifiers?: ASTv1.ElementModifierStatement[]; children?: ASTv1.Statement[]; comments?: ASTv1.MustacheCommentStatement[]; blockParams?: ASTv1.VarHead[] | string[]; openTag?: SourceLocation; closeTag?: Nullable; loc?: SourceLocation; } function buildElement(tag: TagDescriptor, options?: BuildElementOptions): ASTv1.ElementNode; function buildAttr(name: string, value: ASTv1.AttrValue, loc?: SourceLocation): ASTv1.AttrNode; function buildText(chars?: string, loc?: SourceLocation): ASTv1.TextNode; // Expressions function buildSexpr(path: BuilderHead, params?: ASTv1.Expression[], hash?: ASTv1.Hash, loc?: SourceLocation): ASTv1.SubExpression; function buildThis(loc?: SourceLocation): ASTv1.ThisHead; function buildAtName(name: string, loc?: SourceLocation): ASTv1.AtHead; function buildVar(name: string, loc?: SourceLocation): ASTv1.VarHead; function buildHeadFromString(original: string, loc?: SourceLocation): ASTv1.PathHead; function buildCleanPath(head: ASTv1.PathHead, tail?: string[], loc?: SourceLocation): ASTv1.PathExpression; function buildPath(path: ASTv1.PathExpression | string | { head: string; tail: string[]; }, loc?: SourceLocation): ASTv1.PathExpression; function buildPath(path: BuilderHead, loc?: SourceLocation): ASTv1.CallableExpression; function buildPath(path: BuilderHead | ASTv1.Literal, loc?: SourceLocation): ASTv1.Expression; function buildPath(path: ASTv1.Expression, loc?: SourceLocation): ASTv1.Expression; function buildLiteral(type: T["type"], value: T["value"], loc?: SourceLocation): T; // Miscellaneous function buildHash(pairs?: ASTv1.HashPair[], loc?: SourceLocation): ASTv1.Hash; function buildPair(key: string, value: ASTv1.Expression, loc?: SourceLocation): ASTv1.HashPair; function buildProgram(body?: ASTv1.Statement[], blockParams?: string[], loc?: SourceLocation): ASTv1.Template | ASTv1.Block; function buildBlockItself(body?: ASTv1.Statement[], params?: Array, chained?: boolean, loc?: SourceLocation): ASTv1.Block; function buildTemplate(body?: ASTv1.Statement[], blockParams?: string[], loc?: SourceLocation): ASTv1.Template; function buildPosition(line: number, column: number): SourcePosition; function buildLoc(loc: Nullable): SourceSpan; function buildLoc(startLine: number, startColumn: number, endLine?: number, endColumn?: number, source?: string): SourceSpan; const _default: { mustache: typeof buildMustache; block: typeof buildBlock; comment: typeof buildComment; mustacheComment: typeof buildMustacheComment; element: typeof buildElement; elementModifier: typeof buildElementModifier; attr: typeof buildAttr; text: typeof buildText; sexpr: typeof buildSexpr; concat: typeof buildConcat; hash: typeof buildHash; pair: typeof buildPair; literal: typeof buildLiteral; program: typeof buildProgram; blockItself: typeof buildBlockItself; template: typeof buildTemplate; loc: typeof buildLoc; pos: typeof buildPosition; path: typeof buildPath; fullPath: typeof buildCleanPath; head: typeof buildHeadFromString; at: typeof buildAtName; var: typeof buildVar; this: typeof buildThis; string: (value: string) => ASTv1.StringLiteral; boolean: (value: boolean) => ASTv1.BooleanLiteral; number: (value: number) => ASTv1.NumberLiteral; undefined(): ASTv1.UndefinedLiteral; null(): ASTv1.NullLiteral; }; const publicBuilder: typeof _default; interface PendingError { mustache(span: SourceSpan): never; eof(offset: SourceOffset): never; } abstract class HandlebarsNodeVisitors extends Parser { // Because we interleave the HTML and HBS parsing, sometimes the HTML // tokenizer can run out of tokens when we switch into {{...}} or reached // EOF. There are positions where neither of these are expected, and it would // like to generate an error, but there is no span to attach the error to. // This allows the HTML tokenization to stash an error message and the next // mustache visitor will attach the message to the appropriate span and throw // the error. protected pendingError: Nullable; abstract appendToCommentData(s: string): void; abstract beginAttributeValue(quoted: boolean): void; abstract finishAttributeValue(): void; parse(program: HBS.Program, blockParams: string[]): ASTv1.Template; Program(program: HBS.Program, blockParams?: ASTv1.VarHead[]): ASTv1.Block; private parseProgram; BlockStatement(block: HBS.BlockStatement): ASTv1.BlockStatement | void; MustacheStatement(rawMustache: HBS.MustacheStatement): ASTv1.MustacheStatement | void; appendDynamicAttributeValuePart(part: ASTv1.MustacheStatement): void; finalizeTextPart(): void; startTextPart(): void; ContentStatement(content: HBS.ContentStatement): void; CommentStatement(rawComment: HBS.CommentStatement): Nullable; PartialStatement(partial: HBS.PartialStatement): never; PartialBlockStatement(partialBlock: HBS.PartialBlockStatement): never; Decorator(decorator: HBS.Decorator): never; DecoratorBlock(decoratorBlock: HBS.DecoratorBlock): never; SubExpression(sexpr: HBS.SubExpression): ASTv1.SubExpression; PathExpression(path: HBS.PathExpression): ASTv1.PathExpression; Hash(hash: HBS.Hash): ASTv1.Hash; StringLiteral(string: HBS.StringLiteral): ASTv1.StringLiteral; BooleanLiteral(boolean: HBS.BooleanLiteral): ASTv1.BooleanLiteral; NumberLiteral(number: HBS.NumberLiteral): ASTv1.NumberLiteral; UndefinedLiteral(undef: HBS.UndefinedLiteral): ASTv1.UndefinedLiteral; NullLiteral(nul: HBS.NullLiteral): ASTv1.NullLiteral; } class TokenizerEventHandlers extends HandlebarsNodeVisitors { private tagOpenLine; private tagOpenColumn; reset(): void; // Comment beginComment(): void; appendToCommentData(char: string): void; finishComment(): void; // Data beginData(): void; appendToData(char: string): void; finishData(): void; // Tags - basic tagOpen(): void; beginStartTag(): void; beginEndTag(): void; finishTag(): void; finishStartTag(): void; finishEndTag(isVoid: boolean): void; markTagAsSelfClosing(): void; // Tags - name appendToTagName(char: string): void; // Tags - attributes beginAttribute(): void; appendToAttributeName(char: string): void; beginAttributeValue(isQuoted: boolean): void; appendToAttributeValue(char: string): void; finishAttributeValue(): void; private parsePossibleBlockParams; reportSyntaxError(message: string): void; assembleConcatenatedValue(parts: (ASTv1.MustacheStatement | ASTv1.TextNode)[]): ASTv1.ConcatStatement; validateEndTag(tag: StartTag | EndTag, element: ASTv1.ElementNode, selfClosing: boolean): void; assembleAttributeValue(parts: ASTv1.AttrPart[], isQuoted: boolean, isDynamic: boolean, span: src.SourceSpan): ASTv1.AttrValue; } /** ASTPlugins can make changes to the Glimmer template AST before compilation begins. */ interface ASTPluginBuilder { (env: TEnv): ASTPlugin; } interface ASTPlugin { name: string; visitor: NodeVisitor; } interface ASTPluginEnvironment { meta?: object; syntax: Syntax; } interface HandlebarsParseOptions { srcName?: string; ignoreStandalone?: boolean; } interface TemplateIdFn { (src: string): Nullable; } interface PrecompileOptions extends PreprocessOptions { id?: TemplateIdFn; /** * Additional non-native keywords. * * Local variables (block params or lexical scope) always takes precedence, * but otherwise, suitable free variable candidates (e.g. those are not part * of a path) are matched against this list and turned into keywords. * * In strict mode compilation, keywords suppresses the undefined reference * error and will be resolved by the runtime environment. * * In loose mode, keywords are currently ignored and since all free variables * are already resolved by the runtime environment. */ keywords?: readonly string[]; customizeComponentName?: ((input: string) => string) | undefined; } interface PrecompileOptionsWithLexicalScope extends PrecompileOptions { lexicalScope: (variable: string) => boolean; } interface PreprocessOptions { strictMode?: boolean; locals?: string[]; meta?: { moduleName?: string; }; plugins?: { ast?: ASTPluginBuilder[]; }; parseOptions?: HandlebarsParseOptions; customizeComponentName?: ((input: string) => string) | undefined; /** Useful for specifying a group of options together. When `'codemod'` we disable all whitespace control in handlebars (to preserve as much as possible) and we also avoid any escaping/unescaping of HTML entity codes. */ mode?: "codemod" | "precompile"; } interface Syntax { parse: typeof preprocess; builders: typeof publicBuilder; print: typeof print; traverse: typeof traverse; Walker: typeof Walker; } function preprocess(input: string | src.Source | HBS.Program, options?: PreprocessOptions): ASTv1.Template; class Source { readonly source: string; readonly module: string; static from(source: string, options?: PrecompileOptions): Source; constructor(source: string, module?: string); /** * Validate that the character offset represents a position in the source string. */ check(offset: number): boolean; slice(start: number, end: number): string; offsetFor(line: number, column: number): SourceOffset; spanFor({ start, end }: Readonly): SourceSpan; hbsPosFor(offset: number): Nullable; charPosFor(position: SourcePosition): number | null; } enum OffsetKind { /** * We have already computed the character position of this offset or span. */ CharPosition = "CharPosition", /** * This offset or span was instantiated with a Handlebars SourcePosition or SourceLocation. Its * character position will be computed on demand. */ HbsPosition = "HbsPosition", /** * for (rare) situations where a node is created but there was no source location (e.g. the name * "default" in default blocks when the word "default" never appeared in source). This is used * by the internals when there is a legitimate reason for the internals to synthesize a node * with no location. */ InternalsSynthetic = "InternalsSynthetic", /** * For situations where a node represents zero parts of the source (for example, empty arguments). * In general, we attempt to assign these nodes *some* position (empty arguments can be * positioned immediately after the callee), but it's not always possible */ NonExistent = "NonExistent", /** * For situations where a source location was expected, but it didn't correspond to the node in * the source. This happens if a plugin creates broken locations. */ Broken = "Broken" } /** * This file implements the DSL used by span and offset in places where they need to exhaustively * consider all combinations of states (Handlebars offsets, character offsets and invisible/broken * offsets). * * It's probably overkill, but it makes the code that uses it clear. It could be refactored or * removed. */ const MatchAny = "MATCH_ANY"; type MatchAny = "MATCH_ANY"; type Matches = "Char,Hbs" | "Hbs,Char" | "Hbs,Hbs" | "Char,Char" | "Invisible,Any" | "Any,Invisible"; const IsInvisible = "IS_INVISIBLE"; type IsInvisible = "IS_INVISIBLE"; type Pattern = OffsetKind | IsInvisible | MatchAny; class When { _map: Map; get(pattern: Pattern, or: () => Out): Out; add(pattern: Pattern, out: Out): void; match(kind: OffsetKind): Out[]; } type ExhaustiveCheck = Exclude extends never ? ExhaustiveMatcher : Matcher>; type MatchFn = (left: PositionData, right: PositionData) => Out; interface ExhaustiveMatcher { check(): MatchFn; } function match(callback: (m: Matcher) => ExhaustiveMatcher): MatchFn; class Matcher { _whens: When Out>>; /** * You didn't exhaustively match all possibilities. */ protected check(): MatchFn; private matchFor; // This big block is the bulk of the heavy lifting in this file. It facilitates exhaustiveness // checking so that matchers can ensure they've actually covered all the cases (and TypeScript // will treat it as an exhaustive match). when(left: OffsetKind.CharPosition, right: OffsetKind.HbsPosition, callback: (left: CharPosition, right: HbsPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.HbsPosition, right: OffsetKind.CharPosition, callback: (left: HbsPosition, right: CharPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.HbsPosition, right: OffsetKind.HbsPosition, callback: (left: HbsPosition, right: HbsPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.CharPosition, right: OffsetKind.CharPosition, callback: (left: CharPosition, right: CharPosition) => Out): ExhaustiveCheck; when(left: IsInvisible, right: MatchAny, callback: (left: InvisiblePosition, right: PositionData) => Out): Matcher>; when(left: MatchAny, right: IsInvisible, callback: (left: PositionData, right: InvisiblePosition) => Out): ExhaustiveCheck; when(left: MatchAny, right: MatchAny, callback: (left: PositionData, right: PositionData) => Out): ExhaustiveMatcher; } type SerializedSourceSlice = [ chars: Chars, span: src.SerializedSourceSpan ]; class SourceSlice { static synthetic(chars: S): SourceSlice; static load(source: src.Source, slice: SerializedSourceSlice): SourceSlice; readonly chars: Chars; readonly loc: src.SourceSpan; constructor(options: { loc: src.SourceSpan; chars: Chars; }); getString(): string; serialize(): SerializedSourceSlice; } /** * All spans have these details in common. */ interface SpanData { readonly kind: OffsetKind; /** * Convert this span into a string. If the span is broken, return `''`. */ asString(): string; /** * Gets the module the span was located in. */ getModule(): string; /** * Get the starting position for this span. Try to avoid creating new position objects, as they * cache computations. */ getStart(): AnyPosition; /** * Get the ending position for this span. Try to avoid creating new position objects, as they * cache computations. */ getEnd(): AnyPosition; /** * Compute the `SourceLocation` for this span, returned as an instance of `HbsSpan`. */ toHbsSpan(): HbsSpan | null; /** * For compatibility, whenever the `start` or `end` of a {@see SourceOffset} changes, spans are * notified of the change so they can update themselves. This shouldn't happen outside of AST * plugins. */ locDidUpdate(changes: { start?: SourcePosition; end?: SourcePosition; }): void; /** * Serialize into a {@see SerializedSourceSpan}, which is compact and designed for readability in * context like AST Explorer. If you need a {@see SourceLocation}, use {@see toJSON}. */ serialize(): SerializedSourceSpan; } /** * A `SourceSpan` object represents a span of characters inside of a template source. * * There are three kinds of `SourceSpan` objects: * * - `ConcreteSourceSpan`, which contains byte offsets * - `LazySourceSpan`, which contains `SourceLocation`s from the Handlebars AST, which can be * converted to byte offsets on demand. * - `InvisibleSourceSpan`, which represent source strings that aren't present in the source, * because: * - they were created synthetically * - their location is nonsensical (the span is broken) * - they represent nothing in the source (this currently happens only when a bug in the * upstream Handlebars parser fails to assign a location to empty blocks) * * At a high level, all `SourceSpan` objects provide: * * - byte offsets * - source in column and line format * * And you can do these operations on `SourceSpan`s: * * - collapse it to a `SourceSpan` representing its starting or ending position * - slice out some characters, optionally skipping some characters at the beginning or end * - create a new `SourceSpan` with a different starting or ending offset * * All SourceSpan objects implement `SourceLocation`, for compatibility. All SourceSpan * objects have a `toJSON` that emits `SourceLocation`, also for compatibility. * * For compatibility, subclasses of `AbstractSourceSpan` must implement `locDidUpdate`, which * happens when an AST plugin attempts to modify the `start` or `end` of a span directly. * * The goal is to avoid creating any problems for use-cases like AST Explorer. */ class SourceSpan implements SourceLocation { private data; static get NON_EXISTENT(): SourceSpan; static load(source: Source, serialized: SerializedSourceSpan): SourceSpan; static forHbsLoc(source: Source, loc: SourceLocation): SourceSpan; static forCharPositions(source: Source, startPos: number, endPos: number): SourceSpan; static synthetic(chars: string): SourceSpan; static broken(pos?: SourceLocation): SourceSpan; readonly isInvisible: boolean; constructor(data: SpanData & AnySpan); getStart(): SourceOffset; getEnd(): SourceOffset; get loc(): SourceLocation; get module(): string; /** * Get the starting `SourcePosition` for this `SourceSpan`, lazily computing it if needed. */ get startPosition(): SourcePosition; /** * Get the ending `SourcePosition` for this `SourceSpan`, lazily computing it if needed. */ get endPosition(): SourcePosition; /** * Support converting ASTv1 nodes into a serialized format using JSON.stringify. */ toJSON(): SourceLocation; /** * Create a new span with the current span's end and a new beginning. */ withStart(other: SourceOffset): SourceSpan; /** * Create a new span with the current span's beginning and a new ending. */ withEnd(other: SourceOffset): SourceSpan; asString(): string; /** * Convert this `SourceSpan` into a `SourceSlice`. In debug mode, this method optionally checks * that the byte offsets represented by this `SourceSpan` actually correspond to the expected * string. */ toSlice(expected?: string): SourceSlice; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use startPosition instead */ get start(): SourcePosition; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use withStart instead */ set start(position: SourcePosition); /** * For compatibility with SourceLocation in AST plugins * * @deprecated use endPosition instead */ get end(): SourcePosition; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use withEnd instead */ set end(position: SourcePosition); /** * For compatibility with SourceLocation in AST plugins * * @deprecated use module instead */ get source(): string; collapse(where: "start" | "end"): SourceSpan; extend(other: SourceSpan): SourceSpan; serialize(): SerializedSourceSpan; slice({ skipStart, skipEnd }: { skipStart?: number; skipEnd?: number; }): SourceSpan; sliceStartChars({ skipStart, chars }: { skipStart?: number; chars: number; }): SourceSpan; sliceEndChars({ skipEnd, chars }: { skipEnd?: number; chars: number; }): SourceSpan; } type AnySpan = HbsSpan | CharPositionSpan | InvisibleSpan; class CharPositionSpan implements SpanData { readonly source: Source; readonly charPositions: { start: CharPosition; end: CharPosition; }; readonly kind = OffsetKind.CharPosition; _locPosSpan: HbsSpan | BROKEN | null; constructor(source: Source, charPositions: { start: CharPosition; end: CharPosition; }); wrap(): SourceSpan; asString(): string; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; locDidUpdate(): void; toHbsSpan(): HbsSpan | null; serialize(): SerializedSourceSpan; toCharPosSpan(): CharPositionSpan; } class HbsSpan implements SpanData { readonly source: Source; readonly hbsPositions: { start: HbsPosition; end: HbsPosition; }; readonly kind = OffsetKind.HbsPosition; _charPosSpan: CharPositionSpan | BROKEN | null; // the source location from Handlebars + AST Plugins -- could be wrong _providedHbsLoc: SourceLocation | null; constructor(source: Source, hbsPositions: { start: HbsPosition; end: HbsPosition; }, providedHbsLoc?: SourceLocation | null); serialize(): SerializedConcreteSourceSpan; wrap(): SourceSpan; private updateProvided; locDidUpdate({ start, end }: { start?: SourcePosition; end?: SourcePosition; }): void; asString(): string; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; toHbsLoc(): SourceLocation; toHbsSpan(): HbsSpan; toCharPosSpan(): CharPositionSpan | null; } class InvisibleSpan implements SpanData { readonly kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent; // whatever was provided, possibly broken readonly loc: SourceLocation; // if the span represents a synthetic string readonly string: string | null; constructor(kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent, loc: SourceLocation, string?: string | null); serialize(): SerializedConcreteSourceSpan; wrap(): SourceSpan; asString(): string; locDidUpdate({ start, end }: { start?: SourcePosition; end?: SourcePosition; }): void; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; toCharPosSpan(): InvisibleSpan; toHbsSpan(): null; toHbsLoc(): SourceLocation; } const span: MatchFn; type SerializedConcreteSourceSpan = /** collapsed */ number | /** normal */ [ start: number, size: number ] | /** synthetic */ string; type SerializedSourceSpan = SerializedConcreteSourceSpan | OffsetKind.NonExistent | OffsetKind.Broken; interface SourceLocation { start: SourcePosition; end: SourcePosition; } interface SourcePosition { /** >= 1 */ line: number; /** >= 0 */ column: number; } const UNKNOWN_POSITION: Readonly<{ readonly line: 1; readonly column: 0; }>; const SYNTHETIC_LOCATION: Readonly<{ readonly source: "(synthetic)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; /** @deprecated */ const SYNTHETIC: Readonly<{ readonly source: "(synthetic)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; const TEMPORARY_LOCATION: Readonly<{ readonly source: "(temporary)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; const NON_EXISTENT_LOCATION: Readonly<{ readonly source: "(nonexistent)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; const BROKEN_LOCATION: Readonly<{ readonly source: "(broken)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; type LocatedWithSpan = { offsets: SourceSpan; }; type LocatedWithOptionalSpan = { offsets: SourceSpan | null; }; type LocatedWithPositions = { loc: SourceLocation; }; type LocatedWithOptionalPositions = { loc?: SourceLocation; }; function isLocatedWithPositionsArray(location: LocatedWithOptionalPositions[]): location is PresentArray; function isLocatedWithPositions(location: LocatedWithOptionalPositions): location is LocatedWithPositions; type HasSourceLocation = SourceLocation | LocatedWithPositions | PresentArray; type MaybeHasSourceLocation = null | LocatedWithOptionalPositions | LocatedWithOptionalPositions[]; /** * All positions have these details in common. Most notably, all three kinds of positions can * must be able to attempt to convert themselves into {@see CharPosition}. */ interface PositionData { readonly kind: OffsetKind; toCharPos(): CharPosition | null; toJSON(): SourcePosition; } /** * Used to indicate that an attempt to convert a `SourcePosition` to a character offset failed. It * is separate from `null` so that `null` can be used to indicate that the computation wasn't yet * attempted (and therefore to cache the failure) */ const BROKEN = "BROKEN"; type BROKEN = "BROKEN"; type AnyPosition = HbsPosition | CharPosition | InvisiblePosition; /** * A `SourceOffset` represents a single position in the source. * * There are three kinds of backing data for `SourceOffset` objects: * * - `CharPosition`, which contains a character offset into the raw source string * - `HbsPosition`, which contains a `SourcePosition` from the Handlebars AST, which can be * converted to a `CharPosition` on demand. * - `InvisiblePosition`, which represents a position not in source (@see {InvisiblePosition}) */ class SourceOffset { readonly data: PositionData & AnyPosition; /** * Create a `SourceOffset` from a Handlebars `SourcePosition`. It's stored as-is, and converted * into a character offset on demand, which avoids unnecessarily computing the offset of every * `SourceLocation`, but also means that broken `SourcePosition`s are not always detected. */ static forHbsPos(source: Source, pos: SourcePosition): SourceOffset; /** * Create a `SourceOffset` that corresponds to a broken `SourcePosition`. This means that the * calling code determined (or knows) that the `SourceLocation` doesn't correspond correctly to * any part of the source. */ static broken(pos?: SourcePosition): SourceOffset; constructor(data: PositionData & AnyPosition); /** * Get the character offset for this `SourceOffset`, if possible. */ get offset(): number | null; /** * Compare this offset with another one. * * If both offsets are `HbsPosition`s, they're equivalent as long as their lines and columns are * the same. This avoids computing offsets unnecessarily. * * Otherwise, two `SourceOffset`s are equivalent if their successfully computed character offsets * are the same. */ eql(right: SourceOffset): boolean; /** * Create a span that starts from this source offset and ends with another source offset. Avoid * computing character offsets if both `SourceOffset`s are still lazy. */ until(other: SourceOffset): SourceSpan; /** * Create a `SourceOffset` by moving the character position represented by this source offset * forward or backward (if `by` is negative), if possible. * * If this `SourceOffset` can't compute a valid character offset, `move` returns a broken offset. * * If the resulting character offset is less than 0 or greater than the size of the source, `move` * returns a broken offset. */ move(by: number): SourceOffset; /** * Create a new `SourceSpan` that represents a collapsed range at this source offset. Avoid * computing the character offset if it has not already been computed. */ collapsed(): SourceSpan; /** * Convert this `SourceOffset` into a Handlebars {@see SourcePosition} for compatibility with * existing plugins. */ toJSON(): SourcePosition; } class CharPosition implements PositionData { readonly source: Source; readonly charPos: number; readonly kind = OffsetKind.CharPosition; /** Computed from char offset */ _locPos: HbsPosition | BROKEN | null; constructor(source: Source, charPos: number); /** * This is already a `CharPosition`. * * {@see HbsPosition} for the alternative. */ toCharPos(): CharPosition; /** * Produce a Handlebars {@see SourcePosition} for this `CharPosition`. If this `CharPosition` was * computed using {@see SourceOffset#move}, this will compute the `SourcePosition` for the offset. */ toJSON(): SourcePosition; wrap(): SourceOffset; /** * A `CharPosition` always has an offset it can produce without any additional computation. */ get offset(): number; /** * Convert the current character offset to an `HbsPosition`, if it was not already computed. Once * a `CharPosition` has computed its `HbsPosition`, it will not need to do compute it again, and * the same `CharPosition` is retained when used as one of the ends of a `SourceSpan`, so * computing the `HbsPosition` should be a one-time operation. */ toHbsPos(): HbsPosition | null; } class HbsPosition implements PositionData { readonly source: Source; readonly hbsPos: SourcePosition; readonly kind = OffsetKind.HbsPosition; _charPos: CharPosition | BROKEN | null; constructor(source: Source, hbsPos: SourcePosition, charPos?: number | null); /** * Lazily compute the character offset from the {@see SourcePosition}. Once an `HbsPosition` has * computed its `CharPosition`, it will not need to do compute it again, and the same * `HbsPosition` is retained when used as one of the ends of a `SourceSpan`, so computing the * `CharPosition` should be a one-time operation. */ toCharPos(): CharPosition | null; /** * Return the {@see SourcePosition} that this `HbsPosition` was instantiated with. This operation * does not need to compute anything. */ toJSON(): SourcePosition; wrap(): SourceOffset; /** * This is already an `HbsPosition`. * * {@see CharPosition} for the alternative. */ toHbsPos(): HbsPosition; } class InvisiblePosition implements PositionData { readonly kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent; // whatever was provided, possibly broken readonly pos: SourcePosition; constructor(kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent, pos: SourcePosition); /** * A broken position cannot be turned into a {@see CharacterPosition}. */ toCharPos(): null; /** * The serialization of an `InvisiblePosition is whatever Handlebars {@see SourcePosition} was * originally identified as broken, non-existent or synthetic. * * If an `InvisiblePosition` never had an source offset at all, this method returns * {@see UNKNOWN_POSITION} for compatibility. */ toJSON(): SourcePosition; wrap(): SourceOffset; get offset(): null; } type HasSpan = SourceSpan | LocatedWithSpan | PresentArray; type MaybeHasSpan = SourceSpan | LocatedWithOptionalSpan | LocatedWithOptionalSpan[] | null; type ToSourceOffset = number | SourceOffset; class SpanList { static range(span: PresentArray): SourceSpan; static range(span: HasSourceSpan[], fallback: SourceSpan): SourceSpan; _span: SourceSpan[]; constructor(span?: SourceSpan[]); add(offset: SourceSpan): void; getRangeOffset(fallback: SourceSpan): SourceSpan; } type HasSourceSpan = { loc: SourceSpan; } | SourceSpan | [ HasSourceSpan, ...HasSourceSpan[] ]; function loc(span: HasSourceSpan): SourceSpan; type MaybeHasSourceSpan = { loc: SourceSpan; } | SourceSpan | MaybeHasSourceSpan[]; function hasSpan(span: MaybeHasSourceSpan): span is HasSourceSpan; function maybeLoc(location: MaybeHasSourceSpan, fallback: SourceSpan): SourceSpan; interface BaseNode { // Every leaf interface that extends BaseNode must specify a type property. // The type property should be a string literal. For example, Identifier // has: `type: "Identifier"` type: NodeType; loc: src.SourceSpan; } interface CommonProgram extends BaseNode { body: Statement[]; } interface Block extends CommonProgram { type: "Block"; params: VarHead[]; chained?: boolean; /** * string accessor for params.name */ blockParams: string[]; } type EntityEncodingState = "transformed" | "raw"; interface Template extends CommonProgram { type: "Template"; blockParams: string[]; } /** * @deprecated use Template or Block instead */ type Program = Template | Block; type CallableExpression = SubExpression | PathExpression; interface CallParts { path: CallableExpression; params: Expression[]; hash: Hash; loc: src.SourceSpan; } type CallNode = MustacheStatement | BlockStatement | ElementModifierStatement | SubExpression; interface MustacheStatement extends BaseNode { type: "MustacheStatement"; path: Expression; params: Expression[]; hash: Hash; trusting: boolean; strip: StripFlags; /** * @deprecated use trusting instead */ escaped: boolean; } interface BlockStatement extends BaseNode { type: "BlockStatement"; path: CallableExpression; params: Expression[]; hash: Hash; program: Block; inverse?: Nullable; openStrip: StripFlags; inverseStrip: StripFlags; closeStrip: StripFlags; // Printer extension chained?: boolean; } interface ElementModifierStatement extends BaseNode { type: "ElementModifierStatement"; path: CallableExpression; params: Expression[]; hash: Hash; } interface CommentStatement extends BaseNode { type: "CommentStatement"; value: string; } interface MustacheCommentStatement extends BaseNode { type: "MustacheCommentStatement"; value: string; } interface ElementNode extends BaseNode { type: "ElementNode"; path: PathExpression; selfClosing: boolean; attributes: AttrNode[]; params: VarHead[]; modifiers: ElementModifierStatement[]; comments: MustacheCommentStatement[]; children: Statement[]; /** * span for the open tag */ openTag: src.SourceSpan; /** * span for the close tag, null for void or self-closing tags */ closeTag: Nullable; /** * string accessor for path.original */ tag: string; /** * string accessor for params.name */ blockParams: string[]; } type StatementName = "MustacheStatement" | "CommentStatement" | "BlockStatement" | "MustacheCommentStatement" | "TextNode" | "ElementNode"; interface AttrNode extends BaseNode { type: "AttrNode"; name: string; value: AttrValue; } type AttrValue = TextNode | MustacheStatement | ConcatStatement; type AttrPart = TextNode | MustacheStatement; interface TextNode extends BaseNode { type: "TextNode"; chars: string; } interface ConcatStatement extends BaseNode { type: "ConcatStatement"; parts: PresentArray; } type ExpressionName = "SubExpression" | "PathExpression" | LiteralName; interface SubExpression extends BaseNode { type: "SubExpression"; path: CallableExpression; params: Expression[]; hash: Hash; } interface ThisHead { type: "ThisHead"; original: "this"; loc: src.SourceSpan; } interface AtHead { type: "AtHead"; name: string; loc: src.SourceSpan; /** * alias for name */ original: string; } interface VarHead { type: "VarHead"; name: string; loc: src.SourceSpan; /** * alias for name */ original: string; } type PathHead = ThisHead | AtHead | VarHead; interface MinimalPathExpression extends BaseNode { type: "PathExpression"; head: PathHead; tail: string[]; } interface PathExpression extends MinimalPathExpression { type: "PathExpression"; original: string; head: PathHead; tail: string[]; /** * @deprecated use `head` and `tail` instead */ parts: readonly string[]; /** * @deprecated use `head.type` instead */ readonly this: boolean; /** * @deprecated use `head.type' instead */ readonly data: boolean; } type LiteralName = "StringLiteral" | "BooleanLiteral" | "NumberLiteral" | "UndefinedLiteral" | "NullLiteral"; interface StringLiteral extends BaseNode { type: "StringLiteral"; value: string; /** * @deprecated use value instead */ original: string; } interface BooleanLiteral extends BaseNode { type: "BooleanLiteral"; value: boolean; /** * @deprecated use value instead */ original: boolean; } interface NumberLiteral extends BaseNode { type: "NumberLiteral"; value: number; /** * @deprecated use value instead */ original: number; } interface UndefinedLiteral extends BaseNode { type: "UndefinedLiteral"; value: undefined; /** * @deprecated use value instead */ original: undefined; } interface NullLiteral extends BaseNode { type: "NullLiteral"; value: null; /** * @deprecated use value instead */ original: null; } interface Hash extends BaseNode { type: "Hash"; pairs: HashPair[]; } interface HashPair extends BaseNode { type: "HashPair"; key: string; value: Expression; } interface StripFlags { open: boolean; close: boolean; } type Nodes = { Template: Template; Block: Block; MustacheStatement: MustacheStatement; BlockStatement: BlockStatement; ElementModifierStatement: ElementModifierStatement; CommentStatement: CommentStatement; MustacheCommentStatement: MustacheCommentStatement; ElementNode: ElementNode; AttrNode: AttrNode; TextNode: TextNode; ConcatStatement: ConcatStatement; SubExpression: SubExpression; PathExpression: PathExpression; StringLiteral: StringLiteral; BooleanLiteral: BooleanLiteral; NumberLiteral: NumberLiteral; NullLiteral: NullLiteral; UndefinedLiteral: UndefinedLiteral; Hash: Hash; HashPair: HashPair; }; type NodeType = keyof Nodes; type Node = Nodes[NodeType]; // These "sub-node" cannot appear standalone, they are only used inside another // "real" AST node to provide richer information. The distinction mostly exists // for backwards compatibility reason. These nodes are not traversed and do not // have visitor keys for them, so it won't break existing AST consumers (e.g. // those that implemented an `All` visitor may not be expecting these new types // of nodes). // // Conceptually, the idea of "sub-node" does make sense, and you can say source // locations are another kind of these things. However, in these cases, they // actually fully implement the `BaseNode` interface, and only not extending // `BaseNode` because the `type` field is not `keyof Nodes` (which is circular // reasoning). If these are not "real" nodes because they can only appear in // very limited context, then the same reasoning probably applies for, say, // HashPair. // // If we do eventually make some kind of breaking change here, perhaps with // some kind of opt-in, then we can consider upgrading these into "real" nodes, // but for now, this is where they go, and it isn't a huge problem in practice // because there are little utility in traversing these kind of nodes anyway. type SubNodes = { ThisHead: ThisHead; AtHead: AtHead; VarHead: VarHead; }; type SubNodeType = keyof SubNodes; type SubNode = SubNodes[SubNodeType]; type Statement = Nodes[StatementName]; type Statements = Pick; type Literal = Nodes[LiteralName]; type Expression = Nodes[ExpressionName]; type Expressions = Pick; type TopLevelStatement = Statement | Nodes["Block"]; type ParentNode = Template | Block | ElementNode; } declare function getVoidTags(): string[]; interface PrinterOptions { entityEncoding: ASTv1.EntityEncodingState; /** * Used to override the mechanism of printing a given AST.Node. * * This will generally only be useful to source -> source codemods * where you would like to specialize/override the way a given node is * printed (e.g. you would like to preserve as much of the original * formatting as possible). * * When the provided override returns undefined, the default built in printing * will be done for the AST.Node. * * @param ast the ast node to be printed * @param options the options specified during the print() invocation */ override?(ast: ASTv1.Node, options: PrinterOptions): void | string; } /** * Examples when true: * - link * - liNK * * Examples when false: * - Link (component) */ declare function isVoidTag(tag: string): boolean; declare function build(ast: ASTv1.Node, options?: PrinterOptions): string; declare function sortByLoc(a: ASTv1.Node, b: ASTv1.Node): -1 | 0 | 1; interface GetTemplateLocalsOptions { includeKeywords?: boolean; includeHtmlElements?: boolean; } /** * Parses and traverses a given handlebars html template to extract all template locals * referenced that could possible come from the parent scope. Can exclude known keywords * optionally. */ declare function getTemplateLocals(html: string, options?: GetTemplateLocalsOptions): string[]; type Keywords = keyof typeof KEYWORDS_TYPES; type KeywordType = "Call" | "Modifier" | "Append" | "Block"; declare function isKeyword(word: string): word is Keywords; declare function isKeyword(word: string, type: KeywordType): boolean; /** * This includes the full list of keywords currently in use in the template * language, and where their valid usages are. */ declare const KEYWORDS_TYPES: { action: ("Call" | "Modifier")[]; component: ("Block" | "Call" | "Append")[]; debugger: "Append"[]; "each-in": "Block"[]; each: "Block"[]; "has-block-params": ("Call" | "Append")[]; "has-block": ("Call" | "Append")[]; helper: ("Call" | "Append")[]; if: ("Block" | "Call" | "Append")[]; "in-element": "Block"[]; let: "Block"[]; log: ("Call" | "Append")[]; modifier: ("Call" | "Modifier")[]; mount: "Append"[]; mut: ("Call" | "Append")[]; outlet: "Append"[]; readonly: ("Call" | "Append")[]; unbound: ("Call" | "Append")[]; unless: ("Block" | "Call" | "Append")[]; yield: "Append"[]; }; type ParserNodeBuilder = Omit & { start: src.SourceOffset; }; interface StartTag { readonly type: "StartTag"; name: string; nameStart: Nullable; nameEnd: Nullable; readonly attributes: ASTv1.AttrNode[]; readonly modifiers: ASTv1.ElementModifierStatement[]; readonly comments: ASTv1.MustacheCommentStatement[]; readonly params: ASTv1.VarHead[]; selfClosing: boolean; readonly loc: src.SourceSpan; } interface EndTag { readonly type: "EndTag"; name: string; readonly loc: src.SourceSpan; } interface Attribute { name: string; currentPart: ASTv1.TextNode | null; parts: (ASTv1.MustacheStatement | ASTv1.TextNode)[]; isQuoted: boolean; isDynamic: boolean; start: src.SourceOffset; valueSpan: src.SourceSpan; } declare abstract class Parser { protected elementStack: ASTv1.ParentNode[]; private lines; readonly source: src.Source; currentAttribute: Nullable; currentNode: Nullable | ParserNodeBuilder | ParserNodeBuilder | ParserNodeBuilder>>; tokenizer: EventedTokenizer; constructor(source: src.Source, entityParser?: EntityParser, mode?: "precompile" | "codemod"); offset(): src.SourceOffset; pos({ line, column }: src.SourcePosition): src.SourceOffset; finish(node: ParserNodeBuilder): T; abstract parse(node: HBS.Program, locals: string[]): ASTv1.Template; abstract Program(node: HBS.Program): HBS.Output<"Program">; abstract MustacheStatement(node: HBS.MustacheStatement): HBS.Output<"MustacheStatement">; abstract Decorator(node: HBS.Decorator): HBS.Output<"Decorator">; abstract BlockStatement(node: HBS.BlockStatement): HBS.Output<"BlockStatement">; abstract DecoratorBlock(node: HBS.DecoratorBlock): HBS.Output<"DecoratorBlock">; abstract PartialStatement(node: HBS.PartialStatement): HBS.Output<"PartialStatement">; abstract PartialBlockStatement(node: HBS.PartialBlockStatement): HBS.Output<"PartialBlockStatement">; abstract ContentStatement(node: HBS.ContentStatement): HBS.Output<"ContentStatement">; abstract CommentStatement(node: HBS.CommentStatement): HBS.Output<"CommentStatement">; abstract SubExpression(node: HBS.SubExpression): HBS.Output<"SubExpression">; abstract PathExpression(node: HBS.PathExpression): HBS.Output<"PathExpression">; abstract StringLiteral(node: HBS.StringLiteral): HBS.Output<"StringLiteral">; abstract BooleanLiteral(node: HBS.BooleanLiteral): HBS.Output<"BooleanLiteral">; abstract NumberLiteral(node: HBS.NumberLiteral): HBS.Output<"NumberLiteral">; abstract UndefinedLiteral(node: HBS.UndefinedLiteral): HBS.Output<"UndefinedLiteral">; abstract NullLiteral(node: HBS.NullLiteral): HBS.Output<"NullLiteral">; abstract reset(): void; abstract finishData(): void; abstract tagOpen(): void; abstract beginData(): void; abstract appendToData(char: string): void; abstract beginStartTag(): void; abstract appendToTagName(char: string): void; abstract beginAttribute(): void; abstract appendToAttributeName(char: string): void; abstract beginAttributeValue(quoted: boolean): void; abstract appendToAttributeValue(char: string): void; abstract finishAttributeValue(): void; abstract markTagAsSelfClosing(): void; abstract beginEndTag(): void; abstract finishTag(): void; abstract beginComment(): void; abstract appendToCommentData(char: string): void; abstract finishComment(): void; abstract reportSyntaxError(error: string): void; get currentAttr(): Attribute; get currentTag(): ParserNodeBuilder | ParserNodeBuilder; get currentStartTag(): ParserNodeBuilder; get currentEndTag(): ParserNodeBuilder; get currentComment(): ParserNodeBuilder; get currentData(): ParserNodeBuilder; acceptNode(node: HBS.Node): HBS.Output; currentElement(): ASTv1.ParentNode; sourceForNode(node: HBS.Node, endNode?: { loc: HBS.SourceLocation; }): string; } // ensure stays in sync with typing // ParentNode and ChildKey types are derived from VisitorKeysMap declare const visitorKeys: { readonly Template: readonly [ "body" ]; readonly Block: readonly [ "body" ]; readonly MustacheStatement: readonly [ "path", "params", "hash" ]; readonly BlockStatement: readonly [ "path", "params", "hash", "program", "inverse" ]; readonly ElementModifierStatement: readonly [ "path", "params", "hash" ]; readonly CommentStatement: readonly [ ]; readonly MustacheCommentStatement: readonly [ ]; readonly ElementNode: readonly [ "attributes", "modifiers", "children", "comments" ]; readonly AttrNode: readonly [ "value" ]; readonly TextNode: readonly [ ]; readonly ConcatStatement: readonly [ "parts" ]; readonly SubExpression: readonly [ "path", "params", "hash" ]; readonly PathExpression: readonly [ ]; readonly StringLiteral: readonly [ ]; readonly BooleanLiteral: readonly [ ]; readonly NumberLiteral: readonly [ ]; readonly NullLiteral: readonly [ ]; readonly UndefinedLiteral: readonly [ ]; readonly Hash: readonly [ "pairs" ]; readonly HashPair: readonly [ "value" ]; }; type VisitorKeysMap = typeof visitorKeys; type VisitorKeys = { [P in keyof VisitorKeysMap]: VisitorKeysMap[P][number]; }; type VisitorKey = VisitorKeys[N["type"]] & keyof N; declare class WalkerPath { node: N; parent: WalkerPath | null; parentKey: string | null; constructor(node: N, parent?: WalkerPath | null, parentKey?: string | null); get parentNode(): ASTv1.Node | null; parents(): Iterable | null>; } interface FullNodeTraversal { enter?(node: N, path: WalkerPath): void; exit?(node: N, path: WalkerPath): void; keys?: KeysVisitor; } type NodeHandler = (node: N, path: WalkerPath) => void; type NodeTraversal = FullNodeTraversal | NodeHandler; type NodeVisitor = { [P in keyof ASTv1.Nodes]?: NodeTraversal; } & { All?: NodeTraversal; /** * @deprecated use Template or Block instead */ Program?: NodeTraversal; }; interface FullKeyTraversal { enter?(node: N, key: K): void; exit?(node: N, key: K): void; } type KeyHandler> = (node: N, key: K) => void; type KeyTraversal> = FullKeyTraversal | KeyHandler; type KeysVisitor = { [P in VisitorKey]?: KeyTraversal; } & { All?: KeyTraversal>; /** * @deprecated use Template or Block instead */ Program?: KeyTraversal; }; declare const print: typeof build; declare function traverse(node: ASTv1.Node, visitor: NodeVisitor): void; type NodeCallback = (node: N, walker: Walker) => void; declare class Walker { order?: unknown; stack: unknown[]; constructor(order?: unknown); visit(node: Nullable, visitor: NodeCallback): void; children(node: N & ASTv1.Node, callback: NodeCallback): void; } declare class Source { readonly source: string; readonly module: string; static from(source: string, options?: PrecompileOptions): Source; constructor(source: string, module?: string); /** * Validate that the character offset represents a position in the source string. */ check(offset: number): boolean; slice(start: number, end: number): string; offsetFor(line: number, column: number): SourceOffset; spanFor({ start, end }: Readonly): SourceSpan; hbsPosFor(offset: number): Nullable; charPosFor(position: SourcePosition): number | null; } declare enum OffsetKind { /** * We have already computed the character position of this offset or span. */ CharPosition = "CharPosition", /** * This offset or span was instantiated with a Handlebars SourcePosition or SourceLocation. Its * character position will be computed on demand. */ HbsPosition = "HbsPosition", /** * for (rare) situations where a node is created but there was no source location (e.g. the name * "default" in default blocks when the word "default" never appeared in source). This is used * by the internals when there is a legitimate reason for the internals to synthesize a node * with no location. */ InternalsSynthetic = "InternalsSynthetic", /** * For situations where a node represents zero parts of the source (for example, empty arguments). * In general, we attempt to assign these nodes *some* position (empty arguments can be * positioned immediately after the callee), but it's not always possible */ NonExistent = "NonExistent", /** * For situations where a source location was expected, but it didn't correspond to the node in * the source. This happens if a plugin creates broken locations. */ Broken = "Broken" } /** * This file implements the DSL used by span and offset in places where they need to exhaustively * consider all combinations of states (Handlebars offsets, character offsets and invisible/broken * offsets). * * It's probably overkill, but it makes the code that uses it clear. It could be refactored or * removed. */ declare const MatchAny = "MATCH_ANY"; type MatchAny = "MATCH_ANY"; type Matches = "Char,Hbs" | "Hbs,Char" | "Hbs,Hbs" | "Char,Char" | "Invisible,Any" | "Any,Invisible"; declare const IsInvisible = "IS_INVISIBLE"; type IsInvisible = "IS_INVISIBLE"; type Pattern = OffsetKind | IsInvisible | MatchAny; declare class When { _map: Map; get(pattern: Pattern, or: () => Out): Out; add(pattern: Pattern, out: Out): void; match(kind: OffsetKind): Out[]; } type ExhaustiveCheck = Exclude extends never ? ExhaustiveMatcher : Matcher>; type MatchFn = (left: PositionData, right: PositionData) => Out; interface ExhaustiveMatcher { check(): MatchFn; } declare class Matcher { _whens: When Out>>; /** * You didn't exhaustively match all possibilities. */ protected check(): MatchFn; private matchFor; // This big block is the bulk of the heavy lifting in this file. It facilitates exhaustiveness // checking so that matchers can ensure they've actually covered all the cases (and TypeScript // will treat it as an exhaustive match). when(left: OffsetKind.CharPosition, right: OffsetKind.HbsPosition, callback: (left: CharPosition, right: HbsPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.HbsPosition, right: OffsetKind.CharPosition, callback: (left: HbsPosition, right: CharPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.HbsPosition, right: OffsetKind.HbsPosition, callback: (left: HbsPosition, right: HbsPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.CharPosition, right: OffsetKind.CharPosition, callback: (left: CharPosition, right: CharPosition) => Out): ExhaustiveCheck; when(left: IsInvisible, right: MatchAny, callback: (left: InvisiblePosition, right: PositionData) => Out): Matcher>; when(left: MatchAny, right: IsInvisible, callback: (left: PositionData, right: InvisiblePosition) => Out): ExhaustiveCheck; when(left: MatchAny, right: MatchAny, callback: (left: PositionData, right: PositionData) => Out): ExhaustiveMatcher; } type SerializedSourceSlice = [ chars: Chars, span: src.SerializedSourceSpan ]; declare class SourceSlice { static synthetic(chars: S): SourceSlice; static load(source: src.Source, slice: SerializedSourceSlice): SourceSlice; readonly chars: Chars; readonly loc: src.SourceSpan; constructor(options: { loc: src.SourceSpan; chars: Chars; }); getString(): string; serialize(): SerializedSourceSlice; } /** * All spans have these details in common. */ interface SpanData { readonly kind: OffsetKind; /** * Convert this span into a string. If the span is broken, return `''`. */ asString(): string; /** * Gets the module the span was located in. */ getModule(): string; /** * Get the starting position for this span. Try to avoid creating new position objects, as they * cache computations. */ getStart(): AnyPosition; /** * Get the ending position for this span. Try to avoid creating new position objects, as they * cache computations. */ getEnd(): AnyPosition; /** * Compute the `SourceLocation` for this span, returned as an instance of `HbsSpan`. */ toHbsSpan(): HbsSpan | null; /** * For compatibility, whenever the `start` or `end` of a {@see SourceOffset} changes, spans are * notified of the change so they can update themselves. This shouldn't happen outside of AST * plugins. */ locDidUpdate(changes: { start?: SourcePosition; end?: SourcePosition; }): void; /** * Serialize into a {@see SerializedSourceSpan}, which is compact and designed for readability in * context like AST Explorer. If you need a {@see SourceLocation}, use {@see toJSON}. */ serialize(): SerializedSourceSpan; } /** * A `SourceSpan` object represents a span of characters inside of a template source. * * There are three kinds of `SourceSpan` objects: * * - `ConcreteSourceSpan`, which contains byte offsets * - `LazySourceSpan`, which contains `SourceLocation`s from the Handlebars AST, which can be * converted to byte offsets on demand. * - `InvisibleSourceSpan`, which represent source strings that aren't present in the source, * because: * - they were created synthetically * - their location is nonsensical (the span is broken) * - they represent nothing in the source (this currently happens only when a bug in the * upstream Handlebars parser fails to assign a location to empty blocks) * * At a high level, all `SourceSpan` objects provide: * * - byte offsets * - source in column and line format * * And you can do these operations on `SourceSpan`s: * * - collapse it to a `SourceSpan` representing its starting or ending position * - slice out some characters, optionally skipping some characters at the beginning or end * - create a new `SourceSpan` with a different starting or ending offset * * All SourceSpan objects implement `SourceLocation`, for compatibility. All SourceSpan * objects have a `toJSON` that emits `SourceLocation`, also for compatibility. * * For compatibility, subclasses of `AbstractSourceSpan` must implement `locDidUpdate`, which * happens when an AST plugin attempts to modify the `start` or `end` of a span directly. * * The goal is to avoid creating any problems for use-cases like AST Explorer. */ declare class SourceSpan implements SourceLocation { private data; static get NON_EXISTENT(): SourceSpan; static load(source: Source, serialized: SerializedSourceSpan): SourceSpan; static forHbsLoc(source: Source, loc: SourceLocation): SourceSpan; static forCharPositions(source: Source, startPos: number, endPos: number): SourceSpan; static synthetic(chars: string): SourceSpan; static broken(pos?: SourceLocation): SourceSpan; readonly isInvisible: boolean; constructor(data: SpanData & AnySpan); getStart(): SourceOffset; getEnd(): SourceOffset; get loc(): SourceLocation; get module(): string; /** * Get the starting `SourcePosition` for this `SourceSpan`, lazily computing it if needed. */ get startPosition(): SourcePosition; /** * Get the ending `SourcePosition` for this `SourceSpan`, lazily computing it if needed. */ get endPosition(): SourcePosition; /** * Support converting ASTv1 nodes into a serialized format using JSON.stringify. */ toJSON(): SourceLocation; /** * Create a new span with the current span's end and a new beginning. */ withStart(other: SourceOffset): SourceSpan; /** * Create a new span with the current span's beginning and a new ending. */ withEnd(other: SourceOffset): SourceSpan; asString(): string; /** * Convert this `SourceSpan` into a `SourceSlice`. In debug mode, this method optionally checks * that the byte offsets represented by this `SourceSpan` actually correspond to the expected * string. */ toSlice(expected?: string): SourceSlice; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use startPosition instead */ get start(): SourcePosition; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use withStart instead */ set start(position: SourcePosition); /** * For compatibility with SourceLocation in AST plugins * * @deprecated use endPosition instead */ get end(): SourcePosition; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use withEnd instead */ set end(position: SourcePosition); /** * For compatibility with SourceLocation in AST plugins * * @deprecated use module instead */ get source(): string; collapse(where: "start" | "end"): SourceSpan; extend(other: SourceSpan): SourceSpan; serialize(): SerializedSourceSpan; slice({ skipStart, skipEnd }: { skipStart?: number; skipEnd?: number; }): SourceSpan; sliceStartChars({ skipStart, chars }: { skipStart?: number; chars: number; }): SourceSpan; sliceEndChars({ skipEnd, chars }: { skipEnd?: number; chars: number; }): SourceSpan; } type AnySpan = HbsSpan | CharPositionSpan | InvisibleSpan; declare class CharPositionSpan implements SpanData { readonly source: Source; readonly charPositions: { start: CharPosition; end: CharPosition; }; readonly kind = OffsetKind.CharPosition; _locPosSpan: HbsSpan | BROKEN | null; constructor(source: Source, charPositions: { start: CharPosition; end: CharPosition; }); wrap(): SourceSpan; asString(): string; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; locDidUpdate(): void; toHbsSpan(): HbsSpan | null; serialize(): SerializedSourceSpan; toCharPosSpan(): CharPositionSpan; } declare class HbsSpan implements SpanData { readonly source: Source; readonly hbsPositions: { start: HbsPosition; end: HbsPosition; }; readonly kind = OffsetKind.HbsPosition; _charPosSpan: CharPositionSpan | BROKEN | null; // the source location from Handlebars + AST Plugins -- could be wrong _providedHbsLoc: SourceLocation | null; constructor(source: Source, hbsPositions: { start: HbsPosition; end: HbsPosition; }, providedHbsLoc?: SourceLocation | null); serialize(): SerializedConcreteSourceSpan; wrap(): SourceSpan; private updateProvided; locDidUpdate({ start, end }: { start?: SourcePosition; end?: SourcePosition; }): void; asString(): string; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; toHbsLoc(): SourceLocation; toHbsSpan(): HbsSpan; toCharPosSpan(): CharPositionSpan | null; } declare class InvisibleSpan implements SpanData { readonly kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent; // whatever was provided, possibly broken readonly loc: SourceLocation; // if the span represents a synthetic string readonly string: string | null; constructor(kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent, loc: SourceLocation, string?: string | null); serialize(): SerializedConcreteSourceSpan; wrap(): SourceSpan; asString(): string; locDidUpdate({ start, end }: { start?: SourcePosition; end?: SourcePosition; }): void; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; toCharPosSpan(): InvisibleSpan; toHbsSpan(): null; toHbsLoc(): SourceLocation; } declare const span: MatchFn; type SerializedConcreteSourceSpan = /** collapsed */ number | /** normal */ [ start: number, size: number ] | /** synthetic */ string; type SerializedSourceSpan = SerializedConcreteSourceSpan | OffsetKind.NonExistent | OffsetKind.Broken; /** * All positions have these details in common. Most notably, all three kinds of positions can * must be able to attempt to convert themselves into {@see CharPosition}. */ interface PositionData { readonly kind: OffsetKind; toCharPos(): CharPosition | null; toJSON(): SourcePosition; } /** * Used to indicate that an attempt to convert a `SourcePosition` to a character offset failed. It * is separate from `null` so that `null` can be used to indicate that the computation wasn't yet * attempted (and therefore to cache the failure) */ declare const BROKEN = "BROKEN"; type BROKEN = "BROKEN"; type AnyPosition = HbsPosition | CharPosition | InvisiblePosition; /** * A `SourceOffset` represents a single position in the source. * * There are three kinds of backing data for `SourceOffset` objects: * * - `CharPosition`, which contains a character offset into the raw source string * - `HbsPosition`, which contains a `SourcePosition` from the Handlebars AST, which can be * converted to a `CharPosition` on demand. * - `InvisiblePosition`, which represents a position not in source (@see {InvisiblePosition}) */ declare class SourceOffset { readonly data: PositionData & AnyPosition; /** * Create a `SourceOffset` from a Handlebars `SourcePosition`. It's stored as-is, and converted * into a character offset on demand, which avoids unnecessarily computing the offset of every * `SourceLocation`, but also means that broken `SourcePosition`s are not always detected. */ static forHbsPos(source: Source, pos: SourcePosition): SourceOffset; /** * Create a `SourceOffset` that corresponds to a broken `SourcePosition`. This means that the * calling code determined (or knows) that the `SourceLocation` doesn't correspond correctly to * any part of the source. */ static broken(pos?: SourcePosition): SourceOffset; constructor(data: PositionData & AnyPosition); /** * Get the character offset for this `SourceOffset`, if possible. */ get offset(): number | null; /** * Compare this offset with another one. * * If both offsets are `HbsPosition`s, they're equivalent as long as their lines and columns are * the same. This avoids computing offsets unnecessarily. * * Otherwise, two `SourceOffset`s are equivalent if their successfully computed character offsets * are the same. */ eql(right: SourceOffset): boolean; /** * Create a span that starts from this source offset and ends with another source offset. Avoid * computing character offsets if both `SourceOffset`s are still lazy. */ until(other: SourceOffset): SourceSpan; /** * Create a `SourceOffset` by moving the character position represented by this source offset * forward or backward (if `by` is negative), if possible. * * If this `SourceOffset` can't compute a valid character offset, `move` returns a broken offset. * * If the resulting character offset is less than 0 or greater than the size of the source, `move` * returns a broken offset. */ move(by: number): SourceOffset; /** * Create a new `SourceSpan` that represents a collapsed range at this source offset. Avoid * computing the character offset if it has not already been computed. */ collapsed(): SourceSpan; /** * Convert this `SourceOffset` into a Handlebars {@see SourcePosition} for compatibility with * existing plugins. */ toJSON(): SourcePosition; } declare class CharPosition implements PositionData { readonly source: Source; readonly charPos: number; readonly kind = OffsetKind.CharPosition; /** Computed from char offset */ _locPos: HbsPosition | BROKEN | null; constructor(source: Source, charPos: number); /** * This is already a `CharPosition`. * * {@see HbsPosition} for the alternative. */ toCharPos(): CharPosition; /** * Produce a Handlebars {@see SourcePosition} for this `CharPosition`. If this `CharPosition` was * computed using {@see SourceOffset#move}, this will compute the `SourcePosition` for the offset. */ toJSON(): SourcePosition; wrap(): SourceOffset; /** * A `CharPosition` always has an offset it can produce without any additional computation. */ get offset(): number; /** * Convert the current character offset to an `HbsPosition`, if it was not already computed. Once * a `CharPosition` has computed its `HbsPosition`, it will not need to do compute it again, and * the same `CharPosition` is retained when used as one of the ends of a `SourceSpan`, so * computing the `HbsPosition` should be a one-time operation. */ toHbsPos(): HbsPosition | null; } declare class HbsPosition implements PositionData { readonly source: Source; readonly hbsPos: SourcePosition; readonly kind = OffsetKind.HbsPosition; _charPos: CharPosition | BROKEN | null; constructor(source: Source, hbsPos: SourcePosition, charPos?: number | null); /** * Lazily compute the character offset from the {@see SourcePosition}. Once an `HbsPosition` has * computed its `CharPosition`, it will not need to do compute it again, and the same * `HbsPosition` is retained when used as one of the ends of a `SourceSpan`, so computing the * `CharPosition` should be a one-time operation. */ toCharPos(): CharPosition | null; /** * Return the {@see SourcePosition} that this `HbsPosition` was instantiated with. This operation * does not need to compute anything. */ toJSON(): SourcePosition; wrap(): SourceOffset; /** * This is already an `HbsPosition`. * * {@see CharPosition} for the alternative. */ toHbsPos(): HbsPosition; } declare class InvisiblePosition implements PositionData { readonly kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent; // whatever was provided, possibly broken readonly pos: SourcePosition; constructor(kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent, pos: SourcePosition); /** * A broken position cannot be turned into a {@see CharacterPosition}. */ toCharPos(): null; /** * The serialization of an `InvisiblePosition is whatever Handlebars {@see SourcePosition} was * originally identified as broken, non-existent or synthetic. * * If an `InvisiblePosition` never had an source offset at all, this method returns * {@see UNKNOWN_POSITION} for compatibility. */ toJSON(): SourcePosition; wrap(): SourceOffset; get offset(): null; } interface SourceLocation { start: SourcePosition; end: SourcePosition; } interface SourcePosition { /** >= 1 */ line: number; /** >= 0 */ column: number; } type LocatedWithSpan = { offsets: SourceSpan; }; type LocatedWithOptionalSpan = { offsets: SourceSpan | null; }; type LocatedWithPositions = { loc: SourceLocation; }; type LocatedWithOptionalPositions = { loc?: SourceLocation; }; // const SOURCE = new Source('', '(tests)'); // Statements type BuilderHead = string | ASTv1.CallableExpression; type TagDescriptor = string | ASTv1.PathExpression | { path: ASTv1.PathExpression; selfClosing?: boolean; } | { name: string; selfClosing?: boolean; }; declare function buildMustache(path: BuilderHead | ASTv1.Literal, params?: ASTv1.Expression[], hash?: ASTv1.Hash, trusting?: boolean, loc?: SourceLocation, strip?: ASTv1.StripFlags): ASTv1.MustacheStatement; type PossiblyDeprecatedBlock = ASTv1.Block | ASTv1.Template; declare function buildBlock(path: BuilderHead, params: Nullable, hash: Nullable, _defaultBlock: PossiblyDeprecatedBlock, _elseBlock?: Nullable, loc?: SourceLocation, openStrip?: ASTv1.StripFlags, inverseStrip?: ASTv1.StripFlags, closeStrip?: ASTv1.StripFlags): ASTv1.BlockStatement; declare function buildElementModifier(path: BuilderHead, params?: ASTv1.Expression[], hash?: ASTv1.Hash, loc?: Nullable): ASTv1.ElementModifierStatement; declare function buildComment(value: string, loc?: SourceLocation): ASTv1.CommentStatement; declare function buildMustacheComment(value: string, loc?: SourceLocation): ASTv1.MustacheCommentStatement; declare function buildConcat(parts: (ASTv1.TextNode | ASTv1.MustacheStatement)[], loc?: SourceLocation): ASTv1.ConcatStatement; type PathSexp = string | [ "path", string, LocSexp? ]; type ModifierSexp = string | [ PathSexp, LocSexp? ] | [ PathSexp, ASTv1.Expression[], LocSexp? ] | [ PathSexp, ASTv1.Expression[], Dict, LocSexp? ]; type AttrSexp = [ string, ASTv1.AttrNode["value"] | string, LocSexp? ]; type LocSexp = [ "loc", SourceLocation ]; type ElementComment = ASTv1.MustacheCommentStatement | SourceLocation | string; interface BuildElementOptions { attrs?: ASTv1.AttrNode[]; modifiers?: ASTv1.ElementModifierStatement[]; children?: ASTv1.Statement[]; comments?: ASTv1.MustacheCommentStatement[]; blockParams?: ASTv1.VarHead[] | string[]; openTag?: SourceLocation; closeTag?: Nullable; loc?: SourceLocation; } declare function buildElement(tag: TagDescriptor, options?: BuildElementOptions): ASTv1.ElementNode; declare function buildAttr(name: string, value: ASTv1.AttrValue, loc?: SourceLocation): ASTv1.AttrNode; declare function buildText(chars?: string, loc?: SourceLocation): ASTv1.TextNode; // Expressions declare function buildSexpr(path: BuilderHead, params?: ASTv1.Expression[], hash?: ASTv1.Hash, loc?: SourceLocation): ASTv1.SubExpression; declare function buildThis(loc?: SourceLocation): ASTv1.ThisHead; declare function buildAtName(name: string, loc?: SourceLocation): ASTv1.AtHead; declare function buildVar(name: string, loc?: SourceLocation): ASTv1.VarHead; declare function buildHeadFromString(original: string, loc?: SourceLocation): ASTv1.PathHead; declare function buildCleanPath(head: ASTv1.PathHead, tail?: string[], loc?: SourceLocation): ASTv1.PathExpression; declare function buildPath(path: ASTv1.PathExpression | string | { head: string; tail: string[]; }, loc?: SourceLocation): ASTv1.PathExpression; declare function buildPath(path: BuilderHead, loc?: SourceLocation): ASTv1.CallableExpression; declare function buildPath(path: BuilderHead | ASTv1.Literal, loc?: SourceLocation): ASTv1.Expression; declare function buildPath(path: ASTv1.Expression, loc?: SourceLocation): ASTv1.Expression; declare function buildLiteral(type: T["type"], value: T["value"], loc?: SourceLocation): T; // Miscellaneous declare function buildHash(pairs?: ASTv1.HashPair[], loc?: SourceLocation): ASTv1.Hash; declare function buildPair(key: string, value: ASTv1.Expression, loc?: SourceLocation): ASTv1.HashPair; declare function buildProgram(body?: ASTv1.Statement[], blockParams?: string[], loc?: SourceLocation): ASTv1.Template | ASTv1.Block; declare function buildBlockItself(body?: ASTv1.Statement[], params?: Array, chained?: boolean, loc?: SourceLocation): ASTv1.Block; declare function buildTemplate(body?: ASTv1.Statement[], blockParams?: string[], loc?: SourceLocation): ASTv1.Template; declare function buildPosition(line: number, column: number): SourcePosition; declare function buildLoc(loc: Nullable): SourceSpan; declare function buildLoc(startLine: number, startColumn: number, endLine?: number, endColumn?: number, source?: string): SourceSpan; declare const _default: { mustache: typeof buildMustache; block: typeof buildBlock; comment: typeof buildComment; mustacheComment: typeof buildMustacheComment; element: typeof buildElement; elementModifier: typeof buildElementModifier; attr: typeof buildAttr; text: typeof buildText; sexpr: typeof buildSexpr; concat: typeof buildConcat; hash: typeof buildHash; pair: typeof buildPair; literal: typeof buildLiteral; program: typeof buildProgram; blockItself: typeof buildBlockItself; template: typeof buildTemplate; loc: typeof buildLoc; pos: typeof buildPosition; path: typeof buildPath; fullPath: typeof buildCleanPath; head: typeof buildHeadFromString; at: typeof buildAtName; var: typeof buildVar; this: typeof buildThis; string: (value: string) => ASTv1.StringLiteral; boolean: (value: boolean) => ASTv1.BooleanLiteral; number: (value: number) => ASTv1.NumberLiteral; undefined(): ASTv1.UndefinedLiteral; null(): ASTv1.NullLiteral; }; declare const publicBuilder: typeof _default; interface PendingError { mustache(span: SourceSpan): never; eof(offset: SourceOffset): never; } declare abstract class HandlebarsNodeVisitors extends Parser { // Because we interleave the HTML and HBS parsing, sometimes the HTML // tokenizer can run out of tokens when we switch into {{...}} or reached // EOF. There are positions where neither of these are expected, and it would // like to generate an error, but there is no span to attach the error to. // This allows the HTML tokenization to stash an error message and the next // mustache visitor will attach the message to the appropriate span and throw // the error. protected pendingError: Nullable; abstract appendToCommentData(s: string): void; abstract beginAttributeValue(quoted: boolean): void; abstract finishAttributeValue(): void; parse(program: HBS.Program, blockParams: string[]): ASTv1.Template; Program(program: HBS.Program, blockParams?: ASTv1.VarHead[]): ASTv1.Block; private parseProgram; BlockStatement(block: HBS.BlockStatement): ASTv1.BlockStatement | void; MustacheStatement(rawMustache: HBS.MustacheStatement): ASTv1.MustacheStatement | void; appendDynamicAttributeValuePart(part: ASTv1.MustacheStatement): void; finalizeTextPart(): void; startTextPart(): void; ContentStatement(content: HBS.ContentStatement): void; CommentStatement(rawComment: HBS.CommentStatement): Nullable; PartialStatement(partial: HBS.PartialStatement): never; PartialBlockStatement(partialBlock: HBS.PartialBlockStatement): never; Decorator(decorator: HBS.Decorator): never; DecoratorBlock(decoratorBlock: HBS.DecoratorBlock): never; SubExpression(sexpr: HBS.SubExpression): ASTv1.SubExpression; PathExpression(path: HBS.PathExpression): ASTv1.PathExpression; Hash(hash: HBS.Hash): ASTv1.Hash; StringLiteral(string: HBS.StringLiteral): ASTv1.StringLiteral; BooleanLiteral(boolean: HBS.BooleanLiteral): ASTv1.BooleanLiteral; NumberLiteral(number: HBS.NumberLiteral): ASTv1.NumberLiteral; UndefinedLiteral(undef: HBS.UndefinedLiteral): ASTv1.UndefinedLiteral; NullLiteral(nul: HBS.NullLiteral): ASTv1.NullLiteral; } /** ASTPlugins can make changes to the Glimmer template AST before compilation begins. */ interface ASTPluginBuilder { (env: TEnv): ASTPlugin; } interface ASTPlugin { name: string; visitor: NodeVisitor; } interface ASTPluginEnvironment { meta?: object; syntax: Syntax; } interface HandlebarsParseOptions { srcName?: string; ignoreStandalone?: boolean; } interface TemplateIdFn { (src: string): Nullable; } interface PrecompileOptions extends PreprocessOptions { id?: TemplateIdFn; /** * Additional non-native keywords. * * Local variables (block params or lexical scope) always takes precedence, * but otherwise, suitable free variable candidates (e.g. those are not part * of a path) are matched against this list and turned into keywords. * * In strict mode compilation, keywords suppresses the undefined reference * error and will be resolved by the runtime environment. * * In loose mode, keywords are currently ignored and since all free variables * are already resolved by the runtime environment. */ keywords?: readonly string[]; customizeComponentName?: ((input: string) => string) | undefined; } interface PrecompileOptionsWithLexicalScope extends PrecompileOptions { lexicalScope: (variable: string) => boolean; } interface PreprocessOptions { strictMode?: boolean; locals?: string[]; meta?: { moduleName?: string; }; plugins?: { ast?: ASTPluginBuilder[]; }; parseOptions?: HandlebarsParseOptions; customizeComponentName?: ((input: string) => string) | undefined; /** Useful for specifying a group of options together. When `'codemod'` we disable all whitespace control in handlebars (to preserve as much as possible) and we also avoid any escaping/unescaping of HTML entity codes. */ mode?: "codemod" | "precompile"; } interface Syntax { parse: typeof preprocess; builders: typeof publicBuilder; print: typeof print; traverse: typeof traverse; Walker: typeof Walker; } declare function preprocess(input: string | src.Source | HBS.Program, options?: PreprocessOptions): ASTv1.Template; declare class SpanList { static range(span: PresentArray): SourceSpan; static range(span: HasSourceSpan[], fallback: SourceSpan): SourceSpan; _span: SourceSpan[]; constructor(span?: SourceSpan[]); add(offset: SourceSpan): void; getRangeOffset(fallback: SourceSpan): SourceSpan; } type HasSourceSpan = { loc: SourceSpan; } | SourceSpan | [ HasSourceSpan, ...HasSourceSpan[] ]; declare function loc(span: HasSourceSpan): SourceSpan; type MaybeHasSourceSpan = { loc: SourceSpan; } | SourceSpan | MaybeHasSourceSpan[]; declare function hasSpan(span: MaybeHasSourceSpan): span is HasSourceSpan; declare function maybeLoc(location: MaybeHasSourceSpan, fallback: SourceSpan): SourceSpan; declare namespace ASTv2 { type SerializedSourceSlice = [ chars: Chars, span: src.SerializedSourceSpan ]; class SourceSlice { static synthetic(chars: S): SourceSlice; static load(source: src.Source, slice: SerializedSourceSlice): SourceSlice; readonly chars: Chars; readonly loc: src.SourceSpan; constructor(options: { loc: src.SourceSpan; chars: Chars; }); getString(): string; serialize(): SerializedSourceSlice; } interface SourceLocation { start: SourcePosition; end: SourcePosition; } interface SourcePosition { /** >= 1 */ line: number; /** >= 0 */ column: number; } const UNKNOWN_POSITION: Readonly<{ readonly line: 1; readonly column: 0; }>; const SYNTHETIC_LOCATION: Readonly<{ readonly source: "(synthetic)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; /** @deprecated */ const SYNTHETIC: Readonly<{ readonly source: "(synthetic)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; const TEMPORARY_LOCATION: Readonly<{ readonly source: "(temporary)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; const NON_EXISTENT_LOCATION: Readonly<{ readonly source: "(nonexistent)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; const BROKEN_LOCATION: Readonly<{ readonly source: "(broken)"; readonly start: Readonly<{ readonly line: 1; readonly column: 0; }>; readonly end: Readonly<{ readonly line: 1; readonly column: 0; }>; }>; type LocatedWithSpan = { offsets: SourceSpan; }; type LocatedWithOptionalSpan = { offsets: SourceSpan | null; }; type LocatedWithPositions = { loc: SourceLocation; }; type LocatedWithOptionalPositions = { loc?: SourceLocation; }; function isLocatedWithPositionsArray(location: LocatedWithOptionalPositions[]): location is PresentArray; function isLocatedWithPositions(location: LocatedWithOptionalPositions): location is LocatedWithPositions; type HasSourceLocation = SourceLocation | LocatedWithPositions | PresentArray; type MaybeHasSourceLocation = null | LocatedWithOptionalPositions | LocatedWithOptionalPositions[]; type ParserNodeBuilder = Omit & { start: src.SourceOffset; }; interface StartTag { readonly type: "StartTag"; name: string; nameStart: Nullable; nameEnd: Nullable; readonly attributes: ASTv1.AttrNode[]; readonly modifiers: ASTv1.ElementModifierStatement[]; readonly comments: ASTv1.MustacheCommentStatement[]; readonly params: ASTv1.VarHead[]; selfClosing: boolean; readonly loc: src.SourceSpan; } interface EndTag { readonly type: "EndTag"; name: string; readonly loc: src.SourceSpan; } interface Attribute { name: string; currentPart: ASTv1.TextNode | null; parts: (ASTv1.MustacheStatement | ASTv1.TextNode)[]; isQuoted: boolean; isDynamic: boolean; start: src.SourceOffset; valueSpan: src.SourceSpan; } abstract class Parser { protected elementStack: ASTv1.ParentNode[]; private lines; readonly source: src.Source; currentAttribute: Nullable; currentNode: Nullable | ParserNodeBuilder | ParserNodeBuilder | ParserNodeBuilder>>; tokenizer: EventedTokenizer; constructor(source: src.Source, entityParser?: EntityParser, mode?: "precompile" | "codemod"); offset(): src.SourceOffset; pos({ line, column }: src.SourcePosition): src.SourceOffset; finish(node: ParserNodeBuilder): T; abstract parse(node: HBS.Program, locals: string[]): ASTv1.Template; abstract Program(node: HBS.Program): HBS.Output<"Program">; abstract MustacheStatement(node: HBS.MustacheStatement): HBS.Output<"MustacheStatement">; abstract Decorator(node: HBS.Decorator): HBS.Output<"Decorator">; abstract BlockStatement(node: HBS.BlockStatement): HBS.Output<"BlockStatement">; abstract DecoratorBlock(node: HBS.DecoratorBlock): HBS.Output<"DecoratorBlock">; abstract PartialStatement(node: HBS.PartialStatement): HBS.Output<"PartialStatement">; abstract PartialBlockStatement(node: HBS.PartialBlockStatement): HBS.Output<"PartialBlockStatement">; abstract ContentStatement(node: HBS.ContentStatement): HBS.Output<"ContentStatement">; abstract CommentStatement(node: HBS.CommentStatement): HBS.Output<"CommentStatement">; abstract SubExpression(node: HBS.SubExpression): HBS.Output<"SubExpression">; abstract PathExpression(node: HBS.PathExpression): HBS.Output<"PathExpression">; abstract StringLiteral(node: HBS.StringLiteral): HBS.Output<"StringLiteral">; abstract BooleanLiteral(node: HBS.BooleanLiteral): HBS.Output<"BooleanLiteral">; abstract NumberLiteral(node: HBS.NumberLiteral): HBS.Output<"NumberLiteral">; abstract UndefinedLiteral(node: HBS.UndefinedLiteral): HBS.Output<"UndefinedLiteral">; abstract NullLiteral(node: HBS.NullLiteral): HBS.Output<"NullLiteral">; abstract reset(): void; abstract finishData(): void; abstract tagOpen(): void; abstract beginData(): void; abstract appendToData(char: string): void; abstract beginStartTag(): void; abstract appendToTagName(char: string): void; abstract beginAttribute(): void; abstract appendToAttributeName(char: string): void; abstract beginAttributeValue(quoted: boolean): void; abstract appendToAttributeValue(char: string): void; abstract finishAttributeValue(): void; abstract markTagAsSelfClosing(): void; abstract beginEndTag(): void; abstract finishTag(): void; abstract beginComment(): void; abstract appendToCommentData(char: string): void; abstract finishComment(): void; abstract reportSyntaxError(error: string): void; get currentAttr(): Attribute; get currentTag(): ParserNodeBuilder | ParserNodeBuilder; get currentStartTag(): ParserNodeBuilder; get currentEndTag(): ParserNodeBuilder; get currentComment(): ParserNodeBuilder; get currentData(): ParserNodeBuilder; acceptNode(node: HBS.Node): HBS.Output; currentElement(): ASTv1.ParentNode; sourceForNode(node: HBS.Node, endNode?: { loc: HBS.SourceLocation; }): string; } // ensure stays in sync with typing // ParentNode and ChildKey types are derived from VisitorKeysMap const visitorKeys: { readonly Template: readonly [ "body" ]; readonly Block: readonly [ "body" ]; readonly MustacheStatement: readonly [ "path", "params", "hash" ]; readonly BlockStatement: readonly [ "path", "params", "hash", "program", "inverse" ]; readonly ElementModifierStatement: readonly [ "path", "params", "hash" ]; readonly CommentStatement: readonly [ ]; readonly MustacheCommentStatement: readonly [ ]; readonly ElementNode: readonly [ "attributes", "modifiers", "children", "comments" ]; readonly AttrNode: readonly [ "value" ]; readonly TextNode: readonly [ ]; readonly ConcatStatement: readonly [ "parts" ]; readonly SubExpression: readonly [ "path", "params", "hash" ]; readonly PathExpression: readonly [ ]; readonly StringLiteral: readonly [ ]; readonly BooleanLiteral: readonly [ ]; readonly NumberLiteral: readonly [ ]; readonly NullLiteral: readonly [ ]; readonly UndefinedLiteral: readonly [ ]; readonly Hash: readonly [ "pairs" ]; readonly HashPair: readonly [ "value" ]; }; type VisitorKeysMap = typeof visitorKeys; type VisitorKeys = { [P in keyof VisitorKeysMap]: VisitorKeysMap[P][number]; }; type VisitorKey = VisitorKeys[N["type"]] & keyof N; class WalkerPath { node: N; parent: WalkerPath | null; parentKey: string | null; constructor(node: N, parent?: WalkerPath | null, parentKey?: string | null); get parentNode(): ASTv1.Node | null; parents(): Iterable | null>; } interface FullNodeTraversal { enter?(node: N, path: WalkerPath): void; exit?(node: N, path: WalkerPath): void; keys?: KeysVisitor; } type NodeHandler = (node: N, path: WalkerPath) => void; type NodeTraversal = FullNodeTraversal | NodeHandler; type NodeVisitor = { [P in keyof ASTv1.Nodes]?: NodeTraversal; } & { All?: NodeTraversal; /** * @deprecated use Template or Block instead */ Program?: NodeTraversal; }; interface FullKeyTraversal { enter?(node: N, key: K): void; exit?(node: N, key: K): void; } type KeyHandler> = (node: N, key: K) => void; type KeyTraversal> = FullKeyTraversal | KeyHandler; type KeysVisitor = { [P in VisitorKey]?: KeyTraversal; } & { All?: KeyTraversal>; /** * @deprecated use Template or Block instead */ Program?: KeyTraversal; }; const voidMap: Set; function getVoidTags(): string[]; interface PrinterOptions { entityEncoding: ASTv1.EntityEncodingState; /** * Used to override the mechanism of printing a given AST.Node. * * This will generally only be useful to source -> source codemods * where you would like to specialize/override the way a given node is * printed (e.g. you would like to preserve as much of the original * formatting as possible). * * When the provided override returns undefined, the default built in printing * will be done for the AST.Node. * * @param ast the ast node to be printed * @param options the options specified during the print() invocation */ override?(ast: ASTv1.Node, options: PrinterOptions): void | string; } /** * Examples when true: * - link * - liNK * * Examples when false: * - Link (component) */ function isVoidTag(tag: string): boolean; class Printer { private buffer; private options; constructor(options: PrinterOptions); /* This is used by _all_ methods on this Printer class that add to `this.buffer`, it allows consumers of the printer to use alternate string representations for a given node. The primary use case for this are things like source -> source codemod utilities. For example, ember-template-recast attempts to always preserve the original string formatting in each AST node if no modifications are made to it. */ handledByOverride(node: ASTv1.Node, ensureLeadingWhitespace?: boolean): boolean; Node(node: ASTv1.Node): void; Expression(expression: ASTv1.Expression): void; Literal(literal: ASTv1.Literal): void; TopLevelStatement(statement: ASTv1.TopLevelStatement | ASTv1.Template | ASTv1.AttrNode): void; Template(template: ASTv1.Template): void; Block(block: ASTv1.Block): void; TopLevelStatements(statements: ASTv1.TopLevelStatement[]): void; ElementNode(el: ASTv1.ElementNode): void; OpenElementNode(el: ASTv1.ElementNode): void; CloseElementNode(el: ASTv1.ElementNode): void; AttrNode(attr: ASTv1.AttrNode): void; AttrNodeValue(value: ASTv1.AttrNode["value"]): void; TextNode(text: ASTv1.TextNode, isAttr?: boolean): void; MustacheStatement(mustache: ASTv1.MustacheStatement): void; BlockStatement(block: ASTv1.BlockStatement): void; BlockParams(blockParams: string[]): void; ConcatStatement(concat: ASTv1.ConcatStatement): void; MustacheCommentStatement(comment: ASTv1.MustacheCommentStatement): void; ElementModifierStatement(mod: ASTv1.ElementModifierStatement): void; CommentStatement(comment: ASTv1.CommentStatement): void; PathExpression(path: ASTv1.PathExpression): void; SubExpression(sexp: ASTv1.SubExpression): void; Params(params: ASTv1.Expression[]): void; Hash(hash: ASTv1.Hash): void; HashPair(pair: ASTv1.HashPair): void; StringLiteral(str: ASTv1.StringLiteral): void; BooleanLiteral(bool: ASTv1.BooleanLiteral): void; NumberLiteral(number: ASTv1.NumberLiteral): void; UndefinedLiteral(node: ASTv1.UndefinedLiteral): void; NullLiteral(node: ASTv1.NullLiteral): void; print(node: ASTv1.Node): string; } function build(ast: ASTv1.Node, options?: PrinterOptions): string; const print: typeof build; function traverse(node: ASTv1.Node, visitor: NodeVisitor): void; type NodeCallback = (node: N, walker: Walker) => void; class Walker { order?: unknown; stack: unknown[]; constructor(order?: unknown); visit(node: Nullable, visitor: NodeCallback): void; children(node: N & ASTv1.Node, callback: NodeCallback): void; } // const SOURCE = new Source('', '(tests)'); // Statements type BuilderHead = string | ASTv1.CallableExpression; type TagDescriptor = string | ASTv1.PathExpression | { path: ASTv1.PathExpression; selfClosing?: boolean; } | { name: string; selfClosing?: boolean; }; function buildMustache(path: BuilderHead | ASTv1.Literal, params?: ASTv1.Expression[], hash?: ASTv1.Hash, trusting?: boolean, loc?: SourceLocation, strip?: ASTv1.StripFlags): ASTv1.MustacheStatement; type PossiblyDeprecatedBlock = ASTv1.Block | ASTv1.Template; function buildBlock(path: BuilderHead, params: Nullable, hash: Nullable, _defaultBlock: PossiblyDeprecatedBlock, _elseBlock?: Nullable, loc?: SourceLocation, openStrip?: ASTv1.StripFlags, inverseStrip?: ASTv1.StripFlags, closeStrip?: ASTv1.StripFlags): ASTv1.BlockStatement; function buildElementModifier(path: BuilderHead, params?: ASTv1.Expression[], hash?: ASTv1.Hash, loc?: Nullable): ASTv1.ElementModifierStatement; function buildComment(value: string, loc?: SourceLocation): ASTv1.CommentStatement; function buildMustacheComment(value: string, loc?: SourceLocation): ASTv1.MustacheCommentStatement; function buildConcat(parts: (ASTv1.TextNode | ASTv1.MustacheStatement)[], loc?: SourceLocation): ASTv1.ConcatStatement; // Nodes type ElementParts = [ "attrs", ...AttrSexp[] ] | [ "modifiers", ...ModifierSexp[] ] | [ "body", ...ASTv1.Statement[] ] | [ "comments", ...ElementComment[] ] | [ "as", ...string[] ] | [ "loc", SourceLocation ]; type PathSexp = string | [ "path", string, LocSexp? ]; type ModifierSexp = string | [ PathSexp, LocSexp? ] | [ PathSexp, ASTv1.Expression[], LocSexp? ] | [ PathSexp, ASTv1.Expression[], Dict, LocSexp? ]; type AttrSexp = [ string, ASTv1.AttrNode["value"] | string, LocSexp? ]; type LocSexp = [ "loc", SourceLocation ]; type ElementComment = ASTv1.MustacheCommentStatement | SourceLocation | string; type SexpValue = string | ASTv1.Expression[] | Dict | LocSexp | PathSexp | undefined; interface BuildElementOptions { attrs?: ASTv1.AttrNode[]; modifiers?: ASTv1.ElementModifierStatement[]; children?: ASTv1.Statement[]; comments?: ASTv1.MustacheCommentStatement[]; blockParams?: ASTv1.VarHead[] | string[]; openTag?: SourceLocation; closeTag?: Nullable; loc?: SourceLocation; } function buildElement(tag: TagDescriptor, options?: BuildElementOptions): ASTv1.ElementNode; function buildAttr(name: string, value: ASTv1.AttrValue, loc?: SourceLocation): ASTv1.AttrNode; function buildText(chars?: string, loc?: SourceLocation): ASTv1.TextNode; // Expressions function buildSexpr(path: BuilderHead, params?: ASTv1.Expression[], hash?: ASTv1.Hash, loc?: SourceLocation): ASTv1.SubExpression; function buildThis(loc?: SourceLocation): ASTv1.ThisHead; function buildAtName(name: string, loc?: SourceLocation): ASTv1.AtHead; function buildVar(name: string, loc?: SourceLocation): ASTv1.VarHead; function buildHeadFromString(original: string, loc?: SourceLocation): ASTv1.PathHead; function buildCleanPath(head: ASTv1.PathHead, tail?: string[], loc?: SourceLocation): ASTv1.PathExpression; function buildPath(path: ASTv1.PathExpression | string | { head: string; tail: string[]; }, loc?: SourceLocation): ASTv1.PathExpression; function buildPath(path: BuilderHead, loc?: SourceLocation): ASTv1.CallableExpression; function buildPath(path: BuilderHead | ASTv1.Literal, loc?: SourceLocation): ASTv1.Expression; function buildPath(path: ASTv1.Expression, loc?: SourceLocation): ASTv1.Expression; function buildLiteral(type: T["type"], value: T["value"], loc?: SourceLocation): T; // Miscellaneous function buildHash(pairs?: ASTv1.HashPair[], loc?: SourceLocation): ASTv1.Hash; function buildPair(key: string, value: ASTv1.Expression, loc?: SourceLocation): ASTv1.HashPair; function buildProgram(body?: ASTv1.Statement[], blockParams?: string[], loc?: SourceLocation): ASTv1.Template | ASTv1.Block; function buildBlockItself(body?: ASTv1.Statement[], params?: Array, chained?: boolean, loc?: SourceLocation): ASTv1.Block; function buildTemplate(body?: ASTv1.Statement[], blockParams?: string[], loc?: SourceLocation): ASTv1.Template; function buildPosition(line: number, column: number): SourcePosition; function buildLoc(loc: Nullable): SourceSpan; function buildLoc(startLine: number, startColumn: number, endLine?: number, endColumn?: number, source?: string): SourceSpan; const _default: { mustache: typeof buildMustache; block: typeof buildBlock; comment: typeof buildComment; mustacheComment: typeof buildMustacheComment; element: typeof buildElement; elementModifier: typeof buildElementModifier; attr: typeof buildAttr; text: typeof buildText; sexpr: typeof buildSexpr; concat: typeof buildConcat; hash: typeof buildHash; pair: typeof buildPair; literal: typeof buildLiteral; program: typeof buildProgram; blockItself: typeof buildBlockItself; template: typeof buildTemplate; loc: typeof buildLoc; pos: typeof buildPosition; path: typeof buildPath; fullPath: typeof buildCleanPath; head: typeof buildHeadFromString; at: typeof buildAtName; var: typeof buildVar; this: typeof buildThis; string: (value: string) => ASTv1.StringLiteral; boolean: (value: boolean) => ASTv1.BooleanLiteral; number: (value: number) => ASTv1.NumberLiteral; undefined(): ASTv1.UndefinedLiteral; null(): ASTv1.NullLiteral; }; const publicBuilder: typeof _default; interface PendingError { mustache(span: SourceSpan): never; eof(offset: SourceOffset): never; } abstract class HandlebarsNodeVisitors extends Parser { // Because we interleave the HTML and HBS parsing, sometimes the HTML // tokenizer can run out of tokens when we switch into {{...}} or reached // EOF. There are positions where neither of these are expected, and it would // like to generate an error, but there is no span to attach the error to. // This allows the HTML tokenization to stash an error message and the next // mustache visitor will attach the message to the appropriate span and throw // the error. protected pendingError: Nullable; abstract appendToCommentData(s: string): void; abstract beginAttributeValue(quoted: boolean): void; abstract finishAttributeValue(): void; parse(program: HBS.Program, blockParams: string[]): ASTv1.Template; Program(program: HBS.Program, blockParams?: ASTv1.VarHead[]): ASTv1.Block; private parseProgram; BlockStatement(block: HBS.BlockStatement): ASTv1.BlockStatement | void; MustacheStatement(rawMustache: HBS.MustacheStatement): ASTv1.MustacheStatement | void; appendDynamicAttributeValuePart(part: ASTv1.MustacheStatement): void; finalizeTextPart(): void; startTextPart(): void; ContentStatement(content: HBS.ContentStatement): void; CommentStatement(rawComment: HBS.CommentStatement): Nullable; PartialStatement(partial: HBS.PartialStatement): never; PartialBlockStatement(partialBlock: HBS.PartialBlockStatement): never; Decorator(decorator: HBS.Decorator): never; DecoratorBlock(decoratorBlock: HBS.DecoratorBlock): never; SubExpression(sexpr: HBS.SubExpression): ASTv1.SubExpression; PathExpression(path: HBS.PathExpression): ASTv1.PathExpression; Hash(hash: HBS.Hash): ASTv1.Hash; StringLiteral(string: HBS.StringLiteral): ASTv1.StringLiteral; BooleanLiteral(boolean: HBS.BooleanLiteral): ASTv1.BooleanLiteral; NumberLiteral(number: HBS.NumberLiteral): ASTv1.NumberLiteral; UndefinedLiteral(undef: HBS.UndefinedLiteral): ASTv1.UndefinedLiteral; NullLiteral(nul: HBS.NullLiteral): ASTv1.NullLiteral; } class TokenizerEventHandlers extends HandlebarsNodeVisitors { private tagOpenLine; private tagOpenColumn; reset(): void; // Comment beginComment(): void; appendToCommentData(char: string): void; finishComment(): void; // Data beginData(): void; appendToData(char: string): void; finishData(): void; // Tags - basic tagOpen(): void; beginStartTag(): void; beginEndTag(): void; finishTag(): void; finishStartTag(): void; finishEndTag(isVoid: boolean): void; markTagAsSelfClosing(): void; // Tags - name appendToTagName(char: string): void; // Tags - attributes beginAttribute(): void; appendToAttributeName(char: string): void; beginAttributeValue(isQuoted: boolean): void; appendToAttributeValue(char: string): void; finishAttributeValue(): void; private parsePossibleBlockParams; reportSyntaxError(message: string): void; assembleConcatenatedValue(parts: (ASTv1.MustacheStatement | ASTv1.TextNode)[]): ASTv1.ConcatStatement; validateEndTag(tag: StartTag | EndTag, element: ASTv1.ElementNode, selfClosing: boolean): void; assembleAttributeValue(parts: ASTv1.AttrPart[], isQuoted: boolean, isDynamic: boolean, span: src.SourceSpan): ASTv1.AttrValue; } /** ASTPlugins can make changes to the Glimmer template AST before compilation begins. */ interface ASTPluginBuilder { (env: TEnv): ASTPlugin; } interface ASTPlugin { name: string; visitor: NodeVisitor; } interface ASTPluginEnvironment { meta?: object; syntax: Syntax; } interface HandlebarsParseOptions { srcName?: string; ignoreStandalone?: boolean; } interface TemplateIdFn { (src: string): Nullable; } interface PrecompileOptions extends PreprocessOptions { id?: TemplateIdFn; /** * Additional non-native keywords. * * Local variables (block params or lexical scope) always takes precedence, * but otherwise, suitable free variable candidates (e.g. those are not part * of a path) are matched against this list and turned into keywords. * * In strict mode compilation, keywords suppresses the undefined reference * error and will be resolved by the runtime environment. * * In loose mode, keywords are currently ignored and since all free variables * are already resolved by the runtime environment. */ keywords?: readonly string[]; customizeComponentName?: ((input: string) => string) | undefined; } interface PrecompileOptionsWithLexicalScope extends PrecompileOptions { lexicalScope: (variable: string) => boolean; } interface PreprocessOptions { strictMode?: boolean; locals?: string[]; meta?: { moduleName?: string; }; plugins?: { ast?: ASTPluginBuilder[]; }; parseOptions?: HandlebarsParseOptions; customizeComponentName?: ((input: string) => string) | undefined; /** Useful for specifying a group of options together. When `'codemod'` we disable all whitespace control in handlebars (to preserve as much as possible) and we also avoid any escaping/unescaping of HTML entity codes. */ mode?: "codemod" | "precompile"; } interface Syntax { parse: typeof preprocess; builders: typeof publicBuilder; print: typeof print; traverse: typeof traverse; Walker: typeof Walker; } function preprocess(input: string | src.Source | HBS.Program, options?: PreprocessOptions): ASTv1.Template; class Source { readonly source: string; readonly module: string; static from(source: string, options?: PrecompileOptions): Source; constructor(source: string, module?: string); /** * Validate that the character offset represents a position in the source string. */ check(offset: number): boolean; slice(start: number, end: number): string; offsetFor(line: number, column: number): SourceOffset; spanFor({ start, end }: Readonly): SourceSpan; hbsPosFor(offset: number): Nullable; charPosFor(position: SourcePosition): number | null; } enum OffsetKind { /** * We have already computed the character position of this offset or span. */ CharPosition = "CharPosition", /** * This offset or span was instantiated with a Handlebars SourcePosition or SourceLocation. Its * character position will be computed on demand. */ HbsPosition = "HbsPosition", /** * for (rare) situations where a node is created but there was no source location (e.g. the name * "default" in default blocks when the word "default" never appeared in source). This is used * by the internals when there is a legitimate reason for the internals to synthesize a node * with no location. */ InternalsSynthetic = "InternalsSynthetic", /** * For situations where a node represents zero parts of the source (for example, empty arguments). * In general, we attempt to assign these nodes *some* position (empty arguments can be * positioned immediately after the callee), but it's not always possible */ NonExistent = "NonExistent", /** * For situations where a source location was expected, but it didn't correspond to the node in * the source. This happens if a plugin creates broken locations. */ Broken = "Broken" } /** * This file implements the DSL used by span and offset in places where they need to exhaustively * consider all combinations of states (Handlebars offsets, character offsets and invisible/broken * offsets). * * It's probably overkill, but it makes the code that uses it clear. It could be refactored or * removed. */ const MatchAny = "MATCH_ANY"; type MatchAny = "MATCH_ANY"; type Matches = "Char,Hbs" | "Hbs,Char" | "Hbs,Hbs" | "Char,Char" | "Invisible,Any" | "Any,Invisible"; const IsInvisible = "IS_INVISIBLE"; type IsInvisible = "IS_INVISIBLE"; type Pattern = OffsetKind | IsInvisible | MatchAny; class When { _map: Map; get(pattern: Pattern, or: () => Out): Out; add(pattern: Pattern, out: Out): void; match(kind: OffsetKind): Out[]; } type ExhaustiveCheck = Exclude extends never ? ExhaustiveMatcher : Matcher>; type MatchFn = (left: PositionData, right: PositionData) => Out; interface ExhaustiveMatcher { check(): MatchFn; } function match(callback: (m: Matcher) => ExhaustiveMatcher): MatchFn; class Matcher { _whens: When Out>>; /** * You didn't exhaustively match all possibilities. */ protected check(): MatchFn; private matchFor; // This big block is the bulk of the heavy lifting in this file. It facilitates exhaustiveness // checking so that matchers can ensure they've actually covered all the cases (and TypeScript // will treat it as an exhaustive match). when(left: OffsetKind.CharPosition, right: OffsetKind.HbsPosition, callback: (left: CharPosition, right: HbsPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.HbsPosition, right: OffsetKind.CharPosition, callback: (left: HbsPosition, right: CharPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.HbsPosition, right: OffsetKind.HbsPosition, callback: (left: HbsPosition, right: HbsPosition) => Out): ExhaustiveCheck; when(left: OffsetKind.CharPosition, right: OffsetKind.CharPosition, callback: (left: CharPosition, right: CharPosition) => Out): ExhaustiveCheck; when(left: IsInvisible, right: MatchAny, callback: (left: InvisiblePosition, right: PositionData) => Out): Matcher>; when(left: MatchAny, right: IsInvisible, callback: (left: PositionData, right: InvisiblePosition) => Out): ExhaustiveCheck; when(left: MatchAny, right: MatchAny, callback: (left: PositionData, right: PositionData) => Out): ExhaustiveMatcher; } /** * All spans have these details in common. */ interface SpanData { readonly kind: OffsetKind; /** * Convert this span into a string. If the span is broken, return `''`. */ asString(): string; /** * Gets the module the span was located in. */ getModule(): string; /** * Get the starting position for this span. Try to avoid creating new position objects, as they * cache computations. */ getStart(): AnyPosition; /** * Get the ending position for this span. Try to avoid creating new position objects, as they * cache computations. */ getEnd(): AnyPosition; /** * Compute the `SourceLocation` for this span, returned as an instance of `HbsSpan`. */ toHbsSpan(): HbsSpan | null; /** * For compatibility, whenever the `start` or `end` of a {@see SourceOffset} changes, spans are * notified of the change so they can update themselves. This shouldn't happen outside of AST * plugins. */ locDidUpdate(changes: { start?: SourcePosition; end?: SourcePosition; }): void; /** * Serialize into a {@see SerializedSourceSpan}, which is compact and designed for readability in * context like AST Explorer. If you need a {@see SourceLocation}, use {@see toJSON}. */ serialize(): SerializedSourceSpan; } /** * A `SourceSpan` object represents a span of characters inside of a template source. * * There are three kinds of `SourceSpan` objects: * * - `ConcreteSourceSpan`, which contains byte offsets * - `LazySourceSpan`, which contains `SourceLocation`s from the Handlebars AST, which can be * converted to byte offsets on demand. * - `InvisibleSourceSpan`, which represent source strings that aren't present in the source, * because: * - they were created synthetically * - their location is nonsensical (the span is broken) * - they represent nothing in the source (this currently happens only when a bug in the * upstream Handlebars parser fails to assign a location to empty blocks) * * At a high level, all `SourceSpan` objects provide: * * - byte offsets * - source in column and line format * * And you can do these operations on `SourceSpan`s: * * - collapse it to a `SourceSpan` representing its starting or ending position * - slice out some characters, optionally skipping some characters at the beginning or end * - create a new `SourceSpan` with a different starting or ending offset * * All SourceSpan objects implement `SourceLocation`, for compatibility. All SourceSpan * objects have a `toJSON` that emits `SourceLocation`, also for compatibility. * * For compatibility, subclasses of `AbstractSourceSpan` must implement `locDidUpdate`, which * happens when an AST plugin attempts to modify the `start` or `end` of a span directly. * * The goal is to avoid creating any problems for use-cases like AST Explorer. */ class SourceSpan implements SourceLocation { private data; static get NON_EXISTENT(): SourceSpan; static load(source: Source, serialized: SerializedSourceSpan): SourceSpan; static forHbsLoc(source: Source, loc: SourceLocation): SourceSpan; static forCharPositions(source: Source, startPos: number, endPos: number): SourceSpan; static synthetic(chars: string): SourceSpan; static broken(pos?: SourceLocation): SourceSpan; readonly isInvisible: boolean; constructor(data: SpanData & AnySpan); getStart(): SourceOffset; getEnd(): SourceOffset; get loc(): SourceLocation; get module(): string; /** * Get the starting `SourcePosition` for this `SourceSpan`, lazily computing it if needed. */ get startPosition(): SourcePosition; /** * Get the ending `SourcePosition` for this `SourceSpan`, lazily computing it if needed. */ get endPosition(): SourcePosition; /** * Support converting ASTv1 nodes into a serialized format using JSON.stringify. */ toJSON(): SourceLocation; /** * Create a new span with the current span's end and a new beginning. */ withStart(other: SourceOffset): SourceSpan; /** * Create a new span with the current span's beginning and a new ending. */ withEnd(other: SourceOffset): SourceSpan; asString(): string; /** * Convert this `SourceSpan` into a `SourceSlice`. In debug mode, this method optionally checks * that the byte offsets represented by this `SourceSpan` actually correspond to the expected * string. */ toSlice(expected?: string): SourceSlice; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use startPosition instead */ get start(): SourcePosition; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use withStart instead */ set start(position: SourcePosition); /** * For compatibility with SourceLocation in AST plugins * * @deprecated use endPosition instead */ get end(): SourcePosition; /** * For compatibility with SourceLocation in AST plugins * * @deprecated use withEnd instead */ set end(position: SourcePosition); /** * For compatibility with SourceLocation in AST plugins * * @deprecated use module instead */ get source(): string; collapse(where: "start" | "end"): SourceSpan; extend(other: SourceSpan): SourceSpan; serialize(): SerializedSourceSpan; slice({ skipStart, skipEnd }: { skipStart?: number; skipEnd?: number; }): SourceSpan; sliceStartChars({ skipStart, chars }: { skipStart?: number; chars: number; }): SourceSpan; sliceEndChars({ skipEnd, chars }: { skipEnd?: number; chars: number; }): SourceSpan; } type AnySpan = HbsSpan | CharPositionSpan | InvisibleSpan; class CharPositionSpan implements SpanData { readonly source: Source; readonly charPositions: { start: CharPosition; end: CharPosition; }; readonly kind = OffsetKind.CharPosition; _locPosSpan: HbsSpan | BROKEN | null; constructor(source: Source, charPositions: { start: CharPosition; end: CharPosition; }); wrap(): SourceSpan; asString(): string; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; locDidUpdate(): void; toHbsSpan(): HbsSpan | null; serialize(): SerializedSourceSpan; toCharPosSpan(): CharPositionSpan; } class HbsSpan implements SpanData { readonly source: Source; readonly hbsPositions: { start: HbsPosition; end: HbsPosition; }; readonly kind = OffsetKind.HbsPosition; _charPosSpan: CharPositionSpan | BROKEN | null; // the source location from Handlebars + AST Plugins -- could be wrong _providedHbsLoc: SourceLocation | null; constructor(source: Source, hbsPositions: { start: HbsPosition; end: HbsPosition; }, providedHbsLoc?: SourceLocation | null); serialize(): SerializedConcreteSourceSpan; wrap(): SourceSpan; private updateProvided; locDidUpdate({ start, end }: { start?: SourcePosition; end?: SourcePosition; }): void; asString(): string; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; toHbsLoc(): SourceLocation; toHbsSpan(): HbsSpan; toCharPosSpan(): CharPositionSpan | null; } class InvisibleSpan implements SpanData { readonly kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent; // whatever was provided, possibly broken readonly loc: SourceLocation; // if the span represents a synthetic string readonly string: string | null; constructor(kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent, loc: SourceLocation, string?: string | null); serialize(): SerializedConcreteSourceSpan; wrap(): SourceSpan; asString(): string; locDidUpdate({ start, end }: { start?: SourcePosition; end?: SourcePosition; }): void; getModule(): string; getStart(): AnyPosition; getEnd(): AnyPosition; toCharPosSpan(): InvisibleSpan; toHbsSpan(): null; toHbsLoc(): SourceLocation; } const span: MatchFn; type SerializedConcreteSourceSpan = /** collapsed */ number | /** normal */ [ start: number, size: number ] | /** synthetic */ string; type SerializedSourceSpan = SerializedConcreteSourceSpan | OffsetKind.NonExistent | OffsetKind.Broken; /** * All positions have these details in common. Most notably, all three kinds of positions can * must be able to attempt to convert themselves into {@see CharPosition}. */ interface PositionData { readonly kind: OffsetKind; toCharPos(): CharPosition | null; toJSON(): SourcePosition; } /** * Used to indicate that an attempt to convert a `SourcePosition` to a character offset failed. It * is separate from `null` so that `null` can be used to indicate that the computation wasn't yet * attempted (and therefore to cache the failure) */ const BROKEN = "BROKEN"; type BROKEN = "BROKEN"; type AnyPosition = HbsPosition | CharPosition | InvisiblePosition; /** * A `SourceOffset` represents a single position in the source. * * There are three kinds of backing data for `SourceOffset` objects: * * - `CharPosition`, which contains a character offset into the raw source string * - `HbsPosition`, which contains a `SourcePosition` from the Handlebars AST, which can be * converted to a `CharPosition` on demand. * - `InvisiblePosition`, which represents a position not in source (@see {InvisiblePosition}) */ class SourceOffset { readonly data: PositionData & AnyPosition; /** * Create a `SourceOffset` from a Handlebars `SourcePosition`. It's stored as-is, and converted * into a character offset on demand, which avoids unnecessarily computing the offset of every * `SourceLocation`, but also means that broken `SourcePosition`s are not always detected. */ static forHbsPos(source: Source, pos: SourcePosition): SourceOffset; /** * Create a `SourceOffset` that corresponds to a broken `SourcePosition`. This means that the * calling code determined (or knows) that the `SourceLocation` doesn't correspond correctly to * any part of the source. */ static broken(pos?: SourcePosition): SourceOffset; constructor(data: PositionData & AnyPosition); /** * Get the character offset for this `SourceOffset`, if possible. */ get offset(): number | null; /** * Compare this offset with another one. * * If both offsets are `HbsPosition`s, they're equivalent as long as their lines and columns are * the same. This avoids computing offsets unnecessarily. * * Otherwise, two `SourceOffset`s are equivalent if their successfully computed character offsets * are the same. */ eql(right: SourceOffset): boolean; /** * Create a span that starts from this source offset and ends with another source offset. Avoid * computing character offsets if both `SourceOffset`s are still lazy. */ until(other: SourceOffset): SourceSpan; /** * Create a `SourceOffset` by moving the character position represented by this source offset * forward or backward (if `by` is negative), if possible. * * If this `SourceOffset` can't compute a valid character offset, `move` returns a broken offset. * * If the resulting character offset is less than 0 or greater than the size of the source, `move` * returns a broken offset. */ move(by: number): SourceOffset; /** * Create a new `SourceSpan` that represents a collapsed range at this source offset. Avoid * computing the character offset if it has not already been computed. */ collapsed(): SourceSpan; /** * Convert this `SourceOffset` into a Handlebars {@see SourcePosition} for compatibility with * existing plugins. */ toJSON(): SourcePosition; } class CharPosition implements PositionData { readonly source: Source; readonly charPos: number; readonly kind = OffsetKind.CharPosition; /** Computed from char offset */ _locPos: HbsPosition | BROKEN | null; constructor(source: Source, charPos: number); /** * This is already a `CharPosition`. * * {@see HbsPosition} for the alternative. */ toCharPos(): CharPosition; /** * Produce a Handlebars {@see SourcePosition} for this `CharPosition`. If this `CharPosition` was * computed using {@see SourceOffset#move}, this will compute the `SourcePosition` for the offset. */ toJSON(): SourcePosition; wrap(): SourceOffset; /** * A `CharPosition` always has an offset it can produce without any additional computation. */ get offset(): number; /** * Convert the current character offset to an `HbsPosition`, if it was not already computed. Once * a `CharPosition` has computed its `HbsPosition`, it will not need to do compute it again, and * the same `CharPosition` is retained when used as one of the ends of a `SourceSpan`, so * computing the `HbsPosition` should be a one-time operation. */ toHbsPos(): HbsPosition | null; } class HbsPosition implements PositionData { readonly source: Source; readonly hbsPos: SourcePosition; readonly kind = OffsetKind.HbsPosition; _charPos: CharPosition | BROKEN | null; constructor(source: Source, hbsPos: SourcePosition, charPos?: number | null); /** * Lazily compute the character offset from the {@see SourcePosition}. Once an `HbsPosition` has * computed its `CharPosition`, it will not need to do compute it again, and the same * `HbsPosition` is retained when used as one of the ends of a `SourceSpan`, so computing the * `CharPosition` should be a one-time operation. */ toCharPos(): CharPosition | null; /** * Return the {@see SourcePosition} that this `HbsPosition` was instantiated with. This operation * does not need to compute anything. */ toJSON(): SourcePosition; wrap(): SourceOffset; /** * This is already an `HbsPosition`. * * {@see CharPosition} for the alternative. */ toHbsPos(): HbsPosition; } class InvisiblePosition implements PositionData { readonly kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent; // whatever was provided, possibly broken readonly pos: SourcePosition; constructor(kind: OffsetKind.Broken | OffsetKind.InternalsSynthetic | OffsetKind.NonExistent, pos: SourcePosition); /** * A broken position cannot be turned into a {@see CharacterPosition}. */ toCharPos(): null; /** * The serialization of an `InvisiblePosition is whatever Handlebars {@see SourcePosition} was * originally identified as broken, non-existent or synthetic. * * If an `InvisiblePosition` never had an source offset at all, this method returns * {@see UNKNOWN_POSITION} for compatibility. */ toJSON(): SourcePosition; wrap(): SourceOffset; get offset(): null; } /** * Attr nodes look like HTML attributes, but are classified as: * * 1. `HtmlAttr`, which means a regular HTML attribute in Glimmer * 2. `SplatAttr`, which means `...attributes` * 3. `ComponentArg`, which means an attribute whose name begins with `@`, and it is therefore a * component argument. */ type AttrNode = HtmlAttr | SplatAttr | ComponentArg; /** * `HtmlAttr` and `SplatAttr` are grouped together because the order of the `SplatAttr` node, * relative to other attributes, matters. */ type HtmlOrSplatAttr = HtmlAttr | SplatAttr; /** * "Attr Block" nodes are allowed inside an open element tag in templates. They interact with the * element (or component). */ type AttrBlockNode = AttrNode | ElementModifier; interface BaseNodeFields { loc: SourceSpan; } /** * This is a convenience function for creating ASTv2 nodes, with an optional name and the node's * options. * * ```ts * export class HtmlText extends node('HtmlText').fields<{ chars: string }>() {} * ``` * * This creates a new ASTv2 node with the name `'HtmlText'` and one field `chars: string` (in * addition to a `loc: SourceOffsets` field, which all nodes have). * * ```ts * export class Args extends node().fields<{ * positional: PositionalArguments; * named: NamedArguments * }>() {} * ``` * * This creates a new un-named ASTv2 node with two fields (`positional: Positional` and `named: * Named`, in addition to the generic `loc: SourceOffsets` field). * * Once you create a node using `node`, it is instantiated with all of its fields (including `loc`): * * ```ts * new HtmlText({ loc: offsets, chars: someString }); * ``` */ function node(): { fields(): NodeConstructor; }; function node(name: T): { fields(): TypedNodeConstructor; }; interface NodeConstructor { new (fields: Fields): Readonly; } type TypedNode = { type: T; } & Readonly; interface TypedNodeConstructor { new (options: Fields): TypedNode; } const HtmlAttr_base: TypedNodeConstructor<"HtmlAttr", AttrNodeOptions & BaseNodeFields>; /** * `HtmlAttr` nodes are valid HTML attributes, with or without a value. * * Exceptions: * * - `...attributes` is `SplatAttr` * - `@x=` is `ComponentArg` */ class HtmlAttr extends HtmlAttr_base { } const SplatAttr_base: TypedNodeConstructor<"SplatAttr", { symbol: number; } & BaseNodeFields>; class SplatAttr extends SplatAttr_base { } const ComponentArg_base: NodeConstructor; /** * Corresponds to an argument passed by a component (`@x=`) */ class ComponentArg extends ComponentArg_base { /** * Convert the component argument into a named argument node */ toNamedArgument(): NamedArgument; } const ElementModifier_base: TypedNodeConstructor<"ElementModifier", CallFields & BaseNodeFields>; /** * An `ElementModifier` is just a normal call node in modifier position. */ class ElementModifier extends ElementModifier_base { } interface AttrNodeOptions { name: SourceSlice; value: ExpressionNode; trusting: boolean; } interface Upvar { readonly name: string; readonly resolution: ASTv2.FreeVarResolution; } interface SymbolTableOptions { customizeComponentName: (input: string) => string; lexicalScope: (variable: string) => boolean; } abstract class SymbolTable { static top(locals: readonly string[], keywords: readonly string[], options: SymbolTableOptions): ProgramSymbolTable; abstract has(name: string): boolean; abstract get(name: string): [ symbol: number, isRoot: boolean ]; abstract hasKeyword(name: string): boolean; abstract getKeyword(name: string): number; abstract hasLexical(name: string): boolean; abstract getLocalsMap(): Dict; abstract getDebugInfo(): Core.DebugInfo; abstract setHasDebugger(): void; abstract allocateFree(name: string, resolution: ASTv2.FreeVarResolution): number; abstract allocateNamed(name: string): number; abstract allocateBlock(name: string): number; abstract allocate(identifier: string): number; child(locals: string[]): BlockSymbolTable; } class ProgramSymbolTable extends SymbolTable { #private; private templateLocals; private keywords; private options; constructor(templateLocals: readonly string[], keywords: readonly string[], options: SymbolTableOptions); symbols: string[]; upvars: string[]; private size; private named; private blocks; private usedTemplateLocals; hasLexical(name: string): boolean; hasKeyword(name: string): boolean; getKeyword(name: string): number; getUsedTemplateLocals(): string[]; setHasDebugger(): void; get hasEval(): boolean; has(name: string): boolean; get(name: string): [ number, boolean ]; getLocalsMap(): Dict; getDebugInfo(): Core.DebugInfo; allocateFree(name: string, resolution: ASTv2.FreeVarResolution): number; allocateNamed(name: string): number; allocateBlock(name: string): number; allocate(identifier: string): number; } class BlockSymbolTable extends SymbolTable { #private; private parent; symbols: string[]; slots: number[]; constructor(parent: SymbolTable, symbols: string[], slots: number[]); get locals(): string[]; hasLexical(name: string): boolean; getKeyword(name: string): number; hasKeyword(name: string): boolean; has(name: string): boolean; get(name: string): [ number, boolean ]; getLocalsMap(): Dict; getDebugInfo(): Core.DebugInfo; setHasDebugger(): void; allocateFree(name: string, resolution: ASTv2.FreeVarResolution): number; allocateNamed(name: string): number; allocateBlock(name: string): number; allocate(identifier: string): number; } const Template_base: NodeConstructor<{ table: ProgramSymbolTable; } & GlimmerParentNodeOptions & BaseNodeFields>; /** * Corresponds to an entire template. */ class Template extends Template_base { } const Block_base: NodeConstructor<{ scope: BlockSymbolTable; } & GlimmerParentNodeOptions & BaseNodeFields>; /** * Represents a block. In principle this could be merged with `NamedBlock`, because all cases * involving blocks have at least a notional name. */ class Block extends Block_base { } const NamedBlocks_base: NodeConstructor<{ blocks: readonly NamedBlock[]; } & BaseNodeFields>; /** * Corresponds to a collection of named blocks. */ class NamedBlocks extends NamedBlocks_base { /** * Get the `NamedBlock` for a given name. */ get(name: "default"): NamedBlock; get(name: string): NamedBlock | null; } interface NamedBlockFields extends BaseNodeFields { name: SourceSlice; block: Block; // these are not currently supported, but are here for future expansion attrs: readonly HtmlOrSplatAttr[]; componentArgs: readonly ComponentArg[]; modifiers: readonly ElementModifier[]; } const NamedBlock_base: NodeConstructor; /** * Corresponds to a single named block. This is used for anonymous named blocks (`default` and * `else`). */ class NamedBlock extends NamedBlock_base { get args(): Args; } /** * Content Nodes are allowed in content positions in templates. They correspond to behavior in the * [Data][data] tokenization state in HTML. * * [data]: https://html.spec.whatwg.org/multipage/parsing.html#data-state */ type ContentNode = HtmlText | HtmlComment | AppendContent | InvokeBlock | InvokeComponent | SimpleElement | GlimmerComment; const GlimmerComment_base: TypedNodeConstructor<"GlimmerComment", { text: SourceSlice; } & BaseNodeFields>; class GlimmerComment extends GlimmerComment_base { } const HtmlText_base: TypedNodeConstructor<"HtmlText", { chars: string; } & BaseNodeFields>; class HtmlText extends HtmlText_base { } const HtmlComment_base: TypedNodeConstructor<"HtmlComment", { text: SourceSlice; } & BaseNodeFields>; class HtmlComment extends HtmlComment_base { } const AppendContent_base: TypedNodeConstructor<"AppendContent", { value: ExpressionNode; trusting: boolean; table: SymbolTable; } & BaseNodeFields>; class AppendContent extends AppendContent_base { get callee(): ExpressionNode; get args(): Args; } const InvokeBlock_base: TypedNodeConstructor<"InvokeBlock", CallFields & { blocks: NamedBlocks; } & BaseNodeFields>; class InvokeBlock extends InvokeBlock_base { } interface InvokeComponentFields { callee: ExpressionNode; blocks: NamedBlocks; attrs: readonly HtmlOrSplatAttr[]; componentArgs: readonly ComponentArg[]; modifiers: readonly ElementModifier[]; } const InvokeComponent_base: TypedNodeConstructor<"InvokeComponent", InvokeComponentFields & BaseNodeFields>; /** * Corresponds to a component invocation. When the content of a component invocation contains no * named blocks, `blocks` contains a single named block named `"default"`. When a component * invocation is self-closing, `blocks` is empty. */ class InvokeComponent extends InvokeComponent_base { get args(): Args; } interface SimpleElementOptions extends BaseNodeFields { tag: SourceSlice; body: readonly ContentNode[]; attrs: readonly HtmlOrSplatAttr[]; componentArgs: readonly ComponentArg[]; modifiers: readonly ElementModifier[]; } const SimpleElement_base: TypedNodeConstructor<"SimpleElement", SimpleElementOptions & BaseNodeFields>; /** * Corresponds to a simple HTML element. The AST allows component arguments and modifiers to support * future extensions. */ class SimpleElement extends SimpleElement_base { get args(): Args; } type ElementNode = NamedBlock | InvokeComponent | SimpleElement; interface SerializedBaseNode { loc: SerializedSourceSpan; } interface GlimmerParentNodeOptions extends BaseNodeFields { body: readonly ContentNode[]; } interface CallFields extends BaseNodeFields { callee: CalleeNode; args: Args; } type CalleeNode = KeywordExpression | PathExpression | CallExpression; type CallNode = CallExpression | InvokeBlock | AppendContent | InvokeComponent | ElementModifier; /** * Strict resolution is used: * * 1. in a strict mode template * 2. in an local variable invocation with dot paths */ const STRICT_RESOLUTION: { resolution: () => GetContextualFreeOpcode; serialize: () => SerializedResolution; isAngleBracket: false; }; type StrictResolution = typeof STRICT_RESOLUTION; const HTML_RESOLUTION: { isAngleBracket: true; resolution: () => GetContextualFreeOpcode; serialize: () => SerializedResolution; }; type HtmlResolution = typeof HTML_RESOLUTION; function isStrictResolution(value: unknown): value is StrictResolution; /** * A `LooseModeResolution` includes one or more namespaces to resolve the variable in * * In practice, there are a limited number of possible combinations of these degrees of freedom, * and they are captured by the `Namespaces` union below. */ class LooseModeResolution { readonly namespaces: Namespaces; readonly isAngleBracket: boolean; /** * Namespaced resolution is used in an unambiguous syntax position: * * 1. `(sexp)` (namespace: `Helper`) * 2. `{{#block}}` (namespace: `Component`) * 3. `` (namespace: `Modifier`) * 4. `` (namespace: `Component`) */ static namespaced(namespace: FreeVarNamespace, isAngleBracket?: boolean): LooseModeResolution; /** * Append resolution is used when the variable should be resolved in both the `component` and * `helper` namespaces. * * ```hbs * {{x}} * ``` * * ```hbs * {{x y}} * ``` * * ^ In either case, `x` should be resolved in the `component` and `helper` namespaces. */ static append(): LooseModeResolution; /** * Trusting append resolution is used when the variable should be resolved only in the * `helper` namespaces. * * ```hbs * {{{x}}} * ``` * * ```hbs * {{{x y}}} * ``` * * ^ In either case, `x` should be resolved in the `helper` namespace. */ static trustingAppend(): LooseModeResolution; constructor(namespaces: Namespaces, isAngleBracket?: boolean); resolution(): GetContextualFreeOpcode; serialize(): SerializedResolution; } enum FreeVarNamespace { Helper = "Helper", Modifier = "Modifier", Component = "Component" } const HELPER_NAMESPACE = FreeVarNamespace.Helper; const MODIFIER_NAMESPACE = FreeVarNamespace.Modifier; const COMPONENT_NAMESPACE = FreeVarNamespace.Component; /** * A `Namespaced` must be resolved in one or more namespaces. * * ```hbs * * ``` * * ^ `X` is resolved in the `component` namespace * * ```hbs * (x) * ``` * * ^ `x` is resolved in the `helper` namespace * * ```hbs * * ``` * * ^ `x` is resolved in the `modifier` namespace */ type Namespaces = [ FreeVarNamespace.Helper ] | [ FreeVarNamespace.Modifier ] | [ FreeVarNamespace.Component ] | [ FreeVarNamespace.Component, FreeVarNamespace.Helper ]; type FreeVarResolution = StrictResolution | HtmlResolution | LooseModeResolution; // Serialization type SerializedResolution = "Strict" | "Helper" | "Modifier" | "Component" | "ComponentOrHelper"; function loadResolution(resolution: SerializedResolution): FreeVarResolution; const ThisReference_base: TypedNodeConstructor<"This", object & BaseNodeFields>; /** * Corresponds to `this` at the head of an expression. */ class ThisReference extends ThisReference_base { } const ArgReference_base: TypedNodeConstructor<"Arg", { name: SourceSlice; symbol: number; } & BaseNodeFields>; /** * Corresponds to `@` at the beginning of an expression. */ class ArgReference extends ArgReference_base { } const LocalVarReference_base: TypedNodeConstructor<"Local", { name: string; isTemplateLocal: boolean; symbol: number; } & BaseNodeFields>; /** * Corresponds to `` at the beginning of an expression, when `` is in the current * block's scope. */ class LocalVarReference extends LocalVarReference_base { } const FreeVarReference_base: TypedNodeConstructor<"Free", { name: string; resolution: FreeVarResolution; symbol: number; } & BaseNodeFields>; /** * Corresponds to `` at the beginning of an expression, when `` is *not* in the * current block's scope. * * The `resolution: FreeVarResolution` field describes how to resolve the free variable. * * Note: In strict mode, it must always be a variable that is in a concrete JavaScript scope that * the template will be installed into. */ class FreeVarReference extends FreeVarReference_base { } type VariableReference = ThisReference | ArgReference | LocalVarReference | FreeVarReference; /** * A Handlebars literal. * * {@link https://handlebarsjs.com/guide/expressions.html#literal-segments} */ type LiteralValue = string | boolean | number | undefined | null; interface LiteralTypes { string: string; boolean: boolean; number: number; null: null; undefined: undefined; } const LiteralExpression_base: TypedNodeConstructor<"Literal", { value: LiteralValue; } & BaseNodeFields>; /** * Corresponds to a Handlebars literal. * * @see {LiteralValue} */ class LiteralExpression extends LiteralExpression_base { toSlice(this: StringLiteral): SourceSlice; } type StringLiteral = LiteralExpression & { value: string; }; /** * Returns true if an input {@see ExpressionNode} is a literal. */ function isLiteral(node: ExpressionNode, kind?: K): node is StringLiteral; const PathExpression_base: TypedNodeConstructor<"Path", { ref: VariableReference; tail: readonly SourceSlice[]; } & BaseNodeFields>; /** * Corresponds to a path in expression position. * * ```hbs * this * this.x * @x * @x.y * x * x.y * ``` */ class PathExpression extends PathExpression_base { } const KeywordExpression_base: TypedNodeConstructor<"Keyword", { name: string; symbol: number; } & BaseNodeFields>; /** * Corresponds to a known strict-mode keyword. It behaves similarly to a * PathExpression with a FreeVarReference, but implies StrictResolution and * is guaranteed to not have a tail, since `{{outlet.foo}}` would have been * illegal. */ class KeywordExpression extends KeywordExpression_base { } const CallExpression_base: TypedNodeConstructor<"Call", CallFields & BaseNodeFields>; /** * Corresponds to a parenthesized call expression. * * ```hbs * (x) * (x.y) * (x y) * (x.y z) * ``` */ class CallExpression extends CallExpression_base { } const InterpolateExpression_base: TypedNodeConstructor<"Interpolate", { parts: PresentArray; } & BaseNodeFields>; /** * Corresponds to an interpolation in attribute value position. * * ```hbs * ; /** * Corresponds to syntaxes with positional and named arguments: * * - SubExpression * - Invoking Append * - Invoking attributes * - InvokeBlock * * If `Args` is empty, the `SourceOffsets` for this node should be the collapsed position * immediately after the parent call node's `callee`. */ class Args extends Args_base { static empty(loc: SourceSpan): Args; static named(named: NamedArguments): Args; nth(offset: number): ExpressionNode | null; get(name: string): ExpressionNode | null; isEmpty(): boolean; } const PositionalArguments_base: NodeConstructor<{ exprs: readonly ExpressionNode[]; } & BaseNodeFields>; /** * Corresponds to positional arguments. * * If `PositionalArguments` is empty, the `SourceOffsets` for this node should be the collapsed * position immediately after the parent call node's `callee`. */ class PositionalArguments extends PositionalArguments_base { static empty(loc: SourceSpan): PositionalArguments; get size(): number; nth(offset: number): ExpressionNode | null; isEmpty(): boolean; } const NamedArguments_base: NodeConstructor<{ entries: readonly NamedArgument[]; } & BaseNodeFields>; /** * Corresponds to named arguments. * * If `PositionalArguments` and `NamedArguments` are empty, the `SourceOffsets` for this node should * be the same as the `Args` node that contains this node. * * If `PositionalArguments` is not empty but `NamedArguments` is empty, the `SourceOffsets` for this * node should be the collapsed position immediately after the last positional argument. */ class NamedArguments extends NamedArguments_base { static empty(loc: SourceSpan): NamedArguments; get size(): number; get(name: string): ExpressionNode | null; isEmpty(): boolean; } /** * Corresponds to a single named argument. * * ```hbs * x= * ``` */ class NamedArgument { readonly loc: SourceSpan; readonly name: SourceSlice; readonly value: ExpressionNode; constructor(options: { name: SourceSlice; value: ExpressionNode; }); } } interface SymbolTableOptions { customizeComponentName: (input: string) => string; lexicalScope: (variable: string) => boolean; } declare abstract class SymbolTable { static top(locals: readonly string[], keywords: readonly string[], options: SymbolTableOptions): ProgramSymbolTable; abstract has(name: string): boolean; abstract get(name: string): [ symbol: number, isRoot: boolean ]; abstract hasKeyword(name: string): boolean; abstract getKeyword(name: string): number; abstract hasLexical(name: string): boolean; abstract getLocalsMap(): Dict; abstract getDebugInfo(): Core.DebugInfo; abstract setHasDebugger(): void; abstract allocateFree(name: string, resolution: ASTv2.FreeVarResolution): number; abstract allocateNamed(name: string): number; abstract allocateBlock(name: string): number; abstract allocate(identifier: string): number; child(locals: string[]): BlockSymbolTable; } declare class ProgramSymbolTable extends SymbolTable { #private; private templateLocals; private keywords; private options; constructor(templateLocals: readonly string[], keywords: readonly string[], options: SymbolTableOptions); symbols: string[]; upvars: string[]; private size; private named; private blocks; private usedTemplateLocals; hasLexical(name: string): boolean; hasKeyword(name: string): boolean; getKeyword(name: string): number; getUsedTemplateLocals(): string[]; setHasDebugger(): void; get hasEval(): boolean; has(name: string): boolean; get(name: string): [ number, boolean ]; getLocalsMap(): Dict; getDebugInfo(): Core.DebugInfo; allocateFree(name: string, resolution: ASTv2.FreeVarResolution): number; allocateNamed(name: string): number; allocateBlock(name: string): number; allocate(identifier: string): number; } declare class BlockSymbolTable extends SymbolTable { #private; private parent; symbols: string[]; slots: number[]; constructor(parent: SymbolTable, symbols: string[], slots: number[]); get locals(): string[]; hasLexical(name: string): boolean; getKeyword(name: string): number; hasKeyword(name: string): boolean; has(name: string): boolean; get(name: string): [ number, boolean ]; getLocalsMap(): Dict; getDebugInfo(): Core.DebugInfo; setHasDebugger(): void; allocateFree(name: string, resolution: ASTv2.FreeVarResolution): number; allocateNamed(name: string): number; allocateBlock(name: string): number; allocate(identifier: string): number; } interface GlimmerSyntaxError extends Error { location: src.SourceSpan | null; code: string | null; } declare function generateSyntaxError(message: string, location: src.SourceSpan): GlimmerSyntaxError; interface TraversalError extends Error { constructor: TraversalErrorConstructor; key: string; node: ASTv1.Node; parent: Nullable; stack?: string; } interface TraversalErrorConstructor { new (message: string, node: ASTv1.Node, parent: Nullable, key: string): TraversalError; readonly prototype: TraversalError; } declare const TraversalError: TraversalErrorConstructor; declare function cannotRemoveNode(node: ASTv1.Node, parent: ASTv1.Node, key: string): TraversalError; declare function cannotReplaceNode(node: ASTv1.Node, parent: ASTv1.Node, key: string): TraversalError; interface CallParts { callee: ASTv2.CalleeNode; args: ASTv2.Args; } declare class Builder { // TEMPLATE // template(symbols: ProgramSymbolTable, body: ASTv2.ContentNode[], loc: SourceSpan): ASTv2.Template; // INTERNAL (these nodes cannot be reached when doing general-purpose visiting) // block(symbols: BlockSymbolTable, body: ASTv2.ContentNode[], loc: SourceSpan): ASTv2.Block; namedBlock(name: SourceSlice, block: ASTv2.Block, loc: SourceSpan): ASTv2.NamedBlock; simpleNamedBlock(name: SourceSlice, block: ASTv2.Block, loc: SourceSpan): ASTv2.NamedBlock; slice(chars: string, loc: SourceSpan): SourceSlice; args(positional: ASTv2.PositionalArguments, named: ASTv2.NamedArguments, loc: SourceSpan): ASTv2.Args; positional(exprs: ASTv2.ExpressionNode[], loc: SourceSpan): ASTv2.PositionalArguments; namedArgument(key: SourceSlice, value: ASTv2.ExpressionNode): ASTv2.NamedArgument; named(entries: ASTv2.NamedArgument[], loc: SourceSpan): ASTv2.NamedArguments; attr({ name, value, trusting }: { name: SourceSlice; value: ASTv2.ExpressionNode; trusting: boolean; }, loc: SourceSpan): ASTv2.HtmlAttr; splatAttr(symbol: number, loc: SourceSpan): ASTv2.SplatAttr; arg({ name, value, trusting }: { name: SourceSlice; value: ASTv2.ExpressionNode; trusting: boolean; }, loc: SourceSpan): ASTv2.ComponentArg; // EXPRESSIONS // path(head: ASTv2.VariableReference, tail: SourceSlice[], loc: SourceSpan): ASTv2.PathExpression; keyword(name: string, symbol: number, loc: SourceSpan): ASTv2.KeywordExpression; self(loc: SourceSpan): ASTv2.VariableReference; at(name: string, symbol: number, loc: SourceSpan): ASTv2.VariableReference; freeVar({ name, context, symbol, loc }: { name: string; context: ASTv2.FreeVarResolution; symbol: number; loc: SourceSpan; }): ASTv2.FreeVarReference; localVar(name: string, symbol: number, isTemplateLocal: boolean, loc: SourceSpan): ASTv2.VariableReference; sexp(parts: CallParts, loc: SourceSpan): ASTv2.CallExpression; interpolate(parts: ASTv2.ExpressionNode[], loc: SourceSpan): ASTv2.InterpolateExpression; literal(value: string, loc: SourceSpan): ASTv2.LiteralExpression & { value: string; }; literal(value: number, loc: SourceSpan): ASTv2.LiteralExpression & { value: number; }; literal(value: boolean, loc: SourceSpan): ASTv2.LiteralExpression & { value: boolean; }; literal(value: null, loc: SourceSpan): ASTv2.LiteralExpression & { value: null; }; literal(value: undefined, loc: SourceSpan): ASTv2.LiteralExpression & { value: undefined; }; literal(value: string | number | boolean | null | undefined, loc: SourceSpan): ASTv2.LiteralExpression; // STATEMENTS // append({ table, trusting, value }: { table: SymbolTable; trusting: boolean; value: ASTv2.ExpressionNode; }, loc: SourceSpan): ASTv2.AppendContent; modifier({ callee, args }: CallParts, loc: SourceSpan): ASTv2.ElementModifier; namedBlocks(blocks: ASTv2.NamedBlock[], loc: SourceSpan): ASTv2.NamedBlocks; blockStatement({ program, inverse, ...call }: { symbols: SymbolTable; program: ASTv2.Block; inverse?: ASTv2.Block | null; } & CallParts, loc: SourceSpan): ASTv2.InvokeBlock; element(options: BuildBaseElement): BuildElement; } interface BuildBaseElement { selfClosing: boolean; attrs: ASTv2.HtmlOrSplatAttr[]; componentArgs: ASTv2.ComponentArg[]; modifiers: ASTv2.ElementModifier[]; comments: ASTv2.GlimmerComment[]; } declare class BuildElement { readonly base: BuildBaseElement; readonly builder: Builder; constructor(base: BuildBaseElement); simple(tag: SourceSlice, body: ASTv2.ContentNode[], loc: SourceSpan): ASTv2.SimpleElement; named(name: SourceSlice, block: ASTv2.Block, loc: SourceSpan): ASTv2.NamedBlock; selfClosingComponent(callee: ASTv2.ExpressionNode, loc: SourceSpan): ASTv2.InvokeComponent; componentWithDefaultBlock(callee: ASTv2.ExpressionNode, children: ASTv2.ContentNode[], symbols: BlockSymbolTable, loc: SourceSpan): ASTv2.InvokeComponent; componentWithNamedBlocks(callee: ASTv2.ExpressionNode, blocks: PresentArray, loc: SourceSpan): ASTv2.InvokeComponent; } declare function normalize(source: Source, options?: PrecompileOptionsWithLexicalScope): [ ast: ASTv2.Template, locals: string[] ]; interface BaseNodeFields { loc: SourceSpan; } /** * This is a convenience function for creating ASTv2 nodes, with an optional name and the node's * options. * * ```ts * export class HtmlText extends node('HtmlText').fields<{ chars: string }>() {} * ``` * * This creates a new ASTv2 node with the name `'HtmlText'` and one field `chars: string` (in * addition to a `loc: SourceOffsets` field, which all nodes have). * * ```ts * export class Args extends node().fields<{ * positional: PositionalArguments; * named: NamedArguments * }>() {} * ``` * * This creates a new un-named ASTv2 node with two fields (`positional: Positional` and `named: * Named`, in addition to the generic `loc: SourceOffsets` field). * * Once you create a node using `node`, it is instantiated with all of its fields (including `loc`): * * ```ts * new HtmlText({ loc: offsets, chars: someString }); * ``` */ declare function node(): { fields(): NodeConstructor; }; declare function node(name: T): { fields(): TypedNodeConstructor; }; interface NodeConstructor { new (fields: Fields): Readonly; } type TypedNode = { type: T; } & Readonly; interface TypedNodeConstructor { new (options: Fields): TypedNode; } export { build as print, getVoidTags, isVoidTag, sortByLoc, getTemplateLocals, isKeyword, KEYWORDS_TYPES, KeywordType, ASTPlugin, ASTPluginBuilder, ASTPluginEnvironment, PrecompileOptions, PrecompileOptionsWithLexicalScope, preprocess, Syntax, TemplateIdFn, src, SourceSlice, HasSourceSpan, hasSpan, loc, MaybeHasSourceSpan, maybeLoc, SpanList, BlockSymbolTable, ProgramSymbolTable, SymbolTable, generateSyntaxError, GlimmerSyntaxError, cannotRemoveNode, cannotReplaceNode, WalkerPath, traverse, Walker, Walker as Path, ASTv1, ASTv1 as AST, _default as builders, visitorKeys, ASTv2, normalize, node }; export type { PreprocessOptions, NodeVisitor }; //# sourceMappingURL=index.d.ts.map