@gmickel/gno 1.45.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/THIRD_PARTY_NOTICES.md +46 -0
- package/assets/skill/SKILL.md +7 -6
- package/assets/skill/cli-reference.md +14 -6
- package/assets/skill/mcp-reference.md +4 -1
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.0.0.zip.sha256 +1 -0
- package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/browser-extension/dist/preview.html +1 -1
- package/browser-extension/dist/service-worker.js +32 -33
- package/bunfig.toml +2 -0
- package/package.json +40 -26
- package/spec/cli.md +30 -11
- package/spec/db/schema.sql +146 -1
- package/spec/mcp.md +26 -0
- package/src/app/context-runtime-types.ts +3 -0
- package/src/app/context-runtime.ts +2 -0
- package/src/cli/commands/ask.ts +6 -1
- package/src/cli/commands/daemon.ts +21 -8
- package/src/cli/commands/embed.ts +77 -41
- package/src/cli/commands/mcp/install.ts +20 -0
- package/src/cli/commands/mcp/paths.ts +25 -0
- package/src/cli/commands/mcp/status.ts +6 -0
- package/src/cli/detach.ts +3 -2
- package/src/cli/program.ts +6 -0
- package/src/config/types.ts +3 -3
- package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
- package/src/converters/adapters/officeparser/adapter.ts +1 -2
- package/src/converters/versions.ts +6 -8
- package/src/core/context-evidence.ts +8 -4
- package/src/core/job-manager.ts +95 -13
- package/src/core/network-boundary-inventory.ts +10 -0
- package/src/core/shutdown-budget.ts +45 -0
- package/src/embed/backlog.ts +107 -4
- package/src/embed/batch.ts +42 -2
- package/src/embed/fingerprint.ts +16 -0
- package/src/embed/retry.ts +113 -5
- package/src/embed/variant-backlog.ts +105 -0
- package/src/embed/variant-plan.ts +62 -0
- package/src/embed/variant-retry.ts +113 -0
- package/src/ingestion/graph-reconciliation.ts +327 -0
- package/src/ingestion/sync.ts +9 -272
- package/src/llm/http-inference.ts +6 -0
- package/src/llm/httpEmbedding.ts +37 -6
- package/src/llm/httpGeneration.ts +18 -3
- package/src/llm/httpRerank.ts +23 -5
- package/src/llm/inference-cancellation.ts +168 -0
- package/src/llm/inference-scope.ts +202 -0
- package/src/llm/lazy-ports.ts +115 -0
- package/src/llm/native-worker/client.ts +541 -0
- package/src/llm/native-worker/dispatcher.ts +228 -0
- package/src/llm/native-worker/embedding-identity.ts +33 -0
- package/src/llm/native-worker/entry.ts +173 -0
- package/src/llm/native-worker/errors.ts +32 -0
- package/src/llm/native-worker/evaluation.ts +16 -0
- package/src/llm/native-worker/owned-exit.ts +108 -0
- package/src/llm/native-worker/owner.ts +141 -0
- package/src/llm/native-worker/ports.ts +317 -0
- package/src/llm/native-worker/protocol.ts +442 -0
- package/src/llm/native-worker/runtime-config.ts +92 -0
- package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
- package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
- package/src/llm/nodeLlamaCpp/generation.ts +34 -5
- package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
- package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
- package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
- package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
- package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
- package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
- package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
- package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
- package/src/llm/types.ts +35 -5
- package/src/mcp/context.ts +27 -0
- package/src/mcp/http-transport.ts +12 -10
- package/src/mcp/server.ts +3 -0
- package/src/mcp/tool-profile.ts +30 -8
- package/src/mcp/tools/context.ts +8 -11
- package/src/mcp/tools/embed.ts +1 -1
- package/src/mcp/tools/index-cmd.ts +1 -1
- package/src/mcp/tools/index.ts +10 -8
- package/src/mcp/tools/query.ts +14 -30
- package/src/mcp/tools/vsearch.ts +1 -1
- package/src/pipeline/answer.ts +23 -3
- package/src/pipeline/claim-verifier.ts +6 -0
- package/src/pipeline/expansion.ts +43 -40
- package/src/pipeline/explain.ts +6 -2
- package/src/pipeline/filters.ts +63 -0
- package/src/pipeline/fusion.ts +29 -9
- package/src/pipeline/graph-retrieval.ts +29 -9
- package/src/pipeline/hybrid.ts +198 -55
- package/src/pipeline/hydration.ts +161 -0
- package/src/pipeline/owner-fusion.ts +87 -0
- package/src/pipeline/rerank.ts +35 -11
- package/src/pipeline/search.ts +13 -2
- package/src/pipeline/types.ts +5 -3
- package/src/pipeline/vsearch.ts +87 -7
- package/src/sdk/client.ts +47 -3
- package/src/sdk/embed.ts +63 -39
- package/src/serve/background-runtime.ts +1 -1
- package/src/serve/context.ts +41 -56
- package/src/serve/embed-scheduler.ts +58 -35
- package/src/serve/public/components/IndexingProgress.tsx +46 -60
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/lib/shiki-language-ids.ts +14 -0
- package/src/serve/resident-admission.ts +36 -36
- package/src/serve/resident-background-work.ts +20 -2
- package/src/serve/resident-request.ts +11 -5
- package/src/serve/resident-runtime.ts +97 -61
- package/src/serve/resident-shutdown.ts +153 -0
- package/src/serve/routes/api.ts +3 -1
- package/src/serve/server.ts +47 -26
- package/src/store/migrations/028-vector-variants.ts +54 -0
- package/src/store/migrations/029-graph-reference-state.ts +77 -0
- package/src/store/migrations/index.ts +4 -0
- package/src/store/sqlite/adapter.ts +251 -183
- package/src/store/sqlite/eligibility.ts +174 -0
- package/src/store/sqlite/graph-edge-application.ts +66 -0
- package/src/store/sqlite/graph-reference-state.ts +194 -0
- package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
- package/src/store/types.ts +80 -12
- package/src/store/vector/eligibility.ts +36 -0
- package/src/store/vector/freshness.ts +33 -6
- package/src/store/vector/lazy.ts +81 -0
- package/src/store/vector/sqlite-vec.ts +106 -54
- package/src/store/vector/stats.ts +14 -3
- package/src/store/vector/types.ts +35 -2
- package/src/store/vector/variant-search.ts +192 -0
- package/src/store/vector/variants.ts +451 -0
- package/vendor/converters/markitdown-ts/LICENSE +21 -0
- package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
- package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
- package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
- package/vendor/converters/markitdown-ts/package.json +77 -0
- package/vendor/converters/officeparser/LICENSE +21 -0
- package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
- package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
- package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
- package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
- package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
- package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
- package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
- package/vendor/converters/officeparser/dist/cli.js +381 -0
- package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
- package/vendor/converters/officeparser/dist/defaults.js +218 -0
- package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
- package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
- package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
- package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
- package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
- package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
- package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
- package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
- package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
- package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
- package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
- package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
- package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
- package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
- package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
- package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
- package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
- package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
- package/vendor/converters/officeparser/dist/index.d.ts +60 -0
- package/vendor/converters/officeparser/dist/index.js +72 -0
- package/vendor/converters/officeparser/dist/index.mjs +18 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
- package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
- package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
- package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
- package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
- package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
- package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
- package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
- package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
- package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
- package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
- package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
- package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
- package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
- package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
- package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
- package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
- package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
- package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
- package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
- package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
- package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
- package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
- package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
- package/vendor/converters/officeparser/dist/types.js +107 -0
- package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
- package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
- package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
- package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
- package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
- package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
- package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
- package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
- package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
- package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
- package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
- package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
- package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
- package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
- package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
- package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
- package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
- package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
- package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
- package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
- package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
- package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
- package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
- package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
- package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
- package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
- package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
- package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
- package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
- package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
- package/vendor/converters/officeparser/package.json +147 -0
- package/vendor/converters/upstream-manifest.json +124 -0
- package/vendor/dependency-fixes/README.md +77 -0
- package/vendor/dependency-fixes/vendor-converters.py +83 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.45.1.zip.sha256 +0 -1
- package/browser-extension/dist/chunk-627emwpj.js +0 -75
- /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isEmptyMath = exports.mathmlToLatex = exports.mathmlTreeToLatex = exports.ommlToLatex = void 0;
|
|
4
|
+
const xmlUtils_js_1 = require("./xmlUtils.js");
|
|
5
|
+
/**
|
|
6
|
+
* Equation markup normalization.
|
|
7
|
+
*
|
|
8
|
+
* Office documents ship equations in exactly two markups: OOXML's OMML (`<m:oMath>`, used by
|
|
9
|
+
* DOCX and PPTX) and MathML (`<math>`, used by ODF embedded objects, HTML, and EPUB3). Neither
|
|
10
|
+
* is plain text, and neither survives the generic "recurse into unknown elements and concatenate
|
|
11
|
+
* their text" fallback every parser ends with: `<m:num>1</m:num><m:den>2</m:den>` collapses to
|
|
12
|
+
* `12`, which still reads as a number, so nothing downstream can tell the value is wrong.
|
|
13
|
+
*
|
|
14
|
+
* Both markups are converted to LaTeX here rather than to a per-format ad hoc notation, because
|
|
15
|
+
* `MarkdownParser` already emits LaTeX for `$...$` / `$$...$$`. Converging on it means one
|
|
16
|
+
* representation reaches every generator, and a formula survives a docx -> md -> docx round trip
|
|
17
|
+
* instead of degrading at each hop.
|
|
18
|
+
*
|
|
19
|
+
* The output is always emitted as a `code` node carrying `CodeMetadata.math`, matching the
|
|
20
|
+
* contract `MarkdownParser` established - see `src/types.ts`.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Depth cap for the recursive walks below. Equation markup nests (a fraction inside a
|
|
24
|
+
* superscript inside a fraction), and the nesting is attacker-controlled: a few hundred bytes of
|
|
25
|
+
* hand-written XML can carry thousands of levels. The walks are recursive, so an unbounded
|
|
26
|
+
* document would exhaust the stack rather than merely producing odd output. 64 is far past any
|
|
27
|
+
* real equation - the deepest construct in a typical maths paper is 3 or 4 levels.
|
|
28
|
+
*/
|
|
29
|
+
const MAX_MATH_DEPTH = 64;
|
|
30
|
+
/** Marker substituted for a subtree that exceeded MAX_MATH_DEPTH, so truncation is never silent. */
|
|
31
|
+
const TRUNCATED = '\\ldots';
|
|
32
|
+
/**
|
|
33
|
+
* LaTeX metacharacters, escaped in any literal run of document text.
|
|
34
|
+
*
|
|
35
|
+
* The content of `<m:t>`, `<mi>`, `<mn>` and friends is literal characters, never LaTeX source -
|
|
36
|
+
* an author who types `%` into an equation means a percent sign, not a comment. Escaping is
|
|
37
|
+
* therefore lossless, and it also stops document text from injecting control sequences into the
|
|
38
|
+
* `$...$` span it lands in. Backslash must be replaced first or it would re-escape the
|
|
39
|
+
* backslashes introduced by the later replacements.
|
|
40
|
+
*/
|
|
41
|
+
const escapeLatex = (text) => text.replace(/\\/g, '\\textbackslash{}')
|
|
42
|
+
.replace(/([&%$#_{}])/g, '\\$1')
|
|
43
|
+
.replace(/~/g, '\\textasciitilde{}')
|
|
44
|
+
.replace(/\^/g, '\\textasciicircum{}');
|
|
45
|
+
/**
|
|
46
|
+
* Wraps an expression in braces unless it is already a single token.
|
|
47
|
+
*
|
|
48
|
+
* `x^{2}` and `x^2` render identically, but `x^{2y}` and `x^2y` do not, so the braces cannot be
|
|
49
|
+
* dropped whenever the argument is longer than one character. A lone digit or letter is the only
|
|
50
|
+
* safe case, and it is by far the most common one, so special-casing it keeps ordinary output
|
|
51
|
+
* readable without risking a mis-grouped exponent.
|
|
52
|
+
*/
|
|
53
|
+
const group = (latex) => /^[0-9a-zA-Z]$/.test(latex) ? latex : `{${latex}}`;
|
|
54
|
+
/** Strips any namespace prefix: `m:oMath` -> `omath`, `mml:mfrac` -> `mfrac`. */
|
|
55
|
+
const localName = (element) => element.tagName.toLowerCase().replace(/^.*:/, '');
|
|
56
|
+
/** Element children only, in document order. */
|
|
57
|
+
const elementChildren = (element) => {
|
|
58
|
+
const result = [];
|
|
59
|
+
for (let i = 0; i < (element.childNodes?.length ?? 0); i++) {
|
|
60
|
+
const child = element.childNodes[i];
|
|
61
|
+
if ((0, xmlUtils_js_1.isElement)(child))
|
|
62
|
+
result.push(child);
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
};
|
|
66
|
+
// ─── OMML (OOXML: DOCX, PPTX) ────────────────────────────────────────────────
|
|
67
|
+
/**
|
|
68
|
+
* Property elements. These carry styling (`m:ctrlPr` even wraps a full `w:rPr`) and never
|
|
69
|
+
* contribute display text, so they must be skipped rather than descended into - the generic
|
|
70
|
+
* fallback descending into them is one of the ways stray formatting text reached the output.
|
|
71
|
+
*/
|
|
72
|
+
const OMML_PROPERTY_TAGS = new Set([
|
|
73
|
+
'fpr', 'rpr', 'ctrlpr', 'ssubpr', 'ssuppr', 'ssubsuppr', 'dpr', 'radpr', 'narypr',
|
|
74
|
+
'funcpr', 'limlowpr', 'limupppr', 'mpr', 'argpr', 'barpr', 'accpr', 'grouppr',
|
|
75
|
+
'phantpr', 'boxpr', 'eqarrpr', 'spre', 'sty', 'scr', 'brk', 'aln', 'nor',
|
|
76
|
+
]);
|
|
77
|
+
/**
|
|
78
|
+
* `m:scr` math alphabets. OOXML encodes `ℝ` as an ASCII `R` plus a script attribute rather than
|
|
79
|
+
* as the Unicode character ODF uses, so these carry meaning and not merely styling.
|
|
80
|
+
*/
|
|
81
|
+
const OMML_MATH_ALPHABETS = {
|
|
82
|
+
'double-struck': '\\mathbb',
|
|
83
|
+
'script': '\\mathcal',
|
|
84
|
+
'fraktur': '\\mathfrak',
|
|
85
|
+
'monospace': '\\mathtt',
|
|
86
|
+
'sans-serif': '\\mathsf',
|
|
87
|
+
'roman': '\\mathrm',
|
|
88
|
+
};
|
|
89
|
+
/** Named OMML functions that map onto a LaTeX command of the same meaning. */
|
|
90
|
+
const OMML_NARY_OPERATORS = {
|
|
91
|
+
'∑': '\\sum', '∏': '\\prod', '∫': '\\int', '∬': '\\iint', '∭': '\\iiint',
|
|
92
|
+
'∮': '\\oint', '⋃': '\\bigcup', '⋂': '\\bigcap', '⋀': '\\bigwedge', '⋁': '\\bigvee',
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Converts an OMML subtree (`<m:oMath>` or any node within one) to LaTeX.
|
|
96
|
+
*
|
|
97
|
+
* Covers the constructs that actually appear in office documents: fractions, sub/superscripts,
|
|
98
|
+
* delimiters, radicals, n-ary operators, functions, accents, bars, boxes and matrices. Anything
|
|
99
|
+
* unrecognized falls through to concatenating its children, which is the old behaviour and the
|
|
100
|
+
* right degradation for a construct that carries no grouping of its own.
|
|
101
|
+
*/
|
|
102
|
+
const ommlToLatex = (node, depth = 0) => {
|
|
103
|
+
if (!node)
|
|
104
|
+
return '';
|
|
105
|
+
if (node.nodeType === 3)
|
|
106
|
+
return escapeLatex(node.textContent || '');
|
|
107
|
+
if (!(0, xmlUtils_js_1.isElement)(node))
|
|
108
|
+
return '';
|
|
109
|
+
if (depth > MAX_MATH_DEPTH)
|
|
110
|
+
return TRUNCATED;
|
|
111
|
+
const element = node;
|
|
112
|
+
const tag = localName(element);
|
|
113
|
+
if (OMML_PROPERTY_TAGS.has(tag))
|
|
114
|
+
return '';
|
|
115
|
+
const kids = elementChildren(element);
|
|
116
|
+
/** Concatenates every child, used for containers and for unrecognized constructs. */
|
|
117
|
+
const all = () => kids.map(k => (0, exports.ommlToLatex)(k, depth + 1)).join('');
|
|
118
|
+
/** The LaTeX for the first `<m:xxx>` child with the given local name, or '' when absent. */
|
|
119
|
+
const part = (name) => {
|
|
120
|
+
const found = kids.find(k => localName(k) === name);
|
|
121
|
+
return found ? (0, exports.ommlToLatex)(found, depth + 1) : '';
|
|
122
|
+
};
|
|
123
|
+
switch (tag) {
|
|
124
|
+
case 'r': {
|
|
125
|
+
// A run may carry a math alphabet on its own `m:rPr` - `ℝ` is written as a plain `R`
|
|
126
|
+
// with `<m:scr m:val="double-struck"/>`, so dropping the property loses the meaning
|
|
127
|
+
// of the symbol, not just its look. Both `m:rPr` and `w:rPr` reduce to the same local
|
|
128
|
+
// name, so select on content rather than on the prefix.
|
|
129
|
+
const body = all();
|
|
130
|
+
const rPr = kids.find(k => localName(k) === 'rpr'
|
|
131
|
+
&& elementChildren(k).some(p => localName(p) === 'scr' || localName(p) === 'sty'));
|
|
132
|
+
if (!rPr || !body)
|
|
133
|
+
return body;
|
|
134
|
+
const valueOf = (name) => {
|
|
135
|
+
const el = elementChildren(rPr).find(p => localName(p) === name);
|
|
136
|
+
return el?.getAttribute('m:val') ?? el?.getAttribute('val') ?? '';
|
|
137
|
+
};
|
|
138
|
+
const alphabet = OMML_MATH_ALPHABETS[valueOf('scr')]
|
|
139
|
+
?? (valueOf('sty') === 'b' ? '\\mathbf' : undefined);
|
|
140
|
+
return alphabet ? `${alphabet}${group(body)}` : body;
|
|
141
|
+
}
|
|
142
|
+
// Containers: an equation, an argument, a base.
|
|
143
|
+
case 'omath':
|
|
144
|
+
case 'omathpara':
|
|
145
|
+
case 'e':
|
|
146
|
+
case 'num':
|
|
147
|
+
case 'den':
|
|
148
|
+
case 'sub':
|
|
149
|
+
case 'sup':
|
|
150
|
+
case 'lim':
|
|
151
|
+
case 'fname':
|
|
152
|
+
return all();
|
|
153
|
+
case 't':
|
|
154
|
+
return escapeLatex(element.textContent || '');
|
|
155
|
+
case 'f': {
|
|
156
|
+
// `m:type val="lin"` asks for an inline `a/b` rather than a stacked fraction.
|
|
157
|
+
const fPr = kids.find(k => localName(k) === 'fpr');
|
|
158
|
+
const typeEl = fPr ? elementChildren(fPr).find(k => localName(k) === 'type') : undefined;
|
|
159
|
+
const linear = typeEl?.getAttribute('m:val') === 'lin' || typeEl?.getAttribute('val') === 'lin';
|
|
160
|
+
const num = part('num');
|
|
161
|
+
const den = part('den');
|
|
162
|
+
return linear ? `${group(num)}/${group(den)}` : `\\frac${group(num)}${group(den)}`;
|
|
163
|
+
}
|
|
164
|
+
case 'ssup':
|
|
165
|
+
return `${group(part('e'))}^${group(part('sup'))}`;
|
|
166
|
+
case 'ssub':
|
|
167
|
+
return `${group(part('e'))}_${group(part('sub'))}`;
|
|
168
|
+
case 'ssubsup':
|
|
169
|
+
return `${group(part('e'))}_${group(part('sub'))}^${group(part('sup'))}`;
|
|
170
|
+
case 'spre':
|
|
171
|
+
// Pre-sub/superscript: the scripts precede the base.
|
|
172
|
+
return `{}_${group(part('sub'))}^${group(part('sup'))}${group(part('e'))}`;
|
|
173
|
+
case 'd': {
|
|
174
|
+
// Delimiters. The characters are document-supplied and default to parentheses.
|
|
175
|
+
// Plain delimiters rather than \left...\right: an unbalanced \left would break the
|
|
176
|
+
// whole expression, and a document can legitimately open without closing.
|
|
177
|
+
const dPr = kids.find(k => localName(k) === 'dpr');
|
|
178
|
+
const chr = (name, fallback) => {
|
|
179
|
+
const el = dPr ? elementChildren(dPr).find(k => localName(k) === name) : undefined;
|
|
180
|
+
const raw = el?.getAttribute('m:val') ?? el?.getAttribute('val');
|
|
181
|
+
return raw ? escapeLatex(raw) : fallback;
|
|
182
|
+
};
|
|
183
|
+
const beg = chr('begchr', '(');
|
|
184
|
+
const end = chr('endchr', ')');
|
|
185
|
+
const sep = chr('sepchr', ',');
|
|
186
|
+
const args = kids.filter(k => localName(k) === 'e').map(k => (0, exports.ommlToLatex)(k, depth + 1));
|
|
187
|
+
return `${beg}${args.join(sep)}${end}`;
|
|
188
|
+
}
|
|
189
|
+
case 'rad': {
|
|
190
|
+
const deg = part('deg');
|
|
191
|
+
const base = group(part('e'));
|
|
192
|
+
return deg ? `\\sqrt[${deg}]${base}` : `\\sqrt${base}`;
|
|
193
|
+
}
|
|
194
|
+
case 'nary': {
|
|
195
|
+
// Summation/integral and friends: operator, optional bounds, then the operand.
|
|
196
|
+
const naryPr = kids.find(k => localName(k) === 'narypr');
|
|
197
|
+
const chrEl = naryPr ? elementChildren(naryPr).find(k => localName(k) === 'chr') : undefined;
|
|
198
|
+
const chr = chrEl?.getAttribute('m:val') ?? chrEl?.getAttribute('val') ?? '∫';
|
|
199
|
+
const op = OMML_NARY_OPERATORS[chr] ?? escapeLatex(chr);
|
|
200
|
+
const sub = part('sub');
|
|
201
|
+
const sup = part('sup');
|
|
202
|
+
return `${op}${sub ? `_${group(sub)}` : ''}${sup ? `^${group(sup)}` : ''}${part('e')}`;
|
|
203
|
+
}
|
|
204
|
+
case 'func':
|
|
205
|
+
// `sin`, `log`, ... - the name is document text, so it cannot become a bare command.
|
|
206
|
+
return `\\operatorname${group(part('fname'))}${group(part('e'))}`;
|
|
207
|
+
case 'limlow':
|
|
208
|
+
return `${part('e')}_${group(part('lim'))}`;
|
|
209
|
+
case 'limupp':
|
|
210
|
+
return `${part('e')}^${group(part('lim'))}`;
|
|
211
|
+
case 'bar': {
|
|
212
|
+
const barPr = kids.find(k => localName(k) === 'barpr');
|
|
213
|
+
const posEl = barPr ? elementChildren(barPr).find(k => localName(k) === 'pos') : undefined;
|
|
214
|
+
const pos = posEl?.getAttribute('m:val') ?? posEl?.getAttribute('val');
|
|
215
|
+
return `${pos === 'top' ? '\\overline' : '\\underline'}${group(part('e'))}`;
|
|
216
|
+
}
|
|
217
|
+
case 'acc': {
|
|
218
|
+
const accPr = kids.find(k => localName(k) === 'accpr');
|
|
219
|
+
const chrEl = accPr ? elementChildren(accPr).find(k => localName(k) === 'chr') : undefined;
|
|
220
|
+
const chr = chrEl?.getAttribute('m:val') ?? chrEl?.getAttribute('val') ?? '̂';
|
|
221
|
+
const command = chr === '̄' ? '\\bar' : chr === '⃗' ? '\\vec' : chr === '̇' ? '\\dot' : '\\hat';
|
|
222
|
+
return `${command}${group(part('e'))}`;
|
|
223
|
+
}
|
|
224
|
+
case 'box':
|
|
225
|
+
case 'borderbox':
|
|
226
|
+
case 'phant':
|
|
227
|
+
case 'group':
|
|
228
|
+
case 'groupchr':
|
|
229
|
+
return part('e') || all();
|
|
230
|
+
case 'm': {
|
|
231
|
+
// Matrix: rows of cells. `\begin{matrix}` carries no delimiters of its own, which is
|
|
232
|
+
// correct - a bracketed matrix wraps the `m:m` in an `m:d` that supplies them.
|
|
233
|
+
const rows = kids.filter(k => localName(k) === 'mr').map(row => elementChildren(row)
|
|
234
|
+
.filter(cell => localName(cell) === 'e')
|
|
235
|
+
.map(cell => (0, exports.ommlToLatex)(cell, depth + 1))
|
|
236
|
+
.join(' & '));
|
|
237
|
+
return `\\begin{matrix}${rows.join(' \\\\ ')}\\end{matrix}`;
|
|
238
|
+
}
|
|
239
|
+
default:
|
|
240
|
+
return all();
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
exports.ommlToLatex = ommlToLatex;
|
|
244
|
+
// ─── MathML (ODF embedded objects, HTML, EPUB3) ──────────────────────────────
|
|
245
|
+
/** MathML operators that have a dedicated LaTeX command. */
|
|
246
|
+
const MATHML_OPERATORS = {
|
|
247
|
+
'∑': '\\sum', '∏': '\\prod', '∫': '\\int', '∮': '\\oint', '√': '\\sqrt',
|
|
248
|
+
'±': '\\pm', '∓': '\\mp', '×': '\\times', '÷': '\\div', '⋅': '\\cdot',
|
|
249
|
+
'≤': '\\leq', '≥': '\\geq', '≠': '\\neq', '≈': '\\approx', '≡': '\\equiv',
|
|
250
|
+
'∈': '\\in', '∉': '\\notin', '⊂': '\\subset', '⊆': '\\subseteq', '∪': '\\cup',
|
|
251
|
+
'∩': '\\cap', '∞': '\\infty', '→': '\\to', '⇒': '\\Rightarrow', '⇔': '\\Leftrightarrow',
|
|
252
|
+
'∀': '\\forall', '∃': '\\exists', '∂': '\\partial', '∇': '\\nabla', '…': '\\ldots',
|
|
253
|
+
'ℝ': '\\mathbb{R}', 'ℕ': '\\mathbb{N}', 'ℤ': '\\mathbb{Z}', 'ℚ': '\\mathbb{Q}', 'ℂ': '\\mathbb{C}',
|
|
254
|
+
};
|
|
255
|
+
/** Maps a literal run through the operator table, falling back to plain escaped text. */
|
|
256
|
+
const mathmlToken = (raw) => {
|
|
257
|
+
const trimmed = raw.trim();
|
|
258
|
+
return MATHML_OPERATORS[trimmed] ?? escapeLatex(raw);
|
|
259
|
+
};
|
|
260
|
+
/** Local name of a MathNode: `mml:mfrac` -> `mfrac`, `undefined` for a text node. */
|
|
261
|
+
const mathNodeName = (node) => (node.tagName || '').toLowerCase().replace(/^.*:/, '');
|
|
262
|
+
/** Presents an XML DOM node through the MathNode shape. */
|
|
263
|
+
const fromDom = (node) => {
|
|
264
|
+
if (node.nodeType === 3 || !(0, xmlUtils_js_1.isElement)(node)) {
|
|
265
|
+
return { text: node.textContent || '', children: [] };
|
|
266
|
+
}
|
|
267
|
+
const element = node;
|
|
268
|
+
const attributes = {};
|
|
269
|
+
for (let i = 0; i < (element.attributes?.length ?? 0); i++) {
|
|
270
|
+
const attr = element.attributes[i];
|
|
271
|
+
attributes[attr.name] = attr.value;
|
|
272
|
+
}
|
|
273
|
+
return {
|
|
274
|
+
tagName: element.tagName,
|
|
275
|
+
attributes,
|
|
276
|
+
text: element.textContent || '',
|
|
277
|
+
children: elementChildren(element).map(fromDom),
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
/**
|
|
281
|
+
* Converts a MathML subtree to LaTeX.
|
|
282
|
+
*
|
|
283
|
+
* When the document carries a TeX annotation (`<annotation encoding="application/x-tex">`), that
|
|
284
|
+
* is the author's own source and is used verbatim in preference to anything reconstructed here.
|
|
285
|
+
* ODF's `<annotation encoding="StarMath 5.0">` is deliberately not used - StarMath is not LaTeX,
|
|
286
|
+
* and emitting it would put a second notation back into the output this module exists to unify.
|
|
287
|
+
*/
|
|
288
|
+
const mathmlTreeToLatex = (node, depth = 0) => {
|
|
289
|
+
if (!node)
|
|
290
|
+
return '';
|
|
291
|
+
if (!node.tagName)
|
|
292
|
+
return mathmlToken(node.text || '');
|
|
293
|
+
if (depth > MAX_MATH_DEPTH)
|
|
294
|
+
return TRUNCATED;
|
|
295
|
+
const tag = mathNodeName(node);
|
|
296
|
+
const kids = node.children ?? [];
|
|
297
|
+
/**
|
|
298
|
+
* The literal content of a leaf token. The DOM adapter fills `text` with `textContent`, but
|
|
299
|
+
* `HtmlParser` keeps an element's text in child text nodes and leaves `text` unset, so fall
|
|
300
|
+
* back to gathering the children rather than emitting an empty token.
|
|
301
|
+
*/
|
|
302
|
+
const tokenText = () => node.text || kids.map(k => k.text || '').join('');
|
|
303
|
+
const all = () => kids.map(k => (0, exports.mathmlTreeToLatex)(k, depth + 1)).join('');
|
|
304
|
+
const arg = (index) => (kids[index] ? (0, exports.mathmlTreeToLatex)(kids[index], depth + 1) : '');
|
|
305
|
+
switch (tag) {
|
|
306
|
+
case 'math':
|
|
307
|
+
case 'semantics': {
|
|
308
|
+
const tex = kids.find(k => mathNodeName(k) === 'annotation'
|
|
309
|
+
&& /tex/i.test(k.attributes?.['encoding'] || ''));
|
|
310
|
+
// Same reason `tokenText` exists below: an element's text is in `text` for the DOM
|
|
311
|
+
// adapter and in child text nodes for `HtmlParser`, so both have to be consulted.
|
|
312
|
+
if (tex)
|
|
313
|
+
return (tex.text || (tex.children ?? []).map(c => c.text || '').join('')).trim();
|
|
314
|
+
return kids.map(k => (0, exports.mathmlTreeToLatex)(k, depth + 1)).join('');
|
|
315
|
+
}
|
|
316
|
+
case 'mrow':
|
|
317
|
+
case 'mstyle':
|
|
318
|
+
case 'mpadded':
|
|
319
|
+
case 'mphantom':
|
|
320
|
+
return all();
|
|
321
|
+
case 'mi':
|
|
322
|
+
case 'mn':
|
|
323
|
+
case 'mo':
|
|
324
|
+
case 'mtext':
|
|
325
|
+
case 'ms':
|
|
326
|
+
return mathmlToken(tokenText());
|
|
327
|
+
case 'mfrac':
|
|
328
|
+
return `\\frac${group(arg(0))}${group(arg(1))}`;
|
|
329
|
+
case 'msup':
|
|
330
|
+
return `${group(arg(0))}^${group(arg(1))}`;
|
|
331
|
+
case 'msub':
|
|
332
|
+
return `${group(arg(0))}_${group(arg(1))}`;
|
|
333
|
+
case 'msubsup':
|
|
334
|
+
return `${group(arg(0))}_${group(arg(1))}^${group(arg(2))}`;
|
|
335
|
+
case 'munder':
|
|
336
|
+
return `\\underset${group(arg(1))}${group(arg(0))}`;
|
|
337
|
+
case 'mover':
|
|
338
|
+
return `\\overset${group(arg(1))}${group(arg(0))}`;
|
|
339
|
+
case 'munderover':
|
|
340
|
+
return `${group(arg(0))}_${group(arg(1))}^${group(arg(2))}`;
|
|
341
|
+
case 'msqrt':
|
|
342
|
+
return `\\sqrt${group(all())}`;
|
|
343
|
+
case 'mroot':
|
|
344
|
+
return `\\sqrt[${arg(1)}]${group(arg(0))}`;
|
|
345
|
+
case 'mfenced': {
|
|
346
|
+
// Deprecated in MathML 3 but still emitted by older producers.
|
|
347
|
+
const open = escapeLatex(node.attributes?.['open'] ?? '(');
|
|
348
|
+
const close = escapeLatex(node.attributes?.['close'] ?? ')');
|
|
349
|
+
const sep = escapeLatex(node.attributes?.['separators'] ?? ',');
|
|
350
|
+
return `${open}${kids.map(k => (0, exports.mathmlTreeToLatex)(k, depth + 1)).join(sep)}${close}`;
|
|
351
|
+
}
|
|
352
|
+
case 'mtable':
|
|
353
|
+
return `\\begin{matrix}${kids
|
|
354
|
+
.filter(k => mathNodeName(k) === 'mtr')
|
|
355
|
+
.map(row => (row.children ?? [])
|
|
356
|
+
.filter(cell => mathNodeName(cell) === 'mtd')
|
|
357
|
+
.map(cell => (0, exports.mathmlTreeToLatex)(cell, depth + 1))
|
|
358
|
+
.join(' & '))
|
|
359
|
+
.join(' \\\\ ')}\\end{matrix}`;
|
|
360
|
+
case 'mtr':
|
|
361
|
+
case 'mtd':
|
|
362
|
+
return all();
|
|
363
|
+
case 'mspace':
|
|
364
|
+
return ' ';
|
|
365
|
+
// Presentation-only wrappers and the annotations themselves carry nothing renderable:
|
|
366
|
+
// `annotation-xml` duplicates the presentation tree in Content MathML, and emitting both
|
|
367
|
+
// would double every formula that has one.
|
|
368
|
+
case 'annotation':
|
|
369
|
+
case 'annotation-xml':
|
|
370
|
+
case 'maction':
|
|
371
|
+
return '';
|
|
372
|
+
default:
|
|
373
|
+
return all();
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
exports.mathmlTreeToLatex = mathmlTreeToLatex;
|
|
377
|
+
/** Converts a MathML subtree held in an XML DOM (ODF embedded objects) to LaTeX. */
|
|
378
|
+
const mathmlToLatex = (node, depth = 0) => (0, exports.mathmlTreeToLatex)(fromDom(node), depth);
|
|
379
|
+
exports.mathmlToLatex = mathmlToLatex;
|
|
380
|
+
/**
|
|
381
|
+
* True when a converted equation carries nothing worth emitting, so callers can drop the node
|
|
382
|
+
* instead of pushing an empty `$$` into the output.
|
|
383
|
+
*/
|
|
384
|
+
const isEmptyMath = (latex) => latex.trim().length === 0;
|
|
385
|
+
exports.isEmptyMath = isEmptyMath;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module Loader Utility
|
|
3
|
+
*
|
|
4
|
+
* Centralizes dynamic imports for ESM-only packages (like file-type and pdfjs-dist)
|
|
5
|
+
* to maintain CommonJS compatibility while supporting modern ESM dependencies.
|
|
6
|
+
*
|
|
7
|
+
* This approach prevents TypeScript from transpiling dynamic import()
|
|
8
|
+
* into require() when targeting CommonJS.
|
|
9
|
+
*/
|
|
10
|
+
import type * as FileTypeModule from 'file-type' with { 'resolution-mode': 'import' };
|
|
11
|
+
/**
|
|
12
|
+
* Specialized loader for file-type
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadFileType(): Promise<typeof FileTypeModule>;
|
|
15
|
+
/**
|
|
16
|
+
* Specialized loader for pdfjs-dist
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadPdfJs(): Promise<any>;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Module Loader Utility
|
|
4
|
+
*
|
|
5
|
+
* Centralizes dynamic imports for ESM-only packages (like file-type and pdfjs-dist)
|
|
6
|
+
* to maintain CommonJS compatibility while supporting modern ESM dependencies.
|
|
7
|
+
*
|
|
8
|
+
* This approach prevents TypeScript from transpiling dynamic import()
|
|
9
|
+
* into require() when targeting CommonJS.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.loadFileType = loadFileType;
|
|
13
|
+
exports.loadPdfJs = loadPdfJs;
|
|
14
|
+
const envUtils_js_1 = require("./envUtils.js");
|
|
15
|
+
async function loadNodeEsmModule(specifier) {
|
|
16
|
+
// In Node.js, we resolve the specifier to an absolute file URL.
|
|
17
|
+
// This ensures that the dynamic import() call
|
|
18
|
+
// always finds the correct module regardless of the caller's context.
|
|
19
|
+
// This is especially important in Node 18 for sub-paths of packages.
|
|
20
|
+
try {
|
|
21
|
+
const { pathToFileURL } = await import('url');
|
|
22
|
+
// @ts-ignore - require.resolve is available in Node.js CJS context
|
|
23
|
+
const absolutePath = require.resolve(specifier);
|
|
24
|
+
const fileUrl = pathToFileURL(absolutePath).href;
|
|
25
|
+
return import(fileUrl);
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
// Fallback for cases where require.resolve might fail (e.g. non-file specifiers)
|
|
29
|
+
return import(specifier);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns true if require.resolve is available in this runtime context.
|
|
34
|
+
* It is NOT available in native ESM (e.g. the .mjs wrapper) or browser environments.
|
|
35
|
+
* Checking this guards against a ReferenceError that would silently trigger
|
|
36
|
+
* the bundled fallback path for non-bundled ESM consumers.
|
|
37
|
+
*/
|
|
38
|
+
function isRequireAvailable() {
|
|
39
|
+
// @ts-ignore - require may not exist in ESM context
|
|
40
|
+
return typeof require !== 'undefined' && typeof require.resolve === 'function';
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Specialized loader for file-type
|
|
44
|
+
*/
|
|
45
|
+
async function loadFileType() {
|
|
46
|
+
if (!envUtils_js_1.isBrowser) {
|
|
47
|
+
// Ensure environment polyfills for Node.js 18 support
|
|
48
|
+
(0, envUtils_js_1.ensureEnvPolyfills)();
|
|
49
|
+
if (isRequireAvailable()) {
|
|
50
|
+
// Check if node_modules is available at runtime.
|
|
51
|
+
// @ts-ignore - require.resolve is available in Node.js CJS context
|
|
52
|
+
require.resolve(String('file-type'));
|
|
53
|
+
// node_modules present: use the path-resolved loader for Node 18 ESM compatibility
|
|
54
|
+
return loadNodeEsmModule('file-type');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Covers three cases with one return:
|
|
58
|
+
// 1. Node.js standalone/bundled (SEA or bundled CJS): bundler inlines the module at build time.
|
|
59
|
+
// 2. Node.js native ESM (no require available): runtime resolves the bare specifier.
|
|
60
|
+
// 3. Browser: bundler (esbuild/Vite) handles the static-looking dynamic import().
|
|
61
|
+
// Note: bypasses the Node 18 sub-path ESM fix in loadNodeEsmModule, but bundlers handle it.
|
|
62
|
+
return import('file-type');
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Specialized loader for pdfjs-dist
|
|
66
|
+
*/
|
|
67
|
+
async function loadPdfJs() {
|
|
68
|
+
if (!envUtils_js_1.isBrowser) {
|
|
69
|
+
// Ensure environment polyfills for Node.js 18 support
|
|
70
|
+
(0, envUtils_js_1.ensureEnvPolyfills)();
|
|
71
|
+
if (isRequireAvailable()) {
|
|
72
|
+
// @ts-ignore - require.resolve is available in Node.js CJS context
|
|
73
|
+
const pkgExists = (() => { try {
|
|
74
|
+
require.resolve(String('pdfjs-dist'));
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return false;
|
|
79
|
+
} })();
|
|
80
|
+
if (pkgExists) {
|
|
81
|
+
// node_modules present: try the legacy build path first for stability with
|
|
82
|
+
// ESM-only main, then fall back to the package root.
|
|
83
|
+
// Errors from these loaders are NOT swallowed into the bundled-fallback path.
|
|
84
|
+
try {
|
|
85
|
+
return await loadNodeEsmModule('pdfjs-dist/legacy/build/pdf.mjs');
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return await loadNodeEsmModule('pdfjs-dist');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Standalone/bundled fallback for Node.js (SEA, bundled CJS without node_modules, or native ESM context):
|
|
93
|
+
// Load both PDF.js and its worker, and register the worker on globalThis to enable the offline fake-worker.
|
|
94
|
+
// @ts-ignore - Ignore type check for local .mjs files in node_modules/packaging
|
|
95
|
+
const [pdfjs, pdfjsWorker] = await Promise.all([
|
|
96
|
+
// @ts-ignore - mjs imports may not have types
|
|
97
|
+
import('pdfjs-dist/legacy/build/pdf.mjs'),
|
|
98
|
+
// @ts-ignore - mjs imports may not have types
|
|
99
|
+
import('pdfjs-dist/legacy/build/pdf.worker.mjs')
|
|
100
|
+
]);
|
|
101
|
+
globalThis.pdfjsWorker = pdfjsWorker;
|
|
102
|
+
return pdfjs;
|
|
103
|
+
}
|
|
104
|
+
// Browser environment: bundler (esbuild/Vite) handles the standard dynamic import()
|
|
105
|
+
return import('pdfjs-dist');
|
|
106
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OCR (Optical Character Recognition) Utilities
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions for extracting text from images using Tesseract.js.
|
|
5
|
+
* Used when `config.ocr` is enabled to extract text from embedded images in documents.
|
|
6
|
+
*
|
|
7
|
+
* Includes a worker pool via OcrSchedulerManager to improve performance when
|
|
8
|
+
* processing multiple images.
|
|
9
|
+
*
|
|
10
|
+
* @module ocrUtils
|
|
11
|
+
*/
|
|
12
|
+
import { OcrConfig } from '../types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Performs Optical Character Recognition (OCR) on an image to extract text.
|
|
15
|
+
*
|
|
16
|
+
* Uses Tesseract.js to recognize text in the provided image buffer.
|
|
17
|
+
* This is useful for extracting text from screenshots, scanned documents,
|
|
18
|
+
* charts with labels, or any image containing text.
|
|
19
|
+
*
|
|
20
|
+
* This function uses a shared worker pool to minimize initialization overhead.
|
|
21
|
+
*
|
|
22
|
+
* @param image - The image data as a Buffer, file path, or Blob
|
|
23
|
+
* @param config - Optional configuration for language and custom worker paths
|
|
24
|
+
* @returns A promise that resolves to the recognized text as a string
|
|
25
|
+
* @throws {Error} If the image cannot be processed or Tesseract initialization fails
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```typescript
|
|
29
|
+
* // Extract text from an English image
|
|
30
|
+
* const text = await performOcr(imageBuffer, { language: 'eng' });
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @see https://github.com/naptha/tesseract.js for supported languages and options
|
|
34
|
+
*/
|
|
35
|
+
export declare const performOcr: (image: Buffer | string, config?: OcrConfig) => Promise<string>;
|
|
36
|
+
/**
|
|
37
|
+
* Terminates all OCR workers and cleans up resources.
|
|
38
|
+
*
|
|
39
|
+
* Should be called when the application is shutting down or OCR is no longer needed
|
|
40
|
+
* to prevent memory leaks and dangling worker processes.
|
|
41
|
+
*/
|
|
42
|
+
export declare const terminateOcr: () => Promise<void>;
|