@svgrid/enterprise 3.0.1 → 3.0.3
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/LICENSE +94 -24
- package/README.md +36 -4
- package/dist/SvAdvancedFilter.svelte +1 -1
- package/dist/SvAlertsManager.svelte +2 -1
- package/dist/SvBoard.svelte +2 -1
- package/dist/SvExportMenu.svelte +4 -1
- package/dist/SvExportMenu.svelte.d.ts +0 -13
- package/dist/SvExpressionEditor.svelte +3 -3
- package/dist/SvFormulaBar.svelte +680 -0
- package/dist/SvFormulaBar.svelte.d.ts +69 -0
- package/dist/SvGridAlerts.svelte +49 -9
- package/dist/SvGridBoard.svelte +13 -8
- package/dist/SvGridBulkEditDrawer.svelte +26 -2
- package/dist/SvGridEditPanel.svelte +3 -0
- package/dist/SvGridScheduler.svelte +69 -40
- package/dist/SvGridSelectionBar.svelte +10 -3
- package/dist/SvPivotDesigner.svelte +263 -54
- package/dist/SvPivotDesigner.svelte.d.ts +27 -20
- package/dist/SvRibbonIcon.svelte +46 -0
- package/dist/SvRibbonIcon.svelte.d.ts +17 -0
- package/dist/SvSchemaChart.svelte +4 -2
- package/dist/SvSheet.svelte +7914 -0
- package/dist/SvSheet.svelte.d.ts +215 -0
- package/dist/SvSheetChartSetup.svelte +151 -0
- package/dist/SvSheetChartSetup.svelte.d.ts +18 -0
- package/dist/SvSheetComment.svelte +283 -0
- package/dist/SvSheetComment.svelte.d.ts +22 -0
- package/dist/SvSheetConditionalFormat.svelte +159 -0
- package/dist/SvSheetConditionalFormat.svelte.d.ts +14 -0
- package/dist/SvSheetDataValidation.svelte +273 -0
- package/dist/SvSheetDataValidation.svelte.d.ts +14 -0
- package/dist/SvSheetEditRanges.svelte +217 -0
- package/dist/SvSheetEditRanges.svelte.d.ts +15 -0
- package/dist/SvSheetErrors.svelte +125 -0
- package/dist/SvSheetErrors.svelte.d.ts +20 -0
- package/dist/SvSheetEvaluate.svelte +133 -0
- package/dist/SvSheetEvaluate.svelte.d.ts +15 -0
- package/dist/SvSheetFilterMenu.svelte +320 -0
- package/dist/SvSheetFilterMenu.svelte.d.ts +22 -0
- package/dist/SvSheetFindReplace.svelte +132 -0
- package/dist/SvSheetFindReplace.svelte.d.ts +10 -0
- package/dist/SvSheetFormatCells.svelte +465 -0
- package/dist/SvSheetFormatCells.svelte.d.ts +17 -0
- package/dist/SvSheetGoalSeek.svelte +145 -0
- package/dist/SvSheetGoalSeek.svelte.d.ts +12 -0
- package/dist/SvSheetInsertFunction.svelte +149 -0
- package/dist/SvSheetInsertFunction.svelte.d.ts +8 -0
- package/dist/SvSheetIteration.svelte +81 -0
- package/dist/SvSheetIteration.svelte.d.ts +10 -0
- package/dist/SvSheetLink.svelte +99 -0
- package/dist/SvSheetLink.svelte.d.ts +17 -0
- package/dist/SvSheetListPicker.svelte +91 -0
- package/dist/SvSheetListPicker.svelte.d.ts +10 -0
- package/dist/SvSheetManageRules.svelte +187 -0
- package/dist/SvSheetManageRules.svelte.d.ts +16 -0
- package/dist/SvSheetNameManager.svelte +227 -0
- package/dist/SvSheetNameManager.svelte.d.ts +11 -0
- package/dist/SvSheetPageSetup.svelte +159 -0
- package/dist/SvSheetPageSetup.svelte.d.ts +13 -0
- package/dist/SvSheetPasteSpecial.svelte +107 -0
- package/dist/SvSheetPasteSpecial.svelte.d.ts +12 -0
- package/dist/SvSheetPivot.svelte +220 -0
- package/dist/SvSheetPivot.svelte.d.ts +21 -0
- package/dist/SvSheetProtectSheet.svelte +81 -0
- package/dist/SvSheetProtectSheet.svelte.d.ts +11 -0
- package/dist/SvSheetRemoveDuplicates.svelte +152 -0
- package/dist/SvSheetRemoveDuplicates.svelte.d.ts +12 -0
- package/dist/SvSheetRibbon.svelte +1254 -0
- package/dist/SvSheetRibbon.svelte.d.ts +34 -0
- package/dist/SvSheetSizeDialog.svelte +60 -0
- package/dist/SvSheetSizeDialog.svelte.d.ts +11 -0
- package/dist/SvSheetSort.svelte +218 -0
- package/dist/SvSheetSort.svelte.d.ts +28 -0
- package/dist/SvSheetSparklines.svelte +135 -0
- package/dist/SvSheetSparklines.svelte.d.ts +14 -0
- package/dist/SvSheetTable.svelte +160 -0
- package/dist/SvSheetTable.svelte.d.ts +24 -0
- package/dist/SvSheetTabs.svelte +571 -0
- package/dist/SvSheetTabs.svelte.d.ts +50 -0
- package/dist/SvSheetTabs.test-harness.svelte.d.ts +17 -0
- package/dist/SvSheetTabs.test-harness.svelte.js +22 -0
- package/dist/SvSheetTextToColumns.svelte +172 -0
- package/dist/SvSheetTextToColumns.svelte.d.ts +13 -0
- package/dist/SvSheetValidationAlert.svelte +85 -0
- package/dist/SvSheetValidationAlert.svelte.d.ts +15 -0
- package/dist/advanced-filter-enable.js +1 -1
- package/dist/alerts/alert-engine.d.ts +6 -0
- package/dist/alerts/alert-engine.js +21 -4
- package/dist/alerts/alert-formats.js +2 -0
- package/dist/alerts/alert-types.d.ts +1 -1
- package/dist/alerts.d.ts +1 -1
- package/dist/alerts.js +2 -2
- package/dist/board.js +2 -2
- package/dist/bulk-edit.d.ts +3 -1
- package/dist/bulk-edit.js +1 -1
- package/dist/cdn/svgrid-enterprise.svelte-external.js +43538 -6539
- package/dist/designer/assets/GridMenus-8gTNssgV.js +8 -0
- package/dist/designer/assets/SvChartMenu-BDoeqGz6.js +1 -0
- package/dist/designer/assets/SvChartMenu-BYO9cYdy.css +1 -0
- package/dist/designer/assets/SvDateRangeInput-BBRzrQeg.js +1 -0
- package/dist/designer/assets/SvDateTimePicker-DCPg7WGN.js +1 -0
- package/dist/designer/assets/SvGridCellEditor-DMoWJjEI.js +4 -0
- package/dist/designer/assets/SvGridChart-BgLuPO7I.css +1 -0
- package/dist/designer/assets/SvGridChart-Cy1ATrWh.js +3 -0
- package/dist/designer/assets/SvGridChartBuilder-08YWWeqY.css +1 -0
- package/dist/designer/assets/SvGridChartBuilder-eQ3mn0L9.js +1 -0
- package/dist/designer/assets/SvGridChartPanel-4Pc8y5yO.css +1 -0
- package/dist/designer/assets/SvGridChartPanel-CATdVc9X.js +4 -0
- package/dist/designer/assets/{SvGridChartView-DUc-1RUf.css → SvGridChartView-7msfnWZT.css} +1 -1
- package/dist/designer/assets/SvGridChartView-CmsZtCED.js +1 -0
- package/dist/designer/assets/SvGridDropdown-Cjz0H-fI.js +1 -0
- package/dist/designer/assets/SvListBox-BDS66lmZ.js +110 -0
- package/dist/designer/assets/SvMenuList-DJ47ba1h.css +1 -0
- package/dist/designer/assets/SvMenuList-Dgq2D5VN.js +1 -0
- package/dist/designer/assets/SvTabs-2mHC6oaz.js +1 -0
- package/dist/designer/assets/SvTabs-DKmwb5p1.css +1 -0
- package/dist/designer/assets/cell-formatting-BbubJTVz.js +1 -0
- package/dist/designer/assets/chart-Cn7MnNqA.js +1 -0
- package/dist/designer/assets/chart-export-B6bkQ3X8.js +11 -0
- package/dist/designer/assets/chart-export-pdf-BbA28-gt.js +11 -0
- package/dist/designer/assets/chart-panel-messages-Dz7PTIqT.js +1 -0
- package/dist/designer/assets/chart-summary-BD1qYB2R.js +1 -0
- package/dist/designer/assets/chart-trend-B8xr5LuD.js +1 -0
- package/dist/designer/assets/chart-validate-BMqM-qkF.js +1 -0
- package/dist/designer/assets/column-resize-BYDzR1Ve.js +1 -0
- package/dist/designer/assets/date-format-B8JbEtIG.js +1 -0
- package/dist/designer/assets/date-format-DKS-z0xS.css +1 -0
- package/dist/designer/assets/{dismissable-BO547MH9.js → dismissable-ChWRPkoa.js} +1 -1
- package/dist/designer/assets/editor-contract-Bpoa7A5g.js +1 -0
- package/dist/designer/assets/{export-format-D-eP4b2l.js → export-format-DGckmgKr.js} +1 -1
- package/dist/designer/assets/focus-trap-V2-6Fy9I.js +1 -0
- package/dist/designer/assets/{index-C_a9Cj8Y.js → index-D5bVbuzI.js} +318 -315
- package/dist/designer/assets/index-_JVFxt02.css +1 -0
- package/dist/designer/assets/list-option-BP_dWS66.js +1 -0
- package/dist/designer/assets/row-resize-BInFWCpr.js +1 -0
- package/dist/designer/assets/server-block-cache-CXJKkJpy.js +1 -0
- package/dist/designer/assets/src-CITpcm6b.js +1 -0
- package/dist/designer/assets/src-DUQ4xE3x.js +58 -0
- package/dist/designer/assets/validate-C3B8QKsM.js +1 -0
- package/dist/designer/index.html +29 -19
- package/dist/export-pdf.d.ts +164 -0
- package/dist/export-pdf.js +346 -15
- package/dist/export.js +25 -10
- package/dist/gantt/SvGridGantt.svelte +2890 -0
- package/dist/gantt/SvGridGantt.svelte.d.ts +30 -0
- package/dist/gantt/gantt-config.d.ts +73 -0
- package/dist/gantt/gantt-config.js +1 -0
- package/dist/gantt/gantt-critical-path.d.ts +67 -0
- package/dist/gantt/gantt-critical-path.js +207 -0
- package/dist/gantt/gantt-model.d.ts +257 -0
- package/dist/gantt/gantt-model.js +651 -0
- package/dist/gantt/gantt-resources.d.ts +59 -0
- package/dist/gantt/gantt-resources.js +71 -0
- package/dist/gantt/gantt.d.ts +7 -0
- package/dist/gantt/gantt.js +36 -0
- package/dist/gantt/index.d.ts +15 -0
- package/dist/gantt/index.js +22 -0
- package/dist/gantt/timeline-arrows.d.ts +102 -0
- package/dist/gantt/timeline-arrows.js +181 -0
- package/dist/import.d.ts +2 -2
- package/dist/import.js +1 -1
- package/dist/index.d.ts +93 -3
- package/dist/index.js +107 -3
- package/dist/install.js +13 -1
- package/dist/license-core.d.ts +17 -1
- package/dist/license-core.js +16 -5
- package/dist/license.d.ts +18 -2
- package/dist/license.js +71 -6
- package/dist/node/studio.js +203 -9
- package/dist/pivot-chart.d.ts +25 -1
- package/dist/pivot-chart.js +25 -69
- package/dist/pivot-enable.js +2 -2
- package/dist/scheduler-dependencies.d.ts +35 -0
- package/dist/scheduler-dependencies.js +36 -1
- package/dist/scheduler.js +2 -2
- package/dist/selection-bar.js +2 -2
- package/dist/server/SvGroupCell.svelte +213 -0
- package/dist/server/SvGroupCell.svelte.d.ts +62 -0
- package/dist/server/SvRowGroupPanel.svelte +322 -0
- package/dist/server/SvRowGroupPanel.svelte.d.ts +37 -0
- package/dist/server/enable.d.ts +17 -0
- package/dist/server/enable.js +49 -0
- package/dist/server/index.d.ts +22 -0
- package/dist/server/index.js +24 -0
- package/dist/server/messages.d.ts +45 -0
- package/dist/server/messages.js +35 -0
- package/dist/server/server-group-model.d.ts +104 -0
- package/dist/server/server-group-model.js +272 -0
- package/dist/server/server-pivot.d.ts +46 -0
- package/dist/server/server-pivot.js +57 -0
- package/dist/server/server-row-model.d.ts +547 -0
- package/dist/server/server-row-model.js +1551 -0
- package/dist/server/server-selection.d.ts +99 -0
- package/dist/server/server-selection.js +215 -0
- package/dist/server/svgrid-adapter.d.ts +155 -0
- package/dist/server/svgrid-adapter.js +202 -0
- package/dist/sheet/address.d.ts +43 -0
- package/dist/sheet/address.js +81 -0
- package/dist/sheet/ast.d.ts +138 -0
- package/dist/sheet/ast.js +70 -0
- package/dist/sheet/auto-filter.d.ts +120 -0
- package/dist/sheet/auto-filter.js +295 -0
- package/dist/sheet/autocomplete.d.ts +51 -0
- package/dist/sheet/autocomplete.js +248 -0
- package/dist/sheet/cell-images.d.ts +39 -0
- package/dist/sheet/cell-images.js +90 -0
- package/dist/sheet/cell-types.d.ts +58 -0
- package/dist/sheet/cell-types.js +96 -0
- package/dist/sheet/coerce.d.ts +71 -0
- package/dist/sheet/coerce.js +289 -0
- package/dist/sheet/commands.d.ts +89 -0
- package/dist/sheet/commands.js +230 -0
- package/dist/sheet/comments.d.ts +63 -0
- package/dist/sheet/comments.js +131 -0
- package/dist/sheet/conditional-formats.d.ts +167 -0
- package/dist/sheet/conditional-formats.js +341 -0
- package/dist/sheet/csv.d.ts +32 -0
- package/dist/sheet/csv.js +158 -0
- package/dist/sheet/culture.d.ts +87 -0
- package/dist/sheet/culture.js +247 -0
- package/dist/sheet/delta.d.ts +102 -0
- package/dist/sheet/delta.js +203 -0
- package/dist/sheet/deps.d.ts +104 -0
- package/dist/sheet/deps.js +274 -0
- package/dist/sheet/document.d.ts +252 -0
- package/dist/sheet/document.js +465 -0
- package/dist/sheet/edit-keys.d.ts +14 -0
- package/dist/sheet/edit-keys.js +40 -0
- package/dist/sheet/engine.d.ts +67 -0
- package/dist/sheet/engine.js +19 -0
- package/dist/sheet/entry.d.ts +35 -0
- package/dist/sheet/entry.js +226 -0
- package/dist/sheet/error-check.d.ts +49 -0
- package/dist/sheet/error-check.js +83 -0
- package/dist/sheet/evaluate-steps.d.ts +48 -0
- package/dist/sheet/evaluate-steps.js +196 -0
- package/dist/sheet/evaluate.d.ts +128 -0
- package/dist/sheet/evaluate.js +1049 -0
- package/dist/sheet/filter-files.d.ts +37 -0
- package/dist/sheet/filter-files.js +465 -0
- package/dist/sheet/find-replace.d.ts +62 -0
- package/dist/sheet/find-replace.js +152 -0
- package/dist/sheet/format-store.d.ts +114 -0
- package/dist/sheet/format-store.js +243 -0
- package/dist/sheet/freeze.d.ts +54 -0
- package/dist/sheet/freeze.js +58 -0
- package/dist/sheet/from-rows.d.ts +14 -0
- package/dist/sheet/from-rows.js +50 -0
- package/dist/sheet/function-catalog.d.ts +10 -0
- package/dist/sheet/function-catalog.js +385 -0
- package/dist/sheet/functions.d.ts +28 -0
- package/dist/sheet/functions.js +634 -0
- package/dist/sheet/goal-seek.d.ts +73 -0
- package/dist/sheet/goal-seek.js +153 -0
- package/dist/sheet/index.d.ts +80 -0
- package/dist/sheet/index.js +80 -0
- package/dist/sheet/links.d.ts +57 -0
- package/dist/sheet/links.js +174 -0
- package/dist/sheet/merges.d.ts +71 -0
- package/dist/sheet/merges.js +137 -0
- package/dist/sheet/messages.d.ts +778 -0
- package/dist/sheet/messages.js +806 -0
- package/dist/sheet/names.d.ts +31 -0
- package/dist/sheet/names.js +87 -0
- package/dist/sheet/navigate.d.ts +52 -0
- package/dist/sheet/navigate.js +135 -0
- package/dist/sheet/number-format.d.ts +110 -0
- package/dist/sheet/number-format.js +905 -0
- package/dist/sheet/objects.d.ts +106 -0
- package/dist/sheet/objects.js +149 -0
- package/dist/sheet/ods-document.d.ts +44 -0
- package/dist/sheet/ods-document.js +1275 -0
- package/dist/sheet/open-file.d.ts +26 -0
- package/dist/sheet/open-file.js +56 -0
- package/dist/sheet/outline.d.ts +82 -0
- package/dist/sheet/outline.js +228 -0
- package/dist/sheet/packs/array.d.ts +16 -0
- package/dist/sheet/packs/array.js +172 -0
- package/dist/sheet/packs/database.d.ts +42 -0
- package/dist/sheet/packs/database.js +142 -0
- package/dist/sheet/packs/engineering.d.ts +2 -0
- package/dist/sheet/packs/engineering.js +296 -0
- package/dist/sheet/packs/financial.d.ts +5 -0
- package/dist/sheet/packs/financial.js +220 -0
- package/dist/sheet/packs/math-stats.d.ts +2 -0
- package/dist/sheet/packs/math-stats.js +372 -0
- package/dist/sheet/packs/special.d.ts +44 -0
- package/dist/sheet/packs/special.js +187 -0
- package/dist/sheet/packs/stats-dist.d.ts +2 -0
- package/dist/sheet/packs/stats-dist.js +785 -0
- package/dist/sheet/packs/text-date.d.ts +2 -0
- package/dist/sheet/packs/text-date.js +332 -0
- package/dist/sheet/packs/trig.d.ts +2 -0
- package/dist/sheet/packs/trig.js +73 -0
- package/dist/sheet/page-setup.d.ts +73 -0
- package/dist/sheet/page-setup.js +73 -0
- package/dist/sheet/palette.d.ts +19 -0
- package/dist/sheet/palette.js +84 -0
- package/dist/sheet/parse.d.ts +13 -0
- package/dist/sheet/parse.js +140 -0
- package/dist/sheet/paste-special.d.ts +186 -0
- package/dist/sheet/paste-special.js +601 -0
- package/dist/sheet/pivot-range.d.ts +160 -0
- package/dist/sheet/pivot-range.js +333 -0
- package/dist/sheet/presence.d.ts +73 -0
- package/dist/sheet/presence.js +79 -0
- package/dist/sheet/print.d.ts +104 -0
- package/dist/sheet/print.js +169 -0
- package/dist/sheet/protection.d.ts +75 -0
- package/dist/sheet/protection.js +101 -0
- package/dist/sheet/rects.d.ts +45 -0
- package/dist/sheet/rects.js +112 -0
- package/dist/sheet/refs.d.ts +130 -0
- package/dist/sheet/refs.js +413 -0
- package/dist/sheet/ribbon-icons.d.ts +31 -0
- package/dist/sheet/ribbon-icons.js +536 -0
- package/dist/sheet/ribbon.d.ts +173 -0
- package/dist/sheet/ribbon.js +1054 -0
- package/dist/sheet/sheet-kinds.d.ts +74 -0
- package/dist/sheet/sheet-kinds.js +91 -0
- package/dist/sheet/shortcuts.d.ts +174 -0
- package/dist/sheet/shortcuts.js +674 -0
- package/dist/sheet/sort.d.ts +51 -0
- package/dist/sheet/sort.js +107 -0
- package/dist/sheet/sparklines.d.ts +111 -0
- package/dist/sheet/sparklines.js +204 -0
- package/dist/sheet/structure.d.ts +87 -0
- package/dist/sheet/structure.js +166 -0
- package/dist/sheet/table-styles.d.ts +74 -0
- package/dist/sheet/table-styles.js +152 -0
- package/dist/sheet/tables.d.ts +89 -0
- package/dist/sheet/tables.js +178 -0
- package/dist/sheet/tokenize.d.ts +71 -0
- package/dist/sheet/tokenize.js +355 -0
- package/dist/sheet/transforms.d.ts +76 -0
- package/dist/sheet/transforms.js +154 -0
- package/dist/sheet/validation.d.ts +108 -0
- package/dist/sheet/validation.js +278 -0
- package/dist/sheet/workbook.d.ts +217 -0
- package/dist/sheet/workbook.js +1120 -0
- package/dist/sheet/xls-cfb.d.ts +32 -0
- package/dist/sheet/xls-cfb.js +290 -0
- package/dist/sheet/xls-document.d.ts +10 -0
- package/dist/sheet/xls-document.js +1243 -0
- package/dist/sheet/xls-formula.d.ts +40 -0
- package/dist/sheet/xls-formula.js +569 -0
- package/dist/sheet/xlsx-document.d.ts +108 -0
- package/dist/sheet/xlsx-document.js +1849 -0
- package/dist/sheet/xlsx-drawing.d.ts +99 -0
- package/dist/sheet/xlsx-drawing.js +420 -0
- package/dist/sheet-enable.d.ts +6 -0
- package/dist/sheet-enable.js +45 -0
- package/dist/sheet-text.d.ts +7 -0
- package/dist/sheet-text.js +29 -0
- package/dist/sources/auth-supabase.js +2 -2
- package/dist/sources/realtime-supabase.js +2 -2
- package/dist/sources/rest.d.ts +6 -2
- package/dist/sources/rest.js +42 -7
- package/dist/sources/supabase.d.ts +10 -1
- package/dist/sources/supabase.js +73 -40
- package/dist/studio/emit-project.js +14 -1
- package/dist/studio/index.js +1 -1
- package/dist/studio/project.d.ts +11 -2
- package/dist/studio/project.js +5 -2
- package/dist/studio/ui-components.generated.js +170 -3
- package/dist/sveltekit/in-memory.d.ts +2 -2
- package/dist/sveltekit/in-memory.js +125 -4
- package/dist/sveltekit/index.d.ts +1 -1
- package/dist/sveltekit/index.js +1 -1
- package/dist/sveltekit/query-plan.d.ts +50 -4
- package/dist/sveltekit/query-plan.js +25 -3
- package/dist/sveltekit/sql-source.d.ts +6 -0
- package/dist/sveltekit/sql-source.js +34 -6
- package/dist/sveltekit/sql.d.ts +31 -0
- package/dist/sveltekit/sql.js +135 -25
- package/dist/sveltekit/transport.d.ts +10 -2
- package/dist/sveltekit/transport.js +30 -6
- package/dist/upgrade-prompt.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/watermark.js +35 -2
- package/dist/wc/GridMenus-By9vPuq0.js +1088 -0
- package/dist/wc/SvChartMenu-CQNrQGT2.js +308 -0
- package/dist/wc/SvDateRangeInput-DR6m7bSM.js +199 -0
- package/dist/wc/SvDateTimePicker-D-vRnaMo.js +771 -0
- package/dist/wc/SvField-B_kurx_P.js +149 -0
- package/dist/wc/SvGrid.helpers-BdVDtjUm.js +135 -0
- package/dist/wc/SvGridCellEditor-Bnf1Kr5C.js +560 -0
- package/dist/wc/SvGridChart-BqUJh2pG.js +3572 -0
- package/dist/wc/SvGridChartBuilder-CGycC5cn.js +988 -0
- package/dist/wc/SvGridChartPanel-CRnizsHD.js +1746 -0
- package/dist/wc/SvGridChartView-D1pa_xMy.js +47 -0
- package/dist/wc/SvGridDropdown-45WsObLL.js +259 -0
- package/dist/wc/SvModal-DrfOYYyX.js +189 -0
- package/dist/wc/cell-formatting-CBfgahv1.js +86 -0
- package/dist/wc/chart-6OXlybVT.js +4341 -0
- package/dist/wc/chart-export-CeSADGfi.js +135 -0
- package/dist/wc/chart-export-pdf-BGko7MER.js +104 -0
- package/dist/wc/chart-summary-2m3ia1-n.js +137 -0
- package/dist/wc/chart-trend-CQOQtTMl.js +50 -0
- package/dist/wc/chart-validate-CD6ptiwg.js +180 -0
- package/dist/wc/client-DQIzjDBG.js +3064 -0
- package/dist/wc/column-resize-DUPgynvc.js +101 -0
- package/dist/wc/date-format-DS-z_h9v.js +1130 -0
- package/dist/wc/dismissable-CQ6XFXsk.js +45 -0
- package/dist/wc/editor-contract-peBDxir_.js +22 -0
- package/dist/wc/editor-registry-DxGKqcvx.js +24 -0
- package/dist/wc/focus-trap-Dbb2tJxb.js +65 -0
- package/dist/wc/list-option-DrRyivWp.js +82 -0
- package/dist/wc/popover-WsGlvtQv.js +69 -0
- package/dist/wc/positioning-BiKLfu1E.js +112 -0
- package/dist/wc/react.d.ts +41 -0
- package/dist/wc/react.js +90 -0
- package/dist/wc/rolldown-runtime-Dy4uBu1J.js +11 -0
- package/dist/wc/row-drag-touch-CycRR65n.js +93 -0
- package/dist/wc/row-resize-limG_N1z.js +111 -0
- package/dist/wc/sv-sheet-element.d.ts +97 -0
- package/dist/wc/sv-sheet-element.js +44213 -0
- package/dist/wc/svelte-virtualizer.svelte-CXtQy2TQ.js +530 -0
- package/dist/wc/validate-BqDthkNr.js +88 -0
- package/dist/wc/vue.d.ts +31 -0
- package/dist/wc/vue.js +75 -0
- package/package.json +36 -6
- package/dist/designer/assets/GridMenus-B1JtIN21.js +0 -8
- package/dist/designer/assets/SvDateRangeInput-CjO7nn_x.js +0 -1
- package/dist/designer/assets/SvDateTimePicker-ByBD_ov6.js +0 -1
- package/dist/designer/assets/SvField-YDLipR6O.css +0 -1
- package/dist/designer/assets/SvField-cj1PFNgZ.js +0 -1
- package/dist/designer/assets/SvGridCellEditor-0W1L2hJ1.js +0 -2
- package/dist/designer/assets/SvGridChart-DBOR4xcz.js +0 -2
- package/dist/designer/assets/SvGridChart-fkMWeh1J.css +0 -1
- package/dist/designer/assets/SvGridChartPanel-symrhNnR.js +0 -11
- package/dist/designer/assets/SvGridChartView-BmRxq6mU.js +0 -1
- package/dist/designer/assets/SvGridDropdown-Bb3HH2Aj.js +0 -1
- package/dist/designer/assets/SvListBox-1oUF6Iav.js +0 -110
- package/dist/designer/assets/cell-formatting-wr5wm7US.js +0 -1
- package/dist/designer/assets/chart-DXFganU8.js +0 -1
- package/dist/designer/assets/column-resize-C_inr5zT.js +0 -1
- package/dist/designer/assets/date-format-DGagAqRc.css +0 -1
- package/dist/designer/assets/date-format-onlYDsrY.js +0 -1
- package/dist/designer/assets/easing-zaypKrr0.js +0 -3
- package/dist/designer/assets/index-k2stW6L8.css +0 -1
- package/dist/designer/assets/row-resize-B0FWHcNr.js +0 -1
- package/dist/designer/assets/src-D9p27OGC.js +0 -58
- package/dist/designer/assets/validate-h-aslRV9.js +0 -1
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The function table.
|
|
3
|
+
*
|
|
4
|
+
* Each entry receives its arguments already evaluated, in two shapes:
|
|
5
|
+
* - `flat` every argument flattened into one list, ranges expanded. What
|
|
6
|
+
* SUM and COUNT want.
|
|
7
|
+
* - `args` one list per argument, so a function can tell `SUM(A1:A3, 5)`
|
|
8
|
+
* from `SUM(A1:A3)` and `SUMIF` can line a range up against a
|
|
9
|
+
* parallel one.
|
|
10
|
+
* - `grids` the 2-D shape of any range argument, kept for VLOOKUP / INDEX /
|
|
11
|
+
* MATCH, which lose meaning once flattened.
|
|
12
|
+
*
|
|
13
|
+
* Functions that must NOT evaluate every argument (IF, IFERROR, AND, OR with
|
|
14
|
+
* short-circuit semantics) are handled in the evaluator instead, because by the
|
|
15
|
+
* time a table entry runs, evaluation has already happened.
|
|
16
|
+
*/
|
|
17
|
+
import { isError, err } from './ast.js';
|
|
18
|
+
import { toNumber, toBool, toText, looseEquals, compare, patternEquals, hasWildcards, wildcardRegExp, unescapeWildcards, numericOnly, isBlank, toDate, isoDate as iso, criteriaHits, multiCriteriaHits, criteriaPairs, } from './coerce.js';
|
|
19
|
+
import { formatWithPattern } from './number-format.js';
|
|
20
|
+
import { FINANCIAL_FUNCTIONS } from './packs/financial.js';
|
|
21
|
+
import { MATH_STATS_FUNCTIONS } from './packs/math-stats.js';
|
|
22
|
+
import { TEXT_DATE_FUNCTIONS } from './packs/text-date.js';
|
|
23
|
+
import { TRIG_FUNCTIONS } from './packs/trig.js';
|
|
24
|
+
import { ENGINEERING_FUNCTIONS } from './packs/engineering.js';
|
|
25
|
+
import { DATABASE_FUNCTIONS } from './packs/database.js';
|
|
26
|
+
import { STATS_DIST_FUNCTIONS } from './packs/stats-dist.js';
|
|
27
|
+
const first = (a) => a.flat[0] ?? '';
|
|
28
|
+
const nth = (a, i) => a.args[i]?.[0] ?? '';
|
|
29
|
+
function sum(values) {
|
|
30
|
+
return numericOnly(values).reduce((x, y) => x + y, 0);
|
|
31
|
+
}
|
|
32
|
+
function average(values) {
|
|
33
|
+
const ns = numericOnly(values);
|
|
34
|
+
if (ns.length === 0)
|
|
35
|
+
return err('#DIV/0!');
|
|
36
|
+
return ns.reduce((x, y) => x + y, 0) / ns.length;
|
|
37
|
+
}
|
|
38
|
+
function roundTo(value, digits) {
|
|
39
|
+
const f = Math.pow(10, digits);
|
|
40
|
+
// Scale, round, unscale. The epsilon nudge keeps 1.005 -> 1.01 rather than
|
|
41
|
+
// 1.00, which is the binary-float surprise users report as a bug.
|
|
42
|
+
return Math.round((value * f) * (1 + Number.EPSILON)) / f;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Excel's approximate match, which is what the lookup family does when it
|
|
46
|
+
* cannot find the value itself. The column is taken as sorted, and the answer
|
|
47
|
+
* is the entry NEAREST the needle on one side: `dir` 1 for the largest entry
|
|
48
|
+
* not past it (VLOOKUP / HLOOKUP with range_lookup TRUE, MATCH 1, XLOOKUP -1),
|
|
49
|
+
* -1 for the smallest entry not before it (MATCH -1, XLOOKUP 1).
|
|
50
|
+
*
|
|
51
|
+
* Only cells of the needle's own type take part, so the text header sitting
|
|
52
|
+
* above a numeric tier table cannot become the answer. Among equal entries the
|
|
53
|
+
* later one wins, as Excel's own search lands on the last of a run.
|
|
54
|
+
*/
|
|
55
|
+
function nearestIndex(pool, needle, dir) {
|
|
56
|
+
let best = -1;
|
|
57
|
+
for (let i = 0; i < pool.length; i += 1) {
|
|
58
|
+
const v = pool[i];
|
|
59
|
+
if (v === undefined || v === '' || isError(v))
|
|
60
|
+
continue;
|
|
61
|
+
if (typeof v !== typeof needle)
|
|
62
|
+
continue;
|
|
63
|
+
const side = compare(v, needle);
|
|
64
|
+
if (dir === 1 ? side > 0 : side < 0)
|
|
65
|
+
continue;
|
|
66
|
+
if (best < 0 || compare(v, pool[best]) * dir >= 0)
|
|
67
|
+
best = i;
|
|
68
|
+
}
|
|
69
|
+
return best;
|
|
70
|
+
}
|
|
71
|
+
/** FIND and SEARCH count their optional start from 1; -1 says the argument
|
|
72
|
+
* is out of range, which Excel reports as #VALUE!. */
|
|
73
|
+
function startPosition(a) {
|
|
74
|
+
if (a.args[2] === undefined)
|
|
75
|
+
return 0;
|
|
76
|
+
const given = Math.trunc(toNumber(nth(a, 2)));
|
|
77
|
+
return given < 1 ? -1 : given - 1;
|
|
78
|
+
}
|
|
79
|
+
/** The index of the `instance`-th `delim` in `s`, counted from the start for
|
|
80
|
+
* a positive instance and from the end for a negative one, or null when
|
|
81
|
+
* there are fewer than that many. Backs TEXTBEFORE and TEXTAFTER. */
|
|
82
|
+
function nthDelimiter(s, delim, instance) {
|
|
83
|
+
const positions = [];
|
|
84
|
+
for (let from = 0;;) {
|
|
85
|
+
const at = s.indexOf(delim, from);
|
|
86
|
+
if (at < 0)
|
|
87
|
+
break;
|
|
88
|
+
positions.push(at);
|
|
89
|
+
from = at + delim.length;
|
|
90
|
+
}
|
|
91
|
+
if (instance > 0)
|
|
92
|
+
return instance <= positions.length ? positions[instance - 1] : null;
|
|
93
|
+
if (instance < 0) {
|
|
94
|
+
const k = positions.length + instance;
|
|
95
|
+
return k >= 0 ? positions[k] : null;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
/** Where a wildcard pattern starts inside a text, or -1. Excel reports the
|
|
100
|
+
* earliest position a match can begin at, so the search walks forward and
|
|
101
|
+
* tries every ending from the shortest up. */
|
|
102
|
+
function wildcardSearch(text, pattern, from = 0) {
|
|
103
|
+
const re = wildcardRegExp(pattern);
|
|
104
|
+
for (let start = from; start <= text.length; start += 1) {
|
|
105
|
+
for (let end = start; end <= text.length; end += 1) {
|
|
106
|
+
if (re.test(text.slice(start, end)))
|
|
107
|
+
return start;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return -1;
|
|
111
|
+
}
|
|
112
|
+
export const FUNCTIONS = {
|
|
113
|
+
// ---- Math and aggregation -------------------------------------------
|
|
114
|
+
SUM: (a) => sum(a.flat),
|
|
115
|
+
AVERAGE: (a) => average(a.flat),
|
|
116
|
+
AVG: (a) => average(a.flat),
|
|
117
|
+
MIN: (a) => { const n = numericOnly(a.flat); return n.length ? Math.min(...n) : 0; },
|
|
118
|
+
MAX: (a) => { const n = numericOnly(a.flat); return n.length ? Math.max(...n) : 0; },
|
|
119
|
+
COUNT: (a) => a.flat.filter((v) => typeof v === 'number').length,
|
|
120
|
+
COUNTA: (a) => a.flat.filter((v) => !isBlank(v)).length,
|
|
121
|
+
COUNTBLANK: (a) => a.flat.filter((v) => isBlank(v)).length,
|
|
122
|
+
ABS: (a) => Math.abs(toNumber(first(a))),
|
|
123
|
+
INT: (a) => Math.floor(toNumber(first(a))),
|
|
124
|
+
MOD: (a) => {
|
|
125
|
+
const d = toNumber(nth(a, 1));
|
|
126
|
+
if (d === 0)
|
|
127
|
+
return err('#DIV/0!');
|
|
128
|
+
// Excel's MOD follows the sign of the divisor, unlike JavaScript's %.
|
|
129
|
+
const n = toNumber(nth(a, 0));
|
|
130
|
+
return n - d * Math.floor(n / d);
|
|
131
|
+
},
|
|
132
|
+
POWER: (a) => {
|
|
133
|
+
// The cube root of a negative is NaN in JavaScript and #NUM! in Excel;
|
|
134
|
+
// letting NaN out reaches the sheet as a blank, which says nothing.
|
|
135
|
+
const out = Math.pow(toNumber(nth(a, 0)), toNumber(nth(a, 1)));
|
|
136
|
+
return Number.isFinite(out) ? out : err('#NUM!');
|
|
137
|
+
},
|
|
138
|
+
/** Excel's NA(): the #N/A a lookup writes when it finds nothing. */
|
|
139
|
+
NA: () => err('#N/A'),
|
|
140
|
+
// Excel's TRUE() and FALSE(). Worth having for their own sake, and a file
|
|
141
|
+
// from LibreOffice writes every boolean cell as one of them.
|
|
142
|
+
TRUE: () => true,
|
|
143
|
+
FALSE: () => false,
|
|
144
|
+
SQRT: (a) => {
|
|
145
|
+
const n = toNumber(first(a));
|
|
146
|
+
return n < 0 ? err('#NUM!') : Math.sqrt(n);
|
|
147
|
+
},
|
|
148
|
+
ROUND: (a) => roundTo(toNumber(nth(a, 0)), Math.round(toNumber(nth(a, 1) || 0))),
|
|
149
|
+
ROUNDUP: (a) => {
|
|
150
|
+
const d = Math.round(toNumber(nth(a, 1) || 0));
|
|
151
|
+
const f = Math.pow(10, d);
|
|
152
|
+
const v = toNumber(nth(a, 0));
|
|
153
|
+
return (v < 0 ? -Math.ceil(-v * f) : Math.ceil(v * f)) / f;
|
|
154
|
+
},
|
|
155
|
+
ROUNDDOWN: (a) => {
|
|
156
|
+
const d = Math.round(toNumber(nth(a, 1) || 0));
|
|
157
|
+
const f = Math.pow(10, d);
|
|
158
|
+
const v = toNumber(nth(a, 0));
|
|
159
|
+
return (v < 0 ? -Math.floor(-v * f) : Math.floor(v * f)) / f;
|
|
160
|
+
},
|
|
161
|
+
MEDIAN: (a) => {
|
|
162
|
+
const n = numericOnly(a.flat).sort((x, y) => x - y);
|
|
163
|
+
if (!n.length)
|
|
164
|
+
return err('#NUM!');
|
|
165
|
+
const mid = Math.floor(n.length / 2);
|
|
166
|
+
return n.length % 2 ? n[mid] : (n[mid - 1] + n[mid]) / 2;
|
|
167
|
+
},
|
|
168
|
+
STDEV: (a) => {
|
|
169
|
+
const n = numericOnly(a.flat);
|
|
170
|
+
if (n.length < 2)
|
|
171
|
+
return err('#DIV/0!');
|
|
172
|
+
const mean = n.reduce((x, y) => x + y, 0) / n.length;
|
|
173
|
+
const variance = n.reduce((acc, v) => acc + (v - mean) ** 2, 0) / (n.length - 1);
|
|
174
|
+
return Math.sqrt(variance);
|
|
175
|
+
},
|
|
176
|
+
RANK: (a) => {
|
|
177
|
+
const value = toNumber(nth(a, 0));
|
|
178
|
+
const pool = numericOnly(a.args[1] ?? []);
|
|
179
|
+
const ascending = a.args[2] !== undefined && toBool(nth(a, 2));
|
|
180
|
+
const sorted = pool.slice().sort((x, y) => (ascending ? x - y : y - x));
|
|
181
|
+
const at = sorted.indexOf(value);
|
|
182
|
+
return at < 0 ? err('#N/A') : at + 1;
|
|
183
|
+
},
|
|
184
|
+
// ---- Conditional aggregation ----------------------------------------
|
|
185
|
+
SUMIF: (a) => {
|
|
186
|
+
const range = a.args[0] ?? [];
|
|
187
|
+
const hits = criteriaHits(range, nth(a, 1));
|
|
188
|
+
// The optional third argument is the range actually summed.
|
|
189
|
+
const target = a.args[2] ?? range;
|
|
190
|
+
return sum(hits.map((i) => target[i] ?? ''));
|
|
191
|
+
},
|
|
192
|
+
COUNTIF: (a) => criteriaHits(a.args[0] ?? [], nth(a, 1)).length,
|
|
193
|
+
AVERAGEIF: (a) => {
|
|
194
|
+
const range = a.args[0] ?? [];
|
|
195
|
+
const hits = criteriaHits(range, nth(a, 1));
|
|
196
|
+
const target = a.args[2] ?? range;
|
|
197
|
+
return average(hits.map((i) => target[i] ?? ''));
|
|
198
|
+
},
|
|
199
|
+
SUMIFS: (a) => {
|
|
200
|
+
const target = a.args[0] ?? [];
|
|
201
|
+
return sum(multiCriteriaHits(criteriaPairs(a.args, 1)).map((i) => target[i] ?? ''));
|
|
202
|
+
},
|
|
203
|
+
COUNTIFS: (a) => multiCriteriaHits(criteriaPairs(a.args, 0)).length,
|
|
204
|
+
// ---- Logical ---------------------------------------------------------
|
|
205
|
+
NOT: (a) => !toBool(first(a)),
|
|
206
|
+
AND: (a) => a.flat.every((v) => toBool(v)),
|
|
207
|
+
OR: (a) => a.flat.some((v) => toBool(v)),
|
|
208
|
+
XOR: (a) => a.flat.filter((v) => toBool(v)).length % 2 === 1,
|
|
209
|
+
// ---- Information -----------------------------------------------------
|
|
210
|
+
// What a value IS, not what it can be coerced to: "12" typed as text is
|
|
211
|
+
// text here, the way Excel answers, and a blank is neither.
|
|
212
|
+
ISNUMBER: (a) => typeof first(a) === 'number',
|
|
213
|
+
ISTEXT: (a) => typeof first(a) === 'string' && first(a) !== '',
|
|
214
|
+
ISLOGICAL: (a) => typeof first(a) === 'boolean',
|
|
215
|
+
ISBLANK: (a) => first(a) === '',
|
|
216
|
+
// ---- Text ------------------------------------------------------------
|
|
217
|
+
LEN: (a) => toText(first(a)).length,
|
|
218
|
+
LEFT: (a) => toText(nth(a, 0)).slice(0, Math.max(0, Math.round(toNumber(a.args[1] ? nth(a, 1) : 1)))),
|
|
219
|
+
RIGHT: (a) => {
|
|
220
|
+
const s = toText(nth(a, 0));
|
|
221
|
+
const n = Math.max(0, Math.round(toNumber(a.args[1] ? nth(a, 1) : 1)));
|
|
222
|
+
return n >= s.length ? s : s.slice(s.length - n);
|
|
223
|
+
},
|
|
224
|
+
MID: (a) => {
|
|
225
|
+
const s = toText(nth(a, 0));
|
|
226
|
+
const start = Math.round(toNumber(nth(a, 1)));
|
|
227
|
+
if (start < 1)
|
|
228
|
+
return err('#VALUE!');
|
|
229
|
+
return s.slice(start - 1, start - 1 + Math.max(0, Math.round(toNumber(nth(a, 2)))));
|
|
230
|
+
},
|
|
231
|
+
UPPER: (a) => toText(first(a)).toUpperCase(),
|
|
232
|
+
LOWER: (a) => toText(first(a)).toLowerCase(),
|
|
233
|
+
TRIM: (a) => toText(first(a)).trim().replace(/\s+/g, ' '),
|
|
234
|
+
// Excel's HYPERLINK shows the friendly name and follows the link. The
|
|
235
|
+
// shell reads the link off the cell (`sheet/links.ts`), which is where a
|
|
236
|
+
// link put there by Insert > Link lives too, so a cell is clickable
|
|
237
|
+
// whichever way its link arrived; the value here is only what it shows.
|
|
238
|
+
HYPERLINK: (a) => {
|
|
239
|
+
const target = toText(first(a));
|
|
240
|
+
const friendly = a.args.length > 1 ? nth(a, 1) : undefined;
|
|
241
|
+
return friendly === undefined || friendly === '' ? target : friendly;
|
|
242
|
+
},
|
|
243
|
+
/**
|
|
244
|
+
* IMAGE(source, [alt]): a picture IN the cell. The value is the source,
|
|
245
|
+
* so the formula reads like any other one and a cell that reads it gets
|
|
246
|
+
* an address rather than a picture it cannot use; the shell is what
|
|
247
|
+
* draws it, from the call it finds on the cell (`sheet/cell-images.ts`).
|
|
248
|
+
*/
|
|
249
|
+
IMAGE: (a) => toText(first(a)),
|
|
250
|
+
CONCAT: (a) => a.flat.map((v) => toText(v)).join(''),
|
|
251
|
+
CONCATENATE: (a) => a.flat.map((v) => toText(v)).join(''),
|
|
252
|
+
TEXTJOIN: (a) => {
|
|
253
|
+
const sep = toText(nth(a, 0));
|
|
254
|
+
const skipEmpty = toBool(nth(a, 1));
|
|
255
|
+
const rest = a.args.slice(2).flat();
|
|
256
|
+
return rest.filter((v) => !skipEmpty || !isBlank(v)).map((v) => toText(v)).join(sep);
|
|
257
|
+
},
|
|
258
|
+
// SUBSTITUTE(text, old, new, [instance]): every occurrence by default, or
|
|
259
|
+
// just the instance-th one when the fourth argument names it, the way Excel
|
|
260
|
+
// rewrites the second slash of a date and leaves the first.
|
|
261
|
+
SUBSTITUTE: (a) => {
|
|
262
|
+
const s = toText(nth(a, 0));
|
|
263
|
+
const find = toText(nth(a, 1));
|
|
264
|
+
const replace = toText(nth(a, 2));
|
|
265
|
+
if (find === '')
|
|
266
|
+
return s;
|
|
267
|
+
if (a.args[3] === undefined)
|
|
268
|
+
return s.split(find).join(replace);
|
|
269
|
+
const instance = Math.trunc(toNumber(nth(a, 3)));
|
|
270
|
+
if (instance < 1)
|
|
271
|
+
return err('#VALUE!');
|
|
272
|
+
let count = 0;
|
|
273
|
+
let from = 0;
|
|
274
|
+
for (;;) {
|
|
275
|
+
const at = s.indexOf(find, from);
|
|
276
|
+
// Fewer than `instance` occurrences: Excel leaves the text as it is.
|
|
277
|
+
if (at < 0)
|
|
278
|
+
return s;
|
|
279
|
+
count += 1;
|
|
280
|
+
if (count === instance)
|
|
281
|
+
return s.slice(0, at) + replace + s.slice(at + find.length);
|
|
282
|
+
from = at + find.length;
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
// TEXTBEFORE / TEXTAFTER(text, delimiter, [instance]): the part before or
|
|
286
|
+
// after the instance-th delimiter, counted from the end when instance is
|
|
287
|
+
// negative. The delimiter that is not there is #N/A, unless a sixth
|
|
288
|
+
// `if_not_found` is given.
|
|
289
|
+
TEXTBEFORE: (a) => {
|
|
290
|
+
const s = toText(nth(a, 0));
|
|
291
|
+
const delim = toText(nth(a, 1));
|
|
292
|
+
const instance = a.args[2] !== undefined ? Math.trunc(toNumber(nth(a, 2))) : 1;
|
|
293
|
+
if (delim === '')
|
|
294
|
+
return '';
|
|
295
|
+
const at = nthDelimiter(s, delim, instance);
|
|
296
|
+
return at === null ? (a.args[5] !== undefined ? nth(a, 5) : err('#N/A')) : s.slice(0, at);
|
|
297
|
+
},
|
|
298
|
+
TEXTAFTER: (a) => {
|
|
299
|
+
const s = toText(nth(a, 0));
|
|
300
|
+
const delim = toText(nth(a, 1));
|
|
301
|
+
const instance = a.args[2] !== undefined ? Math.trunc(toNumber(nth(a, 2))) : 1;
|
|
302
|
+
if (delim === '')
|
|
303
|
+
return s;
|
|
304
|
+
const at = nthDelimiter(s, delim, instance);
|
|
305
|
+
return at === null ? (a.args[5] !== undefined ? nth(a, 5) : err('#N/A')) : s.slice(at + delim.length);
|
|
306
|
+
},
|
|
307
|
+
// DOLLAR / FIXED(number, [decimals], [no_commas]): a number as the text of
|
|
308
|
+
// a currency or a fixed-decimal figure, grouped in thousands. DOLLAR wraps
|
|
309
|
+
// a negative in parentheses; a negative decimals rounds to the left of the
|
|
310
|
+
// point, so DOLLAR(1234.5, -2) is "$1,200".
|
|
311
|
+
DOLLAR: (a) => {
|
|
312
|
+
const decimals = a.args[1] !== undefined ? Math.trunc(toNumber(nth(a, 1))) : 2;
|
|
313
|
+
const rounded = roundTo(toNumber(nth(a, 0)), decimals);
|
|
314
|
+
const places = Math.max(decimals, 0);
|
|
315
|
+
const body = `$${Math.abs(rounded).toLocaleString('en-US', { minimumFractionDigits: places, maximumFractionDigits: places })}`;
|
|
316
|
+
return rounded < 0 ? `(${body})` : body;
|
|
317
|
+
},
|
|
318
|
+
FIXED: (a) => {
|
|
319
|
+
const decimals = a.args[1] !== undefined ? Math.trunc(toNumber(nth(a, 1))) : 2;
|
|
320
|
+
const noCommas = a.args[2] !== undefined && toBool(nth(a, 2));
|
|
321
|
+
const rounded = roundTo(toNumber(nth(a, 0)), decimals);
|
|
322
|
+
const places = Math.max(decimals, 0);
|
|
323
|
+
return noCommas
|
|
324
|
+
? rounded.toFixed(places)
|
|
325
|
+
: rounded.toLocaleString('en-US', { minimumFractionDigits: places, maximumFractionDigits: places });
|
|
326
|
+
},
|
|
327
|
+
// COMBIN / PERMUT(n, k): the ways to choose k of n, unordered and ordered.
|
|
328
|
+
// The product form keeps the intermediate values small, so a big n does not
|
|
329
|
+
// overflow the way n! would.
|
|
330
|
+
COMBIN: (a) => {
|
|
331
|
+
const n = Math.trunc(toNumber(nth(a, 0)));
|
|
332
|
+
const k = Math.trunc(toNumber(nth(a, 1)));
|
|
333
|
+
if (n < 0 || k < 0 || k > n)
|
|
334
|
+
return err('#NUM!');
|
|
335
|
+
let result = 1;
|
|
336
|
+
for (let i = 0; i < k; i += 1)
|
|
337
|
+
result = (result * (n - i)) / (i + 1);
|
|
338
|
+
return Math.round(result);
|
|
339
|
+
},
|
|
340
|
+
PERMUT: (a) => {
|
|
341
|
+
const n = Math.trunc(toNumber(nth(a, 0)));
|
|
342
|
+
const k = Math.trunc(toNumber(nth(a, 1)));
|
|
343
|
+
if (n < 0 || k < 0 || k > n)
|
|
344
|
+
return err('#NUM!');
|
|
345
|
+
let result = 1;
|
|
346
|
+
for (let i = 0; i < k; i += 1)
|
|
347
|
+
result *= n - i;
|
|
348
|
+
return result;
|
|
349
|
+
},
|
|
350
|
+
// TYPE(value): 1 a number, 2 text, 4 a logical, 16 an error, 64 an array.
|
|
351
|
+
TYPE: (a) => {
|
|
352
|
+
const grid = a.grids[0];
|
|
353
|
+
if (grid && (grid.length > 1 || (grid[0]?.length ?? 0) > 1))
|
|
354
|
+
return 64;
|
|
355
|
+
const v = nth(a, 0);
|
|
356
|
+
if (isError(v))
|
|
357
|
+
return 16;
|
|
358
|
+
if (typeof v === 'number')
|
|
359
|
+
return 1;
|
|
360
|
+
if (typeof v === 'boolean')
|
|
361
|
+
return 4;
|
|
362
|
+
return 2;
|
|
363
|
+
},
|
|
364
|
+
// FIND(find, within, [start]): case sensitive, 1-based, #VALUE! when the
|
|
365
|
+
// text is not there. The third argument is where the search BEGINS, and
|
|
366
|
+
// the answer is still counted from the start of the text, which is what
|
|
367
|
+
// makes the walk over every occurrence work.
|
|
368
|
+
FIND: (a) => {
|
|
369
|
+
const from = startPosition(a);
|
|
370
|
+
if (from < 0)
|
|
371
|
+
return err('#VALUE!');
|
|
372
|
+
const at = toText(nth(a, 1)).indexOf(toText(nth(a, 0)), from);
|
|
373
|
+
return at < 0 ? err('#VALUE!') : at + 1;
|
|
374
|
+
},
|
|
375
|
+
// SEARCH is FIND's case-insensitive twin, and unlike FIND it reads Excel's
|
|
376
|
+
// wildcards: =SEARCH("n?rth", A1) finds either spelling.
|
|
377
|
+
SEARCH: (a) => {
|
|
378
|
+
const needle = toText(nth(a, 0));
|
|
379
|
+
const hay = toText(nth(a, 1));
|
|
380
|
+
const from = startPosition(a);
|
|
381
|
+
if (from < 0)
|
|
382
|
+
return err('#VALUE!');
|
|
383
|
+
if (hasWildcards(needle)) {
|
|
384
|
+
const at = wildcardSearch(hay, needle, from);
|
|
385
|
+
return at < 0 ? err('#VALUE!') : at + 1;
|
|
386
|
+
}
|
|
387
|
+
const at = hay.toLowerCase().indexOf(unescapeWildcards(needle).toLowerCase(), from);
|
|
388
|
+
return at < 0 ? err('#VALUE!') : at + 1;
|
|
389
|
+
},
|
|
390
|
+
/**
|
|
391
|
+
* TEXT(value, format): the value through a number-format string, which is
|
|
392
|
+
* the same grammar a cell's own format speaks. It reads dates, fractions,
|
|
393
|
+
* elapsed time and the rest, since it is the same compiler; a colour in
|
|
394
|
+
* the pattern is ignored, as Excel ignores it here, and an empty pattern
|
|
395
|
+
* is an empty string.
|
|
396
|
+
*/
|
|
397
|
+
TEXT: (a) => {
|
|
398
|
+
const pattern = toText(nth(a, 1));
|
|
399
|
+
if (pattern === '')
|
|
400
|
+
return '';
|
|
401
|
+
return formatWithPattern(first(a), pattern);
|
|
402
|
+
},
|
|
403
|
+
// ---- Date ------------------------------------------------------------
|
|
404
|
+
TODAY: () => iso(new Date()),
|
|
405
|
+
NOW: () => new Date().toISOString().slice(0, 19).replace('T', ' '),
|
|
406
|
+
YEAR: (a) => toDate(first(a)).getUTCFullYear(),
|
|
407
|
+
MONTH: (a) => toDate(first(a)).getUTCMonth() + 1,
|
|
408
|
+
DAY: (a) => toDate(first(a)).getUTCDate(),
|
|
409
|
+
DATE: (a) => iso(new Date(Date.UTC(Math.round(toNumber(nth(a, 0))), Math.round(toNumber(nth(a, 1))) - 1, Math.round(toNumber(nth(a, 2)))))),
|
|
410
|
+
EOMONTH: (a) => {
|
|
411
|
+
const d = toDate(nth(a, 0));
|
|
412
|
+
const months = Math.round(toNumber(nth(a, 1)));
|
|
413
|
+
// Day 0 of the following month is the last day of the target month.
|
|
414
|
+
return iso(new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + months + 1, 0)));
|
|
415
|
+
},
|
|
416
|
+
// DAYS(end, start): whole days, negative when the end comes first.
|
|
417
|
+
DAYS: (a) => Math.round((toDate(nth(a, 0)).getTime() - toDate(nth(a, 1)).getTime()) / 86400000),
|
|
418
|
+
// DATEDIF(start, end, unit): Excel's six units - "d", "m", "y" for the
|
|
419
|
+
// whole difference, and "md", "ym", "yd" for the part left when the higher
|
|
420
|
+
// units are set aside, which is how an age reads "y years, m months, d
|
|
421
|
+
// days". #NUM! when the start comes after the end, as Excel gives.
|
|
422
|
+
DATEDIF: (a) => {
|
|
423
|
+
const start = toDate(nth(a, 0));
|
|
424
|
+
const end = toDate(nth(a, 1));
|
|
425
|
+
if (end.getTime() < start.getTime())
|
|
426
|
+
return err('#NUM!');
|
|
427
|
+
const unit = toText(nth(a, 2)).toUpperCase();
|
|
428
|
+
const day = 86400000;
|
|
429
|
+
if (unit === 'D')
|
|
430
|
+
return Math.floor((end.getTime() - start.getTime()) / day);
|
|
431
|
+
let months = (end.getUTCFullYear() - start.getUTCFullYear()) * 12 + (end.getUTCMonth() - start.getUTCMonth());
|
|
432
|
+
if (end.getUTCDate() < start.getUTCDate())
|
|
433
|
+
months -= 1;
|
|
434
|
+
if (unit === 'M')
|
|
435
|
+
return months;
|
|
436
|
+
if (unit === 'Y')
|
|
437
|
+
return Math.floor(months / 12);
|
|
438
|
+
// Months ignoring years: the month part of the whole difference.
|
|
439
|
+
if (unit === 'YM')
|
|
440
|
+
return months % 12;
|
|
441
|
+
// Days ignoring months and years: the days past the last whole month.
|
|
442
|
+
// Anchoring `months` months onto the start, its day clamped to that
|
|
443
|
+
// month's length, keeps the count from going negative on the awkward
|
|
444
|
+
// month-end cases Excel itself is inconsistent about (Jan 31 -> Mar 1).
|
|
445
|
+
if (unit === 'MD') {
|
|
446
|
+
const anchorMonth = start.getUTCMonth() + months;
|
|
447
|
+
const lastDay = new Date(Date.UTC(start.getUTCFullYear(), anchorMonth + 1, 0)).getUTCDate();
|
|
448
|
+
const anchorDay = Math.min(start.getUTCDate(), lastDay);
|
|
449
|
+
const anchor = Date.UTC(start.getUTCFullYear(), anchorMonth, anchorDay);
|
|
450
|
+
return Math.floor((end.getTime() - anchor) / day);
|
|
451
|
+
}
|
|
452
|
+
// Days ignoring years: the days between, with the start moved to end's
|
|
453
|
+
// year (or the year before, when that would overshoot the end).
|
|
454
|
+
if (unit === 'YD') {
|
|
455
|
+
let anchor = Date.UTC(end.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate());
|
|
456
|
+
if (anchor > end.getTime())
|
|
457
|
+
anchor = Date.UTC(end.getUTCFullYear() - 1, start.getUTCMonth(), start.getUTCDate());
|
|
458
|
+
return Math.floor((end.getTime() - anchor) / day);
|
|
459
|
+
}
|
|
460
|
+
return err('#NUM!');
|
|
461
|
+
},
|
|
462
|
+
// ---- Lookup ----------------------------------------------------------
|
|
463
|
+
// VLOOKUP(lookup, table, colIndex, [rangeLookup]). The fourth argument is
|
|
464
|
+
// Excel's range_lookup and it defaults to TRUE: the banded lookup - tax
|
|
465
|
+
// brackets, commission tiers, a grade table - is the DEFAULT reading, and
|
|
466
|
+
// FALSE is how you ask for an exact match.
|
|
467
|
+
VLOOKUP: (a) => {
|
|
468
|
+
const needle = nth(a, 0);
|
|
469
|
+
const grid = a.grids[1];
|
|
470
|
+
if (!grid)
|
|
471
|
+
return err('#REF!');
|
|
472
|
+
const col = Math.round(toNumber(nth(a, 2)));
|
|
473
|
+
if (col < 1)
|
|
474
|
+
return err('#VALUE!');
|
|
475
|
+
const keys = grid.map((row) => row[0] ?? '');
|
|
476
|
+
const exact = a.args[3] !== undefined && !toBool(nth(a, 3));
|
|
477
|
+
const at = exact
|
|
478
|
+
? keys.findIndex((v) => patternEquals(v, needle))
|
|
479
|
+
: nearestIndex(keys, needle, 1);
|
|
480
|
+
if (at < 0)
|
|
481
|
+
return err('#N/A');
|
|
482
|
+
const cell = grid[at][col - 1];
|
|
483
|
+
return cell === undefined ? err('#REF!') : cell;
|
|
484
|
+
},
|
|
485
|
+
// HLOOKUP reads the same way, along the header row instead of down the
|
|
486
|
+
// first column.
|
|
487
|
+
HLOOKUP: (a) => {
|
|
488
|
+
const needle = nth(a, 0);
|
|
489
|
+
const grid = a.grids[1];
|
|
490
|
+
if (!grid)
|
|
491
|
+
return err('#REF!');
|
|
492
|
+
const rowIndex = Math.round(toNumber(nth(a, 2)));
|
|
493
|
+
if (rowIndex < 1)
|
|
494
|
+
return err('#VALUE!');
|
|
495
|
+
const header = grid[0] ?? [];
|
|
496
|
+
const exact = a.args[3] !== undefined && !toBool(nth(a, 3));
|
|
497
|
+
const at = exact
|
|
498
|
+
? header.findIndex((v) => patternEquals(v, needle))
|
|
499
|
+
: nearestIndex(header, needle, 1);
|
|
500
|
+
if (at < 0)
|
|
501
|
+
return err('#N/A');
|
|
502
|
+
const cell = grid[rowIndex - 1]?.[at];
|
|
503
|
+
return cell === undefined ? err('#REF!') : cell;
|
|
504
|
+
},
|
|
505
|
+
MATCH: (a) => {
|
|
506
|
+
const needle = nth(a, 0);
|
|
507
|
+
const pool = a.args[1] ?? [];
|
|
508
|
+
const mode = a.args[2] ? Math.round(toNumber(nth(a, 2))) : 1;
|
|
509
|
+
if (mode === 0) {
|
|
510
|
+
// An exact match takes Excel's wildcards: =MATCH("North*", ...).
|
|
511
|
+
const at = pool.findIndex((v) => patternEquals(v, needle));
|
|
512
|
+
return at < 0 ? err('#N/A') : at + 1;
|
|
513
|
+
}
|
|
514
|
+
// Ordered search: 1 wants the last value not past the needle in an
|
|
515
|
+
// ascending range, -1 the last value not before it in a descending one.
|
|
516
|
+
const best = nearestIndex(pool, needle, mode === 1 ? 1 : -1);
|
|
517
|
+
return best < 0 ? err('#N/A') : best + 1;
|
|
518
|
+
},
|
|
519
|
+
INDEX: (a) => {
|
|
520
|
+
const grid = a.grids[0];
|
|
521
|
+
if (!grid) {
|
|
522
|
+
const at = Math.round(toNumber(nth(a, 1)));
|
|
523
|
+
const v = (a.args[0] ?? [])[at - 1];
|
|
524
|
+
return v === undefined ? err('#REF!') : v;
|
|
525
|
+
}
|
|
526
|
+
const given = Math.round(toNumber(nth(a, 1)));
|
|
527
|
+
// With one number, a one-column range indexes by row and a one-row range
|
|
528
|
+
// by column, as Excel does: =INDEX(B4:D4, 2) is the second scenario
|
|
529
|
+
// heading, not #REF!.
|
|
530
|
+
const oneRow = grid.length === 1 && !a.args[2];
|
|
531
|
+
const rowIndex = oneRow ? 1 : given;
|
|
532
|
+
const colIndex = oneRow ? given : a.args[2] ? Math.round(toNumber(nth(a, 2))) : 1;
|
|
533
|
+
const row = grid[rowIndex - 1];
|
|
534
|
+
if (!row)
|
|
535
|
+
return err('#REF!');
|
|
536
|
+
const cell = row[colIndex - 1];
|
|
537
|
+
return cell === undefined ? err('#REF!') : cell;
|
|
538
|
+
},
|
|
539
|
+
// XLOOKUP(lookup, haystack, results, [ifMissing], [matchMode], [searchMode]).
|
|
540
|
+
// matchMode 0 is the exact match it defaults to, -1 falls back to the next
|
|
541
|
+
// smaller item, 1 to the next larger one and 2 reads the value as a wildcard
|
|
542
|
+
// pattern; a negative searchMode reads the range from the end, which is how
|
|
543
|
+
// you pick the LAST of several matches.
|
|
544
|
+
XLOOKUP: (a) => {
|
|
545
|
+
const needle = nth(a, 0);
|
|
546
|
+
const haystack = a.args[1] ?? [];
|
|
547
|
+
const results = a.args[2] ?? [];
|
|
548
|
+
const mode = a.args[4] !== undefined ? Math.round(toNumber(nth(a, 4))) : 0;
|
|
549
|
+
const back = a.args[5] !== undefined && Math.round(toNumber(nth(a, 5))) < 0;
|
|
550
|
+
// Unlike the older lookups, XLOOKUP reads wildcards only when asked:
|
|
551
|
+
// match mode 2.
|
|
552
|
+
const same = mode === 2
|
|
553
|
+
? (v) => patternEquals(v, needle)
|
|
554
|
+
: (v) => looseEquals(v, needle);
|
|
555
|
+
let at = -1;
|
|
556
|
+
for (let i = 0; i < haystack.length; i += 1) {
|
|
557
|
+
const j = back ? haystack.length - 1 - i : i;
|
|
558
|
+
if (same(haystack[j])) {
|
|
559
|
+
at = j;
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (at < 0 && mode === -1)
|
|
564
|
+
at = nearestIndex(haystack, needle, 1);
|
|
565
|
+
if (at < 0 && mode === 1)
|
|
566
|
+
at = nearestIndex(haystack, needle, -1);
|
|
567
|
+
if (at < 0)
|
|
568
|
+
return a.args[3] !== undefined ? nth(a, 3) : err('#N/A');
|
|
569
|
+
const cell = results[at];
|
|
570
|
+
return cell === undefined ? err('#REF!') : cell;
|
|
571
|
+
},
|
|
572
|
+
// LOOKUP(value, vector, [result]): the old approximate lookup that assumes
|
|
573
|
+
// its vector is sorted ascending and takes the largest item not past the
|
|
574
|
+
// value, returning the matching cell of the result vector - the lookup
|
|
575
|
+
// vector itself when none is given.
|
|
576
|
+
LOOKUP: (a) => {
|
|
577
|
+
const needle = nth(a, 0);
|
|
578
|
+
const vector = a.args[1] ?? [];
|
|
579
|
+
const result = a.args[2] ?? vector;
|
|
580
|
+
const at = nearestIndex(vector, needle, 1);
|
|
581
|
+
if (at < 0)
|
|
582
|
+
return err('#N/A');
|
|
583
|
+
const cell = result[at];
|
|
584
|
+
return cell === undefined ? err('#N/A') : cell;
|
|
585
|
+
},
|
|
586
|
+
// XMATCH(value, array, [matchMode], [searchMode]): MATCH's modern twin.
|
|
587
|
+
// matchMode 0 is the exact default, -1 falls back to the next smaller item,
|
|
588
|
+
// 1 to the next larger, 2 reads a wildcard; a negative searchMode reads from
|
|
589
|
+
// the end, so it finds the LAST of several matches.
|
|
590
|
+
XMATCH: (a) => {
|
|
591
|
+
const needle = nth(a, 0);
|
|
592
|
+
const pool = a.args[1] ?? [];
|
|
593
|
+
const mode = a.args[2] !== undefined ? Math.round(toNumber(nth(a, 2))) : 0;
|
|
594
|
+
const back = a.args[3] !== undefined && Math.round(toNumber(nth(a, 3))) < 0;
|
|
595
|
+
const same = mode === 2
|
|
596
|
+
? (v) => patternEquals(v, needle)
|
|
597
|
+
: (v) => looseEquals(v, needle);
|
|
598
|
+
let at = -1;
|
|
599
|
+
for (let i = 0; i < pool.length; i += 1) {
|
|
600
|
+
const j = back ? pool.length - 1 - i : i;
|
|
601
|
+
if (same(pool[j])) {
|
|
602
|
+
at = j;
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
if (at < 0 && mode === -1)
|
|
607
|
+
at = nearestIndex(pool, needle, 1);
|
|
608
|
+
if (at < 0 && mode === 1)
|
|
609
|
+
at = nearestIndex(pool, needle, -1);
|
|
610
|
+
return at < 0 ? err('#N/A') : at + 1;
|
|
611
|
+
},
|
|
612
|
+
// ---- The packs: financial, more math and statistics, more text and
|
|
613
|
+
// date. Each lives in its own module under ./packs so this table stays
|
|
614
|
+
// readable; all of them are on by default, as a sheet user expects PMT
|
|
615
|
+
// to work without registering anything.
|
|
616
|
+
...FINANCIAL_FUNCTIONS,
|
|
617
|
+
...MATH_STATS_FUNCTIONS,
|
|
618
|
+
...TEXT_DATE_FUNCTIONS,
|
|
619
|
+
...TRIG_FUNCTIONS,
|
|
620
|
+
...ENGINEERING_FUNCTIONS,
|
|
621
|
+
...DATABASE_FUNCTIONS,
|
|
622
|
+
...STATS_DIST_FUNCTIONS,
|
|
623
|
+
};
|
|
624
|
+
/** Merge caller-supplied functions over the built-ins. Keys are uppercased so
|
|
625
|
+
* a consumer can register `myFn` and write `=MYFN()`. */
|
|
626
|
+
export function withCustomFunctions(custom) {
|
|
627
|
+
if (!custom)
|
|
628
|
+
return FUNCTIONS;
|
|
629
|
+
const out = { ...FUNCTIONS };
|
|
630
|
+
for (const [name, fn] of Object.entries(custom))
|
|
631
|
+
out[name.toUpperCase()] = fn;
|
|
632
|
+
return out;
|
|
633
|
+
}
|
|
634
|
+
export { isError };
|