@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
@@ -1,8 +1,7 @@
1
1
  import { AlternativeFormatInputPart } from '../../parts/BinaryPart.mjs';
2
- import { Emulator } from '../listnumbering/Emulator.mjs';
3
2
  import { runItemsOf, selectedBranchOf, segmentsOf, hiddenRunsOf, SDT_TYPES } from '../content/tree.mjs';
4
3
  import { TextBlock, TextRun, TextRow, TextCell, TextField, TextNumbering, TextRevision, TextWarning, TextComment, TextImage, TextResult, } from './TextResult.mjs';
5
- import { calendarText } from './TextContext.mjs';
4
+ import { revisionDateText } from '../content/tracking.mjs';
6
5
  import { normalize } from './normalize.mjs';
7
6
  const W_NS = 'http://schemas.openxmlformats.org/wordprocessingml/2006/main';
8
7
  const R_NS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
@@ -146,8 +145,9 @@ function asciiFont(rPr) {
146
145
  var _a;
147
146
  return (_a = rPr === null || rPr === void 0 ? void 0 : rPr.rFonts) === null || _a === void 0 ? void 0 : _a.ascii;
148
147
  }
148
+ /** A revision with its author and its stamp as REQ-702 writes it: the author's local time, the offset where known (CR-012 section 23.7). */
149
149
  function revisionOf(tc, type) {
150
- return new TextRevision(type, tc.author, calendarText(tc.date));
150
+ return new TextRevision(type, tc.author, revisionDateText(tc.date, tc.dateUtc));
151
151
  }
152
152
  /**
153
153
  * Each item's place in `Paragraph.text` (CR-012 D2, section 4.4): the content API's own reader since phase 4
@@ -172,6 +172,8 @@ class FieldState {
172
172
  this.locked = false;
173
173
  /** A table of contents under `toc: false` (D12): nothing of it is read. */
174
174
  this.toc = false;
175
+ /** A SET field: its stored result is never shown (Word hides it; REQ-505, CR-012 section 26). */
176
+ this.hiddenResult = false;
175
177
  this.codeStart = 0;
176
178
  this.previousFloor = 0;
177
179
  }
@@ -185,6 +187,7 @@ class FieldState {
185
187
  f.computed = this.computed;
186
188
  f.link = this.link;
187
189
  f.toc = this.toc;
190
+ f.hiddenResult = this.hiddenResult;
188
191
  return f;
189
192
  }
190
193
  }
@@ -220,6 +223,8 @@ class Story {
220
223
  this.pending = [];
221
224
  this.tableDepth = 0;
222
225
  this.noteNumber = 0;
226
+ if (part)
227
+ x.storyParts.add(part);
223
228
  }
224
229
  /** The resolver the walk reads styles with, for `officeSpans`' hidden rule. */
225
230
  get resolver() {
@@ -268,6 +273,8 @@ export class Extractor {
268
273
  this.context = context;
269
274
  this.warnings = [];
270
275
  this.warned = new Set();
276
+ /** The parts this reading took a story from, for what the walk can't meet (`partWarningsUnmet`). */
277
+ this.storyParts = new Set();
271
278
  /** What every address this extraction makes starts with. */
272
279
  this.root = '';
273
280
  /** The run properties a paragraph style and character style give, by their ids. */
@@ -283,19 +290,39 @@ export class Extractor {
283
290
  }
284
291
  // --- the package ------------------------------------------------------------------------------
285
292
  extract() {
286
- var _a;
293
+ var _a, _b, _c, _d, _e, _f, _g;
287
294
  const out = [];
288
295
  const comments = new Map();
296
+ // a name the container held twice, the first copy read (REQ-206, CR-024): the package's, so every reading of it says so
297
+ for (const d of (_b = (_a = this.trees.pkg) === null || _a === void 0 ? void 0 : _a.duplicateEntries) !== null && _b !== void 0 ? _b : []) {
298
+ this.warn(new TextWarning(TextWarning.PACKAGE_DUPLICATE_ENTRY, undefined, undefined, undefined, d.entry, d.count));
299
+ }
300
+ // more than one officeDocument relationship, the last's target read (REQ-206's statement, CR-024 section 9)
301
+ const mainParts = (_c = this.trees.pkg) === null || _c === void 0 ? void 0 : _c.multipleMainParts;
302
+ if (mainParts)
303
+ this.warn(new TextWarning(TextWarning.PACKAGE_MULTIPLE_MAIN_PARTS, undefined, undefined, undefined, mainParts.partName, mainParts.count));
304
+ // an External main relationship dropped, this package's own repair (REQ-206's NOTE, CR-031), and a relationships part read
305
+ // by local name (CR-031 section 2.3): the load's, so every reading says so
306
+ const external = (_d = this.trees.pkg) === null || _d === void 0 ? void 0 : _d.externalMainPart;
307
+ if (external)
308
+ this.warn(new TextWarning(TextWarning.PACKAGE_EXTERNAL_MAIN_PART, undefined, undefined, undefined, external.partName, external.urls[0]));
309
+ for (const r of (_f = (_e = this.trees.pkg) === null || _e === void 0 ? void 0 : _e.relationshipsNamespaces) !== null && _f !== void 0 ? _f : []) {
310
+ this.warn(new TextWarning(TextWarning.PACKAGE_RELATIONSHIPS_NAMESPACE, undefined, undefined, undefined, r.partName, r.count));
311
+ }
289
312
  const metadata = this.metadata();
290
313
  const main = this.trees.main;
291
314
  const body = main === null || main === void 0 ? void 0 : main.document.body;
292
- if (!main || !body)
315
+ if (!main || !body) {
316
+ if (main)
317
+ this.storyParts.add(main.part);
318
+ this.partWarningsUnmet();
293
319
  return new TextResult(out, comments, this.warnings, metadata, this.options);
320
+ }
294
321
  // the main story, each text box after its anchor; sections recorded as they end
295
322
  const story = new Story(this, 'MAIN', `${this.root}body`, main.part);
296
323
  story.sections = [];
297
324
  const mainBlocks = [];
298
- this.blocks((_a = body.content) !== null && _a !== void 0 ? _a : [], `${this.root}body`, story, mainBlocks);
325
+ this.blocks((_g = body.content) !== null && _g !== void 0 ? _g : [], `${this.root}body`, story, mainBlocks);
299
326
  story.sections.push(body.sectPr);
300
327
  this.context.mainRead = true;
301
328
  const headers = this.options.includes.has('headers');
@@ -315,19 +342,35 @@ export class Extractor {
315
342
  // comments, rendered at their references (REQ-504)
316
343
  if (this.commentsIncluded())
317
344
  this.comments(comments);
345
+ this.partWarningsUnmet();
318
346
  return new TextResult(out, comments, this.warnings, metadata, this.options);
319
347
  }
320
- /** The result's metadata: `fields_update_on_open` and the document properties (REQ-801, REQ-515). */
348
+ /** The result's metadata: `fields_update_on_open`, `repaired` and the document properties (REQ-801, REQ-207, REQ-515). */
321
349
  metadata() {
322
- var _a;
323
- const metadata = { [TextResult.FIELDS_UPDATE_ON_OPEN]: this.fieldsUpdateOnOpen() };
324
- Object.assign(metadata, (_a = this.trees.properties) !== null && _a !== void 0 ? _a : {});
350
+ var _a, _b, _c;
351
+ const metadata = {
352
+ [TextResult.FIELDS_UPDATE_ON_OPEN]: this.fieldsUpdateOnOpen(),
353
+ [TextResult.REPAIRED]: (_b = (_a = this.trees.pkg) === null || _a === void 0 ? void 0 : _a.repaired) !== null && _b !== void 0 ? _b : 'none',
354
+ };
355
+ Object.assign(metadata, (_c = this.trees.properties) !== null && _c !== void 0 ? _c : {});
356
+ // a properties part read for the metadata written (REQ-515), where it could not be read (WD 0.76)
357
+ if (this.options.metadata)
358
+ for (const role of ['core', 'app', 'custom'])
359
+ this.consult(role);
325
360
  return metadata;
326
361
  }
362
+ /** `w:updateFields`, which every result's metadata carries: so a settings part that cannot be read is needed by every reading. */
327
363
  fieldsUpdateOnOpen() {
328
364
  var _a;
365
+ this.consult('settings');
329
366
  return on((_a = this.trees.settings) === null || _a === void 0 ? void 0 : _a.updateFields);
330
367
  }
368
+ /** A part the reading needs here: `part.not_read`, once, where it could not be read (REQ-801; CR-012 section 28). */
369
+ consult(role) {
370
+ const partName = this.trees.notRead.get(role);
371
+ if (partName !== undefined)
372
+ this.warn(new TextWarning(TextWarning.PART_NOT_READ, undefined, undefined, undefined, partName));
373
+ }
331
374
  commentsIncluded() {
332
375
  return this.view === 'markup' || this.options.comments;
333
376
  }
@@ -346,31 +389,35 @@ export class Extractor {
346
389
  const metadata = {};
347
390
  if (this.trees.pkg !== undefined)
348
391
  metadata[TextResult.FIELDS_UPDATE_ON_OPEN] = this.fieldsUpdateOnOpen();
392
+ this.partWarningsUnmet();
349
393
  return new TextResult(out, new Map(), this.warnings, metadata, this.options);
350
394
  }
351
395
  /** The notes of one kind, in the context's reference order (`Texts.of(notesPart)`). */
352
396
  extractNotes(type) {
353
397
  const out = [];
354
398
  this.notes(type, out);
399
+ this.partWarningsUnmet();
355
400
  return new TextResult(out, new Map(), this.warnings, { [TextResult.FIELDS_UPDATE_ON_OPEN]: this.fieldsUpdateOnOpen() }, this.options);
356
401
  }
357
402
  /** The comments (`Texts.of(commentsPart)`): what the view includes, in the comments part's order. */
358
403
  extractComments() {
359
404
  const comments = new Map();
360
405
  this.comments(comments);
406
+ this.partWarningsUnmet();
361
407
  return new TextResult([], comments, this.warnings, { [TextResult.FIELDS_UPDATE_ON_OPEN]: this.fieldsUpdateOnOpen() }, this.options);
362
408
  }
363
409
  // --- the glossary (REQ-516) -------------------------------------------------------------------
364
410
  glossary(out) {
365
- var _a, _b, _c;
411
+ var _a, _b, _c, _d;
412
+ this.storyRead((_a = this.trees.main) === null || _a === void 0 ? void 0 : _a.part.glossaryDocumentPart);
366
413
  const g = this.trees.glossary;
367
- const parts = (_b = (_a = g === null || g === void 0 ? void 0 : g.tree.docParts) === null || _a === void 0 ? void 0 : _a.docPart) !== null && _b !== void 0 ? _b : [];
414
+ const parts = (_c = (_b = g === null || g === void 0 ? void 0 : g.tree.docParts) === null || _b === void 0 ? void 0 : _b.docPart) !== null && _c !== void 0 ? _c : [];
368
415
  for (let i = 0; i < parts.length; i++) {
369
416
  const body = parts[i].docPartBody;
370
417
  if (!body)
371
418
  continue;
372
419
  const prefix = `${this.root}glossary:${i}`;
373
- this.blocks((_c = body.content) !== null && _c !== void 0 ? _c : [], prefix, new Story(this, 'GLOSSARY', prefix, g.part), out);
420
+ this.blocks((_d = body.content) !== null && _d !== void 0 ? _d : [], prefix, new Story(this, 'GLOSSARY', prefix, g.part), out);
374
421
  }
375
422
  }
376
423
  // --- block level ------------------------------------------------------------------------------
@@ -378,11 +425,15 @@ export class Extractor {
378
425
  blocks(items, prefix, story, sink, state = PLAIN) {
379
426
  if (!items)
380
427
  return;
428
+ const dropCap = {};
381
429
  for (let i = 0; i < items.length; i++)
382
- i = this.block(items, i, prefix, story, sink, state);
430
+ i = this.block(items, i, prefix, story, sink, state, dropCap);
383
431
  }
384
- /** The block at `items[i]` into `sink`, with the paragraphs a view joins to it; the index of the last item it took. */
385
- block(items, i, prefix, story, sink, state) {
432
+ /**
433
+ * The block at `items[i]` into `sink`, with the paragraphs a view joins to it; the index of the last item it took.
434
+ * `dropCap` is a drop cap's frame paragraph just read in the same container, for the paragraph next to take (REQ-521).
435
+ */
436
+ block(items, i, prefix, story, sink, state, dropCap = {}) {
386
437
  var _a, _b, _c;
387
438
  const item = items[i];
388
439
  if (this.removes(item))
@@ -390,6 +441,8 @@ export class Extractor {
390
441
  const v = unwrap(item);
391
442
  const address = `${prefix}/${i}`;
392
443
  const tn = typeOf(v);
444
+ if (tn !== P && !isMarker(item))
445
+ dropCap.block = undefined; // a table, a control, the end: left as it is
393
446
  if (tn === P) {
394
447
  const chain = [v];
395
448
  const addresses = [address];
@@ -411,9 +464,14 @@ export class Extractor {
411
464
  if ((_a = this.plan) === null || _a === void 0 ? void 0 : _a.joinsIntoTable(chain[chain.length - 1])) {
412
465
  // a deleted mark with a table next and text left: into the table's first cell (docx4j CR-043 section 17)
413
466
  this.pendingTableJoin = { chain, addresses };
467
+ dropCap.block = undefined;
414
468
  return j;
415
469
  }
416
- this.paragraph(chain, addresses, story, sink, state);
470
+ const taking = dropCap.block;
471
+ dropCap.block = undefined;
472
+ const block = this.paragraph(chain, addresses, story, sink, state, taking);
473
+ if (taking === undefined && block !== undefined && this.dropCapFrame(chain, block))
474
+ dropCap.block = block;
417
475
  return j;
418
476
  }
419
477
  if (tn === TBL) {
@@ -424,6 +482,7 @@ export class Extractor {
424
482
  this.pendingTableJoin = undefined;
425
483
  this.paragraph(chain, addresses, story, sink, state);
426
484
  }
485
+ dropCap.block = undefined;
427
486
  }
428
487
  else if (isSdt(v) && this.unwraps(item)) {
429
488
  // an inserted control rejected: its content in its place, its properties gone
@@ -454,7 +513,7 @@ export class Extractor {
454
513
  }
455
514
  else if (tn === AC) {
456
515
  const ac = v;
457
- this.compareBranches(ac, address);
516
+ this.compareBranches(ac, address, story);
458
517
  this.blocks(selectedBranchOf(ac), address, story, sink, state);
459
518
  }
460
519
  else if (revisionHolder(item) !== undefined) {
@@ -532,15 +591,20 @@ export class Extractor {
532
591
  }
533
592
  return -1;
534
593
  }
535
- paragraph(chain, addresses, story, sink, state) {
594
+ /**
595
+ * A paragraph chain's block into the sink, returned; undefined where it makes none. A drop cap's frame paragraph read
596
+ * just before (`dropCap`; REQ-521) is taken in at its start.
597
+ */
598
+ paragraph(chain, addresses, story, sink, state, dropCap) {
536
599
  var _a, _b, _c, _d;
537
600
  const first = chain[0];
538
601
  const last = chain[chain.length - 1];
539
602
  const block = new TextBlock('PARAGRAPH', story.kind, addresses[0]);
603
+ this.consult('styles'); // every block is resolved through the part's defaults
540
604
  if (this.fieldsOnly) {
541
605
  for (let c = 0; c < chain.length; c++)
542
606
  this.runs(chain[c].content, new ParagraphState(block, chain[c], addresses[c], story), state);
543
- return;
607
+ return undefined;
544
608
  }
545
609
  if (chain.length > 1)
546
610
  block.joined = addresses.slice(1);
@@ -577,7 +641,7 @@ export class Extractor {
577
641
  block.runs.length = 0;
578
642
  this.flushIfOutsideTable(story, sink);
579
643
  this.endSection(last, story);
580
- return;
644
+ return undefined;
581
645
  }
582
646
  block.hidden = hiddenParagraph;
583
647
  if (!this.options.hidden) {
@@ -589,7 +653,7 @@ export class Extractor {
589
653
  // a table of contents' paragraph, under toc: false (D12): no line at all
590
654
  this.flushIfOutsideTable(story, sink);
591
655
  this.endSection(last, story);
592
- return;
656
+ return undefined;
593
657
  }
594
658
  // one count per paragraph: the label (list_labels) and the numbering's value come from it
595
659
  if (this.trees.pkg !== undefined && (this.options.listLabels || block.numbering !== undefined)) {
@@ -600,9 +664,78 @@ export class Extractor {
600
664
  block.numbering.value = counted.count;
601
665
  }
602
666
  block.section = (_d = (_c = story.sections) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0;
603
- sink.push(block);
667
+ if (dropCap === undefined || !this.joinDropCap(dropCap, block, story, sink))
668
+ sink.push(block);
604
669
  this.flushIfOutsideTable(story, sink);
605
670
  this.endSection(last, story);
671
+ return block;
672
+ }
673
+ /**
674
+ * Whether a paragraph just read is a drop cap's frame, for the paragraph next to take (REQ-521; CR-012 section 24.3):
675
+ * under `drop_caps: join`, one `w:p` whose `w:framePr/@w:dropCap` (its own, or its style's) is `drop` or `margin`, whose
676
+ * text is at most one word (no white space and no space character, U+00A0 included), and which ends no section.
677
+ */
678
+ dropCapFrame(chain, block) {
679
+ var _a, _b;
680
+ if (this.options.dropCaps !== 'join' || chain.length !== 1)
681
+ return false;
682
+ const p = chain[0];
683
+ if ((_a = p.pPr) === null || _a === void 0 ? void 0 : _a.sectPr)
684
+ return false;
685
+ // Java's Character.isWhitespace or isSpaceChar, docx4j's test
686
+ if (/[\t-\r\x1C-\x1F\p{Z}]/u.test(block.text))
687
+ return false;
688
+ let pPr = this.viewPPr(p);
689
+ if (this.resolver) {
690
+ try {
691
+ pPr = this.resolver.getEffectivePPr(pPr);
692
+ }
693
+ catch {
694
+ // the paragraph's own properties, as read
695
+ }
696
+ }
697
+ const dropCap = (_b = pPr === null || pPr === void 0 ? void 0 : pPr.framePr) === null || _b === void 0 ? void 0 : _b.dropCap;
698
+ return dropCap === 'drop' || dropCap === 'margin';
699
+ }
700
+ /**
701
+ * A drop cap's frame paragraph joined to the block after it (REQ-521): its runs and fields put at the block's start with
702
+ * no separator, the block (its address, its properties) in the frame's place in the sink, so that what the frame
703
+ * anchored still follows it; the warning `paragraph.drop_cap_joined` at the frame's address. The letter's run merges
704
+ * into the word's first run on docx4j's rule (the same kind, hidden and placeholder flags, revision and formatting; D6,
705
+ * Jason 2026-11-02), which replaces section 4.4's `officeOffset` contiguity rule at this one join, the two runs' text
706
+ * coming from two paragraphs' `Paragraph.text`: the merged run keeps the letter's source, and its `officeOffset` is
707
+ * undefined. False, and nothing done, where the frame is not in the sink.
708
+ */
709
+ joinDropCap(frame, block, story, sink) {
710
+ var _a;
711
+ const at = sink.lastIndexOf(frame);
712
+ if (at < 0)
713
+ return false;
714
+ const runs = [...frame.runs];
715
+ let first = 0;
716
+ if (runs.length > 0 && block.runs.length > 0) {
717
+ const left = runs[runs.length - 1];
718
+ const right = block.runs[0];
719
+ if (left.kind === 'TEXT' && right.kind === 'TEXT' && !left.math && !right.math && left.hidden === right.hidden
720
+ && left.placeholder === right.placeholder && sameRevision(left.revision, right.revision) && left.sameFormat(right)) {
721
+ const merged = new TextRun('TEXT', left.text + right.text, left.revision);
722
+ merged.hidden = left.hidden;
723
+ merged.placeholder = left.placeholder;
724
+ merged.copyFormat(left);
725
+ merged.source = left.source;
726
+ runs[runs.length - 1] = merged;
727
+ first = 1;
728
+ }
729
+ }
730
+ runs.push(...block.runs.slice(first));
731
+ block.runs.length = 0;
732
+ block.runs.push(...runs);
733
+ block.fields.unshift(...frame.fields);
734
+ block.revisions += frame.revisions;
735
+ block.hidden = block.hidden && frame.hidden;
736
+ sink[at] = block;
737
+ this.warn(new TextWarning(TextWarning.DROP_CAP_JOINED, frame.address, undefined, undefined, (_a = story.part) === null || _a === void 0 ? void 0 : _a.partName.name));
738
+ return true;
606
739
  }
607
740
  endSection(last, story) {
608
741
  var _a;
@@ -624,7 +757,10 @@ export class Extractor {
624
757
  }
625
758
  }
626
759
  // --- altChunk (REQ-513) -----------------------------------------------------------------------
627
- /** An `altChunk`: not expanded until CR-012 phase 5e, which raises `altchunk.not_expanded` with its content type. */
760
+ /**
761
+ * An `altChunk`: not expanded until CR-012 phase 5e, which raises `altchunk.not_expanded` naming the chunk's part, its
762
+ * selector (WD 0.47, CR-012 section 22.2 (a)), with its content type.
763
+ */
628
764
  altChunk(chunk, address, story) {
629
765
  var _a;
630
766
  const part = related(story.part, chunk.id);
@@ -632,7 +768,7 @@ export class Extractor {
632
768
  return;
633
769
  const ct = (_a = part.contentType) !== null && _a !== void 0 ? _a : '';
634
770
  const semi = ct.indexOf(';');
635
- this.warn(new TextWarning(TextWarning.ALTCHUNK_NOT_EXPANDED, address, undefined, (semi >= 0 ? ct.slice(0, semi) : ct).trim()));
771
+ this.warn(new TextWarning(TextWarning.ALTCHUNK_NOT_EXPANDED, address, undefined, (semi >= 0 ? ct.slice(0, semi) : ct).trim(), part.partName.name));
636
772
  }
637
773
  // --- bound values (REQ-509) -------------------------------------------------------------------
638
774
  /**
@@ -648,6 +784,10 @@ export class Extractor {
648
784
  const binding = (_a = sdtPrChild(pr, 'dataBinding')) === null || _a === void 0 ? void 0 : _a.value;
649
785
  if (!binding)
650
786
  return undefined;
787
+ // a store it names that could not be read: read as absent, the binding resolved by REQ-509's repair (CR-012 section 28, D3)
788
+ const unread = this.trees.unreadStoreOf(binding);
789
+ if (unread !== undefined)
790
+ this.warn(new TextWarning(TextWarning.PART_NOT_READ, undefined, undefined, undefined, unread));
651
791
  const value = this.trees.boundValue(binding);
652
792
  if (value === undefined)
653
793
  return undefined;
@@ -756,16 +896,16 @@ export class Extractor {
756
896
  const numId = String(numIdValue);
757
897
  if (Number(numIdValue) === 0)
758
898
  return undefined;
899
+ const emulator = this.numberingEmulator();
759
900
  const ilvlValue = (_b = numPr === null || numPr === void 0 ? void 0 : numPr.ilvl) === null || _b === void 0 ? void 0 : _b.val;
760
901
  const ilvl = ilvlValue === undefined || ilvlValue === null ? 0 : Number(ilvlValue);
761
902
  let format;
762
903
  let text;
763
904
  let abstractNumId;
764
905
  let start = 1;
765
- const part = this.trees.numberingPart;
766
906
  const definitions = this.trees.numbering;
767
907
  try {
768
- if (part && !directNumId && this.linkedElsewhere(part, numId, String(ilvl), pStyle))
908
+ if (emulator && !directNumId && this.linkedElsewhere(emulator, numId, String(ilvl), pStyle))
769
909
  return undefined;
770
910
  const list = definitions === null || definitions === void 0 ? void 0 : definitions.list(numId);
771
911
  abstractNumId = (_c = list === null || list === void 0 ? void 0 : list.abstractDefinition) === null || _c === void 0 ? void 0 : _c.id;
@@ -784,10 +924,21 @@ export class Extractor {
784
924
  numbering.abstractNumId = abstractNumId;
785
925
  return numbering;
786
926
  }
927
+ /**
928
+ * The numbering a numbered paragraph is counted by (`PackageTrees.numberingFor`): where the numbering part is absent or
929
+ * cannot be read, Word's default definition, and `part.absent` or `part.not_read` naming the part, once (WD 0.76).
930
+ */
931
+ numberingEmulator() {
932
+ const missing = this.trees.numberingMissing;
933
+ if (missing !== undefined && this.trees.pkg !== undefined) {
934
+ this.warn(new TextWarning(missing.kind === 'part.absent' ? TextWarning.PART_ABSENT : TextWarning.PART_NOT_READ, undefined, undefined, undefined, missing.partName));
935
+ }
936
+ return this.trees.numberingFor();
937
+ }
787
938
  /** Whether the level belongs to a paragraph style that is neither the paragraph's nor one its style is based on. */
788
- linkedElsewhere(part, numId, ilvl, pStyle) {
939
+ linkedElsewhere(emulator, numId, ilvl, pStyle) {
789
940
  var _a, _b, _c, _d;
790
- const linked = Emulator.levelStyleId(part, numId, ilvl);
941
+ const linked = emulator.levelStyleId(numId, ilvl);
791
942
  if (linked === undefined || linked === '')
792
943
  return false;
793
944
  // a paragraph naming no style is in the default paragraph style, which can own a level
@@ -803,11 +954,11 @@ export class Extractor {
803
954
  }
804
955
  /** The paragraph counted in its story's numbering state; undefined where it is not numbered. */
805
956
  count(p, story) {
806
- const pkg = this.trees.pkg;
807
- if (!pkg || !this.trees.numberingPart)
957
+ const emulator = this.trees.emulator;
958
+ if (this.trees.pkg === undefined || !emulator)
808
959
  return undefined;
809
960
  try {
810
- return Emulator.getNumber(pkg, p.pPr, story.numbering());
961
+ return emulator.getNumber(p.pPr, story.numbering());
811
962
  }
812
963
  catch {
813
964
  return undefined;
@@ -817,6 +968,7 @@ export class Extractor {
817
968
  table(tbl, address, story, sink, state) {
818
969
  var _a, _b;
819
970
  const block = new TextBlock('TABLE', story.kind, address);
971
+ this.consult('styles');
820
972
  block.section = (_b = (_a = story.sections) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
821
973
  block.source = tbl;
822
974
  story.tableDepth++;
@@ -866,7 +1018,7 @@ export class Extractor {
866
1018
  else if (typeOf(v) === AC) {
867
1019
  // a row-level mc:AlternateContent: its selected branch's rows, addressed from the element (CR-013)
868
1020
  const ac = v;
869
- this.compareBranches(ac, address);
1021
+ this.compareBranches(ac, address, story);
870
1022
  this.rows(selectedBranchOf(ac), address, story, table, state);
871
1023
  }
872
1024
  else {
@@ -917,7 +1069,7 @@ export class Extractor {
917
1069
  else if (typeOf(v) === AC) {
918
1070
  // a cell-level mc:AlternateContent: its selected branch's cells, addressed from the element (CR-013)
919
1071
  const ac = v;
920
- this.compareBranches(ac, address);
1072
+ this.compareBranches(ac, address, story);
921
1073
  this.cells(selectedBranchOf(ac), address, story, row, state);
922
1074
  }
923
1075
  else {
@@ -945,7 +1097,7 @@ export class Extractor {
945
1097
  }
946
1098
  else if (tn === AC) {
947
1099
  const ac = v;
948
- this.compareBranches(ac, para.block.address);
1100
+ this.compareBranches(ac, para.block.address, para.story);
949
1101
  this.runs(selectedBranchOf(ac), para, state);
950
1102
  }
951
1103
  else if (isSdt(v) && this.unwraps(item)) {
@@ -1047,6 +1199,7 @@ export class Extractor {
1047
1199
  const f = fields[0];
1048
1200
  if (f) {
1049
1201
  f.separated = true;
1202
+ f.hiddenResult = isSetField(f.instr);
1050
1203
  f.link = fieldHyperlinkTarget(f.instr);
1051
1204
  if (!this.options.toc && !suppressed(para.story) && isTocField(f.instr)) {
1052
1205
  f.toc = true;
@@ -1188,7 +1341,7 @@ export class Extractor {
1188
1341
  }
1189
1342
  case 'AlternateContent': {
1190
1343
  const ac = v;
1191
- this.compareBranches(ac, para.block.address);
1344
+ this.compareBranches(ac, para.block.address, para.story);
1192
1345
  for (const o of (_b = selectedBranchOf(ac)) !== null && _b !== void 0 ? _b : [])
1193
1346
  this.runItem(o, r, hidden, para, state);
1194
1347
  return;
@@ -1215,6 +1368,8 @@ export class Extractor {
1215
1368
  }
1216
1369
  if (suppressed(para.story))
1217
1370
  return;
1371
+ if (para.story.fields.some((f) => f.hiddenResult))
1372
+ return; // a SET's stored value: never shown
1218
1373
  if (!(hidden && !this.options.hidden)) {
1219
1374
  for (const f of para.story.fields)
1220
1375
  f.result += s;
@@ -1271,7 +1426,7 @@ export class Extractor {
1271
1426
  this.warn(new TextWarning(TextWarning.FIELD_NO_RESULT, para.block.address));
1272
1427
  }
1273
1428
  simpleField(field, para, state) {
1274
- var _a;
1429
+ var _a, _b, _c;
1275
1430
  if (suppressed(para.story))
1276
1431
  return; // inside a computed field's cached result
1277
1432
  const instr = (_a = field.instr) !== null && _a !== void 0 ? _a : '';
@@ -1281,6 +1436,15 @@ export class Extractor {
1281
1436
  }
1282
1437
  if (this.options.fieldCodes && !inCode(para.story))
1283
1438
  this.addText(para, instr, 'FIELD_CODE', false, state);
1439
+ if (isSetField(instr)) {
1440
+ // a SET's stored value is never shown (REQ-505), in this form as in the complex one (FieldState.hiddenResult)
1441
+ this.resultOf(field.content, para, state, undefined, true);
1442
+ const stored = ((_c = (_b = field.content) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0) > 0;
1443
+ para.block.fields.push(new TextField(instr, stored ? '' : undefined));
1444
+ if (!stored)
1445
+ this.warn(new TextWarning(TextWarning.FIELD_NO_RESULT, para.block.address));
1446
+ return;
1447
+ }
1284
1448
  const before = para.block.runs.length;
1285
1449
  const text = this.resultOf(field.content, para, state, fieldHyperlinkTarget(instr));
1286
1450
  const hasResult = text !== '' || para.block.runs.length > before;
@@ -1288,11 +1452,12 @@ export class Extractor {
1288
1452
  if (!hasResult)
1289
1453
  this.warn(new TextWarning(TextWarning.FIELD_NO_RESULT, para.block.address));
1290
1454
  }
1291
- /** The runs of a simple field's result, added to the paragraph; their text. */
1292
- resultOf(content, para, state, link) {
1455
+ /** The runs of a simple field's result, added to the paragraph; their text. `hidden`: a result never shown (a SET's). */
1456
+ resultOf(content, para, state, link, hidden = false) {
1293
1457
  const capture = new FieldState();
1294
1458
  capture.separated = true;
1295
1459
  capture.link = link;
1460
+ capture.hiddenResult = hidden;
1296
1461
  para.story.fields.push(capture);
1297
1462
  try {
1298
1463
  this.runs(content, para, state);
@@ -1377,7 +1542,7 @@ export class Extractor {
1377
1542
  return false;
1378
1543
  case AC: {
1379
1544
  const ac = value;
1380
- this.compareBranches(ac, para.block.address);
1545
+ this.compareBranches(ac, para.block.address, para.story);
1381
1546
  for (const o of (_a = selectedBranchOf(ac)) !== null && _a !== void 0 ? _a : [])
1382
1547
  walk(unwrap(o), 1, visitor);
1383
1548
  return false;
@@ -1502,13 +1667,13 @@ export class Extractor {
1502
1667
  * differ after REQ-1201's normalisation. A branch's text is every `w:t`, `m:t` and `a:t` in it, whatever
1503
1668
  * the view and hidden or not, as docx4j reads it: a comparison made at load knows no view, and a branch
1504
1669
  * that differs only in hidden or deleted text is one an agent should hear of (Jason, 2026-10-21, for WD
1505
- * 0.29; CR-012 section 15.6).
1670
+ * 0.29; CR-012 section 15.6). `mce.nothing_selected` (REQ-305): where the element has Choices and nothing is selected.
1506
1671
  */
1507
- compareBranches(ac, address) {
1672
+ compareBranches(ac, address, story) {
1508
1673
  var _a, _b, _c, _d;
1509
1674
  if (!this.options.warnings || this.fieldsOnly)
1510
1675
  return;
1511
- const selected = selectedBranchOf(ac);
1676
+ const selected = selectedBranchOf(ac, { onNothingSelected: ({ namespaces }) => this.nothingSelected(address, story.part, namespaces) });
1512
1677
  if (selected === undefined)
1513
1678
  return;
1514
1679
  const mine = branchText(selected);
@@ -1529,6 +1694,44 @@ export class Extractor {
1529
1694
  }
1530
1695
  }
1531
1696
  }
1697
+ /** `mce.nothing_selected`, its selector the part and its `detail` the namespaces (REQ-801). */
1698
+ nothingSelected(address, part, namespaces) {
1699
+ this.warn(new TextWarning(TextWarning.MCE_NOTHING_SELECTED, address, undefined, undefined, part === null || part === void 0 ? void 0 : part.partName.name, namespaces.join(' ')));
1700
+ }
1701
+ /**
1702
+ * What the walk can't meet, from the warnings the load's passes recorded on each part this reading took, none with an address:
1703
+ * `mce.nothing_selected` for an element a resolving load took out or one at a part's root (CR-029 section 3.5);
1704
+ * `mce.undeclared_prefix` (REQ-323, CR-030), on a story part or the styles, numbering or settings part the reading consults;
1705
+ * and `part.unexpected_root` (REQ-320, CR-028 D11).
1706
+ */
1707
+ partWarningsUnmet() {
1708
+ var _a, _b;
1709
+ if (!this.options.warnings || this.fieldsOnly)
1710
+ return;
1711
+ const main = (_a = this.trees.main) === null || _a === void 0 ? void 0 : _a.part;
1712
+ const consulted = [main === null || main === void 0 ? void 0 : main.styleDefinitionsPart, main === null || main === void 0 ? void 0 : main.numberingDefinitionsPart, main === null || main === void 0 ? void 0 : main.documentSettingsPart];
1713
+ for (const part of [...this.storyParts, ...consulted]) {
1714
+ if (!part)
1715
+ continue;
1716
+ for (const w of (_b = part.warnings) !== null && _b !== void 0 ? _b : []) {
1717
+ if (w.code === 'mce.nothing_selected' && (w.removed || w.root))
1718
+ this.nothingSelected(undefined, part, w.namespaces);
1719
+ else if (w.code === 'mce.undeclared_prefix')
1720
+ this.warn(new TextWarning(TextWarning.MCE_UNDECLARED_PREFIX, undefined, undefined, undefined, part.partName.name, w.prefixes.join(' ')));
1721
+ else if (w.code === 'part.unexpected_root')
1722
+ this.warn(new TextWarning(TextWarning.PART_UNEXPECTED_ROOT, undefined, undefined, undefined, w.partName, w.root));
1723
+ }
1724
+ }
1725
+ }
1726
+ /**
1727
+ * A story part the reading takes that could not be read: none of its text, and `content.not_read` naming it (REQ-801),
1728
+ * at the story's address prefix for a header or footer; docx4j's `storyContent` (`4fdd80063`).
1729
+ */
1730
+ storyRead(part, address) {
1731
+ if (part && this.trees.unreadable.has(part)) {
1732
+ this.warn(new TextWarning(TextWarning.CONTENT_NOT_READ, address, undefined, undefined, part.partName.name));
1733
+ }
1734
+ }
1532
1735
  warn(w) {
1533
1736
  if (this.warned.has(w.key))
1534
1737
  return;
@@ -1538,6 +1741,7 @@ export class Extractor {
1538
1741
  // --- headers and footers by section (REQ-502) ---------------------------------------------------
1539
1742
  sectionsWithHeaders(sections, mainBlocks, headers, footers, out) {
1540
1743
  var _a, _b;
1744
+ this.consult('settings');
1541
1745
  const evenAndOdd = on((_a = this.trees.settings) === null || _a === void 0 ? void 0 : _a.evenAndOddHeaders);
1542
1746
  const emitted = new Set();
1543
1747
  const lastHeader = new Map();
@@ -1581,15 +1785,19 @@ export class Extractor {
1581
1785
  emitted.add(rId);
1582
1786
  const main = this.trees.main;
1583
1787
  const part = main ? related(main.part, rId) : undefined;
1788
+ const prefix = `${this.root}${kind === 'HEADER' ? 'header:' : 'footer:'}${rId}`;
1789
+ this.storyRead(part, prefix);
1584
1790
  const content = part ? this.trees.headersAndFooters.get(part) : undefined;
1585
1791
  if (!content)
1586
1792
  return;
1587
- const prefix = `${this.root}${kind === 'HEADER' ? 'header:' : 'footer:'}${rId}`;
1588
1793
  const story = new Story(this, kind, prefix, part);
1589
1794
  this.blocks(blockItems(content), prefix, story, out);
1590
1795
  }
1591
1796
  /** A header or footer part's content as its own story (`Texts.of(headerPart)`). */
1592
1797
  headerOrFooterPart(part, kind, rId) {
1798
+ // read alone, a part that could not be read throws why, as the main part does (CR-012 section 25, D1)
1799
+ if (this.trees.unreadable.has(part))
1800
+ throw this.trees.unreadable.get(part);
1593
1801
  const out = [];
1594
1802
  const content = this.trees.headersAndFooters.get(part);
1595
1803
  const prefix = `${this.root}${kind === 'HEADER' ? 'header:' : 'footer:'}${rId}`;
@@ -1599,12 +1807,13 @@ export class Extractor {
1599
1807
  }
1600
1808
  // --- notes (REQ-503) ------------------------------------------------------------------------
1601
1809
  notes(type, out) {
1602
- var _a;
1810
+ var _a, _b, _c;
1811
+ this.storyRead(type === 'footnote' ? (_a = this.trees.main) === null || _a === void 0 ? void 0 : _a.part.footnotesPart : (_b = this.trees.main) === null || _b === void 0 ? void 0 : _b.part.endnotesPart);
1603
1812
  const holder = type === 'footnote' ? this.trees.footnotes : this.trees.endnotes;
1604
1813
  const numbers = type === 'footnote' ? this.context.footnotes : this.context.endnotes;
1605
1814
  if (!holder || numbers.size === 0)
1606
1815
  return;
1607
- const notes = ((_a = (type === 'footnote' ? holder.tree.footnote : holder.tree.endnote)) !== null && _a !== void 0 ? _a : []);
1816
+ const notes = ((_c = (type === 'footnote' ? holder.tree.footnote : holder.tree.endnote)) !== null && _c !== void 0 ? _c : []);
1608
1817
  const byId = new Map();
1609
1818
  for (const note of notes)
1610
1819
  if (note.id !== undefined && note.id !== null)
@@ -1649,19 +1858,20 @@ export class Extractor {
1649
1858
  }
1650
1859
  // --- comments (REQ-504) ---------------------------------------------------------------------
1651
1860
  comments(out) {
1652
- var _a, _b, _c, _d, _e;
1861
+ var _a, _b, _c, _d, _e, _f;
1862
+ this.storyRead((_a = this.trees.main) === null || _a === void 0 ? void 0 : _a.part.commentsPart);
1653
1863
  const part = this.trees.comments;
1654
1864
  if (!part)
1655
1865
  return;
1656
1866
  const extended = new Map();
1657
- for (const ex of ((_b = (_a = this.trees.commentsExtended) === null || _a === void 0 ? void 0 : _a.commentEx) !== null && _b !== void 0 ? _b : [])) {
1867
+ for (const ex of ((_c = (_b = this.trees.commentsExtended) === null || _b === void 0 ? void 0 : _b.commentEx) !== null && _c !== void 0 ? _c : [])) {
1658
1868
  if (ex.paraId)
1659
1869
  extended.set(ex.paraId.toUpperCase(), ex);
1660
1870
  }
1661
1871
  const idByParaId = new Map();
1662
1872
  const anchored = this.trees.anchoredComments();
1663
- for (const c of ((_c = part.tree.comment) !== null && _c !== void 0 ? _c : [])) {
1664
- if ((_d = this.plan) === null || _d === void 0 ? void 0 : _d.removesComment(c.id))
1873
+ for (const c of ((_d = part.tree.comment) !== null && _d !== void 0 ? _d : [])) {
1874
+ if ((_e = this.plan) === null || _e === void 0 ? void 0 : _e.removesComment(c.id))
1665
1875
  continue;
1666
1876
  const id = c.id === undefined || c.id === null ? '' : String(c.id);
1667
1877
  // a comment with no anchor in the document is none of its text: Word drops it on save (REQ-504)
@@ -1670,10 +1880,11 @@ export class Extractor {
1670
1880
  const comment = new TextComment(id);
1671
1881
  comment.author = c.author;
1672
1882
  comment.initials = c.initials;
1673
- comment.date = calendarText(c.date);
1883
+ const paraId = lastParaId(c.content);
1884
+ // REQ-702's form: w:date's wall clock, the offset where the comments extensible part's w16cex:dateUtc gives it
1885
+ comment.date = revisionDateText(c.date, paraId === undefined ? undefined : this.trees.commentDatesUtc.get(paraId.toUpperCase()));
1674
1886
  const prefix = `${this.root}comment:${id}`;
1675
1887
  this.blocks(c.content, prefix, new Story(this, 'COMMENT', prefix, part.part), comment.blocks);
1676
- const paraId = lastParaId(c.content);
1677
1888
  if (paraId !== undefined) {
1678
1889
  idByParaId.set(paraId.toUpperCase(), id);
1679
1890
  const ex = extended.get(paraId.toUpperCase());
@@ -1690,7 +1901,7 @@ export class Extractor {
1690
1901
  const parent = idByParaId.get(comment.parentId.toUpperCase());
1691
1902
  comment.parentId = parent;
1692
1903
  if (parent !== undefined)
1693
- (_e = out.get(parent)) === null || _e === void 0 ? void 0 : _e.replies.push(comment);
1904
+ (_f = out.get(parent)) === null || _f === void 0 ? void 0 : _f.replies.push(comment);
1694
1905
  }
1695
1906
  }
1696
1907
  // --- the view -------------------------------------------------------------------------------
@@ -1727,20 +1938,42 @@ export class Extractor {
1727
1938
  /**
1728
1939
  * A run's formatting beyond its paragraph style's (CR-046 phase 3): bold, italic, struck through,
1729
1940
  * monospaced, each as the run's own property gives it, else its styles', where the paragraph style
1730
- * alone doesn't give it. A run carrying only that.
1941
+ * alone doesn't give it. And, whatever the paragraph style says, what the text shows (docx4j CR-069;
1942
+ * CR-012 section 24): its case, folded the same way, a run under both caps and small caps being caps
1943
+ * (WD REQ-607); its vertical alignment (REQ-710); and a cased run's language. A run carrying only that.
1731
1944
  */
1732
1945
  formatOf(r, p) {
1733
- var _a;
1946
+ var _a, _b;
1734
1947
  const own = r.rPr;
1735
1948
  const styles = this.styleRPr((_a = own === null || own === void 0 ? void 0 : own.rStyle) === null || _a === void 0 ? void 0 : _a.val, p);
1736
1949
  const paragraph = this.styleRPr(undefined, p);
1737
1950
  const f = new TextRun('TEXT', '', undefined);
1738
1951
  f.bold = onOf(own === null || own === void 0 ? void 0 : own.b, styles === null || styles === void 0 ? void 0 : styles.b) && !on(paragraph === null || paragraph === void 0 ? void 0 : paragraph.b);
1739
1952
  f.italic = onOf(own === null || own === void 0 ? void 0 : own.i, styles === null || styles === void 0 ? void 0 : styles.i) && !on(paragraph === null || paragraph === void 0 ? void 0 : paragraph.i);
1740
- f.strike = onOf(own === null || own === void 0 ? void 0 : own.strike, styles === null || styles === void 0 ? void 0 : styles.strike) && !on(paragraph === null || paragraph === void 0 ? void 0 : paragraph.strike);
1953
+ // struck once or twice (w:dstrike: docx4j CR-069 phase 4, CR-012 section 24.5), the paragraph style's either cancelling it
1954
+ f.strike = (onOf(own === null || own === void 0 ? void 0 : own.strike, styles === null || styles === void 0 ? void 0 : styles.strike) || onOf(own === null || own === void 0 ? void 0 : own.dstrike, styles === null || styles === void 0 ? void 0 : styles.dstrike))
1955
+ && !(on(paragraph === null || paragraph === void 0 ? void 0 : paragraph.strike) || on(paragraph === null || paragraph === void 0 ? void 0 : paragraph.dstrike));
1741
1956
  f.monospace = isMonospace(this.runFont(r, p)) && !isMonospace(asciiFont(paragraph));
1957
+ f.caps = onOf(own === null || own === void 0 ? void 0 : own.caps, styles === null || styles === void 0 ? void 0 : styles.caps);
1958
+ f.smallCaps = !f.caps && onOf(own === null || own === void 0 ? void 0 : own.smallCaps, styles === null || styles === void 0 ? void 0 : styles.smallCaps);
1959
+ const vertAlign = (_b = own === null || own === void 0 ? void 0 : own.vertAlign) !== null && _b !== void 0 ? _b : styles === null || styles === void 0 ? void 0 : styles.vertAlign;
1960
+ if ((vertAlign === null || vertAlign === void 0 ? void 0 : vertAlign.val) === 'superscript')
1961
+ f.verticalAlignment = 'SUPERSCRIPT';
1962
+ if ((vertAlign === null || vertAlign === void 0 ? void 0 : vertAlign.val) === 'subscript')
1963
+ f.verticalAlignment = 'SUBSCRIPT';
1964
+ if (f.caps || f.smallCaps)
1965
+ f.language = this.language(own, styles);
1742
1966
  return f;
1743
1967
  }
1968
+ /**
1969
+ * The language a cased run's capitals are mapped by (WD REQ-607): its own `w:lang/@w:val`, else its styles' (with the
1970
+ * document defaults'), else the `default_language` option. `w:themeFontLang` is no link (WD 0.80, CR-012 section 24.8):
1971
+ * it chooses among the theme's fonts, and Word cases such a run by its editing language, which the option stands in for.
1972
+ */
1973
+ language(own, styles) {
1974
+ var _a, _b;
1975
+ return (_b = (_a = langOf(own === null || own === void 0 ? void 0 : own.lang)) !== null && _a !== void 0 ? _a : langOf(styles === null || styles === void 0 ? void 0 : styles.lang)) !== null && _b !== void 0 ? _b : this.options.defaultLanguage;
1976
+ }
1744
1977
  /** The run's font for `monospace`: its own `w:rFonts/@w:ascii`, else its styles'. */
1745
1978
  runFont(r, p) {
1746
1979
  var _a, _b, _c;
@@ -1830,6 +2063,12 @@ function textLength(block) {
1830
2063
  function sameRevision(a, b) {
1831
2064
  return a === undefined ? b === undefined : a.equals(b);
1832
2065
  }
2066
+ /** A `w:lang`'s `w:val`, trimmed; undefined for none or an empty one. */
2067
+ function langOf(l) {
2068
+ var _a;
2069
+ const v = (_a = l === null || l === void 0 ? void 0 : l.val) === null || _a === void 0 ? void 0 : _a.trim();
2070
+ return v === undefined || v === '' ? undefined : v;
2071
+ }
1833
2072
  /** An on/off property: the run's own where it has one, else its styles'. */
1834
2073
  function onOf(own, styles) {
1835
2074
  if (own !== undefined)
@@ -1878,6 +2117,11 @@ export function isTocField(instr) {
1878
2117
  const tokens = fieldTokens(instr);
1879
2118
  return tokens.length > 0 && tokens[0].toUpperCase() === 'TOC';
1880
2119
  }
2120
+ /** A SET field's code: Word stores its value as its result, under a bookmark of its name, and shows nothing (REQ-505). */
2121
+ function isSetField(instr) {
2122
+ const tokens = fieldTokens(instr);
2123
+ return tokens.length > 0 && tokens[0].toUpperCase() === 'SET';
2124
+ }
1881
2125
  /** A table of contents' code, shown under `field_codes` until it was known to be one, taken out again. */
1882
2126
  function removeFieldCode(f, para) {
1883
2127
  // what follows the field may merge with what preceded it, as it would with no field codes