/** * `parseman/language-service` — the external, grammar-agnostic IDE layer. * * A grammar is pure structure (it carries no recovery/completion/lint config). * `languageService(grammar, config)` layers editor behaviour ON TOP, keyed by rule * name = node type, without ever modifying the grammar: * * - `parse(src, { tolerant })` → CST + `ParseError[]` (recovers on the compiled * fast path when `grammar` is a `compile(g, { recovery: true })` grammar). * - `diagnostics(src)` → structural parse errors + your per-node-type lint rules. * - `completionsAt(src, offset)` → the grammar's expected-token set at the cursor, * mapped through your per-rule semantic completion handlers. * * The grammar can be the interpreter combinator OR a compiled grammar — the domain * knowledge (what to suggest after `color:`, which nodes to lint) lives here, in the * consumer's config, never in the grammar. */ import type { Combinator, ParseContext, ParseResult, Span, ParseError } from '../types.ts'; import type { Walkable } from '../cst/walk.ts'; import { type Registry } from '../functional/doc.ts'; import type { NodeLike } from '../cst/types.ts'; export type Severity = 'error' | 'warning' | 'info'; export type Diagnostic = { severity: Severity; message: string; span: Span; }; export type CompletionItem = { label: string; detail?: string; }; /** A CST node/leaf as a diagnostics handler sees it: the walk shape plus span/value. */ export type LsNode = Walkable & { readonly span: Span; readonly value?: string; }; /** Context handed to a completion handler: which rule the cursor sits in and the * grammar's raw expected-token labels there. */ export type CompletionContext = { rule: string | null; expected: string[]; offset: number; }; export type LanguageServiceConfig = { /** Lint/diagnostic rules keyed by node type (rule name). Return zero or more * Diagnostics for each matching node. */ diagnostics?: Record Diagnostic | Diagnostic[] | null | undefined | void>; /** Semantic completion handlers keyed by the rule the cursor is in. Turn the * grammar's structural expectation into domain suggestions. */ complete?: Record CompletionItem[]>; }; /** Grammar the service drives: an interpreter combinator or a compiled entry fn. */ type Grammar = Combinator | ((input: string, pos: number, ctx: ParseContext) => ParseResult); /** * What you hand `languageService`: * - a single entry (combinator or `compile()`d fn) — stateless methods only, or * - `{ rules, root }` (a `rules()` registry + its root rule name) — also unlocks * `openDocument`, the live incremental editor document. */ export type GrammarInput = Grammar | { rules: Registry; root: string; }; /** * A live incremental document — the fused editor backend. Holds a tolerant * `parseDoc` whose tree survives broken input (recovery) and re-parses only the * edited span on `edit()`. Diagnostics walk the maintained tree (recovered errors * ride inside it as `parseError` nodes), so they stay complete across edits without * re-parsing the whole document. */ export type LsDocument = { /** The current CST with ABSOLUTE spans (recovered errors embedded as parseError nodes). */ readonly tree: LsNode | null; /** Apply an editor change (byte offsets in the CURRENT text); returns the next document. */ edit(from: number, to: number, replacement: string): LsDocument; /** Structural parse errors (from the tree) + your per-node-type lint rules. */ diagnostics(): Diagnostic[]; /** Completions at a cursor offset in the current text. */ completionsAt(offset: number): CompletionItem[]; }; export type LanguageService = { parse(src: string, opts?: { tolerant?: boolean; }): ParseResult & { errors: ParseError[]; }; diagnostics(src: string): Diagnostic[]; completionsAt(src: string, offset: number): CompletionItem[]; /** Open a live incremental document. Requires `languageService({ rules, root }, …)`. */ openDocument(src: string): LsDocument; }; export declare function languageService(grammar: GrammarInput, config?: LanguageServiceConfig): LanguageService; export {}; //# sourceMappingURL=index.d.ts.map