js.documents 7.10.4 → 7.11.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
@@ -270,7 +270,7 @@ const pdfBytes = docxToPdf(docxBytes, {
270
270
 
271
271
  The tree and the flat `ContentDocument` are one format in two encodings, related by three laws (stated on [document-schema.js#20](https://github.com/ExaDev/document-schema.js/issues/20), proven over this package's real corpus by the bijection suite in `src/convert/bijection.test.ts`): (i) `flattenTree(assembleTree(c))` reproduces `c` exactly, up to one declared normalisation (a present-but-empty sheet `embeddedObjects` array normalises to the field absent); (ii) effective-property equality holds universally — a factored and an unfactored serialisation of one document resolve to the same properties; (iii) minting is idempotent — factoring a second time produces the identical styles table.
272
272
 
273
- Three flat-form signals drive the grouping, and all three are reproduced exactly on the way back: `headingLevel`, `list.level`, and — since document-schema.js 4.2.0 — the `constructStart`/`constructEnd` block pair that delimits a fidelity construct (a docx SDT, an ODF field, a tracked-change span, a bookmark, a hyperlink region, a division). `decompose` promotes each marker pair to a construct group carrying the `ConstructDescriptor` and holding the delimited region as its children, decomposed on its own; `flattenTree` writes the pair back around that region. A construct is a semantic wrapper rather than a container, so it neither disturbs the enclosing heading/list nesting it sits inside nor resets the style chain resolving onto it — content inside a construct still inherits the ambient heading's or section's factored properties, exactly as if the construct were not there. Markers must pair up within one container's block flow: an unmatched `constructEnd`, or a `constructStart` a container never closes, throws document-schema.js's `ConstructMarkerImbalanceError` (carrying its `ConstructMarkerImbalance` payload, so the offending block index is available without parsing the message) rather than being repaired into a plausible tree. The format codecs do not emit markers yetconstruct extraction per format is tracked separately on [document-schema.js#22](https://github.com/ExaDev/document-schema.js/issues/22) but the decompose/flatten boundary itself handles them today, so a caller hand-building marker content needs no change at that boundary specifically. Reaching further than the boundary is a mixed picture, not a blanket guarantee: `buildMarkdownText` passes markers through to markdown-codec's own bracket-resolving writer, which renders each construct it has a markdown spelling for (a footnote definition, a blockquote division, a titled image's link wrapper) and renders the rest transparently with a diagnostic — markdown-codec's own read side emits those pairs, so this package's editor and conversion round trips depend on it; building docx/odt bytes back from marker-carrying flat content silently drops the markers, since neither builder reads or writes them yet; and the layout engines (`convertWordprocessingToLayout`, `convertShape`) silently skip a marker block during pagination — harmless there, since a marker carries no content of its own to render.
273
+ Three flat-form signals drive the grouping, and all three are reproduced exactly on the way back: `headingLevel`, `list.level`, and — since document-schema.js 4.2.0 — the `constructStart`/`constructEnd` block pair that delimits a fidelity construct (a docx SDT, an ODF field, a tracked-change span, a bookmark, a hyperlink region, a division). `decompose` promotes each marker pair to a construct group carrying the `ConstructDescriptor` and holding the delimited region as its children, decomposed on its own; `flattenTree` writes the pair back around that region. A construct is a semantic wrapper rather than a container, so it neither disturbs the enclosing heading/list nesting it sits inside nor resets the style chain resolving onto it — content inside a construct still inherits the ambient heading's or section's factored properties, exactly as if the construct were not there. Markers must pair up within one container's block flow: an unmatched `constructEnd`, or a `constructStart` a container never closes, throws document-schema.js's `ConstructMarkerImbalanceError` (carrying its `ConstructMarkerImbalance` payload, so the offending block index is available without parsing the message) rather than being repaired into a plausible tree. The format codecs emit and consume these markers on both sides today ooxml.js's docx pair (SDTs, bookmarks, tracked changes, block-scoped fields), odf.js's odt reader for divisions, index wrappers, and cross-paragraph bookmarks with its writer covering the construct kinds it models and refusing the rest by name, markdown-codec, rtf-codec, and epub-codec in both directions, and this package's own PDF reconstruction emitting division and anchor pairs — so the marker machinery has real producers and consumers, not just the boundary transform. Reaching further than the codecs is still a mixed picture, not a blanket guarantee: `buildMarkdownText` passes markers through to markdown-codec's own bracket-resolving writer, which renders each construct it has a markdown spelling for (a footnote definition, a blockquote division, a titled image's link wrapper) and renders the rest transparently with a diagnostic — markdown-codec's own read side emits those pairs, so this package's editor and conversion round trips depend on it; building docx bytes from marker-carrying flat content writes a bookmark anchor's pair as real `w:bookmarkStart`/`w:bookmarkEnd` around the blocks it spans, and the odt builder does the same through `text:bookmark-start`/`-end` — the one construct family expressible append-only in either format's body flow — while the wrapper-shaped kinds (an SDT, a tracked change, a division) are dropped rather than written, since neither editor model has a surface for them; and the layout engines (`convertWordprocessingToLayout`, `convertShape`) silently skip a marker block during pagination — harmless there, since a marker carries no content of its own to render.
274
274
 
275
275
  `assembleTree` is the one constructor behind every construction site — decompose, then `factorStyles`, the minting pass that hoists property tuples occurring two or more times onto a group-wrapper ref plus a `styles` table entry (deterministic order; `frames`/`sourcePath`/`styleId` are per-node facts and never factor). The transform belongs to `document-schema.js`, which owns both encodings and publishes `assembleTree`, `decompose`, `flattenTree`, `factorStyles`, `ConstructMarkerImbalanceError`, and the `TreeChildren` type for any caller composing its own boundary — import them from there, not from this package. documents.js consumes that transform at its own boundary and re-exports none of it; the readers, builders, layout engines, and editors here keep producing and consuming the flat form, so the tree exists only where a `DocumentTree` is constructed or consumed:
276
276
 
@@ -4,6 +4,7 @@ import { MarkdownImageResolver } from "markdown-codec";
4
4
  import { z } from "zod";
5
5
  //#region src/convert/port.d.ts
6
6
  declare const DocumentFormatSchema: z.ZodEnum<{
7
+ wpd: "wpd";
7
8
  docx: "docx";
8
9
  pptx: "pptx";
9
10
  xlsx: "xlsx";
@@ -12,15 +13,14 @@ declare const DocumentFormatSchema: z.ZodEnum<{
12
13
  ods: "ods";
13
14
  odg: "odg";
14
15
  svg: "svg";
15
- odf: "odf";
16
16
  csv: "csv";
17
17
  markdown: "markdown";
18
18
  rtf: "rtf";
19
19
  doc: "doc";
20
20
  xls: "xls";
21
21
  ppt: "ppt";
22
- wpd: "wpd";
23
22
  epub: "epub";
23
+ odf: "odf";
24
24
  pdf: "pdf";
25
25
  }>;
26
26
  type DocumentFormat = z.infer<typeof DocumentFormatSchema>;
@@ -4,6 +4,7 @@ import { z } from "zod";
4
4
  import { MarkdownImageResolver } from "markdown-codec";
5
5
  //#region src/convert/port.d.ts
6
6
  declare const DocumentFormatSchema: z.ZodEnum<{
7
+ wpd: "wpd";
7
8
  docx: "docx";
8
9
  pptx: "pptx";
9
10
  xlsx: "xlsx";
@@ -12,15 +13,14 @@ declare const DocumentFormatSchema: z.ZodEnum<{
12
13
  ods: "ods";
13
14
  odg: "odg";
14
15
  svg: "svg";
15
- odf: "odf";
16
16
  csv: "csv";
17
17
  markdown: "markdown";
18
18
  rtf: "rtf";
19
19
  doc: "doc";
20
20
  xls: "xls";
21
21
  ppt: "ppt";
22
- wpd: "wpd";
23
22
  epub: "epub";
23
+ odf: "odf";
24
24
  pdf: "pdf";
25
25
  }>;
26
26
  type DocumentFormat = z.infer<typeof DocumentFormatSchema>;
@@ -13,6 +13,31 @@ const require_edit_docx_numbering = require("./numbering.cjs");
13
13
  let ooxml_js = require("ooxml.js");
14
14
  let document_schema_js = require("document-schema.js");
15
15
  //#region src/edit/docx/content.ts
16
+ var ConstructMarkerState = class {
17
+ nextBookmarkId = 1;
18
+ open = [];
19
+ openConstruct(body, marker) {
20
+ const detail = marker.descriptor;
21
+ if (detail.kind === "anchor" && detail.anchorType === "bookmark") {
22
+ const id = this.nextBookmarkId;
23
+ this.nextBookmarkId += 1;
24
+ this.open.push({
25
+ isBookmark: true,
26
+ id
27
+ });
28
+ body.appendBookmarkStart(id, detail.name);
29
+ return;
30
+ }
31
+ this.open.push({
32
+ isBookmark: false,
33
+ id: -1
34
+ });
35
+ }
36
+ closeConstruct(body) {
37
+ const entry = this.open.pop();
38
+ if (entry?.isBookmark) body.appendBookmarkEnd(entry.id);
39
+ }
40
+ };
16
41
  function buildDocxPackage(content, options) {
17
42
  if (content.kind !== "wordprocessing") throw new Error("buildDocxPackage requires a wordprocessing ContentDocument");
18
43
  const clock = options?.clock ?? require_ports_clock.systemClock;
@@ -49,12 +74,13 @@ function buildDocxPackage(content, options) {
49
74
  });
50
75
  }
51
76
  const editor = new require_edit_docx_editor.DocxEditor(pkg);
77
+ const markers = new ConstructMarkerState();
52
78
  (numIdLevels.size > 0 ? content.sections.map((section) => ({
53
79
  ...section,
54
80
  blocks: remapListNumIds(section.blocks, remap)
55
81
  })) : content.sections).forEach((section, sectionIndex) => {
56
82
  if (sectionIndex > 0) editor.body.appendPageBreak();
57
- appendBlocks(editor.body, section.blocks, options);
83
+ appendBlocks(editor.body, section.blocks, options, markers);
58
84
  });
59
85
  return editor.toPackage();
60
86
  }
@@ -97,7 +123,7 @@ function remapListNumIds(blocks, numIdMap) {
97
123
  return block;
98
124
  });
99
125
  }
100
- function appendBlocks(body, blocks, options) {
126
+ function appendBlocks(body, blocks, options, markers) {
101
127
  let index = 0;
102
128
  while (index < blocks.length) {
103
129
  const block = blocks[index];
@@ -118,7 +144,7 @@ function appendBlocks(body, blocks, options) {
118
144
  index += 2;
119
145
  continue;
120
146
  }
121
- if (block !== void 0) appendBlock(body, block, options);
147
+ if (block !== void 0) appendBlock(body, block, options, markers);
122
148
  index += 1;
123
149
  }
124
150
  }
@@ -202,7 +228,7 @@ function appendTable(body, block) {
202
228
  function appendCellBlock(cell, block) {
203
229
  if (block.kind === "paragraph") populateParagraph(cell.appendParagraph(), block);
204
230
  }
205
- function appendBlock(body, block, options) {
231
+ function appendBlock(body, block, options, markers) {
206
232
  if (block.kind === "paragraph") populateParagraph(body.appendParagraph(), block);
207
233
  else if (block.kind === "image") {
208
234
  const paragraph = body.appendParagraph();
@@ -217,6 +243,8 @@ function appendBlock(body, block, options) {
217
243
  } else if (block.kind === "pageBreak") body.appendPageBreak();
218
244
  else if (block.kind === "table") appendTable(body, block);
219
245
  else if (block.kind === "embeddedObject") appendEmbeddedObject(body, block, options);
246
+ else if (block.kind === "constructStart") markers.openConstruct(body, block);
247
+ else markers.closeConstruct(body);
220
248
  }
221
249
  function appendEmbeddedObject(body, block, options) {
222
250
  if (require_model_embedded_drawing.drawingOfBlock(block) !== void 0) {
@@ -12,6 +12,31 @@ import { NUMBERING_CONTENT_TYPE, NUMBERING_PART_PATH, NUMBERING_REL_TYPE, buildN
12
12
  import { base64ToBytes } from "ooxml.js";
13
13
  import { resolveCellFillColor } from "document-schema.js";
14
14
  //#region src/edit/docx/content.ts
15
+ var ConstructMarkerState = class {
16
+ nextBookmarkId = 1;
17
+ open = [];
18
+ openConstruct(body, marker) {
19
+ const detail = marker.descriptor;
20
+ if (detail.kind === "anchor" && detail.anchorType === "bookmark") {
21
+ const id = this.nextBookmarkId;
22
+ this.nextBookmarkId += 1;
23
+ this.open.push({
24
+ isBookmark: true,
25
+ id
26
+ });
27
+ body.appendBookmarkStart(id, detail.name);
28
+ return;
29
+ }
30
+ this.open.push({
31
+ isBookmark: false,
32
+ id: -1
33
+ });
34
+ }
35
+ closeConstruct(body) {
36
+ const entry = this.open.pop();
37
+ if (entry?.isBookmark) body.appendBookmarkEnd(entry.id);
38
+ }
39
+ };
15
40
  function buildDocxPackage(content, options) {
16
41
  if (content.kind !== "wordprocessing") throw new Error("buildDocxPackage requires a wordprocessing ContentDocument");
17
42
  const clock = options?.clock ?? systemClock;
@@ -48,12 +73,13 @@ function buildDocxPackage(content, options) {
48
73
  });
49
74
  }
50
75
  const editor = new DocxEditor(pkg);
76
+ const markers = new ConstructMarkerState();
51
77
  (numIdLevels.size > 0 ? content.sections.map((section) => ({
52
78
  ...section,
53
79
  blocks: remapListNumIds(section.blocks, remap)
54
80
  })) : content.sections).forEach((section, sectionIndex) => {
55
81
  if (sectionIndex > 0) editor.body.appendPageBreak();
56
- appendBlocks(editor.body, section.blocks, options);
82
+ appendBlocks(editor.body, section.blocks, options, markers);
57
83
  });
58
84
  return editor.toPackage();
59
85
  }
@@ -96,7 +122,7 @@ function remapListNumIds(blocks, numIdMap) {
96
122
  return block;
97
123
  });
98
124
  }
99
- function appendBlocks(body, blocks, options) {
125
+ function appendBlocks(body, blocks, options, markers) {
100
126
  let index = 0;
101
127
  while (index < blocks.length) {
102
128
  const block = blocks[index];
@@ -117,7 +143,7 @@ function appendBlocks(body, blocks, options) {
117
143
  index += 2;
118
144
  continue;
119
145
  }
120
- if (block !== void 0) appendBlock(body, block, options);
146
+ if (block !== void 0) appendBlock(body, block, options, markers);
121
147
  index += 1;
122
148
  }
123
149
  }
@@ -201,7 +227,7 @@ function appendTable(body, block) {
201
227
  function appendCellBlock(cell, block) {
202
228
  if (block.kind === "paragraph") populateParagraph(cell.appendParagraph(), block);
203
229
  }
204
- function appendBlock(body, block, options) {
230
+ function appendBlock(body, block, options, markers) {
205
231
  if (block.kind === "paragraph") populateParagraph(body.appendParagraph(), block);
206
232
  else if (block.kind === "image") {
207
233
  const paragraph = body.appendParagraph();
@@ -216,6 +242,8 @@ function appendBlock(body, block, options) {
216
242
  } else if (block.kind === "pageBreak") body.appendPageBreak();
217
243
  else if (block.kind === "table") appendTable(body, block);
218
244
  else if (block.kind === "embeddedObject") appendEmbeddedObject(body, block, options);
245
+ else if (block.kind === "constructStart") markers.openConstruct(body, block);
246
+ else markers.closeConstruct(body);
219
247
  }
220
248
  function appendEmbeddedObject(body, block, options) {
221
249
  if (drawingOfBlock(block) !== void 0) {
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_xml_entities = require("../../xml/entities.cjs");
2
3
  const require_xml_fragment = require("../../xml/fragment.cjs");
3
4
  const require_metadata_core_patch = require("../../metadata/core-patch.cjs");
4
5
  const require_model_metadata = require("../../model/metadata.cjs");
@@ -61,6 +62,15 @@ var DocxBodyImpl = class {
61
62
  const paragraph = require_xml_fragment.el("w:p", {}, [run]);
62
63
  this.body.children.splice(bodyInsertionPoint(this.body), 0, paragraph);
63
64
  }
65
+ appendBookmarkStart(id, name) {
66
+ this.body.children.splice(bodyInsertionPoint(this.body), 0, require_xml_fragment.el("w:bookmarkStart", {
67
+ "w:id": String(id),
68
+ "w:name": require_xml_entities.encodeXmlText(name)
69
+ }));
70
+ }
71
+ appendBookmarkEnd(id) {
72
+ this.body.children.splice(bodyInsertionPoint(this.body), 0, require_xml_fragment.el("w:bookmarkEnd", { "w:id": String(id) }));
73
+ }
64
74
  };
65
75
  var DocxEditor = class {
66
76
  body;
@@ -9,6 +9,8 @@ interface DocxBody {
9
9
  appendParagraph(init?: ParagraphInit): DocxParagraph;
10
10
  appendTable(init: TableInit): DocxTable;
11
11
  appendPageBreak(): void;
12
+ appendBookmarkStart(id: number, name: string): void;
13
+ appendBookmarkEnd(id: number): void;
12
14
  }
13
15
  declare class DocxEditor {
14
16
  readonly body: DocxBody;
@@ -9,6 +9,8 @@ interface DocxBody {
9
9
  appendParagraph(init?: ParagraphInit): DocxParagraph;
10
10
  appendTable(init: TableInit): DocxTable;
11
11
  appendPageBreak(): void;
12
+ appendBookmarkStart(id: number, name: string): void;
13
+ appendBookmarkEnd(id: number): void;
12
14
  }
13
15
  declare class DocxEditor {
14
16
  readonly body: DocxBody;
@@ -1,3 +1,4 @@
1
+ import { encodeXmlText } from "../../xml/entities.js";
1
2
  import { el } from "../../xml/fragment.js";
2
3
  import { patchOoxmlCorePropertiesOnPackage } from "../../metadata/core-patch.js";
3
4
  import { resolveMetadataTimestamps } from "../../model/metadata.js";
@@ -60,6 +61,15 @@ var DocxBodyImpl = class {
60
61
  const paragraph = el("w:p", {}, [run]);
61
62
  this.body.children.splice(bodyInsertionPoint(this.body), 0, paragraph);
62
63
  }
64
+ appendBookmarkStart(id, name) {
65
+ this.body.children.splice(bodyInsertionPoint(this.body), 0, el("w:bookmarkStart", {
66
+ "w:id": String(id),
67
+ "w:name": encodeXmlText(name)
68
+ }));
69
+ }
70
+ appendBookmarkEnd(id) {
71
+ this.body.children.splice(bodyInsertionPoint(this.body), 0, el("w:bookmarkEnd", { "w:id": String(id) }));
72
+ }
63
73
  };
64
74
  var DocxEditor = class {
65
75
  body;
@@ -14,9 +14,10 @@ function buildOdtPackage(content, options) {
14
14
  const clock = options?.clock ?? require_ports_clock.systemClock;
15
15
  const metadata = require_model_metadata.resolveMetadataTimestamps(content.metadata, clock);
16
16
  const editor = new require_edit_odt_editor.OdtEditor(require_edit_odt_scaffold.createEmptyOdtPackage({ metadata }));
17
+ const markers = new ConstructMarkerState();
17
18
  content.sections.forEach((section, sectionIndex) => {
18
19
  if (sectionIndex > 0) editor.body.appendPageBreak();
19
- appendBlocks(editor.body, section.blocks);
20
+ appendBlocks(editor.body, section.blocks, markers);
20
21
  });
21
22
  return editor.toPackage();
22
23
  }
@@ -36,7 +37,7 @@ function appendMergedImageParagraph(body, paragraphBlock, imageBlock) {
36
37
  altText: imageBlock.altText
37
38
  });
38
39
  }
39
- function appendBlocks(body, blocks) {
40
+ function appendBlocks(body, blocks, markers) {
40
41
  let i = 0;
41
42
  while (i < blocks.length) {
42
43
  const block = blocks[i];
@@ -61,7 +62,7 @@ function appendBlocks(body, blocks) {
61
62
  appendListRun(body, run);
62
63
  continue;
63
64
  }
64
- appendBlock(body, block);
65
+ appendBlock(body, block, markers);
65
66
  i++;
66
67
  }
67
68
  }
@@ -187,7 +188,29 @@ function appendCellBlock(cell, block) {
187
188
  altText: block.altText
188
189
  });
189
190
  }
190
- function appendBlock(body, block) {
191
+ var ConstructMarkerState = class {
192
+ open = [];
193
+ openConstruct(body, marker) {
194
+ const detail = marker.descriptor;
195
+ if (detail.kind === "anchor" && detail.anchorType === "bookmark") {
196
+ this.open.push({
197
+ isBookmark: true,
198
+ name: detail.name
199
+ });
200
+ body.appendBookmarkStart(detail.name);
201
+ return;
202
+ }
203
+ this.open.push({
204
+ isBookmark: false,
205
+ name: ""
206
+ });
207
+ }
208
+ closeConstruct(body) {
209
+ const entry = this.open.pop();
210
+ if (entry?.isBookmark) body.appendBookmarkEnd(entry.name);
211
+ }
212
+ };
213
+ function appendBlock(body, block, markers) {
191
214
  if (block.kind === "paragraph") populateParagraph(body.appendParagraph(), block, { headings: "element" });
192
215
  else if (block.kind === "image") body.appendParagraph().insertImageAfter({
193
216
  format: block.format,
@@ -199,6 +222,8 @@ function appendBlock(body, block) {
199
222
  else if (block.kind === "pageBreak") body.appendPageBreak();
200
223
  else if (block.kind === "table") appendTable(body, block);
201
224
  else if (block.kind === "embeddedObject") appendEmbeddedObject(body, block);
225
+ else if (block.kind === "constructStart") markers.openConstruct(body, block);
226
+ else markers.closeConstruct(body);
202
227
  }
203
228
  function appendEmbeddedObject(body, block) {
204
229
  if (require_model_embedded_drawing.drawingOfBlock(block) !== void 0) {
@@ -13,9 +13,10 @@ function buildOdtPackage(content, options) {
13
13
  const clock = options?.clock ?? systemClock;
14
14
  const metadata = resolveMetadataTimestamps(content.metadata, clock);
15
15
  const editor = new OdtEditor(createEmptyOdtPackage({ metadata }));
16
+ const markers = new ConstructMarkerState();
16
17
  content.sections.forEach((section, sectionIndex) => {
17
18
  if (sectionIndex > 0) editor.body.appendPageBreak();
18
- appendBlocks(editor.body, section.blocks);
19
+ appendBlocks(editor.body, section.blocks, markers);
19
20
  });
20
21
  return editor.toPackage();
21
22
  }
@@ -35,7 +36,7 @@ function appendMergedImageParagraph(body, paragraphBlock, imageBlock) {
35
36
  altText: imageBlock.altText
36
37
  });
37
38
  }
38
- function appendBlocks(body, blocks) {
39
+ function appendBlocks(body, blocks, markers) {
39
40
  let i = 0;
40
41
  while (i < blocks.length) {
41
42
  const block = blocks[i];
@@ -60,7 +61,7 @@ function appendBlocks(body, blocks) {
60
61
  appendListRun(body, run);
61
62
  continue;
62
63
  }
63
- appendBlock(body, block);
64
+ appendBlock(body, block, markers);
64
65
  i++;
65
66
  }
66
67
  }
@@ -186,7 +187,29 @@ function appendCellBlock(cell, block) {
186
187
  altText: block.altText
187
188
  });
188
189
  }
189
- function appendBlock(body, block) {
190
+ var ConstructMarkerState = class {
191
+ open = [];
192
+ openConstruct(body, marker) {
193
+ const detail = marker.descriptor;
194
+ if (detail.kind === "anchor" && detail.anchorType === "bookmark") {
195
+ this.open.push({
196
+ isBookmark: true,
197
+ name: detail.name
198
+ });
199
+ body.appendBookmarkStart(detail.name);
200
+ return;
201
+ }
202
+ this.open.push({
203
+ isBookmark: false,
204
+ name: ""
205
+ });
206
+ }
207
+ closeConstruct(body) {
208
+ const entry = this.open.pop();
209
+ if (entry?.isBookmark) body.appendBookmarkEnd(entry.name);
210
+ }
211
+ };
212
+ function appendBlock(body, block, markers) {
190
213
  if (block.kind === "paragraph") populateParagraph(body.appendParagraph(), block, { headings: "element" });
191
214
  else if (block.kind === "image") body.appendParagraph().insertImageAfter({
192
215
  format: block.format,
@@ -198,6 +221,8 @@ function appendBlock(body, block) {
198
221
  else if (block.kind === "pageBreak") body.appendPageBreak();
199
222
  else if (block.kind === "table") appendTable(body, block);
200
223
  else if (block.kind === "embeddedObject") appendEmbeddedObject(body, block);
224
+ else if (block.kind === "constructStart") markers.openConstruct(body, block);
225
+ else markers.closeConstruct(body);
201
226
  }
202
227
  function appendEmbeddedObject(body, block) {
203
228
  if (drawingOfBlock(block) !== void 0) {
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_xml_entities = require("../../xml/entities.cjs");
2
3
  const require_metadata_core_patch = require("../../metadata/core-patch.cjs");
3
4
  const require_model_metadata = require("../../model/metadata.cjs");
4
5
  const require_ports_clock = require("../../ports/clock.cjs");
@@ -69,6 +70,28 @@ var OdtBodyImpl = class {
69
70
  });
70
71
  this.officeText.children.push(paragraphElement);
71
72
  }
73
+ appendBookmarkStart(name) {
74
+ this.officeText.children.push({
75
+ type: "element",
76
+ tag: "text:bookmark-start",
77
+ attributes: [{
78
+ name: "text:name",
79
+ value: require_xml_entities.encodeXmlText(name)
80
+ }],
81
+ children: []
82
+ });
83
+ }
84
+ appendBookmarkEnd(name) {
85
+ this.officeText.children.push({
86
+ type: "element",
87
+ tag: "text:bookmark-end",
88
+ attributes: [{
89
+ name: "text:name",
90
+ value: require_xml_entities.encodeXmlText(name)
91
+ }],
92
+ children: []
93
+ });
94
+ }
72
95
  };
73
96
  var OdtEditor = class {
74
97
  body;
@@ -12,6 +12,8 @@ interface OdtBody {
12
12
  appendPageBreak(): void;
13
13
  appendFormula(formula: ContentFormula, frame: Box): OdtParagraph;
14
14
  appendVectors(vectors: readonly ContentVector[]): OdtParagraph;
15
+ appendBookmarkStart(name: string): void;
16
+ appendBookmarkEnd(name: string): void;
15
17
  }
16
18
  declare class OdtEditor {
17
19
  readonly body: OdtBody;
@@ -12,6 +12,8 @@ interface OdtBody {
12
12
  appendPageBreak(): void;
13
13
  appendFormula(formula: ContentFormula, frame: Box): OdtParagraph;
14
14
  appendVectors(vectors: readonly ContentVector[]): OdtParagraph;
15
+ appendBookmarkStart(name: string): void;
16
+ appendBookmarkEnd(name: string): void;
15
17
  }
16
18
  declare class OdtEditor {
17
19
  readonly body: OdtBody;
@@ -1,3 +1,4 @@
1
+ import { encodeXmlText as encodeXmlText$1 } from "../../xml/entities.js";
1
2
  import { patchOdfMetadataOnPackage } from "../../metadata/core-patch.js";
2
3
  import { resolveMetadataTimestamps } from "../../model/metadata.js";
3
4
  import { systemClock } from "../../ports/clock.js";
@@ -68,6 +69,28 @@ var OdtBodyImpl = class {
68
69
  });
69
70
  this.officeText.children.push(paragraphElement);
70
71
  }
72
+ appendBookmarkStart(name) {
73
+ this.officeText.children.push({
74
+ type: "element",
75
+ tag: "text:bookmark-start",
76
+ attributes: [{
77
+ name: "text:name",
78
+ value: encodeXmlText$1(name)
79
+ }],
80
+ children: []
81
+ });
82
+ }
83
+ appendBookmarkEnd(name) {
84
+ this.officeText.children.push({
85
+ type: "element",
86
+ tag: "text:bookmark-end",
87
+ attributes: [{
88
+ name: "text:name",
89
+ value: encodeXmlText$1(name)
90
+ }],
91
+ children: []
92
+ });
93
+ }
71
94
  };
72
95
  var OdtEditor = class {
73
96
  body;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js.documents",
3
- "version": "7.10.4",
3
+ "version": "7.11.0",
4
4
  "description": "Bidirectional docx/pptx <-> PDF conversion and a read+write editable OOXML document model, built on ooxml.js and Zod 4 codecs.",
5
5
  "type": "module",
6
6
  "repository": {