teasel
Search
Search the documentation

@teasel/parser

Every export of the package, as its declarations say.

Options

export interface Options {
    /** @default 'script' */
    sourceType?: 'script' | 'module';
    /**
     * Parse TypeScript. `'erase'` parses it and emits JavaScript: annotations, type-only
     * declarations and imports go, assertions give way to their expression, and what erasure
     * cannot express (enums, namespaces with values, parameter properties, `export =`, `import =`)
     * stays in the tree and is listed as `typescript` on the answer, as are the proposals
     * JavaScript itself has: decorators and accessor fields (`AccessorProperty`).
     */
    typescript?: boolean | 'erase';
    /** Attach `leadingComments`, `trailingComments` and `innerComments` to nodes, and list every comment read as `comments` on the answer. */
    comments?: boolean;
    /**
     * Scope analysis: the answer lists `scopes`, `bindings` and `references`, and `scopeOf` and
     * `referenceOf` answer for a node. The tree itself carries nothing, and a copy of a node
     * carries no facts. TypeScript type positions bind nothing.
     */
    scopes?: boolean;
    /**
     * Add `loc` with line and column to every node. `'js'` adds it to the JavaScript nodes and
     * comments only: a host's own nodes, a stylesheet's included, keep `start` and `end`.
     * @default false
     */
    locations?: boolean | 'js';
    /** Mark a node the source wraps in parens with `parenthesized: true`, absent otherwise. */
    parenthesized?: boolean;
    allowReturnOutsideFunction?: boolean;
    allowAwaitOutsideFunction?: boolean;
    allowSuperOutsideMethod?: boolean;
    allowUndeclaredExports?: boolean;
    /**
     * List syntax errors on the answer as `errors` instead of throwing the first: a missing
     * operand, name or pattern is an `Identifier` named `''` of no width where it was expected,
     * and a statement or entry that cannot be read is skipped to the next stop token or
     * unmatched closing bracket, an empty identifier standing for it. Placeholders are neither
     * bindings nor references.
     */
    errorRecovery?: boolean;
}

parentOf

The node node is a child of; undefined for the root of an answer and for a comment listed in comments. A literal's regex and a template element's value are not nodes and have none.

export declare function parentOf(node: Node | HostNode | Comment | null | undefined): Node | HostNode | undefined;

scopeOf

With scopes: the scope node opens, when it opens one.

export declare function scopeOf(node: Node | HostNode | null | undefined): Scope | undefined;

referenceOf

With scopes: the reference an identifier makes, the binding itself for the identifier that declares it; a global's too, which no binding lists. Undefined when the identifier names no value, a property key say.

export declare function referenceOf(node: Node | null | undefined): Reference | undefined;

Piece

One piece of JavaScript read at a position of the source, as far as it goes; until ends it where the host's own tokens follow. A piece is built once and read at any position of any source. T is what its parse answers with.

export declare class Piece<T> {
    #private;
    private constructor();
    /**
     * The same piece, ended where one of the host's own tokens, words or punctuators, follows.
     * One read outside every bracket the parse opened, where the expression could end, ends it:
     * `,` ends an expression before a sequence would, and `/>` is never a division. A `then`
     * after `.` is a property name. A TypeScript `as` is the host's unless another `as` follows
     * the assertion, so `xs as T[] as item` ends after the type.
     */
    until(...tokens: string[]): Piece<T>;
}

js

JavaScript: a parse of it reads the whole source, or the program inside [start, end]. Its members read one piece.

export declare const js: Language<Program> & {
    readonly expression: Piece<Expression>;
    /** An assignment target: an identifier or a destructuring pattern. */
    readonly pattern: Piece<Pattern>;
    /** A parenthesized parameter list, as an arrow function's is read. */
    readonly params: Piece<Pattern[]>;
    readonly statement: Piece<Statement>;
    /** A `TSTypeParameterDeclaration`; TypeScript only, `not_typescript` otherwise. */
    readonly typeParameters: Piece<Node>;
    /** The fields TypeScript may add to a node of any type, holding nodes: annotations, type parameters and arguments, what a class implements, decorators. */
    readonly extras: readonly string[];
};

css

CSS: a parse of it reads the whole source as a stylesheet, a StyleSheet of rules and at-rules with its comments listed.

export declare const css: Language<HostNode>;

Source

A source kept with its options; a parse keeps nothing of it in the engine. Offsets are UTF-16; positions stay those of the whole source. A lone surrogate in the text reaches the parser as U+FFFD, the way TextEncoder encodes it, so string values, template cooked and raw text and regex patterns carry U+FFFD there while spans and loc are right.

export declare class Source {
    #private;
    constructor(source: string, options?: Options);
    /**
     * What `what` answers with: `js` by default, the whole source as a program. A piece of
     * JavaScript is read at `at`, a UTF-16 offset, or at `[start, end]` as if the source ended at
     * `end`; `js` takes the same for the program inside a range. `css` reads the whole source as a
     * stylesheet. A grammar from
     * `@teasel/parser/grammar` reads the whole source as a document of its host language: the
     * host's own nodes around the JavaScript ones, in one tree, in TypeScript when the grammar
     * says so of a script tag. The engine read the grammar when it was made.
     */
    parse(): Parsed<Program>;
    parse<T>(piece: Piece<T>, at?: number | [start: number, end: number]): Parsed<T>;
    parse(language: typeof js, at?: number | [start: number, end: number]): Parsed<Program>;
    parse<T>(what: Piece<T> | typeof js, at?: number | [start: number, end: number]): Parsed<T | Program>;
    parse<T>(language: Language<T>): Parsed<T>;
}

Scope

A scope, as one of scopes on the answer.

export interface Scope {
    kind: 'module' | 'script' | 'function' | 'function-name' | 'class' | 'block' | 'catch' | 'for' | 'switch' | 'static-block' | 'with' | 'namespace' | 'enum' | 'fragment';
    /** The node that opens it; null for a function-name scope and for the scope around a parameter list parsed on its own. */
    node: Node | HostNode | null;
    parent: Scope | null;
    /** An `await` or `for await` runs directly in it, no function around; only a program or fragment scope can say so. */
    topLevelAwait: boolean;
}

Binding

A binding, as one of bindings on the answer: one an identifier declares, or the arguments a function reads.

export type Binding = Declared | Arguments;

Declared

A binding an identifier declares. It is the reference that identifier makes, the first of its own: referenceOf answers with it, and its binding is itself.

export interface Declared extends Reference {
    name: string;
    /**
     * What declared it. `function-name` and `class-name` are the name a function expression or a class
     * expression has inside itself, `const f = function g() {}` declaring `g`. `pattern` is a name that
     * a `js.pattern` piece declares, parsed on its own; a `js.params` piece declares `param`s.
     */
    kind: 'var' | 'let' | 'const' | 'using' | 'await using' | 'function' | 'class' | 'param' | 'catch' | 'import' | 'function-name' | 'class-name' | 'enum' | 'enum-member' | 'namespace' | 'pattern';
    /** The identifier that declares it. */
    node: Identifier;
    /** The scope it is declared in. */
    scope: Scope;
    /** What declares it: the declarator, function, class, import specifier, catch clause or enum, as eslint-scope's definition node; null for a pattern or parameter list parsed on its own. */
    declaration: Node | null;
    binding: Declared;
    declares: true;
    /** The declaration binds a value: an initializer, a parameter, a function, a class, an import; not a bare `let x;`. */
    write: boolean;
    read: false;
    mutate: false;
    /** The initializer of a declarator, `1` in `let x = 1`; null otherwise, the iterated expression of a `for-of` and a parameter's default being on the tree. */
    writeExpr: Expression | null;
}

Arguments

The arguments of a function that reads it: bound by the call, declared by no identifier.

export interface Arguments {
    name: 'arguments';
    kind: 'arguments';
    scope: Scope;
    node: null;
    declaration: null;
    binding: Arguments;
    declares: true;
    write: true;
    read: false;
    mutate: false;
    writeExpr: null;
}

Root

A piece of JavaScript a host read on its own, as one of roots on a document's answer, with what the tables hold for it.

export interface Root {
    node: Node;
    /** The scope the piece sits in. */
    scope: Scope;
    /** The scopes opened inside it, the bindings declared and the references made there. */
    scopes: Scope[];
    bindings: Binding[];
    references: Reference[];
}

Reference

A reference, as one of references on the answer: an identifier using a name, or declaring it again. A binding is one too, the reference its declaring identifier makes.

export interface Reference {
    node: Identifier;
    /** The scope the reference is made from. */
    scope: Scope;
    /** Null for a global. */
    binding: Binding | null;
    /** The identifier is assigned to, updated or bound by a destructuring assignment. */
    write: boolean;
    /** A member of the identifier's value is assigned to, updated or deleted. */
    mutate: boolean;
    /** The identifier's value is read: every reference but a declaration, a plain assignment's target or a destructuring one's; a compound assignment or an update reads and writes. */
    read: boolean;
    /** What a write assigns: the right side of the assignment, the iterated expression of a `for-in` or `for-of`, or what a declaration is initialized with, as eslint-scope's `writeExpr`; null for an update. */
    writeExpr: Expression | null;
    /** The identifier declares its binding: the binding itself for the first declaration, and a reference of its own for a name declared again, `var x` twice, which writes when a value is bound there. */
    declares: boolean;
}

Span

A range of the source, with loc when locations is on.

export interface Span {
    start: number;
    end: number;
    loc?: SourceLocation;
}

Comment

export interface Comment extends Span {
    type: 'Line' | 'Block';
    value: string;
}

Kept

A node erasure left in place, by type.

export interface Kept extends Span {
    type: string;
}

Recovered

A syntax error, as errors lists it. A parse that cannot answer throws the first as a SyntaxError with these fields, its message the code then each argument in quotes, expected '}'.

export interface Recovered {
    /** What went wrong, for a host to branch on; what each code means is at Error codes. */
    code: Code;
    /** What the error is about, a name or a token, when the code takes any. */
    args: readonly string[];
    /** The start of the token the parser could not accept; for `unexpected_eof`, the end of what was parsed. */
    pos: number;
    /** The end of that token, or `pos` when the cause is elsewhere, an earlier declaration say. */
    end: number;
    /** 1-based line and 0-based column of `pos`; a thrown `invalid_request` for a bad offset and a thrown `nesting_depth` for a tree too deep for the stack have neither. */
    line: number;
    column: number;
}

Language

What a parse reads as a whole and up to the end it is given: JavaScript, or a host language by its grammar. T is what its parse answers with.

export interface Language<T> {
    /** For every type of node a parse of the language answers with, the fields that hold a node or a list of nodes: what a walk follows. A grammar's names the JavaScript types beside the host's. */
    readonly children: Readonly<Record<string, readonly string[]>>;
}

Parsed

What a parse returns: the node, or the patterns of a parameter list, and what the options add; a key is there exactly when its option is on.

export interface Parsed<T> {
    node: T;
    /** The offset after everything the parse consumed: the node, its closing parens and the comments after it; a program's is the end it was given. */
    end: number;
    /** Every comment read, in source order; with `comments`. */
    comments?: Comment[];
    /** What erasure left in place; with `typescript: 'erase'`. */
    typescript?: Kept[];
    /** The errors recovered from, in source order; with `errorRecovery`. */
    errors?: Recovered[];
    /** With `scopes`. */
    scopes?: Scope[];
    bindings?: Binding[];
    references?: Reference[];
    /** With `scopes`, for a document read by a host grammar: its pieces of JavaScript in source order. */
    roots?: Root[];
}

HostNode

A node of a host language, as its grammar names the type and the fields; the JavaScript under it is ESTree. The node a grammar wraps children in has no span.

export interface HostNode extends Partial<Span> {
    type: string;
    [field: string]: unknown;
}

Code

What a parse error names in code; what each means is at Error codes.

export type Code = (typeof CODES)[number];