odf-kit 0.9.7 → 0.9.8
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 +18 -0
- package/README.md +75 -4
- package/dist/ods-reader/html-renderer.d.ts +19 -0
- package/dist/ods-reader/html-renderer.d.ts.map +1 -0
- package/dist/ods-reader/html-renderer.js +123 -0
- package/dist/ods-reader/html-renderer.js.map +1 -0
- package/dist/ods-reader/index.d.ts +19 -0
- package/dist/ods-reader/index.d.ts.map +1 -0
- package/dist/ods-reader/index.js +22 -0
- package/dist/ods-reader/index.js.map +1 -0
- package/dist/ods-reader/parser.d.ts +24 -0
- package/dist/ods-reader/parser.d.ts.map +1 -0
- package/dist/ods-reader/parser.js +544 -0
- package/dist/ods-reader/parser.js.map +1 -0
- package/dist/ods-reader/types.d.ts +139 -0
- package/dist/ods-reader/types.d.ts.map +1 -0
- package/dist/ods-reader/types.js +7 -0
- package/dist/ods-reader/types.js.map +1 -0
- package/package.json +9 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@ All notable changes to odf-kit will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.9.8] - 2026-04-10
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`readOds()`** — Parse an ODS file into a structured `OdsDocumentModel`. Returns typed JavaScript values — `string`, `number`, `boolean`, `Date` — never display-formatted strings. Available via `odf-kit/ods-reader`.
|
|
13
|
+
- **`odsToHtml()`** — Convert an ODS file directly to an HTML string. Each sheet rendered as a `<table>` with inline styles. Available via `odf-kit/ods-reader`.
|
|
14
|
+
- **`OdsDocumentModel`** — sheets → rows → cells with `value`, `type`, `formula?`, `displayText?`, `colSpan?`, `rowSpan?`, `formatting?`.
|
|
15
|
+
- **Cell types:** `"string"`, `"float"`, `"date"`, `"boolean"`, `"formula"`, `"empty"`, `"covered"`.
|
|
16
|
+
- **Formula cells** — `value` is the cached result, `formula` is the original formula string (e.g. `"=SUM(A1:A10)"`).
|
|
17
|
+
- **Merged cell handling** — primary cell has `colSpan`/`rowSpan`, covered cells have `type: "covered"` and `value: null` at correct physical column indices.
|
|
18
|
+
- **Cell formatting** — `OdsCellFormatting` with bold, italic, underline, fontSize, fontFamily, color, backgroundColor, textAlign, verticalAlign, numberFormat, dateFormat. Set `includeFormatting: false` for faster parsing when only values are needed.
|
|
19
|
+
- **Sheet metadata** — tab color, freeze rows/columns read from settings.xml.
|
|
20
|
+
- **Document metadata** — title, creator, description from meta.xml.
|
|
21
|
+
- **`odf-kit/ods-reader`** sub-export added.
|
|
22
|
+
- **`odf-kit/odt-reader`** alias added for `odf-kit/reader` — consistent naming with `odf-kit/ods-reader`.
|
|
23
|
+
- 40 new tests (889 total).
|
|
24
|
+
|
|
8
25
|
## [0.9.7] - 2026-04-10
|
|
9
26
|
|
|
10
27
|
### Added
|
|
@@ -169,6 +186,7 @@ Initial release. Complete ODT generation support.
|
|
|
169
186
|
- Tables, page layout, headers/footers, page breaks, lists, tab stops.
|
|
170
187
|
- Method chaining. Full TypeScript types. ESM-only, Node.js 22+. 102 tests.
|
|
171
188
|
|
|
189
|
+
[0.9.8]: https://github.com/GitHubNewbie0/odf-kit/releases/tag/v0.9.8
|
|
172
190
|
[0.9.7]: https://github.com/GitHubNewbie0/odf-kit/releases/tag/v0.9.7
|
|
173
191
|
[0.9.6]: https://github.com/GitHubNewbie0/odf-kit/releases/tag/v0.9.6
|
|
174
192
|
[0.9.5]: https://github.com/GitHubNewbie0/odf-kit/releases/tag/v0.9.5
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Generate, fill, read, and convert OpenDocument Format files (.odt, .ods) in Type
|
|
|
8
8
|
npm install odf-kit
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Nine ways to work with ODF files
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
14
|
// 1. Build an ODT document from scratch
|
|
@@ -119,7 +119,16 @@ const html = odtToHtml(bytes); // styled HTML string
|
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
```typescript
|
|
122
|
-
// 8.
|
|
122
|
+
// 8. Read an existing .ods spreadsheet
|
|
123
|
+
import { readOds, odsToHtml } from "odf-kit/ods-reader";
|
|
124
|
+
|
|
125
|
+
const bytes = readFileSync("data.ods");
|
|
126
|
+
const model = readOds(bytes); // structured model — typed values
|
|
127
|
+
const html = odsToHtml(bytes); // HTML table string
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// 9. Convert .odt to Typst for PDF generation
|
|
123
132
|
import { odtToTypst } from "odf-kit/typst";
|
|
124
133
|
import { execSync } from "child_process";
|
|
125
134
|
|
|
@@ -140,7 +149,8 @@ Node.js 22+ required. ESM only. Sub-exports:
|
|
|
140
149
|
|
|
141
150
|
```typescript
|
|
142
151
|
import { OdtDocument, OdsDocument, htmlToOdt, markdownToOdt, tiptapToOdt, fillTemplate } from "odf-kit";
|
|
143
|
-
import { readOdt, odtToHtml }
|
|
152
|
+
import { readOdt, odtToHtml } from "odf-kit/odt-reader";
|
|
153
|
+
import { readOds, odsToHtml } from "odf-kit/ods-reader";
|
|
144
154
|
import { odtToTypst, modelToTypst } from "odf-kit/typst";
|
|
145
155
|
```
|
|
146
156
|
|
|
@@ -597,7 +607,7 @@ Falsy values (`false`, `null`, `undefined`, `0`, `""`, `[]`) remove the block. T
|
|
|
597
607
|
`odf-kit/reader` parses `.odt` files into a structured model and renders to HTML.
|
|
598
608
|
|
|
599
609
|
```typescript
|
|
600
|
-
import { readOdt, odtToHtml } from "odf-kit/reader";
|
|
610
|
+
import { readOdt, odtToHtml } from "odf-kit/odt-reader";
|
|
601
611
|
|
|
602
612
|
const bytes = readFileSync("report.odt");
|
|
603
613
|
const model = readOdt(bytes);
|
|
@@ -611,6 +621,65 @@ const marked = odtToHtml(bytes, {}, { trackedChanges: "changes" });
|
|
|
611
621
|
|
|
612
622
|
---
|
|
613
623
|
|
|
624
|
+
## Read: ODS Spreadsheets
|
|
625
|
+
|
|
626
|
+
`odf-kit/ods-reader` parses `.ods` files into a structured model and renders to HTML.
|
|
627
|
+
|
|
628
|
+
```typescript
|
|
629
|
+
import { readOds, odsToHtml } from "odf-kit/ods-reader";
|
|
630
|
+
import { readFileSync } from "fs";
|
|
631
|
+
|
|
632
|
+
const bytes = readFileSync("data.ods");
|
|
633
|
+
|
|
634
|
+
// Structured model — typed JavaScript values
|
|
635
|
+
const model = readOds(bytes);
|
|
636
|
+
for (const sheet of model.sheets) {
|
|
637
|
+
console.log(sheet.name);
|
|
638
|
+
for (const row of sheet.rows) {
|
|
639
|
+
for (const cell of row.cells) {
|
|
640
|
+
console.log(cell.colIndex, cell.type, cell.value);
|
|
641
|
+
// e.g. 0 "float" 1234.56
|
|
642
|
+
// e.g. 1 "string" "Hello"
|
|
643
|
+
// e.g. 2 "date" Date { 2026-01-15 }
|
|
644
|
+
// e.g. 3 "formula" 100 (cell.formula = "=SUM(A1:A10)")
|
|
645
|
+
// e.g. 4 "covered" null (part of a merged cell)
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// HTML table
|
|
651
|
+
const html = odsToHtml(bytes);
|
|
652
|
+
|
|
653
|
+
// Fast mode — values only, no formatting
|
|
654
|
+
const model2 = readOds(bytes, { includeFormatting: false });
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
### Cell types
|
|
658
|
+
|
|
659
|
+
| Type | `value` | Notes |
|
|
660
|
+
|------|---------|-------|
|
|
661
|
+
| `"string"` | `string` | |
|
|
662
|
+
| `"float"` | `number` | Includes percentage and currency cells |
|
|
663
|
+
| `"date"` | `Date` (UTC) | |
|
|
664
|
+
| `"boolean"` | `boolean` | |
|
|
665
|
+
| `"formula"` | cached result | `cell.formula` has original string e.g. `"=SUM(A1:A10)"` |
|
|
666
|
+
| `"empty"` | `null` | |
|
|
667
|
+
| `"covered"` | `null` | Covered by a merge — correct `colIndex` always maintained |
|
|
668
|
+
|
|
669
|
+
### Merged cells
|
|
670
|
+
|
|
671
|
+
Primary cells have `colSpan` and/or `rowSpan`. Covered cells have `type: "covered"`, `value: null`, and the correct physical `colIndex` — no offset confusion.
|
|
672
|
+
|
|
673
|
+
```typescript
|
|
674
|
+
// A1:C1 merged — reading row 0:
|
|
675
|
+
// cell 0: { type: "string", value: "Header", colSpan: 3 }
|
|
676
|
+
// cell 1: { type: "covered", value: null, colIndex: 1 }
|
|
677
|
+
// cell 2: { type: "covered", value: null, colIndex: 2 }
|
|
678
|
+
// cell 3: { type: "string", value: "D1", colIndex: 3 } ← always correct
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
---
|
|
682
|
+
|
|
614
683
|
## Typst: ODT to PDF
|
|
615
684
|
|
|
616
685
|
```typescript
|
|
@@ -783,6 +852,8 @@ odf-kit targets ODF 1.2 (ISO/IEC 26300). Generated files include proper ZIP pack
|
|
|
783
852
|
|
|
784
853
|
## Version history
|
|
785
854
|
|
|
855
|
+
**v0.9.8** — ODS reader: `readOds()` and `odsToHtml()` via `odf-kit/ods-reader`. Typed values, formula strings, merged cell handling, formatting, metadata. `odf-kit/odt-reader` alias added. 889 tests passing.
|
|
856
|
+
|
|
786
857
|
**v0.9.7** — ODS enhancements: number formats (integer, decimal:N, percentage, currency), merged cells (colSpan/rowSpan), freeze rows/columns, hyperlinks in cells, sheet tab color. 849 tests passing.
|
|
787
858
|
|
|
788
859
|
**v0.9.6** — `tiptapToOdt()`: TipTap/ProseMirror JSON→ODT conversion. `TiptapNode`, `TiptapMark`, `TiptapToOdtOptions` types. `unknownNodeHandler` for custom extensions. Image support via pre-fetched bytes map. 817 tests passing.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ODS HTML renderer — converts an OdsDocumentModel to an HTML string.
|
|
3
|
+
*
|
|
4
|
+
* Each sheet is rendered as an HTML <table>. Merged cells use colspan/rowspan.
|
|
5
|
+
* Covered cells are omitted. Cell formatting is applied as inline styles.
|
|
6
|
+
*/
|
|
7
|
+
import type { OdsDocumentModel, OdsHtmlOptions } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Render an OdsDocumentModel as an HTML string.
|
|
10
|
+
*
|
|
11
|
+
* Each sheet is rendered as a `<table>`. Merged cells use `colspan`/`rowspan`.
|
|
12
|
+
* Covered cells are omitted. Cell formatting applied as inline styles.
|
|
13
|
+
*
|
|
14
|
+
* @param model - Parsed document model from readOds().
|
|
15
|
+
* @param options - Optional rendering options.
|
|
16
|
+
* @returns HTML string.
|
|
17
|
+
*/
|
|
18
|
+
export declare function renderOdsHtml(model: OdsDocumentModel, options?: OdsHtmlOptions): string;
|
|
19
|
+
//# sourceMappingURL=html-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-renderer.d.ts","sourceRoot":"","sources":["../../src/ods-reader/html-renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,gBAAgB,EAKhB,cAAc,EACf,MAAM,YAAY,CAAC;AA2GpB;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CASvF"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ODS HTML renderer — converts an OdsDocumentModel to an HTML string.
|
|
3
|
+
*
|
|
4
|
+
* Each sheet is rendered as an HTML <table>. Merged cells use colspan/rowspan.
|
|
5
|
+
* Covered cells are omitted. Cell formatting is applied as inline styles.
|
|
6
|
+
*/
|
|
7
|
+
// ─── Style Building ───────────────────────────────────────────────────
|
|
8
|
+
function buildInlineStyle(fmt) {
|
|
9
|
+
const parts = [];
|
|
10
|
+
if (fmt.bold)
|
|
11
|
+
parts.push("font-weight:bold");
|
|
12
|
+
if (fmt.italic)
|
|
13
|
+
parts.push("font-style:italic");
|
|
14
|
+
if (fmt.underline)
|
|
15
|
+
parts.push("text-decoration:underline");
|
|
16
|
+
if (fmt.fontSize)
|
|
17
|
+
parts.push(`font-size:${fmt.fontSize}`);
|
|
18
|
+
if (fmt.fontFamily)
|
|
19
|
+
parts.push(`font-family:${fmt.fontFamily}`);
|
|
20
|
+
if (fmt.color)
|
|
21
|
+
parts.push(`color:${fmt.color}`);
|
|
22
|
+
if (fmt.backgroundColor)
|
|
23
|
+
parts.push(`background-color:${fmt.backgroundColor}`);
|
|
24
|
+
if (fmt.textAlign)
|
|
25
|
+
parts.push(`text-align:${fmt.textAlign}`);
|
|
26
|
+
if (fmt.verticalAlign)
|
|
27
|
+
parts.push(`vertical-align:${fmt.verticalAlign}`);
|
|
28
|
+
return parts.join(";");
|
|
29
|
+
}
|
|
30
|
+
// ─── HTML Escaping ────────────────────────────────────────────────────
|
|
31
|
+
function escapeHtml(text) {
|
|
32
|
+
return text
|
|
33
|
+
.replace(/&/g, "&")
|
|
34
|
+
.replace(/</g, "<")
|
|
35
|
+
.replace(/>/g, ">")
|
|
36
|
+
.replace(/"/g, """);
|
|
37
|
+
}
|
|
38
|
+
// ─── Cell Rendering ───────────────────────────────────────────────────
|
|
39
|
+
function renderCellValue(cell) {
|
|
40
|
+
// Prefer display text when available
|
|
41
|
+
if (cell.displayText !== undefined && cell.displayText !== "") {
|
|
42
|
+
return escapeHtml(cell.displayText);
|
|
43
|
+
}
|
|
44
|
+
if (cell.value === null || cell.value === undefined)
|
|
45
|
+
return "";
|
|
46
|
+
if (cell.value instanceof Date) {
|
|
47
|
+
return escapeHtml(cell.value.toISOString().slice(0, 10));
|
|
48
|
+
}
|
|
49
|
+
return escapeHtml(String(cell.value));
|
|
50
|
+
}
|
|
51
|
+
function renderCell(cell, includeStyles, prefix) {
|
|
52
|
+
const attrs = [`class="${prefix}-cell"`];
|
|
53
|
+
if (cell.colSpan && cell.colSpan > 1)
|
|
54
|
+
attrs.push(`colspan="${cell.colSpan}"`);
|
|
55
|
+
if (cell.rowSpan && cell.rowSpan > 1)
|
|
56
|
+
attrs.push(`rowspan="${cell.rowSpan}"`);
|
|
57
|
+
if (includeStyles && cell.formatting) {
|
|
58
|
+
const style = buildInlineStyle(cell.formatting);
|
|
59
|
+
if (style)
|
|
60
|
+
attrs.push(`style="${style}"`);
|
|
61
|
+
}
|
|
62
|
+
// Right-align numbers by default if no explicit alignment
|
|
63
|
+
if (includeStyles &&
|
|
64
|
+
!cell.formatting?.textAlign &&
|
|
65
|
+
(cell.type === "float" || cell.type === "formula")) {
|
|
66
|
+
const existingStyle = attrs.find((a) => a.startsWith("style="));
|
|
67
|
+
if (existingStyle) {
|
|
68
|
+
const idx = attrs.indexOf(existingStyle);
|
|
69
|
+
attrs[idx] = existingStyle.replace('"', '"text-align:right;');
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
attrs.push(`style="text-align:right"`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const content = renderCellValue(cell);
|
|
76
|
+
return `<td ${attrs.join(" ")}>${content}</td>`;
|
|
77
|
+
}
|
|
78
|
+
// ─── Row Rendering ────────────────────────────────────────────────────
|
|
79
|
+
function renderRow(row, includeStyles, prefix) {
|
|
80
|
+
const cells = row.cells
|
|
81
|
+
.filter((c) => c.type !== "covered")
|
|
82
|
+
.map((c) => renderCell(c, includeStyles, prefix))
|
|
83
|
+
.join("");
|
|
84
|
+
const style = includeStyles && row.height ? ` style="height:${row.height}"` : "";
|
|
85
|
+
return `<tr class="${prefix}-row"${style}>${cells}</tr>`;
|
|
86
|
+
}
|
|
87
|
+
// ─── Sheet Rendering ──────────────────────────────────────────────────
|
|
88
|
+
function renderSheet(sheet, includeStyles, prefix) {
|
|
89
|
+
if (sheet.rows.length === 0) {
|
|
90
|
+
return `<h2 class="${prefix}-sheet-name">${escapeHtml(sheet.name)}</h2>\n<table class="${prefix}-sheet"></table>`;
|
|
91
|
+
}
|
|
92
|
+
const rows = sheet.rows
|
|
93
|
+
.map((r) => renderRow(r, includeStyles, prefix))
|
|
94
|
+
.join("\n ");
|
|
95
|
+
return [
|
|
96
|
+
`<h2 class="${prefix}-sheet-name">${escapeHtml(sheet.name)}</h2>`,
|
|
97
|
+
`<table class="${prefix}-sheet">`,
|
|
98
|
+
` <tbody>`,
|
|
99
|
+
` ${rows}`,
|
|
100
|
+
` </tbody>`,
|
|
101
|
+
`</table>`,
|
|
102
|
+
].join("\n");
|
|
103
|
+
}
|
|
104
|
+
// ─── Public API ───────────────────────────────────────────────────────
|
|
105
|
+
/**
|
|
106
|
+
* Render an OdsDocumentModel as an HTML string.
|
|
107
|
+
*
|
|
108
|
+
* Each sheet is rendered as a `<table>`. Merged cells use `colspan`/`rowspan`.
|
|
109
|
+
* Covered cells are omitted. Cell formatting applied as inline styles.
|
|
110
|
+
*
|
|
111
|
+
* @param model - Parsed document model from readOds().
|
|
112
|
+
* @param options - Optional rendering options.
|
|
113
|
+
* @returns HTML string.
|
|
114
|
+
*/
|
|
115
|
+
export function renderOdsHtml(model, options) {
|
|
116
|
+
const includeStyles = options?.includeStyles ?? true;
|
|
117
|
+
const prefix = options?.classPrefix ?? "ods";
|
|
118
|
+
const sheets = model.sheets
|
|
119
|
+
.map((s) => renderSheet(s, includeStyles, prefix))
|
|
120
|
+
.join("\n\n");
|
|
121
|
+
return `<div class="${prefix}-document">\n${sheets}\n</div>`;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=html-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html-renderer.js","sourceRoot":"","sources":["../../src/ods-reader/html-renderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReadOdsOptions, OdsHtmlOptions } from "./types.js";
|
|
2
|
+
export { readOds } from "./parser.js";
|
|
3
|
+
export type { OdsDocumentModel, OdsMetadata, OdsSheetModel, OdsRowModel, OdsCellModel, OdsCellFormatting, ReadOdsOptions, OdsHtmlOptions, } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Convert an ODS file directly to an HTML string.
|
|
6
|
+
*
|
|
7
|
+
* Convenience wrapper around readOds() + renderOdsHtml().
|
|
8
|
+
*
|
|
9
|
+
* @param bytes - Raw .ods file bytes.
|
|
10
|
+
* @param htmlOptions - Optional HTML rendering options.
|
|
11
|
+
* @param readOptions - Optional parsing options.
|
|
12
|
+
* @returns HTML string with one <table> per sheet.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* import { odsToHtml } from "odf-kit/ods-reader"
|
|
16
|
+
* const html = odsToHtml(readFileSync("data.ods"))
|
|
17
|
+
*/
|
|
18
|
+
export declare function odsToHtml(bytes: Uint8Array, htmlOptions?: OdsHtmlOptions, readOptions?: ReadOdsOptions): string;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ods-reader/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjE,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,cAAc,GACf,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,UAAU,EACjB,WAAW,CAAC,EAAE,cAAc,EAC5B,WAAW,CAAC,EAAE,cAAc,GAC3B,MAAM,CAGR"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { readOds } from "./parser.js";
|
|
2
|
+
import { renderOdsHtml } from "./html-renderer.js";
|
|
3
|
+
export { readOds } from "./parser.js";
|
|
4
|
+
/**
|
|
5
|
+
* Convert an ODS file directly to an HTML string.
|
|
6
|
+
*
|
|
7
|
+
* Convenience wrapper around readOds() + renderOdsHtml().
|
|
8
|
+
*
|
|
9
|
+
* @param bytes - Raw .ods file bytes.
|
|
10
|
+
* @param htmlOptions - Optional HTML rendering options.
|
|
11
|
+
* @param readOptions - Optional parsing options.
|
|
12
|
+
* @returns HTML string with one <table> per sheet.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* import { odsToHtml } from "odf-kit/ods-reader"
|
|
16
|
+
* const html = odsToHtml(readFileSync("data.ods"))
|
|
17
|
+
*/
|
|
18
|
+
export function odsToHtml(bytes, htmlOptions, readOptions) {
|
|
19
|
+
const model = readOds(bytes, readOptions);
|
|
20
|
+
return renderOdsHtml(model, htmlOptions);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ods-reader/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAYtC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,SAAS,CACvB,KAAiB,EACjB,WAA4B,EAC5B,WAA4B;IAE5B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAC1C,OAAO,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ODS parser — reads an .ods file and builds an OdsDocumentModel.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline:
|
|
5
|
+
* 1. Unzip the .ods bytes with fflate
|
|
6
|
+
* 2. Parse content.xml — walk office:spreadsheet → table:table → table:table-row → table:table-cell
|
|
7
|
+
* 3. Resolve cell types and values from office:value-type attributes
|
|
8
|
+
* 4. Handle table:number-columns-repeated / table:number-rows-repeated (LibreOffice compression)
|
|
9
|
+
* 5. Handle merged cells — colSpan/rowSpan on primary, covered cells at correct indices
|
|
10
|
+
* 6. Resolve cell styles from automatic-styles → OdsCellFormatting
|
|
11
|
+
* 7. Parse settings.xml for freeze row/column configuration
|
|
12
|
+
* 8. Parse meta.xml for document metadata
|
|
13
|
+
* 9. Return OdsDocumentModel
|
|
14
|
+
*/
|
|
15
|
+
import type { OdsDocumentModel, ReadOdsOptions } from "./types.js";
|
|
16
|
+
/**
|
|
17
|
+
* Parse an ODS file into a structured document model.
|
|
18
|
+
*
|
|
19
|
+
* @param bytes - Raw .ods file bytes (Uint8Array).
|
|
20
|
+
* @param options - Optional parsing options.
|
|
21
|
+
* @returns Structured OdsDocumentModel.
|
|
22
|
+
*/
|
|
23
|
+
export declare function readOds(bytes: Uint8Array, options?: ReadOdsOptions): OdsDocumentModel;
|
|
24
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/ods-reader/parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EACV,gBAAgB,EAMhB,cAAc,EACf,MAAM,YAAY,CAAC;AAsfpB;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,gBAAgB,CAwErF"}
|
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ODS parser — reads an .ods file and builds an OdsDocumentModel.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline:
|
|
5
|
+
* 1. Unzip the .ods bytes with fflate
|
|
6
|
+
* 2. Parse content.xml — walk office:spreadsheet → table:table → table:table-row → table:table-cell
|
|
7
|
+
* 3. Resolve cell types and values from office:value-type attributes
|
|
8
|
+
* 4. Handle table:number-columns-repeated / table:number-rows-repeated (LibreOffice compression)
|
|
9
|
+
* 5. Handle merged cells — colSpan/rowSpan on primary, covered cells at correct indices
|
|
10
|
+
* 6. Resolve cell styles from automatic-styles → OdsCellFormatting
|
|
11
|
+
* 7. Parse settings.xml for freeze row/column configuration
|
|
12
|
+
* 8. Parse meta.xml for document metadata
|
|
13
|
+
* 9. Return OdsDocumentModel
|
|
14
|
+
*/
|
|
15
|
+
import { unzipSync, strFromU8 } from "fflate";
|
|
16
|
+
import { parseXml } from "../reader/xml-parser.js";
|
|
17
|
+
// ─── XML Helpers ──────────────────────────────────────────────────────
|
|
18
|
+
/** Return the first direct element child with the given tag, or undefined. */
|
|
19
|
+
function findElement(node, tag) {
|
|
20
|
+
for (const child of node.children) {
|
|
21
|
+
if (child.type === "element" && child.tag === tag)
|
|
22
|
+
return child;
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
/** Return all direct element children with the given tag. */
|
|
27
|
+
function findElements(node, tag) {
|
|
28
|
+
return node.children.filter((c) => c.type === "element" && c.tag === tag);
|
|
29
|
+
}
|
|
30
|
+
/** Return the concatenated text content of all text:p children. */
|
|
31
|
+
function cellDisplayText(cell) {
|
|
32
|
+
const parts = [];
|
|
33
|
+
for (const child of cell.children) {
|
|
34
|
+
if (child.type === "element" && child.tag === "text:p") {
|
|
35
|
+
parts.push(extractTextContent(child));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return parts.join("\n");
|
|
39
|
+
}
|
|
40
|
+
/** Recursively extract all text from a node. */
|
|
41
|
+
function extractTextContent(node) {
|
|
42
|
+
const parts = [];
|
|
43
|
+
for (const child of node.children) {
|
|
44
|
+
if (child.type === "text") {
|
|
45
|
+
parts.push(child.text);
|
|
46
|
+
}
|
|
47
|
+
else if (child.type === "element") {
|
|
48
|
+
if (child.tag === "text:s") {
|
|
49
|
+
// text:s c="N" = N spaces
|
|
50
|
+
const count = parseInt(child.attrs["text:c"] ?? "1", 10);
|
|
51
|
+
parts.push(" ".repeat(count));
|
|
52
|
+
}
|
|
53
|
+
else if (child.tag === "text:tab") {
|
|
54
|
+
parts.push("\t");
|
|
55
|
+
}
|
|
56
|
+
else if (child.tag === "text:line-break") {
|
|
57
|
+
parts.push("\n");
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
parts.push(extractTextContent(child));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return parts.join("");
|
|
65
|
+
}
|
|
66
|
+
// ─── Style Resolution ─────────────────────────────────────────────────
|
|
67
|
+
/**
|
|
68
|
+
* Parse automatic-styles from content.xml and build a map from
|
|
69
|
+
* style name → OdsCellFormatting.
|
|
70
|
+
*/
|
|
71
|
+
function buildStyleMap(contentRoot) {
|
|
72
|
+
const map = new Map();
|
|
73
|
+
const autoStyles = findElement(contentRoot, "office:automatic-styles");
|
|
74
|
+
if (!autoStyles)
|
|
75
|
+
return map;
|
|
76
|
+
// Build number-style name → format string map
|
|
77
|
+
const numberStyles = new Map();
|
|
78
|
+
for (const child of autoStyles.children) {
|
|
79
|
+
if (child.type !== "element")
|
|
80
|
+
continue;
|
|
81
|
+
const name = child.attrs["style:name"];
|
|
82
|
+
if (!name)
|
|
83
|
+
continue;
|
|
84
|
+
if (child.tag === "number:number-style" || child.tag === "number:currency-style") {
|
|
85
|
+
numberStyles.set(name, parseNumberStyleName(name));
|
|
86
|
+
}
|
|
87
|
+
else if (child.tag === "number:date-style") {
|
|
88
|
+
numberStyles.set(name, parseDateStyleName(name));
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Build cell style map
|
|
92
|
+
for (const child of autoStyles.children) {
|
|
93
|
+
if (child.type !== "element" || child.tag !== "style:style")
|
|
94
|
+
continue;
|
|
95
|
+
if (child.attrs["style:family"] !== "table-cell")
|
|
96
|
+
continue;
|
|
97
|
+
const name = child.attrs["style:name"];
|
|
98
|
+
if (!name)
|
|
99
|
+
continue;
|
|
100
|
+
const formatting = {};
|
|
101
|
+
// Data style (number/date format)
|
|
102
|
+
const dataStyleName = child.attrs["style:data-style-name"];
|
|
103
|
+
if (dataStyleName) {
|
|
104
|
+
const fmt = numberStyles.get(dataStyleName);
|
|
105
|
+
if (fmt) {
|
|
106
|
+
if (fmt.startsWith("date:")) {
|
|
107
|
+
formatting.dateFormat = fmt.slice(5);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
formatting.numberFormat = fmt;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Table cell properties
|
|
115
|
+
const cellProps = findElement(child, "style:table-cell-properties");
|
|
116
|
+
if (cellProps) {
|
|
117
|
+
const bg = cellProps.attrs["fo:background-color"];
|
|
118
|
+
if (bg && bg !== "transparent")
|
|
119
|
+
formatting.backgroundColor = bg;
|
|
120
|
+
const va = cellProps.attrs["style:vertical-align"];
|
|
121
|
+
if (va === "top" || va === "middle" || va === "bottom") {
|
|
122
|
+
formatting.verticalAlign = va;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Text properties
|
|
126
|
+
const textProps = findElement(child, "style:text-properties");
|
|
127
|
+
if (textProps) {
|
|
128
|
+
const fw = textProps.attrs["fo:font-weight"];
|
|
129
|
+
if (fw === "bold")
|
|
130
|
+
formatting.bold = true;
|
|
131
|
+
const fs = textProps.attrs["fo:font-style"];
|
|
132
|
+
if (fs === "italic")
|
|
133
|
+
formatting.italic = true;
|
|
134
|
+
const ul = textProps.attrs["style:text-underline-style"];
|
|
135
|
+
if (ul && ul !== "none")
|
|
136
|
+
formatting.underline = true;
|
|
137
|
+
const color = textProps.attrs["fo:color"];
|
|
138
|
+
if (color)
|
|
139
|
+
formatting.color = color;
|
|
140
|
+
const fontSize = textProps.attrs["fo:font-size"];
|
|
141
|
+
if (fontSize)
|
|
142
|
+
formatting.fontSize = fontSize;
|
|
143
|
+
const fontFamily = textProps.attrs["fo:font-family"] ?? textProps.attrs["style:font-name"];
|
|
144
|
+
if (fontFamily)
|
|
145
|
+
formatting.fontFamily = fontFamily;
|
|
146
|
+
}
|
|
147
|
+
// Paragraph properties (text-align)
|
|
148
|
+
const paraProps = findElement(child, "style:paragraph-properties");
|
|
149
|
+
if (paraProps) {
|
|
150
|
+
const ta = paraProps.attrs["fo:text-align"];
|
|
151
|
+
if (ta === "start" || ta === "left")
|
|
152
|
+
formatting.textAlign = "left";
|
|
153
|
+
else if (ta === "center")
|
|
154
|
+
formatting.textAlign = "center";
|
|
155
|
+
else if (ta === "end" || ta === "right")
|
|
156
|
+
formatting.textAlign = "right";
|
|
157
|
+
}
|
|
158
|
+
if (Object.keys(formatting).length > 0) {
|
|
159
|
+
map.set(name, formatting);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return map;
|
|
163
|
+
}
|
|
164
|
+
/** Reverse-engineer a human-readable format string from a style name. */
|
|
165
|
+
function parseNumberStyleName(name) {
|
|
166
|
+
// Our generated style names: Nnum-int, Nnum-dec2, Nnum-pct2, Nnum-eur2 etc.
|
|
167
|
+
if (name === "Nnum-int")
|
|
168
|
+
return "integer";
|
|
169
|
+
const decMatch = name.match(/^Nnum-dec(\d+)$/);
|
|
170
|
+
if (decMatch)
|
|
171
|
+
return `decimal:${decMatch[1]}`;
|
|
172
|
+
const pctMatch = name.match(/^Nnum-pct(\d+)$/);
|
|
173
|
+
if (pctMatch)
|
|
174
|
+
return `percentage:${pctMatch[1]}`;
|
|
175
|
+
const curMatch = name.match(/^Nnum-([a-z]{3})(\d+)$/);
|
|
176
|
+
if (curMatch)
|
|
177
|
+
return `currency:${curMatch[1].toUpperCase()}:${curMatch[2]}`;
|
|
178
|
+
return name; // unknown — return as-is
|
|
179
|
+
}
|
|
180
|
+
/** Reverse-engineer a date format string from a style name. */
|
|
181
|
+
function parseDateStyleName(name) {
|
|
182
|
+
switch (name) {
|
|
183
|
+
case "Ndate-iso":
|
|
184
|
+
return "date:YYYY-MM-DD";
|
|
185
|
+
case "Ndate-dmy":
|
|
186
|
+
return "date:DD/MM/YYYY";
|
|
187
|
+
case "Ndate-mdy":
|
|
188
|
+
return "date:MM/DD/YYYY";
|
|
189
|
+
case "Ndate-dt":
|
|
190
|
+
return "date:YYYY-MM-DD HH:MM:SS";
|
|
191
|
+
default:
|
|
192
|
+
return `date:${name}`;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// ─── Cell Value Parsing ───────────────────────────────────────────────
|
|
196
|
+
/** Parse a date value from an ODS office:date-value attribute. */
|
|
197
|
+
function parseDateValue(dateStr) {
|
|
198
|
+
// ISO date: "2026-01-15" or datetime: "2026-01-15T10:30:00"
|
|
199
|
+
return new Date(dateStr + (dateStr.includes("T") ? "Z" : "T00:00:00Z"));
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Parse a table:table-cell element into an OdsCellModel.
|
|
203
|
+
*
|
|
204
|
+
* @param cellEl - The XML element (table:table-cell or table:covered-table-cell)
|
|
205
|
+
* @param colIndex - Physical column index
|
|
206
|
+
* @param styleMap - Resolved cell styles
|
|
207
|
+
* @param includeFormatting - Whether to include formatting
|
|
208
|
+
*/
|
|
209
|
+
function parseCellElement(cellEl, colIndex, styleMap, includeFormatting) {
|
|
210
|
+
// Covered cell
|
|
211
|
+
if (cellEl.tag === "table:covered-table-cell") {
|
|
212
|
+
return { colIndex, type: "covered", value: null };
|
|
213
|
+
}
|
|
214
|
+
const valueType = cellEl.attrs["office:value-type"];
|
|
215
|
+
const colSpan = parseInt(cellEl.attrs["table:number-columns-spanned"] ?? "1", 10);
|
|
216
|
+
const rowSpan = parseInt(cellEl.attrs["table:number-rows-spanned"] ?? "1", 10);
|
|
217
|
+
const styleName = cellEl.attrs["table:style-name"];
|
|
218
|
+
const displayText = cellDisplayText(cellEl);
|
|
219
|
+
const cell = {
|
|
220
|
+
colIndex,
|
|
221
|
+
type: "empty",
|
|
222
|
+
value: null,
|
|
223
|
+
};
|
|
224
|
+
if (displayText)
|
|
225
|
+
cell.displayText = displayText;
|
|
226
|
+
if (colSpan > 1)
|
|
227
|
+
cell.colSpan = colSpan;
|
|
228
|
+
if (rowSpan > 1)
|
|
229
|
+
cell.rowSpan = rowSpan;
|
|
230
|
+
// Formatting
|
|
231
|
+
if (includeFormatting && styleName) {
|
|
232
|
+
const fmt = styleMap.get(styleName);
|
|
233
|
+
if (fmt)
|
|
234
|
+
cell.formatting = fmt;
|
|
235
|
+
}
|
|
236
|
+
// Formula
|
|
237
|
+
const formula = cellEl.attrs["table:formula"];
|
|
238
|
+
if (formula) {
|
|
239
|
+
cell.formula = formula.replace(/^of:/, "");
|
|
240
|
+
}
|
|
241
|
+
// Value type dispatch
|
|
242
|
+
switch (valueType) {
|
|
243
|
+
case "string":
|
|
244
|
+
cell.type = "string";
|
|
245
|
+
cell.value = displayText || cellEl.attrs["office:string-value"] || "";
|
|
246
|
+
break;
|
|
247
|
+
case "float":
|
|
248
|
+
cell.type = formula ? "formula" : "float";
|
|
249
|
+
cell.value = parseFloat(cellEl.attrs["office:value"] ?? "0");
|
|
250
|
+
break;
|
|
251
|
+
case "percentage":
|
|
252
|
+
cell.type = formula ? "formula" : "float";
|
|
253
|
+
// ODS stores raw decimal (0.1234 = 12.34%) — return raw value
|
|
254
|
+
cell.value = parseFloat(cellEl.attrs["office:value"] ?? "0");
|
|
255
|
+
break;
|
|
256
|
+
case "currency":
|
|
257
|
+
cell.type = formula ? "formula" : "float";
|
|
258
|
+
cell.value = parseFloat(cellEl.attrs["office:value"] ?? "0");
|
|
259
|
+
break;
|
|
260
|
+
case "date":
|
|
261
|
+
cell.type = formula ? "formula" : "date";
|
|
262
|
+
cell.value = parseDateValue(cellEl.attrs["office:date-value"] ?? "");
|
|
263
|
+
break;
|
|
264
|
+
case "boolean":
|
|
265
|
+
cell.type = formula ? "formula" : "boolean";
|
|
266
|
+
cell.value = cellEl.attrs["office:boolean-value"] === "true";
|
|
267
|
+
break;
|
|
268
|
+
default:
|
|
269
|
+
// No value-type attribute — empty cell (or formula with no cached result)
|
|
270
|
+
if (formula) {
|
|
271
|
+
cell.type = "formula";
|
|
272
|
+
cell.value = null;
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
return cell;
|
|
277
|
+
}
|
|
278
|
+
// ─── Sheet Parsing ────────────────────────────────────────────────────
|
|
279
|
+
/**
|
|
280
|
+
* Parse a table:table element into an OdsSheetModel.
|
|
281
|
+
*/
|
|
282
|
+
function parseSheet(tableEl, styleMap, includeFormatting, freezeRows, freezeColumns) {
|
|
283
|
+
const name = tableEl.attrs["table:name"] ?? "Sheet";
|
|
284
|
+
// Extract tab color from the table style
|
|
285
|
+
// table:tab-color is on style:table-properties inside automatic-styles
|
|
286
|
+
// We can't easily reach it here — it will be resolved by the caller
|
|
287
|
+
const sheet = {
|
|
288
|
+
name,
|
|
289
|
+
rows: [],
|
|
290
|
+
columnWidths: new Map(),
|
|
291
|
+
freezeRows,
|
|
292
|
+
freezeColumns,
|
|
293
|
+
};
|
|
294
|
+
// Count columns from table:table-column elements (for future column width support)
|
|
295
|
+
for (const child of tableEl.children) {
|
|
296
|
+
if (child.type !== "element")
|
|
297
|
+
continue;
|
|
298
|
+
if (child.tag !== "table:table-column")
|
|
299
|
+
continue;
|
|
300
|
+
// repeated count tracked but not used yet — column width resolution is future work
|
|
301
|
+
}
|
|
302
|
+
// Parse rows
|
|
303
|
+
let rowIdx = 0;
|
|
304
|
+
for (const child of tableEl.children) {
|
|
305
|
+
if (child.type !== "element")
|
|
306
|
+
continue;
|
|
307
|
+
if (child.tag !== "table:table-row")
|
|
308
|
+
continue;
|
|
309
|
+
const rowRepeated = parseInt(child.attrs["table:number-rows-repeated"] ?? "1", 10);
|
|
310
|
+
const rowHeight = child.attrs["style:row-height"];
|
|
311
|
+
// Parse cells in this row
|
|
312
|
+
const baseCells = [];
|
|
313
|
+
let physicalCol = 0;
|
|
314
|
+
for (const cellEl of child.children) {
|
|
315
|
+
if (cellEl.type !== "element")
|
|
316
|
+
continue;
|
|
317
|
+
if (cellEl.tag !== "table:table-cell" && cellEl.tag !== "table:covered-table-cell")
|
|
318
|
+
continue;
|
|
319
|
+
const repeated = parseInt(cellEl.attrs["table:number-columns-repeated"] ?? "1", 10);
|
|
320
|
+
if (repeated > 1) {
|
|
321
|
+
// Repeated cells — expand them
|
|
322
|
+
for (let r = 0; r < repeated; r++) {
|
|
323
|
+
const cell = parseCellElement(cellEl, physicalCol, styleMap, includeFormatting);
|
|
324
|
+
cell.colIndex = physicalCol;
|
|
325
|
+
baseCells.push(cell);
|
|
326
|
+
physicalCol++;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
const cell = parseCellElement(cellEl, physicalCol, styleMap, includeFormatting);
|
|
331
|
+
baseCells.push(cell);
|
|
332
|
+
physicalCol++;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// Trim trailing empty cells
|
|
336
|
+
let lastNonEmpty = baseCells.length - 1;
|
|
337
|
+
while (lastNonEmpty >= 0 && baseCells[lastNonEmpty].type === "empty") {
|
|
338
|
+
lastNonEmpty--;
|
|
339
|
+
}
|
|
340
|
+
const trimmedCells = baseCells.slice(0, lastNonEmpty + 1);
|
|
341
|
+
// Only emit row if it has content (or rowRepeated is small — avoid thousands of empty rows)
|
|
342
|
+
const hasContent = trimmedCells.some((c) => c.type !== "empty" && c.type !== "covered");
|
|
343
|
+
if (hasContent) {
|
|
344
|
+
// Emit this row (and repeated copies if they also have content — rare)
|
|
345
|
+
for (let r = 0; r < Math.min(rowRepeated, 1); r++) {
|
|
346
|
+
const row = {
|
|
347
|
+
index: rowIdx + r,
|
|
348
|
+
cells: trimmedCells.map((c) => ({ ...c })),
|
|
349
|
+
};
|
|
350
|
+
if (rowHeight)
|
|
351
|
+
row.height = rowHeight;
|
|
352
|
+
sheet.rows.push(row);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
rowIdx += rowRepeated;
|
|
356
|
+
}
|
|
357
|
+
return sheet;
|
|
358
|
+
}
|
|
359
|
+
// ─── Settings Parsing ─────────────────────────────────────────────────
|
|
360
|
+
/**
|
|
361
|
+
* Parse settings.xml to extract freeze row/column configuration.
|
|
362
|
+
* Returns a map from sheet name → { freezeRows, freezeColumns }.
|
|
363
|
+
*/
|
|
364
|
+
function parseSettings(settingsXml) {
|
|
365
|
+
const result = new Map();
|
|
366
|
+
try {
|
|
367
|
+
const root = parseXml(settingsXml);
|
|
368
|
+
// Navigate: office:settings → config:config-item-set (ooo:view-settings)
|
|
369
|
+
// → config:config-item-map-indexed (Views) → config:config-item-map-entry
|
|
370
|
+
// → config:config-item-map-named (Tables) → config:config-item-map-entry (sheet name)
|
|
371
|
+
const settings = findElement(root, "office:settings");
|
|
372
|
+
if (!settings)
|
|
373
|
+
return result;
|
|
374
|
+
for (const itemSet of findElements(settings, "config:config-item-set")) {
|
|
375
|
+
if (itemSet.attrs["config:name"] !== "ooo:view-settings")
|
|
376
|
+
continue;
|
|
377
|
+
const indexed = findElement(itemSet, "config:config-item-map-indexed");
|
|
378
|
+
if (!indexed)
|
|
379
|
+
continue;
|
|
380
|
+
const viewEntry = findElement(indexed, "config:config-item-map-entry");
|
|
381
|
+
if (!viewEntry)
|
|
382
|
+
continue;
|
|
383
|
+
const tablesNamed = findElement(viewEntry, "config:config-item-map-named");
|
|
384
|
+
if (!tablesNamed)
|
|
385
|
+
continue;
|
|
386
|
+
for (const sheetEntry of findElements(tablesNamed, "config:config-item-map-entry")) {
|
|
387
|
+
const sheetName = sheetEntry.attrs["config:name"];
|
|
388
|
+
if (!sheetName)
|
|
389
|
+
continue;
|
|
390
|
+
const freeze = {};
|
|
391
|
+
for (const item of findElements(sheetEntry, "config:config-item")) {
|
|
392
|
+
const itemName = item.attrs["config:name"];
|
|
393
|
+
const itemValue = parseInt(item.children.find((c) => c.type === "text")?.text ?? "0", 10);
|
|
394
|
+
if (itemName === "VerticalSplitPosition" && itemValue > 0) {
|
|
395
|
+
freeze.freezeRows = itemValue;
|
|
396
|
+
}
|
|
397
|
+
else if (itemName === "HorizontalSplitPosition" && itemValue > 0) {
|
|
398
|
+
freeze.freezeColumns = itemValue;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
if (Object.keys(freeze).length > 0) {
|
|
402
|
+
result.set(sheetName, freeze);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
catch {
|
|
408
|
+
// Malformed settings.xml — silently ignore
|
|
409
|
+
}
|
|
410
|
+
return result;
|
|
411
|
+
}
|
|
412
|
+
// ─── Metadata Parsing ─────────────────────────────────────────────────
|
|
413
|
+
function parseMetaXml(metaXml) {
|
|
414
|
+
const metadata = {};
|
|
415
|
+
try {
|
|
416
|
+
const root = parseXml(metaXml);
|
|
417
|
+
const meta = findElement(root, "office:meta");
|
|
418
|
+
if (!meta)
|
|
419
|
+
return metadata;
|
|
420
|
+
for (const child of meta.children) {
|
|
421
|
+
if (child.type !== "element")
|
|
422
|
+
continue;
|
|
423
|
+
const text = extractTextContent(child);
|
|
424
|
+
switch (child.tag) {
|
|
425
|
+
case "dc:title":
|
|
426
|
+
metadata.title = text;
|
|
427
|
+
break;
|
|
428
|
+
case "dc:creator":
|
|
429
|
+
case "meta:initial-creator":
|
|
430
|
+
if (!metadata.creator)
|
|
431
|
+
metadata.creator = text;
|
|
432
|
+
break;
|
|
433
|
+
case "dc:description":
|
|
434
|
+
metadata.description = text;
|
|
435
|
+
break;
|
|
436
|
+
case "meta:creation-date":
|
|
437
|
+
metadata.creationDate = text;
|
|
438
|
+
break;
|
|
439
|
+
case "dc:date":
|
|
440
|
+
metadata.lastModified = text;
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
catch {
|
|
446
|
+
// Malformed meta.xml — silently ignore
|
|
447
|
+
}
|
|
448
|
+
return metadata;
|
|
449
|
+
}
|
|
450
|
+
// ─── Tab Color Extraction ─────────────────────────────────────────────
|
|
451
|
+
/**
|
|
452
|
+
* Extract sheet tab colors from content.xml automatic-styles.
|
|
453
|
+
* Returns a map from table style name (e.g. "ta1") → hex color.
|
|
454
|
+
*/
|
|
455
|
+
function buildTabColorMap(contentRoot) {
|
|
456
|
+
const map = new Map();
|
|
457
|
+
const autoStyles = findElement(contentRoot, "office:automatic-styles");
|
|
458
|
+
if (!autoStyles)
|
|
459
|
+
return map;
|
|
460
|
+
for (const child of autoStyles.children) {
|
|
461
|
+
if (child.type !== "element" || child.tag !== "style:style")
|
|
462
|
+
continue;
|
|
463
|
+
if (child.attrs["style:family"] !== "table")
|
|
464
|
+
continue;
|
|
465
|
+
const name = child.attrs["style:name"];
|
|
466
|
+
if (!name)
|
|
467
|
+
continue;
|
|
468
|
+
const tableProps = findElement(child, "style:table-properties");
|
|
469
|
+
if (!tableProps)
|
|
470
|
+
continue;
|
|
471
|
+
const tabColor = tableProps.attrs["table:tab-color"];
|
|
472
|
+
if (tabColor)
|
|
473
|
+
map.set(name, tabColor);
|
|
474
|
+
}
|
|
475
|
+
return map;
|
|
476
|
+
}
|
|
477
|
+
// ─── Public API ───────────────────────────────────────────────────────
|
|
478
|
+
/**
|
|
479
|
+
* Parse an ODS file into a structured document model.
|
|
480
|
+
*
|
|
481
|
+
* @param bytes - Raw .ods file bytes (Uint8Array).
|
|
482
|
+
* @param options - Optional parsing options.
|
|
483
|
+
* @returns Structured OdsDocumentModel.
|
|
484
|
+
*/
|
|
485
|
+
export function readOds(bytes, options) {
|
|
486
|
+
const includeFormatting = options?.includeFormatting ?? true;
|
|
487
|
+
// Unzip
|
|
488
|
+
const files = unzipSync(bytes);
|
|
489
|
+
// Required: content.xml
|
|
490
|
+
const contentData = files["content.xml"];
|
|
491
|
+
if (!contentData)
|
|
492
|
+
throw new Error("readOds: content.xml not found in ODS package");
|
|
493
|
+
const contentXml = strFromU8(contentData);
|
|
494
|
+
const contentRoot = parseXml(contentXml);
|
|
495
|
+
// Optional: meta.xml
|
|
496
|
+
let metadata;
|
|
497
|
+
const metaData = files["meta.xml"];
|
|
498
|
+
if (metaData) {
|
|
499
|
+
metadata = parseMetaXml(strFromU8(metaData));
|
|
500
|
+
}
|
|
501
|
+
// Optional: settings.xml (freeze rows/columns)
|
|
502
|
+
const freezeMap = new Map();
|
|
503
|
+
const settingsData = files["settings.xml"];
|
|
504
|
+
if (settingsData) {
|
|
505
|
+
const parsed = parseSettings(strFromU8(settingsData));
|
|
506
|
+
for (const [k, v] of parsed)
|
|
507
|
+
freezeMap.set(k, v);
|
|
508
|
+
}
|
|
509
|
+
// Build style map from content.xml automatic-styles
|
|
510
|
+
const styleMap = includeFormatting
|
|
511
|
+
? buildStyleMap(contentRoot)
|
|
512
|
+
: new Map();
|
|
513
|
+
// Build tab color map
|
|
514
|
+
const tabColorMap = buildTabColorMap(contentRoot);
|
|
515
|
+
// Find office:spreadsheet
|
|
516
|
+
const body = findElement(contentRoot, "office:body");
|
|
517
|
+
if (!body)
|
|
518
|
+
throw new Error("readOds: office:body not found in content.xml");
|
|
519
|
+
const spreadsheet = findElement(body, "office:spreadsheet");
|
|
520
|
+
if (!spreadsheet)
|
|
521
|
+
throw new Error("readOds: office:spreadsheet not found in content.xml");
|
|
522
|
+
// Parse each sheet
|
|
523
|
+
const sheets = [];
|
|
524
|
+
for (const child of spreadsheet.children) {
|
|
525
|
+
if (child.type !== "element" || child.tag !== "table:table")
|
|
526
|
+
continue;
|
|
527
|
+
const tableStyleName = child.attrs["table:style-name"];
|
|
528
|
+
const freeze = freezeMap.get(child.attrs["table:name"] ?? "");
|
|
529
|
+
const sheet = parseSheet(child, styleMap, includeFormatting, freeze?.freezeRows, freeze?.freezeColumns);
|
|
530
|
+
// Apply tab color from table style
|
|
531
|
+
if (tableStyleName) {
|
|
532
|
+
const tabColor = tabColorMap.get(tableStyleName);
|
|
533
|
+
if (tabColor)
|
|
534
|
+
sheet.tabColor = tabColor;
|
|
535
|
+
}
|
|
536
|
+
sheets.push(sheet);
|
|
537
|
+
}
|
|
538
|
+
const model = { sheets };
|
|
539
|
+
if (metadata && Object.keys(metadata).length > 0) {
|
|
540
|
+
model.metadata = metadata;
|
|
541
|
+
}
|
|
542
|
+
return model;
|
|
543
|
+
}
|
|
544
|
+
//# sourceMappingURL=parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/ods-reader/parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ODS reader type definitions.
|
|
3
|
+
*
|
|
4
|
+
* These types describe the in-memory model returned by readOds().
|
|
5
|
+
*/
|
|
6
|
+
/** Top-level ODS document model returned by readOds(). */
|
|
7
|
+
export interface OdsDocumentModel {
|
|
8
|
+
/** Sheets in tab order. */
|
|
9
|
+
sheets: OdsSheetModel[];
|
|
10
|
+
/** Document metadata from meta.xml. */
|
|
11
|
+
metadata?: OdsMetadata;
|
|
12
|
+
}
|
|
13
|
+
/** Document metadata from meta.xml. */
|
|
14
|
+
export interface OdsMetadata {
|
|
15
|
+
title?: string;
|
|
16
|
+
creator?: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
creationDate?: string;
|
|
19
|
+
lastModified?: string;
|
|
20
|
+
}
|
|
21
|
+
/** A single sheet (tab) in the spreadsheet. */
|
|
22
|
+
export interface OdsSheetModel {
|
|
23
|
+
/** Sheet tab name. */
|
|
24
|
+
name: string;
|
|
25
|
+
/** Tab color if set (hex or CSS named color). */
|
|
26
|
+
tabColor?: string;
|
|
27
|
+
/** Rows in order. Sparse rows (e.g. from table:number-rows-repeated) are expanded. */
|
|
28
|
+
rows: OdsRowModel[];
|
|
29
|
+
/** Column widths by zero-based column index. */
|
|
30
|
+
columnWidths: Map<number, string>;
|
|
31
|
+
/** Number of frozen rows (from settings.xml). */
|
|
32
|
+
freezeRows?: number;
|
|
33
|
+
/** Number of frozen columns (from settings.xml). */
|
|
34
|
+
freezeColumns?: number;
|
|
35
|
+
}
|
|
36
|
+
/** A row of cells. */
|
|
37
|
+
export interface OdsRowModel {
|
|
38
|
+
/** Zero-based row index within the sheet. */
|
|
39
|
+
index: number;
|
|
40
|
+
/** Cells in column order. Covered cells have type "covered". */
|
|
41
|
+
cells: OdsCellModel[];
|
|
42
|
+
/** Row height if explicitly set. */
|
|
43
|
+
height?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A single cell in the spreadsheet.
|
|
47
|
+
*
|
|
48
|
+
* Cell types:
|
|
49
|
+
* - `"string"` — text value; `value` is a string
|
|
50
|
+
* - `"float"` — numeric value; `value` is a number
|
|
51
|
+
* - `"date"` — date/datetime; `value` is a Date (UTC)
|
|
52
|
+
* - `"boolean"` — boolean; `value` is true or false
|
|
53
|
+
* - `"formula"` — formula cell; `value` is the cached result, `formula` is the original string
|
|
54
|
+
* - `"empty"` — no content; `value` is null
|
|
55
|
+
* - `"covered"` — covered by a merge from a primary cell; `value` is null
|
|
56
|
+
*/
|
|
57
|
+
export interface OdsCellModel {
|
|
58
|
+
/** Zero-based column index. Always correct regardless of merges. */
|
|
59
|
+
colIndex: number;
|
|
60
|
+
/** Cell type. */
|
|
61
|
+
type: "string" | "float" | "date" | "boolean" | "formula" | "empty" | "covered";
|
|
62
|
+
/**
|
|
63
|
+
* The typed JavaScript value.
|
|
64
|
+
* - string → string
|
|
65
|
+
* - float → number
|
|
66
|
+
* - date → Date (UTC)
|
|
67
|
+
* - boolean → boolean
|
|
68
|
+
* - formula → cached result (number, string, or boolean)
|
|
69
|
+
* - empty/covered → null
|
|
70
|
+
*/
|
|
71
|
+
value: string | number | boolean | Date | null;
|
|
72
|
+
/**
|
|
73
|
+
* Original formula string for formula cells (e.g. `"=SUM(A1:A10)"`).
|
|
74
|
+
* The `of:` OpenFormula prefix is stripped.
|
|
75
|
+
* Undefined for non-formula cells.
|
|
76
|
+
*/
|
|
77
|
+
formula?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Display text as it appears in the cell (the text:p content).
|
|
80
|
+
* e.g. `"1,234.56"` for a formatted number, `"15/01/2026"` for a date.
|
|
81
|
+
* May differ from `value` when number or date formatting is applied.
|
|
82
|
+
*/
|
|
83
|
+
displayText?: string;
|
|
84
|
+
/**
|
|
85
|
+
* Number of columns this cell spans (1 = no merge).
|
|
86
|
+
* Only set when > 1.
|
|
87
|
+
*/
|
|
88
|
+
colSpan?: number;
|
|
89
|
+
/**
|
|
90
|
+
* Number of rows this cell spans (1 = no merge).
|
|
91
|
+
* Only set when > 1.
|
|
92
|
+
*/
|
|
93
|
+
rowSpan?: number;
|
|
94
|
+
/** Cell formatting extracted from the cell style. */
|
|
95
|
+
formatting?: OdsCellFormatting;
|
|
96
|
+
}
|
|
97
|
+
/** Cell formatting properties extracted from ODS automatic styles. */
|
|
98
|
+
export interface OdsCellFormatting {
|
|
99
|
+
bold?: boolean;
|
|
100
|
+
italic?: boolean;
|
|
101
|
+
underline?: boolean;
|
|
102
|
+
fontSize?: string;
|
|
103
|
+
fontFamily?: string;
|
|
104
|
+
/** Text color. */
|
|
105
|
+
color?: string;
|
|
106
|
+
/** Cell background color. */
|
|
107
|
+
backgroundColor?: string;
|
|
108
|
+
/** Horizontal text alignment. */
|
|
109
|
+
textAlign?: "left" | "center" | "right";
|
|
110
|
+
/** Vertical alignment. */
|
|
111
|
+
verticalAlign?: "top" | "middle" | "bottom";
|
|
112
|
+
/** Number format string (e.g. `"decimal:2"`, `"currency:EUR"`, `"percentage"`). */
|
|
113
|
+
numberFormat?: string;
|
|
114
|
+
/** Date format string (e.g. `"YYYY-MM-DD"`, `"DD/MM/YYYY"`). */
|
|
115
|
+
dateFormat?: string;
|
|
116
|
+
}
|
|
117
|
+
/** Options for {@link readOds}. */
|
|
118
|
+
export interface ReadOdsOptions {
|
|
119
|
+
/**
|
|
120
|
+
* Whether to include cell formatting in the model.
|
|
121
|
+
* Defaults to `true`. Set to `false` for faster parsing when
|
|
122
|
+
* only values and types are needed.
|
|
123
|
+
*/
|
|
124
|
+
includeFormatting?: boolean;
|
|
125
|
+
}
|
|
126
|
+
/** Options for {@link odsToHtml}. */
|
|
127
|
+
export interface OdsHtmlOptions {
|
|
128
|
+
/**
|
|
129
|
+
* Whether to include inline styles from cell formatting.
|
|
130
|
+
* Defaults to `true`.
|
|
131
|
+
*/
|
|
132
|
+
includeStyles?: boolean;
|
|
133
|
+
/**
|
|
134
|
+
* CSS class prefix for generated elements.
|
|
135
|
+
* Defaults to `"ods"`.
|
|
136
|
+
*/
|
|
137
|
+
classPrefix?: string;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ods-reader/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ods-reader/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "odf-kit",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.8",
|
|
4
4
|
"description": "Generate, fill, read, and convert OpenDocument Format (.odt) files in JavaScript and TypeScript. Works in Node.js and browsers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,10 +14,18 @@
|
|
|
14
14
|
"types": "./dist/odt/index.d.ts",
|
|
15
15
|
"import": "./dist/odt/index.js"
|
|
16
16
|
},
|
|
17
|
+
"./odt-reader": {
|
|
18
|
+
"types": "./dist/reader/index.d.ts",
|
|
19
|
+
"import": "./dist/reader/index.js"
|
|
20
|
+
},
|
|
17
21
|
"./ods": {
|
|
18
22
|
"types": "./dist/ods/index.d.ts",
|
|
19
23
|
"import": "./dist/ods/index.js"
|
|
20
24
|
},
|
|
25
|
+
"./ods-reader": {
|
|
26
|
+
"types": "./dist/ods-reader/index.d.ts",
|
|
27
|
+
"import": "./dist/ods-reader/index.js"
|
|
28
|
+
},
|
|
21
29
|
"./template": {
|
|
22
30
|
"types": "./dist/template/index.d.ts",
|
|
23
31
|
"import": "./dist/template/index.js"
|