@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,855 @@
1
+ /**
2
+ * Date / Time Functions — Native RuntimeValue implementation.
3
+ *
4
+ * All Date objects returned by `excelToDate()` represent an Excel serial on
5
+ * the UTC timeline (midnight UTC for the corresponding date). Consequently
6
+ * every field accessor must be the UTC variant (`getUTCFullYear`,
7
+ * `getUTCMonth`, …) and every `Date` constructed from y/m/d components must
8
+ * be built with `Date.UTC(...)`. Using local-time accessors would make
9
+ * results depend on the host timezone — e.g. `YEAR(DATE(2024,1,1))` would
10
+ * return 2023 when evaluated on a machine west of UTC at midnight UTC.
11
+ *
12
+ * Exceptions (intentionally use local time):
13
+ * - `TODAY` / `NOW` — read the user's wall clock, which is genuinely in the
14
+ * local timezone. The Excel serial is then constructed using
15
+ * `Date.UTC(year, month, day)` so that the resulting serial round-trips
16
+ * correctly through `excelToDate()`.
17
+ */
18
+ import { dateToExcel, excelToDate } from "../../../utils/utils.base.js";
19
+ import { RVKind, ERRORS, isError, isArray, toNumberRV, toStringRV, toBooleanRV, rvNumber, rvBoolean } from "../runtime/values.js";
20
+ import { isDate1904 } from "./_date-context.js";
21
+ import { argToNumber, checkError } from "./_shared.js";
22
+ // ============================================================================
23
+ // Helpers
24
+ // ============================================================================
25
+ /** Convert an Excel serial to a UTC `Date`, honouring the active date1904 mode. */
26
+ function toDate(serial) {
27
+ return excelToDate(serial, isDate1904());
28
+ }
29
+ /** Convert a UTC `Date` back to an Excel serial, honouring the active date1904 mode. */
30
+ function fromDate(d) {
31
+ return dateToExcel(d, isDate1904());
32
+ }
33
+ /** Collect holiday serial numbers from a RuntimeValue argument (array or scalar). */
34
+ function collectHolidays(arg) {
35
+ const set = new Set();
36
+ if (isArray(arg)) {
37
+ for (const row of arg.rows) {
38
+ for (const cell of row) {
39
+ if (cell.kind === RVKind.Number) {
40
+ set.add(Math.floor(cell.value));
41
+ }
42
+ }
43
+ }
44
+ }
45
+ else {
46
+ const n = toNumberRV(arg);
47
+ if (n.kind === RVKind.Number) {
48
+ set.add(Math.floor(n.value));
49
+ }
50
+ }
51
+ return set;
52
+ }
53
+ // ============================================================================
54
+ // Date Functions
55
+ // ============================================================================
56
+ /**
57
+ * TODAY — today's date (at the user's local timezone).
58
+ *
59
+ * The user's concept of "today" is based on their wall clock, so we read
60
+ * local-time fields from `new Date()`. The resulting y/m/d components are
61
+ * then packed into a UTC serial so downstream date arithmetic is consistent.
62
+ */
63
+ export const fnTODAY = () => {
64
+ const now = new Date();
65
+ return rvNumber(fromDate(new Date(Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()))));
66
+ };
67
+ /**
68
+ * NOW — current date and time.
69
+ *
70
+ * Excel stores the result as an untimezoned serial, but the user expects
71
+ * their local wall-clock reading. `dateToExcel(new Date())` effectively
72
+ * takes `Date.now()` in UTC-ms; any conversion to the user's timezone
73
+ * would require tz metadata we do not have. We therefore keep the current
74
+ * UTC-ms based conversion, matching historical behaviour.
75
+ */
76
+ export const fnNOW = () => {
77
+ const now = new Date();
78
+ return rvNumber(fromDate(now));
79
+ };
80
+ export const fnYEAR = args => {
81
+ const n = argToNumber(args[0]);
82
+ if (isError(n)) {
83
+ return n;
84
+ }
85
+ return rvNumber(toDate(n.value).getUTCFullYear());
86
+ };
87
+ export const fnMONTH = args => {
88
+ const n = argToNumber(args[0]);
89
+ if (isError(n)) {
90
+ return n;
91
+ }
92
+ return rvNumber(toDate(n.value).getUTCMonth() + 1);
93
+ };
94
+ export const fnDAY = args => {
95
+ const n = argToNumber(args[0]);
96
+ if (isError(n)) {
97
+ return n;
98
+ }
99
+ return rvNumber(toDate(n.value).getUTCDate());
100
+ };
101
+ export const fnDATE = args => {
102
+ const year = argToNumber(args[0]);
103
+ if (isError(year)) {
104
+ return year;
105
+ }
106
+ const month = argToNumber(args[1]);
107
+ if (isError(month)) {
108
+ return month;
109
+ }
110
+ const day = argToNumber(args[2]);
111
+ if (isError(day)) {
112
+ return day;
113
+ }
114
+ // Excel's DATE interprets a year in [0, 1899] as (year + 1900). JavaScript's
115
+ // Date constructor already applies this convention for [0, 99], but it does
116
+ // NOT apply it for [100, 1899] — we have to do it ourselves. Years below 0
117
+ // or above 9999 are rejected as #NUM! (Excel's documented range).
118
+ let y = Math.trunc(year.value);
119
+ if (y < 0 || y > 9999) {
120
+ return ERRORS.NUM;
121
+ }
122
+ if (y < 1900) {
123
+ y += 1900;
124
+ // Excel rejects years outside [1900, 9999] after this coercion.
125
+ if (y > 9999) {
126
+ return ERRORS.NUM;
127
+ }
128
+ }
129
+ // Lotus 1-2-3 bug: DATE(1900,2,29) should return serial 60 even though
130
+ // 1900 is not a leap year. JavaScript's Date constructor rolls Feb 29, 1900
131
+ // forward to March 1, 1900, so we handle this specially. Run this check
132
+ // *after* the `y < 1900 → y + 1900` coercion so that `DATE(0, 2, 29)` and
133
+ // `DATE(1900, 2, 29)` resolve to the same serial (R6-P1-1).
134
+ if (y === 1900 && month.value === 2 && day.value === 29) {
135
+ return rvNumber(60); // The fictitious Feb 29, 1900
136
+ }
137
+ const d = new Date(Date.UTC(y, month.value - 1, day.value));
138
+ // The `Date.UTC` constructor maps two-digit years through its own legacy
139
+ // rule (+1900), so for `y` in [0, 99] we end up with the same value we
140
+ // already coerced above. Force the full year to be safe — but preserve
141
+ // month/day carry-over from out-of-range values (Excel allows DATE(2024,
142
+ // 13, 1) → 2025-01-01).
143
+ if (y < 100) {
144
+ d.setUTCFullYear(y);
145
+ }
146
+ return rvNumber(fromDate(d));
147
+ };
148
+ export const fnTIME = args => {
149
+ const hour = argToNumber(args[0]);
150
+ if (isError(hour)) {
151
+ return hour;
152
+ }
153
+ const minute = argToNumber(args[1]);
154
+ if (isError(minute)) {
155
+ return minute;
156
+ }
157
+ const second = argToNumber(args[2]);
158
+ if (isError(second)) {
159
+ return second;
160
+ }
161
+ // Excel's TIME rejects negative arguments outright and wraps anything >= 24
162
+ // hours back into the [0, 1) fraction-of-day range. Without the modulo,
163
+ // `TIME(25, 0, 0)` would produce a value > 1, which breaks downstream
164
+ // date-time arithmetic that expects a pure time fraction.
165
+ if (hour.value < 0 || minute.value < 0 || second.value < 0) {
166
+ return ERRORS.NUM;
167
+ }
168
+ const total = (hour.value * 3600 + minute.value * 60 + second.value) / 86400;
169
+ // total could still be >= 1 if e.g. hour=25; wrap into [0, 1).
170
+ return rvNumber(total - Math.floor(total));
171
+ };
172
+ export const fnHOUR = args => {
173
+ const n = argToNumber(args[0]);
174
+ if (isError(n)) {
175
+ return n;
176
+ }
177
+ if (n.value < 0) {
178
+ return ERRORS.NUM;
179
+ }
180
+ const totalSeconds = Math.round((n.value % 1) * 86400);
181
+ return rvNumber(Math.floor(totalSeconds / 3600) % 24);
182
+ };
183
+ export const fnMINUTE = args => {
184
+ const n = argToNumber(args[0]);
185
+ if (isError(n)) {
186
+ return n;
187
+ }
188
+ if (n.value < 0) {
189
+ return ERRORS.NUM;
190
+ }
191
+ const totalSeconds = Math.round((n.value % 1) * 86400);
192
+ return rvNumber(Math.floor(totalSeconds / 60) % 60);
193
+ };
194
+ export const fnSECOND = args => {
195
+ const n = argToNumber(args[0]);
196
+ if (isError(n)) {
197
+ return n;
198
+ }
199
+ if (n.value < 0) {
200
+ return ERRORS.NUM;
201
+ }
202
+ const totalSeconds = Math.round((n.value % 1) * 86400);
203
+ return rvNumber(totalSeconds % 60);
204
+ };
205
+ export const fnWEEKDAY = args => {
206
+ const n = argToNumber(args[0]);
207
+ if (isError(n)) {
208
+ return n;
209
+ }
210
+ const d = toDate(n.value);
211
+ const returnType = args.length > 1 ? argToNumber(args[1]) : rvNumber(1);
212
+ if (isError(returnType)) {
213
+ return returnType;
214
+ }
215
+ const day = d.getUTCDay(); // 0=Sun, 6=Sat
216
+ switch (returnType.value) {
217
+ case 1:
218
+ return rvNumber(day + 1); // 1=Sun, 7=Sat
219
+ case 2:
220
+ return rvNumber(day === 0 ? 7 : day); // 1=Mon, 7=Sun
221
+ case 3:
222
+ return rvNumber(day === 0 ? 6 : day - 1); // 0=Mon, 6=Sun
223
+ case 11: // Mon=1..Sun=7
224
+ case 12: // Tue=1..Mon=7
225
+ case 13: // Wed=1..Tue=7
226
+ case 14: // Thu=1..Wed=7
227
+ case 15: // Fri=1..Thu=7
228
+ case 16: // Sat=1..Fri=7
229
+ case 17: // Sun=1..Sat=7
230
+ return rvNumber(((((day - (returnType.value - 10)) % 7) + 7) % 7) + 1);
231
+ default:
232
+ return ERRORS.NUM;
233
+ }
234
+ };
235
+ export const fnEOMONTH = args => {
236
+ const startDate = argToNumber(args[0]);
237
+ if (isError(startDate)) {
238
+ return startDate;
239
+ }
240
+ const months = argToNumber(args[1]);
241
+ if (isError(months)) {
242
+ return months;
243
+ }
244
+ const d = toDate(startDate.value);
245
+ const result = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + months.value + 1, 0));
246
+ return rvNumber(fromDate(result));
247
+ };
248
+ export const fnEDATE = args => {
249
+ const startDate = argToNumber(args[0]);
250
+ if (isError(startDate)) {
251
+ return startDate;
252
+ }
253
+ const months = argToNumber(args[1]);
254
+ if (isError(months)) {
255
+ return months;
256
+ }
257
+ const d = toDate(startDate.value);
258
+ const result = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + months.value, d.getUTCDate()));
259
+ return rvNumber(fromDate(result));
260
+ };
261
+ export const fnDATEDIF = args => {
262
+ const startN = argToNumber(args[0]);
263
+ if (isError(startN)) {
264
+ return startN;
265
+ }
266
+ const endN = argToNumber(args[1]);
267
+ if (isError(endN)) {
268
+ return endN;
269
+ }
270
+ // DATEDIF requires end >= start; otherwise #NUM! per Excel.
271
+ if (endN.value < startN.value) {
272
+ return ERRORS.NUM;
273
+ }
274
+ const unit = toStringRV(args[2]).toUpperCase();
275
+ const startD = toDate(startN.value);
276
+ const endD = toDate(endN.value);
277
+ const sy = startD.getUTCFullYear();
278
+ const sm = startD.getUTCMonth();
279
+ const sd = startD.getUTCDate();
280
+ const ey = endD.getUTCFullYear();
281
+ const em = endD.getUTCMonth();
282
+ const ed = endD.getUTCDate();
283
+ switch (unit) {
284
+ case "Y":
285
+ return rvNumber(ey - sy - (em < sm || (em === sm && ed < sd) ? 1 : 0));
286
+ case "M":
287
+ return rvNumber((ey - sy) * 12 + em - sm - (ed < sd ? 1 : 0));
288
+ case "D":
289
+ return rvNumber(Math.floor((endD.getTime() - startD.getTime()) / 86400000));
290
+ case "MD": {
291
+ // Days between the dates, ignoring months and years.
292
+ // If end.day >= start.day → ed - sd; otherwise borrow days from the
293
+ // previous month of endD (last-day-of-prev-month - start.day + end.day).
294
+ if (ed >= sd) {
295
+ return rvNumber(ed - sd);
296
+ }
297
+ // days in the month before endD's month
298
+ const daysInPrevMonth = new Date(Date.UTC(ey, em, 0)).getUTCDate();
299
+ return rvNumber(daysInPrevMonth - sd + ed);
300
+ }
301
+ case "YM": {
302
+ // Months between the dates, ignoring days and years.
303
+ let months = em - sm;
304
+ if (ed < sd) {
305
+ months -= 1;
306
+ }
307
+ if (months < 0) {
308
+ months += 12;
309
+ }
310
+ return rvNumber(months);
311
+ }
312
+ case "YD": {
313
+ // Days between the dates as though they were in the same year, ignoring years.
314
+ // Align endD to startD's year (or next year if end < start in same-year terms).
315
+ const sameYearEnd = Date.UTC(sy, em, ed);
316
+ const startUTC = Date.UTC(sy, sm, sd);
317
+ let diff = sameYearEnd - startUTC;
318
+ if (diff < 0) {
319
+ // end falls earlier in the year than start → roll forward one year
320
+ const nextYearEnd = Date.UTC(sy + 1, em, ed);
321
+ diff = nextYearEnd - startUTC;
322
+ }
323
+ return rvNumber(Math.floor(diff / 86400000));
324
+ }
325
+ default:
326
+ return ERRORS.NUM;
327
+ }
328
+ };
329
+ export const fnDAYS = args => {
330
+ const end = argToNumber(args[0]);
331
+ if (isError(end)) {
332
+ return end;
333
+ }
334
+ const start = argToNumber(args[1]);
335
+ if (isError(start)) {
336
+ return start;
337
+ }
338
+ return rvNumber(Math.floor(end.value) - Math.floor(start.value));
339
+ };
340
+ export const fnISOWEEKNUM = args => {
341
+ const n = argToNumber(args[0]);
342
+ if (isError(n)) {
343
+ return n;
344
+ }
345
+ const d = toDate(n.value);
346
+ const temp = new Date(d.getTime());
347
+ temp.setUTCDate(temp.getUTCDate() + 3 - ((temp.getUTCDay() + 6) % 7));
348
+ const week1 = new Date(Date.UTC(temp.getUTCFullYear(), 0, 4));
349
+ return rvNumber(1 +
350
+ Math.round(((temp.getTime() - week1.getTime()) / 86400000 - 3 + ((week1.getUTCDay() + 6) % 7)) / 7));
351
+ };
352
+ export const fnWEEKNUM = args => {
353
+ const n = argToNumber(args[0]);
354
+ if (isError(n)) {
355
+ return n;
356
+ }
357
+ const d = toDate(n.value);
358
+ const returnType = args.length > 1 ? argToNumber(args[1]) : rvNumber(1);
359
+ if (isError(returnType)) {
360
+ return returnType;
361
+ }
362
+ const rt = returnType.value;
363
+ // Type 21 is ISO 8601 week.
364
+ if (rt === 21) {
365
+ return fnISOWEEKNUM(args);
366
+ }
367
+ // Excel maps `return_type` to the day-of-week that starts the week:
368
+ // 1 (default) → Sunday
369
+ // 2 or 11 → Monday
370
+ // 12 → Tuesday, 13 → Wednesday, … 17 → Saturday
371
+ // (16 → Friday, 17 → Saturday)
372
+ // Any other value is #NUM!.
373
+ let startDay; // 0 = Sunday … 6 = Saturday
374
+ switch (rt) {
375
+ case 1:
376
+ startDay = 0;
377
+ break;
378
+ case 2:
379
+ case 11:
380
+ startDay = 1;
381
+ break;
382
+ case 12:
383
+ startDay = 2;
384
+ break;
385
+ case 13:
386
+ startDay = 3;
387
+ break;
388
+ case 14:
389
+ startDay = 4;
390
+ break;
391
+ case 15:
392
+ startDay = 5;
393
+ break;
394
+ case 16:
395
+ startDay = 6;
396
+ break;
397
+ case 17:
398
+ startDay = 0;
399
+ break;
400
+ default:
401
+ return ERRORS.NUM;
402
+ }
403
+ const jan1 = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
404
+ const jan1Day = jan1.getUTCDay();
405
+ const dayOfYear = Math.floor((d.getTime() - jan1.getTime()) / 86400000);
406
+ return rvNumber(Math.floor((dayOfYear + ((jan1Day - startDay + 7) % 7)) / 7) + 1);
407
+ };
408
+ function networkdaysHelper(startN, endN, holidays) {
409
+ const s = Math.floor(Math.min(startN, endN));
410
+ const e = Math.floor(Math.max(startN, endN));
411
+ const sign = startN <= endN ? 1 : -1;
412
+ let count = 0;
413
+ for (let d = s; d <= e; d++) {
414
+ const dt = toDate(d);
415
+ const dow = dt.getUTCDay();
416
+ if (dow !== 0 && dow !== 6 && !holidays.has(d)) {
417
+ count++;
418
+ }
419
+ }
420
+ return count * sign;
421
+ }
422
+ export const fnNETWORKDAYS = args => {
423
+ const startN = argToNumber(args[0]);
424
+ if (isError(startN)) {
425
+ return startN;
426
+ }
427
+ const endN = argToNumber(args[1]);
428
+ if (isError(endN)) {
429
+ return endN;
430
+ }
431
+ const holidays = args.length > 2 ? collectHolidays(args[2]) : new Set();
432
+ return rvNumber(networkdaysHelper(startN.value, endN.value, holidays));
433
+ };
434
+ export const fnWORKDAY = args => {
435
+ const startN = argToNumber(args[0]);
436
+ if (isError(startN)) {
437
+ return startN;
438
+ }
439
+ const days = argToNumber(args[1]);
440
+ if (isError(days)) {
441
+ return days;
442
+ }
443
+ const holidays = args.length > 2 ? collectHolidays(args[2]) : new Set();
444
+ let current = Math.floor(startN.value);
445
+ const step = days.value >= 0 ? 1 : -1;
446
+ let remaining = Math.abs(days.value);
447
+ while (remaining > 0) {
448
+ current += step;
449
+ const dt = toDate(current);
450
+ const dow = dt.getUTCDay();
451
+ if (dow !== 0 && dow !== 6 && !holidays.has(current)) {
452
+ remaining--;
453
+ }
454
+ }
455
+ return rvNumber(current);
456
+ };
457
+ export const fnYEARFRAC = args => {
458
+ const startN = argToNumber(args[0]);
459
+ if (isError(startN)) {
460
+ return startN;
461
+ }
462
+ const endN = argToNumber(args[1]);
463
+ if (isError(endN)) {
464
+ return endN;
465
+ }
466
+ const basis = args.length > 2 ? argToNumber(args[2]) : rvNumber(0);
467
+ if (isError(basis)) {
468
+ return basis;
469
+ }
470
+ const sd = toDate(Math.min(startN.value, endN.value));
471
+ const ed = toDate(Math.max(startN.value, endN.value));
472
+ const diffDays = Math.abs(Math.floor(endN.value) - Math.floor(startN.value));
473
+ switch (basis.value) {
474
+ case 0: {
475
+ // US (NASD) 30/360
476
+ let d1 = sd.getUTCDate();
477
+ const m1 = sd.getUTCMonth() + 1;
478
+ const y1 = sd.getUTCFullYear();
479
+ let d2 = ed.getUTCDate();
480
+ const m2 = ed.getUTCMonth() + 1;
481
+ const y2 = ed.getUTCFullYear();
482
+ // NASD adjustment rules
483
+ if (d1 === 31) {
484
+ d1 = 30;
485
+ }
486
+ if (d2 === 31 && d1 >= 30) {
487
+ d2 = 30;
488
+ }
489
+ // Handle end-of-Feb for start date
490
+ const feb1 = new Date(Date.UTC(y1, 1, 29)).getUTCMonth() === 1 ? 29 : 28;
491
+ if (m1 === 2 && d1 === feb1) {
492
+ d1 = 30;
493
+ if (m2 === 2) {
494
+ const feb2 = new Date(Date.UTC(y2, 1, 29)).getUTCMonth() === 1 ? 29 : 28;
495
+ if (d2 === feb2) {
496
+ d2 = 30;
497
+ }
498
+ }
499
+ }
500
+ const days30_360 = (y2 - y1) * 360 + (m2 - m1) * 30 + (d2 - d1);
501
+ return rvNumber(days30_360 / 360);
502
+ }
503
+ case 1: {
504
+ // Actual/Actual (ISDA convention, matches Excel's behaviour).
505
+ //
506
+ // Same-year is easy: divide by the length of that calendar year.
507
+ // Across years we split the interval into its leap-year portion and
508
+ // non-leap-year portion, then sum `leapDays/366 + nonLeapDays/365`.
509
+ // This is the ISDA "Act/Act" rule; simple averaging of year lengths
510
+ // (the previous implementation) produces visibly wrong answers like
511
+ // `YEARFRAC("2020-01-01","2021-01-01",1) ≈ 1.001368` where Excel
512
+ // returns exactly 1.
513
+ const y1 = sd.getUTCFullYear();
514
+ const y2 = ed.getUTCFullYear();
515
+ if (y1 === y2) {
516
+ const yearDays = (Date.UTC(y1 + 1, 0, 1) - Date.UTC(y1, 0, 1)) / 86400000;
517
+ return rvNumber(diffDays / yearDays);
518
+ }
519
+ let leapDays = 0;
520
+ let nonLeapDays = 0;
521
+ const sdMs = sd.getTime();
522
+ const edMs = ed.getTime();
523
+ for (let y = y1; y <= y2; y++) {
524
+ const yStart = Math.max(sdMs, Date.UTC(y, 0, 1));
525
+ const yEnd = Math.min(edMs, Date.UTC(y + 1, 0, 1));
526
+ if (yEnd <= yStart) {
527
+ continue;
528
+ }
529
+ const d = (yEnd - yStart) / 86400000;
530
+ const isLeap = (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0;
531
+ if (isLeap) {
532
+ leapDays += d;
533
+ }
534
+ else {
535
+ nonLeapDays += d;
536
+ }
537
+ }
538
+ return rvNumber(leapDays / 366 + nonLeapDays / 365);
539
+ }
540
+ case 2: // Actual/360
541
+ return rvNumber(diffDays / 360);
542
+ case 3: // Actual/365
543
+ return rvNumber(diffDays / 365);
544
+ case 4: {
545
+ // European 30/360
546
+ const d1 = Math.min(sd.getUTCDate(), 30);
547
+ const d2 = Math.min(ed.getUTCDate(), 30);
548
+ const m1 = sd.getUTCMonth() + 1;
549
+ const m2 = ed.getUTCMonth() + 1;
550
+ const y1 = sd.getUTCFullYear();
551
+ const y2 = ed.getUTCFullYear();
552
+ const days30_360 = (y2 - y1) * 360 + (m2 - m1) * 30 + (d2 - d1);
553
+ return rvNumber(days30_360 / 360);
554
+ }
555
+ default:
556
+ return ERRORS.NUM;
557
+ }
558
+ };
559
+ export const fnDATEVALUE = args => {
560
+ const err = checkError(args[0]);
561
+ if (err) {
562
+ return err;
563
+ }
564
+ const text = toStringRV(args[0]).trim();
565
+ // Lotus 1-2-3 bug: "2/29/1900" or "February 29, 1900" etc. should return 60
566
+ const lotus29 = /^(2[/-]29[/-]1900|1900[/-]2[/-]29|1900[/-]02[/-]29|02[/-]29[/-]1900|Feb(ruary)?\s+29[,]?\s+1900)$/i;
567
+ if (lotus29.test(text)) {
568
+ return rvNumber(60);
569
+ }
570
+ const parsed = parseDateOnly(text);
571
+ if (!parsed) {
572
+ return ERRORS.VALUE;
573
+ }
574
+ return rvNumber(fromDate(new Date(Date.UTC(parsed.y, parsed.m - 1, parsed.d))));
575
+ };
576
+ export const fnTIMEVALUE = args => {
577
+ const err = checkError(args[0]);
578
+ if (err) {
579
+ return err;
580
+ }
581
+ const text = toStringRV(args[0]).trim();
582
+ const parsed = parseTimeOnly(text);
583
+ if (parsed === null) {
584
+ return ERRORS.VALUE;
585
+ }
586
+ return rvNumber(parsed);
587
+ };
588
+ // ============================================================================
589
+ // Date / Time parsing (deterministic, independent of host locale)
590
+ //
591
+ // `new Date(text)` is unreliable across engines (Chrome parses "1/2/3" as
592
+ // US MDY, Node varies by version, and locale influences both). We hand-
593
+ // roll a small parser that accepts the formats Excel's DATEVALUE does and
594
+ // rejects everything else.
595
+ // ============================================================================
596
+ const MONTH_NAMES = {
597
+ jan: 1,
598
+ january: 1,
599
+ feb: 2,
600
+ february: 2,
601
+ mar: 3,
602
+ march: 3,
603
+ apr: 4,
604
+ april: 4,
605
+ may: 5,
606
+ jun: 6,
607
+ june: 6,
608
+ jul: 7,
609
+ july: 7,
610
+ aug: 8,
611
+ august: 8,
612
+ sep: 9,
613
+ sept: 9,
614
+ september: 9,
615
+ oct: 10,
616
+ october: 10,
617
+ nov: 11,
618
+ november: 11,
619
+ dec: 12,
620
+ december: 12
621
+ };
622
+ /** Parse a date-only string into `{y, m, d}` or `null` on rejection. */
623
+ function parseDateOnly(raw) {
624
+ const s = raw.trim();
625
+ // Strip a trailing time component (e.g. "2024-01-15 14:30") — but only
626
+ // split at a space that is followed by a digit, so a spelled-out date
627
+ // like "Jan 15, 2024" (which has month-name and day-number separated
628
+ // by spaces) survives for the "Mmm D, YYYY" matcher below.
629
+ // A naive `indexOf(" ")` truncated "Jan 15, 2024" to just "Jan".
630
+ const trailingTime = /^(.+?)\s(\d{1,2}:[\d:]+(?:\s*[AaPp]\.?[Mm]\.?)?)$/.exec(s);
631
+ const datePart = trailingTime ? trailingTime[1].trim() : s;
632
+ // ISO YYYY-MM-DD or YYYY/MM/DD
633
+ let m = /^(\d{4})[/-](\d{1,2})[/-](\d{1,2})$/.exec(datePart);
634
+ if (m) {
635
+ return validateYmd(+m[1], +m[2], +m[3]);
636
+ }
637
+ // US M/D/YYYY or M-D-YYYY
638
+ m = /^(\d{1,2})[/-](\d{1,2})[/-](\d{2,4})$/.exec(datePart);
639
+ if (m) {
640
+ let y = +m[3];
641
+ if (y < 100) {
642
+ // Excel's pivot: 00-29 → 2000s, 30-99 → 1900s
643
+ y += y < 30 ? 2000 : 1900;
644
+ }
645
+ return validateYmd(y, +m[1], +m[2]);
646
+ }
647
+ // D-Mmm-YY or D-Mmm-YYYY
648
+ m = /^(\d{1,2})[ /-]([A-Za-z]{3,9})[ /-]?(\d{2,4})?$/.exec(datePart);
649
+ if (m) {
650
+ const month = MONTH_NAMES[m[2].toLowerCase()];
651
+ if (!month) {
652
+ return null;
653
+ }
654
+ // Excel's DATEVALUE substitutes the host's current calendar year when
655
+ // the input omits a year (e.g. "15-Jan"). This matches Excel on the
656
+ // desktop, but note that the return value is not stable across time
657
+ // zones or years — tests that exercise this branch should freeze the
658
+ // clock (or supply a year) if they need reproducibility.
659
+ let y = m[3] ? +m[3] : new Date().getFullYear();
660
+ if (y < 100) {
661
+ y += y < 30 ? 2000 : 1900;
662
+ }
663
+ return validateYmd(y, month, +m[1]);
664
+ }
665
+ // "Mmm D, YYYY" or "Month D, YYYY"
666
+ m = /^([A-Za-z]{3,9})\s+(\d{1,2}),?\s+(\d{2,4})$/.exec(datePart);
667
+ if (m) {
668
+ const month = MONTH_NAMES[m[1].toLowerCase()];
669
+ if (!month) {
670
+ return null;
671
+ }
672
+ let y = +m[3];
673
+ if (y < 100) {
674
+ y += y < 30 ? 2000 : 1900;
675
+ }
676
+ return validateYmd(y, month, +m[2]);
677
+ }
678
+ return null;
679
+ }
680
+ /** Validate a calendar date and return null for out-of-range components. */
681
+ function validateYmd(y, mo, d) {
682
+ if (y < 0 || y > 9999 || mo < 1 || mo > 12 || d < 1 || d > 31) {
683
+ return null;
684
+ }
685
+ // Day-of-month range check using UTC (leap years included).
686
+ const dt = new Date(Date.UTC(y, mo - 1, d));
687
+ if (dt.getUTCFullYear() !== y || dt.getUTCMonth() !== mo - 1 || dt.getUTCDate() !== d) {
688
+ return null;
689
+ }
690
+ return { y, m: mo, d };
691
+ }
692
+ /** Parse a time-only string into a fraction-of-day in [0, 1). */
693
+ function parseTimeOnly(raw) {
694
+ // Optional AM/PM suffix; captured case-insensitively.
695
+ const m = /^(\d{1,2})(?::(\d{1,2}))?(?::(\d{1,2}(?:\.\d+)?))?(?:\s*([AaPp])\.?\s*[Mm]\.?)?$/.exec(raw);
696
+ if (!m) {
697
+ return null;
698
+ }
699
+ let h = +m[1];
700
+ const min = m[2] ? +m[2] : 0;
701
+ const sec = m[3] ? +m[3] : 0;
702
+ if (min >= 60 || sec >= 60 || min < 0 || sec < 0) {
703
+ return null;
704
+ }
705
+ if (m[4]) {
706
+ const pm = m[4].toLowerCase() === "p";
707
+ if (h < 1 || h > 12) {
708
+ return null;
709
+ }
710
+ if (pm && h < 12) {
711
+ h += 12;
712
+ }
713
+ else if (!pm && h === 12) {
714
+ h = 0;
715
+ }
716
+ }
717
+ else {
718
+ if (h < 0 || h > 23) {
719
+ return null;
720
+ }
721
+ }
722
+ return (h * 3600 + min * 60 + sec) / 86400;
723
+ }
724
+ // ============================================================================
725
+ // More Date/Time Functions
726
+ // ============================================================================
727
+ export const fnDAYS360 = args => {
728
+ const startN = argToNumber(args[0]);
729
+ if (isError(startN)) {
730
+ return startN;
731
+ }
732
+ const endN = argToNumber(args[1]);
733
+ if (isError(endN)) {
734
+ return endN;
735
+ }
736
+ const methodRV = args.length > 2 ? toBooleanRV(args[2]) : rvBoolean(false);
737
+ if (isError(methodRV)) {
738
+ return methodRV;
739
+ }
740
+ const method = methodRV.value;
741
+ const sd = toDate(startN.value);
742
+ const ed = toDate(endN.value);
743
+ let d1 = sd.getUTCDate();
744
+ let d2 = ed.getUTCDate();
745
+ const m1 = sd.getUTCMonth() + 1;
746
+ const m2 = ed.getUTCMonth() + 1;
747
+ const y1 = sd.getUTCFullYear();
748
+ const y2 = ed.getUTCFullYear();
749
+ if (method) {
750
+ if (d1 === 31) {
751
+ d1 = 30;
752
+ }
753
+ if (d2 === 31) {
754
+ d2 = 30;
755
+ }
756
+ }
757
+ else {
758
+ if (d1 === 31) {
759
+ d1 = 30;
760
+ }
761
+ if (d2 === 31 && d1 >= 30) {
762
+ d2 = 30;
763
+ }
764
+ }
765
+ return rvNumber((y2 - y1) * 360 + (m2 - m1) * 30 + (d2 - d1));
766
+ };
767
+ /** Map weekend-type code to the set of day-of-week indices (0=Sun..6=Sat) that are weekends. */
768
+ function getWeekendDays(weekendType) {
769
+ switch (weekendType) {
770
+ case 1:
771
+ return new Set([0, 6]); // Sat, Sun
772
+ case 2:
773
+ return new Set([0, 1]); // Sun, Mon
774
+ case 3:
775
+ return new Set([1, 2]); // Mon, Tue
776
+ case 4:
777
+ return new Set([2, 3]); // Tue, Wed
778
+ case 5:
779
+ return new Set([3, 4]); // Wed, Thu
780
+ case 6:
781
+ return new Set([4, 5]); // Thu, Fri
782
+ case 7:
783
+ return new Set([5, 6]); // Fri, Sat
784
+ case 11:
785
+ return new Set([0]); // Sun only
786
+ case 12:
787
+ return new Set([1]); // Mon only
788
+ case 13:
789
+ return new Set([2]); // Tue only
790
+ case 14:
791
+ return new Set([3]); // Wed only
792
+ case 15:
793
+ return new Set([4]); // Thu only
794
+ case 16:
795
+ return new Set([5]); // Fri only
796
+ case 17:
797
+ return new Set([6]); // Sat only
798
+ default:
799
+ return new Set([0, 6]); // Default: Sat, Sun
800
+ }
801
+ }
802
+ export const fnNETWORKDAYS_INTL = args => {
803
+ const startN = argToNumber(args[0]);
804
+ if (isError(startN)) {
805
+ return startN;
806
+ }
807
+ const endN = argToNumber(args[1]);
808
+ if (isError(endN)) {
809
+ return endN;
810
+ }
811
+ const weekendArg = args.length > 2 ? argToNumber(args[2]) : rvNumber(1);
812
+ if (isError(weekendArg)) {
813
+ return weekendArg;
814
+ }
815
+ const holidays = args.length > 3 ? collectHolidays(args[3]) : new Set();
816
+ const weekendDays = getWeekendDays(weekendArg.value);
817
+ const s = Math.floor(Math.min(startN.value, endN.value));
818
+ const e = Math.floor(Math.max(startN.value, endN.value));
819
+ const sign = startN.value <= endN.value ? 1 : -1;
820
+ let count = 0;
821
+ for (let d = s; d <= e; d++) {
822
+ const dt = toDate(d);
823
+ if (!weekendDays.has(dt.getUTCDay()) && !holidays.has(d)) {
824
+ count++;
825
+ }
826
+ }
827
+ return rvNumber(count * sign);
828
+ };
829
+ export const fnWORKDAY_INTL = args => {
830
+ const startN = argToNumber(args[0]);
831
+ if (isError(startN)) {
832
+ return startN;
833
+ }
834
+ const days = argToNumber(args[1]);
835
+ if (isError(days)) {
836
+ return days;
837
+ }
838
+ const weekendArg = args.length > 2 ? argToNumber(args[2]) : rvNumber(1);
839
+ if (isError(weekendArg)) {
840
+ return weekendArg;
841
+ }
842
+ const holidays = args.length > 3 ? collectHolidays(args[3]) : new Set();
843
+ const weekendDays = getWeekendDays(weekendArg.value);
844
+ let current = Math.floor(startN.value);
845
+ const step = days.value >= 0 ? 1 : -1;
846
+ let remaining = Math.abs(days.value);
847
+ while (remaining > 0) {
848
+ current += step;
849
+ const dt = toDate(current);
850
+ if (!weekendDays.has(dt.getUTCDay()) && !holidays.has(current)) {
851
+ remaining--;
852
+ }
853
+ }
854
+ return rvNumber(current);
855
+ };