omni-viewer-core 0.10.0 → 0.11.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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/dist/i18n/catalog.en.js +35 -1
  3. package/dist/i18n/catalog.ja.js +34 -0
  4. package/dist/i18n/catalog.ko.js +34 -0
  5. package/dist/i18n/catalog.zh-cn.js +34 -0
  6. package/dist/parsers/latex/index.d.ts +198 -0
  7. package/dist/parsers/latex/index.js +1604 -0
  8. package/dist/parsers/parquet/index.d.ts +13 -0
  9. package/dist/parsers/parquet/index.js +2 -2
  10. package/dist/registry/index.d.ts +2 -1
  11. package/dist/registry/index.js +12 -3
  12. package/dist/registry/sniff.d.ts +8 -1
  13. package/dist/registry/sniff.js +12 -0
  14. package/dist/styles/latex.css +44 -0
  15. package/dist/styles/markdown.css +4 -3
  16. package/dist/styles/parquet.css +1 -1
  17. package/dist/viewers/latex/controller.d.ts +34 -0
  18. package/dist/viewers/latex/controller.js +61 -0
  19. package/dist/viewers/latex/includes.d.ts +44 -0
  20. package/dist/viewers/latex/includes.js +284 -0
  21. package/dist/viewers/latex/index.d.ts +79 -0
  22. package/dist/viewers/latex/index.js +691 -0
  23. package/dist/viewers/latex/self-loading.d.ts +11 -0
  24. package/dist/viewers/latex/self-loading.js +42 -0
  25. package/dist/viewers/latex/styles.d.ts +1 -0
  26. package/dist/viewers/latex/styles.js +45 -0
  27. package/dist/viewers/markdown/index.d.ts +10 -8
  28. package/dist/viewers/markdown/index.js +269 -13
  29. package/dist/viewers/markdown/source-map.d.ts +47 -0
  30. package/dist/viewers/markdown/source-map.js +267 -0
  31. package/dist/viewers/markdown/styles.d.ts +1 -1
  32. package/dist/viewers/markdown/styles.js +4 -3
  33. package/dist/viewers/math.d.ts +34 -0
  34. package/dist/viewers/math.js +21 -0
  35. package/dist/viewers/parquet/index.d.ts +2 -0
  36. package/dist/viewers/parquet/index.js +41 -6
  37. package/dist/viewers/parquet/styles.d.ts +1 -1
  38. package/dist/viewers/parquet/styles.js +1 -1
  39. package/package.json +15 -1
package/README.md CHANGED
@@ -13,7 +13,7 @@ models, viewers mount into a DOM element, and everything host-specific
13
13
  ## Supported formats
14
14
 
15
15
  - **Documents** — PDF, Word (DOCX and legacy DOC), HWP, PowerPoint (PPTX and
16
- legacy PPT), Markdown
16
+ legacy PPT), Markdown, LaTeX (structure and math preview, not typesetting)
17
17
  - **Data & spreadsheets** — Excel, CSV/TSV, JSON, JSONL/NDJSON, YAML, TOML,
18
18
  Parquet, Avro, HDF5, MATLAB MAT, Safetensors, Protocol Buffers, ReqIF, SQLite
19
19
  - **Media & graphics** — audio (waveform/spectrogram), video, images,
@@ -123,9 +123,43 @@ export const CATALOG_EN = {
123
123
  'markdown.invalid': 'Invalid', 'markdown.modified': 'Modified', 'markdown.editable': 'Editable',
124
124
  'markdown.edited': 'Edited', 'markdown.htmlCopied': 'HTML copied', 'markdown.sourceCopied': 'Source copied',
125
125
  'markdown.summary': '{lines} lines, {words} words', 'markdown.renderedDiagrams': 'Rendered · {count} diagram(s)',
126
- 'markdown.diagramFailed': 'Unable to render diagram.', 'markdown.toc': 'Contents',
126
+ 'markdown.diagramFailed': 'Unable to render diagram.', 'markdown.toc': 'Outline',
127
127
  'markdown.copyCode': 'Copy code', 'markdown.assetUnavailable': 'Image unavailable',
128
128
  'diag.markdown.limit-exceeded': 'The Markdown document exceeds a supported limit.',
129
+ 'latex.title': 'LaTeX', 'latex.preview': 'Preview', 'latex.split': 'Split', 'latex.source': 'Source',
130
+ 'latex.outline': 'Outline', 'latex.outlineEmpty': 'No sections found',
131
+ 'latex.render': 'Render', 'latex.undo': 'Undo', 'latex.redo': 'Redo',
132
+ 'latex.copySource': 'Copy source', 'latex.sourceCopied': 'Source copied',
133
+ 'latex.ready': 'Ready', 'latex.parsed': 'Parsed', 'latex.invalid': 'Invalid',
134
+ 'latex.editable': 'Editable', 'latex.edited': 'Edited',
135
+ 'latex.partialRender': 'Partial preview — structure and math only, not typeset output',
136
+ 'latex.documentClass': 'Class: {name}', 'latex.sectionCount': '{count} section(s)',
137
+ 'latex.unsupportedEnvironment': '{environment} — not rendered',
138
+ 'latex.unresolvedInput': '\\{command} — external file not resolved',
139
+ 'latex.floatCaptionOnly': '{environment} — caption only',
140
+ 'latex.parseFailed': 'This file could not be read as a LaTeX document.',
141
+ 'latex.mathNotInstalled': 'Math renderer not installed — formulas are shown as TeX',
142
+ 'latex.mathFailed': 'This formula could not be rendered; its TeX source is shown.',
143
+ 'latex.includedFrom': 'Included from {path}',
144
+ 'latex.goToReference': 'Go to {target}',
145
+ 'diag.latex.include-blocked': 'The include path {path} was refused because it leaves the document folder.',
146
+ 'diag.latex.include-missing': 'The included file {path} could not be read.',
147
+ 'diag.latex.include-cycle': 'The included file {path} was skipped because it is already part of this document.',
148
+ 'diag.latex.include-depth-exceeded': 'Included files are nested deeper than the supported limit.',
149
+ 'diag.latex.include-limit-exceeded': 'The included files exceed a supported limit.',
150
+ 'diag.latex.include-unreadable': 'The included file {path} could not be read as LaTeX.',
151
+ 'latex.linkBlocked': 'This link scheme is not allowed.',
152
+ 'latex.navigationUnavailable': 'Opening links is unavailable on this platform',
153
+ 'diag.latex.not-latex': 'No \\documentclass was found, so the document structure was not interpreted.',
154
+ 'diag.latex.no-document-environment': 'The document environment was not found; the file was read as a fragment.',
155
+ 'diag.latex.unsupported-environment': 'The {environment} environment is not rendered; its source is shown instead.',
156
+ 'diag.latex.unsupported-command': 'The \\{command} command could not be read and was left as source.',
157
+ 'diag.latex.unresolved-input': '\\{command} ({path}) was not resolved — external files are never read.',
158
+ 'diag.latex.unbalanced-environment': 'The {environment} environment is missing its \\end.',
159
+ 'diag.latex.limit-exceeded': 'The LaTeX document exceeds a supported limit.',
160
+ 'diag.latex.depth-exceeded': 'The LaTeX document nests deeper than the supported limit.',
161
+ 'diag.latex.math-limit-exceeded': 'A formula exceeds the supported size and is shown as source.',
162
+ 'diag.latex.float-caption-only': 'Only the caption of the {environment} environment is shown.',
129
163
  'archive.title': 'Archive', 'archive.search': 'Search entries', 'archive.entries': '{count} entries',
130
164
  'archive.previewUnavailable': 'Preview unavailable', 'archive.mediaUnsupported': 'Media preview is unsupported.',
131
165
  'archive.encrypted': 'This archive is encrypted.', 'archive.encryptedEntries': 'This archive contains {count} encrypted entries.',
@@ -130,6 +130,40 @@ export const CATALOG_JA = {
130
130
  'markdown.diagramFailed': 'ダイアグラムをレンダリングできません。', 'markdown.toc': '目次',
131
131
  'markdown.copyCode': 'コードをコピー', 'markdown.assetUnavailable': '画像を利用できません',
132
132
  'diag.markdown.limit-exceeded': 'Markdown文書が対応上限を超えています。',
133
+ 'latex.title': 'LaTeX', 'latex.preview': 'プレビュー', 'latex.split': '分割', 'latex.source': 'ソース',
134
+ 'latex.outline': 'アウトライン', 'latex.outlineEmpty': 'セクションが見つかりません',
135
+ 'latex.render': 'レンダー', 'latex.undo': '元に戻す', 'latex.redo': 'やり直し',
136
+ 'latex.copySource': 'ソースをコピー', 'latex.sourceCopied': 'ソースをコピーしました',
137
+ 'latex.ready': '準備完了', 'latex.parsed': '解析済み', 'latex.invalid': '無効',
138
+ 'latex.editable': '編集可能', 'latex.edited': '編集済み',
139
+ 'latex.partialRender': '部分プレビュー — 構造と数式のみで、組版結果ではありません',
140
+ 'latex.documentClass': 'クラス: {name}', 'latex.sectionCount': 'セクション {count} 個',
141
+ 'latex.unsupportedEnvironment': '{environment} — レンダーしません',
142
+ 'latex.unresolvedInput': '\\{command} — 外部ファイルは解決しません',
143
+ 'latex.floatCaptionOnly': '{environment} — キャプションのみ',
144
+ 'latex.parseFailed': 'このファイルはLaTeX文書として読み取れませんでした。',
145
+ 'latex.mathNotInstalled': '数式レンダラーが未インストールのため、数式をTeXソースで表示します',
146
+ 'latex.mathFailed': 'この数式をレンダーできなかったため、TeXソースを表示します。',
147
+ 'latex.includedFrom': '{path}から取り込み',
148
+ 'latex.goToReference': '{target}へ移動',
149
+ 'diag.latex.include-blocked': '{path}は文書フォルダーの外に出るため取り込みませんでした。',
150
+ 'diag.latex.include-missing': '取り込んだファイル{path}を読み取れませんでした。',
151
+ 'diag.latex.include-cycle': '取り込んだファイル{path}は既にこの文書に含まれているためスキップしました。',
152
+ 'diag.latex.include-depth-exceeded': '取り込んだファイルの入れ子が対応上限より深くなっています。',
153
+ 'diag.latex.include-limit-exceeded': '取り込んだファイルが対応上限を超えています。',
154
+ 'diag.latex.include-unreadable': '取り込んだファイル{path}をLaTeXとして読み取れませんでした。',
155
+ 'latex.linkBlocked': 'このリンクスキームは許可されていません。',
156
+ 'latex.navigationUnavailable': 'このプラットフォームではリンクを開けません',
157
+ 'diag.latex.not-latex': '\\documentclassがないため、文書構造を解釈しませんでした。',
158
+ 'diag.latex.no-document-environment': 'document環境がないため、断片として読み取りました。',
159
+ 'diag.latex.unsupported-environment': '{environment}環境はレンダーせず、ソースをそのまま表示します。',
160
+ 'diag.latex.unsupported-command': '\\{command}コマンドを読み取れず、ソースのまま残しました。',
161
+ 'diag.latex.unresolved-input': '\\{command} ({path}) は解決しませんでした — 外部ファイルは読み取りません。',
162
+ 'diag.latex.unbalanced-environment': '{environment}環境に\\endがありません。',
163
+ 'diag.latex.limit-exceeded': 'LaTeX文書が対応上限を超えています。',
164
+ 'diag.latex.depth-exceeded': 'LaTeX文書の入れ子が対応上限より深くなっています。',
165
+ 'diag.latex.math-limit-exceeded': '数式が対応サイズを超えたため、ソースとして表示します。',
166
+ 'diag.latex.float-caption-only': '{environment}環境はキャプションのみ表示します。',
133
167
  'archive.title': 'アーカイブ', 'archive.search': '項目を検索', 'archive.entries': '{count}項目',
134
168
  'archive.previewUnavailable': 'プレビューできません', 'archive.mediaUnsupported': 'メディアのプレビューには対応していません。',
135
169
  'archive.encrypted': 'このアーカイブは暗号化されています。', 'archive.encryptedEntries': 'このアーカイブには暗号化された項目が{count}件あります。',
@@ -126,6 +126,40 @@ export const CATALOG_KO = {
126
126
  'markdown.diagramFailed': '다이어그램을 렌더링할 수 없습니다.', 'markdown.toc': '목차',
127
127
  'markdown.copyCode': '코드 복사', 'markdown.assetUnavailable': '이미지를 사용할 수 없음',
128
128
  'diag.markdown.limit-exceeded': 'Markdown 문서가 지원 한도를 초과합니다.',
129
+ 'latex.title': 'LaTeX', 'latex.preview': '미리보기', 'latex.split': '분할', 'latex.source': '원문',
130
+ 'latex.outline': '개요', 'latex.outlineEmpty': '절을 찾지 못했습니다',
131
+ 'latex.render': '렌더', 'latex.undo': '실행 취소', 'latex.redo': '다시 실행',
132
+ 'latex.copySource': '원문 복사', 'latex.sourceCopied': '원문을 복사했습니다',
133
+ 'latex.ready': '준비됨', 'latex.parsed': '해석됨', 'latex.invalid': '잘못됨',
134
+ 'latex.editable': '편집 가능', 'latex.edited': '편집함',
135
+ 'latex.partialRender': '부분 미리보기 — 구조와 수식만, 조판 결과가 아닙니다',
136
+ 'latex.documentClass': '클래스: {name}', 'latex.sectionCount': '절 {count}개',
137
+ 'latex.unsupportedEnvironment': '{environment} — 렌더하지 않음',
138
+ 'latex.unresolvedInput': '\\{command} — 외부 파일을 해석하지 않음',
139
+ 'latex.floatCaptionOnly': '{environment} — 캡션만 표시',
140
+ 'latex.parseFailed': 'LaTeX 문서로 읽을 수 없는 파일입니다.',
141
+ 'latex.mathNotInstalled': '수식 렌더러가 설치되지 않아 수식을 TeX 원문으로 표시합니다',
142
+ 'latex.mathFailed': '이 수식을 렌더하지 못해 TeX 원문을 표시합니다.',
143
+ 'latex.includedFrom': '{path}에서 포함됨',
144
+ 'latex.goToReference': '{target}(으)로 이동',
145
+ 'diag.latex.include-blocked': '{path}는 문서 폴더를 벗어나므로 포함하지 않았습니다.',
146
+ 'diag.latex.include-missing': '포함된 파일 {path}를 읽지 못했습니다.',
147
+ 'diag.latex.include-cycle': '포함된 파일 {path}는 이미 이 문서에 포함되어 있어 건너뛰었습니다.',
148
+ 'diag.latex.include-depth-exceeded': '포함된 파일의 중첩이 지원 한도보다 깊습니다.',
149
+ 'diag.latex.include-limit-exceeded': '포함된 파일이 지원 한도를 초과합니다.',
150
+ 'diag.latex.include-unreadable': '포함된 파일 {path}를 LaTeX으로 읽지 못했습니다.',
151
+ 'latex.linkBlocked': '허용되지 않는 링크 스킴입니다.',
152
+ 'latex.navigationUnavailable': '이 플랫폼에서는 링크를 열 수 없습니다',
153
+ 'diag.latex.not-latex': '\\documentclass가 없어 문서 구조를 해석하지 않았습니다.',
154
+ 'diag.latex.no-document-environment': 'document 환경이 없어 문서 조각으로 읽었습니다.',
155
+ 'diag.latex.unsupported-environment': '{environment} 환경은 렌더하지 않으며 원문을 그대로 표시합니다.',
156
+ 'diag.latex.unsupported-command': '\\{command} 명령을 읽지 못해 원문으로 남겼습니다.',
157
+ 'diag.latex.unresolved-input': '\\{command} ({path})를 해석하지 않았습니다 — 외부 파일은 읽지 않습니다.',
158
+ 'diag.latex.unbalanced-environment': '{environment} 환경에 \\end가 없습니다.',
159
+ 'diag.latex.limit-exceeded': 'LaTeX 문서가 지원 한도를 초과합니다.',
160
+ 'diag.latex.depth-exceeded': 'LaTeX 문서의 중첩이 지원 한도보다 깊습니다.',
161
+ 'diag.latex.math-limit-exceeded': '수식이 지원 크기를 초과하여 원문으로 표시합니다.',
162
+ 'diag.latex.float-caption-only': '{environment} 환경은 캡션만 표시합니다.',
129
163
  'archive.title': '압축 파일', 'archive.search': '항목 검색', 'archive.entries': '항목 {count}개',
130
164
  'archive.previewUnavailable': '미리보기를 사용할 수 없음', 'archive.mediaUnsupported': '미디어 미리보기는 지원되지 않습니다.',
131
165
  'archive.encrypted': '이 압축 파일은 암호화되어 있습니다.', 'archive.encryptedEntries': '이 압축 파일에는 암호화된 항목이 {count}개 있습니다.',
@@ -123,6 +123,40 @@ export const CATALOG_ZH_CN = {
123
123
  'markdown.diagramFailed': '无法渲染图表。', 'markdown.toc': '目录',
124
124
  'markdown.copyCode': '复制代码', 'markdown.assetUnavailable': '图像不可用',
125
125
  'diag.markdown.limit-exceeded': 'Markdown 文档超过支持的限制。',
126
+ 'latex.title': 'LaTeX', 'latex.preview': '预览', 'latex.split': '分栏', 'latex.source': '源代码',
127
+ 'latex.outline': '大纲', 'latex.outlineEmpty': '未找到章节',
128
+ 'latex.render': '渲染', 'latex.undo': '撤销', 'latex.redo': '重做',
129
+ 'latex.copySource': '复制源代码', 'latex.sourceCopied': '已复制源代码',
130
+ 'latex.ready': '就绪', 'latex.parsed': '已解析', 'latex.invalid': '无效',
131
+ 'latex.editable': '可编辑', 'latex.edited': '已编辑',
132
+ 'latex.partialRender': '部分预览 — 仅结构与公式,并非排版结果',
133
+ 'latex.documentClass': '文档类:{name}', 'latex.sectionCount': '{count} 个章节',
134
+ 'latex.unsupportedEnvironment': '{environment} — 不渲染',
135
+ 'latex.unresolvedInput': '\\{command} — 不解析外部文件',
136
+ 'latex.floatCaptionOnly': '{environment} — 仅显示题注',
137
+ 'latex.parseFailed': '无法将此文件作为 LaTeX 文档读取。',
138
+ 'latex.mathNotInstalled': '未安装公式渲染器 — 公式以 TeX 源代码显示',
139
+ 'latex.mathFailed': '无法渲染此公式,改为显示其 TeX 源代码。',
140
+ 'latex.includedFrom': '引入自 {path}',
141
+ 'latex.goToReference': '跳转到 {target}',
142
+ 'diag.latex.include-blocked': '{path} 超出文档目录,已拒绝引入。',
143
+ 'diag.latex.include-missing': '无法读取引入的文件 {path}。',
144
+ 'diag.latex.include-cycle': '引入的文件 {path} 已包含在此文档中,已跳过。',
145
+ 'diag.latex.include-depth-exceeded': '引入文件的嵌套超过支持的深度限制。',
146
+ 'diag.latex.include-limit-exceeded': '引入的文件超过支持的限制。',
147
+ 'diag.latex.include-unreadable': '无法将引入的文件 {path} 作为 LaTeX 读取。',
148
+ 'latex.linkBlocked': '不允许此链接协议。',
149
+ 'latex.navigationUnavailable': '此平台无法打开链接',
150
+ 'diag.latex.not-latex': '未找到 \\documentclass,因此未解释文档结构。',
151
+ 'diag.latex.no-document-environment': '未找到 document 环境,已按文档片段读取。',
152
+ 'diag.latex.unsupported-environment': '{environment} 环境不渲染,改为显示其源代码。',
153
+ 'diag.latex.unsupported-command': '无法读取 \\{command} 命令,已保留为源代码。',
154
+ 'diag.latex.unresolved-input': '\\{command}({path})未解析 — 从不读取外部文件。',
155
+ 'diag.latex.unbalanced-environment': '{environment} 环境缺少 \\end。',
156
+ 'diag.latex.limit-exceeded': 'LaTeX 文档超过支持的限制。',
157
+ 'diag.latex.depth-exceeded': 'LaTeX 文档的嵌套超过支持的深度限制。',
158
+ 'diag.latex.math-limit-exceeded': '公式超过支持的大小,改为显示源代码。',
159
+ 'diag.latex.float-caption-only': '{environment} 环境仅显示题注。',
126
160
  'archive.title': '压缩包', 'archive.search': '搜索条目', 'archive.entries': '{count} 个条目',
127
161
  'archive.previewUnavailable': '无法预览', 'archive.mediaUnsupported': '不支持媒体预览。',
128
162
  'archive.encrypted': '此压缩包已加密。', 'archive.encryptedEntries': '此压缩包包含 {count} 个加密条目。',
@@ -0,0 +1,198 @@
1
+ import { type ParseOptions, type ParseOutcome } from '../types.js';
2
+ export interface LatexSpan {
3
+ start: number;
4
+ end: number;
5
+ }
6
+ export interface LatexPackage {
7
+ name: string;
8
+ options: string[];
9
+ }
10
+ export interface LatexPreamble {
11
+ documentClass?: string;
12
+ classOptions: string[];
13
+ packages: LatexPackage[];
14
+ /**
15
+ * Argument-less `\newcommand{\R}{\mathbb{R}}` substitutions only, keyed
16
+ * without the leading backslash. Stage 2 passes these to KaTeX as `macros`.
17
+ * Macros taking arguments are intentionally absent — expanding them is the
18
+ * interpreter this parser refuses to be (§2).
19
+ */
20
+ macros: Record<string, string>;
21
+ /**
22
+ * `\newtheorem{thm}{Theorem}` declarations, keyed by environment name with
23
+ * the printed title as value. Theorem-like environments are document
24
+ * defined, so without this map they are indistinguishable from any other
25
+ * unknown environment and their prose would be dumped as source.
26
+ */
27
+ theorems: Record<string, string>;
28
+ /**
29
+ * Characters `\MakeShortVerb` turned into inline-verbatim delimiters, as in
30
+ * the `doc` package's `\MakeShortVerb{\|}`. Package documentation writes
31
+ * `|\newcommand{\x}{…}|` to *show* code; without this the scanner would
32
+ * execute what the author meant to display.
33
+ */
34
+ shortVerbs: string[];
35
+ /**
36
+ * `\input`/`\include` targets declared in the preamble. Documents routinely
37
+ * keep their macros in a separate file, and those definitions decide whether
38
+ * the body's formulas render, so the paths are surfaced for the viewer's
39
+ * resolver even though the preamble itself produces no blocks.
40
+ */
41
+ inputs: string[];
42
+ /** Verbatim preamble source, for display. */
43
+ raw: string;
44
+ }
45
+ export type LatexEmphasis = 'it' | 'bf' | 'tt';
46
+ export type LatexInline = {
47
+ kind: 'text';
48
+ value: string;
49
+ } | {
50
+ kind: 'math';
51
+ source: string;
52
+ display: false;
53
+ } | {
54
+ kind: 'emphasis';
55
+ style: LatexEmphasis;
56
+ content: LatexInline[];
57
+ } | {
58
+ kind: 'ref';
59
+ target: string;
60
+ } | {
61
+ kind: 'cite';
62
+ keys: string[];
63
+ } | {
64
+ kind: 'link';
65
+ url: string;
66
+ text: string;
67
+ } | {
68
+ kind: 'unsupported';
69
+ source: string;
70
+ };
71
+ export type LatexBlock = {
72
+ kind: 'heading';
73
+ level: number;
74
+ id: string;
75
+ title: LatexInline[];
76
+ label?: string;
77
+ span: LatexSpan;
78
+ } | {
79
+ kind: 'paragraph';
80
+ content: LatexInline[];
81
+ span: LatexSpan;
82
+ } | {
83
+ kind: 'math';
84
+ source: string;
85
+ display: boolean;
86
+ label?: string;
87
+ span: LatexSpan;
88
+ } | {
89
+ kind: 'list';
90
+ ordered: boolean;
91
+ items: LatexBlock[][];
92
+ span: LatexSpan;
93
+ } | {
94
+ kind: 'theorem';
95
+ environment: string;
96
+ title: string;
97
+ note?: LatexInline[];
98
+ body: LatexBlock[];
99
+ label?: string;
100
+ span: LatexSpan;
101
+ } | {
102
+ kind: 'table';
103
+ columns: LatexColumnAlign[];
104
+ rows: LatexTableCell[][];
105
+ span: LatexSpan;
106
+ } | {
107
+ kind: 'verbatim';
108
+ source: string;
109
+ span: LatexSpan;
110
+ } | {
111
+ kind: 'float';
112
+ environment: string;
113
+ caption?: LatexInline[];
114
+ span: LatexSpan;
115
+ } | {
116
+ kind: 'unresolved';
117
+ command: string;
118
+ path: string;
119
+ span: LatexSpan;
120
+ }
121
+ /** A resolved `\input`/`\include`. Never produced by the parser — the core
122
+ * has no filesystem (L4); the viewer builds these from an injected
123
+ * resolver, so `blocks` carry spans into the *included* file, not this one. */
124
+ | {
125
+ kind: 'include';
126
+ command: string;
127
+ path: string;
128
+ blocks: LatexBlock[];
129
+ span: LatexSpan;
130
+ } | {
131
+ kind: 'unsupported';
132
+ environment: string;
133
+ source: string;
134
+ span: LatexSpan;
135
+ };
136
+ export type LatexColumnAlign = 'left' | 'center' | 'right';
137
+ export interface LatexTableCell {
138
+ content: LatexInline[];
139
+ /** `\multicolumn{n}{…}{…}` — cells spanning one column omit this. */
140
+ span?: number;
141
+ }
142
+ export interface LatexHeading {
143
+ level: number;
144
+ text: string;
145
+ id: string;
146
+ span: LatexSpan;
147
+ /** Set when the heading came from an included file (span is into that file). */
148
+ source?: string;
149
+ }
150
+ export interface LatexDocument {
151
+ /** Complete decoded source, retained for source view / edit / writeback. */
152
+ text: string;
153
+ preamble: LatexPreamble;
154
+ body: LatexBlock[];
155
+ /** Flat outline in source order (§3 navigation). */
156
+ outline: LatexHeading[];
157
+ /** Region of `text` the block scanner covered. */
158
+ bodySpan: LatexSpan;
159
+ }
160
+ export interface LatexStructuralLimits {
161
+ maxBlocks: number;
162
+ maxOutline: number;
163
+ maxMathSegments: number;
164
+ maxInlineMathLength: number;
165
+ maxDisplayMathLength: number;
166
+ maxDepth: number;
167
+ }
168
+ /** docs/viewers/latex.md §4. Inline/display math lengths match the markdown
169
+ * viewer's existing constants so the two paths agree on what is "a formula". */
170
+ export declare const LATEX_DEFAULT_LIMITS: {
171
+ readonly maxInputBytes: number;
172
+ readonly maxBlocks: 200000;
173
+ readonly maxOutline: 10000;
174
+ readonly maxMathSegments: 5000;
175
+ readonly maxInlineMathLength: 1000;
176
+ readonly maxDisplayMathLength: 5000;
177
+ readonly maxDepth: 64;
178
+ };
179
+ export interface LatexParseOptions extends ParseOptions {
180
+ latexLimits?: Partial<LatexStructuralLimits>;
181
+ /**
182
+ * Parse a body fragment that has no `\documentclass` of its own — an
183
+ * `\input`ed chapter file. Without this the parser refuses to guess at the
184
+ * structure of a `.tex` file that might be plain TeX (§1); with it the
185
+ * caller is asserting the file is a LaTeX fragment. Spans stay relative to
186
+ * the fragment's own text, which is why this exists instead of wrapping the
187
+ * source in a synthetic document.
188
+ */
189
+ fragment?: boolean;
190
+ }
191
+ /**
192
+ * Structure-only LaTeX parse. Input-caused problems never throw: unparseable
193
+ * bytes become `failed`, everything the scanner cannot model becomes a
194
+ * diagnostic plus an `unsupported`/`unresolved` block and a `partial` status.
195
+ */
196
+ export declare function parseLatex(data: Uint8Array, options?: LatexParseOptions): ParseOutcome<LatexDocument>;
197
+ /** Flattened text of inline nodes — outline labels, link text, copy output. */
198
+ export declare function plainText(nodes: readonly LatexInline[]): string;