@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.
- package/README.md +25 -2
- package/README_zh.md +29 -6
- package/dist/browser/index.browser.d.ts +1 -1
- package/dist/browser/index.browser.js +4 -0
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.js +4 -0
- package/dist/browser/modules/excel/cell.d.ts +17 -3
- package/dist/browser/modules/excel/cell.js +170 -22
- package/dist/browser/modules/excel/defined-names.d.ts +96 -1
- package/dist/browser/modules/excel/defined-names.js +411 -21
- package/dist/browser/modules/excel/image.d.ts +11 -0
- package/dist/browser/modules/excel/image.js +24 -1
- package/dist/browser/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
- package/dist/browser/modules/excel/stream/workbook-reader.browser.js +14 -0
- package/dist/browser/modules/excel/stream/workbook-reader.d.ts +2 -1
- package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
- package/dist/browser/modules/excel/stream/workbook-writer.browser.js +48 -1
- package/dist/browser/modules/excel/stream/workbook-writer.d.ts +3 -2
- package/dist/browser/modules/excel/stream/worksheet-reader.js +17 -1
- package/dist/browser/modules/excel/stream/worksheet-writer.d.ts +39 -6
- package/dist/browser/modules/excel/stream/worksheet-writer.js +45 -5
- package/dist/browser/modules/excel/table.js +15 -2
- package/dist/browser/modules/excel/types.d.ts +133 -2
- package/dist/browser/modules/excel/utils/col-cache.d.ts +1 -0
- package/dist/browser/modules/excel/utils/col-cache.js +15 -0
- package/dist/browser/modules/excel/utils/drawing-utils.d.ts +3 -3
- package/dist/browser/modules/excel/utils/drawing-utils.js +4 -0
- package/dist/browser/modules/excel/utils/external-link-formula.d.ts +76 -0
- package/dist/browser/modules/excel/utils/external-link-formula.js +208 -0
- package/dist/browser/modules/excel/utils/iterate-stream.d.ts +9 -3
- package/dist/browser/modules/excel/utils/iterate-stream.js +3 -1
- package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +19 -0
- package/dist/browser/modules/excel/utils/ooxml-paths.js +37 -2
- package/dist/browser/modules/excel/utils/shared-strings.d.ts +8 -3
- package/dist/browser/modules/excel/utils/shared-strings.js +21 -2
- package/dist/browser/modules/excel/utils/workbook-protection.d.ts +30 -0
- package/dist/browser/modules/excel/utils/workbook-protection.js +30 -0
- package/dist/browser/modules/excel/workbook.browser.d.ts +257 -6
- package/dist/browser/modules/excel/workbook.browser.js +318 -34
- package/dist/browser/modules/excel/workbook.d.ts +1 -1
- package/dist/browser/modules/excel/worksheet.d.ts +3 -1
- package/dist/browser/modules/excel/worksheet.js +21 -2
- package/dist/browser/modules/excel/xlsx/rel-type.d.ts +15 -0
- package/dist/browser/modules/excel/xlsx/rel-type.js +16 -1
- package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
- package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
- package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
- package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
- package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
- package/dist/browser/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
- package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
- package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
- package/dist/browser/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
- package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
- package/dist/browser/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
- package/dist/browser/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
- package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
- package/dist/browser/modules/excel/xlsx/xform/style/border-xform.js +4 -1
- package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +410 -20
- package/dist/browser/modules/excel/xlsx/xlsx.d.ts +7 -4
- package/dist/browser/modules/excel/xlsx/xlsx.js +4 -5
- package/dist/browser/modules/formula/compile/address-utils.d.ts +62 -0
- package/dist/browser/modules/formula/compile/address-utils.js +83 -0
- package/dist/browser/modules/formula/compile/binder.d.ts +42 -0
- package/dist/browser/modules/formula/compile/binder.js +487 -0
- package/dist/browser/modules/formula/compile/bound-ast.d.ts +230 -0
- package/dist/browser/modules/formula/compile/bound-ast.js +80 -0
- package/dist/browser/modules/formula/compile/compiled-formula.d.ts +137 -0
- package/dist/browser/modules/formula/compile/compiled-formula.js +383 -0
- package/dist/browser/modules/formula/compile/dependency-analysis.d.ts +93 -0
- package/dist/browser/modules/formula/compile/dependency-analysis.js +432 -0
- package/dist/browser/modules/formula/compile/structured-ref-utils.d.ts +93 -0
- package/dist/browser/modules/formula/compile/structured-ref-utils.js +136 -0
- package/dist/browser/modules/formula/default-syntax-probe.d.ts +79 -0
- package/dist/browser/modules/formula/default-syntax-probe.js +83 -0
- package/dist/browser/modules/formula/functions/_date-context.d.ts +4 -0
- package/dist/browser/modules/formula/functions/_date-context.js +29 -0
- package/dist/browser/modules/formula/functions/_shared.d.ts +121 -0
- package/dist/browser/modules/formula/functions/_shared.js +381 -0
- package/dist/browser/modules/formula/functions/conditional.d.ts +27 -0
- package/dist/browser/modules/formula/functions/conditional.js +343 -0
- package/dist/browser/modules/formula/functions/database.d.ts +37 -0
- package/dist/browser/modules/formula/functions/database.js +274 -0
- package/dist/browser/modules/formula/functions/date.d.ts +61 -0
- package/dist/browser/modules/formula/functions/date.js +855 -0
- package/dist/browser/modules/formula/functions/dynamic-array.d.ts +23 -0
- package/dist/browser/modules/formula/functions/dynamic-array.js +860 -0
- package/dist/browser/modules/formula/functions/engineering.d.ts +57 -0
- package/dist/browser/modules/formula/functions/engineering.js +1128 -0
- package/dist/browser/modules/formula/functions/financial.d.ts +202 -0
- package/dist/browser/modules/formula/functions/financial.js +2296 -0
- package/dist/browser/modules/formula/functions/lookup.d.ts +18 -0
- package/dist/browser/modules/formula/functions/lookup.js +886 -0
- package/dist/browser/modules/formula/functions/math.d.ts +114 -0
- package/dist/browser/modules/formula/functions/math.js +1406 -0
- package/dist/browser/modules/formula/functions/statistical.d.ts +193 -0
- package/dist/browser/modules/formula/functions/statistical.js +3390 -0
- package/dist/browser/modules/formula/functions/text.d.ts +86 -0
- package/dist/browser/modules/formula/functions/text.js +1845 -0
- package/dist/browser/modules/formula/host-registry.d.ts +53 -0
- package/dist/browser/modules/formula/host-registry.js +69 -0
- package/dist/browser/modules/formula/index.d.ts +39 -0
- package/dist/browser/modules/formula/index.js +49 -0
- package/dist/browser/modules/formula/install.d.ts +62 -0
- package/dist/browser/modules/formula/install.js +88 -0
- package/dist/browser/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
- package/dist/browser/modules/formula/integration/apply-writeback-plan.js +210 -0
- package/dist/browser/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
- package/dist/browser/modules/formula/integration/calculate-formulas-impl.js +616 -0
- package/dist/browser/modules/formula/integration/calculate-formulas.d.ts +67 -0
- package/dist/browser/modules/formula/integration/calculate-formulas.js +68 -0
- package/dist/browser/modules/formula/integration/formula-instance.d.ts +64 -0
- package/dist/browser/modules/formula/integration/formula-instance.js +79 -0
- package/dist/browser/modules/formula/integration/workbook-adapter.d.ts +26 -0
- package/dist/browser/modules/formula/integration/workbook-adapter.js +324 -0
- package/dist/browser/modules/formula/integration/workbook-snapshot.d.ts +267 -0
- package/dist/browser/modules/formula/integration/workbook-snapshot.js +77 -0
- package/dist/browser/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
- package/dist/browser/modules/formula/materialize/build-writeback-plan.js +473 -0
- package/dist/browser/modules/formula/materialize/spill-engine.d.ts +9 -0
- package/dist/browser/modules/formula/materialize/spill-engine.js +38 -0
- package/dist/browser/modules/formula/materialize/types.d.ts +179 -0
- package/dist/browser/modules/formula/materialize/types.js +29 -0
- package/dist/browser/modules/formula/materialize/writeback-plan.d.ts +167 -0
- package/dist/browser/modules/formula/materialize/writeback-plan.js +27 -0
- package/dist/browser/modules/formula/runtime/evaluator.d.ts +151 -0
- package/dist/browser/modules/formula/runtime/evaluator.js +2291 -0
- package/dist/browser/modules/formula/runtime/function-registry.d.ts +47 -0
- package/dist/browser/modules/formula/runtime/function-registry.js +840 -0
- package/dist/browser/modules/formula/runtime/values.d.ts +211 -0
- package/dist/browser/modules/formula/runtime/values.js +385 -0
- package/dist/browser/modules/formula/syntax/ast.d.ts +129 -0
- package/dist/browser/modules/formula/syntax/ast.js +28 -0
- package/dist/browser/modules/formula/syntax/parser.d.ts +18 -0
- package/dist/browser/modules/formula/syntax/parser.js +439 -0
- package/dist/browser/modules/formula/syntax/token-types.d.ts +153 -0
- package/dist/browser/modules/formula/syntax/token-types.js +59 -0
- package/dist/browser/modules/formula/syntax/tokenizer.d.ts +10 -0
- package/dist/browser/modules/formula/syntax/tokenizer.js +1074 -0
- package/dist/browser/modules/pdf/excel-bridge.js +9 -0
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/modules/excel/cell.js +170 -22
- package/dist/cjs/modules/excel/defined-names.js +411 -21
- package/dist/cjs/modules/excel/image.js +24 -1
- package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +14 -0
- package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +48 -1
- package/dist/cjs/modules/excel/stream/worksheet-reader.js +17 -1
- package/dist/cjs/modules/excel/stream/worksheet-writer.js +45 -5
- package/dist/cjs/modules/excel/table.js +15 -2
- package/dist/cjs/modules/excel/utils/col-cache.js +15 -0
- package/dist/cjs/modules/excel/utils/drawing-utils.js +4 -0
- package/dist/cjs/modules/excel/utils/external-link-formula.js +212 -0
- package/dist/cjs/modules/excel/utils/iterate-stream.js +3 -1
- package/dist/cjs/modules/excel/utils/ooxml-paths.js +42 -2
- package/dist/cjs/modules/excel/utils/shared-strings.js +21 -2
- package/dist/cjs/modules/excel/utils/workbook-protection.js +33 -0
- package/dist/cjs/modules/excel/workbook.browser.js +318 -34
- package/dist/cjs/modules/excel/worksheet.js +20 -1
- package/dist/cjs/modules/excel/xlsx/rel-type.js +16 -1
- package/dist/cjs/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
- package/dist/cjs/modules/excel/xlsx/xform/book/external-link-xform.js +333 -0
- package/dist/cjs/modules/excel/xlsx/xform/book/external-reference-xform.js +27 -0
- package/dist/cjs/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
- package/dist/cjs/modules/excel/xlsx/xform/book/workbook-protection-xform.js +69 -0
- package/dist/cjs/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
- package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +18 -0
- package/dist/cjs/modules/excel/xlsx/xform/core/metadata-xform.js +161 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +108 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
- package/dist/cjs/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
- package/dist/cjs/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
- package/dist/cjs/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +83 -0
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
- package/dist/cjs/modules/excel/xlsx/xform/style/border-xform.js +4 -1
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +408 -18
- package/dist/cjs/modules/excel/xlsx/xlsx.js +4 -5
- package/dist/cjs/modules/formula/compile/address-utils.js +89 -0
- package/dist/cjs/modules/formula/compile/binder.js +489 -0
- package/dist/cjs/modules/formula/compile/bound-ast.js +68 -0
- package/dist/cjs/modules/formula/compile/compiled-formula.js +387 -0
- package/dist/cjs/modules/formula/compile/dependency-analysis.js +437 -0
- package/dist/cjs/modules/formula/compile/structured-ref-utils.js +141 -0
- package/dist/cjs/modules/formula/default-syntax-probe.js +87 -0
- package/dist/cjs/modules/formula/functions/_date-context.js +33 -0
- package/dist/cjs/modules/formula/functions/_shared.js +396 -0
- package/dist/cjs/modules/formula/functions/conditional.js +354 -0
- package/dist/cjs/modules/formula/functions/database.js +288 -0
- package/dist/cjs/modules/formula/functions/date.js +883 -0
- package/dist/cjs/modules/formula/functions/dynamic-array.js +881 -0
- package/dist/cjs/modules/formula/functions/engineering.js +1183 -0
- package/dist/cjs/modules/formula/functions/financial.js +2348 -0
- package/dist/cjs/modules/formula/functions/lookup.js +902 -0
- package/dist/cjs/modules/formula/functions/math.js +1487 -0
- package/dist/cjs/modules/formula/functions/statistical.js +3488 -0
- package/dist/cjs/modules/formula/functions/text.js +1889 -0
- package/dist/cjs/modules/formula/host-registry.js +75 -0
- package/dist/cjs/modules/formula/index.js +58 -0
- package/dist/cjs/modules/formula/install.js +93 -0
- package/dist/cjs/modules/formula/integration/apply-writeback-plan.js +213 -0
- package/dist/cjs/modules/formula/integration/calculate-formulas-impl.js +619 -0
- package/dist/cjs/modules/formula/integration/calculate-formulas.js +71 -0
- package/dist/cjs/modules/formula/integration/formula-instance.js +82 -0
- package/dist/cjs/modules/formula/integration/workbook-adapter.js +327 -0
- package/dist/cjs/modules/formula/integration/workbook-snapshot.js +84 -0
- package/dist/cjs/modules/formula/materialize/build-writeback-plan.js +475 -0
- package/dist/cjs/modules/formula/materialize/spill-engine.js +42 -0
- package/dist/cjs/modules/formula/materialize/types.js +32 -0
- package/dist/cjs/modules/formula/materialize/writeback-plan.js +28 -0
- package/dist/cjs/modules/formula/runtime/evaluator.js +2298 -0
- package/dist/cjs/modules/formula/runtime/function-registry.js +846 -0
- package/dist/cjs/modules/formula/runtime/values.js +385 -0
- package/dist/cjs/modules/formula/syntax/ast.js +8 -0
- package/dist/cjs/modules/formula/syntax/parser.js +440 -0
- package/dist/cjs/modules/formula/syntax/token-types.js +32 -0
- package/dist/cjs/modules/formula/syntax/tokenizer.js +1076 -0
- package/dist/cjs/modules/pdf/excel-bridge.js +9 -0
- package/dist/esm/index.browser.js +4 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/modules/excel/cell.js +170 -22
- package/dist/esm/modules/excel/defined-names.js +411 -21
- package/dist/esm/modules/excel/image.js +24 -1
- package/dist/esm/modules/excel/stream/workbook-reader.browser.js +14 -0
- package/dist/esm/modules/excel/stream/workbook-writer.browser.js +48 -1
- package/dist/esm/modules/excel/stream/worksheet-reader.js +17 -1
- package/dist/esm/modules/excel/stream/worksheet-writer.js +45 -5
- package/dist/esm/modules/excel/table.js +15 -2
- package/dist/esm/modules/excel/utils/col-cache.js +15 -0
- package/dist/esm/modules/excel/utils/drawing-utils.js +4 -0
- package/dist/esm/modules/excel/utils/external-link-formula.js +208 -0
- package/dist/esm/modules/excel/utils/iterate-stream.js +3 -1
- package/dist/esm/modules/excel/utils/ooxml-paths.js +37 -2
- package/dist/esm/modules/excel/utils/shared-strings.js +21 -2
- package/dist/esm/modules/excel/utils/workbook-protection.js +30 -0
- package/dist/esm/modules/excel/workbook.browser.js +318 -34
- package/dist/esm/modules/excel/worksheet.js +21 -2
- package/dist/esm/modules/excel/xlsx/rel-type.js +16 -1
- package/dist/esm/modules/excel/xlsx/xform/book/defined-name-xform.js +21 -86
- package/dist/esm/modules/excel/xlsx/xform/book/external-link-xform.js +330 -0
- package/dist/esm/modules/excel/xlsx/xform/book/external-reference-xform.js +24 -0
- package/dist/esm/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.js +11 -2
- package/dist/esm/modules/excel/xlsx/xform/book/workbook-protection-xform.js +66 -0
- package/dist/esm/modules/excel/xlsx/xform/book/workbook-xform.js +38 -5
- package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +19 -1
- package/dist/esm/modules/excel/xlsx/xform/core/metadata-xform.js +158 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +105 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +3 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/drawing-xform.js +10 -2
- package/dist/esm/modules/excel/xlsx/xform/sheet/cell-xform.js +166 -8
- package/dist/esm/modules/excel/xlsx/xform/sheet/data-validations-xform.js +1 -1
- package/dist/esm/modules/excel/xlsx/xform/sheet/ignored-errors-xform.js +80 -0
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +9 -4
- package/dist/esm/modules/excel/xlsx/xform/style/border-xform.js +4 -1
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +410 -20
- package/dist/esm/modules/excel/xlsx/xlsx.js +4 -5
- package/dist/esm/modules/formula/compile/address-utils.js +83 -0
- package/dist/esm/modules/formula/compile/binder.js +487 -0
- package/dist/esm/modules/formula/compile/bound-ast.js +80 -0
- package/dist/esm/modules/formula/compile/compiled-formula.js +383 -0
- package/dist/esm/modules/formula/compile/dependency-analysis.js +432 -0
- package/dist/esm/modules/formula/compile/structured-ref-utils.js +136 -0
- package/dist/esm/modules/formula/default-syntax-probe.js +83 -0
- package/dist/esm/modules/formula/functions/_date-context.js +29 -0
- package/dist/esm/modules/formula/functions/_shared.js +381 -0
- package/dist/esm/modules/formula/functions/conditional.js +343 -0
- package/dist/esm/modules/formula/functions/database.js +274 -0
- package/dist/esm/modules/formula/functions/date.js +855 -0
- package/dist/esm/modules/formula/functions/dynamic-array.js +860 -0
- package/dist/esm/modules/formula/functions/engineering.js +1128 -0
- package/dist/esm/modules/formula/functions/financial.js +2296 -0
- package/dist/esm/modules/formula/functions/lookup.js +886 -0
- package/dist/esm/modules/formula/functions/math.js +1406 -0
- package/dist/esm/modules/formula/functions/statistical.js +3390 -0
- package/dist/esm/modules/formula/functions/text.js +1845 -0
- package/dist/esm/modules/formula/host-registry.js +69 -0
- package/dist/esm/modules/formula/index.js +49 -0
- package/dist/esm/modules/formula/install.js +88 -0
- package/dist/esm/modules/formula/integration/apply-writeback-plan.js +210 -0
- package/dist/esm/modules/formula/integration/calculate-formulas-impl.js +616 -0
- package/dist/esm/modules/formula/integration/calculate-formulas.js +68 -0
- package/dist/esm/modules/formula/integration/formula-instance.js +79 -0
- package/dist/esm/modules/formula/integration/workbook-adapter.js +324 -0
- package/dist/esm/modules/formula/integration/workbook-snapshot.js +77 -0
- package/dist/esm/modules/formula/materialize/build-writeback-plan.js +473 -0
- package/dist/esm/modules/formula/materialize/spill-engine.js +38 -0
- package/dist/esm/modules/formula/materialize/types.js +29 -0
- package/dist/esm/modules/formula/materialize/writeback-plan.js +27 -0
- package/dist/esm/modules/formula/runtime/evaluator.js +2291 -0
- package/dist/esm/modules/formula/runtime/function-registry.js +840 -0
- package/dist/esm/modules/formula/runtime/values.js +385 -0
- package/dist/esm/modules/formula/syntax/ast.js +28 -0
- package/dist/esm/modules/formula/syntax/parser.js +439 -0
- package/dist/esm/modules/formula/syntax/token-types.js +59 -0
- package/dist/esm/modules/formula/syntax/tokenizer.js +1074 -0
- package/dist/esm/modules/pdf/excel-bridge.js +9 -0
- package/dist/iife/excelts.iife.js +2302 -373
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +34 -34
- package/dist/types/index.browser.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/modules/excel/cell.d.ts +17 -3
- package/dist/types/modules/excel/defined-names.d.ts +96 -1
- package/dist/types/modules/excel/image.d.ts +11 -0
- package/dist/types/modules/excel/stream/workbook-reader.browser.d.ts +9 -3
- package/dist/types/modules/excel/stream/workbook-reader.d.ts +2 -1
- package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +39 -5
- package/dist/types/modules/excel/stream/workbook-writer.d.ts +3 -2
- package/dist/types/modules/excel/stream/worksheet-writer.d.ts +39 -6
- package/dist/types/modules/excel/types.d.ts +133 -2
- package/dist/types/modules/excel/utils/col-cache.d.ts +1 -0
- package/dist/types/modules/excel/utils/drawing-utils.d.ts +3 -3
- package/dist/types/modules/excel/utils/external-link-formula.d.ts +76 -0
- package/dist/types/modules/excel/utils/iterate-stream.d.ts +9 -3
- package/dist/types/modules/excel/utils/ooxml-paths.d.ts +19 -0
- package/dist/types/modules/excel/utils/shared-strings.d.ts +8 -3
- package/dist/types/modules/excel/utils/workbook-protection.d.ts +30 -0
- package/dist/types/modules/excel/workbook.browser.d.ts +257 -6
- package/dist/types/modules/excel/workbook.d.ts +1 -1
- package/dist/types/modules/excel/worksheet.d.ts +3 -1
- package/dist/types/modules/excel/xlsx/rel-type.d.ts +15 -0
- package/dist/types/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +6 -5
- package/dist/types/modules/excel/xlsx/xform/book/external-link-xform.d.ts +84 -0
- package/dist/types/modules/excel/xlsx/xform/book/external-reference-xform.d.ts +17 -0
- package/dist/types/modules/excel/xlsx/xform/book/workbook-calc-properties-xform.d.ts +3 -0
- package/dist/types/modules/excel/xlsx/xform/book/workbook-protection-xform.d.ts +20 -0
- package/dist/types/modules/excel/xlsx/xform/core/metadata-xform.d.ts +56 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.d.ts +26 -0
- package/dist/types/modules/excel/xlsx/xform/sheet/cell-xform.d.ts +1 -1
- package/dist/types/modules/excel/xlsx/xform/sheet/ignored-errors-xform.d.ts +21 -0
- package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +172 -13
- package/dist/types/modules/excel/xlsx/xlsx.d.ts +7 -4
- package/dist/types/modules/formula/compile/address-utils.d.ts +62 -0
- package/dist/types/modules/formula/compile/binder.d.ts +42 -0
- package/dist/types/modules/formula/compile/bound-ast.d.ts +230 -0
- package/dist/types/modules/formula/compile/compiled-formula.d.ts +137 -0
- package/dist/types/modules/formula/compile/dependency-analysis.d.ts +93 -0
- package/dist/types/modules/formula/compile/structured-ref-utils.d.ts +93 -0
- package/dist/types/modules/formula/default-syntax-probe.d.ts +79 -0
- package/dist/types/modules/formula/functions/_date-context.d.ts +4 -0
- package/dist/types/modules/formula/functions/_shared.d.ts +121 -0
- package/dist/types/modules/formula/functions/conditional.d.ts +27 -0
- package/dist/types/modules/formula/functions/database.d.ts +37 -0
- package/dist/types/modules/formula/functions/date.d.ts +61 -0
- package/dist/types/modules/formula/functions/dynamic-array.d.ts +23 -0
- package/dist/types/modules/formula/functions/engineering.d.ts +57 -0
- package/dist/types/modules/formula/functions/financial.d.ts +202 -0
- package/dist/types/modules/formula/functions/lookup.d.ts +18 -0
- package/dist/types/modules/formula/functions/math.d.ts +114 -0
- package/dist/types/modules/formula/functions/statistical.d.ts +193 -0
- package/dist/types/modules/formula/functions/text.d.ts +86 -0
- package/dist/types/modules/formula/host-registry.d.ts +53 -0
- package/dist/types/modules/formula/index.d.ts +39 -0
- package/dist/types/modules/formula/install.d.ts +62 -0
- package/dist/types/modules/formula/integration/apply-writeback-plan.d.ts +26 -0
- package/dist/types/modules/formula/integration/calculate-formulas-impl.d.ts +30 -0
- package/dist/types/modules/formula/integration/calculate-formulas.d.ts +67 -0
- package/dist/types/modules/formula/integration/formula-instance.d.ts +64 -0
- package/dist/types/modules/formula/integration/workbook-adapter.d.ts +26 -0
- package/dist/types/modules/formula/integration/workbook-snapshot.d.ts +267 -0
- package/dist/types/modules/formula/materialize/build-writeback-plan.d.ts +34 -0
- package/dist/types/modules/formula/materialize/spill-engine.d.ts +9 -0
- package/dist/types/modules/formula/materialize/types.d.ts +179 -0
- package/dist/types/modules/formula/materialize/writeback-plan.d.ts +167 -0
- package/dist/types/modules/formula/runtime/evaluator.d.ts +151 -0
- package/dist/types/modules/formula/runtime/function-registry.d.ts +47 -0
- package/dist/types/modules/formula/runtime/values.d.ts +211 -0
- package/dist/types/modules/formula/syntax/ast.d.ts +129 -0
- package/dist/types/modules/formula/syntax/parser.d.ts +18 -0
- package/dist/types/modules/formula/syntax/token-types.d.ts +153 -0
- package/dist/types/modules/formula/syntax/tokenizer.d.ts +10 -0
- package/package.json +28 -28
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency Graph for Formula Calculation
|
|
3
|
+
*
|
|
4
|
+
* Builds a dependency graph from compiled formulas' static dependencies,
|
|
5
|
+
* then produces a topological evaluation order with circular reference
|
|
6
|
+
* detection.
|
|
7
|
+
*
|
|
8
|
+
* Key exports:
|
|
9
|
+
* - `buildDependencyGraphFromDeps()` — build graph from CompiledFormula static deps
|
|
10
|
+
* - `topologicalSort()` — produce evaluation order, detecting circular refs
|
|
11
|
+
*/
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Cell Key Helpers
|
|
14
|
+
// ============================================================================
|
|
15
|
+
function makeKey(sheet, row, col) {
|
|
16
|
+
return `${sheet}!${row}:${col}`;
|
|
17
|
+
}
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Dependency Reference → Cell Key Expansion
|
|
20
|
+
// ============================================================================
|
|
21
|
+
/**
|
|
22
|
+
* Type guard: is this a range reference (has `top` property)?
|
|
23
|
+
*/
|
|
24
|
+
function isRange(ref) {
|
|
25
|
+
return "top" in ref;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Expand a set of DepRefs into concrete cell keys.
|
|
29
|
+
* For single-cell refs, the key is produced directly.
|
|
30
|
+
* For range refs, we check which formula cells fall within the range rather
|
|
31
|
+
* than enumerating every cell (which would be prohibitively expensive for
|
|
32
|
+
* whole-column ranges like A:A).
|
|
33
|
+
*/
|
|
34
|
+
function expandRefsToKeys(refs, formulaKeySet, formulaCellCoordsBySheet) {
|
|
35
|
+
const keys = new Set();
|
|
36
|
+
for (const ref of refs) {
|
|
37
|
+
if (isRange(ref)) {
|
|
38
|
+
const rangeSize = (ref.bottom - ref.top + 1) * (ref.right - ref.left + 1);
|
|
39
|
+
if (rangeSize <= 10000) {
|
|
40
|
+
// Small-to-medium range: enumerate every cell
|
|
41
|
+
for (let r = ref.top; r <= ref.bottom; r++) {
|
|
42
|
+
for (let c = ref.left; c <= ref.right; c++) {
|
|
43
|
+
keys.add(makeKey(ref.sheet, r, c));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Large range (e.g. whole column A:A): scan formula cells in the
|
|
49
|
+
// referenced sheet only and check containment.
|
|
50
|
+
const sheetCoords = formulaCellCoordsBySheet.get(ref.sheet);
|
|
51
|
+
if (sheetCoords) {
|
|
52
|
+
for (const [fKey, coord] of sheetCoords) {
|
|
53
|
+
if (coord.row >= ref.top &&
|
|
54
|
+
coord.row <= ref.bottom &&
|
|
55
|
+
coord.col >= ref.left &&
|
|
56
|
+
coord.col <= ref.right) {
|
|
57
|
+
keys.add(fKey);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Single cell — always add
|
|
65
|
+
keys.add(makeKey(ref.sheet, ref.row, ref.col));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return keys;
|
|
69
|
+
}
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// Build Dependency Graph from CompiledFormula StaticDeps
|
|
72
|
+
// ============================================================================
|
|
73
|
+
/**
|
|
74
|
+
* Build a dependency graph from compiled formulas' static dependencies.
|
|
75
|
+
*
|
|
76
|
+
* Operates on the already-resolved `StaticDependencySet` from each compiled
|
|
77
|
+
* formula. Since names and structured references are already resolved by
|
|
78
|
+
* the binder, the dependency edges are complete.
|
|
79
|
+
*
|
|
80
|
+
* @param compiled - Map from formula cell key to compiled formula with static deps
|
|
81
|
+
* @param producerMap - Optional map from cell key → formula key that produces
|
|
82
|
+
* that cell's value (via CSE distribution or dynamic-array spill). Allows
|
|
83
|
+
* dependency edges to be added to the producer even when the target cell
|
|
84
|
+
* isn't itself a formula.
|
|
85
|
+
* @returns The complete dependency graph
|
|
86
|
+
*/
|
|
87
|
+
export function buildDependencyGraphFromDeps(compiled, producerMap) {
|
|
88
|
+
// Build a lookup of all formula cell coordinates for range intersection.
|
|
89
|
+
// We group by sheet so that large-range containment scans only visit the
|
|
90
|
+
// relevant sheet's formula cells instead of the entire workbook.
|
|
91
|
+
const formulaKeySet = new Set();
|
|
92
|
+
const formulaCellCoordsBySheet = new Map();
|
|
93
|
+
const formulaKeys = [];
|
|
94
|
+
for (const [key, cf] of compiled) {
|
|
95
|
+
formulaKeySet.add(key);
|
|
96
|
+
// Use the instance's already-known coordinates instead of reverse-parsing
|
|
97
|
+
// the key string — saves two lastIndexOf calls and two parseInt calls
|
|
98
|
+
// per formula on cold-start.
|
|
99
|
+
const inst = cf.instance;
|
|
100
|
+
const coord = { sheet: inst.sheetName, row: inst.row, col: inst.col };
|
|
101
|
+
let list = formulaCellCoordsBySheet.get(inst.sheetName);
|
|
102
|
+
if (!list) {
|
|
103
|
+
list = [];
|
|
104
|
+
formulaCellCoordsBySheet.set(inst.sheetName, list);
|
|
105
|
+
}
|
|
106
|
+
list.push([key, coord]);
|
|
107
|
+
formulaKeys.push(key);
|
|
108
|
+
}
|
|
109
|
+
// Forward edges: formula key → set of keys it depends on
|
|
110
|
+
const dependsOn = new Map();
|
|
111
|
+
// Reverse edges: cell key → set of formula keys that depend on it
|
|
112
|
+
const dependedBy = new Map();
|
|
113
|
+
for (const [key, cf] of compiled) {
|
|
114
|
+
const deps = cf.staticDeps;
|
|
115
|
+
// Convert StaticDependencySet to DepRef[]
|
|
116
|
+
const refs = [];
|
|
117
|
+
// Direct cell deps always pass through verbatim.
|
|
118
|
+
for (const cell of deps.cells) {
|
|
119
|
+
refs.push({ sheet: cell.sheet, row: cell.row, col: cell.col });
|
|
120
|
+
}
|
|
121
|
+
// Area deps normally expand into every cell in the range. For areas
|
|
122
|
+
// that start at a dynamic-array master (e.g. the `A1:A5` in
|
|
123
|
+
// `SUM(A1:A5)` where A1 is a live `=SEQUENCE(5)`), we replace the
|
|
124
|
+
// expansion with a single dependency on the master. Evaluator-time
|
|
125
|
+
// `getCellValue` then reads the master's cached array result for
|
|
126
|
+
// the ghost positions, so downstream formulas see the full spill
|
|
127
|
+
// in the same calc pass. Without this, A2..A5 aren't yet in the
|
|
128
|
+
// snapshot on the first run and the SUM only picks up A1.
|
|
129
|
+
const dynMasterDeps = [];
|
|
130
|
+
for (const area of deps.areas) {
|
|
131
|
+
const topLeftKey = makeKey(area.sheet, area.top, area.left);
|
|
132
|
+
const masterCf = compiled.get(topLeftKey);
|
|
133
|
+
const isDynMaster = masterCf !== undefined &&
|
|
134
|
+
(masterCf.instance.isDynamicArray || masterCf.isDynamicArrayFunction);
|
|
135
|
+
if (isDynMaster) {
|
|
136
|
+
dynMasterDeps.push(topLeftKey);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
refs.push({
|
|
140
|
+
sheet: area.sheet,
|
|
141
|
+
top: area.top,
|
|
142
|
+
left: area.left,
|
|
143
|
+
bottom: area.bottom,
|
|
144
|
+
right: area.right
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// Expand to concrete cell keys
|
|
148
|
+
const depKeys = expandRefsToKeys(refs, formulaKeySet, formulaCellCoordsBySheet);
|
|
149
|
+
for (const mk of dynMasterDeps) {
|
|
150
|
+
depKeys.add(mk);
|
|
151
|
+
}
|
|
152
|
+
// Remap producer keys: if a dep points to a cell that's not a formula
|
|
153
|
+
// but IS produced by another formula (CSE target or spill target),
|
|
154
|
+
// depend on the producer instead.
|
|
155
|
+
if (producerMap && producerMap.size > 0) {
|
|
156
|
+
const remapped = new Set();
|
|
157
|
+
for (const depKey of depKeys) {
|
|
158
|
+
if (!formulaKeySet.has(depKey)) {
|
|
159
|
+
const producer = producerMap.get(depKey);
|
|
160
|
+
if (producer) {
|
|
161
|
+
remapped.add(producer);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
remapped.add(depKey);
|
|
166
|
+
}
|
|
167
|
+
dependsOn.set(key, remapped);
|
|
168
|
+
for (const depKey of remapped) {
|
|
169
|
+
let set = dependedBy.get(depKey);
|
|
170
|
+
if (!set) {
|
|
171
|
+
set = new Set();
|
|
172
|
+
dependedBy.set(depKey, set);
|
|
173
|
+
}
|
|
174
|
+
set.add(key);
|
|
175
|
+
}
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
dependsOn.set(key, depKeys);
|
|
179
|
+
// Build reverse index
|
|
180
|
+
for (const depKey of depKeys) {
|
|
181
|
+
let set = dependedBy.get(depKey);
|
|
182
|
+
if (!set) {
|
|
183
|
+
set = new Set();
|
|
184
|
+
dependedBy.set(depKey, set);
|
|
185
|
+
}
|
|
186
|
+
set.add(key);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// Detect circular references
|
|
190
|
+
const { circularKeys } = detectCircularRefs(formulaKeys, dependsOn);
|
|
191
|
+
return {
|
|
192
|
+
dependsOn,
|
|
193
|
+
dependedBy,
|
|
194
|
+
formulaKeys,
|
|
195
|
+
circularKeys
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
// ============================================================================
|
|
199
|
+
// Merge Runtime Dynamic Dependencies
|
|
200
|
+
// ============================================================================
|
|
201
|
+
/**
|
|
202
|
+
* Merge runtime-discovered dynamic dependencies into a dependency graph.
|
|
203
|
+
*
|
|
204
|
+
* After evaluating formulas that contain INDIRECT/OFFSET, the runtime
|
|
205
|
+
* dependency recorder has collected the actual cell accesses. This function
|
|
206
|
+
* incorporates those dynamic edges into the graph and re-detects cycles.
|
|
207
|
+
*
|
|
208
|
+
* Returns a new graph if edges were added, or the original graph if no
|
|
209
|
+
* dynamic deps were recorded.
|
|
210
|
+
*/
|
|
211
|
+
export function mergeDynamicDeps(graph, dynamicDeps) {
|
|
212
|
+
if (dynamicDeps.size === 0) {
|
|
213
|
+
return { graph, changed: false };
|
|
214
|
+
}
|
|
215
|
+
// First pass: detect whether any new edges would actually be added.
|
|
216
|
+
// Cloning the full dependsOn/dependedBy maps is expensive for large
|
|
217
|
+
// workbooks; skip it entirely when there's no real work to do.
|
|
218
|
+
let needsClone = false;
|
|
219
|
+
for (const [formulaKey, accessedKeys] of dynamicDeps) {
|
|
220
|
+
const existing = graph.dependsOn.get(formulaKey);
|
|
221
|
+
for (const k of accessedKeys) {
|
|
222
|
+
if (!existing || !existing.has(k)) {
|
|
223
|
+
needsClone = true;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (needsClone) {
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (!needsClone) {
|
|
232
|
+
return { graph, changed: false };
|
|
233
|
+
}
|
|
234
|
+
// Clone forward and reverse edges
|
|
235
|
+
const newDependsOn = new Map();
|
|
236
|
+
for (const [k, v] of graph.dependsOn) {
|
|
237
|
+
newDependsOn.set(k, new Set(v));
|
|
238
|
+
}
|
|
239
|
+
const newDependedBy = new Map();
|
|
240
|
+
for (const [k, v] of graph.dependedBy) {
|
|
241
|
+
newDependedBy.set(k, new Set(v));
|
|
242
|
+
}
|
|
243
|
+
// Add dynamic edges
|
|
244
|
+
for (const [formulaKey, accessedKeys] of dynamicDeps) {
|
|
245
|
+
let deps = newDependsOn.get(formulaKey);
|
|
246
|
+
if (!deps) {
|
|
247
|
+
deps = new Set();
|
|
248
|
+
newDependsOn.set(formulaKey, deps);
|
|
249
|
+
}
|
|
250
|
+
for (const accessedKey of accessedKeys) {
|
|
251
|
+
if (!deps.has(accessedKey)) {
|
|
252
|
+
deps.add(accessedKey);
|
|
253
|
+
// Update reverse edge
|
|
254
|
+
let rev = newDependedBy.get(accessedKey);
|
|
255
|
+
if (!rev) {
|
|
256
|
+
rev = new Set();
|
|
257
|
+
newDependedBy.set(accessedKey, rev);
|
|
258
|
+
}
|
|
259
|
+
rev.add(formulaKey);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
// Re-detect cycles with the augmented graph
|
|
264
|
+
const { circularKeys } = detectCircularRefs(graph.formulaKeys, newDependsOn);
|
|
265
|
+
return {
|
|
266
|
+
graph: {
|
|
267
|
+
dependsOn: newDependsOn,
|
|
268
|
+
dependedBy: newDependedBy,
|
|
269
|
+
formulaKeys: graph.formulaKeys,
|
|
270
|
+
circularKeys
|
|
271
|
+
},
|
|
272
|
+
changed: true
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
// ============================================================================
|
|
276
|
+
// Circular Reference Detection
|
|
277
|
+
// ============================================================================
|
|
278
|
+
/**
|
|
279
|
+
* Detect circular references using Tarjan's SCC algorithm.
|
|
280
|
+
*
|
|
281
|
+
* A formula is "circular" if it belongs to a strongly connected component
|
|
282
|
+
* of size > 1, or if it has a direct self-loop (A = f(A)).
|
|
283
|
+
*
|
|
284
|
+
* This correctly identifies ALL nodes in cycles, including nodes reachable
|
|
285
|
+
* only through cross-edges to already-visited SCC members — a case that
|
|
286
|
+
* a simple 3-color DFS misses (e.g. diamond cycles like A→B→C→A plus A→D→C).
|
|
287
|
+
*/
|
|
288
|
+
function detectCircularRefs(formulaKeys, dependsOn) {
|
|
289
|
+
const circularKeys = new Set();
|
|
290
|
+
// Tarjan's iterative SCC
|
|
291
|
+
const index = new Map();
|
|
292
|
+
const lowlink = new Map();
|
|
293
|
+
const onStack = new Set();
|
|
294
|
+
const sccStack = [];
|
|
295
|
+
let nextIndex = 0;
|
|
296
|
+
for (const startKey of formulaKeys) {
|
|
297
|
+
if (index.has(startKey)) {
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
const dfsStack = [];
|
|
301
|
+
index.set(startKey, nextIndex);
|
|
302
|
+
lowlink.set(startKey, nextIndex);
|
|
303
|
+
nextIndex++;
|
|
304
|
+
sccStack.push(startKey);
|
|
305
|
+
onStack.add(startKey);
|
|
306
|
+
dfsStack.push({
|
|
307
|
+
key: startKey,
|
|
308
|
+
iter: (dependsOn.get(startKey) ?? new Set())[Symbol.iterator](),
|
|
309
|
+
pendingChild: null
|
|
310
|
+
});
|
|
311
|
+
while (dfsStack.length > 0) {
|
|
312
|
+
const frame = dfsStack[dfsStack.length - 1];
|
|
313
|
+
// If we just returned from a child, update our lowlink
|
|
314
|
+
if (frame.pendingChild !== null) {
|
|
315
|
+
const childLow = lowlink.get(frame.pendingChild);
|
|
316
|
+
lowlink.set(frame.key, Math.min(lowlink.get(frame.key), childLow));
|
|
317
|
+
frame.pendingChild = null;
|
|
318
|
+
}
|
|
319
|
+
const next = frame.iter.next();
|
|
320
|
+
if (next.done) {
|
|
321
|
+
// Finished processing all children — check if this is an SCC root
|
|
322
|
+
if (lowlink.get(frame.key) === index.get(frame.key)) {
|
|
323
|
+
const scc = [];
|
|
324
|
+
let node;
|
|
325
|
+
do {
|
|
326
|
+
node = sccStack.pop();
|
|
327
|
+
onStack.delete(node);
|
|
328
|
+
scc.push(node);
|
|
329
|
+
} while (node !== frame.key);
|
|
330
|
+
// Mark as circular if SCC has > 1 node, OR if it's a self-loop
|
|
331
|
+
const hasSelfLoop = scc.length === 1 && dependsOn.get(scc[0])?.has(scc[0]);
|
|
332
|
+
if (scc.length > 1 || hasSelfLoop) {
|
|
333
|
+
for (const k of scc) {
|
|
334
|
+
circularKeys.add(k);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
dfsStack.pop();
|
|
339
|
+
// Record returning to parent so it can update its lowlink
|
|
340
|
+
if (dfsStack.length > 0) {
|
|
341
|
+
dfsStack[dfsStack.length - 1].pendingChild = frame.key;
|
|
342
|
+
}
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
const depKey = next.value;
|
|
346
|
+
if (!index.has(depKey)) {
|
|
347
|
+
// Unvisited — push new frame
|
|
348
|
+
index.set(depKey, nextIndex);
|
|
349
|
+
lowlink.set(depKey, nextIndex);
|
|
350
|
+
nextIndex++;
|
|
351
|
+
sccStack.push(depKey);
|
|
352
|
+
onStack.add(depKey);
|
|
353
|
+
dfsStack.push({
|
|
354
|
+
key: depKey,
|
|
355
|
+
iter: (dependsOn.get(depKey) ?? new Set())[Symbol.iterator](),
|
|
356
|
+
pendingChild: null
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
else if (onStack.has(depKey)) {
|
|
360
|
+
// Back edge — update lowlink with dep's index
|
|
361
|
+
lowlink.set(frame.key, Math.min(lowlink.get(frame.key), index.get(depKey)));
|
|
362
|
+
}
|
|
363
|
+
// Cross edge to fully-processed SCC: skip (correct Tarjan behavior)
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return { circularKeys };
|
|
367
|
+
}
|
|
368
|
+
// ============================================================================
|
|
369
|
+
// Topological Sort (Kahn's Algorithm)
|
|
370
|
+
// ============================================================================
|
|
371
|
+
/**
|
|
372
|
+
* Produce a topological evaluation order for formula cells using Kahn's algorithm.
|
|
373
|
+
* Cells with no dependencies are evaluated first. Circular references are
|
|
374
|
+
* appended at the end in their original order.
|
|
375
|
+
*/
|
|
376
|
+
export function topologicalSort(graph) {
|
|
377
|
+
const { formulaKeys, dependsOn, circularKeys } = graph;
|
|
378
|
+
const formulaKeySet = new Set(formulaKeys);
|
|
379
|
+
const inDegree = new Map();
|
|
380
|
+
for (const key of formulaKeys) {
|
|
381
|
+
if (circularKeys.has(key)) {
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const deps = dependsOn.get(key);
|
|
385
|
+
if (!deps) {
|
|
386
|
+
inDegree.set(key, 0);
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
let count = 0;
|
|
390
|
+
for (const depKey of deps) {
|
|
391
|
+
if (formulaKeySet.has(depKey) && !circularKeys.has(depKey)) {
|
|
392
|
+
count++;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
inDegree.set(key, count);
|
|
396
|
+
}
|
|
397
|
+
const queue = [];
|
|
398
|
+
for (const key of formulaKeys) {
|
|
399
|
+
if (circularKeys.has(key)) {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
if ((inDegree.get(key) ?? 0) === 0) {
|
|
403
|
+
queue.push(key);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const sorted = [];
|
|
407
|
+
let head = 0;
|
|
408
|
+
while (head < queue.length) {
|
|
409
|
+
const key = queue[head++];
|
|
410
|
+
sorted.push(key);
|
|
411
|
+
const dependents = graph.dependedBy.get(key);
|
|
412
|
+
if (dependents) {
|
|
413
|
+
for (const depKey of dependents) {
|
|
414
|
+
if (circularKeys.has(depKey) || !formulaKeySet.has(depKey)) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
const deg = (inDegree.get(depKey) ?? 1) - 1;
|
|
418
|
+
inDegree.set(depKey, deg);
|
|
419
|
+
if (deg === 0) {
|
|
420
|
+
queue.push(depKey);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
// Append circular reference cells at the end in original order
|
|
426
|
+
for (const key of formulaKeys) {
|
|
427
|
+
if (circularKeys.has(key)) {
|
|
428
|
+
sorted.push(key);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return sorted;
|
|
432
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for structured reference (table) row-range resolution.
|
|
3
|
+
*
|
|
4
|
+
* The row-range logic for structured references is needed in three places:
|
|
5
|
+
* - binder (compile-time range resolution)
|
|
6
|
+
* - compiled-formula (static dependency extraction)
|
|
7
|
+
* - evaluator (runtime evaluation)
|
|
8
|
+
*
|
|
9
|
+
* This module provides the canonical implementation to avoid triplication.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Derive `TableGeometry` from a table's snapshot fields.
|
|
13
|
+
*
|
|
14
|
+
* The data row range excludes the header (if any) but also excludes the
|
|
15
|
+
* totals row — totals, when present, occupy `dataRowEnd + 1`.
|
|
16
|
+
*/
|
|
17
|
+
export function buildTableGeometry(table) {
|
|
18
|
+
const topLeftRow = table.topLeft.row;
|
|
19
|
+
const dataRowStart = topLeftRow + (table.hasHeaderRow ? 1 : 0);
|
|
20
|
+
const dataRowEnd = dataRowStart + table.dataRowCount - 1;
|
|
21
|
+
return {
|
|
22
|
+
topLeftRow,
|
|
23
|
+
dataRowStart,
|
|
24
|
+
dataRowEnd,
|
|
25
|
+
hasHeaderRow: table.hasHeaderRow,
|
|
26
|
+
hasTotalsRow: table.hasTotalsRow
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a list of structured-reference column names to a contiguous
|
|
31
|
+
* column range `[colLeft, colRight]` in absolute sheet coordinates.
|
|
32
|
+
*
|
|
33
|
+
* @param columns - Requested column names (case-insensitive match).
|
|
34
|
+
* @param table - Table whose columns are searched.
|
|
35
|
+
* @param mode -
|
|
36
|
+
* - `"strict"` — return `"error"` if any name is missing (used by
|
|
37
|
+
* binder and evaluator — unknown columns are `#REF!` errors).
|
|
38
|
+
* - `"permissive"` — ignore missing names; if ALL names are missing,
|
|
39
|
+
* falls back to the full table width (used by static-deps extraction,
|
|
40
|
+
* where a conservative over-estimate is acceptable).
|
|
41
|
+
* @returns `{ colLeft, colRight }`, or `"error"` in strict mode when a
|
|
42
|
+
* column name is not found. If `columns` is empty, returns the full
|
|
43
|
+
* table width.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveStructuredRefColumns(columns, table, mode) {
|
|
46
|
+
const tl = table.topLeft;
|
|
47
|
+
const width = table.columns.length;
|
|
48
|
+
if (columns.length === 0) {
|
|
49
|
+
return { colLeft: tl.col, colRight: tl.col + width - 1 };
|
|
50
|
+
}
|
|
51
|
+
const indices = [];
|
|
52
|
+
for (const colName of columns) {
|
|
53
|
+
const idx = table.columns.findIndex(c => c.name.toLowerCase() === colName.toLowerCase());
|
|
54
|
+
if (idx === -1) {
|
|
55
|
+
if (mode === "strict") {
|
|
56
|
+
return "error";
|
|
57
|
+
}
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
indices.push(idx);
|
|
61
|
+
}
|
|
62
|
+
if (indices.length === 0) {
|
|
63
|
+
// permissive + all names missing → conservative full-width fallback
|
|
64
|
+
return { colLeft: tl.col, colRight: tl.col + width - 1 };
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
colLeft: tl.col + Math.min(...indices),
|
|
68
|
+
colRight: tl.col + Math.max(...indices)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Resolve structured reference specials to a row range.
|
|
73
|
+
*
|
|
74
|
+
* This is the single source of truth for the mapping from
|
|
75
|
+
* `#All`, `#Headers`, `#Data`, `#Totals`, `#This Row` (and their
|
|
76
|
+
* combinations) to concrete row numbers.
|
|
77
|
+
*/
|
|
78
|
+
export function resolveStructuredRefRows(specials, geo) {
|
|
79
|
+
// Tokenizer stashes unknown `[#Something]` tokens with a sentinel
|
|
80
|
+
// prefix. Surface them as errors rather than let them alias to the
|
|
81
|
+
// default-data-range path below.
|
|
82
|
+
for (const s of specials) {
|
|
83
|
+
if (s.startsWith("#__INVALID__")) {
|
|
84
|
+
return "error";
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const hasAll = specials.includes("#All");
|
|
88
|
+
const hasHeaders = specials.includes("#Headers");
|
|
89
|
+
const hasTotals = specials.includes("#Totals");
|
|
90
|
+
const hasData = specials.includes("#Data");
|
|
91
|
+
const hasThisRow = specials.includes("#This Row");
|
|
92
|
+
if (hasAll) {
|
|
93
|
+
return {
|
|
94
|
+
rowTop: geo.topLeftRow,
|
|
95
|
+
rowBottom: geo.hasTotalsRow ? geo.dataRowEnd + 1 : geo.dataRowEnd
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (hasThisRow) {
|
|
99
|
+
return "thisRow";
|
|
100
|
+
}
|
|
101
|
+
if (hasHeaders && hasTotals) {
|
|
102
|
+
return {
|
|
103
|
+
rowTop: geo.topLeftRow,
|
|
104
|
+
rowBottom: geo.hasTotalsRow ? geo.dataRowEnd + 1 : geo.dataRowEnd
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (hasHeaders && hasData) {
|
|
108
|
+
return {
|
|
109
|
+
rowTop: geo.hasHeaderRow ? geo.topLeftRow : geo.dataRowStart,
|
|
110
|
+
rowBottom: geo.dataRowEnd
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (hasData && hasTotals) {
|
|
114
|
+
return {
|
|
115
|
+
rowTop: geo.dataRowStart,
|
|
116
|
+
rowBottom: geo.hasTotalsRow ? geo.dataRowEnd + 1 : geo.dataRowEnd
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
if (hasHeaders) {
|
|
120
|
+
if (geo.hasHeaderRow) {
|
|
121
|
+
return { rowTop: geo.topLeftRow, rowBottom: geo.topLeftRow };
|
|
122
|
+
}
|
|
123
|
+
// Table without a header row: Excel reports #REF! rather than silently
|
|
124
|
+
// aliasing to the first data row. Returning the data row here would
|
|
125
|
+
// route `Table1[#Headers]` to real data values, masking user mistakes.
|
|
126
|
+
return "error";
|
|
127
|
+
}
|
|
128
|
+
if (hasTotals) {
|
|
129
|
+
if (geo.hasTotalsRow) {
|
|
130
|
+
return { rowTop: geo.dataRowEnd + 1, rowBottom: geo.dataRowEnd + 1 };
|
|
131
|
+
}
|
|
132
|
+
return "error";
|
|
133
|
+
}
|
|
134
|
+
// #Data or no specials → data range
|
|
135
|
+
return { rowTop: geo.dataRowStart, rowBottom: geo.dataRowEnd };
|
|
136
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formula-syntax probe slot.
|
|
3
|
+
*
|
|
4
|
+
* ## What this is
|
|
5
|
+
*
|
|
6
|
+
* `DefinedNames` (in the excel module) needs a way to tell whether a raw
|
|
7
|
+
* defined-name text like `OFFSET(Sheet1!$A$1,0,0,3,1)` is a parseable
|
|
8
|
+
* formula or opaque content to preserve verbatim. The only authoritative
|
|
9
|
+
* answer comes from the formula tokenizer + parser, which ship in the
|
|
10
|
+
* `@cj-tech-master/excelts/formula` subpath and are an opt-in
|
|
11
|
+
* dependency.
|
|
12
|
+
*
|
|
13
|
+
* This file is a tiny passive registration slot — a single `let` with
|
|
14
|
+
* a getter/setter pair — carrying **no** formula-engine code. Importing
|
|
15
|
+
* `DefinedNames` pulls in this slot (~0.5 KB minified) but never drags
|
|
16
|
+
* in the tokenizer, parser, or evaluator.
|
|
17
|
+
*
|
|
18
|
+
* ## Classification semantics
|
|
19
|
+
*
|
|
20
|
+
* - **No probe installed** (default): `DefinedNames` classifies any
|
|
21
|
+
* non-range, non-wrapper text as **opaque**. The `rawText` is
|
|
22
|
+
* preserved so XLSX round-trip bytes are stable; the entry simply
|
|
23
|
+
* cannot be evaluated — which is correct, because no formula engine
|
|
24
|
+
* is available anyway.
|
|
25
|
+
*
|
|
26
|
+
* - **Probe installed** (after `installFormulaEngine()`): `DefinedNames`
|
|
27
|
+
* classifies strictly. Parseable text becomes `formula`, unparseable
|
|
28
|
+
* text becomes `opaque`.
|
|
29
|
+
*
|
|
30
|
+
* ## Why the slot lives in the formula module
|
|
31
|
+
*
|
|
32
|
+
* Module dependency direction: `excel` may import from `formula`
|
|
33
|
+
* (layer 4 → layer 3), but `formula` must not import from `excel`. The
|
|
34
|
+
* probe slot is a *formula-module concept* (it wraps a formula
|
|
35
|
+
* tokenizer+parser) that excel consults; keeping it here preserves the
|
|
36
|
+
* one-way dependency.
|
|
37
|
+
*
|
|
38
|
+
* ## Construction-time injection is also supported
|
|
39
|
+
*
|
|
40
|
+
* `Workbook` and `DefinedNames` each accept an explicit
|
|
41
|
+
* `formulaSyntaxProbe` option. That is the preferred API for callers
|
|
42
|
+
* who want deterministic, per-instance behaviour (e.g. a test that
|
|
43
|
+
* needs a specific probe without touching process-global state). The
|
|
44
|
+
* default-probe slot here is the convenience layer for
|
|
45
|
+
* `installFormulaEngine()` — call it once at startup and every
|
|
46
|
+
* subsequent `new Workbook()` picks up strict classification
|
|
47
|
+
* automatically.
|
|
48
|
+
*
|
|
49
|
+
* ## Lookup timing
|
|
50
|
+
*
|
|
51
|
+
* `DefinedNames` reads the default probe lazily, at the moment `model`
|
|
52
|
+
* is assigned (i.e. during XLSX parsing). This means the common
|
|
53
|
+
* sequence
|
|
54
|
+
*
|
|
55
|
+
* ```ts
|
|
56
|
+
* const wb = new Workbook();
|
|
57
|
+
* installFormulaEngine(); // later
|
|
58
|
+
* await wb.xlsx.load(buffer); // sees the installed probe
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* works correctly — the probe installed before `load()` is the one
|
|
62
|
+
* used, regardless of when `Workbook` itself was constructed.
|
|
63
|
+
*/
|
|
64
|
+
let defaultProbe = null;
|
|
65
|
+
/**
|
|
66
|
+
* Install (or clear) the process-wide default syntax probe.
|
|
67
|
+
*
|
|
68
|
+
* Called from `installFormulaEngine()` in `./install`. Passing `null`
|
|
69
|
+
* uninstalls the probe — symmetric with the formula-engine registry and
|
|
70
|
+
* useful for tests that exercise the "no probe" classification path.
|
|
71
|
+
*/
|
|
72
|
+
export function setDefaultSyntaxProbe(probe) {
|
|
73
|
+
defaultProbe = probe;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Retrieve the currently-installed default probe, or `null` if none is
|
|
77
|
+
* installed. Consumers (chiefly `DefinedNames`) should treat `null` as
|
|
78
|
+
* a signal to use conservative (opaque) classification rather than
|
|
79
|
+
* guessing.
|
|
80
|
+
*/
|
|
81
|
+
export function getDefaultSyntaxProbe() {
|
|
82
|
+
return defaultProbe;
|
|
83
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Date context shared between formula functions and the evaluator.
|
|
3
|
+
*
|
|
4
|
+
* Native function signatures (`NativeFn = (args: RuntimeValue[]) => RuntimeValue`)
|
|
5
|
+
* have no access to the evaluation context, so date/time functions cannot
|
|
6
|
+
* receive the workbook's `date1904` flag through a parameter. Rather than
|
|
7
|
+
* plumb a new argument through 200+ function signatures, we store the flag
|
|
8
|
+
* in a module-local variable. The evaluator sets it before evaluating any
|
|
9
|
+
* formula in a calculation session.
|
|
10
|
+
*
|
|
11
|
+
* ## Thread safety
|
|
12
|
+
*
|
|
13
|
+
* JavaScript runtimes are single-threaded and a single calculation session
|
|
14
|
+
* operates on exactly one workbook at a time, so a module-level variable is
|
|
15
|
+
* safe in practice. If the engine is ever extended to support concurrent
|
|
16
|
+
* calculations across different workbooks (e.g. via worker threads), each
|
|
17
|
+
* worker will have its own module instance and remain correctly isolated.
|
|
18
|
+
* Nested synchronous calls within the same session all share the same
|
|
19
|
+
* workbook, so the flag remains correct throughout.
|
|
20
|
+
*/
|
|
21
|
+
let currentDate1904 = false;
|
|
22
|
+
/** Set the workbook-wide `date1904` mode for the current calculation session. */
|
|
23
|
+
export function setDate1904(v) {
|
|
24
|
+
currentDate1904 = v;
|
|
25
|
+
}
|
|
26
|
+
/** Read the workbook-wide `date1904` mode. */
|
|
27
|
+
export function isDate1904() {
|
|
28
|
+
return currentDate1904;
|
|
29
|
+
}
|