js.documents 6.4.1 → 6.5.1

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.
Files changed (72) hide show
  1. package/README.md +72 -29
  2. package/dist/codecs/read.cjs +15 -0
  3. package/dist/codecs/read.js +15 -0
  4. package/dist/codecs/registry.cjs +18 -0
  5. package/dist/codecs/registry.js +18 -0
  6. package/dist/convert/capability.cjs +18 -0
  7. package/dist/convert/capability.js +18 -0
  8. package/dist/convert/codec.cjs +15 -0
  9. package/dist/convert/codec.d.cts +4 -1
  10. package/dist/convert/codec.d.ts +4 -1
  11. package/dist/convert/codec.js +16 -4
  12. package/dist/convert/composition.cjs +59 -4
  13. package/dist/convert/composition.d.cts +2 -2
  14. package/dist/convert/composition.d.ts +2 -2
  15. package/dist/convert/composition.js +59 -4
  16. package/dist/convert/convert.cjs +12 -0
  17. package/dist/convert/convert.d.cts +4 -1
  18. package/dist/convert/convert.d.ts +4 -1
  19. package/dist/convert/convert.js +10 -1
  20. package/dist/convert/from-pdf.cjs +12 -0
  21. package/dist/convert/from-pdf.d.cts +4 -1
  22. package/dist/convert/from-pdf.d.ts +4 -1
  23. package/dist/convert/from-pdf.js +10 -1
  24. package/dist/convert/port.cjs +3 -0
  25. package/dist/convert/port.d.cts +3 -0
  26. package/dist/convert/port.d.ts +3 -0
  27. package/dist/convert/port.js +3 -0
  28. package/dist/edit/odg/page.d.cts +1 -1
  29. package/dist/edit/odg/page.d.ts +1 -1
  30. package/dist/edit/odp/image.cjs +1 -1
  31. package/dist/edit/odp/image.js +1 -1
  32. package/dist/edit/odp/shape.cjs +5 -2
  33. package/dist/edit/odp/shape.d.cts +1 -1
  34. package/dist/edit/odp/shape.d.ts +1 -1
  35. package/dist/edit/odp/shape.js +6 -3
  36. package/dist/edit/odp/slide.d.cts +1 -1
  37. package/dist/edit/odp/slide.d.ts +1 -1
  38. package/dist/edit/pptx/image.cjs +1 -1
  39. package/dist/edit/pptx/image.js +1 -1
  40. package/dist/edit/pptx/shape.cjs +7 -5
  41. package/dist/edit/pptx/shape.d.cts +1 -1
  42. package/dist/edit/pptx/shape.d.ts +1 -1
  43. package/dist/edit/pptx/shape.js +7 -5
  44. package/dist/edit/pptx/slide.d.cts +2 -2
  45. package/dist/edit/pptx/slide.d.ts +2 -2
  46. package/dist/edit/pptx/table.d.cts +1 -1
  47. package/dist/edit/pptx/table.d.ts +1 -1
  48. package/dist/index.cjs +42 -0
  49. package/dist/index.d.cts +12 -8
  50. package/dist/index.d.ts +12 -8
  51. package/dist/index.js +9 -5
  52. package/dist/metadata/write.cjs +3 -0
  53. package/dist/metadata/write.js +3 -0
  54. package/dist/model/bytes.cjs +19 -0
  55. package/dist/model/bytes.d.cts +4 -1
  56. package/dist/model/bytes.d.ts +4 -1
  57. package/dist/model/bytes.js +17 -1
  58. package/dist/ppt/read.cjs +13 -0
  59. package/dist/ppt/read.d.cts +5 -0
  60. package/dist/ppt/read.d.ts +5 -0
  61. package/dist/ppt/read.js +12 -0
  62. package/dist/ppt/write.cjs +12 -0
  63. package/dist/ppt/write.d.cts +5 -0
  64. package/dist/ppt/write.d.ts +5 -0
  65. package/dist/ppt/write.js +11 -0
  66. package/dist/{shape-xpgICOEx.d.ts → shape-B_vI18gH.d.ts} +1 -1
  67. package/dist/{shape-Ca-xsrde.d.cts → shape-C2ef6uwC.d.cts} +1 -1
  68. package/dist/{shape-DqkYq1OL.d.cts → shape-CQa4zif9.d.cts} +1 -1
  69. package/dist/{shape-BY5P8kDn.d.ts → shape-DwZouh8R.d.ts} +1 -1
  70. package/dist/{table-C_KDsX5R.d.cts → table-CtbzOK8s.d.cts} +1 -1
  71. package/dist/{table-C3VWWdjr.d.ts → table-D2CgT0Gf.d.ts} +1 -1
  72. package/package.json +12 -8
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![GitHub](https://img.shields.io/badge/GitHub-181717?logo=github&logoColor=white)](https://github.com/ExaDev/documents.js/tree/main/packages/documents.js) [![npm](https://img.shields.io/badge/npm-CB3837?logo=npm&logoColor=white)](https://www.npmjs.com/package/documents.js) [![npm version](https://img.shields.io/npm/v/documents.js)](https://www.npmjs.com/package/documents.js) [![CI](https://img.shields.io/github/actions/workflow/status/ExaDev/documents.js/ci.yml?branch=main)](https://github.com/ExaDev/documents.js/actions)
4
4
 
5
- > Converts between any two compatible document formats through a shared content/layout pivot. docx, pptx, odt, odp, ods, odg, xlsx, csv (TSV is the same format with a tab delimiter), svg, markdown, and rtf all read into and build from the same shared `ContentDocument` model (reported to callers as the tree-form `DocumentTree`), with PDF — reached through pdf-codec's own `LayoutDocument` view — as the one format every variant can reach; wpd (WordPerfect 6.x-X6) reads into the same wordprocessing variant as a read-only source, routable everywhere the others are but never buildable as a target, since wpd-codec ships no writer. A composition engine (`convertDocument`) routes 141 (source, target) pairs across the twelve content formats and PDF, including twenty-two PDF-pivot round trips (the eight layout-engine formats, plus xlsx and csv composing through ods, and rtf composing through docx/odt/markdown), twenty-four cross-format bridge functions (same-variant direct copies, cross-variant semantic transforms, and PDF-composed), twelve one-way wpd-sourced routes, plus special-case conversions for `.odm` master documents, `.odb` database front-ends (HSQLDB and Firebird, four storage tiers), standalone `.odf` formula documents, and a bounded SQL/rpt-formula engine for `.odb` reports. Also includes: read-and-write live-view editors for all six editable formats, docx comment/footnote/header-footer exposure via `readDocxExtras`, real font resolution (source-embedded faces ahead of caller-supplied, vendored substitutes, and the standard 14), a hand-written MathML typesetting engine with embedded-font PDF rendering and a matching MathML ⇄ OMML translator, LaTeX lowering into the schema's two-layer semantic math core (pinned temml parser, symbol tables from prose, a coherence lint), and a fully hand-written PDF codec. Built on [ooxml.js](../ooxml.js/README.md), [odf.js](../odf.js/README.md), [pdf-codec](../pdf-codec/README.md), [markdown-codec](../markdown-codec/README.md), [rtf-codec](../rtf-codec/README.md), [wpd-codec](../wpd-codec/README.md), and [document-schema.js](../document-schema.js/README.md).
5
+ > Converts between any two compatible document formats through a shared content/layout pivot. docx, pptx, odt, odp, ods, odg, xlsx, csv (TSV is the same format with a tab delimiter), svg, markdown, rtf, and the three legacy binary formats doc/xls/ppt ([MS-DOC], BIFF8, [MS-PPT], each wrapped in an [MS-CFB] compound file) all read into and build from the same shared `ContentDocument` model (reported to callers as the tree-form `DocumentTree`), with PDF — reached through pdf-codec's own `LayoutDocument` view — as the one format every variant can reach; wpd (WordPerfect 6.x-X6) reads into the same wordprocessing variant as a read-only source, routable everywhere the others are but never buildable as a target, since wpd-codec ships no writer. A composition engine (`convertDocument`) routes 208 (source, target) pairs across the fifteen content formats and PDF, including twenty-eight PDF-pivot round trips (the eight layout-engine formats, plus xlsx/csv/xls composing through ods, and rtf/doc composing through docx/odt/markdown and ppt composing through pptx/odp), twenty-four cross-format bridge functions (same-variant direct copies, cross-variant semantic transforms, and PDF-composed), fifteen one-way wpd-sourced routes, plus special-case conversions for `.odm` master documents, `.odb` database front-ends (HSQLDB and Firebird, four storage tiers), standalone `.odf` formula documents, and a bounded SQL/rpt-formula engine for `.odb` reports. Also includes: read-and-write live-view editors for all six editable formats, docx comment/footnote/header-footer exposure via `readDocxExtras`, real font resolution (source-embedded faces ahead of caller-supplied, vendored substitutes, and the standard 14), a hand-written MathML typesetting engine with embedded-font PDF rendering and a matching MathML ⇄ OMML translator, LaTeX lowering into the schema's two-layer semantic math core (pinned temml parser, symbol tables from prose, a coherence lint), and a fully hand-written PDF codec. Built on [ooxml.js](../ooxml.js/README.md), [odf.js](../odf.js/README.md), [pdf-codec](../pdf-codec/README.md), [markdown-codec](../markdown-codec/README.md), [rtf-codec](../rtf-codec/README.md), [wpd-codec](../wpd-codec/README.md), [doc-codec](../doc-codec/README.md), [xls-codec](../xls-codec/README.md), [ppt-codec](../ppt-codec/README.md), [archive-codec](../archive-codec/README.md), and [document-schema.js](../document-schema.js/README.md).
6
6
 
7
7
  `documents.js` extends `ooxml.js` in two directions `ooxml.js` deliberately does not cover: full PDF support (parsing and generating, via `pdf-codec`), and a read-**and-write** manipulation API for docx/pptx content — `ooxml.js`'s own typed readers are one-way. The PDF codec is hand-written against ISO 32000-1, with no external PDF library as a dependency — see [Fidelity](#fidelity) and pdf-codec's own README for the honest trade-off (not as robust against adversarial PDFs as a 15+-year-hardened library; fully auditable and dependency-free instead). `src/mathml/` (the MathML typesetting engine) stays in this package and is hand-written too, for the same supply-chain reason. The one deliberate exception on the math side is the LaTeX parser: `src/latex/` lowers LaTeX into the schema's semantic core over a pinned exact-version [temml](https://temml.org) dependency — see [LaTeX lowering into the semantic core](#latex-lowering-into-the-semantic-core) for why a LaTeX grammar is the one component not worth hand-writing and what the pin guarantees.
8
8
 
@@ -15,6 +15,10 @@ graph TD
15
15
  mdcodec("markdown-codec")
16
16
  rtfcodec("rtf-codec")
17
17
  wpdcodec("wpd-codec")
18
+ doccodec("doc-codec")
19
+ xlscodec("xls-codec")
20
+ pptcodec("ppt-codec")
21
+ archivecodec("archive-codec")
18
22
  bytecodec("byte-codec")
19
23
  documents("documents.js")
20
24
  mcp("document-mcp")
@@ -26,6 +30,9 @@ graph TD
26
30
  schema --> mdcodec
27
31
  schema --> rtfcodec
28
32
  schema --> wpdcodec
33
+ schema --> doccodec
34
+ schema --> xlscodec
35
+ schema --> pptcodec
29
36
  schema --> documents
30
37
  ooxml --> documents
31
38
  odf --> documents
@@ -33,6 +40,13 @@ graph TD
33
40
  mdcodec --> documents
34
41
  rtfcodec --> documents
35
42
  wpdcodec --> documents
43
+ doccodec --> documents
44
+ xlscodec --> documents
45
+ pptcodec --> documents
46
+ archivecodec --> doccodec
47
+ archivecodec --> xlscodec
48
+ archivecodec --> pptcodec
49
+ archivecodec --> documents
36
50
  bytecodec --> pdfcodec
37
51
  bytecodec --> documents
38
52
  documents --> mcp
@@ -48,6 +62,10 @@ graph TD
48
62
  click mdcodec "https://github.com/ExaDev/documents.js/tree/main/packages/markdown-codec" "markdown-codec"
49
63
  click rtfcodec "https://github.com/ExaDev/documents.js/tree/main/packages/rtf-codec" "rtf-codec"
50
64
  click wpdcodec "https://github.com/ExaDev/documents.js/tree/main/packages/wpd-codec" "wpd-codec"
65
+ click doccodec "https://github.com/ExaDev/documents.js/tree/main/packages/doc-codec" "doc-codec"
66
+ click xlscodec "https://github.com/ExaDev/documents.js/tree/main/packages/xls-codec" "xls-codec"
67
+ click pptcodec "https://github.com/ExaDev/documents.js/tree/main/packages/ppt-codec" "ppt-codec"
68
+ click archivecodec "https://github.com/ExaDev/documents.js/tree/main/packages/archive-codec" "archive-codec"
51
69
  click bytecodec "https://github.com/ExaDev/documents.js/tree/main/packages/byte-codec" "byte-codec"
52
70
  click documents "https://github.com/ExaDev/documents.js" "documents.js"
53
71
  click mcp "https://github.com/ExaDev/documents.js/tree/main/packages/document-mcp" "document-mcp"
@@ -80,7 +98,7 @@ npm install documents.js document-schema.js
80
98
 
81
99
  ### The generic entry point: `convertDocument`
82
100
 
83
- A single function, `convertDocument`, sits behind every named conversion and reaches every pair the composition engine can route — all 141 supported (source, target) combinations. The named functions below are thin one-line forwarders to it; they remain the ergonomic layer for a caller who wants a fixed pair and autocomplete discovery, while `convertDocument` is the first-class entry point for a caller working from a runtime format pair (CLI, MCP tool, matrix enumeration).
101
+ A single function, `convertDocument`, sits behind every named conversion and reaches every pair the composition engine can route — all 208 supported (source, target) combinations. The named functions below are thin one-line forwarders to it; they remain the ergonomic layer for a caller who wants a fixed pair and autocomplete discovery, while `convertDocument` is the first-class entry point for a caller working from a runtime format pair (CLI, MCP tool, matrix enumeration).
84
102
 
85
103
  ```ts
86
104
  import { convertDocument } from "documents.js";
@@ -99,11 +117,12 @@ const odtBytes = convertDocument("docx", "odt", docxBytes, {
99
117
 
100
118
  ### PDF-pivot conversions
101
119
 
102
- The sixteen round-trip ergonomic conversions between the formats with their own layout engine and PDF (docx/pptx/odt/odp/ods/odg/markdown/svg ⇄ PDF, all round-tripping both ways), plus `xlsxToPdf`/`pdfToXlsx` and `csvToPdf`/`pdfToCsv` (each composing its ods bridge with the ods⇄pdf layout pair internally — neither xlsx nor csv has a layout engine of its own), and `rtfToPdf`/`pdfToRtf` (composing a docx bridge with the docx⇄pdf layout pair internally, for the identical reason rtf-codec has no layout engine of its own either):
120
+ The sixteen round-trip ergonomic conversions between the formats with their own layout engine and PDF (docx/pptx/odt/odp/ods/odg/markdown/svg ⇄ PDF, all round-tripping both ways), plus `xlsxToPdf`/`pdfToXlsx` and `csvToPdf`/`pdfToCsv` (each composing its ods bridge with the ods⇄pdf layout pair internally — neither xlsx nor csv has a layout engine of its own), and `rtfToPdf`/`pdfToRtf`, `docToPdf`/`pdfToDoc`, `xlsToPdf`/`pdfToXls`, `pptToPdf`/`pdfToPpt` (each composing a same-variant bridge doc/rtf through docx, xls through ods, ppt through pptx — with that bridge target's own layout pair internally, for the identical reason: none of the four has a layout engine of its own):
103
121
 
104
122
  ```ts
105
123
  import {
106
124
  csvToPdf,
125
+ docToPdf,
107
126
  docxToPdf,
108
127
  markdownToPdf,
109
128
  odgToPdf,
@@ -111,19 +130,24 @@ import {
111
130
  odsToPdf,
112
131
  odtToPdf,
113
132
  pdfToCsv,
133
+ pdfToDoc,
114
134
  pdfToDocx,
115
135
  pdfToMarkdown,
116
136
  pdfToOdg,
117
137
  pdfToOdp,
118
138
  pdfToOds,
119
139
  pdfToOdt,
140
+ pdfToPpt,
120
141
  pdfToPptx,
121
142
  pdfToRtf,
122
143
  pdfToSvg,
144
+ pdfToXls,
123
145
  pdfToXlsx,
146
+ pptToPdf,
124
147
  pptxToPdf,
125
148
  rtfToPdf,
126
149
  svgToPdf,
150
+ xlsToPdf,
127
151
  xlsxToPdf,
128
152
  } from "documents.js";
129
153
 
@@ -159,6 +183,15 @@ const svgBytes2 = pdfToSvg(pdfFromSvg); // readPdf -> reconstructDrawing -> buil
159
183
 
160
184
  const pdfFromRtf = rtfToPdf(rtfBytes); // composes an rtf -> docx bridge -> docx -> pdf toPdf internally
161
185
  const rtfBytes2 = pdfToRtf(pdfFromRtf); // composes pdf -> docx fromPdf -> docx -> rtf internally
186
+
187
+ const pdfFromDoc = docToPdf(docBytes); // composes a doc -> docx bridge -> docx -> pdf toPdf internally
188
+ const docBytes2 = pdfToDoc(pdfFromDoc); // composes pdf -> docx fromPdf -> docx -> doc internally
189
+
190
+ const pdfFromXls = xlsToPdf(xlsBytes); // composes an xls -> ods bridge -> ods -> pdf toPdf internally
191
+ const xlsBytes2 = pdfToXls(pdfFromXls); // composes pdf -> ods fromPdf -> ods -> xls internally
192
+
193
+ const pdfFromPpt = pptToPdf(pptBytes); // composes a ppt -> pptx bridge -> pptx -> pdf toPdf internally
194
+ const pptBytes2 = pdfToPpt(pdfFromPpt); // composes pdf -> pptx fromPdf -> pptx -> ppt internally
162
195
  ```
163
196
 
164
197
  Each accepts an optional `signal` (`AbortSignal`) and either `onSubstitution` (X → PDF, called per character not representable in a standard-14 font) or `sink` (PDF → X, called per recoverable parse diagnostic). Every X → PDF conversion additionally accepts `fonts` (extra `ProvidedFont` faces) and `onFontSubstitution` (per family+weight+style that resolved to something else). Neither is needed for the common case — see [Fonts](#fonts).
@@ -200,14 +233,14 @@ const { document, diagnostics } = await converter.convert(
200
233
  );
201
234
  ```
202
235
 
203
- `DocumentFormat` includes `docx`/`pptx`/`xlsx`/`odt`/`odp`/`ods`/`odg`/`svg`/`odf`/`csv`/`markdown`/`rtf`/`wpd`/`pdf` — fourteen members, `wpd` the one read-only member: it appears as a source in `conversions` but never as a target, since wpd-codec ships no writer. The port's `conversions` list is derived from `resolveCompositionPlan` plus the `odf`→`pdf` special case — 141 pairs total. `DocumentFormat` is inferred from `DocumentFormatSchema` (a real Zod schema); `DOCUMENT_FORMATS` is exported as a plain array derived from the same schema:
236
+ `DocumentFormat` includes `docx`/`pptx`/`xlsx`/`odt`/`odp`/`ods`/`odg`/`svg`/`odf`/`csv`/`markdown`/`rtf`/`doc`/`xls`/`ppt`/`wpd`/`pdf` — seventeen members, `wpd` the one read-only member: it appears as a source in `conversions` but never as a target, since wpd-codec ships no writer. The port's `conversions` list is derived from `resolveCompositionPlan` plus the `odf`→`pdf` special case — 208 pairs total. `DocumentFormat` is inferred from `DocumentFormatSchema` (a real Zod schema); `DOCUMENT_FORMATS` is exported as a plain array derived from the same schema:
204
237
 
205
238
  The port also exposes `contractVersion: number`, bumped only when `DocumentConverter`'s own contract shape changes — a new field on `ConversionResult` a caller might need to branch on, or a new `ConversionOptions` field an implementation is now expected to honour — never when the `conversions` table simply grows with more supported source/target pairs (that's discoverable at runtime via `conversions` itself). It is currently `7`: the bump from `6` reflects `ConversionResult.package` changing type to the tree-form `DocumentTree` described below, which a caller reading that field must now flatten rather than read directly.
206
239
 
207
240
  ```ts
208
241
  import { DOCUMENT_FORMATS, DocumentFormatSchema } from "documents.js";
209
242
 
210
- console.log(DOCUMENT_FORMATS); // ['docx', 'pptx', 'xlsx', 'odt', 'odp', 'ods', 'odg', 'svg', 'odf', 'csv', 'markdown', 'rtf', 'wpd', 'pdf']
243
+ console.log(DOCUMENT_FORMATS); // ['docx', 'pptx', 'xlsx', 'odt', 'odp', 'ods', 'odg', 'svg', 'odf', 'csv', 'markdown', 'rtf', 'doc', 'xls', 'ppt', 'wpd', 'pdf']
211
244
  DocumentFormatSchema.parse(userSuppliedFormat); // throws a ZodError for anything outside that list
212
245
  ```
213
246
 
@@ -501,7 +534,7 @@ const layout = readPdf(pdfBytes); // -> LayoutDocument: pages of positioned text
501
534
  const bytes = writePdf(layout);
502
535
  ```
503
536
 
504
- The twelve PDF round trips and sixteen PDF-bypassing bridge directions are also available as schema-validated [`z.codec()`](https://zod.dev) pairs (`pdfCodec`, `docxPdfCodec`, `pptxPdfCodec`, `odtPdfCodec`, `odpPdfCodec`, `odsPdfCodec`, `odgPdfCodec`, `svgPdfCodec`, `xlsxPdfCodec`, `csvPdfCodec`, `markdownPdfCodec`, `rtfPdfCodec`, `odtDocxCodec`, `odpPptxCodec`, `odsXlsxCodec`, `odsCsvCodec`, `xlsxCsvCodec`, `odgSvgCodec`, `markdownDocxCodec`, `markdownOdtCodec`) — the no-options form, adding automatic two-way schema validation. The two PDF-composed pairs have codec forms too (`xlsxMarkdownCodec`, `csvMarkdownCodec`):
537
+ The fifteen PDF round trips and sixteen PDF-bypassing bridge directions are also available as schema-validated [`z.codec()`](https://zod.dev) pairs (`pdfCodec`, `docxPdfCodec`, `pptxPdfCodec`, `odtPdfCodec`, `odpPdfCodec`, `odsPdfCodec`, `odgPdfCodec`, `svgPdfCodec`, `xlsxPdfCodec`, `csvPdfCodec`, `markdownPdfCodec`, `rtfPdfCodec`, `docPdfCodec`, `xlsPdfCodec`, `pptPdfCodec`, `odtDocxCodec`, `odpPptxCodec`, `odsXlsxCodec`, `odsCsvCodec`, `xlsxCsvCodec`, `odgSvgCodec`, `markdownDocxCodec`, `markdownOdtCodec`) — the no-options form, adding automatic two-way schema validation. The two PDF-composed pairs have codec forms too (`xlsxMarkdownCodec`, `csvMarkdownCodec`):
505
538
 
506
539
  ```ts
507
540
  import { z } from "zod";
@@ -761,6 +794,7 @@ The package is layered from generic primitives outward to the two conversion dir
761
794
  - **`src/omml/`** — the MathML ⇄ OMML structural translator, both directions. `write.ts` covers the identical construct set `src/mathml/layout.ts` typesets; `read.ts` covers strictly more (reads what Word authored, not just what this package writes). Lives outside `src/mathml/` because its I/O type is `ooxml.js`'s `XmlElement` and `src/mathml/` imports no package.
762
795
  - **`src/ooxml/`** — thin adapters over `ooxml.js`'s own flat `readDocxContent`/`readPptxContent` readers, wrapping results into `ContentDocument`. `docx/formula.ts` is the one local reading pass (splicing OOXML math equations). `docx/extras.ts`'s `readDocxExtras` returns comments/footnotes/header-footer parts, section header/footer references, and numbering.
763
796
  - **`src/odf/`** — ODF-side counterparts: `readOdtContent`/`readOdpContent`/`readOdsContent`/`readOdgContent` are thin adapters over `odf.js`. `formula/read.ts`/`formula/detect.ts` handle embedded formula detection (genuinely new work with no `odf.js`-side equivalent).
797
+ - **`src/ppt/`** — the one legacy-binary-format adapter with a genuine wrap of its own: `ppt-codec`'s `readPptContent`/`writePptContent` operate on the flat `{ metadata, slides }` shape (mirroring `ooxml.js`'s/`odf.js`'s own upstream flat readers), not a full `'presentation'`-kind `ContentDocument` directly, so `read.ts`/`write.ts` do the envelope wrap/unwrap `src/ooxml/pptx/read.ts`/`src/odf/odp/read.ts` also do for their own formats -- minus the formula/vector-recovery passes those two run, since `ppt-codec` has no upstream equivalent to splice in. `doc` and `xls` need no equivalent module: `doc-codec`'s `readDocContent`/`writeDocContent` and `xls-codec`'s `readXlsContent`/`writeXlsContent` already read/write a real `ContentDocument` directly (the latter over `XlsContentDocument`, a plain narrowed alias), so both are called straight from `src/codecs/read.ts`/`src/codecs/registry.ts`/`src/convert/composition.ts`, exactly like `rtf-codec`'s own pair.
764
798
  - **`src/latex/`** — the LaTeX presentation → `MathExpression` lowering: `temml.ts` is the pinned-parser boundary (exact-version temml, its internal parse API guarded behind structural type guards), `lower.ts` the mechanical rules and their degradations, `symbols.ts` the glyph/command map and the prose definition scanner, `rational.ts` the exact-rational helpers, `lint.ts` the coherence lint. See [LaTeX lowering into the semantic core](#latex-lowering-into-the-semantic-core).
765
799
  - **`src/markdown/`** — third adapter family, via `markdown-codec`. `readMarkdownContent` passes `readMarkdownContent`'s (markdown-codec's flat reader, so named since that package's 4.0.0; the bare `readMarkdown` name is now its tree-form `DocumentTree` reader) result through the math-lowering pass (`math.ts` — markdown-codec's preserved `$$` display blocks and `\( \)` inline spans become two-layer formula blocks, with the document's symbol table seeded from its own prose). `buildMarkdownText` wraps `writeMarkdownContent`, reconstructing markdown math syntax from formula blocks carrying a presentation layer. `text.ts` is the byte↔text boundary. `MarkdownEditor` holds a mutable in-memory `ContentDocument`.
766
800
  - **`src/csv/`** — fourth adapter family, sharing the spreadsheet variant with xlsx/ods. `records.ts` is the RFC 4180 record parser/writer (one shared `quoteCsvField`, also used by the `.odb` CSV exporter); `text.ts` is the byte↔text boundary, rejecting malformed UTF-8; `read.ts` turns records into a spreadsheet `ContentDocument` (first record as verbatim string header, data cells through the same cell-typing heuristic `pdfToOds` uses); `write.ts` turns one sheet of a spreadsheet `ContentDocument` back into records via each cell's `displayText`. TSV is the same format with `{ delimiter: '\t' }` on either side.
@@ -774,7 +808,7 @@ The package is layered from generic primitives outward to the two conversion dir
774
808
  - **`src/metadata/`** — cross-format metadata read/write via `DOCUMENT_FORMAT_CODECS`.
775
809
  - **`src/package-codec.ts`** — `decodeDocumentPackage`/`encodeDocumentPackage`/`decodeOdbPackage`.
776
810
 
777
- Dependency direction is downward and checkable. Eight external dependencies each own a distinct concern: `ooxml.js` (docx/pptx/xlsx), `odf.js` (odt/ods/odp/odg), `document-schema.js` (shared schemas + port contracts), `pdf-codec` (PDF codec + text-layout/font primitives), `byte-codec` (byte/image utilities), `markdown-codec` (markdown), `rtf-codec` (rtf), `wpd-codec` (wpd, read-only). No `PdfObject`/`PdfDict`/`PdfStream` type appears anywhere in this package.
811
+ Dependency direction is downward and checkable. Twelve external dependencies each own a distinct concern: `ooxml.js` (docx/pptx/xlsx), `odf.js` (odt/ods/odp/odg), `document-schema.js` (shared schemas + port contracts), `pdf-codec` (PDF codec + text-layout/font primitives), `byte-codec` (byte/image utilities), `markdown-codec` (markdown), `rtf-codec` (rtf), `wpd-codec` (wpd, read-only), `doc-codec` (doc), `xls-codec` (xls), `ppt-codec` (ppt, through this package's own `src/ppt/` envelope adapter), `archive-codec` (the `[MS-CFB]` compound-file detection all three legacy binary codecs' own bytes schemas build on). No `PdfObject`/`PdfDict`/`PdfStream` type appears anywhere in this package.
778
812
 
779
813
  ## Build, test, and lint
780
814
 
@@ -887,26 +921,29 @@ To run a single test file: `pnpm vitest run src/path/to/file.test.ts`.
887
921
 
888
922
  ## Fidelity
889
923
 
890
- Read as **row → column**. `✓` lossless, `~` bounded, `✗` lossy, `✗✗` severe, `→` one-way, `–` no conversion. `.odm`/`.odb` sit outside this table. `rtf` is wired into the composition engine and bidirectionally routable to every other format here except `csv`/`xlsx` (one hop past the pathfinder's own 3-hop cap) and `odf` (excluded from routing entirely — see below). `wpd` is wired in as a read-only source (see composition.ts's own `ReadOnlyContentFormat`): routable to every other format here except `odf`, exactly like `rtf`'s reach, but every one of its cells is `→` rather than a fidelity grade, since a read-only format has no reverse direction to compare against and no column of its own — nothing ever routes to `wpd`, wpd-codec having no writer at all. Every cell below is derived from `resolveCompositionPlan`'s actual resolved route for that pair (hop count and hop kind — same-variant bridge, cross-variant transform, or PDF pivot), not hand-reasoned: the pathfinder generates the full cross-product of same-variant and cross-variant-transform edges, so a pair can be routable even with no named convenience function for it (e.g. `odp → docx`, `odt → pptx`).
891
-
892
- | ↓ from \ to → | docx | pptx | xlsx | odt | odp | ods | odg | svg | odf | markdown | csv | rtf | wpd | pdf |
893
- | ------------- | ---- | ---- | ---- | --- | --- | --- | --- | --- | --- | -------- | --- | --- | --- | --- |
894
- | **docx** | — | ~ | ✗ | ✓ | ~ | ✗ | ✗ | ✗ | – | ✗ | ✗ | ✗ | – | ~ |
895
- | **pptx** | ~ | — | ✗ | ~ | ✓ | ✗ | ~ | ~ | – | ~ | ✗ | ~ | – | ~ |
896
- | **xlsx** | ✗ | ✗ | — | ✗ | ✗ | ~ | ✗ | ✗ | – | ✗✗ | ~ | – | – | ~ |
897
- | **odt** | ✓ | ~ | ✗ | — | ~ | ✗ | ✗ | ✗ | – | ✗ | ✗ | ✗ | – | ~ |
898
- | **odp** | ~ | ✓ | ✗ | ~ | — | ✗ | ~ | ~ | – | ~ | ✗ | ~ | – | ~ |
899
- | **ods** | ✗ | ✗ | ~ | ✗ | ✗ | — | ✗ | ✗ | – | ✗✗ | ~ | ✗ | – | ~ |
900
- | **odg** | ✗ | ~ | ✗ | ✗ | ~ | ✗ | — | ✓ | – | ✗ | ✗ | ✗ | – | ~ |
901
- | **svg** | ✗ | ~ | ✗ | ✗ | ~ | ✗ | ✓ | — | – | ✗✗ | ✗✗ | ✗ | – | ~ |
902
- | **odf** | – | – | – | – | – | – | – | – | — | – | – | – | – | → |
903
- | **markdown** | ~ | ~ | ✗✗ | ~ | ~ | ✗ | ✗ | ✗✗ | – | — | ✗✗ | ~ | – | ~ |
904
- | **csv** | ✗ | ✗ | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | – | ✗✗ | — | – | – | ~ |
905
- | **rtf** | ~ | ~ | – | ~ | ~ | ✗ | ✗ | ✗ | – | ✗ | – | — | – | ~ |
906
- | **wpd** | | | | | | | | | – | | | | — | |
907
- | **pdf** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | – | ✗✗ | | | – | — |
908
-
909
- 141 of 182 directional pairs are routable. The shared `ContentDocument` model is the hub, not PDFtwenty bridges bypass PDF entirely.
924
+ Read as **row → column**. `✓` lossless, `~` bounded, `✗` lossy, `✗✗` severe, `→` one-way, `–` no conversion. `.odm`/`.odb` sit outside this table. `rtf` is wired into the composition engine and bidirectionally routable to every other format here except `csv`/`xlsx` (one hop past the pathfinder's own 3-hop cap) and `odf` (excluded from routing entirely — see below). `wpd` is wired in as a read-only source (see composition.ts's own `ReadOnlyContentFormat`): routable to every other format here except `odf`, exactly like `rtf`'s reach, but every one of its cells is `→` rather than a fidelity grade, since a read-only format has no reverse direction to compare against and no column of its own — nothing ever routes to `wpd`, wpd-codec having no writer at all. Every cell below is derived from `resolveCompositionPlan`'s actual resolved route for that pair (hop count and hop kind — same-variant bridge, cross-variant transform, or PDF pivot), not hand-reasoned: the pathfinder generates the full cross-product of same-variant and cross-variant-transform edges, so a pair can be routable even with no named convenience function for it (e.g. `odp → docx`, `odt → pptx`). `doc`/`xls`/`ppt` (the three legacy binary formats — see doc-codec/xls-codec/ppt-codec's own READMEs for exactly what each reads/writes) are wired into the composition engine too, and bidirectionally routable to most of the formats here (`doc` reaches everything except `csv`/`xlsx`/`xls`; `xls` reaches everything except `doc`/`ppt`/`rtf`; `ppt` reaches everything except `csv`/`xlsx`/`xls`, each the identical one-hop-too-many gap `rtf`'s own `csv`/`xlsx` pair already has, for the same reason — none of the three has a toPdf/fromPdf edge of its own) — like the `rtf` extension before them (ExaDev/documents.js#853), all three now carry a real per-pair fidelity audit in the table below ([ExaDev/documents.js#880](https://github.com/ExaDev/documents.js/issues/880)), checked the same way: every `doc`/`xls`/`ppt` cell is verified against `resolveCompositionPlan`'s actual resolved route for that pair plus that codec's own documented read/write scope, not guessed from the hop shape alone.
925
+
926
+ | ↓ from \ to → | docx | pptx | xlsx | odt | odp | ods | odg | svg | odf | markdown | csv | rtf | doc | xls | ppt | wpd | pdf |
927
+ | ------------- | ---- | ---- | ---- | --- | --- | --- | --- | --- | --- | -------- | --- | --- | --- | --- | --- | --- | --- |
928
+ | **docx** | — | ~ | ✗ | ✓ | ~ | ✗ | ✗ | ✗ | – | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | – | ~ |
929
+ | **pptx** | ~ | — | ✗ | ~ | ✓ | ✗ | ~ | ~ | – | ~ | ✗ | ~ | ✗ | ✗ | ✗ | – | ~ |
930
+ | **xlsx** | ✗ | ✗ | — | ✗ | ✗ | ~ | ✗ | ✗ | – | ✗✗ | ~ | – | – | ✗ | – | – | ~ |
931
+ | **odt** | ✓ | ~ | ✗ | — | ~ | ✗ | ✗ | ✗ | – | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | – | ~ |
932
+ | **odp** | ~ | ✓ | ✗ | ~ | — | ✗ | ~ | ~ | – | ~ | ✗ | ~ | ✗ | ✗ | ✗ | – | ~ |
933
+ | **ods** | ✗ | ✗ | ~ | ✗ | ✗ | — | ✗ | ✗ | – | ✗✗ | ~ | ✗ | ✗ | ✗ | ✗ | – | ~ |
934
+ | **odg** | ✗ | ~ | ✗ | ✗ | ~ | ✗ | — | ✓ | – | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | – | ~ |
935
+ | **svg** | ✗ | ~ | ✗ | ✗ | ~ | ✗ | ✓ | — | – | ✗✗ | ✗✗ | ✗ | ✗ | ✗ | ✗ | – | ~ |
936
+ | **odf** | – | – | – | – | – | – | – | – | — | – | – | – | – | – | – | – | → |
937
+ | **markdown** | ~ | ~ | ✗✗ | ~ | ~ | ✗ | ✗ | ✗✗ | – | — | ✗✗ | ~ | ✗ | ✗✗ | ✗ | – | ~ |
938
+ | **csv** | ✗ | ✗ | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | – | ✗✗ | — | – | – | ✓ | – | – | ~ |
939
+ | **rtf** | ~ | ~ | – | ~ | ~ | ✗ | ✗ | ✗ | – | ✗ | – | — | ✗ | – | ✗ | – | ~ |
940
+ | **doc** | | | | | | | | | – | | | | — | | ✗ | – | ~ |
941
+ | **xls** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | – | ✗✗ | ~ | | – | — | – | – | ~ |
942
+ | **ppt** | ✗ | ✗ | – | ✗ | ✗ | ✗ | ✗ | ✗ | – | ✗ | – | ✗ | ✗ | – | — | – | ~ |
943
+ | **wpd** | → | → | → | → | → | → | → | → | – | → | → | → | → | → | → | | → |
944
+ | **pdf** | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | – | ✗✗ | ✗ | ✗ | ✗ | ✗ | ✗ | – | — |
945
+
946
+ 208 of 272 directional pairs are routable. The shared `ContentDocument` model is the hub, not PDF — 112 of those 208 directional pairs (61 counted as an undirected format relationship, since most run both ways; ten don't, all of them `wpd`'s own outbound-only routes) resolve to a route whose every hop is a bridge, never touching PDF at all, confirmed by walking `resolveCompositionPlan` over every pair and checking no hop's executor is `toPdf`/`fromPdf`.
910
947
 
911
948
  **X → PDF** is a genuine layout render: positioned text, images, tables, lists, vector primitives, styled through the full cascade. It is a faithful visual approximation, not pixel-identical — closeness depends on font availability.
912
949
 
@@ -922,13 +959,19 @@ Read as **row → column**. `✓` lossless, `~` bounded, `✗` lossy, `✗✗` s
922
959
 
923
960
  **`markdownToPdf`/`pdfToMarkdown`** is the lossiest round trip: `markdownToPdf` is faithful, but `pdfToMarkdown` stacks reconstruction lossiness PLUS markdown's coarser vocabulary (no colour, font, size, alignment). Two structure signals do survive it (ExaDev/documents.js#584): every page boundary arrives as an exact `<!-- page break -->` marker (one per boundary — the one fact a rendered PDF states precisely), and headings are inferred from font size — each distinct size at least 2pt above the document's modal body size is a heading, ranked largest-first into `Heading1..6`, which inverts this package's own heading render sizes exactly and is a heuristic (the well-worn "largest text is the title" reading) for any other producer. Tables reach markdown as GFM pipe tables wherever the gridline-lattice gate succeeds; a table rendered without drawn gridlines (which includes every `markdownToPdf`-authored one, markdown carrying no border concept) correctly comes back as tab-separated prose rather than invented structure. The PDF-composed markdown bridges (`xlsxToMarkdown`/`markdownToXlsx`, `csvToMarkdown`/`markdownToCsv`) stack the same two losses in both directions — hence their `✗✗` cells. `ods ⇄ markdown` stacks the identical pair of losses even without a named bridge function: the pathfinder's own bare toPdf-then-fromPdf route carries no extra hop, but the two legs are the same render-then-reconstruct-into-markdown pair, so both directions are `✗✗` too.
924
961
 
925
- **The same-variant bridge pairs** (odt⇄docx, odp⇄pptx, ods⇄xlsx, csv⇄ods, csv⇄xlsx, svg⇄odg, plus rtf's own docx⇄rtf/odt⇄rtf) bypass PDF entirely — no layout engine, no reconstruction. Text, styling, tables, lists, rotated shapes survive completely wherever both formats' `ContentDocument` coverage matches. `ods⇄xlsx` has small format-boundary limits (time cells, formula dialects). Embedded formulas survive `odtToDocx` as real OOXML math. The csv pairs are bounded by what csv itself carries: toward ods/xlsx nothing the csv had is lost, while writing to csv collapses each cell to its `displayText` — formulas become their rendered values, formatting disappears, and a multi-sheet source must name the sheet it wants. The svg pair carries the six vector primitives losslessly in both directions; its one asymmetry is paint defaults — SVG's absent-fill-is-black versus a drawing frame's no-fill. `docx⇄rtf`/`odt⇄rtf` are asymmetric the other way round: rtf-codec's own [Scope](../rtf-codec/README.md#scope) carries colour, font family/size, alignment, multiple sections, cell borders/shading/both merge directions, bookmarks, and tracked changes, so nothing docx/odt already lost crossing to rtf and back is lost a second time going rtf → docx/odt. What going docx/odt → rtf still drops is superscript/subscript and right-to-left text — and neither is an RTF gap: `ContentRun` carries no vertical-alignment or direction field at all, so the same content is lost crossing to _any_ format in this family, exactly as `epub-codec` reports for its own `<sub>`/`<sup>`.
962
+ **The same-variant bridge pairs** (odt⇄docx, odp⇄pptx, ods⇄xlsx, csv⇄ods, csv⇄xlsx, csv⇄xls, svg⇄odg, plus rtf's own docx⇄rtf/odt⇄rtf) bypass PDF entirely — no layout engine, no reconstruction. Text, styling, tables, lists, rotated shapes survive completely wherever both formats' `ContentDocument` coverage matches. `ods⇄xlsx` has small format-boundary limits (time cells, formula dialects). Embedded formulas survive `odtToDocx` as real OOXML math. The csv pairs are bounded by what csv itself carries: toward ods/xlsx/xls nothing the csv had is lost, while writing to csv collapses each cell to its `displayText` — formulas become their rendered values, formatting disappears, and a multi-sheet source must name the sheet it wants. The svg pair carries the six vector primitives losslessly in both directions; its one asymmetry is paint defaults — SVG's absent-fill-is-black versus a drawing frame's no-fill. `docx⇄rtf`/`odt⇄rtf` are asymmetric the other way round: rtf-codec's own [Scope](../rtf-codec/README.md#scope) carries colour, font family/size, alignment, multiple sections, cell borders/shading/both merge directions, bookmarks, and tracked changes, so nothing docx/odt already lost crossing to rtf and back is lost a second time going rtf → docx/odt. What going docx/odt → rtf still drops is superscript/subscript and right-to-left text — and neither is an RTF gap: `ContentRun` carries no vertical-alignment or direction field at all, so the same content is lost crossing to _any_ format in this family, exactly as `epub-codec` reports for its own `<sub>`/`<sup>`.
926
963
 
927
964
  **The markdown and rtf bridge pairs into/out of markdown** bypass PDF too, but markdown's grammar has no construct for colour/font/size/alignment — `docxToMarkdown`/`odtToMarkdown` and rtf → markdown all drop them (format-boundary loss, not approximation). rtf carries all four natively (unlike markdown), so `markdown → rtf` loses nothing markdown had, the same asymmetry `markdown → docx`/`markdown → odt` already show.
928
965
 
929
966
  **Every wordprocessing-family format (docx/odt/markdown/rtf) bridges to every presentation-family format (pptx/odp), and every drawing-family format (odg/svg) bridges to every presentation-family format too, through a semantic transform** — not just the two hand-written convenience pairs (docx⇄pptx, odt⇄odp): the pathfinder generates the full cross-product from the same two transform functions (`wordprocessingToPresentation`/`presentationToWordprocessing`, `drawingToPresentation`/`presentationToDrawing`), so e.g. `odp → docx` and `odt → pptx` are real routable pairs with no named function of their own. Slide boundaries are heuristic, but blocks survive intact. A wordprocessing format reaching a drawing format (or vice versa) chains two such transforms through presentation as a hub (e.g. `docx → pptx → odg`) with no PDF pivot at all — cheaper than a PDF round trip, but compounding two structural transforms is more lossy than one, hence those cells' `✗` rather than `~`.
930
967
 
931
- **`wpd`'s whole row is `→`, never a fidelity grade, because it is read-only.** wpd-codec has a real reader and no writer at all (a deliberate scope decision, not an omission — see that package's own Scope), so there is no reverse conversion to measure loss against the way every other pair in this table can be. `wpd → docx`/`wpd → odt`/`wpd → markdown`/`wpd → rtf` are same-variant bridges at cost 1; `wpd → pptx`/`wpd → odp` are cross-variant transforms at cost 2; `wpd → pdf` is a direct layout-engine pass, the same edge markdown's own `hasLayoutPath` justifies; everything else composes through one of those. `wpd → odf` is the one cell excluded, matching every other row: nothing routes to `odf`.
968
+ **`wpd`'s whole row is `→`, never a fidelity grade, because it is read-only.** wpd-codec has a real reader and no writer at all (a deliberate scope decision, not an omission — see that package's own Scope), so there is no reverse conversion to measure loss against the way every other pair in this table can be. `wpd → docx`/`wpd → odt`/`wpd → markdown`/`wpd → rtf` are same-variant bridges at cost 1; `wpd → pptx`/`wpd → odp` are cross-variant transforms at cost 2; `wpd → pdf` is a direct layout-engine pass, the same edge markdown's own `hasLayoutPath` justifies; everything else composes through one of those. `wpd → odf` is the one cell excluded, matching every other row, and `wpd → doc`/`wpd → xls`/`wpd → ppt` route exactly as `wpd`'s reach into `rtf` already does — same-variant/cross-variant edges into a narrower legacy sibling, still `→` rather than a grade, since `wpd` never carries a reverse direction to measure loss against regardless of how rich or narrow the target is.
969
+
970
+ **`doc`'s own bridges lose far more than `rtf`'s did, and its writer refuses rather than approximates a genuine construct kind.** doc-codec's reader (see that package's own [Status](../doc-codec/README.md#status)) reads real tables (row/column/cell structure, horizontal and vertical merge) but still drops images, style-inherited formatting, subdocuments, every section beyond the first, numbering definitions, metadata, and hyperlinks/fields — a much narrower read than docx/odt offer, so every `doc → X` cell in this table stays `✗` regardless of `X`'s own richness: that content is already gone before any target is reached, tables now surviving the crossing notwithstanding. Going the other way, `writeDocContent` writes a `ContentTable` (a table nested inside a table cell is the one genuine table-shaped refusal, alongside cell shading/borders it silently does not carry — see doc-codec's own [Tables](../doc-codec/README.md#tables) section) but still does not approximate an image or a section beyond the first — it throws `DocUnsupportedError` rather than dropping or flattening either. Every `X → doc` cell where `X`'s own content can genuinely carry an image (`docx`, `odt`, `markdown`, `rtf`, and anything reconstructed with one via a PDF pivot) stays rated `✗` on the same basis as every other `doc` cell, and for those sources that direction can still mean the conversion fails outright for a real document rather than merely losing formatting — there is no partial write for a document containing an image, though a table alone no longer forces that failure.
971
+
972
+ **`xls`'s writer never touches formulas, per-cell fonts, or images**, so `xls⇄xlsx`/`xls⇄ods` are rated `✗` rather than the `~` their full-featured `xlsx⇄ods` counterpart earns: a real workbook's formulas and per-cell font are silently dropped in both directions (neither is ever read by xls-codec, so neither can be written back either — see that package's own [Writer scope](../xls-codec/README.md#writer-scope) and [Read-side gaps](../xls-codec/README.md#read-side-gaps)), a materially bigger gap than `xlsx⇄ods`'s own "small format-boundary limits" (time cells, formula dialects). A cell's background fill and per-side borders, its own alignment, a sheet's print settings, and the workbook's own metadata do all survive the crossing — each is read and written for real by xls-codec — so the downgrade rests on formulas and font alone. `csv⇄xls` is the one `xls` pair that escapes this downgrade: csv can carry neither formulas nor per-cell fonts to begin with, so it loses nothing crossing into `xls` that it would not also lose crossing into `xlsx`/`ods` — `csv → xls` is `✓`, matching `csv → xlsx`/`csv → ods`, and `xls → csv` is `~`, matching `xlsx → csv`, since csv always collapses a cell to its `displayText` regardless of how rich the source was. `xls⇄markdown` needs the identical extra `ods`-bridge hop before the same PDF pivot that already earns `xlsx⇄markdown`/`csv⇄markdown` their `✗✗` — so `xls⇄markdown` is `✗✗` too, for the same reason. A `.xls` cell grid outside BIFF8's own 65536-row/256-column limit is refused outright, the one write-side hard stop `xls-codec` shares with `doc-codec`'s own refusals.
973
+
974
+ **`ppt`'s writer drops what it can't express instead of throwing**, unlike `doc`'s: an image, table, or OLE-embedded shape is silently excluded from the written text body rather than refusing the whole conversion (see that package's own [Writing a document](../ppt-codec/README.md#writing-a-document)) — genuinely gentler failure behaviour than `doc`'s hard stop, but the loss itself is just as real, so `ppt` cells are rated `✗` on the same basis as `doc`'s rather than upgraded for failing more softly. `ppt`'s reader is narrower again than `pptx`'s own: only plain text-box shapes with basic character formatting come back at all — no images, tables, OLE objects, masters, layouts, scheme colours, or per-shape insets (see that package's own [What it does not read yet](../ppt-codec/README.md#what-it-does-not-read-yet)) — so every `ppt → X` cell already reflects that ceiling before `X`'s own capacity ever matters.
932
975
 
933
976
  **`.odb` extraction** is genuine verified data extraction across all four tiers, differing by what each storage shape carries. BLOB content recovers byte-for-byte. No reverse direction.
934
977
 
@@ -13,9 +13,12 @@ const require_csv_text = require("../csv/text.cjs");
13
13
  const require_csv_read = require("../csv/read.cjs");
14
14
  const require_svg_text = require("../svg/text.cjs");
15
15
  const require_svg_read = require("../svg/read.cjs");
16
+ const require_ppt_read = require("../ppt/read.cjs");
16
17
  const require_ports_abort = require("../ports/abort.cjs");
17
18
  const require_package_codec = require("../package-codec.cjs");
18
19
  let ooxml_js = require("ooxml.js");
20
+ let doc_codec = require("doc-codec");
21
+ let xls_codec = require("xls-codec");
19
22
  let rtf_codec = require("rtf-codec");
20
23
  let wpd_codec = require("wpd-codec");
21
24
  let pdf_codec_read = require("pdf-codec/read");
@@ -56,10 +59,22 @@ const CONTENT_READERS = {
56
59
  csv: (bytes) => require_csv_read.readCsvContent(require_csv_text.decodeCsvText(bytes)),
57
60
  svg: (bytes) => require_svg_read.readSvgContent(require_svg_text.decodeSvgText(bytes)),
58
61
  rtf: (bytes, options) => (0, rtf_codec.readRtfContent)(bytes, { signal: options?.signal }).document,
62
+ doc: (bytes, options) => {
63
+ require_ports_abort.throwIfAborted(options?.signal);
64
+ return (0, doc_codec.readDocContent)(require_model_bytes.requireArrayBufferBytes(bytes));
65
+ },
59
66
  xlsx: (bytes, options) => {
60
67
  require_ports_abort.throwIfAborted(options?.signal);
61
68
  return (0, ooxml_js.readXlsxContent)(require_package_codec.decodeDocumentPackage("xlsx", require_model_bytes.requireArrayBufferBytes(bytes)));
62
69
  },
70
+ xls: (bytes, options) => {
71
+ require_ports_abort.throwIfAborted(options?.signal);
72
+ return (0, xls_codec.readXlsContent)(require_model_bytes.requireArrayBufferBytes(bytes));
73
+ },
74
+ ppt: (bytes, options) => {
75
+ require_ports_abort.throwIfAborted(options?.signal);
76
+ return require_ppt_read.readPptContent(require_model_bytes.requireArrayBufferBytes(bytes));
77
+ },
63
78
  wpd: (bytes, options) => {
64
79
  require_ports_abort.throwIfAborted(options?.signal);
65
80
  return (0, wpd_codec.readWpdContent)(bytes);
@@ -12,9 +12,12 @@ import { decodeCsvText } from "../csv/text.js";
12
12
  import { readCsvContent } from "../csv/read.js";
13
13
  import { decodeSvgText } from "../svg/text.js";
14
14
  import { readSvgContent } from "../svg/read.js";
15
+ import { readPptContent } from "../ppt/read.js";
15
16
  import { throwIfAborted } from "../ports/abort.js";
16
17
  import { decodeDocumentPackage } from "../package-codec.js";
17
18
  import { readXlsxContent } from "ooxml.js";
19
+ import { readDocContent } from "doc-codec";
20
+ import { readXlsContent } from "xls-codec";
18
21
  import { readRtfContent } from "rtf-codec";
19
22
  import { readWpdContent } from "wpd-codec";
20
23
  import { readPdf } from "pdf-codec/read";
@@ -55,10 +58,22 @@ const CONTENT_READERS = {
55
58
  csv: (bytes) => readCsvContent(decodeCsvText(bytes)),
56
59
  svg: (bytes) => readSvgContent(decodeSvgText(bytes)),
57
60
  rtf: (bytes, options) => readRtfContent(bytes, { signal: options?.signal }).document,
61
+ doc: (bytes, options) => {
62
+ throwIfAborted(options?.signal);
63
+ return readDocContent(requireArrayBufferBytes(bytes));
64
+ },
58
65
  xlsx: (bytes, options) => {
59
66
  throwIfAborted(options?.signal);
60
67
  return readXlsxContent(decodeDocumentPackage("xlsx", requireArrayBufferBytes(bytes)));
61
68
  },
69
+ xls: (bytes, options) => {
70
+ throwIfAborted(options?.signal);
71
+ return readXlsContent(requireArrayBufferBytes(bytes));
72
+ },
73
+ ppt: (bytes, options) => {
74
+ throwIfAborted(options?.signal);
75
+ return readPptContent(requireArrayBufferBytes(bytes));
76
+ },
62
77
  wpd: (bytes, options) => {
63
78
  throwIfAborted(options?.signal);
64
79
  return readWpdContent(bytes);
@@ -11,10 +11,13 @@ const require_csv_text = require("../csv/text.cjs");
11
11
  const require_csv_write = require("../csv/write.cjs");
12
12
  const require_svg_text = require("../svg/text.cjs");
13
13
  const require_svg_write = require("../svg/write.cjs");
14
+ const require_ppt_write = require("../ppt/write.cjs");
14
15
  const require_package_codec = require("../package-codec.cjs");
15
16
  const require_codecs_read = require("./read.cjs");
16
17
  let ooxml_js = require("ooxml.js");
17
18
  let pdf_codec = require("pdf-codec");
19
+ let doc_codec = require("doc-codec");
20
+ let xls_codec = require("xls-codec");
18
21
  let rtf_codec = require("rtf-codec");
19
22
  //#region src/codecs/registry.ts
20
23
  const DOCUMENT_FORMAT_CODECS = {
@@ -59,6 +62,21 @@ const DOCUMENT_FORMAT_CODECS = {
59
62
  read: require_codecs_read.CONTENT_READERS.rtf,
60
63
  write: (content) => (0, rtf_codec.writeRtfContent)(content)
61
64
  } },
65
+ doc: { content: {
66
+ read: require_codecs_read.CONTENT_READERS.doc,
67
+ write: (content) => (0, doc_codec.writeDocContent)(content)
68
+ } },
69
+ xls: { content: {
70
+ read: require_codecs_read.CONTENT_READERS.xls,
71
+ write: (content) => {
72
+ if (content.kind !== "spreadsheet") throw new Error("DOCUMENT_FORMAT_CODECS.xls.content.write: expected a spreadsheet ContentDocument");
73
+ return (0, xls_codec.writeXlsContent)(content);
74
+ }
75
+ } },
76
+ ppt: { content: {
77
+ read: require_codecs_read.CONTENT_READERS.ppt,
78
+ write: (content) => require_ppt_write.writePptContent(content)
79
+ } },
62
80
  pdf: { layout: {
63
81
  read: require_codecs_read.readDocumentLayout,
64
82
  write: (layout, options) => (0, pdf_codec.writePdf)(layout, { signal: options?.signal })
@@ -10,10 +10,13 @@ import { encodeCsvText } from "../csv/text.js";
10
10
  import { buildCsvText } from "../csv/write.js";
11
11
  import { encodeSvgText } from "../svg/text.js";
12
12
  import { buildSvgText } from "../svg/write.js";
13
+ import { writePptContent } from "../ppt/write.js";
13
14
  import { encodeDocumentPackage } from "../package-codec.js";
14
15
  import { CONTENT_READERS, readDocumentLayout } from "./read.js";
15
16
  import { buildXlsxPackageFromContent } from "ooxml.js";
16
17
  import { writePdf } from "pdf-codec";
18
+ import { writeDocContent } from "doc-codec";
19
+ import { writeXlsContent } from "xls-codec";
17
20
  import { writeRtfContent } from "rtf-codec";
18
21
  //#region src/codecs/registry.ts
19
22
  const DOCUMENT_FORMAT_CODECS = {
@@ -58,6 +61,21 @@ const DOCUMENT_FORMAT_CODECS = {
58
61
  read: CONTENT_READERS.rtf,
59
62
  write: (content) => writeRtfContent(content)
60
63
  } },
64
+ doc: { content: {
65
+ read: CONTENT_READERS.doc,
66
+ write: (content) => writeDocContent(content)
67
+ } },
68
+ xls: { content: {
69
+ read: CONTENT_READERS.xls,
70
+ write: (content) => {
71
+ if (content.kind !== "spreadsheet") throw new Error("DOCUMENT_FORMAT_CODECS.xls.content.write: expected a spreadsheet ContentDocument");
72
+ return writeXlsContent(content);
73
+ }
74
+ } },
75
+ ppt: { content: {
76
+ read: CONTENT_READERS.ppt,
77
+ write: (content) => writePptContent(content)
78
+ } },
61
79
  pdf: { layout: {
62
80
  read: readDocumentLayout,
63
81
  write: (layout, options) => writePdf(layout, { signal: options?.signal })
@@ -73,6 +73,24 @@ const FORMAT_CAPABILITIES = {
73
73
  hasLayoutPath: false,
74
74
  readOnly: false
75
75
  },
76
+ doc: {
77
+ format: "doc",
78
+ variant: "wordprocessing",
79
+ hasLayoutPath: false,
80
+ readOnly: false
81
+ },
82
+ xls: {
83
+ format: "xls",
84
+ variant: "spreadsheet",
85
+ hasLayoutPath: false,
86
+ readOnly: false
87
+ },
88
+ ppt: {
89
+ format: "ppt",
90
+ variant: "presentation",
91
+ hasLayoutPath: false,
92
+ readOnly: false
93
+ },
76
94
  wpd: {
77
95
  format: "wpd",
78
96
  variant: "wordprocessing",
@@ -72,6 +72,24 @@ const FORMAT_CAPABILITIES = {
72
72
  hasLayoutPath: false,
73
73
  readOnly: false
74
74
  },
75
+ doc: {
76
+ format: "doc",
77
+ variant: "wordprocessing",
78
+ hasLayoutPath: false,
79
+ readOnly: false
80
+ },
81
+ xls: {
82
+ format: "xls",
83
+ variant: "spreadsheet",
84
+ hasLayoutPath: false,
85
+ readOnly: false
86
+ },
87
+ ppt: {
88
+ format: "ppt",
89
+ variant: "presentation",
90
+ hasLayoutPath: false,
91
+ readOnly: false
92
+ },
75
93
  wpd: {
76
94
  format: "wpd",
77
95
  variant: "wordprocessing",
@@ -37,6 +37,18 @@ const rtfPdfCodec = zod.z.codec(rtf_codec.RtfBytesSchema, require_model_bytes.Pd
37
37
  decode: (rtfBytes) => require_convert_convert.rtfToPdf(rtfBytes),
38
38
  encode: (pdfBytes) => require_convert_from_pdf.pdfToRtf(pdfBytes)
39
39
  });
40
+ const docPdfCodec = zod.z.codec(require_model_bytes.DocBytesSchema, require_model_bytes.PdfBytesSchema, {
41
+ decode: (docBytes) => require_convert_convert.docToPdf(docBytes),
42
+ encode: (pdfBytes) => require_convert_from_pdf.pdfToDoc(pdfBytes)
43
+ });
44
+ const xlsPdfCodec = zod.z.codec(require_model_bytes.XlsBytesSchema, require_model_bytes.PdfBytesSchema, {
45
+ decode: (xlsBytes) => require_convert_convert.xlsToPdf(xlsBytes),
46
+ encode: (pdfBytes) => require_convert_from_pdf.pdfToXls(pdfBytes)
47
+ });
48
+ const pptPdfCodec = zod.z.codec(require_model_bytes.PptBytesSchema, require_model_bytes.PdfBytesSchema, {
49
+ decode: (pptBytes) => require_convert_convert.pptToPdf(pptBytes),
50
+ encode: (pdfBytes) => require_convert_from_pdf.pdfToPpt(pdfBytes)
51
+ });
40
52
  const markdownPdfCodec = zod.z.codec(require_model_bytes.MarkdownBytesSchema, require_model_bytes.PdfBytesSchema, {
41
53
  decode: (markdownBytes) => require_convert_convert.markdownToPdf(markdownBytes),
42
54
  encode: (pdfBytes) => require_convert_from_pdf.pdfToMarkdown(pdfBytes)
@@ -92,6 +104,7 @@ const csvMarkdownCodec = zod.z.codec(require_model_bytes.CsvBytesSchema, require
92
104
  //#endregion
93
105
  exports.csvMarkdownCodec = csvMarkdownCodec;
94
106
  exports.csvPdfCodec = csvPdfCodec;
107
+ exports.docPdfCodec = docPdfCodec;
95
108
  exports.docxPdfCodec = docxPdfCodec;
96
109
  exports.markdownDocxCodec = markdownDocxCodec;
97
110
  exports.markdownOdtCodec = markdownOdtCodec;
@@ -105,9 +118,11 @@ exports.odsPdfCodec = odsPdfCodec;
105
118
  exports.odsXlsxCodec = odsXlsxCodec;
106
119
  exports.odtDocxCodec = odtDocxCodec;
107
120
  exports.odtPdfCodec = odtPdfCodec;
121
+ exports.pptPdfCodec = pptPdfCodec;
108
122
  exports.pptxPdfCodec = pptxPdfCodec;
109
123
  exports.rtfPdfCodec = rtfPdfCodec;
110
124
  exports.svgPdfCodec = svgPdfCodec;
125
+ exports.xlsPdfCodec = xlsPdfCodec;
111
126
  exports.xlsxCsvCodec = xlsxCsvCodec;
112
127
  exports.xlsxMarkdownCodec = xlsxMarkdownCodec;
113
128
  exports.xlsxPdfCodec = xlsxPdfCodec;
@@ -8,6 +8,9 @@ declare const odsPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8
8
8
  declare const odgPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
9
9
  declare const xlsxPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
10
10
  declare const rtfPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
11
+ declare const docPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
12
+ declare const xlsPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
13
+ declare const pptPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
11
14
  declare const markdownPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
12
15
  declare const svgPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
13
16
  declare const odtDocxCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
@@ -22,4 +25,4 @@ declare const xlsxCsvCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint
22
25
  declare const odgSvgCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
23
26
  declare const csvMarkdownCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
24
27
  //#endregion
25
- export { csvMarkdownCodec, csvPdfCodec, docxPdfCodec, markdownDocxCodec, markdownOdtCodec, markdownPdfCodec, odgPdfCodec, odgSvgCodec, odpPdfCodec, odpPptxCodec, odsCsvCodec, odsPdfCodec, odsXlsxCodec, odtDocxCodec, odtPdfCodec, pptxPdfCodec, rtfPdfCodec, svgPdfCodec, xlsxCsvCodec, xlsxMarkdownCodec, xlsxPdfCodec };
28
+ export { csvMarkdownCodec, csvPdfCodec, docPdfCodec, docxPdfCodec, markdownDocxCodec, markdownOdtCodec, markdownPdfCodec, odgPdfCodec, odgSvgCodec, odpPdfCodec, odpPptxCodec, odsCsvCodec, odsPdfCodec, odsXlsxCodec, odtDocxCodec, odtPdfCodec, pptPdfCodec, pptxPdfCodec, rtfPdfCodec, svgPdfCodec, xlsPdfCodec, xlsxCsvCodec, xlsxMarkdownCodec, xlsxPdfCodec };
@@ -8,6 +8,9 @@ declare const odsPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8
8
8
  declare const odgPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
9
9
  declare const xlsxPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
10
10
  declare const rtfPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
11
+ declare const docPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
12
+ declare const xlsPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
13
+ declare const pptPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
11
14
  declare const markdownPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
12
15
  declare const svgPdfCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
13
16
  declare const odtDocxCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
@@ -22,4 +25,4 @@ declare const xlsxCsvCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint
22
25
  declare const odgSvgCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
23
26
  declare const csvMarkdownCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>, z.ZodCustom<Uint8Array<ArrayBuffer>, Uint8Array<ArrayBuffer>>>;
24
27
  //#endregion
25
- export { csvMarkdownCodec, csvPdfCodec, docxPdfCodec, markdownDocxCodec, markdownOdtCodec, markdownPdfCodec, odgPdfCodec, odgSvgCodec, odpPdfCodec, odpPptxCodec, odsCsvCodec, odsPdfCodec, odsXlsxCodec, odtDocxCodec, odtPdfCodec, pptxPdfCodec, rtfPdfCodec, svgPdfCodec, xlsxCsvCodec, xlsxMarkdownCodec, xlsxPdfCodec };
28
+ export { csvMarkdownCodec, csvPdfCodec, docPdfCodec, docxPdfCodec, markdownDocxCodec, markdownOdtCodec, markdownPdfCodec, odgPdfCodec, odgSvgCodec, odpPdfCodec, odpPptxCodec, odsCsvCodec, odsPdfCodec, odsXlsxCodec, odtDocxCodec, odtPdfCodec, pptPdfCodec, pptxPdfCodec, rtfPdfCodec, svgPdfCodec, xlsPdfCodec, xlsxCsvCodec, xlsxMarkdownCodec, xlsxPdfCodec };
@@ -1,6 +1,6 @@
1
- import { CsvBytesSchema, DocxBytesSchema, MarkdownBytesSchema, OdgBytesSchema, OdpBytesSchema, OdsBytesSchema, OdtBytesSchema, PdfBytesSchema, PptxBytesSchema, SvgBytesSchema, XlsxBytesSchema } from "../model/bytes.js";
2
- import { csvToMarkdown, csvToOds, csvToPdf, csvToXlsx, docxToMarkdown, docxToOdt, docxToPdf, markdownToCsv, markdownToDocx, markdownToOdt, markdownToPdf, markdownToXlsx, odgToPdf, odgToSvg, odpToPdf, odpToPptx, odsToCsv, odsToPdf, odsToXlsx, odtToDocx, odtToMarkdown, odtToPdf, pptxToOdp, pptxToPdf, rtfToPdf, svgToOdg, svgToPdf, xlsxToCsv, xlsxToMarkdown, xlsxToOds, xlsxToPdf } from "./convert.js";
3
- import { pdfToCsv, pdfToDocx, pdfToMarkdown, pdfToOdg, pdfToOdp, pdfToOds, pdfToOdt, pdfToPptx, pdfToRtf, pdfToSvg, pdfToXlsx } from "./from-pdf.js";
1
+ import { CsvBytesSchema, DocBytesSchema, DocxBytesSchema, MarkdownBytesSchema, OdgBytesSchema, OdpBytesSchema, OdsBytesSchema, OdtBytesSchema, PdfBytesSchema, PptBytesSchema, PptxBytesSchema, SvgBytesSchema, XlsBytesSchema, XlsxBytesSchema } from "../model/bytes.js";
2
+ import { csvToMarkdown, csvToOds, csvToPdf, csvToXlsx, docToPdf, docxToMarkdown, docxToOdt, docxToPdf, markdownToCsv, markdownToDocx, markdownToOdt, markdownToPdf, markdownToXlsx, odgToPdf, odgToSvg, odpToPdf, odpToPptx, odsToCsv, odsToPdf, odsToXlsx, odtToDocx, odtToMarkdown, odtToPdf, pptToPdf, pptxToOdp, pptxToPdf, rtfToPdf, svgToOdg, svgToPdf, xlsToPdf, xlsxToCsv, xlsxToMarkdown, xlsxToOds, xlsxToPdf } from "./convert.js";
3
+ import { pdfToCsv, pdfToDoc, pdfToDocx, pdfToMarkdown, pdfToOdg, pdfToOdp, pdfToOds, pdfToOdt, pdfToPpt, pdfToPptx, pdfToRtf, pdfToSvg, pdfToXls, pdfToXlsx } from "./from-pdf.js";
4
4
  import { z } from "zod";
5
5
  import { RtfBytesSchema } from "rtf-codec";
6
6
  //#region src/convert/codec.ts
@@ -36,6 +36,18 @@ const rtfPdfCodec = z.codec(RtfBytesSchema, PdfBytesSchema, {
36
36
  decode: (rtfBytes) => rtfToPdf(rtfBytes),
37
37
  encode: (pdfBytes) => pdfToRtf(pdfBytes)
38
38
  });
39
+ const docPdfCodec = z.codec(DocBytesSchema, PdfBytesSchema, {
40
+ decode: (docBytes) => docToPdf(docBytes),
41
+ encode: (pdfBytes) => pdfToDoc(pdfBytes)
42
+ });
43
+ const xlsPdfCodec = z.codec(XlsBytesSchema, PdfBytesSchema, {
44
+ decode: (xlsBytes) => xlsToPdf(xlsBytes),
45
+ encode: (pdfBytes) => pdfToXls(pdfBytes)
46
+ });
47
+ const pptPdfCodec = z.codec(PptBytesSchema, PdfBytesSchema, {
48
+ decode: (pptBytes) => pptToPdf(pptBytes),
49
+ encode: (pdfBytes) => pdfToPpt(pdfBytes)
50
+ });
39
51
  const markdownPdfCodec = z.codec(MarkdownBytesSchema, PdfBytesSchema, {
40
52
  decode: (markdownBytes) => markdownToPdf(markdownBytes),
41
53
  encode: (pdfBytes) => pdfToMarkdown(pdfBytes)
@@ -89,4 +101,4 @@ const csvMarkdownCodec = z.codec(CsvBytesSchema, MarkdownBytesSchema, {
89
101
  encode: (markdownBytes) => markdownToCsv(markdownBytes)
90
102
  });
91
103
  //#endregion
92
- export { csvMarkdownCodec, csvPdfCodec, docxPdfCodec, markdownDocxCodec, markdownOdtCodec, markdownPdfCodec, odgPdfCodec, odgSvgCodec, odpPdfCodec, odpPptxCodec, odsCsvCodec, odsPdfCodec, odsXlsxCodec, odtDocxCodec, odtPdfCodec, pptxPdfCodec, rtfPdfCodec, svgPdfCodec, xlsxCsvCodec, xlsxMarkdownCodec, xlsxPdfCodec };
104
+ export { csvMarkdownCodec, csvPdfCodec, docPdfCodec, docxPdfCodec, markdownDocxCodec, markdownOdtCodec, markdownPdfCodec, odgPdfCodec, odgSvgCodec, odpPdfCodec, odpPptxCodec, odsCsvCodec, odsPdfCodec, odsXlsxCodec, odtDocxCodec, odtPdfCodec, pptPdfCodec, pptxPdfCodec, rtfPdfCodec, svgPdfCodec, xlsPdfCodec, xlsxCsvCodec, xlsxMarkdownCodec, xlsxPdfCodec };