@glimmer/syntax
Version:
1,379 lines (1,352 loc) • 76 kB
TypeScript
import { Nullable, Maybe, PresentArray, GetContextualFreeOpcode, Dict, Core } from '@glimmer/interfaces';
/**
* @module
*
* This file contains types for the raw AST returned from the Handlebars parser.
* These types were originally imported from
* https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/handlebars/index.d.ts.
*/
interface CommonNode {
loc: SourceLocation$1;
}
interface SourceLocation$1 {
source: string;
start: Position;
end: Position;
}
interface Position {
line: number;
column: number;
}
interface Program$1 extends CommonNode {
type: 'Program';
body: Statement$1[];
blockParams?: string[];
chained?: boolean;
}
type Statement$1 = MustacheStatement$1 | BlockStatement$1 | DecoratorBlock | PartialStatement | PartialBlockStatement | ContentStatement | CommentStatement$1;
interface CommonMustache extends CommonNode {
path: Expression$1;
params: Expression$1[];
hash: Hash$1;
escaped: boolean;
strip: StripFlags$1;
}
interface MustacheStatement$1 extends CommonMustache {
type: 'MustacheStatement';
}
interface CommonBlock extends CommonNode {
chained: boolean;
path: PathExpression$2 | SubExpression$1;
params: Expression$1[];
hash: Hash$1;
program: Program$1;
inverse?: Program$1;
openStrip?: StripFlags$1;
inverseStrip?: StripFlags$1;
closeStrip?: StripFlags$1;
}
interface BlockStatement$1 extends CommonBlock {
type: 'BlockStatement';
}
interface DecoratorBlock extends CommonBlock {
type: 'DecoratorBlock';
}
interface PartialStatement extends CommonNode {
type: 'PartialStatement';
name: PathExpression$2 | SubExpression$1;
params: Expression$1[];
hash: Hash$1;
indent: string;
strip: StripFlags$1;
}
interface PartialBlockStatement extends CommonNode {
type: 'PartialBlockStatement';
name: PathExpression$2 | SubExpression$1;
params: Expression$1[];
hash: Hash$1;
program: Program$1;
openStrip: StripFlags$1;
closeStrip: StripFlags$1;
}
interface ContentStatement extends CommonNode {
type: 'ContentStatement';
value: string;
original: StripFlags$1;
}
interface CommentStatement$1 extends CommonNode {
type: 'CommentStatement';
value: string;
strip: StripFlags$1;
}
type Expression$1 = SubExpression$1 | PathExpression$2 | Literal$1;
interface SubExpression$1 extends CommonNode {
type: 'SubExpression';
path: PathExpression$2 | SubExpression$1;
params: Expression$1[];
hash: Hash$1;
}
interface PathExpression$2 extends CommonNode {
type: 'PathExpression';
data: boolean;
depth: number;
parts: string[];
original: string;
}
type Literal$1 = StringLiteral$2 | BooleanLiteral$1 | NumberLiteral$1 | UndefinedLiteral$1 | NullLiteral$1;
interface StringLiteral$2 extends CommonNode {
type: 'StringLiteral';
value: string;
original: string;
}
interface BooleanLiteral$1 extends CommonNode {
type: 'BooleanLiteral';
value: boolean;
original: boolean;
}
interface NumberLiteral$1 extends CommonNode {
type: 'NumberLiteral';
value: number;
original: number;
}
interface UndefinedLiteral$1 extends CommonNode {
type: 'UndefinedLiteral';
}
interface NullLiteral$1 extends CommonNode {
type: 'NullLiteral';
}
interface Hash$1 extends CommonNode {
pairs: HashPair$1[];
}
interface HashPair$1 extends CommonNode {
key: string;
value: Expression$1;
}
interface StripFlags$1 {
open: boolean;
close: boolean;
}
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<N extends Node> = VisitorKeys[N['type']] & keyof N;
declare class WalkerPath<N extends Node> {
node: N;
parent: WalkerPath<Node> | null;
parentKey: string | null;
constructor(node: N, parent?: WalkerPath<Node> | null, parentKey?: string | null);
get parentNode(): Node | null;
parents(): Iterable<WalkerPath<Node> | null>;
}
interface FullNodeTraversal<N extends Node> {
enter?(node: N, path: WalkerPath<N>): void;
exit?(node: N, path: WalkerPath<N>): void;
keys?: KeysVisitor<N>;
}
type NodeHandler<N extends Node> = (node: N, path: WalkerPath<N>) => Node | Node[] | undefined | void;
type NodeTraversal<N extends Node> = FullNodeTraversal<N> | NodeHandler<N>;
type NodeVisitor = {
[P in keyof Nodes]?: NodeTraversal<Nodes[P]>;
} & {
All?: NodeTraversal<Node>;
/**
* @deprecated use Template or Block instead
*/
Program?: NodeTraversal<Template$1 | Block$1>;
};
interface FullKeyTraversal<N extends Node, K extends string> {
enter?(node: N, key: K): void;
exit?(node: N, key: K): void;
}
type KeyHandler<N extends Node, K extends VisitorKey<N>> = (node: N, key: K) => void;
type KeyTraversal<N extends Node, K extends VisitorKey<N>> = FullKeyTraversal<N, K> | KeyHandler<N, K>;
type KeysVisitor<N extends Node> = {
[P in VisitorKey<N>]?: KeyTraversal<N, P>;
} & {
All?: KeyTraversal<N, VisitorKey<N>>;
/**
* @deprecated use Template or Block instead
*/
Program?: KeyTraversal<Template$1 | Block$1, 'body'>;
};
declare function traverse(node: Node, visitor: NodeVisitor): void;
type NodeCallback<N extends Node> = (node: N, walker: Walker) => void;
declare class Walker {
order?: unknown | undefined;
stack: unknown[];
constructor(order?: unknown | undefined);
visit<N extends Node>(node: Nullable<N>, visitor: NodeCallback<N>): void;
children<N extends Node>(node: N & Node, callback: NodeCallback<N & Node>): void;
}
type BuilderHead = string | CallableExpression;
type TagDescriptor = string | PathExpression$1 | {
path: PathExpression$1;
selfClosing?: boolean;
} | {
name: string;
selfClosing?: boolean;
};
declare function buildMustache(path: BuilderHead | Literal, params?: Expression[], hash?: Hash, trusting?: boolean, loc?: SourceLocation, strip?: StripFlags): MustacheStatement;
type PossiblyDeprecatedBlock = Block$1 | Template$1;
declare function buildBlock(path: BuilderHead, params: Nullable<Expression[]>, hash: Nullable<Hash>, _defaultBlock: PossiblyDeprecatedBlock, _elseBlock?: Nullable<PossiblyDeprecatedBlock>, loc?: SourceLocation, openStrip?: StripFlags, inverseStrip?: StripFlags, closeStrip?: StripFlags): BlockStatement;
declare function buildElementModifier(path: BuilderHead, params?: Expression[], hash?: Hash, loc?: Nullable<SourceLocation>): ElementModifierStatement;
declare function buildComment(value: string, loc?: SourceLocation): CommentStatement;
declare function buildMustacheComment(value: string, loc?: SourceLocation): MustacheCommentStatement;
declare function buildConcat(parts: (TextNode | MustacheStatement)[], loc?: SourceLocation): ConcatStatement;
interface BuildElementOptions {
attrs?: AttrNode$1[];
modifiers?: ElementModifierStatement[];
children?: Statement[];
comments?: MustacheCommentStatement[];
blockParams?: VarHead[] | string[];
openTag?: SourceLocation;
closeTag?: Maybe<SourceLocation>;
loc?: SourceLocation;
}
declare function buildElement(tag: TagDescriptor, options?: BuildElementOptions): ElementNode$1;
declare function buildAttr(name: string, value: AttrValue, loc?: SourceLocation): AttrNode$1;
declare function buildText(chars?: string, loc?: SourceLocation): TextNode;
declare function buildSexpr(path: BuilderHead, params?: Expression[], hash?: Hash, loc?: SourceLocation): SubExpression;
declare function buildThis(loc?: SourceLocation): ThisHead;
declare function buildAtName(name: string, loc?: SourceLocation): AtHead;
declare function buildVar(name: string, loc?: SourceLocation): VarHead;
declare function buildHeadFromString(original: string, loc?: SourceLocation): PathHead;
declare function buildCleanPath(head: PathHead, tail?: string[], loc?: SourceLocation): PathExpression$1;
declare function buildPath(path: PathExpression$1 | string | {
head: string;
tail: string[];
}, loc?: SourceLocation): PathExpression$1;
declare function buildPath(path: BuilderHead, loc?: SourceLocation): CallableExpression;
declare function buildPath(path: BuilderHead | Literal | Expression, loc?: SourceLocation): Expression;
declare function buildLiteral<T extends Literal>(type: T['type'], value: T['value'], loc?: SourceLocation): T;
declare function buildHash(pairs?: HashPair[], loc?: SourceLocation): Hash;
declare function buildPair(key: string, value: Expression, loc?: SourceLocation): HashPair;
declare function buildProgram(body?: Statement[], blockParams?: string[], loc?: SourceLocation): Template$1 | Block$1;
declare function buildBlockItself(body?: Statement[], params?: Array<VarHead | string>, chained?: boolean, loc?: SourceLocation): Block$1;
declare function buildTemplate(body?: Statement[], blockParams?: string[], loc?: SourceLocation): Template$1;
declare function buildPosition(line: number, column: number): SourcePosition;
declare function buildLoc(loc: Nullable<SourceLocation>): 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) => StringLiteral$1;
boolean: (value: boolean) => BooleanLiteral;
number: (value: number) => NumberLiteral;
undefined(): UndefinedLiteral;
null(): NullLiteral;
};
/**
ASTPlugins can make changes to the Glimmer template AST before
compilation begins.
*/
interface ASTPluginBuilder<TEnv extends ASTPluginEnvironment = ASTPluginEnvironment> {
(env: TEnv): ASTPlugin;
}
interface ASTPlugin {
name: string;
visitor: NodeVisitor;
}
interface ASTPluginEnvironment {
meta?: object | undefined;
syntax: Syntax;
}
interface HandlebarsParseOptions {
srcName?: string;
ignoreStandalone?: boolean;
}
interface TemplateIdFn {
(src: string): Nullable<string>;
}
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[];
/**
* In loose mode, this hook allows embedding environments to customize the name of an
* angle-bracket component. In practice, this means that `<HelloWorld />` in Ember is
* compiled by Glimmer as an invocation of a component named `hello-world`.
*
* It's a little weird that this is needed in addition to the resolver, but it's a
* classic-only feature and it seems fine to leave it alone for classic consumers.
*/
customizeComponentName?: ((input: string) => string) | undefined;
}
interface PrecompileOptionsWithLexicalScope extends PrecompileOptions {
lexicalScope: (variable: string) => boolean;
/**
* If `emit.debugSymbols` is set to `true`, the name of lexical local variables
* will be included in the wire format.
*/
emit?: {
debugSymbols?: boolean;
} | undefined;
}
interface PreprocessOptions {
strictMode?: boolean | undefined;
locals?: string[] | undefined;
meta?: {
moduleName?: string | undefined;
} | undefined;
plugins?: {
ast?: ASTPluginBuilder[] | undefined;
} | undefined;
parseOptions?: HandlebarsParseOptions | undefined;
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' | undefined;
}
interface Syntax {
parse: typeof preprocess;
builders: typeof _default;
print: typeof build;
traverse: typeof traverse;
Walker: typeof Walker;
}
declare function preprocess(input: string | Source | Program$1, options?: PreprocessOptions): Template$1;
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.
*/
validate(offset: number): boolean;
slice(start: number, end: number): string;
offsetFor(line: number, column: number): SourceOffset;
spanFor({ start, end }: Readonly<SourceLocation>): SourceSpan;
hbsPosFor(offset: number): Nullable<SourcePosition>;
charPosFor(position: SourcePosition): number | null;
}
/**
* We have already computed the character position of this offset or span.
*/
type CharOffsetKind = 'CharPosition';
/**
* This offset or span was instantiated with a Handlebars SourcePosition or SourceLocation. Its
* character position will be computed on demand.
*/
type HbsPositionKind = '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.
*/
type InternalSyntheticKind = '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
*/
type NonExistentKind = '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.
*/
type BrokenKind = 'Broken';
type OffsetKind = CharOffsetKind | HbsPositionKind | InvisibleKind;
/**
* These kinds describe spans that don't have a concrete location in the original source.
*/
type InvisibleKind = BrokenKind | InternalSyntheticKind | NonExistentKind;
type SerializedSourceSlice<Chars extends string = string> = [
chars: Chars,
span: SerializedSourceSpan
];
declare class SourceSlice<Chars extends string = string> {
static synthetic<S extends string>(chars: S): SourceSlice<S>;
static load(source: Source, slice: SerializedSourceSlice): SourceSlice;
readonly chars: Chars;
readonly loc: SourceSpan;
constructor(options: {
loc: SourceSpan;
chars: Chars;
});
getString(): string;
serialize(): SerializedSourceSlice<Chars>;
}
/**
* 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`.
*/
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 {
#private;
readonly source: Source;
readonly charPositions: {
start: CharPosition;
end: CharPosition;
};
readonly kind: "CharPosition";
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(): this;
}
declare class HbsSpan implements SpanData {
#private;
readonly source: Source;
readonly hbsPositions: {
start: HbsPosition;
end: HbsPosition;
};
readonly kind: "HbsPosition";
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(): this;
toCharPosSpan(): CharPositionSpan | null;
}
declare class InvisibleSpan implements SpanData {
readonly kind: InvisibleKind;
readonly loc: SourceLocation;
readonly string: string | null;
constructor(kind: InvisibleKind, 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(): this;
toHbsSpan(): null;
toHbsLoc(): SourceLocation;
}
type SerializedConcreteSourceSpan = /** collapsed */ number | /** normal */ [start: number, size: number] | /** synthetic */ string;
type SerializedSourceSpan = SerializedConcreteSourceSpan;
interface SourceLocation {
start: SourcePosition;
end: SourcePosition;
}
interface SourcePosition {
/** >= 1 */
line: number;
/** >= 0 */
column: number;
}
declare const UNKNOWN_POSITION: Readonly<{
readonly line: 1;
readonly column: 0;
}>;
declare 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;
}>;
}>;
declare 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;
}>;
}>;
/**
* 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: "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(): this;
/**
* 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: "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(): this;
}
declare class InvisiblePosition implements PositionData {
readonly kind: BrokenKind | InternalSyntheticKind | NonExistentKind;
readonly pos: SourcePosition;
constructor(kind: BrokenKind | InternalSyntheticKind | NonExistentKind, 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;
}
declare class SpanList {
static range(span: PresentArray<HasSourceSpan>): 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;
type api$2_HasSourceSpan = HasSourceSpan;
type api$2_MaybeHasSourceSpan = MaybeHasSourceSpan;
declare const api$2_NON_EXISTENT_LOCATION: typeof NON_EXISTENT_LOCATION;
declare const api$2_SYNTHETIC_LOCATION: typeof SYNTHETIC_LOCATION;
type api$2_SerializedSourceSpan = SerializedSourceSpan;
type api$2_Source = Source;
declare const api$2_Source: typeof Source;
type api$2_SourceLocation = SourceLocation;
type api$2_SourceOffset = SourceOffset;
declare const api$2_SourceOffset: typeof SourceOffset;
type api$2_SourcePosition = SourcePosition;
type api$2_SourceSlice<Chars extends string = string> = SourceSlice<Chars>;
declare const api$2_SourceSlice: typeof SourceSlice;
type api$2_SourceSpan = SourceSpan;
declare const api$2_SourceSpan: typeof SourceSpan;
type api$2_SpanList = SpanList;
declare const api$2_SpanList: typeof SpanList;
declare const api$2_UNKNOWN_POSITION: typeof UNKNOWN_POSITION;
declare const api$2_hasSpan: typeof hasSpan;
declare const api$2_loc: typeof loc;
declare const api$2_maybeLoc: typeof maybeLoc;
declare namespace api$2 {
export { type api$2_HasSourceSpan as HasSourceSpan, type api$2_MaybeHasSourceSpan as MaybeHasSourceSpan, api$2_NON_EXISTENT_LOCATION as NON_EXISTENT_LOCATION, api$2_SYNTHETIC_LOCATION as SYNTHETIC_LOCATION, type api$2_SerializedSourceSpan as SerializedSourceSpan, api$2_Source as Source, type api$2_SourceLocation as SourceLocation, api$2_SourceOffset as SourceOffset, type api$2_SourcePosition as SourcePosition, api$2_SourceSlice as SourceSlice, api$2_SourceSpan as SourceSpan, api$2_SpanList as SpanList, api$2_UNKNOWN_POSITION as UNKNOWN_POSITION, api$2_hasSpan as hasSpan, api$2_loc as loc, api$2_maybeLoc as maybeLoc };
}
interface BaseNode {
type: NodeType;
loc: SourceSpan;
}
interface CommonProgram extends BaseNode {
body: Statement[];
}
interface Block$1 extends CommonProgram {
type: 'Block';
params: VarHead[];
chained?: boolean;
/**
* string accessor for params.name
*/
blockParams: string[];
}
type EntityEncodingState = 'transformed' | 'raw';
interface Template$1 extends CommonProgram {
type: 'Template';
blockParams: string[];
}
/**
* @deprecated use Template or Block instead
*/
type Program = Template$1 | Block$1;
type CallableExpression = SubExpression | PathExpression$1;
interface CallParts {
path: CallableExpression;
params: Expression[];
hash: Hash;
loc: SourceSpan;
}
type CallNode$1 = 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$1;
inverse?: Nullable<Block$1>;
openStrip: StripFlags;
inverseStrip: StripFlags;
closeStrip: StripFlags;
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$1 extends BaseNode {
type: 'ElementNode';
path: PathExpression$1;
selfClosing: boolean;
attributes: AttrNode$1[];
params: VarHead[];
modifiers: ElementModifierStatement[];
comments: MustacheCommentStatement[];
children: Statement[];
/**
* span for the open tag
*/
openTag: SourceSpan;
/**
* span for the close tag, null for void or self-closing tags
*/
closeTag: Nullable<SourceSpan>;
/**
* string accessor for path.original
*/
tag: string;
/**
* string accessor for params.name
*/
blockParams: string[];
}
type StatementName = 'MustacheStatement' | 'CommentStatement' | 'BlockStatement' | 'MustacheCommentStatement' | 'TextNode' | 'ElementNode';
interface AttrNode$1 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<TextNode | MustacheStatement>;
}
type ExpressionName = 'SubExpression' | 'PathExpression' | LiteralName;
interface SubExpression extends BaseNode {
type: 'SubExpression';
path: CallableExpression;
params: Expression[];
hash: Hash;
}
interface ThisHead {
type: 'ThisHead';
original: 'this';
loc: SourceSpan;
}
interface AtHead {
type: 'AtHead';
name: string;
loc: SourceSpan;
/**
* alias for name
*/
original: string;
}
interface VarHead {
type: 'VarHead';
name: string;
loc: SourceSpan;
/**
* alias for name
*/
original: string;
}
type PathHead = ThisHead | AtHead | VarHead;
interface MinimalPathExpression extends BaseNode {
type: 'PathExpression';
head: PathHead;
tail: string[];
}
interface PathExpression$1 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$1 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$1;
Block: Block$1;
MustacheStatement: MustacheStatement;
BlockStatement: BlockStatement;
ElementModifierStatement: ElementModifierStatement;
CommentStatement: CommentStatement;
MustacheCommentStatement: MustacheCommentStatement;
ElementNode: ElementNode$1;
AttrNode: AttrNode$1;
TextNode: TextNode;
ConcatStatement: ConcatStatement;
SubExpression: SubExpression;
PathExpression: PathExpression$1;
StringLiteral: StringLiteral$1;
BooleanLiteral: BooleanLiteral;
NumberLiteral: NumberLiteral;
NullLiteral: NullLiteral;
UndefinedLiteral: UndefinedLiteral;
Hash: Hash;
HashPair: HashPair;
};
type NodeType = keyof Nodes;
type Node = Nodes[NodeType];
type SubNodes = {
ThisHead: ThisHead;
AtHead: AtHead;
VarHead: VarHead;
};
type SubNodeType = keyof SubNodes;
type SubNode = SubNodes[SubNodeType];
type Statement = Nodes[StatementName];
type Statements = Pick<Nodes, StatementName>;
type Literal = Nodes[LiteralName];
type Expression = Nodes[ExpressionName];
type Expressions = Pick<Nodes, ExpressionName>;
type TopLevelStatement = Statement | Nodes['Block'];
type ParentNode = Template$1 | Block$1 | ElementNode$1;
type api$1_AtHead = AtHead;
type api$1_AttrPart = AttrPart;
type api$1_AttrValue = AttrValue;
type api$1_BaseNode = BaseNode;
type api$1_BlockStatement = BlockStatement;
type api$1_BooleanLiteral = BooleanLiteral;
type api$1_CallParts = CallParts;
type api$1_CallableExpression = CallableExpression;
type api$1_CommentStatement = CommentStatement;
type api$1_CommonProgram = CommonProgram;
type api$1_ConcatStatement = ConcatStatement;
type api$1_ElementModifierStatement = ElementModifierStatement;
type api$1_EntityEncodingState = EntityEncodingState;
type api$1_Expression = Expression;
type api$1_ExpressionName = ExpressionName;
type api$1_Expressions = Expressions;
type api$1_Hash = Hash;
type api$1_HashPair = HashPair;
type api$1_Literal = Literal;
type api$1_LiteralName = LiteralName;
type api$1_MinimalPathExpression = MinimalPathExpression;
type api$1_MustacheCommentStatement = MustacheCommentStatement;
type api$1_MustacheStatement = MustacheStatement;
type api$1_Node = Node;
type api$1_NodeType = NodeType;
type api$1_Nodes = Nodes;
type api$1_NullLiteral = NullLiteral;
type api$1_NumberLiteral = NumberLiteral;
type api$1_ParentNode = ParentNode;
type api$1_PathHead = PathHead;
type api$1_Program = Program;
type api$1_SourceLocation = SourceLocation;
type api$1_SourcePosition = SourcePosition;
type api$1_Statement = Statement;
type api$1_StatementName = StatementName;
type api$1_Statements = Statements;
type api$1_StripFlags = StripFlags;
type api$1_SubExpression = SubExpression;
type api$1_SubNode = SubNode;
type api$1_SubNodeType = SubNodeType;
type api$1_SubNodes = SubNodes;
type api$1_TextNode = TextNode;
type api$1_ThisHead = ThisHead;
type api$1_TopLevelStatement = TopLevelStatement;
type api$1_UndefinedLiteral = UndefinedLiteral;
type api$1_VarHead = VarHead;
declare namespace api$1 {
export type { api$1_AtHead as AtHead, AttrNode$1 as AttrNode, api$1_AttrPart as AttrPart, api$1_AttrValue as AttrValue, api$1_BaseNode as BaseNode, Block$1 as Block, api$1_BlockStatement as BlockStatement, api$1_BooleanLiteral as BooleanLiteral, CallNode$1 as CallNode, api$1_CallParts as CallParts, api$1_CallableExpression as CallableExpression, api$1_CommentStatement as CommentStatement, api$1_CommonProgram as CommonProgram, api$1_ConcatStatement as ConcatStatement, api$1_ElementModifierStatement as ElementModifierStatement, ElementNode$1 as ElementNode, api$1_EntityEncodingState as EntityEncodingState, api$1_Expression as Expression, api$1_ExpressionName as ExpressionName, api$1_Expressions as Expressions, api$1_Hash as Hash, api$1_HashPair as HashPair, api$1_Literal as Literal, api$1_LiteralName as LiteralName, api$1_MinimalPathExpression as MinimalPathExpression, api$1_MustacheCommentStatement as MustacheCommentStatement, api$1_MustacheStatement as MustacheStatement, api$1_Node as Node, api$1_NodeType as NodeType, api$1_Nodes as Nodes, api$1_NullLiteral as NullLiteral, api$1_NumberLiteral as NumberLiteral, api$1_ParentNode as ParentNode, PathExpression$1 as PathExpression, api$1_PathHead as PathHead, SourcePosition as Position, api$1_Program as Program, api$1_SourceLocation as SourceLocation, api$1_SourcePosition as SourcePosition, api$1_Statement as Statement, api$1_StatementName as StatementName, api$1_Statements as Statements, StringLiteral$1 as StringLiteral, api$1_StripFlags as StripFlags, api$1_SubExpression as SubExpression, api$1_SubNode as SubNode, api$1_SubNodeType as SubNodeType, api$1_SubNodes as SubNodes, Template$1 as Template, api$1_TextNode as TextNode, api$1_ThisHead as ThisHead, api$1_TopLevelStatement as TopLevelStatement, api$1_UndefinedLiteral as UndefinedLiteral, api$1_VarHead as VarHead };
}
declare function getVoidTags(): string[];
interface PrinterOptions {
entityEncoding: 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: 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: Node, options?: PrinterOptions): string;
declare function sortByLoc(a: Node, b: 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"[];
};
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<Fields extends object>(): NodeConstructor<Fields & BaseNodeFields>;
};
declare function node<T extends string>(name: T): {
fields<Fields extends object>(): TypedNodeConstructor<T, Fields & BaseNodeFields>;
};
interface NodeConstructor<Fields> {
new (fields: Fields): Readonly<Fields>;
}
type TypedNode<T extends string, Fields> = {
type: T;
} & Readonly<Fields>;
interface TypedNodeConstructor<T extends string, Fields> {
new (options: Fields): TypedNode<T, Fields>;
}
/**
* 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;
declare const HtmlAttr_base: TypedNodeConstructor<"HtmlAttr", AttrNodeOptions & BaseNodeFields>;
/**
* `HtmlAttr` nodes are valid HTML attributes, with or without a value.
*
* Exceptions:
*
* - `...attributes` is `SplatAttr`
* - `@x=<value>` is `ComponentArg`
*/
declare class HtmlAttr extends HtmlAttr_base {
}
declare const SplatAttr_base: TypedNodeConstru