js.documents 10.0.0 → 12.0.0

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 CHANGED
@@ -805,8 +805,8 @@ The package is layered from generic primitives outward to the two conversion dir
805
805
  - **`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.
806
806
  - **`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).
807
807
  - **`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`.
808
- - **`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.
809
- - **`src/svg/`** — fifth adapter family, sharing the drawing variant with odg. `text.ts` is the byte↔text boundary, rejecting malformed UTF-8; `read.ts` maps the six SVG shape primitives (rect/circle/ellipse/line/polyline/polygon/path) onto a one-page drawing `ContentDocument`, with transform lists composed as 2×3 affines and CSS lengths and the viewBox map resolved into page points; `write.ts` writes the six primitives back out, one shape element each; `path.ts` is the full SVG path-data grammar (M/L/H/V/C/S/Z plus Q/T/A and the relative forms — S/Q/T convert exactly, A is the one bounded approximation at ≤90° per cubic); `transform.ts` parses and composes the transform attribute and classifies the result by frame representability; `units.ts` resolves CSS length units and the viewBox; `paint.ts` resolves fill/stroke presentation attributes and dash styles; `diagnostics.ts` is the shared scope-limit vocabulary.
808
+ - **`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, working the character encoding out from the bytes through [byte-codec](../byte-codec/README.md#text-decoding) rather than assuming UTF-8, so Excel's own windows-1252 export reads, and refusing bytes that are not text at all; `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.
809
+ - **`src/svg/`** — fifth adapter family, sharing the drawing variant with odg. `text.ts` is the byte↔text boundary, still rejecting anything but UTF-8 where csv and markdown now detect the encoding, because SVG is XML and XML's own encoding declaration is authoritative ([#1359](https://github.com/ExaDev/documents.js/issues/1359)); `read.ts` maps the six SVG shape primitives (rect/circle/ellipse/line/polyline/polygon/path) onto a one-page drawing `ContentDocument`, with transform lists composed as 2×3 affines and CSS lengths and the viewBox map resolved into page points; `write.ts` writes the six primitives back out, one shape element each; `path.ts` is the full SVG path-data grammar (M/L/H/V/C/S/Z plus Q/T/A and the relative forms — S/Q/T convert exactly, A is the one bounded approximation at ≤90° per cubic); `transform.ts` parses and composes the transform attribute and classifies the result by frame representability; `units.ts` resolves CSS length units and the viewBox; `paint.ts` resolves fill/stroke presentation attributes and dash styles; `diagnostics.ts` is the shared scope-limit vocabulary.
810
810
  - **`src/layout/`** — the pure conversion algorithms: `engine.ts` (wordprocessing → layout: flow, line-breaking, pagination), `slides.ts` (presentation → layout: direct placement), `sheets.ts` (spreadsheet → layout: grid, print settings, the first algorithm accepting `AbortSignal`), `drawing.ts` (drawing → layout: vector primitives + shape reuse), `reconstruct.ts` (layout → content: baseline clustering for wordprocessing/presentation, near-1:1 mapping for drawing, gridline-lattice-or-text-clustering for spreadsheet; plus the PDF construct surfacing — link reconciliation to `ContentRun.hyperlink` or link constructs, hidden-layer content dropped, anchor/comment and AcroForm contentControl constructs, and tagged-structure semantics where the file states them: heading levels from owning `H1`..`H6` elements over the font-size census, lattice-free table recovery from `/Table`/`/TR`/`/TH`/`/TD` ownership, and `division` constructs around `/Part`/`/Sect`/`/Div` extents).
811
811
  - **`src/hsqldb/`** — `.odb` decoders, four tiers: `script.ts` (TEXT-script DDL/DML parser), `rowformat.ts`/`cache.ts` (CACHED binary row-store), `binary-script.ts` (BINARY/COMPRESSED whole-script). All import only `document-schema.js` — no odf.js knowledge.
812
812
  - **`src/firebird/`** — Tier 3: gbak logical-backup reader. `reader.ts` (attribute framing + RLE decompression + XDR decoding), `schema.ts`/`data.ts` (table/row walking). No ratified spec — built against Firebird's own engine source.
@@ -925,7 +925,7 @@ To run a single test file: `pnpm vitest run src/path/to/file.test.ts`.
925
925
  - **Every markdown construct-mapping gap is a documented `MarkdownDiagnosticCodes` entry** (`md/invented-page-geometry`, `md/nested-emphasis-flattened`, `md/link-title-dropped`, `md/blockquote-container-skipped`, `md/list-item-block-unlisted`, `md/image-unresolved`, `md/raw-html-preserved-as-text`/`md/raw-html-dropped`, `md/front-matter-key-unmapped`, `md/heading-level-clamped`, `md/adjacent-links-merged`, `md/code-span-as-monospace-run`, `md/paragraph-indent-dropped`, `md/list-numid-fallback`, `md/table-cell-formatting-dropped`, `md/table-cell-multi-paragraph-joined`) — never a silent approximation. The info-string, multi-block-item, and blockquote-depth gaps that used to be in this list are closed: a fence's language word rides `ContentParagraph.codeLanguage`, item identity rides `ContentListMembership.itemId`, and a blockquote carries a `division` construct pair.
926
926
  - **`buildMarkdownText` throws for non-`'wordprocessing'` `ContentDocument`.**
927
927
  - **`buildMarkdownText` passes `constructStart`/`constructEnd` markers through to markdown-codec's own writer**, which resolves them as balanced brackets: a construct with a markdown spelling renders as that syntax (a footnote definition, a blockquote division, a titled image's link wrapper), one without renders its extent transparently under a diagnostic. A genuinely unbalanced list still throws — markdown-codec's own `MarkdownUnbalancedConstructMarkersError`, the shared definition of that check. The old `MarkdownConstructUnsupportedError` refusal is gone: markdown-codec's read side now emits marker pairs of its own (blockquotes, titled images), so a writer that refused markers would refuse this package's own editor round trips.
928
- - **`decodeMarkdownText` throws on malformed UTF-8** rather than producing U+FFFD.
928
+ - **`decodeMarkdownText` detects the character encoding** rather than assuming UTF-8, so a file saved in the Windows system code page or as UTF-16 reads; it throws for bytes that are not text rather than producing U+FFFD.
929
929
  - **The composition engine routes every pair generically** through a declarative primitive registry and minimum-cost pathfinder. `resolveCompositionPlan` finds the minimum-cost route (same-variant bridge < cross-variant transform < via-PDF multi-hop). Named functions are thin forwarders.
930
930
 
931
931
  ## Fidelity
package/dist/csv/text.cjs CHANGED
@@ -1,22 +1,40 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ let byte_codec = require("byte-codec");
2
3
  //#region src/csv/text.ts
3
- var CsvInvalidUtf8Error = class extends Error {
4
- constructor() {
5
- super("csv text must be well-formed UTF-8");
6
- this.name = "CsvInvalidUtf8Error";
4
+ /** Thrown when csv bytes cannot be decoded as text at all: they are binary, they contradict an encoding the caller declared or a byte order mark named, or they match none of the encodings byte-codec's decodeText supports. */
5
+ var CsvUndecodableTextError = class extends Error {
6
+ /** Which of those three it was, carried through from byte-codec so a caller can branch on it without unwrapping `cause`. */
7
+ reason;
8
+ constructor(cause) {
9
+ super(`csv bytes could not be decoded as text: ${cause.message}`, { cause });
10
+ this.name = "CsvUndecodableTextError";
11
+ this.reason = cause.reason;
7
12
  }
8
13
  };
9
- function decodeCsvText(bytes) {
14
+ /**
15
+ * Decodes csv bytes to text, working the character encoding out from the bytes.
16
+ * @param bytes - The csv bytes.
17
+ * @param options - An explicit `encoding` to decode under, skipping detection. Reach for it when the bytes are in an encoding detection cannot see, a mark-less UTF-16 file holding CJK text being the case that occurs.
18
+ * @throws CsvUndecodableTextError When the bytes are not text, or match none of the supported encodings.
19
+ * @returns The csv text.
20
+ */
21
+ function decodeCsvText(bytes, options) {
10
22
  try {
11
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
12
- } catch {
13
- throw new CsvInvalidUtf8Error();
23
+ return (0, byte_codec.decodeText)(bytes, options).text;
24
+ } catch (error) {
25
+ if (error instanceof byte_codec.UndecodableTextError) throw new CsvUndecodableTextError(error);
26
+ throw error;
14
27
  }
15
28
  }
29
+ /**
30
+ * Encodes csv text as UTF-8 bytes.
31
+ * @param text - The csv text.
32
+ * @returns The UTF-8 bytes, whatever encoding the text was originally decoded from.
33
+ */
16
34
  function encodeCsvText(text) {
17
35
  return new TextEncoder().encode(text);
18
36
  }
19
37
  //#endregion
20
- exports.CsvInvalidUtf8Error = CsvInvalidUtf8Error;
38
+ exports.CsvUndecodableTextError = CsvUndecodableTextError;
21
39
  exports.decodeCsvText = decodeCsvText;
22
40
  exports.encodeCsvText = encodeCsvText;
@@ -1,8 +1,24 @@
1
+ import { DecodeTextOptions, UndecodableTextError } from "byte-codec";
1
2
  //#region src/csv/text.d.ts
2
- declare class CsvInvalidUtf8Error extends Error {
3
- constructor();
3
+ /** Thrown when csv bytes cannot be decoded as text at all: they are binary, they contradict an encoding the caller declared or a byte order mark named, or they match none of the encodings byte-codec's decodeText supports. */
4
+ declare class CsvUndecodableTextError extends Error {
5
+ /** Which of those three it was, carried through from byte-codec so a caller can branch on it without unwrapping `cause`. */
6
+ readonly reason: UndecodableTextError["reason"];
7
+ constructor(cause: UndecodableTextError);
4
8
  }
5
- declare function decodeCsvText(bytes: Uint8Array): string;
9
+ /**
10
+ * Decodes csv bytes to text, working the character encoding out from the bytes.
11
+ * @param bytes - The csv bytes.
12
+ * @param options - An explicit `encoding` to decode under, skipping detection. Reach for it when the bytes are in an encoding detection cannot see, a mark-less UTF-16 file holding CJK text being the case that occurs.
13
+ * @throws CsvUndecodableTextError When the bytes are not text, or match none of the supported encodings.
14
+ * @returns The csv text.
15
+ */
16
+ declare function decodeCsvText(bytes: Uint8Array, options?: DecodeTextOptions): string;
17
+ /**
18
+ * Encodes csv text as UTF-8 bytes.
19
+ * @param text - The csv text.
20
+ * @returns The UTF-8 bytes, whatever encoding the text was originally decoded from.
21
+ */
6
22
  declare function encodeCsvText(text: string): Uint8Array<ArrayBuffer>;
7
23
  //#endregion
8
- export { CsvInvalidUtf8Error, decodeCsvText, encodeCsvText };
24
+ export { CsvUndecodableTextError, decodeCsvText, encodeCsvText };
@@ -1,8 +1,24 @@
1
+ import { DecodeTextOptions, UndecodableTextError } from "byte-codec";
1
2
  //#region src/csv/text.d.ts
2
- declare class CsvInvalidUtf8Error extends Error {
3
- constructor();
3
+ /** Thrown when csv bytes cannot be decoded as text at all: they are binary, they contradict an encoding the caller declared or a byte order mark named, or they match none of the encodings byte-codec's decodeText supports. */
4
+ declare class CsvUndecodableTextError extends Error {
5
+ /** Which of those three it was, carried through from byte-codec so a caller can branch on it without unwrapping `cause`. */
6
+ readonly reason: UndecodableTextError["reason"];
7
+ constructor(cause: UndecodableTextError);
4
8
  }
5
- declare function decodeCsvText(bytes: Uint8Array): string;
9
+ /**
10
+ * Decodes csv bytes to text, working the character encoding out from the bytes.
11
+ * @param bytes - The csv bytes.
12
+ * @param options - An explicit `encoding` to decode under, skipping detection. Reach for it when the bytes are in an encoding detection cannot see, a mark-less UTF-16 file holding CJK text being the case that occurs.
13
+ * @throws CsvUndecodableTextError When the bytes are not text, or match none of the supported encodings.
14
+ * @returns The csv text.
15
+ */
16
+ declare function decodeCsvText(bytes: Uint8Array, options?: DecodeTextOptions): string;
17
+ /**
18
+ * Encodes csv text as UTF-8 bytes.
19
+ * @param text - The csv text.
20
+ * @returns The UTF-8 bytes, whatever encoding the text was originally decoded from.
21
+ */
6
22
  declare function encodeCsvText(text: string): Uint8Array<ArrayBuffer>;
7
23
  //#endregion
8
- export { CsvInvalidUtf8Error, decodeCsvText, encodeCsvText };
24
+ export { CsvUndecodableTextError, decodeCsvText, encodeCsvText };
package/dist/csv/text.js CHANGED
@@ -1,19 +1,37 @@
1
+ import { UndecodableTextError, decodeText } from "byte-codec";
1
2
  //#region src/csv/text.ts
2
- var CsvInvalidUtf8Error = class extends Error {
3
- constructor() {
4
- super("csv text must be well-formed UTF-8");
5
- this.name = "CsvInvalidUtf8Error";
3
+ /** Thrown when csv bytes cannot be decoded as text at all: they are binary, they contradict an encoding the caller declared or a byte order mark named, or they match none of the encodings byte-codec's decodeText supports. */
4
+ var CsvUndecodableTextError = class extends Error {
5
+ /** Which of those three it was, carried through from byte-codec so a caller can branch on it without unwrapping `cause`. */
6
+ reason;
7
+ constructor(cause) {
8
+ super(`csv bytes could not be decoded as text: ${cause.message}`, { cause });
9
+ this.name = "CsvUndecodableTextError";
10
+ this.reason = cause.reason;
6
11
  }
7
12
  };
8
- function decodeCsvText(bytes) {
13
+ /**
14
+ * Decodes csv bytes to text, working the character encoding out from the bytes.
15
+ * @param bytes - The csv bytes.
16
+ * @param options - An explicit `encoding` to decode under, skipping detection. Reach for it when the bytes are in an encoding detection cannot see, a mark-less UTF-16 file holding CJK text being the case that occurs.
17
+ * @throws CsvUndecodableTextError When the bytes are not text, or match none of the supported encodings.
18
+ * @returns The csv text.
19
+ */
20
+ function decodeCsvText(bytes, options) {
9
21
  try {
10
- return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
11
- } catch {
12
- throw new CsvInvalidUtf8Error();
22
+ return decodeText(bytes, options).text;
23
+ } catch (error) {
24
+ if (error instanceof UndecodableTextError) throw new CsvUndecodableTextError(error);
25
+ throw error;
13
26
  }
14
27
  }
28
+ /**
29
+ * Encodes csv text as UTF-8 bytes.
30
+ * @param text - The csv text.
31
+ * @returns The UTF-8 bytes, whatever encoding the text was originally decoded from.
32
+ */
15
33
  function encodeCsvText(text) {
16
34
  return new TextEncoder().encode(text);
17
35
  }
18
36
  //#endregion
19
- export { CsvInvalidUtf8Error, decodeCsvText, encodeCsvText };
37
+ export { CsvUndecodableTextError, decodeCsvText, encodeCsvText };
@@ -210,11 +210,10 @@ function docxRowCells(positions, positionsByRow) {
210
210
  }
211
211
  function appendTable(body, block) {
212
212
  require_edit_table_grid.assertTableObeysGridRule(block, "buildDocxPackage");
213
- const columns = block.columnWidthsPt.length;
214
- if (block.rows.length === 0 || columns === 0) return;
213
+ if (block.rows.length === 0) throw new Error("buildDocxPackage: table has no rows, and a table with no rows cannot be written in every word-processing format (ODF requires at least one table:table-row)");
215
214
  const table = body.appendTable({
216
215
  rows: 0,
217
- columns,
216
+ columns: (0, document_schema_js.tableGridColumnCount)(block),
218
217
  columnWidthsTwips: block.columnWidthsPt.map(require_model_units.ptToTwips)
219
218
  });
220
219
  const positionsByRow = (0, document_schema_js.walkTableGrid)(block);
@@ -11,7 +11,7 @@ import { FLOW_CONTAINER_ORIGIN, drawingOfBlock, embeddedDrawingVectors } from ".
11
11
  import { formulaOfBlock, formulaPlaceholderText } from "../../model/formula.js";
12
12
  import { NUMBERING_CONTENT_TYPE, NUMBERING_PART_PATH, NUMBERING_REL_TYPE, buildNumberingRoot, declaration } from "./numbering.js";
13
13
  import { base64ToBytes } from "ooxml.js";
14
- import { resolveCellFillColor, tableCellColumnSpan, tableCellRowSpan, walkTableGrid } from "document-schema.js";
14
+ import { resolveCellFillColor, tableCellColumnSpan, tableCellRowSpan, tableGridColumnCount, walkTableGrid } from "document-schema.js";
15
15
  //#region src/edit/docx/content.ts
16
16
  var ConstructMarkerState = class {
17
17
  nextBookmarkId = 1;
@@ -209,11 +209,10 @@ function docxRowCells(positions, positionsByRow) {
209
209
  }
210
210
  function appendTable(body, block) {
211
211
  assertTableObeysGridRule(block, "buildDocxPackage");
212
- const columns = block.columnWidthsPt.length;
213
- if (block.rows.length === 0 || columns === 0) return;
212
+ if (block.rows.length === 0) throw new Error("buildDocxPackage: table has no rows, and a table with no rows cannot be written in every word-processing format (ODF requires at least one table:table-row)");
214
213
  const table = body.appendTable({
215
214
  rows: 0,
216
- columns,
215
+ columns: tableGridColumnCount(block),
217
216
  columnWidthsTwips: block.columnWidthsPt.map(ptToTwips)
218
217
  });
219
218
  const positionsByRow = walkTableGrid(block);
@@ -52,11 +52,7 @@ function appendShape(slide, shape) {
52
52
  if (shape.blocks.length === 1 && onlyBlock?.kind === "table") {
53
53
  const { shape: tableFrame, table } = slide.addTable({
54
54
  frame: shape.frame,
55
- table: {
56
- rows: 0,
57
- columns: onlyBlock.columnWidthsPt.length,
58
- columnWidthsPt: onlyBlock.columnWidthsPt
59
- }
55
+ table: require_edit_odt_content.odtTableInit(onlyBlock, "buildOdpPackage")
60
56
  });
61
57
  if (shape.rotationDeg !== void 0) tableFrame.rotationDeg = shape.rotationDeg;
62
58
  require_edit_odt_content.populateOdtTable(table, onlyBlock);
@@ -2,7 +2,7 @@ import { resolveMetadataTimestamps } from "../../model/metadata.js";
2
2
  import { systemClock } from "../../ports/clock.js";
3
3
  import { drawingOfBlock, embeddedDrawingVectors } from "../../model/embedded-drawing.js";
4
4
  import { formulaOfBlock, formulaPlaceholderText } from "../../model/formula.js";
5
- import { populateOdtTable, populateParagraph } from "../odt/content.js";
5
+ import { odtTableInit, populateOdtTable, populateParagraph } from "../odt/content.js";
6
6
  import { createEmptyOdpPackage } from "./scaffold.js";
7
7
  import { OdpEditor } from "./editor.js";
8
8
  import { base64ToBytes } from "odf.js";
@@ -51,11 +51,7 @@ function appendShape(slide, shape) {
51
51
  if (shape.blocks.length === 1 && onlyBlock?.kind === "table") {
52
52
  const { shape: tableFrame, table } = slide.addTable({
53
53
  frame: shape.frame,
54
- table: {
55
- rows: 0,
56
- columns: onlyBlock.columnWidthsPt.length,
57
- columnWidthsPt: onlyBlock.columnWidthsPt
58
- }
54
+ table: odtTableInit(onlyBlock, "buildOdpPackage")
59
55
  });
60
56
  if (shape.rotationDeg !== void 0) tableFrame.rotationDeg = shape.rotationDeg;
61
57
  populateOdtTable(table, onlyBlock);
@@ -1,7 +1,7 @@
1
1
  import { t as ImageInit } from "../../image-D1z0T9Za.cjs";
2
2
  import { t as OdpShape } from "../../shape-Kmmxib5z.cjs";
3
3
  import { s as OdgVector } from "../../vector-DDP7hgvm.cjs";
4
- import { o as TableInit, r as OdtTable } from "../../table-CCjF09Ho.cjs";
4
+ import { o as TableInit, r as OdtTable } from "../../table-BT3wN3Hd.cjs";
5
5
  import { Box, ContentFormula, ContentVector } from "document-schema.js";
6
6
  import { Package, XmlElement, XmlNode } from "odf.js";
7
7
  //#region src/edit/odp/slide.d.ts
@@ -1,7 +1,7 @@
1
1
  import { t as ImageInit } from "../../image-D1z0T9Za.js";
2
2
  import { t as OdpShape } from "../../shape-ZAfNsCC5.js";
3
3
  import { s as OdgVector } from "../../vector-DDP7hgvm.js";
4
- import { o as TableInit, r as OdtTable } from "../../table-BMYJo_-F.js";
4
+ import { o as TableInit, r as OdtTable } from "../../table-DhTy5Re7.js";
5
5
  import { Box, ContentFormula, ContentVector } from "document-schema.js";
6
6
  import { Package, XmlElement, XmlNode } from "odf.js";
7
7
  //#region src/edit/odp/slide.d.ts
@@ -158,14 +158,23 @@ function applyCellDecoration(target, cell) {
158
158
  if (cell.background !== void 0) target.background = (0, document_schema_js.resolveCellFillColor)(cell.background);
159
159
  if (cell.borders !== void 0) target.borders = cell.borders;
160
160
  }
161
- function appendTable(body, block) {
162
- const columns = block.columnWidthsPt.length;
163
- if (block.rows.length === 0 || columns === 0) return;
164
- populateOdtTable(body.appendTable({
161
+ /**
162
+ * The arguments that create the empty `table:table` a ContentTable is written into: no rows, since populateOdtTable appends one per ContentTableRow, and as many columns as the table's grid is wide.
163
+ *
164
+ * The grid width is what the rows and `columnWidthsPt` together state (tableGridColumnCount), so a table whose rows carry cells but which states no column widths still gets one `table:table-column` per grid column; a column with no stated width takes an equal share of the default table width, the same as any column created without one. `columnWidthsPt` is passed through untouched, so a width the table does state is always written.
165
+ *
166
+ * Throws when the table has no rows: ODF requires a `table:table` to hold at least one `table:table-row`, so no faithful spelling exists, and dropping the table would lose it without a trace. `entryPoint` names the caller in the message. A table that breaks the grid rule is refused by populateOdtTable before it writes anything, and a table with no rows has no grid fault to report, so the two checks never compete.
167
+ */
168
+ function odtTableInit(block, entryPoint) {
169
+ if (block.rows.length === 0) throw new Error(`${entryPoint}: table has no rows, and ODF requires a table:table to hold at least one table:table-row`);
170
+ return {
165
171
  rows: 0,
166
- columns,
172
+ columns: (0, document_schema_js.tableGridColumnCount)(block),
167
173
  columnWidthsPt: block.columnWidthsPt
168
- }), block);
174
+ };
175
+ }
176
+ function appendTable(body, block) {
177
+ populateOdtTable(body.appendTable(odtTableInit(block, "buildOdtPackage")), block);
169
178
  }
170
179
  function appendCellBlock(cell, block) {
171
180
  if (block.kind === "paragraph") populateParagraph(cell.appendParagraph(), block, { headings: "element" });
@@ -242,5 +251,6 @@ function appendEmbeddedObject(body, block) {
242
251
  }
243
252
  //#endregion
244
253
  exports.buildOdtPackage = buildOdtPackage;
254
+ exports.odtTableInit = odtTableInit;
245
255
  exports.populateOdtTable = populateOdtTable;
246
256
  exports.populateParagraph = populateParagraph;
@@ -1,6 +1,6 @@
1
1
  import { t as ClockPort } from "../../clock-C7SUuYN0.cjs";
2
2
  import { t as OdtParagraph } from "../../paragraph-CRaLSzWz.cjs";
3
- import { r as OdtTable } from "../../table-CCjF09Ho.cjs";
3
+ import { o as TableInit, r as OdtTable } from "../../table-BT3wN3Hd.cjs";
4
4
  import { ContentDocument, ContentParagraph, ContentTable } from "document-schema.js";
5
5
  import { Package } from "odf.js";
6
6
  //#region src/edit/odt/content.d.ts
@@ -13,5 +13,13 @@ interface PopulateParagraphOptions {
13
13
  }
14
14
  declare function populateParagraph(paragraph: OdtParagraph, block: ContentParagraph, options: PopulateParagraphOptions): void;
15
15
  declare function populateOdtTable(table: OdtTable, block: ContentTable): void;
16
+ /**
17
+ * The arguments that create the empty `table:table` a ContentTable is written into: no rows, since populateOdtTable appends one per ContentTableRow, and as many columns as the table's grid is wide.
18
+ *
19
+ * The grid width is what the rows and `columnWidthsPt` together state (tableGridColumnCount), so a table whose rows carry cells but which states no column widths still gets one `table:table-column` per grid column; a column with no stated width takes an equal share of the default table width, the same as any column created without one. `columnWidthsPt` is passed through untouched, so a width the table does state is always written.
20
+ *
21
+ * Throws when the table has no rows: ODF requires a `table:table` to hold at least one `table:table-row`, so no faithful spelling exists, and dropping the table would lose it without a trace. `entryPoint` names the caller in the message. A table that breaks the grid rule is refused by populateOdtTable before it writes anything, and a table with no rows has no grid fault to report, so the two checks never compete.
22
+ */
23
+ declare function odtTableInit(block: ContentTable, entryPoint: string): TableInit;
16
24
  //#endregion
17
- export { BuildOdtPackageOptions, PopulateParagraphOptions, buildOdtPackage, populateOdtTable, populateParagraph };
25
+ export { BuildOdtPackageOptions, PopulateParagraphOptions, buildOdtPackage, odtTableInit, populateOdtTable, populateParagraph };
@@ -1,6 +1,6 @@
1
1
  import { t as ClockPort } from "../../clock-C7SUuYN0.js";
2
2
  import { t as OdtParagraph } from "../../paragraph-D4f705GG.js";
3
- import { r as OdtTable } from "../../table-BMYJo_-F.js";
3
+ import { o as TableInit, r as OdtTable } from "../../table-DhTy5Re7.js";
4
4
  import { ContentDocument, ContentParagraph, ContentTable } from "document-schema.js";
5
5
  import { Package } from "odf.js";
6
6
  //#region src/edit/odt/content.d.ts
@@ -13,5 +13,13 @@ interface PopulateParagraphOptions {
13
13
  }
14
14
  declare function populateParagraph(paragraph: OdtParagraph, block: ContentParagraph, options: PopulateParagraphOptions): void;
15
15
  declare function populateOdtTable(table: OdtTable, block: ContentTable): void;
16
+ /**
17
+ * The arguments that create the empty `table:table` a ContentTable is written into: no rows, since populateOdtTable appends one per ContentTableRow, and as many columns as the table's grid is wide.
18
+ *
19
+ * The grid width is what the rows and `columnWidthsPt` together state (tableGridColumnCount), so a table whose rows carry cells but which states no column widths still gets one `table:table-column` per grid column; a column with no stated width takes an equal share of the default table width, the same as any column created without one. `columnWidthsPt` is passed through untouched, so a width the table does state is always written.
20
+ *
21
+ * Throws when the table has no rows: ODF requires a `table:table` to hold at least one `table:table-row`, so no faithful spelling exists, and dropping the table would lose it without a trace. `entryPoint` names the caller in the message. A table that breaks the grid rule is refused by populateOdtTable before it writes anything, and a table with no rows has no grid fault to report, so the two checks never compete.
22
+ */
23
+ declare function odtTableInit(block: ContentTable, entryPoint: string): TableInit;
16
24
  //#endregion
17
- export { BuildOdtPackageOptions, PopulateParagraphOptions, buildOdtPackage, populateOdtTable, populateParagraph };
25
+ export { BuildOdtPackageOptions, PopulateParagraphOptions, buildOdtPackage, odtTableInit, populateOdtTable, populateParagraph };
@@ -6,7 +6,7 @@ import { formulaOfBlock, formulaPlaceholderText } from "../../model/formula.js";
6
6
  import { headingStyleName } from "./paragraph.js";
7
7
  import { createEmptyOdtPackage } from "./scaffold.js";
8
8
  import { OdtEditor } from "./editor.js";
9
- import { resolveCellFillColor, tableCellColumnSpan, tableCellRowSpan, walkTableGrid } from "document-schema.js";
9
+ import { resolveCellFillColor, tableCellColumnSpan, tableCellRowSpan, tableGridColumnCount, walkTableGrid } from "document-schema.js";
10
10
  import { base64ToBytes } from "odf.js";
11
11
  //#region src/edit/odt/content.ts
12
12
  function buildOdtPackage(content, options) {
@@ -157,14 +157,23 @@ function applyCellDecoration(target, cell) {
157
157
  if (cell.background !== void 0) target.background = resolveCellFillColor(cell.background);
158
158
  if (cell.borders !== void 0) target.borders = cell.borders;
159
159
  }
160
- function appendTable(body, block) {
161
- const columns = block.columnWidthsPt.length;
162
- if (block.rows.length === 0 || columns === 0) return;
163
- populateOdtTable(body.appendTable({
160
+ /**
161
+ * The arguments that create the empty `table:table` a ContentTable is written into: no rows, since populateOdtTable appends one per ContentTableRow, and as many columns as the table's grid is wide.
162
+ *
163
+ * The grid width is what the rows and `columnWidthsPt` together state (tableGridColumnCount), so a table whose rows carry cells but which states no column widths still gets one `table:table-column` per grid column; a column with no stated width takes an equal share of the default table width, the same as any column created without one. `columnWidthsPt` is passed through untouched, so a width the table does state is always written.
164
+ *
165
+ * Throws when the table has no rows: ODF requires a `table:table` to hold at least one `table:table-row`, so no faithful spelling exists, and dropping the table would lose it without a trace. `entryPoint` names the caller in the message. A table that breaks the grid rule is refused by populateOdtTable before it writes anything, and a table with no rows has no grid fault to report, so the two checks never compete.
166
+ */
167
+ function odtTableInit(block, entryPoint) {
168
+ if (block.rows.length === 0) throw new Error(`${entryPoint}: table has no rows, and ODF requires a table:table to hold at least one table:table-row`);
169
+ return {
164
170
  rows: 0,
165
- columns,
171
+ columns: tableGridColumnCount(block),
166
172
  columnWidthsPt: block.columnWidthsPt
167
- }), block);
173
+ };
174
+ }
175
+ function appendTable(body, block) {
176
+ populateOdtTable(body.appendTable(odtTableInit(block, "buildOdtPackage")), block);
168
177
  }
169
178
  function appendCellBlock(cell, block) {
170
179
  if (block.kind === "paragraph") populateParagraph(cell.appendParagraph(), block, { headings: "element" });
@@ -240,4 +249,4 @@ function appendEmbeddedObject(body, block) {
240
249
  body.appendFormula(formula, block.frame);
241
250
  }
242
251
  //#endregion
243
- export { buildOdtPackage, populateOdtTable, populateParagraph };
252
+ export { buildOdtPackage, odtTableInit, populateOdtTable, populateParagraph };
@@ -1,7 +1,7 @@
1
1
  import { t as ClockPort } from "../../clock-C7SUuYN0.cjs";
2
2
  import { n as ParagraphInit, t as OdtParagraph } from "../../paragraph-CRaLSzWz.cjs";
3
3
  import { t as OdtList } from "../../list-C_UPIZWM.cjs";
4
- import { o as TableInit, r as OdtTable } from "../../table-CCjF09Ho.cjs";
4
+ import { o as TableInit, r as OdtTable } from "../../table-BT3wN3Hd.cjs";
5
5
  import { Box, ContentControlDescriptor, ContentFormula, ContentVector, DivisionDescriptor, LayoutMetadata } from "document-schema.js";
6
6
  import { Package } from "odf.js";
7
7
  //#region src/edit/odt/editor.d.ts
@@ -1,7 +1,7 @@
1
1
  import { t as ClockPort } from "../../clock-C7SUuYN0.js";
2
2
  import { n as ParagraphInit, t as OdtParagraph } from "../../paragraph-D4f705GG.js";
3
3
  import { t as OdtList } from "../../list-C2GWIe6E.js";
4
- import { o as TableInit, r as OdtTable } from "../../table-BMYJo_-F.js";
4
+ import { o as TableInit, r as OdtTable } from "../../table-DhTy5Re7.js";
5
5
  import { Box, ContentControlDescriptor, ContentFormula, ContentVector, DivisionDescriptor, LayoutMetadata } from "document-schema.js";
6
6
  import { Package } from "odf.js";
7
7
  //#region src/edit/odt/editor.d.ts