@cj-tech-master/excelts 9.2.1 → 9.3.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 (383) hide show
  1. package/README.md +25 -2
  2. package/README_zh.md +29 -6
  3. package/dist/browser/index.browser.d.ts +1 -1
  4. package/dist/browser/index.browser.js +4 -0
  5. package/dist/browser/index.d.ts +1 -1
  6. package/dist/browser/index.js +4 -0
  7. package/dist/browser/modules/excel/cell.d.ts +17 -3
  8. package/dist/browser/modules/excel/cell.js +170 -22
  9. package/dist/browser/modules/excel/defined-names.d.ts +96 -1
  10. package/dist/browser/modules/excel/defined-names.js +411 -21
  11. package/dist/browser/modules/excel/image.d.ts +11 -0
  12. package/dist/browser/modules/excel/image.js +24 -1
  13. package/dist/browser/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
  14. package/dist/browser/modules/excel/stream/workbook-reader.browser.js +14 -0
  15. package/dist/browser/modules/excel/stream/workbook-reader.d.ts +2 -1
  16. package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
  17. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +48 -1
  18. package/dist/browser/modules/excel/stream/workbook-writer.d.ts +3 -2
  19. package/dist/browser/modules/excel/stream/worksheet-reader.js +17 -1
  20. package/dist/browser/modules/excel/stream/worksheet-writer.d.ts +39 -6
  21. package/dist/browser/modules/excel/stream/worksheet-writer.js +45 -5
  22. package/dist/browser/modules/excel/table.js +15 -2
  23. package/dist/browser/modules/excel/types.d.ts +133 -2
  24. package/dist/browser/modules/excel/utils/col-cache.d.ts +1 -0
  25. package/dist/browser/modules/excel/utils/col-cache.js +15 -0
  26. package/dist/browser/modules/excel/utils/drawing-utils.d.ts +3 -3
  27. package/dist/browser/modules/excel/utils/drawing-utils.js +4 -0
  28. package/dist/browser/modules/excel/utils/external-link-formula.d.ts +76 -0
  29. package/dist/browser/modules/excel/utils/external-link-formula.js +208 -0
  30. package/dist/browser/modules/excel/utils/iterate-stream.d.ts +9 -3
  31. package/dist/browser/modules/excel/utils/iterate-stream.js +3 -1
  32. package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +19 -0
  33. package/dist/browser/modules/excel/utils/ooxml-paths.js +37 -2
  34. package/dist/browser/modules/excel/utils/shared-strings.d.ts +8 -3
  35. package/dist/browser/modules/excel/utils/shared-strings.js +21 -2
  36. package/dist/browser/modules/excel/utils/workbook-protection.d.ts +30 -0
  37. package/dist/browser/modules/excel/utils/workbook-protection.js +30 -0
  38. package/dist/browser/modules/excel/workbook.browser.d.ts +257 -6
  39. package/dist/browser/modules/excel/workbook.browser.js +318 -34
  40. package/dist/browser/modules/excel/workbook.d.ts +1 -1
  41. package/dist/browser/modules/excel/worksheet.d.ts +3 -1
  42. package/dist/browser/modules/excel/worksheet.js +21 -2
  43. package/dist/browser/modules/excel/xlsx/rel-type.d.ts +15 -0
  44. package/dist/browser/modules/excel/xlsx/rel-type.js +16 -1
  45. package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
  46. package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
  47. package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
  48. package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
  49. package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
  50. package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
  51. package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
  52. package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
  53. package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
  54. package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
  55. package/dist/browser/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
  56. package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
  57. package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
  58. package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
  59. package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
  60. package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
  61. package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
  62. package/dist/browser/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
  63. package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
  64. package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
  65. package/dist/browser/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
  66. package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
  67. package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
  68. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
  69. package/dist/browser/modules/excel/xlsx/xform/style/border-xform.js +4 -1
  70. package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
  71. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +410 -20
  72. package/dist/browser/modules/excel/xlsx/xlsx.d.ts +7 -4
  73. package/dist/browser/modules/excel/xlsx/xlsx.js +4 -5
  74. package/dist/browser/modules/formula/compile/address-utils.d.ts +62 -0
  75. package/dist/browser/modules/formula/compile/address-utils.js +83 -0
  76. package/dist/browser/modules/formula/compile/binder.d.ts +42 -0
  77. package/dist/browser/modules/formula/compile/binder.js +487 -0
  78. package/dist/browser/modules/formula/compile/bound-ast.d.ts +230 -0
  79. package/dist/browser/modules/formula/compile/bound-ast.js +80 -0
  80. package/dist/browser/modules/formula/compile/compiled-formula.d.ts +137 -0
  81. package/dist/browser/modules/formula/compile/compiled-formula.js +383 -0
  82. package/dist/browser/modules/formula/compile/dependency-analysis.d.ts +93 -0
  83. package/dist/browser/modules/formula/compile/dependency-analysis.js +432 -0
  84. package/dist/browser/modules/formula/compile/structured-ref-utils.d.ts +93 -0
  85. package/dist/browser/modules/formula/compile/structured-ref-utils.js +136 -0
  86. package/dist/browser/modules/formula/default-syntax-probe.d.ts +79 -0
  87. package/dist/browser/modules/formula/default-syntax-probe.js +83 -0
  88. package/dist/browser/modules/formula/functions/_date-context.d.ts +4 -0
  89. package/dist/browser/modules/formula/functions/_date-context.js +29 -0
  90. package/dist/browser/modules/formula/functions/_shared.d.ts +121 -0
  91. package/dist/browser/modules/formula/functions/_shared.js +381 -0
  92. package/dist/browser/modules/formula/functions/conditional.d.ts +27 -0
  93. package/dist/browser/modules/formula/functions/conditional.js +343 -0
  94. package/dist/browser/modules/formula/functions/database.d.ts +37 -0
  95. package/dist/browser/modules/formula/functions/database.js +274 -0
  96. package/dist/browser/modules/formula/functions/date.d.ts +61 -0
  97. package/dist/browser/modules/formula/functions/date.js +855 -0
  98. package/dist/browser/modules/formula/functions/dynamic-array.d.ts +23 -0
  99. package/dist/browser/modules/formula/functions/dynamic-array.js +860 -0
  100. package/dist/browser/modules/formula/functions/engineering.d.ts +57 -0
  101. package/dist/browser/modules/formula/functions/engineering.js +1128 -0
  102. package/dist/browser/modules/formula/functions/financial.d.ts +202 -0
  103. package/dist/browser/modules/formula/functions/financial.js +2296 -0
  104. package/dist/browser/modules/formula/functions/lookup.d.ts +18 -0
  105. package/dist/browser/modules/formula/functions/lookup.js +886 -0
  106. package/dist/browser/modules/formula/functions/math.d.ts +114 -0
  107. package/dist/browser/modules/formula/functions/math.js +1406 -0
  108. package/dist/browser/modules/formula/functions/statistical.d.ts +193 -0
  109. package/dist/browser/modules/formula/functions/statistical.js +3390 -0
  110. package/dist/browser/modules/formula/functions/text.d.ts +86 -0
  111. package/dist/browser/modules/formula/functions/text.js +1845 -0
  112. package/dist/browser/modules/formula/host-registry.d.ts +53 -0
  113. package/dist/browser/modules/formula/host-registry.js +69 -0
  114. package/dist/browser/modules/formula/index.d.ts +39 -0
  115. package/dist/browser/modules/formula/index.js +49 -0
  116. package/dist/browser/modules/formula/install.d.ts +62 -0
  117. package/dist/browser/modules/formula/install.js +88 -0
  118. package/dist/browser/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
  119. package/dist/browser/modules/formula/integration/apply-writeback-plan.js +210 -0
  120. package/dist/browser/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
  121. package/dist/browser/modules/formula/integration/calculate-formulas-impl.js +616 -0
  122. package/dist/browser/modules/formula/integration/calculate-formulas.d.ts +67 -0
  123. package/dist/browser/modules/formula/integration/calculate-formulas.js +68 -0
  124. package/dist/browser/modules/formula/integration/formula-instance.d.ts +64 -0
  125. package/dist/browser/modules/formula/integration/formula-instance.js +79 -0
  126. package/dist/browser/modules/formula/integration/workbook-adapter.d.ts +26 -0
  127. package/dist/browser/modules/formula/integration/workbook-adapter.js +324 -0
  128. package/dist/browser/modules/formula/integration/workbook-snapshot.d.ts +267 -0
  129. package/dist/browser/modules/formula/integration/workbook-snapshot.js +77 -0
  130. package/dist/browser/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
  131. package/dist/browser/modules/formula/materialize/build-writeback-plan.js +473 -0
  132. package/dist/browser/modules/formula/materialize/spill-engine.d.ts +9 -0
  133. package/dist/browser/modules/formula/materialize/spill-engine.js +38 -0
  134. package/dist/browser/modules/formula/materialize/types.d.ts +179 -0
  135. package/dist/browser/modules/formula/materialize/types.js +29 -0
  136. package/dist/browser/modules/formula/materialize/writeback-plan.d.ts +167 -0
  137. package/dist/browser/modules/formula/materialize/writeback-plan.js +27 -0
  138. package/dist/browser/modules/formula/runtime/evaluator.d.ts +151 -0
  139. package/dist/browser/modules/formula/runtime/evaluator.js +2291 -0
  140. package/dist/browser/modules/formula/runtime/function-registry.d.ts +47 -0
  141. package/dist/browser/modules/formula/runtime/function-registry.js +840 -0
  142. package/dist/browser/modules/formula/runtime/values.d.ts +211 -0
  143. package/dist/browser/modules/formula/runtime/values.js +385 -0
  144. package/dist/browser/modules/formula/syntax/ast.d.ts +129 -0
  145. package/dist/browser/modules/formula/syntax/ast.js +28 -0
  146. package/dist/browser/modules/formula/syntax/parser.d.ts +18 -0
  147. package/dist/browser/modules/formula/syntax/parser.js +439 -0
  148. package/dist/browser/modules/formula/syntax/token-types.d.ts +153 -0
  149. package/dist/browser/modules/formula/syntax/token-types.js +59 -0
  150. package/dist/browser/modules/formula/syntax/tokenizer.d.ts +10 -0
  151. package/dist/browser/modules/formula/syntax/tokenizer.js +1074 -0
  152. package/dist/browser/modules/pdf/excel-bridge.js +9 -0
  153. package/dist/cjs/index.js +4 -0
  154. package/dist/cjs/modules/excel/cell.js +170 -22
  155. package/dist/cjs/modules/excel/defined-names.js +411 -21
  156. package/dist/cjs/modules/excel/image.js +24 -1
  157. package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +14 -0
  158. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +48 -1
  159. package/dist/cjs/modules/excel/stream/worksheet-reader.js +17 -1
  160. package/dist/cjs/modules/excel/stream/worksheet-writer.js +45 -5
  161. package/dist/cjs/modules/excel/table.js +15 -2
  162. package/dist/cjs/modules/excel/utils/col-cache.js +15 -0
  163. package/dist/cjs/modules/excel/utils/drawing-utils.js +4 -0
  164. package/dist/cjs/modules/excel/utils/external-link-formula.js +212 -0
  165. package/dist/cjs/modules/excel/utils/iterate-stream.js +3 -1
  166. package/dist/cjs/modules/excel/utils/ooxml-paths.js +42 -2
  167. package/dist/cjs/modules/excel/utils/shared-strings.js +21 -2
  168. package/dist/cjs/modules/excel/utils/workbook-protection.js +33 -0
  169. package/dist/cjs/modules/excel/workbook.browser.js +318 -34
  170. package/dist/cjs/modules/excel/worksheet.js +20 -1
  171. package/dist/cjs/modules/excel/xlsx/rel-type.js +16 -1
  172. package/dist/cjs/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
  173. package/dist/cjs/modules/excel/xlsx/xform/book/external-link-xform.js +333 -0
  174. package/dist/cjs/modules/excel/xlsx/xform/book/external-reference-xform.js +27 -0
  175. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
  176. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-protection-xform.js +69 -0
  177. package/dist/cjs/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
  178. package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +18 -0
  179. package/dist/cjs/modules/excel/xlsx/xform/core/metadata-xform.js +161 -0
  180. package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +108 -0
  181. package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
  182. package/dist/cjs/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
  183. package/dist/cjs/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
  184. package/dist/cjs/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
  185. package/dist/cjs/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +83 -0
  186. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
  187. package/dist/cjs/modules/excel/xlsx/xform/style/border-xform.js +4 -1
  188. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +408 -18
  189. package/dist/cjs/modules/excel/xlsx/xlsx.js +4 -5
  190. package/dist/cjs/modules/formula/compile/address-utils.js +89 -0
  191. package/dist/cjs/modules/formula/compile/binder.js +489 -0
  192. package/dist/cjs/modules/formula/compile/bound-ast.js +68 -0
  193. package/dist/cjs/modules/formula/compile/compiled-formula.js +387 -0
  194. package/dist/cjs/modules/formula/compile/dependency-analysis.js +437 -0
  195. package/dist/cjs/modules/formula/compile/structured-ref-utils.js +141 -0
  196. package/dist/cjs/modules/formula/default-syntax-probe.js +87 -0
  197. package/dist/cjs/modules/formula/functions/_date-context.js +33 -0
  198. package/dist/cjs/modules/formula/functions/_shared.js +396 -0
  199. package/dist/cjs/modules/formula/functions/conditional.js +354 -0
  200. package/dist/cjs/modules/formula/functions/database.js +288 -0
  201. package/dist/cjs/modules/formula/functions/date.js +883 -0
  202. package/dist/cjs/modules/formula/functions/dynamic-array.js +881 -0
  203. package/dist/cjs/modules/formula/functions/engineering.js +1183 -0
  204. package/dist/cjs/modules/formula/functions/financial.js +2348 -0
  205. package/dist/cjs/modules/formula/functions/lookup.js +902 -0
  206. package/dist/cjs/modules/formula/functions/math.js +1487 -0
  207. package/dist/cjs/modules/formula/functions/statistical.js +3488 -0
  208. package/dist/cjs/modules/formula/functions/text.js +1889 -0
  209. package/dist/cjs/modules/formula/host-registry.js +75 -0
  210. package/dist/cjs/modules/formula/index.js +58 -0
  211. package/dist/cjs/modules/formula/install.js +93 -0
  212. package/dist/cjs/modules/formula/integration/apply-writeback-plan.js +213 -0
  213. package/dist/cjs/modules/formula/integration/calculate-formulas-impl.js +619 -0
  214. package/dist/cjs/modules/formula/integration/calculate-formulas.js +71 -0
  215. package/dist/cjs/modules/formula/integration/formula-instance.js +82 -0
  216. package/dist/cjs/modules/formula/integration/workbook-adapter.js +327 -0
  217. package/dist/cjs/modules/formula/integration/workbook-snapshot.js +84 -0
  218. package/dist/cjs/modules/formula/materialize/build-writeback-plan.js +475 -0
  219. package/dist/cjs/modules/formula/materialize/spill-engine.js +42 -0
  220. package/dist/cjs/modules/formula/materialize/types.js +32 -0
  221. package/dist/cjs/modules/formula/materialize/writeback-plan.js +28 -0
  222. package/dist/cjs/modules/formula/runtime/evaluator.js +2298 -0
  223. package/dist/cjs/modules/formula/runtime/function-registry.js +846 -0
  224. package/dist/cjs/modules/formula/runtime/values.js +385 -0
  225. package/dist/cjs/modules/formula/syntax/ast.js +8 -0
  226. package/dist/cjs/modules/formula/syntax/parser.js +440 -0
  227. package/dist/cjs/modules/formula/syntax/token-types.js +32 -0
  228. package/dist/cjs/modules/formula/syntax/tokenizer.js +1076 -0
  229. package/dist/cjs/modules/pdf/excel-bridge.js +9 -0
  230. package/dist/esm/index.browser.js +4 -0
  231. package/dist/esm/index.js +4 -0
  232. package/dist/esm/modules/excel/cell.js +170 -22
  233. package/dist/esm/modules/excel/defined-names.js +411 -21
  234. package/dist/esm/modules/excel/image.js +24 -1
  235. package/dist/esm/modules/excel/stream/workbook-reader.browser.js +14 -0
  236. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +48 -1
  237. package/dist/esm/modules/excel/stream/worksheet-reader.js +17 -1
  238. package/dist/esm/modules/excel/stream/worksheet-writer.js +45 -5
  239. package/dist/esm/modules/excel/table.js +15 -2
  240. package/dist/esm/modules/excel/utils/col-cache.js +15 -0
  241. package/dist/esm/modules/excel/utils/drawing-utils.js +4 -0
  242. package/dist/esm/modules/excel/utils/external-link-formula.js +208 -0
  243. package/dist/esm/modules/excel/utils/iterate-stream.js +3 -1
  244. package/dist/esm/modules/excel/utils/ooxml-paths.js +37 -2
  245. package/dist/esm/modules/excel/utils/shared-strings.js +21 -2
  246. package/dist/esm/modules/excel/utils/workbook-protection.js +30 -0
  247. package/dist/esm/modules/excel/workbook.browser.js +318 -34
  248. package/dist/esm/modules/excel/worksheet.js +21 -2
  249. package/dist/esm/modules/excel/xlsx/rel-type.js +16 -1
  250. package/dist/esm/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
  251. package/dist/esm/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
  252. package/dist/esm/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
  253. package/dist/esm/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
  254. package/dist/esm/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
  255. package/dist/esm/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
  256. package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
  257. package/dist/esm/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
  258. package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
  259. package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
  260. package/dist/esm/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
  261. package/dist/esm/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
  262. package/dist/esm/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
  263. package/dist/esm/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
  264. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
  265. package/dist/esm/modules/excel/xlsx/xform/style/border-xform.js +4 -1
  266. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +410 -20
  267. package/dist/esm/modules/excel/xlsx/xlsx.js +4 -5
  268. package/dist/esm/modules/formula/compile/address-utils.js +83 -0
  269. package/dist/esm/modules/formula/compile/binder.js +487 -0
  270. package/dist/esm/modules/formula/compile/bound-ast.js +80 -0
  271. package/dist/esm/modules/formula/compile/compiled-formula.js +383 -0
  272. package/dist/esm/modules/formula/compile/dependency-analysis.js +432 -0
  273. package/dist/esm/modules/formula/compile/structured-ref-utils.js +136 -0
  274. package/dist/esm/modules/formula/default-syntax-probe.js +83 -0
  275. package/dist/esm/modules/formula/functions/_date-context.js +29 -0
  276. package/dist/esm/modules/formula/functions/_shared.js +381 -0
  277. package/dist/esm/modules/formula/functions/conditional.js +343 -0
  278. package/dist/esm/modules/formula/functions/database.js +274 -0
  279. package/dist/esm/modules/formula/functions/date.js +855 -0
  280. package/dist/esm/modules/formula/functions/dynamic-array.js +860 -0
  281. package/dist/esm/modules/formula/functions/engineering.js +1128 -0
  282. package/dist/esm/modules/formula/functions/financial.js +2296 -0
  283. package/dist/esm/modules/formula/functions/lookup.js +886 -0
  284. package/dist/esm/modules/formula/functions/math.js +1406 -0
  285. package/dist/esm/modules/formula/functions/statistical.js +3390 -0
  286. package/dist/esm/modules/formula/functions/text.js +1845 -0
  287. package/dist/esm/modules/formula/host-registry.js +69 -0
  288. package/dist/esm/modules/formula/index.js +49 -0
  289. package/dist/esm/modules/formula/install.js +88 -0
  290. package/dist/esm/modules/formula/integration/apply-writeback-plan.js +210 -0
  291. package/dist/esm/modules/formula/integration/calculate-formulas-impl.js +616 -0
  292. package/dist/esm/modules/formula/integration/calculate-formulas.js +68 -0
  293. package/dist/esm/modules/formula/integration/formula-instance.js +79 -0
  294. package/dist/esm/modules/formula/integration/workbook-adapter.js +324 -0
  295. package/dist/esm/modules/formula/integration/workbook-snapshot.js +77 -0
  296. package/dist/esm/modules/formula/materialize/build-writeback-plan.js +473 -0
  297. package/dist/esm/modules/formula/materialize/spill-engine.js +38 -0
  298. package/dist/esm/modules/formula/materialize/types.js +29 -0
  299. package/dist/esm/modules/formula/materialize/writeback-plan.js +27 -0
  300. package/dist/esm/modules/formula/runtime/evaluator.js +2291 -0
  301. package/dist/esm/modules/formula/runtime/function-registry.js +840 -0
  302. package/dist/esm/modules/formula/runtime/values.js +385 -0
  303. package/dist/esm/modules/formula/syntax/ast.js +28 -0
  304. package/dist/esm/modules/formula/syntax/parser.js +439 -0
  305. package/dist/esm/modules/formula/syntax/token-types.js +59 -0
  306. package/dist/esm/modules/formula/syntax/tokenizer.js +1074 -0
  307. package/dist/esm/modules/pdf/excel-bridge.js +9 -0
  308. package/dist/iife/excelts.iife.js +2302 -373
  309. package/dist/iife/excelts.iife.js.map +1 -1
  310. package/dist/iife/excelts.iife.min.js +34 -34
  311. package/dist/types/index.browser.d.ts +1 -1
  312. package/dist/types/index.d.ts +1 -1
  313. package/dist/types/modules/excel/cell.d.ts +17 -3
  314. package/dist/types/modules/excel/defined-names.d.ts +96 -1
  315. package/dist/types/modules/excel/image.d.ts +11 -0
  316. package/dist/types/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
  317. package/dist/types/modules/excel/stream/workbook-reader.d.ts +2 -1
  318. package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
  319. package/dist/types/modules/excel/stream/workbook-writer.d.ts +3 -2
  320. package/dist/types/modules/excel/stream/worksheet-writer.d.ts +39 -6
  321. package/dist/types/modules/excel/types.d.ts +133 -2
  322. package/dist/types/modules/excel/utils/col-cache.d.ts +1 -0
  323. package/dist/types/modules/excel/utils/drawing-utils.d.ts +3 -3
  324. package/dist/types/modules/excel/utils/external-link-formula.d.ts +76 -0
  325. package/dist/types/modules/excel/utils/iterate-stream.d.ts +9 -3
  326. package/dist/types/modules/excel/utils/ooxml-paths.d.ts +19 -0
  327. package/dist/types/modules/excel/utils/shared-strings.d.ts +8 -3
  328. package/dist/types/modules/excel/utils/workbook-protection.d.ts +30 -0
  329. package/dist/types/modules/excel/workbook.browser.d.ts +257 -6
  330. package/dist/types/modules/excel/workbook.d.ts +1 -1
  331. package/dist/types/modules/excel/worksheet.d.ts +3 -1
  332. package/dist/types/modules/excel/xlsx/rel-type.d.ts +15 -0
  333. package/dist/types/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
  334. package/dist/types/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
  335. package/dist/types/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
  336. package/dist/types/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
  337. package/dist/types/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
  338. package/dist/types/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
  339. package/dist/types/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
  340. package/dist/types/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
  341. package/dist/types/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
  342. package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
  343. package/dist/types/modules/excel/xlsx/xlsx.d.ts +7 -4
  344. package/dist/types/modules/formula/compile/address-utils.d.ts +62 -0
  345. package/dist/types/modules/formula/compile/binder.d.ts +42 -0
  346. package/dist/types/modules/formula/compile/bound-ast.d.ts +230 -0
  347. package/dist/types/modules/formula/compile/compiled-formula.d.ts +137 -0
  348. package/dist/types/modules/formula/compile/dependency-analysis.d.ts +93 -0
  349. package/dist/types/modules/formula/compile/structured-ref-utils.d.ts +93 -0
  350. package/dist/types/modules/formula/default-syntax-probe.d.ts +79 -0
  351. package/dist/types/modules/formula/functions/_date-context.d.ts +4 -0
  352. package/dist/types/modules/formula/functions/_shared.d.ts +121 -0
  353. package/dist/types/modules/formula/functions/conditional.d.ts +27 -0
  354. package/dist/types/modules/formula/functions/database.d.ts +37 -0
  355. package/dist/types/modules/formula/functions/date.d.ts +61 -0
  356. package/dist/types/modules/formula/functions/dynamic-array.d.ts +23 -0
  357. package/dist/types/modules/formula/functions/engineering.d.ts +57 -0
  358. package/dist/types/modules/formula/functions/financial.d.ts +202 -0
  359. package/dist/types/modules/formula/functions/lookup.d.ts +18 -0
  360. package/dist/types/modules/formula/functions/math.d.ts +114 -0
  361. package/dist/types/modules/formula/functions/statistical.d.ts +193 -0
  362. package/dist/types/modules/formula/functions/text.d.ts +86 -0
  363. package/dist/types/modules/formula/host-registry.d.ts +53 -0
  364. package/dist/types/modules/formula/index.d.ts +39 -0
  365. package/dist/types/modules/formula/install.d.ts +62 -0
  366. package/dist/types/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
  367. package/dist/types/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
  368. package/dist/types/modules/formula/integration/calculate-formulas.d.ts +67 -0
  369. package/dist/types/modules/formula/integration/formula-instance.d.ts +64 -0
  370. package/dist/types/modules/formula/integration/workbook-adapter.d.ts +26 -0
  371. package/dist/types/modules/formula/integration/workbook-snapshot.d.ts +267 -0
  372. package/dist/types/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
  373. package/dist/types/modules/formula/materialize/spill-engine.d.ts +9 -0
  374. package/dist/types/modules/formula/materialize/types.d.ts +179 -0
  375. package/dist/types/modules/formula/materialize/writeback-plan.d.ts +167 -0
  376. package/dist/types/modules/formula/runtime/evaluator.d.ts +151 -0
  377. package/dist/types/modules/formula/runtime/function-registry.d.ts +47 -0
  378. package/dist/types/modules/formula/runtime/values.d.ts +211 -0
  379. package/dist/types/modules/formula/syntax/ast.d.ts +129 -0
  380. package/dist/types/modules/formula/syntax/parser.d.ts +18 -0
  381. package/dist/types/modules/formula/syntax/token-types.d.ts +153 -0
  382. package/dist/types/modules/formula/syntax/tokenizer.d.ts +10 -0
  383. package/package.json +28 -28
@@ -0,0 +1,30 @@
1
+ import { Encryptor } from "./encryptor.js";
2
+ import { uint8ArrayToBase64 } from "../../../utils/utils.js";
3
+ /**
4
+ * Build a workbook-protection object with optional password hashing.
5
+ *
6
+ * This is the shared implementation used by both `Workbook.protect()` and
7
+ * `WorkbookWriter.protect()`. The caller is responsible for assigning the
8
+ * result to its own `protection` field.
9
+ *
10
+ * @param password - Optional password to hash
11
+ * @param options - Optional protection flags (lockStructure, lockWindows, lockRevision, spinCount)
12
+ * @returns A fully-populated workbook-protection object
13
+ */
14
+ export async function buildWorkbookProtection(password, options) {
15
+ const protection = {
16
+ lockStructure: options?.lockStructure ?? true,
17
+ lockWindows: options?.lockWindows,
18
+ lockRevision: options?.lockRevision
19
+ };
20
+ if (password) {
21
+ protection.algorithmName = "SHA-512";
22
+ protection.saltValue = uint8ArrayToBase64(Encryptor.randomBytes(16));
23
+ protection.spinCount =
24
+ options?.spinCount != null && Number.isFinite(options.spinCount)
25
+ ? Math.round(Math.max(0, options.spinCount))
26
+ : 100000;
27
+ protection.hashValue = await Encryptor.convertPasswordToHash(password, "SHA-512", protection.saltValue, protection.spinCount);
28
+ }
29
+ return protection;
30
+ }
@@ -17,8 +17,10 @@ import { DefinedNames } from "./defined-names.js";
17
17
  import { ExcelDownloadError, ExcelNotSupportedError } from "./errors.js";
18
18
  import { WorkbookReader } from "./stream/workbook-reader.js";
19
19
  import { WorkbookWriter } from "./stream/workbook-writer.js";
20
+ import { buildWorkbookProtection } from "./utils/workbook-protection.js";
20
21
  import { Worksheet } from "./worksheet.js";
21
22
  import { XLSX } from "./xlsx/xlsx.js";
23
+ import { invokeFormulaEngine } from "../formula/host-registry.js";
22
24
  import { formatMarkdown } from "../markdown/format/index.js";
23
25
  import { parseMarkdown, parseMarkdownAll } from "../markdown/parse/index.js";
24
26
  import { pipeline } from "../stream/index.js";
@@ -70,48 +72,80 @@ function createDefaultValueMapper(dateFormats, options) {
70
72
  return datumNumber;
71
73
  }
72
74
  }
73
- const date = dateParser.parse(datum);
74
- if (date) {
75
- return date;
76
- }
77
- const special = SpecialValues[datum];
78
- if (special !== undefined) {
79
- return special;
75
+ if (typeof datum === "string") {
76
+ const date = dateParser.parse(datum);
77
+ if (date) {
78
+ return date;
79
+ }
80
+ const special = SpecialValues[datum];
81
+ if (special !== undefined) {
82
+ return special;
83
+ }
80
84
  }
81
85
  return datum;
82
86
  };
83
87
  }
84
88
  /**
85
89
  * Create a value mapper for writing Excel values to CSV format.
86
- * Handles hyperlinks, formulas, rich text, dates, errors, and objects.
90
+ *
91
+ * Branches below correspond to each member of the `CellValue` union, in an
92
+ * order that prefers the most specific shape:
93
+ * 1. Hyperlink — emit the URL (falling back to display text)
94
+ * 2. Formula / SharedFormula / ArrayFormula — emit the evaluated `result`
95
+ * 3. RichText — flatten runs to plain text
96
+ * 4. Checkbox — emit the boolean state
97
+ * 5. Error — emit the Excel error token (e.g. "#N/A")
98
+ * 6. Date — format via the configured DateFormatter
99
+ * 7. Primitive — pass through (`string | number | boolean | null | undefined`)
100
+ *
101
+ * An object that does not match any of the above is stringified as JSON so
102
+ * the CSV remains round-trippable rather than producing `[object Object]`.
87
103
  */
88
104
  function createDefaultWriteMapper(dateFormat, dateUTC) {
89
105
  const formatter = dateFormat
90
106
  ? DateFormatter.create(dateFormat, { utc: dateUTC })
91
107
  : DateFormatter.iso(dateUTC);
92
108
  return function mapValue(value) {
93
- if (value) {
94
- if (value.text || value.hyperlink) {
95
- return value.hyperlink || value.text || "";
96
- }
97
- if (value.formula || value.result) {
98
- return value.result || "";
99
- }
100
- // Handle rich text - extract and concatenate all text fragments
101
- if (value.richText && Array.isArray(value.richText)) {
102
- return value.richText.map((r) => r.text).join("");
103
- }
104
- if (value instanceof Date) {
105
- return formatter.format(value);
106
- }
107
- if (value.error) {
108
- return value.error;
109
- }
110
- if (typeof value === "object") {
111
- return JSON.stringify(value);
112
- }
109
+ if (value === null || value === undefined) {
110
+ return value;
111
+ }
112
+ if (value instanceof Date) {
113
+ return formatter.format(value);
114
+ }
115
+ if (typeof value !== "object") {
116
+ // string | number | boolean
117
+ return value;
118
+ }
119
+ // --- Object variants of CellValue ---
120
+ // Hyperlink: prefer URL, fall back to display text.
121
+ // Accepts objects carrying either `hyperlink` or just `text` — the latter
122
+ // is a historical input shape some callers use to denote a "link-like"
123
+ // cell value without an actual URL; preserving it maintains backward
124
+ // compatibility with pre-existing CSV output.
125
+ const maybeLink = value;
126
+ if (typeof maybeLink.hyperlink === "string" || typeof maybeLink.text === "string") {
127
+ const url = typeof maybeLink.hyperlink === "string" ? maybeLink.hyperlink : "";
128
+ const text = typeof maybeLink.text === "string" ? maybeLink.text : "";
129
+ return url || text || "";
130
+ }
131
+ // Formula / SharedFormula / ArrayFormula — all carry an evaluated `result`
132
+ if ("formula" in value || "sharedFormula" in value) {
133
+ return value.result ?? "";
134
+ }
135
+ // Rich text — flatten runs
136
+ if ("richText" in value && Array.isArray(value.richText)) {
137
+ return value.richText.map(r => r.text).join("");
138
+ }
139
+ // Checkbox
140
+ if ("checkbox" in value && typeof value.checkbox === "boolean") {
141
+ return value.checkbox;
113
142
  }
114
- return value;
143
+ // Error
144
+ if ("error" in value && typeof value.error === "string") {
145
+ return value.error;
146
+ }
147
+ // Unknown object shape — round-trippable fallback
148
+ return JSON.stringify(value);
115
149
  };
116
150
  }
117
151
  // =============================================================================
@@ -238,7 +272,18 @@ class Workbook {
238
272
  // ===========================================================================
239
273
  // Constructor
240
274
  // ===========================================================================
241
- constructor() {
275
+ /**
276
+ * @param options Optional construction options.
277
+ * - `formulaSyntaxProbe`: An explicit tokenizer+parser probe used to
278
+ * classify defined-name text during XLSX load. Providing this makes
279
+ * classification deterministic for *this* workbook regardless of
280
+ * whether `installFormulaEngine()` has been called. Most callers
281
+ * don't need it — `installFormulaEngine()` registers a
282
+ * process-wide default probe that is picked up automatically.
283
+ */
284
+ constructor(options) {
285
+ /** Global registry of table names (lowercase) for cross-worksheet uniqueness checks. */
286
+ this._tableNames = new Set();
242
287
  this.category = "";
243
288
  this.company = "";
244
289
  this.created = new Date();
@@ -254,9 +299,33 @@ class Workbook {
254
299
  this.views = [];
255
300
  this.media = [];
256
301
  this.pivotTables = [];
302
+ this.externalLinks = [];
257
303
  this._passthrough = {};
258
304
  this._rawDrawings = {};
259
- this._definedNames = new DefinedNames();
305
+ this._writerExternalLinkCache = new Map();
306
+ this._definedNames = new DefinedNames(options?.formulaSyntaxProbe);
307
+ }
308
+ // ===========================================================================
309
+ // Default Font
310
+ // ===========================================================================
311
+ /**
312
+ * The default font for the workbook (fontId=0 / "Normal" style).
313
+ * Cells without explicit font styles will inherit this font in Excel.
314
+ *
315
+ * @example
316
+ * ```ts
317
+ * wb.defaultFont = { name: "Arial", size: 12 };
318
+ * ```
319
+ *
320
+ * When reading an existing XLSX file, this preserves the original default font
321
+ * for round-trip fidelity. Setting it on a new workbook changes the default
322
+ * from Calibri 11 to your chosen font.
323
+ */
324
+ get defaultFont() {
325
+ return this._defaultFont;
326
+ }
327
+ set defaultFont(font) {
328
+ this._defaultFont = font;
260
329
  }
261
330
  // ===========================================================================
262
331
  // Sheet Import
@@ -285,6 +354,25 @@ class Workbook {
285
354
  return newWs;
286
355
  }
287
356
  // ===========================================================================
357
+ // Workbook Protection
358
+ // ===========================================================================
359
+ /**
360
+ * Protect the workbook structure with an optional password.
361
+ * Prevents users from adding, deleting, renaming, moving, or copying worksheets.
362
+ *
363
+ * @param password - Optional password to protect the structure
364
+ * @param options - Optional protection flags (lockStructure, lockWindows, lockRevision)
365
+ */
366
+ async protect(password, options) {
367
+ this.protection = await buildWorkbookProtection(password, options);
368
+ }
369
+ /**
370
+ * Remove workbook structure protection.
371
+ */
372
+ unprotect() {
373
+ this.protection = undefined;
374
+ }
375
+ // ===========================================================================
288
376
  // Format Operations (xlsx)
289
377
  // ===========================================================================
290
378
  /**
@@ -431,7 +519,10 @@ class Workbook {
431
519
  });
432
520
  }
433
521
  parser.on("data", (row) => {
434
- // When headers: true, CsvParserStream emits objects; otherwise arrays
522
+ // When headers: true, CsvParserStream emits objects; otherwise arrays.
523
+ // The CSV parser only ever emits primitive CellValue-compatible shapes
524
+ // (string/number/boolean/Date/null). Narrow once here so the rest of
525
+ // the pipeline — including the user-supplied `map` — sees CellValue.
435
526
  if (useHeaders && headerRow && row && typeof row === "object" && !Array.isArray(row)) {
436
527
  // Convert object row to array using header order
437
528
  const rowObj = row;
@@ -498,7 +589,8 @@ class Workbook {
498
589
  });
499
590
  }
500
591
  parser.on("data", (row) => {
501
- // When headers: true, CsvParserStream emits objects; otherwise arrays
592
+ // When headers: true, CsvParserStream emits objects; otherwise arrays.
593
+ // See createCsvReadStream for the rationale on narrowing to CellValue.
502
594
  if (useHeaders && headerRow && row && typeof row === "object" && !Array.isArray(row)) {
503
595
  // Convert object row to array using header order
504
596
  const rowObj = row;
@@ -925,6 +1017,50 @@ class Workbook {
925
1017
  return this._definedNames;
926
1018
  }
927
1019
  // ===========================================================================
1020
+ // Formula Calculation
1021
+ // ===========================================================================
1022
+ /**
1023
+ * Recalculate all formula cells in this workbook.
1024
+ *
1025
+ * Evaluates every formula cell using the built-in calculation engine and updates
1026
+ * each cell's cached `result` value in-place. Formulas are evaluated with
1027
+ * recursive dependency resolution, memoization, and circular reference detection.
1028
+ *
1029
+ * Call this after programmatically modifying cell values that are referenced by
1030
+ * formulas, to ensure formula results reflect the latest data.
1031
+ *
1032
+ * Unsupported functions preserve their original cached result if one exists.
1033
+ *
1034
+ * ## Tree-shaking note
1035
+ *
1036
+ * The formula engine ships ~200KB of code (433 Excel functions, parser,
1037
+ * evaluator, dependency graph, spill materialiser). To keep it out of
1038
+ * bundles that don't need it, the engine is registered at runtime
1039
+ * rather than imported by the core `Workbook` module. Call
1040
+ * {@link installFormulaEngine} once at startup before the first call
1041
+ * to this method, or a clear error will be thrown explaining what to do.
1042
+ *
1043
+ * ```ts
1044
+ * import { installFormulaEngine } from "@cj-tech-master/excelts/formula";
1045
+ *
1046
+ * installFormulaEngine(); // once, at startup
1047
+ *
1048
+ * sheet.getCell("A1").value = 100;
1049
+ * workbook.calculateFormulas(); // now works
1050
+ * ```
1051
+ *
1052
+ * Callers who prefer a zero-side-effect, tree-shakeable surface can
1053
+ * use the functional equivalent directly:
1054
+ *
1055
+ * ```ts
1056
+ * import { calculateFormulas } from "@cj-tech-master/excelts/formula";
1057
+ * calculateFormulas(workbook);
1058
+ * ```
1059
+ */
1060
+ calculateFormulas() {
1061
+ invokeFormulaEngine(this);
1062
+ }
1063
+ // ===========================================================================
928
1064
  // Themes
929
1065
  // ===========================================================================
930
1066
  clearThemes() {
@@ -946,6 +1082,145 @@ class Workbook {
946
1082
  return this.media[Number(id)];
947
1083
  }
948
1084
  // ===========================================================================
1085
+ // External Workbook Links
1086
+ // ===========================================================================
1087
+ /**
1088
+ * Declare that formulas in this workbook may reference an external
1089
+ * workbook. Registers the target so the output file contains the required
1090
+ * `xl/externalLinks/externalLink{N}.xml` part plus its `.rels` sibling
1091
+ * and Office/WPS can resolve the reference correctly.
1092
+ *
1093
+ * When Office opens the file, it resolves a relative `target` like
1094
+ * `"测试.xlsx"` **relative to the current workbook's directory** — which
1095
+ * is the exact behaviour the user expects when they write
1096
+ * `=[测试.xlsx]Sheet1!A1`. Absolute `file:///…` or `http(s)://…` URIs
1097
+ * are accepted and written through unchanged.
1098
+ *
1099
+ * @returns the registered {@link ExternalLinkModel}. Its `index` field is
1100
+ * the 1-based number used inside the `[N]` prefix of on-disk formula
1101
+ * strings (the library rewrites `[target]` forms to `[index]` at write
1102
+ * time automatically).
1103
+ *
1104
+ * @example
1105
+ * ```ts
1106
+ * const wb = new Workbook();
1107
+ * const ws = wb.addWorksheet("Main");
1108
+ *
1109
+ * // Declare the link once — sheet names and cached values are optional
1110
+ * // but improve interoperability (Excel displays cached values when the
1111
+ * // external file is unavailable).
1112
+ * wb.addExternalLink({
1113
+ * target: "测试.xlsx",
1114
+ * sheetNames: ["Sheet1"],
1115
+ * cachedValues: { Sheet1: { A1: 42 } }
1116
+ * });
1117
+ *
1118
+ * // Write the formula using either the target name OR the numeric index;
1119
+ * // the library normalises both to the on-disk `[N]` form.
1120
+ * ws.getCell("A1").value = { formula: "=[测试.xlsx]Sheet1!A1", result: 42 };
1121
+ * ```
1122
+ */
1123
+ addExternalLink(input) {
1124
+ const link = {
1125
+ index: this.externalLinks.length + 1,
1126
+ target: input.target,
1127
+ targetMode: input.targetMode ?? "External",
1128
+ sheetNames: input.sheetNames ? [...input.sheetNames] : [],
1129
+ cachedValues: input.cachedValues ? { ...input.cachedValues } : {}
1130
+ };
1131
+ this.externalLinks.push(link);
1132
+ return link;
1133
+ }
1134
+ /**
1135
+ * Retrieve an external link by its 1-based on-disk index (the number
1136
+ * inside the `[N]` formula prefix) or by matching target path.
1137
+ */
1138
+ getExternalLink(indexOrTarget) {
1139
+ if (typeof indexOrTarget === "number") {
1140
+ return this.externalLinks[indexOrTarget - 1];
1141
+ }
1142
+ const lower = indexOrTarget.toLowerCase();
1143
+ return this.externalLinks.find(link => link.target.toLowerCase() === lower);
1144
+ }
1145
+ /**
1146
+ * @internal — used by the writer to obtain the full list of external
1147
+ * links to serialise, including entries auto-discovered from formula
1148
+ * strings during earlier writes. User-visible `externalLinks` always
1149
+ * comes first (in declaration order) so explicit `addExternalLink()`
1150
+ * indices are stable across writes.
1151
+ */
1152
+ _collectExternalLinksForWrite() {
1153
+ const userLower = new Set(this.externalLinks.map(l => l.target.toLowerCase()));
1154
+ const combined = this.externalLinks.map((link, i) => ({
1155
+ ...link,
1156
+ index: i + 1,
1157
+ sheetNames: [...(link.sheetNames ?? [])],
1158
+ cachedValues: { ...(link.cachedValues ?? {}) },
1159
+ targetMode: link.targetMode ?? "External"
1160
+ }));
1161
+ for (const cached of this._writerExternalLinkCache.values()) {
1162
+ if (userLower.has(cached.target.toLowerCase())) {
1163
+ // User explicitly added a link with the same target after an
1164
+ // auto-discovery pass — prefer the user's definition, drop the
1165
+ // cached one.
1166
+ continue;
1167
+ }
1168
+ combined.push({
1169
+ ...cached,
1170
+ index: combined.length + 1,
1171
+ sheetNames: [...cached.sheetNames],
1172
+ cachedValues: { ...cached.cachedValues }
1173
+ });
1174
+ }
1175
+ return combined;
1176
+ }
1177
+ /**
1178
+ * @internal — record an auto-discovered external link (seen in a
1179
+ * formula but not explicitly declared). Idempotent by target; the
1180
+ * sheet name is upserted onto the existing cached entry when present.
1181
+ * Returns the 1-based index the link will carry in the output file.
1182
+ */
1183
+ _recordAutoExternalLink(target, sheetName) {
1184
+ const lower = target.toLowerCase();
1185
+ // If the user explicitly declared a link with this target, we respect
1186
+ // their definition verbatim: no sheetName upserts, no cache entry.
1187
+ // Excel needs the user-declared sheetNames to match the refs, and
1188
+ // augmenting them on the user's behalf could silently hide a typo.
1189
+ const existingUserIdx = this.externalLinks.findIndex(l => l.target.toLowerCase() === lower);
1190
+ if (existingUserIdx !== -1) {
1191
+ return existingUserIdx + 1;
1192
+ }
1193
+ let cached = this._writerExternalLinkCache.get(lower);
1194
+ if (!cached) {
1195
+ cached = {
1196
+ // Index is provisional — the real on-disk index is recomputed by
1197
+ // `_collectExternalLinksForWrite()` at serialisation time.
1198
+ index: 0,
1199
+ target,
1200
+ targetMode: "External",
1201
+ sheetNames: [],
1202
+ cachedValues: {}
1203
+ };
1204
+ this._writerExternalLinkCache.set(lower, cached);
1205
+ }
1206
+ if (sheetName && !cached.sheetNames.includes(sheetName)) {
1207
+ cached.sheetNames.push(sheetName);
1208
+ }
1209
+ // Recompute final index: user entries first, then cache entries in
1210
+ // insertion order. The caller needs the *on-disk* index so that the
1211
+ // formula it's rewriting matches the link that will be serialised.
1212
+ const userCount = this.externalLinks.length;
1213
+ let cacheIdx = 0;
1214
+ for (const key of this._writerExternalLinkCache.keys()) {
1215
+ cacheIdx++;
1216
+ if (key === lower) {
1217
+ return userCount + cacheIdx;
1218
+ }
1219
+ }
1220
+ // Unreachable — we just inserted.
1221
+ return userCount + this._writerExternalLinkCache.size;
1222
+ }
1223
+ // ===========================================================================
949
1224
  // Model (Serialization)
950
1225
  // ===========================================================================
951
1226
  get model() {
@@ -956,6 +1231,7 @@ class Workbook {
956
1231
  created: this.created,
957
1232
  modified: this.modified,
958
1233
  properties: this.properties,
1234
+ protection: this.protection,
959
1235
  worksheets: this.worksheets.map(worksheet => worksheet.model),
960
1236
  sheets: this.worksheets.map(ws => ws.model).filter(Boolean),
961
1237
  definedNames: this._definedNames.model,
@@ -976,7 +1252,8 @@ class Workbook {
976
1252
  calcProperties: this.calcProperties,
977
1253
  passthrough: this._passthrough,
978
1254
  rawDrawings: this._rawDrawings,
979
- defaultFont: this._defaultFont
1255
+ defaultFont: this._defaultFont,
1256
+ externalLinks: this.externalLinks
980
1257
  };
981
1258
  }
982
1259
  set model(value) {
@@ -996,8 +1273,10 @@ class Workbook {
996
1273
  this.revision = value.revision;
997
1274
  this.contentStatus = value.contentStatus;
998
1275
  this.properties = value.properties;
1276
+ this.protection = value.protection;
999
1277
  this.calcProperties = value.calcProperties;
1000
1278
  this._worksheets = [];
1279
+ this._tableNames.clear();
1001
1280
  value.worksheets.forEach(worksheetModel => {
1002
1281
  const { id, name, state } = worksheetModel;
1003
1282
  const orderNo = value.sheets && value.sheets.findIndex(ws => ws.id === id);
@@ -1023,6 +1302,11 @@ class Workbook {
1023
1302
  this._rawDrawings = value.rawDrawings || {};
1024
1303
  // Preserve default font for round-trip fidelity
1025
1304
  this._defaultFont = value.defaultFont;
1305
+ // Preserve external workbook references (empty array if none)
1306
+ this.externalLinks = value.externalLinks ? [...value.externalLinks] : [];
1307
+ // Reset the writer-scoped auto-discovery cache — loading a fresh
1308
+ // workbook replaces any accumulated state from previous writes.
1309
+ this._writerExternalLinkCache = new Map();
1026
1310
  }
1027
1311
  }
1028
1312
  // ===========================================================================
@@ -1,7 +1,7 @@
1
1
  import { Column } from "./column.js";
2
2
  import { DataValidations } from "./data-validations.js";
3
3
  import { Enums } from "./enums.js";
4
- import { WorksheetNameError, MergeConflictError } from "./errors.js";
4
+ import { WorksheetNameError, MergeConflictError, TableError } from "./errors.js";
5
5
  import { FormCheckbox } from "./form-control.js";
6
6
  import { Image } from "./image.js";
7
7
  import { makePivotTable } from "./pivot-table.js";
@@ -104,6 +104,8 @@ class Worksheet {
104
104
  this.conditionalFormattings = [];
105
105
  // for form controls (legacy checkboxes, etc.)
106
106
  this.formControls = [];
107
+ // ignored errors (suppress green triangles in Excel)
108
+ this.ignoredErrors = [];
107
109
  // watermark configuration
108
110
  this._watermark = null;
109
111
  }
@@ -1107,8 +1109,19 @@ class Worksheet {
1107
1109
  */
1108
1110
  addTable(model) {
1109
1111
  const table = new Table(this, model);
1110
- // Use table.name (sanitized by Table.validate()) as the key
1112
+ // table.name is sanitized by Table.validate() check against the
1113
+ // sanitized name so that e.g. "My Table" and "My_Table" (which both
1114
+ // sanitize to "My_Table") are correctly detected as duplicates.
1115
+ const nameKey = table.name.toLowerCase();
1116
+ if (this.tables[table.name]) {
1117
+ throw new TableError(`Table name "${table.name}" already exists in worksheet "${this.name}".`);
1118
+ }
1119
+ if (this.workbook._tableNames.has(nameKey)) {
1120
+ throw new TableError(`Table name "${table.name}" already exists in another worksheet. ` +
1121
+ `Table names must be unique across the entire workbook (case-insensitive).`);
1122
+ }
1111
1123
  this.tables[table.name] = table;
1124
+ this.workbook._tableNames.add(nameKey);
1112
1125
  return table;
1113
1126
  }
1114
1127
  /**
@@ -1121,6 +1134,9 @@ class Worksheet {
1121
1134
  * Delete table by name
1122
1135
  */
1123
1136
  removeTable(name) {
1137
+ if (this.tables[name]) {
1138
+ this.workbook._tableNames.delete(name.toLowerCase());
1139
+ }
1124
1140
  delete this.tables[name];
1125
1141
  }
1126
1142
  /**
@@ -1368,6 +1384,7 @@ class Worksheet {
1368
1384
  pivotTables: this.pivotTables,
1369
1385
  conditionalFormattings: this.conditionalFormattings,
1370
1386
  formControls: this.formControls.map(fc => fc.model),
1387
+ ignoredErrors: this.ignoredErrors,
1371
1388
  watermark: this._watermark,
1372
1389
  drawing: this._drawing
1373
1390
  };
@@ -1452,10 +1469,12 @@ class Worksheet {
1452
1469
  const t = new Table(this, table);
1453
1470
  t.model = table;
1454
1471
  tables[table.name] = t;
1472
+ this.workbook._tableNames.add(table.name.toLowerCase());
1455
1473
  return tables;
1456
1474
  }, {});
1457
1475
  this.pivotTables = value.pivotTables;
1458
1476
  this.conditionalFormattings = value.conditionalFormattings;
1477
+ this.ignoredErrors = value.ignoredErrors ?? [];
1459
1478
  // Form controls are currently write-only (not parsed from XLSX)
1460
1479
  this.formControls = [];
1461
1480
  // Preserve loaded drawing data (charts, etc.)
@@ -16,6 +16,21 @@ const RelType = {
16
16
  PivotCacheRecords: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotCacheRecords",
17
17
  PivotTable: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/pivotTable",
18
18
  FeaturePropertyBag: "http://schemas.microsoft.com/office/2022/11/relationships/FeaturePropertyBag",
19
- CtrlProp: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp"
19
+ CtrlProp: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/ctrlProp",
20
+ SheetMetadata: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata",
21
+ /**
22
+ * Relationship type for the externalLink part referenced from
23
+ * xl/_rels/workbook.xml.rels. Target is an internal path like
24
+ * `externalLinks/externalLink1.xml`.
25
+ */
26
+ ExternalLink: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",
27
+ /**
28
+ * Relationship type used *inside* xl/externalLinks/_rels/externalLinkN.xml.rels
29
+ * to point at the actual external workbook. When `TargetMode="External"` and
30
+ * `Target` is a bare relative path (e.g. `"测试.xlsx"`), Office resolves it
31
+ * relative to the current workbook's directory — exactly the behaviour users
32
+ * expect from `=[测试.xlsx]Sheet1!A1`.
33
+ */
34
+ ExternalLinkPath: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath"
20
35
  };
21
36
  export { RelType };