@docx4j/core-ts 0.3.0 → 0.3.2

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 (42) hide show
  1. package/dist/model/content/Body.mjs +40 -19
  2. package/dist/model/content/Comment.d.mts +6 -0
  3. package/dist/model/content/Comment.mjs +76 -22
  4. package/dist/model/content/ContentControl.d.mts +11 -1
  5. package/dist/model/content/ContentControl.mjs +69 -10
  6. package/dist/model/content/Paragraph.d.mts +37 -2
  7. package/dist/model/content/Paragraph.mjs +140 -38
  8. package/dist/model/content/Range.mjs +49 -5
  9. package/dist/model/content/Table.mjs +6 -8
  10. package/dist/model/content/TrackedChange.d.mts +32 -4
  11. package/dist/model/content/TrackedChange.mjs +271 -34
  12. package/dist/model/content/index.d.mts +1 -1
  13. package/dist/model/content/index.mjs +1 -1
  14. package/dist/model/content/stylesFacade.mjs +9 -3
  15. package/dist/model/content/tracking.d.mts +65 -5
  16. package/dist/model/content/tracking.mjs +170 -43
  17. package/dist/model/customxml/XmlMapping.d.mts +20 -4
  18. package/dist/model/customxml/XmlMapping.mjs +44 -6
  19. package/dist/model/customxml/bindings.d.mts +9 -2
  20. package/dist/model/customxml/bindings.mjs +18 -2
  21. package/dist/model/customxml/index.d.mts +1 -1
  22. package/dist/model/customxml/index.mjs +1 -1
  23. package/dist/model/customxml/insert.d.mts +10 -0
  24. package/dist/model/customxml/insert.mjs +13 -0
  25. package/dist/model/fonts/RunFontSelector.d.mts +8 -1
  26. package/dist/model/fonts/RunFontSelector.mjs +6 -5
  27. package/dist/model/properties/PropertyResolver.d.mts +110 -10
  28. package/dist/model/properties/PropertyResolver.mjs +300 -31
  29. package/dist/model/properties/index.d.mts +3 -0
  30. package/dist/model/properties/index.mjs +2 -0
  31. package/dist/model/properties/table.d.mts +155 -0
  32. package/dist/model/properties/table.mjs +315 -0
  33. package/dist/model/properties/tableStyleConditions.d.mts +101 -0
  34. package/dist/model/properties/tableStyleConditions.mjs +296 -0
  35. package/dist/packages/WordprocessingMLPackage.d.mts +6 -0
  36. package/dist/packages/WordprocessingMLPackage.mjs +11 -0
  37. package/dist/parts/wml/commentStyles.d.mts +3 -0
  38. package/dist/parts/wml/commentStyles.mjs +25 -0
  39. package/dist/parts/wml/comments.mjs +4 -22
  40. package/dist/parts/wml/placeholderStyle.d.mts +3 -0
  41. package/dist/parts/wml/placeholderStyle.mjs +13 -0
  42. package/package.json +2 -2
@@ -0,0 +1,155 @@
1
+ import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
2
+ import { type Condition, type Look } from './tableStyleConditions.mjs';
3
+ /**
4
+ * The table level of a paragraph's formatting, as a value: two paragraphs whose keys are equal
5
+ * get the same contribution from their table. A structured key, never a joined string (docx4j
6
+ * CR-030 D8: ids may contain the separator); `mask` is the conditions as a number, so a cache
7
+ * keys on the table style id and then on it.
8
+ */
9
+ export declare class CellContextKey {
10
+ readonly tableStyleId: string | undefined;
11
+ /** The conditional formats which give the paragraph text formatting, `wholeTable` included where the style has one. */
12
+ readonly conditions: ReadonlySet<Condition>;
13
+ /** The conditions as bits over {@link PRECEDENCE}. */
14
+ readonly mask: number;
15
+ constructor(tableStyleId: string | undefined,
16
+ /** The conditional formats which give the paragraph text formatting, `wholeTable` included where the style has one. */
17
+ conditions: ReadonlySet<Condition>);
18
+ equals(other: CellContextKey | undefined): boolean;
19
+ toString(): string;
20
+ }
21
+ /**
22
+ * Where a paragraph sits in a table, as far as its formatting is concerned: the table style
23
+ * which applies to the table, and the conditional formats the paragraph is under. Handed to the
24
+ * `PropertyResolver` overloads which take one. Obtained from a {@link TableContext}
25
+ * (`forParagraph`), from a {@link TableContextTracker} during a walk, or from
26
+ * `PropertyResolver.cellContextOf(p)`. Undefined stands for "not in a table". Immutable.
27
+ */
28
+ export declare class CellContext {
29
+ /** The id of the table style the table resolves to, or undefined where none applies. */
30
+ readonly tableStyleId: string | undefined;
31
+ /** That style's `w:basedOn` chain merged (`getTableStyleChain`): shared, read it only. */
32
+ readonly tableStyle: wml.Style;
33
+ /** The conditions the paragraph is under, gated by the table's `w:tblLook`. */
34
+ readonly conditions: ReadonlySet<Condition>;
35
+ /**
36
+ * The table style's conditional formats which apply here and give text a `w:pPr` or `w:rPr`,
37
+ * in the order they are applied (ECMA-376-1 17.7.6).
38
+ */
39
+ readonly textConditions: readonly wml.CTTblStylePr[];
40
+ /**
41
+ * Whether the table style gives this paragraph anything at all: its own `w:pPr` or `w:rPr`, or
42
+ * a conditional format with one. Where it does not, resolving with this context gives the same
43
+ * answer as resolving without one.
44
+ */
45
+ readonly formatsText: boolean;
46
+ /** What the table level's composition depends on. A value, for keying caches. */
47
+ readonly key: CellContextKey;
48
+ constructor(
49
+ /** The id of the table style the table resolves to, or undefined where none applies. */
50
+ tableStyleId: string | undefined,
51
+ /** That style's `w:basedOn` chain merged (`getTableStyleChain`): shared, read it only. */
52
+ tableStyle: wml.Style, conditions: ReadonlySet<Condition> | undefined);
53
+ toString(): string;
54
+ }
55
+ /** What a {@link TableContext} needs of the resolver; `PropertyResolver` satisfies it. */
56
+ export interface TableStyleSource {
57
+ getTableStyleIdOf(tblPr: wml.CTTblPrBase | undefined): string | undefined;
58
+ getTableStyleChain(styleId: string | undefined): wml.Style;
59
+ }
60
+ /**
61
+ * What a table's paragraphs need to know about it to be formatted: the table style it resolves
62
+ * to (its `w:basedOn` chain merged), the conditional formats its `w:tblLook` asks for, its band
63
+ * sizes, and where each row and cell sits. {@link forParagraph} then gives the
64
+ * {@link CellContext} of a paragraph in one of its cells.
65
+ *
66
+ * A reading of the table's *content* (rows, spans, look), so it is built fresh for each table by
67
+ * `PropertyResolver.tableContext(tbl)` and held by the caller while it is in the table; the
68
+ * resolver keeps none (a cached one would go stale when a row is added). The rows and cells are
69
+ * counted with nested tables excluded, a cell's column its row's `w:gridBefore` plus the spans
70
+ * before it.
71
+ */
72
+ export declare class TableContext {
73
+ /** The id of the table style the table resolves to, or undefined. */
74
+ readonly tableStyleId: string | undefined;
75
+ /** Whether the table states its own `w:tblStyle` (rather than taking the default table style). */
76
+ readonly namesStyle: boolean;
77
+ /** The table style's chain merged; shared, read it only. */
78
+ readonly tableStyle: wml.Style;
79
+ readonly look: Look;
80
+ readonly rowBandSize: number;
81
+ readonly colBandSize: number;
82
+ readonly rowCount: number;
83
+ readonly colCount: number;
84
+ private readonly rowIndex;
85
+ /** [first grid column, span] per cell */
86
+ private readonly cellColumns;
87
+ /** Use `PropertyResolver.tableContext(tbl)`. */
88
+ constructor(tbl: wml.Tbl, resolver: TableStyleSource);
89
+ /**
90
+ * The context of a paragraph in this table: the conditions its row, its cell and its own
91
+ * `w:cnfStyle` caches say it is under, or its position where they say nothing. A row or cell
92
+ * this table does not hold (a nested table's, or one added since this context was built) is
93
+ * under no condition.
94
+ */
95
+ forParagraph(tr: wml.Tr | undefined, tc: wml.Tc | undefined, pPr?: wml.PPr | undefined): CellContext;
96
+ /** The context of a cell, for its row and cell properties: {@link forParagraph} without a paragraph's own `w:cnfStyle`. */
97
+ forCell(tr: wml.Tr | undefined, tc: wml.Tc | undefined): CellContext;
98
+ /** The row-axis conditions a row is under, for its own properties; none for a row this table does not hold. */
99
+ rowConditions(tr: wml.Tr | undefined): Set<Condition>;
100
+ /** The table style's `w:tblStylePr` entries which apply under these conditions, in order: all of them. */
101
+ applicable(conditions: ReadonlySet<Condition>): wml.CTTblStylePr[];
102
+ /** The row's index in the table, nested tables excluded, or -1 for a row it does not hold. */
103
+ rowIndexOf(tr: wml.Tr | undefined): number;
104
+ private conditions;
105
+ }
106
+ /** What a tracker needs of the resolver. */
107
+ export interface TableContextSource {
108
+ tableContext(tbl: wml.Tbl): TableContext;
109
+ }
110
+ /**
111
+ * Knows, for each paragraph a walk reaches, the table context the paragraph is in: the way to
112
+ * resolve every paragraph of a document in context (`PropertyResolver.cellContextOf(p)` builds a
113
+ * {@link TableContext} per call and is for one paragraph at a time).
114
+ *
115
+ * docx4j's is a `TraversalUtil` callback to extend; here it is the stack on its own, driven by
116
+ * any walker: call {@link enter} with each object before descending into it and the function it
117
+ * returns afterwards, and {@link cellContext} for each paragraph. {@link walk} is a walker that
118
+ * does so over a whole tree.
119
+ *
120
+ * The table on top of the stack is the paragraph's own (a nested table pushes its own context).
121
+ * A text box is a story of its own, so the walk starts an empty stack inside every text box and
122
+ * restores the cell's on the way out.
123
+ */
124
+ export declare class TableContextTracker {
125
+ private readonly resolver;
126
+ /** One entry per table being walked, innermost last; a barrier (no table) inside a text box. */
127
+ private readonly stack;
128
+ constructor(resolver: TableContextSource | undefined);
129
+ /**
130
+ * Call before descending into an object (a `w:tbl`, `w:tr`, `w:tc`, or anything else: other
131
+ * types change nothing unless they begin a story); call what it returns after its children.
132
+ */
133
+ enter(o: unknown): () => void;
134
+ /** The context of a paragraph reached by this walk, or undefined where it is in no table (or in a text box). */
135
+ cellContext(p: wml.P): CellContext | undefined;
136
+ /** The table the walk is in, or undefined (outside any table, or in a text box). */
137
+ tableContext(): TableContext | undefined;
138
+ /**
139
+ * Walks everything under `root` (an object, an element pair or an array of them), in document
140
+ * 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.
142
+ */
143
+ walk(root: unknown, visit: (p: wml.P, cellContext: CellContext | undefined) => void): void;
144
+ }
145
+ /**
146
+ * The nearest enclosing cell, row and table of a paragraph, through its `PARENT` pointers and
147
+ * whatever lies between (`w:sdt`, `w:customXml`, `w:smartTag`); undefined where the paragraph is
148
+ * in no table, where a story begins before a cell is reached, or where the pointers are not
149
+ * there (content built by hand and never linked: `linkParents`).
150
+ */
151
+ export declare function enclosingCellOf(p: wml.P): {
152
+ tbl: wml.Tbl;
153
+ tr: wml.Tr;
154
+ tc: wml.Tc;
155
+ } | undefined;
@@ -0,0 +1,315 @@
1
+ import { isEmptyPPr, isEmptyRPr } from './styleUtil.mjs';
2
+ import { rowsOf, cellsOf } from '../content/tree.mjs';
3
+ import { PRECEDENCE, DEFAULT_LOOK, lookOf, rowBandSize, colBandSize, rowCnf, resolve, rowConditions, applicable, formatsText, key as conditionsKey, } from './tableStyleConditions.mjs';
4
+ /** The conditions as bits over {@link PRECEDENCE}: an exact value for keying caches. */
5
+ function maskOf(conditions) {
6
+ let mask = 0;
7
+ PRECEDENCE.forEach((t, i) => { if (conditions.has(t))
8
+ mask |= 1 << i; });
9
+ return mask;
10
+ }
11
+ /**
12
+ * The table level of a paragraph's formatting, as a value: two paragraphs whose keys are equal
13
+ * get the same contribution from their table. A structured key, never a joined string (docx4j
14
+ * CR-030 D8: ids may contain the separator); `mask` is the conditions as a number, so a cache
15
+ * keys on the table style id and then on it.
16
+ */
17
+ export class CellContextKey {
18
+ constructor(tableStyleId,
19
+ /** The conditional formats which give the paragraph text formatting, `wholeTable` included where the style has one. */
20
+ conditions) {
21
+ this.tableStyleId = tableStyleId;
22
+ this.conditions = conditions;
23
+ this.mask = maskOf(conditions);
24
+ }
25
+ equals(other) {
26
+ return other !== undefined && this.tableStyleId === other.tableStyleId && this.mask === other.mask;
27
+ }
28
+ toString() {
29
+ var _a;
30
+ return `${(_a = this.tableStyleId) !== null && _a !== void 0 ? _a : null} [${PRECEDENCE.filter((t) => this.conditions.has(t)).join(', ')}]`;
31
+ }
32
+ }
33
+ /**
34
+ * Where a paragraph sits in a table, as far as its formatting is concerned: the table style
35
+ * which applies to the table, and the conditional formats the paragraph is under. Handed to the
36
+ * `PropertyResolver` overloads which take one. Obtained from a {@link TableContext}
37
+ * (`forParagraph`), from a {@link TableContextTracker} during a walk, or from
38
+ * `PropertyResolver.cellContextOf(p)`. Undefined stands for "not in a table". Immutable.
39
+ */
40
+ export class CellContext {
41
+ constructor(
42
+ /** The id of the table style the table resolves to, or undefined where none applies. */
43
+ tableStyleId,
44
+ /** That style's `w:basedOn` chain merged (`getTableStyleChain`): shared, read it only. */
45
+ tableStyle, conditions) {
46
+ this.tableStyleId = tableStyleId;
47
+ this.tableStyle = tableStyle;
48
+ const c = new Set(conditions !== null && conditions !== void 0 ? conditions : []);
49
+ this.conditions = c;
50
+ const text = [];
51
+ const named = new Set();
52
+ for (const pr of applicable(tableStyle, c)) {
53
+ if (formatsText(pr)) {
54
+ text.push(pr);
55
+ named.add(pr.type);
56
+ }
57
+ }
58
+ this.textConditions = text;
59
+ this.formatsText = text.length > 0 || !isEmptyPPr(tableStyle.pPr) || !isEmptyRPr(tableStyle.rPr);
60
+ this.key = new CellContextKey(tableStyleId, named);
61
+ }
62
+ toString() {
63
+ var _a;
64
+ return `CellContext[${(_a = this.tableStyleId) !== null && _a !== void 0 ? _a : null} ${conditionsKey(this.conditions)}]`;
65
+ }
66
+ }
67
+ function gridOf(tr, name) {
68
+ var _a, _b, _c, _d;
69
+ for (const item of ((_b = (_a = tr.trPr) === null || _a === void 0 ? void 0 : _a.cnfStyleOrDivIdOrGridBefore) !== null && _b !== void 0 ? _b : [])) {
70
+ if (((_c = item === null || item === void 0 ? void 0 : item.name) === null || _c === void 0 ? void 0 : _c.localPart) === name) {
71
+ const val = (_d = item.value) === null || _d === void 0 ? void 0 : _d.val;
72
+ return typeof val === 'number' ? Math.max(0, Math.trunc(val)) : 0;
73
+ }
74
+ }
75
+ return 0;
76
+ }
77
+ /**
78
+ * What a table's paragraphs need to know about it to be formatted: the table style it resolves
79
+ * to (its `w:basedOn` chain merged), the conditional formats its `w:tblLook` asks for, its band
80
+ * sizes, and where each row and cell sits. {@link forParagraph} then gives the
81
+ * {@link CellContext} of a paragraph in one of its cells.
82
+ *
83
+ * A reading of the table's *content* (rows, spans, look), so it is built fresh for each table by
84
+ * `PropertyResolver.tableContext(tbl)` and held by the caller while it is in the table; the
85
+ * resolver keeps none (a cached one would go stale when a row is added). The rows and cells are
86
+ * counted with nested tables excluded, a cell's column its row's `w:gridBefore` plus the spans
87
+ * before it.
88
+ */
89
+ export class TableContext {
90
+ /** Use `PropertyResolver.tableContext(tbl)`. */
91
+ constructor(tbl, resolver) {
92
+ this.rowIndex = new Map();
93
+ /** [first grid column, span] per cell */
94
+ this.cellColumns = new Map();
95
+ const tblPr = tbl.tblPr;
96
+ this.tableStyleId = resolver.getTableStyleIdOf(tblPr);
97
+ this.namesStyle = (tblPr === null || tblPr === void 0 ? void 0 : tblPr.tblStyle) !== undefined;
98
+ this.tableStyle = resolver.getTableStyleChain(this.tableStyleId);
99
+ // the table's own tblPr decides the look and band sizes; the style's is the fallback
100
+ const stylePr = this.tableStyle.tblPr;
101
+ if ((tblPr === null || tblPr === void 0 ? void 0 : tblPr.tblLook) !== undefined)
102
+ this.look = lookOf(tblPr.tblLook);
103
+ else if ((stylePr === null || stylePr === void 0 ? void 0 : stylePr.tblLook) !== undefined)
104
+ this.look = lookOf(stylePr.tblLook);
105
+ else
106
+ this.look = DEFAULT_LOOK;
107
+ this.rowBandSize = (tblPr === null || tblPr === void 0 ? void 0 : tblPr.tblStyleRowBandSize) !== undefined ? rowBandSize(tblPr) : rowBandSize(stylePr);
108
+ this.colBandSize = (tblPr === null || tblPr === void 0 ? void 0 : tblPr.tblStyleColBandSize) !== undefined ? colBandSize(tblPr) : colBandSize(stylePr);
109
+ const rows = rowsOf(tbl);
110
+ let cols = 0;
111
+ rows.forEach((located, r) => {
112
+ var _a, _b;
113
+ const tr = located.element.value;
114
+ this.rowIndex.set(tr, r);
115
+ let c = gridOf(tr, 'gridBefore');
116
+ for (const cell of cellsOf(tr)) {
117
+ const tc = cell.element.value;
118
+ const val = (_b = (_a = tc.tcPr) === null || _a === void 0 ? void 0 : _a.gridSpan) === null || _b === void 0 ? void 0 : _b.val;
119
+ const span = typeof val === 'number' ? Math.max(1, Math.trunc(val)) : 1;
120
+ this.cellColumns.set(tc, [c, span]);
121
+ c += span;
122
+ }
123
+ c += gridOf(tr, 'gridAfter');
124
+ if (c > cols)
125
+ cols = c;
126
+ });
127
+ this.rowCount = rows.length;
128
+ this.colCount = cols;
129
+ }
130
+ /**
131
+ * The context of a paragraph in this table: the conditions its row, its cell and its own
132
+ * `w:cnfStyle` caches say it is under, or its position where they say nothing. A row or cell
133
+ * this table does not hold (a nested table's, or one added since this context was built) is
134
+ * under no condition.
135
+ */
136
+ forParagraph(tr, tc, pPr) {
137
+ return new CellContext(this.tableStyleId, this.tableStyle, this.conditions(tr, tc, pPr));
138
+ }
139
+ /** The context of a cell, for its row and cell properties: {@link forParagraph} without a paragraph's own `w:cnfStyle`. */
140
+ forCell(tr, tc) {
141
+ return this.forParagraph(tr, tc, undefined);
142
+ }
143
+ /** The row-axis conditions a row is under, for its own properties; none for a row this table does not hold. */
144
+ rowConditions(tr) {
145
+ const r = tr === undefined ? undefined : this.rowIndex.get(tr);
146
+ if (r === undefined)
147
+ return new Set();
148
+ return rowConditions(this.look, this.rowBandSize, r, this.rowCount, rowCnf(tr.trPr));
149
+ }
150
+ /** The table style's `w:tblStylePr` entries which apply under these conditions, in order: all of them. */
151
+ applicable(conditions) {
152
+ return applicable(this.tableStyle, conditions);
153
+ }
154
+ /** The row's index in the table, nested tables excluded, or -1 for a row it does not hold. */
155
+ rowIndexOf(tr) {
156
+ const r = tr === undefined ? undefined : this.rowIndex.get(tr);
157
+ return r === undefined ? -1 : r;
158
+ }
159
+ conditions(tr, tc, pPr) {
160
+ var _a;
161
+ const r = tr === undefined ? undefined : this.rowIndex.get(tr);
162
+ const cc = tc === undefined ? undefined : this.cellColumns.get(tc);
163
+ if (r === undefined || cc === undefined)
164
+ return new Set();
165
+ return resolve(this.look, this.rowBandSize, this.colBandSize, r, this.rowCount, cc[0], cc[1], this.colCount, rowCnf(tr.trPr), (_a = tc.tcPr) === null || _a === void 0 ? void 0 : _a.cnfStyle, pPr === null || pPr === void 0 ? void 0 : pPr.cnfStyle);
166
+ }
167
+ }
168
+ const TBL = 'org_docx4j_wml.Tbl';
169
+ const TR = 'org_docx4j_wml.Tr';
170
+ const TC = 'org_docx4j_wml.Tc';
171
+ const P = 'org_docx4j_wml.P';
172
+ const TXBX_CONTENT = 'org_docx4j_wml.CTTxbxContent';
173
+ /**
174
+ * The objects a walk entering which enters another story: `w:txbxContent`, and what a walk
175
+ * reaches it through (a VML text box, a DrawingML anchor or inline). Word gives the paragraphs
176
+ * of a text box anchored in a cell none of the table's formatting (docx4j CR-030 probe T3).
177
+ */
178
+ const STORY_BOUNDARIES = new Set([
179
+ TXBX_CONTENT,
180
+ 'org_docx4j_vml.CTTextbox',
181
+ 'org_docx4j_dml_wordprocessingDrawing.Anchor',
182
+ 'org_docx4j_dml_wordprocessingDrawing.Inline',
183
+ ]);
184
+ /**
185
+ * Knows, for each paragraph a walk reaches, the table context the paragraph is in: the way to
186
+ * resolve every paragraph of a document in context (`PropertyResolver.cellContextOf(p)` builds a
187
+ * {@link TableContext} per call and is for one paragraph at a time).
188
+ *
189
+ * docx4j's is a `TraversalUtil` callback to extend; here it is the stack on its own, driven by
190
+ * any walker: call {@link enter} with each object before descending into it and the function it
191
+ * returns afterwards, and {@link cellContext} for each paragraph. {@link walk} is a walker that
192
+ * does so over a whole tree.
193
+ *
194
+ * The table on top of the stack is the paragraph's own (a nested table pushes its own context).
195
+ * A text box is a story of its own, so the walk starts an empty stack inside every text box and
196
+ * restores the cell's on the way out.
197
+ */
198
+ export class TableContextTracker {
199
+ constructor(resolver) {
200
+ this.resolver = resolver;
201
+ /** One entry per table being walked, innermost last; a barrier (no table) inside a text box. */
202
+ this.stack = [];
203
+ }
204
+ /**
205
+ * Call before descending into an object (a `w:tbl`, `w:tr`, `w:tc`, or anything else: other
206
+ * types change nothing unless they begin a story); call what it returns after its children.
207
+ */
208
+ enter(o) {
209
+ var _a;
210
+ const typeName = o === null || o === void 0 ? void 0 : o.TYPE_NAME;
211
+ if (typeName === undefined)
212
+ return NOTHING;
213
+ const enclosing = this.stack[this.stack.length - 1];
214
+ if (typeName === TBL) {
215
+ // with no resolver, nothing is tracked: every paragraph is in no table
216
+ this.stack.push({ table: (_a = this.resolver) === null || _a === void 0 ? void 0 : _a.tableContext(o), tr: undefined, tc: undefined });
217
+ return () => { this.stack.pop(); };
218
+ }
219
+ if (STORY_BOUNDARIES.has(typeName)) {
220
+ this.stack.push({ table: undefined, tr: undefined, tc: undefined });
221
+ return () => { this.stack.pop(); };
222
+ }
223
+ if ((enclosing === null || enclosing === void 0 ? void 0 : enclosing.table) !== undefined && typeName === TR) {
224
+ const { tr, tc } = enclosing;
225
+ enclosing.tr = o;
226
+ enclosing.tc = undefined;
227
+ return () => { enclosing.tr = tr; enclosing.tc = tc; };
228
+ }
229
+ if ((enclosing === null || enclosing === void 0 ? void 0 : enclosing.table) !== undefined && typeName === TC) {
230
+ const tc = enclosing.tc;
231
+ enclosing.tc = o;
232
+ return () => { enclosing.tc = tc; };
233
+ }
234
+ return NOTHING;
235
+ }
236
+ /** The context of a paragraph reached by this walk, or undefined where it is in no table (or in a text box). */
237
+ cellContext(p) {
238
+ const f = this.stack[this.stack.length - 1];
239
+ if ((f === null || f === void 0 ? void 0 : f.table) === undefined)
240
+ return undefined;
241
+ return f.table.forParagraph(f.tr, f.tc, p.pPr);
242
+ }
243
+ /** The table the walk is in, or undefined (outside any table, or in a text box). */
244
+ tableContext() {
245
+ var _a;
246
+ return (_a = this.stack[this.stack.length - 1]) === null || _a === void 0 ? void 0 : _a.table;
247
+ }
248
+ /**
249
+ * Walks everything under `root` (an object, an element pair or an array of them), in document
250
+ * 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.
252
+ */
253
+ walk(root, visit) {
254
+ const seen = new Set();
255
+ const descend = (o, depth) => {
256
+ if (o === null || typeof o !== 'object' || depth > 200)
257
+ return;
258
+ if (Array.isArray(o)) {
259
+ for (const item of o)
260
+ descend(item, depth + 1);
261
+ return;
262
+ }
263
+ if (seen.has(o))
264
+ return;
265
+ seen.add(o);
266
+ const typeName = o.TYPE_NAME;
267
+ if (typeName === P)
268
+ visit(o, this.cellContext(o));
269
+ const leave = this.enter(o);
270
+ for (const key of Object.keys(o)) {
271
+ if (key === 'PARENT')
272
+ continue;
273
+ descend(o[key], depth + 1);
274
+ }
275
+ leave();
276
+ };
277
+ descend(root, 0);
278
+ }
279
+ }
280
+ const NOTHING = () => { };
281
+ /** The types at which a walk up the parent pointers has left the cell's story, or reached a story root. */
282
+ const STORY_ROOTS = new Set([
283
+ TXBX_CONTENT, 'org_docx4j_wml.CTFtnEdn', 'org_docx4j_wml.Comments.Comment',
284
+ 'org_docx4j_wml.Hdr', 'org_docx4j_wml.Ftr', 'org_docx4j_wml.Body', 'org_docx4j_wml.Document',
285
+ ]);
286
+ /**
287
+ * The nearest enclosing cell, row and table of a paragraph, through its `PARENT` pointers and
288
+ * whatever lies between (`w:sdt`, `w:customXml`, `w:smartTag`); undefined where the paragraph is
289
+ * in no table, where a story begins before a cell is reached, or where the pointers are not
290
+ * there (content built by hand and never linked: `linkParents`).
291
+ */
292
+ export function enclosingCellOf(p) {
293
+ let tc;
294
+ let tr;
295
+ const parentOf = (o) => o === null || o === void 0 ? void 0 : o.PARENT;
296
+ let hops = 0;
297
+ for (let o = parentOf(p); o !== undefined && o !== null && hops < 1000; o = parentOf(o), hops++) {
298
+ const typeName = o.TYPE_NAME;
299
+ if (typeName === undefined)
300
+ continue;
301
+ if (STORY_ROOTS.has(typeName))
302
+ return undefined;
303
+ if (typeName === TC) {
304
+ tc !== null && tc !== void 0 ? tc : (tc = o);
305
+ }
306
+ else if (typeName === TR) {
307
+ if (tc !== undefined && tr === undefined)
308
+ tr = o;
309
+ }
310
+ else if (typeName === TBL) {
311
+ return tr === undefined || tc === undefined ? undefined : { tbl: o, tr, tc };
312
+ }
313
+ }
314
+ return undefined;
315
+ }
@@ -0,0 +1,101 @@
1
+ import type * as wml from '@docx4j/generated-objects-ts/modules/org_docx4j_wml';
2
+ export type Condition = wml.STTblStyleOverrideType;
3
+ /**
4
+ * The order in which a table style's conditional formats are applied to a cell, later
5
+ * overriding earlier (ECMA-376-1 17.7.6).
6
+ */
7
+ export declare const PRECEDENCE: readonly Condition[];
8
+ /** Which conditional formats a table asks for: `w:tblPr/w:tblLook`, resolved. */
9
+ export interface Look {
10
+ readonly firstRow: boolean;
11
+ readonly lastRow: boolean;
12
+ readonly firstColumn: boolean;
13
+ readonly lastColumn: boolean;
14
+ /** Horizontal (row) banding is on: `w:noHBand` is off. */
15
+ readonly hBand: boolean;
16
+ /** Vertical (column) banding is on: `w:noVBand` is off. */
17
+ readonly vBand: boolean;
18
+ }
19
+ /**
20
+ * What Word assumes where a table states no `w:tblLook` at all: its own default, `04A0` - first
21
+ * row, first column and row banding on, column banding off.
22
+ */
23
+ export declare const DEFAULT_LOOK: Look;
24
+ /**
25
+ * The look a `w:tblLook` states. The six attributes win where any of them is present; otherwise
26
+ * the legacy `w:val` bitmask (0x0020 firstRow, 0x0040 lastRow, 0x0080 firstColumn, 0x0100
27
+ * lastColumn, 0x0200 noHBand, 0x0400 noVBand); none, or an empty element, is {@link DEFAULT_LOOK}.
28
+ */
29
+ export declare function lookOf(tblLook: wml.CTTblLook | undefined): Look;
30
+ /** Whether a look lets the condition through at all. */
31
+ export declare function lookAllows(look: Look, t: Condition): boolean;
32
+ /**
33
+ * `w:tblStyleRowBandSize`, at least 1 where it is stated, and 0 where it is not: Word bands no
34
+ * row of a table whose style chain and own `w:tblPr` state no band size, whatever its `w:tblLook`
35
+ * and the style's band conditions (measured, docx4j CR-030 probes T9 and T10, D11: Word's re-save
36
+ * writes no band bit, and its PDF has no band formatting; a size stated by the table alone is
37
+ * enough). Until docx4j 0349796f9 an absent size was taken as 1.
38
+ */
39
+ export declare function rowBandSize(tblPr: wml.CTTblPrBase | undefined): number;
40
+ /**
41
+ * `w:tblStyleColBandSize`, as {@link rowBandSize} for the columns: 0, no vertical banding, where
42
+ * it is not stated. (By the rows' rule; the columns themselves were not probed in Word.)
43
+ */
44
+ export declare function colBandSize(tblPr: wml.CTTblPrBase | undefined): number;
45
+ /**
46
+ * The conditions a `w:cnfStyle` bitmask names: twelve characters, firstRow, lastRow,
47
+ * firstColumn, lastColumn, oddVBand, evenVBand, oddHBand, evenHBand, then the corners nw, ne,
48
+ * sw, se. A short string is read as far as it goes; none is the empty set.
49
+ */
50
+ export declare function fromCnf(cnf: wml.CTCnf | string | undefined): Set<Condition>;
51
+ /** The `w:cnfStyle` of a row, or undefined where the row states none. */
52
+ export declare function rowCnf(trPr: wml.CTTrPrBase | undefined): wml.CTCnf | undefined;
53
+ /** Remove the conditions the look does not allow (in place), and return the set. */
54
+ export declare function gate(conditions: Set<Condition>, look?: Look): Set<Condition>;
55
+ /**
56
+ * The conditions a cell is under by its position alone, with no `w:cnfStyle` to go by.
57
+ *
58
+ * Banding counts from the first row (column) which is not under a condition of its own: where
59
+ * the look has `firstRow` on, row 1 is the first banded row; a last row (column) the look gives
60
+ * its own condition is left out of the bands too. A band is `w:tblStyleRowBandSize` rows deep,
61
+ * and a size of 0 (none stated anywhere, see {@link rowBandSize}) bands nothing.
62
+ * A cell spanning several columns is placed by its first column, and is in the last column
63
+ * where its span reaches it.
64
+ */
65
+ export declare function atPosition(look: Look, rowBand: number, colBand: number, row: number, rowCount: number, col: number, colSpan: number, colCount: number): Set<Condition>;
66
+ /**
67
+ * The conditions a cell (or a paragraph in it) is under: the `w:cnfStyle` caches where the
68
+ * document has them, the position where it has not, gated by the look (docx4j
69
+ * `TableStyleConditions.resolve`).
70
+ *
71
+ * Word writes the row-axis bits on the `w:tr`, the column-axis bits on the `w:tc` and the
72
+ * row-axis bits again on each `w:p`, and never the corner bits. So the row's cache, where there
73
+ * is one, decides the row axis, the cell's the column axis, a paragraph's bits are added on
74
+ * whichever axis they name, and the corners are derived from the result. An axis with no cache
75
+ * falls back to {@link atPosition}. Every bit is then gated by the look, so a stale cache cannot
76
+ * switch on a format the table has turned off.
77
+ */
78
+ export declare function resolve(look: Look, rowBand: number, colBand: number, row: number, rowCount: number, col: number, colSpan: number, colCount: number, rowCnfStyle: wml.CTCnf | undefined, cellCnf: wml.CTCnf | undefined, paraCnf: wml.CTCnf | undefined): Set<Condition>;
79
+ /**
80
+ * The row-axis conditions a row is under - first row, last row, or a horizontal band - for the
81
+ * row's own properties: its `w:cnfStyle` where it has one, else its position, gated by the look.
82
+ */
83
+ export declare function rowConditions(look: Look, rowBand: number, row: number, rowCount: number, rowCnfStyle: wml.CTCnf | undefined): Set<Condition>;
84
+ /**
85
+ * The style's `w:tblStylePr` entry for a condition, or undefined. Pass the merged table style
86
+ * (`PropertyResolver.getTableStyleChain`) to see inherited conditions.
87
+ */
88
+ export declare function lookup(tableStyle: wml.Style | undefined, type: Condition): wml.CTTblStylePr | undefined;
89
+ /**
90
+ * The style's `w:tblStylePr` entries which apply under these conditions, in the order they are
91
+ * to be applied ({@link PRECEDENCE}); a `wholeTable` entry, where the style has one, always
92
+ * applies and comes first.
93
+ */
94
+ export declare function applicable(tableStyle: wml.Style | undefined, conditions: ReadonlySet<Condition> | undefined): wml.CTTblStylePr[];
95
+ /** Whether the entry has any paragraph or run formatting to contribute. */
96
+ export declare function formatsText(pr: wml.CTTblStylePr | undefined): boolean;
97
+ /**
98
+ * A short name for a set of conditions, in precedence order - `firstCol-firstRow-nwCell` - the
99
+ * form docx4j's goldens and synthetic style ids use; the empty string for none.
100
+ */
101
+ export declare function key(conditions: ReadonlySet<Condition> | undefined): string;