rtf-codec 3.0.4 → 4.0.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.
- package/README.md +2 -2
- package/dist/cell-format.cjs +77 -0
- package/dist/cell-format.d.cts +6 -2
- package/dist/cell-format.d.ts +6 -2
- package/dist/cell-format.js +76 -1
- package/dist/codec.cjs +1 -1
- package/dist/codec.d.cts +2 -2
- package/dist/codec.d.ts +2 -2
- package/dist/codec.js +1 -1
- package/dist/read.cjs +2 -5
- package/dist/read.js +3 -6
- package/dist/write.cjs +6 -6
- package/dist/write.js +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -121,7 +121,7 @@ On the way out, **every non-ASCII character leaves as `\uN`** with a one-charact
|
|
|
121
121
|
| Paragraphs | `\par`, `\pard`, alignment, indents, spacing, `\slN`/`\slmultN`, `\pagebb` |
|
|
122
122
|
| Runs | `\b`, `\i`, `\ul` (every variant), `\strike`, `\fN`, `\fsN`, `\cfN`, `\v` (dropped as hidden) |
|
|
123
123
|
| Tables | `\trowd`, `\cellxN`, `\trleftN`, `\cell`, `\row`, multi-paragraph cells |
|
|
124
|
-
| Table cells | `\clbrdrt`/`l`/`b`/`r` with the whole `<brdr>` production, `\clcbpatN` shading, and both merge families (`\clvmgf`/`\clvmrg`, `\clmgf`/`\clmrg`)
|
|
124
|
+
| Table cells | `\clbrdrt`/`l`/`b`/`r` with the whole `<brdr>` production, `\clcbpatN`/`\clcfpatN`/`\clshdngN` shading (a real two-colour pattern fill, not just a flat colour -- see below), and both merge families (`\clvmgf`/`\clvmrg`, `\clmgf`/`\clmrg`) |
|
|
125
125
|
| Bookmarks | `\*\bkmkstart`/`\*\bkmkend` as `anchor` constructs, with `\bkmkcolfN`/`\bkmkcollN` quarantined as residue |
|
|
126
126
|
| Revision marks | The whole `<chrev>` production as `provenance` constructs: `\revised`, `\deleted`, `\mvf`/`\mvt`, `\crauthN`, with authors and `\revdttmN` dates |
|
|
127
127
|
| Form fields | A `\field` whose `\*\fldinst` names FORMTEXT/FORMCHECKBOX/FORMDROPDOWN, plus whatever `\*\formfield` data it carries (`\*\ffname` as its tag, `\*\ffhelptext` as its alias when `\ffownhelp` says it is author-set rather than auto-generated, `\ffprot` as its lock, a checkbox's own `\ffres`/`\ffdefres` as its checked state, a dropdown's own `\ffres`/`\ffdefres` as its selected entry alongside its `\*\ffl` option list), as a `contentControl` construct (plainText/checkbox/dropDown). A plainText field's own `\*\ffdeftext` group is recognised but its content is skipped whole rather than captured, since `value` names the control's CURRENT value, which for a text field is the wrapped-run text already carried in the extent's own children, not `\ffdeftext`'s default/reset text (see Write below for the one direction `\ffdeftext` does feed `value`); the same applies to the four other `\*\formfield` destination strings RTF's own Form Fields table names alongside it (`\*\ffformat`, `\*\ffstattext`, `\*\ffentrymcr`, `\*\ffexitmcr`), each skipped whole for the identical reason -- no `ContentControlDescriptor` field exists to carry any of them |
|
|
@@ -161,7 +161,7 @@ Each of these is reported through a diagnostic rather than dropped silently —
|
|
|
161
161
|
| A real, foreign `\object`'s OLE data | This package's own `\objdata` payload round-trips fully (see [Embedded objects](#embedded-objects)); a real Word-authored OLESaveToStream structure (an actual embedded `.xls`/`.doc`/OLE-control payload) has no decoder here and degrades with a diagnostic, recovering `\result`'s own fallback paragraphs when present instead of the real object. |
|
|
162
162
|
| Superscript/subscript (`\super`, `\sub`, `\upN`, `\dnN`), character scaling, kerning, background colour | **A schema gap, not an RTF one.** `ContentRun` carries no vertical-alignment field at all -- `epub-codec` reports the identical gap for its own `<sub>`/`<sup>`, and `ooxml.js`'s docx reader has no `w:vertAlign` handling either. Closing it is a change to `document-schema.js` and every codec that would then carry it, not to this one. |
|
|
163
163
|
| Right-to-left text (`\rtlch`, `\ltrch`, `\rtlpar`, `\rtlrow`, `\rtldoc`) | The same shape of gap: no `ContentDocument` field carries text direction, at any of the four scopes RTF states it at. |
|
|
164
|
-
| Cell vertical alignment (`\clvertalt`/`\clvertalc`/`\clvertalb`), diagonal cell borders (`\cldglu`/`\cldgll`)
|
|
164
|
+
| Cell vertical alignment (`\clvertalt`/`\clvertalc`/`\clvertalb`), diagonal cell borders (`\cldglu`/`\cldgll`) | `ContentTableCell.borders` has no diagonal member, so a diagonal rule is not a side; there is no vertical-alignment field to carry the other three into either. |
|
|
165
165
|
| A bookmark whose two halves straddle a table cell wall | `document-schema.js` ratifies this as a drop rather than a shape to repair: each block list is its own bracket scope, and pairing across two of them would need the marker ids its contract deliberately refuses. |
|
|
166
166
|
| A contentControl extent that crosses another contentControl extent in the same paragraph | RTF's `\*\formfield` destination can only nest, never cross: a `{\field...}` group nests cleanly inside another one's own `\fldrslt`, but two extents that start-before/end-after each other have no valid brace sequence, since whichever closes second would close the other's own braces instead of its own. |
|
|
167
167
|
| Two block-scoped bookmarks whose real ranges are disjoint but whose halves both land in the same paragraph (one's `\bkmkend`, the other's `\bkmkstart`) | A paragraph is this reader's finest addressable block-extent unit, so the shared paragraph's own block index gets claimed by both bookmarks' extents even though their real text never overlapped -- a genuine crossing pair, not a nesting one, and `document-schema.js`'s own construct group has no shape for that (a tree would need two subtrees crossing, which no tree holds). The later-starting bookmark is dropped with a diagnostic; the earlier one keeps its extent intact. |
|
package/dist/cell-format.cjs
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_units = require("./units.cjs");
|
|
3
|
+
let document_schema_js = require("document-schema.js");
|
|
3
4
|
//#region src/cell-format.ts
|
|
5
|
+
const PERCENT_STEPS = [
|
|
6
|
+
[5, "percent5"],
|
|
7
|
+
[10, "percent10"],
|
|
8
|
+
[12, "percent12"],
|
|
9
|
+
[15, "percent15"],
|
|
10
|
+
[20, "percent20"],
|
|
11
|
+
[25, "percent25"],
|
|
12
|
+
[30, "percent30"],
|
|
13
|
+
[35, "percent35"],
|
|
14
|
+
[37, "percent37"],
|
|
15
|
+
[40, "percent40"],
|
|
16
|
+
[45, "percent45"],
|
|
17
|
+
[50, "percent50"],
|
|
18
|
+
[55, "percent55"],
|
|
19
|
+
[60, "percent60"],
|
|
20
|
+
[62, "percent62"],
|
|
21
|
+
[65, "percent65"],
|
|
22
|
+
[70, "percent70"],
|
|
23
|
+
[75, "percent75"],
|
|
24
|
+
[80, "percent80"],
|
|
25
|
+
[85, "percent85"],
|
|
26
|
+
[87, "percent87"],
|
|
27
|
+
[90, "percent90"],
|
|
28
|
+
[95, "percent95"]
|
|
29
|
+
];
|
|
30
|
+
function nearestPercentType(percent) {
|
|
31
|
+
return PERCENT_STEPS.reduce((best, step) => Math.abs(step[0] - percent) < Math.abs(best[0] - percent) ? step : best)[1];
|
|
32
|
+
}
|
|
4
33
|
const CELL_BORDER_SIDES = /* @__PURE__ */ new Map([
|
|
5
34
|
["clbrdrt", "top"],
|
|
6
35
|
["clbrdrl", "left"],
|
|
@@ -49,6 +78,8 @@ function newPendingCell() {
|
|
|
49
78
|
borders: {},
|
|
50
79
|
side: void 0,
|
|
51
80
|
backgroundIndex: void 0,
|
|
81
|
+
foregroundIndex: void 0,
|
|
82
|
+
shadingPercent: void 0,
|
|
52
83
|
verticalMergeFirst: false,
|
|
53
84
|
verticalMergeContinuation: false,
|
|
54
85
|
horizontalMergeFirst: false,
|
|
@@ -83,6 +114,12 @@ function applyCellDefinitionControlWord(name, param, cell) {
|
|
|
83
114
|
case "clcbpat":
|
|
84
115
|
cell.backgroundIndex = param;
|
|
85
116
|
return true;
|
|
117
|
+
case "clcfpat":
|
|
118
|
+
cell.foregroundIndex = param;
|
|
119
|
+
return true;
|
|
120
|
+
case "clshdng":
|
|
121
|
+
cell.shadingPercent = param === void 0 ? void 0 : param / 100;
|
|
122
|
+
return true;
|
|
86
123
|
}
|
|
87
124
|
const pending = cell.side === void 0 ? void 0 : cell.borders[cell.side];
|
|
88
125
|
if (pending === void 0) return false;
|
|
@@ -121,6 +158,26 @@ function resolveBorder(pending, colorAt) {
|
|
|
121
158
|
...style === void 0 || style === "solid" ? {} : { style }
|
|
122
159
|
};
|
|
123
160
|
}
|
|
161
|
+
function resolveCellFill(pending, colorAt) {
|
|
162
|
+
if (pending.backgroundIndex === void 0) return;
|
|
163
|
+
const backgroundColor = colorAt(pending.backgroundIndex);
|
|
164
|
+
const shading = pending.shadingPercent ?? 0;
|
|
165
|
+
if (shading <= 0) return backgroundColor === void 0 ? void 0 : {
|
|
166
|
+
kind: "solid",
|
|
167
|
+
color: backgroundColor
|
|
168
|
+
};
|
|
169
|
+
const foregroundColor = pending.foregroundIndex === void 0 ? void 0 : colorAt(pending.foregroundIndex);
|
|
170
|
+
if (shading >= 100) return foregroundColor === void 0 ? void 0 : {
|
|
171
|
+
kind: "solid",
|
|
172
|
+
color: foregroundColor
|
|
173
|
+
};
|
|
174
|
+
return {
|
|
175
|
+
kind: "pattern",
|
|
176
|
+
patternType: nearestPercentType(shading),
|
|
177
|
+
...foregroundColor === void 0 ? {} : { foregroundColor },
|
|
178
|
+
...backgroundColor === void 0 ? {} : { backgroundColor }
|
|
179
|
+
};
|
|
180
|
+
}
|
|
124
181
|
function borderControlWords(side, border, colorIndex) {
|
|
125
182
|
const sideWord = [...CELL_BORDER_SIDES].find(([, value]) => value === side)?.[0];
|
|
126
183
|
if (sideWord === void 0) return "";
|
|
@@ -134,9 +191,29 @@ const BORDER_STYLE_CONTROL_WORDS = {
|
|
|
134
191
|
dotted: "brdrdot",
|
|
135
192
|
double: "brdrdb"
|
|
136
193
|
};
|
|
194
|
+
/** The inverse of PERCENT_STEPS, keyed by patternType. */
|
|
195
|
+
const PERCENT_TYPE_TO_VALUE = new Map(PERCENT_STEPS.map(([percent, patternType]) => [patternType, percent]));
|
|
196
|
+
function cellFillControlWords(fill, colorIndexOf) {
|
|
197
|
+
switch (fill.kind) {
|
|
198
|
+
case "solid": {
|
|
199
|
+
const index = colorIndexOf(fill.color);
|
|
200
|
+
return index === void 0 ? "" : `\\clcbpat${String(index)}`;
|
|
201
|
+
}
|
|
202
|
+
case "pattern": {
|
|
203
|
+
const percent = PERCENT_TYPE_TO_VALUE.get(fill.patternType);
|
|
204
|
+
if (percent === void 0) throw new Error(`rtf-codec cannot write a '${fill.patternType}' cell fill: RTF's own \\clshdngN is a flat two-colour percentage blend with no named stripe/cross/grid pattern of its own, and that pattern name belongs only to the ST_Shd/ST_PatternType half of ContentCellPatternType's shared vocabulary`);
|
|
205
|
+
const backgroundIndex = fill.backgroundColor === void 0 ? void 0 : colorIndexOf(fill.backgroundColor);
|
|
206
|
+
const foregroundIndex = fill.foregroundColor === void 0 ? void 0 : colorIndexOf(fill.foregroundColor);
|
|
207
|
+
return (backgroundIndex === void 0 ? "" : `\\clcbpat${String(backgroundIndex)}`) + (foregroundIndex === void 0 ? "" : `\\clcfpat${String(foregroundIndex)}`) + `\\clshdng${String(percent * 100)}`;
|
|
208
|
+
}
|
|
209
|
+
default: throw new Error(`rtf-codec cannot write a cell fill with kind '${(0, document_schema_js.unrecognizedFillKind)(fill)}': ContentCellFillSchema's discriminated union only defines 'solid' and 'pattern'`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
137
212
|
//#endregion
|
|
138
213
|
exports.CELL_BORDER_SIDES = CELL_BORDER_SIDES;
|
|
139
214
|
exports.applyCellDefinitionControlWord = applyCellDefinitionControlWord;
|
|
140
215
|
exports.borderControlWords = borderControlWords;
|
|
216
|
+
exports.cellFillControlWords = cellFillControlWords;
|
|
141
217
|
exports.newPendingCell = newPendingCell;
|
|
142
218
|
exports.resolveBorder = resolveBorder;
|
|
219
|
+
exports.resolveCellFill = resolveCellFill;
|
package/dist/cell-format.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Color, ContentBorder, ContentStrokeStyle } from "document-schema.js";
|
|
1
|
+
import { Color, ContentBorder, ContentCellFill, ContentStrokeStyle } from "document-schema.js";
|
|
2
2
|
//#region src/cell-format.d.ts
|
|
3
3
|
type CellBorderSide = "top" | "left" | "bottom" | "right";
|
|
4
4
|
declare const CELL_BORDER_SIDES: ReadonlyMap<string, CellBorderSide>;
|
|
@@ -12,6 +12,8 @@ interface PendingCell {
|
|
|
12
12
|
borders: Partial<Record<CellBorderSide, PendingBorder>>;
|
|
13
13
|
side: CellBorderSide | undefined;
|
|
14
14
|
backgroundIndex: number | undefined;
|
|
15
|
+
foregroundIndex: number | undefined;
|
|
16
|
+
shadingPercent: number | undefined;
|
|
15
17
|
verticalMergeFirst: boolean;
|
|
16
18
|
verticalMergeContinuation: boolean;
|
|
17
19
|
horizontalMergeFirst: boolean;
|
|
@@ -20,6 +22,8 @@ interface PendingCell {
|
|
|
20
22
|
declare function newPendingCell(): PendingCell;
|
|
21
23
|
declare function applyCellDefinitionControlWord(name: string, param: number | undefined, cell: PendingCell): boolean;
|
|
22
24
|
declare function resolveBorder(pending: PendingBorder, colorAt: (index: number) => Color | undefined): ContentBorder | undefined;
|
|
25
|
+
declare function resolveCellFill(pending: PendingCell, colorAt: (index: number) => Color | undefined): ContentCellFill | undefined;
|
|
23
26
|
declare function borderControlWords(side: CellBorderSide, border: ContentBorder, colorIndex: number | undefined): string;
|
|
27
|
+
declare function cellFillControlWords(fill: ContentCellFill, colorIndexOf: (color: Color) => number | undefined): string;
|
|
24
28
|
//#endregion
|
|
25
|
-
export { CELL_BORDER_SIDES, CellBorderSide, PendingBorder, PendingCell, applyCellDefinitionControlWord, borderControlWords, newPendingCell, resolveBorder };
|
|
29
|
+
export { CELL_BORDER_SIDES, CellBorderSide, PendingBorder, PendingCell, applyCellDefinitionControlWord, borderControlWords, cellFillControlWords, newPendingCell, resolveBorder, resolveCellFill };
|
package/dist/cell-format.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Color, ContentBorder, ContentStrokeStyle } from "document-schema.js";
|
|
1
|
+
import { Color, ContentBorder, ContentCellFill, ContentStrokeStyle } from "document-schema.js";
|
|
2
2
|
//#region src/cell-format.d.ts
|
|
3
3
|
type CellBorderSide = "top" | "left" | "bottom" | "right";
|
|
4
4
|
declare const CELL_BORDER_SIDES: ReadonlyMap<string, CellBorderSide>;
|
|
@@ -12,6 +12,8 @@ interface PendingCell {
|
|
|
12
12
|
borders: Partial<Record<CellBorderSide, PendingBorder>>;
|
|
13
13
|
side: CellBorderSide | undefined;
|
|
14
14
|
backgroundIndex: number | undefined;
|
|
15
|
+
foregroundIndex: number | undefined;
|
|
16
|
+
shadingPercent: number | undefined;
|
|
15
17
|
verticalMergeFirst: boolean;
|
|
16
18
|
verticalMergeContinuation: boolean;
|
|
17
19
|
horizontalMergeFirst: boolean;
|
|
@@ -20,6 +22,8 @@ interface PendingCell {
|
|
|
20
22
|
declare function newPendingCell(): PendingCell;
|
|
21
23
|
declare function applyCellDefinitionControlWord(name: string, param: number | undefined, cell: PendingCell): boolean;
|
|
22
24
|
declare function resolveBorder(pending: PendingBorder, colorAt: (index: number) => Color | undefined): ContentBorder | undefined;
|
|
25
|
+
declare function resolveCellFill(pending: PendingCell, colorAt: (index: number) => Color | undefined): ContentCellFill | undefined;
|
|
23
26
|
declare function borderControlWords(side: CellBorderSide, border: ContentBorder, colorIndex: number | undefined): string;
|
|
27
|
+
declare function cellFillControlWords(fill: ContentCellFill, colorIndexOf: (color: Color) => number | undefined): string;
|
|
24
28
|
//#endregion
|
|
25
|
-
export { CELL_BORDER_SIDES, CellBorderSide, PendingBorder, PendingCell, applyCellDefinitionControlWord, borderControlWords, newPendingCell, resolveBorder };
|
|
29
|
+
export { CELL_BORDER_SIDES, CellBorderSide, PendingBorder, PendingCell, applyCellDefinitionControlWord, borderControlWords, cellFillControlWords, newPendingCell, resolveBorder, resolveCellFill };
|
package/dist/cell-format.js
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
import { pointsToTwips, twipsToPoints } from "./units.js";
|
|
2
|
+
import { unrecognizedFillKind } from "document-schema.js";
|
|
2
3
|
//#region src/cell-format.ts
|
|
4
|
+
const PERCENT_STEPS = [
|
|
5
|
+
[5, "percent5"],
|
|
6
|
+
[10, "percent10"],
|
|
7
|
+
[12, "percent12"],
|
|
8
|
+
[15, "percent15"],
|
|
9
|
+
[20, "percent20"],
|
|
10
|
+
[25, "percent25"],
|
|
11
|
+
[30, "percent30"],
|
|
12
|
+
[35, "percent35"],
|
|
13
|
+
[37, "percent37"],
|
|
14
|
+
[40, "percent40"],
|
|
15
|
+
[45, "percent45"],
|
|
16
|
+
[50, "percent50"],
|
|
17
|
+
[55, "percent55"],
|
|
18
|
+
[60, "percent60"],
|
|
19
|
+
[62, "percent62"],
|
|
20
|
+
[65, "percent65"],
|
|
21
|
+
[70, "percent70"],
|
|
22
|
+
[75, "percent75"],
|
|
23
|
+
[80, "percent80"],
|
|
24
|
+
[85, "percent85"],
|
|
25
|
+
[87, "percent87"],
|
|
26
|
+
[90, "percent90"],
|
|
27
|
+
[95, "percent95"]
|
|
28
|
+
];
|
|
29
|
+
function nearestPercentType(percent) {
|
|
30
|
+
return PERCENT_STEPS.reduce((best, step) => Math.abs(step[0] - percent) < Math.abs(best[0] - percent) ? step : best)[1];
|
|
31
|
+
}
|
|
3
32
|
const CELL_BORDER_SIDES = /* @__PURE__ */ new Map([
|
|
4
33
|
["clbrdrt", "top"],
|
|
5
34
|
["clbrdrl", "left"],
|
|
@@ -48,6 +77,8 @@ function newPendingCell() {
|
|
|
48
77
|
borders: {},
|
|
49
78
|
side: void 0,
|
|
50
79
|
backgroundIndex: void 0,
|
|
80
|
+
foregroundIndex: void 0,
|
|
81
|
+
shadingPercent: void 0,
|
|
51
82
|
verticalMergeFirst: false,
|
|
52
83
|
verticalMergeContinuation: false,
|
|
53
84
|
horizontalMergeFirst: false,
|
|
@@ -82,6 +113,12 @@ function applyCellDefinitionControlWord(name, param, cell) {
|
|
|
82
113
|
case "clcbpat":
|
|
83
114
|
cell.backgroundIndex = param;
|
|
84
115
|
return true;
|
|
116
|
+
case "clcfpat":
|
|
117
|
+
cell.foregroundIndex = param;
|
|
118
|
+
return true;
|
|
119
|
+
case "clshdng":
|
|
120
|
+
cell.shadingPercent = param === void 0 ? void 0 : param / 100;
|
|
121
|
+
return true;
|
|
85
122
|
}
|
|
86
123
|
const pending = cell.side === void 0 ? void 0 : cell.borders[cell.side];
|
|
87
124
|
if (pending === void 0) return false;
|
|
@@ -120,6 +157,26 @@ function resolveBorder(pending, colorAt) {
|
|
|
120
157
|
...style === void 0 || style === "solid" ? {} : { style }
|
|
121
158
|
};
|
|
122
159
|
}
|
|
160
|
+
function resolveCellFill(pending, colorAt) {
|
|
161
|
+
if (pending.backgroundIndex === void 0) return;
|
|
162
|
+
const backgroundColor = colorAt(pending.backgroundIndex);
|
|
163
|
+
const shading = pending.shadingPercent ?? 0;
|
|
164
|
+
if (shading <= 0) return backgroundColor === void 0 ? void 0 : {
|
|
165
|
+
kind: "solid",
|
|
166
|
+
color: backgroundColor
|
|
167
|
+
};
|
|
168
|
+
const foregroundColor = pending.foregroundIndex === void 0 ? void 0 : colorAt(pending.foregroundIndex);
|
|
169
|
+
if (shading >= 100) return foregroundColor === void 0 ? void 0 : {
|
|
170
|
+
kind: "solid",
|
|
171
|
+
color: foregroundColor
|
|
172
|
+
};
|
|
173
|
+
return {
|
|
174
|
+
kind: "pattern",
|
|
175
|
+
patternType: nearestPercentType(shading),
|
|
176
|
+
...foregroundColor === void 0 ? {} : { foregroundColor },
|
|
177
|
+
...backgroundColor === void 0 ? {} : { backgroundColor }
|
|
178
|
+
};
|
|
179
|
+
}
|
|
123
180
|
function borderControlWords(side, border, colorIndex) {
|
|
124
181
|
const sideWord = [...CELL_BORDER_SIDES].find(([, value]) => value === side)?.[0];
|
|
125
182
|
if (sideWord === void 0) return "";
|
|
@@ -133,5 +190,23 @@ const BORDER_STYLE_CONTROL_WORDS = {
|
|
|
133
190
|
dotted: "brdrdot",
|
|
134
191
|
double: "brdrdb"
|
|
135
192
|
};
|
|
193
|
+
/** The inverse of PERCENT_STEPS, keyed by patternType. */
|
|
194
|
+
const PERCENT_TYPE_TO_VALUE = new Map(PERCENT_STEPS.map(([percent, patternType]) => [patternType, percent]));
|
|
195
|
+
function cellFillControlWords(fill, colorIndexOf) {
|
|
196
|
+
switch (fill.kind) {
|
|
197
|
+
case "solid": {
|
|
198
|
+
const index = colorIndexOf(fill.color);
|
|
199
|
+
return index === void 0 ? "" : `\\clcbpat${String(index)}`;
|
|
200
|
+
}
|
|
201
|
+
case "pattern": {
|
|
202
|
+
const percent = PERCENT_TYPE_TO_VALUE.get(fill.patternType);
|
|
203
|
+
if (percent === void 0) throw new Error(`rtf-codec cannot write a '${fill.patternType}' cell fill: RTF's own \\clshdngN is a flat two-colour percentage blend with no named stripe/cross/grid pattern of its own, and that pattern name belongs only to the ST_Shd/ST_PatternType half of ContentCellPatternType's shared vocabulary`);
|
|
204
|
+
const backgroundIndex = fill.backgroundColor === void 0 ? void 0 : colorIndexOf(fill.backgroundColor);
|
|
205
|
+
const foregroundIndex = fill.foregroundColor === void 0 ? void 0 : colorIndexOf(fill.foregroundColor);
|
|
206
|
+
return (backgroundIndex === void 0 ? "" : `\\clcbpat${String(backgroundIndex)}`) + (foregroundIndex === void 0 ? "" : `\\clcfpat${String(foregroundIndex)}`) + `\\clshdng${String(percent * 100)}`;
|
|
207
|
+
}
|
|
208
|
+
default: throw new Error(`rtf-codec cannot write a cell fill with kind '${unrecognizedFillKind(fill)}': ContentCellFillSchema's discriminated union only defines 'solid' and 'pattern'`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
136
211
|
//#endregion
|
|
137
|
-
export { CELL_BORDER_SIDES, applyCellDefinitionControlWord, borderControlWords, newPendingCell, resolveBorder };
|
|
212
|
+
export { CELL_BORDER_SIDES, applyCellDefinitionControlWord, borderControlWords, cellFillControlWords, newPendingCell, resolveBorder, resolveCellFill };
|
package/dist/codec.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_read = require("./read.cjs");
|
|
3
3
|
const require_write = require("./write.cjs");
|
|
4
|
-
let zod = require("zod");
|
|
5
4
|
let document_schema_js = require("document-schema.js");
|
|
5
|
+
let zod = require("zod");
|
|
6
6
|
//#region src/codec.ts
|
|
7
7
|
const RTF_MAGIC = [
|
|
8
8
|
123,
|
package/dist/codec.d.cts
CHANGED
|
@@ -1425,10 +1425,10 @@ declare const rtfContentCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, U
|
|
|
1425
1425
|
endColumn: z.ZodNumber;
|
|
1426
1426
|
}, z.core.$strip>>;
|
|
1427
1427
|
type: z.ZodEnum<{
|
|
1428
|
-
decimal: "decimal";
|
|
1429
|
-
list: "list";
|
|
1430
1428
|
date: "date";
|
|
1431
1429
|
custom: "custom";
|
|
1430
|
+
decimal: "decimal";
|
|
1431
|
+
list: "list";
|
|
1432
1432
|
time: "time";
|
|
1433
1433
|
whole: "whole";
|
|
1434
1434
|
textLength: "textLength";
|
package/dist/codec.d.ts
CHANGED
|
@@ -1425,10 +1425,10 @@ declare const rtfContentCodec: z.ZodCodec<z.ZodCustom<Uint8Array<ArrayBuffer>, U
|
|
|
1425
1425
|
endColumn: z.ZodNumber;
|
|
1426
1426
|
}, z.core.$strip>>;
|
|
1427
1427
|
type: z.ZodEnum<{
|
|
1428
|
-
decimal: "decimal";
|
|
1429
|
-
list: "list";
|
|
1430
1428
|
date: "date";
|
|
1431
1429
|
custom: "custom";
|
|
1430
|
+
decimal: "decimal";
|
|
1431
|
+
list: "list";
|
|
1432
1432
|
time: "time";
|
|
1433
1433
|
whole: "whole";
|
|
1434
1434
|
textLength: "textLength";
|
package/dist/codec.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readRtf, readRtfContent } from "./read.js";
|
|
2
2
|
import { writeRtf, writeRtfContent } from "./write.js";
|
|
3
|
-
import { z } from "zod";
|
|
4
3
|
import { ContentDocumentSchema, DocumentTreeSchema } from "document-schema.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
5
|
//#region src/codec.ts
|
|
6
6
|
const RTF_MAGIC = [
|
|
7
7
|
123,
|
package/dist/read.cjs
CHANGED
|
@@ -634,15 +634,12 @@ var ContentBuilder = class {
|
|
|
634
634
|
rowSpan += 1;
|
|
635
635
|
}
|
|
636
636
|
const borders = this.resolveBorders(definition);
|
|
637
|
-
const
|
|
637
|
+
const background = definition === void 0 ? void 0 : require_cell_format.resolveCellFill(definition, (index) => this.header.colors[index]);
|
|
638
638
|
return {
|
|
639
639
|
blocks: cell.blocks,
|
|
640
640
|
...colSpan > 1 ? { colSpan } : {},
|
|
641
641
|
...rowSpan > 1 ? { rowSpan } : {},
|
|
642
|
-
...
|
|
643
|
-
kind: "solid",
|
|
644
|
-
color: backgroundColor
|
|
645
|
-
} },
|
|
642
|
+
...background === void 0 ? {} : { background },
|
|
646
643
|
...borders === void 0 ? {} : { borders }
|
|
647
644
|
};
|
|
648
645
|
}) }));
|
package/dist/read.js
CHANGED
|
@@ -2,7 +2,7 @@ import { bytesToBase64, hexToBytes } from "./base64.js";
|
|
|
2
2
|
import { RtfDiagnosticCodes, RtfInputTooLargeError, RtfNestingLimitExceededError, RtfNotAnRtfDocumentError } from "./diagnostics.js";
|
|
3
3
|
import { appendBytes, asciiStringFromBytes, rtfBytesFromLatin1 } from "./bytes.js";
|
|
4
4
|
import { halfPointsToPoints, pixelsToPoints, twipsToPoints } from "./units.js";
|
|
5
|
-
import { applyCellDefinitionControlWord, newPendingCell, resolveBorder } from "./cell-format.js";
|
|
5
|
+
import { applyCellDefinitionControlWord, newPendingCell, resolveBorder, resolveCellFill } from "./cell-format.js";
|
|
6
6
|
import { NO_REVISION, bookmarkAnchorDescriptor, coalesceRunConstructs, formFieldContentControl, formFieldControlType, provenanceDescriptors } from "./constructs.js";
|
|
7
7
|
import { readEmbeddedObjectData } from "./embedded-object.js";
|
|
8
8
|
import { decodeCodepageBytes } from "./codepage.js";
|
|
@@ -633,15 +633,12 @@ var ContentBuilder = class {
|
|
|
633
633
|
rowSpan += 1;
|
|
634
634
|
}
|
|
635
635
|
const borders = this.resolveBorders(definition);
|
|
636
|
-
const
|
|
636
|
+
const background = definition === void 0 ? void 0 : resolveCellFill(definition, (index) => this.header.colors[index]);
|
|
637
637
|
return {
|
|
638
638
|
blocks: cell.blocks,
|
|
639
639
|
...colSpan > 1 ? { colSpan } : {},
|
|
640
640
|
...rowSpan > 1 ? { rowSpan } : {},
|
|
641
|
-
...
|
|
642
|
-
kind: "solid",
|
|
643
|
-
color: backgroundColor
|
|
644
|
-
} },
|
|
641
|
+
...background === void 0 ? {} : { background },
|
|
645
642
|
...borders === void 0 ? {} : { borders }
|
|
646
643
|
};
|
|
647
644
|
}) }));
|
package/dist/write.cjs
CHANGED
|
@@ -79,7 +79,11 @@ function collectTables(document) {
|
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
81
81
|
if (block.kind === "table") for (const row of block.rows) for (const cell of row.cells) {
|
|
82
|
-
|
|
82
|
+
if (cell.background?.kind === "solid") noteColor(cell.background.color);
|
|
83
|
+
else if (cell.background?.kind === "pattern") {
|
|
84
|
+
noteColor(cell.background.foregroundColor);
|
|
85
|
+
noteColor(cell.background.backgroundColor);
|
|
86
|
+
}
|
|
83
87
|
for (const side of CELL_BORDER_ORDER) noteColor(cell.borders?.[side]?.color);
|
|
84
88
|
for (const inner of cell.blocks) noteBlock(inner);
|
|
85
89
|
}
|
|
@@ -631,11 +635,7 @@ var RtfWriter = class {
|
|
|
631
635
|
const border = borders[side];
|
|
632
636
|
if (border !== void 0) out += require_cell_format.borderControlWords(side, border, colorIndexOf(border.color, this.tables.colors));
|
|
633
637
|
}
|
|
634
|
-
|
|
635
|
-
if (cellBackgroundColor !== void 0) {
|
|
636
|
-
const index = colorIndexOf(cellBackgroundColor, this.tables.colors);
|
|
637
|
-
if (index !== void 0) out += `\\clcbpat${String(index)}`;
|
|
638
|
-
}
|
|
638
|
+
if (cell.background !== void 0) out += require_cell_format.cellFillControlWords(cell.background, (color) => colorIndexOf(color, this.tables.colors));
|
|
639
639
|
return `${out}\\cellx${String(rightTwips)}`;
|
|
640
640
|
}
|
|
641
641
|
writeCellBlocks(blocks) {
|
package/dist/write.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { base64ToBytes, bytesToHex } from "./base64.js";
|
|
2
2
|
import { RtfDiagnosticCodes, RtfUnsupportedDocumentKindError } from "./diagnostics.js";
|
|
3
3
|
import { pointsToHalfPoints, pointsToTwips } from "./units.js";
|
|
4
|
-
import { borderControlWords } from "./cell-format.js";
|
|
4
|
+
import { borderControlWords, cellFillControlWords } from "./cell-format.js";
|
|
5
5
|
import { bookmarkResidueControlWords, dttmFromIso, isBookmarkAnchor } from "./constructs.js";
|
|
6
6
|
import { writeEmbeddedObjectData } from "./embedded-object.js";
|
|
7
7
|
import { parseRtfListNumId } from "./list-id.js";
|
|
8
|
-
import { clampHeadingLevel, colorToRgbHex, flattenTree
|
|
8
|
+
import { clampHeadingLevel, colorToRgbHex, flattenTree } from "document-schema.js";
|
|
9
9
|
//#region src/write.ts
|
|
10
10
|
const LEVEL_NUMBER_FORMAT_BULLET = 23;
|
|
11
11
|
const LEVEL_NUMBER_FORMAT_ARABIC = 0;
|
|
@@ -78,7 +78,11 @@ function collectTables(document) {
|
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
80
|
if (block.kind === "table") for (const row of block.rows) for (const cell of row.cells) {
|
|
81
|
-
|
|
81
|
+
if (cell.background?.kind === "solid") noteColor(cell.background.color);
|
|
82
|
+
else if (cell.background?.kind === "pattern") {
|
|
83
|
+
noteColor(cell.background.foregroundColor);
|
|
84
|
+
noteColor(cell.background.backgroundColor);
|
|
85
|
+
}
|
|
82
86
|
for (const side of CELL_BORDER_ORDER) noteColor(cell.borders?.[side]?.color);
|
|
83
87
|
for (const inner of cell.blocks) noteBlock(inner);
|
|
84
88
|
}
|
|
@@ -630,11 +634,7 @@ var RtfWriter = class {
|
|
|
630
634
|
const border = borders[side];
|
|
631
635
|
if (border !== void 0) out += borderControlWords(side, border, colorIndexOf(border.color, this.tables.colors));
|
|
632
636
|
}
|
|
633
|
-
|
|
634
|
-
if (cellBackgroundColor !== void 0) {
|
|
635
|
-
const index = colorIndexOf(cellBackgroundColor, this.tables.colors);
|
|
636
|
-
if (index !== void 0) out += `\\clcbpat${String(index)}`;
|
|
637
|
-
}
|
|
637
|
+
if (cell.background !== void 0) out += cellFillControlWords(cell.background, (color) => colorIndexOf(color, this.tables.colors));
|
|
638
638
|
return `${out}\\cellx${String(rightTwips)}`;
|
|
639
639
|
}
|
|
640
640
|
writeCellBlocks(blocks) {
|
package/package.json
CHANGED