@beyondwork/docx-react-component 1.0.29 → 1.0.31
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/package.json +65 -96
- package/src/README.md +85 -0
- package/src/api/README.md +26 -0
- package/src/api/public-types.ts +1952 -0
- package/src/api/session-state.ts +62 -0
- package/src/compare/diff-engine.ts +623 -0
- package/src/compare/export-redlines.ts +280 -0
- package/src/compare/index.ts +25 -0
- package/src/compare/snapshot.ts +97 -0
- package/src/component-inventory.md +99 -0
- package/src/core/README.md +10 -0
- package/src/core/commands/README.md +3 -0
- package/{dist/chunk-TJBP2K4T.js → src/core/commands/formatting-commands.ts} +536 -196
- package/src/core/commands/image-commands.ts +373 -0
- package/src/core/commands/index.ts +1879 -0
- package/src/core/commands/list-commands.ts +565 -0
- package/src/core/commands/paragraph-layout-commands.ts +339 -0
- package/src/core/commands/review-commands.ts +108 -0
- package/{dist/core/commands/section-layout-commands.cjs → src/core/commands/section-layout-commands.ts} +340 -137
- package/src/core/commands/structural-helpers.ts +309 -0
- package/{dist/core/commands/style-commands.cjs → src/core/commands/style-commands.ts} +113 -65
- package/src/core/commands/table-structure-commands.ts +854 -0
- package/{dist/chunk-UZXBISGO.js → src/core/commands/text-commands.ts} +142 -86
- package/src/core/schema/README.md +3 -0
- package/src/core/schema/text-schema.ts +516 -0
- package/src/core/search/search-text.ts +357 -0
- package/src/core/selection/README.md +3 -0
- package/src/core/selection/mapping.ts +289 -0
- package/src/core/selection/review-anchors.ts +183 -0
- package/src/core/state/README.md +3 -0
- package/src/core/state/editor-state.ts +892 -0
- package/src/core/state/text-transaction.ts +869 -0
- package/src/formats/xlsx/io/parse-shared-strings.ts +41 -0
- package/src/formats/xlsx/io/parse-sheet.ts +459 -0
- package/src/formats/xlsx/io/parse-styles.ts +59 -0
- package/src/formats/xlsx/io/parse-workbook.ts +75 -0
- package/src/formats/xlsx/io/serialize-shared-strings.ts +72 -0
- package/src/formats/xlsx/io/serialize-sheet.ts +333 -0
- package/src/formats/xlsx/io/serialize-styles.ts +98 -0
- package/src/formats/xlsx/io/serialize-workbook.ts +429 -0
- package/src/formats/xlsx/io/xlsx-session.ts +314 -0
- package/src/formats/xlsx/model/cell.ts +189 -0
- package/src/formats/xlsx/model/sheet.ts +326 -0
- package/src/formats/xlsx/model/styles.ts +118 -0
- package/src/formats/xlsx/model/workbook.ts +453 -0
- package/src/formats/xlsx/runtime/cell-commands.ts +567 -0
- package/src/formats/xlsx/runtime/sheet-commands.ts +206 -0
- package/src/formats/xlsx/runtime/workbook-runtime.ts +177 -0
- package/src/formats/xlsx/runtime/workbook-transaction.ts +822 -0
- package/src/index.ts +142 -0
- package/src/io/README.md +10 -0
- package/src/io/docx-session.ts +3175 -0
- package/src/io/export/README.md +3 -0
- package/src/io/export/export-session.ts +220 -0
- package/src/io/export/minimal-docx.ts +115 -0
- package/src/io/export/reattach-preserved-parts.ts +54 -0
- package/src/io/export/serialize-comments.ts +947 -0
- package/src/io/export/serialize-footnotes.ts +394 -0
- package/src/io/export/serialize-headers-footers.ts +368 -0
- package/src/io/export/serialize-main-document.ts +1342 -0
- package/src/io/export/serialize-numbering.ts +218 -0
- package/src/io/export/serialize-revisions.ts +389 -0
- package/src/io/export/serialize-runtime-revisions.ts +463 -0
- package/src/io/export/serialize-tables.ts +174 -0
- package/src/io/export/split-review-boundaries.ts +356 -0
- package/src/io/export/split-story-blocks-for-runtime-revisions.ts +252 -0
- package/src/io/export/table-properties-xml.ts +318 -0
- package/src/io/normalize/README.md +3 -0
- package/src/io/normalize/normalize-text.ts +670 -0
- package/src/io/ooxml/README.md +3 -0
- package/src/io/ooxml/highlight-colors.ts +39 -0
- package/src/io/ooxml/numbering-sentinels.ts +44 -0
- package/src/io/ooxml/parse-comments.ts +852 -0
- package/src/io/ooxml/parse-complex-content.ts +287 -0
- package/src/io/ooxml/parse-fields.ts +834 -0
- package/src/io/ooxml/parse-footnotes.ts +952 -0
- package/src/io/ooxml/parse-headers-footers.ts +1212 -0
- package/src/io/ooxml/parse-inline-media.ts +461 -0
- package/src/io/ooxml/parse-main-document.ts +2947 -0
- package/src/io/ooxml/parse-numbering.ts +747 -0
- package/src/io/ooxml/parse-revisions.ts +1045 -0
- package/src/io/ooxml/parse-settings.ts +184 -0
- package/src/io/ooxml/parse-shapes.ts +296 -0
- package/src/io/ooxml/parse-styles.ts +639 -0
- package/src/io/ooxml/parse-tables.ts +627 -0
- package/src/io/ooxml/parse-theme.ts +346 -0
- package/src/io/ooxml/part-manifest.ts +136 -0
- package/src/io/ooxml/revision-boundaries.ts +475 -0
- package/src/io/ooxml/workflow-payload.ts +544 -0
- package/src/io/opc/README.md +3 -0
- package/src/io/opc/corrupt-package.ts +166 -0
- package/src/io/opc/docx-package.ts +74 -0
- package/src/io/opc/package-reader.ts +325 -0
- package/src/io/opc/package-writer.ts +273 -0
- package/src/io/source-package-provenance.ts +241 -0
- package/{dist/chunk-RMH72RZI.js → src/legal/bookmarks.ts} +130 -44
- package/src/legal/cross-references.ts +414 -0
- package/src/legal/defined-terms.ts +203 -0
- package/src/legal/index.ts +32 -0
- package/src/legal/signature-blocks.ts +259 -0
- package/src/model/README.md +3 -0
- package/src/model/canonical-document.ts +2722 -0
- package/src/model/cds-1.0.0.ts +212 -0
- package/src/model/snapshot.ts +760 -0
- package/src/preservation/README.md +3 -0
- package/src/preservation/markup-compatibility.ts +48 -0
- package/src/preservation/opaque-fragment-store.ts +89 -0
- package/src/preservation/opaque-region.ts +233 -0
- package/src/preservation/package-preservation.ts +113 -0
- package/src/preservation/preserved-part-manifest.ts +56 -0
- package/src/preservation/relationship-retention.ts +57 -0
- package/src/preservation/store.ts +255 -0
- package/src/review/README.md +16 -0
- package/src/review/store/README.md +3 -0
- package/src/review/store/comment-anchors.ts +70 -0
- package/src/review/store/comment-remapping.ts +154 -0
- package/src/review/store/comment-store.ts +349 -0
- package/src/review/store/comment-thread.ts +109 -0
- package/src/review/store/revision-actions.ts +423 -0
- package/src/review/store/revision-store.ts +323 -0
- package/src/review/store/revision-types.ts +182 -0
- package/src/review/store/runtime-comment-store.ts +43 -0
- package/src/runtime/README.md +3 -0
- package/src/runtime/ai-action-policy.ts +764 -0
- package/src/runtime/context-analytics.ts +824 -0
- package/src/runtime/document-layout.ts +332 -0
- package/src/runtime/document-locations.ts +521 -0
- package/src/runtime/document-navigation.ts +616 -0
- package/src/runtime/document-outline.ts +440 -0
- package/src/runtime/document-runtime.ts +4055 -0
- package/src/runtime/document-search.ts +145 -0
- package/src/runtime/event-refresh-hints.ts +137 -0
- package/src/runtime/numbering-prefix.ts +244 -0
- package/src/runtime/page-layout-estimation.ts +305 -0
- package/src/runtime/read-only-diagnostics-runtime.ts +241 -0
- package/src/runtime/resolved-numbering-geometry.ts +293 -0
- package/src/runtime/review-runtime.ts +44 -0
- package/src/runtime/revision-runtime.ts +107 -0
- package/src/runtime/session-capabilities.ts +192 -0
- package/src/runtime/story-context.ts +164 -0
- package/src/runtime/story-targeting.ts +162 -0
- package/src/runtime/suggestions-snapshot.ts +137 -0
- package/src/runtime/surface-projection.ts +1553 -0
- package/src/runtime/table-commands.ts +173 -0
- package/src/runtime/table-schema.ts +309 -0
- package/src/runtime/table-style-resolver.ts +409 -0
- package/src/runtime/view-state.ts +493 -0
- package/src/runtime/virtualized-rendering.ts +258 -0
- package/src/runtime/workflow-markup.ts +393 -0
- package/src/ui/README.md +30 -0
- package/src/ui/WordReviewEditor.tsx +5268 -0
- package/src/ui/browser-export.ts +52 -0
- package/src/ui/comments/README.md +3 -0
- package/src/ui/compatibility/README.md +3 -0
- package/src/ui/editor-command-bag.ts +127 -0
- package/src/ui/editor-runtime-boundary.ts +1558 -0
- package/src/ui/editor-shell-view.tsx +144 -0
- package/src/ui/editor-surface/README.md +3 -0
- package/src/ui/editor-surface-controller.tsx +66 -0
- package/src/ui/headless/comment-decoration-model.ts +124 -0
- package/src/ui/headless/preserve-editor-selection.ts +5 -0
- package/src/ui/headless/revision-decoration-model.ts +128 -0
- package/src/ui/headless/selection-helpers.ts +54 -0
- package/src/ui/headless/selection-tool-context.ts +19 -0
- package/src/ui/headless/selection-tool-resolver.ts +752 -0
- package/src/ui/headless/selection-tool-types.ts +129 -0
- package/src/ui/headless/selection-toolbar-model.ts +11 -0
- package/src/ui/headless/use-editor-keyboard.ts +103 -0
- package/src/ui/review/README.md +3 -0
- package/src/ui/runtime-shortcut-dispatch.ts +365 -0
- package/src/ui/runtime-snapshot-selectors.ts +197 -0
- package/src/ui/shared/revision-filters.ts +31 -0
- package/src/ui/status/README.md +3 -0
- package/src/ui/theme/README.md +3 -0
- package/src/ui/toolbar/README.md +3 -0
- package/src/ui/workflow-surface-blocked-rails.ts +94 -0
- package/src/ui-tailwind/chrome/chrome-preset-model.ts +107 -0
- package/src/ui-tailwind/chrome/chrome-preset-toolbar.tsx +15 -0
- package/src/ui-tailwind/chrome/responsive-chrome.ts +46 -0
- package/src/ui-tailwind/chrome/review-queue-bar.tsx +97 -0
- package/src/ui-tailwind/chrome/tw-alert-banner.tsx +64 -0
- package/src/ui-tailwind/chrome/tw-context-analytics-summary.tsx +122 -0
- package/src/ui-tailwind/chrome/tw-image-context-toolbar.tsx +121 -0
- package/src/ui-tailwind/chrome/tw-layout-panel.tsx +114 -0
- package/src/ui-tailwind/chrome/tw-object-context-toolbar.tsx +30 -0
- package/src/ui-tailwind/chrome/tw-page-ruler.tsx +365 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-blocked.tsx +23 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-comment.tsx +35 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-formatting.tsx +37 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-host.tsx +303 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-structure.tsx +116 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-suggestion.tsx +29 -0
- package/src/ui-tailwind/chrome/tw-selection-tool-workflow.tsx +27 -0
- package/src/ui-tailwind/chrome/tw-selection-toolbar.tsx +186 -0
- package/src/ui-tailwind/chrome/tw-suggestion-card.tsx +139 -0
- package/src/ui-tailwind/chrome/tw-table-context-toolbar.tsx +250 -0
- package/src/ui-tailwind/chrome/tw-unsaved-modal.tsx +58 -0
- package/src/ui-tailwind/chrome/use-before-unload.ts +20 -0
- package/src/ui-tailwind/editor-surface/perf-probe.ts +179 -0
- package/src/ui-tailwind/editor-surface/pm-command-bridge.ts +189 -0
- package/src/ui-tailwind/editor-surface/pm-contextual-ui.ts +31 -0
- package/src/ui-tailwind/editor-surface/pm-decorations.ts +411 -0
- package/src/ui-tailwind/editor-surface/pm-position-map.ts +123 -0
- package/src/ui-tailwind/editor-surface/pm-schema.ts +927 -0
- package/src/ui-tailwind/editor-surface/pm-state-from-snapshot.ts +567 -0
- package/src/ui-tailwind/editor-surface/search-plugin.ts +168 -0
- package/src/ui-tailwind/editor-surface/surface-build-keys.ts +63 -0
- package/src/ui-tailwind/editor-surface/tw-caret.tsx +12 -0
- package/src/ui-tailwind/editor-surface/tw-editor-surface.tsx +150 -0
- package/src/ui-tailwind/editor-surface/tw-inline-token.tsx +129 -0
- package/src/ui-tailwind/editor-surface/tw-opaque-block.tsx +58 -0
- package/src/ui-tailwind/editor-surface/tw-paragraph-block.tsx +151 -0
- package/src/ui-tailwind/editor-surface/tw-prosemirror-surface.tsx +1047 -0
- package/src/ui-tailwind/editor-surface/tw-segment-view.tsx +111 -0
- package/src/ui-tailwind/editor-surface/tw-table-node-view.tsx +503 -0
- package/src/ui-tailwind/index.ts +62 -0
- package/src/ui-tailwind/page-chrome-model.ts +27 -0
- package/src/ui-tailwind/review/tw-comment-sidebar.tsx +406 -0
- package/src/ui-tailwind/review/tw-health-panel.tsx +149 -0
- package/src/ui-tailwind/review/tw-review-rail.tsx +130 -0
- package/src/ui-tailwind/review/tw-revision-sidebar.tsx +164 -0
- package/src/ui-tailwind/status/tw-status-bar.tsx +65 -0
- package/{dist → src}/ui-tailwind/theme/editor-theme.css +58 -40
- package/src/ui-tailwind/toolbar/toolbar-layout.ts +47 -0
- package/src/ui-tailwind/toolbar/tw-toolbar-icon-button.tsx +52 -0
- package/src/ui-tailwind/toolbar/tw-toolbar.tsx +1478 -0
- package/src/ui-tailwind/tw-review-workspace.tsx +1587 -0
- package/src/validation/README.md +3 -0
- package/src/validation/compatibility-engine.ts +878 -0
- package/src/validation/compatibility-report.ts +161 -0
- package/src/validation/diagnostics.ts +204 -0
- package/src/validation/docx-comment-proof.ts +720 -0
- package/src/validation/import-diagnostics.ts +128 -0
- package/src/validation/low-priority-word-surfaces.ts +373 -0
- package/dist/canonical-document-BLEbzL2J.d.cts +0 -844
- package/dist/canonical-document-BLEbzL2J.d.ts +0 -844
- package/dist/chunk-2FJS5GZM.js +0 -763
- package/dist/chunk-2FJS5GZM.js.map +0 -1
- package/dist/chunk-2OQBZS3F.js +0 -446
- package/dist/chunk-2OQBZS3F.js.map +0 -1
- package/dist/chunk-2S7W4KFO.js +0 -127
- package/dist/chunk-2S7W4KFO.js.map +0 -1
- package/dist/chunk-2TG72QSW.js +0 -3874
- package/dist/chunk-2TG72QSW.js.map +0 -1
- package/dist/chunk-36QNIZBO.js +0 -532
- package/dist/chunk-36QNIZBO.js.map +0 -1
- package/dist/chunk-4AQOYAW4.js +0 -3069
- package/dist/chunk-4AQOYAW4.js.map +0 -1
- package/dist/chunk-4D5EWJ3P.js +0 -77
- package/dist/chunk-4D5EWJ3P.js.map +0 -1
- package/dist/chunk-5FN54NDH.js +0 -2257
- package/dist/chunk-5FN54NDH.js.map +0 -1
- package/dist/chunk-BOYGQYRQ.js +0 -7306
- package/dist/chunk-BOYGQYRQ.js.map +0 -1
- package/dist/chunk-CN3XMECL.js +0 -212
- package/dist/chunk-CN3XMECL.js.map +0 -1
- package/dist/chunk-EBI3BX6U.js +0 -164
- package/dist/chunk-EBI3BX6U.js.map +0 -1
- package/dist/chunk-EILUG3VB.js +0 -1275
- package/dist/chunk-EILUG3VB.js.map +0 -1
- package/dist/chunk-FUDY333O.js +0 -70
- package/dist/chunk-FUDY333O.js.map +0 -1
- package/dist/chunk-GBVOWFIK.js +0 -1237
- package/dist/chunk-GBVOWFIK.js.map +0 -1
- package/dist/chunk-H4TQ3H3Y.js +0 -262
- package/dist/chunk-H4TQ3H3Y.js.map +0 -1
- package/dist/chunk-JGB3IXZO.js +0 -189
- package/dist/chunk-JGB3IXZO.js.map +0 -1
- package/dist/chunk-KD2QRQPY.js +0 -4342
- package/dist/chunk-KD2QRQPY.js.map +0 -1
- package/dist/chunk-KLMXQVYK.js +0 -369
- package/dist/chunk-KLMXQVYK.js.map +0 -1
- package/dist/chunk-KZUG5KFQ.js +0 -214
- package/dist/chunk-KZUG5KFQ.js.map +0 -1
- package/dist/chunk-QDAQ4CJU.js +0 -345
- package/dist/chunk-QDAQ4CJU.js.map +0 -1
- package/dist/chunk-RMH72RZI.js.map +0 -1
- package/dist/chunk-SWKWQZXM.js +0 -117
- package/dist/chunk-SWKWQZXM.js.map +0 -1
- package/dist/chunk-TJBP2K4T.js.map +0 -1
- package/dist/chunk-TLCEAQDQ.js +0 -542
- package/dist/chunk-TLCEAQDQ.js.map +0 -1
- package/dist/chunk-UZXBISGO.js.map +0 -1
- package/dist/chunk-WGBAKP3Q.js +0 -3220
- package/dist/chunk-WGBAKP3Q.js.map +0 -1
- package/dist/compare/index.cjs +0 -5475
- package/dist/compare/index.cjs.map +0 -1
- package/dist/compare/index.d.cts +0 -114
- package/dist/compare/index.d.ts +0 -114
- package/dist/compare/index.js +0 -731
- package/dist/compare/index.js.map +0 -1
- package/dist/core/commands/formatting-commands.cjs +0 -828
- package/dist/core/commands/formatting-commands.cjs.map +0 -1
- package/dist/core/commands/formatting-commands.d.cts +0 -63
- package/dist/core/commands/formatting-commands.d.ts +0 -63
- package/dist/core/commands/formatting-commands.js +0 -37
- package/dist/core/commands/formatting-commands.js.map +0 -1
- package/dist/core/commands/image-commands.cjs +0 -2023
- package/dist/core/commands/image-commands.cjs.map +0 -1
- package/dist/core/commands/image-commands.d.cts +0 -58
- package/dist/core/commands/image-commands.d.ts +0 -58
- package/dist/core/commands/image-commands.js +0 -18
- package/dist/core/commands/image-commands.js.map +0 -1
- package/dist/core/commands/section-layout-commands.cjs.map +0 -1
- package/dist/core/commands/section-layout-commands.d.cts +0 -62
- package/dist/core/commands/section-layout-commands.d.ts +0 -62
- package/dist/core/commands/section-layout-commands.js +0 -21
- package/dist/core/commands/section-layout-commands.js.map +0 -1
- package/dist/core/commands/style-commands.cjs.map +0 -1
- package/dist/core/commands/style-commands.d.cts +0 -13
- package/dist/core/commands/style-commands.d.ts +0 -13
- package/dist/core/commands/style-commands.js +0 -9
- package/dist/core/commands/style-commands.js.map +0 -1
- package/dist/core/commands/table-structure-commands.cjs +0 -1883
- package/dist/core/commands/table-structure-commands.cjs.map +0 -1
- package/dist/core/commands/table-structure-commands.d.cts +0 -59
- package/dist/core/commands/table-structure-commands.d.ts +0 -59
- package/dist/core/commands/table-structure-commands.js +0 -12
- package/dist/core/commands/table-structure-commands.js.map +0 -1
- package/dist/core/commands/text-commands.cjs +0 -2391
- package/dist/core/commands/text-commands.cjs.map +0 -1
- package/dist/core/commands/text-commands.d.cts +0 -24
- package/dist/core/commands/text-commands.d.ts +0 -24
- package/dist/core/commands/text-commands.js +0 -28
- package/dist/core/commands/text-commands.js.map +0 -1
- package/dist/core/selection/mapping.cjs +0 -200
- package/dist/core/selection/mapping.cjs.map +0 -1
- package/dist/core/selection/mapping.d.cts +0 -2
- package/dist/core/selection/mapping.d.ts +0 -2
- package/dist/core/selection/mapping.js +0 -31
- package/dist/core/selection/mapping.js.map +0 -1
- package/dist/core/state/editor-state.cjs +0 -2278
- package/dist/core/state/editor-state.cjs.map +0 -1
- package/dist/core/state/editor-state.d.cts +0 -2
- package/dist/core/state/editor-state.d.ts +0 -2
- package/dist/core/state/editor-state.js +0 -26
- package/dist/core/state/editor-state.js.map +0 -1
- package/dist/index.cjs +0 -38553
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -15
- package/dist/index.d.ts +0 -15
- package/dist/index.js +0 -7856
- package/dist/index.js.map +0 -1
- package/dist/io/docx-session.cjs +0 -16236
- package/dist/io/docx-session.cjs.map +0 -1
- package/dist/io/docx-session.d.cts +0 -21
- package/dist/io/docx-session.d.ts +0 -21
- package/dist/io/docx-session.js +0 -18
- package/dist/io/docx-session.js.map +0 -1
- package/dist/legal/index.cjs +0 -3900
- package/dist/legal/index.cjs.map +0 -1
- package/dist/legal/index.d.cts +0 -86
- package/dist/legal/index.d.ts +0 -86
- package/dist/legal/index.js +0 -616
- package/dist/legal/index.js.map +0 -1
- package/dist/public-types-7ZL_94cz.d.ts +0 -1573
- package/dist/public-types-CeMaDueh.d.cts +0 -1573
- package/dist/public-types.cjs +0 -19
- package/dist/public-types.cjs.map +0 -1
- package/dist/public-types.d.cts +0 -2
- package/dist/public-types.d.ts +0 -2
- package/dist/public-types.js +0 -1
- package/dist/public-types.js.map +0 -1
- package/dist/runtime/document-runtime.cjs +0 -11140
- package/dist/runtime/document-runtime.cjs.map +0 -1
- package/dist/runtime/document-runtime.d.cts +0 -231
- package/dist/runtime/document-runtime.d.ts +0 -231
- package/dist/runtime/document-runtime.js +0 -21
- package/dist/runtime/document-runtime.js.map +0 -1
- package/dist/structural-helpers-CilgOVhh.d.cts +0 -10
- package/dist/structural-helpers-q0Gd-eBN.d.ts +0 -10
- package/dist/ui-tailwind/editor-surface/search-plugin.cjs +0 -313
- package/dist/ui-tailwind/editor-surface/search-plugin.cjs.map +0 -1
- package/dist/ui-tailwind/editor-surface/search-plugin.d.cts +0 -67
- package/dist/ui-tailwind/editor-surface/search-plugin.d.ts +0 -67
- package/dist/ui-tailwind/editor-surface/search-plugin.js +0 -23
- package/dist/ui-tailwind/editor-surface/search-plugin.js.map +0 -1
- package/dist/ui-tailwind/index.cjs +0 -4833
- package/dist/ui-tailwind/index.cjs.map +0 -1
- package/dist/ui-tailwind/index.d.cts +0 -617
- package/dist/ui-tailwind/index.d.ts +0 -617
- package/dist/ui-tailwind/index.js +0 -575
- package/dist/ui-tailwind/index.js.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses xl/sharedStrings.xml and returns the shared string table as an ordered array.
|
|
3
|
+
*
|
|
4
|
+
* Handles both simple text (<si><t>...</t></si>) and rich text runs
|
|
5
|
+
* (<si><r><t>...</t></r></si>) by concatenating all <t> content within each <si>.
|
|
6
|
+
*/
|
|
7
|
+
export function parseSharedStringsXml(xml: string): string[] {
|
|
8
|
+
const result: string[] = [];
|
|
9
|
+
const siPattern = /<si>([\s\S]*?)<\/si>/g;
|
|
10
|
+
let siMatch: RegExpExecArray | null;
|
|
11
|
+
|
|
12
|
+
while ((siMatch = siPattern.exec(xml)) !== null) {
|
|
13
|
+
const siContent = siMatch[1] ?? "";
|
|
14
|
+
result.push(extractSharedStringText(siContent));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function extractSharedStringText(siContent: string): string {
|
|
21
|
+
// Collect text from all <t> elements (handles plain and rich text runs).
|
|
22
|
+
// The xml:space="preserve" attribute is not significant for the string value.
|
|
23
|
+
const tPattern = /<t(?:\s[^>]*)?>([^<]*)<\/t>/g;
|
|
24
|
+
const parts: string[] = [];
|
|
25
|
+
let tMatch: RegExpExecArray | null;
|
|
26
|
+
|
|
27
|
+
while ((tMatch = tPattern.exec(siContent)) !== null) {
|
|
28
|
+
parts.push(decodeXmlEntities(tMatch[1] ?? ""));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return parts.join("");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function decodeXmlEntities(value: string): string {
|
|
35
|
+
return value
|
|
36
|
+
.replace(/"/g, '"')
|
|
37
|
+
.replace(/'/g, "'")
|
|
38
|
+
.replace(/</g, "<")
|
|
39
|
+
.replace(/>/g, ">")
|
|
40
|
+
.replace(/&/g, "&");
|
|
41
|
+
}
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { decodeXmlEntities } from "./parse-shared-strings.ts";
|
|
2
|
+
import { parseXmlAttributes } from "./parse-styles.ts";
|
|
3
|
+
|
|
4
|
+
// Re-export for external use
|
|
5
|
+
export { decodeXmlEntities };
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A parsed cell from a SpreadsheetML worksheet.
|
|
9
|
+
*
|
|
10
|
+
* Row and col are zero-based indices. The value discriminated union covers all
|
|
11
|
+
* SpreadsheetML cell type codes: s (shared string), inlineStr, n/absent (number),
|
|
12
|
+
* b (boolean), e (error), str (formula string result), and blank.
|
|
13
|
+
*/
|
|
14
|
+
export type XlsxParsedCellValue =
|
|
15
|
+
| { type: "blank" }
|
|
16
|
+
| { type: "text"; value: string; fromSharedString: boolean }
|
|
17
|
+
| { type: "number"; value: number }
|
|
18
|
+
| { type: "boolean"; value: boolean }
|
|
19
|
+
| {
|
|
20
|
+
type: "formula";
|
|
21
|
+
formula: string;
|
|
22
|
+
referenceTokens: string[];
|
|
23
|
+
cachedValue: XlsxParsedFormulaCachedValue | null;
|
|
24
|
+
}
|
|
25
|
+
| { type: "error"; errorCode: string };
|
|
26
|
+
|
|
27
|
+
export type XlsxParsedFormulaCachedValue =
|
|
28
|
+
| { type: "blank" }
|
|
29
|
+
| { type: "text"; value: string }
|
|
30
|
+
| { type: "number"; value: number }
|
|
31
|
+
| { type: "boolean"; value: boolean }
|
|
32
|
+
| { type: "error"; errorCode: string };
|
|
33
|
+
|
|
34
|
+
export interface XlsxParsedCell {
|
|
35
|
+
row: number;
|
|
36
|
+
col: number;
|
|
37
|
+
value: XlsxParsedCellValue;
|
|
38
|
+
styleIndex: number | null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A parsed merge range from the <mergeCells> section.
|
|
43
|
+
* All indices are zero-based.
|
|
44
|
+
*/
|
|
45
|
+
export interface XlsxParsedMerge {
|
|
46
|
+
startRow: number;
|
|
47
|
+
startCol: number;
|
|
48
|
+
endRow: number;
|
|
49
|
+
endCol: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface XlsxParsedDimension {
|
|
53
|
+
startRow: number;
|
|
54
|
+
startCol: number;
|
|
55
|
+
endRow: number;
|
|
56
|
+
endCol: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface SheetParseResult {
|
|
60
|
+
cells: XlsxParsedCell[];
|
|
61
|
+
merges: XlsxParsedMerge[];
|
|
62
|
+
dimension: XlsxParsedDimension | null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Parses xl/worksheets/sheetN.xml.
|
|
67
|
+
*
|
|
68
|
+
* @param xml - Raw XML string of the worksheet part.
|
|
69
|
+
* @param sharedStrings - The shared string table from parseSharedStringsXml.
|
|
70
|
+
*/
|
|
71
|
+
export function parseSheetXml(
|
|
72
|
+
xml: string,
|
|
73
|
+
sharedStrings: readonly string[],
|
|
74
|
+
): SheetParseResult {
|
|
75
|
+
const cells: XlsxParsedCell[] = [];
|
|
76
|
+
const merges: XlsxParsedMerge[] = [];
|
|
77
|
+
const dimension = parseSheetDimension(xml);
|
|
78
|
+
|
|
79
|
+
const sheetDataMatch = /<sheetData>([\s\S]*?)<\/sheetData>/i.exec(xml);
|
|
80
|
+
if (sheetDataMatch) {
|
|
81
|
+
parseSheetData(sheetDataMatch[1] ?? "", sharedStrings, cells);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const mergeCellsMatch = /<mergeCells\b[^>]*>([\s\S]*?)<\/mergeCells>/i.exec(xml);
|
|
85
|
+
if (mergeCellsMatch) {
|
|
86
|
+
parseMergeCells(mergeCellsMatch[1] ?? "", merges);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return { cells, merges, dimension };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function parseSheetData(
|
|
93
|
+
sheetDataXml: string,
|
|
94
|
+
sharedStrings: readonly string[],
|
|
95
|
+
out: XlsxParsedCell[],
|
|
96
|
+
): void {
|
|
97
|
+
// Match non-empty rows (<row ...>...</row>)
|
|
98
|
+
const rowPattern = /<row\b([^>]*)>([\s\S]*?)<\/row>/g;
|
|
99
|
+
let rowMatch: RegExpExecArray | null;
|
|
100
|
+
|
|
101
|
+
while ((rowMatch = rowPattern.exec(sheetDataXml)) !== null) {
|
|
102
|
+
const rowContent = rowMatch[2] ?? "";
|
|
103
|
+
parseRowCells(rowContent, sharedStrings, out);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function parseRowCells(
|
|
108
|
+
rowXml: string,
|
|
109
|
+
sharedStrings: readonly string[],
|
|
110
|
+
out: XlsxParsedCell[],
|
|
111
|
+
): void {
|
|
112
|
+
// Match cells: both non-empty (<c ...>...</c>) and self-closing (<c .../>)
|
|
113
|
+
const cellPattern = /<c\b([^>]*)(?:>([\s\S]*?)<\/c>|\/>)/g;
|
|
114
|
+
let cellMatch: RegExpExecArray | null;
|
|
115
|
+
|
|
116
|
+
while ((cellMatch = cellPattern.exec(rowXml)) !== null) {
|
|
117
|
+
const attrs = parseXmlAttributes(cellMatch[1] ?? "");
|
|
118
|
+
const content = cellMatch[2] ?? "";
|
|
119
|
+
const cell = parseCell(attrs, content, sharedStrings);
|
|
120
|
+
if (cell !== null) {
|
|
121
|
+
out.push(cell);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function parseCell(
|
|
127
|
+
attrs: Record<string, string>,
|
|
128
|
+
content: string,
|
|
129
|
+
sharedStrings: readonly string[],
|
|
130
|
+
): XlsxParsedCell | null {
|
|
131
|
+
const ref = attrs["r"];
|
|
132
|
+
if (!ref) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const cellRef = parseCellRef(ref);
|
|
137
|
+
if (cellRef === null) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const styleIndexAttr = attrs["s"];
|
|
142
|
+
const styleIndex =
|
|
143
|
+
styleIndexAttr !== undefined ? parseInt(styleIndexAttr, 10) : null;
|
|
144
|
+
|
|
145
|
+
const typeCode = attrs["t"] ?? "n";
|
|
146
|
+
const rawValue = extractTextContent(content, "v");
|
|
147
|
+
const formulaText = extractTextContent(content, "f");
|
|
148
|
+
const inlineText = extractInlineStringText(content);
|
|
149
|
+
|
|
150
|
+
const value = resolveCellValue(typeCode, rawValue, formulaText, inlineText, sharedStrings);
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
row: cellRef.row,
|
|
154
|
+
col: cellRef.col,
|
|
155
|
+
value,
|
|
156
|
+
styleIndex: styleIndex !== null && !Number.isNaN(styleIndex) ? styleIndex : null,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function resolveCellValue(
|
|
161
|
+
typeCode: string,
|
|
162
|
+
rawValue: string | null,
|
|
163
|
+
formulaText: string | null,
|
|
164
|
+
inlineText: string | null,
|
|
165
|
+
sharedStrings: readonly string[],
|
|
166
|
+
): XlsxParsedCellValue {
|
|
167
|
+
// Formula cells may have any result type; store formula + cached value.
|
|
168
|
+
if (formulaText !== null) {
|
|
169
|
+
const decodedFormula = decodeXmlEntities(formulaText);
|
|
170
|
+
return {
|
|
171
|
+
type: "formula",
|
|
172
|
+
formula: decodedFormula,
|
|
173
|
+
referenceTokens: extractFormulaReferenceTokens(decodedFormula),
|
|
174
|
+
cachedValue: resolveFormulaCachedValue(typeCode, rawValue, inlineText, sharedStrings),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
switch (typeCode) {
|
|
179
|
+
case "s": {
|
|
180
|
+
// Shared string reference
|
|
181
|
+
const index = rawValue !== null ? parseInt(rawValue, 10) : NaN;
|
|
182
|
+
const text =
|
|
183
|
+
!Number.isNaN(index) && index >= 0 && index < sharedStrings.length
|
|
184
|
+
? (sharedStrings[index] ?? "")
|
|
185
|
+
: "";
|
|
186
|
+
return { type: "text", value: text, fromSharedString: true };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
case "inlineStr": {
|
|
190
|
+
return { type: "text", value: inlineText ?? "", fromSharedString: false };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
case "str": {
|
|
194
|
+
// Formula result is a string; formula text would have been captured above.
|
|
195
|
+
// Here the cell carries only the cached string value (no formula tag).
|
|
196
|
+
return {
|
|
197
|
+
type: "text",
|
|
198
|
+
value: rawValue !== null ? decodeXmlEntities(rawValue) : "",
|
|
199
|
+
fromSharedString: false,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
case "b": {
|
|
204
|
+
return { type: "boolean", value: rawValue === "1" };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
case "e": {
|
|
208
|
+
return {
|
|
209
|
+
type: "error",
|
|
210
|
+
errorCode:
|
|
211
|
+
rawValue !== null ? decodeXmlEntities(rawValue) : "#ERROR!",
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
default: {
|
|
216
|
+
// "n" or absent — numeric value
|
|
217
|
+
if (rawValue === null || rawValue === "") {
|
|
218
|
+
return { type: "blank" };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const numericValue = parseFloat(rawValue);
|
|
222
|
+
return Number.isNaN(numericValue)
|
|
223
|
+
? { type: "blank" }
|
|
224
|
+
: { type: "number", value: numericValue };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function resolveFormulaCachedValue(
|
|
230
|
+
typeCode: string,
|
|
231
|
+
rawValue: string | null,
|
|
232
|
+
inlineText: string | null,
|
|
233
|
+
sharedStrings: readonly string[],
|
|
234
|
+
): XlsxParsedFormulaCachedValue | null {
|
|
235
|
+
switch (typeCode) {
|
|
236
|
+
case "s": {
|
|
237
|
+
const index = rawValue !== null ? parseInt(rawValue, 10) : NaN;
|
|
238
|
+
return {
|
|
239
|
+
type: "text",
|
|
240
|
+
value:
|
|
241
|
+
!Number.isNaN(index) && index >= 0 && index < sharedStrings.length
|
|
242
|
+
? (sharedStrings[index] ?? "")
|
|
243
|
+
: "",
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
case "inlineStr":
|
|
248
|
+
return { type: "text", value: inlineText ?? "" };
|
|
249
|
+
|
|
250
|
+
case "str":
|
|
251
|
+
return rawValue === null
|
|
252
|
+
? { type: "blank" }
|
|
253
|
+
: { type: "text", value: decodeXmlEntities(rawValue) };
|
|
254
|
+
|
|
255
|
+
case "b":
|
|
256
|
+
return rawValue === null
|
|
257
|
+
? { type: "blank" }
|
|
258
|
+
: { type: "boolean", value: rawValue === "1" };
|
|
259
|
+
|
|
260
|
+
case "e":
|
|
261
|
+
return rawValue === null
|
|
262
|
+
? { type: "blank" }
|
|
263
|
+
: { type: "error", errorCode: decodeXmlEntities(rawValue) };
|
|
264
|
+
|
|
265
|
+
default: {
|
|
266
|
+
if (rawValue === null || rawValue === "") {
|
|
267
|
+
return { type: "blank" };
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const numericValue = Number(rawValue);
|
|
271
|
+
if (!Number.isNaN(numericValue)) {
|
|
272
|
+
return { type: "number", value: numericValue };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (rawValue === "TRUE" || rawValue === "FALSE") {
|
|
276
|
+
return { type: "boolean", value: rawValue === "TRUE" };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return { type: "text", value: decodeXmlEntities(rawValue) };
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function extractTextContent(xml: string, tagName: string): string | null {
|
|
285
|
+
const pattern = new RegExp(`<${tagName}(?:\\s[^>]*)?>([^<]*)</${tagName}>`, "i");
|
|
286
|
+
const match = pattern.exec(xml);
|
|
287
|
+
return match ? (match[1] ?? null) : null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function extractInlineStringText(cellContent: string): string | null {
|
|
291
|
+
// <is> contains rich text identical to shared string runs
|
|
292
|
+
const isMatch = /<is>([\s\S]*?)<\/is>/i.exec(cellContent);
|
|
293
|
+
if (!isMatch) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const tPattern = /<t(?:\s[^>]*)?>([^<]*)<\/t>/g;
|
|
298
|
+
const parts: string[] = [];
|
|
299
|
+
let tMatch: RegExpExecArray | null;
|
|
300
|
+
|
|
301
|
+
while ((tMatch = tPattern.exec(isMatch[1] ?? "")) !== null) {
|
|
302
|
+
parts.push(decodeXmlEntities(tMatch[1] ?? ""));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
return parts.join("");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function parseMergeCells(mergeCellsXml: string, out: XlsxParsedMerge[]): void {
|
|
309
|
+
const mergePattern = /<mergeCell\b([^>]*?)(?:\/>|>[\s\S]*?<\/mergeCell>)/g;
|
|
310
|
+
let match: RegExpExecArray | null;
|
|
311
|
+
|
|
312
|
+
while ((match = mergePattern.exec(mergeCellsXml)) !== null) {
|
|
313
|
+
const attrs = parseXmlAttributes(match[1] ?? "");
|
|
314
|
+
const ref = attrs["ref"] ?? "";
|
|
315
|
+
const merge = parseMergeRef(ref);
|
|
316
|
+
if (merge !== null) {
|
|
317
|
+
out.push(merge);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function parseMergeRef(ref: string): XlsxParsedMerge | null {
|
|
323
|
+
const parts = ref.split(":");
|
|
324
|
+
if (parts.length !== 2) {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const start = parseCellRef(parts[0] ?? "");
|
|
329
|
+
const end = parseCellRef(parts[1] ?? "");
|
|
330
|
+
if (start === null || end === null) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
startRow: start.row,
|
|
336
|
+
startCol: start.col,
|
|
337
|
+
endRow: end.row,
|
|
338
|
+
endCol: end.col,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function parseSheetDimension(xml: string): XlsxParsedDimension | null {
|
|
343
|
+
const dimensionMatch = /<dimension\b([^>]*?)(?:\/>|>)/i.exec(xml);
|
|
344
|
+
if (!dimensionMatch) {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const attrs = parseXmlAttributes(dimensionMatch[1] ?? "");
|
|
349
|
+
const ref = attrs["ref"];
|
|
350
|
+
if (!ref) {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return parseDimensionRef(ref);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const SHEET_PREFIX_PATTERN =
|
|
358
|
+
"(?:'(?:[^']|'')+'|[A-Za-z_][A-Za-z0-9_.]*)!";
|
|
359
|
+
const CELL_REFERENCE_PATTERN = "\\$?[A-Z]{1,3}\\$?[1-9][0-9]*";
|
|
360
|
+
const RANGE_REFERENCE_PATTERN =
|
|
361
|
+
`${CELL_REFERENCE_PATTERN}(?::${CELL_REFERENCE_PATTERN})?`;
|
|
362
|
+
const FORMULA_REFERENCE_PATTERN = new RegExp(
|
|
363
|
+
String.raw`(?<![A-Za-z0-9_.$])(?:${SHEET_PREFIX_PATTERN})?${RANGE_REFERENCE_PATTERN}(?![A-Za-z0-9_])`,
|
|
364
|
+
"g",
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
function extractFormulaReferenceTokens(formula: string): string[] {
|
|
368
|
+
const maskedFormula = maskQuotedFormulaStrings(formula);
|
|
369
|
+
const tokens: string[] = [];
|
|
370
|
+
const seen = new Set<string>();
|
|
371
|
+
|
|
372
|
+
for (const match of maskedFormula.matchAll(FORMULA_REFERENCE_PATTERN)) {
|
|
373
|
+
const index = match.index ?? -1;
|
|
374
|
+
if (index < 0) {
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
const token = formula.slice(index, index + match[0].length);
|
|
378
|
+
if (seen.has(token)) {
|
|
379
|
+
continue;
|
|
380
|
+
}
|
|
381
|
+
seen.add(token);
|
|
382
|
+
tokens.push(token);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return tokens;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function maskQuotedFormulaStrings(formula: string): string {
|
|
389
|
+
let output = "";
|
|
390
|
+
let inString = false;
|
|
391
|
+
|
|
392
|
+
for (let index = 0; index < formula.length; index += 1) {
|
|
393
|
+
const char = formula[index];
|
|
394
|
+
const next = formula[index + 1];
|
|
395
|
+
|
|
396
|
+
if (char === "\"") {
|
|
397
|
+
output += char;
|
|
398
|
+
if (inString && next === "\"") {
|
|
399
|
+
output += " ";
|
|
400
|
+
index += 1;
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
inString = !inString;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
output += inString ? " " : char;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return output;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function parseDimensionRef(ref: string): XlsxParsedDimension | null {
|
|
414
|
+
const [startRef, endRef = startRef] = ref.split(":");
|
|
415
|
+
if (!startRef || !endRef) {
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const start = parseCellRef(startRef);
|
|
420
|
+
const end = parseCellRef(endRef);
|
|
421
|
+
if (start === null || end === null) {
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return {
|
|
426
|
+
startRow: start.row,
|
|
427
|
+
startCol: start.col,
|
|
428
|
+
endRow: end.row,
|
|
429
|
+
endCol: end.col,
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function parseCellRef(ref: string): { row: number; col: number } | null {
|
|
434
|
+
const match = /^([A-Z]+)([0-9]+)$/i.exec(ref.trim());
|
|
435
|
+
if (!match) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return {
|
|
440
|
+
col: colLettersToIndex(match[1] ?? ""),
|
|
441
|
+
row: parseInt(match[2] ?? "1", 10) - 1,
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Converts a column letter sequence to a zero-based column index.
|
|
447
|
+
* "A" -> 0, "Z" -> 25, "AA" -> 26, "AZ" -> 51, "BA" -> 52.
|
|
448
|
+
*/
|
|
449
|
+
function colLettersToIndex(letters: string): number {
|
|
450
|
+
let result = 0;
|
|
451
|
+
|
|
452
|
+
for (const char of letters.toUpperCase()) {
|
|
453
|
+
result = result * 26 + (char.charCodeAt(0) - 64);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return result - 1;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export { parseCellRef, colLettersToIndex };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses xl/styles.xml for the cellXfs table (cell format entries).
|
|
3
|
+
*
|
|
4
|
+
* Each entry provides style references (numFmtId, fontId, fillId, borderId)
|
|
5
|
+
* that cells reference by zero-based index via the s= attribute.
|
|
6
|
+
*/
|
|
7
|
+
export interface XlsxStyleEntry {
|
|
8
|
+
numFmtId: number;
|
|
9
|
+
fontId: number;
|
|
10
|
+
fillId: number;
|
|
11
|
+
borderId: number;
|
|
12
|
+
rawAttributes: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function parseStylesXml(xml: string): XlsxStyleEntry[] {
|
|
16
|
+
const cellXfsMatch = /<cellXfs\b[^>]*>([\s\S]*?)<\/cellXfs>/i.exec(xml);
|
|
17
|
+
if (!cellXfsMatch) {
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const cellXfsContent = cellXfsMatch[1] ?? "";
|
|
22
|
+
const xfPattern = /<xf\b([^>]*?)(?:\/>|>[\s\S]*?<\/xf>)/g;
|
|
23
|
+
const entries: XlsxStyleEntry[] = [];
|
|
24
|
+
let xfMatch: RegExpExecArray | null;
|
|
25
|
+
|
|
26
|
+
while ((xfMatch = xfPattern.exec(cellXfsContent)) !== null) {
|
|
27
|
+
const attrs = parseXmlAttributes(xfMatch[1] ?? "");
|
|
28
|
+
entries.push({
|
|
29
|
+
numFmtId: parseIntAttr(attrs["numFmtId"], 0),
|
|
30
|
+
fontId: parseIntAttr(attrs["fontId"], 0),
|
|
31
|
+
fillId: parseIntAttr(attrs["fillId"], 0),
|
|
32
|
+
borderId: parseIntAttr(attrs["borderId"], 0),
|
|
33
|
+
rawAttributes: attrs,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return entries;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function parseIntAttr(value: string | undefined, defaultValue: number): number {
|
|
41
|
+
if (value === undefined || value === "") {
|
|
42
|
+
return defaultValue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const parsed = parseInt(value, 10);
|
|
46
|
+
return Number.isNaN(parsed) ? defaultValue : parsed;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function parseXmlAttributes(rawAttributes: string): Record<string, string> {
|
|
50
|
+
const attributes: Record<string, string> = {};
|
|
51
|
+
const attributePattern = /([A-Za-z_][\w:.-]*)="([^"]*)"/g;
|
|
52
|
+
let match: RegExpExecArray | null;
|
|
53
|
+
|
|
54
|
+
while ((match = attributePattern.exec(rawAttributes)) !== null) {
|
|
55
|
+
attributes[match[1]] = match[2];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return attributes;
|
|
59
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { parseXmlAttributes } from "./parse-styles.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Represents a single sheet entry from the workbook's sheet registry.
|
|
5
|
+
*/
|
|
6
|
+
export interface WorkbookSheetEntry {
|
|
7
|
+
/** Human-readable sheet name. */
|
|
8
|
+
name: string;
|
|
9
|
+
/** Workbook-internal numeric sheet ID string. */
|
|
10
|
+
sheetId: string;
|
|
11
|
+
/** Relationship ID used to look up the sheet part path. */
|
|
12
|
+
relationshipId: string;
|
|
13
|
+
/** Visibility state; defaults to "visible" when absent. */
|
|
14
|
+
state: "visible" | "hidden" | "veryHidden";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface WorkbookParseResult {
|
|
18
|
+
sheets: WorkbookSheetEntry[];
|
|
19
|
+
/**
|
|
20
|
+
* Whether the workbook uses the 1904 date base.
|
|
21
|
+
* Most xlsx files use 1900 (false). Mac-originated files may use 1904 (true).
|
|
22
|
+
*/
|
|
23
|
+
date1904: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Parses xl/workbook.xml and returns the ordered sheet registry.
|
|
28
|
+
*
|
|
29
|
+
* The r:id attribute in <sheet> elements uses the XML namespace prefix r.
|
|
30
|
+
* The attribute parser handles namespace-prefixed names (e.g. "r:id") correctly.
|
|
31
|
+
*/
|
|
32
|
+
export function parseWorkbookXml(xml: string): WorkbookParseResult {
|
|
33
|
+
const sheets: WorkbookSheetEntry[] = [];
|
|
34
|
+
const sheetPattern = /<sheet\b([^>]*?)(?:\/>|>[\s\S]*?<\/sheet>)/g;
|
|
35
|
+
let match: RegExpExecArray | null;
|
|
36
|
+
|
|
37
|
+
while ((match = sheetPattern.exec(xml)) !== null) {
|
|
38
|
+
const attrs = parseXmlAttributes(match[1] ?? "");
|
|
39
|
+
const name = attrs["name"] ?? "";
|
|
40
|
+
const sheetId = attrs["sheetId"] ?? "";
|
|
41
|
+
const relationshipId = attrs["r:id"] ?? attrs["id"] ?? "";
|
|
42
|
+
|
|
43
|
+
if (!name || !sheetId || !relationshipId) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const stateAttr = attrs["state"];
|
|
48
|
+
const state: WorkbookSheetEntry["state"] =
|
|
49
|
+
stateAttr === "hidden"
|
|
50
|
+
? "hidden"
|
|
51
|
+
: stateAttr === "veryHidden"
|
|
52
|
+
? "veryHidden"
|
|
53
|
+
: "visible";
|
|
54
|
+
|
|
55
|
+
sheets.push({ name, sheetId, relationshipId, state });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const date1904 = parseDate1904(xml);
|
|
59
|
+
|
|
60
|
+
return { sheets, date1904 };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Extracts the date1904 flag from the <workbookPr> element.
|
|
65
|
+
* Returns false (1900 base) if the attribute is absent or not "1" or "true".
|
|
66
|
+
*/
|
|
67
|
+
function parseDate1904(xml: string): boolean {
|
|
68
|
+
const workbookPrMatch = /<workbookPr\b([^>]*?)(?:\/>|>)/i.exec(xml);
|
|
69
|
+
if (!workbookPrMatch) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const attrs = parseXmlAttributes(workbookPrMatch[1] ?? "");
|
|
73
|
+
const val = attrs["date1904"];
|
|
74
|
+
return val === "1" || val === "true";
|
|
75
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { CanonicalWorkbook } from "../model/workbook.ts";
|
|
2
|
+
import { listSheets } from "../model/workbook.ts";
|
|
3
|
+
|
|
4
|
+
const SHARED_STRINGS_NAMESPACE = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
5
|
+
|
|
6
|
+
export interface SharedStringTableSerialization {
|
|
7
|
+
xml: string;
|
|
8
|
+
strings: string[];
|
|
9
|
+
indexByValue: Map<string, number>;
|
|
10
|
+
totalCount: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function buildSharedStringsTable(
|
|
14
|
+
workbook: CanonicalWorkbook,
|
|
15
|
+
): SharedStringTableSerialization {
|
|
16
|
+
const strings: string[] = [];
|
|
17
|
+
const indexByValue = new Map<string, number>();
|
|
18
|
+
let totalCount = 0;
|
|
19
|
+
|
|
20
|
+
for (const sheet of listSheets(workbook)) {
|
|
21
|
+
for (const cell of sheet.cells.values()) {
|
|
22
|
+
if (cell.kind !== "text") {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
totalCount += 1;
|
|
27
|
+
|
|
28
|
+
if (!indexByValue.has(cell.value)) {
|
|
29
|
+
indexByValue.set(cell.value, strings.length);
|
|
30
|
+
strings.push(cell.value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
xml: serializeSharedStringsXml(strings, totalCount),
|
|
37
|
+
strings,
|
|
38
|
+
indexByValue,
|
|
39
|
+
totalCount,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function serializeSharedStringsXml(
|
|
44
|
+
strings: readonly string[],
|
|
45
|
+
totalCount: number = strings.length,
|
|
46
|
+
): string {
|
|
47
|
+
const items = strings.map(serializeSharedStringItem);
|
|
48
|
+
const body = items.length > 0 ? `\n${items.join("\n")}\n` : "";
|
|
49
|
+
|
|
50
|
+
return [
|
|
51
|
+
`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>`,
|
|
52
|
+
`<sst xmlns="${SHARED_STRINGS_NAMESPACE}" count="${totalCount}" uniqueCount="${strings.length}">${body}</sst>`,
|
|
53
|
+
].join("\n");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function serializeSharedStringItem(value: string): string {
|
|
57
|
+
const preserveSpace = requiresPreservedSpace(value) ? ` xml:space="preserve"` : "";
|
|
58
|
+
return ` <si><t${preserveSpace}>${escapeXml(value)}</t></si>`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function requiresPreservedSpace(value: string): boolean {
|
|
62
|
+
return /^\s/.test(value) || /\s$/.test(value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function escapeXml(value: string): string {
|
|
66
|
+
return value
|
|
67
|
+
.replace(/&/g, "&")
|
|
68
|
+
.replace(/"/g, """)
|
|
69
|
+
.replace(/</g, "<")
|
|
70
|
+
.replace(/>/g, ">")
|
|
71
|
+
.replace(/'/g, "'");
|
|
72
|
+
}
|