@docx4j/core-ts 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +60 -0
  2. package/dist/model/content/Body.mjs +6 -17
  3. package/dist/model/content/Comment.d.mts +2 -2
  4. package/dist/model/content/Comment.mjs +12 -7
  5. package/dist/model/content/ContentControl.d.mts +1 -1
  6. package/dist/model/content/ContentControl.mjs +8 -4
  7. package/dist/model/content/Font.d.mts +4 -1
  8. package/dist/model/content/Font.mjs +6 -2
  9. package/dist/model/content/List.d.mts +6 -3
  10. package/dist/model/content/List.mjs +15 -8
  11. package/dist/model/content/Paragraph.d.mts +12 -2
  12. package/dist/model/content/Paragraph.mjs +31 -11
  13. package/dist/model/content/Table.mjs +26 -16
  14. package/dist/model/content/TrackedChange.d.mts +2 -2
  15. package/dist/model/content/TrackedChange.mjs +6 -3
  16. package/dist/model/content/index.d.mts +3 -1
  17. package/dist/model/content/index.mjs +4 -1
  18. package/dist/model/content/ooxml.mjs +12 -1
  19. package/dist/model/content/paraIds.d.mts +5 -0
  20. package/dist/model/content/paraIds.mjs +54 -0
  21. package/dist/model/content/search.d.mts +2 -0
  22. package/dist/model/content/search.mjs +51 -7
  23. package/dist/model/content/story.d.mts +5 -2
  24. package/dist/model/content/story.mjs +6 -3
  25. package/dist/model/content/tableRules.mjs +2 -0
  26. package/dist/model/content/tracking.d.mts +35 -6
  27. package/dist/model/content/tracking.mjs +93 -12
  28. package/dist/model/content/tree.d.mts +7 -8
  29. package/dist/model/content/tree.mjs +7 -9
  30. package/dist/model/content/wordRange.d.mts +48 -0
  31. package/dist/model/content/wordRange.mjs +97 -0
  32. package/dist/model/customxml/CustomXmlPartCollection.d.mts +22 -1
  33. package/dist/model/customxml/CustomXmlPartCollection.mjs +48 -2
  34. package/dist/model/customxml/XmlMapping.d.mts +31 -7
  35. package/dist/model/customxml/XmlMapping.mjs +53 -10
  36. package/dist/model/customxml/bindings.d.mts +12 -2
  37. package/dist/model/customxml/bindings.mjs +98 -16
  38. package/dist/model/customxml/index.d.mts +1 -0
  39. package/dist/model/customxml/index.mjs +1 -0
  40. package/dist/model/customxml/opendope.d.mts +4 -1
  41. package/dist/model/customxml/opendope.mjs +9 -6
  42. package/dist/model/customxml/pictures.mjs +5 -3
  43. package/dist/model/customxml/storeItems.d.mts +57 -0
  44. package/dist/model/customxml/storeItems.mjs +122 -0
  45. package/dist/model/customxml/xhtml.mjs +15 -20
  46. package/dist/model/dateZone.d.mts +25 -0
  47. package/dist/model/dateZone.mjs +57 -0
  48. package/dist/model/index.d.mts +1 -0
  49. package/dist/model/index.mjs +1 -0
  50. package/dist/model/properties/PropertyResolver.d.mts +14 -1
  51. package/dist/model/properties/PropertyResolver.mjs +18 -3
  52. package/dist/model/properties/index.d.mts +1 -1
  53. package/dist/model/properties/log.mjs +2 -2
  54. package/dist/model/properties/styleUtil.d.mts +3 -1
  55. package/dist/model/properties/styleUtil.mjs +20 -24
  56. package/dist/model/text/CaseMapping.d.mts +38 -0
  57. package/dist/model/text/CaseMapping.mjs +86 -0
  58. package/dist/model/text/Extractor.d.mts +66 -6
  59. package/dist/model/text/Extractor.mjs +300 -56
  60. package/dist/model/text/PlainText.mjs +7 -4
  61. package/dist/model/text/TextContext.d.mts +103 -8
  62. package/dist/model/text/TextContext.mjs +228 -53
  63. package/dist/model/text/TextOptions.d.mts +88 -5
  64. package/dist/model/text/TextOptions.mjs +158 -17
  65. package/dist/model/text/TextResult.d.mts +126 -9
  66. package/dist/model/text/TextResult.mjs +115 -12
  67. package/dist/model/text/WmlToMarkdown.mjs +32 -7
  68. package/dist/model/text/caseMapping.generated.d.mts +7 -0
  69. package/dist/model/text/caseMapping.generated.mjs +214 -0
  70. package/dist/model/text/index.d.mts +3 -2
  71. package/dist/model/text/index.mjs +1 -0
  72. package/dist/model/wordIntegers.d.mts +29 -0
  73. package/dist/model/wordIntegers.mjs +78 -0
  74. package/dist/office-js/document.mjs +15 -1
  75. package/dist/office-js/toApiScript.mjs +8 -7
  76. package/dist/opc/DirectoryPartStore.d.mts +6 -2
  77. package/dist/opc/DirectoryPartStore.mjs +11 -4
  78. package/dist/opc/FlatOpcPartStore.d.mts +4 -2
  79. package/dist/opc/FlatOpcPartStore.mjs +11 -8
  80. package/dist/opc/Load.d.mts +32 -0
  81. package/dist/opc/Load.mjs +115 -5
  82. package/dist/opc/PartStore.d.mts +34 -1
  83. package/dist/opc/PartStore.mjs +71 -8
  84. package/dist/opc/Save.d.mts +17 -2
  85. package/dist/opc/Save.mjs +100 -4
  86. package/dist/opc/ZipPartStore.d.mts +4 -2
  87. package/dist/opc/ZipPartStore.mjs +12 -7
  88. package/dist/opc/exceptions.d.mts +140 -0
  89. package/dist/opc/exceptions.mjs +108 -0
  90. package/dist/opc/index.d.mts +7 -4
  91. package/dist/opc/index.mjs +5 -3
  92. package/dist/opc/mce/preprocessor.d.mts +121 -10
  93. package/dist/opc/mce/preprocessor.mjs +122 -21
  94. package/dist/opc/mce/understood.d.mts +3 -35
  95. package/dist/opc/mce/understood.mjs +27 -53
  96. package/dist/opc/repair/breaks.d.mts +23 -0
  97. package/dist/opc/repair/breaks.mjs +288 -0
  98. package/dist/opc/repair/hosts.d.mts +12 -0
  99. package/dist/opc/repair/hosts.mjs +33 -0
  100. package/dist/opc/repair/mainRoot.d.mts +19 -0
  101. package/dist/opc/repair/mainRoot.mjs +168 -0
  102. package/dist/opc/repair/unknownElements.d.mts +8 -0
  103. package/dist/opc/repair/unknownElements.mjs +180 -0
  104. package/dist/opc/repair/wmlNames.generated.d.mts +2 -0
  105. package/dist/opc/repair/wmlNames.generated.mjs +80 -0
  106. package/dist/opc/skipped.d.mts +50 -0
  107. package/dist/opc/skipped.mjs +140 -0
  108. package/dist/packages/OpcPackage.d.mts +98 -5
  109. package/dist/packages/OpcPackage.mjs +122 -7
  110. package/dist/packages/WordprocessingMLPackage.mjs +3 -1
  111. package/dist/packages/index.d.mts +1 -1
  112. package/dist/parts/Part.d.mts +5 -1
  113. package/dist/parts/RelationshipsPart.d.mts +15 -0
  114. package/dist/parts/RelationshipsPart.mjs +66 -1
  115. package/dist/parts/XmlPart.d.mts +54 -5
  116. package/dist/parts/XmlPart.mjs +203 -10
  117. package/dist/parts/wml/index.d.mts +12 -1
  118. package/dist/parts/wml/index.mjs +25 -1
  119. package/package.json +2 -2
package/README.md CHANGED
@@ -57,6 +57,66 @@ intermediate form and a builder from it, CR-005 section 8; the HTML parser is yo
57
57
  container; nothing else in the package imports a `node:` builtin, so a browser or add-in bundle
58
58
  never sees one).
59
59
 
60
+ ### Repairs
61
+
62
+ Some packages Word opens only after its repair prompt, and some it won't open at all. `LoadOptions.repair`
63
+ (WD REQ-207, [CR-031](docs/change-requests/CR-031-the-repair-option.md)) says how a load treats them:
64
+
65
+ ```ts
66
+ const pkg = await WordprocessingMLPackage.load(bytes, { repair: 'word' });
67
+ pkg.repaired; // 'none', 'word' or 'own'; a text result's metadata.repaired says the same
68
+ ```
69
+
70
+ | The package | `refuse`, the default | `word` | `all` |
71
+ |---|---|---|---|
72
+ | Two zip entries of one name (OPC part names, without case) | `DuplicateEntryException` | The first of each read, as Word does: `package.duplicate_entry` | As `word` |
73
+ | More than one `officeDocument` relationship | `MultipleMainPartsException` | The last one's target read, as a fresh Word does: `package.multiple_main_parts` | As `word` |
74
+ | A relationships part in another namespace, or in none | `RelationshipsNamespaceException` | Every relationship read by its local name, as Word does: `package.relationships_namespace` | As `word` |
75
+ | An `External` `officeDocument` relationship beside an internal one | `ExternalMainPartException` | Refused: Word refuses it even through its repair | This package's own repair: the internal part read, every `External` main relationship dropped, its URL never fetched: `package.external_main_part` |
76
+ | An `External` `officeDocument` relationship alone | Refused: no main document part (REQ-321) | Refused | Refused |
77
+
78
+ Each warning is on `pkg.warnings` and, in the text model, a warning of the same code. A save then writes the
79
+ repaired package: one entry of each name, one main relationship, the right namespace, no `External` main
80
+ relationship. `repair` doesn't open the save's own gate ([CR-025](docs/change-requests/CR-025-dropped-content-reported.md)):
81
+ a changed part is written without what Word's own save drops too, such as an ignorable element Word doesn't understand,
82
+ each listed on `pkg.lastSave.dropped`; one that would lose anything else Word keeps, or won't open, needs
83
+ `pkg.checkLossOnSave = false`, each item then on `pkg.lastSave.lost`. Each `part.skipped` warning says which (`onSave`). The other shapes
84
+ Word repairs, such as an undeclared `mc:Ignorable` prefix or an element the model has no place for, read the same at
85
+ every value (CR-031 section 2.1.1).
86
+
87
+ ### Saving
88
+
89
+ A save copies every part nothing changed byte for byte, and re-marshals only what was read. Before it writes
90
+ anything, it checks what it would write. It refuses a file Word would refuse or repair, and a save that would lose
91
+ content Word keeps. Each check has a switch on the package, and each records what it let through on `pkg.lastSave`:
92
+
93
+ | A save that would | Throws | To write it anyway | Recorded on `pkg.lastSave` |
94
+ |---|---|---|---|
95
+ | Write a child its container never admits: a run straight in the body, a table in a paragraph, a string in a run ([CR-016](docs/change-requests/CR-016-misplaced-content-refused.md)) | `MisplacedContentException` (`target.misplaced`, each child with its part, path and the fix) | `pkg.checkContentOnSave = false` | `misplaced` |
96
+ | Lose what the read skipped, where Word's save keeps it or Word won't open the file ([CR-025](docs/change-requests/CR-025-dropped-content-reported.md)) | `SaveLossException` (`save.content_lost`, each part) | `pkg.checkLossOnSave = false` | `lost` |
97
+ | Lose what the read skipped, where Word's own save drops it too | Nothing: written without it | | `dropped` |
98
+
99
+ ```ts
100
+ import { SaveLossException } from '@docx4j/core-ts';
101
+
102
+ try {
103
+ await pkg.save();
104
+ } catch (e) {
105
+ if (!(e instanceof SaveLossException)) throw e;
106
+ pkg.checkLossOnSave = false; // accept the loss: e.losses names each part
107
+ await pkg.save();
108
+ pkg.lastSave.lost; // what went, each a part.skipped warning
109
+ }
110
+ ```
111
+
112
+ Only a part that was read is checked, so a package loaded and saved untouched is never refused. What a load found
113
+ is on `pkg.warnings` before any save: content the read skipped (`part.skipped`, its `onSave` saying which row it
114
+ falls in), misplaced children, and integer values past what Word stores (`value.out_of_range`, which a save writes
115
+ as held and lists on `lastSave.outOfRange`). `part.checkContent()` and `pkg.checkContent()` run the first check on
116
+ request, changing nothing. Two more switches change what a save writes: `pkg.normaliseOnSave` (run properties in
117
+ Word's normal form, on by default) and `pkg.writeTimesOnSave` (the core properties' times, off by default).
118
+ `pkg.dateTimeZone` is the time zone every revision's and comment's date is written and read in.
119
+
60
120
  ### Guides
61
121
 
62
122
  | | |
@@ -18,11 +18,12 @@ import { wrappingCellOf, paragraphEndOf, endsWithParagraph, endWithParagraph, en
18
18
  import { keepCellMarkLast } from './spanEdits.mjs';
19
19
  import { expandReplacement, paragraphMarkPieces, refuseMarkReplacement, refuseWildcardMarkReplacement } from './search.mjs';
20
20
  import { commentApi } from './comments.mjs';
21
- import { storyLayout } from './story.mjs';
21
+ import { storyLayout, shownInOriginalView } from './story.mjs';
22
22
  import { trackerOf, trackInsertedBlock, markHolderInserted } from './tracking.mjs';
23
23
  import { trackedChangesOfRow, trackedChangeTokensOfParagraph, groupTouching, BREAK, tablePropertiesChangeOf, cellChangeOf, bodySectionChangeOf, resolveUnlisted, holderChangeAt, resolving, resolvePieces, alternateTokens, listedListing, pairTwins } from './TrackedChange.mjs';
24
24
  import { pieceMatcher } from './trackedChangeFilter.mjs';
25
25
  import { listsOf, listLabelsOf } from './List.mjs';
26
+ import { assignParaIds } from './paraIds.mjs';
26
27
  /**
27
28
  * A subset of Office JS `Word.Body` over any container with block-level content: the main
28
29
  * document's body, a header, a footer, a footnote, a cell or a content control. A view: the
@@ -302,7 +303,7 @@ export class Body {
302
303
  const { text } = storyLayout(this.content, (el, items) => {
303
304
  const p = new Paragraph(el, items, this);
304
305
  return view === 'original' ? p.getText({ view }) : p.text;
305
- }, view === 'original' ? (p) => { var _a, _b; return ((_b = (_a = p.pPr) === null || _a === void 0 ? void 0 : _a.rPr) === null || _b === void 0 ? void 0 : _b.ins) === undefined; } : undefined);
306
+ }, view === 'original' ? shownInOriginalView : undefined);
306
307
  // the last paragraph's mark is not written
307
308
  return text.endsWith('\r') ? text.slice(0, -1) : text;
308
309
  }
@@ -420,8 +421,7 @@ export class Body {
420
421
  for (const el of elements) {
421
422
  linkParents(el, owner);
422
423
  const tn = typeNameOf(el);
423
- if (tn === 'org_docx4j_wml.P')
424
- this.assignParaId(el.value);
424
+ assignParaIds(this.container, [el]); // whatever it holds: a table's rows and cells, a control's paragraphs
425
425
  // everything it holds is an insertion: the runs in its links and inline controls, the rows and
426
426
  // nested tables of a table, a block control's content and the control itself (CR-002 section 37)
427
427
  if (tracker)
@@ -475,9 +475,7 @@ export class Body {
475
475
  keepCellMarkLast(new Paragraph(end.element, content, this), content);
476
476
  return;
477
477
  }
478
- const appended = endWithParagraph(cell);
479
- if (appended)
480
- this.assignParaId(appended);
478
+ endWithParagraph(cell);
481
479
  }
482
480
  /** The package's DOM preprocessor (the MCE one), for fragments and incoming packages. */
483
481
  preprocessor() {
@@ -1055,16 +1053,7 @@ export class Body {
1055
1053
  * @internal a paragraph split (CR-014 phase 2) gives its new first half one.
1056
1054
  */
1057
1055
  assignParaId(p) {
1058
- if (p.paraId)
1059
- return;
1060
- const paragraphs = this.paragraphsIn('every');
1061
- if (!paragraphs.some((q) => q.paraId !== undefined))
1062
- return;
1063
- let id;
1064
- do {
1065
- id = Math.floor(Math.random() * 0x7fffffff).toString(16).toUpperCase().padStart(8, '0');
1066
- } while (paragraphs.some((q) => q.paraId === id));
1067
- p.paraId = id;
1056
+ assignParaIds(this.container, [p]);
1068
1057
  }
1069
1058
  // --- comments (CR-002 phase G) ---
1070
1059
  /**
@@ -36,8 +36,8 @@ export declare class Comment {
36
36
  /**
37
37
  * When the comment was made, as Word means it (CR-002 section 29, the revision dates' rule): its
38
38
  * `w16cex:dateUtc` when the document has one for it, which is UTC; else `w:date`, which Word writes
39
- * on the author's local wall clock whatever its `Z` says, read as local time. Undefined when the
40
- * comment carries neither.
39
+ * on the author's local wall clock whatever its `Z` says, read as local time in the package's
40
+ * `dateTimeZone` (CR-018), else the runtime's. Undefined when the comment carries neither.
41
41
  */
42
42
  get creationDate(): Date | undefined;
43
43
  /** The comment's paragraphs as a `Body` (extension: the same content API as the document's). */
@@ -10,7 +10,7 @@ import { Paragraph } from './Paragraph.mjs';
10
10
  import { Range } from './Range.mjs';
11
11
  import { runOf, paragraphOf, typeNameOf, selectedBranchOf, BRANCH_TYPES } from './tree.mjs';
12
12
  import { storyLayout } from './story.mjs';
13
- import { revisionDateOf, wordCalendarOf, copyRPr } from './tracking.mjs';
13
+ import { revisionDateOf, wordCalendarOf, nowToTheMinute, copyRPr } from './tracking.mjs';
14
14
  import { relationshipIdsIn, queueRelationshipRemovals } from './relationships.mjs';
15
15
  import { COMMENT_REFERENCE_STYLE, COMMENT_TEXT_STYLE, commentExOf, commentIdsOf, commentPartsAccess, commentParaId, initialsOf, isDone, markersOf, markersOfParagraph, nextCommentId, paraIdTaken, randomHexId, removeMarkers, setCommentApi, } from './comments.mjs';
16
16
  /**
@@ -56,8 +56,8 @@ export class Comment {
56
56
  /**
57
57
  * When the comment was made, as Word means it (CR-002 section 29, the revision dates' rule): its
58
58
  * `w16cex:dateUtc` when the document has one for it, which is UTC; else `w:date`, which Word writes
59
- * on the author's local wall clock whatever its `Z` says, read as local time. Undefined when the
60
- * comment carries neither.
59
+ * on the author's local wall clock whatever its `Z` says, read as local time in the package's
60
+ * `dateTimeZone` (CR-018), else the runtime's. Undefined when the comment carries neither.
61
61
  */
62
62
  get creationDate() {
63
63
  var _a;
@@ -67,7 +67,7 @@ export class Comment {
67
67
  if (utc)
68
68
  return utc;
69
69
  }
70
- return revisionDateOf({ date: this.element.date });
70
+ return revisionDateOf({ date: this.element.date }, zoneOf(this.body.package_));
71
71
  }
72
72
  /** The comment's paragraphs as a `Body` (extension: the same content API as the document's). */
73
73
  get commentBody() {
@@ -551,13 +551,14 @@ function addComment(parts, body, id, paragraphs, parent, options) {
551
551
  var _a, _b, _c, _d, _e, _f;
552
552
  var _g, _h;
553
553
  const author = (_a = options === null || options === void 0 ? void 0 : options.author) !== null && _a !== void 0 ? _a : parts.author;
554
- // one instant for w:date (the local wall clock, as Word writes it) and w16cex:dateUtc (UTC)
555
- const made = (_b = options === null || options === void 0 ? void 0 : options.date) !== null && _b !== void 0 ? _b : new Date();
554
+ // one instant for w:date (the local wall clock in the package's zone, as Word writes it) and w16cex:dateUtc (UTC);
555
+ // a new comment is stamped to the minute, as a revision is and as Word stamps (CR-018, the date rule's point 5)
556
+ const made = (_b = options === null || options === void 0 ? void 0 : options.date) !== null && _b !== void 0 ? _b : nowToTheMinute();
556
557
  const paraId = randomHexId((candidate) => paraIdTaken(parts, body.container, candidate));
557
558
  paragraphs[0].value.paraId = paraId;
558
559
  const comment = wmlFactory.createCommentsComment({
559
560
  id, author: author.name, initials: (_c = options === null || options === void 0 ? void 0 : options.initials) !== null && _c !== void 0 ? _c : initialsOf(author),
560
- date: wordCalendarOf(made),
561
+ date: wordCalendarOf(made, zoneOf(body.package_)),
561
562
  content: paragraphs,
562
563
  });
563
564
  const comments = ((_d = (_g = parts.comments).comment) !== null && _d !== void 0 ? _d : (_g.comment = []));
@@ -797,3 +798,7 @@ function unique(ids) {
797
798
  return ids.filter((id) => (seen.has(id) ? false : (seen.add(id), true)));
798
799
  }
799
800
  setCommentApi({ commentsOf, insertComment });
801
+ /** The package's `dateTimeZone` (CR-018), read duck-typed since the package module cannot be imported here. */
802
+ function zoneOf(pkg) {
803
+ return pkg === null || pkg === void 0 ? void 0 : pkg.dateTimeZone;
804
+ }
@@ -296,7 +296,7 @@ export declare class ContentControl {
296
296
  get inBranch(): boolean;
297
297
  /** Refuses a write to a control in a branch (CR-013 D4). Internal: the control's mutators, and its kinds', call it first. */
298
298
  assertWritable(): void;
299
- /** The table a row-level or cell-level control belongs to. */
299
+ /** The table a row-level or cell-level control belongs to, through the row-level controls around it, nested to any depth. */
300
300
  private ancestorTable;
301
301
  }
302
302
  /**
@@ -19,6 +19,7 @@ import { sdtProperty, sdtKindOf } from '@docx4j/generated-objects-ts/builders/wm
19
19
  import { typeNameOf, childrenOf, runItemsOf, runsOf, linkParents, runOf, SDT_TYPES, ALTERNATE_CONTENT, BLOCK_LEVEL_TYPES, branchListsOf, inBranch, assertOutsideBranch } from './tree.mjs';
20
20
  import { Range } from './Range.mjs';
21
21
  import { Table } from './Table.mjs';
22
+ import { assignParaIds } from './paraIds.mjs';
22
23
  /** The namespaces of the Word 2010 and 2012 content-control properties. */
23
24
  export const W14_NS = 'http://schemas.microsoft.com/office/word/2010/wordml';
24
25
  export const W15_NS = 'http://schemas.microsoft.com/office/word/2012/wordml';
@@ -223,6 +224,7 @@ export class ContentControl {
223
224
  const content = ((_a = (_b = this.sdt.sdtContent).content) !== null && _a !== void 0 ? _a : (_b.content = []));
224
225
  content.push(p);
225
226
  linkParents(p, this.sdt.sdtContent);
227
+ assignParaIds(this.sdt.sdtContent, [p]);
226
228
  return body.paragraphs[0];
227
229
  }
228
230
  /**
@@ -434,6 +436,7 @@ export class ContentControl {
434
436
  const p = el.p({ ...(pPr ? { pPr: deepCopy(pPr) } : {}), content: runs });
435
437
  content.splice(at++, 0, p);
436
438
  linkParents(p, this.sdt.sdtContent);
439
+ assignParaIds(this.sdt.sdtContent, [p]);
437
440
  }
438
441
  }
439
442
  insertTextInto(text, location) {
@@ -908,6 +911,7 @@ export class ContentControl {
908
911
  const p = paragraphElementOf(runs);
909
912
  content.push(p);
910
913
  linkParents(p, sdt.sdtContent);
914
+ assignParaIds(sdt.sdtContent, [p]);
911
915
  }
912
916
  }
913
917
  else {
@@ -925,6 +929,7 @@ export class ContentControl {
925
929
  const p = paragraphElementOf(runs);
926
930
  content.push(p);
927
931
  linkParents(p, sdt.sdtContent);
932
+ assignParaIds(sdt.sdtContent, [p]);
928
933
  }
929
934
  const others = blocks.filter((e) => e !== paragraph);
930
935
  if (others.length > 0)
@@ -962,8 +967,7 @@ export class ContentControl {
962
967
  */
963
968
  syncBoundNode() {
964
969
  try {
965
- if (this.xmlMapping.isMapped)
966
- updateFromControl(this);
970
+ updateFromControl(this);
967
971
  }
968
972
  catch {
969
973
  // the part is not parsed, or the engine is not ready: leave it to updateFromContentControls()
@@ -995,11 +999,11 @@ export class ContentControl {
995
999
  assertWritable() {
996
1000
  assertOutsideBranch(this.element.value, 'ContentControl');
997
1001
  }
998
- /** The table a row-level or cell-level control belongs to. */
1002
+ /** The table a row-level or cell-level control belongs to, through the row-level controls around it, nested to any depth. */
999
1003
  ancestorTable() {
1000
1004
  var _a;
1001
1005
  let current = this.element.value.PARENT;
1002
- for (let guard = 0; current && guard < 8; guard++) {
1006
+ for (let guard = 0; current && guard < 256; guard++) {
1003
1007
  if (typeNameOf(current) === 'org_docx4j_wml.Tbl') {
1004
1008
  const tbl = current;
1005
1009
  const container = childrenOf(((_a = tbl.PARENT) !== null && _a !== void 0 ? _a : {}));
@@ -108,7 +108,10 @@ export declare class Font {
108
108
  */
109
109
  get name(): string;
110
110
  set name(v: string);
111
- /** Size in points (w:sz is half-points); 0 only in a direct-formatting view with no w:sz; `null` where the runs differ. */
111
+ /**
112
+ * Size in points (w:sz is half-points); 0 only in a direct-formatting view with no w:sz; `null` where the runs differ. A
113
+ * size written is held to the range Word 365 stores w:sz in, 0 to 32767.5 pt (CR-002 section 65): outside it, `InvalidArgument`.
114
+ */
112
115
  get size(): number;
113
116
  set size(v: number);
114
117
  /**
@@ -1,4 +1,5 @@
1
1
  import { applyRunOptions, readRunOptions } from '@docx4j/generated-objects-ts/builders/wml';
2
+ import { withinWord, WORD_STORAGE } from './wordRange.mjs';
2
3
  import { WordColors } from '../color/WordColors.mjs';
3
4
  /** A paragraph mark's run properties as a `Font` reads them: `w:pPr/w:rPr` without the mark's own revisions. */
4
5
  export function markHolderOf(p) {
@@ -134,9 +135,12 @@ export class Font {
134
135
  return all.length > 0 && all.every((n) => n === all[0]) ? all[0] : '';
135
136
  }
136
137
  set name(v) { this.apply({ name: v }); }
137
- /** Size in points (w:sz is half-points); 0 only in a direct-formatting view with no w:sz; `null` where the runs differ. */
138
+ /**
139
+ * Size in points (w:sz is half-points); 0 only in a direct-formatting view with no w:sz; `null` where the runs differ. A
140
+ * size written is held to the range Word 365 stores w:sz in, 0 to 32767.5 pt (CR-002 section 65): outside it, `InvalidArgument`.
141
+ */
138
142
  get size() { return this.value('size'); }
139
- set size(v) { this.apply({ size: v }); }
143
+ set size(v) { withinWord('Font.size', v, WORD_STORAGE.sz); this.apply({ size: v }); }
140
144
  /**
141
145
  * '#RRGGBB': in the effective view the colour Word draws, so a theme colour (`w:themeColor`, with its tint or shade)
142
146
  * through the document's theme, as Office JS reads it (check 53; CR-008 phase 2), and `#000000` for automatic; in
@@ -164,9 +164,12 @@ export declare class List {
164
164
  */
165
165
  setLevelBullet(level: number, listBullet: ListBullet, charCode?: number, fontName?: string): void;
166
166
  /**
167
- * Office JS `list.setLevelIndents(level, textIndent, bulletNumberPictureIndent)`, both in
168
- * points: the level's `w:ind/@w:left` is where the text sits and the label's position is the
169
- * hanging indent from it (or `w:firstLine` where the label sits to the right of the text).
167
+ * Office JS `list.setLevelIndents(level, textIndent, bulletNumberPictureIndent)`, both in points: the level's
168
+ * `w:ind/@w:left` is the text indent, and the label's indent is relative to it, "the same as paragraph first line
169
+ * indent": a first-line indent, or a hanging indent for a negative (check 71 case 86: Word wrote (-1, 0) as
170
+ * `w:left="-20" w:firstLine="0"`; until CR-002 section 65.5 it was taken as the label's absolute position).
171
+ * Each is held to the range Word stores it in (section 65); the text indent to Word's own setter's limit, short of
172
+ * 1584 pt either way (check 71b, section 65.9), the label's indent to its storage, unmeasured by Word's setter.
170
173
  */
171
174
  setLevelIndents(level: number, textIndent: number, bulletNumberPictureIndent: number): void;
172
175
  /** Office JS `list.setLevelAlignment(level, alignment)`: the level's `w:lvlJc`. */
@@ -7,6 +7,7 @@ import { NumberingState, storyKindOf } from '../listnumbering/state.mjs';
7
7
  import { LEVELS } from '../listnumbering/definitions.mjs';
8
8
  import { isElement, linkParents, selectedBranchOf, ALTERNATE_CONTENT } from './tree.mjs';
9
9
  import { Font } from './Font.mjs';
10
+ import { withinWord, WORD_STORAGE } from './wordRange.mjs';
10
11
  function packageOf(body) {
11
12
  const pkg = body.package_;
12
13
  return typeof (pkg === null || pkg === void 0 ? void 0 : pkg.getMainDocumentPart) === 'function' ? pkg : undefined;
@@ -350,24 +351,30 @@ export class List {
350
351
  this.written();
351
352
  }
352
353
  /**
353
- * Office JS `list.setLevelIndents(level, textIndent, bulletNumberPictureIndent)`, both in
354
- * points: the level's `w:ind/@w:left` is where the text sits and the label's position is the
355
- * hanging indent from it (or `w:firstLine` where the label sits to the right of the text).
354
+ * Office JS `list.setLevelIndents(level, textIndent, bulletNumberPictureIndent)`, both in points: the level's
355
+ * `w:ind/@w:left` is the text indent, and the label's indent is relative to it, "the same as paragraph first line
356
+ * indent": a first-line indent, or a hanging indent for a negative (check 71 case 86: Word wrote (-1, 0) as
357
+ * `w:left="-20" w:firstLine="0"`; until CR-002 section 65.5 it was taken as the label's absolute position).
358
+ * Each is held to the range Word stores it in (section 65); the text indent to Word's own setter's limit, short of
359
+ * 1584 pt either way (check 71b, section 65.9), the label's indent to its storage, unmeasured by Word's setter.
356
360
  */
357
361
  setLevelIndents(level, textIndent, bulletNumberPictureIndent) {
358
362
  var _a, _b;
363
+ // within the ranges Word 365 stores the level's w:ind in (CR-002 section 65), before anything changes
364
+ const left = withinWord('List.setLevelIndents (textIndent)', textIndent, WORD_STORAGE.lvlIndLeft);
365
+ const label = bulletNumberPictureIndent < 0
366
+ ? withinWord('List.setLevelIndents (a hanging bulletNumberPictureIndent)', -bulletNumberPictureIndent, WORD_STORAGE.indHanging)
367
+ : withinWord('List.setLevelIndents (bulletNumberPictureIndent)', bulletNumberPictureIndent, WORD_STORAGE.indFirstLine);
359
368
  const lvl = this.writableLvl(level);
360
369
  const pPr = ((_a = lvl.pPr) !== null && _a !== void 0 ? _a : (lvl.pPr = { TYPE_NAME: 'org_docx4j_wml.PPr' }));
361
370
  const ind = ((_b = pPr.ind) !== null && _b !== void 0 ? _b : (pPr.ind = f.createPPrBaseInd({})));
362
- const left = Math.round(textIndent * TWIPS_PER_POINT);
363
- const label = Math.round(bulletNumberPictureIndent * TWIPS_PER_POINT);
364
371
  ind.left = left;
365
- if (label <= left) {
366
- ind.hanging = left - label;
372
+ if (bulletNumberPictureIndent < 0) {
373
+ ind.hanging = label;
367
374
  delete ind.firstLine;
368
375
  }
369
376
  else {
370
- ind.firstLine = label - left;
377
+ ind.firstLine = label;
371
378
  delete ind.hanging;
372
379
  }
373
380
  linkParents(pPr, lvl);
@@ -142,7 +142,11 @@ export declare class Paragraph {
142
142
  * hold for any value. Undefined without a resolver, where the value is written as asked.
143
143
  */
144
144
  private inheritedAlignment;
145
- /** Indents and spacing in points, as Office JS; the effective values (CR-001 Phase B step 2). */
145
+ /**
146
+ * Indents and spacing in points, as Office JS; the effective values (CR-001 Phase B step 2). A value written is held to
147
+ * the range Word 365 stores its attribute in (`withinWord`, CR-002 section 65): outside it, `InvalidArgument`, before
148
+ * anything changes.
149
+ */
146
150
  get leftIndent(): number;
147
151
  set leftIndent(pt: number);
148
152
  get rightIndent(): number;
@@ -156,6 +160,11 @@ export declare class Paragraph {
156
160
  set spaceAfter(pt: number);
157
161
  /** Line spacing in points: w:line/240 lines of 12pt when the rule is auto, else w:line twips; 0 when not set. */
158
162
  get lineSpacing(): number;
163
+ /**
164
+ * Writes `w:line` as 20 × points under `w:lineRule="auto"`, as Word 365's own setter does (check 71b: 0.75 pt as
165
+ * `w:line="15" w:lineRule="auto"`; Office JS: "in the Word UI, this value is divided by 12", so 12 pt is single spacing),
166
+ * within Word's own limits, 0.75 to 1584 pt (CR-002 section 65.9). Until check 71b it wrote an exact rule.
167
+ */
159
168
  set lineSpacing(pt: number);
160
169
  /** w:outlineLvl + 1 (1 to 9); 10 for body text, as Office JS. A heading style supplies it. */
161
170
  get outlineLevel(): number;
@@ -242,7 +251,8 @@ export declare class Paragraph {
242
251
  /**
243
252
  * The character Office JS gives for this paragraph's mark at the end of its 'Whole' range (check 48):
244
253
  * `\t` for the last paragraph of a table cell, the cell's end; nothing for a mark tracked as deleted, which
245
- * Word's default view doesn't show (CR-012 section 19, check 58); and `\r` for any other.
254
+ * Word's default view doesn't show (CR-012 section 19, check 58), or as moved from, as the paragraph's runs read
255
+ * (CR-002 section 64); and `\r` for any other.
246
256
  */
247
257
  get markText(): string;
248
258
  /**
@@ -3,6 +3,8 @@ import { Docx4JException } from '../../opc/exceptions.mjs';
3
3
  import { NotSupportedError } from '../../office-js/errors.mjs';
4
4
  import { t as textItem, br as breakItem } from '@docx4j/generated-objects-ts/builders/wml';
5
5
  import { segmentsOf, runsOf, runItemsOf, inShowingPlaceholder, linkParents, typeNameOf, W_NS, runOf, paragraphOf, revisionKindOf, objectInSpan, WHOLE, isAlternateContent, selectedBranchOf, inBranch, assertOutsideBranch } from './tree.mjs';
6
+ import { shownInDefaultView } from './story.mjs';
7
+ import { withinWord, WORD_STORAGE } from './wordRange.mjs';
6
8
  import { relationshipIdsIn, queueRelationshipRemovals } from './relationships.mjs';
7
9
  function withRPr(run, rPr) {
8
10
  if (rPr)
@@ -229,36 +231,54 @@ export class Paragraph {
229
231
  // in a table cell what is inherited includes the table style's (CR-007)
230
232
  return alignmentOf(resolver.getEffectivePPr(rest, resolver.cellContextOf(this.p)), true);
231
233
  }
232
- /** Indents and spacing in points, as Office JS; the effective values (CR-001 Phase B step 2). */
234
+ /**
235
+ * Indents and spacing in points, as Office JS; the effective values (CR-001 Phase B step 2). A value written is held to
236
+ * the range Word 365 stores its attribute in (`withinWord`, CR-002 section 65): outside it, `InvalidArgument`, before
237
+ * anything changes.
238
+ */
233
239
  get leftIndent() { var _a, _b; return ((_b = (_a = this.effectivePPr.ind) === null || _a === void 0 ? void 0 : _a.left) !== null && _b !== void 0 ? _b : 0) / TWIPS_PER_POINT; }
234
- set leftIndent(pt) { this.ind().left = Math.round(pt * TWIPS_PER_POINT); this.settleFormatting(); }
240
+ set leftIndent(pt) { const v = withinWord('Paragraph.leftIndent', pt, WORD_STORAGE.indLeft); this.ind().left = v; this.settleFormatting(); }
235
241
  get rightIndent() { var _a, _b; return ((_b = (_a = this.effectivePPr.ind) === null || _a === void 0 ? void 0 : _a.right) !== null && _b !== void 0 ? _b : 0) / TWIPS_PER_POINT; }
236
- set rightIndent(pt) { this.ind().right = Math.round(pt * TWIPS_PER_POINT); this.settleFormatting(); }
242
+ set rightIndent(pt) { const v = withinWord('Paragraph.rightIndent', pt, WORD_STORAGE.indRight); this.ind().right = v; this.settleFormatting(); }
237
243
  /** First-line indent; negative for a hanging indent, as Office JS. */
238
244
  get firstLineIndent() {
239
245
  return firstLineIndentOf(this.effectivePPr);
240
246
  }
241
247
  set firstLineIndent(pt) {
248
+ const v = pt < 0
249
+ ? withinWord('Paragraph.firstLineIndent (a hanging indent)', -pt, WORD_STORAGE.indHanging)
250
+ : withinWord('Paragraph.firstLineIndent', pt, WORD_STORAGE.indFirstLine);
242
251
  const ind = this.ind();
243
252
  if (pt < 0) {
244
- ind.hanging = Math.round(-pt * TWIPS_PER_POINT);
253
+ ind.hanging = v;
245
254
  delete ind.firstLine;
246
255
  }
247
256
  else {
248
- ind.firstLine = Math.round(pt * TWIPS_PER_POINT);
257
+ ind.firstLine = v;
249
258
  delete ind.hanging;
250
259
  }
251
260
  this.settleFormatting();
252
261
  }
253
262
  get spaceBefore() { var _a, _b; return ((_b = (_a = this.effectivePPr.spacing) === null || _a === void 0 ? void 0 : _a.before) !== null && _b !== void 0 ? _b : 0) / TWIPS_PER_POINT; }
254
- set spaceBefore(pt) { this.spacing().before = Math.round(pt * TWIPS_PER_POINT); this.settleFormatting(); }
263
+ set spaceBefore(pt) { const v = withinWord('Paragraph.spaceBefore', pt, WORD_STORAGE.spacingBefore); this.spacing().before = v; this.settleFormatting(); }
255
264
  get spaceAfter() { var _a, _b; return ((_b = (_a = this.effectivePPr.spacing) === null || _a === void 0 ? void 0 : _a.after) !== null && _b !== void 0 ? _b : 0) / TWIPS_PER_POINT; }
256
- set spaceAfter(pt) { this.spacing().after = Math.round(pt * TWIPS_PER_POINT); this.settleFormatting(); }
265
+ set spaceAfter(pt) { const v = withinWord('Paragraph.spaceAfter', pt, WORD_STORAGE.spacingAfter); this.spacing().after = v; this.settleFormatting(); }
257
266
  /** Line spacing in points: w:line/240 lines of 12pt when the rule is auto, else w:line twips; 0 when not set. */
258
267
  get lineSpacing() {
259
268
  return lineSpacingOf(this.effectivePPr);
260
269
  }
261
- set lineSpacing(pt) { const s = this.spacing(); s.line = Math.round(pt * TWIPS_PER_POINT); s.lineRule = 'exact'; this.settleFormatting(); }
270
+ /**
271
+ * Writes `w:line` as 20 × points under `w:lineRule="auto"`, as Word 365's own setter does (check 71b: 0.75 pt as
272
+ * `w:line="15" w:lineRule="auto"`; Office JS: "in the Word UI, this value is divided by 12", so 12 pt is single spacing),
273
+ * within Word's own limits, 0.75 to 1584 pt (CR-002 section 65.9). Until check 71b it wrote an exact rule.
274
+ */
275
+ set lineSpacing(pt) {
276
+ const v = withinWord('Paragraph.lineSpacing', pt, WORD_STORAGE.spacingLineAuto);
277
+ const s = this.spacing();
278
+ s.line = v;
279
+ s.lineRule = 'auto';
280
+ this.settleFormatting();
281
+ }
262
282
  /** w:outlineLvl + 1 (1 to 9); 10 for body text, as Office JS. A heading style supplies it. */
263
283
  get outlineLevel() { return outlineLevelOf(this.effectivePPr); }
264
284
  set outlineLevel(level) { const pPr = this.pPr(); if (level >= 10 || level < 1)
@@ -528,13 +548,13 @@ export class Paragraph {
528
548
  /**
529
549
  * The character Office JS gives for this paragraph's mark at the end of its 'Whole' range (check 48):
530
550
  * `\t` for the last paragraph of a table cell, the cell's end; nothing for a mark tracked as deleted, which
531
- * Word's default view doesn't show (CR-012 section 19, check 58); and `\r` for any other.
551
+ * Word's default view doesn't show (CR-012 section 19, check 58), or as moved from, as the paragraph's runs read
552
+ * (CR-002 section 64); and `\r` for any other.
532
553
  */
533
554
  get markText() {
534
- var _a, _b;
535
555
  if (lastInCell(this.p))
536
556
  return '\t';
537
- return ((_b = (_a = this.p.pPr) === null || _a === void 0 ? void 0 : _a.rPr) === null || _b === void 0 ? void 0 : _b.del) !== undefined ? '' : '\r';
557
+ return shownInDefaultView(this.p) ? '\r' : '';
538
558
  }
539
559
  /**
540
560
  * Removes the paragraph from its container. While the package tracks changes, the content
@@ -5,6 +5,8 @@ import { typeNameOf, childrenOf, linkParents, rowsOf, cellsOf, inBranch, assertO
5
5
  import { builtInOf, idOfBuiltIn, styleNameOf, styleIdOf } from './styles.mjs';
6
6
  import { trackInsertedBlocks } from './tracking.mjs';
7
7
  import { insertGridColumns, deleteGridColumns, gridRangeOf, textWidthTwips, widthTypeOf, layoutModeOf } from './tableColumns.mjs';
8
+ import { withinWord, WORD_STORAGE } from './wordRange.mjs';
9
+ import { assignParaIds } from './paraIds.mjs';
8
10
  /** The default table width in twips (A4 with 2.54 cm margins), as the objects package's `tbl` builder uses. */
9
11
  const DEFAULT_WIDTH = 9026;
10
12
  const TWIPS_PER_POINT = 20;
@@ -138,6 +140,7 @@ export class Table {
138
140
  container.splice(at, 0, ...added);
139
141
  for (const row of added)
140
142
  linkParents(row, this.tbl);
143
+ assignParaIds(this.tbl, added);
141
144
  markRowsInserted(this.changeTracker, added);
142
145
  return added.map((element) => new TableRow(element, container, this));
143
146
  }
@@ -176,6 +179,7 @@ export class Table {
176
179
  this.assertWritable();
177
180
  const at = location === 'Start' ? 0 : this.columnWidths().length;
178
181
  const inserted = insertGridColumns(this.tbl, this.textWidth(), at, columnCount, values, this.changeTracker);
182
+ assignParaIds(this.tbl, inserted.cells);
179
183
  return this.cellViewsOf(inserted.cells);
180
184
  }
181
185
  /**
@@ -328,6 +332,7 @@ export class TableRow {
328
332
  const owner = (_a = ownerOfArray(this.container, this.parentTable.tbl)) !== null && _a !== void 0 ? _a : this.parentTable.tbl;
329
333
  for (const row of added)
330
334
  linkParents(row, owner);
335
+ assignParaIds(this.parentTable.tbl, added);
331
336
  markRowsInserted(this.parentTable.changeTracker, added);
332
337
  return added.map((element) => new TableRow(element, this.container, this.parentTable));
333
338
  }
@@ -434,16 +439,14 @@ export class TableCell {
434
439
  var _a, _b;
435
440
  var _c, _d;
436
441
  this.assertWritable();
437
- const twips = Math.round(points * TWIPS_PER_POINT);
442
+ // within the range Word 365 stores w:tcW/@w:w in, a percentage's fiftieths too (CR-002 section 65), before anything changes
443
+ const pct = widthTypeOf(this.tc, this.parentTable.tbl) === 'pct';
444
+ const w = pct
445
+ ? withinWord('TableCell.width', points, WORD_STORAGE.tcWPct, Math.round((Math.round(points * TWIPS_PER_POINT) * 5000) / this.parentTable.textWidth()))
446
+ : withinWord('TableCell.width', points, WORD_STORAGE.tcWDxa);
438
447
  const tcW = ((_b = (_d = ((_a = (_c = this.tc).tcPr) !== null && _a !== void 0 ? _a : (_c.tcPr = {}))).tcW) !== null && _b !== void 0 ? _b : (_d.tcW = {}));
439
- if (widthTypeOf(this.tc, this.parentTable.tbl) === 'pct') {
440
- tcW.w = Math.round((twips * 5000) / this.parentTable.textWidth());
441
- tcW.type = 'pct';
442
- }
443
- else {
444
- tcW.w = twips;
445
- tcW.type = 'dxa';
446
- }
448
+ tcW.w = w;
449
+ tcW.type = pct ? 'pct' : 'dxa';
447
450
  }
448
451
  /**
449
452
  * New columns before or after this cell (Office JS `TableCell.insertColumns`), the new cells
@@ -457,6 +460,7 @@ export class TableCell {
457
460
  throw new Docx4JException('This cell is not in its row');
458
461
  const table = this.parentTable;
459
462
  const inserted = insertGridColumns(table.tbl, table.textWidth(), location === 'Before' ? range.start : range.end, columnCount, values, table.changeTracker);
463
+ assignParaIds(table.tbl, inserted.cells);
460
464
  return table.cellViewsOf(inserted.cells);
461
465
  }
462
466
  /** Removes the grid columns this cell covers (Office JS `TableCell.deleteColumn`); tracked as `Table.deleteColumns` is. */
@@ -519,8 +523,8 @@ export function cellOf(value, parentBody) {
519
523
  }
520
524
  if (!tc)
521
525
  return undefined;
522
- // a cell-level content control sits between the cell and the row
523
- const tr = ancestorOf(tc, 'org_docx4j_wml.Tr', 4);
526
+ // cell-level content controls sit between the cell and the row, nested to any depth
527
+ const tr = ancestorOf(tc, 'org_docx4j_wml.Tr');
524
528
  if (!tr)
525
529
  return undefined;
526
530
  const tbl = ancestorTable(tr);
@@ -538,14 +542,20 @@ export function cellOf(value, parentBody) {
538
542
  const cell = cellsOf(tr, 'read').find((c) => c.element.value === tc);
539
543
  return cell ? new TableCell(cell.element, cell.container, rowView) : undefined;
540
544
  }
541
- /** The w:tbl a row is in, through a row-level content control if there is one. */
545
+ /**
546
+ * The w:tbl a row is in, through the row-level content controls around it, nested to any depth: a repeating section's
547
+ * item inside the section puts four holders between the row and its table (the editor's finding on `invoice2013.docx`, 2026-10-26; CR-002 section 64).
548
+ */
542
549
  function ancestorTable(tr) {
543
- return ancestorOf(tr, 'org_docx4j_wml.Tbl', 4);
550
+ return ancestorOf(tr, 'org_docx4j_wml.Tbl');
544
551
  }
545
- /** The nearest ancestor of a type, at most `depth` PARENT steps up (the sdt wrappers are steps). */
546
- function ancestorOf(value, typeName, depth) {
552
+ /**
553
+ * The nearest ancestor of a type. Only holders stand between a cell and its row, or a row and its table (content
554
+ * controls, custom XML, a kept `mc:AlternateContent`'s branch), so the nearest is the one; the guard only stops a cycle.
555
+ */
556
+ function ancestorOf(value, typeName) {
547
557
  let current = value.PARENT;
548
- for (let guard = 0; current && guard < depth; guard++) {
558
+ for (let guard = 0; current && guard < 256; guard++) {
549
559
  if (typeNameOf(current) === typeName)
550
560
  return current;
551
561
  current = current.PARENT;
@@ -195,8 +195,8 @@ export declare class TrackedChange {
195
195
  get author(): string;
196
196
  /**
197
197
  * When the change was made: `w16du:dateUtc` if the markup has it, else `w:date` read as Word writes
198
- * it, local wall-clock time (`revisionDateOf`, CR-002 section 29); a group's is its first piece's,
199
- * as Office JS reports it.
198
+ * it, local wall-clock time in the package's `dateTimeZone`, else the runtime's (`revisionDateOf`,
199
+ * CR-002 section 29, CR-018); a group's is its first piece's, as Office JS reports it.
200
200
  */
201
201
  get date(): Date | undefined;
202
202
  /** The annotation id (`w:id`; an extension). */
@@ -46,11 +46,12 @@ export class TrackedChange {
46
46
  }
47
47
  /**
48
48
  * When the change was made: `w16du:dateUtc` if the markup has it, else `w:date` read as Word writes
49
- * it, local wall-clock time (`revisionDateOf`, CR-002 section 29); a group's is its first piece's,
50
- * as Office JS reports it.
49
+ * it, local wall-clock time in the package's `dateTimeZone`, else the runtime's (`revisionDateOf`,
50
+ * CR-002 section 29, CR-018); a group's is its first piece's, as Office JS reports it.
51
51
  */
52
52
  get date() {
53
- return revisionDateOf(this.target.value);
53
+ var _a;
54
+ return revisionDateOf(this.target.value, (_a = this.package_) === null || _a === void 0 ? void 0 : _a.dateTimeZone);
54
55
  }
55
56
  /** The annotation id (`w:id`; an extension). */
56
57
  get id() {
@@ -2071,6 +2072,8 @@ function tokensOfRunLevel(paragraph, items, out, listing) {
2071
2072
  var _a, _b, _c;
2072
2073
  for (let i = 0; i < items.length; i++) {
2073
2074
  const el = items[i];
2075
+ if (el.value === undefined)
2076
+ continue; // a DOM element a branch's wildcard keeps: no change in it to list (CR-026 section 4.8)
2074
2077
  // an inline control or custom XML element that is itself an insertion: a piece, then what is in it
2075
2078
  const inserted = holderChangeAt(items, i, paragraph);
2076
2079
  if (inserted) {