@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.
@@ -0,0 +1,420 @@
1
+ /**
2
+ * Source-location primitives shared by every stage of the compiler.
3
+ *
4
+ * Every token and AST node carries a {@link SourceRange} so that diagnostics,
5
+ * editor tooling (hover, completion, error underlines) and incremental
6
+ * re-parsing can map results back to the exact bytes in the original source.
7
+ */
8
+ /** A single position in the source text. */
9
+ interface Position {
10
+ /** Zero-based UTF-16 code-unit offset from the start of the document. */
11
+ offset: number;
12
+ /** One-based line number. */
13
+ line: number;
14
+ /** One-based column number. */
15
+ column: number;
16
+ }
17
+ /** A half-open `[start, end)` range in the source text. */
18
+ interface SourceRange {
19
+ start: Position;
20
+ end: Position;
21
+ }
22
+ /** Convenience constructor for a {@link Position}. */
23
+ declare function pos(offset: number, line: number, column: number): Position;
24
+ /** Convenience constructor for a {@link SourceRange}. */
25
+ declare function range(start: Position, end: Position): SourceRange;
26
+ /** Merge two ranges into the smallest range that contains both. */
27
+ declare function mergeRanges(a: SourceRange, b: SourceRange): SourceRange;
28
+ /** Test whether an offset falls within a range (start inclusive, end inclusive). */
29
+ declare function rangeContains(r: SourceRange, offset: number): boolean;
30
+
31
+ /**
32
+ * The ReTeX Abstract Syntax Tree.
33
+ *
34
+ * Every node is a member of the {@link Node} discriminated union keyed on
35
+ * `type`. Nodes fall into three broad families:
36
+ *
37
+ * - **Structural** — {@link DocumentNode}, {@link GroupNode}, {@link ParBreakNode}.
38
+ * - **Inline / typography** — text, marks (bold/italic/…), links, icons.
39
+ * - **Resume semantics** — sections, jobs, education, skills, contact fields.
40
+ *
41
+ * Unknown or plugin-provided commands are preserved as {@link CommandNode} so
42
+ * the tree is always a faithful, loss-less representation of the source and can
43
+ * be re-rendered by custom renderers.
44
+ */
45
+ interface NodeBase {
46
+ type: string;
47
+ /** Source span this node was produced from. Synthetic nodes may omit it. */
48
+ range?: SourceRange;
49
+ /**
50
+ * Stable structural hash used by the incremental compiler / render cache.
51
+ * Populated lazily; never authored by hand.
52
+ */
53
+ hash?: string;
54
+ }
55
+ interface DocumentNode extends NodeBase {
56
+ type: "document";
57
+ children: Node[];
58
+ }
59
+ /** A literal run of text. */
60
+ interface TextNode extends NodeBase {
61
+ type: "text";
62
+ value: string;
63
+ }
64
+ /** A paragraph break (one or more blank lines). */
65
+ interface ParBreakNode extends NodeBase {
66
+ type: "parbreak";
67
+ }
68
+ /** An explicit line break (`\\` or `\newline`). */
69
+ interface LineBreakNode extends NodeBase {
70
+ type: "linebreak";
71
+ }
72
+ /** A horizontal rule (`\hrule` / `\divider`). */
73
+ interface RuleNode extends NodeBase {
74
+ type: "rule";
75
+ }
76
+ /** Spacing primitive (`\vspace{1em}` / `\hspace{...}`). */
77
+ interface SpaceNode extends NodeBase {
78
+ type: "space";
79
+ axis: "horizontal" | "vertical";
80
+ size: string;
81
+ }
82
+ /** A bare `{ ... }` group. Mostly used to scope font switches. */
83
+ interface GroupNode extends NodeBase {
84
+ type: "group";
85
+ children: Node[];
86
+ }
87
+ type MarkType = "bold" | "italic" | "underline" | "strike";
88
+ /** Simple wrapping mark such as `\textbf{...}`. */
89
+ interface MarkNode extends NodeBase {
90
+ type: MarkType;
91
+ children: Node[];
92
+ }
93
+ /** `\textcolor{#hex|name}{...}` */
94
+ interface ColorNode extends NodeBase {
95
+ type: "color";
96
+ color: string;
97
+ children: Node[];
98
+ }
99
+ /** `\themecolor{primary}{...}` — color resolved from the active theme. */
100
+ interface ThemeColorNode extends NodeBase {
101
+ type: "themecolor";
102
+ token: string;
103
+ children: Node[];
104
+ }
105
+ /** `\fontsize{14pt}{...}` */
106
+ interface FontSizeNode extends NodeBase {
107
+ type: "fontsize";
108
+ size: string;
109
+ children: Node[];
110
+ }
111
+ /** `\fontfamily{Inter}{...}` */
112
+ interface FontFamilyNode extends NodeBase {
113
+ type: "fontfamily";
114
+ family: string;
115
+ children: Node[];
116
+ }
117
+ /** Relative size switch: `\small`, `\large`, `\Large`, `\Huge`. */
118
+ type FontScale = "small" | "normal" | "large" | "Large" | "Huge";
119
+ interface FontScaleNode extends NodeBase {
120
+ type: "fontscale";
121
+ scale: FontScale;
122
+ /** Content the switch applies to (rest of the enclosing group). */
123
+ children: Node[];
124
+ }
125
+ /** `\href{url}{label}` */
126
+ interface LinkNode extends NodeBase {
127
+ type: "link";
128
+ /** Sanitized, render-safe URL. */
129
+ href: string;
130
+ /** Original, unsanitized URL (kept for diagnostics / round-tripping). */
131
+ rawHref: string;
132
+ children: Node[];
133
+ }
134
+ /** `\url{url}` — renders the URL as its own label. */
135
+ interface UrlNode extends NodeBase {
136
+ type: "url";
137
+ href: string;
138
+ rawHref: string;
139
+ }
140
+ /** `\icon{github}` */
141
+ interface IconNode extends NodeBase {
142
+ type: "icon";
143
+ name: string;
144
+ }
145
+ interface SectionNode extends NodeBase {
146
+ type: "section";
147
+ title: string;
148
+ /** 1 = `\section`, 2 = `\subsection`. */
149
+ level: number;
150
+ }
151
+ type ListKind = "itemize" | "enumerate";
152
+ interface ListNode extends NodeBase {
153
+ type: "list";
154
+ kind: ListKind;
155
+ items: ListItemNode[];
156
+ }
157
+ interface ListItemNode extends NodeBase {
158
+ type: "item";
159
+ children: Node[];
160
+ }
161
+ interface ColumnsNode extends NodeBase {
162
+ type: "columns";
163
+ columns: ColumnNode[];
164
+ /** Gap between columns, e.g. `"1.5rem"`. */
165
+ gap?: string;
166
+ }
167
+ interface ColumnNode extends NodeBase {
168
+ type: "column";
169
+ /** Width as authored (`"40%"`, `"200px"`, `"2fr"`). */
170
+ width: string;
171
+ children: Node[];
172
+ }
173
+ type ContactField = "name" | "title" | "email" | "phone" | "location" | "website";
174
+ /** One of the single-value header commands (`\name`, `\email`, …). */
175
+ interface ContactNode extends NodeBase {
176
+ type: "contact";
177
+ field: ContactField;
178
+ value: string;
179
+ }
180
+ /** Parsed `key=value` map preserving per-field source ranges. */
181
+ interface FieldMap {
182
+ [key: string]: string;
183
+ }
184
+ /** `\job{title=…, company=…, …}{ body }` */
185
+ interface JobNode extends NodeBase {
186
+ type: "job";
187
+ fields: FieldMap;
188
+ children: Node[];
189
+ }
190
+ /** `\education{school=…, degree=…, …}{ body? }` */
191
+ interface EducationNode extends NodeBase {
192
+ type: "education";
193
+ fields: FieldMap;
194
+ children: Node[];
195
+ }
196
+ /** `\project{name=…, …}{ body? }` */
197
+ interface ProjectNode extends NodeBase {
198
+ type: "project";
199
+ fields: FieldMap;
200
+ children: Node[];
201
+ }
202
+ /** `\skills{a, b, c}` */
203
+ interface SkillsNode extends NodeBase {
204
+ type: "skills";
205
+ items: string[];
206
+ }
207
+ /** A parsed argument attached to a generic {@link CommandNode}. */
208
+ interface ArgumentNode {
209
+ kind: "required" | "optional";
210
+ /** Parsed children for `content` arguments. */
211
+ children: Node[];
212
+ /** Raw text for `string`/verbatim arguments. */
213
+ raw?: string;
214
+ range?: SourceRange;
215
+ }
216
+ /**
217
+ * A command the core does not model natively — including every
218
+ * plugin-registered command and any unknown command encountered during
219
+ * lenient parsing. Keeps the tree loss-less.
220
+ */
221
+ interface CommandNode extends NodeBase {
222
+ type: "command";
223
+ name: string;
224
+ args: ArgumentNode[];
225
+ }
226
+ /** A placeholder emitted during error recovery so rendering can continue. */
227
+ interface ErrorNode extends NodeBase {
228
+ type: "error";
229
+ message: string;
230
+ /** The raw source that could not be parsed. */
231
+ raw: string;
232
+ }
233
+ type Node = DocumentNode | TextNode | ParBreakNode | LineBreakNode | RuleNode | SpaceNode | GroupNode | MarkNode | ColorNode | ThemeColorNode | FontSizeNode | FontFamilyNode | FontScaleNode | LinkNode | UrlNode | IconNode | SectionNode | ListNode | ListItemNode | ColumnsNode | ColumnNode | ContactNode | JobNode | EducationNode | ProjectNode | SkillsNode | CommandNode | ErrorNode;
234
+ type NodeType = Node["type"];
235
+ /** Map from node `type` to its concrete interface, for typed visitors. */
236
+ interface NodeMap {
237
+ document: DocumentNode;
238
+ text: TextNode;
239
+ parbreak: ParBreakNode;
240
+ linebreak: LineBreakNode;
241
+ rule: RuleNode;
242
+ space: SpaceNode;
243
+ group: GroupNode;
244
+ bold: MarkNode;
245
+ italic: MarkNode;
246
+ underline: MarkNode;
247
+ strike: MarkNode;
248
+ color: ColorNode;
249
+ themecolor: ThemeColorNode;
250
+ fontsize: FontSizeNode;
251
+ fontfamily: FontFamilyNode;
252
+ fontscale: FontScaleNode;
253
+ link: LinkNode;
254
+ url: UrlNode;
255
+ icon: IconNode;
256
+ section: SectionNode;
257
+ list: ListNode;
258
+ item: ListItemNode;
259
+ columns: ColumnsNode;
260
+ column: ColumnNode;
261
+ contact: ContactNode;
262
+ job: JobNode;
263
+ education: EducationNode;
264
+ project: ProjectNode;
265
+ skills: SkillsNode;
266
+ command: CommandNode;
267
+ error: ErrorNode;
268
+ }
269
+ /** Nodes that carry a `children: Node[]` array. */
270
+ type ParentNode = Extract<Node, {
271
+ children: Node[];
272
+ }>;
273
+ declare function isParent(node: Node): node is ParentNode;
274
+ /** Type guard generator for a given node type. */
275
+ declare function isNode<T extends NodeType>(node: Node, type: T): node is NodeMap[T];
276
+
277
+ /**
278
+ * Theme model. Themes are plain data so they can be serialized, shipped over
279
+ * the wire, edited in a GUI, or composed at runtime. {@link resolveTheme}
280
+ * (see `src/theme`) deep-merges a partial theme over the default.
281
+ */
282
+ interface ThemeColors {
283
+ /** Brand / accent color used for links, section rules, highlights. */
284
+ primary: string;
285
+ /** Muted secondary color for meta text (dates, locations). */
286
+ secondary: string;
287
+ /** Default body text color. */
288
+ text: string;
289
+ /** De-emphasized text color. */
290
+ muted: string;
291
+ /** Page background. */
292
+ background: string;
293
+ /** Hairline / border color. */
294
+ border: string;
295
+ /** Arbitrary named swatches usable via `\themecolor{name}`. */
296
+ [token: string]: string;
297
+ }
298
+ interface ThemeFonts {
299
+ /** Font stack for headings (`\name`, `\section`). */
300
+ heading: string;
301
+ /** Font stack for body text. */
302
+ body: string;
303
+ /** Monospace stack (code, technical skills). */
304
+ mono: string;
305
+ }
306
+ interface ThemeFontSizes {
307
+ /** Base body size, e.g. `"11pt"`. */
308
+ base: string;
309
+ small: string;
310
+ large: string;
311
+ Large: string;
312
+ Huge: string;
313
+ /** `\name` size. */
314
+ name: string;
315
+ /** `\section` heading size. */
316
+ section: string;
317
+ }
318
+ interface ThemeSpacing {
319
+ /** Vertical rhythm unit. */
320
+ unit: string;
321
+ section: string;
322
+ item: string;
323
+ /** Page padding when rendering a full document. */
324
+ page: string;
325
+ }
326
+ interface ThemePage {
327
+ /** CSS page size keyword or dimensions, e.g. `"A4"` or `"8.5in 11in"`. */
328
+ size: string;
329
+ margin: string;
330
+ /** Max content width for screen preview. */
331
+ maxWidth: string;
332
+ }
333
+ interface Theme {
334
+ name: string;
335
+ colors: ThemeColors;
336
+ fonts: ThemeFonts;
337
+ fontSizes: ThemeFontSizes;
338
+ spacing: ThemeSpacing;
339
+ page: ThemePage;
340
+ /** Section heading style hint consumed by renderers. */
341
+ sectionStyle: "underline" | "rule" | "plain" | "bar";
342
+ }
343
+ /** A user-supplied theme override; everything is optional and deep-merged. */
344
+ type PartialTheme = {
345
+ name?: string;
346
+ colors?: Partial<ThemeColors>;
347
+ fonts?: Partial<ThemeFonts>;
348
+ fontSizes?: Partial<ThemeFontSizes>;
349
+ spacing?: Partial<ThemeSpacing>;
350
+ page?: Partial<ThemePage>;
351
+ sectionStyle?: Theme["sectionStyle"];
352
+ };
353
+
354
+ /**
355
+ * Minimal structural type for a JSX factory (React.createElement, Preact's `h`,
356
+ * etc.). Declaring it locally means the package has **no** hard React
357
+ * dependency — callers pass whichever factory they use.
358
+ */
359
+ type JsxFactory = (type: unknown, props: Record<string, unknown> | null, ...children: unknown[]) => unknown;
360
+ /** A React render override keyed by node `type` or `command:<name>`. */
361
+ type ReactRenderFn = (node: Node, ctx: ReactRenderContext, renderChildren: (nodes: Node[]) => unknown[]) => unknown;
362
+ interface ReactRenderContext {
363
+ theme: Theme;
364
+ classPrefix: string;
365
+ h: JsxFactory;
366
+ Fragment: unknown;
367
+ overrides: Map<string, ReactRenderFn>;
368
+ renderNodes: (nodes: Node[]) => unknown[];
369
+ cls: (name: string) => string;
370
+ }
371
+ interface ReactRenderOptions {
372
+ /** JSX factory. Required. Pass `React.createElement`. */
373
+ createElement: JsxFactory;
374
+ /** Fragment component. Pass `React.Fragment`. Falls back to a `<div>`. */
375
+ Fragment?: unknown;
376
+ theme?: Theme;
377
+ classPrefix?: string;
378
+ overrides?: Map<string, ReactRenderFn>;
379
+ header?: boolean;
380
+ }
381
+ /**
382
+ * The React renderer. Produces a React element tree mirroring the HTML
383
+ * renderer's structure and class names, so the same theme stylesheet applies.
384
+ */
385
+ declare class ReactRenderer {
386
+ private readonly theme;
387
+ private readonly prefix;
388
+ private readonly h;
389
+ private readonly Fragment;
390
+ private readonly overrides;
391
+ private readonly useHeader;
392
+ private key;
393
+ constructor(options: ReactRenderOptions);
394
+ /** The stylesheet for the active theme. Render it in a `<style>` yourself. */
395
+ styles(): string;
396
+ /** Render the document AST to a React element. */
397
+ render(ast: DocumentNode): unknown;
398
+ private ctx;
399
+ private renderSection;
400
+ private renderPreamble;
401
+ private renderFlow;
402
+ private renderInline;
403
+ private renderNode;
404
+ private renderContact;
405
+ private contactLink;
406
+ private renderLink;
407
+ private renderList;
408
+ private renderColumns;
409
+ private renderEntry;
410
+ private renderCommand;
411
+ private renderIcon;
412
+ private el;
413
+ private frag;
414
+ private dim;
415
+ private cls;
416
+ }
417
+ /** Render a document AST to a React element tree. */
418
+ declare function renderReact(ast: DocumentNode, options: ReactRenderOptions): unknown;
419
+
420
+ export { isNode as $, type ArgumentNode as A, ReactRenderer as B, type CommandNode as C, type DocumentNode as D, type EducationNode as E, type FieldMap as F, type GroupNode as G, type RuleNode as H, type IconNode as I, type JobNode as J, type SkillsNode as K, type LineBreakNode as L, type MarkNode as M, type Node as N, type SpaceNode as O, type PartialTheme as P, type TextNode as Q, type ReactRenderFn as R, type SourceRange as S, type Theme as T, type ThemeColorNode as U, type ThemeColors as V, type ThemeFontSizes as W, type ThemeFonts as X, type ThemePage as Y, type ThemeSpacing as Z, type UrlNode as _, type ContactNode as a, isParent as a0, mergeRanges as a1, pos as a2, range as a3, rangeContains as a4, renderReact as a5, type SectionNode as b, type ReactRenderOptions as c, type ColorNode as d, type ColumnNode as e, type ColumnsNode as f, type ContactField as g, type ErrorNode as h, type FontFamilyNode as i, type FontScale as j, type FontScaleNode as k, type FontSizeNode as l, type JsxFactory as m, type LinkNode as n, type ListItemNode as o, type ListKind as p, type ListNode as q, type MarkType as r, type NodeBase as s, type NodeMap as t, type NodeType as u, type ParBreakNode as v, type ParentNode as w, type Position as x, type ProjectNode as y, type ReactRenderContext as z };