@shbernal/ts-xlsx 1.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/LICENSE +23 -0
- package/README.md +230 -0
- package/dist/core/address.d.ts +49 -0
- package/dist/core/address.js +125 -0
- package/dist/core/autofilter.d.ts +55 -0
- package/dist/core/autofilter.js +48 -0
- package/dist/core/cell.d.ts +132 -0
- package/dist/core/cell.js +249 -0
- package/dist/core/color-resolution.d.ts +58 -0
- package/dist/core/color-resolution.js +170 -0
- package/dist/core/column.d.ts +87 -0
- package/dist/core/column.js +167 -0
- package/dist/core/comment-thread.d.ts +116 -0
- package/dist/core/comment-thread.js +62 -0
- package/dist/core/conditional-formatting-overlay.d.ts +15 -0
- package/dist/core/conditional-formatting-overlay.js +24 -0
- package/dist/core/conditional-formatting.d.ts +70 -0
- package/dist/core/conditional-formatting.js +35 -0
- package/dist/core/containers.d.ts +2 -0
- package/dist/core/containers.js +25 -0
- package/dist/core/data-validation-overlay.d.ts +28 -0
- package/dist/core/data-validation-overlay.js +56 -0
- package/dist/core/data-validation.d.ts +38 -0
- package/dist/core/data-validation.js +13 -0
- package/dist/core/date.d.ts +25 -0
- package/dist/core/date.js +58 -0
- package/dist/core/formula.d.ts +49 -0
- package/dist/core/formula.js +319 -0
- package/dist/core/grid-edits.d.ts +22 -0
- package/dist/core/grid-edits.js +206 -0
- package/dist/core/image.d.ts +76 -0
- package/dist/core/image.js +65 -0
- package/dist/core/internal.d.ts +11 -0
- package/dist/core/internal.js +29 -0
- package/dist/core/merge.d.ts +13 -0
- package/dist/core/merge.js +26 -0
- package/dist/core/modern-functions.d.ts +1 -0
- package/dist/core/modern-functions.js +165 -0
- package/dist/core/page-setup.d.ts +94 -0
- package/dist/core/page-setup.js +6 -0
- package/dist/core/pivot-table.d.ts +113 -0
- package/dist/core/pivot-table.js +249 -0
- package/dist/core/preserved.d.ts +58 -0
- package/dist/core/preserved.js +5 -0
- package/dist/core/protection.d.ts +67 -0
- package/dist/core/protection.js +68 -0
- package/dist/core/range.d.ts +112 -0
- package/dist/core/range.js +283 -0
- package/dist/core/row.d.ts +73 -0
- package/dist/core/row.js +135 -0
- package/dist/core/style.d.ts +246 -0
- package/dist/core/style.js +125 -0
- package/dist/core/table-style.d.ts +67 -0
- package/dist/core/table-style.js +90 -0
- package/dist/core/table.d.ts +194 -0
- package/dist/core/table.js +291 -0
- package/dist/core/theme.d.ts +90 -0
- package/dist/core/theme.js +272 -0
- package/dist/core/value.d.ts +115 -0
- package/dist/core/value.js +144 -0
- package/dist/core/workbook-protection.d.ts +27 -0
- package/dist/core/workbook-protection.js +25 -0
- package/dist/core/workbook.d.ts +528 -0
- package/dist/core/workbook.js +732 -0
- package/dist/core/worksheet-model.d.ts +34 -0
- package/dist/core/worksheet-model.js +100 -0
- package/dist/core/worksheet.d.ts +647 -0
- package/dist/core/worksheet.js +1025 -0
- package/dist/customui/errors.d.ts +15 -0
- package/dist/customui/errors.js +15 -0
- package/dist/customui/index.d.ts +2 -0
- package/dist/customui/index.js +7 -0
- package/dist/customui/ribbon.d.ts +86 -0
- package/dist/customui/ribbon.js +180 -0
- package/dist/entries/core.d.ts +23 -0
- package/dist/entries/core.js +20 -0
- package/dist/entries/csv.d.ts +2 -0
- package/dist/entries/csv.js +6 -0
- package/dist/entries/customui.d.ts +1 -0
- package/dist/entries/customui.js +3 -0
- package/dist/entries/errors.d.ts +7 -0
- package/dist/entries/errors.js +20 -0
- package/dist/entries/vba.d.ts +2 -0
- package/dist/entries/vba.js +7 -0
- package/dist/entries/xlsb.d.ts +1 -0
- package/dist/entries/xlsb.js +7 -0
- package/dist/entries/xlsx.d.ts +5 -0
- package/dist/entries/xlsx.js +18 -0
- package/dist/errors.d.ts +65 -0
- package/dist/errors.js +66 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +19 -0
- package/dist/io/csv/read.d.ts +15 -0
- package/dist/io/csv/read.js +113 -0
- package/dist/io/csv/write.d.ts +28 -0
- package/dist/io/csv/write.js +124 -0
- package/dist/io/opc/errors.d.ts +46 -0
- package/dist/io/opc/errors.js +49 -0
- package/dist/io/opc/inflate.d.ts +15 -0
- package/dist/io/opc/inflate.js +91 -0
- package/dist/io/opc/namespaces.d.ts +18 -0
- package/dist/io/opc/namespaces.js +18 -0
- package/dist/io/opc/part-paths.d.ts +4 -0
- package/dist/io/opc/part-paths.js +35 -0
- package/dist/io/opc/read-opc.d.ts +24 -0
- package/dist/io/opc/read-opc.js +153 -0
- package/dist/io/opc/read-options.d.ts +10 -0
- package/dist/io/opc/read-options.js +7 -0
- package/dist/io/opc/rels.d.ts +15 -0
- package/dist/io/opc/rels.js +28 -0
- package/dist/io/opc/sniff-format.d.ts +27 -0
- package/dist/io/opc/sniff-format.js +92 -0
- package/dist/io/style/xf-style.d.ts +47 -0
- package/dist/io/style/xf-style.js +95 -0
- package/dist/io/xlsb/errors.d.ts +15 -0
- package/dist/io/xlsb/errors.js +15 -0
- package/dist/io/xlsb/formula.d.ts +48 -0
- package/dist/io/xlsb/formula.js +398 -0
- package/dist/io/xlsb/primitives.d.ts +86 -0
- package/dist/io/xlsb/primitives.js +230 -0
- package/dist/io/xlsb/ptg-functions.d.ts +16 -0
- package/dist/io/xlsb/ptg-functions.js +659 -0
- package/dist/io/xlsb/read-shared-strings.d.ts +2 -0
- package/dist/io/xlsb/read-shared-strings.js +22 -0
- package/dist/io/xlsb/read-styles.d.ts +4 -0
- package/dist/io/xlsb/read-styles.js +386 -0
- package/dist/io/xlsb/read-worksheet.d.ts +9 -0
- package/dist/io/xlsb/read-worksheet.js +301 -0
- package/dist/io/xlsb/read.d.ts +20 -0
- package/dist/io/xlsb/read.js +199 -0
- package/dist/io/xlsb/record-stream.d.ts +14 -0
- package/dist/io/xlsb/record-stream.js +56 -0
- package/dist/io/xlsb/record-types.d.ts +55 -0
- package/dist/io/xlsb/record-types.js +73 -0
- package/dist/io/xlsx/cell-accumulator.d.ts +25 -0
- package/dist/io/xlsx/cell-accumulator.js +172 -0
- package/dist/io/xlsx/cell-value.d.ts +32 -0
- package/dist/io/xlsx/cell-value.js +85 -0
- package/dist/io/xlsx/comments.d.ts +74 -0
- package/dist/io/xlsx/comments.js +243 -0
- package/dist/io/xlsx/conditional-formatting.d.ts +32 -0
- package/dist/io/xlsx/conditional-formatting.js +464 -0
- package/dist/io/xlsx/data-validation.d.ts +20 -0
- package/dist/io/xlsx/data-validation.js +258 -0
- package/dist/io/xlsx/edit-vba.d.ts +23 -0
- package/dist/io/xlsx/edit-vba.js +139 -0
- package/dist/io/xlsx/errors.d.ts +17 -0
- package/dist/io/xlsx/errors.js +17 -0
- package/dist/io/xlsx/hyperlinks.d.ts +42 -0
- package/dist/io/xlsx/hyperlinks.js +139 -0
- package/dist/io/xlsx/images.d.ts +34 -0
- package/dist/io/xlsx/images.js +218 -0
- package/dist/io/xlsx/namespaces.d.ts +55 -0
- package/dist/io/xlsx/namespaces.js +55 -0
- package/dist/io/xlsx/package-plan.d.ts +103 -0
- package/dist/io/xlsx/package-plan.js +168 -0
- package/dist/io/xlsx/pivot-read.d.ts +5 -0
- package/dist/io/xlsx/pivot-read.js +134 -0
- package/dist/io/xlsx/pivot.d.ts +12 -0
- package/dist/io/xlsx/pivot.js +141 -0
- package/dist/io/xlsx/read-rows.d.ts +85 -0
- package/dist/io/xlsx/read-rows.js +286 -0
- package/dist/io/xlsx/read-styles.d.ts +8 -0
- package/dist/io/xlsx/read-styles.js +551 -0
- package/dist/io/xlsx/read-worksheet.d.ts +4 -0
- package/dist/io/xlsx/read-worksheet.js +528 -0
- package/dist/io/xlsx/read.d.ts +32 -0
- package/dist/io/xlsx/read.js +680 -0
- package/dist/io/xlsx/relationships.d.ts +33 -0
- package/dist/io/xlsx/relationships.js +47 -0
- package/dist/io/xlsx/rich-runs.d.ts +13 -0
- package/dist/io/xlsx/rich-runs.js +59 -0
- package/dist/io/xlsx/rich-text.d.ts +7 -0
- package/dist/io/xlsx/rich-text.js +23 -0
- package/dist/io/xlsx/shared-formulas.d.ts +6 -0
- package/dist/io/xlsx/shared-formulas.js +52 -0
- package/dist/io/xlsx/shared-strings-read.d.ts +2 -0
- package/dist/io/xlsx/shared-strings-read.js +70 -0
- package/dist/io/xlsx/shared-strings.d.ts +17 -0
- package/dist/io/xlsx/shared-strings.js +50 -0
- package/dist/io/xlsx/sheet-properties.d.ts +13 -0
- package/dist/io/xlsx/sheet-properties.js +211 -0
- package/dist/io/xlsx/styles.d.ts +138 -0
- package/dist/io/xlsx/styles.js +821 -0
- package/dist/io/xlsx/tables.d.ts +9 -0
- package/dist/io/xlsx/tables.js +208 -0
- package/dist/io/xlsx/threaded-comments.d.ts +102 -0
- package/dist/io/xlsx/threaded-comments.js +308 -0
- package/dist/io/xlsx/workbook-xml.d.ts +12 -0
- package/dist/io/xlsx/workbook-xml.js +353 -0
- package/dist/io/xlsx/worksheet-xml.d.ts +86 -0
- package/dist/io/xlsx/worksheet-xml.js +643 -0
- package/dist/io/xlsx/write-stream.d.ts +171 -0
- package/dist/io/xlsx/write-stream.js +399 -0
- package/dist/io/xlsx/write.d.ts +81 -0
- package/dist/io/xlsx/write.js +396 -0
- package/dist/io/xlsx/x14-ext.d.ts +9 -0
- package/dist/io/xlsx/x14-ext.js +12 -0
- package/dist/vba/cfb-writer.d.ts +19 -0
- package/dist/vba/cfb-writer.js +277 -0
- package/dist/vba/cfb.d.ts +16 -0
- package/dist/vba/cfb.js +324 -0
- package/dist/vba/codepage.d.ts +18 -0
- package/dist/vba/codepage.js +87 -0
- package/dist/vba/errors.d.ts +24 -0
- package/dist/vba/errors.js +24 -0
- package/dist/vba/index.d.ts +5 -0
- package/dist/vba/index.js +15 -0
- package/dist/vba/ms-ovba.d.ts +12 -0
- package/dist/vba/ms-ovba.js +176 -0
- package/dist/vba/project-editor.d.ts +62 -0
- package/dist/vba/project-editor.js +377 -0
- package/dist/vba/project.d.ts +45 -0
- package/dist/vba/project.js +160 -0
- package/dist/vba/vba-encoding.d.ts +14 -0
- package/dist/vba/vba-encoding.js +39 -0
- package/dist/xml/errors.d.ts +15 -0
- package/dist/xml/errors.js +15 -0
- package/dist/xml/xml-read.d.ts +107 -0
- package/dist/xml/xml-read.js +283 -0
- package/dist/xml/xml.d.ts +41 -0
- package/dist/xml/xml.js +86 -0
- package/package.json +117 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
// The BIFF12 style-sheet reader: `xl/styles.bin` in, the same {@link StyleTable} the XML reader
|
|
2
|
+
// produces out. Every collection (`fmts`, `fonts`, `fills`, `borders`, `cellStyleXfs`, `cellXfs`,
|
|
3
|
+
// `styles`) is a Begin/End record pair around its entries, so the pass tracks which collection it is
|
|
4
|
+
// inside — `BrtXF` appears in two of them and is meaningless without that context.
|
|
5
|
+
//
|
|
6
|
+
// The resolution *rules* are deliberately not restated here: number-format ids go through the XML
|
|
7
|
+
// reader's `numFmtCodeFor`, and each facet is emitted with the same "only when it differs from the
|
|
8
|
+
// default" discipline the XML path uses. That is what makes the binary and XML readings of one
|
|
9
|
+
// workbook the same model rather than two similar ones — a bottom vertical alignment, a locked cell,
|
|
10
|
+
// or a General number format is written explicitly in BIFF12 and omitted in XML, so the binary side
|
|
11
|
+
// has to drop exactly what the XML side never had.
|
|
12
|
+
import { assignStyleFacets } from "../../core/style.js";
|
|
13
|
+
import { numFmtCodeFor } from "../style/xf-style.js";
|
|
14
|
+
import { RecordReader } from "./primitives.js";
|
|
15
|
+
import { readRecords } from "./record-stream.js";
|
|
16
|
+
import { BRT } from "./record-types.js";
|
|
17
|
+
const COLLECTION_STARTS = new Map([
|
|
18
|
+
[BRT.BeginFmts, 'fmts'],
|
|
19
|
+
[BRT.BeginFonts, 'fonts'],
|
|
20
|
+
[BRT.BeginFills, 'fills'],
|
|
21
|
+
[BRT.BeginBorders, 'borders'],
|
|
22
|
+
[BRT.BeginCellStyleXFs, 'cellStyleXfs'],
|
|
23
|
+
[BRT.BeginCellXFs, 'cellXfs'],
|
|
24
|
+
[BRT.BeginStyles, 'styles'],
|
|
25
|
+
]);
|
|
26
|
+
const COLLECTION_ENDS = new Set([
|
|
27
|
+
BRT.EndFmts,
|
|
28
|
+
BRT.EndFonts,
|
|
29
|
+
BRT.EndFills,
|
|
30
|
+
BRT.EndBorders,
|
|
31
|
+
BRT.EndCellStyleXFs,
|
|
32
|
+
BRT.EndCellXFs,
|
|
33
|
+
BRT.EndStyles,
|
|
34
|
+
]);
|
|
35
|
+
/** Parse `xl/styles.bin` into the flat cell-format table a worksheet's style indices resolve against. */
|
|
36
|
+
export function parseStyleTable(part) {
|
|
37
|
+
if (part === undefined)
|
|
38
|
+
return { cellXfs: [], namedStyles: [] };
|
|
39
|
+
const numFmtCodes = new Map();
|
|
40
|
+
const fonts = [];
|
|
41
|
+
const fills = [];
|
|
42
|
+
const borders = [];
|
|
43
|
+
const namedXfs = [];
|
|
44
|
+
const directXfs = [];
|
|
45
|
+
const labels = [];
|
|
46
|
+
let collection;
|
|
47
|
+
for (const record of readRecords(part)) {
|
|
48
|
+
if (COLLECTION_ENDS.has(record.type)) {
|
|
49
|
+
collection = undefined;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const started = COLLECTION_STARTS.get(record.type);
|
|
53
|
+
if (started !== undefined) {
|
|
54
|
+
collection = started;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const reader = new RecordReader(record.data);
|
|
58
|
+
switch (record.type) {
|
|
59
|
+
case BRT.Fmt:
|
|
60
|
+
if (collection === 'fmts')
|
|
61
|
+
numFmtCodes.set(reader.u16(), reader.wideString());
|
|
62
|
+
break;
|
|
63
|
+
case BRT.Font:
|
|
64
|
+
if (collection === 'fonts')
|
|
65
|
+
fonts.push(readFont(reader));
|
|
66
|
+
break;
|
|
67
|
+
case BRT.Fill:
|
|
68
|
+
if (collection === 'fills')
|
|
69
|
+
fills.push(readFill(reader));
|
|
70
|
+
break;
|
|
71
|
+
case BRT.Border:
|
|
72
|
+
if (collection === 'borders')
|
|
73
|
+
borders.push(readBorder(reader));
|
|
74
|
+
break;
|
|
75
|
+
case BRT.XF:
|
|
76
|
+
if (collection === 'cellXfs' || collection === 'cellStyleXfs') {
|
|
77
|
+
const deps = { fonts, fills, borders, numFmtCodes };
|
|
78
|
+
(collection === 'cellXfs' ? directXfs : namedXfs).push(readXf(reader, deps, collection === 'cellXfs'));
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
case BRT.Style:
|
|
82
|
+
if (collection === 'styles')
|
|
83
|
+
labels.push(readStyleLabel(reader));
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Layer each direct format over the named style its xfId links to, exactly as the XML reader does:
|
|
90
|
+
// a facet the cell's own xf sets wins, one it leaves unset falls through to the named base.
|
|
91
|
+
const cellXfs = directXfs.map((xf) => {
|
|
92
|
+
if (xf.xfId === undefined)
|
|
93
|
+
return xf;
|
|
94
|
+
const named = namedXfs[xf.xfId];
|
|
95
|
+
return named === undefined ? xf : { ...named, ...xf };
|
|
96
|
+
});
|
|
97
|
+
const namedStyles = namedXfs.map((xf, index) => {
|
|
98
|
+
const label = labels.find((entry) => entry.xfId === index);
|
|
99
|
+
const style = {};
|
|
100
|
+
assignStyleFacets(style, xf);
|
|
101
|
+
if (label?.name !== undefined)
|
|
102
|
+
style.name = label.name;
|
|
103
|
+
if (label?.builtinId !== undefined)
|
|
104
|
+
style.builtinId = label.builtinId;
|
|
105
|
+
return style;
|
|
106
|
+
});
|
|
107
|
+
// Font 0 is the workbook's declared default, carried out whole as well as flattened onto the xfs
|
|
108
|
+
// that name it — see {@link StyleTable.defaultFont}. The XML reader does the same.
|
|
109
|
+
const defaultFont = fonts[0];
|
|
110
|
+
return defaultFont === undefined ? { cellXfs, namedStyles } : { cellXfs, namedStyles, defaultFont };
|
|
111
|
+
}
|
|
112
|
+
// `BrtXF` ([MS-XLSB] 2.4.876): five facet indices, the two inline alignment scalars, then two flag
|
|
113
|
+
// words. `isDirect` distinguishes a cellXfs entry (whose ixfeParent links to a named style) from a
|
|
114
|
+
// cellStyleXfs entry (whose ixfeParent is the 0xFFFF "I am the named style" marker).
|
|
115
|
+
function readXf(reader, deps, isDirect) {
|
|
116
|
+
const parent = reader.u16();
|
|
117
|
+
const numFmt = numFmtCodeFor(reader.u16(), deps.numFmtCodes);
|
|
118
|
+
const font = deps.fonts[reader.u16()];
|
|
119
|
+
const fill = deps.fills[reader.u16()];
|
|
120
|
+
const borderIndex = reader.u16();
|
|
121
|
+
// Border 0 is the genuinely empty default (font 0, by contrast, is the workbook's real default
|
|
122
|
+
// face), so only a custom index names an actual border — the same asymmetry the XML reader keeps.
|
|
123
|
+
const border = borderIndex > 0 ? deps.borders[borderIndex] : undefined;
|
|
124
|
+
const rotation = reader.u8();
|
|
125
|
+
const indent = reader.u8();
|
|
126
|
+
const flags = reader.u16();
|
|
127
|
+
const draft = {};
|
|
128
|
+
if (numFmt !== undefined)
|
|
129
|
+
draft.numFmt = numFmt;
|
|
130
|
+
if (font)
|
|
131
|
+
draft.font = font;
|
|
132
|
+
if (fill)
|
|
133
|
+
draft.fill = fill;
|
|
134
|
+
if (border)
|
|
135
|
+
draft.border = border;
|
|
136
|
+
const alignment = readAlignment(flags, rotation, indent);
|
|
137
|
+
if (alignment !== undefined)
|
|
138
|
+
draft.alignment = alignment;
|
|
139
|
+
const protection = readProtection(flags);
|
|
140
|
+
if (protection !== undefined)
|
|
141
|
+
draft.protection = protection;
|
|
142
|
+
// f123Prefix is the binary spelling of the `quotePrefix` attribute: the cell's text is displayed
|
|
143
|
+
// with a leading apostrophe stripped.
|
|
144
|
+
if ((flags & 0x8000) !== 0)
|
|
145
|
+
draft.quotePrefix = true;
|
|
146
|
+
// Only a link beyond the Normal default (0) carries information, and only a direct format has one.
|
|
147
|
+
if (isDirect && parent !== NOT_A_CELL_XF && parent > 0)
|
|
148
|
+
draft.xfId = parent;
|
|
149
|
+
return draft;
|
|
150
|
+
}
|
|
151
|
+
// The `ixfeParent` value a cell *style* XF carries in place of a link, since it is itself the base.
|
|
152
|
+
const NOT_A_CELL_XF = 0xffff;
|
|
153
|
+
// BIFF12 states every alignment field on every xf, where XML omits the ones at their default. Keep
|
|
154
|
+
// only what the XML reader would have seen, so the two readings of one workbook agree: `general`
|
|
155
|
+
// horizontal, `bottom` vertical, and zero rotation/indent/reading-order are absences, not values.
|
|
156
|
+
function readAlignment(flags, rotation, indent) {
|
|
157
|
+
const out = {};
|
|
158
|
+
const horizontal = HORIZONTAL_ALIGNMENTS[flags & 0b111];
|
|
159
|
+
if (horizontal !== undefined)
|
|
160
|
+
out.horizontal = horizontal;
|
|
161
|
+
const vertical = VERTICAL_ALIGNMENTS[(flags >> 3) & 0b111];
|
|
162
|
+
if (vertical !== undefined)
|
|
163
|
+
out.vertical = vertical;
|
|
164
|
+
if (rotation !== 0)
|
|
165
|
+
out.textRotation = rotation;
|
|
166
|
+
if ((flags & 0x0040) !== 0)
|
|
167
|
+
out.wrapText = true;
|
|
168
|
+
if (indent !== 0)
|
|
169
|
+
out.indent = indent;
|
|
170
|
+
if ((flags & 0x0100) !== 0)
|
|
171
|
+
out.shrinkToFit = true;
|
|
172
|
+
const readingOrder = (flags >> 10) & 0b11;
|
|
173
|
+
if (readingOrder !== 0)
|
|
174
|
+
out.readingOrder = readingOrder;
|
|
175
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
176
|
+
}
|
|
177
|
+
// `locked` defaults to TRUE in OOXML, so an *unlocked* cell is the state that carries information;
|
|
178
|
+
// `hidden` defaults to false, so only a set flag does. A default xf yields no protection at all.
|
|
179
|
+
function readProtection(flags) {
|
|
180
|
+
const out = {};
|
|
181
|
+
if ((flags & 0x1000) === 0)
|
|
182
|
+
out.locked = false;
|
|
183
|
+
if ((flags & 0x2000) !== 0)
|
|
184
|
+
out.hidden = true;
|
|
185
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
186
|
+
}
|
|
187
|
+
// `alc` ([MS-XLSB] 2.4.876), indexed by its stored value. `general` is index 0 and is left out
|
|
188
|
+
// deliberately: it is the type-dependent default, which the model spells as no horizontal alignment.
|
|
189
|
+
const HORIZONTAL_ALIGNMENTS = [
|
|
190
|
+
undefined,
|
|
191
|
+
'left',
|
|
192
|
+
'center',
|
|
193
|
+
'right',
|
|
194
|
+
'fill',
|
|
195
|
+
'justify',
|
|
196
|
+
'centerContinuous',
|
|
197
|
+
'distributed',
|
|
198
|
+
];
|
|
199
|
+
// `alcv`, likewise — with `bottom` (index 2) left out as the default.
|
|
200
|
+
const VERTICAL_ALIGNMENTS = [
|
|
201
|
+
'top',
|
|
202
|
+
'center',
|
|
203
|
+
undefined,
|
|
204
|
+
'justify',
|
|
205
|
+
'distributed',
|
|
206
|
+
];
|
|
207
|
+
// `BrtFont` ([MS-XLSB] 2.4.690). Weight is a numeric scale (400 normal, 700 bold) rather than a flag,
|
|
208
|
+
// and the italic/strike/outline bits live in a separate word from it.
|
|
209
|
+
function readFont(reader) {
|
|
210
|
+
const height = reader.u16();
|
|
211
|
+
const flags = reader.u16();
|
|
212
|
+
const weight = reader.u16();
|
|
213
|
+
const script = reader.u16();
|
|
214
|
+
const underline = reader.u8();
|
|
215
|
+
const family = reader.u8();
|
|
216
|
+
const charset = reader.u8();
|
|
217
|
+
reader.skip(1); // unused
|
|
218
|
+
const color = reader.color();
|
|
219
|
+
const scheme = reader.u8();
|
|
220
|
+
const name = reader.wideString();
|
|
221
|
+
const font = {};
|
|
222
|
+
if (name !== '')
|
|
223
|
+
font.name = name;
|
|
224
|
+
// Stored in twips; the model (like the XML) carries points.
|
|
225
|
+
if (height > 0)
|
|
226
|
+
font.size = height / 20;
|
|
227
|
+
if (family !== 0)
|
|
228
|
+
font.family = family;
|
|
229
|
+
if (charset !== 0)
|
|
230
|
+
font.charset = charset;
|
|
231
|
+
if (scheme === 1)
|
|
232
|
+
font.scheme = 'major';
|
|
233
|
+
else if (scheme === 2)
|
|
234
|
+
font.scheme = 'minor';
|
|
235
|
+
if (color !== undefined)
|
|
236
|
+
font.color = color;
|
|
237
|
+
// Each boolean facet is recorded only when on, mirroring XML's present-or-absent `<b/>`/`<i/>`:
|
|
238
|
+
// a non-bold font must not read back as `bold: false`.
|
|
239
|
+
if (weight >= BOLD_WEIGHT)
|
|
240
|
+
font.bold = true;
|
|
241
|
+
if ((flags & 0b0000_0010) !== 0)
|
|
242
|
+
font.italic = true;
|
|
243
|
+
if ((flags & 0b0000_1000) !== 0)
|
|
244
|
+
font.strike = true;
|
|
245
|
+
if ((flags & 0b0001_0000) !== 0)
|
|
246
|
+
font.outline = true;
|
|
247
|
+
const underlineStyle = UNDERLINE_STYLES.get(underline);
|
|
248
|
+
if (underlineStyle !== undefined)
|
|
249
|
+
font.underline = underlineStyle;
|
|
250
|
+
if (script === 1)
|
|
251
|
+
font.vertAlign = 'superscript';
|
|
252
|
+
else if (script === 2)
|
|
253
|
+
font.vertAlign = 'subscript';
|
|
254
|
+
return font;
|
|
255
|
+
}
|
|
256
|
+
const BOLD_WEIGHT = 700;
|
|
257
|
+
// `uls` ([MS-XLSB] 2.4.690). A single underline is `true`, not `'single'`, because that is what XML's
|
|
258
|
+
// bare `<u/>` — which is what Excel writes for it — reads back as.
|
|
259
|
+
const UNDERLINE_STYLES = new Map([
|
|
260
|
+
[0x01, true],
|
|
261
|
+
[0x02, 'double'],
|
|
262
|
+
[0x21, 'singleAccounting'],
|
|
263
|
+
[0x22, 'doubleAccounting'],
|
|
264
|
+
]);
|
|
265
|
+
// `BrtFill` ([MS-XLSB] 2.4.681). The pattern code and OOXML's `ST_PatternType` enumerate the same
|
|
266
|
+
// patterns in the same order, so the code indexes the name list directly.
|
|
267
|
+
function readFill(reader) {
|
|
268
|
+
const pattern = FILL_PATTERNS[reader.u32()];
|
|
269
|
+
// `none` is the absence of a fill, and an unmodelled pattern (a gradient — see below) is dropped
|
|
270
|
+
// rather than guessed, so an unfilled cell reads back unfilled either way.
|
|
271
|
+
if (pattern === undefined)
|
|
272
|
+
return undefined;
|
|
273
|
+
// BIFF12 always states both colours; XML states only the ones the fill actually has, using the two
|
|
274
|
+
// legacy-palette sentinels for the rest — 64 is "automatic foreground", 65 "automatic background".
|
|
275
|
+
// Dropping each in its own slot reproduces exactly what the XML reader sees: an untouched hatch
|
|
276
|
+
// pattern carries no colours at all, while a solid fill keeps the explicit `bgColor indexed="64"`
|
|
277
|
+
// Excel writes beside its foreground.
|
|
278
|
+
const fgColor = notSentinel(reader.color(), AUTOMATIC_FOREGROUND);
|
|
279
|
+
const bgColor = notSentinel(reader.color(), AUTOMATIC_BACKGROUND);
|
|
280
|
+
return {
|
|
281
|
+
type: 'pattern',
|
|
282
|
+
pattern,
|
|
283
|
+
...(fgColor ? { fgColor } : {}),
|
|
284
|
+
...(bgColor ? { bgColor } : {}),
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
const AUTOMATIC_FOREGROUND = 64;
|
|
288
|
+
const AUTOMATIC_BACKGROUND = 65;
|
|
289
|
+
function notSentinel(color, sentinel) {
|
|
290
|
+
return color?.indexed === sentinel ? undefined : color;
|
|
291
|
+
}
|
|
292
|
+
// Indexed by the stored `fls` value. Index 0 (`none`) is deliberately absent: an unfilled cell
|
|
293
|
+
// carries no fill. Gradient fills (`fls` 0x28) are not decoded in this cut — the stop array's layout
|
|
294
|
+
// is the one piece of BrtFill this reader has no Excel-authored sample to check against, and a
|
|
295
|
+
// silently wrong gradient is worse than none.
|
|
296
|
+
const FILL_PATTERNS = [
|
|
297
|
+
undefined,
|
|
298
|
+
'solid',
|
|
299
|
+
'mediumGray',
|
|
300
|
+
'darkGray',
|
|
301
|
+
'lightGray',
|
|
302
|
+
'darkHorizontal',
|
|
303
|
+
'darkVertical',
|
|
304
|
+
'darkDown',
|
|
305
|
+
'darkUp',
|
|
306
|
+
'darkGrid',
|
|
307
|
+
'darkTrellis',
|
|
308
|
+
'lightHorizontal',
|
|
309
|
+
'lightVertical',
|
|
310
|
+
'lightDown',
|
|
311
|
+
'lightUp',
|
|
312
|
+
'lightGrid',
|
|
313
|
+
'lightTrellis',
|
|
314
|
+
'gray125',
|
|
315
|
+
'gray0625',
|
|
316
|
+
];
|
|
317
|
+
// `BrtBorder` ([MS-XLSB] 2.4.314): the two diagonal-direction bits, then five `Blxf` edges in the
|
|
318
|
+
// order top, bottom, left, right, diagonal — which is *not* the model's or the schema's order, so
|
|
319
|
+
// the edges are read positionally and named here.
|
|
320
|
+
function readBorder(reader) {
|
|
321
|
+
const flags = reader.u8();
|
|
322
|
+
const top = readEdge(reader);
|
|
323
|
+
const bottom = readEdge(reader);
|
|
324
|
+
const left = readEdge(reader);
|
|
325
|
+
const right = readEdge(reader);
|
|
326
|
+
const diagonal = readEdge(reader);
|
|
327
|
+
const border = {};
|
|
328
|
+
if (left)
|
|
329
|
+
border.left = left;
|
|
330
|
+
if (right)
|
|
331
|
+
border.right = right;
|
|
332
|
+
if (top)
|
|
333
|
+
border.top = top;
|
|
334
|
+
if (bottom)
|
|
335
|
+
border.bottom = bottom;
|
|
336
|
+
if (diagonal)
|
|
337
|
+
border.diagonal = diagonal;
|
|
338
|
+
if ((flags & 0b01) !== 0)
|
|
339
|
+
border.diagonalDown = true;
|
|
340
|
+
if ((flags & 0b10) !== 0)
|
|
341
|
+
border.diagonalUp = true;
|
|
342
|
+
// An all-default border is the empty one every unbordered cell shares; it carries nothing.
|
|
343
|
+
return Object.keys(border).length > 0 ? border : undefined;
|
|
344
|
+
}
|
|
345
|
+
// A `Blxf` ([MS-XLSB] 2.5.5): a line style, a reserved byte, and a colour. Style 0 is "no edge",
|
|
346
|
+
// which the model spells by omitting the edge rather than by a `none` value.
|
|
347
|
+
function readEdge(reader) {
|
|
348
|
+
const style = BORDER_STYLES[reader.u8()];
|
|
349
|
+
reader.skip(1); // reserved
|
|
350
|
+
const color = reader.color();
|
|
351
|
+
if (style === undefined)
|
|
352
|
+
return undefined;
|
|
353
|
+
return color === undefined ? { style } : { style, color };
|
|
354
|
+
}
|
|
355
|
+
// Indexed by the stored `dg` value; index 0 (`none`) is absent, as above. The order is the binary
|
|
356
|
+
// format's own and differs from `ST_BorderStyle`'s declaration order, so it cannot be shared.
|
|
357
|
+
const BORDER_STYLES = [
|
|
358
|
+
undefined,
|
|
359
|
+
'thin',
|
|
360
|
+
'medium',
|
|
361
|
+
'dashed',
|
|
362
|
+
'dotted',
|
|
363
|
+
'thick',
|
|
364
|
+
'double',
|
|
365
|
+
'hair',
|
|
366
|
+
'mediumDashed',
|
|
367
|
+
'dashDot',
|
|
368
|
+
'mediumDashDot',
|
|
369
|
+
'dashDotDot',
|
|
370
|
+
'mediumDashDotDot',
|
|
371
|
+
'slantDashDot',
|
|
372
|
+
];
|
|
373
|
+
// `BrtStyle` ([MS-XLSB] 2.4.809): which cellStyleXfs entry this names, and how it is labelled. The
|
|
374
|
+
// gallery index is only meaningful for a built-in style, which the flag word declares.
|
|
375
|
+
function readStyleLabel(reader) {
|
|
376
|
+
const xfId = reader.u32();
|
|
377
|
+
const flags = reader.u16();
|
|
378
|
+
const builtinId = reader.u8();
|
|
379
|
+
reader.skip(1); // iLevel: the outline depth of a built-in RowLevel/ColLevel style.
|
|
380
|
+
const name = reader.wideString();
|
|
381
|
+
return {
|
|
382
|
+
xfId,
|
|
383
|
+
...(name !== '' ? { name } : {}),
|
|
384
|
+
...((flags & 0b1) !== 0 ? { builtinId } : {}),
|
|
385
|
+
};
|
|
386
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Worksheet } from '../../core/worksheet.ts';
|
|
2
|
+
import { type XfStyle } from '../style/xf-style.ts';
|
|
3
|
+
import { type FormulaScope } from './formula.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Read a worksheet part into `sheet`: its column and row geometry, its merged ranges, and every
|
|
6
|
+
* non-empty cell with the style its index resolves to in `xfStyles` and, for a formula cell, the text
|
|
7
|
+
* its token stream decodes to through `scope`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseWorksheet(part: Uint8Array, sheet: Worksheet, sharedStrings: readonly string[], xfStyles: ReadonlyArray<XfStyle>, scope: FormulaScope): void;
|