@docx4j/core-ts 0.1.0 → 0.1.1

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 (168) hide show
  1. package/README.md +410 -10
  2. package/dist/model/content/Body.d.mts +109 -4
  3. package/dist/model/content/Body.mjs +300 -29
  4. package/dist/model/content/Comment.d.mts +78 -0
  5. package/dist/model/content/Comment.mjs +429 -0
  6. package/dist/model/content/ContentControl.d.mts +173 -0
  7. package/dist/model/content/ContentControl.mjs +638 -0
  8. package/dist/model/content/Font.d.mts +48 -8
  9. package/dist/model/content/Font.mjs +55 -13
  10. package/dist/model/content/InlinePicture.d.mts +103 -0
  11. package/dist/model/content/InlinePicture.mjs +361 -0
  12. package/dist/model/content/List.d.mts +253 -0
  13. package/dist/model/content/List.mjs +778 -0
  14. package/dist/model/content/Paragraph.d.mts +213 -16
  15. package/dist/model/content/Paragraph.mjs +611 -57
  16. package/dist/model/content/Range.d.mts +48 -4
  17. package/dist/model/content/Range.mjs +161 -4
  18. package/dist/model/content/Table.d.mts +130 -0
  19. package/dist/model/content/Table.mjs +429 -0
  20. package/dist/model/content/TrackedChange.d.mts +96 -0
  21. package/dist/model/content/TrackedChange.mjs +352 -0
  22. package/dist/model/content/comments.d.mts +122 -0
  23. package/dist/model/content/comments.mjs +248 -0
  24. package/dist/model/content/index.d.mts +13 -3
  25. package/dist/model/content/index.mjs +15 -3
  26. package/dist/model/content/ooxml.d.mts +17 -0
  27. package/dist/model/content/ooxml.mjs +214 -0
  28. package/dist/model/content/styles.d.mts +21 -0
  29. package/dist/model/content/styles.mjs +86 -0
  30. package/dist/model/content/tracking.d.mts +104 -0
  31. package/dist/model/content/tracking.mjs +313 -0
  32. package/dist/model/content/tree.d.mts +56 -9
  33. package/dist/model/content/tree.mjs +104 -31
  34. package/dist/model/customxml/CustomXmlPart.d.mts +158 -0
  35. package/dist/model/customxml/CustomXmlPart.mjs +415 -0
  36. package/dist/model/customxml/CustomXmlPartCollection.d.mts +68 -0
  37. package/dist/model/customxml/CustomXmlPartCollection.mjs +183 -0
  38. package/dist/model/customxml/XmlMapping.d.mts +46 -0
  39. package/dist/model/customxml/XmlMapping.mjs +98 -0
  40. package/dist/model/customxml/bindings.d.mts +41 -0
  41. package/dist/model/customxml/bindings.mjs +230 -0
  42. package/dist/model/customxml/index.d.mts +7 -0
  43. package/dist/model/customxml/index.mjs +9 -0
  44. package/dist/model/customxml/insert.d.mts +20 -0
  45. package/dist/model/customxml/insert.mjs +22 -0
  46. package/dist/model/customxml/kinds.d.mts +103 -0
  47. package/dist/model/customxml/kinds.mjs +267 -0
  48. package/dist/model/customxml/xpath.d.mts +52 -0
  49. package/dist/model/customxml/xpath.mjs +205 -0
  50. package/dist/model/fonts/CJKToEnglish.d.mts +2 -0
  51. package/dist/model/fonts/CJKToEnglish.mjs +16 -0
  52. package/dist/model/fonts/FontFallback.d.mts +58 -0
  53. package/dist/model/fonts/FontFallback.mjs +219 -0
  54. package/dist/model/fonts/IdentityPlusMapper.d.mts +7 -0
  55. package/dist/model/fonts/IdentityPlusMapper.mjs +19 -0
  56. package/dist/model/fonts/LanguageTagToScriptMapping.d.mts +7 -0
  57. package/dist/model/fonts/LanguageTagToScriptMapping.mjs +67 -0
  58. package/dist/model/fonts/Mapper.d.mts +190 -0
  59. package/dist/model/fonts/Mapper.mjs +481 -0
  60. package/dist/model/fonts/PhysicalFont.d.mts +34 -0
  61. package/dist/model/fonts/PhysicalFont.mjs +62 -0
  62. package/dist/model/fonts/RunFontSelector.d.mts +194 -0
  63. package/dist/model/fonts/RunFontSelector.mjs +441 -0
  64. package/dist/model/fonts/ThemeFonts.d.mts +17 -0
  65. package/dist/model/fonts/ThemeFonts.mjs +76 -0
  66. package/dist/model/fonts/defaultTheme.d.mts +37 -0
  67. package/dist/model/fonts/defaultTheme.mjs +57 -0
  68. package/dist/model/fonts/families.generated.d.mts +11 -0
  69. package/dist/model/fonts/families.generated.mjs +17 -0
  70. package/dist/model/fonts/fontsInUse.d.mts +39 -0
  71. package/dist/model/fonts/fontsInUse.mjs +183 -0
  72. package/dist/model/fonts/index.d.mts +14 -0
  73. package/dist/model/fonts/index.mjs +29 -0
  74. package/dist/model/fonts/lookup.d.mts +5 -0
  75. package/dist/model/fonts/lookup.mjs +12 -0
  76. package/dist/model/fonts/registry.d.mts +31 -0
  77. package/dist/model/fonts/registry.mjs +103 -0
  78. package/dist/model/fonts/scripts.d.mts +2 -0
  79. package/dist/model/fonts/scripts.mjs +78 -0
  80. package/dist/model/fonts/substitutions.generated.d.mts +30 -0
  81. package/dist/model/fonts/substitutions.generated.mjs +12 -0
  82. package/dist/model/fonts/themes.generated.d.mts +6 -0
  83. package/dist/model/fonts/themes.generated.mjs +11 -0
  84. package/dist/model/index.d.mts +5 -0
  85. package/dist/model/index.mjs +13 -1
  86. package/dist/model/listnumbering/Emulator.d.mts +187 -0
  87. package/dist/model/listnumbering/Emulator.mjs +332 -0
  88. package/dist/model/listnumbering/definitions.d.mts +251 -0
  89. package/dist/model/listnumbering/definitions.mjs +571 -0
  90. package/dist/model/listnumbering/formats.d.mts +25 -0
  91. package/dist/model/listnumbering/formats.mjs +320 -0
  92. package/dist/model/listnumbering/index.d.mts +4 -0
  93. package/dist/model/listnumbering/index.mjs +15 -0
  94. package/dist/model/listnumbering/state.d.mts +97 -0
  95. package/dist/model/listnumbering/state.mjs +179 -0
  96. package/dist/model/properties/PropertyResolver.d.mts +216 -0
  97. package/dist/model/properties/PropertyResolver.mjs +524 -0
  98. package/dist/model/properties/catalogue.d.mts +179 -0
  99. package/dist/model/properties/catalogue.mjs +860 -0
  100. package/dist/model/properties/index.d.mts +4 -0
  101. package/dist/model/properties/index.mjs +9 -0
  102. package/dist/model/properties/log.d.mts +7 -0
  103. package/dist/model/properties/log.mjs +25 -0
  104. package/dist/model/properties/styleUtil.d.mts +112 -0
  105. package/dist/model/properties/styleUtil.mjs +359 -0
  106. package/dist/node/index.d.mts +1 -0
  107. package/dist/node/index.mjs +12 -0
  108. package/dist/office-js/document.d.mts +111 -0
  109. package/dist/office-js/document.mjs +267 -0
  110. package/dist/office-js/enums.d.mts +187 -0
  111. package/dist/office-js/enums.mjs +176 -0
  112. package/dist/office-js/errors.d.mts +29 -0
  113. package/dist/office-js/errors.mjs +39 -0
  114. package/dist/office-js/extras.d.mts +5 -0
  115. package/dist/office-js/extras.mjs +29 -0
  116. package/dist/office-js/fragment.d.mts +10 -0
  117. package/dist/office-js/fragment.mjs +23 -0
  118. package/dist/office-js/index.d.mts +183 -0
  119. package/dist/office-js/index.mjs +54 -0
  120. package/dist/office-js/proxy.d.mts +72 -0
  121. package/dist/office-js/proxy.mjs +279 -0
  122. package/dist/office-js/run.d.mts +32 -0
  123. package/dist/office-js/run.mjs +66 -0
  124. package/dist/office-js/supported.d.mts +7 -0
  125. package/dist/office-js/supported.generated.d.mts +1 -0
  126. package/dist/office-js/supported.generated.mjs +235 -0
  127. package/dist/office-js/supported.mjs +53 -0
  128. package/dist/office-js/toApiScript.d.mts +25 -0
  129. package/dist/office-js/toApiScript.mjs +394 -0
  130. package/dist/opc/ContentTypes.d.mts +1 -0
  131. package/dist/opc/ContentTypes.mjs +1 -0
  132. package/dist/opc/DirectoryPartStore.d.mts +47 -0
  133. package/dist/opc/DirectoryPartStore.mjs +123 -0
  134. package/dist/opc/exceptions.d.mts +30 -0
  135. package/dist/opc/exceptions.mjs +38 -0
  136. package/dist/opc/index.d.mts +1 -1
  137. package/dist/opc/index.mjs +1 -1
  138. package/dist/packages/OpcPackage.d.mts +19 -1
  139. package/dist/packages/OpcPackage.mjs +29 -0
  140. package/dist/packages/PresentationMLPackage.d.mts +71 -1
  141. package/dist/packages/PresentationMLPackage.mjs +179 -0
  142. package/dist/packages/SpreadsheetMLPackage.d.mts +30 -1
  143. package/dist/packages/SpreadsheetMLPackage.mjs +78 -0
  144. package/dist/packages/WordprocessingMLPackage.d.mts +124 -2
  145. package/dist/packages/WordprocessingMLPackage.mjs +309 -2
  146. package/dist/packages/index.d.mts +1 -1
  147. package/dist/packages/index.mjs +1 -1
  148. package/dist/parts/DefaultXmlPart.d.mts +18 -0
  149. package/dist/parts/DefaultXmlPart.mjs +34 -5
  150. package/dist/parts/PartRegistry.mjs +1 -0
  151. package/dist/parts/XmlPart.d.mts +33 -0
  152. package/dist/parts/XmlPart.mjs +105 -2
  153. package/dist/parts/pml/defaults.d.mts +6 -0
  154. package/dist/parts/pml/defaults.mjs +53 -0
  155. package/dist/parts/pml/index.d.mts +66 -3
  156. package/dist/parts/pml/index.mjs +206 -7
  157. package/dist/parts/pml/placeholders.d.mts +71 -0
  158. package/dist/parts/pml/placeholders.mjs +141 -0
  159. package/dist/parts/sml/index.d.mts +19 -1
  160. package/dist/parts/sml/index.mjs +60 -1
  161. package/dist/parts/wml/comments.d.mts +1 -0
  162. package/dist/parts/wml/comments.mjs +179 -0
  163. package/dist/parts/wml/defaultNumbering.d.mts +1 -0
  164. package/dist/parts/wml/defaultNumbering.mjs +216 -0
  165. package/dist/parts/wml/index.d.mts +121 -0
  166. package/dist/parts/wml/index.mjs +291 -0
  167. package/dist/xml/dom.mjs +1 -2
  168. package/package.json +25 -4
@@ -1,8 +1,18 @@
1
- import { Docx4JException } from '../../opc/exceptions.mjs';
2
- import { typeNameOf, childrenOf, linkParents, BLOCK_LEVEL_TYPES, textOf } from './tree.mjs';
3
- import { wml as parseFragment, r as textRun, br as breakItem } from '@docx4j/generated-objects-ts/builders/wml';
1
+ import { Docx4JException, PropertyResolverNotCreatedException } from '../../opc/exceptions.mjs';
2
+ import { typeNameOf, childrenOf, linkParents, BLOCK_LEVEL_TYPES, textOf, textOfView, rowsOf, cellsOf } from './tree.mjs';
3
+ import { r as textRun, br as breakItem, tbl as tableOf } from '@docx4j/generated-objects-ts/builders/wml';
4
4
  import { runOf, paragraphOf } from './tree.mjs';
5
5
  import { Paragraph } from './Paragraph.mjs';
6
+ import { Table } from './Table.mjs';
7
+ import { ContentControl, collectControls } from './ContentControl.mjs';
8
+ import { sdt as sdtOf, nextSdtId } from '@docx4j/generated-objects-ts/builders/wml';
9
+ import { controlIdScope, sdtKindFor } from '../customxml/insert.mjs';
10
+ import { InlinePicture, addImage, writableWidthEmu } from './InlinePicture.mjs';
11
+ import { contentOf } from './ooxml.mjs';
12
+ import { commentApi } from './comments.mjs';
13
+ import { trackerOf, trackInsertedParagraph, trackInsertedTable } from './tracking.mjs';
14
+ import { trackedChangesOfRow } from './TrackedChange.mjs';
15
+ import { listsOf, listLabelsOf } from './List.mjs';
6
16
  /**
7
17
  * A subset of Office JS `Word.Body` over any container with block-level content: the main
8
18
  * document's body, a header, a footer, a footnote, a cell or a content control. A view: the
@@ -21,6 +31,20 @@ export class Body {
21
31
  this.prefix = prefix;
22
32
  this.package_ = package_;
23
33
  }
34
+ /**
35
+ * The package's `PropertyResolver`, which every effective-formatting read goes through
36
+ * (CR-001 Phase B step 2). Throws `PropertyResolverNotCreatedException` when this body has
37
+ * no package, or the package has not built one yet: building it unmarshals the styles part,
38
+ * which cannot be done synchronously, so `await pkg.getPropertyResolver()` (or `getBody()`,
39
+ * which does it) first - or read direct formatting with `{ direct: true }`.
40
+ */
41
+ get propertyResolver() {
42
+ const pkg = this.package_;
43
+ const resolver = pkg === null || pkg === void 0 ? void 0 : pkg.propertyResolverOrUndefined;
44
+ if (!resolver)
45
+ throw new PropertyResolverNotCreatedException();
46
+ return resolver;
47
+ }
24
48
  /** The live content array (docx4j getContent()); block-level elements only, sectPr excluded. */
25
49
  get content() {
26
50
  var _a;
@@ -31,7 +55,7 @@ export class Body {
31
55
  get paragraphs() {
32
56
  const out = [];
33
57
  const visit = (items) => {
34
- var _a, _b, _c;
58
+ var _a;
35
59
  for (const el of items) {
36
60
  const tn = typeNameOf(el);
37
61
  if (tn === 'org_docx4j_wml.P')
@@ -41,9 +65,9 @@ export class Body {
41
65
  if (typeof v !== 'object' || v === null)
42
66
  continue;
43
67
  if (tn === 'org_docx4j_wml.Tbl') {
44
- for (const row of (_a = childrenOf(v)) !== null && _a !== void 0 ? _a : [])
45
- for (const cell of (_b = childrenOf(row.value)) !== null && _b !== void 0 ? _b : [])
46
- visit((_c = childrenOf(cell.value)) !== null && _c !== void 0 ? _c : []);
68
+ for (const row of rowsOf(v))
69
+ for (const cell of cellsOf(row.element.value))
70
+ visit((_a = childrenOf(cell.element.value)) !== null && _a !== void 0 ? _a : []);
47
71
  }
48
72
  else {
49
73
  const children = childrenOf(v);
@@ -56,14 +80,70 @@ export class Body {
56
80
  visit(this.content);
57
81
  return out;
58
82
  }
59
- /** The tables directly in this body (as elements; `Table` views are CR-002 Phase C). */
83
+ /** The tables directly in this body, as Office JS reports them (nested tables are a cell's). */
60
84
  get tables() {
61
- return this.content.filter((el) => typeNameOf(el) === 'org_docx4j_wml.Tbl').map((element) => ({ element, container: this.content }));
85
+ return this.content.filter((el) => typeNameOf(el) === 'org_docx4j_wml.Tbl').map((element) => new Table(element, this.content, this));
86
+ }
87
+ /** Every content control in this body, in document order, nested ones included. */
88
+ get contentControls() {
89
+ const out = [];
90
+ collectControls(this.content, this, out);
91
+ return out;
92
+ }
93
+ /** Every inline picture in this body, in document order (Office JS Body.inlinePictures). */
94
+ get inlinePictures() {
95
+ return this.paragraphs.flatMap((p) => p.inlinePictures);
96
+ }
97
+ /**
98
+ * Office JS `body.lists`: every `w:num` a paragraph of this body names, in the order they are
99
+ * first used (CR-002 phase H). Empty where the document has no numbering part, or where
100
+ * nothing has read it yet (`await pkg.getBody()` builds the resolver, which does).
101
+ */
102
+ get lists() {
103
+ return listsOf(this);
104
+ }
105
+ /**
106
+ * Every numbered paragraph of this body's **story** with its label, level, list and sibling
107
+ * index, in one walk (extension). `listItem.listString` walks the story per read, which is
108
+ * what Word's counting needs; this is the way to ask for all of them at once.
109
+ *
110
+ * Keyed by the `w:p` itself: `labels.get(paragraph.p)?.listString`.
111
+ */
112
+ listLabels() {
113
+ return listLabelsOf(this);
114
+ }
115
+ /**
116
+ * A view over a container nested in this body (a cell, a content control), sharing this body's
117
+ * part and package. The address prefix is the container's own address, so that the addresses a
118
+ * nested body reports carry on from this one.
119
+ */
120
+ sub(container, prefix = this.prefix) {
121
+ return new Body(this.part, container, prefix, this.package_);
122
+ }
123
+ /** The view of a `w:p` somewhere in this body's tree; its container comes from PARENT. */
124
+ paragraphFor(p) {
125
+ var _a;
126
+ const container = childrenOf(((_a = p.PARENT) !== null && _a !== void 0 ? _a : {}));
127
+ const element = container === null || container === void 0 ? void 0 : container.find((e) => e.value === p);
128
+ return element && container ? new Paragraph(element, container, this) : undefined;
62
129
  }
63
130
  /** The text, a paragraph per line. */
64
131
  get text() {
65
132
  return this.paragraphs.map((p) => p.text).join('\n');
66
133
  }
134
+ /**
135
+ * The text in one of the two views (extension; `text` is the accepted one).
136
+ * `{ view: 'original' }` reads the document as it was before the tracked changes.
137
+ */
138
+ getText(options) {
139
+ if ((options === null || options === void 0 ? void 0 : options.view) !== 'original')
140
+ return this.text;
141
+ return this.paragraphs.map((p) => textOfView(p.p, options)).join('\n');
142
+ }
143
+ /** The package's change tracker while `changeTrackingMode` is on; undefined when it is off (CR-002 phase F). */
144
+ get changeTracker() {
145
+ return trackerOf(this.package_);
146
+ }
67
147
  insertParagraph(text, location) {
68
148
  const el = paragraphOf(text === '' ? [] : [textRun(text)]);
69
149
  return this.insertElement(el, location);
@@ -80,10 +160,40 @@ export class Body {
80
160
  return paragraphs[0].insertText(text, 'Start');
81
161
  return paragraphs[paragraphs.length - 1].insertText(text, 'End');
82
162
  }
163
+ /**
164
+ * A table of `rowCount` by `columnCount` cells at the start or end (Office JS insertTable);
165
+ * `values` fills it row by row. The columns are equal over the section's text width.
166
+ */
167
+ insertTable(rowCount, columnCount, location, values) {
168
+ if (rowCount < 1 || columnCount < 1)
169
+ throw new Docx4JException(`A table needs at least one row and one column; got ${rowCount} by ${columnCount}`);
170
+ const rows = Array.from({ length: rowCount }, (_, r) => Array.from({ length: columnCount }, (_, c) => { var _a, _b; return (_b = (_a = values === null || values === void 0 ? void 0 : values[r]) === null || _a === void 0 ? void 0 : _a[c]) !== null && _b !== void 0 ? _b : ''; }));
171
+ const width = writableWidthTwips(this.container);
172
+ const element = tableOf(rows, width ? { width } : {});
173
+ this.insertElement(element, location);
174
+ return new Table(element, this.content, this);
175
+ }
176
+ /**
177
+ * Adds the image as a part of this body's part, with a relationship, and shows it in a new
178
+ * paragraph at the start or the end (Office JS insertInlinePictureFromBase64). An image wider
179
+ * than the text area is scaled down, as docx4j's CxCy.scale does.
180
+ */
181
+ insertInlinePictureFromBase64(base64, location, options) {
182
+ if (!this.part)
183
+ throw new Docx4JException('This body has no part, so an image cannot be related to it');
184
+ const { run, drawing } = addImage(this.part, base64, this.container, writableWidthEmu(this.container), options);
185
+ const paragraph = this.insertParagraph('', location);
186
+ paragraph.p.content.push(run);
187
+ linkParents(run, paragraph.p);
188
+ return new InlinePicture(drawing, run, paragraph);
189
+ }
83
190
  insertBreak(type, location) {
84
191
  const p = this.insertParagraph('', location);
85
- p.p.content.push(runOf([breakItem(type === 'Page' ? 'page' : undefined)]));
86
- linkParents(p.p.content, p.p);
192
+ const run = runOf([breakItem(type === 'Page' ? 'page' : undefined)]);
193
+ const tracker = this.changeTracker;
194
+ const item = tracker ? tracker.ins([run]) : run;
195
+ p.p.content.push(item);
196
+ linkParents(item, p.p);
87
197
  }
88
198
  /**
89
199
  * Inserts block-level elements (docx4j addObject): at the start or end of this body, or
@@ -113,19 +223,48 @@ export class Body {
113
223
  }
114
224
  container.splice(index, 0, ...elements);
115
225
  const owner = this.ownerOf(container);
226
+ const tracker = this.changeTracker;
116
227
  for (const el of elements) {
117
228
  linkParents(el, owner);
118
- if (typeNameOf(el) === 'org_docx4j_wml.P')
229
+ const tn = typeNameOf(el);
230
+ if (tn === 'org_docx4j_wml.P') {
119
231
  this.assignParaId(el.value);
232
+ if (tracker)
233
+ trackInsertedParagraph(tracker, el.value);
234
+ }
235
+ else if (tn === 'org_docx4j_wml.Tbl' && tracker) {
236
+ trackInsertedTable(tracker, el.value);
237
+ }
120
238
  }
121
239
  const first = elements[0];
122
240
  return typeNameOf(first) === 'org_docx4j_wml.P' ? new Paragraph(first, container, this) : { element: first, container };
123
241
  }
124
242
  /** Inserts a WML fragment (one or more w:p / w:tbl / ... as inside document.xml); the standard prefixes are declared for it. */
125
243
  async insertXml(xml, location, target) {
244
+ return this.insertContent(await contentOf(xml, { preprocess: this.preprocessor() }), location, target);
245
+ }
246
+ /**
247
+ * Word's `insertOoxml`: a flat OPC `pkg:package` string, whose body content is inserted with
248
+ * the parts it references (images, embedded objects) copied into this package under fresh
249
+ * names and relationship ids; styles and numbering are not merged (CR-002 open question 5).
250
+ * A bare `w:p` / `w:tbl` fragment is accepted too, as `insertXml` takes. Returns the views of
251
+ * what was inserted, as `insertXml` does, since a package may bring several blocks.
252
+ */
253
+ async insertOoxml(ooxml, location, target) {
254
+ const elements = await contentOf(ooxml, { preprocess: this.preprocessor(), target: this.part });
255
+ if (location === 'Replace') {
256
+ this.clear();
257
+ return this.insertContent(elements, 'End');
258
+ }
259
+ return this.insertContent(elements, location, target);
260
+ }
261
+ /** The package's DOM preprocessor (the MCE one), for fragments and incoming packages. */
262
+ preprocessor() {
126
263
  var _a;
127
264
  const preprocess = (_a = this.package_) === null || _a === void 0 ? void 0 : _a.loadOptions.preprocessor;
128
- const elements = await parseFragment(xml, { wrapper: 'body', preprocess: preprocess ? (doc) => preprocess(doc) : undefined });
265
+ return preprocess ? (doc) => preprocess(doc) : undefined;
266
+ }
267
+ insertContent(elements, location, target) {
129
268
  if (elements.length === 0)
130
269
  return [];
131
270
  this.insertElement(elements, location, target);
@@ -137,9 +276,109 @@ export class Body {
137
276
  search(text, options) {
138
277
  return this.paragraphs.flatMap((p) => p.search(text, options));
139
278
  }
140
- /** Removes everything (section properties stay). */
279
+ /**
280
+ * Replaces every match of `find` with `replace`, last match first so that the offsets of the
281
+ * ones still to do stay valid (CR-002 section 3.7). Returns the number replaced; tracked when
282
+ * the package's `changeTrackingMode` is on.
283
+ */
284
+ replaceText(find, replace, options) {
285
+ const matches = this.search(find, options);
286
+ for (let i = matches.length - 1; i >= 0; i--)
287
+ matches[i].insertText(replace, 'Replace');
288
+ return matches.length;
289
+ }
290
+ /**
291
+ * Removes everything (section properties stay). While the package tracks changes, every
292
+ * paragraph is marked deleted and every row's `w:trPr` takes a `w:del` instead.
293
+ */
141
294
  clear() {
142
- this.content.length = 0;
295
+ const tracker = this.changeTracker;
296
+ if (!tracker) {
297
+ this.content.length = 0;
298
+ return;
299
+ }
300
+ for (const row of this.rowElements())
301
+ tracker.markRowDeleted(row.value);
302
+ for (const p of this.paragraphs)
303
+ p.delete();
304
+ }
305
+ // --- change tracking (CR-002 phase F) ---------------------------------------------------
306
+ /** Every tracked change in this body, in document order. */
307
+ getTrackedChanges() {
308
+ const out = [];
309
+ const visit = (items, into) => {
310
+ var _a;
311
+ for (const el of items) {
312
+ const tn = typeNameOf(el);
313
+ if (tn === 'org_docx4j_wml.P') {
314
+ into.push(...new Paragraph(el, items, this).getTrackedChanges());
315
+ continue;
316
+ }
317
+ const v = el.value;
318
+ if (typeof v !== 'object' || v === null)
319
+ continue;
320
+ if (tn === 'org_docx4j_wml.Tbl') {
321
+ for (const row of rowsOf(v)) {
322
+ // A row that is itself a revision reports as one change, as Office JS does: the
323
+ // markup its cells carry (Word marks every run and mark of a deleted or inserted row)
324
+ // belongs to that change, which accepts or rejects it along with the row.
325
+ const inner = [];
326
+ for (const cell of cellsOf(row.element.value))
327
+ visit((_a = childrenOf(cell.element.value)) !== null && _a !== void 0 ? _a : [], inner);
328
+ const rowChanges = trackedChangesOfRow(row.element, row.container, inner);
329
+ into.push(...(rowChanges.length > 0 ? rowChanges : inner));
330
+ }
331
+ continue;
332
+ }
333
+ const children = childrenOf(v);
334
+ if (children)
335
+ visit(children, into);
336
+ }
337
+ };
338
+ visit(this.content, out);
339
+ return out;
340
+ }
341
+ /**
342
+ * Accepts every tracked change, last first so that a paragraph join never disturbs one still
343
+ * to do (docx4j `AcceptTrackedChanges` is the reference). Returns how many were accepted.
344
+ */
345
+ acceptAll() {
346
+ const changes = this.getTrackedChanges();
347
+ for (let i = changes.length - 1; i >= 0; i--)
348
+ changes[i].accept();
349
+ return changes.length;
350
+ }
351
+ /** Rejects every tracked change, last first. Returns how many were rejected. */
352
+ rejectAll() {
353
+ const changes = this.getTrackedChanges();
354
+ for (let i = changes.length - 1; i >= 0; i--)
355
+ changes[i].reject();
356
+ return changes.length;
357
+ }
358
+ /** Every `w:tr` in this body's tables, in document order (rows of nested tables included). */
359
+ rowElements() {
360
+ const out = [];
361
+ const visit = (items) => {
362
+ var _a;
363
+ for (const el of items) {
364
+ const v = el.value;
365
+ if (typeof v !== 'object' || v === null)
366
+ continue;
367
+ if (typeNameOf(el) === 'org_docx4j_wml.Tbl') {
368
+ for (const row of rowsOf(v)) {
369
+ out.push(row.element);
370
+ for (const cell of cellsOf(row.element.value))
371
+ visit((_a = childrenOf(cell.element.value)) !== null && _a !== void 0 ? _a : []);
372
+ }
373
+ continue;
374
+ }
375
+ const children = childrenOf(v);
376
+ if (children)
377
+ visit(children);
378
+ }
379
+ };
380
+ visit(this.content);
381
+ return out;
143
382
  }
144
383
  /** The part's XML (extension; Office JS getOoxml wraps it in a package). */
145
384
  async getXml() {
@@ -158,14 +397,16 @@ export class Body {
158
397
  : this.paragraphs.find((q) => q.text.includes(address.contains));
159
398
  return p ? { element: p.element, container: p.container } : undefined;
160
399
  }
161
- const parts = address.split('/');
162
- const prefix = parts[0];
163
- if (prefix !== this.prefix && !(prefix === 'body' && this.prefix === 'body'))
400
+ // The prefix may itself hold slashes: a cell's body is addressed 'body/4/0/1'.
401
+ if (!address.startsWith(this.prefix))
402
+ return undefined;
403
+ const tail = address.substring(this.prefix.length);
404
+ if (tail !== '' && !tail.startsWith('/'))
164
405
  return undefined;
165
406
  let current = this.container;
166
407
  let container;
167
408
  let element;
168
- for (const seg of parts.slice(1)) {
409
+ for (const seg of tail === '' ? [] : tail.substring(1).split('/')) {
169
410
  container = childrenOf(current);
170
411
  const i = Number(seg);
171
412
  if (!container || !Number.isInteger(i) || i < 0 || i >= container.length)
@@ -257,7 +498,6 @@ export class Body {
257
498
  return this.container;
258
499
  let owner = this.container;
259
500
  const seek = (value) => {
260
- var _a, _b;
261
501
  const children = childrenOf(value);
262
502
  if (!children)
263
503
  return false;
@@ -270,9 +510,9 @@ export class Body {
270
510
  if (typeof v !== 'object' || v === null)
271
511
  continue;
272
512
  if (typeNameOf(el) === 'org_docx4j_wml.Tbl') {
273
- for (const row of (_a = childrenOf(v)) !== null && _a !== void 0 ? _a : [])
274
- for (const cell of (_b = childrenOf(row.value)) !== null && _b !== void 0 ? _b : [])
275
- if (seek(cell.value))
513
+ for (const row of rowsOf(v))
514
+ for (const cell of cellsOf(row.element.value))
515
+ if (seek(cell.element.value))
276
516
  return true;
277
517
  }
278
518
  else if (seek(v))
@@ -288,7 +528,6 @@ export class Body {
288
528
  containerOf(element) {
289
529
  let found = this.content;
290
530
  const seek = (value) => {
291
- var _a, _b;
292
531
  const children = childrenOf(value);
293
532
  if (!children)
294
533
  return false;
@@ -301,9 +540,9 @@ export class Body {
301
540
  if (typeof v !== 'object' || v === null)
302
541
  continue;
303
542
  if (typeNameOf(el) === 'org_docx4j_wml.Tbl') {
304
- for (const row of (_a = childrenOf(v)) !== null && _a !== void 0 ? _a : [])
305
- for (const cell of (_b = childrenOf(row.value)) !== null && _b !== void 0 ? _b : [])
306
- if (seek(cell.value))
543
+ for (const row of rowsOf(v))
544
+ for (const cell of cellsOf(row.element.value))
545
+ if (seek(cell.element.value))
307
546
  return true;
308
547
  }
309
548
  else if (seek(v))
@@ -322,8 +561,8 @@ export class Body {
322
561
  let parent = child.PARENT;
323
562
  if (!parent)
324
563
  return undefined;
325
- // sdtContent is not a level of its own
326
- if ((_a = parent.TYPE_NAME) === null || _a === void 0 ? void 0 : _a.endsWith('SdtContentBlock'))
564
+ // sdtContent is not a level of its own, at block, row, cell or run level
565
+ if (/SdtContent(Block|Row|Cell|Run)$/.test((_a = parent.TYPE_NAME) !== null && _a !== void 0 ? _a : ''))
327
566
  parent = parent.PARENT;
328
567
  if (!parent)
329
568
  return undefined;
@@ -355,6 +594,38 @@ export class Body {
355
594
  usesParaIds() {
356
595
  return this.paragraphs.some((q) => q.paraId !== undefined);
357
596
  }
597
+ // --- comments (CR-002 phase G) ---
598
+ /**
599
+ * The comments anchored in this body, in document order, with replies nested under their
600
+ * parent (only top-level comments are in the array). Asynchronous because it unmarshals the
601
+ * comment parts.
602
+ */
603
+ async getComments() {
604
+ return commentApi().commentsOf(this);
605
+ }
606
+ // --- content controls (CR-002 phase E) ---
607
+ /**
608
+ * Wraps everything this body holds in a new content control (Office JS
609
+ * `Body.insertContentControl`), typed for the kind when one is given; the `w:id` is free in this
610
+ * body. Returns the control.
611
+ */
612
+ insertContentControl(kind) {
613
+ const content = [...this.content];
614
+ const sdt = sdtOf(content, { kind: sdtKindFor(kind), id: nextSdtId(controlIdScope(this)), form: 'block' });
615
+ this.content.length = 0;
616
+ this.content.push(sdt);
617
+ linkParents(sdt, this.container);
618
+ return new ContentControl(sdt, this.content, this);
619
+ }
620
+ }
621
+ /** The width of the text area in twips (page width less the margins), for a new table. */
622
+ function writableWidthTwips(container) {
623
+ var _a, _b, _c, _d, _e, _f, _g;
624
+ const pgSz = (_a = container.sectPr) === null || _a === void 0 ? void 0 : _a.pgSz;
625
+ if (!(pgSz === null || pgSz === void 0 ? void 0 : pgSz.w))
626
+ return undefined;
627
+ const width = pgSz.w - ((_d = (_c = (_b = container.sectPr) === null || _b === void 0 ? void 0 : _b.pgMar) === null || _c === void 0 ? void 0 : _c.left) !== null && _d !== void 0 ? _d : 0) - ((_g = (_f = (_e = container.sectPr) === null || _e === void 0 ? void 0 : _e.pgMar) === null || _f === void 0 ? void 0 : _f.right) !== null && _g !== void 0 ? _g : 0);
628
+ return width > 0 ? width : undefined;
358
629
  }
359
630
  function describe(el) {
360
631
  var _a, _b;
@@ -0,0 +1,78 @@
1
+ import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
2
+ import { Body } from './Body.mjs';
3
+ import { Paragraph } from './Paragraph.mjs';
4
+ import { Range } from './Range.mjs';
5
+ import { type CommentParts } from './comments.mjs';
6
+ /**
7
+ * A subset of Office JS `Word.Comment` over a `w:comment` and the markers that anchor it. A view:
8
+ * the tree is the state, and a view may be created and discarded freely. Replies are `Comment`s
9
+ * too (Office JS has a separate `CommentReply`; see the CR's section 9), threaded through
10
+ * `w15:commentsEx`.
11
+ */
12
+ export declare class Comment {
13
+ /** The `w:comment` (extension; the model holds comments as values, not `{ name, value }` pairs). */
14
+ readonly element: wml.Comments.Comment;
15
+ /** The document's comment parts. */
16
+ readonly parts: CommentParts;
17
+ /** The body the comment is anchored in. */
18
+ readonly body: Body;
19
+ private parentComment;
20
+ private readonly replyList;
21
+ private bodyView;
22
+ constructor(
23
+ /** The `w:comment` (extension; the model holds comments as values, not `{ name, value }` pairs). */
24
+ element: wml.Comments.Comment,
25
+ /** The document's comment parts. */
26
+ parts: CommentParts,
27
+ /** The body the comment is anchored in. */
28
+ body: Body);
29
+ /** `w:id` (extension: Office JS's `id` is a string; this is the OOXML id docx4j users work with). */
30
+ get id(): number;
31
+ get authorName(): string;
32
+ /** `w:initials` (extension; Office JS has no initials). */
33
+ get initials(): string;
34
+ /** The author's email from `w:people`, '' when the document records none. */
35
+ get authorEmail(): string;
36
+ /** `w:date`; undefined when the comment carries none. */
37
+ get creationDate(): Date | undefined;
38
+ /** The comment's paragraphs as a `Body` (extension: the same content API as the document's). */
39
+ get commentBody(): Body;
40
+ /** The comment's paragraphs (extension). */
41
+ get paragraphs(): Paragraph[];
42
+ /** The comment's text, a paragraph per line; setting it replaces the paragraphs. */
43
+ get content(): string;
44
+ set content(text: string);
45
+ /** `w15:done`: whether the thread is resolved. Setting it creates the w15 part when the document has none. */
46
+ get resolved(): boolean;
47
+ set resolved(value: boolean);
48
+ /** The `w14:paraId` of the comment's first paragraph: the key of its w15 and w16cid entries (extension). */
49
+ get paraId(): string | undefined;
50
+ /** The replies to this comment, in document order; a reply's own replies nest further (Word shows one level). */
51
+ get replies(): Comment[];
52
+ /** The comment this one replies to (extension). */
53
+ get parent(): Comment | undefined;
54
+ /** A reply in the same thread, anchored to the same range, as Word writes them. */
55
+ reply(text: string): Promise<Comment>;
56
+ /** Removes the comment and its replies: the markers, the reference runs and every side-part entry. */
57
+ delete(): Promise<void>;
58
+ /**
59
+ * The commented range: a `Range` per paragraph the comment touches (extension; Office JS
60
+ * returns one `Range`). Empty when the comment has no markers in this body.
61
+ */
62
+ getRange(): Range[];
63
+ /** This comment and, depth first, its replies. */
64
+ private thread;
65
+ private removeSelf;
66
+ /** The first paragraph's `w14:paraId`, assigned when the comment has none (Word always writes one). */
67
+ ensureParaId(): string;
68
+ /** Used by `commentsOf` while threading. */
69
+ addReply(reply: Comment): void;
70
+ }
71
+ /** `Range.insertComment` (CR-002 section 3.8): the markers, the comment and the side-part entries. */
72
+ export declare function insertComment(range: Range, text: string): Promise<Comment>;
73
+ /**
74
+ * `getComments()` on a body, a paragraph or a range: the comments anchored there in document
75
+ * order, replies nested under their parent (a reply is in the array only when its parent is not).
76
+ */
77
+ export declare function commentsOf(scope: Body | Paragraph | Range): Promise<Comment[]>;
78
+ export type { CommentParts, Author } from './comments.mjs';