244 lines
4.6 KiB
TypeScript
244 lines
4.6 KiB
TypeScript
export type TokenType =
|
|
| "tag"
|
|
| "text"
|
|
| "code"
|
|
| "out"
|
|
| "comment"
|
|
| "doctype"
|
|
| "keyword"
|
|
| "frontmatter"
|
|
| "test"
|
|
| "rawtext";
|
|
|
|
export interface RawAttribute {
|
|
name: string;
|
|
value?: string;
|
|
kind: "string" | "expression" | "boolean";
|
|
}
|
|
|
|
/** A single line of a template, already split into its semantic parts. */
|
|
export interface Token {
|
|
type: TokenType;
|
|
/** Indentation width, used to build the tree. */
|
|
indent: number;
|
|
/** Line number in the source file, used for error messages. */
|
|
line: number;
|
|
/** Raw text of the line. */
|
|
value: string;
|
|
/** Tag name, only for `tag` tokens. */
|
|
name?: string;
|
|
/** Attributes, only for `tag` tokens. */
|
|
attributes?: RawAttribute[];
|
|
/** Inline text following the tag, only for `tag` tokens. */
|
|
text?: string;
|
|
/** Buffered expression of the tag, e.g. `p= title`. */
|
|
output?: string;
|
|
/** Keyword name, only for `keyword` tokens. */
|
|
keyword?: string;
|
|
/** Keyword payload (`each item in items`), only for `keyword` tokens. */
|
|
keywordValue?: string;
|
|
/** Whether the tag is followed by a block of raw text (`p.`). */
|
|
blockText?: boolean;
|
|
/** A generated relation identity declared with `tag@name()` in SPUG. */
|
|
anchor?: { name: string; expression?: string };
|
|
/** Whether a comment is silent (`//-`). */
|
|
silent?: boolean;
|
|
/** Whether an output expression is escaped (`=` vs `!=`). */
|
|
escaped?: boolean;
|
|
}
|
|
|
|
export type TextPart =
|
|
| { type: "literal"; value: string }
|
|
| { type: "expression"; code: string; escaped: boolean };
|
|
|
|
export interface PropDeclaration {
|
|
name: string;
|
|
/** Type expression as written in the template. */
|
|
type: string;
|
|
optional: boolean;
|
|
/** Default value expression, when declared with `=`. */
|
|
defaultValue?: string;
|
|
}
|
|
|
|
export interface ElementNode {
|
|
kind: "element";
|
|
name: string;
|
|
attributes: RawAttribute[];
|
|
children: Node[];
|
|
selfClosing: boolean;
|
|
/** A generated relation identity declared with `tag@name()` in SPUG. */
|
|
anchor?: { name: string; expression?: string };
|
|
}
|
|
|
|
export interface TextNode {
|
|
kind: "text";
|
|
parts: TextPart[];
|
|
}
|
|
|
|
export interface RawTextNode {
|
|
kind: "rawtext";
|
|
value: string;
|
|
}
|
|
|
|
export interface CodeNode {
|
|
kind: "code";
|
|
code: string;
|
|
}
|
|
|
|
export interface OutNode {
|
|
kind: "out";
|
|
code: string;
|
|
escaped: boolean;
|
|
}
|
|
|
|
export interface CommentNode {
|
|
kind: "comment";
|
|
value: string;
|
|
silent: boolean;
|
|
children: Node[];
|
|
}
|
|
|
|
export interface DoctypeNode {
|
|
kind: "doctype";
|
|
value: string;
|
|
}
|
|
|
|
export interface IfBranch {
|
|
/** `null` marks the `else` branch. */
|
|
test: string | null;
|
|
negate: boolean;
|
|
children: Node[];
|
|
}
|
|
|
|
export interface IfNode {
|
|
kind: "if";
|
|
branches: IfBranch[];
|
|
}
|
|
|
|
export interface EachNode {
|
|
kind: "each";
|
|
value: string;
|
|
key?: string;
|
|
list: string;
|
|
children: Node[];
|
|
}
|
|
|
|
export interface WhileNode {
|
|
kind: "while";
|
|
test: string;
|
|
children: Node[];
|
|
}
|
|
|
|
export interface CaseNode {
|
|
kind: "case";
|
|
subject: string;
|
|
cases: { test?: string; children: Node[] }[];
|
|
}
|
|
|
|
export interface MixinDefNode {
|
|
kind: "mixin";
|
|
name: string;
|
|
params: string;
|
|
children: Node[];
|
|
}
|
|
|
|
export interface MixinCallNode {
|
|
kind: "mixin-call";
|
|
name: string;
|
|
args: string;
|
|
children: Node[];
|
|
}
|
|
|
|
export interface IncludeNode {
|
|
kind: "include";
|
|
path: string;
|
|
/** Included file content, resolved by the linker. */
|
|
children: Node[];
|
|
}
|
|
|
|
export interface ExtendsNode {
|
|
kind: "extends";
|
|
path: string;
|
|
}
|
|
|
|
export interface BlockNode {
|
|
kind: "block";
|
|
name: string;
|
|
mode: "replace" | "append" | "prepend";
|
|
children: Node[];
|
|
}
|
|
|
|
export interface SlotNode {
|
|
kind: "slot";
|
|
name: string;
|
|
children: Node[];
|
|
}
|
|
|
|
export interface YieldNode {
|
|
kind: "yield";
|
|
name: string;
|
|
}
|
|
|
|
export interface PropsNode {
|
|
kind: "props";
|
|
props: PropDeclaration[];
|
|
}
|
|
|
|
export interface ComponentNode {
|
|
kind: "component" | "island";
|
|
name: string;
|
|
/** Prop name to expression. */
|
|
props: Record<string, string>;
|
|
/** Renderers that are applied inline by the component. */
|
|
renders: { name: string; children: Node[] }[];
|
|
}
|
|
|
|
/**
|
|
* A block of assertions.
|
|
*/
|
|
export interface TestNode {
|
|
kind: "test";
|
|
/** The assertions of the block. */
|
|
code: string;
|
|
}
|
|
|
|
/**
|
|
* A renderer that is applied inline.
|
|
*/
|
|
export interface RenderNode {
|
|
kind: "render";
|
|
/** Name of the prop the renderer is handed to. */
|
|
name: string;
|
|
children: Node[];
|
|
}
|
|
|
|
export interface PortalNode {
|
|
kind: "portal";
|
|
name: string;
|
|
children: Node[];
|
|
}
|
|
|
|
export type Node =
|
|
| ElementNode
|
|
| TextNode
|
|
| RawTextNode
|
|
| CodeNode
|
|
| OutNode
|
|
| CommentNode
|
|
| DoctypeNode
|
|
| IfNode
|
|
| EachNode
|
|
| WhileNode
|
|
| CaseNode
|
|
| MixinDefNode
|
|
| MixinCallNode
|
|
| IncludeNode
|
|
| ExtendsNode
|
|
| BlockNode
|
|
| SlotNode
|
|
| YieldNode
|
|
| PropsNode
|
|
| ComponentNode
|
|
| TestNode
|
|
| RenderNode
|
|
| PortalNode;
|