js.documents 12.1.0 → 14.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.
Files changed (58) hide show
  1. package/README.md +1 -1
  2. package/dist/codecs/read.cjs +1 -1
  3. package/dist/codecs/read.js +1 -1
  4. package/dist/codecs/registry.cjs +1 -1
  5. package/dist/codecs/registry.js +1 -1
  6. package/dist/convert/composition.cjs +1 -1
  7. package/dist/convert/composition.js +1 -1
  8. package/dist/edit/docx/content.cjs +1 -0
  9. package/dist/edit/docx/content.js +1 -0
  10. package/dist/edit/docx/table.cjs +14 -0
  11. package/dist/edit/docx/table.d.cts +2 -0
  12. package/dist/edit/docx/table.d.ts +2 -0
  13. package/dist/edit/docx/table.js +14 -0
  14. package/dist/edit/odf-repeated-runs.cjs +99 -0
  15. package/dist/edit/odf-repeated-runs.d.cts +22 -0
  16. package/dist/edit/odf-repeated-runs.d.ts +22 -0
  17. package/dist/edit/odf-repeated-runs.js +87 -0
  18. package/dist/edit/odp/slide.d.cts +1 -1
  19. package/dist/edit/odp/slide.d.ts +1 -1
  20. package/dist/edit/ods/address.cjs +9 -101
  21. package/dist/edit/ods/address.d.cts +2 -18
  22. package/dist/edit/ods/address.d.ts +2 -18
  23. package/dist/edit/ods/address.js +4 -86
  24. package/dist/edit/ods/column-row.cjs +7 -6
  25. package/dist/edit/ods/column-row.js +2 -1
  26. package/dist/edit/ods/floating.cjs +5 -4
  27. package/dist/edit/ods/floating.js +2 -1
  28. package/dist/edit/ods/print-settings.cjs +8 -7
  29. package/dist/edit/ods/print-settings.js +2 -1
  30. package/dist/edit/ods/sheet.cjs +2 -1
  31. package/dist/edit/ods/sheet.js +2 -1
  32. package/dist/edit/odt/content.cjs +2 -0
  33. package/dist/edit/odt/content.d.cts +1 -1
  34. package/dist/edit/odt/content.d.ts +1 -1
  35. package/dist/edit/odt/content.js +2 -0
  36. package/dist/edit/odt/editor.d.cts +1 -1
  37. package/dist/edit/odt/editor.d.ts +1 -1
  38. package/dist/edit/odt/table.cjs +114 -22
  39. package/dist/edit/odt/table.d.cts +1 -1
  40. package/dist/edit/odt/table.d.ts +1 -1
  41. package/dist/edit/odt/table.js +114 -22
  42. package/dist/index.cjs +3 -2
  43. package/dist/index.d.cts +3 -3
  44. package/dist/index.d.ts +3 -3
  45. package/dist/index.js +2 -2
  46. package/dist/model/bytes.cjs +5 -8
  47. package/dist/model/bytes.js +5 -8
  48. package/dist/svg/text.cjs +41 -8
  49. package/dist/svg/text.d.cts +25 -3
  50. package/dist/svg/text.d.ts +25 -3
  51. package/dist/svg/text.js +40 -8
  52. package/dist/svg/xml-encoding.cjs +91 -0
  53. package/dist/svg/xml-encoding.d.cts +32 -0
  54. package/dist/svg/xml-encoding.d.ts +32 -0
  55. package/dist/svg/xml-encoding.js +88 -0
  56. package/dist/{table-BT3wN3Hd.d.cts → table-Bt9ahRyh.d.cts} +2 -0
  57. package/dist/{table-DhTy5Re7.d.ts → table-Cou5rKOo.d.ts} +2 -0
  58. package/package.json +14 -14
package/README.md CHANGED
@@ -806,7 +806,7 @@ The package is layered from generic primitives outward to the two conversion dir
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
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.
809
+ - **`src/svg/`** — fifth adapter family, sharing the drawing variant with odg. `text.ts` is the byte↔text boundary: unlike csv and markdown, it does not detect the encoding from the bytes, because SVG is XML and XML's own `<?xml ... encoding="..."?>` declaration is authoritative; `xml-encoding.ts` reads that declaration (or a byte order mark) from the leading bytes per XML 1.0's own external-encoding-detection algorithm, ahead of any real decode, with UTF-8 the strict default when neither is present; `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.
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_svg_text = require("../svg/text.cjs");
2
3
  const require_model_bytes = require("../model/bytes.cjs");
3
4
  const require_markdown_read = require("../markdown/read.cjs");
4
5
  const require_read = require("../read-pPa9I8MO.cjs");
@@ -12,7 +13,6 @@ const require_odf_odg_read = require("../odf/odg/read.cjs");
12
13
  const require_markdown_text = require("../markdown/text.cjs");
13
14
  const require_csv_text = require("../csv/text.cjs");
14
15
  const require_csv_read = require("../csv/read.cjs");
15
- const require_svg_text = require("../svg/text.cjs");
16
16
  const require_svg_read = require("../svg/read.cjs");
17
17
  const require_ports_abort = require("../ports/abort.cjs");
18
18
  const require_package_codec = require("../package-codec.cjs");
@@ -1,3 +1,4 @@
1
+ import { decodeSvgText } from "../svg/text.js";
1
2
  import { requireArrayBufferBytes } from "../model/bytes.js";
2
3
  import { readMarkdownContent } from "../markdown/read.js";
3
4
  import { t as readPptContent } from "../read--7mUJ4w7.js";
@@ -11,7 +12,6 @@ import { readOdgContent } from "../odf/odg/read.js";
11
12
  import { decodeMarkdownText } from "../markdown/text.js";
12
13
  import { decodeCsvText } from "../csv/text.js";
13
14
  import { readCsvContent } from "../csv/read.js";
14
- import { decodeSvgText } from "../svg/text.js";
15
15
  import { readSvgContent } from "../svg/read.js";
16
16
  import { throwIfAborted } from "../ports/abort.js";
17
17
  import { decodeDocumentPackage } from "../package-codec.js";
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_svg_text = require("../svg/text.cjs");
2
3
  const require_edit_docx_content = require("../edit/docx/content.cjs");
3
4
  const require_edit_pptx_content = require("../edit/pptx/content.cjs");
4
5
  const require_edit_odt_content = require("../edit/odt/content.cjs");
@@ -10,7 +11,6 @@ const require_ppt_write = require("../ppt/write.cjs");
10
11
  const require_markdown_text = require("../markdown/text.cjs");
11
12
  const require_csv_text = require("../csv/text.cjs");
12
13
  const require_csv_write = require("../csv/write.cjs");
13
- const require_svg_text = require("../svg/text.cjs");
14
14
  const require_svg_write = require("../svg/write.cjs");
15
15
  const require_package_codec = require("../package-codec.cjs");
16
16
  const require_codecs_read = require("./read.cjs");
@@ -1,3 +1,4 @@
1
+ import { encodeSvgText } from "../svg/text.js";
1
2
  import { buildDocxPackage } from "../edit/docx/content.js";
2
3
  import { buildPptxPackage } from "../edit/pptx/content.js";
3
4
  import { buildOdtPackage } from "../edit/odt/content.js";
@@ -9,7 +10,6 @@ import { writePptContent } from "../ppt/write.js";
9
10
  import { encodeMarkdownText } from "../markdown/text.js";
10
11
  import { encodeCsvText } from "../csv/text.js";
11
12
  import { buildCsvText } from "../csv/write.js";
12
- import { encodeSvgText } from "../svg/text.js";
13
13
  import { buildSvgText } from "../svg/write.js";
14
14
  import { encodeDocumentPackage } from "../package-codec.js";
15
15
  import { CONTENT_READERS, readDocumentLayout } from "./read.js";
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_svg_text = require("../svg/text.cjs");
2
3
  const require_model_bytes = require("../model/bytes.cjs");
3
4
  const require_edit_docx_content = require("../edit/docx/content.cjs");
4
5
  const require_edit_pptx_content = require("../edit/pptx/content.cjs");
@@ -20,7 +21,6 @@ const require_markdown_text = require("../markdown/text.cjs");
20
21
  const require_csv_text = require("../csv/text.cjs");
21
22
  const require_csv_read = require("../csv/read.cjs");
22
23
  const require_csv_write = require("../csv/write.cjs");
23
- const require_svg_text = require("../svg/text.cjs");
24
24
  const require_svg_read = require("../svg/read.cjs");
25
25
  const require_svg_write = require("../svg/write.cjs");
26
26
  const require_ports_abort = require("../ports/abort.cjs");
@@ -1,3 +1,4 @@
1
+ import { decodeSvgText, encodeSvgText } from "../svg/text.js";
1
2
  import { requireArrayBufferBytes } from "../model/bytes.js";
2
3
  import { buildDocxPackage } from "../edit/docx/content.js";
3
4
  import { buildPptxPackage } from "../edit/pptx/content.js";
@@ -19,7 +20,6 @@ import { decodeMarkdownText, encodeMarkdownText } from "../markdown/text.js";
19
20
  import { decodeCsvText, encodeCsvText } from "../csv/text.js";
20
21
  import { readCsvContent } from "../csv/read.js";
21
22
  import { buildCsvText } from "../csv/write.js";
22
- import { decodeSvgText, encodeSvgText } from "../svg/text.js";
23
23
  import { readSvgContent } from "../svg/read.js";
24
24
  import { buildSvgText } from "../svg/write.js";
25
25
  import { throwIfAborted } from "../ports/abort.js";
@@ -221,6 +221,7 @@ function appendTable(body, block) {
221
221
  const rowCells = docxRowCells(positionsByRow[rowIndex], positionsByRow);
222
222
  const tableRow = table.appendRow(rowCells.length);
223
223
  tableRow.heightPt = row.heightPt;
224
+ tableRow.isHeader = row.isHeader === true;
224
225
  const domCells = tableRow.cells();
225
226
  rowCells.forEach(({ cell, colSpan, verticalMerge }, cellIndex) => {
226
227
  const tableCell = domCells[cellIndex];
@@ -220,6 +220,7 @@ function appendTable(body, block) {
220
220
  const rowCells = docxRowCells(positionsByRow[rowIndex], positionsByRow);
221
221
  const tableRow = table.appendRow(rowCells.length);
222
222
  tableRow.heightPt = row.heightPt;
223
+ tableRow.isHeader = row.isHeader === true;
223
224
  const domCells = tableRow.cells();
224
225
  rowCells.forEach(({ cell, colSpan, verticalMerge }, cellIndex) => {
225
226
  const tableCell = domCells[cellIndex];
@@ -196,6 +196,20 @@ var DocxTableRow = class {
196
196
  "w:hRule": "atLeast"
197
197
  }));
198
198
  }
199
+ get isHeader() {
200
+ const trPr = this.trPrElement(false);
201
+ const tblHeader = trPr === void 0 ? void 0 : require_xml_edit.directChildElement(trPr, "w:tblHeader");
202
+ if (tblHeader === void 0) return false;
203
+ const val = (0, ooxml_js.attr)(tblHeader, "w:val");
204
+ return val !== "0" && val !== "false" && val !== "off";
205
+ }
206
+ set isHeader(value) {
207
+ const trPr = this.trPrElement(value);
208
+ if (trPr === void 0) return;
209
+ trPr.children = trPr.children.filter((c) => !(c.type === "element" && c.tag === "w:tblHeader"));
210
+ if (!value) return;
211
+ trPr.children.push(require_xml_fragment.el("w:tblHeader", {}));
212
+ }
199
213
  mergeCellsHorizontally(startColumnIndex, colSpan) {
200
214
  if (!Number.isInteger(colSpan) || colSpan < 1) throw new Error(`mergeCellsHorizontally: colSpan must be a positive integer, got ${colSpan}`);
201
215
  const plan = planHorizontalMerge(this.node, startColumnIndex, colSpan, false);
@@ -33,6 +33,8 @@ declare class DocxTableRow {
33
33
  cells(): DocxTableCell[];
34
34
  get heightPt(): number | undefined;
35
35
  set heightPt(value: number | undefined);
36
+ get isHeader(): boolean;
37
+ set isHeader(value: boolean);
36
38
  mergeCellsHorizontally(startColumnIndex: number, colSpan: number): DocxTableCell;
37
39
  }
38
40
  declare class DocxTable {
@@ -33,6 +33,8 @@ declare class DocxTableRow {
33
33
  cells(): DocxTableCell[];
34
34
  get heightPt(): number | undefined;
35
35
  set heightPt(value: number | undefined);
36
+ get isHeader(): boolean;
37
+ set isHeader(value: boolean);
36
38
  mergeCellsHorizontally(startColumnIndex: number, colSpan: number): DocxTableCell;
37
39
  }
38
40
  declare class DocxTable {
@@ -195,6 +195,20 @@ var DocxTableRow = class {
195
195
  "w:hRule": "atLeast"
196
196
  }));
197
197
  }
198
+ get isHeader() {
199
+ const trPr = this.trPrElement(false);
200
+ const tblHeader = trPr === void 0 ? void 0 : directChildElement(trPr, "w:tblHeader");
201
+ if (tblHeader === void 0) return false;
202
+ const val = attr(tblHeader, "w:val");
203
+ return val !== "0" && val !== "false" && val !== "off";
204
+ }
205
+ set isHeader(value) {
206
+ const trPr = this.trPrElement(value);
207
+ if (trPr === void 0) return;
208
+ trPr.children = trPr.children.filter((c) => !(c.type === "element" && c.tag === "w:tblHeader"));
209
+ if (!value) return;
210
+ trPr.children.push(el("w:tblHeader", {}));
211
+ }
198
212
  mergeCellsHorizontally(startColumnIndex, colSpan) {
199
213
  if (!Number.isInteger(colSpan) || colSpan < 1) throw new Error(`mergeCellsHorizontally: colSpan must be a positive integer, got ${colSpan}`);
200
214
  const plan = planHorizontalMerge(this.node, startColumnIndex, colSpan, false);
@@ -0,0 +1,99 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/edit/odf-repeated-runs.ts
3
+ const ROW_TAG = "table:table-row";
4
+ const CELL_TAG = "table:table-cell";
5
+ const COVERED_CELL_TAG = "table:covered-table-cell";
6
+ const ROW_REPEAT_ATTR = "table:number-rows-repeated";
7
+ const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
8
+ function isElementWithTag(tag) {
9
+ return (node) => node.type === "element" && node.tag === tag;
10
+ }
11
+ function isCellOrCoveredCell(node) {
12
+ return node.type === "element" && (node.tag === "table:table-cell" || node.tag === "table:covered-table-cell");
13
+ }
14
+ function validateIndex(value, label) {
15
+ if (!Number.isInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer, got ${value}`);
16
+ }
17
+ function readRunRepeatCount(node, attrName) {
18
+ const raw = node.attributes.find((attribute) => attribute.name === attrName)?.value;
19
+ if (raw === void 0) return 1;
20
+ const parsed = Number.parseInt(raw, 10);
21
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
22
+ }
23
+ function collectRunMembers(children, isMember, headerWrapperTag) {
24
+ const members = [];
25
+ children.forEach((node, outerPosition) => {
26
+ if (node.type !== "element") return;
27
+ if (headerWrapperTag !== void 0 && node.tag === headerWrapperTag) {
28
+ node.children.forEach((inner, innerPosition) => {
29
+ if (isMember(inner)) members.push({
30
+ node: inner,
31
+ container: node.children,
32
+ containerPosition: innerPosition,
33
+ outerPosition
34
+ });
35
+ });
36
+ return;
37
+ }
38
+ if (isMember(node)) members.push({
39
+ node,
40
+ container: children,
41
+ containerPosition: outerPosition,
42
+ outerPosition
43
+ });
44
+ });
45
+ return members;
46
+ }
47
+ function withRepeatCount(node, attrName, count) {
48
+ const clone = structuredClone(node);
49
+ clone.attributes = clone.attributes.filter((attribute) => attribute.name !== attrName);
50
+ if (count > 1) clone.attributes.push({
51
+ name: attrName,
52
+ value: String(count)
53
+ });
54
+ return clone;
55
+ }
56
+ function replaceRun(children, isMember, targetIndex, repeatAttr, buildEmpty, headerWrapperTag) {
57
+ validateIndex(targetIndex, "targetIndex");
58
+ const members = collectRunMembers(children, isMember, headerWrapperTag);
59
+ let cursor = 0;
60
+ for (const member of members) {
61
+ const count = readRunRepeatCount(member.node, repeatAttr);
62
+ if (targetIndex < cursor + count) {
63
+ const offset = targetIndex - cursor;
64
+ if (count === 1) return member.node;
65
+ const before = offset > 0 ? withRepeatCount(member.node, repeatAttr, offset) : void 0;
66
+ const target = withRepeatCount(member.node, repeatAttr, 1);
67
+ const replacement = [
68
+ before,
69
+ target,
70
+ count - offset - 1 > 0 ? withRepeatCount(member.node, repeatAttr, count - offset - 1) : void 0
71
+ ].filter((candidate) => candidate !== void 0);
72
+ member.container.splice(member.containerPosition, 1, ...replacement);
73
+ return target;
74
+ }
75
+ cursor += count;
76
+ }
77
+ const gap = targetIndex - cursor;
78
+ const lastMember = members[members.length - 1];
79
+ const insertAt = lastMember === void 0 ? children.length : lastMember.outerPosition + 1;
80
+ const toInsert = [];
81
+ if (gap > 0) toInsert.push(withRepeatCount(buildEmpty(), repeatAttr, gap));
82
+ const target = buildEmpty();
83
+ toInsert.push(target);
84
+ children.splice(insertAt, 0, ...toInsert);
85
+ return target;
86
+ }
87
+ //#endregion
88
+ exports.CELL_TAG = CELL_TAG;
89
+ exports.COLUMN_REPEAT_ATTR = COLUMN_REPEAT_ATTR;
90
+ exports.COVERED_CELL_TAG = COVERED_CELL_TAG;
91
+ exports.ROW_REPEAT_ATTR = ROW_REPEAT_ATTR;
92
+ exports.ROW_TAG = ROW_TAG;
93
+ exports.collectRunMembers = collectRunMembers;
94
+ exports.isCellOrCoveredCell = isCellOrCoveredCell;
95
+ exports.isElementWithTag = isElementWithTag;
96
+ exports.readRunRepeatCount = readRunRepeatCount;
97
+ exports.replaceRun = replaceRun;
98
+ exports.validateIndex = validateIndex;
99
+ exports.withRepeatCount = withRepeatCount;
@@ -0,0 +1,22 @@
1
+ import { XmlElement, XmlNode } from "odf.js";
2
+ //#region src/edit/odf-repeated-runs.d.ts
3
+ declare const ROW_TAG = "table:table-row";
4
+ declare const CELL_TAG = "table:table-cell";
5
+ declare const COVERED_CELL_TAG = "table:covered-table-cell";
6
+ declare const ROW_REPEAT_ATTR = "table:number-rows-repeated";
7
+ declare const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
8
+ declare function isElementWithTag(tag: string): (node: XmlNode) => node is XmlElement;
9
+ declare function isCellOrCoveredCell(node: XmlNode): node is XmlElement;
10
+ declare function validateIndex(value: number, label: string): void;
11
+ declare function readRunRepeatCount(node: XmlElement, attrName: string): number;
12
+ interface RunMember {
13
+ readonly node: XmlElement;
14
+ readonly container: XmlNode[];
15
+ readonly containerPosition: number;
16
+ readonly outerPosition: number;
17
+ }
18
+ declare function collectRunMembers(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, headerWrapperTag: string | undefined): RunMember[];
19
+ declare function withRepeatCount(node: XmlElement, attrName: string, count: number): XmlElement;
20
+ declare function replaceRun(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, targetIndex: number, repeatAttr: string, buildEmpty: () => XmlElement, headerWrapperTag?: string): XmlElement;
21
+ //#endregion
22
+ export { CELL_TAG, COLUMN_REPEAT_ATTR, COVERED_CELL_TAG, ROW_REPEAT_ATTR, ROW_TAG, RunMember, collectRunMembers, isCellOrCoveredCell, isElementWithTag, readRunRepeatCount, replaceRun, validateIndex, withRepeatCount };
@@ -0,0 +1,22 @@
1
+ import { XmlElement, XmlNode } from "odf.js";
2
+ //#region src/edit/odf-repeated-runs.d.ts
3
+ declare const ROW_TAG = "table:table-row";
4
+ declare const CELL_TAG = "table:table-cell";
5
+ declare const COVERED_CELL_TAG = "table:covered-table-cell";
6
+ declare const ROW_REPEAT_ATTR = "table:number-rows-repeated";
7
+ declare const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
8
+ declare function isElementWithTag(tag: string): (node: XmlNode) => node is XmlElement;
9
+ declare function isCellOrCoveredCell(node: XmlNode): node is XmlElement;
10
+ declare function validateIndex(value: number, label: string): void;
11
+ declare function readRunRepeatCount(node: XmlElement, attrName: string): number;
12
+ interface RunMember {
13
+ readonly node: XmlElement;
14
+ readonly container: XmlNode[];
15
+ readonly containerPosition: number;
16
+ readonly outerPosition: number;
17
+ }
18
+ declare function collectRunMembers(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, headerWrapperTag: string | undefined): RunMember[];
19
+ declare function withRepeatCount(node: XmlElement, attrName: string, count: number): XmlElement;
20
+ declare function replaceRun(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, targetIndex: number, repeatAttr: string, buildEmpty: () => XmlElement, headerWrapperTag?: string): XmlElement;
21
+ //#endregion
22
+ export { CELL_TAG, COLUMN_REPEAT_ATTR, COVERED_CELL_TAG, ROW_REPEAT_ATTR, ROW_TAG, RunMember, collectRunMembers, isCellOrCoveredCell, isElementWithTag, readRunRepeatCount, replaceRun, validateIndex, withRepeatCount };
@@ -0,0 +1,87 @@
1
+ //#region src/edit/odf-repeated-runs.ts
2
+ const ROW_TAG = "table:table-row";
3
+ const CELL_TAG = "table:table-cell";
4
+ const COVERED_CELL_TAG = "table:covered-table-cell";
5
+ const ROW_REPEAT_ATTR = "table:number-rows-repeated";
6
+ const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
7
+ function isElementWithTag(tag) {
8
+ return (node) => node.type === "element" && node.tag === tag;
9
+ }
10
+ function isCellOrCoveredCell(node) {
11
+ return node.type === "element" && (node.tag === "table:table-cell" || node.tag === "table:covered-table-cell");
12
+ }
13
+ function validateIndex(value, label) {
14
+ if (!Number.isInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer, got ${value}`);
15
+ }
16
+ function readRunRepeatCount(node, attrName) {
17
+ const raw = node.attributes.find((attribute) => attribute.name === attrName)?.value;
18
+ if (raw === void 0) return 1;
19
+ const parsed = Number.parseInt(raw, 10);
20
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
21
+ }
22
+ function collectRunMembers(children, isMember, headerWrapperTag) {
23
+ const members = [];
24
+ children.forEach((node, outerPosition) => {
25
+ if (node.type !== "element") return;
26
+ if (headerWrapperTag !== void 0 && node.tag === headerWrapperTag) {
27
+ node.children.forEach((inner, innerPosition) => {
28
+ if (isMember(inner)) members.push({
29
+ node: inner,
30
+ container: node.children,
31
+ containerPosition: innerPosition,
32
+ outerPosition
33
+ });
34
+ });
35
+ return;
36
+ }
37
+ if (isMember(node)) members.push({
38
+ node,
39
+ container: children,
40
+ containerPosition: outerPosition,
41
+ outerPosition
42
+ });
43
+ });
44
+ return members;
45
+ }
46
+ function withRepeatCount(node, attrName, count) {
47
+ const clone = structuredClone(node);
48
+ clone.attributes = clone.attributes.filter((attribute) => attribute.name !== attrName);
49
+ if (count > 1) clone.attributes.push({
50
+ name: attrName,
51
+ value: String(count)
52
+ });
53
+ return clone;
54
+ }
55
+ function replaceRun(children, isMember, targetIndex, repeatAttr, buildEmpty, headerWrapperTag) {
56
+ validateIndex(targetIndex, "targetIndex");
57
+ const members = collectRunMembers(children, isMember, headerWrapperTag);
58
+ let cursor = 0;
59
+ for (const member of members) {
60
+ const count = readRunRepeatCount(member.node, repeatAttr);
61
+ if (targetIndex < cursor + count) {
62
+ const offset = targetIndex - cursor;
63
+ if (count === 1) return member.node;
64
+ const before = offset > 0 ? withRepeatCount(member.node, repeatAttr, offset) : void 0;
65
+ const target = withRepeatCount(member.node, repeatAttr, 1);
66
+ const replacement = [
67
+ before,
68
+ target,
69
+ count - offset - 1 > 0 ? withRepeatCount(member.node, repeatAttr, count - offset - 1) : void 0
70
+ ].filter((candidate) => candidate !== void 0);
71
+ member.container.splice(member.containerPosition, 1, ...replacement);
72
+ return target;
73
+ }
74
+ cursor += count;
75
+ }
76
+ const gap = targetIndex - cursor;
77
+ const lastMember = members[members.length - 1];
78
+ const insertAt = lastMember === void 0 ? children.length : lastMember.outerPosition + 1;
79
+ const toInsert = [];
80
+ if (gap > 0) toInsert.push(withRepeatCount(buildEmpty(), repeatAttr, gap));
81
+ const target = buildEmpty();
82
+ toInsert.push(target);
83
+ children.splice(insertAt, 0, ...toInsert);
84
+ return target;
85
+ }
86
+ //#endregion
87
+ export { CELL_TAG, COLUMN_REPEAT_ATTR, COVERED_CELL_TAG, ROW_REPEAT_ATTR, ROW_TAG, collectRunMembers, isCellOrCoveredCell, isElementWithTag, readRunRepeatCount, replaceRun, validateIndex, withRepeatCount };
@@ -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-BT3wN3Hd.cjs";
4
+ import { o as TableInit, r as OdtTable } from "../../table-Bt9ahRyh.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-DhTy5Re7.js";
4
+ import { o as TableInit, r as OdtTable } from "../../table-Cou5rKOo.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
@@ -1,126 +1,34 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_xml_fragment = require("../../xml/fragment.cjs");
3
+ const require_edit_odf_repeated_runs = require("../odf-repeated-runs.cjs");
3
4
  //#region src/edit/ods/address.ts
4
- const ROW_TAG = "table:table-row";
5
5
  const COLUMN_TAG = "table:table-column";
6
- const CELL_TAG = "table:table-cell";
7
- const COVERED_CELL_TAG = "table:covered-table-cell";
8
- const ROW_REPEAT_ATTR = "table:number-rows-repeated";
9
- const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
10
6
  const HEADER_ROWS_TAG = "table:table-header-rows";
11
7
  const HEADER_COLUMNS_TAG = "table:table-header-columns";
12
- function isElementWithTag(tag) {
13
- return (node) => node.type === "element" && node.tag === tag;
14
- }
15
- function isCellOrCoveredCell(node) {
16
- return node.type === "element" && (node.tag === "table:table-cell" || node.tag === "table:covered-table-cell");
17
- }
18
- function validateIndex(value, label) {
19
- if (!Number.isInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer, got ${value}`);
20
- }
21
- function readRunRepeatCount(node, attrName) {
22
- const raw = node.attributes.find((attribute) => attribute.name === attrName)?.value;
23
- if (raw === void 0) return 1;
24
- const parsed = Number.parseInt(raw, 10);
25
- return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
26
- }
27
- function collectRunMembers(children, isMember, headerWrapperTag) {
28
- const members = [];
29
- children.forEach((node, outerPosition) => {
30
- if (node.type !== "element") return;
31
- if (headerWrapperTag !== void 0 && node.tag === headerWrapperTag) {
32
- node.children.forEach((inner, innerPosition) => {
33
- if (isMember(inner)) members.push({
34
- node: inner,
35
- container: node.children,
36
- containerPosition: innerPosition,
37
- outerPosition
38
- });
39
- });
40
- return;
41
- }
42
- if (isMember(node)) members.push({
43
- node,
44
- container: children,
45
- containerPosition: outerPosition,
46
- outerPosition
47
- });
48
- });
49
- return members;
50
- }
51
- function withRepeatCount(node, attrName, count) {
52
- const clone = structuredClone(node);
53
- clone.attributes = clone.attributes.filter((attribute) => attribute.name !== attrName);
54
- if (count > 1) clone.attributes.push({
55
- name: attrName,
56
- value: String(count)
57
- });
58
- return clone;
59
- }
60
- function replaceRun(children, isMember, targetIndex, repeatAttr, buildEmpty, headerWrapperTag) {
61
- validateIndex(targetIndex, "targetIndex");
62
- const members = collectRunMembers(children, isMember, headerWrapperTag);
63
- let cursor = 0;
64
- for (const member of members) {
65
- const count = readRunRepeatCount(member.node, repeatAttr);
66
- if (targetIndex < cursor + count) {
67
- const offset = targetIndex - cursor;
68
- if (count === 1) return member.node;
69
- const before = offset > 0 ? withRepeatCount(member.node, repeatAttr, offset) : void 0;
70
- const target = withRepeatCount(member.node, repeatAttr, 1);
71
- const replacement = [
72
- before,
73
- target,
74
- count - offset - 1 > 0 ? withRepeatCount(member.node, repeatAttr, count - offset - 1) : void 0
75
- ].filter((candidate) => candidate !== void 0);
76
- member.container.splice(member.containerPosition, 1, ...replacement);
77
- return target;
78
- }
79
- cursor += count;
80
- }
81
- const gap = targetIndex - cursor;
82
- const lastMember = members[members.length - 1];
83
- const insertAt = lastMember === void 0 ? children.length : lastMember.outerPosition + 1;
84
- const toInsert = [];
85
- if (gap > 0) toInsert.push(withRepeatCount(buildEmpty(), repeatAttr, gap));
86
- const target = buildEmpty();
87
- toInsert.push(target);
88
- children.splice(insertAt, 0, ...toInsert);
89
- return target;
90
- }
91
8
  function ensureColumnCoverage(tableElement, minCount) {
92
9
  if (minCount <= 0) return;
93
- const columnMembers = collectRunMembers(tableElement.children, isElementWithTag(COLUMN_TAG), HEADER_COLUMNS_TAG);
94
- const covered = columnMembers.reduce((sum, member) => sum + readRunRepeatCount(member.node, COLUMN_REPEAT_ATTR), 0);
10
+ const columnMembers = require_edit_odf_repeated_runs.collectRunMembers(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(COLUMN_TAG), HEADER_COLUMNS_TAG);
11
+ const covered = columnMembers.reduce((sum, member) => sum + require_edit_odf_repeated_runs.readRunRepeatCount(member.node, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR), 0);
95
12
  if (covered >= minCount) return;
96
13
  const additional = minCount - covered;
97
- const newColumn = withRepeatCount(require_xml_fragment.el(COLUMN_TAG), COLUMN_REPEAT_ATTR, additional);
14
+ const newColumn = require_edit_odf_repeated_runs.withRepeatCount(require_xml_fragment.el(COLUMN_TAG), require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR, additional);
98
15
  const lastColumn = columnMembers[columnMembers.length - 1];
99
16
  if (lastColumn === void 0) {
100
- const firstRowOrHeaderPosition = tableElement.children.findIndex((node) => isElementWithTag("table:table-row")(node) || isElementWithTag("table:table-header-rows")(node));
17
+ const firstRowOrHeaderPosition = tableElement.children.findIndex((node) => require_edit_odf_repeated_runs.isElementWithTag("table:table-row")(node) || require_edit_odf_repeated_runs.isElementWithTag("table:table-header-rows")(node));
101
18
  const insertAt = firstRowOrHeaderPosition === -1 ? tableElement.children.length : firstRowOrHeaderPosition;
102
19
  tableElement.children.splice(insertAt, 0, newColumn);
103
20
  } else tableElement.children.splice(lastColumn.outerPosition + 1, 0, newColumn);
104
21
  }
105
22
  function resolveCellNode(tableElement, row, column) {
106
- validateIndex(row, "row");
107
- validateIndex(column, "column");
23
+ require_edit_odf_repeated_runs.validateIndex(row, "row");
24
+ require_edit_odf_repeated_runs.validateIndex(column, "column");
108
25
  ensureColumnCoverage(tableElement, column + 1);
109
- return replaceRun(replaceRun(tableElement.children, isElementWithTag(ROW_TAG), row, ROW_REPEAT_ATTR, () => require_xml_fragment.el(ROW_TAG), HEADER_ROWS_TAG).children, isCellOrCoveredCell, column, COLUMN_REPEAT_ATTR, () => require_xml_fragment.el(CELL_TAG));
26
+ const rowElement = require_edit_odf_repeated_runs.replaceRun(tableElement.children, require_edit_odf_repeated_runs.isElementWithTag(require_edit_odf_repeated_runs.ROW_TAG), row, require_edit_odf_repeated_runs.ROW_REPEAT_ATTR, () => require_xml_fragment.el(require_edit_odf_repeated_runs.ROW_TAG), HEADER_ROWS_TAG);
27
+ return require_edit_odf_repeated_runs.replaceRun(rowElement.children, require_edit_odf_repeated_runs.isCellOrCoveredCell, column, require_edit_odf_repeated_runs.COLUMN_REPEAT_ATTR, () => require_xml_fragment.el(require_edit_odf_repeated_runs.CELL_TAG));
110
28
  }
111
29
  //#endregion
112
- exports.CELL_TAG = CELL_TAG;
113
- exports.COLUMN_REPEAT_ATTR = COLUMN_REPEAT_ATTR;
114
30
  exports.COLUMN_TAG = COLUMN_TAG;
115
- exports.COVERED_CELL_TAG = COVERED_CELL_TAG;
116
31
  exports.HEADER_COLUMNS_TAG = HEADER_COLUMNS_TAG;
117
32
  exports.HEADER_ROWS_TAG = HEADER_ROWS_TAG;
118
- exports.ROW_REPEAT_ATTR = ROW_REPEAT_ATTR;
119
- exports.ROW_TAG = ROW_TAG;
120
- exports.collectRunMembers = collectRunMembers;
121
33
  exports.ensureColumnCoverage = ensureColumnCoverage;
122
- exports.isCellOrCoveredCell = isCellOrCoveredCell;
123
- exports.isElementWithTag = isElementWithTag;
124
- exports.readRunRepeatCount = readRunRepeatCount;
125
- exports.replaceRun = replaceRun;
126
34
  exports.resolveCellNode = resolveCellNode;
@@ -1,25 +1,9 @@
1
- import { XmlElement, XmlNode } from "odf.js";
1
+ import { XmlElement } from "odf.js";
2
2
  //#region src/edit/ods/address.d.ts
3
- declare const ROW_TAG = "table:table-row";
4
3
  declare const COLUMN_TAG = "table:table-column";
5
- declare const CELL_TAG = "table:table-cell";
6
- declare const COVERED_CELL_TAG = "table:covered-table-cell";
7
- declare const ROW_REPEAT_ATTR = "table:number-rows-repeated";
8
- declare const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
9
4
  declare const HEADER_ROWS_TAG = "table:table-header-rows";
10
5
  declare const HEADER_COLUMNS_TAG = "table:table-header-columns";
11
- declare function isElementWithTag(tag: string): (node: XmlNode) => node is XmlElement;
12
- declare function isCellOrCoveredCell(node: XmlNode): node is XmlElement;
13
- declare function readRunRepeatCount(node: XmlElement, attrName: string): number;
14
- interface RunMember {
15
- readonly node: XmlElement;
16
- readonly container: XmlNode[];
17
- readonly containerPosition: number;
18
- readonly outerPosition: number;
19
- }
20
- declare function collectRunMembers(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, headerWrapperTag: string | undefined): RunMember[];
21
- declare function replaceRun(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, targetIndex: number, repeatAttr: string, buildEmpty: () => XmlElement, headerWrapperTag?: string): XmlElement;
22
6
  declare function ensureColumnCoverage(tableElement: XmlElement, minCount: number): void;
23
7
  declare function resolveCellNode(tableElement: XmlElement, row: number, column: number): XmlElement;
24
8
  //#endregion
25
- export { CELL_TAG, COLUMN_REPEAT_ATTR, COLUMN_TAG, COVERED_CELL_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG, ROW_REPEAT_ATTR, ROW_TAG, RunMember, collectRunMembers, ensureColumnCoverage, isCellOrCoveredCell, isElementWithTag, readRunRepeatCount, replaceRun, resolveCellNode };
9
+ export { COLUMN_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG, ensureColumnCoverage, resolveCellNode };
@@ -1,25 +1,9 @@
1
- import { XmlElement, XmlNode } from "odf.js";
1
+ import { XmlElement } from "odf.js";
2
2
  //#region src/edit/ods/address.d.ts
3
- declare const ROW_TAG = "table:table-row";
4
3
  declare const COLUMN_TAG = "table:table-column";
5
- declare const CELL_TAG = "table:table-cell";
6
- declare const COVERED_CELL_TAG = "table:covered-table-cell";
7
- declare const ROW_REPEAT_ATTR = "table:number-rows-repeated";
8
- declare const COLUMN_REPEAT_ATTR = "table:number-columns-repeated";
9
4
  declare const HEADER_ROWS_TAG = "table:table-header-rows";
10
5
  declare const HEADER_COLUMNS_TAG = "table:table-header-columns";
11
- declare function isElementWithTag(tag: string): (node: XmlNode) => node is XmlElement;
12
- declare function isCellOrCoveredCell(node: XmlNode): node is XmlElement;
13
- declare function readRunRepeatCount(node: XmlElement, attrName: string): number;
14
- interface RunMember {
15
- readonly node: XmlElement;
16
- readonly container: XmlNode[];
17
- readonly containerPosition: number;
18
- readonly outerPosition: number;
19
- }
20
- declare function collectRunMembers(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, headerWrapperTag: string | undefined): RunMember[];
21
- declare function replaceRun(children: XmlNode[], isMember: (node: XmlNode) => node is XmlElement, targetIndex: number, repeatAttr: string, buildEmpty: () => XmlElement, headerWrapperTag?: string): XmlElement;
22
6
  declare function ensureColumnCoverage(tableElement: XmlElement, minCount: number): void;
23
7
  declare function resolveCellNode(tableElement: XmlElement, row: number, column: number): XmlElement;
24
8
  //#endregion
25
- export { CELL_TAG, COLUMN_REPEAT_ATTR, COLUMN_TAG, COVERED_CELL_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG, ROW_REPEAT_ATTR, ROW_TAG, RunMember, collectRunMembers, ensureColumnCoverage, isCellOrCoveredCell, isElementWithTag, readRunRepeatCount, replaceRun, resolveCellNode };
9
+ export { COLUMN_TAG, HEADER_COLUMNS_TAG, HEADER_ROWS_TAG, ensureColumnCoverage, resolveCellNode };