@regmisatyam/retex 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +492 -0
- package/dist/index.cjs +3444 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +916 -0
- package/dist/index.d.ts +916 -0
- package/dist/index.js +3370 -0
- package/dist/index.js.map +1 -0
- package/dist/react-v8gyKEAs.d.cts +420 -0
- package/dist/react-v8gyKEAs.d.ts +420 -0
- package/dist/react.cjs +805 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +1 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.js +802 -0
- package/dist/react.js.map +1 -0
- package/package.json +85 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,916 @@
|
|
|
1
|
+
import { S as SourceRange, A as ArgumentNode, N as Node, C as CommandNode, T as Theme, D as DocumentNode, a as ContactNode, b as SectionNode, F as FieldMap, R as ReactRenderFn, P as PartialTheme, c as ReactRenderOptions } from './react-v8gyKEAs.cjs';
|
|
2
|
+
export { d as ColorNode, e as ColumnNode, f as ColumnsNode, g as ContactField, E as EducationNode, h as ErrorNode, i as FontFamilyNode, j as FontScale, k as FontScaleNode, l as FontSizeNode, G as GroupNode, I as IconNode, J as JobNode, m as JsxFactory, L as LineBreakNode, n as LinkNode, o as ListItemNode, p as ListKind, q as ListNode, M as MarkNode, r as MarkType, s as NodeBase, t as NodeMap, u as NodeType, v as ParBreakNode, w as ParentNode, x as Position, y as ProjectNode, z as ReactRenderContext, B as ReactRenderer, H as RuleNode, K as SkillsNode, O as SpaceNode, Q as TextNode, U as ThemeColorNode, V as ThemeColors, W as ThemeFontSizes, X as ThemeFonts, Y as ThemePage, Z as ThemeSpacing, _ as UrlNode, $ as isNode, a0 as isParent, a1 as mergeRanges, a2 as pos, a3 as range, a4 as rangeContains, a5 as renderReact } from './react-v8gyKEAs.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Token kinds produced by the {@link Tokenizer}.
|
|
6
|
+
*
|
|
7
|
+
* ReTeX intentionally diverges from TeX in a few places that matter for
|
|
8
|
+
* resumes:
|
|
9
|
+
* - `%` is a *literal* percent sign (so `Reduced latency by 40%` and
|
|
10
|
+
* `\column{40%}` work as written) rather than a comment marker.
|
|
11
|
+
* - Comments use `%%` to end-of-line, which never collides with percentages.
|
|
12
|
+
*/
|
|
13
|
+
declare enum TokenType {
|
|
14
|
+
/** A command such as `\section`, `\textbf`, `\item`. The lexeme excludes the backslash. */
|
|
15
|
+
Command = "Command",
|
|
16
|
+
/** `{` — begin group / argument. */
|
|
17
|
+
LBrace = "LBrace",
|
|
18
|
+
/** `}` — end group / argument. */
|
|
19
|
+
RBrace = "RBrace",
|
|
20
|
+
/** `[` — begin optional argument. */
|
|
21
|
+
LBracket = "LBracket",
|
|
22
|
+
/** `]` — end optional argument. */
|
|
23
|
+
RBracket = "RBracket",
|
|
24
|
+
/** Run of literal text. */
|
|
25
|
+
Text = "Text",
|
|
26
|
+
/** Run of inline whitespace (spaces/tabs, single newline). */
|
|
27
|
+
Whitespace = "Whitespace",
|
|
28
|
+
/** A blank line — paragraph break. */
|
|
29
|
+
ParBreak = "ParBreak",
|
|
30
|
+
/** `\\` — explicit line break. */
|
|
31
|
+
LineBreak = "LineBreak",
|
|
32
|
+
/** `%% ...` comment (stripped from output, surfaced to editor tooling). */
|
|
33
|
+
Comment = "Comment",
|
|
34
|
+
/** End of input. */
|
|
35
|
+
EOF = "EOF"
|
|
36
|
+
}
|
|
37
|
+
/** A lexical token with full source provenance. */
|
|
38
|
+
interface Token {
|
|
39
|
+
type: TokenType;
|
|
40
|
+
/** The exact source text of the token (backslash stripped for commands). */
|
|
41
|
+
value: string;
|
|
42
|
+
range: SourceRange;
|
|
43
|
+
}
|
|
44
|
+
/** Reserved single characters that the tokenizer treats specially. */
|
|
45
|
+
declare const SPECIAL_CHARS: Set<string>;
|
|
46
|
+
|
|
47
|
+
/** Severity levels, ordered the same way LSP orders them. */
|
|
48
|
+
declare enum DiagnosticSeverity {
|
|
49
|
+
Error = "error",
|
|
50
|
+
Warning = "warning",
|
|
51
|
+
Info = "info",
|
|
52
|
+
Hint = "hint"
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Stable, machine-readable diagnostic codes. Editors can key quick-fixes and
|
|
56
|
+
* documentation links off these rather than the (localizable) message text.
|
|
57
|
+
*/
|
|
58
|
+
declare enum DiagnosticCode {
|
|
59
|
+
UnexpectedToken = "RTX1001",
|
|
60
|
+
UnterminatedGroup = "RTX1002",
|
|
61
|
+
UnterminatedArgument = "RTX1003",
|
|
62
|
+
UnexpectedEOF = "RTX1004",
|
|
63
|
+
MismatchedBrace = "RTX1005",
|
|
64
|
+
UnknownCommand = "RTX2001",
|
|
65
|
+
UnknownEnvironment = "RTX2002",
|
|
66
|
+
MissingRequiredArgument = "RTX2003",
|
|
67
|
+
TooManyArguments = "RTX2004",
|
|
68
|
+
MissingEnvironmentEnd = "RTX2005",
|
|
69
|
+
MismatchedEnvironment = "RTX2006",
|
|
70
|
+
InvalidColor = "RTX3001",
|
|
71
|
+
InvalidUrl = "RTX3002",
|
|
72
|
+
InvalidDimension = "RTX3003",
|
|
73
|
+
MissingRequiredField = "RTX3004",
|
|
74
|
+
UnknownField = "RTX3005",
|
|
75
|
+
EmptyArgument = "RTX3006",
|
|
76
|
+
CommandOutsideContext = "RTX4001",
|
|
77
|
+
UnknownIcon = "RTX4002",
|
|
78
|
+
UnknownThemeColor = "RTX4003",
|
|
79
|
+
UnsafeUrlBlocked = "RTX5001"
|
|
80
|
+
}
|
|
81
|
+
/** Optional quick-fix an editor can apply. */
|
|
82
|
+
interface QuickFix {
|
|
83
|
+
title: string;
|
|
84
|
+
/** Replacement text for {@link Diagnostic.range}. */
|
|
85
|
+
replacement: string;
|
|
86
|
+
range?: SourceRange;
|
|
87
|
+
}
|
|
88
|
+
/** A single diagnostic emitted by any stage of the pipeline. */
|
|
89
|
+
interface Diagnostic {
|
|
90
|
+
severity: DiagnosticSeverity;
|
|
91
|
+
code: DiagnosticCode;
|
|
92
|
+
message: string;
|
|
93
|
+
range: SourceRange;
|
|
94
|
+
/** Stage that produced the diagnostic, for filtering. */
|
|
95
|
+
source: "tokenizer" | "parser" | "validator" | "security";
|
|
96
|
+
/** Optional editor quick-fixes. */
|
|
97
|
+
fixes?: QuickFix[];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* How a single argument should be consumed by the parser.
|
|
102
|
+
*
|
|
103
|
+
* - `content` — recursively parse markup (nested commands, text).
|
|
104
|
+
* - `string` — verbatim text; no command expansion (URLs, colors, sizes).
|
|
105
|
+
* - `keyval` — `key=value, key=value` map.
|
|
106
|
+
* - `list` — comma-separated list of trimmed strings.
|
|
107
|
+
*/
|
|
108
|
+
type ArgKind = "content" | "string" | "keyval" | "list";
|
|
109
|
+
interface ArgSpec {
|
|
110
|
+
kind: ArgKind;
|
|
111
|
+
/** When true the argument may be absent (no diagnostic if missing). */
|
|
112
|
+
optional?: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Delimiter pair. `"brace"` (default) → `{...}`; `"bracket"` → `[...]`.
|
|
115
|
+
* An optional brace argument (e.g. an entry body) is still written with
|
|
116
|
+
* `{...}` but may be omitted.
|
|
117
|
+
*/
|
|
118
|
+
delimiter?: "brace" | "bracket";
|
|
119
|
+
/** Human-readable name surfaced in hover docs / diagnostics. */
|
|
120
|
+
name?: string;
|
|
121
|
+
/** Validation hint for `string` args (drives format checks). */
|
|
122
|
+
format?: "color" | "url" | "dimension" | "text";
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Semantic category of a command. Drives default rendering and where the
|
|
126
|
+
* command is legal.
|
|
127
|
+
*
|
|
128
|
+
* - `inline` — flows within text (`\textbf`).
|
|
129
|
+
* - `block` — starts a block (`\section`, `\job`).
|
|
130
|
+
* - `switch` — a state switch that applies to the rest of its group
|
|
131
|
+
* (`\large`, `\bfseries`-style).
|
|
132
|
+
* - `meta` — document metadata that produces no inline flow on its own.
|
|
133
|
+
*/
|
|
134
|
+
type CommandCategory = "inline" | "block" | "switch" | "meta";
|
|
135
|
+
/**
|
|
136
|
+
* A factory the parser calls once arguments are consumed, to build the AST
|
|
137
|
+
* node for a command. Returning `null` drops the command from the tree.
|
|
138
|
+
*/
|
|
139
|
+
type NodeBuilder = (ctx: BuildContext) => Node | Node[] | null;
|
|
140
|
+
interface BuildContext {
|
|
141
|
+
name: string;
|
|
142
|
+
args: ArgumentNode[];
|
|
143
|
+
/** For switches: the trailing content the switch applies to. */
|
|
144
|
+
scope: Node[];
|
|
145
|
+
/** Emit a diagnostic from within a builder. */
|
|
146
|
+
report: (d: Omit<Diagnostic, "source">) => void;
|
|
147
|
+
/** Utilities exposed to plugin authors. */
|
|
148
|
+
utils: BuilderUtils;
|
|
149
|
+
}
|
|
150
|
+
interface BuilderUtils {
|
|
151
|
+
/** Flatten an argument's children into a plain string (best-effort). */
|
|
152
|
+
textOf(arg: ArgumentNode | undefined): string;
|
|
153
|
+
/** Sanitize a URL; returns `"#"` (and reports) when unsafe. */
|
|
154
|
+
safeUrl(url: string): string;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* The contract for a command. Used by the parser (argument signature, scope
|
|
158
|
+
* behavior) and the renderers (when no native node exists, renderers consult
|
|
159
|
+
* the command's per-target `render` map).
|
|
160
|
+
*/
|
|
161
|
+
interface CommandDefinition {
|
|
162
|
+
name: string;
|
|
163
|
+
category?: CommandCategory;
|
|
164
|
+
/** Argument signature, in order. */
|
|
165
|
+
args?: ArgSpec[];
|
|
166
|
+
/**
|
|
167
|
+
* `true` for switches that swallow the remainder of their enclosing group
|
|
168
|
+
* as scoped content (`\large`, `\itshape`).
|
|
169
|
+
*/
|
|
170
|
+
scoped?: boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Builds the AST node. When omitted, the parser emits a generic
|
|
173
|
+
* {@link CommandNode} carrying the parsed arguments.
|
|
174
|
+
*/
|
|
175
|
+
build?: NodeBuilder;
|
|
176
|
+
/** One-line summary for hover docs / completion detail. */
|
|
177
|
+
summary?: string;
|
|
178
|
+
/** Longer documentation (markdown) for hover. */
|
|
179
|
+
documentation?: string;
|
|
180
|
+
/** Example snippet shown in completion / hover. */
|
|
181
|
+
example?: string;
|
|
182
|
+
}
|
|
183
|
+
/** Environment (`\begin{x} … \end{x}`) contract. */
|
|
184
|
+
interface EnvironmentDefinition {
|
|
185
|
+
name: string;
|
|
186
|
+
/**
|
|
187
|
+
* Command that introduces each entry inside the environment, e.g. `item`
|
|
188
|
+
* for `itemize`, `column` for `columns`. The parser uses this to slice
|
|
189
|
+
* the body into entries.
|
|
190
|
+
*/
|
|
191
|
+
itemCommand?: string;
|
|
192
|
+
/** Commands legal as direct children (for validation). `*` allows any. */
|
|
193
|
+
allowedChildren?: string[];
|
|
194
|
+
/** Build the environment node from its parsed body. */
|
|
195
|
+
build?: (ctx: EnvBuildContext) => Node | Node[] | null;
|
|
196
|
+
summary?: string;
|
|
197
|
+
documentation?: string;
|
|
198
|
+
example?: string;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* One entry of an `itemCommand`-delimited environment. For `itemize`, the
|
|
202
|
+
* marker command is `\item`; for `columns`, it is `\column{width}`.
|
|
203
|
+
*/
|
|
204
|
+
interface EnvEntry {
|
|
205
|
+
/** The marker command that introduced the entry, with its parsed arguments. */
|
|
206
|
+
marker: CommandNode;
|
|
207
|
+
/** Content nodes belonging to this entry (up to the next marker / `\end`). */
|
|
208
|
+
content: Node[];
|
|
209
|
+
}
|
|
210
|
+
interface EnvBuildContext {
|
|
211
|
+
name: string;
|
|
212
|
+
/** Parsed body nodes of the environment (always present). */
|
|
213
|
+
body: Node[];
|
|
214
|
+
/**
|
|
215
|
+
* When the environment declares an `itemCommand`, the body sliced into
|
|
216
|
+
* entries at each marker. `undefined` for plain block environments.
|
|
217
|
+
*/
|
|
218
|
+
entries?: EnvEntry[];
|
|
219
|
+
/** Optional `[...]` arguments after `\begin{env}`. */
|
|
220
|
+
options: ArgumentNode[];
|
|
221
|
+
report: (d: Omit<Diagnostic, "source">) => void;
|
|
222
|
+
utils: BuilderUtils;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface TokenizeResult {
|
|
226
|
+
tokens: Token[];
|
|
227
|
+
diagnostics: Diagnostic[];
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Stage 1 of the pipeline. Converts raw ReTeX source into a flat token stream
|
|
231
|
+
* with exact source ranges. The tokenizer is deliberately permissive — it
|
|
232
|
+
* never throws — so the parser can perform error recovery downstream.
|
|
233
|
+
*
|
|
234
|
+
* Design notes specific to resumes:
|
|
235
|
+
* - `%` is a literal percent sign. Comments are `%%` to end-of-line.
|
|
236
|
+
* - Escapes (`\%`, `\&`, `\{`, `\_`, `\$`, `\#`, `\ `) become literal text.
|
|
237
|
+
* - `\\` is an explicit line break.
|
|
238
|
+
* - A whitespace run containing a blank line becomes a single `ParBreak`.
|
|
239
|
+
*/
|
|
240
|
+
declare class Tokenizer {
|
|
241
|
+
private readonly src;
|
|
242
|
+
private offset;
|
|
243
|
+
private line;
|
|
244
|
+
private column;
|
|
245
|
+
private readonly tokens;
|
|
246
|
+
private readonly diagnostics;
|
|
247
|
+
constructor(source: string);
|
|
248
|
+
static tokenize(source: string): TokenizeResult;
|
|
249
|
+
run(): TokenizeResult;
|
|
250
|
+
private scanToken;
|
|
251
|
+
private scanBackslash;
|
|
252
|
+
private scanComment;
|
|
253
|
+
private scanWhitespace;
|
|
254
|
+
private scanText;
|
|
255
|
+
private atEnd;
|
|
256
|
+
private peek;
|
|
257
|
+
private read;
|
|
258
|
+
private position;
|
|
259
|
+
private push;
|
|
260
|
+
}
|
|
261
|
+
/** Convenience wrapper. */
|
|
262
|
+
declare function tokenize(source: string): TokenizeResult;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* The command/environment registry. The parser consults it for argument
|
|
266
|
+
* signatures and node builders; the plugin system mutates it. A registry can
|
|
267
|
+
* be cloned cheaply so an engine instance never mutates shared global state.
|
|
268
|
+
*/
|
|
269
|
+
declare class CommandRegistry {
|
|
270
|
+
private commands;
|
|
271
|
+
private environments;
|
|
272
|
+
registerCommand(def: CommandDefinition): this;
|
|
273
|
+
registerEnvironment(def: EnvironmentDefinition): this;
|
|
274
|
+
getCommand(name: string): CommandDefinition | undefined;
|
|
275
|
+
getEnvironment(name: string): EnvironmentDefinition | undefined;
|
|
276
|
+
hasCommand(name: string): boolean;
|
|
277
|
+
hasEnvironment(name: string): boolean;
|
|
278
|
+
commandNames(): string[];
|
|
279
|
+
environmentNames(): string[];
|
|
280
|
+
allCommands(): CommandDefinition[];
|
|
281
|
+
allEnvironments(): EnvironmentDefinition[];
|
|
282
|
+
/** Shallow-clone the registry (definitions are shared, maps are copied). */
|
|
283
|
+
clone(): CommandRegistry;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Icon registry. Icons are stored as the inner markup of a `0 0 24 24` SVG and
|
|
288
|
+
* use `currentColor` so they inherit surrounding text color. The set is
|
|
289
|
+
* intentionally small and extensible via {@link registerIcon} / plugins.
|
|
290
|
+
*
|
|
291
|
+
* Glyphs are simplified, original representations (not vendor logo artwork) so
|
|
292
|
+
* the package carries no third-party asset licensing.
|
|
293
|
+
*/
|
|
294
|
+
interface IconDefinition {
|
|
295
|
+
/** Inner SVG markup (paths/shapes) with a `0 0 24 24` viewBox. */
|
|
296
|
+
body: string;
|
|
297
|
+
/** Whether shapes are stroked (true) or filled (false). */
|
|
298
|
+
stroked?: boolean;
|
|
299
|
+
/** Aliases that resolve to this icon. */
|
|
300
|
+
aliases?: string[];
|
|
301
|
+
}
|
|
302
|
+
/** Resolve a (possibly aliased) icon name to its canonical key. */
|
|
303
|
+
declare function resolveIconName(name: string): string | undefined;
|
|
304
|
+
declare function hasIcon(name: string): boolean;
|
|
305
|
+
declare function getIcon(name: string): IconDefinition | undefined;
|
|
306
|
+
/** Register (or override) an icon at runtime. Used by plugins. */
|
|
307
|
+
declare function registerIcon(name: string, def: IconDefinition): void;
|
|
308
|
+
/** All canonical icon names, for completion / docs. */
|
|
309
|
+
declare function iconNames(): string[];
|
|
310
|
+
/**
|
|
311
|
+
* Render an icon to an inline SVG string. Returns `null` for unknown icons so
|
|
312
|
+
* callers can emit a diagnostic and a graceful fallback.
|
|
313
|
+
*/
|
|
314
|
+
declare function iconToSvg(name: string, opts?: {
|
|
315
|
+
size?: number | string;
|
|
316
|
+
className?: string;
|
|
317
|
+
}): string | null;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Generate the stylesheet for a rendered resume from a {@link Theme}. Theme
|
|
321
|
+
* values become CSS custom properties so they can be overridden at runtime,
|
|
322
|
+
* and every theme color is exposed as `--retex-color-<token>` for use by
|
|
323
|
+
* `\themecolor`.
|
|
324
|
+
*/
|
|
325
|
+
declare function themeToCss(theme: Theme, prefix?: string): string;
|
|
326
|
+
|
|
327
|
+
/** Node types that participate in block (vertical) flow. */
|
|
328
|
+
declare const BLOCK_TYPES: Set<string>;
|
|
329
|
+
declare function isBlockNode(node: Node): boolean;
|
|
330
|
+
/**
|
|
331
|
+
* Plugin HTML renderer. Receives the node, the active context, and a callback
|
|
332
|
+
* to recursively render child nodes to HTML.
|
|
333
|
+
*/
|
|
334
|
+
type HtmlRenderFn = (node: Node, ctx: HtmlRenderContext, renderChildren: (nodes: Node[]) => string) => string;
|
|
335
|
+
interface HtmlRenderContext {
|
|
336
|
+
theme: Theme;
|
|
337
|
+
classPrefix: string;
|
|
338
|
+
/** Override renderers keyed by node `type` or `command:<name>`. */
|
|
339
|
+
overrides: Map<string, HtmlRenderFn>;
|
|
340
|
+
/** Render arbitrary inline/block nodes to an HTML string. */
|
|
341
|
+
renderNodes: (nodes: Node[]) => string;
|
|
342
|
+
cls: (name: string) => string;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
interface HtmlRenderOptions {
|
|
346
|
+
theme?: Theme;
|
|
347
|
+
/** CSS class prefix. Default `"retex"`. */
|
|
348
|
+
classPrefix?: string;
|
|
349
|
+
/** Plugin render overrides keyed by node `type` or `command:<name>`. */
|
|
350
|
+
overrides?: Map<string, HtmlRenderFn>;
|
|
351
|
+
/** Group leading contact commands into a `<header>`. Default `true`. */
|
|
352
|
+
header?: boolean;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* The HTML renderer. Produces clean, semantic, fully-escaped HTML. Every text
|
|
356
|
+
* node and attribute is escaped; every URL is re-sanitized at render time as a
|
|
357
|
+
* defense-in-depth measure even though the parser already vetted it.
|
|
358
|
+
*/
|
|
359
|
+
declare class HtmlRenderer {
|
|
360
|
+
private readonly theme;
|
|
361
|
+
private readonly prefix;
|
|
362
|
+
private readonly overrides;
|
|
363
|
+
private readonly useHeader;
|
|
364
|
+
private readonly ctx;
|
|
365
|
+
constructor(options?: HtmlRenderOptions);
|
|
366
|
+
/** Render the resume body as an HTML fragment (no `<html>`/`<style>`). */
|
|
367
|
+
render(ast: DocumentNode): string;
|
|
368
|
+
/** Render a complete, standalone HTML document including the stylesheet. */
|
|
369
|
+
renderDocument(ast: DocumentNode, title?: string): string;
|
|
370
|
+
/** The stylesheet for the active theme (without `<style>` tags). */
|
|
371
|
+
styles(): string;
|
|
372
|
+
private renderSection;
|
|
373
|
+
private renderPreamble;
|
|
374
|
+
private renderContactItem;
|
|
375
|
+
private contactLink;
|
|
376
|
+
/** Block-aware rendering: groups inline runs into `<p>`, renders blocks as-is. */
|
|
377
|
+
private renderFlow;
|
|
378
|
+
private renderInline;
|
|
379
|
+
private renderNode;
|
|
380
|
+
private renderLink;
|
|
381
|
+
private renderList;
|
|
382
|
+
private renderColumns;
|
|
383
|
+
private renderSkills;
|
|
384
|
+
private renderEntry;
|
|
385
|
+
private renderCommand;
|
|
386
|
+
private icon;
|
|
387
|
+
private dim;
|
|
388
|
+
private cls;
|
|
389
|
+
}
|
|
390
|
+
/** Render a document AST to an HTML fragment. */
|
|
391
|
+
declare function renderHtml(ast: DocumentNode, options?: HtmlRenderOptions): string;
|
|
392
|
+
/** Render a document AST to a complete standalone HTML page. */
|
|
393
|
+
declare function renderHtmlDocument(ast: DocumentNode, options?: HtmlRenderOptions & {
|
|
394
|
+
title?: string;
|
|
395
|
+
}): string;
|
|
396
|
+
|
|
397
|
+
interface JsonRenderOptions {
|
|
398
|
+
/** Strip `range`/`hash` metadata for a compact, stable payload. */
|
|
399
|
+
stripMeta?: boolean;
|
|
400
|
+
/** `JSON.stringify` indentation (number of spaces). Default 2. */
|
|
401
|
+
indent?: number;
|
|
402
|
+
}
|
|
403
|
+
/** Deep-clone an AST, optionally removing source metadata. */
|
|
404
|
+
declare function toJsonTree(ast: Node, opts?: JsonRenderOptions): unknown;
|
|
405
|
+
/**
|
|
406
|
+
* The JSON renderer. Produces a structured, machine-readable representation of
|
|
407
|
+
* the document AST — handy for editor tooling, diffing, and storage.
|
|
408
|
+
*/
|
|
409
|
+
declare function renderJson(ast: DocumentNode, opts?: JsonRenderOptions): string;
|
|
410
|
+
|
|
411
|
+
interface PrintOptions extends HtmlRenderOptions {
|
|
412
|
+
title?: string;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Build the `@page` CSS for the theme's page geometry. This is what turns a
|
|
416
|
+
* web page into a paginated, print-ready document.
|
|
417
|
+
*/
|
|
418
|
+
declare function pageCss(theme: Theme): string;
|
|
419
|
+
/**
|
|
420
|
+
* Render a print-optimized, standalone HTML document. This is the portable
|
|
421
|
+
* core of the PDF strategy: the same HTML can be
|
|
422
|
+
* - printed to PDF in the browser via `window.print()`,
|
|
423
|
+
* - converted headlessly with Puppeteer/Playwright ({@link renderPdf}), or
|
|
424
|
+
* - handed to any HTML-to-PDF service.
|
|
425
|
+
*/
|
|
426
|
+
declare function renderPrintHtml(ast: DocumentNode, options?: PrintOptions): string;
|
|
427
|
+
interface PdfOptions extends PrintOptions {
|
|
428
|
+
/**
|
|
429
|
+
* Optional injected headless-browser launcher. When omitted, `renderPdf`
|
|
430
|
+
* dynamically imports `puppeteer` if it is installed.
|
|
431
|
+
*/
|
|
432
|
+
launch?: () => Promise<HeadlessBrowser>;
|
|
433
|
+
/** Print background colors/images. Default `true`. */
|
|
434
|
+
printBackground?: boolean;
|
|
435
|
+
}
|
|
436
|
+
/** Minimal structural types for the puppeteer/playwright adapter. */
|
|
437
|
+
interface HeadlessPage {
|
|
438
|
+
setContent(html: string, opts?: {
|
|
439
|
+
waitUntil?: string;
|
|
440
|
+
}): Promise<void>;
|
|
441
|
+
pdf(opts: Record<string, unknown>): Promise<Uint8Array>;
|
|
442
|
+
}
|
|
443
|
+
interface HeadlessBrowser {
|
|
444
|
+
newPage(): Promise<HeadlessPage>;
|
|
445
|
+
close(): Promise<void>;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Render a document to a PDF byte buffer using a headless browser.
|
|
449
|
+
*
|
|
450
|
+
* The default path lazily imports `puppeteer` (an *optional* dependency) so the
|
|
451
|
+
* core library stays dependency-free. Supply `options.launch` to plug in
|
|
452
|
+
* Playwright, a pooled browser, or a remote Chromium instead.
|
|
453
|
+
*
|
|
454
|
+
* @throws if no launcher is available, with guidance on how to enable PDF export.
|
|
455
|
+
*/
|
|
456
|
+
declare function renderPdf(ast: DocumentNode, options?: PdfOptions): Promise<Uint8Array>;
|
|
457
|
+
|
|
458
|
+
/** A document region: an optional leading section heading plus its body. */
|
|
459
|
+
interface Region {
|
|
460
|
+
section?: SectionNode;
|
|
461
|
+
nodes: Node[];
|
|
462
|
+
}
|
|
463
|
+
/** Split a document's children into regions delimited by level-1 sections. */
|
|
464
|
+
declare function toRegions(children: Node[]): Region[];
|
|
465
|
+
interface PreambleParts {
|
|
466
|
+
name?: ContactNode;
|
|
467
|
+
title?: ContactNode;
|
|
468
|
+
contacts: Node[];
|
|
469
|
+
other: Node[];
|
|
470
|
+
}
|
|
471
|
+
/** Separate a preamble into header pieces (name/title/contacts) and the rest. */
|
|
472
|
+
declare function splitPreamble(nodes: Node[]): PreambleParts;
|
|
473
|
+
interface EntryParts {
|
|
474
|
+
title: string;
|
|
475
|
+
subtitle: string;
|
|
476
|
+
dates: string;
|
|
477
|
+
location: string;
|
|
478
|
+
url: string;
|
|
479
|
+
}
|
|
480
|
+
/** Normalize a job/education/project field map into renderable entry parts. */
|
|
481
|
+
declare function entryParts(fields: FieldMap, kind: string): EntryParts;
|
|
482
|
+
declare function dateRange(start?: string, end?: string, date?: string): string;
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* A command definition extended with optional per-target render functions.
|
|
486
|
+
* Passing `render.html` is shorthand for registering an HTML override keyed by
|
|
487
|
+
* `command:<name>` — the common case for a plugin command with no custom AST
|
|
488
|
+
* node (e.g. `\badge{...}`).
|
|
489
|
+
*/
|
|
490
|
+
interface EngineCommand extends CommandDefinition {
|
|
491
|
+
render?: {
|
|
492
|
+
html?: HtmlRenderFn;
|
|
493
|
+
react?: ReactRenderFn;
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* A ReTeX plugin. Everything is optional; a plugin may contribute commands,
|
|
498
|
+
* environments, icons, renderers, theme overrides, or run arbitrary setup
|
|
499
|
+
* against the engine. Plugins never touch global state — they mutate only the
|
|
500
|
+
* engine instance they are installed on.
|
|
501
|
+
*/
|
|
502
|
+
interface ReTeXPlugin {
|
|
503
|
+
name: string;
|
|
504
|
+
commands?: EngineCommand[];
|
|
505
|
+
environments?: EnvironmentDefinition[];
|
|
506
|
+
icons?: Record<string, IconDefinition>;
|
|
507
|
+
/** HTML overrides keyed by node `type` or `command:<name>`. */
|
|
508
|
+
htmlRenderers?: Record<string, HtmlRenderFn>;
|
|
509
|
+
/** React overrides keyed by node `type` or `command:<name>`. */
|
|
510
|
+
reactRenderers?: Record<string, ReactRenderFn>;
|
|
511
|
+
/** A theme patch applied when the plugin is installed. */
|
|
512
|
+
theme?: PartialTheme;
|
|
513
|
+
/** Imperative hook for advanced setup. */
|
|
514
|
+
setup?: (engine: PluginHost) => void;
|
|
515
|
+
}
|
|
516
|
+
/** The subset of the engine surface a plugin's `setup` hook may use. */
|
|
517
|
+
interface PluginHost {
|
|
518
|
+
registerCommand(def: EngineCommand): PluginHost;
|
|
519
|
+
registerEnvironment(def: EnvironmentDefinition): PluginHost;
|
|
520
|
+
registerHtmlRenderer(key: string, fn: HtmlRenderFn): PluginHost;
|
|
521
|
+
registerReactRenderer(key: string, fn: ReactRenderFn): PluginHost;
|
|
522
|
+
registerIcon(name: string, def: IconDefinition): PluginHost;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
interface EngineOptions {
|
|
526
|
+
theme?: Theme | PartialTheme;
|
|
527
|
+
plugins?: ReTeXPlugin[];
|
|
528
|
+
classPrefix?: string;
|
|
529
|
+
/** Max number of compiled documents to cache. Default 64. */
|
|
530
|
+
cacheSize?: number;
|
|
531
|
+
}
|
|
532
|
+
interface CompileResult {
|
|
533
|
+
source: string;
|
|
534
|
+
tokens: Token[];
|
|
535
|
+
ast: DocumentNode;
|
|
536
|
+
diagnostics: Diagnostic[];
|
|
537
|
+
}
|
|
538
|
+
interface CompileOptions {
|
|
539
|
+
/** Run semantic validation in addition to parsing. Default `true`. */
|
|
540
|
+
validate?: boolean;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* The ReTeX engine: the single entry point that wires the tokenizer, parser,
|
|
544
|
+
* validator, renderers, theming, plugins, and caching together.
|
|
545
|
+
*
|
|
546
|
+
* ```ts
|
|
547
|
+
* const engine = new ReTeXEngine({ theme: { colors: { primary: "#7c3aed" } } });
|
|
548
|
+
* engine.registerCommand({ name: "badge", args: [{ kind: "content" }],
|
|
549
|
+
* render: { html: (n, ctx, kids) => `<span class="badge">${kids((n as any).args[0].children)}</span>` } });
|
|
550
|
+
* const html = engine.toHtml(source);
|
|
551
|
+
* ```
|
|
552
|
+
*/
|
|
553
|
+
declare class ReTeXEngine implements PluginHost {
|
|
554
|
+
private registry;
|
|
555
|
+
private theme;
|
|
556
|
+
private readonly prefix;
|
|
557
|
+
private readonly htmlOverrides;
|
|
558
|
+
private readonly reactOverrides;
|
|
559
|
+
private readonly cache;
|
|
560
|
+
private readonly cacheSize;
|
|
561
|
+
private generation;
|
|
562
|
+
constructor(options?: EngineOptions);
|
|
563
|
+
use(plugin: ReTeXPlugin): this;
|
|
564
|
+
registerCommand(def: EngineCommand): this;
|
|
565
|
+
registerEnvironment(def: EnvironmentDefinition): this;
|
|
566
|
+
registerHtmlRenderer(key: string, fn: HtmlRenderFn): this;
|
|
567
|
+
registerReactRenderer(key: string, fn: ReactRenderFn): this;
|
|
568
|
+
registerIcon(name: string, def: IconDefinition): this;
|
|
569
|
+
setTheme(theme: Theme | PartialTheme): this;
|
|
570
|
+
getTheme(): Theme;
|
|
571
|
+
getRegistry(): CommandRegistry;
|
|
572
|
+
tokenize(source: string): TokenizeResult;
|
|
573
|
+
/** Tokenize, parse, and (by default) validate a source string. Cached. */
|
|
574
|
+
compile(source: string, options?: CompileOptions): CompileResult;
|
|
575
|
+
parse(source: string): DocumentNode;
|
|
576
|
+
validate(input: string | DocumentNode): Diagnostic[];
|
|
577
|
+
toHtml(input: string | DocumentNode, options?: HtmlRenderOptions): string;
|
|
578
|
+
toHtmlDocument(input: string | DocumentNode, options?: HtmlRenderOptions & {
|
|
579
|
+
title?: string;
|
|
580
|
+
}): string;
|
|
581
|
+
toReact(input: string | DocumentNode, options: Omit<ReactRenderOptions, "theme" | "classPrefix" | "overrides">): unknown;
|
|
582
|
+
toJson(input: string | DocumentNode, options?: JsonRenderOptions): string;
|
|
583
|
+
toPrintHtml(input: string | DocumentNode, options?: PrintOptions): string;
|
|
584
|
+
toPdf(input: string | DocumentNode, options?: PdfOptions): Promise<Uint8Array>;
|
|
585
|
+
/** The CSS stylesheet for the active theme. */
|
|
586
|
+
styles(): string;
|
|
587
|
+
private astOf;
|
|
588
|
+
private htmlRenderer;
|
|
589
|
+
private printOptions;
|
|
590
|
+
private invalidate;
|
|
591
|
+
private remember;
|
|
592
|
+
}
|
|
593
|
+
/** Create an engine with the default configuration. */
|
|
594
|
+
declare function createEngine(options?: EngineOptions): ReTeXEngine;
|
|
595
|
+
|
|
596
|
+
interface ParseResult {
|
|
597
|
+
ast: DocumentNode;
|
|
598
|
+
diagnostics: Diagnostic[];
|
|
599
|
+
}
|
|
600
|
+
interface ParserOptions {
|
|
601
|
+
registry?: CommandRegistry;
|
|
602
|
+
/**
|
|
603
|
+
* Maximum structural nesting depth before the parser stops recursing and
|
|
604
|
+
* degrades gracefully (emitting a diagnostic). Guards against stack overflow
|
|
605
|
+
* on adversarial input such as thousands of unclosed braces. Default 300.
|
|
606
|
+
*/
|
|
607
|
+
maxDepth?: number;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Stage 2 of the pipeline. A recursive-descent parser that turns the token
|
|
611
|
+
* stream into a {@link DocumentNode}. It is fully error-recovering: it never
|
|
612
|
+
* throws, always returns a tree, and records every problem as a
|
|
613
|
+
* {@link Diagnostic} so editors and the validator can surface them.
|
|
614
|
+
*/
|
|
615
|
+
declare class Parser {
|
|
616
|
+
private readonly tokens;
|
|
617
|
+
private readonly registry;
|
|
618
|
+
private readonly diagnostics;
|
|
619
|
+
private readonly utils;
|
|
620
|
+
private pos;
|
|
621
|
+
private depth;
|
|
622
|
+
private readonly maxDepth;
|
|
623
|
+
private reportedMaxDepth;
|
|
624
|
+
/** Range of the command currently being built, for builder diagnostics. */
|
|
625
|
+
private currentRange;
|
|
626
|
+
constructor(tokens: Token[], options?: ParserOptions);
|
|
627
|
+
static parse(tokens: Token[], options?: ParserOptions): ParseResult;
|
|
628
|
+
parse(): ParseResult;
|
|
629
|
+
private parseContent;
|
|
630
|
+
private parseContentInner;
|
|
631
|
+
private parseNode;
|
|
632
|
+
private parseGroup;
|
|
633
|
+
private parseScopedSwitch;
|
|
634
|
+
private parseCommandApplication;
|
|
635
|
+
private buildCommand;
|
|
636
|
+
private parseArgs;
|
|
637
|
+
private parseArg;
|
|
638
|
+
private parseGreedyArgs;
|
|
639
|
+
/** Concatenate the raw source of tokens until the matching close at depth 0. */
|
|
640
|
+
private readRawUntil;
|
|
641
|
+
private parseEnvironment;
|
|
642
|
+
private parseEnvBody;
|
|
643
|
+
private parseEnvEntries;
|
|
644
|
+
private consumeEnd;
|
|
645
|
+
/** Read a `{name}` group's raw contents, reporting if it is missing. */
|
|
646
|
+
private readGroupName;
|
|
647
|
+
/** Like {@link readGroupName} but returns "" silently when absent. */
|
|
648
|
+
private tryReadGroupRaw;
|
|
649
|
+
/**
|
|
650
|
+
* Recursion-limit fallback: consume the current scope's tokens flatly
|
|
651
|
+
* (tracking nested braces) without descending, so adversarial deep nesting
|
|
652
|
+
* cannot overflow the stack. Emits one diagnostic per parse.
|
|
653
|
+
*/
|
|
654
|
+
private skipFlat;
|
|
655
|
+
private consumeClose;
|
|
656
|
+
private at;
|
|
657
|
+
private atCommand;
|
|
658
|
+
private skipInlineTrivia;
|
|
659
|
+
private skipTrivia;
|
|
660
|
+
private peek;
|
|
661
|
+
private advance;
|
|
662
|
+
private previousEnd;
|
|
663
|
+
private report;
|
|
664
|
+
}
|
|
665
|
+
/** Convenience wrapper. */
|
|
666
|
+
declare function parse(tokens: Token[], options?: ParserOptions): ParseResult;
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Register every built-in command and environment into a fresh registry.
|
|
670
|
+
* The engine calls this once per instance so plugins can extend a private
|
|
671
|
+
* copy without touching global state.
|
|
672
|
+
*/
|
|
673
|
+
declare function createDefaultRegistry(): CommandRegistry;
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Split a comma-separated list, respecting `{...}` and `[...]` nesting so that
|
|
677
|
+
* a brace-protected comma (`{a, b}`) is not treated as a separator.
|
|
678
|
+
*/
|
|
679
|
+
declare function splitTopLevel(raw: string, sep?: string): string[];
|
|
680
|
+
/** Parse a comma-separated list argument into trimmed, non-empty entries. */
|
|
681
|
+
declare function parseListArg(raw: string): string[];
|
|
682
|
+
/**
|
|
683
|
+
* Parse a `key=value, key=value` argument into a {@link FieldMap}.
|
|
684
|
+
*
|
|
685
|
+
* To keep unquoted values like `location=New York, NY` working, any comma
|
|
686
|
+
* segment that contains no `=` is merged back into the previous value (the
|
|
687
|
+
* comma is treated as literal). The first `=` in a segment separates key from
|
|
688
|
+
* value; later `=` characters are preserved in the value.
|
|
689
|
+
*/
|
|
690
|
+
declare function parseKeyValArg(raw: string): FieldMap;
|
|
691
|
+
|
|
692
|
+
/** Damerau-ish Levenshtein distance (no transpositions) for "did you mean?". */
|
|
693
|
+
declare function levenshtein(a: string, b: string): number;
|
|
694
|
+
/** Return the closest candidate to `name` within a small edit distance. */
|
|
695
|
+
declare function closestMatch(name: string, candidates: Iterable<string>): string | undefined;
|
|
696
|
+
|
|
697
|
+
interface ValidateOptions {
|
|
698
|
+
/** When provided, `\themecolor{token}` tokens are checked against it. */
|
|
699
|
+
theme?: Theme;
|
|
700
|
+
}
|
|
701
|
+
/**
|
|
702
|
+
* Stage 3 of the pipeline. Semantic validation over the AST, complementing the
|
|
703
|
+
* syntactic diagnostics produced by the parser. Pure and side-effect free.
|
|
704
|
+
*/
|
|
705
|
+
declare function validate(ast: DocumentNode, options?: ValidateOptions): Diagnostic[];
|
|
706
|
+
|
|
707
|
+
/** Return the child nodes of any node, regardless of where they're stored. */
|
|
708
|
+
declare function childrenOf(node: Node): Node[];
|
|
709
|
+
interface VisitOptions {
|
|
710
|
+
/** Called before visiting children. Return `false` to skip the subtree. */
|
|
711
|
+
enter?: (node: Node, parent: Node | null) => boolean | void;
|
|
712
|
+
/** Called after visiting children. */
|
|
713
|
+
exit?: (node: Node, parent: Node | null) => void;
|
|
714
|
+
}
|
|
715
|
+
/** Depth-first traversal of the tree. */
|
|
716
|
+
declare function walk(root: Node, opts: VisitOptions): void;
|
|
717
|
+
/** Collect every node matching a predicate. */
|
|
718
|
+
declare function collect(root: Node, pred: (n: Node) => boolean): Node[];
|
|
719
|
+
/** Find the innermost node whose range contains `offset`, plus its ancestors. */
|
|
720
|
+
declare function nodePathAt(root: Node, offset: number): Node[];
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Best-effort extraction of the plain-text content of a node or node list.
|
|
724
|
+
* Used to derive section titles, contact values, and accessible labels, and
|
|
725
|
+
* by `keyval`/`list` argument parsing.
|
|
726
|
+
*/
|
|
727
|
+
declare function flattenText(input: Node | Node[]): string;
|
|
728
|
+
/** Collapse internal runs of whitespace and trim — useful for titles/labels. */
|
|
729
|
+
declare function normalizeWhitespace(s: string): string;
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* The default ReTeX theme — a clean, ATS-friendly look that reads well both on
|
|
733
|
+
* screen and in print. All other themes are partial overrides of this one.
|
|
734
|
+
*/
|
|
735
|
+
declare const defaultTheme: Theme;
|
|
736
|
+
|
|
737
|
+
/** Deep-merge a partial theme over a base theme (sub-objects merged shallowly). */
|
|
738
|
+
declare function resolveTheme(partial?: PartialTheme, base?: Theme): Theme;
|
|
739
|
+
/** A modern, accent-forward theme with underlined section headings. */
|
|
740
|
+
declare const modernTheme: Theme;
|
|
741
|
+
/** A restrained, classic serif theme suited to academic CVs. */
|
|
742
|
+
declare const classicTheme: Theme;
|
|
743
|
+
/** A compact, single-accent theme that maximizes content density. */
|
|
744
|
+
declare const compactTheme: Theme;
|
|
745
|
+
/** Built-in theme presets keyed by name. */
|
|
746
|
+
declare const themes: Record<string, Theme>;
|
|
747
|
+
/** Look up a preset theme by name, falling back to the default. */
|
|
748
|
+
declare function getTheme(name: string): Theme;
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Example plugin: `\badge{New}` renders a small pill. Demonstrates a custom
|
|
752
|
+
* inline command with both HTML and React renderers and no custom AST node.
|
|
753
|
+
*/
|
|
754
|
+
declare const badgePlugin: ReTeXPlugin;
|
|
755
|
+
/**
|
|
756
|
+
* Example plugin: `\rating{4}` (out of 5) renders filled/empty dots.
|
|
757
|
+
* Demonstrates a `string` argument and an HTML override.
|
|
758
|
+
*/
|
|
759
|
+
declare const ratingPlugin: ReTeXPlugin;
|
|
760
|
+
|
|
761
|
+
/**
|
|
762
|
+
* Security utilities. ReTeX renders untrusted markup to HTML, so every text
|
|
763
|
+
* node and attribute value must be escaped, and every URL must be vetted
|
|
764
|
+
* before it reaches an `href`/`src`. The engine never evaluates source as
|
|
765
|
+
* code — there is no `eval`, `Function`, or template-string interpolation of
|
|
766
|
+
* user input into executable contexts.
|
|
767
|
+
*/
|
|
768
|
+
/** HTML text-content escaping. Order matters: ampersand first. */
|
|
769
|
+
declare function escapeHtml(input: string): string;
|
|
770
|
+
/** Escaping for values placed inside double-quoted HTML attributes. */
|
|
771
|
+
declare function escapeAttribute(input: string): string;
|
|
772
|
+
interface UrlSanitizeResult {
|
|
773
|
+
/** Safe URL, or `"#"` when the input was rejected. */
|
|
774
|
+
safe: string;
|
|
775
|
+
/** True when the original URL was blocked. */
|
|
776
|
+
blocked: boolean;
|
|
777
|
+
/** The detected scheme, when present. */
|
|
778
|
+
scheme?: string;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Sanitize a URL for use in an `href`.
|
|
782
|
+
*
|
|
783
|
+
* - Relative URLs and fragments are allowed as-is.
|
|
784
|
+
* - Absolute URLs are allowed only for an allow-listed protocol.
|
|
785
|
+
* - `javascript:`, `data:`, `vbscript:`, `file:` and friends are blocked.
|
|
786
|
+
* - Control characters used to obfuscate the scheme are removed first.
|
|
787
|
+
*/
|
|
788
|
+
declare function sanitizeUrl(input: string): UrlSanitizeResult;
|
|
789
|
+
/**
|
|
790
|
+
* Validate a CSS color token. Accepts `#rgb`, `#rrggbb`, `#rrggbbaa`,
|
|
791
|
+
* `rgb()/rgba()/hsl()/hsla()` functional notation, and a curated set of
|
|
792
|
+
* CSS named colors. Anything else is rejected so it can't smuggle
|
|
793
|
+
* `url(javascript:…)` or `expression(...)` into a `style` attribute.
|
|
794
|
+
*/
|
|
795
|
+
declare function isSafeColor(value: string): boolean;
|
|
796
|
+
/**
|
|
797
|
+
* Validate a CSS length/dimension such as `14pt`, `1.5rem`, `40%`, `200px`.
|
|
798
|
+
* Used for `\fontsize`, `\column` widths and spacing commands.
|
|
799
|
+
*/
|
|
800
|
+
declare function isSafeDimension(value: string): boolean;
|
|
801
|
+
/**
|
|
802
|
+
* Sanitize a value destined for a CSS property. Returns `undefined` when the
|
|
803
|
+
* value is unsafe so callers can omit the declaration entirely.
|
|
804
|
+
*/
|
|
805
|
+
declare function sanitizeStyleValue(value: string): string | undefined;
|
|
806
|
+
|
|
807
|
+
type CompletionKind = "command" | "environment" | "field" | "snippet";
|
|
808
|
+
interface CompletionItem {
|
|
809
|
+
label: string;
|
|
810
|
+
kind: CompletionKind;
|
|
811
|
+
detail?: string;
|
|
812
|
+
documentation?: string;
|
|
813
|
+
/** Plain text to insert. */
|
|
814
|
+
insertText: string;
|
|
815
|
+
/** LSP-style snippet with `${n:placeholder}` tab stops. */
|
|
816
|
+
snippet?: string;
|
|
817
|
+
/** Range the completion replaces (the partial token being typed). */
|
|
818
|
+
range?: SourceRange;
|
|
819
|
+
}
|
|
820
|
+
interface HoverInfo {
|
|
821
|
+
/** Markdown documentation. */
|
|
822
|
+
contents: string;
|
|
823
|
+
range: SourceRange;
|
|
824
|
+
}
|
|
825
|
+
type SemanticTokenType = "command" | "command-unknown" | "environment" | "brace" | "bracket" | "text" | "comment" | "linebreak" | "argument";
|
|
826
|
+
interface SemanticToken {
|
|
827
|
+
range: SourceRange;
|
|
828
|
+
type: SemanticTokenType;
|
|
829
|
+
/** e.g. `["section"]`, `["typography"]`, derived from the command category. */
|
|
830
|
+
modifiers: string[];
|
|
831
|
+
}
|
|
832
|
+
interface EditorServiceOptions {
|
|
833
|
+
registry?: CommandRegistry;
|
|
834
|
+
theme?: Theme;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Editor integration surface: everything a code editor (Monaco, CodeMirror, an
|
|
838
|
+
* LSP server) needs to provide a great ReTeX authoring experience —
|
|
839
|
+
* completion, hover docs, semantic highlighting, diagnostics, formatting, and
|
|
840
|
+
* AST inspection. All methods are pure and synchronous.
|
|
841
|
+
*/
|
|
842
|
+
declare class EditorService {
|
|
843
|
+
private readonly registry;
|
|
844
|
+
private readonly theme?;
|
|
845
|
+
constructor(options?: EditorServiceOptions);
|
|
846
|
+
getDiagnostics(source: string): Diagnostic[];
|
|
847
|
+
/** Parse and return the AST for inspection / debugging. */
|
|
848
|
+
inspect(source: string): DocumentNode;
|
|
849
|
+
format(source: string): string;
|
|
850
|
+
getCompletions(source: string, offset: number): CompletionItem[];
|
|
851
|
+
private commandCompletion;
|
|
852
|
+
private environmentCompletion;
|
|
853
|
+
/** Suggest field keys when the cursor is inside a `\job/\education/\project{…}`. */
|
|
854
|
+
private fieldContext;
|
|
855
|
+
getHover(source: string, offset: number): HoverInfo | null;
|
|
856
|
+
private commandDoc;
|
|
857
|
+
private environmentDoc;
|
|
858
|
+
getSemanticTokens(source: string): SemanticToken[];
|
|
859
|
+
private readNameAfter;
|
|
860
|
+
private rangeAt;
|
|
861
|
+
private positionAt;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Serialize an AST back into canonical ReTeX source. Used by the formatter and
|
|
866
|
+
* for round-trip testing. Inline content is printed compactly; block content is
|
|
867
|
+
* separated by blank lines and environments are indented.
|
|
868
|
+
*/
|
|
869
|
+
declare function printDocument(ast: DocumentNode): string;
|
|
870
|
+
|
|
871
|
+
interface Segment {
|
|
872
|
+
start: number;
|
|
873
|
+
end: number;
|
|
874
|
+
startLine: number;
|
|
875
|
+
}
|
|
876
|
+
interface IncrementalStats {
|
|
877
|
+
segments: number;
|
|
878
|
+
cacheHits: number;
|
|
879
|
+
cacheMisses: number;
|
|
880
|
+
}
|
|
881
|
+
interface IncrementalResult {
|
|
882
|
+
ast: DocumentNode;
|
|
883
|
+
diagnostics: Diagnostic[];
|
|
884
|
+
stats: IncrementalStats;
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Incremental, block-level compiler optimized for editors. The document is
|
|
888
|
+
* split into balanced blocks at blank-line boundaries; each block's parse is
|
|
889
|
+
* cached by its exact text. When the user edits one block, only that block is
|
|
890
|
+
* re-tokenized and re-parsed — every other block is served from cache and
|
|
891
|
+
* re-positioned with a cheap range shift.
|
|
892
|
+
*
|
|
893
|
+
* The produced AST is equivalent to a full parse (top-level blocks separated by
|
|
894
|
+
* paragraph breaks), making this a drop-in fast path for live preview.
|
|
895
|
+
*/
|
|
896
|
+
declare class IncrementalCompiler {
|
|
897
|
+
private readonly registry;
|
|
898
|
+
/** Position-independent parse cache, keyed by exact block text. */
|
|
899
|
+
private readonly parseCache;
|
|
900
|
+
/** Position-resolved cache, keyed by `offset:line:text` (already shifted). */
|
|
901
|
+
private positioned;
|
|
902
|
+
private hits;
|
|
903
|
+
private misses;
|
|
904
|
+
constructor(options?: {
|
|
905
|
+
registry?: CommandRegistry;
|
|
906
|
+
});
|
|
907
|
+
/** Clear all caches (e.g. after registering new commands). */
|
|
908
|
+
reset(): void;
|
|
909
|
+
compile(source: string): IncrementalResult;
|
|
910
|
+
}
|
|
911
|
+
/** Split source at blank lines, merging neighbours until each block is balanced. */
|
|
912
|
+
declare function splitBalancedSegments(source: string): Segment[];
|
|
913
|
+
/** Are braces and `\begin`/`\end` balanced in `text`? (Escapes are skipped.) */
|
|
914
|
+
declare function isBalanced(text: string): boolean;
|
|
915
|
+
|
|
916
|
+
export { type ArgKind, type ArgSpec, ArgumentNode, BLOCK_TYPES, type BuildContext, type BuilderUtils, type CommandCategory, type CommandDefinition, CommandNode, CommandRegistry, type CompileOptions, type CompileResult, type CompletionItem, type CompletionKind, ContactNode, type Diagnostic, DiagnosticCode, DiagnosticSeverity, DocumentNode, EditorService, type EditorServiceOptions, type EngineCommand, type EngineOptions, type EntryParts, type EnvBuildContext, type EnvEntry, type EnvironmentDefinition, FieldMap, type HeadlessBrowser, type HeadlessPage, type HoverInfo, type HtmlRenderContext, type HtmlRenderFn, type HtmlRenderOptions, HtmlRenderer, type IconDefinition, IncrementalCompiler, type IncrementalResult, type IncrementalStats, type JsonRenderOptions, Node, type NodeBuilder, type ParseResult, Parser, type ParserOptions, PartialTheme, type PdfOptions, type PluginHost, type PreambleParts, type PrintOptions, type QuickFix, ReTeXEngine, type ReTeXPlugin, ReactRenderFn, ReactRenderOptions, type Region, SPECIAL_CHARS, SectionNode, type SemanticToken, type SemanticTokenType, SourceRange, Theme, type Token, TokenType, type TokenizeResult, Tokenizer, type UrlSanitizeResult, type ValidateOptions, type VisitOptions, badgePlugin, childrenOf, classicTheme, closestMatch, collect, compactTheme, createDefaultRegistry, createEngine, dateRange, defaultTheme, entryParts, escapeAttribute, escapeHtml, flattenText, getIcon, getTheme, hasIcon, iconNames, iconToSvg, isBalanced, isBlockNode, isSafeColor, isSafeDimension, levenshtein, modernTheme, nodePathAt, normalizeWhitespace, pageCss, parse, parseKeyValArg, parseListArg, printDocument, ratingPlugin, registerIcon, renderHtml, renderHtmlDocument, renderJson, renderPdf, renderPrintHtml, resolveIconName, resolveTheme, sanitizeStyleValue, sanitizeUrl, splitBalancedSegments, splitPreamble, splitTopLevel, themeToCss, themes, toJsonTree, toRegions, tokenize, validate, walk };
|