omni-viewer-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +80 -0
  3. package/THIRD_PARTY_NOTICES.md +49 -0
  4. package/dist/assets/audio-engine/audio_engine.mjs +2 -0
  5. package/dist/assets/audio-engine/audio_engine.wasm +0 -0
  6. package/dist/assets/pdfjs/pdf.worker.min.mjs +21 -0
  7. package/dist/host/index.d.ts +133 -0
  8. package/dist/host/index.js +10 -0
  9. package/dist/i18n/catalog.en.d.ts +1 -0
  10. package/dist/i18n/catalog.en.js +411 -0
  11. package/dist/i18n/catalog.ko.d.ts +1 -0
  12. package/dist/i18n/catalog.ko.js +68 -0
  13. package/dist/i18n/index.d.ts +18 -0
  14. package/dist/i18n/index.js +41 -0
  15. package/dist/licenses/emscripten.txt +101 -0
  16. package/dist/licenses/kissfft.txt +28 -0
  17. package/dist/licenses/pdfjs-dist.txt +177 -0
  18. package/dist/parsers/a2l/index.d.ts +1 -0
  19. package/dist/parsers/a2l/index.js +1 -0
  20. package/dist/parsers/archive/index.d.ts +22 -0
  21. package/dist/parsers/archive/index.js +46 -0
  22. package/dist/parsers/archive/model.d.ts +29 -0
  23. package/dist/parsers/archive/model.js +1 -0
  24. package/dist/parsers/archive/worker.d.ts +21 -0
  25. package/dist/parsers/archive/worker.js +1 -0
  26. package/dist/parsers/arxml/index.d.ts +1 -0
  27. package/dist/parsers/arxml/index.js +1 -0
  28. package/dist/parsers/asc/index.d.ts +1 -0
  29. package/dist/parsers/asc/index.js +1 -0
  30. package/dist/parsers/audio/index.d.ts +9 -0
  31. package/dist/parsers/audio/index.js +46 -0
  32. package/dist/parsers/automotive/index.d.ts +33 -0
  33. package/dist/parsers/automotive/index.js +973 -0
  34. package/dist/parsers/blf/index.d.ts +1 -0
  35. package/dist/parsers/blf/index.js +1 -0
  36. package/dist/parsers/csv/delimiter.d.ts +31 -0
  37. package/dist/parsers/csv/delimiter.js +151 -0
  38. package/dist/parsers/csv/index.d.ts +30 -0
  39. package/dist/parsers/csv/index.js +108 -0
  40. package/dist/parsers/csv/parseText.d.ts +20 -0
  41. package/dist/parsers/csv/parseText.js +108 -0
  42. package/dist/parsers/csv/sort.d.ts +26 -0
  43. package/dist/parsers/csv/sort.js +224 -0
  44. package/dist/parsers/csv/statistics.d.ts +49 -0
  45. package/dist/parsers/csv/statistics.js +150 -0
  46. package/dist/parsers/dbc/index.d.ts +56 -0
  47. package/dist/parsers/dbc/index.js +94 -0
  48. package/dist/parsers/doc-binary/index.d.ts +35 -0
  49. package/dist/parsers/doc-binary/index.js +267 -0
  50. package/dist/parsers/doc-binary/vscode-parser.d.ts +142 -0
  51. package/dist/parsers/doc-binary/vscode-parser.js +3747 -0
  52. package/dist/parsers/excel/index.d.ts +17 -0
  53. package/dist/parsers/excel/index.js +406 -0
  54. package/dist/parsers/excel/model.d.ts +80 -0
  55. package/dist/parsers/excel/model.js +48 -0
  56. package/dist/parsers/excel/serialize.d.ts +3 -0
  57. package/dist/parsers/excel/serialize.js +78 -0
  58. package/dist/parsers/hdf5/index.d.ts +75 -0
  59. package/dist/parsers/hdf5/index.js +658 -0
  60. package/dist/parsers/hdf5/node.d.ts +21 -0
  61. package/dist/parsers/hdf5/node.js +95 -0
  62. package/dist/parsers/json/index.d.ts +15 -0
  63. package/dist/parsers/json/index.js +102 -0
  64. package/dist/parsers/json/model.d.ts +42 -0
  65. package/dist/parsers/json/model.js +140 -0
  66. package/dist/parsers/json/parse.d.ts +22 -0
  67. package/dist/parsers/json/parse.js +279 -0
  68. package/dist/parsers/json/tokenizer.d.ts +17 -0
  69. package/dist/parsers/json/tokenizer.js +175 -0
  70. package/dist/parsers/jsonl/index.d.ts +14 -0
  71. package/dist/parsers/jsonl/index.js +18 -0
  72. package/dist/parsers/jsonl/model.d.ts +23 -0
  73. package/dist/parsers/jsonl/model.js +1 -0
  74. package/dist/parsers/jsonl/parse.d.ts +7 -0
  75. package/dist/parsers/jsonl/parse.js +34 -0
  76. package/dist/parsers/markdown/index.d.ts +37 -0
  77. package/dist/parsers/markdown/index.js +59 -0
  78. package/dist/parsers/mat/index.d.ts +31 -0
  79. package/dist/parsers/mat/index.js +426 -0
  80. package/dist/parsers/mermaid/index.d.ts +5 -0
  81. package/dist/parsers/mermaid/index.js +3 -0
  82. package/dist/parsers/mf4/index.d.ts +1 -0
  83. package/dist/parsers/mf4/index.js +1 -0
  84. package/dist/parsers/parquet/index.d.ts +21 -0
  85. package/dist/parsers/parquet/index.js +68 -0
  86. package/dist/parsers/pcap/index.d.ts +1 -0
  87. package/dist/parsers/pcap/index.js +1 -0
  88. package/dist/parsers/pcapng/index.d.ts +1 -0
  89. package/dist/parsers/pcapng/index.js +1 -0
  90. package/dist/parsers/plantuml/index.d.ts +5 -0
  91. package/dist/parsers/plantuml/index.js +4 -0
  92. package/dist/parsers/ppt-binary/index.d.ts +5 -0
  93. package/dist/parsers/ppt-binary/index.js +62 -0
  94. package/dist/parsers/ppt-binary/pptBinaryBuildContext.d.ts +12 -0
  95. package/dist/parsers/ppt-binary/pptBinaryBuildContext.js +40 -0
  96. package/dist/parsers/ppt-binary/pptBinaryContainer.d.ts +4 -0
  97. package/dist/parsers/ppt-binary/pptBinaryContainer.js +174 -0
  98. package/dist/parsers/ppt-binary/pptBinaryTypes.d.ts +125 -0
  99. package/dist/parsers/ppt-binary/pptBinaryTypes.js +1 -0
  100. package/dist/parsers/ppt-binary/pptSlideLayouts.d.ts +9 -0
  101. package/dist/parsers/ppt-binary/pptSlideLayouts.js +510 -0
  102. package/dist/parsers/ppt-binary/vscode-parser.d.ts +116 -0
  103. package/dist/parsers/ppt-binary/vscode-parser.js +2853 -0
  104. package/dist/parsers/ppt-binary/vscode.d.ts +4 -0
  105. package/dist/parsers/ppt-binary/vscode.js +12 -0
  106. package/dist/parsers/pptx/index.d.ts +15 -0
  107. package/dist/parsers/pptx/index.js +88 -0
  108. package/dist/parsers/pptx/vscode-parser.d.ts +167 -0
  109. package/dist/parsers/pptx/vscode-parser.js +1503 -0
  110. package/dist/parsers/pptx/vscode.d.ts +4 -0
  111. package/dist/parsers/pptx/vscode.js +18 -0
  112. package/dist/parsers/pptx/zip-reader.d.ts +3 -0
  113. package/dist/parsers/pptx/zip-reader.js +20 -0
  114. package/dist/parsers/proto/index.d.ts +90 -0
  115. package/dist/parsers/proto/index.js +197 -0
  116. package/dist/parsers/psd/index.d.ts +16 -0
  117. package/dist/parsers/psd/index.js +10 -0
  118. package/dist/parsers/shapefile/dbf.d.ts +23 -0
  119. package/dist/parsers/shapefile/dbf.js +112 -0
  120. package/dist/parsers/shapefile/index.d.ts +44 -0
  121. package/dist/parsers/shapefile/index.js +119 -0
  122. package/dist/parsers/shapefile/reproject.d.ts +10 -0
  123. package/dist/parsers/shapefile/reproject.js +41 -0
  124. package/dist/parsers/slide-model.d.ts +106 -0
  125. package/dist/parsers/slide-model.js +1 -0
  126. package/dist/parsers/toml/index.d.ts +15 -0
  127. package/dist/parsers/toml/index.js +18 -0
  128. package/dist/parsers/toml/model.d.ts +15 -0
  129. package/dist/parsers/toml/model.js +1 -0
  130. package/dist/parsers/toml/parse.d.ts +16 -0
  131. package/dist/parsers/toml/parse.js +266 -0
  132. package/dist/parsers/types.d.ts +103 -0
  133. package/dist/parsers/types.js +106 -0
  134. package/dist/parsers/video/index.d.ts +6 -0
  135. package/dist/parsers/video/index.js +2 -0
  136. package/dist/parsers/yaml/index.d.ts +16 -0
  137. package/dist/parsers/yaml/index.js +58 -0
  138. package/dist/parsers/yaml/model.d.ts +22 -0
  139. package/dist/parsers/yaml/model.js +1 -0
  140. package/dist/parsers/yaml/self-loading.d.ts +3 -0
  141. package/dist/parsers/yaml/self-loading.js +19 -0
  142. package/dist/parsers/zip-scan.d.ts +8 -0
  143. package/dist/parsers/zip-scan.js +80 -0
  144. package/dist/registry/container.d.ts +17 -0
  145. package/dist/registry/container.js +49 -0
  146. package/dist/registry/index.d.ts +133 -0
  147. package/dist/registry/index.js +348 -0
  148. package/dist/registry/probe.d.ts +3 -0
  149. package/dist/registry/probe.js +177 -0
  150. package/dist/registry/sniff.d.ts +17 -0
  151. package/dist/registry/sniff.js +57 -0
  152. package/dist/styles/archive.css +10 -0
  153. package/dist/styles/audio.css +66 -0
  154. package/dist/styles/automotive.css +1 -0
  155. package/dist/styles/csv.css +262 -0
  156. package/dist/styles/excel.css +212 -0
  157. package/dist/styles/fallback.css +48 -0
  158. package/dist/styles/hdf5.css +3 -0
  159. package/dist/styles/hwp.css +12 -0
  160. package/dist/styles/image.css +115 -0
  161. package/dist/styles/json.css +342 -0
  162. package/dist/styles/jsonl.css +1 -0
  163. package/dist/styles/markdown.css +10 -0
  164. package/dist/styles/mat.css +2 -0
  165. package/dist/styles/mermaid.css +1 -0
  166. package/dist/styles/parquet.css +2 -0
  167. package/dist/styles/pdf.css +551 -0
  168. package/dist/styles/plantuml.css +1 -0
  169. package/dist/styles/ppt.css +1 -0
  170. package/dist/styles/proto.css +2 -0
  171. package/dist/styles/psd.css +1 -0
  172. package/dist/styles/shapefile.css +25 -0
  173. package/dist/styles/toml.css +1 -0
  174. package/dist/styles/video.css +74 -0
  175. package/dist/styles/word.css +685 -0
  176. package/dist/styles/yaml.css +1 -0
  177. package/dist/viewers/a2l/index.d.ts +15 -0
  178. package/dist/viewers/a2l/index.js +5 -0
  179. package/dist/viewers/archive/archive-preview-decoder.d.ts +4 -0
  180. package/dist/viewers/archive/archive-preview-decoder.js +223 -0
  181. package/dist/viewers/archive/controller.d.ts +24 -0
  182. package/dist/viewers/archive/controller.js +18 -0
  183. package/dist/viewers/archive/index.d.ts +25 -0
  184. package/dist/viewers/archive/index.js +230 -0
  185. package/dist/viewers/archive/preview.d.ts +2 -0
  186. package/dist/viewers/archive/preview.js +2 -0
  187. package/dist/viewers/archive/styles.d.ts +1 -0
  188. package/dist/viewers/archive/styles.js +11 -0
  189. package/dist/viewers/arxml/index.d.ts +15 -0
  190. package/dist/viewers/arxml/index.js +5 -0
  191. package/dist/viewers/asc/index.d.ts +15 -0
  192. package/dist/viewers/asc/index.js +5 -0
  193. package/dist/viewers/audio/controller.d.ts +33 -0
  194. package/dist/viewers/audio/controller.js +49 -0
  195. package/dist/viewers/audio/engine.d.ts +44 -0
  196. package/dist/viewers/audio/engine.js +108 -0
  197. package/dist/viewers/audio/index.d.ts +92 -0
  198. package/dist/viewers/audio/index.js +448 -0
  199. package/dist/viewers/audio/self-loading.d.ts +7 -0
  200. package/dist/viewers/audio/self-loading.js +42 -0
  201. package/dist/viewers/audio/styles.d.ts +1 -0
  202. package/dist/viewers/audio/styles.js +73 -0
  203. package/dist/viewers/automotive/index.d.ts +8 -0
  204. package/dist/viewers/automotive/index.js +152 -0
  205. package/dist/viewers/automotive/styles.d.ts +1 -0
  206. package/dist/viewers/automotive/styles.js +1 -0
  207. package/dist/viewers/avro/index.d.ts +15 -0
  208. package/dist/viewers/avro/index.js +5 -0
  209. package/dist/viewers/bag/index.d.ts +15 -0
  210. package/dist/viewers/bag/index.js +5 -0
  211. package/dist/viewers/blf/index.d.ts +15 -0
  212. package/dist/viewers/blf/index.js +5 -0
  213. package/dist/viewers/csv/controller.d.ts +126 -0
  214. package/dist/viewers/csv/controller.js +598 -0
  215. package/dist/viewers/csv/index.d.ts +48 -0
  216. package/dist/viewers/csv/index.js +846 -0
  217. package/dist/viewers/csv/styles.d.ts +1 -0
  218. package/dist/viewers/csv/styles.js +267 -0
  219. package/dist/viewers/db3/index.d.ts +15 -0
  220. package/dist/viewers/db3/index.js +5 -0
  221. package/dist/viewers/dbc/index.d.ts +15 -0
  222. package/dist/viewers/dbc/index.js +5 -0
  223. package/dist/viewers/diagram.d.ts +14 -0
  224. package/dist/viewers/diagram.js +95 -0
  225. package/dist/viewers/excel/controller.d.ts +108 -0
  226. package/dist/viewers/excel/controller.js +548 -0
  227. package/dist/viewers/excel/grid.d.ts +28 -0
  228. package/dist/viewers/excel/grid.js +99 -0
  229. package/dist/viewers/excel/index.d.ts +37 -0
  230. package/dist/viewers/excel/index.js +620 -0
  231. package/dist/viewers/excel/self-loading.d.ts +6 -0
  232. package/dist/viewers/excel/self-loading.js +13 -0
  233. package/dist/viewers/excel/styles.d.ts +1 -0
  234. package/dist/viewers/excel/styles.js +216 -0
  235. package/dist/viewers/fallback/index.d.ts +17 -0
  236. package/dist/viewers/fallback/index.js +130 -0
  237. package/dist/viewers/fallback/styles.d.ts +1 -0
  238. package/dist/viewers/fallback/styles.js +49 -0
  239. package/dist/viewers/hdf5/index.d.ts +19 -0
  240. package/dist/viewers/hdf5/index.js +170 -0
  241. package/dist/viewers/hdf5/styles.d.ts +1 -0
  242. package/dist/viewers/hdf5/styles.js +4 -0
  243. package/dist/viewers/hwp/controller.d.ts +19 -0
  244. package/dist/viewers/hwp/controller.js +22 -0
  245. package/dist/viewers/hwp/index.d.ts +39 -0
  246. package/dist/viewers/hwp/index.js +271 -0
  247. package/dist/viewers/hwp/self-loading.d.ts +2 -0
  248. package/dist/viewers/hwp/self-loading.js +6 -0
  249. package/dist/viewers/hwp/styles.d.ts +1 -0
  250. package/dist/viewers/hwp/styles.js +13 -0
  251. package/dist/viewers/image/controller.d.ts +210 -0
  252. package/dist/viewers/image/controller.js +336 -0
  253. package/dist/viewers/image/decode.d.ts +54 -0
  254. package/dist/viewers/image/decode.js +150 -0
  255. package/dist/viewers/image/index.d.ts +38 -0
  256. package/dist/viewers/image/index.js +749 -0
  257. package/dist/viewers/image/limits.d.ts +18 -0
  258. package/dist/viewers/image/limits.js +20 -0
  259. package/dist/viewers/image/styles.d.ts +1 -0
  260. package/dist/viewers/image/styles.js +119 -0
  261. package/dist/viewers/json/controller.d.ts +89 -0
  262. package/dist/viewers/json/controller.js +411 -0
  263. package/dist/viewers/json/index.d.ts +25 -0
  264. package/dist/viewers/json/index.js +503 -0
  265. package/dist/viewers/json/styles.d.ts +1 -0
  266. package/dist/viewers/json/styles.js +346 -0
  267. package/dist/viewers/json/transforms.d.ts +27 -0
  268. package/dist/viewers/json/transforms.js +253 -0
  269. package/dist/viewers/jsonl/controller.d.ts +48 -0
  270. package/dist/viewers/jsonl/controller.js +136 -0
  271. package/dist/viewers/jsonl/index.d.ts +22 -0
  272. package/dist/viewers/jsonl/index.js +184 -0
  273. package/dist/viewers/jsonl/styles.d.ts +1 -0
  274. package/dist/viewers/jsonl/styles.js +1 -0
  275. package/dist/viewers/markdown/controller.d.ts +50 -0
  276. package/dist/viewers/markdown/controller.js +62 -0
  277. package/dist/viewers/markdown/index.d.ts +64 -0
  278. package/dist/viewers/markdown/index.js +425 -0
  279. package/dist/viewers/markdown/math.d.ts +21 -0
  280. package/dist/viewers/markdown/math.js +100 -0
  281. package/dist/viewers/markdown/self-loading.d.ts +5 -0
  282. package/dist/viewers/markdown/self-loading.js +48 -0
  283. package/dist/viewers/markdown/styles.d.ts +1 -0
  284. package/dist/viewers/markdown/styles.js +11 -0
  285. package/dist/viewers/mat/index.d.ts +19 -0
  286. package/dist/viewers/mat/index.js +113 -0
  287. package/dist/viewers/mat/styles.d.ts +1 -0
  288. package/dist/viewers/mat/styles.js +3 -0
  289. package/dist/viewers/media.d.ts +9 -0
  290. package/dist/viewers/media.js +77 -0
  291. package/dist/viewers/mermaid/index.d.ts +17 -0
  292. package/dist/viewers/mermaid/index.js +6 -0
  293. package/dist/viewers/mermaid/self-loading.d.ts +2 -0
  294. package/dist/viewers/mermaid/self-loading.js +2 -0
  295. package/dist/viewers/mf4/index.d.ts +15 -0
  296. package/dist/viewers/mf4/index.js +5 -0
  297. package/dist/viewers/parquet/controller.d.ts +37 -0
  298. package/dist/viewers/parquet/controller.js +26 -0
  299. package/dist/viewers/parquet/index.d.ts +23 -0
  300. package/dist/viewers/parquet/index.js +134 -0
  301. package/dist/viewers/parquet/styles.d.ts +1 -0
  302. package/dist/viewers/parquet/styles.js +3 -0
  303. package/dist/viewers/pcap/index.d.ts +15 -0
  304. package/dist/viewers/pcap/index.js +5 -0
  305. package/dist/viewers/pcapng/index.d.ts +15 -0
  306. package/dist/viewers/pcapng/index.js +5 -0
  307. package/dist/viewers/pdf/controller.d.ts +120 -0
  308. package/dist/viewers/pdf/controller.js +191 -0
  309. package/dist/viewers/pdf/editing.d.ts +26 -0
  310. package/dist/viewers/pdf/editing.js +265 -0
  311. package/dist/viewers/pdf/index.d.ts +88 -0
  312. package/dist/viewers/pdf/index.js +1400 -0
  313. package/dist/viewers/pdf/self-loading.d.ts +6 -0
  314. package/dist/viewers/pdf/self-loading.js +14 -0
  315. package/dist/viewers/pdf/styles.d.ts +1 -0
  316. package/dist/viewers/pdf/styles.js +555 -0
  317. package/dist/viewers/plantuml/index.d.ts +17 -0
  318. package/dist/viewers/plantuml/index.js +6 -0
  319. package/dist/viewers/plantuml/self-loading.d.ts +2 -0
  320. package/dist/viewers/plantuml/self-loading.js +2 -0
  321. package/dist/viewers/ppt/chart.d.ts +8 -0
  322. package/dist/viewers/ppt/chart.js +83 -0
  323. package/dist/viewers/ppt/controller.d.ts +34 -0
  324. package/dist/viewers/ppt/controller.js +27 -0
  325. package/dist/viewers/ppt/index.d.ts +33 -0
  326. package/dist/viewers/ppt/index.js +101 -0
  327. package/dist/viewers/ppt/render.d.ts +5 -0
  328. package/dist/viewers/ppt/render.js +144 -0
  329. package/dist/viewers/ppt/self-loading.d.ts +9 -0
  330. package/dist/viewers/ppt/self-loading.js +4 -0
  331. package/dist/viewers/ppt/styles.d.ts +1 -0
  332. package/dist/viewers/ppt/styles.js +1 -0
  333. package/dist/viewers/proto/index.d.ts +17 -0
  334. package/dist/viewers/proto/index.js +170 -0
  335. package/dist/viewers/proto/styles.d.ts +1 -0
  336. package/dist/viewers/proto/styles.js +2 -0
  337. package/dist/viewers/psd/index.d.ts +27 -0
  338. package/dist/viewers/psd/index.js +39 -0
  339. package/dist/viewers/psd/self-loading.d.ts +10 -0
  340. package/dist/viewers/psd/self-loading.js +20 -0
  341. package/dist/viewers/psd/styles.d.ts +1 -0
  342. package/dist/viewers/psd/styles.js +1 -0
  343. package/dist/viewers/reqif/index.d.ts +15 -0
  344. package/dist/viewers/reqif/index.js +5 -0
  345. package/dist/viewers/shapefile/index.d.ts +35 -0
  346. package/dist/viewers/shapefile/index.js +336 -0
  347. package/dist/viewers/shapefile/self-loading.d.ts +7 -0
  348. package/dist/viewers/shapefile/self-loading.js +32 -0
  349. package/dist/viewers/shapefile/styles.d.ts +1 -0
  350. package/dist/viewers/shapefile/styles.js +28 -0
  351. package/dist/viewers/stp/index.d.ts +15 -0
  352. package/dist/viewers/stp/index.js +5 -0
  353. package/dist/viewers/structured-styles.d.ts +1 -0
  354. package/dist/viewers/structured-styles.js +1 -0
  355. package/dist/viewers/structured.d.ts +36 -0
  356. package/dist/viewers/structured.js +138 -0
  357. package/dist/viewers/toml/controller.d.ts +38 -0
  358. package/dist/viewers/toml/controller.js +61 -0
  359. package/dist/viewers/toml/index.d.ts +18 -0
  360. package/dist/viewers/toml/index.js +34 -0
  361. package/dist/viewers/types.d.ts +36 -0
  362. package/dist/viewers/types.js +9 -0
  363. package/dist/viewers/video/controller.d.ts +29 -0
  364. package/dist/viewers/video/controller.js +54 -0
  365. package/dist/viewers/video/index.d.ts +18 -0
  366. package/dist/viewers/video/index.js +305 -0
  367. package/dist/viewers/video/styles.d.ts +1 -0
  368. package/dist/viewers/video/styles.js +79 -0
  369. package/dist/viewers/word/controller.d.ts +19 -0
  370. package/dist/viewers/word/controller.js +22 -0
  371. package/dist/viewers/word/docx-preprocess.d.ts +63 -0
  372. package/dist/viewers/word/docx-preprocess.js +136 -0
  373. package/dist/viewers/word/index.d.ts +32 -0
  374. package/dist/viewers/word/index.js +187 -0
  375. package/dist/viewers/word/normalize-docx.d.ts +2 -0
  376. package/dist/viewers/word/normalize-docx.js +50 -0
  377. package/dist/viewers/word/paginate.d.ts +1 -0
  378. package/dist/viewers/word/paginate.js +1035 -0
  379. package/dist/viewers/word/self-loading.d.ts +2 -0
  380. package/dist/viewers/word/self-loading.js +7 -0
  381. package/dist/viewers/word/styles.d.ts +1 -0
  382. package/dist/viewers/word/styles.js +686 -0
  383. package/dist/viewers/yaml/controller.d.ts +42 -0
  384. package/dist/viewers/yaml/controller.js +41 -0
  385. package/dist/viewers/yaml/index.d.ts +21 -0
  386. package/dist/viewers/yaml/index.js +20 -0
  387. package/package.json +375 -0
@@ -0,0 +1,17 @@
1
+ import type * as XLSX from 'xlsx';
2
+ import type { ParseOptions, ParseOutcome } from '../types.js';
3
+ import type { ExcelWorkbook } from './model.js';
4
+ export type { CellRange, CellStyle, ExcelCell, ExcelCellType, ExcelSheet, ExcelWorkbook, SheetAoa } from './model.js';
5
+ export { sheetToAoa } from './model.js';
6
+ export { serializeWorkbook } from './serialize.js';
7
+ /** SheetJS is provided by the caller; the base entry never imports it. */
8
+ export interface ExcelParseDeps {
9
+ xlsx: typeof XLSX;
10
+ }
11
+ /** Input ownership: the parser consumes the input (DESIGN.md §3-①). */
12
+ export declare const EXCEL_INPUT_OWNERSHIP: "consumes";
13
+ /** Default cap on the archive's declared uncompressed total (matches
14
+ * ARCHIVE_DEFAULT_LIMITS.maxDecompressedBytes); override via
15
+ * `options.limits.maxDecompressedBytes`. */
16
+ export declare const EXCEL_MAX_DECOMPRESSED_BYTES: number;
17
+ export declare function parseExcel(input: Uint8Array, deps: ExcelParseDeps, options?: ParseOptions): ParseOutcome<ExcelWorkbook>;
@@ -0,0 +1,406 @@
1
+ // Excel parser entry — the core contract surface (docs/viewers/excel.md §2,
2
+ // DESIGN.md §3-①). parseExcel(bytes) -> ParseOutcome<ExcelWorkbook>.
3
+ //
4
+ // SheetJS (`xlsx`) is an optional peer dependency and is **injected** rather
5
+ // than imported at runtime (ExcelParseDeps), so this base entry carries no
6
+ // `import 'xlsx'` — the bundler of a platform that doesn't use the Excel viewer
7
+ // never has to resolve it (ADR 14, X8). Type-only imports below are erased.
8
+ //
9
+ // Input-caused failures never throw; they return `status: 'failed'` (ADR 11).
10
+ // Input ownership is `consumes` — after parsing, the original bytes are not
11
+ // needed (no verbatim view), so a Worker may transfer them (X4, DESIGN §3-①).
12
+ import { DEFAULT_LIMITS, LimitTracker } from '../types.js';
13
+ import { declaredZipUncompressedBytes } from '../zip-scan.js';
14
+ export { sheetToAoa } from './model.js';
15
+ export { serializeWorkbook } from './serialize.js';
16
+ /** Input ownership: the parser consumes the input (DESIGN.md §3-①). */
17
+ export const EXCEL_INPUT_OWNERSHIP = 'consumes';
18
+ /** Default cap on the archive's declared uncompressed total (matches
19
+ * ARCHIVE_DEFAULT_LIMITS.maxDecompressedBytes); override via
20
+ * `options.limits.maxDecompressedBytes`. */
21
+ export const EXCEL_MAX_DECOMPRESSED_BYTES = 1024 * 1024 * 1024;
22
+ export function parseExcel(input, deps, options = {}) {
23
+ const started = Date.now();
24
+ const limits = { ...DEFAULT_LIMITS, ...options.limits };
25
+ const diagnostics = [];
26
+ const finish = (result) => ({
27
+ result,
28
+ execution: {
29
+ workerUsed: false,
30
+ // maxDecompressedBytes is checked against the ZIP central directory's
31
+ // declared sizes before read (zip-scan.ts), but SheetJS decompresses
32
+ // internally, so an archive that lies in its headers is not bounded
33
+ // during inflate — only maxInputBytes (pre-load) and maxEntries
34
+ // (post-read cell cap) are hard here (X4, follow-up: Worker).
35
+ hardLimitEnforced: false,
36
+ elapsedMillis: Date.now() - started
37
+ }
38
+ });
39
+ if (input.byteLength > limits.maxInputBytes) {
40
+ return finish(fail('limit-exceeded', false, 'diag.limit-exceeded.input', diagnostics, {
41
+ maxBytes: limits.maxInputBytes
42
+ }));
43
+ }
44
+ if (options.signal?.aborted) {
45
+ return finish(fail('aborted', true, 'diag.aborted', diagnostics));
46
+ }
47
+ // Zip-bomb pre-scan: reject archives whose central directory declares more
48
+ // uncompressed data than the cap before SheetJS inflates anything. Legacy
49
+ // .xls (CFB) and other non-ZIP inputs return null and pass through.
50
+ const maxDecompressed = limits.maxDecompressedBytes ?? EXCEL_MAX_DECOMPRESSED_BYTES;
51
+ const declared = declaredZipUncompressedBytes(input);
52
+ if (declared !== null && declared > maxDecompressed) {
53
+ return finish(fail('limit-exceeded', false, 'diag.limit-exceeded.decompressed', diagnostics, {
54
+ maxBytes: maxDecompressed
55
+ }));
56
+ }
57
+ let wb;
58
+ try {
59
+ wb = deps.xlsx.read(input, {
60
+ type: 'array',
61
+ cellDates: true,
62
+ cellNF: true,
63
+ cellText: true,
64
+ cellStyles: true // grid mode (X3): populate cell.s / !cols / !rows
65
+ });
66
+ }
67
+ catch (err) {
68
+ const message = String(err?.message ?? err).toLowerCase();
69
+ if (message.includes('password') || message.includes('encrypt')) {
70
+ return finish(fail('password-required', true, 'diag.excel.password-required', diagnostics));
71
+ }
72
+ return finish(fail('invalid-format', false, 'diag.excel.invalid-format', diagnostics));
73
+ }
74
+ const date1904 = readDate1904(wb);
75
+ const sheetNames = Array.isArray(wb.SheetNames) ? [...wb.SheetNames] : [];
76
+ const tracker = new LimitTracker(limits, options.signal);
77
+ const sheets = [];
78
+ let truncated = false;
79
+ let aborted = false;
80
+ let nonEmptySheets = 0;
81
+ for (const name of sheetNames) {
82
+ const ws = wb.Sheets[name];
83
+ const built = ws ? buildSheet(name, ws, deps.xlsx, tracker, limits.maxEntries) : emptySheet(name);
84
+ sheets.push(built.sheet);
85
+ if (built.sheet.usedRange)
86
+ nonEmptySheets++;
87
+ if (built.aborted) {
88
+ aborted = true;
89
+ break;
90
+ }
91
+ if (built.truncated) {
92
+ truncated = true;
93
+ break;
94
+ }
95
+ }
96
+ if (aborted) {
97
+ return finish(fail('aborted', true, 'diag.aborted', diagnostics));
98
+ }
99
+ if (sheetNames.length === 0 || nonEmptySheets === 0) {
100
+ diagnostics.push({
101
+ severity: 'info',
102
+ code: 'excel.empty-workbook',
103
+ messageKey: 'diag.excel.empty-workbook'
104
+ });
105
+ }
106
+ const document = { sheetNames, sheets, date1904 };
107
+ if (truncated) {
108
+ diagnostics.push({
109
+ severity: 'warning',
110
+ code: 'limit-exceeded',
111
+ messageKey: 'diag.limit-exceeded.cells',
112
+ args: { count: tracker.entryCount }
113
+ });
114
+ return finish({ status: 'partial', document, diagnostics });
115
+ }
116
+ return finish({ status: 'ok', document, diagnostics });
117
+ }
118
+ function fail(code, retryable, messageKey, diagnostics, args) {
119
+ return {
120
+ status: 'failed',
121
+ failure: args ? { code, retryable, messageKey, args } : { code, retryable, messageKey },
122
+ diagnostics
123
+ };
124
+ }
125
+ function emptySheet(name) {
126
+ return {
127
+ sheet: { name, usedRange: null, cells: [], rowCount: 0, columnCount: 0 },
128
+ truncated: false,
129
+ aborted: false
130
+ };
131
+ }
132
+ function buildSheet(name, ws, xlsx, tracker, maxEntries) {
133
+ const usedRange = resolveUsedRange(ws, xlsx);
134
+ if (!usedRange) {
135
+ return emptySheet(name);
136
+ }
137
+ // Collect present cells only (sparse) and emit row-major for deterministic
138
+ // order regardless of the object key order SheetJS produced.
139
+ const addresses = [];
140
+ for (const key of Object.keys(ws)) {
141
+ if (key.charCodeAt(0) === 0x21 /* '!' */)
142
+ continue;
143
+ const decoded = xlsx.utils.decode_cell(key);
144
+ addresses.push({ r: decoded.r, c: decoded.c, addr: key });
145
+ }
146
+ addresses.sort((a, b) => (a.r - b.r) || (a.c - b.c));
147
+ const cells = [];
148
+ let truncated = false;
149
+ let aborted = false;
150
+ for (let i = 0; i < addresses.length; i++) {
151
+ const entry = addresses[i];
152
+ const raw = ws[entry.addr];
153
+ if (!raw || raw.t === 'z' || raw.t === undefined)
154
+ continue; // blank/stub
155
+ tracker.addEntries(1);
156
+ // Amortize abort/limit checks: every 512 cells or once over the cap.
157
+ if (i % 512 === 0 || tracker.entryCount > maxEntries) {
158
+ const violation = tracker.checkpoint();
159
+ if (violation?.kind === 'aborted') {
160
+ aborted = true;
161
+ break;
162
+ }
163
+ if (violation) {
164
+ truncated = true;
165
+ break;
166
+ }
167
+ }
168
+ cells.push(mapCell(entry.r, entry.c, raw));
169
+ }
170
+ const sheet = {
171
+ name,
172
+ usedRange,
173
+ cells,
174
+ rowCount: usedRange.r1 - usedRange.r0 + 1,
175
+ columnCount: usedRange.c1 - usedRange.c0 + 1
176
+ };
177
+ // Grid-mode presentation (X3): merges + column/row sizes. Optional — only
178
+ // set when present, so the data mode and existing snapshots are unaffected.
179
+ const merges = ws['!merges']?.map((m) => ({
180
+ r0: m.s.r,
181
+ c0: m.s.c,
182
+ r1: m.e.r,
183
+ c1: m.e.c
184
+ }));
185
+ if (merges && merges.length)
186
+ sheet.merges = merges;
187
+ const cols = ws['!cols'];
188
+ if (cols) {
189
+ const widths = {};
190
+ cols.forEach((col, c) => {
191
+ const px = colWidthPx(col);
192
+ if (px !== null)
193
+ widths[c] = px;
194
+ });
195
+ if (Object.keys(widths).length)
196
+ sheet.columnWidthsPx = widths;
197
+ }
198
+ const rows = ws['!rows'];
199
+ if (rows) {
200
+ const heights = {};
201
+ rows.forEach((row, r) => {
202
+ const px = rowHeightPx(row);
203
+ if (px !== null)
204
+ heights[r] = px;
205
+ });
206
+ if (Object.keys(heights).length)
207
+ sheet.rowHeightsPx = heights;
208
+ }
209
+ return { sheet, truncated, aborted };
210
+ }
211
+ /** Column width in px from SheetJS ColInfo (ported from omni-viewer-web). */
212
+ function colWidthPx(col) {
213
+ if (!col)
214
+ return null;
215
+ if (typeof col.wpx === 'number')
216
+ return clampPx(col.wpx, 24, 800);
217
+ if (typeof col.wch === 'number')
218
+ return clampPx(col.wch * 8 + 12, 24, 800);
219
+ if (typeof col.width === 'number')
220
+ return clampPx((col.width / 256) * 8 + 12, 24, 800);
221
+ return null;
222
+ }
223
+ /** Row height in px from SheetJS RowInfo (ported from omni-viewer-web). */
224
+ function rowHeightPx(row) {
225
+ if (!row)
226
+ return null;
227
+ if (typeof row.hpx === 'number')
228
+ return clampPx(row.hpx, 20, 240);
229
+ if (typeof row.hpt === 'number')
230
+ return clampPx((row.hpt * 96) / 72, 20, 240);
231
+ return null;
232
+ }
233
+ function clampPx(value, min, max) {
234
+ return Math.max(min, Math.min(max, Math.round(value)));
235
+ }
236
+ function resolveUsedRange(ws, xlsx) {
237
+ const ref = ws['!ref'];
238
+ if (ref) {
239
+ try {
240
+ const range = xlsx.utils.decode_range(ref);
241
+ if (range.e.r >= range.s.r && range.e.c >= range.s.c) {
242
+ return { r0: range.s.r, c0: range.s.c, r1: range.e.r, c1: range.e.c };
243
+ }
244
+ }
245
+ catch {
246
+ // fall through to manual reconstruction
247
+ }
248
+ }
249
+ let r0 = Infinity, c0 = Infinity, r1 = -1, c1 = -1;
250
+ for (const key of Object.keys(ws)) {
251
+ if (key.charCodeAt(0) === 0x21)
252
+ continue;
253
+ const cell = xlsx.utils.decode_cell(key);
254
+ if (cell.r < r0)
255
+ r0 = cell.r;
256
+ if (cell.c < c0)
257
+ c0 = cell.c;
258
+ if (cell.r > r1)
259
+ r1 = cell.r;
260
+ if (cell.c > c1)
261
+ c1 = cell.c;
262
+ }
263
+ if (r1 < 0 || c1 < 0)
264
+ return null;
265
+ return { r0, c0, r1, c1 };
266
+ }
267
+ function mapCell(r, c, cell) {
268
+ const w = cell.w != null ? String(cell.w) : (cell.v == null ? '' : String(cell.v));
269
+ let t;
270
+ let v;
271
+ switch (cell.t) {
272
+ case 'n':
273
+ t = 'number';
274
+ v = typeof cell.v === 'number' ? cell.v : Number(cell.v);
275
+ break;
276
+ case 'b':
277
+ t = 'boolean';
278
+ v = Boolean(cell.v);
279
+ break;
280
+ case 'd':
281
+ t = 'date';
282
+ v = cell.v instanceof Date ? dateToIso(cell.v) : String(cell.v ?? '');
283
+ break;
284
+ case 'e':
285
+ t = 'error';
286
+ v = w;
287
+ break;
288
+ default: // 's' | 'str' (formula string result) | anything else
289
+ t = 'text';
290
+ v = cell.v == null ? '' : String(cell.v);
291
+ break;
292
+ }
293
+ const style = mapStyle(cell.s);
294
+ return style ? { r, c, t, v, w, style } : { r, c, t, v, w };
295
+ }
296
+ /** Map a SheetJS cell style object to the semantic CellStyle (grid mode, X3).
297
+ * Ported from omni-viewer-web `mapCellStyle`; stores semantic values, not CSS. */
298
+ function mapStyle(s) {
299
+ if (!s || typeof s !== 'object')
300
+ return undefined;
301
+ const style = s;
302
+ const out = {};
303
+ const font = style.font;
304
+ if (font?.bold)
305
+ out.bold = true;
306
+ if (font?.italic)
307
+ out.italic = true;
308
+ if (typeof font?.sz === 'number')
309
+ out.fontSizePx = Math.max(8, Math.min(64, font.sz));
310
+ const color = normalizeColor(font?.color);
311
+ if (color)
312
+ out.color = color;
313
+ const fill = style.fill;
314
+ const bg = normalizeColor(fill?.fgColor) ?? normalizeColor(fill?.bgColor);
315
+ if (bg && fill?.patternType && fill.patternType !== 'none')
316
+ out.background = bg;
317
+ const align = style.alignment;
318
+ const h = align?.horizontal !== undefined ? String(align.horizontal) : '';
319
+ if (h === 'left' || h === 'center' || h === 'right' || h === 'justify')
320
+ out.align = h;
321
+ else if (h === 'centerContinuous')
322
+ out.align = 'center';
323
+ else if (h === 'distributed')
324
+ out.align = 'justify';
325
+ const va = align?.vertical !== undefined ? String(align.vertical) : '';
326
+ if (va === 'top' || va === 'center' || va === 'bottom')
327
+ out.valign = va;
328
+ if (align?.wrapText)
329
+ out.wrap = true;
330
+ const border = style.border;
331
+ if (border) {
332
+ const edges = {};
333
+ const toEdge = (edge) => {
334
+ if (!edge || typeof edge !== 'object')
335
+ return undefined;
336
+ const e = edge;
337
+ const c = normalizeColor(e.color) ?? '#808080';
338
+ return `${borderStyle(typeof e.style === 'string' ? e.style : undefined)} ${c}`;
339
+ };
340
+ const top = toEdge(border.top);
341
+ const right = toEdge(border.right);
342
+ const bottom = toEdge(border.bottom);
343
+ const left = toEdge(border.left);
344
+ if (top)
345
+ edges.top = top;
346
+ if (right)
347
+ edges.right = right;
348
+ if (bottom)
349
+ edges.bottom = bottom;
350
+ if (left)
351
+ edges.left = left;
352
+ if (Object.keys(edges).length)
353
+ out.borders = edges;
354
+ }
355
+ return Object.keys(out).length ? out : undefined;
356
+ }
357
+ function normalizeColor(color) {
358
+ if (!color || typeof color !== 'object')
359
+ return undefined;
360
+ const rgb = color.rgb;
361
+ if (typeof rgb !== 'string')
362
+ return undefined;
363
+ const raw = rgb.replace('#', '');
364
+ const hex = raw.length > 6 ? raw.slice(-6) : raw;
365
+ return /^[0-9A-Fa-f]{6}$/.test(hex) ? `#${hex}` : undefined;
366
+ }
367
+ function borderStyle(style) {
368
+ switch (style) {
369
+ case 'medium': return '2px solid';
370
+ case 'thick': return '3px solid';
371
+ case 'dashed': return '1px dashed';
372
+ case 'dotted': return '1px dotted';
373
+ case 'double': return '3px double';
374
+ default: return '1px solid'; // thin / hair / unknown
375
+ }
376
+ }
377
+ /**
378
+ * Format a SheetJS date cell to a calendar-preserving ISO string. SheetJS
379
+ * (>=0.20) constructs the Date from the serial's parts in UTC; reading them
380
+ * back with UTC getters round-trips the intended calendar date on any host
381
+ * timezone (deterministic), so we never call local getters (X5, determinism
382
+ * rule). Requires xlsx >=0.20.2 (the peer range) — 0.18 built these Dates
383
+ * from local-time parts, which this would misread.
384
+ */
385
+ function dateToIso(d) {
386
+ if (Number.isNaN(d.getTime()))
387
+ return '';
388
+ const pad = (n, width = 2) => String(n).padStart(width, '0');
389
+ const y = pad(d.getUTCFullYear(), 4);
390
+ const mo = pad(d.getUTCMonth() + 1);
391
+ const da = pad(d.getUTCDate());
392
+ const h = d.getUTCHours();
393
+ const mi = d.getUTCMinutes();
394
+ const s = d.getUTCSeconds();
395
+ const ms = d.getUTCMilliseconds();
396
+ if (h === 0 && mi === 0 && s === 0 && ms === 0)
397
+ return `${y}-${mo}-${da}`;
398
+ const base = `${y}-${mo}-${da}T${pad(h)}:${pad(mi)}:${pad(s)}`;
399
+ return ms ? `${base}.${pad(ms, 3)}` : base;
400
+ }
401
+ function readDate1904(wb) {
402
+ // SheetJS types this as boolean | undefined, but files can carry 1/"1";
403
+ // coerce defensively without tripping strict comparisons.
404
+ const flag = wb.Workbook?.WBProps?.date1904;
405
+ return flag === true || flag === 1 || flag === '1' || flag === 'true';
406
+ }
@@ -0,0 +1,80 @@
1
+ export type ExcelCellType = 'number' | 'text' | 'boolean' | 'date' | 'error';
2
+ /**
3
+ * Semantic (non-CSS) presentation attributes for the grid render mode (X3).
4
+ * Populated only when the parser reads styles; the data (AOA) mode ignores it.
5
+ * Colors are `#rrggbb`; borders are CSS shorthand strings (e.g. '1px solid #333').
6
+ */
7
+ export interface CellStyle {
8
+ bold?: boolean;
9
+ italic?: boolean;
10
+ fontSizePx?: number;
11
+ color?: string;
12
+ background?: string;
13
+ align?: 'left' | 'center' | 'right' | 'justify';
14
+ valign?: 'top' | 'center' | 'bottom';
15
+ wrap?: boolean;
16
+ borders?: {
17
+ top?: string;
18
+ right?: string;
19
+ bottom?: string;
20
+ left?: string;
21
+ };
22
+ }
23
+ /** Inclusive 0-based cell range (used for merges and used ranges). */
24
+ export interface CellRange {
25
+ r0: number;
26
+ c0: number;
27
+ r1: number;
28
+ c1: number;
29
+ }
30
+ export interface ExcelCell {
31
+ /** 0-based absolute row index (sheet origin). */
32
+ r: number;
33
+ /** 0-based absolute column index. */
34
+ c: number;
35
+ t: ExcelCellType;
36
+ /**
37
+ * Raw value. Dates are calendar-preserving ISO-8601 strings (see
38
+ * `dateToIso`); numbers are float64 (SheetJS reads workbook numbers as JS
39
+ * numbers, so values beyond 2^53 already lost precision upstream — X5);
40
+ * errors carry the error text (e.g. '#DIV/0!').
41
+ */
42
+ v: string | number | boolean | null;
43
+ /** Display text as formatted by the source file's number format (`w`). */
44
+ w: string;
45
+ /** Presentation attributes for grid mode (X3); absent when unstyled. */
46
+ style?: CellStyle;
47
+ }
48
+ export interface ExcelSheet {
49
+ name: string;
50
+ /** Inclusive 0-based bounds of the used range, or null when empty. */
51
+ usedRange: CellRange | null;
52
+ /** Sparse — only cells present in the file, row-major (r, then c). */
53
+ cells: ExcelCell[];
54
+ rowCount: number;
55
+ columnCount: number;
56
+ /** Merged cell ranges (grid mode, X3). */
57
+ merges?: CellRange[];
58
+ /** Absolute column index → width in px (grid mode, X3). */
59
+ columnWidthsPx?: Record<number, number>;
60
+ /** Absolute row index → height in px (grid mode, X3). */
61
+ rowHeightsPx?: Record<number, number>;
62
+ }
63
+ export interface ExcelWorkbook {
64
+ sheetNames: string[];
65
+ sheets: ExcelSheet[];
66
+ /** 1904 date system flag (affects how date serials map to calendar dates). */
67
+ date1904: boolean;
68
+ }
69
+ export interface SheetAoa {
70
+ headers: string[];
71
+ rows: string[][];
72
+ }
73
+ /**
74
+ * Derive a dense AOA (header row + data rows) of display strings from a sparse
75
+ * sheet. Missing cells become '' (X5). When `hasHeader`, the first used row is
76
+ * the header; otherwise headers are empty and every used row is a data row.
77
+ * Pure and deterministic — the core viewer/controller calls this; the parser
78
+ * does not, keeping the model grid-shaped.
79
+ */
80
+ export declare function sheetToAoa(sheet: ExcelSheet, hasHeader?: boolean): SheetAoa;
@@ -0,0 +1,48 @@
1
+ // Excel document model (docs/viewers/excel.md §2, X1). The parser preserves a
2
+ // sparse, coordinate-bearing grid — cell address + type + raw value (`v`) +
3
+ // the source file's formatted text (`w`). The AOA text table that the core
4
+ // viewer renders is *derived* from this model (see `sheetToAoa`), so the model
5
+ // stays the single source and web can keep its own grid renderer on top of it
6
+ // (ADR 33). Cell styles / merges / column widths are optional follow-up fields
7
+ // (X3) and are not populated in v1.
8
+ /**
9
+ * Derive a dense AOA (header row + data rows) of display strings from a sparse
10
+ * sheet. Missing cells become '' (X5). When `hasHeader`, the first used row is
11
+ * the header; otherwise headers are empty and every used row is a data row.
12
+ * Pure and deterministic — the core viewer/controller calls this; the parser
13
+ * does not, keeping the model grid-shaped.
14
+ */
15
+ export function sheetToAoa(sheet, hasHeader = true) {
16
+ if (!sheet.usedRange)
17
+ return { headers: [], rows: [] };
18
+ const { r0, c0, r1, c1 } = sheet.usedRange;
19
+ const width = c1 - c0 + 1;
20
+ // Bucket cell display text by row for O(cells) fill instead of O(rows*cols)
21
+ // address lookups.
22
+ const byRow = new Map();
23
+ for (const cell of sheet.cells) {
24
+ let row = byRow.get(cell.r);
25
+ if (!row) {
26
+ row = new Array(width).fill('');
27
+ byRow.set(cell.r, row);
28
+ }
29
+ const col = cell.c - c0;
30
+ if (col >= 0 && col < width)
31
+ row[col] = cell.w;
32
+ }
33
+ const rowAt = (r) => byRow.get(r) ?? new Array(width).fill('');
34
+ let headers;
35
+ let dataStart;
36
+ if (hasHeader) {
37
+ headers = rowAt(r0);
38
+ dataStart = r0 + 1;
39
+ }
40
+ else {
41
+ headers = new Array(width).fill('');
42
+ dataStart = r0;
43
+ }
44
+ const rows = [];
45
+ for (let r = dataStart; r <= r1; r++)
46
+ rows.push(rowAt(r));
47
+ return { headers, rows };
48
+ }
@@ -0,0 +1,3 @@
1
+ import type * as XLSX from 'xlsx';
2
+ import type { ExcelWorkbook } from './model.js';
3
+ export declare function serializeWorkbook(workbook: ExcelWorkbook, xlsx: typeof XLSX): Uint8Array;
@@ -0,0 +1,78 @@
1
+ // Type-preserving XLSX export (docs/viewers/excel.md §2, X7). Re-serializes the
2
+ // original parsed model — using each cell's typed value (`v`/`t`), NOT the
3
+ // display string (`w`) — so numbers stay numbers, booleans stay booleans, and
4
+ // dates stay date-typed cells. Building a worksheet from `w` strings would make
5
+ // everything a text cell (the bug this replaces).
6
+ //
7
+ // Dates: the model stores a calendar-preserving ISO string (model.ts). We
8
+ // rebuild a Date from its numeric components — `Date.UTC(y, m, d, …)`, which is
9
+ // well-defined (not the impl-defined string parse the parser avoided) — and let
10
+ // SheetJS serialize it. SheetJS (>=0.20) maps Dates to serials from their UTC
11
+ // parts, and its own Date→serial→date round-trip is exact, whereas
12
+ // hand-computed serials pick up a sub-minute read-back rounding error.
13
+ // `xlsx` is injected (base entries never import it — ADR 14).
14
+ const ISO_RE = /^(\d{4})-(\d{2})-(\d{2})(?:T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?)?$/;
15
+ export function serializeWorkbook(workbook, xlsx) {
16
+ const wb = xlsx.utils.book_new();
17
+ const sheets = workbook.sheets.length
18
+ ? workbook.sheets
19
+ : [{ name: 'Sheet1', usedRange: null, cells: [], rowCount: 0, columnCount: 0 }];
20
+ for (const sheet of sheets) {
21
+ const ws = {};
22
+ for (const cell of sheet.cells) {
23
+ const address = xlsx.utils.encode_cell({ r: cell.r, c: cell.c });
24
+ ws[address] = toCellObject(cell);
25
+ }
26
+ ws['!ref'] = sheet.usedRange
27
+ ? xlsx.utils.encode_range({
28
+ s: { r: sheet.usedRange.r0, c: sheet.usedRange.c0 },
29
+ e: { r: sheet.usedRange.r1, c: sheet.usedRange.c1 }
30
+ })
31
+ : 'A1';
32
+ // book_append_sheet enforces the 31-char / uniqueness rules SheetJS
33
+ // expects; it also wires SheetNames + Sheets.
34
+ xlsx.utils.book_append_sheet(wb, ws, sheet.name);
35
+ }
36
+ if (workbook.date1904) {
37
+ wb.Workbook = { ...(wb.Workbook ?? {}), WBProps: { ...(wb.Workbook?.WBProps ?? {}), date1904: true } };
38
+ }
39
+ return new Uint8Array(xlsx.write(wb, { type: 'array', bookType: 'xlsx' }));
40
+ }
41
+ function toCellObject(cell) {
42
+ switch (cell.t) {
43
+ case 'number':
44
+ return { t: 'n', v: typeof cell.v === 'number' ? cell.v : Number(cell.v) };
45
+ case 'boolean':
46
+ return { t: 'b', v: Boolean(cell.v) };
47
+ case 'date': {
48
+ const date = typeof cell.v === 'string' ? isoToDate(cell.v) : null;
49
+ if (!date) {
50
+ // Non-ISO date value — keep the visible text rather than guess.
51
+ return { t: 's', v: cell.w || String(cell.v ?? '') };
52
+ }
53
+ // A date-typed cell + date number format makes SheetJS emit a serial
54
+ // and read it back as a date on the next parse (type preserved).
55
+ return { t: 'd', v: date, z: 'yyyy-mm-dd' };
56
+ }
57
+ case 'error':
58
+ return { t: 's', v: cell.w };
59
+ default:
60
+ return { t: 's', v: cell.v == null ? '' : String(cell.v) };
61
+ }
62
+ }
63
+ /** Rebuild a Date from ISO components via `Date.UTC` — mirrors the parser's
64
+ * UTC-getter formatting (SheetJS >=0.20 serializes date cells from UTC
65
+ * parts) so the calendar date round-trips. */
66
+ function isoToDate(iso) {
67
+ const m = ISO_RE.exec(iso);
68
+ if (!m)
69
+ return null;
70
+ const year = Number(m[1]);
71
+ const month = Number(m[2]);
72
+ const day = Number(m[3]);
73
+ const hour = m[4] !== undefined ? Number(m[4]) : 0;
74
+ const minute = m[5] !== undefined ? Number(m[5]) : 0;
75
+ const second = m[6] !== undefined ? Number(m[6]) : 0;
76
+ const millis = m[7] !== undefined ? Number(m[7].padEnd(3, '0')) : 0;
77
+ return new Date(Date.UTC(year, month - 1, day, hour, minute, second, millis));
78
+ }