@docx4j/core-ts 0.3.2 → 0.5.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 (72) hide show
  1. package/README.md +8 -3
  2. package/dist/html/convert.d.mts +116 -0
  3. package/dist/html/convert.mjs +565 -0
  4. package/dist/html/elements.d.mts +19 -0
  5. package/dist/html/elements.mjs +182 -0
  6. package/dist/html/index.d.mts +2 -0
  7. package/dist/html/index.mjs +4 -0
  8. package/dist/model/content/Body.d.mts +13 -1
  9. package/dist/model/content/Body.mjs +97 -19
  10. package/dist/model/content/Comment.mjs +7 -0
  11. package/dist/model/content/InlinePicture.d.mts +89 -10
  12. package/dist/model/content/InlinePicture.mjs +245 -35
  13. package/dist/model/content/List.mjs +10 -1
  14. package/dist/model/content/Paragraph.d.mts +28 -5
  15. package/dist/model/content/Paragraph.mjs +77 -37
  16. package/dist/model/content/Range.d.mts +18 -2
  17. package/dist/model/content/Range.mjs +194 -64
  18. package/dist/model/content/Table.d.mts +38 -0
  19. package/dist/model/content/Table.mjs +80 -2
  20. package/dist/model/content/TrackedChange.d.mts +129 -3
  21. package/dist/model/content/TrackedChange.mjs +577 -12
  22. package/dist/model/content/binder.d.mts +2 -1
  23. package/dist/model/content/binder.mjs +48 -1
  24. package/dist/model/content/index.d.mts +4 -3
  25. package/dist/model/content/index.mjs +3 -2
  26. package/dist/model/content/relationships.d.mts +30 -0
  27. package/dist/model/content/relationships.mjs +133 -0
  28. package/dist/model/content/stylesFacade.d.mts +4 -2
  29. package/dist/model/content/stylesFacade.mjs +20 -6
  30. package/dist/model/content/tableColumns.d.mts +48 -0
  31. package/dist/model/content/tableColumns.mjs +484 -0
  32. package/dist/model/content/tree.d.mts +52 -2
  33. package/dist/model/content/tree.mjs +48 -3
  34. package/dist/model/customxml/CustomXmlPartCollection.d.mts +6 -1
  35. package/dist/model/customxml/CustomXmlPartCollection.mjs +19 -3
  36. package/dist/model/customxml/bindings.d.mts +5 -2
  37. package/dist/model/customxml/bindings.mjs +21 -6
  38. package/dist/model/customxml/index.d.mts +3 -0
  39. package/dist/model/customxml/index.mjs +3 -0
  40. package/dist/model/customxml/opendope.d.mts +32 -0
  41. package/dist/model/customxml/opendope.mjs +56 -0
  42. package/dist/model/customxml/pictures.d.mts +57 -0
  43. package/dist/model/customxml/pictures.mjs +192 -0
  44. package/dist/model/customxml/xhtml.d.mts +42 -0
  45. package/dist/model/customxml/xhtml.mjs +162 -0
  46. package/dist/model/fonts/families.generated.mjs +2 -2
  47. package/dist/model/fonts/registry.mjs +7 -1
  48. package/dist/model/fonts/substitutions.generated.mjs +2 -2
  49. package/dist/model/fonts/themes.generated.mjs +1 -1
  50. package/dist/model/listnumbering/definitions.mjs +18 -0
  51. package/dist/model/properties/PropertyResolver.d.mts +27 -6
  52. package/dist/model/properties/PropertyResolver.mjs +83 -16
  53. package/dist/model/properties/catalogue.d.mts +15 -1
  54. package/dist/model/properties/catalogue.mjs +80 -27
  55. package/dist/model/properties/table.d.mts +16 -2
  56. package/dist/model/properties/table.mjs +13 -3
  57. package/dist/opc/Load.d.mts +9 -2
  58. package/dist/opc/index.d.mts +2 -2
  59. package/dist/opc/index.mjs +2 -2
  60. package/dist/opc/mce/preprocessor.d.mts +62 -6
  61. package/dist/opc/mce/preprocessor.mjs +142 -35
  62. package/dist/opc/mce/understood.d.mts +10 -0
  63. package/dist/opc/mce/understood.mjs +25 -3
  64. package/dist/packages/OpcPackage.d.mts +7 -0
  65. package/dist/packages/OpcPackage.mjs +15 -3
  66. package/dist/packages/WordprocessingMLPackage.d.mts +35 -2
  67. package/dist/packages/WordprocessingMLPackage.mjs +99 -2
  68. package/dist/parts/XmlPart.d.mts +26 -5
  69. package/dist/parts/XmlPart.mjs +67 -18
  70. package/dist/parts/wml/knownStyles.d.mts +1 -0
  71. package/dist/parts/wml/knownStyles.mjs +2233 -0
  72. package/package.json +7 -2
@@ -1,6 +1,6 @@
1
1
  // The Office themes docx4j supplies to a package that has none, one per value of `docx4j.fonts.defaultTheme`.
2
2
  //
3
- // Generated by scripts/generate-substitutions.mjs from docx4j 7fba7a1507fc01fdd7f4dc2f79cdbd6988c044f7:
3
+ // Generated by scripts/generate-substitutions.mjs from docx4j 84d0f8a5b2f0d357b03fae151216ca0757609441:
4
4
  // org/docx4j/openpackaging/parts/WordprocessingML/theme-{2007,2013,2023}.xml
5
5
  // Do not edit; run `npm run generate:fonts` instead.
6
6
  /** Office 2007 to 2010: Cambria / Calibri. */
@@ -1,3 +1,4 @@
1
+ import * as f from '@docx4j/generated-objects-ts/factory/org_docx4j_wml';
1
2
  import { log } from '../properties/log.mjs';
2
3
  import { formatValue } from './formats.mjs';
3
4
  /** How many levels a list definition may have (ECMA-376: `w:ilvl` 0 to 8). */
@@ -216,6 +217,16 @@ export class LevelDefinition {
216
217
  return `LevelDefinition ${this.ilvl} ${(_a = this.numFmt) !== null && _a !== void 0 ? _a : '-'} ${JSON.stringify((_b = this.lvlText) !== null && _b !== void 0 ? _b : '')}`;
217
218
  }
218
219
  }
220
+ /**
221
+ * What Word makes of a `w:lvl` without `w:ilvl`: level 0, with no number. docx4j
222
+ * `ListLevel.emptyLevelZero`; the document's own `w:lvl` is left as it is.
223
+ */
224
+ function emptyLevelZero() {
225
+ const lvl = f.createLvl({ ilvl: 0 });
226
+ lvl.numFmt = f.createNumFmt({ val: 'none' });
227
+ lvl.lvlText = f.createLvlLvlText({ val: '' });
228
+ return lvl;
229
+ }
219
230
  /**
220
231
  * One `w:abstractNum`: its levels, and - where it carries `w:numStyleLink` - the numbering style
221
232
  * whose definition it takes them from. docx4j `AbstractListNumberingDefinition`.
@@ -238,6 +249,13 @@ export class AbstractListDefinition {
238
249
  }
239
250
  /** Adds (or replaces) the level read from this `w:lvl`. docx4j `readLevel`. */
240
251
  readLevel(lvl) {
252
+ if (lvl.ilvl === undefined) {
253
+ // w:ilvl is required. Word reads a w:lvl without it as level 0 and keeps none of its
254
+ // content - no number, no indent - and a later level 0 replaces it as usual (docx4j
255
+ // ListLevel, issue 593 at f6b87cd2f: probes 593-a and 593-b, Word 365, 2026-10-11)
256
+ log.warn('w:lvl without w:ilvl: read as an empty level 0, as Word does');
257
+ lvl = emptyLevelZero();
258
+ }
241
259
  const level = new LevelDefinition(String(lvl.ilvl), lvl);
242
260
  // the REFERENCING abstract list: a w:numStyleLink definition counts on its own (P2)
243
261
  level.abstractNumId = this.id;
@@ -62,6 +62,12 @@ export declare class PropertyResolver {
62
62
  private readonly composedRPrCache;
63
63
  /** See {@link appliesTableStyleSizeJcException}; read once per `refresh()`. */
64
64
  private tableStyleSizeJcException;
65
+ /**
66
+ * Whether the document's own `w:docDefaults` state a size, rather than the 10pt the resolver
67
+ * makes explicit where they do not: the size exception takes the document defaults' size only
68
+ * where they state one. Read once per `refresh()`.
69
+ */
70
+ private docDefaultsStateSize;
65
71
  /** Missing styles are logged once each per resolver. */
66
72
  private readonly missingLogged;
67
73
  private numberingDefinitions;
@@ -205,10 +211,18 @@ export declare class PropertyResolver {
205
211
  private applyCharacterStyleAndDirect;
206
212
  /**
207
213
  * The run properties of the paragraph mark: document defaults, the paragraph style's run
208
- * properties, then the `w:pPr`'s own `w:rPr`. What sizes an empty paragraph, and what a list
209
- * label starts from.
214
+ * properties, the mark's character style, then the `w:pPr`'s own `w:rPr`. What sizes an empty
215
+ * paragraph, and what a list label starts from.
210
216
  */
211
217
  getEffectiveParagraphMarkRPr(pPr: wml.PPr | undefined, cellContext?: CellContext | undefined): wml.RPr;
218
+ /**
219
+ * The paragraph mark's character style (`w:pPr/w:rPr/w:rStyle`) as a level over what is
220
+ * beneath it, then the mark's direct formatting: the order {@link applyCharacterStyleAndDirect}
221
+ * gives a run. docx4j `applyMarkRPr`, since 17.3.2 (fb2a764f7: until then the mark's
222
+ * `w:rStyle` was copied as an attribute and never resolved, so an empty paragraph whose mark
223
+ * names a 9pt character style was sized at its paragraph style's 12pt).
224
+ */
225
+ private applyMarkRPr;
212
226
  /** Whether the run states any formatting of its own (docx4j's deprecated `hasDirectRPrFormatting`). */
213
227
  hasDirectRPrFormatting(rPr: wml.RPr | undefined): boolean;
214
228
  /**
@@ -282,6 +296,12 @@ export declare class PropertyResolver {
282
296
  * is quadratic.
283
297
  */
284
298
  cellContextOf(p: wml.P): CellContext | undefined;
299
+ /**
300
+ * Whether a paragraph in this context is composed over its table level: where the table style
301
+ * gives it text formatting, or, under [MS-DOCX]'s size exception, where the style formats text
302
+ * anywhere ({@link CellContext.styleFormatsText}). docx4j `composes` (900b6a212, 17.3.2).
303
+ */
304
+ private composes;
285
305
  private clearTableCaches;
286
306
  /** The table level's `w:pPr`: the style's own, then its conditional formats'; undefined if none. */
287
307
  private tableLevelPPr;
@@ -290,10 +310,11 @@ export declare class PropertyResolver {
290
310
  private composedPPr;
291
311
  private composedRPr;
292
312
  /**
293
- * [MS-DOCX]'s exception, for a paragraph in a table whose style states a size (or a
294
- * justification): the paragraph's style gives way to it if the style is the default paragraph
295
- * style, or states no size (justification) of its own, and resolves to 12pt (left). A style of
296
- * the paragraph's own which states one keeps it.
313
+ * [MS-DOCX]'s exception, for a paragraph in a table whose style formats text (for the size: the
314
+ * style need not state one, since docx4j 17.3.2) or states a justification: the paragraph's
315
+ * style gives way to it if the style is the default paragraph style, or states no size
316
+ * (justification) of its own, and resolves to 12pt (left). A style of the paragraph's own which
317
+ * states one keeps it.
297
318
  */
298
319
  private paragraphStyleGivesWay;
299
320
  /** Word's built-in Normal Table, as a style: what it applies whatever the document's own definition says. */
@@ -1,5 +1,5 @@
1
1
  import { deepCopy } from '@docx4j/generated-objects-ts';
2
- import { Docx4JException } from '../../opc/exceptions.mjs';
2
+ import { Docx4JException, PartUnmarshalException } from '../../opc/exceptions.mjs';
3
3
  import { log } from './log.mjs';
4
4
  import { NumberingDefinitions } from '../listnumbering/definitions.mjs';
5
5
  import { applyPPr, applyPPrBase, applyRPr, applyStyle, applyStyleLevel, applyTblPr, applyToggles, hasDirectFormattingPPr, hasDirectFormattingRPr, isCyclic, isEmptyStyle, } from './styleUtil.mjs';
@@ -75,6 +75,26 @@ export function headingLevelByName(style) {
75
75
  const match = HEADING_NAME.exec(name.trim());
76
76
  return match ? Number(match[1]) : -1;
77
77
  }
78
+ /**
79
+ * A styles or numbering part the resolver can't do without: when it can't be read, nothing in the
80
+ * document can be given its formatting, so the document is refused (Jason, 2026-10-17), and the
81
+ * error says so before it says what was wrong where. A `PartUnmarshalException` stays one, with its
82
+ * part, location, line and column, so a caller showing the fault reads the same fields as for any
83
+ * part.
84
+ */
85
+ async function readOrRefuse(part, role) {
86
+ try {
87
+ return await part.readContents();
88
+ }
89
+ catch (e) {
90
+ const why = role === 'styles' ? "every paragraph's formatting depends on it" : "its lists' numbers and indents depend on it";
91
+ const lead = `The document cannot be opened: its ${role} part could not be read, and ${why}.`;
92
+ if (e instanceof PartUnmarshalException) {
93
+ throw new PartUnmarshalException(`${lead} ${e.message}`, e.partName, { cause: e, location: e.location, line: e.line, column: e.column });
94
+ }
95
+ throw new Docx4JException(`${lead} ${e instanceof Error ? e.message : String(e)}`, { cause: e });
96
+ }
97
+ }
78
98
  export class PropertyResolver {
79
99
  constructor(provider,
80
100
  /** Set when the styles tree the resolver holds is not the styles part's own. */
@@ -104,6 +124,12 @@ export class PropertyResolver {
104
124
  this.composedRPrCache = new CompositionCache();
105
125
  /** See {@link appliesTableStyleSizeJcException}; read once per `refresh()`. */
106
126
  this.tableStyleSizeJcException = true;
127
+ /**
128
+ * Whether the document's own `w:docDefaults` state a size, rather than the 10pt the resolver
129
+ * makes explicit where they do not: the size exception takes the document defaults' size only
130
+ * where they state one. Read once per `refresh()`.
131
+ */
132
+ this.docDefaultsStateSize = false;
107
133
  /** Missing styles are logged once each per resolver. */
108
134
  this.missingLogged = new Set();
109
135
  this.source = provider();
@@ -132,8 +158,8 @@ export class PropertyResolver {
132
158
  }
133
159
  const stylesPart = main.styleDefinitionsPart;
134
160
  const numberingPart = main.numberingDefinitionsPart;
135
- const privateStyles = stylesPart === undefined ? undefined : await stylesPart.readContents();
136
- const privateNumbering = numberingPart === undefined ? undefined : await numberingPart.readContents();
161
+ const privateStyles = stylesPart === undefined ? undefined : await readOrRefuse(stylesPart, 'styles');
162
+ const privateNumbering = numberingPart === undefined ? undefined : await readOrRefuse(numberingPart, 'numbering');
137
163
  // the settings are read for two compatibility values (CR-007), privately, as the others are
138
164
  const settingsPart = main.documentSettingsPart;
139
165
  let privateSettings;
@@ -189,6 +215,7 @@ export class PropertyResolver {
189
215
  ? { TYPE_NAME: 'org_docx4j_wml.PPr' } : deepCopy(docDefaults.pPrDefault.pPr);
190
216
  this.documentDefaultRPr = ((_f = docDefaults === null || docDefaults === void 0 ? void 0 : docDefaults.rPrDefault) === null || _f === void 0 ? void 0 : _f.rPr) === undefined
191
217
  ? { TYPE_NAME: 'org_docx4j_wml.RPr' } : deepCopy(docDefaults.rPrDefault.rPr);
218
+ this.docDefaultsStateSize = this.documentDefaultRPr.sz !== undefined;
192
219
  if (this.documentDefaultRPr.sz === undefined) {
193
220
  // Word's default made explicit: 10pt where nothing states a size (measured, CR-015 probe
194
221
  // styles-no-size-anywhere: identical to an explicit 10pt run)
@@ -384,7 +411,7 @@ export class PropertyResolver {
384
411
  return styleId;
385
412
  }
386
413
  getEffectivePPr(arg, cellContext) {
387
- if (cellContext !== undefined && cellContext.formatsText && typeof arg !== 'string') {
414
+ if (this.composes(cellContext) && typeof arg !== 'string') {
388
415
  const composed = this.composedPPr(this.paragraphStyleOf(arg), cellContext);
389
416
  if (!hasDirectFormattingPPr(arg))
390
417
  return composed;
@@ -415,7 +442,7 @@ export class PropertyResolver {
415
442
  getEffectiveRPr(arg, pPr, cellContext) {
416
443
  if (typeof arg === 'string')
417
444
  return this.effectiveRPrOfStyle(arg);
418
- if (cellContext !== undefined && cellContext.formatsText) {
445
+ if (this.composes(cellContext)) {
419
446
  const inTable = deepCopy(this.composedRPr(this.paragraphStyleOf(pPr), cellContext));
420
447
  this.applyCharacterStyleAndDirect(arg, inTable);
421
448
  return inTable;
@@ -462,23 +489,43 @@ export class PropertyResolver {
462
489
  }
463
490
  /**
464
491
  * The run properties of the paragraph mark: document defaults, the paragraph style's run
465
- * properties, then the `w:pPr`'s own `w:rPr`. What sizes an empty paragraph, and what a list
466
- * label starts from.
492
+ * properties, the mark's character style, then the `w:pPr`'s own `w:rPr`. What sizes an empty
493
+ * paragraph, and what a list label starts from.
467
494
  */
468
495
  getEffectiveParagraphMarkRPr(pPr, cellContext) {
469
- if (cellContext !== undefined && cellContext.formatsText) {
496
+ if (this.composes(cellContext)) {
470
497
  // in a table cell: the table level beneath the paragraph style's (CR-007)
471
498
  const inTable = deepCopy(this.composedRPr(this.paragraphStyleOf(pPr), cellContext));
472
499
  if ((pPr === null || pPr === void 0 ? void 0 : pPr.rPr) !== undefined)
473
- applyRPr(pPr.rPr, inTable);
500
+ this.applyMarkRPr(pPr.rPr, inTable);
474
501
  return inTable;
475
502
  }
476
503
  const effective = deepCopy(this.documentDefaultRPr);
477
504
  applyRPr(this.getChainRPr(this.paragraphStyleOf(pPr)), effective);
478
505
  if ((pPr === null || pPr === void 0 ? void 0 : pPr.rPr) !== undefined)
479
- applyRPr(pPr.rPr, effective);
506
+ this.applyMarkRPr(pPr.rPr, effective);
480
507
  return effective;
481
508
  }
509
+ /**
510
+ * The paragraph mark's character style (`w:pPr/w:rPr/w:rStyle`) as a level over what is
511
+ * beneath it, then the mark's direct formatting: the order {@link applyCharacterStyleAndDirect}
512
+ * gives a run. docx4j `applyMarkRPr`, since 17.3.2 (fb2a764f7: until then the mark's
513
+ * `w:rStyle` was copied as an attribute and never resolved, so an empty paragraph whose mark
514
+ * names a 9pt character style was sized at its paragraph style's 12pt).
515
+ */
516
+ applyMarkRPr(mark, effective) {
517
+ var _a;
518
+ const runStyleId = (_a = mark.rStyle) === null || _a === void 0 ? void 0 : _a.val;
519
+ if (runStyleId !== undefined) {
520
+ if (this.getLiveStyle(runStyleId) === undefined) {
521
+ this.logMissing(runStyleId);
522
+ }
523
+ else {
524
+ applyStyleLevel(this.getChainRPr(runStyleId), effective, this.documentDefaultRPr);
525
+ }
526
+ }
527
+ applyRPr(mark, effective);
528
+ }
482
529
  /** Whether the run states any formatting of its own (docx4j's deprecated `hasDirectRPrFormatting`). */
483
530
  hasDirectRPrFormatting(rPr) {
484
531
  return hasDirectFormattingRPr(rPr);
@@ -609,6 +656,15 @@ export class PropertyResolver {
609
656
  const found = enclosingCellOf(p);
610
657
  return found === undefined ? undefined : this.tableContext(found.tbl).forParagraph(found.tr, found.tc, p.pPr);
611
658
  }
659
+ /**
660
+ * Whether a paragraph in this context is composed over its table level: where the table style
661
+ * gives it text formatting, or, under [MS-DOCX]'s size exception, where the style formats text
662
+ * anywhere ({@link CellContext.styleFormatsText}). docx4j `composes` (900b6a212, 17.3.2).
663
+ */
664
+ composes(cellContext) {
665
+ return cellContext !== undefined && (cellContext.formatsText
666
+ || (this.tableStyleSizeJcException && cellContext.styleFormatsText));
667
+ }
612
668
  clearTableCaches() {
613
669
  this.tableStyleChains.clear();
614
670
  this.composedPPrCache.clear();
@@ -663,18 +719,29 @@ export class PropertyResolver {
663
719
  // the table and the paragraph style are two levels of the hierarchy: the twelve toggles
664
720
  // combine across them rather than the paragraph's overriding (17.7.3)
665
721
  applyToggles(paragraphLevel, tableLevel, this.documentDefaultRPr, composed);
666
- if (this.tableStyleSizeJcException && (tableOnly === null || tableOnly === void 0 ? void 0 : tableOnly.sz) !== undefined
722
+ // The size the table level gives is its own where the table style states one, else the
723
+ // document defaults' where they state one: Word applies the exception wherever the table
724
+ // style formats text at all, not only where it states a size (docx4j 900b6a212, measured on
725
+ // its table-style-size-trigger probes: in mode 12, with docDefaults 11pt and Normal 12pt, a
726
+ // table style with only a w:pPr, only an rPr colour, or only a firstRow format sets its
727
+ // table's paragraphs at 11pt; with none of these, at Normal's 12pt). But where neither the
728
+ // table style nor the docDefaults state a size, Normal keeps its 12pt, not the 10pt Word
729
+ // falls back to (docx4j's corpus documents 10244 and 12723).
730
+ const tableStatesSize = (tableOnly === null || tableOnly === void 0 ? void 0 : tableOnly.sz) !== undefined;
731
+ if (this.tableStyleSizeJcException && ctx.styleFormatsText && tableLevel.sz !== undefined
732
+ && (tableStatesSize || this.docDefaultsStateSize)
667
733
  && this.paragraphStyleGivesWay(styleId, true)) {
668
- composed.sz = deepCopy(tableOnly.sz);
734
+ composed.sz = deepCopy(tableLevel.sz);
669
735
  }
670
736
  this.composedRPrCache.set(styleId, ctx.key, composed);
671
737
  return composed;
672
738
  }
673
739
  /**
674
- * [MS-DOCX]'s exception, for a paragraph in a table whose style states a size (or a
675
- * justification): the paragraph's style gives way to it if the style is the default paragraph
676
- * style, or states no size (justification) of its own, and resolves to 12pt (left). A style of
677
- * the paragraph's own which states one keeps it.
740
+ * [MS-DOCX]'s exception, for a paragraph in a table whose style formats text (for the size: the
741
+ * style need not state one, since docx4j 17.3.2) or states a justification: the paragraph's
742
+ * style gives way to it if the style is the default paragraph style, or states no size
743
+ * (justification) of its own, and resolves to 12pt (left). A style of the paragraph's own which
744
+ * states one keeps it.
678
745
  */
679
746
  paragraphStyleGivesWay(styleId, size) {
680
747
  var _a, _b, _c, _d;
@@ -39,7 +39,12 @@ export declare function isTrue(value: wml.BooleanDefaultTrue | undefined): boole
39
39
  export declare function isEmptyRStyle(value: wml.RStyle | undefined): boolean;
40
40
  /** docx4j `isEmpty(RFonts)`: insensitive to a `w:hint` (which `apply` still carries). */
41
41
  export declare function isEmptyRFonts(value: wml.RFonts | undefined): boolean;
42
+ /**
43
+ * A `w:color` stating only a theme colour is not empty: it is inherited, where until docx4j CR-034
44
+ * (2e381ef26) it was dropped.
45
+ */
42
46
  export declare function isEmptyColor(value: wml.Color | undefined): boolean;
47
+ /** The underline's colour attributes count, the theme ones too (docx4j CR-034, 2e381ef26). */
43
48
  export declare function isEmptyU(value: wml.U | undefined): boolean;
44
49
  export declare function isEmptyHighlight(value: wml.Highlight | undefined): boolean;
45
50
  /** @since CR-015 phase 1: a style stating only `w:lang` used to count as empty and was never applied. */
@@ -87,8 +92,17 @@ export declare const mergePStyle: Merge<wml.PPrBase.PStyle>;
87
92
  * formatted).
88
93
  */
89
94
  export declare const mergeRFonts: Merge<wml.RFonts>;
95
+ /**
96
+ * A colour inherits as one (docx4j CR-034, 2e381ef26): where the source states a value or a theme
97
+ * reference, its value, theme colour, tint and shade replace the destination's together. Word
98
+ * draws a theme reference over the value written beside it, so taken one by one, a run's
99
+ * `w:val="FF0000"` under a style's `w:themeColor="accent1"` would keep the style's reference and
100
+ * draw accent1, where Word draws red. A tint or shade stated alone still inherits on its own. The
101
+ * same holds for the colours of `w:u`, `w:shd` (its pattern colour and its fill) and the borders.
102
+ * (Attribute by attribute until then, CR-015 phase 1.)
103
+ */
90
104
  export declare const mergeColor: Merge<wml.Color>;
91
- /** `w:val` and the colour attributes each inherit on their own (CR-015 phase 1). */
105
+ /** `w:val` and the colour inherit on their own (CR-015 phase 1), the colour as one ({@link mergeColor}). */
92
106
  export declare const mergeU: Merge<wml.U>;
93
107
  /** `w:val`, `w:eastAsia` and `w:bidi` each name the language of one script range and each inherits. */
94
108
  export declare const mergeLang: Merge<wml.CTLanguage>;
@@ -29,9 +29,12 @@ function emptyThemeColor(value) {
29
29
  function attr(source, destination) {
30
30
  return source === undefined ? destination : source;
31
31
  }
32
- /** docx4j `StyleUtil.apply(STThemeColor, STThemeColor)`: `none` does not override. */
33
- function themeColor(source, destination) {
34
- return emptyThemeColor(source) ? destination : source;
32
+ /**
33
+ * docx4j `StyleUtil.statesColour`: a colour's value or theme reference is stated, so the colour
34
+ * inherits as one (docx4j CR-034, 2e381ef26; see {@link mergeColor}).
35
+ */
36
+ function statesColour(val, theme) {
37
+ return !emptyString(val) || !emptyThemeColor(theme);
35
38
  }
36
39
  /** A merge with no per-attribute rule: a copy of the source where it has one, else the inherited. */
37
40
  export function mergeReplace(source, destination) {
@@ -71,11 +74,20 @@ export function isEmptyRFonts(value) {
71
74
  && emptyString(value.eastAsia) && value.eastAsiaTheme === undefined
72
75
  && emptyString(value.hAnsi) && value.hAnsiTheme === undefined);
73
76
  }
77
+ /**
78
+ * A `w:color` stating only a theme colour is not empty: it is inherited, where until docx4j CR-034
79
+ * (2e381ef26) it was dropped.
80
+ */
74
81
  export function isEmptyColor(value) {
75
- return value === undefined || emptyString(value.val);
82
+ return value === undefined
83
+ || (emptyString(value.val) && value.themeColor === undefined
84
+ && emptyString(value.themeTint) && emptyString(value.themeShade));
76
85
  }
86
+ /** The underline's colour attributes count, the theme ones too (docx4j CR-034, 2e381ef26). */
77
87
  export function isEmptyU(value) {
78
- return value === undefined || (value.val === undefined && emptyString(value.color));
88
+ return value === undefined
89
+ || (value.val === undefined && emptyString(value.color) && value.themeColor === undefined
90
+ && emptyString(value.themeTint) && emptyString(value.themeShade));
79
91
  }
80
92
  export function isEmptyHighlight(value) {
81
93
  return value === undefined || emptyString(value.val);
@@ -291,28 +303,49 @@ export const mergeRFonts = (source, destination) => {
291
303
  out.hint = source.hint;
292
304
  return out;
293
305
  };
306
+ /**
307
+ * A colour inherits as one (docx4j CR-034, 2e381ef26): where the source states a value or a theme
308
+ * reference, its value, theme colour, tint and shade replace the destination's together. Word
309
+ * draws a theme reference over the value written beside it, so taken one by one, a run's
310
+ * `w:val="FF0000"` under a style's `w:themeColor="accent1"` would keep the style's reference and
311
+ * draw accent1, where Word draws red. A tint or shade stated alone still inherits on its own. The
312
+ * same holds for the colours of `w:u`, `w:shd` (its pattern colour and its fill) and the borders.
313
+ * (Attribute by attribute until then, CR-015 phase 1.)
314
+ */
294
315
  export const mergeColor = (source, destination) => {
295
316
  if (isEmptyColor(source))
296
317
  return destination;
297
318
  const s = source;
298
319
  const out = (destination !== null && destination !== void 0 ? destination : {});
299
- out.themeColor = themeColor(s.themeColor, out.themeColor);
300
- out.themeShade = attr(s.themeShade, out.themeShade);
301
- out.themeTint = attr(s.themeTint, out.themeTint);
302
- out.val = attr(s.val, out.val);
320
+ if (statesColour(s.val, s.themeColor)) {
321
+ out.val = s.val;
322
+ out.themeColor = s.themeColor;
323
+ out.themeTint = s.themeTint;
324
+ out.themeShade = s.themeShade;
325
+ }
326
+ else {
327
+ out.themeShade = attr(s.themeShade, out.themeShade);
328
+ out.themeTint = attr(s.themeTint, out.themeTint);
329
+ }
303
330
  return out;
304
331
  };
305
- /** `w:val` and the colour attributes each inherit on their own (CR-015 phase 1). */
332
+ /** `w:val` and the colour inherit on their own (CR-015 phase 1), the colour as one ({@link mergeColor}). */
306
333
  export const mergeU = (source, destination) => {
307
334
  if (isEmptyU(source))
308
335
  return destination;
309
336
  const s = source;
310
337
  const out = destination !== null && destination !== void 0 ? destination : {};
311
338
  out.val = attr(s.val, out.val);
312
- out.color = attr(s.color, out.color);
313
- out.themeColor = themeColor(s.themeColor, out.themeColor);
314
- out.themeTint = attr(s.themeTint, out.themeTint);
315
- out.themeShade = attr(s.themeShade, out.themeShade);
339
+ if (statesColour(s.color, s.themeColor)) {
340
+ out.color = s.color;
341
+ out.themeColor = s.themeColor;
342
+ out.themeTint = s.themeTint;
343
+ out.themeShade = s.themeShade;
344
+ }
345
+ else {
346
+ out.themeTint = attr(s.themeTint, out.themeTint);
347
+ out.themeShade = attr(s.themeShade, out.themeShade);
348
+ }
316
349
  return out;
317
350
  };
318
351
  /** `w:val`, `w:eastAsia` and `w:bidi` each name the language of one script range and each inherits. */
@@ -331,16 +364,29 @@ export const mergeShd = (source, destination) => {
331
364
  return destination;
332
365
  const s = source;
333
366
  const out = (destination !== null && destination !== void 0 ? destination : {});
334
- out.color = attr(s.color, out.color);
335
- out.fill = attr(s.fill, out.fill);
336
367
  out.val = attr(s.val, out.val);
337
- out.themeTint = attr(s.themeTint, out.themeTint);
338
- out.themeShade = attr(s.themeShade, out.themeShade);
339
- out.themeFillTint = attr(s.themeFillTint, out.themeFillTint);
340
- out.themeFillShade = attr(s.themeFillShade, out.themeFillShade);
341
- // the enums only when the source states them (until CR-015 a null source cleared them)
342
- out.themeColor = themeColor(s.themeColor, out.themeColor);
343
- out.themeFill = themeColor(s.themeFill, out.themeFill);
368
+ // the pattern colour and the fill each inherit as one (see mergeColor), so a direct w:shd
369
+ // stating no fill still leaves an inherited w:themeFill (CR-015)
370
+ if (statesColour(s.color, s.themeColor)) {
371
+ out.color = s.color;
372
+ out.themeColor = s.themeColor;
373
+ out.themeTint = s.themeTint;
374
+ out.themeShade = s.themeShade;
375
+ }
376
+ else {
377
+ out.themeTint = attr(s.themeTint, out.themeTint);
378
+ out.themeShade = attr(s.themeShade, out.themeShade);
379
+ }
380
+ if (statesColour(s.fill, s.themeFill)) {
381
+ out.fill = s.fill;
382
+ out.themeFill = s.themeFill;
383
+ out.themeFillTint = s.themeFillTint;
384
+ out.themeFillShade = s.themeFillShade;
385
+ }
386
+ else {
387
+ out.themeFillTint = attr(s.themeFillTint, out.themeFillTint);
388
+ out.themeFillShade = attr(s.themeFillShade, out.themeFillShade);
389
+ }
344
390
  return out;
345
391
  };
346
392
  export const mergeBorder = (source, destination) => {
@@ -348,13 +394,20 @@ export const mergeBorder = (source, destination) => {
348
394
  return destination;
349
395
  const s = source;
350
396
  const out = (destination !== null && destination !== void 0 ? destination : {});
351
- out.color = attr(s.color, out.color);
352
397
  out.space = attr(s.space, out.space);
353
398
  out.sz = attr(s.sz, out.sz);
354
- out.themeColor = themeColor(s.themeColor, out.themeColor);
355
- out.themeShade = attr(s.themeShade, out.themeShade);
356
- out.themeTint = attr(s.themeTint, out.themeTint);
357
399
  out.val = attr(s.val, out.val);
400
+ // the colour inherits as one (see mergeColor)
401
+ if (statesColour(s.color, s.themeColor)) {
402
+ out.color = s.color;
403
+ out.themeColor = s.themeColor;
404
+ out.themeTint = s.themeTint;
405
+ out.themeShade = s.themeShade;
406
+ }
407
+ else {
408
+ out.themeShade = attr(s.themeShade, out.themeShade);
409
+ out.themeTint = attr(s.themeTint, out.themeTint);
410
+ }
358
411
  return out;
359
412
  };
360
413
  export const mergePBdr = (source, destination) => {
@@ -40,9 +40,21 @@ export declare class CellContext {
40
40
  /**
41
41
  * Whether the table style gives this paragraph anything at all: its own `w:pPr` or `w:rPr`, or
42
42
  * a conditional format with one. Where it does not, resolving with this context gives the same
43
- * answer as resolving without one.
43
+ * answer as resolving without one - except under [MS-DOCX]'s size exception, for which see
44
+ * {@link styleFormatsText}.
44
45
  */
45
46
  readonly formatsText: boolean;
47
+ /**
48
+ * Whether the table style formats text anywhere: its own `w:pPr` or `w:rPr`, or a conditional
49
+ * format with one, whether or not that condition holds for this paragraph. Below compatibility
50
+ * mode 15 this, not what applies here, is what brings [MS-DOCX]'s size exception into play:
51
+ * measured on docx4j's table-style-size-trigger probes (its corpus document 1912), a table
52
+ * style with only a `w:pPr`, only an `w:rPr` colour, or only a `firstRow` format sets every row
53
+ * of its table at the document defaults' size where Normal states 12pt - the `firstRow`
54
+ * format's second row included - while a style with none of these leaves Normal's 12pt.
55
+ * docx4j `styleFormatsText()` (900b6a212, 17.3.2).
56
+ */
57
+ readonly styleFormatsText: boolean;
46
58
  /** What the table level's composition depends on. A value, for keying caches. */
47
59
  readonly key: CellContextKey;
48
60
  constructor(
@@ -138,7 +150,9 @@ export declare class TableContextTracker {
138
150
  /**
139
151
  * Walks everything under `root` (an object, an element pair or an array of them), in document
140
152
  * order, calling `visit` for each paragraph with its context. It descends through every
141
- * member but the `PARENT` pointers, so a text box's paragraphs are reached, in no table.
153
+ * member but the `PARENT` pointers, so a text box's paragraphs are reached, in no table. A kept
154
+ * `mc:AlternateContent` is descended through its selected branch alone (`selectedBranchOf`,
155
+ * docx4j's `McMode.READ`), so a text box held in both branches is visited once (CR-010 phase 3).
142
156
  */
143
157
  walk(root: unknown, visit: (p: wml.P, cellContext: CellContext | undefined) => void): void;
144
158
  }
@@ -1,5 +1,5 @@
1
1
  import { isEmptyPPr, isEmptyRPr } from './styleUtil.mjs';
2
- import { rowsOf, cellsOf } from '../content/tree.mjs';
2
+ import { rowsOf, cellsOf, selectedBranchOf, ALTERNATE_CONTENT } from '../content/tree.mjs';
3
3
  import { PRECEDENCE, DEFAULT_LOOK, lookOf, rowBandSize, colBandSize, rowCnf, resolve, rowConditions, applicable, formatsText, key as conditionsKey, } from './tableStyleConditions.mjs';
4
4
  /** The conditions as bits over {@link PRECEDENCE}: an exact value for keying caches. */
5
5
  function maskOf(conditions) {
@@ -43,6 +43,7 @@ export class CellContext {
43
43
  tableStyleId,
44
44
  /** That style's `w:basedOn` chain merged (`getTableStyleChain`): shared, read it only. */
45
45
  tableStyle, conditions) {
46
+ var _a;
46
47
  this.tableStyleId = tableStyleId;
47
48
  this.tableStyle = tableStyle;
48
49
  const c = new Set(conditions !== null && conditions !== void 0 ? conditions : []);
@@ -56,7 +57,10 @@ export class CellContext {
56
57
  }
57
58
  }
58
59
  this.textConditions = text;
59
- this.formatsText = text.length > 0 || !isEmptyPPr(tableStyle.pPr) || !isEmptyRPr(tableStyle.rPr);
60
+ const own = !isEmptyPPr(tableStyle.pPr) || !isEmptyRPr(tableStyle.rPr);
61
+ this.formatsText = text.length > 0 || own;
62
+ this.styleFormatsText = own
63
+ || ((_a = tableStyle.tblStylePr) !== null && _a !== void 0 ? _a : []).some((pr) => pr !== undefined && pr !== null && formatsText(pr));
60
64
  this.key = new CellContextKey(tableStyleId, named);
61
65
  }
62
66
  toString() {
@@ -248,7 +252,9 @@ export class TableContextTracker {
248
252
  /**
249
253
  * Walks everything under `root` (an object, an element pair or an array of them), in document
250
254
  * order, calling `visit` for each paragraph with its context. It descends through every
251
- * member but the `PARENT` pointers, so a text box's paragraphs are reached, in no table.
255
+ * member but the `PARENT` pointers, so a text box's paragraphs are reached, in no table. A kept
256
+ * `mc:AlternateContent` is descended through its selected branch alone (`selectedBranchOf`,
257
+ * docx4j's `McMode.READ`), so a text box held in both branches is visited once (CR-010 phase 3).
252
258
  */
253
259
  walk(root, visit) {
254
260
  const seen = new Set();
@@ -264,6 +270,10 @@ export class TableContextTracker {
264
270
  return;
265
271
  seen.add(o);
266
272
  const typeName = o.TYPE_NAME;
273
+ if (typeName === ALTERNATE_CONTENT) {
274
+ descend(selectedBranchOf(o), depth + 1);
275
+ return;
276
+ }
267
277
  if (typeName === P)
268
278
  visit(o, this.cellContext(o));
269
279
  const leave = this.enter(o);
@@ -5,9 +5,16 @@ import type { OpcPackage } from '../packages/OpcPackage.mjs';
5
5
  export interface LoadOptions {
6
6
  /** Part classes by content type; defaults to docx4j's table. */
7
7
  registry?: PartRegistry;
8
- /** Resolve `mc:AlternateContent` before unmarshalling (default true, as docx4j and Word). */
8
+ /**
9
+ * Resolve `mc:AlternateContent` before unmarshalling, as Word does on open. Default false since
10
+ * CR-010 phase 4: every element is kept with all its branches, as docx4j keeps it since its CR-021;
11
+ * readers take the branch resolving would (`selectedBranchOf`), mutators every branch, and a save
12
+ * writes them all. Either way a part's `warnings` report where the branches' text differs. True
13
+ * resolves, but keeps the element under a `KEPT_HOSTS` host and one nothing can be selected from
14
+ * (CR-010 phase 1).
15
+ */
9
16
  mcePreprocess?: boolean;
10
- /** Runs over every XML part's DOM before it is unmarshalled; set by the package from `mcePreprocess`. */
17
+ /** Runs over every XML part's DOM before it is unmarshalled; set by the package from `mcePreprocess` (`mceKeep` or `mcePreprocess`). */
11
18
  preprocessor?: DomPreprocessor;
12
19
  }
13
20
  /**
@@ -6,7 +6,7 @@ export { ZipPartStore, ZipPartSink } from './ZipPartStore.mjs';
6
6
  export { FlatOpcPartStore, FlatOpcPartSink, type FlatOpcSinkOptions, PKG_NS } from './FlatOpcPartStore.mjs';
7
7
  export { loadPackage, type LoadOptions } from './Load.mjs';
8
8
  export { savePackage } from './Save.mjs';
9
- export { mcePreprocess, createMcePreprocessor, resolveAlternateContent, MCE_NS, type McePreprocessOptions } from './mce/preprocessor.mjs';
10
- export { UNDERSTOOD_NAMESPACES } from './mce/understood.mjs';
9
+ export { mceKeep, mcePreprocess, createMcePreprocessor, resolveAlternateContent, preprocessAlternateContent, MCE_NS, KEPT_HOSTS, type McePreprocessOptions, type McBranchesDifferWarning, type PartWarning, type MceResult } from './mce/preprocessor.mjs';
10
+ export { UNDERSTOOD_NAMESPACES, UNDERSTOOD_PREFIXES } from './mce/understood.mjs';
11
11
  export { Docx4JException, InvalidFormatException, PartUnrecognisedException, PartUnmarshalException, CyclicStylesException, PropertyResolverNotCreatedException } from './exceptions.mjs';
12
12
  export { parseXml, serializeXml, serializeXmlPart, createDocument, encodeText, decodeXmlText, stripXmlDeclaration, base64Encode, base64Decode, childElements, XML_DECLARATION } from '../xml/dom.mjs';
@@ -7,7 +7,7 @@ export { ZipPartStore, ZipPartSink } from './ZipPartStore.mjs';
7
7
  export { FlatOpcPartStore, FlatOpcPartSink, PKG_NS } from './FlatOpcPartStore.mjs';
8
8
  export { loadPackage } from './Load.mjs';
9
9
  export { savePackage } from './Save.mjs';
10
- export { mcePreprocess, createMcePreprocessor, resolveAlternateContent, MCE_NS } from './mce/preprocessor.mjs';
11
- export { UNDERSTOOD_NAMESPACES } from './mce/understood.mjs';
10
+ export { mceKeep, mcePreprocess, createMcePreprocessor, resolveAlternateContent, preprocessAlternateContent, MCE_NS, KEPT_HOSTS } from './mce/preprocessor.mjs';
11
+ export { UNDERSTOOD_NAMESPACES, UNDERSTOOD_PREFIXES } from './mce/understood.mjs';
12
12
  export { Docx4JException, InvalidFormatException, PartUnrecognisedException, PartUnmarshalException, CyclicStylesException, PropertyResolverNotCreatedException } from './exceptions.mjs';
13
13
  export { parseXml, serializeXml, serializeXmlPart, createDocument, encodeText, decodeXmlText, stripXmlDeclaration, base64Encode, base64Decode, childElements, XML_DECLARATION } from '../xml/dom.mjs';