odf.js 1.10.2 → 1.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -10
- package/dist/index.cjs +10 -10
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
**This package does not depend on `ooxml.js`**, even though the two do near-identical jobs for their respective formats: `ooxml.js` is a package signed, SBOM-attested, and branded exclusively around ECMA-376/OOXML, so depending on it here would be a permanently wrong signal for an OASIS-standard codec, and would force a breaking `ooxml.js` release every time an ODF-only fix needed the shared primitive layer. Instead, `odf.js` duplicates the small (~400-line) generic ZIP/XML/`Package` layer as its own code — kept deliberately structurally identical (plain, unmarked shapes, no branding) so TypeScript's structural typing makes the two packages' `Package`/`XmlNode`/`XmlElement` values freely interchangeable wherever a shared consumer (like `documents.js`) needs to treat them uniformly, without either package formally depending on the other.
|
|
10
10
|
|
|
11
|
-
Both packages **do** depend on [`document-
|
|
11
|
+
Both packages **do** depend on [`document-schema.js`](https://github.com/ExaDev/document-schema.js), the genuinely shared canonical schema for `ContentDocument`/`LayoutDocument` — the semantic content model (paragraphs, runs, tables, shapes, slides) both an ODF and an OOXML reader ultimately produce. `odf.js`'s typed readers return the real, imported `ContentSection`/`ContentSlide`/etc. types from that package, not a structurally-similar lookalike, so a downstream consumer (`documents.js`) can run an `.odt` through the exact same layout/pagination engine it already uses for `.docx`, unmodified.
|
|
12
12
|
|
|
13
13
|
## Status
|
|
14
14
|
|
|
@@ -17,9 +17,9 @@ This package is under active development. What's built and shipped:
|
|
|
17
17
|
- **Lossless core** — generic ZIP-of-XML primitives (`Package`/`XmlNode`/`XmlElement`, XML parse/build, zip/unzip, base64, the `packageCodec`/`xmlCodec` `z.codec()` pairs) with zero ODF-specific knowledge.
|
|
18
18
|
- **Namespaces, media types, mimetype, manifest** (`src/ns.ts`, `src/media-type.ts`, `src/mimetype.ts`, `src/manifest.ts`) — full read *and* write, including `META-INF/manifest.xml`'s exhaustive per-part enumeration and the mimetype part's mandatory first-entry/stored/uncompressed byte layout, verified against real LibreOffice-produced output.
|
|
19
19
|
- **Style interning** (`src/styles/`) — `StyleRegistry`: adopts a part's existing automatic styles on construction, finds-or-mints on `intern()`, fingerprints on canonical serialized properties plus parent style name (never `JSON.stringify`), and is collision-checked across all four style containers a document can have.
|
|
20
|
-
- **Shared typed primitives** (`src/typed/shared/`) — ODF length-unit parsing (`cm`/`mm`/`in`/`pt`/`pc`/`px`), A1-style spreadsheet cell-reference computation with repeat-count cursor advancement, colour/geometry/master-page-size parsing into `document-
|
|
21
|
-
- **Typed readers** — `readOdt` (wordprocessing), `readOdp` (presentation slides: `draw:frame`/`draw:g` text/image/table content), `readOdg` (drawing pages: every vector primitive — `draw:rect`/`draw:ellipse`/`draw:circle`/`draw:line`/`draw:path`/`draw:polygon`/`draw:polyline`, plus a recognised `draw:custom-shape` preset subset — in real `draw:z-index`-aware paint order), and `readOds` (spreadsheets: geometry- and print-settings-rich, every `office:value-type` variant with its own OpenFormula string) each resolve a `Package` into `document-
|
|
22
|
-
- **`readOdfFormula`** resolves a standalone or embedded `.odf` formula's `content.xml` — bare MathML with no `office:document-content` wrapper, confirmed against real LibreOffice output — into its raw MathML nodes plus, when present, the formula's own native StarMath annotation string. There is no `document-
|
|
20
|
+
- **Shared typed primitives** (`src/typed/shared/`) — ODF length-unit parsing (`cm`/`mm`/`in`/`pt`/`pc`/`px`), A1-style spreadsheet cell-reference computation with repeat-count cursor advancement, colour/geometry/master-page-size parsing into `document-schema.js`'s own types, ODF's `text:s`/`text:tab`/`text:line-break` whitespace-run decoding, the read-side style cascade (`style:default-style` → parent chain → the referenced style — one layer shorter than OOXML's, since ODF has no separate direct-formatting layer on top), the shared `text:p` → `ContentParagraph`/`ContentRun` and `table:table` → `ContentTable` readers (`readOdfParagraph`/`readOdfTable`) every typed reader below builds on, the `draw:transform`/`draw:g` group-flattening geometry resolver, an `svg:d`/`draw:points` vector-path grammar parser, and `meta.xml` reading.
|
|
21
|
+
- **Typed readers** — `readOdt` (wordprocessing), `readOdp` (presentation slides: `draw:frame`/`draw:g` text/image/table content), `readOdg` (drawing pages: every vector primitive — `draw:rect`/`draw:ellipse`/`draw:circle`/`draw:line`/`draw:path`/`draw:polygon`/`draw:polyline`, plus a recognised `draw:custom-shape` preset subset — in real `draw:z-index`-aware paint order), and `readOds` (spreadsheets: geometry- and print-settings-rich, every `office:value-type` variant with its own OpenFormula string) each resolve a `Package` into `document-schema.js`'s own `ContentSection`/`ContentSlide`/`ContentDrawPage`/`ContentSheet` shapes.
|
|
22
|
+
- **`readOdfFormula`** resolves a standalone or embedded `.odf` formula's `content.xml` — bare MathML with no `office:document-content` wrapper, confirmed against real LibreOffice output — into its raw MathML nodes plus, when present, the formula's own native StarMath annotation string. There is no `document-schema.js` pivot type for MathML, so this reader's own output type is its own.
|
|
23
23
|
- **`readOdm`** resolves a `.odm` master document's own `content.xml` into an ordered list of chapter references (`{ name, href, filterName? }`, one per top-level linked `text:section`) without opening the external `.odt` files those references point at. A master document's chapters are genuinely external files by ODF design, not embedded package sub-documents — confirmed against real LibreOffice output, which never caches a chapter's own content inside the master document itself (see `src/typed/odm/read.ts`'s own top-of-file note).
|
|
24
24
|
- **`readOdbInventory`** resolves a `.odb` database front-end package into connection info plus the *names* of its forms/queries/reports/tables — never their content, and never the embedded/external database engine's own binary or script storage. Confirmed against real LibreOffice output that `office:database` lives directly in the package's ordinary `content.xml` (no separate `database/connection.xml` part, contrary to the OASIS schema's own chapter layout suggesting one), that queries are named inline (`db:queries/db:query`, no manifest part of their own), and that a live engine's own tables have no ODF-level manifest listing at all — only forms/reports genuinely are separate manifest sub-document parts (`forms/<Name>/content.xml`, `reports/<Name>/content.xml`). See `src/typed/odb/read.ts`'s own top-of-file note for the full findings.
|
|
25
25
|
|
|
@@ -79,17 +79,17 @@ Layered from a lossless core outward, mirroring `ooxml.js`'s own structure:
|
|
|
79
79
|
- **`src/package-io/`** — `write.ts` hoists a `mimetype` part first (stored) and `META-INF/manifest.xml` second, if present, before everything else in existing order — the one deliberate behavioural difference from `ooxml.js`'s own writer, and never fabricates either part as a side effect.
|
|
80
80
|
- **`src/manifest.ts`** — unlike `ooxml.js` (which only ever *reads* OPC relationships, leaving writing to `documents.js`), `odf.js` owns manifest read **and** write, since the manifest is ODF's one mandatory part and its correctness is exhaustive.
|
|
81
81
|
- **`src/styles/`** — `properties.ts` (the property-bag shape + real ODF attribute parsing), `serialize.ts` (canonical, deterministic property-bag → XML attributes), `registry.ts` (`StyleRegistry`, ODF's mandatory style-interning layer, no OOXML equivalent), `span.ts` (character-range wrapping into a formattable `text:span`, correctly splitting `text:s`/`text:tab` elements that straddle a boundary).
|
|
82
|
-
- **`src/typed/shared/`** — the ODF-specific typed primitives every future format reader builds on: `units.ts`, `a1.ts`, `color.ts`/`geometry.ts` (parsing into `document-
|
|
83
|
-
- **`src/typed/odt/`, `src/typed/odp/`, `src/typed/odg/`, `src/typed/ods/`** — the built `readOdt`/`readOdp`/`readOdg`/`readOds` readers; **`src/typed/draw/`** — the `draw:frame`/`draw:g`/vector-primitive shape vocabulary `readOdp` and `readOdg` both share; **`src/typed/formula/`, `src/typed/odm/`** — `readOdfFormula` (raw MathML, no `document-
|
|
82
|
+
- **`src/typed/shared/`** — the ODF-specific typed primitives every future format reader builds on: `units.ts`, `a1.ts`, `color.ts`/`geometry.ts` (parsing into `document-schema.js`'s own types, never redefining them), `style.ts` (a thin re-export — ODF's style-properties concern is fully covered by `styles/properties.ts` and the cascade below), `text.ts` (whitespace-run decoding), `cascade.ts` (the read-side style-resolution walk), `paragraph.ts`/`table.ts` (`readOdfParagraph`/`readOdfTable`, the shared `text:p` → `ContentParagraph`/`ContentRun` and `table:table` → `ContentTable` readers `readOdt`, `readOds`, and `typed/draw/shapes.ts` all call), `transform.ts` (the `draw:transform`/`draw:g` group-flattening geometry resolver), `masterpage.ts` (master-page → page-layout page-size/print-settings resolution, shared by a `draw:page`'s own size and a spreadsheet's print settings), `path.ts` (an `svg:d`/`draw:points` vector-path grammar parser), `metadata.ts` (`meta.xml` reading).
|
|
83
|
+
- **`src/typed/odt/`, `src/typed/odp/`, `src/typed/odg/`, `src/typed/ods/`** — the built `readOdt`/`readOdp`/`readOdg`/`readOds` readers; **`src/typed/draw/`** — the `draw:frame`/`draw:g`/vector-primitive shape vocabulary `readOdp` and `readOdg` both share; **`src/typed/formula/`, `src/typed/odm/`** — `readOdfFormula` (raw MathML, no `document-schema.js` pivot) and `readOdm` (a `.odm` master document's own external chapter references — name/href/filter-name per linked `text:section`, never the linked content itself); **`src/typed/odb/`** — `readOdbInventory` (a `.odb` package's own connection info plus form/query/report/table *names*, never their content or the database engine's own storage).
|
|
84
84
|
|
|
85
85
|
## Why no `ooxml.js` dependency
|
|
86
86
|
|
|
87
|
-
See the top of this README — the short version: `ooxml.js`'s branding and signed SBOM make it the wrong dependency for an OASIS-standard package regardless of how much low-level code the two could share; `document-
|
|
87
|
+
See the top of this README — the short version: `ooxml.js`'s branding and signed SBOM make it the wrong dependency for an OASIS-standard package regardless of how much low-level code the two could share; `document-schema.js` is the neutral package both actually depend on for the parts that are genuinely, permanently identical (the semantic content vocabulary), while the ZIP-of-XML primitive layer stays duplicated on purpose.
|
|
88
88
|
|
|
89
89
|
## Conventions
|
|
90
90
|
|
|
91
|
-
- **Zod-first schema/type/guard**, matching `ooxml.js`/`document-
|
|
92
|
-
- **Recursive types use a hand-written structural guard, not `z.lazy`** — the same `z.lazy`-collapses-to-`unknown` issue `ooxml.js`'s `XmlNode` and `document-
|
|
91
|
+
- **Zod-first schema/type/guard**, matching `ooxml.js`/`document-schema.js`: every model type is inferred from its Zod schema, never hand-written.
|
|
92
|
+
- **Recursive types use a hand-written structural guard, not `z.lazy`** — the same `z.lazy`-collapses-to-`unknown` issue `ooxml.js`'s `XmlNode` and `document-schema.js`'s `ContentBlock` already work around.
|
|
93
93
|
- **No type assertions anywhere** — `assertionStyle: 'never'`, `noInlineConfig: true`, matching both sibling packages exactly.
|
|
94
94
|
- **Ground truth over memory for every ODF spec fact.** Namespace URIs, media types, style-property attribute names, and `meta.xml` element names are all verified against either the live OASIS ODF specification or real files produced by an installed LibreOffice, never assumed from pattern-matching an OOXML analogue or a remembered convention — several confirmed traps exist specifically because the "obvious" guess is wrong (see [Gotchas](#gotchas-and-quirks)).
|
|
95
95
|
|
|
@@ -113,7 +113,7 @@ Commits follow Conventional Commits (`feat:`, `fix:`, `test:`, `chore:`, …), e
|
|
|
113
113
|
## References
|
|
114
114
|
|
|
115
115
|
- [ooxml.js](https://github.com/ExaDev/ooxml.js) — the sibling package doing the equivalent lossless-codec job for OOXML (docx/pptx/xlsx). Architecturally mirrored, deliberately not depended on — see [Why no `ooxml.js` dependency](#why-no-ooxmljs-dependency).
|
|
116
|
-
- [document-
|
|
116
|
+
- [document-schema.js](https://github.com/ExaDev/document-schema.js) — the canonical `ContentDocument`/`LayoutDocument` schema pivot both this package and `ooxml.js` depend on.
|
|
117
117
|
- [documents.js](https://github.com/ExaDev/documents.js) — the downstream consumer, already built on this package's typed readers: its own `readOdtContent`/`readOdpContent`/`readOdsContent`/`readOdgContent` are thin adapters over `readOdt`/`readOdp`/`readOds`/`readOdg`, feeding both ODF ⇄ PDF conversion (`odtToPdf`/`odpToPdf`/`odsToPdf`/`odgToPdf` and their inverses) and independently-built live-view ODF editors (`OdtEditor`/`OdpEditor`/`OdsEditor`/`OdgEditor`).
|
|
118
118
|
|
|
119
119
|
## License
|
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
let zod = require("zod");
|
|
3
3
|
let fast_xml_parser = require("fast-xml-parser");
|
|
4
4
|
let fflate = require("fflate");
|
|
5
|
-
let
|
|
5
|
+
let document_schema_js = require("document-schema.js");
|
|
6
6
|
//#region src/model/node.ts
|
|
7
7
|
const AttributeSchema = zod.z.object({
|
|
8
8
|
name: zod.z.string(),
|
|
@@ -730,10 +730,10 @@ function formatOdfLength(pt, unit = "pt") {
|
|
|
730
730
|
const ODF_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/;
|
|
731
731
|
function parseOdfColor(value) {
|
|
732
732
|
if (!ODF_COLOR_PATTERN.test(value)) return;
|
|
733
|
-
return (0,
|
|
733
|
+
return (0, document_schema_js.rgbHexToColor)(value);
|
|
734
734
|
}
|
|
735
735
|
function formatOdfColor(color) {
|
|
736
|
-
return `#${(0,
|
|
736
|
+
return `#${(0, document_schema_js.colorToRgbHex)(color)}`;
|
|
737
737
|
}
|
|
738
738
|
//#endregion
|
|
739
739
|
//#region src/styles/properties.ts
|
|
@@ -744,8 +744,8 @@ const StylePropertiesSchema = zod.z.object({
|
|
|
744
744
|
strike: zod.z.boolean().optional(),
|
|
745
745
|
fontFamily: zod.z.string().optional(),
|
|
746
746
|
sizePt: zod.z.number().optional(),
|
|
747
|
-
color:
|
|
748
|
-
alignment:
|
|
747
|
+
color: document_schema_js.ColorSchema.optional(),
|
|
748
|
+
alignment: document_schema_js.AlignmentSchema.optional(),
|
|
749
749
|
spacingBeforePt: zod.z.number().optional(),
|
|
750
750
|
spacingAfterPt: zod.z.number().optional(),
|
|
751
751
|
lineSpacing: zod.z.number().optional(),
|
|
@@ -2487,7 +2487,7 @@ function readDrawPageContent(children, pkg) {
|
|
|
2487
2487
|
//#region src/typed/odp/read.ts
|
|
2488
2488
|
const CONTENT_PART$6 = "content.xml";
|
|
2489
2489
|
function readSlideSize(page, pkg) {
|
|
2490
|
-
return resolveDrawPageSize(page, pkg) ??
|
|
2490
|
+
return resolveDrawPageSize(page, pkg) ?? document_schema_js.SLIDE_SIZE_WIDESCREEN;
|
|
2491
2491
|
}
|
|
2492
2492
|
function readSlideNotes(page) {
|
|
2493
2493
|
const notes = childrenWithTag(page, "presentation:notes")[0];
|
|
@@ -2566,7 +2566,7 @@ function parseKnownOdfLength$1(value) {
|
|
|
2566
2566
|
if (parsed === void 0) throw new Error(`readOdt: internal error -- "${value}" is not a valid ODF length literal`);
|
|
2567
2567
|
return parsed;
|
|
2568
2568
|
}
|
|
2569
|
-
const DEFAULT_PAGE_SIZE$2 =
|
|
2569
|
+
const DEFAULT_PAGE_SIZE$2 = document_schema_js.PAGE_SIZE_A4;
|
|
2570
2570
|
const DEFAULT_MARGIN_PT$1 = parseKnownOdfLength$1("2cm");
|
|
2571
2571
|
const DEFAULT_MARGINS$1 = {
|
|
2572
2572
|
topPt: DEFAULT_MARGIN_PT$1,
|
|
@@ -2621,7 +2621,7 @@ function readOdt(pkg) {
|
|
|
2621
2621
|
//#endregion
|
|
2622
2622
|
//#region src/typed/odg/read.ts
|
|
2623
2623
|
const CONTENT_PART$4 = "content.xml";
|
|
2624
|
-
const DEFAULT_PAGE_SIZE$1 =
|
|
2624
|
+
const DEFAULT_PAGE_SIZE$1 = document_schema_js.PAGE_SIZE_A4;
|
|
2625
2625
|
function readPage(page, pkg) {
|
|
2626
2626
|
const size = resolveDrawPageSize(page, pkg) ?? DEFAULT_PAGE_SIZE$1;
|
|
2627
2627
|
const { shapes, vectors } = readDrawPageContent(page.children, pkg);
|
|
@@ -2650,7 +2650,7 @@ function parseKnownOdfLength(value) {
|
|
|
2650
2650
|
if (parsed === void 0) throw new Error(`readOds: internal error -- "${value}" is not a valid ODF length literal`);
|
|
2651
2651
|
return parsed;
|
|
2652
2652
|
}
|
|
2653
|
-
const DEFAULT_PAGE_SIZE =
|
|
2653
|
+
const DEFAULT_PAGE_SIZE = document_schema_js.PAGE_SIZE_A4;
|
|
2654
2654
|
const DEFAULT_MARGIN_PT = parseKnownOdfLength("2cm");
|
|
2655
2655
|
const DEFAULT_MARGINS = {
|
|
2656
2656
|
topPt: DEFAULT_MARGIN_PT,
|
|
@@ -3138,7 +3138,7 @@ function readOdbInventory(pkg) {
|
|
|
3138
3138
|
Object.defineProperty(exports, "AlignmentSchema", {
|
|
3139
3139
|
enumerable: true,
|
|
3140
3140
|
get: function() {
|
|
3141
|
-
return
|
|
3141
|
+
return document_schema_js.AlignmentSchema;
|
|
3142
3142
|
}
|
|
3143
3143
|
});
|
|
3144
3144
|
exports.AttributeSchema = AttributeSchema;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { Alignment, AlignmentSchema, Box, Color, ContentDrawPage, ContentParagraph, ContentPathPoint, ContentSection, ContentShape, ContentSheet, ContentSlide, ContentSubpath, ContentTable, ContentVector, LayoutMetadata, Margins, PageSize } from "document-
|
|
2
|
+
import { Alignment, AlignmentSchema, Box, Color, ContentDrawPage, ContentParagraph, ContentPathPoint, ContentSection, ContentShape, ContentSheet, ContentSlide, ContentSubpath, ContentTable, ContentVector, LayoutMetadata, Margins, PageSize } from "document-schema.js";
|
|
3
3
|
//#region src/model/node.d.ts
|
|
4
4
|
declare const AttributeSchema: z.ZodObject<{
|
|
5
5
|
name: z.ZodString;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { Alignment, AlignmentSchema, Box, Color, ContentDrawPage, ContentParagraph, ContentPathPoint, ContentSection, ContentShape, ContentSheet, ContentSlide, ContentSubpath, ContentTable, ContentVector, LayoutMetadata, Margins, PageSize } from "document-
|
|
2
|
+
import { Alignment, AlignmentSchema, Box, Color, ContentDrawPage, ContentParagraph, ContentPathPoint, ContentSection, ContentShape, ContentSheet, ContentSlide, ContentSubpath, ContentTable, ContentVector, LayoutMetadata, Margins, PageSize } from "document-schema.js";
|
|
3
3
|
//#region src/model/node.d.ts
|
|
4
4
|
declare const AttributeSchema: z.ZodObject<{
|
|
5
5
|
name: z.ZodString;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { XMLBuilder, XMLParser } from "fast-xml-parser";
|
|
3
3
|
import { unzipSync, zipSync } from "fflate";
|
|
4
|
-
import { AlignmentSchema, AlignmentSchema as AlignmentSchema$1, ColorSchema, PAGE_SIZE_A4, SLIDE_SIZE_WIDESCREEN, colorToRgbHex, rgbHexToColor } from "document-
|
|
4
|
+
import { AlignmentSchema, AlignmentSchema as AlignmentSchema$1, ColorSchema, PAGE_SIZE_A4, SLIDE_SIZE_WIDESCREEN, colorToRgbHex, rgbHexToColor } from "document-schema.js";
|
|
5
5
|
//#region src/model/node.ts
|
|
6
6
|
const AttributeSchema = z.object({
|
|
7
7
|
name: z.string(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "odf.js",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.4",
|
|
4
4
|
"description": "Type-safe, lossless round-trip conversion between OpenDocument Format packages (odt, ods, odp) and JSON, hand-written and dependency-minimal, built on Zod 4 codecs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"license": "MIT",
|
|
62
62
|
"packageManager": "pnpm@11.6.0",
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"document-
|
|
64
|
+
"document-schema.js": "^1.5.2",
|
|
65
65
|
"fast-xml-parser": "^5.10.1",
|
|
66
66
|
"fflate": "^0.8.3",
|
|
67
67
|
"zod": "^4.4.3"
|