teasel
Search
Search the documentation

@teasel/parser/grammar

Every export of the grammar builders, as their declarations say. A grammar crosses to the engine as JSON.stringify({ name, definition }), which is also what the Rust crate's parse_document and the command line's --host read.

Site

Where a source may be read: a form, a block's body, a directive's attribute value, the document, an element, a this attribute, a text or comment node, the fragment node, a directive's name, a literal.

export type Site = 'form' | 'body' | 'value' | 'document' | 'element' | 'this' | 'text' | 'fragment' | 'directive' | 'literal';

Source

What fills a field: T is what a parse puts there, S where it may be read.

export interface Source<T = unknown, S extends Site = Site, M extends Mods = Plain> {
    readonly from: string;
    readonly read: string;
    readonly optional: M['optional'];
    readonly bind: M['bind'];
    readonly orArg: M['orArg'];
    readonly [out]?: {
        readonly t: T;
        readonly m: M;
        readonly s: (site: S) => void;
    };
}

Children

A node's children: the grammar's fragment node when it has one, else the list.

export interface Children {
    readonly [children]: true;
}

js

JavaScript read at a position of a form.

export declare const js: {
    expression: Source<Expression, "form", Plain>;
    pattern: Source<Pattern, "form", Plain>;
    params: Source<Pattern[], "form", Plain>;
    identifier: Source<Identifier, "form", Plain>;
    identifiers: Source<Identifier[], "form", Plain>;
    statement: Source<Statement, "form", Plain>;
    const: Source<VariableDeclaration, "form", Plain>;
    /** An expression, or its statements as a program when it is not one. */
    code: Source<Program | Expression, "form", Plain>;
    /** The type parameters' text, without the angle brackets. */
    typeParameters: Source<string, "form", Plain>;
    /** The text up to the tag's end word, unread. */
    text: Source<string, "form", Plain>;
};

value

A directive's attribute value.

export declare const value: {
    expression: Source<Expression, "value", Plain>;
    pattern: Source<Pattern, "value", Plain>;
    /** The value as written: text and expressions. */
    raw: Source<Written, "value", Plain>;
};

doc

What the document holds.

export declare const doc: {
    script: Source<Script, "document", With<Plain, "missing", true>>;
    module: Source<Script, "document", With<Plain, "missing", true>>;
    style: Source<HostNode, "document", With<Plain, "missing", true>>;
    comments: Source<Comment[], "document", Plain>;
};

text

A text or comment node's text: as read, and as written.

export declare const text: {
    data: Source<string, "text", Plain>;
    raw: Source<string, "text", Plain>;
};

content

Where the host's content goes: a block's body, an element's children, the document's.

export declare const content: Source<Children, "body" | "document" | "element", Plain>;

nodes

The fragment node's own list.

export declare const nodes: Source<Nodes, "fragment", Plain>;

literal

A value the site always writes.

export declare const literal: <const T extends boolean | null | readonly []>(v: T) => Source<T, 'literal'>;

optional

The field is left out when nothing was read into it. The only way a field is absent.

export declare const optional: <T, S extends Exclude<Site, 'value'>, M extends Mods>(s: Source<T, S, M>) => Source<T, S, With<M, 'optional', true>>;

bind

What the field reads declares names in the scope its site opens.

export declare const bind: (<T extends Bindable, S extends 'form' | 'value', M extends Mods>(s: Source<T, S, M>) => Source<T, S, With<M, 'bind', 'inside'>>) & {
    /** In the scope around the block instead: a snippet's name. */
    outside: <T extends Bindable, M extends Mods>(s: Source<T, 'form', M>) => Source<T, 'form', With<M, 'bind', 'outside'>>;
};

orArg

Without a value, the directive's argument is the value: bind:value.

export declare const orArg: <T, M extends Mods>(s: Source<T, 'value', M>) => Source<T, 'value', With<M, 'orArg', true>>;

Fields

Fields a form reads, each named once, where its source is.

export type Fields<F = Source<any, any, any>> = {
    readonly [field: string]: F;
} & {
    readonly [K in Reserved]?: never;
};

Item

One step of a form: a host word or punctuator, fields, or a group.

export type Item = string | Fields | Opt<readonly Item[]> | OneOf<readonly (readonly Item[])[]> | Scope<readonly Item[]>;

Opt

export interface Opt<I extends readonly unknown[]> {
    readonly opt: I;
}

OneOf

export interface OneOf<A extends readonly (readonly unknown[])[]> {
    readonly oneOf: A;
}

Scope

The document's or fragment's fields whose names the fields inside see.

export interface Scope<I extends readonly unknown[]> {
    readonly scope: I;
}

Form

A form whose fields read what F allows.

export type Form<F> = readonly (string | Fields<F> | Opt<Form<F>> | OneOf<readonly Form<F>[]>)[];

seq

A sequence kept for reuse in several forms.

export declare const seq: <const I extends readonly Item[]>(...items: I) => I;

opt

[ … ]: read when its first word or reader is there.

export declare const opt: <const I extends readonly [Item, ...Item[]]>(...items: I) => Opt<I>;

oneOf

{ a | b }: exactly one, chosen by how it starts; wrap in opt for at most one.

export declare const oneOf: <const A extends readonly [readonly [Item, ...Item[]], ...(readonly [Item, ...Item[]])[]]>(...alternatives: A) => OneOf<A>;

scope

export declare const scope: <const I extends readonly Item[]>(...items: I) => Scope<I>;

Node

A node type and the form its fields come from.

export interface Node<T extends string = string, I extends readonly Item[] = readonly Item[]> {
    readonly node: T;
    readonly form?: I;
}

Place

Where a construct may stand: in content, in an attribute value, among an element's attributes, in the text of an rcdata element.

export type Place = 'content' | 'value' | 'attributes' | 'rcdata';

Piece

A marker and what its form reads after it: a construct's open, a branch, or its close.

export interface Piece<I extends BlockForm = BlockForm> {
    /**
     * Parts that whitespace and comments may stand between; a part is matched as written. A marker
     * that stops partway is another word, `{.5}` no `{...}`, unless it stops after a part's leading
     * punctuation or a whole part: `{#eac` is an error.
     */
    readonly marker: readonly [string, ...string[]];
    /** Whitespace must follow the marker. */
    readonly space?: boolean;
    readonly form: I;
}

Branch

export interface Branch<I extends BlockForm = BlockForm> extends Piece<I> {
    /** The branch opens the construct again inside this field, with this flag true on the one it opens. */
    readonly reopen?: readonly [field: string, flag: string];
}

Tag

A construct without a close: it reads no content and opens no scope.

export interface Tag {
    /** Content when left out. */
    readonly in?: readonly Place[];
    readonly open: Piece<TagForm>;
    readonly branches?: undefined;
    readonly close?: undefined;
}

Block

A construct with a close: its open, and every branch, ends in content.

export interface Block {
    /** Content when left out. */
    readonly in?: readonly Place[];
    readonly open: Piece;
    readonly branches?: readonly Branch[];
    /** Words only: what ends the block. */
    readonly close: Piece<readonly string[]>;
}

Construct

A tag or a block; the type of the node it makes is the key it is written under.

export type Construct = Tag | Block;

Directive

export interface Directive<T extends string = string> extends Node<T, DirectiveForm> {
    readonly unique?: 'kind' | 'attributes';
}

directive

What a directive's attribute name holds.

export declare const directive: {
    kind: Source<string, "directive", Plain>;
    /** The argument; an expression when the directive syntax brackets a dynamic one. */
    arg: Source<string | Expression | null, "directive", Plain>;
    modifiers: Source<string[], "directive", Plain>;
    raw: Source<string, "directive", Plain>;
};

Element

export interface Element<T extends string = string> extends Node<T, Form<Field<'this'>>> {
    readonly root?: true;
    readonly once?: true;
    /** Only inside the element this names. */
    readonly inside?: string;
    readonly outside?: string;
    readonly content?: 'raw' | 'rcdata';
}

element

What an element's tag holds.

export declare const element: {
    tag: Source<string, "element", Plain>;
    attributes: Source<Attributes, "element", Plain>;
    /** The expression of a `this` attribute, which leaves the attributes. */
    this: Source<Expression, "this", Plain>;
    /** The same, a text value read as a string literal. */
    thisOrText: Source<Expression, "this", Plain>;
};

Definition

A host language: its document, its content, and the JavaScript inside them.

export interface Definition {
    readonly document: Node<string, Scoped<Field<'document'> | Source<null | readonly [], 'literal', any>>>;
    readonly text: Node<string, Scoped<Always<'text'>>>;
    readonly comment: Node<string, Scoped<Always<'text'>>>;
    readonly fragment?: Node<string, Scoped<Always<'fragment'>>>;
    /** `{name}` among the attributes is `name={name}`: the marker and the word around the name. */
    readonly attributes?: {
        readonly shorthand?: readonly [open: string, close: string];
    };
    readonly autoclose?: true;
    readonly trim?: true;
    readonly void?: readonly string[];
    readonly verbatim?: string;
    readonly elements: {
        readonly fields: Fields<Always<'element'>>;
        readonly rules?: {
            readonly [name: string]: Element;
        };
        readonly component?: Element;
        readonly other?: Element;
    };
    readonly script?: {
        readonly element: string;
        readonly module?: readonly Marker[];
        readonly typescript?: readonly Marker[];
    };
    readonly style?: string;
    readonly directives?: {
        readonly prefix?: string;
        readonly arg?: string;
        readonly modifier?: string;
        readonly dynamic?: readonly [open: string, close: string];
        readonly unique?: 'raw';
        readonly fields: Fields<Always<'directive'>>;
        readonly shorthands?: {
            readonly [token: string]: readonly [name: string, ...modifiers: string[]];
        };
        readonly rules?: {
            readonly [name: string]: Directive;
        };
        readonly other?: Directive;
    };
    /** By the type of the node each makes. */
    readonly constructs?: {
        readonly [type: string]: Construct;
    };
}

Grammar

export interface Grammar<D extends Definition = Definition> extends Language<NodeOf<D['document'], D>> {
    readonly host: string;
    readonly definition: D;
}

grammar

export declare const grammar: <const D extends Definition>(host: string, definition: D) => Grammar<D>;

Content

What a host's content can hold; an rcdata element's, what stands in rcdata.

export type Content<G extends Definition> = ElementNode<Values<G['elements']['rules']> | G['elements']['component'] | G['elements']['other'], G> | NodeOf<G['text'], G> | NodeOf<G['comment'], G> | Constructs<G, 'content'> | Constructs<G, 'rcdata'>;

Attribute

What an element's attributes can hold.

export type Attribute<G extends Definition> = AttributeNode<G> | DirectiveNode<Values<NonNullable<G['directives']>['rules']> | NonNullable<G['directives']>['other'], G> | Constructs<G, 'attributes'>;

Infer

The tree a grammar's parse answers with.

export type Infer<Gr extends Grammar> = Gr extends Grammar<infer G> ? NodeOf<G['document'], G> : never;

NodeType

A node type of the grammar, by name.

export type NodeType<Gr extends Grammar, T extends string> = Gr extends Grammar<infer G> ? Extract<Content<G> | Attribute<G> | Constructs<G, 'value'> | FragmentNode<G> | ScriptNode<G>, {
    type: T;
}> : never;