@regmisatyam/retex 0.1.0 → 0.2.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 @@
1
+ {"version":3,"sources":["../src/security/sanitize.ts","../src/library/colors.ts","../src/library/fonts.ts","../src/library/shapes.ts","../src/theme/default.ts","../src/theme/themes.ts","../src/library/themes.ts","../src/types/ast.ts","../src/ast/walk.ts","../src/library/registry.ts"],"names":["zero","ZERO_RANGE"],"mappings":"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","file":"library.js","sourcesContent":["/**\n * Security utilities. ReTeX renders untrusted markup to HTML, so every text\n * node and attribute value must be escaped, and every URL must be vetted\n * before it reaches an `href`/`src`. The engine never evaluates source as\n * code — there is no `eval`, `Function`, or template-string interpolation of\n * user input into executable contexts.\n */\n\n/** HTML text-content escaping. Order matters: ampersand first. */\nexport function escapeHtml(input: string): string {\n return input\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\n/** Escaping for values placed inside double-quoted HTML attributes. */\nexport function escapeAttribute(input: string): string {\n return escapeHtml(input);\n}\n\n/** Protocols we consider safe for links. */\nconst SAFE_PROTOCOLS = new Set([\"http:\", \"https:\", \"mailto:\", \"tel:\", \"ftp:\", \"sms:\"]);\n\n/**\n * Matches the leading `scheme:` of a URL. We strip ASCII control characters\n * and whitespace first because browsers ignore them inside the scheme\n * (`java\\tscript:` is a classic bypass).\n */\nconst SCHEME_RE = /^([a-z][a-z0-9+.-]*):/i;\n\n/** Matches ASCII control characters (0x00–0x1F and 0x7F). */\n// eslint-disable-next-line no-control-regex\nconst CONTROL_CHARS_RE = /[\\x00-\\x1f\\x7f]/g;\n\nexport interface UrlSanitizeResult {\n /** Safe URL, or `\"#\"` when the input was rejected. */\n safe: string;\n /** True when the original URL was blocked. */\n blocked: boolean;\n /** The detected scheme, when present. */\n scheme?: string;\n}\n\n/**\n * Sanitize a URL for use in an `href`.\n *\n * - Relative URLs and fragments are allowed as-is.\n * - Absolute URLs are allowed only for an allow-listed protocol.\n * - `javascript:`, `data:`, `vbscript:`, `file:` and friends are blocked.\n * - Control characters used to obfuscate the scheme are removed first.\n */\nexport function sanitizeUrl(input: string): UrlSanitizeResult {\n const raw = String(input ?? \"\").trim();\n\n // Strip ASCII control characters (incl. tabs/newlines) that browsers ignore\n // and that are commonly used to hide a `javascript:` scheme, e.g.\n // `java\\tscript:alert(1)`. They are removed from the emitted value too.\n const cleaned = raw.replace(CONTROL_CHARS_RE, \"\");\n\n const match = SCHEME_RE.exec(cleaned);\n if (!match) {\n // No scheme → relative URL, fragment, query, or protocol-relative.\n return { safe: cleaned, blocked: false };\n }\n\n const scheme = match[1]!.toLowerCase() + \":\";\n if (SAFE_PROTOCOLS.has(scheme)) {\n return { safe: cleaned, blocked: false, scheme };\n }\n\n return { safe: \"#\", blocked: true, scheme };\n}\n\n/**\n * Validate a CSS color token. Accepts `#rgb`, `#rrggbb`, `#rrggbbaa`,\n * `rgb()/rgba()/hsl()/hsla()` functional notation, and a curated set of\n * CSS named colors. Anything else is rejected so it can't smuggle\n * `url(javascript:…)` or `expression(...)` into a `style` attribute.\n */\nexport function isSafeColor(value: string): boolean {\n const v = value.trim();\n if (/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(v)) return true;\n if (/^(rgb|rgba|hsl|hsla)\\(\\s*[0-9.,%\\s/]+\\)$/i.test(v)) return true;\n return CSS_NAMED_COLORS.has(v.toLowerCase());\n}\n\n/**\n * Validate a CSS length/dimension such as `14pt`, `1.5rem`, `40%`, `200px`.\n * Used for `\\fontsize`, `\\column` widths and spacing commands.\n */\nexport function isSafeDimension(value: string): boolean {\n return /^-?\\d*\\.?\\d+(px|pt|em|rem|ex|ch|vw|vh|vmin|vmax|cm|mm|in|pc|%|fr)?$/.test(\n value.trim(),\n );\n}\n\n/**\n * Sanitize a value destined for a CSS property. Returns `undefined` when the\n * value is unsafe so callers can omit the declaration entirely.\n */\nexport function sanitizeStyleValue(value: string): string | undefined {\n const v = value.trim();\n if (/[<>;{}]/.test(v) || /expression|url\\s*\\(|javascript:/i.test(v)) {\n return undefined;\n }\n return v;\n}\n\n/** A pragmatic subset of CSS named colors. */\nexport const CSS_NAMED_COLORS = new Set([\n \"black\",\n \"silver\",\n \"gray\",\n \"grey\",\n \"white\",\n \"maroon\",\n \"red\",\n \"purple\",\n \"fuchsia\",\n \"green\",\n \"lime\",\n \"olive\",\n \"yellow\",\n \"navy\",\n \"blue\",\n \"teal\",\n \"aqua\",\n \"cyan\",\n \"magenta\",\n \"orange\",\n \"pink\",\n \"brown\",\n \"gold\",\n \"indigo\",\n \"violet\",\n \"tan\",\n \"beige\",\n \"ivory\",\n \"coral\",\n \"salmon\",\n \"khaki\",\n \"crimson\",\n \"turquoise\",\n \"lavender\",\n \"plum\",\n \"orchid\",\n \"slateblue\",\n \"slategray\",\n \"steelblue\",\n \"skyblue\",\n \"royalblue\",\n \"midnightblue\",\n \"darkblue\",\n \"darkgreen\",\n \"darkred\",\n \"darkgray\",\n \"darkgrey\",\n \"lightgray\",\n \"lightgrey\",\n \"lightblue\",\n \"transparent\",\n \"currentcolor\",\n \"inherit\",\n]);\n","import type {\n CommandDefinition,\n Position,\n SourceRange,\n ThemeColors,\n} from \"../types/index.js\";\nimport { DiagnosticSeverity, DiagnosticCode } from \"../types/diagnostics.js\";\nimport { isSafeColor } from \"../security/sanitize.js\";\nimport type { ReTeXLibrary } from \"./types.js\";\n\nconst zero: Position = { offset: 0, line: 1, column: 1 };\nconst ZERO_RANGE: SourceRange = { start: zero, end: zero };\n\n/**\n * Commands provided by the `colors` library: `\\textcolor` (an explicit\n * hex/named color) and `\\themecolor` (a swatch from the active theme). Both\n * produce core AST nodes, so the standard renderers display them once the\n * library is active.\n */\nexport const colorCommands: CommandDefinition[] = [\n {\n name: \"textcolor\",\n category: \"inline\",\n args: [\n { kind: \"string\", name: \"color\", format: \"color\" },\n { kind: \"content\", name: \"content\" },\n ],\n summary: \"Color text with a hex/named color.\",\n example: \"\\\\textcolor{#2563eb}{OpenAI}\",\n build: ({ args, utils, report }) => {\n const color = utils.textOf(args[0]).trim();\n if (color && !isSafeColor(color)) {\n report({\n severity: DiagnosticSeverity.Warning,\n code: DiagnosticCode.InvalidColor,\n message: `\"${color}\" is not a recognized color; it will be ignored.`,\n range: args[0]?.range ?? ZERO_RANGE,\n });\n }\n return {\n type: \"color\",\n color: isSafeColor(color) ? color : \"\",\n children: args[1]?.children ?? [],\n };\n },\n },\n {\n name: \"themecolor\",\n category: \"inline\",\n args: [\n { kind: \"string\", name: \"token\" },\n { kind: \"content\", name: \"content\" },\n ],\n summary: \"Color text using a token from the active theme.\",\n example: \"\\\\themecolor{primary}{Highlighted}\",\n build: ({ args, utils }) => ({\n type: \"themecolor\",\n token: utils.textOf(args[0]).trim() || \"primary\",\n children: args[1]?.children ?? [],\n }),\n },\n];\n\n/**\n * A catalog of ready-made color palettes. Apply one as a theme patch, e.g.\n * `new ReTeXEngine({ theme: { colors: palettes.violet } })`, or reference its\n * swatches from `\\themecolor{...}` once `colors` is active.\n */\nexport const palettes: Record<string, ThemeColors> = {\n slate: {\n primary: \"#0f172a\",\n secondary: \"#475569\",\n text: \"#1e293b\",\n muted: \"#64748b\",\n border: \"#cbd5e1\",\n accent: \"#0f172a\",\n },\n blue: {\n primary: \"#2563eb\",\n secondary: \"#64748b\",\n text: \"#1e293b\",\n muted: \"#64748b\",\n border: \"#e2e8f0\",\n accent: \"#2563eb\",\n },\n violet: {\n primary: \"#7c3aed\",\n secondary: \"#6b7280\",\n text: \"#111827\",\n muted: \"#6b7280\",\n border: \"#e5e7eb\",\n accent: \"#7c3aed\",\n },\n emerald: {\n primary: \"#059669\",\n secondary: \"#6b7280\",\n text: \"#111827\",\n muted: \"#6b7280\",\n border: \"#d1fae5\",\n accent: \"#059669\",\n },\n rose: {\n primary: \"#e11d48\",\n secondary: \"#6b7280\",\n text: \"#111827\",\n muted: \"#6b7280\",\n border: \"#fecdd3\",\n accent: \"#e11d48\",\n },\n amber: {\n primary: \"#d97706\",\n secondary: \"#6b7280\",\n text: \"#111827\",\n muted: \"#6b7280\",\n border: \"#fde68a\",\n accent: \"#d97706\",\n },\n};\n\n/**\n * The `colors` library — text color commands plus a palette catalog.\n *\n * ```ts\n * engine.use(colorsLibrary); // or \\usepackage{colors}\n * engine.toHtml(\"\\\\textcolor{#7c3aed}{Hi}\");\n * ```\n */\nexport const colorsLibrary: ReTeXLibrary = {\n name: \"colors\",\n summary: \"Text color (\\\\textcolor, \\\\themecolor) and named palettes.\",\n commands: colorCommands,\n};\n","import type {\n CommandDefinition,\n Position,\n SourceRange,\n ThemeFonts,\n} from \"../types/index.js\";\nimport { DiagnosticSeverity, DiagnosticCode } from \"../types/diagnostics.js\";\nimport { isSafeDimension } from \"../security/sanitize.js\";\nimport type { ReTeXLibrary } from \"./types.js\";\n\nconst zero: Position = { offset: 0, line: 1, column: 1 };\nconst ZERO_RANGE: SourceRange = { start: zero, end: zero };\n\nconst scaleSwitch = (\n name: string,\n scale: \"small\" | \"large\" | \"Large\" | \"Huge\",\n): CommandDefinition => ({\n name,\n category: \"switch\",\n scoped: true,\n summary: `Set the font size to \"${name}\" for the rest of the group.`,\n example: `{\\\\${name} ...}`,\n build: ({ scope }) => ({ type: \"fontscale\", scale, children: scope }),\n});\n\n/**\n * Commands provided by the `fonts` library: explicit family/size control\n * (`\\fontfamily`, `\\fontsize`), the relative size switches (`\\small`, `\\large`,\n * `\\Large`, `\\Huge`, `\\normalsize`), and the monospace switch (`\\ttfamily`).\n */\nexport const fontCommands: CommandDefinition[] = [\n {\n name: \"fontsize\",\n category: \"inline\",\n args: [\n { kind: \"string\", name: \"size\", format: \"dimension\" },\n { kind: \"content\", name: \"content\" },\n ],\n summary: \"Set an explicit font size for the wrapped content.\",\n example: \"\\\\fontsize{14pt}{Custom Size}\",\n build: ({ args, utils, report }) => {\n const size = utils.textOf(args[0]).trim();\n if (size && !isSafeDimension(size)) {\n report({\n severity: DiagnosticSeverity.Warning,\n code: DiagnosticCode.InvalidDimension,\n message: `\"${size}\" is not a valid dimension.`,\n range: args[0]?.range ?? ZERO_RANGE,\n });\n }\n return {\n type: \"fontsize\",\n size: isSafeDimension(size) ? size : \"1em\",\n children: args[1]?.children ?? [],\n };\n },\n },\n {\n name: \"fontfamily\",\n category: \"inline\",\n args: [\n { kind: \"string\", name: \"family\" },\n { kind: \"content\", name: \"content\" },\n ],\n summary: \"Set the font family for the wrapped content.\",\n example: \"\\\\fontfamily{Georgia}{Serif text}\",\n build: ({ args, utils }) => ({\n type: \"fontfamily\",\n family: utils.textOf(args[0]).trim() || \"inherit\",\n children: args[1]?.children ?? [],\n }),\n },\n scaleSwitch(\"small\", \"small\"),\n scaleSwitch(\"large\", \"large\"),\n scaleSwitch(\"Large\", \"Large\"),\n scaleSwitch(\"Huge\", \"Huge\"),\n {\n name: \"normalsize\",\n category: \"switch\",\n scoped: true,\n summary: \"Reset the font size to the document base size.\",\n build: ({ scope }) => ({ type: \"fontscale\", scale: \"normal\", children: scope }),\n },\n {\n name: \"ttfamily\",\n category: \"switch\",\n scoped: true,\n summary: \"Switch to a monospace font for the rest of the group.\",\n build: ({ scope }) => ({\n type: \"fontfamily\",\n family: \"monospace\",\n children: scope,\n }),\n },\n];\n\n/**\n * A catalog of vetted font stacks. Use a key as a `\\fontfamily` argument, or\n * build a `fonts` theme patch with {@link fontTheme}.\n */\nexport const fontStacks: Record<string, string> = {\n inter: '\"Inter\", \"Helvetica Neue\", Helvetica, Arial, sans-serif',\n system: 'system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, sans-serif',\n helvetica: '\"Helvetica Neue\", Helvetica, Arial, sans-serif',\n georgia: 'Georgia, \"Times New Roman\", Times, serif',\n times: '\"Times New Roman\", Times, serif',\n garamond: '\"EB Garamond\", Garamond, Georgia, serif',\n spaceGrotesk: '\"Space Grotesk\", system-ui, sans-serif',\n sourceSerif: '\"Source Serif 4\", Georgia, serif',\n jetbrainsMono: '\"JetBrains Mono\", \"SF Mono\", \"Fira Code\", Consolas, monospace',\n firaCode: '\"Fira Code\", \"JetBrains Mono\", Consolas, monospace',\n ibmPlexMono: '\"IBM Plex Mono\", \"SF Mono\", Consolas, monospace',\n};\n\n/**\n * Build a `fonts` theme patch from named {@link fontStacks} (or raw CSS stacks).\n *\n * ```ts\n * new ReTeXEngine({ theme: { fonts: fontTheme({ heading: \"spaceGrotesk\", body: \"inter\" }) } });\n * ```\n */\nexport function fontTheme(spec: Partial<Record<keyof ThemeFonts, string>>): ThemeFonts {\n const resolve = (v?: string): string | undefined =>\n v == null ? undefined : (fontStacks[v] ?? v);\n return {\n heading: resolve(spec.heading),\n body: resolve(spec.body),\n mono: resolve(spec.mono),\n };\n}\n\n/**\n * The `fonts` library — font family/size control plus a stack catalog.\n *\n * ```ts\n * engine.use(fontsLibrary); // or \\usepackage{fonts}\n * engine.toHtml(\"{\\\\large \\\\fontfamily{Georgia}{Hi}}\");\n * ```\n */\nexport const fontsLibrary: ReTeXLibrary = {\n name: \"fonts\",\n summary: \"Font family & size control (\\\\fontfamily, \\\\fontsize, \\\\small … \\\\Huge).\",\n commands: fontCommands,\n};\n","import type { CommandDefinition, RuleNode } from \"../types/index.js\";\nimport type { ReTeXLibrary } from \"./types.js\";\n\nconst rule = (\n name: string,\n style: RuleNode[\"style\"],\n summary: string,\n): CommandDefinition => ({\n name,\n category: \"block\",\n summary,\n example: `\\\\${name}`,\n build: () => (style ? { type: \"rule\", style } : { type: \"rule\" }),\n});\n\n/**\n * Commands provided by the `shapes` library: horizontal rules / dividers in a\n * few styles, plus explicit spacing. All produce core AST nodes.\n */\nexport const shapeCommands: CommandDefinition[] = [\n rule(\"hrule\", \"solid\", \"A horizontal rule / divider.\"),\n rule(\"divider\", \"solid\", \"A horizontal rule / divider.\"),\n rule(\"dashrule\", \"dashed\", \"A dashed horizontal rule.\"),\n rule(\"dotrule\", \"dotted\", \"A dotted horizontal rule.\"),\n rule(\"thickrule\", \"thick\", \"A thick horizontal rule.\"),\n rule(\"doublerule\", \"double\", \"A double horizontal rule.\"),\n {\n name: \"vspace\",\n category: \"block\",\n args: [{ kind: \"string\", name: \"size\", format: \"dimension\" }],\n summary: \"Vertical space.\",\n example: \"\\\\vspace{1em}\",\n build: ({ args, utils }) => ({\n type: \"space\",\n axis: \"vertical\",\n size: utils.textOf(args[0]).trim() || \"1em\",\n }),\n },\n {\n name: \"hspace\",\n category: \"inline\",\n args: [{ kind: \"string\", name: \"size\", format: \"dimension\" }],\n summary: \"Horizontal space.\",\n example: \"\\\\hspace{1em}\",\n build: ({ args, utils }) => ({\n type: \"space\",\n axis: \"horizontal\",\n size: utils.textOf(args[0]).trim() || \"1em\",\n }),\n },\n];\n\n/**\n * The `shapes` library — rules, dividers, and spacing.\n *\n * ```ts\n * engine.use(shapesLibrary); // or \\usepackage{shapes}\n * engine.toHtml(\"\\\\hrule \\\\dashrule \\\\vspace{1em}\");\n * ```\n */\nexport const shapesLibrary: ReTeXLibrary = {\n name: \"shapes\",\n summary: \"Horizontal rules / dividers (\\\\hrule, \\\\dashrule, …) and spacing.\",\n commands: shapeCommands,\n};\n","import type { Theme } from \"../types/theme.js\";\n\n/**\n * The default ReTeX theme is **blank** — it defines no colors, fonts, sizes, or\n * section decoration. A document rendered with it is a clean, browser-default\n * page: black text, the user agent's default font, plain section headings, and\n * no accent colors or rules. This is \"just simple editing\".\n *\n * Visual styling is opt-in. Import a library to populate this theme:\n *\n * - `\\usepackage{fonts}` / `engine.use(fontsLibrary)` — fonts & sizes\n * - `\\usepackage{shapes}` / `engine.use(shapesLibrary)` — rules, dividers, spacing\n * - `\\usepackage{colors}` / `engine.use(colorsLibrary)` — text color & palettes\n * - `\\usepackage{modern}` / `engine.use(modernTheme)` — a full styled look\n *\n * Every renderer treats theme values as optional and substitutes a neutral,\n * unstyled fallback when a field is absent, so the blank theme always produces\n * a readable document.\n */\nexport const blankTheme: Theme = {\n name: \"blank\",\n};\n\n/** Alias kept for backwards compatibility — the default theme is the blank one. */\nexport const defaultTheme: Theme = blankTheme;\n","import type { PartialTheme, Theme } from \"../types/theme.js\";\nimport { blankTheme, defaultTheme } from \"./default.js\";\n\n/**\n * Deep-merge a partial theme over a base theme (sub-objects merged shallowly).\n * The result always has defined (possibly empty) sub-objects, so consumers can\n * safely read `theme.colors`, `theme.fonts`, … without null checks even when\n * the base is the blank theme.\n */\nexport function resolveTheme(partial?: PartialTheme, base: Theme = defaultTheme): Theme {\n return {\n name: partial?.name ?? base.name,\n colors: { ...base.colors, ...partial?.colors },\n fonts: { ...base.fonts, ...partial?.fonts },\n fontSizes: { ...base.fontSizes, ...partial?.fontSizes },\n spacing: { ...base.spacing, ...partial?.spacing },\n page: { ...base.page, ...partial?.page },\n sectionStyle: partial?.sectionStyle ?? base.sectionStyle,\n headings: { ...base.headings, ...partial?.headings },\n };\n}\n\n/**\n * A complete, ATS-friendly typographic foundation. The styled presets below are\n * built on top of this; the blank default deliberately ships none of it, so a\n * plain document only gets this look once a theme/library is imported.\n */\nconst styledBase: PartialTheme = {\n fonts: {\n heading: '\"Inter\", \"Helvetica Neue\", Helvetica, Arial, sans-serif',\n body: '\"Inter\", \"Helvetica Neue\", Helvetica, Arial, sans-serif',\n mono: '\"JetBrains Mono\", \"SF Mono\", \"Fira Code\", Consolas, monospace',\n },\n fontSizes: {\n base: \"10.5pt\",\n small: \"9pt\",\n large: \"12pt\",\n Large: \"15pt\",\n Huge: \"22pt\",\n name: \"26pt\",\n section: \"13pt\",\n },\n spacing: { unit: \"4px\", section: \"1.1rem\", item: \"0.28rem\", page: \"0.55in\" },\n page: { size: \"Letter\", margin: \"0.55in\", maxWidth: \"8.5in\" },\n headings: { transform: \"uppercase\", tracking: \"0.06em\", nameTracking: \"-0.01em\" },\n};\n\n/** A modern, accent-forward theme with underlined section headings. */\nexport const modernTheme: Theme = resolveTheme({\n ...styledBase,\n name: \"modern\",\n colors: {\n primary: \"#7c3aed\",\n secondary: \"#64748b\",\n text: \"#111827\",\n muted: \"#64748b\",\n background: \"#ffffff\",\n border: \"#e2e8f0\",\n accent: \"#7c3aed\",\n },\n sectionStyle: \"underline\",\n});\n\n/** A restrained, classic serif theme suited to academic CVs. */\nexport const classicTheme: Theme = resolveTheme({\n ...styledBase,\n name: \"classic\",\n colors: {\n primary: \"#111827\",\n secondary: \"#4b5563\",\n text: \"#1e293b\",\n muted: \"#4b5563\",\n background: \"#ffffff\",\n border: \"#cbd5e1\",\n accent: \"#111827\",\n },\n fonts: {\n heading: 'Georgia, \"Times New Roman\", serif',\n body: 'Georgia, \"Times New Roman\", serif',\n mono: 'Consolas, \"Courier New\", monospace',\n },\n sectionStyle: \"rule\",\n});\n\n/** A compact, single-accent theme that maximizes content density. */\nexport const compactTheme: Theme = resolveTheme({\n ...styledBase,\n name: \"compact\",\n colors: {\n primary: \"#2563eb\",\n secondary: \"#64748b\",\n text: \"#1e293b\",\n muted: \"#64748b\",\n background: \"#ffffff\",\n border: \"#e2e8f0\",\n accent: \"#2563eb\",\n },\n fontSizes: {\n base: \"9.5pt\",\n small: \"8pt\",\n large: \"11pt\",\n Large: \"13pt\",\n Huge: \"18pt\",\n name: \"20pt\",\n section: \"11pt\",\n },\n spacing: { unit: \"3px\", section: \"0.7rem\", item: \"0.18rem\", page: \"0.4in\" },\n sectionStyle: \"bar\",\n});\n\n/**\n * Built-in theme presets keyed by name. `default` and `blank` both map to the\n * unstyled theme; the styled presets are opt-in (import them, or activate them\n * with `\\usepackage{modern}` etc.).\n */\nexport const themes: Record<string, Theme> = {\n blank: blankTheme,\n default: blankTheme,\n modern: modernTheme,\n classic: classicTheme,\n compact: compactTheme,\n};\n\n/** Look up a preset theme by name, falling back to the blank default. */\nexport function getTheme(name: string): Theme {\n return themes[name] ?? defaultTheme;\n}\n","import { modernTheme, classicTheme, compactTheme } from \"../theme/themes.js\";\nimport { colorCommands } from \"./colors.js\";\nimport { fontCommands } from \"./fonts.js\";\nimport { shapeCommands } from \"./shapes.js\";\nimport type { ReTeXLibrary } from \"./types.js\";\n\n/**\n * Theme packs bundle a complete styled look *and* the full styling toolkit\n * (color, font, and shape commands), so importing one gives you a polished\n * document plus everything needed to customize it further.\n */\nconst stylingCommands = [...colorCommands, ...fontCommands, ...shapeCommands];\n\n/** `\\usepackage{modern}` — accent-forward look with underlined headings. */\nexport const modernLibrary: ReTeXLibrary = {\n name: \"modern\",\n summary: \"A modern, accent-forward theme (violet, underlined headings).\",\n theme: modernTheme,\n commands: stylingCommands,\n};\n\n/** `\\usepackage{classic}` — restrained serif look for academic CVs. */\nexport const classicLibrary: ReTeXLibrary = {\n name: \"classic\",\n summary: \"A classic serif theme with ruled section headings.\",\n theme: classicTheme,\n commands: stylingCommands,\n};\n\n/** `\\usepackage{compact}` — dense, single-accent look. */\nexport const compactLibrary: ReTeXLibrary = {\n name: \"compact\",\n summary: \"A compact, single-accent theme maximizing content density.\",\n theme: compactTheme,\n commands: stylingCommands,\n};\n","import type { SourceRange } from \"./source.js\";\n\n/**\n * The ReTeX Abstract Syntax Tree.\n *\n * Every node is a member of the {@link Node} discriminated union keyed on\n * `type`. Nodes fall into three broad families:\n *\n * - **Structural** — {@link DocumentNode}, {@link GroupNode}, {@link ParBreakNode}.\n * - **Inline / typography** — text, marks (bold/italic/…), links, icons.\n * - **Resume semantics** — sections, jobs, education, skills, contact fields.\n *\n * Unknown or plugin-provided commands are preserved as {@link CommandNode} so\n * the tree is always a faithful, loss-less representation of the source and can\n * be re-rendered by custom renderers.\n */\n\nexport interface NodeBase {\n type: string;\n /** Source span this node was produced from. Synthetic nodes may omit it. */\n range?: SourceRange;\n /**\n * Stable structural hash used by the incremental compiler / render cache.\n * Populated lazily; never authored by hand.\n */\n hash?: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Structural nodes */\n/* ------------------------------------------------------------------ */\n\nexport interface DocumentNode extends NodeBase {\n type: \"document\";\n children: Node[];\n}\n\n/** A literal run of text. */\nexport interface TextNode extends NodeBase {\n type: \"text\";\n value: string;\n}\n\n/** A paragraph break (one or more blank lines). */\nexport interface ParBreakNode extends NodeBase {\n type: \"parbreak\";\n}\n\n/** An explicit line break (`\\\\` or `\\newline`). */\nexport interface LineBreakNode extends NodeBase {\n type: \"linebreak\";\n}\n\n/** A horizontal rule / divider (`\\hrule`, `\\divider`, and the `shapes` library's\n * styled variants like `\\dashrule`). */\nexport interface RuleNode extends NodeBase {\n type: \"rule\";\n /** Visual style. Defaults to a thin solid line when omitted. */\n style?: \"solid\" | \"dashed\" | \"dotted\" | \"thick\" | \"double\";\n}\n\n/** Spacing primitive (`\\vspace{1em}` / `\\hspace{...}`). */\nexport interface SpaceNode extends NodeBase {\n type: \"space\";\n axis: \"horizontal\" | \"vertical\";\n size: string;\n}\n\n/** A bare `{ ... }` group. Mostly used to scope font switches. */\nexport interface GroupNode extends NodeBase {\n type: \"group\";\n children: Node[];\n}\n\n/**\n * `\\usepackage{shapes, colors}` — a preamble directive that imports one or more\n * styling libraries for the document. Produces no visible output; the engine\n * reads these to register the libraries' commands and merge their theme.\n */\nexport interface UsePackageNode extends NodeBase {\n type: \"usepackage\";\n names: string[];\n}\n\n/* ------------------------------------------------------------------ */\n/* Typography / inline marks */\n/* ------------------------------------------------------------------ */\n\nexport type MarkType = \"bold\" | \"italic\" | \"underline\" | \"strike\";\n\n/** Simple wrapping mark such as `\\textbf{...}`. */\nexport interface MarkNode extends NodeBase {\n type: MarkType;\n children: Node[];\n}\n\n/** `\\textcolor{#hex|name}{...}` */\nexport interface ColorNode extends NodeBase {\n type: \"color\";\n color: string;\n children: Node[];\n}\n\n/** `\\themecolor{primary}{...}` — color resolved from the active theme. */\nexport interface ThemeColorNode extends NodeBase {\n type: \"themecolor\";\n token: string;\n children: Node[];\n}\n\n/** `\\fontsize{14pt}{...}` */\nexport interface FontSizeNode extends NodeBase {\n type: \"fontsize\";\n size: string;\n children: Node[];\n}\n\n/** `\\fontfamily{Inter}{...}` */\nexport interface FontFamilyNode extends NodeBase {\n type: \"fontfamily\";\n family: string;\n children: Node[];\n}\n\n/** Relative size switch: `\\small`, `\\large`, `\\Large`, `\\Huge`. */\nexport type FontScale = \"small\" | \"normal\" | \"large\" | \"Large\" | \"Huge\";\nexport interface FontScaleNode extends NodeBase {\n type: \"fontscale\";\n scale: FontScale;\n /** Content the switch applies to (rest of the enclosing group). */\n children: Node[];\n}\n\n/* ------------------------------------------------------------------ */\n/* Hyperlinks & icons */\n/* ------------------------------------------------------------------ */\n\n/** `\\href{url}{label}` */\nexport interface LinkNode extends NodeBase {\n type: \"link\";\n /** Sanitized, render-safe URL. */\n href: string;\n /** Original, unsanitized URL (kept for diagnostics / round-tripping). */\n rawHref: string;\n children: Node[];\n}\n\n/** `\\url{url}` — renders the URL as its own label. */\nexport interface UrlNode extends NodeBase {\n type: \"url\";\n href: string;\n rawHref: string;\n}\n\n/** `\\icon{github}` */\nexport interface IconNode extends NodeBase {\n type: \"icon\";\n name: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Sections & lists */\n/* ------------------------------------------------------------------ */\n\nexport interface SectionNode extends NodeBase {\n type: \"section\";\n title: string;\n /** 1 = `\\section`, 2 = `\\subsection`. */\n level: number;\n}\n\nexport type ListKind = \"itemize\" | \"enumerate\";\n\nexport interface ListNode extends NodeBase {\n type: \"list\";\n kind: ListKind;\n items: ListItemNode[];\n}\n\nexport interface ListItemNode extends NodeBase {\n type: \"item\";\n children: Node[];\n}\n\n/* ------------------------------------------------------------------ */\n/* Layout */\n/* ------------------------------------------------------------------ */\n\nexport interface ColumnsNode extends NodeBase {\n type: \"columns\";\n columns: ColumnNode[];\n /** Gap between columns, e.g. `\"1.5rem\"`. */\n gap?: string;\n}\n\nexport interface ColumnNode extends NodeBase {\n type: \"column\";\n /** Width as authored (`\"40%\"`, `\"200px\"`, `\"2fr\"`). */\n width: string;\n children: Node[];\n}\n\n/* ------------------------------------------------------------------ */\n/* Resume / CV semantics */\n/* ------------------------------------------------------------------ */\n\nexport type ContactField = \"name\" | \"title\" | \"email\" | \"phone\" | \"location\" | \"website\";\n\n/** One of the single-value header commands (`\\name`, `\\email`, …). */\nexport interface ContactNode extends NodeBase {\n type: \"contact\";\n field: ContactField;\n value: string;\n}\n\n/** Parsed `key=value` map preserving per-field source ranges. */\nexport interface FieldMap {\n [key: string]: string;\n}\n\n/** `\\job{title=…, company=…, …}{ body }` */\nexport interface JobNode extends NodeBase {\n type: \"job\";\n fields: FieldMap;\n children: Node[];\n}\n\n/** `\\education{school=…, degree=…, …}{ body? }` */\nexport interface EducationNode extends NodeBase {\n type: \"education\";\n fields: FieldMap;\n children: Node[];\n}\n\n/** `\\project{name=…, …}{ body? }` */\nexport interface ProjectNode extends NodeBase {\n type: \"project\";\n fields: FieldMap;\n children: Node[];\n}\n\n/** `\\skills{a, b, c}` */\nexport interface SkillsNode extends NodeBase {\n type: \"skills\";\n items: string[];\n}\n\n/* ------------------------------------------------------------------ */\n/* Generic / extensibility / recovery */\n/* ------------------------------------------------------------------ */\n\n/** A parsed argument attached to a generic {@link CommandNode}. */\nexport interface ArgumentNode {\n kind: \"required\" | \"optional\";\n /** Parsed children for `content` arguments. */\n children: Node[];\n /** Raw text for `string`/verbatim arguments. */\n raw?: string;\n range?: SourceRange;\n}\n\n/**\n * A command the core does not model natively — including every\n * plugin-registered command and any unknown command encountered during\n * lenient parsing. Keeps the tree loss-less.\n */\nexport interface CommandNode extends NodeBase {\n type: \"command\";\n name: string;\n args: ArgumentNode[];\n}\n\n/** A placeholder emitted during error recovery so rendering can continue. */\nexport interface ErrorNode extends NodeBase {\n type: \"error\";\n message: string;\n /** The raw source that could not be parsed. */\n raw: string;\n}\n\n/* ------------------------------------------------------------------ */\n/* Union & helpers */\n/* ------------------------------------------------------------------ */\n\nexport type Node =\n | DocumentNode\n | TextNode\n | ParBreakNode\n | LineBreakNode\n | RuleNode\n | SpaceNode\n | GroupNode\n | UsePackageNode\n | MarkNode\n | ColorNode\n | ThemeColorNode\n | FontSizeNode\n | FontFamilyNode\n | FontScaleNode\n | LinkNode\n | UrlNode\n | IconNode\n | SectionNode\n | ListNode\n | ListItemNode\n | ColumnsNode\n | ColumnNode\n | ContactNode\n | JobNode\n | EducationNode\n | ProjectNode\n | SkillsNode\n | CommandNode\n | ErrorNode;\n\nexport type NodeType = Node[\"type\"];\n\n/** Map from node `type` to its concrete interface, for typed visitors. */\nexport interface NodeMap {\n document: DocumentNode;\n text: TextNode;\n parbreak: ParBreakNode;\n linebreak: LineBreakNode;\n rule: RuleNode;\n space: SpaceNode;\n group: GroupNode;\n usepackage: UsePackageNode;\n bold: MarkNode;\n italic: MarkNode;\n underline: MarkNode;\n strike: MarkNode;\n color: ColorNode;\n themecolor: ThemeColorNode;\n fontsize: FontSizeNode;\n fontfamily: FontFamilyNode;\n fontscale: FontScaleNode;\n link: LinkNode;\n url: UrlNode;\n icon: IconNode;\n section: SectionNode;\n list: ListNode;\n item: ListItemNode;\n columns: ColumnsNode;\n column: ColumnNode;\n contact: ContactNode;\n job: JobNode;\n education: EducationNode;\n project: ProjectNode;\n skills: SkillsNode;\n command: CommandNode;\n error: ErrorNode;\n}\n\n/** Nodes that carry a `children: Node[]` array. */\nexport type ParentNode = Extract<Node, { children: Node[] }>;\n\nexport function isParent(node: Node): node is ParentNode {\n return Array.isArray((node as { children?: unknown }).children);\n}\n\n/** Type guard generator for a given node type. */\nexport function isNode<T extends NodeType>(node: Node, type: T): node is NodeMap[T] {\n return node.type === type;\n}\n","import {\n isParent,\n type Node,\n type ParentNode,\n type ListNode,\n type ColumnsNode,\n} from \"../types/ast.js\";\n\n/** Return the child nodes of any node, regardless of where they're stored. */\nexport function childrenOf(node: Node): Node[] {\n if (node.type === \"list\") return (node as ListNode).items;\n if (node.type === \"columns\") return (node as ColumnsNode).columns;\n if (isParent(node)) return (node as ParentNode).children;\n return [];\n}\n\nexport interface VisitOptions {\n /** Called before visiting children. Return `false` to skip the subtree. */\n enter?: (node: Node, parent: Node | null) => boolean | void;\n /** Called after visiting children. */\n exit?: (node: Node, parent: Node | null) => void;\n}\n\n/** Depth-first traversal of the tree. */\nexport function walk(root: Node, opts: VisitOptions): void {\n const visit = (node: Node, parent: Node | null): void => {\n const descend = opts.enter ? opts.enter(node, parent) : undefined;\n if (descend !== false) {\n for (const child of childrenOf(node)) visit(child, node);\n }\n opts.exit?.(node, parent);\n };\n visit(root, null);\n}\n\n/** Collect every node matching a predicate. */\nexport function collect(root: Node, pred: (n: Node) => boolean): Node[] {\n const out: Node[] = [];\n walk(root, {\n enter(n) {\n if (pred(n)) out.push(n);\n },\n });\n return out;\n}\n\n/** Find the innermost node whose range contains `offset`, plus its ancestors. */\nexport function nodePathAt(root: Node, offset: number): Node[] {\n const path: Node[] = [];\n const visit = (node: Node): boolean => {\n const r = node.range;\n if (r && (offset < r.start.offset || offset > r.end.offset)) return false;\n path.push(node);\n for (const child of childrenOf(node)) {\n if (visit(child)) break;\n }\n return true;\n };\n visit(root);\n return path;\n}\n","import {\n TokenType,\n DiagnosticSeverity,\n DiagnosticCode,\n type Token,\n type Node,\n type Theme,\n type Diagnostic,\n type DocumentNode,\n type CommandNode,\n type UsePackageNode,\n} from \"../types/index.js\";\nimport { CommandRegistry } from \"../parser/registry.js\";\nimport { resolveTheme } from \"../theme/themes.js\";\nimport { collect } from \"../ast/walk.js\";\nimport type { HtmlRenderFn } from \"../renderers/context.js\";\nimport type { ReactRenderFn } from \"../renderers/react.js\";\nimport type { ReTeXLibrary } from \"./types.js\";\nimport { colorsLibrary } from \"./colors.js\";\nimport { fontsLibrary } from \"./fonts.js\";\nimport { shapesLibrary } from \"./shapes.js\";\nimport { modernLibrary, classicLibrary, compactLibrary } from \"./themes.js\";\n\n/** Built-in libraries, keyed by their canonical (lowercase) name. */\nexport const builtinLibraries: Record<string, ReTeXLibrary> = {\n colors: colorsLibrary,\n fonts: fontsLibrary,\n shapes: shapesLibrary,\n modern: modernLibrary,\n classic: classicLibrary,\n compact: compactLibrary,\n};\n\n/** Convenience aliases (singular forms). */\nconst ALIASES: Record<string, string> = {\n color: \"colors\",\n font: \"fonts\",\n shape: \"shapes\",\n};\n\n/** Resolve a (possibly aliased / differently-cased) library name. */\nexport function resolveLibraryName(name: string): string | undefined {\n const key = name.trim().toLowerCase();\n if (builtinLibraries[key]) return key;\n if (ALIASES[key]) return ALIASES[key];\n return undefined;\n}\n\n/** Look up a built-in library by name (accepts aliases). */\nexport function getBuiltinLibrary(name: string): ReTeXLibrary | undefined {\n const key = resolveLibraryName(name);\n return key ? builtinLibraries[key] : undefined;\n}\n\n/** All built-in library names, for docs / completion. */\nexport function builtinLibraryNames(): string[] {\n return Object.keys(builtinLibraries);\n}\n\n/**\n * Map of every gated command name → the library that provides it. Powers the\n * \"‹\\textcolor› requires \\usepackage{colors}\" diagnostic. Derived from the\n * library command lists so it can never drift out of sync.\n */\nexport const GATED_COMMANDS: Record<string, string> = (() => {\n const map: Record<string, string> = {};\n const add = (lib: ReTeXLibrary): void => {\n for (const c of lib.commands ?? []) map[c.name] = lib.name;\n };\n add(colorsLibrary);\n add(fontsLibrary);\n add(shapesLibrary);\n return map;\n})();\n\n/** A resolver from a library name to a library object. */\nexport type LibraryLookup = (name: string) => ReTeXLibrary | undefined;\n\nconst dedupe = (names: string[]): string[] => [...new Set(names)];\n\n/**\n * Scan a token stream for `\\usepackage{...}` / `\\use{...}` directives and return\n * the requested library names (in source order, de-duplicated). Used to decide\n * which libraries to activate *before* parsing, since a directive must enable\n * the commands that follow it.\n */\nexport function usedLibraryNamesFromTokens(tokens: Token[]): string[] {\n const names: string[] = [];\n for (let i = 0; i < tokens.length; i++) {\n const t = tokens[i]!;\n if (\n t.type !== TokenType.Command ||\n (t.value !== \"usepackage\" && t.value !== \"use\")\n ) {\n continue;\n }\n let j = i + 1;\n while (\n tokens[j] &&\n (tokens[j]!.type === TokenType.Whitespace ||\n tokens[j]!.type === TokenType.Comment)\n ) {\n j++;\n }\n if (!tokens[j] || tokens[j]!.type !== TokenType.LBrace) continue;\n j++;\n let raw = \"\";\n let depth = 0;\n while (tokens[j] && !(depth === 0 && tokens[j]!.type === TokenType.RBrace)) {\n const tj = tokens[j]!;\n if (tj.type === TokenType.LBrace) depth++;\n else if (tj.type === TokenType.RBrace) depth--;\n raw += tj.type === TokenType.Command ? `\\\\${tj.value}` : tj.value;\n j++;\n }\n for (const part of raw.split(\",\")) {\n const name = part.trim();\n if (name) names.push(name);\n }\n i = j;\n }\n return dedupe(names);\n}\n\n/** Collect library names from `\\usepackage` nodes in a parsed document. */\nexport function usedLibraryNamesFromAst(root: Node): string[] {\n const names: string[] = [];\n for (const node of collect(root, (n) => n.type === \"usepackage\")) {\n for (const name of (node as UsePackageNode).names) {\n const trimmed = name.trim();\n if (trimmed) names.push(trimmed);\n }\n }\n return dedupe(names);\n}\n\nexport interface AppliedLibraries {\n /** A clone of the base registry with the resolved libraries' commands added. */\n registry: CommandRegistry;\n /** The libraries that resolved successfully, in order. */\n libraries: ReTeXLibrary[];\n /** Requested names that did not resolve to any library. */\n missing: string[];\n}\n\n/**\n * Clone `base` and register the commands/environments of every requested\n * library that resolves via `lookup` (built-ins by default). Never mutates the\n * base registry.\n */\nexport function applyLibraries(\n base: CommandRegistry,\n names: string[],\n lookup: LibraryLookup = getBuiltinLibrary,\n): AppliedLibraries {\n const registry = base.clone();\n const libraries: ReTeXLibrary[] = [];\n const missing: string[] = [];\n for (const name of names) {\n const lib = lookup(name);\n if (!lib) {\n missing.push(name);\n continue;\n }\n libraries.push(lib);\n for (const cmd of lib.commands ?? []) registry.registerCommand(cmd);\n for (const env of lib.environments ?? []) registry.registerEnvironment(env);\n }\n return { registry, libraries, missing };\n}\n\n/** Fold each library's theme patch over a base theme, in order. */\nexport function mergeLibraryTheme(base: Theme, libraries: ReTeXLibrary[]): Theme {\n let theme = base;\n for (const lib of libraries) {\n if (lib.theme) theme = resolveTheme(lib.theme, theme);\n }\n return theme;\n}\n\nconst ZERO_RANGE = {\n start: { offset: 0, line: 1, column: 1 },\n end: { offset: 0, line: 1, column: 1 },\n};\n\n/**\n * Refine a diagnostic list with library-awareness:\n *\n * 1. Replace the generic \"unknown command\" diagnostic for a *gated* command\n * (one that lives in a library) with a clear \"import the library\" message.\n * 2. Flag unknown library names in `\\usepackage{...}` directives.\n *\n * Shared by the engine and the editor so both give identical guidance.\n */\nexport function libraryDiagnostics(\n ast: DocumentNode,\n diagnostics: Diagnostic[],\n lookup: LibraryLookup = getBuiltinLibrary,\n): Diagnostic[] {\n const gated = collect(\n ast,\n (n) => n.type === \"command\" && (n as CommandNode).name in GATED_COMMANDS,\n ) as CommandNode[];\n const gatedOffsets = new Set(\n gated.map((n) => n.range?.start.offset).filter((o): o is number => o != null),\n );\n const out = diagnostics.filter(\n (d) =>\n !(\n d.code === DiagnosticCode.UnknownCommand &&\n gatedOffsets.has(d.range.start.offset)\n ),\n );\n for (const node of gated) {\n const lib = GATED_COMMANDS[node.name]!;\n out.push({\n source: \"parser\",\n severity: DiagnosticSeverity.Warning,\n code: DiagnosticCode.LibraryRequired,\n message: `\\\\${node.name} requires the \"${lib}\" library. Add \\\\usepackage{${lib}} to the preamble (or engine.use(${lib}Library)).`,\n range: node.range ?? ZERO_RANGE,\n });\n }\n for (const node of collect(ast, (n) => n.type === \"usepackage\")) {\n for (const name of (node as UsePackageNode).names) {\n if (lookup(name)) continue;\n out.push({\n source: \"parser\",\n severity: DiagnosticSeverity.Warning,\n code: DiagnosticCode.UnknownLibrary,\n message: `Unknown library \"${name}\". Available: ${builtinLibraryNames().join(\", \")}.`,\n range: node.range ?? ZERO_RANGE,\n });\n }\n }\n return out;\n}\n\n/** Collect HTML/React render overrides contributed by a set of libraries. */\nexport function collectLibraryOverrides(libraries: ReTeXLibrary[]): {\n html: Map<string, HtmlRenderFn>;\n react: Map<string, ReactRenderFn>;\n} {\n const html = new Map<string, HtmlRenderFn>();\n const react = new Map<string, ReactRenderFn>();\n for (const lib of libraries) {\n for (const cmd of lib.commands ?? []) {\n if (cmd.render?.html) html.set(`command:${cmd.name}`, cmd.render.html);\n if (cmd.render?.react) react.set(`command:${cmd.name}`, cmd.render.react);\n }\n for (const [k, fn] of Object.entries(lib.htmlRenderers ?? {})) html.set(k, fn);\n for (const [k, fn] of Object.entries(lib.reactRenderers ?? {})) react.set(k, fn);\n }\n return { html, react };\n}\n"]}
@@ -69,9 +69,12 @@ interface ParBreakNode extends NodeBase {
69
69
  interface LineBreakNode extends NodeBase {
70
70
  type: "linebreak";
71
71
  }
72
- /** A horizontal rule (`\hrule` / `\divider`). */
72
+ /** A horizontal rule / divider (`\hrule`, `\divider`, and the `shapes` library's
73
+ * styled variants like `\dashrule`). */
73
74
  interface RuleNode extends NodeBase {
74
75
  type: "rule";
76
+ /** Visual style. Defaults to a thin solid line when omitted. */
77
+ style?: "solid" | "dashed" | "dotted" | "thick" | "double";
75
78
  }
76
79
  /** Spacing primitive (`\vspace{1em}` / `\hspace{...}`). */
77
80
  interface SpaceNode extends NodeBase {
@@ -84,6 +87,15 @@ interface GroupNode extends NodeBase {
84
87
  type: "group";
85
88
  children: Node[];
86
89
  }
90
+ /**
91
+ * `\usepackage{shapes, colors}` — a preamble directive that imports one or more
92
+ * styling libraries for the document. Produces no visible output; the engine
93
+ * reads these to register the libraries' commands and merge their theme.
94
+ */
95
+ interface UsePackageNode extends NodeBase {
96
+ type: "usepackage";
97
+ names: string[];
98
+ }
87
99
  type MarkType = "bold" | "italic" | "underline" | "strike";
88
100
  /** Simple wrapping mark such as `\textbf{...}`. */
89
101
  interface MarkNode extends NodeBase {
@@ -230,7 +242,7 @@ interface ErrorNode extends NodeBase {
230
242
  /** The raw source that could not be parsed. */
231
243
  raw: string;
232
244
  }
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;
245
+ type Node = DocumentNode | TextNode | ParBreakNode | LineBreakNode | RuleNode | SpaceNode | GroupNode | UsePackageNode | MarkNode | ColorNode | ThemeColorNode | FontSizeNode | FontFamilyNode | FontScaleNode | LinkNode | UrlNode | IconNode | SectionNode | ListNode | ListItemNode | ColumnsNode | ColumnNode | ContactNode | JobNode | EducationNode | ProjectNode | SkillsNode | CommandNode | ErrorNode;
234
246
  type NodeType = Node["type"];
235
247
  /** Map from node `type` to its concrete interface, for typed visitors. */
236
248
  interface NodeMap {
@@ -241,6 +253,7 @@ interface NodeMap {
241
253
  rule: RuleNode;
242
254
  space: SpaceNode;
243
255
  group: GroupNode;
256
+ usepackage: UsePackageNode;
244
257
  bold: MarkNode;
245
258
  italic: MarkNode;
246
259
  underline: MarkNode;
@@ -278,77 +291,100 @@ declare function isNode<T extends NodeType>(node: Node, type: T): node is NodeMa
278
291
  * Theme model. Themes are plain data so they can be serialized, shipped over
279
292
  * the wire, edited in a GUI, or composed at runtime. {@link resolveTheme}
280
293
  * (see `src/theme`) deep-merges a partial theme over the default.
294
+ *
295
+ * ReTeX is **blank by default**: the built-in theme defines no colors, fonts,
296
+ * sizes, or section decoration — every field is optional and may be left
297
+ * `undefined`, yielding a plain, browser-default document. Visual styling is
298
+ * opt-in: importing a library (`fonts`, `shapes`, `colors`, or a theme pack
299
+ * like `modern`) populates these fields. Renderers therefore treat every theme
300
+ * value as optional and fall back to a neutral, unstyled default when absent.
281
301
  */
282
302
  interface ThemeColors {
283
303
  /** Brand / accent color used for links, section rules, highlights. */
284
- primary: string;
304
+ primary?: string;
285
305
  /** Muted secondary color for meta text (dates, locations). */
286
- secondary: string;
306
+ secondary?: string;
287
307
  /** Default body text color. */
288
- text: string;
308
+ text?: string;
289
309
  /** De-emphasized text color. */
290
- muted: string;
310
+ muted?: string;
291
311
  /** Page background. */
292
- background: string;
312
+ background?: string;
293
313
  /** Hairline / border color. */
294
- border: string;
314
+ border?: string;
295
315
  /** Arbitrary named swatches usable via `\themecolor{name}`. */
296
- [token: string]: string;
316
+ [token: string]: string | undefined;
297
317
  }
298
318
  interface ThemeFonts {
299
319
  /** Font stack for headings (`\name`, `\section`). */
300
- heading: string;
320
+ heading?: string;
301
321
  /** Font stack for body text. */
302
- body: string;
322
+ body?: string;
303
323
  /** Monospace stack (code, technical skills). */
304
- mono: string;
324
+ mono?: string;
305
325
  }
306
326
  interface ThemeFontSizes {
307
327
  /** Base body size, e.g. `"11pt"`. */
308
- base: string;
309
- small: string;
310
- large: string;
311
- Large: string;
312
- Huge: string;
328
+ base?: string;
329
+ small?: string;
330
+ large?: string;
331
+ Large?: string;
332
+ Huge?: string;
313
333
  /** `\name` size. */
314
- name: string;
334
+ name?: string;
315
335
  /** `\section` heading size. */
316
- section: string;
336
+ section?: string;
317
337
  }
318
338
  interface ThemeSpacing {
319
339
  /** Vertical rhythm unit. */
320
- unit: string;
321
- section: string;
322
- item: string;
340
+ unit?: string;
341
+ section?: string;
342
+ item?: string;
323
343
  /** Page padding when rendering a full document. */
324
- page: string;
344
+ page?: string;
325
345
  }
326
346
  interface ThemePage {
327
347
  /** CSS page size keyword or dimensions, e.g. `"A4"` or `"8.5in 11in"`. */
328
- size: string;
329
- margin: string;
348
+ size?: string;
349
+ margin?: string;
330
350
  /** Max content width for screen preview. */
331
- maxWidth: string;
351
+ maxWidth?: string;
352
+ }
353
+ /**
354
+ * Section / name heading decoration. Drives the few decorative properties that
355
+ * are otherwise neutral in a blank document (uppercasing, letter-spacing). All
356
+ * optional — when absent, headings render plainly.
357
+ */
358
+ interface ThemeHeadings {
359
+ /** `text-transform` for `\section` titles (e.g. `"uppercase"`). */
360
+ transform?: string;
361
+ /** `letter-spacing` for `\section` titles. */
362
+ tracking?: string;
363
+ /** `letter-spacing` for the `\name` heading. */
364
+ nameTracking?: string;
332
365
  }
333
366
  interface Theme {
334
367
  name: string;
335
- colors: ThemeColors;
336
- fonts: ThemeFonts;
337
- fontSizes: ThemeFontSizes;
338
- spacing: ThemeSpacing;
339
- page: ThemePage;
368
+ colors?: ThemeColors;
369
+ fonts?: ThemeFonts;
370
+ fontSizes?: ThemeFontSizes;
371
+ spacing?: ThemeSpacing;
372
+ page?: ThemePage;
340
373
  /** Section heading style hint consumed by renderers. */
341
- sectionStyle: "underline" | "rule" | "plain" | "bar";
374
+ sectionStyle?: "underline" | "rule" | "plain" | "bar";
375
+ /** Optional decorative heading tweaks (uppercasing, tracking). */
376
+ headings?: ThemeHeadings;
342
377
  }
343
378
  /** A user-supplied theme override; everything is optional and deep-merged. */
344
379
  type PartialTheme = {
345
380
  name?: string;
346
- colors?: Partial<ThemeColors>;
347
- fonts?: Partial<ThemeFonts>;
348
- fontSizes?: Partial<ThemeFontSizes>;
349
- spacing?: Partial<ThemeSpacing>;
350
- page?: Partial<ThemePage>;
381
+ colors?: ThemeColors;
382
+ fonts?: ThemeFonts;
383
+ fontSizes?: ThemeFontSizes;
384
+ spacing?: ThemeSpacing;
385
+ page?: ThemePage;
351
386
  sectionStyle?: Theme["sectionStyle"];
387
+ headings?: ThemeHeadings;
352
388
  };
353
389
 
354
390
  /**
@@ -417,4 +453,4 @@ declare class ReactRenderer {
417
453
  /** Render a document AST to a React element tree. */
418
454
  declare function renderReact(ast: DocumentNode, options: ReactRenderOptions): unknown;
419
455
 
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 };
456
+ export { type UrlNode as $, type ArgumentNode as A, ReactRenderer as B, type ContactNode 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 SectionNode as S, type Theme as T, type ThemeColorNode as U, type ThemeColors as V, type ThemeFontSizes as W, type ThemeFonts as X, type ThemeHeadings as Y, type ThemePage as Z, type ThemeSpacing as _, type ReactRenderOptions as a, type UsePackageNode as a0, isNode as a1, isParent as a2, mergeRanges as a3, pos as a4, range as a5, rangeContains as a6, renderReact as a7, type SourceRange as b, type ColorNode as c, type ColumnNode as d, type ColumnsNode as e, type CommandNode 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 };
@@ -69,9 +69,12 @@ interface ParBreakNode extends NodeBase {
69
69
  interface LineBreakNode extends NodeBase {
70
70
  type: "linebreak";
71
71
  }
72
- /** A horizontal rule (`\hrule` / `\divider`). */
72
+ /** A horizontal rule / divider (`\hrule`, `\divider`, and the `shapes` library's
73
+ * styled variants like `\dashrule`). */
73
74
  interface RuleNode extends NodeBase {
74
75
  type: "rule";
76
+ /** Visual style. Defaults to a thin solid line when omitted. */
77
+ style?: "solid" | "dashed" | "dotted" | "thick" | "double";
75
78
  }
76
79
  /** Spacing primitive (`\vspace{1em}` / `\hspace{...}`). */
77
80
  interface SpaceNode extends NodeBase {
@@ -84,6 +87,15 @@ interface GroupNode extends NodeBase {
84
87
  type: "group";
85
88
  children: Node[];
86
89
  }
90
+ /**
91
+ * `\usepackage{shapes, colors}` — a preamble directive that imports one or more
92
+ * styling libraries for the document. Produces no visible output; the engine
93
+ * reads these to register the libraries' commands and merge their theme.
94
+ */
95
+ interface UsePackageNode extends NodeBase {
96
+ type: "usepackage";
97
+ names: string[];
98
+ }
87
99
  type MarkType = "bold" | "italic" | "underline" | "strike";
88
100
  /** Simple wrapping mark such as `\textbf{...}`. */
89
101
  interface MarkNode extends NodeBase {
@@ -230,7 +242,7 @@ interface ErrorNode extends NodeBase {
230
242
  /** The raw source that could not be parsed. */
231
243
  raw: string;
232
244
  }
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;
245
+ type Node = DocumentNode | TextNode | ParBreakNode | LineBreakNode | RuleNode | SpaceNode | GroupNode | UsePackageNode | MarkNode | ColorNode | ThemeColorNode | FontSizeNode | FontFamilyNode | FontScaleNode | LinkNode | UrlNode | IconNode | SectionNode | ListNode | ListItemNode | ColumnsNode | ColumnNode | ContactNode | JobNode | EducationNode | ProjectNode | SkillsNode | CommandNode | ErrorNode;
234
246
  type NodeType = Node["type"];
235
247
  /** Map from node `type` to its concrete interface, for typed visitors. */
236
248
  interface NodeMap {
@@ -241,6 +253,7 @@ interface NodeMap {
241
253
  rule: RuleNode;
242
254
  space: SpaceNode;
243
255
  group: GroupNode;
256
+ usepackage: UsePackageNode;
244
257
  bold: MarkNode;
245
258
  italic: MarkNode;
246
259
  underline: MarkNode;
@@ -278,77 +291,100 @@ declare function isNode<T extends NodeType>(node: Node, type: T): node is NodeMa
278
291
  * Theme model. Themes are plain data so they can be serialized, shipped over
279
292
  * the wire, edited in a GUI, or composed at runtime. {@link resolveTheme}
280
293
  * (see `src/theme`) deep-merges a partial theme over the default.
294
+ *
295
+ * ReTeX is **blank by default**: the built-in theme defines no colors, fonts,
296
+ * sizes, or section decoration — every field is optional and may be left
297
+ * `undefined`, yielding a plain, browser-default document. Visual styling is
298
+ * opt-in: importing a library (`fonts`, `shapes`, `colors`, or a theme pack
299
+ * like `modern`) populates these fields. Renderers therefore treat every theme
300
+ * value as optional and fall back to a neutral, unstyled default when absent.
281
301
  */
282
302
  interface ThemeColors {
283
303
  /** Brand / accent color used for links, section rules, highlights. */
284
- primary: string;
304
+ primary?: string;
285
305
  /** Muted secondary color for meta text (dates, locations). */
286
- secondary: string;
306
+ secondary?: string;
287
307
  /** Default body text color. */
288
- text: string;
308
+ text?: string;
289
309
  /** De-emphasized text color. */
290
- muted: string;
310
+ muted?: string;
291
311
  /** Page background. */
292
- background: string;
312
+ background?: string;
293
313
  /** Hairline / border color. */
294
- border: string;
314
+ border?: string;
295
315
  /** Arbitrary named swatches usable via `\themecolor{name}`. */
296
- [token: string]: string;
316
+ [token: string]: string | undefined;
297
317
  }
298
318
  interface ThemeFonts {
299
319
  /** Font stack for headings (`\name`, `\section`). */
300
- heading: string;
320
+ heading?: string;
301
321
  /** Font stack for body text. */
302
- body: string;
322
+ body?: string;
303
323
  /** Monospace stack (code, technical skills). */
304
- mono: string;
324
+ mono?: string;
305
325
  }
306
326
  interface ThemeFontSizes {
307
327
  /** Base body size, e.g. `"11pt"`. */
308
- base: string;
309
- small: string;
310
- large: string;
311
- Large: string;
312
- Huge: string;
328
+ base?: string;
329
+ small?: string;
330
+ large?: string;
331
+ Large?: string;
332
+ Huge?: string;
313
333
  /** `\name` size. */
314
- name: string;
334
+ name?: string;
315
335
  /** `\section` heading size. */
316
- section: string;
336
+ section?: string;
317
337
  }
318
338
  interface ThemeSpacing {
319
339
  /** Vertical rhythm unit. */
320
- unit: string;
321
- section: string;
322
- item: string;
340
+ unit?: string;
341
+ section?: string;
342
+ item?: string;
323
343
  /** Page padding when rendering a full document. */
324
- page: string;
344
+ page?: string;
325
345
  }
326
346
  interface ThemePage {
327
347
  /** CSS page size keyword or dimensions, e.g. `"A4"` or `"8.5in 11in"`. */
328
- size: string;
329
- margin: string;
348
+ size?: string;
349
+ margin?: string;
330
350
  /** Max content width for screen preview. */
331
- maxWidth: string;
351
+ maxWidth?: string;
352
+ }
353
+ /**
354
+ * Section / name heading decoration. Drives the few decorative properties that
355
+ * are otherwise neutral in a blank document (uppercasing, letter-spacing). All
356
+ * optional — when absent, headings render plainly.
357
+ */
358
+ interface ThemeHeadings {
359
+ /** `text-transform` for `\section` titles (e.g. `"uppercase"`). */
360
+ transform?: string;
361
+ /** `letter-spacing` for `\section` titles. */
362
+ tracking?: string;
363
+ /** `letter-spacing` for the `\name` heading. */
364
+ nameTracking?: string;
332
365
  }
333
366
  interface Theme {
334
367
  name: string;
335
- colors: ThemeColors;
336
- fonts: ThemeFonts;
337
- fontSizes: ThemeFontSizes;
338
- spacing: ThemeSpacing;
339
- page: ThemePage;
368
+ colors?: ThemeColors;
369
+ fonts?: ThemeFonts;
370
+ fontSizes?: ThemeFontSizes;
371
+ spacing?: ThemeSpacing;
372
+ page?: ThemePage;
340
373
  /** Section heading style hint consumed by renderers. */
341
- sectionStyle: "underline" | "rule" | "plain" | "bar";
374
+ sectionStyle?: "underline" | "rule" | "plain" | "bar";
375
+ /** Optional decorative heading tweaks (uppercasing, tracking). */
376
+ headings?: ThemeHeadings;
342
377
  }
343
378
  /** A user-supplied theme override; everything is optional and deep-merged. */
344
379
  type PartialTheme = {
345
380
  name?: string;
346
- colors?: Partial<ThemeColors>;
347
- fonts?: Partial<ThemeFonts>;
348
- fontSizes?: Partial<ThemeFontSizes>;
349
- spacing?: Partial<ThemeSpacing>;
350
- page?: Partial<ThemePage>;
381
+ colors?: ThemeColors;
382
+ fonts?: ThemeFonts;
383
+ fontSizes?: ThemeFontSizes;
384
+ spacing?: ThemeSpacing;
385
+ page?: ThemePage;
351
386
  sectionStyle?: Theme["sectionStyle"];
387
+ headings?: ThemeHeadings;
352
388
  };
353
389
 
354
390
  /**
@@ -417,4 +453,4 @@ declare class ReactRenderer {
417
453
  /** Render a document AST to a React element tree. */
418
454
  declare function renderReact(ast: DocumentNode, options: ReactRenderOptions): unknown;
419
455
 
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 };
456
+ export { type UrlNode as $, type ArgumentNode as A, ReactRenderer as B, type ContactNode 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 SectionNode as S, type Theme as T, type ThemeColorNode as U, type ThemeColors as V, type ThemeFontSizes as W, type ThemeFonts as X, type ThemeHeadings as Y, type ThemePage as Z, type ThemeSpacing as _, type ReactRenderOptions as a, type UsePackageNode as a0, isNode as a1, isParent as a2, mergeRanges as a3, pos as a4, range as a5, rangeContains as a6, renderReact as a7, type SourceRange as b, type ColorNode as c, type ColumnNode as d, type ColumnsNode as e, type CommandNode 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 };