@gmickel/gno 1.46.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/README.md +17 -5
  2. package/THIRD_PARTY_NOTICES.md +46 -0
  3. package/assets/skill/SKILL.md +7 -6
  4. package/assets/spa-production.json.gz +0 -0
  5. package/browser-extension/artifacts/gno-browser-clipper-v2.1.0.zip +0 -0
  6. package/browser-extension/artifacts/gno-browser-clipper-v2.1.0.zip.sha256 +1 -0
  7. package/browser-extension/dist/chunk-4tc9v0ja.js +74 -0
  8. package/browser-extension/dist/manifest.json +1 -1
  9. package/browser-extension/dist/preview.html +1 -1
  10. package/browser-extension/dist/service-worker.js +32 -33
  11. package/bunfig.toml +2 -0
  12. package/package.json +40 -26
  13. package/spec/cli.md +29 -4
  14. package/spec/db/schema.sql +146 -1
  15. package/spec/mcp.md +26 -0
  16. package/src/app/context-runtime-types.ts +3 -0
  17. package/src/app/context-runtime.ts +2 -0
  18. package/src/cli/commands/ask.ts +6 -1
  19. package/src/cli/commands/daemon.ts +21 -8
  20. package/src/cli/commands/embed.ts +77 -41
  21. package/src/cli/detach.ts +3 -2
  22. package/src/config/types.ts +3 -3
  23. package/src/converters/adapters/markitdownTs/adapter.ts +1 -2
  24. package/src/converters/adapters/officeparser/adapter.ts +1 -2
  25. package/src/converters/versions.ts +6 -8
  26. package/src/core/context-evidence.ts +8 -4
  27. package/src/core/job-manager.ts +95 -13
  28. package/src/core/network-boundary-inventory.ts +10 -0
  29. package/src/core/shutdown-budget.ts +45 -0
  30. package/src/embed/backlog.ts +107 -4
  31. package/src/embed/batch.ts +42 -2
  32. package/src/embed/fingerprint.ts +16 -0
  33. package/src/embed/retry.ts +113 -5
  34. package/src/embed/variant-backlog.ts +105 -0
  35. package/src/embed/variant-plan.ts +62 -0
  36. package/src/embed/variant-retry.ts +113 -0
  37. package/src/ingestion/graph-reconciliation.ts +327 -0
  38. package/src/ingestion/sync.ts +9 -272
  39. package/src/llm/http-inference.ts +6 -0
  40. package/src/llm/httpEmbedding.ts +37 -6
  41. package/src/llm/httpGeneration.ts +18 -3
  42. package/src/llm/httpRerank.ts +23 -5
  43. package/src/llm/inference-cancellation.ts +168 -0
  44. package/src/llm/inference-scope.ts +202 -0
  45. package/src/llm/lazy-ports.ts +115 -0
  46. package/src/llm/native-worker/client.ts +541 -0
  47. package/src/llm/native-worker/dispatcher.ts +228 -0
  48. package/src/llm/native-worker/embedding-identity.ts +33 -0
  49. package/src/llm/native-worker/entry.ts +173 -0
  50. package/src/llm/native-worker/errors.ts +32 -0
  51. package/src/llm/native-worker/evaluation.ts +16 -0
  52. package/src/llm/native-worker/owned-exit.ts +108 -0
  53. package/src/llm/native-worker/owner.ts +141 -0
  54. package/src/llm/native-worker/ports.ts +317 -0
  55. package/src/llm/native-worker/protocol.ts +442 -0
  56. package/src/llm/native-worker/runtime-config.ts +92 -0
  57. package/src/llm/nodeLlamaCpp/adapter.ts +77 -20
  58. package/src/llm/nodeLlamaCpp/embedding.ts +130 -46
  59. package/src/llm/nodeLlamaCpp/generation.ts +34 -5
  60. package/src/llm/nodeLlamaCpp/lifecycle-options.ts +99 -0
  61. package/src/llm/nodeLlamaCpp/lifecycle.ts +209 -204
  62. package/src/llm/nodeLlamaCpp/rerank-capacity.ts +111 -0
  63. package/src/llm/nodeLlamaCpp/rerank.ts +118 -27
  64. package/src/llm/nodeLlamaCpp/simulator-handle.ts +73 -0
  65. package/src/llm/nodeLlamaCpp/simulator-install.ts +124 -0
  66. package/src/llm/nodeLlamaCpp/simulator-session.ts +240 -0
  67. package/src/llm/nodeLlamaCpp/simulator-types.ts +80 -0
  68. package/src/llm/types.ts +35 -5
  69. package/src/mcp/context.ts +27 -0
  70. package/src/mcp/http-transport.ts +12 -10
  71. package/src/mcp/server.ts +3 -0
  72. package/src/mcp/tool-profile.ts +30 -8
  73. package/src/mcp/tools/context.ts +8 -11
  74. package/src/mcp/tools/embed.ts +1 -1
  75. package/src/mcp/tools/index-cmd.ts +1 -1
  76. package/src/mcp/tools/index.ts +10 -8
  77. package/src/mcp/tools/query.ts +14 -30
  78. package/src/mcp/tools/vsearch.ts +1 -1
  79. package/src/pipeline/answer.ts +23 -3
  80. package/src/pipeline/claim-verifier.ts +6 -0
  81. package/src/pipeline/expansion.ts +43 -40
  82. package/src/pipeline/explain.ts +6 -2
  83. package/src/pipeline/filters.ts +63 -0
  84. package/src/pipeline/fusion.ts +29 -9
  85. package/src/pipeline/graph-retrieval.ts +29 -9
  86. package/src/pipeline/hybrid.ts +198 -55
  87. package/src/pipeline/hydration.ts +161 -0
  88. package/src/pipeline/owner-fusion.ts +87 -0
  89. package/src/pipeline/rerank.ts +35 -11
  90. package/src/pipeline/search.ts +13 -2
  91. package/src/pipeline/types.ts +5 -3
  92. package/src/pipeline/vsearch.ts +87 -7
  93. package/src/sdk/client.ts +47 -3
  94. package/src/sdk/embed.ts +63 -39
  95. package/src/serve/background-runtime.ts +1 -1
  96. package/src/serve/context.ts +41 -56
  97. package/src/serve/embed-scheduler.ts +58 -35
  98. package/src/serve/public/components/IndexingProgress.tsx +46 -60
  99. package/src/serve/public/components/PublishExportDialog.tsx +266 -0
  100. package/src/serve/public/globals.built.css +1 -1
  101. package/src/serve/public/globals.css +35 -0
  102. package/src/serve/public/lib/publish-export.ts +81 -1
  103. package/src/serve/public/lib/shiki-language-ids.ts +14 -0
  104. package/src/serve/public/pages/Collections.tsx +12 -46
  105. package/src/serve/public/pages/DocView.tsx +14 -52
  106. package/src/serve/resident-admission.ts +36 -36
  107. package/src/serve/resident-background-work.ts +20 -2
  108. package/src/serve/resident-request.ts +11 -5
  109. package/src/serve/resident-runtime.ts +97 -61
  110. package/src/serve/resident-shutdown.ts +153 -0
  111. package/src/serve/routes/api.ts +3 -1
  112. package/src/serve/server.ts +47 -26
  113. package/src/store/migrations/028-vector-variants.ts +54 -0
  114. package/src/store/migrations/029-graph-reference-state.ts +77 -0
  115. package/src/store/migrations/index.ts +4 -0
  116. package/src/store/sqlite/adapter.ts +251 -183
  117. package/src/store/sqlite/eligibility.ts +174 -0
  118. package/src/store/sqlite/graph-edge-application.ts +66 -0
  119. package/src/store/sqlite/graph-reference-state.ts +194 -0
  120. package/src/store/sqlite/legacy-vector-ownership.ts +79 -0
  121. package/src/store/types.ts +80 -12
  122. package/src/store/vector/eligibility.ts +36 -0
  123. package/src/store/vector/freshness.ts +33 -6
  124. package/src/store/vector/lazy.ts +81 -0
  125. package/src/store/vector/sqlite-vec.ts +106 -54
  126. package/src/store/vector/stats.ts +14 -3
  127. package/src/store/vector/types.ts +35 -2
  128. package/src/store/vector/variant-search.ts +192 -0
  129. package/src/store/vector/variants.ts +451 -0
  130. package/vendor/converters/markitdown-ts/LICENSE +21 -0
  131. package/vendor/converters/markitdown-ts/dist/index.cjs +1180 -0
  132. package/vendor/converters/markitdown-ts/dist/index.d.cts +46 -0
  133. package/vendor/converters/markitdown-ts/dist/index.d.mts +46 -0
  134. package/vendor/converters/markitdown-ts/dist/index.d.ts +46 -0
  135. package/vendor/converters/markitdown-ts/dist/index.mjs +1152 -0
  136. package/vendor/converters/markitdown-ts/package.json +77 -0
  137. package/vendor/converters/officeparser/LICENSE +21 -0
  138. package/vendor/converters/officeparser/dist/OfficeConverter.d.ts +47 -0
  139. package/vendor/converters/officeparser/dist/OfficeConverter.js +76 -0
  140. package/vendor/converters/officeparser/dist/OfficeGenerator.d.ts +23 -0
  141. package/vendor/converters/officeparser/dist/OfficeGenerator.js +73 -0
  142. package/vendor/converters/officeparser/dist/OfficeParser.d.ts +106 -0
  143. package/vendor/converters/officeparser/dist/OfficeParser.js +332 -0
  144. package/vendor/converters/officeparser/dist/cli.d.ts +28 -0
  145. package/vendor/converters/officeparser/dist/cli.js +381 -0
  146. package/vendor/converters/officeparser/dist/defaults.d.ts +41 -0
  147. package/vendor/converters/officeparser/dist/defaults.js +218 -0
  148. package/vendor/converters/officeparser/dist/generators/BaseGenerator.d.ts +107 -0
  149. package/vendor/converters/officeparser/dist/generators/BaseGenerator.js +248 -0
  150. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.d.ts +82 -0
  151. package/vendor/converters/officeparser/dist/generators/ChunkingGenerator.js +797 -0
  152. package/vendor/converters/officeparser/dist/generators/CsvGenerator.d.ts +38 -0
  153. package/vendor/converters/officeparser/dist/generators/CsvGenerator.js +245 -0
  154. package/vendor/converters/officeparser/dist/generators/EpubGenerator.d.ts +43 -0
  155. package/vendor/converters/officeparser/dist/generators/EpubGenerator.js +315 -0
  156. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.d.ts +59 -0
  157. package/vendor/converters/officeparser/dist/generators/HtmlGenerator.js +1942 -0
  158. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.d.ts +96 -0
  159. package/vendor/converters/officeparser/dist/generators/MarkdownGenerator.js +1175 -0
  160. package/vendor/converters/officeparser/dist/generators/PdfGenerator.d.ts +22 -0
  161. package/vendor/converters/officeparser/dist/generators/PdfGenerator.js +194 -0
  162. package/vendor/converters/officeparser/dist/generators/RtfGenerator.d.ts +29 -0
  163. package/vendor/converters/officeparser/dist/generators/RtfGenerator.js +316 -0
  164. package/vendor/converters/officeparser/dist/generators/TextGenerator.d.ts +13 -0
  165. package/vendor/converters/officeparser/dist/generators/TextGenerator.js +201 -0
  166. package/vendor/converters/officeparser/dist/index.d.ts +60 -0
  167. package/vendor/converters/officeparser/dist/index.js +72 -0
  168. package/vendor/converters/officeparser/dist/index.mjs +18 -0
  169. package/vendor/converters/officeparser/dist/officeparser.browser.d.ts +2621 -0
  170. package/vendor/converters/officeparser/dist/officeparser.browser.iife.js +1336 -0
  171. package/vendor/converters/officeparser/dist/officeparser.browser.mjs +1335 -0
  172. package/vendor/converters/officeparser/dist/officeparser.browser.slim.d.ts +2621 -0
  173. package/vendor/converters/officeparser/dist/officeparser.browser.slim.iife.js +1336 -0
  174. package/vendor/converters/officeparser/dist/officeparser.browser.slim.mjs +1335 -0
  175. package/vendor/converters/officeparser/dist/parsers/CsvParser.d.ts +9 -0
  176. package/vendor/converters/officeparser/dist/parsers/CsvParser.js +115 -0
  177. package/vendor/converters/officeparser/dist/parsers/EpubParser.d.ts +8 -0
  178. package/vendor/converters/officeparser/dist/parsers/EpubParser.js +217 -0
  179. package/vendor/converters/officeparser/dist/parsers/ExcelParser.d.ts +32 -0
  180. package/vendor/converters/officeparser/dist/parsers/ExcelParser.js +736 -0
  181. package/vendor/converters/officeparser/dist/parsers/HtmlParser.d.ts +2 -0
  182. package/vendor/converters/officeparser/dist/parsers/HtmlParser.js +1287 -0
  183. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.d.ts +2 -0
  184. package/vendor/converters/officeparser/dist/parsers/MarkdownParser.js +1272 -0
  185. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.d.ts +31 -0
  186. package/vendor/converters/officeparser/dist/parsers/OpenOfficeParser.js +1819 -0
  187. package/vendor/converters/officeparser/dist/parsers/PdfParser.d.ts +67 -0
  188. package/vendor/converters/officeparser/dist/parsers/PdfParser.js +848 -0
  189. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.d.ts +32 -0
  190. package/vendor/converters/officeparser/dist/parsers/PowerPointParser.js +950 -0
  191. package/vendor/converters/officeparser/dist/parsers/RtfParser.d.ts +187 -0
  192. package/vendor/converters/officeparser/dist/parsers/RtfParser.js +1801 -0
  193. package/vendor/converters/officeparser/dist/parsers/WordParser.d.ts +79 -0
  194. package/vendor/converters/officeparser/dist/parsers/WordParser.js +1177 -0
  195. package/vendor/converters/officeparser/dist/sbom.cdx.json +1763 -0
  196. package/vendor/converters/officeparser/dist/types.d.ts +2507 -0
  197. package/vendor/converters/officeparser/dist/types.js +107 -0
  198. package/vendor/converters/officeparser/dist/utils/astUtils.d.ts +16 -0
  199. package/vendor/converters/officeparser/dist/utils/astUtils.js +33 -0
  200. package/vendor/converters/officeparser/dist/utils/chartUtils.d.ts +6 -0
  201. package/vendor/converters/officeparser/dist/utils/chartUtils.js +257 -0
  202. package/vendor/converters/officeparser/dist/utils/configUtils.d.ts +44 -0
  203. package/vendor/converters/officeparser/dist/utils/configUtils.js +315 -0
  204. package/vendor/converters/officeparser/dist/utils/dateUtils.d.ts +17 -0
  205. package/vendor/converters/officeparser/dist/utils/dateUtils.js +69 -0
  206. package/vendor/converters/officeparser/dist/utils/envUtils.d.ts +29 -0
  207. package/vendor/converters/officeparser/dist/utils/envUtils.js +152 -0
  208. package/vendor/converters/officeparser/dist/utils/errorUtils.d.ts +72 -0
  209. package/vendor/converters/officeparser/dist/utils/errorUtils.js +245 -0
  210. package/vendor/converters/officeparser/dist/utils/imageUtils.d.ts +66 -0
  211. package/vendor/converters/officeparser/dist/utils/imageUtils.js +133 -0
  212. package/vendor/converters/officeparser/dist/utils/mathUtils.d.ts +42 -0
  213. package/vendor/converters/officeparser/dist/utils/mathUtils.js +385 -0
  214. package/vendor/converters/officeparser/dist/utils/moduleLoader.d.ts +18 -0
  215. package/vendor/converters/officeparser/dist/utils/moduleLoader.js +106 -0
  216. package/vendor/converters/officeparser/dist/utils/ocrUtils.d.ts +42 -0
  217. package/vendor/converters/officeparser/dist/utils/ocrUtils.js +428 -0
  218. package/vendor/converters/officeparser/dist/utils/sanitize.d.ts +148 -0
  219. package/vendor/converters/officeparser/dist/utils/sanitize.js +344 -0
  220. package/vendor/converters/officeparser/dist/utils/sheetUtils.d.ts +7 -0
  221. package/vendor/converters/officeparser/dist/utils/sheetUtils.js +35 -0
  222. package/vendor/converters/officeparser/dist/utils/styleMapper.d.ts +36 -0
  223. package/vendor/converters/officeparser/dist/utils/styleMapper.js +224 -0
  224. package/vendor/converters/officeparser/dist/utils/xmlUtils.d.ts +163 -0
  225. package/vendor/converters/officeparser/dist/utils/xmlUtils.js +461 -0
  226. package/vendor/converters/officeparser/dist/utils/zipUtils.d.ts +134 -0
  227. package/vendor/converters/officeparser/dist/utils/zipUtils.js +337 -0
  228. package/vendor/converters/officeparser/package.json +147 -0
  229. package/vendor/converters/upstream-manifest.json +124 -0
  230. package/vendor/dependency-fixes/README.md +77 -0
  231. package/vendor/dependency-fixes/vendor-converters.py +83 -0
  232. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip +0 -0
  233. package/browser-extension/artifacts/gno-browser-clipper-v1.46.0.zip.sha256 +0 -1
  234. package/browser-extension/dist/chunk-627emwpj.js +0 -75
  235. /package/browser-extension/dist/{chunk-ydfx5d7p.css → chunk-z74y8n8c.css} +0 -0
@@ -0,0 +1,736 @@
1
+ "use strict";
2
+ /**
3
+ * Excel Spreadsheet (XLSX) Parser
4
+ *
5
+ * **XLSX Format Overview:**
6
+ * XLSX is the default format for Microsoft Excel since Office 2007, based on OOXML.
7
+ *
8
+ * **File Structure:**
9
+ * - `xl/workbook.xml` - Workbook structure and sheet list
10
+ * - `xl/worksheets/sheet1.xml` - Individual sheet data
11
+ * - `xl/sharedStrings.xml` - Shared string table (cell text)
12
+ * - `xl/styles.xml` - Cell styling information
13
+ * - `xl/drawings/*` - Charts and drawings
14
+ * - `xl/media/*` - Embedded images
15
+ *
16
+ * **Key Elements:**
17
+ * - `<row>` - Table row with row index
18
+ * - `<c r="A1">` - Cell with reference (A1, B2, etc.)
19
+ * - `<v>` - Cell value (number or shared string index)
20
+ * - `<t="s">` - Cell type (s=string, n=number, b=boolean)
21
+ *
22
+ * @module ExcelParser
23
+ * @see https://www.ecma-international.org/publications-and-standards/standards/ecma-376/
24
+ */
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.parseExcel = void 0;
27
+ const types_js_1 = require("../types.js");
28
+ const astUtils_js_1 = require("../utils/astUtils.js");
29
+ const chartUtils_js_1 = require("../utils/chartUtils.js");
30
+ const errorUtils_js_1 = require("../utils/errorUtils.js");
31
+ const imageUtils_js_1 = require("../utils/imageUtils.js");
32
+ const ocrUtils_js_1 = require("../utils/ocrUtils.js");
33
+ const xmlUtils_js_1 = require("../utils/xmlUtils.js");
34
+ const zipUtils_js_1 = require("../utils/zipUtils.js");
35
+ /**
36
+ * Parses an Excel spreadsheet (.xlsx) and extracts sheets, rows, and cells.
37
+ *
38
+ * @param buffer - The XLSX file as a Buffer
39
+ * @param config - Parser configuration
40
+ * @returns A promise resolving to the parsed AST
41
+ */
42
+ const parseExcel = async (buffer, config) => {
43
+ // Honour cancellation requests immediately — before extracting the ZIP archive.
44
+ // XLSX parsing involves decompressing multiple XML sheets and potentially running OCR
45
+ // on embedded chart images, so short-circuiting here saves significant work.
46
+ (0, errorUtils_js_1.checkAbortSignal)(config.abortSignal);
47
+ const sheetsRegex = /xl\/worksheets\/sheet\d+.xml/g;
48
+ const drawingsRegex = /xl\/drawings\/drawing\d+.xml/g;
49
+ const chartsRegex = /xl\/charts\/chart\d+.xml/g;
50
+ const stringsFilePath = 'xl/sharedStrings.xml';
51
+ const mediaFileRegex = /xl\/media\/.*/;
52
+ const corePropsFileRegex = /docProps\/core\.xml/;
53
+ const customPropsFileRegex = /docProps\/custom\.xml/;
54
+ const appPropsFileRegex = /docProps\/app\.xml/;
55
+ const relsRegex = /xl\/worksheets\/_rels\/sheet\d+\.xml\.rels/g;
56
+ const drawingRelsRegex = /xl\/drawings\/_rels\/drawing\d+\.xml\.rels/g;
57
+ const commentsRegex = /xl\/comments\d+\.xml/g;
58
+ const files = await (0, zipUtils_js_1.extractFiles)(buffer, (x) => !!x.match(sheetsRegex) ||
59
+ !!x.match(drawingsRegex) ||
60
+ !!x.match(chartsRegex) ||
61
+ (!config.ignoreComments && !!x.match(commentsRegex)) ||
62
+ x === stringsFilePath ||
63
+ x === 'xl/styles.xml' ||
64
+ x === 'xl/workbook.xml' ||
65
+ x === 'xl/_rels/workbook.xml.rels' ||
66
+ !!x.match(corePropsFileRegex) ||
67
+ !!x.match(customPropsFileRegex) ||
68
+ !!x.match(appPropsFileRegex) ||
69
+ (!!config.extractAttachments && (!!x.match(mediaFileRegex) || !!x.match(drawingRelsRegex))) ||
70
+ ((!!config.extractAttachments || !config.ignoreComments) && !!x.match(relsRegex)), config.decompressionLimits, config);
71
+ // Every workbook has xl/workbook.xml; without it the archive is not a spreadsheet.
72
+ // Resolved up front so a file that cannot be a workbook fails before any of the parsing
73
+ // work below, and read again further down for the sheet-name map.
74
+ const workbookFile = (0, zipUtils_js_1.findRequiredPart)(files, path => path === 'xl/workbook.xml', config, { fileType: 'xlsx', part: 'xl/workbook.xml' });
75
+ // Worksheets, by contrast, are not guaranteed: a workbook holding only chartsheets is
76
+ // valid and simply has no cell text to extract. Warn rather than fail, so the caller can
77
+ // tell "nothing to read here" from "we read nothing".
78
+ if (!files.some(file => !!file.path.match(sheetsRegex)))
79
+ (0, errorUtils_js_1.logWarning)(types_js_1.OfficeWarningType.NO_WORKSHEETS_FOUND, config);
80
+ const sharedStringsFile = files.find(f => f.path === stringsFilePath);
81
+ // Updated to store structured content (rich text runs) or simple string
82
+ const sharedStrings = [];
83
+ if (sharedStringsFile) {
84
+ const xml = (0, xmlUtils_js_1.parseXmlString)(sharedStringsFile.content.toString());
85
+ const siNodes = (0, xmlUtils_js_1.getElementsByTagName)(xml, "si");
86
+ for (const si of siNodes) {
87
+ const runNodes = (0, xmlUtils_js_1.getElementsByTagName)(si, "r");
88
+ if (runNodes.length > 0) {
89
+ // Rich text with runs
90
+ const runs = [];
91
+ for (const run of runNodes) {
92
+ const tNode = (0, xmlUtils_js_1.getElementsByTagName)(run, "t")[0];
93
+ if (tNode) {
94
+ const text = tNode.textContent || '';
95
+ // Extract run formatting
96
+ const rPr = (0, xmlUtils_js_1.getElementsByTagName)(run, "rPr")[0];
97
+ const formatting = {};
98
+ if (rPr) {
99
+ if ((0, xmlUtils_js_1.getElementsByTagName)(rPr, "b").length > 0)
100
+ formatting.bold = true;
101
+ if ((0, xmlUtils_js_1.getElementsByTagName)(rPr, "i").length > 0)
102
+ formatting.italic = true;
103
+ if ((0, xmlUtils_js_1.getElementsByTagName)(rPr, "u").length > 0)
104
+ formatting.underline = true;
105
+ if ((0, xmlUtils_js_1.getElementsByTagName)(rPr, "strike").length > 0)
106
+ formatting.strikethrough = true;
107
+ const sz = (0, xmlUtils_js_1.getElementsByTagName)(rPr, "sz")[0];
108
+ if (sz)
109
+ formatting.size = sz.getAttribute("val") + 'pt';
110
+ const color = (0, xmlUtils_js_1.getElementsByTagName)(rPr, "color")[0];
111
+ if (color) {
112
+ const rgb = color.getAttribute("rgb");
113
+ if (rgb)
114
+ formatting.color = '#' + rgb.substring(2);
115
+ }
116
+ const rFont = (0, xmlUtils_js_1.getElementsByTagName)(rPr, "rFont")[0];
117
+ if (rFont)
118
+ formatting.font = rFont.getAttribute("val") || undefined;
119
+ const vertAlign = (0, xmlUtils_js_1.getElementsByTagName)(rPr, "vertAlign")[0];
120
+ if (vertAlign) {
121
+ const val = vertAlign.getAttribute("val");
122
+ if (val === "subscript")
123
+ formatting.subscript = true;
124
+ if (val === "superscript")
125
+ formatting.superscript = true;
126
+ }
127
+ }
128
+ runs.push({
129
+ type: 'text',
130
+ text: text,
131
+ formatting: Object.keys(formatting).length > 0 ? formatting : undefined
132
+ });
133
+ }
134
+ }
135
+ sharedStrings.push(runs);
136
+ }
137
+ else {
138
+ // Simple text case
139
+ const tNodes = (0, xmlUtils_js_1.getElementsByTagName)(si, "t");
140
+ let text = '';
141
+ for (const t of tNodes) {
142
+ text += t.textContent || '';
143
+ }
144
+ sharedStrings.push(text);
145
+ }
146
+ }
147
+ }
148
+ // Parse styles to build formatting map
149
+ const stylesFile = files.find(f => f.path === 'xl/styles.xml');
150
+ const cellFormatMap = {};
151
+ if (stylesFile) {
152
+ const xml = (0, xmlUtils_js_1.parseXmlString)(stylesFile.content.toString());
153
+ // Parse fonts
154
+ const fontsNode = (0, xmlUtils_js_1.getElementsByTagName)(xml, "fonts")[0];
155
+ const fonts = [];
156
+ if (fontsNode) {
157
+ const fontNodes = (0, xmlUtils_js_1.getElementsByTagName)(fontsNode, "font");
158
+ for (const font of fontNodes) {
159
+ const formatting = {};
160
+ if ((0, xmlUtils_js_1.getElementsByTagName)(font, "b").length > 0)
161
+ formatting.bold = true;
162
+ if ((0, xmlUtils_js_1.getElementsByTagName)(font, "i").length > 0)
163
+ formatting.italic = true;
164
+ if ((0, xmlUtils_js_1.getElementsByTagName)(font, "u").length > 0)
165
+ formatting.underline = true;
166
+ if ((0, xmlUtils_js_1.getElementsByTagName)(font, "strike").length > 0)
167
+ formatting.strikethrough = true;
168
+ const szNode = (0, xmlUtils_js_1.getElementsByTagName)(font, "sz")[0];
169
+ if (szNode) {
170
+ const val = szNode.getAttribute("val");
171
+ if (val)
172
+ formatting.size = val + 'pt';
173
+ }
174
+ const colorNode = (0, xmlUtils_js_1.getElementsByTagName)(font, "color")[0];
175
+ if (colorNode) {
176
+ const rgb = colorNode.getAttribute("rgb");
177
+ if (rgb)
178
+ formatting.color = '#' + rgb.substring(2); // Remove alpha channel
179
+ }
180
+ const nameNode = (0, xmlUtils_js_1.getElementsByTagName)(font, "name")[0];
181
+ if (nameNode) {
182
+ const val = nameNode.getAttribute("val");
183
+ if (val)
184
+ formatting.font = val;
185
+ }
186
+ const vertAlignNode = (0, xmlUtils_js_1.getElementsByTagName)(font, "vertAlign")[0];
187
+ if (vertAlignNode) {
188
+ const val = vertAlignNode.getAttribute("val");
189
+ if (val === "subscript")
190
+ formatting.subscript = true;
191
+ if (val === "superscript")
192
+ formatting.superscript = true;
193
+ }
194
+ fonts.push(formatting);
195
+ }
196
+ }
197
+ // Parse fills (for background color)
198
+ const fillsNode = (0, xmlUtils_js_1.getElementsByTagName)(xml, "fills")[0];
199
+ const fills = [];
200
+ if (fillsNode) {
201
+ const fillNodes = (0, xmlUtils_js_1.getElementsByTagName)(fillsNode, "fill");
202
+ for (const fill of fillNodes) {
203
+ const formatting = {};
204
+ const patternFill = (0, xmlUtils_js_1.getElementsByTagName)(fill, "patternFill")[0];
205
+ if (patternFill) {
206
+ const fgColor = (0, xmlUtils_js_1.getElementsByTagName)(patternFill, "fgColor")[0];
207
+ if (fgColor) {
208
+ const rgb = fgColor.getAttribute("rgb");
209
+ const theme = fgColor.getAttribute("theme");
210
+ if (rgb && rgb !== "00000000") { // Not default/auto
211
+ formatting.backgroundColor = '#' + rgb.substring(2);
212
+ }
213
+ else if (theme) {
214
+ // Basic mapping for standard Office themes (Dark 1, Light 1, Dark 2, Light 2)
215
+ // 0: Light 1 (White), 1: Dark 1 (Black), 2: Light 2 (Tan/Gray), 3: Dark 2 (Blue/Grey)
216
+ const themeIdx = parseInt(theme);
217
+ if (themeIdx === 0)
218
+ formatting.backgroundColor = '#FFFFFF';
219
+ else if (themeIdx === 1)
220
+ formatting.backgroundColor = '#000000';
221
+ else if (themeIdx === 2)
222
+ formatting.backgroundColor = '#EEECE1'; // Standard Light 2
223
+ else if (themeIdx === 3)
224
+ formatting.backgroundColor = '#1F497D'; // Standard Dark 2
225
+ }
226
+ }
227
+ }
228
+ fills.push(formatting);
229
+ }
230
+ }
231
+ // Parse cellXfs (cell format definitions)
232
+ const cellXfsNode = (0, xmlUtils_js_1.getElementsByTagName)(xml, "cellXfs")[0];
233
+ if (cellXfsNode) {
234
+ const xfNodes = (0, xmlUtils_js_1.getElementsByTagName)(cellXfsNode, "xf");
235
+ for (let i = 0; i < xfNodes.length; i++) {
236
+ const xf = xfNodes[i];
237
+ const formatting = {};
238
+ const fontId = xf.getAttribute("fontId");
239
+ if (fontId) {
240
+ const fontIdx = parseInt(fontId);
241
+ if (fonts[fontIdx]) {
242
+ Object.assign(formatting, fonts[fontIdx]);
243
+ }
244
+ }
245
+ const fillId = xf.getAttribute("fillId");
246
+ if (fillId) {
247
+ const fillIdx = parseInt(fillId);
248
+ if (fills[fillIdx] && fills[fillIdx].backgroundColor) {
249
+ formatting.backgroundColor = fills[fillIdx].backgroundColor;
250
+ }
251
+ }
252
+ const alignmentNode = (0, xmlUtils_js_1.getElementsByTagName)(xf, "alignment")[0];
253
+ if (alignmentNode) {
254
+ const horizontal = alignmentNode.getAttribute("horizontal");
255
+ if (horizontal === 'center' || horizontal === 'right' || horizontal === 'justify' || horizontal === 'left') {
256
+ formatting.alignment = horizontal;
257
+ }
258
+ }
259
+ cellFormatMap[i] = formatting;
260
+ }
261
+ }
262
+ }
263
+ const attachments = [];
264
+ const mediaFiles = files.filter(f => f.path.match(/xl\/media\/.*/));
265
+ const chartFiles = files.filter(f => f.path.match(chartsRegex));
266
+ // Map to store image details by drawing file path and relationship ID
267
+ const drawingImageMap = {};
268
+ if (config.extractAttachments) {
269
+ // 1. Parse Drawing Rels to map rIds to media paths
270
+ const drawingRelsFiles = files.filter(f => f.path.match(drawingRelsRegex));
271
+ for (const relFile of drawingRelsFiles) {
272
+ const drawingFilename = relFile.path.split('/').pop()?.replace('.rels', '') || '';
273
+ const drawingPath = `xl/drawings/${drawingFilename}`;
274
+ const relsXml = (0, xmlUtils_js_1.parseXmlString)(relFile.content.toString());
275
+ const relationships = (0, xmlUtils_js_1.getElementsByTagName)(relsXml, "Relationship");
276
+ if (!drawingImageMap[drawingPath]) {
277
+ drawingImageMap[drawingPath] = {};
278
+ }
279
+ for (const rel of relationships) {
280
+ const id = rel.getAttribute("Id");
281
+ const target = rel.getAttribute("Target");
282
+ if (id && target && target.includes('media/')) {
283
+ // Target is usually like "../media/image1.png"
284
+ const mediaPath = 'xl/' + target.replace('../', '');
285
+ drawingImageMap[drawingPath][id] = { path: mediaPath };
286
+ }
287
+ }
288
+ }
289
+ // 2. Parse Drawings to get Alt Text and link to Rels
290
+ const drawingFiles = files.filter(f => f.path.match(drawingsRegex));
291
+ for (const drawingFile of drawingFiles) {
292
+ const xml = (0, xmlUtils_js_1.parseXmlString)(drawingFile.content.toString());
293
+ const pics = (0, xmlUtils_js_1.getElementsByTagName)(xml, "xdr:pic"); // SpreadsheetML drawing
294
+ const rels = drawingImageMap[drawingFile.path] || {};
295
+ for (const pic of pics) {
296
+ const blipFill = (0, xmlUtils_js_1.getElementsByTagName)(pic, "xdr:blipFill")[0];
297
+ const blip = blipFill ? (0, xmlUtils_js_1.getElementsByTagName)(blipFill, "a:blip")[0] : null;
298
+ const embedId = blip ? blip.getAttribute("r:embed") : null;
299
+ const nvPicPr = (0, xmlUtils_js_1.getElementsByTagName)(pic, "xdr:nvPicPr")[0];
300
+ const cNvPr = nvPicPr ? (0, xmlUtils_js_1.getElementsByTagName)(nvPicPr, "xdr:cNvPr")[0] : null;
301
+ const altText = cNvPr ? (cNvPr.getAttribute("descr") || cNvPr.getAttribute("name")) : undefined;
302
+ if (embedId && rels[embedId]) {
303
+ rels[embedId].altText = altText || '';
304
+ }
305
+ }
306
+ }
307
+ // 3. Process Media Files
308
+ for (const media of mediaFiles) {
309
+ const attachment = (0, imageUtils_js_1.createAttachment)(media.path.split('/').pop() || 'image', media.content);
310
+ // Try to find alt text for this media
311
+ let altText = '';
312
+ for (const drawingPath in drawingImageMap) {
313
+ for (const rId in drawingImageMap[drawingPath]) {
314
+ if (drawingImageMap[drawingPath][rId].path === media.path) {
315
+ altText = drawingImageMap[drawingPath][rId].altText || '';
316
+ break;
317
+ }
318
+ }
319
+ if (altText)
320
+ break;
321
+ }
322
+ if (altText)
323
+ attachment.altText = altText;
324
+ attachments.push(attachment);
325
+ if (config.ocr) {
326
+ if (attachment.mimeType.startsWith('image/')) {
327
+ try {
328
+ const ocrText = (await (0, ocrUtils_js_1.performOcr)(media.content, { ...config.ocrConfig })).trim();
329
+ if (ocrText) {
330
+ attachment.ocrText = ocrText;
331
+ }
332
+ }
333
+ catch (e) {
334
+ (0, errorUtils_js_1.logWarning)(types_js_1.OfficeWarningType.OCR_FAILED, config, attachment.name, e);
335
+ }
336
+ }
337
+ }
338
+ }
339
+ for (const chart of chartFiles) {
340
+ const attachment = {
341
+ type: 'chart',
342
+ mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
343
+ data: chart.content.toString('base64'),
344
+ name: chart.path.split('/').pop() || '',
345
+ extension: 'xml'
346
+ };
347
+ // Extract structured chart data
348
+ try {
349
+ const chartData = (0, chartUtils_js_1.extractChartData)(chart.content);
350
+ attachment.chartData = chartData;
351
+ }
352
+ catch (e) {
353
+ (0, errorUtils_js_1.logWarning)(types_js_1.OfficeWarningType.CHART_DATA_EXTRACTION_FAILED, config, chart.path, e);
354
+ }
355
+ attachments.push(attachment);
356
+ }
357
+ }
358
+ // Build map of drawing rId -> chart attachment name for linking
359
+ const drawingChartMap = {};
360
+ if (config.extractAttachments) {
361
+ const drawingRelsFiles = files.filter(f => f.path.match(drawingRelsRegex));
362
+ for (const relFile of drawingRelsFiles) {
363
+ const drawingFilename = relFile.path.split('/').pop()?.replace('.rels', '') || '';
364
+ const drawingPath = `xl/drawings/${drawingFilename}`;
365
+ const relsXml = (0, xmlUtils_js_1.parseXmlString)(relFile.content.toString());
366
+ const relationships = (0, xmlUtils_js_1.getElementsByTagName)(relsXml, "Relationship");
367
+ if (!drawingChartMap[drawingPath]) {
368
+ drawingChartMap[drawingPath] = {};
369
+ }
370
+ for (const rel of relationships) {
371
+ const id = rel.getAttribute("Id");
372
+ const target = rel.getAttribute("Target");
373
+ const type = rel.getAttribute("Type");
374
+ if (id && target && type && type.includes('chart')) {
375
+ // Target is like "../charts/chart1.xml"
376
+ const chartName = target.split('/').pop() || '';
377
+ drawingChartMap[drawingPath][id] = chartName;
378
+ }
379
+ }
380
+ }
381
+ }
382
+ // Parse workbook.xml to get sheet names and map them to sheet files
383
+ const sheetNameMap = {};
384
+ const workbookRelsFile = files.find(f => f.path === 'xl/_rels/workbook.xml.rels');
385
+ if (workbookRelsFile) {
386
+ // Parse rels to get rId -> file mapping
387
+ const relsXml = (0, xmlUtils_js_1.parseXmlString)(workbookRelsFile.content.toString());
388
+ const relationships = (0, xmlUtils_js_1.getElementsByTagName)(relsXml, "Relationship");
389
+ const rIdToFile = {};
390
+ for (const rel of relationships) {
391
+ const rId = rel.getAttribute("Id");
392
+ const target = rel.getAttribute("Target");
393
+ if (rId && target) {
394
+ // Target is like "worksheets/sheet1.xml"
395
+ const filename = target.split('/').pop() || '';
396
+ rIdToFile[rId] = filename;
397
+ }
398
+ }
399
+ // Parse workbook.xml to get sheet name -> rId mapping
400
+ const workbookXml = (0, xmlUtils_js_1.parseXmlString)(workbookFile.content.toString());
401
+ const sheets = (0, xmlUtils_js_1.getElementsByTagName)(workbookXml, "sheet");
402
+ for (const sheet of sheets) {
403
+ (0, errorUtils_js_1.checkAbortSignal)(config.abortSignal);
404
+ const name = sheet.getAttribute("name");
405
+ const rId = sheet.getAttribute("r:id");
406
+ if (name && rId && rIdToFile[rId]) {
407
+ sheetNameMap[rIdToFile[rId]] = name;
408
+ }
409
+ }
410
+ }
411
+ const content = [];
412
+ for (const file of files) {
413
+ if (file.path.match(mediaFileRegex))
414
+ continue;
415
+ if (file.path === stringsFilePath)
416
+ continue;
417
+ if (file.path === 'xl/styles.xml')
418
+ continue;
419
+ if (file.path.match(drawingsRegex))
420
+ continue;
421
+ if (file.path.match(chartsRegex))
422
+ continue;
423
+ if (file.path.match(relsRegex))
424
+ continue;
425
+ if (file.path.match(drawingRelsRegex))
426
+ continue;
427
+ if (file.path.match(sheetsRegex)) {
428
+ const sheetFilename = file.path.split('/').pop() || '';
429
+ const relsFilename = `xl/worksheets/_rels/${sheetFilename}.rels`;
430
+ const relsFile = files.find(f => f.path === relsFilename);
431
+ const drawingMap = {}; // rId -> drawingPath
432
+ const sheetCommentsMap = {};
433
+ if (relsFile) {
434
+ const relsXml = (0, xmlUtils_js_1.parseXmlString)(relsFile.content.toString());
435
+ const relationships = (0, xmlUtils_js_1.getElementsByTagName)(relsXml, "Relationship");
436
+ for (const rel of relationships) {
437
+ const id = rel.getAttribute("Id");
438
+ const target = rel.getAttribute("Target");
439
+ const type = rel.getAttribute("Type");
440
+ if (id && target && type) {
441
+ if (config.extractAttachments && type.includes('drawing')) {
442
+ drawingMap[id] = 'xl/drawings/' + target.replace('../drawings/', '');
443
+ }
444
+ else if (!config.ignoreComments && type.includes('comments')) {
445
+ const commentsPath = 'xl/' + target.replace('../', '');
446
+ const cFile = files.find(f => f.path === commentsPath);
447
+ if (cFile) {
448
+ const cXml = (0, xmlUtils_js_1.parseXmlString)(cFile.content.toString());
449
+ const commentNodes = (0, xmlUtils_js_1.getElementsByTagName)(cXml, "comment");
450
+ const authorsList = (0, xmlUtils_js_1.getElementsByTagName)(cXml, "author");
451
+ const authors = authorsList.map(a => a.textContent || '');
452
+ for (const cNode of commentNodes) {
453
+ const ref = cNode.getAttribute("ref");
454
+ const authorId = cNode.getAttribute("authorId");
455
+ const author = authorId !== null ? authors[parseInt(authorId)] : undefined;
456
+ const tNodes = (0, xmlUtils_js_1.getElementsByTagName)(cNode, "t");
457
+ const text = tNodes.map(t => t.textContent || '').join('');
458
+ if (ref && text) {
459
+ if (!sheetCommentsMap[ref])
460
+ sheetCommentsMap[ref] = [];
461
+ sheetCommentsMap[ref].push({
462
+ type: 'comment',
463
+ text: text,
464
+ children: [{ type: 'text', text: text, formatting: {} }],
465
+ metadata: author ? { author } : undefined
466
+ });
467
+ }
468
+ }
469
+ }
470
+ }
471
+ }
472
+ }
473
+ }
474
+ const rows = [];
475
+ const sheetXml = file.content.toString();
476
+ // regex to match <row> elements, capturing:
477
+ // 1. attributes (e.g., r="1")
478
+ // 2. whether it's self-closing (/>)
479
+ // 3. inner content (for non-self-closing rows)
480
+ const rowRegex = /<row\b([^>]*?)(?:(\/>)|(>([\s\S]*?)<\/row>))/g;
481
+ // matchAll provides an iterator over all matches, which is much more efficient than
482
+ // iterating over a massive sparse row range declared in spreadsheet dimensions.
483
+ const rowMatches = sheetXml.matchAll(rowRegex);
484
+ /** Helper to convert Excel column string (A, B, AA, etc.) to 0-based index */
485
+ const colToNumber = (col) => {
486
+ let num = 0;
487
+ for (let i = 0; i < col.length; i++) {
488
+ num = num * 26 + (col.charCodeAt(i) - 'A'.charCodeAt(0) + 1);
489
+ }
490
+ return num - 1;
491
+ };
492
+ let lastRowIndex = -1;
493
+ for (const rowMatch of rowMatches) {
494
+ (0, errorUtils_js_1.checkAbortSignal)(config.abortSignal);
495
+ const rowXml = rowMatch[0];
496
+ const rowAttrs = rowMatch[1];
497
+ const isSelfClosing = !!rowMatch[2];
498
+ const rowContent = rowMatch[4] || "";
499
+ if (!isSelfClosing && !rowContent.includes('<c'))
500
+ continue;
501
+ const cells = [];
502
+ // regex to match <c> (cell) elements within a row, capturing:
503
+ // 1. cell attributes (e.g., r="A1", t="s")
504
+ // 2. whether it's self-closing (/>)
505
+ // 3. inner content (e.g., <v> value)
506
+ const cRegex = /<c\b([^>]*?)(?:(\/>)|(>([\s\S]*?)<\/c>))/g;
507
+ const cMatches = rowContent.matchAll(cRegex);
508
+ const rMatch = rowAttrs.match(/r="(\d+)"/);
509
+ const rowIndex = rMatch ? parseInt(rMatch[1]) - 1 : lastRowIndex + 1;
510
+ lastRowIndex = rowIndex;
511
+ let lastColIndex = -1;
512
+ for (const cMatch of cMatches) {
513
+ const cXml = cMatch[0];
514
+ const cAttrs = cMatch[1];
515
+ const cContent = cMatch[4] || "";
516
+ // Extract cell value
517
+ const typeMatch = cAttrs.match(/t="([a-zA-Z]+)"/);
518
+ const type = typeMatch ? typeMatch[1] : 'n'; // n = number (default)
519
+ const vMatch = cContent.match(/<v>([\s\S]*?)<\/v>/);
520
+ const tMatch = cContent.match(/<t\b[^>]*>([\s\S]*?)<\/t>/);
521
+ let text = '';
522
+ let cellNodes = [];
523
+ if (type === 's' && vMatch) {
524
+ const idx = parseInt(vMatch[1]);
525
+ const content = sharedStrings[idx];
526
+ if (Array.isArray(content)) {
527
+ // Rich text runs
528
+ // Deep copy runs to avoid reference issues if reused
529
+ cellNodes = JSON.parse(JSON.stringify(content));
530
+ text = cellNodes.map(n => n.text).join('');
531
+ }
532
+ else {
533
+ text = content || '';
534
+ }
535
+ }
536
+ else if (type === 'inlineStr' && tMatch) {
537
+ text = (0, xmlUtils_js_1.decodeXmlEntities)(tMatch[1].trim());
538
+ }
539
+ else if (vMatch) {
540
+ text = vMatch[1].trim();
541
+ }
542
+ // Parse cell coordinate
543
+ const coordMatch = cAttrs.match(/r="([A-Z]+)(\d+)"/);
544
+ let colIndex;
545
+ let ref;
546
+ if (coordMatch) {
547
+ ref = coordMatch[1] + coordMatch[2];
548
+ colIndex = colToNumber(coordMatch[1]);
549
+ // If row index is missing in cell coord (unlikely but possible), use rowIndex
550
+ }
551
+ else {
552
+ colIndex = lastColIndex + 1;
553
+ }
554
+ lastColIndex = colIndex;
555
+ if (text || cellNodes.length > 0) {
556
+ // Extract cell style index
557
+ const styleMatch = cAttrs.match(/s="(\d+)"/);
558
+ const styleIdx = styleMatch ? parseInt(styleMatch[1]) : undefined;
559
+ const cellFormatting = (styleIdx !== undefined && cellFormatMap[styleIdx]) ? cellFormatMap[styleIdx] : {};
560
+ if (cellNodes.length > 0) {
561
+ // If we have specific runs, merge cell styles into them if run style is missing
562
+ // But usually run style overrides cell style (except maybe background)
563
+ for (const node of cellNodes) {
564
+ if (!node.formatting)
565
+ node.formatting = {};
566
+ // Cell background always applies
567
+ if (cellFormatting.backgroundColor)
568
+ node.formatting.backgroundColor = cellFormatting.backgroundColor;
569
+ // Cell alignment always applies
570
+ if (cellFormatting.alignment)
571
+ node.formatting.alignment = cellFormatting.alignment;
572
+ // Font defaults from cell style if not in run
573
+ if (!node.formatting.font && cellFormatting.font)
574
+ node.formatting.font = cellFormatting.font;
575
+ if (!node.formatting.size && cellFormatting.size)
576
+ node.formatting.size = cellFormatting.size;
577
+ }
578
+ }
579
+ else {
580
+ // Simple text node
581
+ cellNodes.push({
582
+ type: 'text',
583
+ text: text,
584
+ formatting: cellFormatting
585
+ });
586
+ }
587
+ const commentsNodeList = (ref && sheetCommentsMap[ref]) ? sheetCommentsMap[ref] : undefined;
588
+ const cellNode = {
589
+ type: 'cell',
590
+ text: text,
591
+ children: cellNodes,
592
+ comments: commentsNodeList,
593
+ metadata: { row: rowIndex, col: colIndex }
594
+ };
595
+ if (config.includeRawContent) {
596
+ cellNode.rawContent = cXml;
597
+ }
598
+ cells.push(cellNode);
599
+ }
600
+ }
601
+ if (cells.length > 0) {
602
+ const rowNode = {
603
+ type: 'row',
604
+ children: cells,
605
+ metadata: undefined
606
+ };
607
+ if (config.includeRawContent) {
608
+ rowNode.rawContent = rowXml;
609
+ }
610
+ rows.push(rowNode);
611
+ }
612
+ }
613
+ // Handle Drawings in Sheet (images and charts)
614
+ if (config.extractAttachments) {
615
+ const drawingMatches = file.content.toString().match(/<drawing r:id="(.*?)"/g);
616
+ if (drawingMatches) {
617
+ for (const match of drawingMatches) {
618
+ const rIdMatch = match.match(/r:id="(.*?)"/);
619
+ const rId = rIdMatch ? rIdMatch[1] : null;
620
+ if (rId && drawingMap[rId]) {
621
+ const drawingPath = drawingMap[rId];
622
+ // Find all images in this drawing
623
+ const images = drawingImageMap[drawingPath];
624
+ if (images) {
625
+ for (const imgId in images) {
626
+ const imgInfo = images[imgId];
627
+ const attachment = attachments.find(a => a.name === imgInfo.path.split('/').pop());
628
+ if (attachment) {
629
+ const imageNode = {
630
+ type: 'image',
631
+ text: '', // Will be populated by assignAttachmentData
632
+ children: [],
633
+ metadata: {
634
+ attachmentName: attachment.name || 'unknown',
635
+ altText: imgInfo.altText || undefined
636
+ }
637
+ };
638
+ rows.push(imageNode);
639
+ }
640
+ }
641
+ }
642
+ // Find all charts in this drawing
643
+ const charts = drawingChartMap[drawingPath];
644
+ if (charts) {
645
+ for (const chartRId in charts) {
646
+ const chartName = charts[chartRId];
647
+ const attachment = attachments.find(a => a.name === chartName);
648
+ if (attachment) {
649
+ const chartNode = {
650
+ type: 'chart',
651
+ text: '', // Will be populated by assignAttachmentData
652
+ children: [],
653
+ metadata: {
654
+ attachmentName: chartName
655
+ }
656
+ };
657
+ rows.push(chartNode);
658
+ }
659
+ }
660
+ }
661
+ }
662
+ }
663
+ }
664
+ }
665
+ // Get proper sheet name from workbook.xml mapping, fallback to filename
666
+ const sheetFileName = file.path.split('/').pop() || 'Sheet';
667
+ const sheetName = sheetNameMap[sheetFileName] || sheetFileName;
668
+ content.push({
669
+ type: 'sheet',
670
+ children: rows,
671
+ metadata: { sheetName },
672
+ rawContent: config.includeRawContent ? file.content.toString() : undefined
673
+ });
674
+ }
675
+ }
676
+ const corePropsFile = files.find(f => f.path.match(corePropsFileRegex));
677
+ const metadata = corePropsFile ? (0, xmlUtils_js_1.parseOfficeMetadata)(corePropsFile.content.toString()) : {};
678
+ const customPropsFile = files.find(f => f.path.match(customPropsFileRegex));
679
+ if (customPropsFile) {
680
+ const customProperties = (0, xmlUtils_js_1.parseOOXMLCustomProperties)(customPropsFile.content.toString());
681
+ if (Object.keys(customProperties).length > 0)
682
+ metadata.customProperties = customProperties;
683
+ }
684
+ const appPropsFile = files.find(f => f.path.match(appPropsFileRegex));
685
+ if (appPropsFile) {
686
+ const appProperties = (0, xmlUtils_js_1.parseOOXMLAppProperties)(appPropsFile.content.toString());
687
+ if (Object.keys(appProperties).length > 0)
688
+ metadata.nativeProperties = appProperties;
689
+ }
690
+ // Link OCR text and chart data to content nodes (like PPTX parser)
691
+ const assignAttachmentData = (nodes) => {
692
+ for (const node of nodes) {
693
+ if ('attachmentName' in (node.metadata || {})) {
694
+ const meta = node.metadata;
695
+ const attachment = attachments.find(a => a.name === meta.attachmentName);
696
+ if (attachment) {
697
+ if (node.type === 'image') {
698
+ // Link OCR text to image node
699
+ if (attachment.ocrText) {
700
+ node.text = attachment.ocrText;
701
+ }
702
+ // Copy altText to attachment
703
+ if (meta.altText) {
704
+ attachment.altText = meta.altText;
705
+ }
706
+ }
707
+ if (node.type === 'chart') {
708
+ // Link chart data text to chart node
709
+ if (attachment.chartData) {
710
+ node.text = attachment.chartData.rawTexts.join(config.newlineDelimiter);
711
+ }
712
+ }
713
+ }
714
+ }
715
+ if (node.children) {
716
+ assignAttachmentData(node.children);
717
+ }
718
+ }
719
+ };
720
+ assignAttachmentData(content);
721
+ const toTextSync = () => content.map(c => {
722
+ // Recursive text extraction
723
+ const getText = (node) => {
724
+ let t = '';
725
+ if (node.children) {
726
+ t += node.children.map(getText).filter(t => t != '').join(!node.children[0]?.children ? '' : config.newlineDelimiter);
727
+ }
728
+ else
729
+ t += node.text || '';
730
+ return t;
731
+ };
732
+ return getText(c);
733
+ }).filter(t => t != '').join(config.newlineDelimiter);
734
+ return (0, astUtils_js_1.createAST)('xlsx', metadata, content, attachments, config, undefined, toTextSync);
735
+ };
736
+ exports.parseExcel = parseExcel;