mulmoclaude 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -0
- package/bin/mulmoclaude.js +202 -0
- package/bin/prepare-dist.js +93 -0
- package/client/assets/chunk-vKJrgz-R-C_I3GbVV.js +1 -0
- package/client/assets/html2canvas-Cx501zZr-BF5dYYkY.js +5 -0
- package/client/assets/index-D8rhwXLq.js +4906 -0
- package/client/assets/index-KNLBjwuh.css +1 -0
- package/client/assets/index.es-D4YyL_Dg-BfRHLTZV.js +5 -0
- package/client/assets/material-icons-Dr0goTwe.woff +0 -0
- package/client/assets/material-icons-kAwBdRge.woff2 +0 -0
- package/client/assets/material-icons-outlined-BpWbwl2n.woff +0 -0
- package/client/assets/material-icons-outlined-DZhiGvEA.woff2 +0 -0
- package/client/assets/material-icons-round-BDlwx-sv.woff +0 -0
- package/client/assets/material-icons-round-DrirKXBx.woff2 +0 -0
- package/client/assets/material-icons-sharp-CH1KkVu7.woff +0 -0
- package/client/assets/material-icons-sharp-gidztirS.woff2 +0 -0
- package/client/assets/material-icons-two-tone-B7wz7mED.woff +0 -0
- package/client/assets/material-icons-two-tone-DuNIpaEj.woff2 +0 -0
- package/client/assets/mulmo_bw-ERmkSv0a.png +0 -0
- package/client/assets/purify.es-Fx1Nqyry-PeS5RUhs.js +2 -0
- package/client/assets/typeof-DBp4T-Ny-BC0P-2DM.js +1 -0
- package/client/index.html +28 -0
- package/package.json +66 -0
- package/server/agent/attachmentConverter.ts +270 -0
- package/server/agent/config.ts +414 -0
- package/server/agent/index.ts +260 -0
- package/server/agent/mcp-server.ts +412 -0
- package/server/agent/mcp-tools/index.ts +63 -0
- package/server/agent/mcp-tools/x.ts +188 -0
- package/server/agent/plugin-names.ts +75 -0
- package/server/agent/prompt.ts +349 -0
- package/server/agent/resumeFailover.ts +129 -0
- package/server/agent/sandboxMounts.ts +329 -0
- package/server/agent/stream.ts +194 -0
- package/server/api/auth/bearerAuth.ts +61 -0
- package/server/api/auth/token.ts +98 -0
- package/server/api/csrfGuard.ts +85 -0
- package/server/api/routes/agent.ts +478 -0
- package/server/api/routes/chart.ts +98 -0
- package/server/api/routes/chat-index.ts +46 -0
- package/server/api/routes/config.ts +258 -0
- package/server/api/routes/dispatchResponse.ts +79 -0
- package/server/api/routes/files.ts +812 -0
- package/server/api/routes/html.ts +101 -0
- package/server/api/routes/image.ts +169 -0
- package/server/api/routes/mulmo-script.ts +712 -0
- package/server/api/routes/mulmoScriptValidate.ts +101 -0
- package/server/api/routes/notifications.ts +69 -0
- package/server/api/routes/pdf.ts +163 -0
- package/server/api/routes/plugins.ts +276 -0
- package/server/api/routes/presentHtml.ts +48 -0
- package/server/api/routes/roles.ts +125 -0
- package/server/api/routes/scheduler.ts +153 -0
- package/server/api/routes/schedulerHandlers.ts +151 -0
- package/server/api/routes/schedulerTasks.ts +163 -0
- package/server/api/routes/sessions.ts +294 -0
- package/server/api/routes/sessionsCursor.ts +59 -0
- package/server/api/routes/skills.ts +195 -0
- package/server/api/routes/sources.ts +540 -0
- package/server/api/routes/todos.ts +263 -0
- package/server/api/routes/todosColumnsHandlers.ts +347 -0
- package/server/api/routes/todosHandlers.ts +274 -0
- package/server/api/routes/todosItemsHandlers.ts +386 -0
- package/server/api/routes/wiki/pageIndex.ts +53 -0
- package/server/api/routes/wiki.ts +363 -0
- package/server/api/sandboxStatus.ts +64 -0
- package/server/events/notifications.ts +160 -0
- package/server/events/pub-sub/index.ts +45 -0
- package/server/events/relay-client.ts +288 -0
- package/server/events/scheduler-adapter.ts +302 -0
- package/server/events/session-store/index.ts +492 -0
- package/server/events/task-manager/index.ts +181 -0
- package/server/index.ts +572 -0
- package/server/system/config.ts +243 -0
- package/server/system/credentials.ts +220 -0
- package/server/system/docker.ts +97 -0
- package/server/system/env.ts +109 -0
- package/server/system/logger/config.ts +112 -0
- package/server/system/logger/formatters.ts +40 -0
- package/server/system/logger/index.ts +53 -0
- package/server/system/logger/rotation.ts +37 -0
- package/server/system/logger/sinks.ts +101 -0
- package/server/system/logger/types.ts +29 -0
- package/server/utils/date.ts +57 -0
- package/server/utils/errors.ts +7 -0
- package/server/utils/fetch.ts +27 -0
- package/server/utils/files/atomic.ts +125 -0
- package/server/utils/files/html-io.ts +20 -0
- package/server/utils/files/image-store.ts +66 -0
- package/server/utils/files/index.ts +45 -0
- package/server/utils/files/journal-io.ts +213 -0
- package/server/utils/files/json.ts +69 -0
- package/server/utils/files/markdown-store.ts +33 -0
- package/server/utils/files/naming.ts +50 -0
- package/server/utils/files/reference-dirs-io.ts +45 -0
- package/server/utils/files/roles-io.ts +45 -0
- package/server/utils/files/safe.ts +106 -0
- package/server/utils/files/scheduler-io.ts +20 -0
- package/server/utils/files/scheduler-overrides-io.ts +64 -0
- package/server/utils/files/session-io.ts +136 -0
- package/server/utils/files/spreadsheet-store.ts +63 -0
- package/server/utils/files/todos-io.ts +29 -0
- package/server/utils/files/user-tasks-io.ts +25 -0
- package/server/utils/files/workspace-io.ts +221 -0
- package/server/utils/gemini.ts +59 -0
- package/server/utils/gitignore.ts +69 -0
- package/server/utils/http.ts +15 -0
- package/server/utils/httpError.ts +61 -0
- package/server/utils/id.ts +16 -0
- package/server/utils/json.ts +83 -0
- package/server/utils/logBackgroundError.ts +22 -0
- package/server/utils/markdown.ts +82 -0
- package/server/utils/request.ts +29 -0
- package/server/utils/slug.ts +50 -0
- package/server/utils/spawn.ts +62 -0
- package/server/utils/time.ts +34 -0
- package/server/utils/types.ts +47 -0
- package/server/workspace/chat-index/index.ts +153 -0
- package/server/workspace/chat-index/indexer.ts +209 -0
- package/server/workspace/chat-index/paths.ts +34 -0
- package/server/workspace/chat-index/summarizer.ts +247 -0
- package/server/workspace/chat-index/types.ts +38 -0
- package/server/workspace/custom-dirs.ts +220 -0
- package/server/workspace/helps/business.md +104 -0
- package/server/workspace/helps/github.md +23 -0
- package/server/workspace/helps/index.md +60 -0
- package/server/workspace/helps/mulmoscript.md +249 -0
- package/server/workspace/helps/sandbox.md +90 -0
- package/server/workspace/helps/spreadsheet.md +43 -0
- package/server/workspace/helps/telegram.md +135 -0
- package/server/workspace/helps/wiki.md +131 -0
- package/server/workspace/journal/archivist.ts +386 -0
- package/server/workspace/journal/dailyPass.ts +743 -0
- package/server/workspace/journal/diff.ts +71 -0
- package/server/workspace/journal/index.ts +185 -0
- package/server/workspace/journal/indexFile.ts +136 -0
- package/server/workspace/journal/linkRewrite.ts +4 -0
- package/server/workspace/journal/memoryExtractor.ts +130 -0
- package/server/workspace/journal/optimizationPass.ts +160 -0
- package/server/workspace/journal/paths.ts +76 -0
- package/server/workspace/journal/state.ts +125 -0
- package/server/workspace/paths.ts +158 -0
- package/server/workspace/reference-dirs.ts +252 -0
- package/server/workspace/roles.ts +37 -0
- package/server/workspace/skills/discovery.ts +125 -0
- package/server/workspace/skills/index.ts +10 -0
- package/server/workspace/skills/parser.ts +144 -0
- package/server/workspace/skills/paths.ts +41 -0
- package/server/workspace/skills/scheduler.ts +149 -0
- package/server/workspace/skills/types.ts +30 -0
- package/server/workspace/skills/user-tasks.ts +257 -0
- package/server/workspace/skills/writer.ts +189 -0
- package/server/workspace/sources/arxivDiscovery.ts +182 -0
- package/server/workspace/sources/classifier.ts +268 -0
- package/server/workspace/sources/fetchers/arxiv.ts +170 -0
- package/server/workspace/sources/fetchers/github.ts +106 -0
- package/server/workspace/sources/fetchers/githubIssues.ts +208 -0
- package/server/workspace/sources/fetchers/githubReleases.ts +186 -0
- package/server/workspace/sources/fetchers/index.ts +71 -0
- package/server/workspace/sources/fetchers/registerAll.ts +15 -0
- package/server/workspace/sources/fetchers/rss.ts +141 -0
- package/server/workspace/sources/fetchers/rssParser.ts +295 -0
- package/server/workspace/sources/httpFetcher.ts +230 -0
- package/server/workspace/sources/interests.ts +120 -0
- package/server/workspace/sources/paths.ts +110 -0
- package/server/workspace/sources/pipeline/dedup.ts +60 -0
- package/server/workspace/sources/pipeline/fetch.ts +136 -0
- package/server/workspace/sources/pipeline/index.ts +249 -0
- package/server/workspace/sources/pipeline/notify.ts +72 -0
- package/server/workspace/sources/pipeline/plan.ts +66 -0
- package/server/workspace/sources/pipeline/summarize.ts +189 -0
- package/server/workspace/sources/pipeline/write.ts +185 -0
- package/server/workspace/sources/rateLimiter.ts +148 -0
- package/server/workspace/sources/registry.ts +326 -0
- package/server/workspace/sources/robots.ts +271 -0
- package/server/workspace/sources/sourceState.ts +135 -0
- package/server/workspace/sources/taxonomy.ts +74 -0
- package/server/workspace/sources/types.ts +144 -0
- package/server/workspace/sources/urls.ts +112 -0
- package/server/workspace/tool-trace/classify.ts +114 -0
- package/server/workspace/tool-trace/index.ts +250 -0
- package/server/workspace/tool-trace/writeSearch.ts +98 -0
- package/server/workspace/wiki-backlinks/index.ts +107 -0
- package/server/workspace/wiki-backlinks/sessionBacklinks.ts +144 -0
- package/server/workspace/workspace.ts +66 -0
- package/src/App.vue +720 -0
- package/src/assets/mulmo_bw.png +0 -0
- package/src/components/CanvasViewToggle.vue +27 -0
- package/src/components/ChatAttachmentPreview.vue +45 -0
- package/src/components/ChatImagePreview.vue +17 -0
- package/src/components/ChatInput.vue +208 -0
- package/src/components/FileContentHeader.vue +49 -0
- package/src/components/FileContentRenderer.vue +162 -0
- package/src/components/FileTree.vue +115 -0
- package/src/components/FileTreePane.vue +85 -0
- package/src/components/FilesView.vue +206 -0
- package/src/components/LockStatusPopup.vue +111 -0
- package/src/components/NotificationBell.vue +131 -0
- package/src/components/NotificationToast.vue +72 -0
- package/src/components/PluginLauncher.vue +138 -0
- package/src/components/RightSidebar.vue +113 -0
- package/src/components/RoleSelector.vue +64 -0
- package/src/components/SessionHistoryPanel.vue +176 -0
- package/src/components/SessionTabBar.vue +81 -0
- package/src/components/SettingsMcpTab.vue +350 -0
- package/src/components/SettingsModal.vue +275 -0
- package/src/components/SettingsReferenceDirsTab.vue +173 -0
- package/src/components/SettingsWorkspaceDirsTab.vue +174 -0
- package/src/components/SidebarHeader.vue +69 -0
- package/src/components/StackView.vue +360 -0
- package/src/components/SuggestionsPanel.vue +65 -0
- package/src/components/TodoExplorer.vue +358 -0
- package/src/components/ToolResultsPanel.vue +77 -0
- package/src/components/todo/TodoAddDialog.vue +131 -0
- package/src/components/todo/TodoEditDialog.vue +47 -0
- package/src/components/todo/TodoEditPanel.vue +113 -0
- package/src/components/todo/TodoKanbanView.vue +249 -0
- package/src/components/todo/TodoListView.vue +79 -0
- package/src/components/todo/TodoTableView.vue +177 -0
- package/src/composables/useActiveSession.ts +40 -0
- package/src/composables/useAppApi.ts +45 -0
- package/src/composables/useCanvasViewMode.ts +121 -0
- package/src/composables/useChatScroll.ts +47 -0
- package/src/composables/useClickOutside.ts +26 -0
- package/src/composables/useClipboardCopy.ts +44 -0
- package/src/composables/useContentDisplay.ts +52 -0
- package/src/composables/useDebugBeat.ts +23 -0
- package/src/composables/useDynamicFavicon.ts +115 -0
- package/src/composables/useEventListeners.ts +42 -0
- package/src/composables/useExpandedDirs.ts +64 -0
- package/src/composables/useFaviconState.ts +30 -0
- package/src/composables/useFileSelection.ts +115 -0
- package/src/composables/useFileSortMode.ts +24 -0
- package/src/composables/useFileTree.ts +85 -0
- package/src/composables/useFreshPluginData.ts +89 -0
- package/src/composables/useHealth.ts +38 -0
- package/src/composables/useImeAwareEnter.ts +57 -0
- package/src/composables/useKeyNavigation.ts +60 -0
- package/src/composables/useMarkdownLinkHandler.ts +46 -0
- package/src/composables/useMarkdownMode.ts +17 -0
- package/src/composables/useMcpTools.ts +71 -0
- package/src/composables/useMergedSessions.ts +27 -0
- package/src/composables/useNotifications.ts +90 -0
- package/src/composables/usePdfDownload.ts +60 -0
- package/src/composables/usePendingCalls.ts +77 -0
- package/src/composables/usePubSub.ts +85 -0
- package/src/composables/useRightSidebar.ts +23 -0
- package/src/composables/useRoles.ts +34 -0
- package/src/composables/useSandboxStatus.ts +67 -0
- package/src/composables/useSelectedResult.ts +49 -0
- package/src/composables/useSessionDerived.ts +51 -0
- package/src/composables/useSessionHistory.ts +81 -0
- package/src/composables/useSessionSync.ts +57 -0
- package/src/composables/useViewLayout.ts +55 -0
- package/src/config/apiRoutes.ts +173 -0
- package/src/config/pubsubChannels.ts +45 -0
- package/src/config/roles.ts +335 -0
- package/src/config/schedulerActions.ts +25 -0
- package/src/config/toolNames.ts +71 -0
- package/src/config/workspacePaths.ts +24 -0
- package/src/index.css +107 -0
- package/src/main.ts +25 -0
- package/src/plugins/canvas/Preview.vue +13 -0
- package/src/plugins/canvas/View.vue +333 -0
- package/src/plugins/canvas/definition.ts +38 -0
- package/src/plugins/canvas/index.ts +36 -0
- package/src/plugins/chart/Preview.vue +49 -0
- package/src/plugins/chart/View.vue +143 -0
- package/src/plugins/chart/definition.ts +58 -0
- package/src/plugins/chart/index.ts +52 -0
- package/src/plugins/editImage/Preview.vue +13 -0
- package/src/plugins/editImage/View.vue +13 -0
- package/src/plugins/editImage/definition.ts +27 -0
- package/src/plugins/editImage/index.ts +36 -0
- package/src/plugins/generateImage/Preview.vue +13 -0
- package/src/plugins/generateImage/View.vue +33 -0
- package/src/plugins/generateImage/definition.ts +32 -0
- package/src/plugins/generateImage/index.ts +56 -0
- package/src/plugins/manageRoles/Preview.vue +49 -0
- package/src/plugins/manageRoles/View.vue +525 -0
- package/src/plugins/manageRoles/definition.ts +43 -0
- package/src/plugins/manageRoles/index.ts +47 -0
- package/src/plugins/manageSkills/Preview.vue +21 -0
- package/src/plugins/manageSkills/View.vue +321 -0
- package/src/plugins/manageSkills/definition.ts +49 -0
- package/src/plugins/manageSkills/index.ts +49 -0
- package/src/plugins/manageSource/Preview.vue +33 -0
- package/src/plugins/manageSource/View.vue +697 -0
- package/src/plugins/manageSource/definition.ts +63 -0
- package/src/plugins/manageSource/index.ts +66 -0
- package/src/plugins/markdown/Preview.vue +77 -0
- package/src/plugins/markdown/View.vue +476 -0
- package/src/plugins/markdown/definition.ts +50 -0
- package/src/plugins/markdown/index.ts +36 -0
- package/src/plugins/presentHtml/Preview.vue +25 -0
- package/src/plugins/presentHtml/View.vue +52 -0
- package/src/plugins/presentHtml/definition.ts +27 -0
- package/src/plugins/presentHtml/helpers.ts +72 -0
- package/src/plugins/presentHtml/index.ts +41 -0
- package/src/plugins/presentMulmoScript/Preview.vue +23 -0
- package/src/plugins/presentMulmoScript/View.vue +1166 -0
- package/src/plugins/presentMulmoScript/definition.ts +95 -0
- package/src/plugins/presentMulmoScript/helpers.ts +162 -0
- package/src/plugins/presentMulmoScript/index.ts +40 -0
- package/src/plugins/scheduler/Preview.vue +67 -0
- package/src/plugins/scheduler/TasksTab.vue +205 -0
- package/src/plugins/scheduler/View.vue +565 -0
- package/src/plugins/scheduler/definition.ts +57 -0
- package/src/plugins/scheduler/index.ts +45 -0
- package/src/plugins/scheduler/viewModes.ts +26 -0
- package/src/plugins/spreadsheet/Preview.vue +29 -0
- package/src/plugins/spreadsheet/View.vue +997 -0
- package/src/plugins/spreadsheet/cellHighlights.ts +79 -0
- package/src/plugins/spreadsheet/definition.ts +121 -0
- package/src/plugins/spreadsheet/engine/calculator.ts +459 -0
- package/src/plugins/spreadsheet/engine/cellBuilder.ts +81 -0
- package/src/plugins/spreadsheet/engine/date-parser.ts +220 -0
- package/src/plugins/spreadsheet/engine/date-utils.ts +56 -0
- package/src/plugins/spreadsheet/engine/engine.ts +176 -0
- package/src/plugins/spreadsheet/engine/evaluator.ts +390 -0
- package/src/plugins/spreadsheet/engine/formatter.ts +172 -0
- package/src/plugins/spreadsheet/engine/formulaRefs.ts +101 -0
- package/src/plugins/spreadsheet/engine/functions/date.ts +299 -0
- package/src/plugins/spreadsheet/engine/functions/financial.ts +387 -0
- package/src/plugins/spreadsheet/engine/functions/index.ts +16 -0
- package/src/plugins/spreadsheet/engine/functions/logical.ts +262 -0
- package/src/plugins/spreadsheet/engine/functions/lookup.ts +400 -0
- package/src/plugins/spreadsheet/engine/functions/mathematical.ts +297 -0
- package/src/plugins/spreadsheet/engine/functions/statistical.ts +338 -0
- package/src/plugins/spreadsheet/engine/functions/text.ts +389 -0
- package/src/plugins/spreadsheet/engine/index.ts +27 -0
- package/src/plugins/spreadsheet/engine/jsonCellLocator.ts +111 -0
- package/src/plugins/spreadsheet/engine/parser.ts +143 -0
- package/src/plugins/spreadsheet/engine/registry.ts +150 -0
- package/src/plugins/spreadsheet/engine/responseDecoder.ts +67 -0
- package/src/plugins/spreadsheet/engine/types.ts +64 -0
- package/src/plugins/spreadsheet/index.ts +36 -0
- package/src/plugins/textResponse/Preview.vue +94 -0
- package/src/plugins/textResponse/View.vue +503 -0
- package/src/plugins/textResponse/definition.ts +34 -0
- package/src/plugins/textResponse/index.ts +27 -0
- package/src/plugins/textResponse/plugin.ts +29 -0
- package/src/plugins/textResponse/samples.ts +97 -0
- package/src/plugins/textResponse/types.ts +11 -0
- package/src/plugins/todo/Preview.vue +63 -0
- package/src/plugins/todo/View.vue +364 -0
- package/src/plugins/todo/composables/useTodos.ts +177 -0
- package/src/plugins/todo/definition.ts +45 -0
- package/src/plugins/todo/index.ts +61 -0
- package/src/plugins/todo/labels.ts +163 -0
- package/src/plugins/todo/priority.ts +98 -0
- package/src/plugins/todo/viewModes.ts +19 -0
- package/src/plugins/ui-image/ImagePreview.vue +23 -0
- package/src/plugins/ui-image/ImageView.vue +34 -0
- package/src/plugins/ui-image/index.ts +3 -0
- package/src/plugins/ui-image/types.ts +4 -0
- package/src/plugins/wiki/Preview.vue +65 -0
- package/src/plugins/wiki/View.vue +342 -0
- package/src/plugins/wiki/definition.ts +25 -0
- package/src/plugins/wiki/helpers.ts +59 -0
- package/src/plugins/wiki/index.ts +52 -0
- package/src/router/guards.ts +61 -0
- package/src/router/index.ts +50 -0
- package/src/tools/index.ts +52 -0
- package/src/tools/types.ts +27 -0
- package/src/types/events.ts +16 -0
- package/src/types/fileTree.ts +13 -0
- package/src/types/notification.ts +67 -0
- package/src/types/session.ts +116 -0
- package/src/types/sse.ts +90 -0
- package/src/types/toolCallHistory.ts +13 -0
- package/src/utils/agent/eventDispatch.ts +74 -0
- package/src/utils/agent/request.ts +55 -0
- package/src/utils/agent/toolCalls.ts +62 -0
- package/src/utils/api.ts +218 -0
- package/src/utils/canvas/viewMode.ts +46 -0
- package/src/utils/dom/authTokenMeta.ts +20 -0
- package/src/utils/dom/clickOutside.ts +11 -0
- package/src/utils/dom/externalLink.ts +57 -0
- package/src/utils/dom/scrollable.ts +24 -0
- package/src/utils/errors.ts +11 -0
- package/src/utils/files/expandedDirs.ts +25 -0
- package/src/utils/files/filename.ts +12 -0
- package/src/utils/files/sortChildren.ts +20 -0
- package/src/utils/filesPreview/schedulerPreview.ts +38 -0
- package/src/utils/filesPreview/todoPreview.ts +40 -0
- package/src/utils/format/date.ts +85 -0
- package/src/utils/format/frontmatter.ts +80 -0
- package/src/utils/format/jsonSyntax.ts +109 -0
- package/src/utils/html/previewCsp.ts +65 -0
- package/src/utils/image/resolve.ts +8 -0
- package/src/utils/image/rewriteMarkdownImageRefs.ts +182 -0
- package/src/utils/markdown/extractFirstH1.ts +39 -0
- package/src/utils/notification/dispatch.ts +22 -0
- package/src/utils/path/relativeLink.ts +130 -0
- package/src/utils/role/icon.ts +20 -0
- package/src/utils/role/merge.ts +10 -0
- package/src/utils/role/plugins.ts +12 -0
- package/src/utils/session/mergeSessions.ts +103 -0
- package/src/utils/session/seedRoleDefault.ts +35 -0
- package/src/utils/session/sessionEntries.ts +121 -0
- package/src/utils/session/sessionFactory.ts +22 -0
- package/src/utils/session/sessionHelpers.ts +99 -0
- package/src/utils/tools/dedup.ts +17 -0
- package/src/utils/tools/mcp.ts +33 -0
- package/src/utils/tools/pendingCalls.ts +16 -0
- package/src/utils/tools/result.ts +40 -0
- package/src/utils/types.ts +44 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a SpreadsheetCell from the raw input captured by the mini
|
|
3
|
+
* editor (type + value / formula / format). Extracted from
|
|
4
|
+
* `saveMiniEditor` in `src/plugins/spreadsheet/View.vue` where it
|
|
5
|
+
* was inlined as ~30 lines of nested if/else that pushed the
|
|
6
|
+
* surrounding function over the cognitive-complexity threshold.
|
|
7
|
+
*
|
|
8
|
+
* Pure — no refs, no DOM, no side effects. Given the same inputs
|
|
9
|
+
* it always returns the same SpreadsheetCell. Tested in
|
|
10
|
+
* `test/plugins/spreadsheet/engine/test_cellBuilder.ts`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { SpreadsheetCell } from "./types.js";
|
|
14
|
+
|
|
15
|
+
/** Inputs to the cell builder. Mirrors the mini editor refs in the
|
|
16
|
+
* View but as plain values so unit tests don't need a Vue runtime. */
|
|
17
|
+
export interface MiniEditorInput {
|
|
18
|
+
/** "string" → value is stored as-is as a string.
|
|
19
|
+
* Anything else → the `formula` field is parsed (formula / number / raw string). */
|
|
20
|
+
type: string;
|
|
21
|
+
/** Used when type === "string". Coerced to string. */
|
|
22
|
+
value: unknown;
|
|
23
|
+
/** Used when type !== "string". Trimmed before classification. */
|
|
24
|
+
formula?: string;
|
|
25
|
+
/** Optional format code (e.g. "$#,##0.00"). */
|
|
26
|
+
format?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Anchored at the start of the input (after optional unary +/-) so we
|
|
30
|
+
// only treat expressions that clearly begin with a function call as
|
|
31
|
+
// formulas. Unanchored would match "abc FOO(" inside ordinary text.
|
|
32
|
+
const FORMULA_FUNCTION_CALL = /^[-+]?\s*[A-Z]+\s*\(/i;
|
|
33
|
+
|
|
34
|
+
// `A1 + B2` style — cell reference next to an arithmetic operator.
|
|
35
|
+
const FORMULA_CELL_OP = /[A-Z]+\d+\s*[+\-*/^]/;
|
|
36
|
+
|
|
37
|
+
// `6/100`, `5 * 2` — arithmetic between two literal numbers.
|
|
38
|
+
const FORMULA_NUMERIC_OP = /\d+\s*[+\-*/^]\s*\d+/;
|
|
39
|
+
|
|
40
|
+
// Strict numeric literal. `parseFloat` accepts trailing junk
|
|
41
|
+
// ("42abc" → 42) which silently corrupts user input; this anchor
|
|
42
|
+
// ensures the ENTIRE trimmed string is a number.
|
|
43
|
+
const STRICT_NUMBER = /^[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?$/;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Best-effort formula detection. The rules are conservative enough
|
|
47
|
+
* that plain text like "hello world" stays as text, but any input
|
|
48
|
+
* with arithmetic operators or function calls is treated as a
|
|
49
|
+
* formula and gets the "=" prefix the engine expects.
|
|
50
|
+
*/
|
|
51
|
+
export function looksLikeFormula(input: string): boolean {
|
|
52
|
+
return FORMULA_FUNCTION_CALL.test(input) || FORMULA_CELL_OP.test(input) || FORMULA_NUMERIC_OP.test(input);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Parse the raw (non-string-type) editor input into a cell value.
|
|
57
|
+
* Priority: formula > number > raw string > empty string.
|
|
58
|
+
*/
|
|
59
|
+
export function parseNonStringInput(raw: string): number | string {
|
|
60
|
+
const input = raw.trim();
|
|
61
|
+
if (input === "") return "";
|
|
62
|
+
if (looksLikeFormula(input)) return `=${input}`;
|
|
63
|
+
return STRICT_NUMBER.test(input) ? Number(input) : input;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Build the full SpreadsheetCell from a mini editor input record.
|
|
68
|
+
* String type short-circuits to `{ v: String(value) }`.
|
|
69
|
+
* Everything else goes through parseNonStringInput for formula /
|
|
70
|
+
* number / text classification, then optionally attaches `f`.
|
|
71
|
+
*/
|
|
72
|
+
export function buildCellFromInput(input: MiniEditorInput): SpreadsheetCell {
|
|
73
|
+
if (input.type === "string") {
|
|
74
|
+
return { v: String(input.value) };
|
|
75
|
+
}
|
|
76
|
+
const cell: SpreadsheetCell = { v: parseNonStringInput(input.formula ?? "") };
|
|
77
|
+
if (input.format && input.format.length > 0) {
|
|
78
|
+
cell.f = input.format;
|
|
79
|
+
}
|
|
80
|
+
return cell;
|
|
81
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Date Parsing Utilities
|
|
3
|
+
*
|
|
4
|
+
* Parse various date string formats into Excel serial numbers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { dateToSerial, MONTH_NAMES_SHORT, MONTH_NAMES_FULL } from "./date-utils";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Check if a string looks like a date
|
|
11
|
+
*
|
|
12
|
+
* @param str - String to check
|
|
13
|
+
* @returns true if string matches common date patterns
|
|
14
|
+
*/
|
|
15
|
+
export function isDateLike(str: string): boolean {
|
|
16
|
+
if (typeof str !== "string") return false;
|
|
17
|
+
if (str.length < 6 || str.length > 30) return false; // Reasonable length for dates
|
|
18
|
+
|
|
19
|
+
// Common date patterns:
|
|
20
|
+
// MM/DD/YYYY, DD/MM/YYYY, M/D/YYYY
|
|
21
|
+
// YYYY-MM-DD, YYYY/MM/DD
|
|
22
|
+
// DD-MMM-YYYY, D-MMM-YYYY
|
|
23
|
+
// MMM D, YYYY, MMMM D, YYYY
|
|
24
|
+
|
|
25
|
+
// Pattern 1: Contains digits and separators (/, -, space)
|
|
26
|
+
const hasDigits = /\d/.test(str);
|
|
27
|
+
const hasSeparator = /[/\-\s,]/.test(str);
|
|
28
|
+
|
|
29
|
+
if (!hasDigits || !hasSeparator) return false;
|
|
30
|
+
|
|
31
|
+
// Pattern 2: Matches common date formats
|
|
32
|
+
const datePatterns = [
|
|
33
|
+
/^\d{1,2}\/\d{1,2}\/\d{2,4}$/, // MM/DD/YYYY or DD/MM/YYYY
|
|
34
|
+
/^\d{4}-\d{1,2}-\d{1,2}$/, // YYYY-MM-DD
|
|
35
|
+
/^\d{4}\/\d{1,2}\/\d{1,2}$/, // YYYY/MM/DD
|
|
36
|
+
/^\d{1,2}-[A-Za-z]{3}-\d{2,4}$/, // DD-MMM-YYYY
|
|
37
|
+
/^[A-Za-z]{3,9}\s+\d{1,2},?\s+\d{4}$/, // MMM D, YYYY or MMMM D, YYYY
|
|
38
|
+
/^\d{1,2}\s+[A-Za-z]{3,9}\s+\d{4}$/, // D MMM YYYY
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
return datePatterns.some((pattern) => pattern.test(str.trim()));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Parse a month name to month number (1-12)
|
|
46
|
+
*/
|
|
47
|
+
function parseMonthName(monthStr: string): number | null {
|
|
48
|
+
const month = monthStr.toLowerCase();
|
|
49
|
+
|
|
50
|
+
// Try short names
|
|
51
|
+
const shortIndex = MONTH_NAMES_SHORT.findIndex((m) => m.toLowerCase() === month);
|
|
52
|
+
if (shortIndex !== -1) return shortIndex + 1;
|
|
53
|
+
|
|
54
|
+
// Try full names
|
|
55
|
+
const fullIndex = MONTH_NAMES_FULL.findIndex((m) => m.toLowerCase() === month);
|
|
56
|
+
if (fullIndex !== -1) return fullIndex + 1;
|
|
57
|
+
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Parse a date string into Excel serial number
|
|
63
|
+
*
|
|
64
|
+
* Supports formats:
|
|
65
|
+
* - MM/DD/YYYY, M/D/YYYY
|
|
66
|
+
* - DD/MM/YYYY (when day > 12)
|
|
67
|
+
* - YYYY-MM-DD, YYYY/MM/DD (ISO format)
|
|
68
|
+
* - DD-MMM-YYYY, D-MMM-YYYY
|
|
69
|
+
* - MMM D, YYYY, MMMM D, YYYY
|
|
70
|
+
*
|
|
71
|
+
* @param dateStr - String that might contain a date
|
|
72
|
+
* @param preferDDMMYYYY - Prefer DD/MM/YYYY over MM/DD/YYYY for ambiguous dates (default: false)
|
|
73
|
+
* @returns Serial number or null if not a valid date
|
|
74
|
+
*/
|
|
75
|
+
export function parseDate(dateStr: string, preferDDMMYYYY: boolean = false): number | null {
|
|
76
|
+
if (!isDateLike(dateStr)) return null;
|
|
77
|
+
|
|
78
|
+
const trimmed = dateStr.trim();
|
|
79
|
+
|
|
80
|
+
// Try YYYY-MM-DD or YYYY/MM/DD (ISO format)
|
|
81
|
+
const isoMatch = trimmed.match(/^(\d{4})[-/](\d{1,2})[-/](\d{1,2})$/);
|
|
82
|
+
if (isoMatch) {
|
|
83
|
+
const year = parseInt(isoMatch[1]);
|
|
84
|
+
const month = parseInt(isoMatch[2]);
|
|
85
|
+
const day = parseInt(isoMatch[3]);
|
|
86
|
+
|
|
87
|
+
if (isValidDate(year, month, day)) {
|
|
88
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
89
|
+
return dateToSerial(date);
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Try DD-MMM-YYYY or D-MMM-YYYY
|
|
95
|
+
const dmmyMatch = trimmed.match(/^(\d{1,2})-([A-Za-z]{3})-(\d{2,4})$/);
|
|
96
|
+
if (dmmyMatch) {
|
|
97
|
+
const day = parseInt(dmmyMatch[1]);
|
|
98
|
+
const monthName = dmmyMatch[2];
|
|
99
|
+
let year = parseInt(dmmyMatch[3]);
|
|
100
|
+
|
|
101
|
+
// Handle 2-digit years
|
|
102
|
+
if (year < 100) {
|
|
103
|
+
year = year < 30 ? 2000 + year : 1900 + year;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const month = parseMonthName(monthName);
|
|
107
|
+
if (month && isValidDate(year, month, day)) {
|
|
108
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
109
|
+
return dateToSerial(date);
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Try MMM D, YYYY or MMMM D, YYYY
|
|
115
|
+
const mmmMatch = trimmed.match(/^([A-Za-z]{3,9})\s+(\d{1,2}),?\s+(\d{4})$/);
|
|
116
|
+
if (mmmMatch) {
|
|
117
|
+
const monthName = mmmMatch[1];
|
|
118
|
+
const day = parseInt(mmmMatch[2]);
|
|
119
|
+
const year = parseInt(mmmMatch[3]);
|
|
120
|
+
|
|
121
|
+
const month = parseMonthName(monthName);
|
|
122
|
+
if (month && isValidDate(year, month, day)) {
|
|
123
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
124
|
+
return dateToSerial(date);
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Try D MMM YYYY
|
|
130
|
+
const dMmmMatch = trimmed.match(/^(\d{1,2})\s+([A-Za-z]{3,9})\s+(\d{4})$/);
|
|
131
|
+
if (dMmmMatch) {
|
|
132
|
+
const day = parseInt(dMmmMatch[1]);
|
|
133
|
+
const monthName = dMmmMatch[2];
|
|
134
|
+
const year = parseInt(dMmmMatch[3]);
|
|
135
|
+
|
|
136
|
+
const month = parseMonthName(monthName);
|
|
137
|
+
if (month && isValidDate(year, month, day)) {
|
|
138
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
139
|
+
return dateToSerial(date);
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Try MM/DD/YYYY or DD/MM/YYYY
|
|
145
|
+
const slashMatch = trimmed.match(/^(\d{1,2})\/(\d{1,2})\/(\d{2,4})$/);
|
|
146
|
+
if (slashMatch) {
|
|
147
|
+
const first = parseInt(slashMatch[1]);
|
|
148
|
+
const second = parseInt(slashMatch[2]);
|
|
149
|
+
let year = parseInt(slashMatch[3]);
|
|
150
|
+
|
|
151
|
+
// Handle 2-digit years
|
|
152
|
+
if (year < 100) {
|
|
153
|
+
year = year < 30 ? 2000 + year : 1900 + year;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Determine if it's MM/DD/YYYY or DD/MM/YYYY
|
|
157
|
+
// If first > 12, it must be DD/MM; if second > 12, it must be MM/DD
|
|
158
|
+
// Otherwise use preference (default to MM/DD for US format)
|
|
159
|
+
const isDayFirst = first > 12 || (second <= 12 && first <= 12 && preferDDMMYYYY);
|
|
160
|
+
const month = isDayFirst ? second : first;
|
|
161
|
+
const day = isDayFirst ? first : second;
|
|
162
|
+
|
|
163
|
+
if (isValidDate(year, month, day)) {
|
|
164
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
165
|
+
return dateToSerial(date);
|
|
166
|
+
}
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Validate that a date is valid
|
|
175
|
+
*/
|
|
176
|
+
function isValidDate(year: number, month: number, day: number): boolean {
|
|
177
|
+
// Check basic ranges
|
|
178
|
+
if (year < 1900 || year > 2100) return false;
|
|
179
|
+
if (month < 1 || month > 12) return false;
|
|
180
|
+
if (day < 1 || day > 31) return false;
|
|
181
|
+
|
|
182
|
+
// Check if day is valid for the given month
|
|
183
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
184
|
+
|
|
185
|
+
// If the date rolls over to the next month, it's invalid
|
|
186
|
+
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get default date format based on parsed date
|
|
191
|
+
*
|
|
192
|
+
* @param originalStr - Original date string
|
|
193
|
+
* @returns Appropriate format code
|
|
194
|
+
*/
|
|
195
|
+
export function getDefaultDateFormat(originalStr: string): string {
|
|
196
|
+
const trimmed = originalStr.trim();
|
|
197
|
+
|
|
198
|
+
// YYYY-MM-DD → use same format
|
|
199
|
+
if (/^\d{4}-\d{1,2}-\d{1,2}$/.test(trimmed)) {
|
|
200
|
+
return "YYYY-MM-DD";
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// DD-MMM-YYYY → use same format
|
|
204
|
+
if (/^\d{1,2}-[A-Za-z]{3}-\d{2,4}$/.test(trimmed)) {
|
|
205
|
+
return "DD-MMM-YYYY";
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// MMM D, YYYY → use same format
|
|
209
|
+
if (/^[A-Za-z]{3}\s+\d{1,2},?\s+\d{4}$/.test(trimmed)) {
|
|
210
|
+
return "MMM D, YYYY";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// MMMM D, YYYY → use same format
|
|
214
|
+
if (/^[A-Za-z]{4,9}\s+\d{1,2},?\s+\d{4}$/.test(trimmed)) {
|
|
215
|
+
return "MMMM D, YYYY";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Default to MM/DD/YYYY for slash-separated dates
|
|
219
|
+
return "MM/DD/YYYY";
|
|
220
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Date Utility Functions
|
|
3
|
+
*
|
|
4
|
+
* Shared utilities for converting between JavaScript Date objects and Excel serial numbers.
|
|
5
|
+
* Excel stores dates as sequential serial numbers so they can be used in calculations.
|
|
6
|
+
* January 1, 1900 is serial number 1.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Constants
|
|
10
|
+
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
11
|
+
// Excel base date: Dec 30, 1899 (to handle the 1900 leap year bug correctly)
|
|
12
|
+
const EXCEL_BASE_DATE = new Date(Date.UTC(1899, 11, 30));
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Convert JavaScript Date to Excel Serial Number
|
|
16
|
+
*
|
|
17
|
+
* @param date - JavaScript Date object
|
|
18
|
+
* @returns Excel serial number (days since Dec 30, 1899)
|
|
19
|
+
*/
|
|
20
|
+
export const dateToSerial = (date: Date): number => {
|
|
21
|
+
const diff = date.getTime() - EXCEL_BASE_DATE.getTime();
|
|
22
|
+
return diff / MS_PER_DAY;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Convert Excel Serial Number to JavaScript Date
|
|
27
|
+
*
|
|
28
|
+
* @param serial - Excel serial number
|
|
29
|
+
* @returns JavaScript Date object
|
|
30
|
+
*/
|
|
31
|
+
export const serialToDate = (serial: number): Date => {
|
|
32
|
+
const days = Math.floor(serial);
|
|
33
|
+
const timePart = serial - days;
|
|
34
|
+
|
|
35
|
+
const date = new Date(EXCEL_BASE_DATE.getTime() + days * MS_PER_DAY);
|
|
36
|
+
|
|
37
|
+
// Add time component
|
|
38
|
+
const totalSeconds = Math.round(timePart * 24 * 60 * 60);
|
|
39
|
+
date.setSeconds(date.getSeconds() + totalSeconds);
|
|
40
|
+
|
|
41
|
+
return date;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Month names for formatting
|
|
46
|
+
*/
|
|
47
|
+
export const MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
48
|
+
|
|
49
|
+
export const MONTH_NAMES_FULL = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Day names for formatting
|
|
53
|
+
*/
|
|
54
|
+
export const DAY_NAMES_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
55
|
+
|
|
56
|
+
export const DAY_NAMES_FULL = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpreadsheetEngine - Main API
|
|
3
|
+
*
|
|
4
|
+
* High-level interface for spreadsheet calculations
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { calculateSheet, calculateWorkbook } from "./calculator";
|
|
8
|
+
import type { SheetData, CalculatedSheet, EngineOptions, SpreadsheetCell } from "./types";
|
|
9
|
+
import { isObj } from "../../../utils/types";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* SpreadsheetEngine - Main calculation engine class
|
|
13
|
+
*
|
|
14
|
+
* Provides a clean API for calculating spreadsheet formulas with support for:
|
|
15
|
+
* - Formula evaluation (SUM, AVERAGE, IF, etc.)
|
|
16
|
+
* - Cell references (A1, $B$2, Sheet1!C3)
|
|
17
|
+
* - Cross-sheet references
|
|
18
|
+
* - Number formatting ($#,##0.00, 0.00%, etc.)
|
|
19
|
+
* - Circular reference detection
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const engine = new SpreadsheetEngine();
|
|
24
|
+
* const sheet = {
|
|
25
|
+
* name: 'Sales',
|
|
26
|
+
* data: [
|
|
27
|
+
* [{v: 'Product'}, {v: 'Price'}, {v: 'Qty'}, {v: 'Total'}],
|
|
28
|
+
* [{v: 'Widget'}, {v: 10}, {v: 100}, {v: '=B2*C2'}],
|
|
29
|
+
* ]
|
|
30
|
+
* };
|
|
31
|
+
* const result = engine.calculate(sheet);
|
|
32
|
+
* console.log(result.data); // [['Product', 'Price', 'Qty', 'Total'], ['Widget', 10, 100, 1000]]
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class SpreadsheetEngine {
|
|
36
|
+
private options: Required<EngineOptions>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Create a new SpreadsheetEngine
|
|
40
|
+
*
|
|
41
|
+
* @param options - Configuration options
|
|
42
|
+
*/
|
|
43
|
+
constructor(options: EngineOptions = {}) {
|
|
44
|
+
this.options = {
|
|
45
|
+
maxIterations: options.maxIterations ?? 100,
|
|
46
|
+
enableCrossSheetRefs: options.enableCrossSheetRefs ?? true,
|
|
47
|
+
strictMode: options.strictMode ?? false,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Calculate a single sheet
|
|
53
|
+
*
|
|
54
|
+
* Evaluates all formulas in the sheet and applies number formatting.
|
|
55
|
+
* Returns calculated values with formula metadata and any errors.
|
|
56
|
+
*
|
|
57
|
+
* @param sheet - Sheet data with formulas
|
|
58
|
+
* @param allSheets - Optional array of all sheets for cross-sheet references
|
|
59
|
+
* @returns Calculated sheet with evaluated formulas
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* const result = engine.calculate({
|
|
64
|
+
* name: 'Budget',
|
|
65
|
+
* data: [
|
|
66
|
+
* [{v: 'Item'}, {v: 'Amount'}],
|
|
67
|
+
* [{v: 'Revenue'}, {v: 1000}],
|
|
68
|
+
* [{v: 'Expenses'}, {v: 600}],
|
|
69
|
+
* [{v: 'Profit'}, {v: '=B2-B3'}],
|
|
70
|
+
* ]
|
|
71
|
+
* });
|
|
72
|
+
* console.log(result.data[3][1]); // 400
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
calculate(sheet: SheetData, allSheets?: SheetData[]): CalculatedSheet {
|
|
76
|
+
return calculateSheet(sheet, allSheets);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Calculate all sheets in a workbook
|
|
81
|
+
*
|
|
82
|
+
* Evaluates formulas across multiple sheets with support for
|
|
83
|
+
* cross-sheet references (e.g., Sheet1!A1).
|
|
84
|
+
*
|
|
85
|
+
* @param sheets - Array of sheets to calculate
|
|
86
|
+
* @returns Array of calculated sheets
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const results = engine.calculateWorkbook([
|
|
91
|
+
* { name: 'Data', data: [[{v: 100}]] },
|
|
92
|
+
* { name: 'Summary', data: [[{v: '=Data!A1*2'}]] }
|
|
93
|
+
* ]);
|
|
94
|
+
* console.log(results[1].data[0][0]); // 200
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
calculateWorkbook(sheets: SheetData[]): CalculatedSheet[] {
|
|
98
|
+
return calculateWorkbook(sheets);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get current engine options
|
|
103
|
+
*
|
|
104
|
+
* @returns Current configuration options
|
|
105
|
+
*/
|
|
106
|
+
getOptions(): Required<EngineOptions> {
|
|
107
|
+
return { ...this.options };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Update engine options
|
|
112
|
+
*
|
|
113
|
+
* @param options - Options to update
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* engine.setOptions({ strictMode: true });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
setOptions(options: Partial<EngineOptions>): void {
|
|
121
|
+
this.options = {
|
|
122
|
+
...this.options,
|
|
123
|
+
...options,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Create a simple sheet from array data
|
|
129
|
+
*
|
|
130
|
+
* Helper method to create a SheetData object from simple arrays.
|
|
131
|
+
* Automatically converts values to SpreadsheetCell format.
|
|
132
|
+
*
|
|
133
|
+
* @param name - Sheet name
|
|
134
|
+
* @param data - Array of arrays (rows and cells)
|
|
135
|
+
* @returns SheetData object
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const sheet = engine.createSheet('Sales', [
|
|
140
|
+
* ['Product', 'Price', 'Qty', 'Total'],
|
|
141
|
+
* ['Widget', 10, 100, '=B2*C2'],
|
|
142
|
+
* ]);
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
createSheet(name: string, data: Array<Array<SpreadsheetCell | string | number>>): SheetData {
|
|
146
|
+
return {
|
|
147
|
+
name,
|
|
148
|
+
data: data.map((row) =>
|
|
149
|
+
row.map((cell) => {
|
|
150
|
+
if (isObj(cell) && "v" in cell) {
|
|
151
|
+
return cell as SpreadsheetCell;
|
|
152
|
+
}
|
|
153
|
+
return { v: cell };
|
|
154
|
+
}),
|
|
155
|
+
),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Convert calculated sheet data to string array
|
|
161
|
+
*
|
|
162
|
+
* Helper method for testing and output formatting.
|
|
163
|
+
*
|
|
164
|
+
* @param calculated - Calculated sheet
|
|
165
|
+
* @returns 2D array of strings
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```typescript
|
|
169
|
+
* const result = engine.calculate(sheet);
|
|
170
|
+
* const stringArray = engine.toStringArray(result);
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
toStringArray(calculated: CalculatedSheet): string[][] {
|
|
174
|
+
return calculated.data.map((row) => row.map((cell) => String(cell ?? "")));
|
|
175
|
+
}
|
|
176
|
+
}
|