@ai-matrx/office 0.5.2 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.3
4
+
5
+ New `./docs/host` entry: the Docs host ports alone (`configureDocsHost`, `getDocsHost`, `DocsHostPorts`, `DocsSupabase`). It imports nothing heavy, so a start-up module can register the host without pulling the document engine (Univer, lodash-es, rxjs, mammoth) into first load. `./docs` still re-exports the same functions; both share one `globalThis` slot.
6
+
7
+ ### Consumer action
8
+
9
+ Import `configureDocsHost` from `@ai-matrx/office/docs/host` in the start-up module.
10
+
3
11
  ## 0.5.2
4
12
 
5
13
  No API change. The docs file-import test runs under jsdom (`jsdom` is now a dev dependency, so the isolated publish run can start its worker).
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-2UBGQUXW.cjs","../src/core/document-page-style.ts"],"names":[],"mappings":"AAAA;ACiBA,IAAM,YAAA,EAAc,CAAA;AAEpB,IAAM,SAAA,EAAW,CAAA;AAMV,IAAM,YAAA,EAAc,EAAA;AAgBpB,IAAM,4BAAA,EAA6C;AAAA,EACxD,QAAA,EAAU,EAAE,KAAA,EAAO,GAAA,EAAK,MAAA,EAAQ,KAAK,CAAA;AAAA,EACrC,cAAA,EAAgB,WAAA;AAAA,EAChB,UAAA,EAAY,QAAA;AAAA,EACZ,SAAA,EAAW,WAAA;AAAA,EACX,YAAA,EAAc,WAAA;AAAA,EACd,UAAA,EAAY,WAAA;AAAA,EACZ,WAAA,EAAa,WAAA;AAAA;AAAA;AAAA,EAGb,qBAAA,EAAuB,EAAE,UAAA,EAAY,EAAE,CAAA,EAAG,EAAE,CAAA,EAAG,UAAA,EAAY,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,WAAA,EAAa,KAAK;AAC1F,CAAA;AAGO,SAAS,wBAAA,CAAA,EAA0C;AACxD,EAAA,OAAO;AAAA,IACL,GAAG,2BAAA;AAAA,IACH,QAAA,EAAU,EAAE,GAAG,2BAAA,CAA4B,SAAU,CAAA;AAAA,IACrD,qBAAA,EAAuB,EAAE,GAAG,2BAAA,CAA4B,sBAAuB;AAAA,EACjF,CAAA;AACF;AAOO,SAAS,yBAAA,CAA0B,KAAA,EAA2C;AACnF,EAAA,MAAM,KAAA,kBAAO,KAAA,2BAAO,UAAA;AACpB,EAAA,OACE,CAAC,CAAC,KAAA,GACF,IAAA,CAAK,MAAA,IAAU,IAAA,GACf,IAAA,CAAK,OAAA,IAAW,IAAA,mBAChB,KAAA,6BAAO,aAAA,IAAe,GAAA,mBACtB,KAAA,6BAAO,cAAA,IAAgB,GAAA,mBACvB,KAAA,6BAAO,YAAA,IAAc,GAAA,mBACrB,KAAA,6BAAO,eAAA,IAAiB,EAAA;AAE5B;AAeO,IAAM,YAAA,EAAc,CAAC,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAS,CAAA;AACrF,IAAM,mBAAA,EAAqB,WAAA,CAAY,CAAC,CAAA;ADlE/C;AACA;AACE;AACA;AACA;AACA;AACF,iOAAC","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-2UBGQUXW.cjs","sourcesContent":[null,"/**\n * The ONE page geometry every Matrx cloud document is laid out with.\n *\n * Univer lays a document out inside `documentStyle.pageSize`. With no pageSize\n * the docs renderer has no page box at all: text never wraps (it runs off the\n * right edge) and the vertical extent is unbounded, so the docs viewport\n * reports nothing to scroll — the wheel is swallowed and the page sits frozen\n * at the top. Every writer of a Univer snapshot MUST stamp this style.\n *\n * Consumers: `DocumentEditor` (new empty doc), `markdown-to-univer-doc`\n * (markdown import), and `sanitizeUniverDocSnapshot` (recovery for snapshots\n * that reached storage without it — notably `origin='agent'` writes).\n */\nimport type { DocumentFlavor, IDocumentData, PageOrientType } from \"@univerjs/core\";\n\n// Univer's enum values, written out: this file is read by tests and the markdown importer, which must not\n// pull Univer's runtime in just for four numbers (guarded by the page-style test).\nconst TRADITIONAL = 1 as DocumentFlavor;\nconst MODERN = 2 as DocumentFlavor;\nconst PORTRAIT = 0 as PageOrientType;\nconst LANDSCAPE = 1 as PageOrientType;\n\ntype DocumentStyle = NonNullable<IDocumentData[\"documentStyle\"]>;\n\n/** Univer lays documents out in 96-dpi CSS pixels: one inch is 96 units. */\nexport const PX_PER_INCH = 96;\n\n/** Paper sizes the Page setup dialog offers, in 96-dpi pixels, portrait (width x height). */\nexport const PAPER_SIZES = {\n Letter: { width: 816, height: 1056, label: \"Letter (8.5 x 11 in)\" },\n Legal: { width: 816, height: 1344, label: \"Legal (8.5 x 14 in)\" },\n Tabloid: { width: 1056, height: 1632, label: \"Tabloid (11 x 17 in)\" },\n Executive: { width: 696, height: 1008, label: \"Executive (7.25 x 10.5 in)\" },\n Statement: { width: 528, height: 816, label: \"Statement (5.5 x 8.5 in)\" },\n A3: { width: 1123, height: 1587, label: \"A3 (11.69 x 16.54 in)\" },\n A4: { width: 794, height: 1124, label: \"A4 (8.27 x 11.69 in)\" },\n A5: { width: 559, height: 794, label: \"A5 (5.83 x 8.27 in)\" },\n} as const;\nexport type PaperSizeName = keyof typeof PAPER_SIZES;\n\n/** A real page, like Google Docs: Letter, one-inch margins (624px of text), paginated. */\nexport const DEFAULT_DOCUMENT_PAGE_STYLE: DocumentStyle = {\n pageSize: { width: 816, height: 1056 },\n documentFlavor: TRADITIONAL,\n pageOrient: PORTRAIT,\n marginTop: PX_PER_INCH,\n marginBottom: PX_PER_INCH,\n marginLeft: PX_PER_INCH,\n marginRight: PX_PER_INCH,\n // Univer applies no paragraph spacing to a paginated page by itself; without this every paragraph\n // runs into the next (Google Docs' own default: 1.15 lines, 10px after).\n defaultParagraphStyle: { spaceAbove: { v: 0 }, spaceBelow: { v: 10 }, lineSpacing: 1.15 },\n};\n\n/** Fresh copy — Univer mutates the style it is handed. */\nexport function defaultDocumentPageStyle(): DocumentStyle {\n return {\n ...DEFAULT_DOCUMENT_PAGE_STYLE,\n pageSize: { ...DEFAULT_DOCUMENT_PAGE_STYLE.pageSize! },\n defaultParagraphStyle: { ...DEFAULT_DOCUMENT_PAGE_STYLE.defaultParagraphStyle! },\n };\n}\n\n/**\n * The squeezed geometry every document was stamped with until 2026-10-15: A4 at 72 dpi (595 x 842)\n * with 90/72 margins, in Univer's pageless flavour, so the text column was ~415px with no paper.\n * Pageless was never offered then, so this exact shape is always the old default, never a choice.\n */\nexport function isLegacySqueezedPageStyle(style: DocumentStyle | undefined): boolean {\n const size = style?.pageSize;\n return (\n !!size &&\n size.width === 595 &&\n size.height === 842 &&\n style?.marginLeft === 90 &&\n style?.marginRight === 90 &&\n style?.marginTop === 72 &&\n style?.marginBottom === 72\n );\n}\n\n/** What the Page setup dialog edits. Margins are in inches, like Google's. */\nexport interface PageSetupValues {\n pageless: boolean;\n orientation: \"portrait\" | \"landscape\";\n paper: PaperSizeName;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /** Paper colour, hex. Always a light colour so the black ink stays readable. */\n pageColor: string;\n}\n\nexport const PAGE_COLORS = [\"#ffffff\", \"#fff8e7\", \"#f3f3f3\", \"#e8f0fe\", \"#e6f4ea\", \"#fef7e0\"] as const;\nexport const DEFAULT_PAGE_COLOR = PAGE_COLORS[0];\n/** Key on `documentStyle` carrying the paper colour (Univer paints it from the host's surface theme). */\nexport const PAGE_COLOR_KEY = \"matrxPageColor\";\n\nconst round2 = (n: number) => Math.round(n * 100) / 100;\n\n/** The dialog's values, read from a document's style (missing parts fall back to the default page). */\nexport function pageSetupFromStyle(style: DocumentStyle | undefined): PageSetupValues {\n const landscape = style?.pageOrient === LANDSCAPE;\n const w = style?.pageSize?.width ?? DEFAULT_DOCUMENT_PAGE_STYLE.pageSize!.width!;\n const h = style?.pageSize?.height ?? DEFAULT_DOCUMENT_PAGE_STYLE.pageSize!.height!;\n const [pw, ph] = landscape ? [h, w] : [w, h];\n const paper =\n (Object.keys(PAPER_SIZES) as PaperSizeName[]).find(\n (k) => Math.abs(PAPER_SIZES[k].width - pw) <= 1 && Math.abs(PAPER_SIZES[k].height - ph) <= 1,\n ) ?? \"Letter\";\n const inch = (v: number | undefined) => round2((v ?? PX_PER_INCH) / PX_PER_INCH);\n const color = (style as Record<string, unknown> | undefined)?.[PAGE_COLOR_KEY];\n return {\n pageless: style?.documentFlavor === MODERN,\n orientation: landscape ? \"landscape\" : \"portrait\",\n paper,\n marginTop: inch(style?.marginTop),\n marginBottom: inch(style?.marginBottom),\n marginLeft: inch(style?.marginLeft),\n marginRight: inch(style?.marginRight),\n pageColor: typeof color === \"string\" && color ? color : DEFAULT_PAGE_COLOR,\n };\n}\n\n/** Params for Univer's `docs.command.page-setup` (pageSize is the as-printed size: swapped when landscape). */\nexport function pageSetupCommandParams(v: PageSetupValues) {\n const base = PAPER_SIZES[v.paper];\n const landscape = v.orientation === \"landscape\";\n return {\n documentFlavor: v.pageless ? MODERN : TRADITIONAL,\n pageOrient: landscape ? LANDSCAPE : PORTRAIT,\n pageSize: landscape ? { width: base.height, height: base.width } : { width: base.width, height: base.height },\n marginTop: Math.round(v.marginTop * PX_PER_INCH),\n marginBottom: Math.round(v.marginBottom * PX_PER_INCH),\n marginLeft: Math.round(v.marginLeft * PX_PER_INCH),\n marginRight: Math.round(v.marginRight * PX_PER_INCH),\n };\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/_work/aidream/aidream/apps/shared/office/dist/chunk-2UBGQUXW.cjs","../src/core/document-page-style.ts"],"names":[],"mappings":"AAAA;ACiBA,IAAM,YAAA,EAAc,CAAA;AAEpB,IAAM,SAAA,EAAW,CAAA;AAMV,IAAM,YAAA,EAAc,EAAA;AAgBpB,IAAM,4BAAA,EAA6C;AAAA,EACxD,QAAA,EAAU,EAAE,KAAA,EAAO,GAAA,EAAK,MAAA,EAAQ,KAAK,CAAA;AAAA,EACrC,cAAA,EAAgB,WAAA;AAAA,EAChB,UAAA,EAAY,QAAA;AAAA,EACZ,SAAA,EAAW,WAAA;AAAA,EACX,YAAA,EAAc,WAAA;AAAA,EACd,UAAA,EAAY,WAAA;AAAA,EACZ,WAAA,EAAa,WAAA;AAAA;AAAA;AAAA,EAGb,qBAAA,EAAuB,EAAE,UAAA,EAAY,EAAE,CAAA,EAAG,EAAE,CAAA,EAAG,UAAA,EAAY,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,WAAA,EAAa,KAAK;AAC1F,CAAA;AAGO,SAAS,wBAAA,CAAA,EAA0C;AACxD,EAAA,OAAO;AAAA,IACL,GAAG,2BAAA;AAAA,IACH,QAAA,EAAU,EAAE,GAAG,2BAAA,CAA4B,SAAU,CAAA;AAAA,IACrD,qBAAA,EAAuB,EAAE,GAAG,2BAAA,CAA4B,sBAAuB;AAAA,EACjF,CAAA;AACF;AAOO,SAAS,yBAAA,CAA0B,KAAA,EAA2C;AACnF,EAAA,MAAM,KAAA,kBAAO,KAAA,2BAAO,UAAA;AACpB,EAAA,OACE,CAAC,CAAC,KAAA,GACF,IAAA,CAAK,MAAA,IAAU,IAAA,GACf,IAAA,CAAK,OAAA,IAAW,IAAA,mBAChB,KAAA,6BAAO,aAAA,IAAe,GAAA,mBACtB,KAAA,6BAAO,cAAA,IAAgB,GAAA,mBACvB,KAAA,6BAAO,YAAA,IAAc,GAAA,mBACrB,KAAA,6BAAO,eAAA,IAAiB,EAAA;AAE5B;AAeO,IAAM,YAAA,EAAc,CAAC,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAA,EAAW,SAAS,CAAA;AACrF,IAAM,mBAAA,EAAqB,WAAA,CAAY,CAAC,CAAA;ADlE/C;AACA;AACE;AACA;AACA;AACA;AACF,iOAAC","file":"/home/runner/_work/aidream/aidream/apps/shared/office/dist/chunk-2UBGQUXW.cjs","sourcesContent":[null,"/**\n * The ONE page geometry every Matrx cloud document is laid out with.\n *\n * Univer lays a document out inside `documentStyle.pageSize`. With no pageSize\n * the docs renderer has no page box at all: text never wraps (it runs off the\n * right edge) and the vertical extent is unbounded, so the docs viewport\n * reports nothing to scroll — the wheel is swallowed and the page sits frozen\n * at the top. Every writer of a Univer snapshot MUST stamp this style.\n *\n * Consumers: `DocumentEditor` (new empty doc), `markdown-to-univer-doc`\n * (markdown import), and `sanitizeUniverDocSnapshot` (recovery for snapshots\n * that reached storage without it — notably `origin='agent'` writes).\n */\nimport type { DocumentFlavor, IDocumentData, PageOrientType } from \"@univerjs/core\";\n\n// Univer's enum values, written out: this file is read by tests and the markdown importer, which must not\n// pull Univer's runtime in just for four numbers (guarded by the page-style test).\nconst TRADITIONAL = 1 as DocumentFlavor;\nconst MODERN = 2 as DocumentFlavor;\nconst PORTRAIT = 0 as PageOrientType;\nconst LANDSCAPE = 1 as PageOrientType;\n\ntype DocumentStyle = NonNullable<IDocumentData[\"documentStyle\"]>;\n\n/** Univer lays documents out in 96-dpi CSS pixels: one inch is 96 units. */\nexport const PX_PER_INCH = 96;\n\n/** Paper sizes the Page setup dialog offers, in 96-dpi pixels, portrait (width x height). */\nexport const PAPER_SIZES = {\n Letter: { width: 816, height: 1056, label: \"Letter (8.5 x 11 in)\" },\n Legal: { width: 816, height: 1344, label: \"Legal (8.5 x 14 in)\" },\n Tabloid: { width: 1056, height: 1632, label: \"Tabloid (11 x 17 in)\" },\n Executive: { width: 696, height: 1008, label: \"Executive (7.25 x 10.5 in)\" },\n Statement: { width: 528, height: 816, label: \"Statement (5.5 x 8.5 in)\" },\n A3: { width: 1123, height: 1587, label: \"A3 (11.69 x 16.54 in)\" },\n A4: { width: 794, height: 1124, label: \"A4 (8.27 x 11.69 in)\" },\n A5: { width: 559, height: 794, label: \"A5 (5.83 x 8.27 in)\" },\n} as const;\nexport type PaperSizeName = keyof typeof PAPER_SIZES;\n\n/** A real page, like Google Docs: Letter, one-inch margins (624px of text), paginated. */\nexport const DEFAULT_DOCUMENT_PAGE_STYLE: DocumentStyle = {\n pageSize: { width: 816, height: 1056 },\n documentFlavor: TRADITIONAL,\n pageOrient: PORTRAIT,\n marginTop: PX_PER_INCH,\n marginBottom: PX_PER_INCH,\n marginLeft: PX_PER_INCH,\n marginRight: PX_PER_INCH,\n // Univer applies no paragraph spacing to a paginated page by itself; without this every paragraph\n // runs into the next (Google Docs' own default: 1.15 lines, 10px after).\n defaultParagraphStyle: { spaceAbove: { v: 0 }, spaceBelow: { v: 10 }, lineSpacing: 1.15 },\n};\n\n/** Fresh copy — Univer mutates the style it is handed. */\nexport function defaultDocumentPageStyle(): DocumentStyle {\n return {\n ...DEFAULT_DOCUMENT_PAGE_STYLE,\n pageSize: { ...DEFAULT_DOCUMENT_PAGE_STYLE.pageSize! },\n defaultParagraphStyle: { ...DEFAULT_DOCUMENT_PAGE_STYLE.defaultParagraphStyle! },\n };\n}\n\n/**\n * The squeezed geometry every document was stamped with until 2026-10-15: A4 at 72 dpi (595 x 842)\n * with 90/72 margins, in Univer's pageless flavour, so the text column was ~415px with no paper.\n * Pageless was never offered then, so this exact shape is always the old default, never a choice.\n */\nexport function isLegacySqueezedPageStyle(style: DocumentStyle | undefined): boolean {\n const size = style?.pageSize;\n return (\n !!size &&\n size.width === 595 &&\n size.height === 842 &&\n style?.marginLeft === 90 &&\n style?.marginRight === 90 &&\n style?.marginTop === 72 &&\n style?.marginBottom === 72\n );\n}\n\n/** What the Page setup dialog edits. Margins are in inches, like Google's. */\nexport interface PageSetupValues {\n pageless: boolean;\n orientation: \"portrait\" | \"landscape\";\n paper: PaperSizeName;\n marginTop: number;\n marginBottom: number;\n marginLeft: number;\n marginRight: number;\n /** Paper colour, hex. Always a light colour so the black ink stays readable. */\n pageColor: string;\n}\n\nexport const PAGE_COLORS = [\"#ffffff\", \"#fff8e7\", \"#f3f3f3\", \"#e8f0fe\", \"#e6f4ea\", \"#fef7e0\"] as const;\nexport const DEFAULT_PAGE_COLOR = PAGE_COLORS[0];\n/** Key on `documentStyle` carrying the paper colour (Univer paints it from the host's surface theme). */\nexport const PAGE_COLOR_KEY = \"matrxPageColor\";\n\nconst round2 = (n: number) => Math.round(n * 100) / 100;\n\n/** The dialog's values, read from a document's style (missing parts fall back to the default page). */\nexport function pageSetupFromStyle(style: DocumentStyle | undefined): PageSetupValues {\n const landscape = style?.pageOrient === LANDSCAPE;\n const w = style?.pageSize?.width ?? DEFAULT_DOCUMENT_PAGE_STYLE.pageSize!.width!;\n const h = style?.pageSize?.height ?? DEFAULT_DOCUMENT_PAGE_STYLE.pageSize!.height!;\n const [pw, ph] = landscape ? [h, w] : [w, h];\n const paper =\n (Object.keys(PAPER_SIZES) as PaperSizeName[]).find(\n (k) => Math.abs(PAPER_SIZES[k].width - pw) <= 1 && Math.abs(PAPER_SIZES[k].height - ph) <= 1,\n ) ?? \"Letter\";\n const inch = (v: number | undefined) => round2((v ?? PX_PER_INCH) / PX_PER_INCH);\n const color = (style as Record<string, unknown> | undefined)?.[PAGE_COLOR_KEY];\n return {\n pageless: style?.documentFlavor === MODERN,\n orientation: landscape ? \"landscape\" : \"portrait\",\n paper,\n marginTop: inch(style?.marginTop),\n marginBottom: inch(style?.marginBottom),\n marginLeft: inch(style?.marginLeft),\n marginRight: inch(style?.marginRight),\n pageColor: typeof color === \"string\" && color ? color : DEFAULT_PAGE_COLOR,\n };\n}\n\n/** Params for Univer's `docs.command.page-setup` (pageSize is the as-printed size: swapped when landscape). */\nexport function pageSetupCommandParams(v: PageSetupValues) {\n const base = PAPER_SIZES[v.paper];\n const landscape = v.orientation === \"landscape\";\n return {\n documentFlavor: v.pageless ? MODERN : TRADITIONAL,\n pageOrient: landscape ? LANDSCAPE : PORTRAIT,\n pageSize: landscape ? { width: base.height, height: base.width } : { width: base.width, height: base.height },\n marginTop: Math.round(v.marginTop * PX_PER_INCH),\n marginBottom: Math.round(v.marginBottom * PX_PER_INCH),\n marginLeft: Math.round(v.marginLeft * PX_PER_INCH),\n marginRight: Math.round(v.marginRight * PX_PER_INCH),\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-BWMAYLW4.cjs","../src/docs/ports.ts","../src/docs/document-service.ts","../src/docs/sanitize-univer-doc-snapshot.ts"],"names":["error"],"mappings":"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","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-BWMAYLW4.cjs","sourcesContent":[null,"/**\n * The host ports of the Docs model and io.\n *\n * The package owns the document service, the open-document model and the converters, but two things\n * belong to the app that mounts them: the database client (a package owns no client) and the server\n * request that converts a .docx to .odt / .rtf (the app owns the server URL, auth and error capture).\n * The host states them once at start-up with `configureDocsHost`. State sits on a `globalThis` slot\n * so a dual-bundled copy of the package still sees one host. An unconfigured port THROWS naming\n * itself (nothing fails silently).\n */\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\n\n/** A Supabase client over any schema: the package cannot import the app's generated database types. */\nexport type DocsSupabase = SupabaseClient<any, any, any>;\n\nexport interface DocsHostPorts {\n /** The app's database client (signed in as the person). */\n getSupabase(): DocsSupabase;\n /** An authenticated request to the Matrx server returning the raw `Response` (the open-format converter). */\n requestRaw(path: string, init: { method: \"POST\"; body: FormData }): Promise<Response>;\n}\n\nconst SLOT = Symbol.for(\"ai-matrx.office.docs-host\");\ntype Slot = { ports?: DocsHostPorts };\nconst slot = (): Slot => {\n const g = globalThis as Record<symbol, Slot | undefined>;\n return (g[SLOT] ??= {});\n};\n\nexport function configureDocsHost(ports: DocsHostPorts): void {\n slot().ports = ports;\n}\n\nexport function getDocsHost(): DocsHostPorts {\n const ports = slot().ports;\n if (!ports) throw new Error(\"@ai-matrx/office/docs: configureDocsHost(ports) was not called before the document service ran.\");\n return ports;\n}\n","/**\n * Document service — typed wrappers for `udt_documents` + `udt_document_snapshots`.\n *\n * Cloud document editor backed by Univer's preset-docs-core. Same shape as\n * `workbook-service.ts` — metadata in `udt_documents`, content state in\n * append-only `udt_document_snapshots`. The editor hydrates from the LATEST\n * snapshot and writes a new snapshot per save (debounced on the client —\n * see DocumentEditor).\n *\n * What lives elsewhere:\n * - Sharing / permissions: features/sharing/ + `has_permission(...)` RLS\n * - The open document (one model per id per tab: load, one save, realtime,\n * collab): features/documents/document-model/\n * - Component (a view of that model): features/documents/components/DocumentEditor\n *\n * Mirrors `workbook-service.ts`. If you're changing the shape of one, change\n * the other at the same time — see `features/data-tables/FEATURE.md`.\n */\nimport { requireOrganizationContext } from \"@ai-matrx/api\";\nimport { getClaimsUser } from \"@ai-matrx/auth\";\nimport { readAllRows, tryWriteOne, writeOneRow } from \"@ai-matrx/data/db\";\nimport type { ServiceResult } from \"@ai-matrx/records/core\";\n\nimport type { DocumentRow, DocumentSnapshot, DocumentSnapshotOrigin } from \"../core\";\nimport { getDocsHost } from \"./ports\";\n\n/** The app's database client, read through the host port at call time. */\nconst db = () => getDocsHost().getSupabase();\n// ─── documents ───────────────────────────────────────────────────────────────\n\nexport type CreateDocumentArgs = {\n name: string;\n description?: string | null;\n /** Origin label for the document itself, mirrors `udt_documents.source`. */\n source?: \"created\" | \"imported_docx\" | \"imported_md\" | \"imported_txt\" | \"linked_gdoc\";\n organizationId: string;\n projectId?: string | null;\n taskId?: string | null;\n isPublic?: boolean;\n /**\n * cld_files.id of the source upload (DOCX / MD / TXT blob). Set on the\n * import flow so the lossless original is recoverable; FK is ON DELETE SET\n * NULL, so deleting the file just nulls the link — the document survives.\n */\n originalFileId?: string | null;\n};\n\nexport async function createDocument(\n args: CreateDocumentArgs,\n): Promise<ServiceResult<DocumentRow>> {\n let organizationId: string;\n try {\n organizationId = requireOrganizationContext(undefined, args.organizationId);\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Select an organization before creating a document.\",\n };\n }\n\n const { data: userData, error: userErr } = await getClaimsUser(db());\n if (userErr || !userData?.user) {\n return {\n success: false,\n error: userErr?.message ?? \"not authenticated\",\n };\n }\n\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .insert({\n document_name: args.name,\n description: args.description ?? null,\n source: args.source ?? \"created\",\n organization_id: organizationId,\n project_id: args.projectId ?? null,\n task_id: args.taskId ?? null,\n original_file_id: args.originalFileId ?? null,\n // CANONICAL columns (workbench_udt_canonical_step1). `visibility` is the\n // source of truth; the legacy `is_public` boolean is derived from it by\n // the workbench._bridge_legacy_owner trigger, so writing both here would\n // be two authorities for one fact. A new document defaults to `internal`\n // — it is org work product, not an individual person's private thing\n // (db-rules §6) — unless the caller explicitly asked for public.\n created_by: userData.user.id,\n visibility: args.isPublic ? \"public\" : \"internal\",\n })\n .select(\"*\")\n .single();\n if (error) return { success: false, error: error.message };\n return { success: true, data: data as DocumentRow };\n}\n\nexport async function listAccessibleDocuments(): Promise<\n ServiceResult<DocumentRow[]>\n> {\n // RLS handles owner / published-to-the-web / shared access. The library and\n // the pickers treat this list as COMPLETE (\"you have no such document\"), so\n // it pages past PostgREST's silent 1000-row cap (D190).\n try {\n const rows = await readAllRows<DocumentRow>(\n ({ from, to }) =>\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .select(\"*\", { count: \"exact\" })\n .is(\"deleted_at\", null)\n .order(\"updated_at\", { ascending: false })\n .order(\"id\", { ascending: true })\n .range(from, to)\n .returns<DocumentRow[]>(),\n { label: \"workbench.udt_documents accessible documents\" },\n );\n return { success: true, data: rows };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport async function getDocument(\n documentId: string,\n): Promise<ServiceResult<DocumentRow>> {\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .select(\"*\")\n .eq(\"id\", documentId)\n .is(\"deleted_at\", null)\n .maybeSingle();\n if (error) return { success: false, error: error.message };\n if (!data) {\n // A trashed or unreachable document is a state the person can act on,\n // never PostgREST's \"Cannot coerce the result to a single JSON object\".\n return {\n success: false,\n error:\n \"This document is in the trash or you no longer have access to it. Restore it from Trash, or ask its owner to share it again.\",\n };\n }\n return { success: true, data: data as DocumentRow };\n}\n\nexport async function renameDocument(\n documentId: string,\n name: string,\n): Promise<ServiceResult<DocumentRow>> {\n const { data, error } = await writeOneRow(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ document_name: name, updated_at: new Date().toISOString() })\n .eq(\"id\", documentId)\n .select(\"*\"),\n { action: \"update\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: data as DocumentRow };\n}\n\n/**\n * Move the document into a project (or out of one with `null`). Sibling of\n * `renameDocument`: the one named setter for `project_id`.\n */\nexport async function moveDocument(\n documentId: string,\n projectId: string | null,\n): Promise<ServiceResult<DocumentRow>> {\n const { data, error } = await writeOneRow(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ project_id: projectId, updated_at: new Date().toISOString() })\n .eq(\"id\", documentId)\n .select(\"*\"),\n { action: \"update\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: data as DocumentRow };\n}\n\n/**\n * Rewrite the document's description. Sibling of `renameDocument` — the two\n * human-authored fields on `udt_documents` each get a named setter so callers\n * never hand-roll a `.from(\"udt_documents\").update(...)`. Pass `null` (or an\n * empty string) to clear it.\n *\n * Added when the documents surface became agent-writable: the\n * `document_description` write target on `/documents/[id]` is its caller, the\n * same way `updateWorkbookDescription` serves `workbook_description`. Keeping\n * the pair symmetric is this file's standing contract with `workbook-service`\n * (see the module header).\n */\nexport async function updateDocumentDescription(\n documentId: string,\n description: string | null,\n): Promise<ServiceResult<DocumentRow>> {\n const { data, error } = await writeOneRow(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({\n description: description && description.length > 0 ? description : null,\n updated_at: new Date().toISOString(),\n })\n .eq(\"id\", documentId)\n .select(\"*\"),\n { action: \"update\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: data as DocumentRow };\n}\n\n/**\n * Soft delete — the document is tombstoned, not destroyed, and its snapshots stay\n * with it. Every read path filters `deleted_at is null`. Pair with\n * restoreDocument for undo. (aidream migration 0458.)\n */\nexport async function restoreDocument(\n documentId: string,\n): Promise<ServiceResult<true>> {\n const { error } = await tryWriteOne(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ deleted_at: null })\n .eq(\"id\", documentId)\n .select(\"id\"),\n { action: \"restore\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: true };\n}\n\n/**\n * Archive (delete means archive: never a hard delete) — only for rolling back a document this very flow just created and\n * failed to populate. Never use for a user-initiated delete: that is\n * deleteDocument, which tombstones and stays recoverable.\n */\nexport async function discardFailedDocument(\n documentId: string,\n): Promise<ServiceResult<true>> {\n const { error } = await tryWriteOne(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ deleted_at: new Date().toISOString() })\n .eq(\"id\", documentId)\n .select(\"id\"),\n { action: \"archive\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: true };\n}\n\nexport async function deleteDocument(\n documentId: string,\n): Promise<ServiceResult<true>> {\n const { error } = await tryWriteOne(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ deleted_at: new Date().toISOString() })\n .eq(\"id\", documentId)\n .select(\"id\"),\n { action: \"delete\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: true };\n}\n\n// ─── snapshots (document content) ────────────────────────────────────────────\n\n/**\n * Latest-snapshot fetch — what an opened document hydrates from. Returns\n * `data: null` (success path) when the document has no snapshots yet (newly\n * created, never saved). Distinguish \"no snapshot\" from \"load error\" by\n * checking `result.data === null`.\n */\nexport async function getLatestDocumentSnapshot(\n documentId: string,\n): Promise<ServiceResult<DocumentSnapshot | null>> {\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_document_snapshots\")\n .select(\"*\")\n .eq(\"document_id\", documentId)\n .order(\"created_at\", { ascending: false })\n .limit(1)\n .maybeSingle();\n if (error) return { success: false, error: error.message };\n return { success: true, data: (data ?? null) as DocumentSnapshot | null };\n}\n\nexport type SaveDocumentSnapshotArgs = {\n documentId: string;\n snapshot: unknown; // opaque to us — Univer IDocumentData decides the shape\n label?: string | null;\n origin?: DocumentSnapshotOrigin;\n};\n\nexport async function saveDocumentSnapshot(\n args: SaveDocumentSnapshotArgs,\n): Promise<ServiceResult<DocumentSnapshot>> {\n const { data: userData } = await getClaimsUser(db());\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_document_snapshots\")\n .insert({\n document_id: args.documentId,\n snapshot: args.snapshot as never,\n label: args.label ?? null,\n origin: args.origin ?? \"autosave\",\n created_by: userData?.user?.id ?? null,\n })\n .select(\"*\")\n .single();\n if (error) return { success: false, error: error.message };\n\n // Touch the parent document's updated_at so list views can sort by recency\n // without scanning snapshots. Best-effort — failure here is harmless.\n // write-lands-exempt: best-effort recency stamp on the parent document; the snapshot insert above is the real write\n await db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ updated_at: new Date().toISOString() })\n .eq(\"id\", args.documentId);\n\n return { success: true, data: data as DocumentSnapshot };\n}\n\n/**\n * An independent copy of a document: its own row, with the latest snapshot copied over, so editing the copy never\n * touches the original. The copy lives in the original's organization and project. Used by a board-template use.\n */\nexport async function copyDocument(\n documentId: string,\n name?: string,\n): Promise<ServiceResult<DocumentRow>> {\n const original = await getDocument(documentId);\n if (!original.success) return original;\n const row = original.data;\n if (!row.organization_id) {\n return { success: false, error: \"This document has no organization and cannot be copied.\" };\n }\n const created = await createDocument({\n name: name ?? row.document_name,\n description: row.description ?? null,\n organizationId: row.organization_id,\n projectId: row.project_id ?? null,\n isPublic: row.visibility === \"public\",\n });\n if (!created.success) return created;\n const latest = await getLatestDocumentSnapshot(documentId);\n if (!latest.success) return latest;\n if (latest.data) {\n const saved = await saveDocumentSnapshot({\n documentId: created.data.id,\n snapshot: latest.data.snapshot,\n label: latest.data.label,\n origin: \"autosave\",\n });\n if (!saved.success) return saved;\n }\n return created;\n}\n\n/** Trash view: the caller's own archived documents (RLS decides what is readable). */\nexport async function listTrashedDocuments(): Promise<\n ServiceResult<DocumentRow[]>\n> {\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .select(\"*\")\n .not(\"deleted_at\", \"is\", null)\n .order(\"deleted_at\", { ascending: false });\n if (error) return { success: false, error: error.message };\n return { success: true, data: (data ?? []) as DocumentRow[] };\n}\n\nexport async function listDocumentSnapshots(\n documentId: string,\n limit = 50,\n): Promise<ServiceResult<DocumentSnapshot[]>> {\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_document_snapshots\")\n // component-created-by-ok: append-only snapshot with NO updated_by column and NO parent-rewrite trigger — created_by is the author the client wrote at insert (the only person field this table has)\n .select(\"id, document_id, label, origin, created_by, created_at\")\n .eq(\"document_id\", documentId)\n .order(\"created_at\", { ascending: false })\n .limit(limit);\n if (error) return { success: false, error: error.message };\n return { success: true, data: (data ?? []) as DocumentSnapshot[] };\n}\n","/**\n * sanitizeUniverDocSnapshot — defensive normalizer for Univer document\n * snapshots loaded from storage.\n *\n * WHY THIS EXISTS (loud recovery layer):\n * Univer's `NamedStyleType` is a NUMERIC enum (`HEADING_1 = 4`, `HEADING_2 = 5`,\n * …). Some snapshots in storage were produced by an external markdown→Univer\n * converter that wrote the *string* name (`\"HEADING_1\"`) into\n * `paragraphStyle.namedStyleType` instead of the numeric value. At render time\n * Univer does `HEADING_ICON_MAP[namedStyleType]` → `undefined` →\n * `icon.key` throws `Cannot read properties of undefined (reading 'key')` inside\n * the `<ParagraphMenu>` component the moment the cursor lands in a heading. That\n * uncaught error tears down Univer's React root, so the document loads and then\n * vanishes. See `features/data-tables/FEATURE.md`.\n *\n * This normalizer converts those string enum values back to numbers BEFORE the\n * snapshot reaches `createUniverDoc`. It is a recovery layer: when it fires it\n * means malformed data slipped past the writer, so it SCREAMS (console.warn)\n * with a count and the document id. The proper long-term fix is to make the\n * writer emit numeric enum values; until then this keeps the editor alive.\n *\n * Returns the SAME object (mutated in place) for ergonomic call sites, plus a\n * `fixed` count via the second return slot is intentionally avoided — callers\n * only need the sanitized snapshot; the warning is the signal.\n */\nimport { NamedStyleType } from \"@univerjs/core\";\nimport type { IDocumentData } from \"@univerjs/core\";\n\nimport {\n defaultDocumentPageStyle,\n isLegacySqueezedPageStyle,\n} from \"../core\";\n\n/**\n * Map of every string name that could appear in a legacy snapshot to its\n * canonical numeric `NamedStyleType`. Built from the enum itself so it stays in\n * lockstep with Univer (numeric enums expose name→value on string keys).\n */\nconst NAMED_STYLE_STRING_TO_NUMBER: Record<string, number> = Object.fromEntries(\n Object.entries(NamedStyleType)\n .filter(([key, val]) => typeof val === \"number\" && isNaN(Number(key)))\n .map(([key, val]) => [key, val as number]),\n);\n\n/**\n * Normalize a Univer document snapshot in place. Currently fixes string-valued\n * `paragraphStyle.namedStyleType` (the confirmed `<ParagraphMenu>` crash). New\n * classes of string-vs-enum corruption should be added here, not patched at the\n * call site.\n *\n * @param snapshot The snapshot about to be passed to `createUniverDoc`.\n * @param docId Document id, for the loud warning only.\n * @returns the same snapshot reference (mutated).\n */\nexport function sanitizeUniverDocSnapshot(\n snapshot: Partial<IDocumentData>,\n docId?: string,\n): Partial<IDocumentData> {\n restorePageStyle(snapshot, docId);\n\n const paragraphs = snapshot?.body?.paragraphs;\n if (!Array.isArray(paragraphs)) return snapshot;\n\n let fixed = 0;\n for (const paragraph of paragraphs) {\n const style = paragraph?.paragraphStyle as\n { namedStyleType?: unknown } | undefined;\n const value = style?.namedStyleType;\n if (typeof value === \"string\") {\n const numeric = NAMED_STYLE_STRING_TO_NUMBER[value];\n if (numeric !== undefined) {\n (style as { namedStyleType?: number }).namedStyleType = numeric;\n fixed += 1;\n } else {\n // Unknown string we can't map — drop it so Univer falls back to\n // NORMAL_TEXT rather than crashing on the lookup.\n delete (style as { namedStyleType?: unknown }).namedStyleType;\n fixed += 1;\n }\n }\n }\n\n if (fixed > 0) {\n console.warn(\n `[data-tables] RECOVERY: sanitized ${fixed} string namedStyleType value(s) ` +\n `to numeric NamedStyleType in document snapshot${docId ? ` ${docId}` : \"\"}. ` +\n `The snapshot was written with the wrong enum encoding (string instead of ` +\n `number) and would have crashed Univer's <ParagraphMenu>. Fix the snapshot ` +\n `writer to emit numeric NamedStyleType values.`,\n );\n }\n\n return snapshot;\n}\n\n/**\n * Second recovery: a snapshot with no `documentStyle.pageSize` has no page box,\n * so Univer lays the body out unbounded — text never wraps and the docs\n * viewport reports no scrollable extent, which reads to the user as \"the\n * document won't scroll\". Snapshots written by agents (`origin='agent'`) and by\n * older converters reach storage with `documentStyle: {}`. Stamp the canonical\n * page geometry back on and SCREAM: the writer is the real bug.\n */\nfunction restorePageStyle(snapshot: Partial<IDocumentData>, docId?: string) {\n if (!snapshot || typeof snapshot !== \"object\") return;\n\n // THE SQUEEZED PAGE (2026-10-15): documents carried A4-at-72dpi geometry in Univer's pageless\n // flavour — a 415px text column with no paper. Move them to a real Letter page, unchanged text.\n // A document with no flavour at all is a paginated page too (Univer would otherwise pick pageless).\n const style = snapshot.documentStyle;\n if (style?.pageSize?.width && isLegacySqueezedPageStyle(style)) {\n const page = defaultDocumentPageStyle();\n snapshot.documentStyle = { ...style, ...page, defaultParagraphStyle: style.defaultParagraphStyle ?? page.defaultParagraphStyle } as typeof style;\n return;\n }\n if (style?.pageSize?.width) {\n if (!style.documentFlavor) {\n const page = defaultDocumentPageStyle();\n Object.assign(style, { documentFlavor: page.documentFlavor });\n if (page.defaultParagraphStyle) style.defaultParagraphStyle ??= page.defaultParagraphStyle;\n }\n return;\n }\n\n snapshot.documentStyle = {\n ...defaultDocumentPageStyle(),\n ...(snapshot.documentStyle ?? {}),\n pageSize: defaultDocumentPageStyle().pageSize,\n } as NonNullable<typeof snapshot.documentStyle>;\n\n console.warn(\n `[data-tables] RECOVERY: document snapshot${docId ? ` ${docId}` : \"\"} had no ` +\n `documentStyle.pageSize — restored the default Letter page geometry. Without a ` +\n `page box Univer lays the body out unbounded: text does not wrap and the ` +\n `viewport has no scrollable extent, so the document appears frozen. Fix the ` +\n `snapshot writer (agent/markdown converters must stamp ` +\n `DEFAULT_DOCUMENT_PAGE_STYLE).`,\n );\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/_work/aidream/aidream/apps/shared/office/dist/chunk-BWMAYLW4.cjs","../src/docs/ports.ts","../src/docs/document-service.ts","../src/docs/sanitize-univer-doc-snapshot.ts"],"names":["error"],"mappings":"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","file":"/home/runner/_work/aidream/aidream/apps/shared/office/dist/chunk-BWMAYLW4.cjs","sourcesContent":[null,"/**\n * The host ports of the Docs model and io.\n *\n * The package owns the document service, the open-document model and the converters, but two things\n * belong to the app that mounts them: the database client (a package owns no client) and the server\n * request that converts a .docx to .odt / .rtf (the app owns the server URL, auth and error capture).\n * The host states them once at start-up with `configureDocsHost`. State sits on a `globalThis` slot\n * so a dual-bundled copy of the package still sees one host. An unconfigured port THROWS naming\n * itself (nothing fails silently).\n */\nimport type { SupabaseClient } from \"@supabase/supabase-js\";\n\n/** A Supabase client over any schema: the package cannot import the app's generated database types. */\nexport type DocsSupabase = SupabaseClient<any, any, any>;\n\nexport interface DocsHostPorts {\n /** The app's database client (signed in as the person). */\n getSupabase(): DocsSupabase;\n /** An authenticated request to the Matrx server returning the raw `Response` (the open-format converter). */\n requestRaw(path: string, init: { method: \"POST\"; body: FormData }): Promise<Response>;\n}\n\nconst SLOT = Symbol.for(\"ai-matrx.office.docs-host\");\ntype Slot = { ports?: DocsHostPorts };\nconst slot = (): Slot => {\n const g = globalThis as Record<symbol, Slot | undefined>;\n return (g[SLOT] ??= {});\n};\n\nexport function configureDocsHost(ports: DocsHostPorts): void {\n slot().ports = ports;\n}\n\nexport function getDocsHost(): DocsHostPorts {\n const ports = slot().ports;\n if (!ports) throw new Error(\"@ai-matrx/office/docs: configureDocsHost(ports) was not called before the document service ran.\");\n return ports;\n}\n","/**\n * Document service — typed wrappers for `udt_documents` + `udt_document_snapshots`.\n *\n * Cloud document editor backed by Univer's preset-docs-core. Same shape as\n * `workbook-service.ts` — metadata in `udt_documents`, content state in\n * append-only `udt_document_snapshots`. The editor hydrates from the LATEST\n * snapshot and writes a new snapshot per save (debounced on the client —\n * see DocumentEditor).\n *\n * What lives elsewhere:\n * - Sharing / permissions: features/sharing/ + `has_permission(...)` RLS\n * - The open document (one model per id per tab: load, one save, realtime,\n * collab): features/documents/document-model/\n * - Component (a view of that model): features/documents/components/DocumentEditor\n *\n * Mirrors `workbook-service.ts`. If you're changing the shape of one, change\n * the other at the same time — see `features/data-tables/FEATURE.md`.\n */\nimport { requireOrganizationContext } from \"@ai-matrx/api\";\nimport { getClaimsUser } from \"@ai-matrx/auth\";\nimport { readAllRows, tryWriteOne, writeOneRow } from \"@ai-matrx/data/db\";\nimport type { ServiceResult } from \"@ai-matrx/records/core\";\n\nimport type { DocumentRow, DocumentSnapshot, DocumentSnapshotOrigin } from \"../core\";\nimport { getDocsHost } from \"./ports\";\n\n/** The app's database client, read through the host port at call time. */\nconst db = () => getDocsHost().getSupabase();\n// ─── documents ───────────────────────────────────────────────────────────────\n\nexport type CreateDocumentArgs = {\n name: string;\n description?: string | null;\n /** Origin label for the document itself, mirrors `udt_documents.source`. */\n source?: \"created\" | \"imported_docx\" | \"imported_md\" | \"imported_txt\" | \"linked_gdoc\";\n organizationId: string;\n projectId?: string | null;\n taskId?: string | null;\n isPublic?: boolean;\n /**\n * cld_files.id of the source upload (DOCX / MD / TXT blob). Set on the\n * import flow so the lossless original is recoverable; FK is ON DELETE SET\n * NULL, so deleting the file just nulls the link — the document survives.\n */\n originalFileId?: string | null;\n};\n\nexport async function createDocument(\n args: CreateDocumentArgs,\n): Promise<ServiceResult<DocumentRow>> {\n let organizationId: string;\n try {\n organizationId = requireOrganizationContext(undefined, args.organizationId);\n } catch (error) {\n return {\n success: false,\n error:\n error instanceof Error\n ? error.message\n : \"Select an organization before creating a document.\",\n };\n }\n\n const { data: userData, error: userErr } = await getClaimsUser(db());\n if (userErr || !userData?.user) {\n return {\n success: false,\n error: userErr?.message ?? \"not authenticated\",\n };\n }\n\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .insert({\n document_name: args.name,\n description: args.description ?? null,\n source: args.source ?? \"created\",\n organization_id: organizationId,\n project_id: args.projectId ?? null,\n task_id: args.taskId ?? null,\n original_file_id: args.originalFileId ?? null,\n // CANONICAL columns (workbench_udt_canonical_step1). `visibility` is the\n // source of truth; the legacy `is_public` boolean is derived from it by\n // the workbench._bridge_legacy_owner trigger, so writing both here would\n // be two authorities for one fact. A new document defaults to `internal`\n // — it is org work product, not an individual person's private thing\n // (db-rules §6) — unless the caller explicitly asked for public.\n created_by: userData.user.id,\n visibility: args.isPublic ? \"public\" : \"internal\",\n })\n .select(\"*\")\n .single();\n if (error) return { success: false, error: error.message };\n return { success: true, data: data as DocumentRow };\n}\n\nexport async function listAccessibleDocuments(): Promise<\n ServiceResult<DocumentRow[]>\n> {\n // RLS handles owner / published-to-the-web / shared access. The library and\n // the pickers treat this list as COMPLETE (\"you have no such document\"), so\n // it pages past PostgREST's silent 1000-row cap (D190).\n try {\n const rows = await readAllRows<DocumentRow>(\n ({ from, to }) =>\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .select(\"*\", { count: \"exact\" })\n .is(\"deleted_at\", null)\n .order(\"updated_at\", { ascending: false })\n .order(\"id\", { ascending: true })\n .range(from, to)\n .returns<DocumentRow[]>(),\n { label: \"workbench.udt_documents accessible documents\" },\n );\n return { success: true, data: rows };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : String(error),\n };\n }\n}\n\nexport async function getDocument(\n documentId: string,\n): Promise<ServiceResult<DocumentRow>> {\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .select(\"*\")\n .eq(\"id\", documentId)\n .is(\"deleted_at\", null)\n .maybeSingle();\n if (error) return { success: false, error: error.message };\n if (!data) {\n // A trashed or unreachable document is a state the person can act on,\n // never PostgREST's \"Cannot coerce the result to a single JSON object\".\n return {\n success: false,\n error:\n \"This document is in the trash or you no longer have access to it. Restore it from Trash, or ask its owner to share it again.\",\n };\n }\n return { success: true, data: data as DocumentRow };\n}\n\nexport async function renameDocument(\n documentId: string,\n name: string,\n): Promise<ServiceResult<DocumentRow>> {\n const { data, error } = await writeOneRow(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ document_name: name, updated_at: new Date().toISOString() })\n .eq(\"id\", documentId)\n .select(\"*\"),\n { action: \"update\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: data as DocumentRow };\n}\n\n/**\n * Move the document into a project (or out of one with `null`). Sibling of\n * `renameDocument`: the one named setter for `project_id`.\n */\nexport async function moveDocument(\n documentId: string,\n projectId: string | null,\n): Promise<ServiceResult<DocumentRow>> {\n const { data, error } = await writeOneRow(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ project_id: projectId, updated_at: new Date().toISOString() })\n .eq(\"id\", documentId)\n .select(\"*\"),\n { action: \"update\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: data as DocumentRow };\n}\n\n/**\n * Rewrite the document's description. Sibling of `renameDocument` — the two\n * human-authored fields on `udt_documents` each get a named setter so callers\n * never hand-roll a `.from(\"udt_documents\").update(...)`. Pass `null` (or an\n * empty string) to clear it.\n *\n * Added when the documents surface became agent-writable: the\n * `document_description` write target on `/documents/[id]` is its caller, the\n * same way `updateWorkbookDescription` serves `workbook_description`. Keeping\n * the pair symmetric is this file's standing contract with `workbook-service`\n * (see the module header).\n */\nexport async function updateDocumentDescription(\n documentId: string,\n description: string | null,\n): Promise<ServiceResult<DocumentRow>> {\n const { data, error } = await writeOneRow(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({\n description: description && description.length > 0 ? description : null,\n updated_at: new Date().toISOString(),\n })\n .eq(\"id\", documentId)\n .select(\"*\"),\n { action: \"update\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: data as DocumentRow };\n}\n\n/**\n * Soft delete — the document is tombstoned, not destroyed, and its snapshots stay\n * with it. Every read path filters `deleted_at is null`. Pair with\n * restoreDocument for undo. (aidream migration 0458.)\n */\nexport async function restoreDocument(\n documentId: string,\n): Promise<ServiceResult<true>> {\n const { error } = await tryWriteOne(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ deleted_at: null })\n .eq(\"id\", documentId)\n .select(\"id\"),\n { action: \"restore\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: true };\n}\n\n/**\n * Archive (delete means archive: never a hard delete) — only for rolling back a document this very flow just created and\n * failed to populate. Never use for a user-initiated delete: that is\n * deleteDocument, which tombstones and stays recoverable.\n */\nexport async function discardFailedDocument(\n documentId: string,\n): Promise<ServiceResult<true>> {\n const { error } = await tryWriteOne(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ deleted_at: new Date().toISOString() })\n .eq(\"id\", documentId)\n .select(\"id\"),\n { action: \"archive\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: true };\n}\n\nexport async function deleteDocument(\n documentId: string,\n): Promise<ServiceResult<true>> {\n const { error } = await tryWriteOne(\n db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ deleted_at: new Date().toISOString() })\n .eq(\"id\", documentId)\n .select(\"id\"),\n { action: \"delete\", noun: \"document\" },\n );\n if (error) return { success: false, error: error.message };\n return { success: true, data: true };\n}\n\n// ─── snapshots (document content) ────────────────────────────────────────────\n\n/**\n * Latest-snapshot fetch — what an opened document hydrates from. Returns\n * `data: null` (success path) when the document has no snapshots yet (newly\n * created, never saved). Distinguish \"no snapshot\" from \"load error\" by\n * checking `result.data === null`.\n */\nexport async function getLatestDocumentSnapshot(\n documentId: string,\n): Promise<ServiceResult<DocumentSnapshot | null>> {\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_document_snapshots\")\n .select(\"*\")\n .eq(\"document_id\", documentId)\n .order(\"created_at\", { ascending: false })\n .limit(1)\n .maybeSingle();\n if (error) return { success: false, error: error.message };\n return { success: true, data: (data ?? null) as DocumentSnapshot | null };\n}\n\nexport type SaveDocumentSnapshotArgs = {\n documentId: string;\n snapshot: unknown; // opaque to us — Univer IDocumentData decides the shape\n label?: string | null;\n origin?: DocumentSnapshotOrigin;\n};\n\nexport async function saveDocumentSnapshot(\n args: SaveDocumentSnapshotArgs,\n): Promise<ServiceResult<DocumentSnapshot>> {\n const { data: userData } = await getClaimsUser(db());\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_document_snapshots\")\n .insert({\n document_id: args.documentId,\n snapshot: args.snapshot as never,\n label: args.label ?? null,\n origin: args.origin ?? \"autosave\",\n created_by: userData?.user?.id ?? null,\n })\n .select(\"*\")\n .single();\n if (error) return { success: false, error: error.message };\n\n // Touch the parent document's updated_at so list views can sort by recency\n // without scanning snapshots. Best-effort — failure here is harmless.\n // write-lands-exempt: best-effort recency stamp on the parent document; the snapshot insert above is the real write\n await db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .update({ updated_at: new Date().toISOString() })\n .eq(\"id\", args.documentId);\n\n return { success: true, data: data as DocumentSnapshot };\n}\n\n/**\n * An independent copy of a document: its own row, with the latest snapshot copied over, so editing the copy never\n * touches the original. The copy lives in the original's organization and project. Used by a board-template use.\n */\nexport async function copyDocument(\n documentId: string,\n name?: string,\n): Promise<ServiceResult<DocumentRow>> {\n const original = await getDocument(documentId);\n if (!original.success) return original;\n const row = original.data;\n if (!row.organization_id) {\n return { success: false, error: \"This document has no organization and cannot be copied.\" };\n }\n const created = await createDocument({\n name: name ?? row.document_name,\n description: row.description ?? null,\n organizationId: row.organization_id,\n projectId: row.project_id ?? null,\n isPublic: row.visibility === \"public\",\n });\n if (!created.success) return created;\n const latest = await getLatestDocumentSnapshot(documentId);\n if (!latest.success) return latest;\n if (latest.data) {\n const saved = await saveDocumentSnapshot({\n documentId: created.data.id,\n snapshot: latest.data.snapshot,\n label: latest.data.label,\n origin: \"autosave\",\n });\n if (!saved.success) return saved;\n }\n return created;\n}\n\n/** Trash view: the caller's own archived documents (RLS decides what is readable). */\nexport async function listTrashedDocuments(): Promise<\n ServiceResult<DocumentRow[]>\n> {\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_documents\")\n .select(\"*\")\n .not(\"deleted_at\", \"is\", null)\n .order(\"deleted_at\", { ascending: false });\n if (error) return { success: false, error: error.message };\n return { success: true, data: (data ?? []) as DocumentRow[] };\n}\n\nexport async function listDocumentSnapshots(\n documentId: string,\n limit = 50,\n): Promise<ServiceResult<DocumentSnapshot[]>> {\n const { data, error } = await db()\n .schema(\"workbench\")\n .from(\"udt_document_snapshots\")\n // component-created-by-ok: append-only snapshot with NO updated_by column and NO parent-rewrite trigger — created_by is the author the client wrote at insert (the only person field this table has)\n .select(\"id, document_id, label, origin, created_by, created_at\")\n .eq(\"document_id\", documentId)\n .order(\"created_at\", { ascending: false })\n .limit(limit);\n if (error) return { success: false, error: error.message };\n return { success: true, data: (data ?? []) as DocumentSnapshot[] };\n}\n","/**\n * sanitizeUniverDocSnapshot — defensive normalizer for Univer document\n * snapshots loaded from storage.\n *\n * WHY THIS EXISTS (loud recovery layer):\n * Univer's `NamedStyleType` is a NUMERIC enum (`HEADING_1 = 4`, `HEADING_2 = 5`,\n * …). Some snapshots in storage were produced by an external markdown→Univer\n * converter that wrote the *string* name (`\"HEADING_1\"`) into\n * `paragraphStyle.namedStyleType` instead of the numeric value. At render time\n * Univer does `HEADING_ICON_MAP[namedStyleType]` → `undefined` →\n * `icon.key` throws `Cannot read properties of undefined (reading 'key')` inside\n * the `<ParagraphMenu>` component the moment the cursor lands in a heading. That\n * uncaught error tears down Univer's React root, so the document loads and then\n * vanishes. See `features/data-tables/FEATURE.md`.\n *\n * This normalizer converts those string enum values back to numbers BEFORE the\n * snapshot reaches `createUniverDoc`. It is a recovery layer: when it fires it\n * means malformed data slipped past the writer, so it SCREAMS (console.warn)\n * with a count and the document id. The proper long-term fix is to make the\n * writer emit numeric enum values; until then this keeps the editor alive.\n *\n * Returns the SAME object (mutated in place) for ergonomic call sites, plus a\n * `fixed` count via the second return slot is intentionally avoided — callers\n * only need the sanitized snapshot; the warning is the signal.\n */\nimport { NamedStyleType } from \"@univerjs/core\";\nimport type { IDocumentData } from \"@univerjs/core\";\n\nimport {\n defaultDocumentPageStyle,\n isLegacySqueezedPageStyle,\n} from \"../core\";\n\n/**\n * Map of every string name that could appear in a legacy snapshot to its\n * canonical numeric `NamedStyleType`. Built from the enum itself so it stays in\n * lockstep with Univer (numeric enums expose name→value on string keys).\n */\nconst NAMED_STYLE_STRING_TO_NUMBER: Record<string, number> = Object.fromEntries(\n Object.entries(NamedStyleType)\n .filter(([key, val]) => typeof val === \"number\" && isNaN(Number(key)))\n .map(([key, val]) => [key, val as number]),\n);\n\n/**\n * Normalize a Univer document snapshot in place. Currently fixes string-valued\n * `paragraphStyle.namedStyleType` (the confirmed `<ParagraphMenu>` crash). New\n * classes of string-vs-enum corruption should be added here, not patched at the\n * call site.\n *\n * @param snapshot The snapshot about to be passed to `createUniverDoc`.\n * @param docId Document id, for the loud warning only.\n * @returns the same snapshot reference (mutated).\n */\nexport function sanitizeUniverDocSnapshot(\n snapshot: Partial<IDocumentData>,\n docId?: string,\n): Partial<IDocumentData> {\n restorePageStyle(snapshot, docId);\n\n const paragraphs = snapshot?.body?.paragraphs;\n if (!Array.isArray(paragraphs)) return snapshot;\n\n let fixed = 0;\n for (const paragraph of paragraphs) {\n const style = paragraph?.paragraphStyle as\n { namedStyleType?: unknown } | undefined;\n const value = style?.namedStyleType;\n if (typeof value === \"string\") {\n const numeric = NAMED_STYLE_STRING_TO_NUMBER[value];\n if (numeric !== undefined) {\n (style as { namedStyleType?: number }).namedStyleType = numeric;\n fixed += 1;\n } else {\n // Unknown string we can't map — drop it so Univer falls back to\n // NORMAL_TEXT rather than crashing on the lookup.\n delete (style as { namedStyleType?: unknown }).namedStyleType;\n fixed += 1;\n }\n }\n }\n\n if (fixed > 0) {\n console.warn(\n `[data-tables] RECOVERY: sanitized ${fixed} string namedStyleType value(s) ` +\n `to numeric NamedStyleType in document snapshot${docId ? ` ${docId}` : \"\"}. ` +\n `The snapshot was written with the wrong enum encoding (string instead of ` +\n `number) and would have crashed Univer's <ParagraphMenu>. Fix the snapshot ` +\n `writer to emit numeric NamedStyleType values.`,\n );\n }\n\n return snapshot;\n}\n\n/**\n * Second recovery: a snapshot with no `documentStyle.pageSize` has no page box,\n * so Univer lays the body out unbounded — text never wraps and the docs\n * viewport reports no scrollable extent, which reads to the user as \"the\n * document won't scroll\". Snapshots written by agents (`origin='agent'`) and by\n * older converters reach storage with `documentStyle: {}`. Stamp the canonical\n * page geometry back on and SCREAM: the writer is the real bug.\n */\nfunction restorePageStyle(snapshot: Partial<IDocumentData>, docId?: string) {\n if (!snapshot || typeof snapshot !== \"object\") return;\n\n // THE SQUEEZED PAGE (2026-10-15): documents carried A4-at-72dpi geometry in Univer's pageless\n // flavour — a 415px text column with no paper. Move them to a real Letter page, unchanged text.\n // A document with no flavour at all is a paginated page too (Univer would otherwise pick pageless).\n const style = snapshot.documentStyle;\n if (style?.pageSize?.width && isLegacySqueezedPageStyle(style)) {\n const page = defaultDocumentPageStyle();\n snapshot.documentStyle = { ...style, ...page, defaultParagraphStyle: style.defaultParagraphStyle ?? page.defaultParagraphStyle } as typeof style;\n return;\n }\n if (style?.pageSize?.width) {\n if (!style.documentFlavor) {\n const page = defaultDocumentPageStyle();\n Object.assign(style, { documentFlavor: page.documentFlavor });\n if (page.defaultParagraphStyle) style.defaultParagraphStyle ??= page.defaultParagraphStyle;\n }\n return;\n }\n\n snapshot.documentStyle = {\n ...defaultDocumentPageStyle(),\n ...(snapshot.documentStyle ?? {}),\n pageSize: defaultDocumentPageStyle().pageSize,\n } as NonNullable<typeof snapshot.documentStyle>;\n\n console.warn(\n `[data-tables] RECOVERY: document snapshot${docId ? ` ${docId}` : \"\"} had no ` +\n `documentStyle.pageSize — restored the default Letter page geometry. Without a ` +\n `page box Univer lays the body out unbounded: text does not wrap and the ` +\n `viewport has no scrollable extent, so the document appears frozen. Fix the ` +\n `snapshot writer (agent/markdown converters must stamp ` +\n `DEFAULT_DOCUMENT_PAGE_STYLE).`,\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-O6FTSXHE.cjs","../src/docs/markdown-to-univer-doc.ts"],"names":[],"mappings":"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","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-O6FTSXHE.cjs","sourcesContent":[null,"/**\n * markdown-to-univer-doc — convert a markdown string into a Univer\n * `IDocumentData` snapshot that the document editor (preset-docs-core) can\n * hydrate directly.\n *\n * Why this exists: the document system stores opaque Univer `IDocumentData`\n * (see `document-service.ts` + `components/DocumentEditor.tsx`). To send any\n * markdown surface (an assistant message, a note, a scraper result) into a\n * cloud document, we need markdown → IDocumentData. There was no converter, so\n * \"Add to docs\" was a stub. This is the missing primitive — reuse it for every\n * markdown → document export, never re-implement a one-off.\n *\n * The output is RENDERED content, not raw markdown text: `**bold**` becomes a\n * bold text run, `# Heading` becomes a larger bold paragraph, `- item` becomes\n * a bulleted line. The document never contains literal markdown syntax.\n *\n * Univer body model (the part we build):\n * - `dataStream` — the text. `\\r` terminates a paragraph; a trailing `\\n`\n * terminates the (single) section. Mirrors the empty doc\n * `\"\\r\\n\"` shape in DocumentEditor.defaultEmptyDocument().\n * - `paragraphs` — one entry per `\\r`, `startIndex` = the `\\r` offset.\n * - `textRuns` — `{ st, ed, ts }` style overlays on character ranges.\n * - `sectionBreaks` — the trailing `\\n`.\n *\n * Scope: headings, paragraphs, bold/italic/strikethrough/inline-code, links\n * (Univer hyperlink ranges keep the address), unordered/ordered lists, blockquotes, fenced code\n * blocks, horizontal rules, and GFM tables (real Univer tables). Nested\n * emphasis is supported. Anything exotic degrades to plain readable text rather\n * than leaking syntax.\n */\n\nimport { plainTitleFromMarkdown } from \"@ai-matrx/rich-content/utils/plain-title\";\nimport {\n BooleanNumber,\n CustomRangeType,\n ObjectRelativeFromH,\n ObjectRelativeFromV,\n TableAlignmentType,\n TableRowHeightRule,\n TableSizeType,\n TableTextWrapType,\n createParagraphId,\n createSectionId,\n} from \"@univerjs/core\";\nimport type {\n ICustomRange,\n IDocumentData,\n IParagraph,\n ISectionBreak,\n ITextRun,\n ITextStyle,\n} from \"@univerjs/core\";\nimport { LocaleType } from \"@univerjs/presets\";\n\nimport {\n DEFAULT_DOCUMENT_PAGE_STYLE,\n defaultDocumentPageStyle,\n} from \"../core\";\nimport {\n codeSpanText,\n fenceLineKinds,\n findTableEnd,\n mapCodeRanges,\n rowCells,\n tableStartsAt,\n unescapeCellPipes,\n} from \"@ai-matrx/content-ir/source\";\n\n// ─── inline parsing ──────────────────────────────────────────────────────────\n\ninterface InlineStyle {\n bold?: boolean;\n italic?: boolean;\n code?: boolean;\n strike?: boolean;\n /** Link address — becomes a Univer hyperlink range, never just its text. */\n link?: string;\n}\n\ninterface Segment extends InlineStyle {\n text: string;\n /** A picture (`![alt](src)`): `text` holds its alt. */\n image?: string;\n}\n\n// Order matters: `**`/`__` before `*`/`_` so bold wins over italic; code and\n// links are matched atomically. Link target excludes whitespace to avoid\n// swallowing trailing prose.\nconst INLINE_RE =\n /!\\[([^\\]]*)\\]\\(([^)\\s]+)\\)|(\\*\\*|__)([\\s\\S]+?)\\3|(\\*|_)([\\s\\S]+?)\\5|~~([\\s\\S]+?)~~|\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/g;\n\nconst CODE_TOKEN = /\\uE400(\\d+)\\uE401/g;\n\n/**\n * Inline markdown → styled segments. Code spans come from THE one code-range\n * rule (@ai-matrx/content-ir/source) and are held behind placeholders, so the\n * emphasis pattern never reads inside code and code inside **bold** stays code.\n */\nfunction parseInline(text: string, base: InlineStyle = {}): Segment[] {\n const codes: string[] = [];\n const held = text.includes(\"`\")\n ? mapCodeRanges(text, (range, raw) => {\n if (range.kind !== \"span\") return raw;\n codes.push(codeSpanText(raw));\n return `\\uE400${codes.length - 1}\\uE401`;\n })\n : text;\n if (codes.length === 0) return parseStyled(held, base);\n return parseStyled(held, base).flatMap((seg) => {\n const out: Segment[] = [];\n let at = 0;\n for (const m of seg.text.matchAll(CODE_TOKEN)) {\n if ((m.index ?? 0) > at) out.push({ ...seg, text: seg.text.slice(at, m.index) });\n out.push({ ...seg, text: codes[Number(m[1])] ?? \"\", code: true });\n at = (m.index ?? 0) + m[0].length;\n }\n if (at < seg.text.length) out.push({ ...seg, text: seg.text.slice(at) });\n return out.filter((s) => s.text.length > 0);\n });\n}\n\nfunction parseStyled(text: string, base: InlineStyle = {}): Segment[] {\n const segs: Segment[] = [];\n let last = 0;\n let m: RegExpExecArray | null;\n const re = new RegExp(INLINE_RE.source, \"g\");\n while ((m = re.exec(text)) !== null) {\n if (m.index > last) segs.push({ text: text.slice(last, m.index), ...base });\n if (m[2] !== undefined) {\n // Picture → its own segment (alt as text); the builder decides how it lands.\n segs.push({ ...base, text: m[1] || \"image\", image: m[2] });\n } else if (m[3] !== undefined) {\n segs.push(...parseStyled(m[4]!, { ...base, bold: true }));\n } else if (m[5] !== undefined) {\n segs.push(...parseStyled(m[6]!, { ...base, italic: true }));\n } else if (m[7] !== undefined) {\n segs.push(...parseStyled(m[7], { ...base, strike: true }));\n } else if (m[8] !== undefined) {\n // Link → its text carries the address as a hyperlink range.\n segs.push(...parseStyled(m[8], { ...base, link: m[9]! }));\n }\n last = re.lastIndex;\n }\n if (last < text.length) segs.push({ text: text.slice(last), ...base });\n return segs.filter((s) => s.text.length > 0);\n}\n\n// ─── style helpers ───────────────────────────────────────────────────────────\n\nconst HEADING_FONT_SIZE: Record<number, number> = {\n 1: 26,\n 2: 22,\n 3: 18,\n 4: 16,\n 5: 14,\n 6: 13,\n};\n\ninterface ParagraphOpts {\n /** 1-6 → heading; undefined → body text. */\n heading?: number;\n /** Render the whole paragraph in a monospace font (code block lines). */\n mono?: boolean;\n}\n\nfunction buildTextStyle(\n seg: Segment,\n opts: ParagraphOpts,\n): ITextStyle | undefined {\n const ts: ITextStyle = {};\n if (seg.bold || opts.heading) ts.bl = BooleanNumber.TRUE;\n if (seg.italic) ts.it = BooleanNumber.TRUE;\n if (seg.strike) ts.st = { s: BooleanNumber.TRUE };\n if (seg.code || opts.mono) ts.ff = \"monospace\";\n if (opts.heading) ts.fs = HEADING_FONT_SIZE[opts.heading] ?? 16;\n else if (seg.code || opts.mono) ts.fs = 12;\n return Object.keys(ts).length > 0 ? ts : undefined;\n}\n\n// ─── document builder ────────────────────────────────────────────────────────\n\n/** Univer's numeric NamedStyleType.HEADING_1 (HEADING_2..5 follow). */\nconst NAMED_HEADING_1 = 4;\n\nclass DocBuilder {\n private parts: string[] = [];\n private cursor = 0;\n private paragraphs: IParagraph[] = [];\n private paragraphIds = new Set<string>();\n private textRuns: ITextRun[] = [];\n private sectionBreaks: ISectionBreak[] = [];\n private sectionIds = new Set<string>();\n private customRanges: ICustomRange[] = [];\n private tables: NonNullable<NonNullable<IDocumentData[\"body\"]>[\"tables\"]> = [];\n private tableSource: NonNullable<IDocumentData[\"tableSource\"]> = {};\n private customBlocks: { startIndex: number; blockId: string }[] = [];\n private drawings: Record<string, Record<string, unknown>> = {};\n /** Pictures that are not ours (e.g. Google's): kept as a visible link, counted. */\n linkedImages = 0;\n\n /**\n * One picture. Ours (`matrx-file:<id>[#WxH]`) becomes a real inline drawing;\n * any other address is a visible \"alt\" link to it, never dropped.\n */\n private addImage(seg: Segment, opts: ParagraphOpts): void {\n const src = seg.image ?? \"\";\n const own = src.match(/^(matrx-file:[0-9a-f-]+)(?:#(\\d+)x(\\d+))?$/i);\n if (!own) {\n this.linkedImages += 1;\n this.addInline([{ text: seg.text || \"image\", link: src }], opts);\n return;\n }\n const blockId = `img${Object.keys(this.drawings).length}${Math.random().toString(36).slice(2, 6)}`;\n const width = Number(own[2]) || 320;\n const height = Number(own[3]) || 240;\n this.customBlocks.push({ startIndex: this.cursor, blockId });\n this.parts.push(CUSTOM_BLOCK);\n this.cursor += 1;\n this.drawings[blockId] = {\n drawingId: blockId,\n drawingType: 0,\n imageSourceType: \"URL\",\n source: own[1],\n title: seg.text === \"image\" ? \"\" : seg.text,\n description: \"\",\n layoutType: 0,\n wrapText: 0,\n behindDoc: 0,\n distT: 0,\n distB: 0,\n distL: 0,\n distR: 0,\n transform: { left: 0, top: 0, width, height },\n docTransform: {\n size: { width, height },\n angle: 0,\n positionH: { relativeFrom: ObjectRelativeFromH.PAGE, posOffset: 0 },\n positionV: { relativeFrom: ObjectRelativeFromV.PARAGRAPH, posOffset: 0 },\n },\n };\n }\n\n /** Segment text + styles + hyperlink ranges, no paragraph terminator. */\n private addInline(segments: Segment[], opts: ParagraphOpts): void {\n let openLink: string | undefined;\n let linkStart = 0;\n const closeLink = () => {\n if (openLink === undefined) return;\n this.parts.push(LINK_END);\n this.customRanges.push({\n startIndex: linkStart,\n endIndex: this.cursor,\n rangeId: `link-${this.customRanges.length}-${linkStart}`,\n rangeType: CustomRangeType.HYPERLINK,\n properties: { url: openLink },\n });\n this.cursor += 1;\n openLink = undefined;\n };\n for (const seg of segments) {\n if (!seg.text) continue;\n if (seg.image !== undefined) {\n closeLink();\n this.addImage(seg, opts);\n continue;\n }\n if (seg.link !== openLink) {\n closeLink();\n if (seg.link !== undefined) {\n openLink = seg.link;\n linkStart = this.cursor;\n this.parts.push(LINK_START);\n this.cursor += 1;\n }\n }\n const st = this.cursor;\n this.parts.push(seg.text);\n this.cursor += seg.text.length;\n const ts = buildTextStyle(seg, opts);\n if (ts) this.textRuns.push({ st, ed: this.cursor, ts });\n }\n closeLink();\n }\n\n addParagraph(segments: Segment[], opts: ParagraphOpts = {}): void {\n this.addInline(segments, opts);\n // Paragraph terminator.\n this.parts.push(\"\\r\");\n this.paragraphs.push({\n startIndex: this.cursor,\n paragraphId: createParagraphId(this.paragraphIds),\n // A heading is a real heading paragraph (outline, Format > Paragraph styles), not only big bold text.\n ...(opts.heading ? { paragraphStyle: { namedStyleType: NAMED_HEADING_1 + Math.min(opts.heading, 5) - 1 } } : {}),\n });\n this.cursor += 1;\n }\n\n /**\n * A real Univer table (dataStream table tokens + `tables` + `tableSource`),\n * the same shape Insert > Table writes. `rows[r][c]` = that cell's segments.\n */\n addTable(rows: Segment[][][], headerBold: boolean): void {\n const colCount = Math.max(1, ...rows.map((r) => r.length));\n const pageWidth =\n (DEFAULT_DOCUMENT_PAGE_STYLE.pageSize?.width ?? 595) -\n (DEFAULT_DOCUMENT_PAGE_STYLE.marginLeft ?? 90) -\n (DEFAULT_DOCUMENT_PAGE_STYLE.marginRight ?? 90);\n const tableId = cryptoRandomId().replace(/-/g, \"\").slice(0, 6);\n const start = this.cursor;\n this.parts.push(TABLE_START);\n this.cursor += 1;\n rows.forEach((row, r) => {\n this.parts.push(TABLE_ROW_START);\n this.cursor += 1;\n for (let c = 0; c < colCount; c++) {\n this.parts.push(TABLE_CELL_START);\n this.cursor += 1;\n const cell = row[c] ?? [];\n const cellStart = this.cursor;\n this.addInline(cell, {});\n if (r === 0 && headerBold) this.boldRunsSince(cellStart);\n this.parts.push(\"\\r\");\n this.paragraphs.push({\n startIndex: this.cursor,\n paragraphId: createParagraphId(this.paragraphIds),\n paragraphStyle: {\n spaceAbove: { v: 3 },\n lineSpacing: 2,\n spaceBelow: { v: 0 },\n },\n });\n this.cursor += 1;\n this.parts.push(\"\\n\");\n this.sectionBreaks.push({\n startIndex: this.cursor,\n sectionId: createSectionId(this.sectionIds),\n });\n this.cursor += 1;\n this.parts.push(TABLE_CELL_END);\n this.cursor += 1;\n }\n this.parts.push(TABLE_ROW_END);\n this.cursor += 1;\n });\n this.parts.push(TABLE_END);\n this.cursor += 1;\n this.tables.push({ startIndex: start, endIndex: this.cursor, tableId });\n const margin = {\n start: { v: 10 },\n end: { v: 10 },\n top: { v: 5 },\n bottom: { v: 5 },\n };\n this.tableSource[tableId] = {\n tableRows: rows.map(() => ({\n tableCells: Array.from({ length: colCount }, () => ({ margin: { ...margin } })),\n trHeight: { val: { v: 30 }, hRule: TableRowHeightRule.AUTO },\n })),\n tableColumns: Array.from({ length: colCount }, () => ({\n size: { type: TableSizeType.SPECIFIED, width: { v: pageWidth / colCount } },\n })),\n tableId,\n align: TableAlignmentType.START,\n indent: { v: 0 },\n textWrap: TableTextWrapType.NONE,\n position: {\n positionH: { relativeFrom: ObjectRelativeFromH.PAGE, posOffset: 0 },\n positionV: { relativeFrom: ObjectRelativeFromV.PAGE, posOffset: 0 },\n },\n dist: { distB: 0, distL: 0, distR: 0, distT: 0 },\n cellMargin: { ...margin },\n size: { type: TableSizeType.UNSPECIFIED, width: { v: pageWidth } },\n } as NonNullable<IDocumentData[\"tableSource\"]>[string];\n // A table is always followed by a paragraph (Univer's own insert adds one).\n this.addParagraph([]);\n }\n\n /** Header cells: bold every run written since `from` (plain runs get one). */\n private boldRunsSince(from: number): void {\n const end = this.cursor;\n if (end <= from) return;\n const covered = this.textRuns.filter((t) => t.st >= from);\n for (const t of covered) t.ts = { ...t.ts, bl: BooleanNumber.TRUE };\n let at = from;\n const gaps: ITextRun[] = [];\n for (const t of [...covered].sort((a, b) => a.st - b.st)) {\n if (t.st > at) gaps.push({ st: at, ed: t.st, ts: { bl: BooleanNumber.TRUE } });\n at = Math.max(at, t.ed);\n }\n if (at < end) gaps.push({ st: at, ed: end, ts: { bl: BooleanNumber.TRUE } });\n this.textRuns.push(...gaps);\n }\n\n isEmpty(): boolean {\n return this.paragraphs.length === 0;\n }\n\n build(title: string): Partial<IDocumentData> {\n if (this.isEmpty()) {\n // Univer requires at least one paragraph + section break.\n this.parts.push(\"\\r\");\n this.paragraphs.push({\n startIndex: this.cursor,\n paragraphId: createParagraphId(this.paragraphIds),\n });\n this.cursor += 1;\n }\n this.parts.push(\"\\n\");\n const sectionBreaks: ISectionBreak[] = [\n ...this.sectionBreaks,\n {\n startIndex: this.cursor,\n sectionId: createSectionId(this.sectionIds),\n },\n ];\n this.cursor += 1;\n\n const id = cryptoRandomId();\n const drawingIds = Object.keys(this.drawings);\n for (const d of drawingIds) Object.assign(this.drawings[d]!, { unitId: id, subUnitId: id });\n return {\n id,\n locale: LocaleType.EN_US,\n title,\n body: {\n dataStream: this.parts.join(\"\"),\n paragraphs: this.paragraphs,\n textRuns: this.textRuns.sort((a, b) => a.st - b.st),\n sectionBreaks,\n ...(this.customRanges.length ? { customRanges: this.customRanges } : {}),\n ...(this.tables.length ? { tables: this.tables } : {}),\n ...(this.customBlocks.length ? { customBlocks: this.customBlocks } : {}),\n },\n ...(drawingIds.length\n ? { drawings: this.drawings as unknown as IDocumentData[\"drawings\"], drawingsOrder: drawingIds }\n : {}),\n ...(this.tables.length ? { tableSource: this.tableSource } : {}),\n documentStyle: defaultDocumentPageStyle(),\n } as Partial<IDocumentData>;\n }\n}\n\n// Univer's DataStreamTreeTokenType control characters (literals: this module is\n// also loaded where Univer's runtime is not).\nconst TABLE_START = \"\\x1A\";\nconst TABLE_ROW_START = \"\\x1B\";\nconst TABLE_CELL_START = \"\\x1C\";\nconst TABLE_CELL_END = \"\\x1D\";\nconst TABLE_ROW_END = \"\\x0E\";\nconst TABLE_END = \"\\x0F\";\nconst LINK_START = \"\\x1F\";\nconst LINK_END = \"\\x1E\";\nconst CUSTOM_BLOCK = \"\\b\";\n\n// ─── block helpers ───────────────────────────────────────────────────────────\n\n// THE GFM row rule (gfm-table-lines): an escaped `\\|` stays in its cell and\n// shows as `|` (the one cell-pipe rule), exactly as chat and Studio draw it.\nconst splitTableRow = (line: string): string[] => rowCells(line).map(unescapeCellPipes);\n\nfunction addTable(builder: DocBuilder, tableLines: string[]): void {\n const header = splitTableRow(tableLines[0]!);\n // tableLines[1] is the `---|---` separator — skip it.\n const body = tableLines\n .slice(2)\n .map(splitTableRow)\n .filter((r) => r.some((c) => c.length > 0));\n const toCells = (cells: string[]): Segment[][] => cells.map((cell) => parseInline(cell));\n builder.addTable([toCells(header), ...body.map(toCells)], true);\n}\n\n/**\n * Remove reasoning/thinking blocks so they never leak into the document.\n * Defensive — most callers pass already-flattened text, but a raw markdown\n * source could still carry `<think>` / `<thinking>` tags.\n */\nfunction stripThinking(markdown: string): string {\n return markdown\n .replace(/<think(?:ing)?>[\\s\\S]*?<\\/think(?:ing)?>/gi, \"\")\n .trim();\n}\n\nfunction cryptoRandomId(): string {\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) {\n return crypto.randomUUID();\n }\n return `doc-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n// ─── public API ──────────────────────────────────────────────────────────────\n\n/**\n * Convert markdown to a Univer `IDocumentData` snapshot. Pure — no I/O. Pass\n * the result straight to `saveDocumentSnapshot`.\n */\nexport function markdownToUniverDoc(\n markdown: string,\n title = \"Untitled document\",\n): Partial<IDocumentData> {\n const builder = new DocBuilder();\n const cleaned = stripThinking(markdown ?? \"\")\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\");\n const lines = cleaned.split(\"\\n\");\n // Fenced code by THE one code-range rule (@ai-matrx/content-ir/source).\n const kinds = fenceLineKinds(cleaned);\n\n let i = 0;\n let paragraphBuf: string[] = [];\n\n const flushParagraph = () => {\n if (paragraphBuf.length === 0) return;\n const text = paragraphBuf.join(\" \").trim();\n if (text) builder.addParagraph(parseInline(text));\n paragraphBuf = [];\n };\n\n while (i < lines.length) {\n const line = lines[i]!;\n const trimmed = line.trim();\n\n // Blank line — paragraph boundary.\n if (!trimmed) {\n flushParagraph();\n i++;\n continue;\n }\n\n // Fenced code block.\n if (kinds[i] === \"open\") {\n flushParagraph();\n i++;\n const code: string[] = [];\n while (i < lines.length && kinds[i] === \"body\") {\n code.push(lines[i]!);\n i++;\n }\n if (kinds[i] === \"close\") i++; // consume the closing fence\n for (const c of code) {\n builder.addParagraph([{ text: c.length ? c : \" \", code: true }], {\n mono: true,\n });\n }\n continue;\n }\n\n // ATX heading.\n const heading = trimmed.match(/^(#{1,6})\\s+(.*)$/);\n if (heading) {\n flushParagraph();\n builder.addParagraph(parseInline(heading[2]!.trim()), {\n heading: heading[1]!.length,\n });\n i++;\n continue;\n }\n\n // Horizontal rule.\n if (/^(\\s*[-*_]\\s*){3,}$/.test(trimmed) && /^[\\s\\-*_]+$/.test(trimmed)) {\n flushParagraph();\n builder.addParagraph([{ text: \"\\u2014\".repeat(24) }]);\n i++;\n continue;\n }\n\n // GFM table (THE rule, gfm-table-lines): a header — with or without edge\n // pipes — immediately followed by its delimiter row.\n if (tableStartsAt(lines, i)) {\n flushParagraph();\n const tableLines: string[] = [];\n const tableEnd = findTableEnd(lines, i);\n while (i < tableEnd) {\n tableLines.push(lines[i]!.trim());\n i++;\n }\n addTable(builder, tableLines);\n continue;\n }\n\n // Blockquote.\n const quote = trimmed.match(/^>\\s?(.*)$/);\n if (quote) {\n flushParagraph();\n builder.addParagraph(parseInline(quote[1]!), {});\n i++;\n continue;\n }\n\n // List item (ordered or unordered, with nesting by indent).\n const list = line.match(/^(\\s*)([-*+]|\\d+[.)])\\s+(.*)$/);\n if (list) {\n flushParagraph();\n const indent = list[1]!.replace(/\\t/g, \" \").length;\n const level = Math.min(Math.floor(indent / 2), 5);\n const ordered = /\\d/.test(list[2]!);\n const marker = ordered ? `${list[2]!.replace(/[.)]$/, \"\")}.` : \"\\u2022\";\n const prefix = `${\" \".repeat(level)}${marker} `;\n builder.addParagraph([{ text: prefix }, ...parseInline(list[3]!)]);\n i++;\n continue;\n }\n\n // Default — accumulate into the current paragraph.\n paragraphBuf.push(trimmed);\n i++;\n }\n\n flushParagraph();\n return builder.build(title);\n}\n\n/**\n * Derive a sensible document name from markdown: first heading, else first\n * non-empty line, trimmed of markdown syntax. Falls back to a dated default.\n */\nexport function deriveDocumentName(markdown: string): string {\n const cleaned = stripThinking(markdown ?? \"\");\n // First heading, else the first line — through the ONE plain-text title\n // projection (components/markdown-core/plain-title.ts).\n const lines = cleaned.split(\"\\n\");\n const heading = lines.find((l) => /^\\s{0,3}#{1,6}\\s+/.test(l));\n const plain = plainTitleFromMarkdown(heading ?? cleaned);\n if (!plain) {\n return `Document ${new Date().toLocaleDateString()}`;\n }\n return plainTitleFromMarkdown(plain, { maxLength: 80 });\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/_work/aidream/aidream/apps/shared/office/dist/chunk-O6FTSXHE.cjs","../src/docs/markdown-to-univer-doc.ts"],"names":[],"mappings":"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","file":"/home/runner/_work/aidream/aidream/apps/shared/office/dist/chunk-O6FTSXHE.cjs","sourcesContent":[null,"/**\n * markdown-to-univer-doc — convert a markdown string into a Univer\n * `IDocumentData` snapshot that the document editor (preset-docs-core) can\n * hydrate directly.\n *\n * Why this exists: the document system stores opaque Univer `IDocumentData`\n * (see `document-service.ts` + `components/DocumentEditor.tsx`). To send any\n * markdown surface (an assistant message, a note, a scraper result) into a\n * cloud document, we need markdown → IDocumentData. There was no converter, so\n * \"Add to docs\" was a stub. This is the missing primitive — reuse it for every\n * markdown → document export, never re-implement a one-off.\n *\n * The output is RENDERED content, not raw markdown text: `**bold**` becomes a\n * bold text run, `# Heading` becomes a larger bold paragraph, `- item` becomes\n * a bulleted line. The document never contains literal markdown syntax.\n *\n * Univer body model (the part we build):\n * - `dataStream` — the text. `\\r` terminates a paragraph; a trailing `\\n`\n * terminates the (single) section. Mirrors the empty doc\n * `\"\\r\\n\"` shape in DocumentEditor.defaultEmptyDocument().\n * - `paragraphs` — one entry per `\\r`, `startIndex` = the `\\r` offset.\n * - `textRuns` — `{ st, ed, ts }` style overlays on character ranges.\n * - `sectionBreaks` — the trailing `\\n`.\n *\n * Scope: headings, paragraphs, bold/italic/strikethrough/inline-code, links\n * (Univer hyperlink ranges keep the address), unordered/ordered lists, blockquotes, fenced code\n * blocks, horizontal rules, and GFM tables (real Univer tables). Nested\n * emphasis is supported. Anything exotic degrades to plain readable text rather\n * than leaking syntax.\n */\n\nimport { plainTitleFromMarkdown } from \"@ai-matrx/rich-content/utils/plain-title\";\nimport {\n BooleanNumber,\n CustomRangeType,\n ObjectRelativeFromH,\n ObjectRelativeFromV,\n TableAlignmentType,\n TableRowHeightRule,\n TableSizeType,\n TableTextWrapType,\n createParagraphId,\n createSectionId,\n} from \"@univerjs/core\";\nimport type {\n ICustomRange,\n IDocumentData,\n IParagraph,\n ISectionBreak,\n ITextRun,\n ITextStyle,\n} from \"@univerjs/core\";\nimport { LocaleType } from \"@univerjs/presets\";\n\nimport {\n DEFAULT_DOCUMENT_PAGE_STYLE,\n defaultDocumentPageStyle,\n} from \"../core\";\nimport {\n codeSpanText,\n fenceLineKinds,\n findTableEnd,\n mapCodeRanges,\n rowCells,\n tableStartsAt,\n unescapeCellPipes,\n} from \"@ai-matrx/content-ir/source\";\n\n// ─── inline parsing ──────────────────────────────────────────────────────────\n\ninterface InlineStyle {\n bold?: boolean;\n italic?: boolean;\n code?: boolean;\n strike?: boolean;\n /** Link address — becomes a Univer hyperlink range, never just its text. */\n link?: string;\n}\n\ninterface Segment extends InlineStyle {\n text: string;\n /** A picture (`![alt](src)`): `text` holds its alt. */\n image?: string;\n}\n\n// Order matters: `**`/`__` before `*`/`_` so bold wins over italic; code and\n// links are matched atomically. Link target excludes whitespace to avoid\n// swallowing trailing prose.\nconst INLINE_RE =\n /!\\[([^\\]]*)\\]\\(([^)\\s]+)\\)|(\\*\\*|__)([\\s\\S]+?)\\3|(\\*|_)([\\s\\S]+?)\\5|~~([\\s\\S]+?)~~|\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/g;\n\nconst CODE_TOKEN = /\\uE400(\\d+)\\uE401/g;\n\n/**\n * Inline markdown → styled segments. Code spans come from THE one code-range\n * rule (@ai-matrx/content-ir/source) and are held behind placeholders, so the\n * emphasis pattern never reads inside code and code inside **bold** stays code.\n */\nfunction parseInline(text: string, base: InlineStyle = {}): Segment[] {\n const codes: string[] = [];\n const held = text.includes(\"`\")\n ? mapCodeRanges(text, (range, raw) => {\n if (range.kind !== \"span\") return raw;\n codes.push(codeSpanText(raw));\n return `\\uE400${codes.length - 1}\\uE401`;\n })\n : text;\n if (codes.length === 0) return parseStyled(held, base);\n return parseStyled(held, base).flatMap((seg) => {\n const out: Segment[] = [];\n let at = 0;\n for (const m of seg.text.matchAll(CODE_TOKEN)) {\n if ((m.index ?? 0) > at) out.push({ ...seg, text: seg.text.slice(at, m.index) });\n out.push({ ...seg, text: codes[Number(m[1])] ?? \"\", code: true });\n at = (m.index ?? 0) + m[0].length;\n }\n if (at < seg.text.length) out.push({ ...seg, text: seg.text.slice(at) });\n return out.filter((s) => s.text.length > 0);\n });\n}\n\nfunction parseStyled(text: string, base: InlineStyle = {}): Segment[] {\n const segs: Segment[] = [];\n let last = 0;\n let m: RegExpExecArray | null;\n const re = new RegExp(INLINE_RE.source, \"g\");\n while ((m = re.exec(text)) !== null) {\n if (m.index > last) segs.push({ text: text.slice(last, m.index), ...base });\n if (m[2] !== undefined) {\n // Picture → its own segment (alt as text); the builder decides how it lands.\n segs.push({ ...base, text: m[1] || \"image\", image: m[2] });\n } else if (m[3] !== undefined) {\n segs.push(...parseStyled(m[4]!, { ...base, bold: true }));\n } else if (m[5] !== undefined) {\n segs.push(...parseStyled(m[6]!, { ...base, italic: true }));\n } else if (m[7] !== undefined) {\n segs.push(...parseStyled(m[7], { ...base, strike: true }));\n } else if (m[8] !== undefined) {\n // Link → its text carries the address as a hyperlink range.\n segs.push(...parseStyled(m[8], { ...base, link: m[9]! }));\n }\n last = re.lastIndex;\n }\n if (last < text.length) segs.push({ text: text.slice(last), ...base });\n return segs.filter((s) => s.text.length > 0);\n}\n\n// ─── style helpers ───────────────────────────────────────────────────────────\n\nconst HEADING_FONT_SIZE: Record<number, number> = {\n 1: 26,\n 2: 22,\n 3: 18,\n 4: 16,\n 5: 14,\n 6: 13,\n};\n\ninterface ParagraphOpts {\n /** 1-6 → heading; undefined → body text. */\n heading?: number;\n /** Render the whole paragraph in a monospace font (code block lines). */\n mono?: boolean;\n}\n\nfunction buildTextStyle(\n seg: Segment,\n opts: ParagraphOpts,\n): ITextStyle | undefined {\n const ts: ITextStyle = {};\n if (seg.bold || opts.heading) ts.bl = BooleanNumber.TRUE;\n if (seg.italic) ts.it = BooleanNumber.TRUE;\n if (seg.strike) ts.st = { s: BooleanNumber.TRUE };\n if (seg.code || opts.mono) ts.ff = \"monospace\";\n if (opts.heading) ts.fs = HEADING_FONT_SIZE[opts.heading] ?? 16;\n else if (seg.code || opts.mono) ts.fs = 12;\n return Object.keys(ts).length > 0 ? ts : undefined;\n}\n\n// ─── document builder ────────────────────────────────────────────────────────\n\n/** Univer's numeric NamedStyleType.HEADING_1 (HEADING_2..5 follow). */\nconst NAMED_HEADING_1 = 4;\n\nclass DocBuilder {\n private parts: string[] = [];\n private cursor = 0;\n private paragraphs: IParagraph[] = [];\n private paragraphIds = new Set<string>();\n private textRuns: ITextRun[] = [];\n private sectionBreaks: ISectionBreak[] = [];\n private sectionIds = new Set<string>();\n private customRanges: ICustomRange[] = [];\n private tables: NonNullable<NonNullable<IDocumentData[\"body\"]>[\"tables\"]> = [];\n private tableSource: NonNullable<IDocumentData[\"tableSource\"]> = {};\n private customBlocks: { startIndex: number; blockId: string }[] = [];\n private drawings: Record<string, Record<string, unknown>> = {};\n /** Pictures that are not ours (e.g. Google's): kept as a visible link, counted. */\n linkedImages = 0;\n\n /**\n * One picture. Ours (`matrx-file:<id>[#WxH]`) becomes a real inline drawing;\n * any other address is a visible \"alt\" link to it, never dropped.\n */\n private addImage(seg: Segment, opts: ParagraphOpts): void {\n const src = seg.image ?? \"\";\n const own = src.match(/^(matrx-file:[0-9a-f-]+)(?:#(\\d+)x(\\d+))?$/i);\n if (!own) {\n this.linkedImages += 1;\n this.addInline([{ text: seg.text || \"image\", link: src }], opts);\n return;\n }\n const blockId = `img${Object.keys(this.drawings).length}${Math.random().toString(36).slice(2, 6)}`;\n const width = Number(own[2]) || 320;\n const height = Number(own[3]) || 240;\n this.customBlocks.push({ startIndex: this.cursor, blockId });\n this.parts.push(CUSTOM_BLOCK);\n this.cursor += 1;\n this.drawings[blockId] = {\n drawingId: blockId,\n drawingType: 0,\n imageSourceType: \"URL\",\n source: own[1],\n title: seg.text === \"image\" ? \"\" : seg.text,\n description: \"\",\n layoutType: 0,\n wrapText: 0,\n behindDoc: 0,\n distT: 0,\n distB: 0,\n distL: 0,\n distR: 0,\n transform: { left: 0, top: 0, width, height },\n docTransform: {\n size: { width, height },\n angle: 0,\n positionH: { relativeFrom: ObjectRelativeFromH.PAGE, posOffset: 0 },\n positionV: { relativeFrom: ObjectRelativeFromV.PARAGRAPH, posOffset: 0 },\n },\n };\n }\n\n /** Segment text + styles + hyperlink ranges, no paragraph terminator. */\n private addInline(segments: Segment[], opts: ParagraphOpts): void {\n let openLink: string | undefined;\n let linkStart = 0;\n const closeLink = () => {\n if (openLink === undefined) return;\n this.parts.push(LINK_END);\n this.customRanges.push({\n startIndex: linkStart,\n endIndex: this.cursor,\n rangeId: `link-${this.customRanges.length}-${linkStart}`,\n rangeType: CustomRangeType.HYPERLINK,\n properties: { url: openLink },\n });\n this.cursor += 1;\n openLink = undefined;\n };\n for (const seg of segments) {\n if (!seg.text) continue;\n if (seg.image !== undefined) {\n closeLink();\n this.addImage(seg, opts);\n continue;\n }\n if (seg.link !== openLink) {\n closeLink();\n if (seg.link !== undefined) {\n openLink = seg.link;\n linkStart = this.cursor;\n this.parts.push(LINK_START);\n this.cursor += 1;\n }\n }\n const st = this.cursor;\n this.parts.push(seg.text);\n this.cursor += seg.text.length;\n const ts = buildTextStyle(seg, opts);\n if (ts) this.textRuns.push({ st, ed: this.cursor, ts });\n }\n closeLink();\n }\n\n addParagraph(segments: Segment[], opts: ParagraphOpts = {}): void {\n this.addInline(segments, opts);\n // Paragraph terminator.\n this.parts.push(\"\\r\");\n this.paragraphs.push({\n startIndex: this.cursor,\n paragraphId: createParagraphId(this.paragraphIds),\n // A heading is a real heading paragraph (outline, Format > Paragraph styles), not only big bold text.\n ...(opts.heading ? { paragraphStyle: { namedStyleType: NAMED_HEADING_1 + Math.min(opts.heading, 5) - 1 } } : {}),\n });\n this.cursor += 1;\n }\n\n /**\n * A real Univer table (dataStream table tokens + `tables` + `tableSource`),\n * the same shape Insert > Table writes. `rows[r][c]` = that cell's segments.\n */\n addTable(rows: Segment[][][], headerBold: boolean): void {\n const colCount = Math.max(1, ...rows.map((r) => r.length));\n const pageWidth =\n (DEFAULT_DOCUMENT_PAGE_STYLE.pageSize?.width ?? 595) -\n (DEFAULT_DOCUMENT_PAGE_STYLE.marginLeft ?? 90) -\n (DEFAULT_DOCUMENT_PAGE_STYLE.marginRight ?? 90);\n const tableId = cryptoRandomId().replace(/-/g, \"\").slice(0, 6);\n const start = this.cursor;\n this.parts.push(TABLE_START);\n this.cursor += 1;\n rows.forEach((row, r) => {\n this.parts.push(TABLE_ROW_START);\n this.cursor += 1;\n for (let c = 0; c < colCount; c++) {\n this.parts.push(TABLE_CELL_START);\n this.cursor += 1;\n const cell = row[c] ?? [];\n const cellStart = this.cursor;\n this.addInline(cell, {});\n if (r === 0 && headerBold) this.boldRunsSince(cellStart);\n this.parts.push(\"\\r\");\n this.paragraphs.push({\n startIndex: this.cursor,\n paragraphId: createParagraphId(this.paragraphIds),\n paragraphStyle: {\n spaceAbove: { v: 3 },\n lineSpacing: 2,\n spaceBelow: { v: 0 },\n },\n });\n this.cursor += 1;\n this.parts.push(\"\\n\");\n this.sectionBreaks.push({\n startIndex: this.cursor,\n sectionId: createSectionId(this.sectionIds),\n });\n this.cursor += 1;\n this.parts.push(TABLE_CELL_END);\n this.cursor += 1;\n }\n this.parts.push(TABLE_ROW_END);\n this.cursor += 1;\n });\n this.parts.push(TABLE_END);\n this.cursor += 1;\n this.tables.push({ startIndex: start, endIndex: this.cursor, tableId });\n const margin = {\n start: { v: 10 },\n end: { v: 10 },\n top: { v: 5 },\n bottom: { v: 5 },\n };\n this.tableSource[tableId] = {\n tableRows: rows.map(() => ({\n tableCells: Array.from({ length: colCount }, () => ({ margin: { ...margin } })),\n trHeight: { val: { v: 30 }, hRule: TableRowHeightRule.AUTO },\n })),\n tableColumns: Array.from({ length: colCount }, () => ({\n size: { type: TableSizeType.SPECIFIED, width: { v: pageWidth / colCount } },\n })),\n tableId,\n align: TableAlignmentType.START,\n indent: { v: 0 },\n textWrap: TableTextWrapType.NONE,\n position: {\n positionH: { relativeFrom: ObjectRelativeFromH.PAGE, posOffset: 0 },\n positionV: { relativeFrom: ObjectRelativeFromV.PAGE, posOffset: 0 },\n },\n dist: { distB: 0, distL: 0, distR: 0, distT: 0 },\n cellMargin: { ...margin },\n size: { type: TableSizeType.UNSPECIFIED, width: { v: pageWidth } },\n } as NonNullable<IDocumentData[\"tableSource\"]>[string];\n // A table is always followed by a paragraph (Univer's own insert adds one).\n this.addParagraph([]);\n }\n\n /** Header cells: bold every run written since `from` (plain runs get one). */\n private boldRunsSince(from: number): void {\n const end = this.cursor;\n if (end <= from) return;\n const covered = this.textRuns.filter((t) => t.st >= from);\n for (const t of covered) t.ts = { ...t.ts, bl: BooleanNumber.TRUE };\n let at = from;\n const gaps: ITextRun[] = [];\n for (const t of [...covered].sort((a, b) => a.st - b.st)) {\n if (t.st > at) gaps.push({ st: at, ed: t.st, ts: { bl: BooleanNumber.TRUE } });\n at = Math.max(at, t.ed);\n }\n if (at < end) gaps.push({ st: at, ed: end, ts: { bl: BooleanNumber.TRUE } });\n this.textRuns.push(...gaps);\n }\n\n isEmpty(): boolean {\n return this.paragraphs.length === 0;\n }\n\n build(title: string): Partial<IDocumentData> {\n if (this.isEmpty()) {\n // Univer requires at least one paragraph + section break.\n this.parts.push(\"\\r\");\n this.paragraphs.push({\n startIndex: this.cursor,\n paragraphId: createParagraphId(this.paragraphIds),\n });\n this.cursor += 1;\n }\n this.parts.push(\"\\n\");\n const sectionBreaks: ISectionBreak[] = [\n ...this.sectionBreaks,\n {\n startIndex: this.cursor,\n sectionId: createSectionId(this.sectionIds),\n },\n ];\n this.cursor += 1;\n\n const id = cryptoRandomId();\n const drawingIds = Object.keys(this.drawings);\n for (const d of drawingIds) Object.assign(this.drawings[d]!, { unitId: id, subUnitId: id });\n return {\n id,\n locale: LocaleType.EN_US,\n title,\n body: {\n dataStream: this.parts.join(\"\"),\n paragraphs: this.paragraphs,\n textRuns: this.textRuns.sort((a, b) => a.st - b.st),\n sectionBreaks,\n ...(this.customRanges.length ? { customRanges: this.customRanges } : {}),\n ...(this.tables.length ? { tables: this.tables } : {}),\n ...(this.customBlocks.length ? { customBlocks: this.customBlocks } : {}),\n },\n ...(drawingIds.length\n ? { drawings: this.drawings as unknown as IDocumentData[\"drawings\"], drawingsOrder: drawingIds }\n : {}),\n ...(this.tables.length ? { tableSource: this.tableSource } : {}),\n documentStyle: defaultDocumentPageStyle(),\n } as Partial<IDocumentData>;\n }\n}\n\n// Univer's DataStreamTreeTokenType control characters (literals: this module is\n// also loaded where Univer's runtime is not).\nconst TABLE_START = \"\\x1A\";\nconst TABLE_ROW_START = \"\\x1B\";\nconst TABLE_CELL_START = \"\\x1C\";\nconst TABLE_CELL_END = \"\\x1D\";\nconst TABLE_ROW_END = \"\\x0E\";\nconst TABLE_END = \"\\x0F\";\nconst LINK_START = \"\\x1F\";\nconst LINK_END = \"\\x1E\";\nconst CUSTOM_BLOCK = \"\\b\";\n\n// ─── block helpers ───────────────────────────────────────────────────────────\n\n// THE GFM row rule (gfm-table-lines): an escaped `\\|` stays in its cell and\n// shows as `|` (the one cell-pipe rule), exactly as chat and Studio draw it.\nconst splitTableRow = (line: string): string[] => rowCells(line).map(unescapeCellPipes);\n\nfunction addTable(builder: DocBuilder, tableLines: string[]): void {\n const header = splitTableRow(tableLines[0]!);\n // tableLines[1] is the `---|---` separator — skip it.\n const body = tableLines\n .slice(2)\n .map(splitTableRow)\n .filter((r) => r.some((c) => c.length > 0));\n const toCells = (cells: string[]): Segment[][] => cells.map((cell) => parseInline(cell));\n builder.addTable([toCells(header), ...body.map(toCells)], true);\n}\n\n/**\n * Remove reasoning/thinking blocks so they never leak into the document.\n * Defensive — most callers pass already-flattened text, but a raw markdown\n * source could still carry `<think>` / `<thinking>` tags.\n */\nfunction stripThinking(markdown: string): string {\n return markdown\n .replace(/<think(?:ing)?>[\\s\\S]*?<\\/think(?:ing)?>/gi, \"\")\n .trim();\n}\n\nfunction cryptoRandomId(): string {\n if (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto) {\n return crypto.randomUUID();\n }\n return `doc-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n// ─── public API ──────────────────────────────────────────────────────────────\n\n/**\n * Convert markdown to a Univer `IDocumentData` snapshot. Pure — no I/O. Pass\n * the result straight to `saveDocumentSnapshot`.\n */\nexport function markdownToUniverDoc(\n markdown: string,\n title = \"Untitled document\",\n): Partial<IDocumentData> {\n const builder = new DocBuilder();\n const cleaned = stripThinking(markdown ?? \"\")\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\");\n const lines = cleaned.split(\"\\n\");\n // Fenced code by THE one code-range rule (@ai-matrx/content-ir/source).\n const kinds = fenceLineKinds(cleaned);\n\n let i = 0;\n let paragraphBuf: string[] = [];\n\n const flushParagraph = () => {\n if (paragraphBuf.length === 0) return;\n const text = paragraphBuf.join(\" \").trim();\n if (text) builder.addParagraph(parseInline(text));\n paragraphBuf = [];\n };\n\n while (i < lines.length) {\n const line = lines[i]!;\n const trimmed = line.trim();\n\n // Blank line — paragraph boundary.\n if (!trimmed) {\n flushParagraph();\n i++;\n continue;\n }\n\n // Fenced code block.\n if (kinds[i] === \"open\") {\n flushParagraph();\n i++;\n const code: string[] = [];\n while (i < lines.length && kinds[i] === \"body\") {\n code.push(lines[i]!);\n i++;\n }\n if (kinds[i] === \"close\") i++; // consume the closing fence\n for (const c of code) {\n builder.addParagraph([{ text: c.length ? c : \" \", code: true }], {\n mono: true,\n });\n }\n continue;\n }\n\n // ATX heading.\n const heading = trimmed.match(/^(#{1,6})\\s+(.*)$/);\n if (heading) {\n flushParagraph();\n builder.addParagraph(parseInline(heading[2]!.trim()), {\n heading: heading[1]!.length,\n });\n i++;\n continue;\n }\n\n // Horizontal rule.\n if (/^(\\s*[-*_]\\s*){3,}$/.test(trimmed) && /^[\\s\\-*_]+$/.test(trimmed)) {\n flushParagraph();\n builder.addParagraph([{ text: \"\\u2014\".repeat(24) }]);\n i++;\n continue;\n }\n\n // GFM table (THE rule, gfm-table-lines): a header — with or without edge\n // pipes — immediately followed by its delimiter row.\n if (tableStartsAt(lines, i)) {\n flushParagraph();\n const tableLines: string[] = [];\n const tableEnd = findTableEnd(lines, i);\n while (i < tableEnd) {\n tableLines.push(lines[i]!.trim());\n i++;\n }\n addTable(builder, tableLines);\n continue;\n }\n\n // Blockquote.\n const quote = trimmed.match(/^>\\s?(.*)$/);\n if (quote) {\n flushParagraph();\n builder.addParagraph(parseInline(quote[1]!), {});\n i++;\n continue;\n }\n\n // List item (ordered or unordered, with nesting by indent).\n const list = line.match(/^(\\s*)([-*+]|\\d+[.)])\\s+(.*)$/);\n if (list) {\n flushParagraph();\n const indent = list[1]!.replace(/\\t/g, \" \").length;\n const level = Math.min(Math.floor(indent / 2), 5);\n const ordered = /\\d/.test(list[2]!);\n const marker = ordered ? `${list[2]!.replace(/[.)]$/, \"\")}.` : \"\\u2022\";\n const prefix = `${\" \".repeat(level)}${marker} `;\n builder.addParagraph([{ text: prefix }, ...parseInline(list[3]!)]);\n i++;\n continue;\n }\n\n // Default — accumulate into the current paragraph.\n paragraphBuf.push(trimmed);\n i++;\n }\n\n flushParagraph();\n return builder.build(title);\n}\n\n/**\n * Derive a sensible document name from markdown: first heading, else first\n * non-empty line, trimmed of markdown syntax. Falls back to a dated default.\n */\nexport function deriveDocumentName(markdown: string): string {\n const cleaned = stripThinking(markdown ?? \"\");\n // First heading, else the first line — through the ONE plain-text title\n // projection (components/markdown-core/plain-title.ts).\n const lines = cleaned.split(\"\\n\");\n const heading = lines.find((l) => /^\\s{0,3}#{1,6}\\s+/.test(l));\n const plain = plainTitleFromMarkdown(heading ?? cleaned);\n if (!plain) {\n return `Document ${new Date().toLocaleDateString()}`;\n }\n return plainTitleFromMarkdown(plain, { maxLength: 80 });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-QZE7HBZB.cjs","../src/sheets/xlsx-to-univer.ts","../src/sheets/xlsx-to-univer-excel.ts","../src/sheets/xlsx-shared.ts"],"names":[],"mappings":"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","file":"/home/runner/work/aidream/aidream/apps/shared/office/dist/chunk-QZE7HBZB.cjs","sourcesContent":[null,"/**\n * xlsxToUniverWorkbook — parse a spreadsheet file into a Univer IWorkbookData\n * suitable for `apiRef.createWorkbook(...)` and for persistence as the initial\n * snapshot of a new workbook.\n *\n * ONE reader: ExcelJS (`xlsx-to-univer-excel`) holds styles, number formats,\n * widths, heights, frozen panes, merges, validation, conditional formatting,\n * filter range, notes, links and pictures. A file that is not already an\n * .xlsx (.xls, .ods, .csv, .tsv) is first re-written as an .xlsx by the\n * Alchemy workbook door — values, formulas and merges — and read by that same\n * reader, so there is no second import path to drift.\n */\n\nimport { readWorkbook } from \"@ai-matrx/alchemy/operate/read\";\nimport { writeWorkbookBytes } from \"@ai-matrx/alchemy/operate/formats/xlsx\";\nimport type { WorkbookJson } from \"@ai-matrx/alchemy/operate/read\";\nimport type { IWorkbookData } from \"@univerjs/core\";\nimport { importXlsxWithExcelJs, type XlsxImportOptions } from \"./xlsx-to-univer-excel\";\n\n/** A legacy or text spreadsheet as .xlsx bytes (values, formulas, merges). */\nasync function legacyToXlsxBytes(file: File): Promise<ArrayBuffer> {\n const wb = await readWorkbook(file, { dates: true, formulas: true });\n const json: WorkbookJson = {\n sheets: wb.sheets.map((ws) => {\n const range = ws.range ?? { s: { r: 0, c: 0 }, e: { r: -1, c: -1 } };\n const rows: WorkbookJson[\"sheets\"][number][\"rows\"] = [];\n for (let r = 0; r <= range.e.r; r++) {\n const row: WorkbookJson[\"sheets\"][number][\"rows\"][number] = [];\n for (let c = 0; c <= range.e.c; c++) {\n const cell = ws.cell(r, c);\n if (!cell || cell.v === undefined || cell.v === null) {\n row.push(null);\n continue;\n }\n const v = cell.v instanceof Date ? cell.v.toISOString().slice(0, 10) : cell.v;\n if (cell.f) row.push({ v: typeof v === \"boolean\" || typeof v === \"number\" ? v : String(v), f: cell.f.replace(/^=/, \"\") });\n else row.push(v);\n }\n rows.push(row);\n }\n return { name: ws.name.slice(0, 31) || \"Sheet1\", rows, merges: ws.merges };\n }),\n };\n const bytes = await writeWorkbookBytes(json);\n return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;\n}\n\n/**\n * Parse a spreadsheet file into a Univer workbook. Whatever could not be\n * carried is reported through `options.onDropped` (the caller tells the person).\n */\nexport async function xlsxToUniverWorkbook(\n file: File,\n options: XlsxImportOptions = {},\n): Promise<Partial<IWorkbookData>> {\n if (/\\.xlsx$/i.test(file.name)) return importXlsxWithExcelJs(file, options);\n const data = await legacyToXlsxBytes(file);\n return importXlsxWithExcelJs({ name: file.name, arrayBuffer: async () => data }, options);\n}\n","/**\n * Full-fidelity .xlsx -> Univer reader (ExcelJS). The inverse of\n * `univer-to-xlsx.ts`: styles, number formats, column widths, row heights,\n * frozen panes, merges, data validation, conditional formatting, the filter\n * range, notes, cell links and pictures. Free of Univer runtime imports (enums\n * are numbers) so it runs under tests as well as in the browser.\n */\n\nimport type { IWorkbookData } from \"@univerjs/core\";\nimport { loadExcelJs, type ExcelJSTypes } from \"@ai-matrx/print/xlsx-styled\";\nimport {\n H_ALIGN_IN,\n RESOURCE,\n V_ALIGN_IN,\n argbToColor,\n borderFromExcel,\n colCharsToPx,\n parseA1Range,\n rowPtToPx,\n writeResource,\n type RangeLike,\n type UniverResource,\n} from \"./xlsx-shared\";\n\nexport type XlsxImportOptions = {\n /** Stores a picture and returns its file id; without it pictures are reported, not imported. */\n uploadImage?: (bytes: Uint8Array, extension: string) => Promise<string>;\n /** Called once per thing the file held that could not be carried. */\n onDropped?: (what: string) => void;\n};\n\ntype Json = Record<string, any>; // eslint-disable-line @typescript-eslint/no-explicit-any -- Univer resource payloads are untyped JSON\n\nconst THEME = [\"FFFFFF\", \"000000\", \"E7E6E6\", \"44546A\", \"4472C4\", \"ED7D31\", \"A5A5A5\", \"FFC000\", \"5B9BD5\", \"70AD47\"];\nconst colorOf = (c: Partial<ExcelJSTypes.Color> | undefined): string | undefined =>\n c?.argb ? argbToColor(c.argb) : typeof c?.theme === \"number\" && THEME[c.theme] ? `#${THEME[c.theme]!.toLowerCase()}` : undefined;\n\nconst rid = (prefix: string) => `${prefix}${Math.random().toString(36).slice(2, 10)}`;\nconst sheetId = (name: string) => `${name.replace(/[^A-Za-z0-9_-]+/g, \"-\").slice(0, 32) || \"sheet\"}-${Math.random().toString(36).slice(2, 8)}`;\n\nexport async function importXlsxWithExcelJs(\n file: { name: string; arrayBuffer(): Promise<ArrayBuffer> },\n options: XlsxImportOptions = {},\n): Promise<Partial<IWorkbookData>> {\n const ExcelJS = await loadExcelJs();\n const wb = new ExcelJS.Workbook();\n await wb.xlsx.load(await file.arrayBuffer());\n\n const dropped = new Set<string>();\n const styles: Record<string, Json> = {};\n const styleIds = new Map<string, string>();\n const styleId = (st: Json): string => {\n const key = JSON.stringify(st);\n let id = styleIds.get(key);\n if (!id) {\n id = `s${styleIds.size + 1}`;\n styleIds.set(key, id);\n styles[id] = st;\n }\n return id;\n };\n\n const sheets: Record<string, Json> = {};\n const sheetOrder: string[] = [];\n const resources: UniverResource[] = [];\n const validation: Json = {};\n const conditional: Json = {};\n const filters: Json = {};\n const notes: Json = {};\n const drawings: Json = {};\n const unitId = `wb-${rid(\"\")}`;\n\n for (const ws of wb.worksheets) {\n const id = sheetId(ws.name);\n sheetOrder.push(id);\n const cellData: Record<number, Record<number, Json>> = {};\n let maxR = 0;\n let maxC = 0;\n const sheetNotes: Json = {};\n\n ws.eachRow({ includeEmpty: false }, (row, rowNumber) => {\n row.eachCell({ includeEmpty: false }, (cell, colNumber) => {\n const r = rowNumber - 1;\n const c = colNumber - 1;\n const out = toCell(cell, styleId);\n if (out) {\n (cellData[r] ??= {})[c] = out;\n maxR = Math.max(maxR, r);\n maxC = Math.max(maxC, c);\n }\n const note = cell.note;\n const text = typeof note === \"string\" ? note : (note as Json | undefined)?.texts?.map((t: Json) => t.text).join(\"\");\n if (text) {\n ((sheetNotes[r] ??= {}) as Json)[c] = { id: rid(\"n\"), row: r, col: c, width: 160, height: 72, note: text, show: false };\n }\n });\n });\n if (Object.keys(sheetNotes).length) notes[id] = sheetNotes;\n\n const sheet: Json = {\n id,\n name: ws.name.slice(0, 31),\n cellData,\n rowCount: Math.max(maxR + 1, ws.rowCount, 100),\n columnCount: Math.max(maxC + 1, ws.columnCount, 26),\n };\n\n const tab = colorOf(ws.properties?.tabColor);\n if (tab) sheet.tabColor = tab;\n\n const merges = (ws.model as Json).merges as string[] | undefined;\n const mergeData = (merges ?? []).map((m) => parseA1Range(m)).filter((m): m is RangeLike => !!m);\n if (mergeData.length) {\n sheet.mergeData = mergeData;\n sheet.rowCount = Math.max(sheet.rowCount, ...mergeData.map((m) => m.endRow + 1));\n sheet.columnCount = Math.max(sheet.columnCount, ...mergeData.map((m) => m.endColumn + 1));\n }\n\n const columnData: Json = {};\n for (let c = 1; c <= Math.min(ws.columnCount, 2000); c++) {\n const col = ws.getColumn(c);\n if (typeof col.width === \"number\" || col.hidden) {\n columnData[c - 1] = {\n ...(typeof col.width === \"number\" ? { w: colCharsToPx(col.width) } : {}),\n ...(col.hidden ? { hd: 1 } : {}),\n };\n }\n }\n if (Object.keys(columnData).length) sheet.columnData = columnData;\n\n const rowData: Json = {};\n ws.eachRow({ includeEmpty: true }, (row, n) => {\n if (typeof row.height === \"number\" || row.hidden) {\n rowData[n - 1] = {\n ...(typeof row.height === \"number\" ? { h: rowPtToPx(row.height), hd: row.hidden ? 1 : 0 } : { hd: 1 }),\n };\n }\n });\n if (Object.keys(rowData).length) sheet.rowData = rowData;\n\n const view = ws.views?.[0] as Json | undefined;\n if (view?.state === \"frozen\" && (view.xSplit || view.ySplit)) {\n sheet.freeze = {\n xSplit: view.xSplit ?? 0,\n ySplit: view.ySplit ?? 0,\n startColumn: view.xSplit ?? 0,\n startRow: view.ySplit ?? 0,\n };\n }\n\n // ── data validation\n const dvModel = ((ws as Json).dataValidations as Json | undefined)?.model as Record<string, Json> | undefined;\n const rules = dataValidationRules(dvModel ?? {});\n if (rules.length) validation[id] = rules;\n\n // ── conditional formatting\n const cf = conditionalRules(((ws as Json).conditionalFormattings ?? []) as Json[], dropped);\n if (cf.length) conditional[id] = cf;\n\n // ── filter range\n const af = ws.autoFilter as ExcelJSTypes.AutoFilter | undefined;\n if (af) {\n const range =\n typeof af === \"string\"\n ? parseA1Range(af)\n : af.from && af.to\n ? {\n startRow: (af.from as Json).row - 1,\n startColumn: (af.from as Json).column - 1,\n endRow: (af.to as Json).row - 1,\n endColumn: (af.to as Json).column - 1,\n }\n : null;\n if (range) filters[id] = { ref: range, filterColumns: [] };\n }\n\n // ── pictures\n const images = ws.getImages();\n if (images.length) {\n if (!options.uploadImage) {\n dropped.add(\"Pictures in the file were not imported\");\n } else {\n const data: Record<string, Json> = {};\n const order: string[] = [];\n for (const img of images) {\n try {\n const media = wb.getImage(Number(img.imageId)) as Json;\n const bytes = new Uint8Array(media.buffer as ArrayBuffer);\n const fileId = await options.uploadImage(bytes, String(media.extension ?? \"png\"));\n const tl = img.range.tl as Json;\n const ext = (img.range as Json).ext as Json | undefined;\n const br = img.range.br as Json | undefined;\n const width = ext?.width ?? ((br?.nativeCol ?? tl.nativeCol + 3) - tl.nativeCol) * 88;\n const height = ext?.height ?? ((br?.nativeRow ?? tl.nativeRow + 6) - tl.nativeRow) * 24;\n const drawingId = rid(\"img\");\n const column = Math.floor(tl.nativeCol ?? tl.col);\n const rowIdx = Math.floor(tl.nativeRow ?? tl.row);\n data[drawingId] = {\n unitId,\n subUnitId: id,\n drawingId,\n drawingType: 0,\n imageSourceType: \"URL\",\n source: `matrx-file:${fileId}`,\n transform: { left: column * 88, top: rowIdx * 24, width, height, angle: 0 },\n sheetTransform: {\n from: { column, columnOffset: 0, row: rowIdx, rowOffset: 0 },\n to: { column: column + Math.max(1, Math.round(width / 88)), columnOffset: 0, row: rowIdx + Math.max(1, Math.round(height / 24)), rowOffset: 0 },\n },\n };\n order.push(drawingId);\n } catch {\n dropped.add(\"Some pictures could not be stored and were left out\");\n }\n }\n if (order.length) drawings[id] = { data, order };\n }\n }\n\n if ((ws.getTables?.() ?? []).length) dropped.add(\"Excel tables became plain ranges (their data and styling are kept)\");\n sheets[id] = sheet;\n }\n\n if (Object.keys(validation).length) writeResource(resources, RESOURCE.validation, validation);\n if (Object.keys(conditional).length) writeResource(resources, RESOURCE.conditional, conditional);\n if (Object.keys(filters).length) writeResource(resources, RESOURCE.filter, filters);\n if (Object.keys(notes).length) writeResource(resources, RESOURCE.note, notes);\n if (Object.keys(drawings).length) writeResource(resources, RESOURCE.drawing, drawings);\n\n for (const d of dropped) options.onDropped?.(d);\n\n return {\n id: unitId,\n sheetOrder,\n name: file.name.replace(/\\.[^.]+$/, \"\"),\n appVersion: \"1\",\n locale: \"enUS\" as IWorkbookData[\"locale\"],\n styles,\n sheets,\n resources,\n } as Partial<IWorkbookData>;\n}\n\nfunction toStyle(cell: ExcelJSTypes.Cell): Json | undefined {\n const st: Json = {};\n const f = cell.font;\n if (f) {\n if (f.name) st.ff = f.name;\n if (f.size) st.fs = f.size;\n if (f.bold) st.bl = 1;\n if (f.italic) st.it = 1;\n if (f.underline) st.ul = { s: 1 };\n if (f.strike) st.st = { s: 1 };\n const cl = colorOf(f.color);\n if (cl) st.cl = { rgb: cl };\n }\n const fill = cell.fill as Json | undefined;\n if (fill?.type === \"pattern\" && fill.pattern === \"solid\") {\n const bg = colorOf(fill.fgColor);\n if (bg) st.bg = { rgb: bg };\n }\n const al = cell.alignment;\n if (al) {\n if (al.horizontal && H_ALIGN_IN[al.horizontal]) st.ht = H_ALIGN_IN[al.horizontal];\n if (al.vertical && V_ALIGN_IN[al.vertical]) st.vt = V_ALIGN_IN[al.vertical];\n if (al.wrapText) st.tb = 3;\n }\n const bd = cell.border as Json | undefined;\n if (bd) {\n const out: Json = {};\n for (const [side, key] of [[\"top\", \"t\"], [\"bottom\", \"b\"], [\"left\", \"l\"], [\"right\", \"r\"]] as const) {\n const s = borderFromExcel(bd[side]?.style);\n if (s) out[key] = { s, cl: { rgb: colorOf(bd[side]?.color) ?? \"#000000\" } };\n }\n if (Object.keys(out).length) st.bd = out;\n }\n if (cell.numFmt && cell.numFmt !== \"General\") st.n = { pattern: cell.numFmt };\n return Object.keys(st).length ? st : undefined;\n}\n\nconst EXCEL_EPOCH_OFFSET_DAYS = 25569;\n\nfunction toCell(cell: ExcelJSTypes.Cell, styleId: (s: Json) => string): Json | null {\n const out: Json = {};\n let st = toStyle(cell);\n const v = cell.value as unknown;\n const setNumber = (n: number) => {\n out.v = n;\n out.t = 2;\n };\n const apply = (value: unknown) => {\n if (value instanceof Date) {\n setNumber(value.getTime() / 86_400_000 + EXCEL_EPOCH_OFFSET_DAYS);\n st = { ...(st ?? {}), n: (st?.n as Json | undefined) ?? { pattern: \"yyyy-mm-dd\" } };\n } else if (typeof value === \"number\") setNumber(value);\n else if (typeof value === \"boolean\") {\n out.v = value ? 1 : 0;\n out.t = 3;\n } else if (typeof value === \"string\") {\n out.v = value;\n out.t = 1;\n } else if (value && typeof value === \"object\" && \"error\" in (value as Json)) {\n out.v = String((value as Json).error);\n out.t = 1;\n }\n };\n if (v && typeof v === \"object\" && !(v instanceof Date)) {\n const o = v as Json;\n if (\"formula\" in o || \"sharedFormula\" in o) {\n const f = o.formula ?? o.sharedFormula;\n if (f) out.f = `=${String(f).replace(/^=/, \"\")}`;\n apply(o.result);\n } else if (Array.isArray(o.richText)) {\n apply(o.richText.map((r: Json) => r.text).join(\"\"));\n } else if (\"hyperlink\" in o) {\n const text = String(typeof o.text === \"object\" ? (o.text?.richText ?? []).map((r: Json) => r.text).join(\"\") : (o.text ?? o.hyperlink));\n out.v = text;\n out.t = 1;\n out.p = linkDoc(text, String(o.hyperlink));\n } else apply(o);\n } else {\n apply(v);\n }\n if (st) out.s = styleId(st);\n return out.v === undefined && out.f === undefined && !out.s ? null : out;\n}\n\nfunction linkDoc(text: string, url: string): Json {\n return {\n id: \"d\",\n documentStyle: {},\n body: {\n dataStream: `${text}\\r\\n`,\n textRuns: [],\n paragraphs: [{ startIndex: text.length }],\n customRanges: [\n { startIndex: 0, endIndex: Math.max(0, text.length - 1), rangeId: rid(\"link\"), rangeType: 0, properties: { url } },\n ],\n },\n };\n}\n\nfunction dataValidationRules(model: Record<string, Json>): Json[] {\n const groups = new Map<string, { rule: Json; cells: [number, number][] }>();\n for (const [ref, dv] of Object.entries(model)) {\n const pos = parseA1Range(ref);\n if (!pos) continue;\n const type = String(dv.type);\n const rule: Json = {\n allowBlank: dv.allowBlank !== false,\n showErrorMessage: dv.showErrorMessage !== false,\n ...(dv.error ? { error: dv.error } : {}),\n ...(dv.errorTitle ? { errorTitle: dv.errorTitle } : {}),\n ...(dv.prompt ? { prompt: dv.prompt, showInputMessage: true } : {}),\n };\n const f = (dv.formulae ?? []) as unknown[];\n if (type === \"list\") {\n const raw = String(f[0] ?? \"\");\n const literal = /^\"(.*)\"$/.exec(raw);\n Object.assign(rule, { type: \"list\", formula1: literal ? literal[1] : raw, formula2: \"\", showDropDown: true });\n } else if ([\"whole\", \"decimal\", \"date\", \"time\", \"textLength\"].includes(type)) {\n Object.assign(rule, { type, operator: dv.operator ?? \"between\", formula1: String(f[0] ?? \"\"), formula2: f[1] !== undefined ? String(f[1]) : \"\" });\n } else if (type === \"custom\") {\n Object.assign(rule, { type: \"custom\", formula1: String(f[0] ?? \"\") });\n } else continue;\n const key = JSON.stringify(rule);\n const g = groups.get(key) ?? { rule, cells: [] };\n g.cells.push([pos.startRow, pos.startColumn]);\n groups.set(key, g);\n }\n return [...groups.values()].map(({ rule, cells }) => ({ uid: rid(\"dv\"), ...rule, ranges: compressCells(cells) }));\n}\n\n/** Single cells -> the fewest vertical runs. */\nfunction compressCells(cells: [number, number][]): RangeLike[] {\n const sorted = [...cells].sort((a, b) => a[1] - b[1] || a[0] - b[0]);\n const out: RangeLike[] = [];\n for (const [r, c] of sorted) {\n const last = out[out.length - 1];\n if (last && last.startColumn === c && last.endColumn === c && last.endRow === r - 1) last.endRow = r;\n else out.push({ startRow: r, endRow: r, startColumn: c, endColumn: c });\n }\n return out;\n}\n\nfunction dxfToStyle(style: Json | undefined): Json {\n const out: Json = {};\n const fg = colorOf(style?.font?.color);\n if (fg) out.cl = { rgb: fg };\n if (style?.font?.bold) out.bl = 1;\n if (style?.font?.italic) out.it = 1;\n const bg = colorOf(style?.fill?.bgColor) ?? colorOf(style?.fill?.fgColor);\n if (bg) out.bg = { rgb: bg };\n return out;\n}\n\nfunction conditionalRules(formats: Json[], dropped: Set<string>): Json[] {\n const out: Json[] = [];\n for (const cf of formats) {\n const ranges = String(cf.ref ?? \"\").split(/\\s+/).map((r) => parseA1Range(r)).filter((r): r is RangeLike => !!r);\n if (!ranges.length) continue;\n for (const rule of (cf.rules ?? []) as Json[]) {\n let mapped: Json | null = null;\n const style = dxfToStyle(rule.style);\n if (rule.type === \"cellIs\") {\n const nums = ((rule.formulae ?? []) as unknown[]).map(Number);\n const between = rule.operator === \"between\" || rule.operator === \"notBetween\";\n mapped = { type: \"highlightCell\", subType: \"number\", operator: rule.operator, value: between ? nums.slice(0, 2) : nums[0], style };\n } else if (rule.type === \"containsText\") {\n mapped = { type: \"highlightCell\", subType: \"text\", operator: \"containsText\", value: String(rule.text ?? \"\"), style };\n } else if (rule.type === \"expression\") {\n mapped = { type: \"highlightCell\", subType: \"formula\", value: `=${String((rule.formulae ?? [])[0] ?? \"\")}`, style };\n } else if (rule.type === \"colorScale\") {\n mapped = {\n type: \"colorScale\",\n config: ((rule.cfvo ?? []) as Json[]).map((v, i) => ({\n index: i,\n color: colorOf(rule.color?.[i]) ?? \"#ffffff\",\n value: { type: v.type, ...(v.value !== undefined ? { value: v.value } : {}) },\n })),\n };\n } else if (rule.type === \"dataBar\") {\n const [min, max] = (rule.cfvo ?? []) as Json[];\n mapped = {\n type: \"dataBar\",\n isShowValue: true,\n config: {\n min: { type: min?.type ?? \"min\" },\n max: { type: max?.type ?? \"max\" },\n isGradient: rule.gradient !== false,\n positiveColor: colorOf(rule.color) ?? \"#638ec6\",\n nativeColor: \"#ff0000\",\n },\n };\n }\n if (!mapped) {\n dropped.add(\"Some conditional formats (icon sets, top/bottom, date rules) were not imported\");\n continue;\n }\n out.push({ cfId: rid(\"cf\"), ranges, stopIfTrue: Boolean(rule.stopIfTrue), rule: mapped });\n }\n }\n return out;\n}\n","/**\n * Shared vocabulary between the xlsx importer and exporter: how Univer's\n * style numbers, colours and units map to the xlsx file's.\n *\n * Univer enums are written as numbers here so these helpers stay free of any\n * Univer import (they run in tests and in both directions).\n */\n\nexport const RESOURCE = {\n validation: \"SHEET_DATA_VALIDATION_PLUGIN\",\n conditional: \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\",\n filter: \"SHEET_FILTER_PLUGIN\",\n note: \"SHEET_NOTE_PLUGIN\",\n comments: \"SHEET_UNIVER_THREAD_COMMENT_PLUGIN\",\n drawing: \"SHEET_DRAWING_PLUGIN\",\n table: \"SHEET_TABLE_PLUGIN\",\n} as const;\n\nexport type UniverResource = { name: string; data: string };\n\nexport function readResource<T = unknown>(\n resources: readonly UniverResource[] | undefined,\n name: string,\n): T | undefined {\n const raw = resources?.find((r) => r.name === name)?.data;\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return undefined;\n }\n}\n\nexport function writeResource(resources: UniverResource[], name: string, value: unknown): void {\n const i = resources.findIndex((r) => r.name === name);\n const entry = { name, data: JSON.stringify(value) };\n if (i >= 0) resources[i] = entry;\n else resources.push(entry);\n}\n\n/** Excel column width (characters) <-> Univer pixels. */\nexport const colPxToChars = (px: number): number => Math.max(0, Math.round((px / 7) * 100) / 100);\nexport const colCharsToPx = (chars: number): number => Math.round(chars * 7);\n/** Excel row height (points) <-> Univer pixels. */\nexport const rowPxToPt = (px: number): number => Math.round(px * 0.75 * 100) / 100;\nexport const rowPtToPx = (pt: number): number => Math.round((pt / 0.75) * 100) / 100;\n\n/** Univer colour (\"#rrggbb\", \"rgb(r,g,b)\", \"rgba(...)\") -> ARGB hex, or undefined. */\nexport function colorToArgb(input: string | undefined | null): string | undefined {\n if (!input) return undefined;\n const s = input.trim();\n const hex = /^#?([0-9a-f]{6})$/i.exec(s);\n if (hex) return `FF${hex[1]!.toUpperCase()}`;\n const short = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(s);\n if (short) return `FF${short[1]}${short[1]}${short[2]}${short[2]}${short[3]}${short[3]}`.toUpperCase();\n const rgb = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i.exec(s);\n if (rgb) {\n const h = (n: string) => Number(n).toString(16).padStart(2, \"0\");\n return `FF${h(rgb[1]!)}${h(rgb[2]!)}${h(rgb[3]!)}`.toUpperCase();\n }\n return undefined;\n}\n\n/** ARGB (or RGB) hex from a file -> Univer \"#rrggbb\". */\nexport function argbToColor(argb: string | undefined | null): string | undefined {\n if (!argb) return undefined;\n const v = argb.replace(/^#/, \"\");\n if (v.length === 8) return `#${v.slice(2).toLowerCase()}`;\n if (v.length === 6) return `#${v.toLowerCase()}`;\n return undefined;\n}\n\n// Univer BorderStyleTypes number <-> ExcelJS border style name.\nconst BORDER_OUT: Record<number, string> = {\n 1: \"thin\", 2: \"hair\", 3: \"dotted\", 4: \"dashed\", 5: \"dashDot\", 6: \"dashDotDot\", 7: \"double\",\n 8: \"medium\", 9: \"mediumDashed\", 10: \"mediumDashDot\", 11: \"mediumDashDotDot\", 12: \"slantDashDot\", 13: \"thick\",\n};\nexport const borderToExcel = (n: number | undefined): string | undefined =>\n n === undefined ? undefined : BORDER_OUT[n];\nexport const borderFromExcel = (name: string | undefined): number | undefined => {\n if (!name) return undefined;\n const hit = Object.entries(BORDER_OUT).find(([, v]) => v === name);\n return hit ? Number(hit[0]) : undefined;\n};\n\nexport const H_ALIGN_OUT: Record<number, string> = { 1: \"left\", 2: \"center\", 3: \"right\", 4: \"justify\", 5: \"justify\", 6: \"distributed\" };\nexport const V_ALIGN_OUT: Record<number, string> = { 1: \"top\", 2: \"middle\", 3: \"bottom\" };\nexport const H_ALIGN_IN: Record<string, number> = { left: 1, center: 2, right: 3, justify: 4, fill: 1, centerContinuous: 2, distributed: 6 };\nexport const V_ALIGN_IN: Record<string, number> = { top: 1, middle: 2, bottom: 3, distributed: 2, justify: 2 };\n\n/** 0-based (row, col) -> \"A1\" (no $). */\nexport function a1(row: number, col: number): string {\n let n = col + 1;\n let letters = \"\";\n while (n > 0) {\n const m = (n - 1) % 26;\n letters = String.fromCharCode(65 + m) + letters;\n n = Math.floor((n - 1) / 26);\n }\n return `${letters}${row + 1}`;\n}\n\nexport type RangeLike = { startRow: number; endRow: number; startColumn: number; endColumn: number };\nexport const rangeToA1 = (r: RangeLike): string =>\n r.startRow === r.endRow && r.startColumn === r.endColumn\n ? a1(r.startRow, r.startColumn)\n : `${a1(r.startRow, r.startColumn)}:${a1(r.endRow, r.endColumn)}`;\n\n/** \"A1\" or \"A1:C5\" -> range (0-based), or null. */\nexport function parseA1Range(ref: string): RangeLike | null {\n const m = /^\\$?([A-Z]+)\\$?(\\d+)(?::\\$?([A-Z]+)\\$?(\\d+))?$/i.exec(ref.trim());\n if (!m) return null;\n const col = (s: string) => [...s.toUpperCase()].reduce((acc, ch) => acc * 26 + ch.charCodeAt(0) - 64, 0) - 1;\n const sc = col(m[1]!);\n const sr = Number(m[2]!) - 1;\n return { startRow: sr, startColumn: sc, endRow: m[4] ? Number(m[4]) - 1 : sr, endColumn: m[3] ? col(m[3]) : sc };\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/_work/aidream/aidream/apps/shared/office/dist/chunk-QZE7HBZB.cjs","../src/sheets/xlsx-to-univer.ts","../src/sheets/xlsx-to-univer-excel.ts","../src/sheets/xlsx-shared.ts"],"names":[],"mappings":"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","file":"/home/runner/_work/aidream/aidream/apps/shared/office/dist/chunk-QZE7HBZB.cjs","sourcesContent":[null,"/**\n * xlsxToUniverWorkbook — parse a spreadsheet file into a Univer IWorkbookData\n * suitable for `apiRef.createWorkbook(...)` and for persistence as the initial\n * snapshot of a new workbook.\n *\n * ONE reader: ExcelJS (`xlsx-to-univer-excel`) holds styles, number formats,\n * widths, heights, frozen panes, merges, validation, conditional formatting,\n * filter range, notes, links and pictures. A file that is not already an\n * .xlsx (.xls, .ods, .csv, .tsv) is first re-written as an .xlsx by the\n * Alchemy workbook door — values, formulas and merges — and read by that same\n * reader, so there is no second import path to drift.\n */\n\nimport { readWorkbook } from \"@ai-matrx/alchemy/operate/read\";\nimport { writeWorkbookBytes } from \"@ai-matrx/alchemy/operate/formats/xlsx\";\nimport type { WorkbookJson } from \"@ai-matrx/alchemy/operate/read\";\nimport type { IWorkbookData } from \"@univerjs/core\";\nimport { importXlsxWithExcelJs, type XlsxImportOptions } from \"./xlsx-to-univer-excel\";\n\n/** A legacy or text spreadsheet as .xlsx bytes (values, formulas, merges). */\nasync function legacyToXlsxBytes(file: File): Promise<ArrayBuffer> {\n const wb = await readWorkbook(file, { dates: true, formulas: true });\n const json: WorkbookJson = {\n sheets: wb.sheets.map((ws) => {\n const range = ws.range ?? { s: { r: 0, c: 0 }, e: { r: -1, c: -1 } };\n const rows: WorkbookJson[\"sheets\"][number][\"rows\"] = [];\n for (let r = 0; r <= range.e.r; r++) {\n const row: WorkbookJson[\"sheets\"][number][\"rows\"][number] = [];\n for (let c = 0; c <= range.e.c; c++) {\n const cell = ws.cell(r, c);\n if (!cell || cell.v === undefined || cell.v === null) {\n row.push(null);\n continue;\n }\n const v = cell.v instanceof Date ? cell.v.toISOString().slice(0, 10) : cell.v;\n if (cell.f) row.push({ v: typeof v === \"boolean\" || typeof v === \"number\" ? v : String(v), f: cell.f.replace(/^=/, \"\") });\n else row.push(v);\n }\n rows.push(row);\n }\n return { name: ws.name.slice(0, 31) || \"Sheet1\", rows, merges: ws.merges };\n }),\n };\n const bytes = await writeWorkbookBytes(json);\n return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;\n}\n\n/**\n * Parse a spreadsheet file into a Univer workbook. Whatever could not be\n * carried is reported through `options.onDropped` (the caller tells the person).\n */\nexport async function xlsxToUniverWorkbook(\n file: File,\n options: XlsxImportOptions = {},\n): Promise<Partial<IWorkbookData>> {\n if (/\\.xlsx$/i.test(file.name)) return importXlsxWithExcelJs(file, options);\n const data = await legacyToXlsxBytes(file);\n return importXlsxWithExcelJs({ name: file.name, arrayBuffer: async () => data }, options);\n}\n","/**\n * Full-fidelity .xlsx -> Univer reader (ExcelJS). The inverse of\n * `univer-to-xlsx.ts`: styles, number formats, column widths, row heights,\n * frozen panes, merges, data validation, conditional formatting, the filter\n * range, notes, cell links and pictures. Free of Univer runtime imports (enums\n * are numbers) so it runs under tests as well as in the browser.\n */\n\nimport type { IWorkbookData } from \"@univerjs/core\";\nimport { loadExcelJs, type ExcelJSTypes } from \"@ai-matrx/print/xlsx-styled\";\nimport {\n H_ALIGN_IN,\n RESOURCE,\n V_ALIGN_IN,\n argbToColor,\n borderFromExcel,\n colCharsToPx,\n parseA1Range,\n rowPtToPx,\n writeResource,\n type RangeLike,\n type UniverResource,\n} from \"./xlsx-shared\";\n\nexport type XlsxImportOptions = {\n /** Stores a picture and returns its file id; without it pictures are reported, not imported. */\n uploadImage?: (bytes: Uint8Array, extension: string) => Promise<string>;\n /** Called once per thing the file held that could not be carried. */\n onDropped?: (what: string) => void;\n};\n\ntype Json = Record<string, any>; // eslint-disable-line @typescript-eslint/no-explicit-any -- Univer resource payloads are untyped JSON\n\nconst THEME = [\"FFFFFF\", \"000000\", \"E7E6E6\", \"44546A\", \"4472C4\", \"ED7D31\", \"A5A5A5\", \"FFC000\", \"5B9BD5\", \"70AD47\"];\nconst colorOf = (c: Partial<ExcelJSTypes.Color> | undefined): string | undefined =>\n c?.argb ? argbToColor(c.argb) : typeof c?.theme === \"number\" && THEME[c.theme] ? `#${THEME[c.theme]!.toLowerCase()}` : undefined;\n\nconst rid = (prefix: string) => `${prefix}${Math.random().toString(36).slice(2, 10)}`;\nconst sheetId = (name: string) => `${name.replace(/[^A-Za-z0-9_-]+/g, \"-\").slice(0, 32) || \"sheet\"}-${Math.random().toString(36).slice(2, 8)}`;\n\nexport async function importXlsxWithExcelJs(\n file: { name: string; arrayBuffer(): Promise<ArrayBuffer> },\n options: XlsxImportOptions = {},\n): Promise<Partial<IWorkbookData>> {\n const ExcelJS = await loadExcelJs();\n const wb = new ExcelJS.Workbook();\n await wb.xlsx.load(await file.arrayBuffer());\n\n const dropped = new Set<string>();\n const styles: Record<string, Json> = {};\n const styleIds = new Map<string, string>();\n const styleId = (st: Json): string => {\n const key = JSON.stringify(st);\n let id = styleIds.get(key);\n if (!id) {\n id = `s${styleIds.size + 1}`;\n styleIds.set(key, id);\n styles[id] = st;\n }\n return id;\n };\n\n const sheets: Record<string, Json> = {};\n const sheetOrder: string[] = [];\n const resources: UniverResource[] = [];\n const validation: Json = {};\n const conditional: Json = {};\n const filters: Json = {};\n const notes: Json = {};\n const drawings: Json = {};\n const unitId = `wb-${rid(\"\")}`;\n\n for (const ws of wb.worksheets) {\n const id = sheetId(ws.name);\n sheetOrder.push(id);\n const cellData: Record<number, Record<number, Json>> = {};\n let maxR = 0;\n let maxC = 0;\n const sheetNotes: Json = {};\n\n ws.eachRow({ includeEmpty: false }, (row, rowNumber) => {\n row.eachCell({ includeEmpty: false }, (cell, colNumber) => {\n const r = rowNumber - 1;\n const c = colNumber - 1;\n const out = toCell(cell, styleId);\n if (out) {\n (cellData[r] ??= {})[c] = out;\n maxR = Math.max(maxR, r);\n maxC = Math.max(maxC, c);\n }\n const note = cell.note;\n const text = typeof note === \"string\" ? note : (note as Json | undefined)?.texts?.map((t: Json) => t.text).join(\"\");\n if (text) {\n ((sheetNotes[r] ??= {}) as Json)[c] = { id: rid(\"n\"), row: r, col: c, width: 160, height: 72, note: text, show: false };\n }\n });\n });\n if (Object.keys(sheetNotes).length) notes[id] = sheetNotes;\n\n const sheet: Json = {\n id,\n name: ws.name.slice(0, 31),\n cellData,\n rowCount: Math.max(maxR + 1, ws.rowCount, 100),\n columnCount: Math.max(maxC + 1, ws.columnCount, 26),\n };\n\n const tab = colorOf(ws.properties?.tabColor);\n if (tab) sheet.tabColor = tab;\n\n const merges = (ws.model as Json).merges as string[] | undefined;\n const mergeData = (merges ?? []).map((m) => parseA1Range(m)).filter((m): m is RangeLike => !!m);\n if (mergeData.length) {\n sheet.mergeData = mergeData;\n sheet.rowCount = Math.max(sheet.rowCount, ...mergeData.map((m) => m.endRow + 1));\n sheet.columnCount = Math.max(sheet.columnCount, ...mergeData.map((m) => m.endColumn + 1));\n }\n\n const columnData: Json = {};\n for (let c = 1; c <= Math.min(ws.columnCount, 2000); c++) {\n const col = ws.getColumn(c);\n if (typeof col.width === \"number\" || col.hidden) {\n columnData[c - 1] = {\n ...(typeof col.width === \"number\" ? { w: colCharsToPx(col.width) } : {}),\n ...(col.hidden ? { hd: 1 } : {}),\n };\n }\n }\n if (Object.keys(columnData).length) sheet.columnData = columnData;\n\n const rowData: Json = {};\n ws.eachRow({ includeEmpty: true }, (row, n) => {\n if (typeof row.height === \"number\" || row.hidden) {\n rowData[n - 1] = {\n ...(typeof row.height === \"number\" ? { h: rowPtToPx(row.height), hd: row.hidden ? 1 : 0 } : { hd: 1 }),\n };\n }\n });\n if (Object.keys(rowData).length) sheet.rowData = rowData;\n\n const view = ws.views?.[0] as Json | undefined;\n if (view?.state === \"frozen\" && (view.xSplit || view.ySplit)) {\n sheet.freeze = {\n xSplit: view.xSplit ?? 0,\n ySplit: view.ySplit ?? 0,\n startColumn: view.xSplit ?? 0,\n startRow: view.ySplit ?? 0,\n };\n }\n\n // ── data validation\n const dvModel = ((ws as Json).dataValidations as Json | undefined)?.model as Record<string, Json> | undefined;\n const rules = dataValidationRules(dvModel ?? {});\n if (rules.length) validation[id] = rules;\n\n // ── conditional formatting\n const cf = conditionalRules(((ws as Json).conditionalFormattings ?? []) as Json[], dropped);\n if (cf.length) conditional[id] = cf;\n\n // ── filter range\n const af = ws.autoFilter as ExcelJSTypes.AutoFilter | undefined;\n if (af) {\n const range =\n typeof af === \"string\"\n ? parseA1Range(af)\n : af.from && af.to\n ? {\n startRow: (af.from as Json).row - 1,\n startColumn: (af.from as Json).column - 1,\n endRow: (af.to as Json).row - 1,\n endColumn: (af.to as Json).column - 1,\n }\n : null;\n if (range) filters[id] = { ref: range, filterColumns: [] };\n }\n\n // ── pictures\n const images = ws.getImages();\n if (images.length) {\n if (!options.uploadImage) {\n dropped.add(\"Pictures in the file were not imported\");\n } else {\n const data: Record<string, Json> = {};\n const order: string[] = [];\n for (const img of images) {\n try {\n const media = wb.getImage(Number(img.imageId)) as Json;\n const bytes = new Uint8Array(media.buffer as ArrayBuffer);\n const fileId = await options.uploadImage(bytes, String(media.extension ?? \"png\"));\n const tl = img.range.tl as Json;\n const ext = (img.range as Json).ext as Json | undefined;\n const br = img.range.br as Json | undefined;\n const width = ext?.width ?? ((br?.nativeCol ?? tl.nativeCol + 3) - tl.nativeCol) * 88;\n const height = ext?.height ?? ((br?.nativeRow ?? tl.nativeRow + 6) - tl.nativeRow) * 24;\n const drawingId = rid(\"img\");\n const column = Math.floor(tl.nativeCol ?? tl.col);\n const rowIdx = Math.floor(tl.nativeRow ?? tl.row);\n data[drawingId] = {\n unitId,\n subUnitId: id,\n drawingId,\n drawingType: 0,\n imageSourceType: \"URL\",\n source: `matrx-file:${fileId}`,\n transform: { left: column * 88, top: rowIdx * 24, width, height, angle: 0 },\n sheetTransform: {\n from: { column, columnOffset: 0, row: rowIdx, rowOffset: 0 },\n to: { column: column + Math.max(1, Math.round(width / 88)), columnOffset: 0, row: rowIdx + Math.max(1, Math.round(height / 24)), rowOffset: 0 },\n },\n };\n order.push(drawingId);\n } catch {\n dropped.add(\"Some pictures could not be stored and were left out\");\n }\n }\n if (order.length) drawings[id] = { data, order };\n }\n }\n\n if ((ws.getTables?.() ?? []).length) dropped.add(\"Excel tables became plain ranges (their data and styling are kept)\");\n sheets[id] = sheet;\n }\n\n if (Object.keys(validation).length) writeResource(resources, RESOURCE.validation, validation);\n if (Object.keys(conditional).length) writeResource(resources, RESOURCE.conditional, conditional);\n if (Object.keys(filters).length) writeResource(resources, RESOURCE.filter, filters);\n if (Object.keys(notes).length) writeResource(resources, RESOURCE.note, notes);\n if (Object.keys(drawings).length) writeResource(resources, RESOURCE.drawing, drawings);\n\n for (const d of dropped) options.onDropped?.(d);\n\n return {\n id: unitId,\n sheetOrder,\n name: file.name.replace(/\\.[^.]+$/, \"\"),\n appVersion: \"1\",\n locale: \"enUS\" as IWorkbookData[\"locale\"],\n styles,\n sheets,\n resources,\n } as Partial<IWorkbookData>;\n}\n\nfunction toStyle(cell: ExcelJSTypes.Cell): Json | undefined {\n const st: Json = {};\n const f = cell.font;\n if (f) {\n if (f.name) st.ff = f.name;\n if (f.size) st.fs = f.size;\n if (f.bold) st.bl = 1;\n if (f.italic) st.it = 1;\n if (f.underline) st.ul = { s: 1 };\n if (f.strike) st.st = { s: 1 };\n const cl = colorOf(f.color);\n if (cl) st.cl = { rgb: cl };\n }\n const fill = cell.fill as Json | undefined;\n if (fill?.type === \"pattern\" && fill.pattern === \"solid\") {\n const bg = colorOf(fill.fgColor);\n if (bg) st.bg = { rgb: bg };\n }\n const al = cell.alignment;\n if (al) {\n if (al.horizontal && H_ALIGN_IN[al.horizontal]) st.ht = H_ALIGN_IN[al.horizontal];\n if (al.vertical && V_ALIGN_IN[al.vertical]) st.vt = V_ALIGN_IN[al.vertical];\n if (al.wrapText) st.tb = 3;\n }\n const bd = cell.border as Json | undefined;\n if (bd) {\n const out: Json = {};\n for (const [side, key] of [[\"top\", \"t\"], [\"bottom\", \"b\"], [\"left\", \"l\"], [\"right\", \"r\"]] as const) {\n const s = borderFromExcel(bd[side]?.style);\n if (s) out[key] = { s, cl: { rgb: colorOf(bd[side]?.color) ?? \"#000000\" } };\n }\n if (Object.keys(out).length) st.bd = out;\n }\n if (cell.numFmt && cell.numFmt !== \"General\") st.n = { pattern: cell.numFmt };\n return Object.keys(st).length ? st : undefined;\n}\n\nconst EXCEL_EPOCH_OFFSET_DAYS = 25569;\n\nfunction toCell(cell: ExcelJSTypes.Cell, styleId: (s: Json) => string): Json | null {\n const out: Json = {};\n let st = toStyle(cell);\n const v = cell.value as unknown;\n const setNumber = (n: number) => {\n out.v = n;\n out.t = 2;\n };\n const apply = (value: unknown) => {\n if (value instanceof Date) {\n setNumber(value.getTime() / 86_400_000 + EXCEL_EPOCH_OFFSET_DAYS);\n st = { ...(st ?? {}), n: (st?.n as Json | undefined) ?? { pattern: \"yyyy-mm-dd\" } };\n } else if (typeof value === \"number\") setNumber(value);\n else if (typeof value === \"boolean\") {\n out.v = value ? 1 : 0;\n out.t = 3;\n } else if (typeof value === \"string\") {\n out.v = value;\n out.t = 1;\n } else if (value && typeof value === \"object\" && \"error\" in (value as Json)) {\n out.v = String((value as Json).error);\n out.t = 1;\n }\n };\n if (v && typeof v === \"object\" && !(v instanceof Date)) {\n const o = v as Json;\n if (\"formula\" in o || \"sharedFormula\" in o) {\n const f = o.formula ?? o.sharedFormula;\n if (f) out.f = `=${String(f).replace(/^=/, \"\")}`;\n apply(o.result);\n } else if (Array.isArray(o.richText)) {\n apply(o.richText.map((r: Json) => r.text).join(\"\"));\n } else if (\"hyperlink\" in o) {\n const text = String(typeof o.text === \"object\" ? (o.text?.richText ?? []).map((r: Json) => r.text).join(\"\") : (o.text ?? o.hyperlink));\n out.v = text;\n out.t = 1;\n out.p = linkDoc(text, String(o.hyperlink));\n } else apply(o);\n } else {\n apply(v);\n }\n if (st) out.s = styleId(st);\n return out.v === undefined && out.f === undefined && !out.s ? null : out;\n}\n\nfunction linkDoc(text: string, url: string): Json {\n return {\n id: \"d\",\n documentStyle: {},\n body: {\n dataStream: `${text}\\r\\n`,\n textRuns: [],\n paragraphs: [{ startIndex: text.length }],\n customRanges: [\n { startIndex: 0, endIndex: Math.max(0, text.length - 1), rangeId: rid(\"link\"), rangeType: 0, properties: { url } },\n ],\n },\n };\n}\n\nfunction dataValidationRules(model: Record<string, Json>): Json[] {\n const groups = new Map<string, { rule: Json; cells: [number, number][] }>();\n for (const [ref, dv] of Object.entries(model)) {\n const pos = parseA1Range(ref);\n if (!pos) continue;\n const type = String(dv.type);\n const rule: Json = {\n allowBlank: dv.allowBlank !== false,\n showErrorMessage: dv.showErrorMessage !== false,\n ...(dv.error ? { error: dv.error } : {}),\n ...(dv.errorTitle ? { errorTitle: dv.errorTitle } : {}),\n ...(dv.prompt ? { prompt: dv.prompt, showInputMessage: true } : {}),\n };\n const f = (dv.formulae ?? []) as unknown[];\n if (type === \"list\") {\n const raw = String(f[0] ?? \"\");\n const literal = /^\"(.*)\"$/.exec(raw);\n Object.assign(rule, { type: \"list\", formula1: literal ? literal[1] : raw, formula2: \"\", showDropDown: true });\n } else if ([\"whole\", \"decimal\", \"date\", \"time\", \"textLength\"].includes(type)) {\n Object.assign(rule, { type, operator: dv.operator ?? \"between\", formula1: String(f[0] ?? \"\"), formula2: f[1] !== undefined ? String(f[1]) : \"\" });\n } else if (type === \"custom\") {\n Object.assign(rule, { type: \"custom\", formula1: String(f[0] ?? \"\") });\n } else continue;\n const key = JSON.stringify(rule);\n const g = groups.get(key) ?? { rule, cells: [] };\n g.cells.push([pos.startRow, pos.startColumn]);\n groups.set(key, g);\n }\n return [...groups.values()].map(({ rule, cells }) => ({ uid: rid(\"dv\"), ...rule, ranges: compressCells(cells) }));\n}\n\n/** Single cells -> the fewest vertical runs. */\nfunction compressCells(cells: [number, number][]): RangeLike[] {\n const sorted = [...cells].sort((a, b) => a[1] - b[1] || a[0] - b[0]);\n const out: RangeLike[] = [];\n for (const [r, c] of sorted) {\n const last = out[out.length - 1];\n if (last && last.startColumn === c && last.endColumn === c && last.endRow === r - 1) last.endRow = r;\n else out.push({ startRow: r, endRow: r, startColumn: c, endColumn: c });\n }\n return out;\n}\n\nfunction dxfToStyle(style: Json | undefined): Json {\n const out: Json = {};\n const fg = colorOf(style?.font?.color);\n if (fg) out.cl = { rgb: fg };\n if (style?.font?.bold) out.bl = 1;\n if (style?.font?.italic) out.it = 1;\n const bg = colorOf(style?.fill?.bgColor) ?? colorOf(style?.fill?.fgColor);\n if (bg) out.bg = { rgb: bg };\n return out;\n}\n\nfunction conditionalRules(formats: Json[], dropped: Set<string>): Json[] {\n const out: Json[] = [];\n for (const cf of formats) {\n const ranges = String(cf.ref ?? \"\").split(/\\s+/).map((r) => parseA1Range(r)).filter((r): r is RangeLike => !!r);\n if (!ranges.length) continue;\n for (const rule of (cf.rules ?? []) as Json[]) {\n let mapped: Json | null = null;\n const style = dxfToStyle(rule.style);\n if (rule.type === \"cellIs\") {\n const nums = ((rule.formulae ?? []) as unknown[]).map(Number);\n const between = rule.operator === \"between\" || rule.operator === \"notBetween\";\n mapped = { type: \"highlightCell\", subType: \"number\", operator: rule.operator, value: between ? nums.slice(0, 2) : nums[0], style };\n } else if (rule.type === \"containsText\") {\n mapped = { type: \"highlightCell\", subType: \"text\", operator: \"containsText\", value: String(rule.text ?? \"\"), style };\n } else if (rule.type === \"expression\") {\n mapped = { type: \"highlightCell\", subType: \"formula\", value: `=${String((rule.formulae ?? [])[0] ?? \"\")}`, style };\n } else if (rule.type === \"colorScale\") {\n mapped = {\n type: \"colorScale\",\n config: ((rule.cfvo ?? []) as Json[]).map((v, i) => ({\n index: i,\n color: colorOf(rule.color?.[i]) ?? \"#ffffff\",\n value: { type: v.type, ...(v.value !== undefined ? { value: v.value } : {}) },\n })),\n };\n } else if (rule.type === \"dataBar\") {\n const [min, max] = (rule.cfvo ?? []) as Json[];\n mapped = {\n type: \"dataBar\",\n isShowValue: true,\n config: {\n min: { type: min?.type ?? \"min\" },\n max: { type: max?.type ?? \"max\" },\n isGradient: rule.gradient !== false,\n positiveColor: colorOf(rule.color) ?? \"#638ec6\",\n nativeColor: \"#ff0000\",\n },\n };\n }\n if (!mapped) {\n dropped.add(\"Some conditional formats (icon sets, top/bottom, date rules) were not imported\");\n continue;\n }\n out.push({ cfId: rid(\"cf\"), ranges, stopIfTrue: Boolean(rule.stopIfTrue), rule: mapped });\n }\n }\n return out;\n}\n","/**\n * Shared vocabulary between the xlsx importer and exporter: how Univer's\n * style numbers, colours and units map to the xlsx file's.\n *\n * Univer enums are written as numbers here so these helpers stay free of any\n * Univer import (they run in tests and in both directions).\n */\n\nexport const RESOURCE = {\n validation: \"SHEET_DATA_VALIDATION_PLUGIN\",\n conditional: \"SHEET_CONDITIONAL_FORMATTING_PLUGIN\",\n filter: \"SHEET_FILTER_PLUGIN\",\n note: \"SHEET_NOTE_PLUGIN\",\n comments: \"SHEET_UNIVER_THREAD_COMMENT_PLUGIN\",\n drawing: \"SHEET_DRAWING_PLUGIN\",\n table: \"SHEET_TABLE_PLUGIN\",\n} as const;\n\nexport type UniverResource = { name: string; data: string };\n\nexport function readResource<T = unknown>(\n resources: readonly UniverResource[] | undefined,\n name: string,\n): T | undefined {\n const raw = resources?.find((r) => r.name === name)?.data;\n if (!raw) return undefined;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return undefined;\n }\n}\n\nexport function writeResource(resources: UniverResource[], name: string, value: unknown): void {\n const i = resources.findIndex((r) => r.name === name);\n const entry = { name, data: JSON.stringify(value) };\n if (i >= 0) resources[i] = entry;\n else resources.push(entry);\n}\n\n/** Excel column width (characters) <-> Univer pixels. */\nexport const colPxToChars = (px: number): number => Math.max(0, Math.round((px / 7) * 100) / 100);\nexport const colCharsToPx = (chars: number): number => Math.round(chars * 7);\n/** Excel row height (points) <-> Univer pixels. */\nexport const rowPxToPt = (px: number): number => Math.round(px * 0.75 * 100) / 100;\nexport const rowPtToPx = (pt: number): number => Math.round((pt / 0.75) * 100) / 100;\n\n/** Univer colour (\"#rrggbb\", \"rgb(r,g,b)\", \"rgba(...)\") -> ARGB hex, or undefined. */\nexport function colorToArgb(input: string | undefined | null): string | undefined {\n if (!input) return undefined;\n const s = input.trim();\n const hex = /^#?([0-9a-f]{6})$/i.exec(s);\n if (hex) return `FF${hex[1]!.toUpperCase()}`;\n const short = /^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec(s);\n if (short) return `FF${short[1]}${short[1]}${short[2]}${short[2]}${short[3]}${short[3]}`.toUpperCase();\n const rgb = /^rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i.exec(s);\n if (rgb) {\n const h = (n: string) => Number(n).toString(16).padStart(2, \"0\");\n return `FF${h(rgb[1]!)}${h(rgb[2]!)}${h(rgb[3]!)}`.toUpperCase();\n }\n return undefined;\n}\n\n/** ARGB (or RGB) hex from a file -> Univer \"#rrggbb\". */\nexport function argbToColor(argb: string | undefined | null): string | undefined {\n if (!argb) return undefined;\n const v = argb.replace(/^#/, \"\");\n if (v.length === 8) return `#${v.slice(2).toLowerCase()}`;\n if (v.length === 6) return `#${v.toLowerCase()}`;\n return undefined;\n}\n\n// Univer BorderStyleTypes number <-> ExcelJS border style name.\nconst BORDER_OUT: Record<number, string> = {\n 1: \"thin\", 2: \"hair\", 3: \"dotted\", 4: \"dashed\", 5: \"dashDot\", 6: \"dashDotDot\", 7: \"double\",\n 8: \"medium\", 9: \"mediumDashed\", 10: \"mediumDashDot\", 11: \"mediumDashDotDot\", 12: \"slantDashDot\", 13: \"thick\",\n};\nexport const borderToExcel = (n: number | undefined): string | undefined =>\n n === undefined ? undefined : BORDER_OUT[n];\nexport const borderFromExcel = (name: string | undefined): number | undefined => {\n if (!name) return undefined;\n const hit = Object.entries(BORDER_OUT).find(([, v]) => v === name);\n return hit ? Number(hit[0]) : undefined;\n};\n\nexport const H_ALIGN_OUT: Record<number, string> = { 1: \"left\", 2: \"center\", 3: \"right\", 4: \"justify\", 5: \"justify\", 6: \"distributed\" };\nexport const V_ALIGN_OUT: Record<number, string> = { 1: \"top\", 2: \"middle\", 3: \"bottom\" };\nexport const H_ALIGN_IN: Record<string, number> = { left: 1, center: 2, right: 3, justify: 4, fill: 1, centerContinuous: 2, distributed: 6 };\nexport const V_ALIGN_IN: Record<string, number> = { top: 1, middle: 2, bottom: 3, distributed: 2, justify: 2 };\n\n/** 0-based (row, col) -> \"A1\" (no $). */\nexport function a1(row: number, col: number): string {\n let n = col + 1;\n let letters = \"\";\n while (n > 0) {\n const m = (n - 1) % 26;\n letters = String.fromCharCode(65 + m) + letters;\n n = Math.floor((n - 1) / 26);\n }\n return `${letters}${row + 1}`;\n}\n\nexport type RangeLike = { startRow: number; endRow: number; startColumn: number; endColumn: number };\nexport const rangeToA1 = (r: RangeLike): string =>\n r.startRow === r.endRow && r.startColumn === r.endColumn\n ? a1(r.startRow, r.startColumn)\n : `${a1(r.startRow, r.startColumn)}:${a1(r.endRow, r.endColumn)}`;\n\n/** \"A1\" or \"A1:C5\" -> range (0-based), or null. */\nexport function parseA1Range(ref: string): RangeLike | null {\n const m = /^\\$?([A-Z]+)\\$?(\\d+)(?::\\$?([A-Z]+)\\$?(\\d+))?$/i.exec(ref.trim());\n if (!m) return null;\n const col = (s: string) => [...s.toUpperCase()].reduce((acc, ch) => acc * 26 + ch.charCodeAt(0) - 64, 0) - 1;\n const sc = col(m[1]!);\n const sr = Number(m[2]!) - 1;\n return { startRow: sr, startColumn: sc, endRow: m[4] ? Number(m[4]) - 1 : sr, endColumn: m[3] ? col(m[3]) : sc };\n}\n"]}