@usejunior/docx-core 0.18.0 → 0.20.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 (142) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/core-types.d.ts +1 -139
  3. package/dist/core-types.d.ts.map +1 -1
  4. package/dist/core-types.js +1 -3
  5. package/dist/core-types.js.map +1 -1
  6. package/dist/generation/emit/borders.d.ts +14 -0
  7. package/dist/generation/emit/borders.d.ts.map +1 -0
  8. package/dist/generation/emit/borders.js +45 -0
  9. package/dist/generation/emit/borders.js.map +1 -0
  10. package/dist/generation/emit/properties.d.ts +1 -1
  11. package/dist/generation/emit/properties.d.ts.map +1 -1
  12. package/dist/generation/emit/properties.js +4 -0
  13. package/dist/generation/emit/properties.js.map +1 -1
  14. package/dist/generation/emit/table.d.ts.map +1 -1
  15. package/dist/generation/emit/table.js +3 -31
  16. package/dist/generation/emit/table.js.map +1 -1
  17. package/dist/generation/index.d.ts +1 -1
  18. package/dist/generation/index.d.ts.map +1 -1
  19. package/dist/generation/types.d.ts +9 -0
  20. package/dist/generation/types.d.ts.map +1 -1
  21. package/dist/generation/types.js.map +1 -1
  22. package/dist/generation/validate-spec.d.ts.map +1 -1
  23. package/dist/generation/validate-spec.js +2 -0
  24. package/dist/generation/validate-spec.js.map +1 -1
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +11 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/integration/generation-probes.d.ts +36 -2
  30. package/dist/integration/generation-probes.d.ts.map +1 -1
  31. package/dist/integration/generation-probes.js +137 -15
  32. package/dist/integration/generation-probes.js.map +1 -1
  33. package/dist/integration/libreoffice-oracle.js +1 -1
  34. package/dist/integration/synthetic-docx-fixture.d.ts.map +1 -1
  35. package/dist/integration/synthetic-docx-fixture.js +37 -20
  36. package/dist/integration/synthetic-docx-fixture.js.map +1 -1
  37. package/dist/primitives/accept_ai_edits.js +14 -2
  38. package/dist/primitives/accept_ai_edits.js.map +1 -1
  39. package/dist/primitives/accept_changes.d.ts +7 -0
  40. package/dist/primitives/accept_changes.d.ts.map +1 -1
  41. package/dist/primitives/accept_changes.js +92 -4
  42. package/dist/primitives/accept_changes.js.map +1 -1
  43. package/dist/primitives/bookmarks.d.ts +1 -0
  44. package/dist/primitives/bookmarks.d.ts.map +1 -1
  45. package/dist/primitives/bookmarks.js +1 -1
  46. package/dist/primitives/bookmarks.js.map +1 -1
  47. package/dist/primitives/comments.d.ts +31 -4
  48. package/dist/primitives/comments.d.ts.map +1 -1
  49. package/dist/primitives/comments.js +111 -12
  50. package/dist/primitives/comments.js.map +1 -1
  51. package/dist/primitives/document.d.ts +47 -1
  52. package/dist/primitives/document.d.ts.map +1 -1
  53. package/dist/primitives/document.js +198 -13
  54. package/dist/primitives/document.js.map +1 -1
  55. package/dist/primitives/document_view-headings.d.ts +3 -1
  56. package/dist/primitives/document_view-headings.d.ts.map +1 -1
  57. package/dist/primitives/document_view-headings.js +5 -5
  58. package/dist/primitives/document_view-headings.js.map +1 -1
  59. package/dist/primitives/document_view.d.ts +2 -0
  60. package/dist/primitives/document_view.d.ts.map +1 -1
  61. package/dist/primitives/document_view.js +18 -4
  62. package/dist/primitives/document_view.js.map +1 -1
  63. package/dist/primitives/field_evaluation.d.ts +70 -0
  64. package/dist/primitives/field_evaluation.d.ts.map +1 -0
  65. package/dist/primitives/field_evaluation.js +462 -0
  66. package/dist/primitives/field_evaluation.js.map +1 -0
  67. package/dist/primitives/footnotes.d.ts +17 -3
  68. package/dist/primitives/footnotes.d.ts.map +1 -1
  69. package/dist/primitives/footnotes.js +64 -17
  70. package/dist/primitives/footnotes.js.map +1 -1
  71. package/dist/primitives/formatting_tags.js +2 -2
  72. package/dist/primitives/formatting_tags.js.map +1 -1
  73. package/dist/primitives/index.d.ts +8 -1
  74. package/dist/primitives/index.d.ts.map +1 -1
  75. package/dist/primitives/index.js +8 -1
  76. package/dist/primitives/index.js.map +1 -1
  77. package/dist/primitives/merge_runs.d.ts +3 -1
  78. package/dist/primitives/merge_runs.d.ts.map +1 -1
  79. package/dist/primitives/merge_runs.js +12 -2
  80. package/dist/primitives/merge_runs.js.map +1 -1
  81. package/dist/primitives/namespaces.d.ts +12 -2
  82. package/dist/primitives/namespaces.d.ts.map +1 -1
  83. package/dist/primitives/namespaces.js +13 -2
  84. package/dist/primitives/namespaces.js.map +1 -1
  85. package/dist/primitives/note_conversion.d.ts +11 -0
  86. package/dist/primitives/note_conversion.d.ts.map +1 -0
  87. package/dist/primitives/note_conversion.js +12 -0
  88. package/dist/primitives/note_conversion.js.map +1 -0
  89. package/dist/primitives/opc-target.d.ts +24 -0
  90. package/dist/primitives/opc-target.d.ts.map +1 -0
  91. package/dist/primitives/opc-target.js +99 -0
  92. package/dist/primitives/opc-target.js.map +1 -0
  93. package/dist/primitives/paragraph_numbering.d.ts +40 -0
  94. package/dist/primitives/paragraph_numbering.d.ts.map +1 -0
  95. package/dist/primitives/paragraph_numbering.js +198 -0
  96. package/dist/primitives/paragraph_numbering.js.map +1 -0
  97. package/dist/primitives/reject_changes.d.ts +7 -0
  98. package/dist/primitives/reject_changes.d.ts.map +1 -1
  99. package/dist/primitives/reject_changes.js +133 -10
  100. package/dist/primitives/reject_changes.js.map +1 -1
  101. package/dist/primitives/sectPrAudit.d.ts +18 -1
  102. package/dist/primitives/sectPrAudit.d.ts.map +1 -1
  103. package/dist/primitives/sectPrAudit.js +120 -34
  104. package/dist/primitives/sectPrAudit.js.map +1 -1
  105. package/dist/primitives/sections.d.ts +134 -0
  106. package/dist/primitives/sections.d.ts.map +1 -0
  107. package/dist/primitives/sections.js +644 -0
  108. package/dist/primitives/sections.js.map +1 -0
  109. package/dist/primitives/serialize_html.d.ts.map +1 -1
  110. package/dist/primitives/serialize_html.js +18 -7
  111. package/dist/primitives/serialize_html.js.map +1 -1
  112. package/dist/primitives/styles.d.ts +60 -0
  113. package/dist/primitives/styles.d.ts.map +1 -1
  114. package/dist/primitives/styles.js +206 -25
  115. package/dist/primitives/styles.js.map +1 -1
  116. package/dist/primitives/symbol_run_content.d.ts +42 -0
  117. package/dist/primitives/symbol_run_content.d.ts.map +1 -0
  118. package/dist/primitives/symbol_run_content.js +79 -0
  119. package/dist/primitives/symbol_run_content.js.map +1 -0
  120. package/dist/primitives/text.d.ts +29 -0
  121. package/dist/primitives/text.d.ts.map +1 -1
  122. package/dist/primitives/text.js +354 -44
  123. package/dist/primitives/text.js.map +1 -1
  124. package/dist/primitives/track-changes-emitter.d.ts +9 -0
  125. package/dist/primitives/track-changes-emitter.d.ts.map +1 -1
  126. package/dist/primitives/track-changes-emitter.js +40 -2
  127. package/dist/primitives/track-changes-emitter.js.map +1 -1
  128. package/dist/primitives/validate_document.d.ts.map +1 -1
  129. package/dist/primitives/validate_document.js +22 -1
  130. package/dist/primitives/validate_document.js.map +1 -1
  131. package/dist/shared/docx/DocxArchive.d.ts.map +1 -1
  132. package/dist/shared/docx/DocxArchive.js +7 -0
  133. package/dist/shared/docx/DocxArchive.js.map +1 -1
  134. package/dist/shared/field-semantics.d.ts +26 -0
  135. package/dist/shared/field-semantics.d.ts.map +1 -0
  136. package/dist/shared/field-semantics.js +232 -0
  137. package/dist/shared/field-semantics.js.map +1 -0
  138. package/dist/shared/field-structure.d.ts +14 -0
  139. package/dist/shared/field-structure.d.ts.map +1 -1
  140. package/dist/shared/field-structure.js +98 -7
  141. package/dist/shared/field-structure.js.map +1 -1
  142. package/package.json +3 -5
@@ -0,0 +1,644 @@
1
+ import { findParagraphByBookmarkId, getParagraphBookmarkId, insertSingleParagraphBookmark, } from './bookmarks.js';
2
+ import { childElements, createWmlElement, getDirectChildrenByName, isW } from './dom-helpers.js';
3
+ import { OOXML, W } from './namespaces.js';
4
+ import { allocateRevisionId, buildSectPrChangeElement, } from './track-changes-emitter.js';
5
+ export class SectionMutationError extends Error {
6
+ code;
7
+ constructor(code, message) {
8
+ super(message);
9
+ this.code = code;
10
+ this.name = 'SectionMutationError';
11
+ }
12
+ }
13
+ function getWAttr(el, localName) {
14
+ return el.getAttributeNS(OOXML.W_NS, localName)
15
+ || el.getAttribute(`w:${localName}`)
16
+ || null;
17
+ }
18
+ function getRAttr(el, localName) {
19
+ return el.getAttributeNS(OOXML.R_NS, localName)
20
+ || el.getAttribute(`r:${localName}`)
21
+ || null;
22
+ }
23
+ function decimalAttr(el, localName) {
24
+ if (!el)
25
+ return null;
26
+ const raw = getWAttr(el, localName);
27
+ if (raw === null || !/^-?\d+$/.test(raw))
28
+ return null;
29
+ const value = Number(raw);
30
+ return Number.isSafeInteger(value) ? value : null;
31
+ }
32
+ /**
33
+ * Collect the two canonical live section-property placements without
34
+ * descending into `w:sectPrChange` snapshots.
35
+ *
36
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.18
37
+ * @see #654
38
+ */
39
+ function collectLiveSections(doc) {
40
+ const body = doc.getElementsByTagNameNS(OOXML.W_NS, W.body).item(0);
41
+ if (!body)
42
+ return [];
43
+ const sections = [];
44
+ const paragraphs = body.getElementsByTagNameNS(OOXML.W_NS, W.p);
45
+ for (let i = 0; i < paragraphs.length; i++) {
46
+ const paragraph = paragraphs.item(i);
47
+ const pPr = getDirectChildrenByName(paragraph, W.pPr)[0];
48
+ const sectPr = pPr
49
+ ? getDirectChildrenByName(pPr, W.sectPr)[0]
50
+ : undefined;
51
+ if (sectPr) {
52
+ sections.push({ sectPr, location: 'paragraph', paragraph });
53
+ }
54
+ }
55
+ const finalSectPr = childElements(body)
56
+ .find((child) => isW(child, W.sectPr));
57
+ if (finalSectPr) {
58
+ sections.push({ sectPr: finalSectPr, location: 'body', paragraph: null });
59
+ }
60
+ return sections;
61
+ }
62
+ function projectReferences(sectPr, localName) {
63
+ return getDirectChildrenByName(sectPr, localName).map((reference) => ({
64
+ type: getWAttr(reference, W.type),
65
+ relationshipId: getRAttr(reference, 'id'),
66
+ }));
67
+ }
68
+ function projectSection(section, sectionIndex) {
69
+ const type = getDirectChildrenByName(section.sectPr, W.type)[0] ?? null;
70
+ const pgNumType = getDirectChildrenByName(section.sectPr, W.pgNumType)[0] ?? null;
71
+ const pgSz = getDirectChildrenByName(section.sectPr, W.pgSz)[0] ?? null;
72
+ const pgMar = getDirectChildrenByName(section.sectPr, W.pgMar)[0] ?? null;
73
+ return {
74
+ sectionIndex,
75
+ location: section.location,
76
+ anchorParagraphId: section.paragraph
77
+ ? getParagraphBookmarkId(section.paragraph)
78
+ : null,
79
+ breakType: type ? getWAttr(type, W.val) : null,
80
+ pageNumberStart: decimalAttr(pgNumType, W.start),
81
+ pageNumberFormat: pgNumType ? getWAttr(pgNumType, 'fmt') : null,
82
+ pageSize: pgSz
83
+ ? {
84
+ widthTwips: decimalAttr(pgSz, W.w),
85
+ heightTwips: decimalAttr(pgSz, 'h'),
86
+ orientation: getWAttr(pgSz, 'orient'),
87
+ }
88
+ : null,
89
+ margins: pgMar
90
+ ? {
91
+ topTwips: decimalAttr(pgMar, W.top),
92
+ rightTwips: decimalAttr(pgMar, W.right),
93
+ bottomTwips: decimalAttr(pgMar, W.bottom),
94
+ leftTwips: decimalAttr(pgMar, W.left),
95
+ headerTwips: decimalAttr(pgMar, 'header'),
96
+ footerTwips: decimalAttr(pgMar, 'footer'),
97
+ gutterTwips: decimalAttr(pgMar, 'gutter'),
98
+ }
99
+ : null,
100
+ headers: projectReferences(section.sectPr, W.headerReference),
101
+ footers: projectReferences(section.sectPr, W.footerReference),
102
+ };
103
+ }
104
+ /**
105
+ * Return canonical main-document section properties in document order.
106
+ *
107
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.18
108
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.12
109
+ * @see #654
110
+ */
111
+ export function getDocumentSections(doc) {
112
+ return collectLiveSections(doc).map(projectSection);
113
+ }
114
+ const PAGE_SIZE_KEYS = [
115
+ 'widthTwips',
116
+ 'heightTwips',
117
+ 'orientation',
118
+ ];
119
+ const MARGIN_KEYS = [
120
+ 'topTwips',
121
+ 'rightTwips',
122
+ 'bottomTwips',
123
+ 'leftTwips',
124
+ 'headerTwips',
125
+ 'footerTwips',
126
+ 'gutterTwips',
127
+ ];
128
+ function hasDefinedValue(value, keys) {
129
+ return value !== undefined && keys.some((key) => value[key] !== undefined);
130
+ }
131
+ function validatePositiveTwips(value, label) {
132
+ if (!Number.isSafeInteger(value) || value <= 0) {
133
+ throw new SectionMutationError('INVALID_PAGE_SIZE', `${label} must be a positive safe integer.`);
134
+ }
135
+ }
136
+ function validateSignedTwips(value, label) {
137
+ if (!Number.isSafeInteger(value)) {
138
+ throw new SectionMutationError('INVALID_PAGE_MARGINS', `${label} must be a safe integer.`);
139
+ }
140
+ }
141
+ function validateUnsignedTwips(value, label) {
142
+ if (!Number.isSafeInteger(value) || value < 0) {
143
+ throw new SectionMutationError('INVALID_PAGE_MARGINS', `${label} must be a non-negative safe integer.`);
144
+ }
145
+ }
146
+ function validateMutation(mutation) {
147
+ if (!Number.isSafeInteger(mutation.sectionIndex) || mutation.sectionIndex < 0) {
148
+ throw new SectionMutationError('INVALID_SECTION_INDEX', 'sectionIndex must be a non-negative safe integer.');
149
+ }
150
+ const hasPageSize = hasDefinedValue(mutation.pageSize, PAGE_SIZE_KEYS);
151
+ const hasMargins = hasDefinedValue(mutation.margins, MARGIN_KEYS);
152
+ if (mutation.pageNumberStart === undefined
153
+ && !hasPageSize
154
+ && !hasMargins) {
155
+ throw new SectionMutationError('EMPTY_SECTION_MUTATION', 'At least one section page-setup value must be provided.');
156
+ }
157
+ if (mutation.pageNumberStart !== undefined) {
158
+ if (!Number.isSafeInteger(mutation.pageNumberStart)
159
+ || mutation.pageNumberStart < 0) {
160
+ throw new SectionMutationError('INVALID_PAGE_NUMBER_START', 'pageNumberStart must be a non-negative safe integer.');
161
+ }
162
+ }
163
+ if (mutation.pageSize?.widthTwips !== undefined) {
164
+ validatePositiveTwips(mutation.pageSize.widthTwips, 'pageSize.widthTwips');
165
+ }
166
+ if (mutation.pageSize?.heightTwips !== undefined) {
167
+ validatePositiveTwips(mutation.pageSize.heightTwips, 'pageSize.heightTwips');
168
+ }
169
+ if (mutation.pageSize?.orientation !== undefined
170
+ && mutation.pageSize.orientation !== 'portrait'
171
+ && mutation.pageSize.orientation !== 'landscape') {
172
+ throw new SectionMutationError('INVALID_PAGE_ORIENTATION', 'pageSize.orientation must be "portrait" or "landscape".');
173
+ }
174
+ if (mutation.margins?.topTwips !== undefined) {
175
+ validateSignedTwips(mutation.margins.topTwips, 'margins.topTwips');
176
+ }
177
+ if (mutation.margins?.bottomTwips !== undefined) {
178
+ validateSignedTwips(mutation.margins.bottomTwips, 'margins.bottomTwips');
179
+ }
180
+ for (const key of [
181
+ 'rightTwips',
182
+ 'leftTwips',
183
+ 'headerTwips',
184
+ 'footerTwips',
185
+ 'gutterTwips',
186
+ ]) {
187
+ const value = mutation.margins?.[key];
188
+ if (value !== undefined)
189
+ validateUnsignedTwips(value, `margins.${key}`);
190
+ }
191
+ }
192
+ function insertPgSzInSchemaOrder(sectPr, pgSz) {
193
+ const successors = new Set([
194
+ W.pgMar,
195
+ 'paperSrc',
196
+ 'pgBorders',
197
+ 'lnNumType',
198
+ W.pgNumType,
199
+ 'cols',
200
+ 'formProt',
201
+ 'vAlign',
202
+ 'noEndnote',
203
+ W.titlePg,
204
+ 'textDirection',
205
+ 'bidi',
206
+ 'rtlGutter',
207
+ 'docGrid',
208
+ 'printerSettings',
209
+ 'sectPrChange',
210
+ ]);
211
+ const successor = childElements(sectPr)
212
+ .find((child) => successors.has(child.localName));
213
+ if (successor)
214
+ sectPr.insertBefore(pgSz, successor);
215
+ else
216
+ sectPr.appendChild(pgSz);
217
+ }
218
+ function insertPgMarInSchemaOrder(sectPr, pgMar) {
219
+ const successors = new Set([
220
+ 'paperSrc',
221
+ 'pgBorders',
222
+ 'lnNumType',
223
+ W.pgNumType,
224
+ 'cols',
225
+ 'formProt',
226
+ 'vAlign',
227
+ 'noEndnote',
228
+ W.titlePg,
229
+ 'textDirection',
230
+ 'bidi',
231
+ 'rtlGutter',
232
+ 'docGrid',
233
+ 'printerSettings',
234
+ 'sectPrChange',
235
+ ]);
236
+ const successor = childElements(sectPr)
237
+ .find((child) => successors.has(child.localName));
238
+ if (successor)
239
+ sectPr.insertBefore(pgMar, successor);
240
+ else
241
+ sectPr.appendChild(pgMar);
242
+ }
243
+ function insertPgNumTypeInSchemaOrder(sectPr, pgNumType) {
244
+ const successors = new Set([
245
+ 'cols',
246
+ 'formProt',
247
+ 'vAlign',
248
+ 'noEndnote',
249
+ W.titlePg,
250
+ 'textDirection',
251
+ 'bidi',
252
+ 'rtlGutter',
253
+ 'docGrid',
254
+ 'printerSettings',
255
+ 'sectPrChange',
256
+ ]);
257
+ const successor = childElements(sectPr)
258
+ .find((child) => successors.has(child.localName));
259
+ if (successor)
260
+ sectPr.insertBefore(pgNumType, successor);
261
+ else
262
+ sectPr.appendChild(pgNumType);
263
+ }
264
+ function setSectionBreakType(sectPr, breakType) {
265
+ const existingTypes = getDirectChildrenByName(sectPr, W.type);
266
+ let type = existingTypes[0];
267
+ for (const duplicate of existingTypes.slice(1)) {
268
+ sectPr.removeChild(duplicate);
269
+ }
270
+ if (!type) {
271
+ type = createWmlElement(sectPr.ownerDocument, W.type);
272
+ const successor = childElements(sectPr).find((child) => child.localName !== W.headerReference
273
+ && child.localName !== W.footerReference);
274
+ if (successor)
275
+ sectPr.insertBefore(type, successor);
276
+ else
277
+ sectPr.appendChild(type);
278
+ }
279
+ type.setAttributeNS(OOXML.W_NS, `w:${W.val}`, breakType);
280
+ }
281
+ function removeDirectSectionChange(sectPr) {
282
+ for (const change of getDirectChildrenByName(sectPr, 'sectPrChange')) {
283
+ sectPr.removeChild(change);
284
+ }
285
+ }
286
+ function resetNonRelationshipSectionProperties(sectPr) {
287
+ for (const child of childElements(sectPr)) {
288
+ if (!isW(child, W.headerReference)
289
+ && !isW(child, W.footerReference)) {
290
+ sectPr.removeChild(child);
291
+ }
292
+ }
293
+ for (let i = sectPr.attributes.length - 1; i >= 0; i--) {
294
+ const attribute = sectPr.attributes.item(i);
295
+ if (attribute?.namespaceURI === OOXML.W_NS) {
296
+ sectPr.removeAttributeNode(attribute);
297
+ }
298
+ }
299
+ }
300
+ function ensureProspectiveSectionMutationIsValid(doc, sectionIndex, mutation, inheritProperties, currentSectPr) {
301
+ const fullMutation = { sectionIndex, ...mutation };
302
+ validateMutation(fullMutation);
303
+ const prospectiveSectPr = inheritProperties
304
+ ? currentSectPr.cloneNode(true)
305
+ : createWmlElement(doc, W.sectPr);
306
+ if (!inheritProperties) {
307
+ for (const reference of childElements(currentSectPr)) {
308
+ if (isW(reference, W.headerReference)
309
+ || isW(reference, W.footerReference)) {
310
+ prospectiveSectPr.appendChild(reference.cloneNode(true));
311
+ }
312
+ }
313
+ }
314
+ assertMissingElementsCanBeCreated({ sectPr: prospectiveSectPr, location: 'body', paragraph: null }, fullMutation);
315
+ }
316
+ function paragraphInsertionReference(anchor) {
317
+ let cursor = anchor.nextSibling;
318
+ while (cursor) {
319
+ if (cursor.nodeType !== 1) {
320
+ cursor = cursor.nextSibling;
321
+ continue;
322
+ }
323
+ if (isW(cursor, W.bookmarkEnd)) {
324
+ cursor = cursor.nextSibling;
325
+ continue;
326
+ }
327
+ break;
328
+ }
329
+ return cursor;
330
+ }
331
+ function addParagraphInsertionMarker(doc, pPr, ctx) {
332
+ const rPr = createWmlElement(doc, W.rPr);
333
+ rPr.appendChild(createWmlElement(doc, 'ins', {
334
+ 'w:id': String(allocateRevisionId(ctx.idState)),
335
+ 'w:author': ctx.author,
336
+ 'w:date': ctx.date,
337
+ }));
338
+ pPr.insertBefore(rPr, pPr.firstChild);
339
+ }
340
+ function requestedValueDiffers(element, localName, value) {
341
+ return value !== undefined
342
+ && (!element || getWAttr(element, localName) !== String(value));
343
+ }
344
+ function assertMissingElementsCanBeCreated(liveSection, mutation) {
345
+ if (hasDefinedValue(mutation.pageSize, PAGE_SIZE_KEYS)
346
+ && getDirectChildrenByName(liveSection.sectPr, W.pgSz).length === 0
347
+ && (mutation.pageSize?.widthTwips === undefined
348
+ || mutation.pageSize.heightTwips === undefined)) {
349
+ throw new SectionMutationError('INCOMPLETE_PAGE_SIZE', 'A section without w:pgSz requires both widthTwips and heightTwips.');
350
+ }
351
+ if (hasDefinedValue(mutation.margins, MARGIN_KEYS)
352
+ && getDirectChildrenByName(liveSection.sectPr, W.pgMar).length === 0
353
+ && MARGIN_KEYS.some((key) => mutation.margins?.[key] === undefined)) {
354
+ throw new SectionMutationError('INCOMPLETE_PAGE_MARGINS', 'A section without w:pgMar requires all seven margin values.');
355
+ }
356
+ }
357
+ /**
358
+ * Atomically update one section's page setup while preserving every
359
+ * unspecified section property and recording one prior-state snapshot.
360
+ *
361
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.13
362
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.11
363
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.12
364
+ * @conformance ECMA-376 edition 5, Part 1 § 17.13.5.32
365
+ * @see #654
366
+ */
367
+ export function updateSectionProperties(doc, mutation, ctx) {
368
+ validateMutation(mutation);
369
+ const liveSection = collectLiveSections(doc)[mutation.sectionIndex];
370
+ if (!liveSection) {
371
+ throw new SectionMutationError('SECTION_NOT_FOUND', `Section index ${mutation.sectionIndex} was not found.`);
372
+ }
373
+ assertMissingElementsCanBeCreated(liveSection, mutation);
374
+ const existingPgNumTypes = getDirectChildrenByName(liveSection.sectPr, W.pgNumType);
375
+ const existingPageSizes = getDirectChildrenByName(liveSection.sectPr, W.pgSz);
376
+ const existingMargins = getDirectChildrenByName(liveSection.sectPr, W.pgMar);
377
+ const previousSection = projectSection(liveSection, mutation.sectionIndex);
378
+ const pageNumberChanged = mutation.pageNumberStart !== undefined && (existingPgNumTypes.length !== 1
379
+ || decimalAttr(existingPgNumTypes[0] ?? null, W.start) !== mutation.pageNumberStart);
380
+ const pageSizeChanged = hasDefinedValue(mutation.pageSize, PAGE_SIZE_KEYS) && (existingPageSizes.length !== 1
381
+ || requestedValueDiffers(existingPageSizes[0], W.w, mutation.pageSize?.widthTwips)
382
+ || requestedValueDiffers(existingPageSizes[0], 'h', mutation.pageSize?.heightTwips)
383
+ || requestedValueDiffers(existingPageSizes[0], 'orient', mutation.pageSize?.orientation));
384
+ const marginsChanged = hasDefinedValue(mutation.margins, MARGIN_KEYS) && (existingMargins.length !== 1
385
+ || requestedValueDiffers(existingMargins[0], W.top, mutation.margins?.topTwips)
386
+ || requestedValueDiffers(existingMargins[0], W.right, mutation.margins?.rightTwips)
387
+ || requestedValueDiffers(existingMargins[0], W.bottom, mutation.margins?.bottomTwips)
388
+ || requestedValueDiffers(existingMargins[0], W.left, mutation.margins?.leftTwips)
389
+ || requestedValueDiffers(existingMargins[0], 'header', mutation.margins?.headerTwips)
390
+ || requestedValueDiffers(existingMargins[0], 'footer', mutation.margins?.footerTwips)
391
+ || requestedValueDiffers(existingMargins[0], 'gutter', mutation.margins?.gutterTwips));
392
+ if (!pageNumberChanged && !pageSizeChanged && !marginsChanged) {
393
+ return {
394
+ sectionIndex: mutation.sectionIndex,
395
+ changed: false,
396
+ previousSection,
397
+ currentSection: previousSection,
398
+ };
399
+ }
400
+ const oldSectPr = liveSection.sectPr.cloneNode(true);
401
+ if (pageSizeChanged) {
402
+ let pgSz = existingPageSizes[0];
403
+ for (const duplicate of existingPageSizes.slice(1)) {
404
+ liveSection.sectPr.removeChild(duplicate);
405
+ }
406
+ if (!pgSz) {
407
+ pgSz = createWmlElement(doc, W.pgSz);
408
+ insertPgSzInSchemaOrder(liveSection.sectPr, pgSz);
409
+ }
410
+ const pageSizeAttrs = [
411
+ [W.w, mutation.pageSize?.widthTwips],
412
+ ['h', mutation.pageSize?.heightTwips],
413
+ ['orient', mutation.pageSize?.orientation],
414
+ ];
415
+ for (const [name, value] of pageSizeAttrs) {
416
+ if (value !== undefined) {
417
+ pgSz.setAttributeNS(OOXML.W_NS, `w:${name}`, String(value));
418
+ }
419
+ }
420
+ }
421
+ if (marginsChanged) {
422
+ let pgMar = existingMargins[0];
423
+ for (const duplicate of existingMargins.slice(1)) {
424
+ liveSection.sectPr.removeChild(duplicate);
425
+ }
426
+ if (!pgMar) {
427
+ pgMar = createWmlElement(doc, W.pgMar);
428
+ insertPgMarInSchemaOrder(liveSection.sectPr, pgMar);
429
+ }
430
+ const marginAttrs = [
431
+ [W.top, mutation.margins?.topTwips],
432
+ [W.right, mutation.margins?.rightTwips],
433
+ [W.bottom, mutation.margins?.bottomTwips],
434
+ [W.left, mutation.margins?.leftTwips],
435
+ ['header', mutation.margins?.headerTwips],
436
+ ['footer', mutation.margins?.footerTwips],
437
+ ['gutter', mutation.margins?.gutterTwips],
438
+ ];
439
+ for (const [name, value] of marginAttrs) {
440
+ if (value !== undefined) {
441
+ pgMar.setAttributeNS(OOXML.W_NS, `w:${name}`, String(value));
442
+ }
443
+ }
444
+ }
445
+ if (pageNumberChanged) {
446
+ let pgNumType = existingPgNumTypes[0];
447
+ for (const duplicate of existingPgNumTypes.slice(1)) {
448
+ liveSection.sectPr.removeChild(duplicate);
449
+ }
450
+ if (!pgNumType) {
451
+ pgNumType = createWmlElement(doc, W.pgNumType);
452
+ insertPgNumTypeInSchemaOrder(liveSection.sectPr, pgNumType);
453
+ }
454
+ pgNumType.setAttributeNS(OOXML.W_NS, `w:${W.start}`, String(mutation.pageNumberStart));
455
+ }
456
+ if (ctx) {
457
+ for (const stale of getDirectChildrenByName(liveSection.sectPr, 'sectPrChange')) {
458
+ liveSection.sectPr.removeChild(stale);
459
+ }
460
+ liveSection.sectPr.appendChild(buildSectPrChangeElement(oldSectPr, ctx));
461
+ }
462
+ return {
463
+ sectionIndex: mutation.sectionIndex,
464
+ changed: true,
465
+ previousSection,
466
+ currentSection: projectSection(liveSection, mutation.sectionIndex),
467
+ };
468
+ }
469
+ const SECTION_BREAK_TYPES = new Set([
470
+ 'nextPage',
471
+ 'nextColumn',
472
+ 'continuous',
473
+ 'evenPage',
474
+ 'oddPage',
475
+ ]);
476
+ function removeInsertedBoundaryWithBookmarks(paragraph) {
477
+ const parent = paragraph.parentNode;
478
+ if (!parent)
479
+ return;
480
+ const previous = paragraph.previousSibling;
481
+ const next = paragraph.nextSibling;
482
+ if (previous?.nodeType === 1 && isW(previous, W.bookmarkStart)) {
483
+ parent.removeChild(previous);
484
+ }
485
+ if (next?.nodeType === 1 && isW(next, W.bookmarkEnd)) {
486
+ parent.removeChild(next);
487
+ }
488
+ parent.removeChild(paragraph);
489
+ }
490
+ /**
491
+ * Insert one main-document section boundary after a stable direct-body
492
+ * paragraph and optionally initialize the following section's page setup.
493
+ *
494
+ * The dedicated boundary paragraph carries an inserted paragraph-mark revision
495
+ * so accepting retains the split and rejecting removes it. Following-section
496
+ * property overrides use one prior-state snapshot.
497
+ *
498
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.18
499
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.22
500
+ * @conformance ECMA-376 edition 5, Part 1 § 17.13.5.20
501
+ * @conformance ECMA-376 edition 5, Part 1 § 17.13.5.32
502
+ * @see #654
503
+ */
504
+ export function insertSectionBreak(doc, mutation, ctx) {
505
+ if (typeof mutation.anchorParagraphId !== 'string'
506
+ || mutation.anchorParagraphId.trim().length === 0) {
507
+ throw new SectionMutationError('INVALID_SECTION_ANCHOR', 'anchorParagraphId must be a non-empty paragraph id.');
508
+ }
509
+ if (!SECTION_BREAK_TYPES.has(mutation.breakType)) {
510
+ throw new SectionMutationError('INVALID_SECTION_BREAK_TYPE', 'breakType must be nextPage, nextColumn, continuous, evenPage, or oddPage.');
511
+ }
512
+ if (mutation.inheritProperties !== undefined
513
+ && typeof mutation.inheritProperties !== 'boolean') {
514
+ throw new SectionMutationError('INVALID_INHERIT_PROPERTIES', 'inheritProperties must be a boolean.');
515
+ }
516
+ const anchor = findParagraphByBookmarkId(doc, mutation.anchorParagraphId);
517
+ if (!anchor) {
518
+ throw new SectionMutationError('SECTION_ANCHOR_NOT_FOUND', `Paragraph "${mutation.anchorParagraphId}" was not found or was ambiguous.`);
519
+ }
520
+ const body = doc.getElementsByTagNameNS(OOXML.W_NS, W.body).item(0);
521
+ if (!body || anchor.parentNode !== body) {
522
+ throw new SectionMutationError('SECTION_ANCHOR_NOT_BODY', 'The section-break anchor must be a direct child of the main document body.');
523
+ }
524
+ const anchorPPr = getDirectChildrenByName(anchor, W.pPr)[0];
525
+ if (anchorPPr
526
+ && getDirectChildrenByName(anchorPPr, W.sectPr).length > 0) {
527
+ throw new SectionMutationError('SECTION_BOUNDARY_EXISTS', 'The anchor paragraph already ends a section.');
528
+ }
529
+ const liveSections = collectLiveSections(doc);
530
+ let containingSection;
531
+ let cursor = anchor.nextSibling;
532
+ while (cursor) {
533
+ if (cursor.nodeType === 1) {
534
+ const element = cursor;
535
+ if (isW(element, W.p)) {
536
+ const pPr = getDirectChildrenByName(element, W.pPr)[0];
537
+ const sectPr = pPr
538
+ ? getDirectChildrenByName(pPr, W.sectPr)[0]
539
+ : undefined;
540
+ if (sectPr) {
541
+ containingSection = liveSections.find((section) => section.sectPr === sectPr);
542
+ break;
543
+ }
544
+ }
545
+ else if (isW(element, W.sectPr)) {
546
+ containingSection = liveSections.find((section) => section.sectPr === element);
547
+ break;
548
+ }
549
+ }
550
+ cursor = cursor.nextSibling;
551
+ }
552
+ if (!containingSection) {
553
+ throw new SectionMutationError('SECTION_NOT_FOUND', 'No live section boundary follows the anchor paragraph.');
554
+ }
555
+ const sectionIndex = liveSections.indexOf(containingSection);
556
+ if (sectionIndex < 0) {
557
+ throw new SectionMutationError('SECTION_NOT_FOUND', 'The containing section could not be resolved.');
558
+ }
559
+ const inheritProperties = mutation.inheritProperties ?? true;
560
+ if (mutation.newSection) {
561
+ ensureProspectiveSectionMutationIsValid(doc, sectionIndex, mutation.newSection, inheritProperties, containingSection.sectPr);
562
+ }
563
+ const sectionCountBefore = liveSections.length;
564
+ const originalFollowingSectPr = containingSection.sectPr.cloneNode(true);
565
+ const boundarySectPr = originalFollowingSectPr.cloneNode(true);
566
+ removeDirectSectionChange(boundarySectPr);
567
+ setSectionBreakType(boundarySectPr, mutation.breakType);
568
+ const boundaryParagraph = createWmlElement(doc, W.p);
569
+ const boundaryPPr = createWmlElement(doc, W.pPr);
570
+ if (ctx)
571
+ addParagraphInsertionMarker(doc, boundaryPPr, ctx);
572
+ boundaryPPr.appendChild(boundarySectPr);
573
+ boundaryParagraph.appendChild(boundaryPPr);
574
+ let followingChanged = false;
575
+ let boundaryInserted = false;
576
+ try {
577
+ if (!inheritProperties) {
578
+ resetNonRelationshipSectionProperties(containingSection.sectPr);
579
+ followingChanged = true;
580
+ if (mutation.newSection) {
581
+ updateSectionProperties(doc, { sectionIndex, ...mutation.newSection });
582
+ }
583
+ if (ctx) {
584
+ containingSection.sectPr.appendChild(buildSectPrChangeElement(originalFollowingSectPr, ctx));
585
+ }
586
+ }
587
+ else if (mutation.newSection) {
588
+ followingChanged = updateSectionProperties(doc, { sectionIndex, ...mutation.newSection }, ctx).changed;
589
+ }
590
+ body.insertBefore(boundaryParagraph, paragraphInsertionReference(anchor));
591
+ boundaryInserted = true;
592
+ const insertedBoundaryParagraphId = insertSingleParagraphBookmark(doc, boundaryParagraph);
593
+ const sectionsAfter = getDocumentSections(doc);
594
+ if (sectionsAfter.length !== sectionCountBefore + 1) {
595
+ throw new SectionMutationError('SECTION_INSERTION_INVARIANT', 'Section insertion did not add exactly one live section.');
596
+ }
597
+ const precedingSection = sectionsAfter[sectionIndex];
598
+ const followingSection = sectionsAfter[sectionIndex + 1];
599
+ if (!precedingSection
600
+ || !followingSection
601
+ || precedingSection.anchorParagraphId !== insertedBoundaryParagraphId) {
602
+ throw new SectionMutationError('SECTION_INSERTION_INVARIANT', 'Inserted section boundaries were not projected at the expected indexes.');
603
+ }
604
+ return {
605
+ changed: true,
606
+ insertedBoundaryParagraphId,
607
+ precedingSectionIndex: sectionIndex,
608
+ followingSectionIndex: sectionIndex + 1,
609
+ sectionCountBefore,
610
+ sectionCountAfter: sectionsAfter.length,
611
+ precedingSection,
612
+ followingSection,
613
+ };
614
+ }
615
+ catch (error) {
616
+ if (boundaryInserted && boundaryParagraph.parentNode) {
617
+ removeInsertedBoundaryWithBookmarks(boundaryParagraph);
618
+ }
619
+ const liveParent = containingSection.sectPr.parentNode;
620
+ if (followingChanged && liveParent) {
621
+ liveParent.replaceChild(originalFollowingSectPr, containingSection.sectPr);
622
+ }
623
+ throw error;
624
+ }
625
+ }
626
+ /**
627
+ * Set one section's page-number restart while preserving all unrelated section
628
+ * properties and recording the prior state when a revision context is supplied.
629
+ *
630
+ * @conformance ECMA-376 edition 5, Part 1 § 17.6.12
631
+ * @conformance ECMA-376 edition 5, Part 1 § 17.13.5.32
632
+ * @see #654
633
+ */
634
+ export function setSectionPageNumberStart(doc, mutation, ctx) {
635
+ const result = updateSectionProperties(doc, mutation, ctx);
636
+ return {
637
+ sectionIndex: result.sectionIndex,
638
+ changed: result.changed,
639
+ previousPageNumberStart: result.previousSection.pageNumberStart,
640
+ currentPageNumberStart: result.currentSection.pageNumberStart
641
+ ?? mutation.pageNumberStart,
642
+ };
643
+ }
644
+ //# sourceMappingURL=sections.js.map