> ## Documentation Index
> Fetch the complete documentation index at: https://narrator.ami.rip/llms.txt
> Use this file to discover all available pages before exploring further.

# TsPlugin

> The type every TypeScript and JavaScript plugin implements.

```ts theme={null}
import { definePlugin, type TsPlugin } from "@usenarrator/lang-ts";
```

```ts theme={null}
type TsPlugin<P = any> = {
  name: string;
  phrases?: Phrasebooks<P>;
  library?: { name: string; versions: string };
  vocabulary?: Vocabulary;
  ambient?: string[];
  errors?: string[] | RegExp;
  errorLabels?: Record<string, string>;
  constants?: Record<string, string>;
  calls?: Record<string, CallRule<P>>;
  conditions?: Record<string, CondRule<P>>;
  members?: Record<string, MemberRule<P>>;
  jsx?: JsxRule<P>;
  statements?: StmtRule<P>[];
  describeSchema?: (e: Engine, n: N, say: P) => string | null;
};
```

`P` is the type of the plugin's phrasebook. Use `definePlugin(plugin)` to have it inferred from `phrases.en`.

## Fields

<ParamField path="name" type="string" required>
  A unique name. Locales override this plugin's phrases under `locale.plugins[name]`.
</ParamField>

<ParamField path="phrases" type="{ en: P } & { [locale: string]: P }">
  Phrasebooks keyed by locale id. `en` is required. A phrasebook may also include `glossary`, `constants` and `errorLabels`, which the engine merges over the plugin's own fields.
</ParamField>

<ParamField path="library" type="{ name: string; versions: string }">
  The npm package this plugin reads and the semver range it was written against. The engine doesn't enforce it; guard rules with `e.usesLibrary` and pick readings with `e.libraryMajor`. See [Plugin versioning](/guides/plugin-versioning). With `library` set, call and condition rules also match the library's exports when they're imported under another name or through a namespace. See [Imports under another name](/guides/writing-a-plugin#imports-under-another-name).
</ParamField>

<ParamField path="vocabulary" type="Vocabulary">
  Glossary entries, acronyms, verbs and predicate prefixes used to read identifiers.
</ParamField>

<ParamField path="ambient" type="string[]">
  Identifiers that are plumbing, dropped from argument lists and member chains. The built-in `std` plugin marks `ctx` as ambient.
</ParamField>

<ParamField path="errors" type="string[] | RegExp">
  Constructor names whose instances are errors. The built-in `std` plugin uses `/Error$/`.
</ParamField>

<ParamField path="errorLabels" type="Record<string, string>">
  How to name an error class when it's thrown.
</ParamField>

<ParamField path="constants" type="Record<string, string>">
  Exact source text mapped to a phrase.
</ParamField>

<ParamField path="calls" type="Record<string, CallRule<P>>">
  Call rules keyed by callee. See [rule keys](/guides/writing-a-plugin#rule-keys) and the [key grammar](/guides/writing-a-plugin#key-grammar). A key no code can match is reported with `console.warn` when the plugin loads.
</ParamField>

<ParamField path="conditions" type="Record<string, CondRule<P>>">
  Condition rules, used when a call appears where a yes or no answer is expected.
</ParamField>

<ParamField path="members" type="Record<string, MemberRule<P>>">
  Property-read rules keyed by `Obj.prop`, `*.owner.prop`, `*.prop`, `Obj.*` or `*.owner.*`, tried in that order. See [member rules](/guides/writing-a-plugin#member-rules-and-jsx).
</ParamField>

<ParamField path="jsx" type="JsxRule<P>">
  Reads a JSX element or fragment wherever the engine meets one. Later plugins' rules are tried first.
</ParamField>

<ParamField path="statements" type="StmtRule<P>[]">
  Rules that can take over a whole statement. Each returns `true` once it has emitted lines, or `false`.
</ParamField>

<ParamField path="describeSchema" type="(e, n, say) => string | null">
  Describes a schema-builder expression as a type, or returns `null` if the node isn't one.
</ParamField>

## Rules

```ts theme={null}
type RuleResult = Doc | string | null | undefined;

type CallRule<P> = (ctx: { node: N; args: N[]; obj: N | null; e: Engine; stmt: boolean; say: P }) => RuleResult;
type CondRule<P> = (ctx: { node: N; args: N[]; obj: N | null; e: Engine; neg: boolean; say: P }) => RuleResult;
type StmtRule<P> = (ctx: { node: N; e: Engine; d: number; say: P }) => boolean;
type MemberRule<P> = (ctx: { node: N; obj: N; prop: string; e: Engine; say: P }) => RuleResult;
type JsxRule<P> = (ctx: { node: N; e: Engine; say: P }) => RuleResult;
```

<ResponseField name="node" type="N">
  The call expression, member expression, JSX element or statement. `N` is an ESTree node from oxc. For tagged template keys, it is the tagged template and `args[0]` is its template literal.
</ResponseField>

<ResponseField name="args" type="N[]">
  The call's arguments.
</ResponseField>

<ResponseField name="obj" type="N | null">
  The receiver for `Obj.method` and `*.method` keys, otherwise `null`. For member rules, the object whose property is read.
</ResponseField>

<ResponseField name="prop" type="string">
  For member rules, the property name.
</ResponseField>

<ResponseField name="stmt" type="boolean">
  `true` when the call is a statement on its own, so it should read as an action ("Send the receipt") rather than a noun ("the receipt that was sent").
</ResponseField>

<ResponseField name="neg" type="boolean">
  For condition rules, `true` when the condition is negated.
</ResponseField>

<ResponseField name="d" type="number">
  For statement rules, the indent depth to emit lines at. Return `true` once you've emitted lines, or `false` to let the engine handle the statement.
</ResponseField>

<ResponseField name="say" type="P">
  This plugin's phrasebook for the active locale.
</ResponseField>

Return `null` or `undefined` to let the next rule try. A string result is treated as a `Doc` with no block lines.

A rule that throws, or returns anything else, is treated as if it returned `null` (or `false` for a statement rule), and any lines it emitted are removed. The failure is recorded in the narration's `stats.ruleErrors` as `{ plugin, rule, message, count }`, where `rule` reads like `calls["*.plus"]`, `statements[0]`, `jsx` or `describeSchema`. See [When a rule fails](/guides/writing-a-plugin#when-a-rule-fails).

## Other exports

| Export | Description |
| - | - |
| `definePlugin(p)` | Identity function that infers `P`. |
| `ImportInfo` | `{ from: string; name: string }`, the value type of `e.imports`. |
| `unwrap(n)` | Strips parentheses, TypeScript casts and assertions, optional chains and `await` from a node. |
| `std`, `stdEn` | The built-in plugin for JavaScript itself and its English phrasebook. |
| `typescript(options)` | The TypeScript source language. See the [Engine reference](/reference/engine). |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.