@shbernal/ts-xlsx 3.1.0 → 3.2.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 +30 -23
- package/dist/bytes.d.ts +3 -2
- package/dist/core/address.d.ts +36 -0
- package/dist/core/address.js +47 -9
- package/dist/core/array-formula-ranges.d.ts +33 -0
- package/dist/core/array-formula-ranges.js +62 -0
- package/dist/core/color-resolution.js +2 -2
- package/dist/core/column.js +3 -2
- package/dist/core/comment-thread.d.ts +7 -3
- package/dist/core/conditional-formatting-overlay.d.ts +9 -0
- package/dist/core/conditional-formatting-overlay.js +28 -1
- package/dist/core/conditional-formatting.d.ts +98 -10
- package/dist/core/conditional-formatting.js +42 -1
- package/dist/core/data-validation-overlay.d.ts +5 -0
- package/dist/core/data-validation-overlay.js +15 -0
- package/dist/core/data-validation.d.ts +16 -0
- package/dist/core/data-validation.js +15 -0
- package/dist/core/date-format.js +14 -4
- package/dist/core/date.js +1 -1
- package/dist/core/formula-references.d.ts +26 -0
- package/dist/core/formula-references.js +173 -0
- package/dist/core/formula-scan.d.ts +2 -0
- package/dist/core/formula-scan.js +58 -0
- package/dist/core/formula.d.ts +51 -18
- package/dist/core/formula.js +77 -86
- package/dist/core/function-values.d.ts +4 -0
- package/dist/core/function-values.js +58 -0
- package/dist/core/future-functions.d.ts +3 -0
- package/dist/core/{modern-functions.js → future-functions.js} +119 -88
- package/dist/core/grid-edits.d.ts +28 -0
- package/dist/core/grid-edits.js +193 -25
- package/dist/core/hyperlink.d.ts +39 -0
- package/dist/core/hyperlink.js +88 -0
- package/dist/core/image.d.ts +36 -5
- package/dist/core/image.js +9 -0
- package/dist/core/internal.d.ts +3 -1
- package/dist/core/limits.d.ts +5 -3
- package/dist/core/merge.d.ts +13 -0
- package/dist/core/merge.js +15 -1
- package/dist/core/page-setup.d.ts +26 -11
- package/dist/core/pivot-table.d.ts +49 -10
- package/dist/core/pivot-table.js +55 -21
- package/dist/core/protection.d.ts +66 -4
- package/dist/core/protection.js +4 -0
- package/dist/core/row.js +3 -2
- package/dist/core/structured-reference.d.ts +7 -0
- package/dist/core/structured-reference.js +7 -0
- package/dist/core/table.d.ts +38 -8
- package/dist/core/table.js +37 -7
- package/dist/core/theme.d.ts +2 -0
- package/dist/core/theme.js +4 -1
- package/dist/core/value.d.ts +51 -28
- package/dist/core/value.js +15 -12
- package/dist/core/workbook-styles.d.ts +17 -1
- package/dist/core/workbook-styles.js +4 -0
- package/dist/core/workbook-theme.js +5 -3
- package/dist/core/workbook.d.ts +20 -3
- package/dist/core/workbook.js +26 -5
- package/dist/core/worksheet-merges.d.ts +9 -4
- package/dist/core/worksheet-merges.js +17 -11
- package/dist/core/worksheet-model.d.ts +1 -1
- package/dist/core/worksheet-model.js +4 -0
- package/dist/core/worksheet-pictures.d.ts +3 -3
- package/dist/core/worksheet-pictures.js +7 -6
- package/dist/core/worksheet.d.ts +110 -21
- package/dist/core/worksheet.js +174 -49
- package/dist/entries/core.d.ts +7 -5
- package/dist/entries/core.js +4 -3
- package/dist/entries/errors.d.ts +1 -0
- package/dist/entries/errors.js +1 -0
- package/dist/errors.js +1 -1
- package/dist/io/cell-metadata/metadata.d.ts +42 -0
- package/dist/io/cell-metadata/metadata.js +35 -0
- package/dist/io/cell-metadata/rich-values.d.ts +11 -0
- package/dist/io/cell-metadata/rich-values.js +80 -0
- package/dist/io/csv/delimiter.d.ts +14 -2
- package/dist/io/csv/delimiter.js +12 -0
- package/dist/io/csv/errors.d.ts +14 -0
- package/dist/io/csv/errors.js +5 -0
- package/dist/io/csv/read.d.ts +6 -1
- package/dist/io/csv/read.js +46 -24
- package/dist/io/csv/write.d.ts +10 -3
- package/dist/io/csv/write.js +16 -7
- package/dist/io/opc/part-paths.js +4 -4
- package/dist/io/opc/read-opc.d.ts +4 -0
- package/dist/io/opc/read-opc.js +10 -4
- package/dist/io/opc/strict-relationships.d.ts +2 -0
- package/dist/io/opc/strict-relationships.js +12 -0
- package/dist/io/read-policy/column-budget.d.ts +26 -0
- package/dist/io/{xlsx → read-policy}/column-budget.js +4 -8
- package/dist/io/read-policy/read-repair.d.ts +74 -0
- package/dist/io/read-policy/read-repair.js +119 -0
- package/dist/io/style/cell-style-resolution.d.ts +25 -0
- package/dist/io/style/cell-style-resolution.js +30 -0
- package/dist/io/xlsb/formula.js +4 -2
- package/dist/io/xlsb/ptg-functions.js +110 -0
- package/dist/io/xlsb/read-metadata.d.ts +7 -0
- package/dist/io/xlsb/read-metadata.js +69 -0
- package/dist/io/xlsb/read-worksheet.d.ts +6 -0
- package/dist/io/xlsb/read-worksheet.js +95 -37
- package/dist/io/xlsb/read.js +26 -8
- package/dist/io/xlsb/record-types.d.ts +13 -0
- package/dist/io/xlsb/record-types.js +13 -0
- package/dist/io/xlsb/sheet-protection.d.ts +20 -0
- package/dist/io/xlsb/sheet-protection.js +60 -0
- package/dist/io/xlsx/cell-accumulator.d.ts +20 -12
- package/dist/io/xlsx/cell-accumulator.js +49 -19
- package/dist/io/xlsx/cell-metadata.d.ts +39 -0
- package/dist/io/xlsx/cell-metadata.js +162 -0
- package/dist/io/xlsx/cell-value.d.ts +16 -4
- package/dist/io/xlsx/cell-value.js +38 -21
- package/dist/io/xlsx/color-xml.js +1 -1
- package/dist/io/xlsx/column-span.d.ts +11 -0
- package/dist/io/xlsx/column-span.js +9 -0
- package/dist/io/xlsx/comments.d.ts +3 -28
- package/dist/io/xlsx/comments.js +3 -65
- package/dist/io/xlsx/conditional-formatting.d.ts +42 -25
- package/dist/io/xlsx/conditional-formatting.js +424 -129
- package/dist/io/xlsx/data-validation.d.ts +12 -7
- package/dist/io/xlsx/data-validation.js +41 -29
- package/dist/io/xlsx/edit-vba.js +43 -36
- package/dist/io/xlsx/hyperlinks.d.ts +16 -50
- package/dist/io/xlsx/hyperlinks.js +8 -37
- package/dist/io/xlsx/images.d.ts +49 -16
- package/dist/io/xlsx/images.js +145 -44
- package/dist/io/xlsx/namespaces.d.ts +8 -0
- package/dist/io/xlsx/namespaces.js +4 -0
- package/dist/io/xlsx/package-plan.d.ts +48 -15
- package/dist/io/xlsx/package-plan.js +46 -9
- package/dist/io/xlsx/part-names.d.ts +6 -8
- package/dist/io/xlsx/part-names.js +3 -7
- package/dist/io/xlsx/pivot.d.ts +5 -5
- package/dist/io/xlsx/pivot.js +23 -22
- package/dist/io/xlsx/preserved-splices.d.ts +6 -0
- package/dist/io/xlsx/preserved-splices.js +74 -0
- package/dist/io/xlsx/read-comments.d.ts +29 -0
- package/dist/io/xlsx/read-comments.js +75 -0
- package/dist/io/xlsx/read-parts.d.ts +2 -2
- package/dist/io/xlsx/read-parts.js +44 -37
- package/dist/io/xlsx/read-pivot.js +9 -3
- package/dist/io/xlsx/read-rich-runs.d.ts +8 -5
- package/dist/io/xlsx/read-rich-runs.js +18 -1
- package/dist/io/xlsx/read-rows.d.ts +18 -7
- package/dist/io/xlsx/read-rows.js +47 -37
- package/dist/io/xlsx/read-styles.d.ts +0 -25
- package/dist/io/xlsx/read-styles.js +39 -34
- package/dist/io/xlsx/read-workbook-xml.d.ts +6 -0
- package/dist/io/xlsx/read-workbook-xml.js +9 -4
- package/dist/io/xlsx/read-worksheet.d.ts +8 -3
- package/dist/io/xlsx/read-worksheet.js +45 -23
- package/dist/io/xlsx/read.d.ts +0 -4
- package/dist/io/xlsx/read.js +17 -21
- package/dist/io/xlsx/relationships.d.ts +3 -0
- package/dist/io/xlsx/relationships.js +4 -0
- package/dist/io/xlsx/row-position.d.ts +3 -1
- package/dist/io/xlsx/row-xml.d.ts +18 -7
- package/dist/io/xlsx/row-xml.js +54 -35
- package/dist/io/xlsx/sheet-properties.js +68 -42
- package/dist/io/xlsx/strict-parts.d.ts +7 -0
- package/dist/io/xlsx/strict-parts.js +171 -0
- package/dist/io/xlsx/style-elements.d.ts +0 -2
- package/dist/io/xlsx/style-elements.js +9 -29
- package/dist/io/xlsx/styles.d.ts +5 -0
- package/dist/io/xlsx/styles.js +11 -5
- package/dist/io/xlsx/tables.d.ts +10 -2
- package/dist/io/xlsx/tables.js +49 -42
- package/dist/io/xlsx/theme-xml.d.ts +6 -0
- package/dist/io/xlsx/theme-xml.js +16 -19
- package/dist/io/xlsx/threaded-comments.d.ts +6 -1
- package/dist/io/xlsx/threaded-comments.js +14 -7
- package/dist/io/xlsx/workbook-xml.d.ts +13 -24
- package/dist/io/xlsx/workbook-xml.js +15 -33
- package/dist/io/xlsx/worksheet-xml.d.ts +5 -2
- package/dist/io/xlsx/worksheet-xml.js +37 -69
- package/dist/io/xlsx/write-stream.d.ts +28 -6
- package/dist/io/xlsx/write-stream.js +42 -17
- package/dist/io/xlsx/write.d.ts +11 -4
- package/dist/io/xlsx/write.js +153 -90
- package/dist/rel-type.d.ts +9 -0
- package/dist/rel-type.js +3 -0
- package/dist/vba/bytes.d.ts +2 -0
- package/dist/vba/bytes.js +11 -0
- package/dist/vba/cfb-format.d.ts +47 -0
- package/dist/vba/cfb-format.js +34 -0
- package/dist/vba/cfb-writer.d.ts +1 -2
- package/dist/vba/cfb-writer.js +33 -36
- package/dist/vba/cfb.d.ts +9 -4
- package/dist/vba/cfb.js +55 -43
- package/dist/vba/dir-records.d.ts +6 -0
- package/dist/vba/dir-records.js +10 -2
- package/dist/vba/errors.d.ts +4 -4
- package/dist/vba/index.d.ts +0 -2
- package/dist/vba/index.js +0 -2
- package/dist/vba/ms-ovba.d.ts +6 -2
- package/dist/vba/ms-ovba.js +15 -6
- package/dist/vba/project-editor.js +102 -87
- package/dist/vba/project.d.ts +4 -0
- package/dist/vba/project.js +12 -6
- package/dist/vba/vba-encoding.d.ts +4 -10
- package/dist/vba/vba-encoding.js +2 -15
- package/dist/xml/xml-read.d.ts +29 -1
- package/dist/xml/xml-read.js +56 -0
- package/dist/xml/xml-scan.d.ts +13 -0
- package/dist/xml/xml-scan.js +58 -7
- package/dist/xml/xml.d.ts +33 -1
- package/dist/xml/xml.js +22 -0
- package/package.json +5 -4
- package/skills/ts-xlsx-upstream/SKILL.md +21 -13
- package/dist/core/modern-functions.d.ts +0 -1
- package/dist/io/xlsx/cell-style-resolution.d.ts +0 -25
- package/dist/io/xlsx/cell-style-resolution.js +0 -29
- package/dist/io/xlsx/column-budget.d.ts +0 -26
- package/dist/io/xlsx/read-repair.d.ts +0 -26
- package/dist/io/xlsx/read-repair.js +0 -39
|
@@ -3,13 +3,15 @@ import { PassThrough } from 'node:stream';
|
|
|
3
3
|
import { Zip, ZipDeflate } from 'fflate';
|
|
4
4
|
import { concat } from '../../bytes.js';
|
|
5
5
|
import { encodeAddress, tryDecodeCellRef } from '../../core/address.js';
|
|
6
|
+
import { formulaPlacement } from '../../core/array-formula-ranges.js';
|
|
7
|
+
import { formulaNamesInScope } from '../../core/formula.js';
|
|
6
8
|
import { INTERNAL } from '../../core/internal.js';
|
|
7
9
|
import { isSharedFormulaValue } from '../../core/value.js';
|
|
8
|
-
import { Workbook } from '../../core/workbook.js';
|
|
10
|
+
import { Workbook, } from '../../core/workbook.js';
|
|
9
11
|
import { AuthoringError, quoted } from '../../errors.js';
|
|
10
12
|
import { FIXED_ENTRY_MTIME } from '../opc/zip-mtime.js';
|
|
13
|
+
import { WorkbookMetadataTable } from './cell-metadata.js';
|
|
11
14
|
import { collectNotes } from './comments.js';
|
|
12
|
-
import { collectHyperlinks } from './hyperlinks.js';
|
|
13
15
|
import { buildColumnDefaults, Extent, renderRow, } from './row-xml.js';
|
|
14
16
|
import { buildPackageParts, createStyleRegistry } from './write.js';
|
|
15
17
|
export class StreamedRow {
|
|
@@ -22,6 +24,11 @@ export class StreamedRow {
|
|
|
22
24
|
this.#sheet = sheet;
|
|
23
25
|
this.#number = number;
|
|
24
26
|
}
|
|
27
|
+
static [INTERNAL] = {
|
|
28
|
+
create(cells, sheet, number) {
|
|
29
|
+
return new StreamedRow(cells, sheet, number);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
25
32
|
get cells() {
|
|
26
33
|
return this.#cells;
|
|
27
34
|
}
|
|
@@ -29,7 +36,7 @@ export class StreamedRow {
|
|
|
29
36
|
if (this.#committed)
|
|
30
37
|
return;
|
|
31
38
|
this.#committed = true;
|
|
32
|
-
this.#sheet?.[INTERNAL].flushRow(this.#number
|
|
39
|
+
this.#sheet?.[INTERNAL].flushRow(this.#number);
|
|
33
40
|
}
|
|
34
41
|
}
|
|
35
42
|
export class WorksheetStreamWriter {
|
|
@@ -43,18 +50,22 @@ export class WorksheetStreamWriter {
|
|
|
43
50
|
#flushedNumbers = new Set();
|
|
44
51
|
#extent = new Extent();
|
|
45
52
|
#rowOutline = new Map();
|
|
46
|
-
#hyperlinks = [];
|
|
47
53
|
#notes = [];
|
|
54
|
+
#formulas = [];
|
|
48
55
|
#dateEpoch;
|
|
49
|
-
|
|
56
|
+
#definedNames;
|
|
57
|
+
#cellMetadata;
|
|
58
|
+
constructor(sheet, eager, styles, cellMetadata, dateEpoch, definedNames) {
|
|
50
59
|
this.#sheet = sheet;
|
|
51
60
|
this.#eager = eager;
|
|
52
61
|
this.#styles = styles;
|
|
62
|
+
this.#cellMetadata = cellMetadata;
|
|
53
63
|
this.#dateEpoch = dateEpoch;
|
|
64
|
+
this.#definedNames = definedNames;
|
|
54
65
|
}
|
|
55
66
|
static [INTERNAL] = {
|
|
56
|
-
create(sheet, eager, styles, dateEpoch) {
|
|
57
|
-
return new WorksheetStreamWriter(sheet, eager, styles, dateEpoch);
|
|
67
|
+
create(sheet, eager, styles, cellMetadata, dateEpoch, definedNames) {
|
|
68
|
+
return new WorksheetStreamWriter(sheet, eager, styles, cellMetadata, dateEpoch, definedNames);
|
|
58
69
|
},
|
|
59
70
|
};
|
|
60
71
|
get name() {
|
|
@@ -66,14 +77,14 @@ export class WorksheetStreamWriter {
|
|
|
66
77
|
addRow(values) {
|
|
67
78
|
this.#assertOpen();
|
|
68
79
|
if (!this.#eager)
|
|
69
|
-
return
|
|
80
|
+
return StreamedRow[INTERNAL].create(this.#sheet.addRow(values), null, 0);
|
|
70
81
|
const number = this.#nextRowNumber();
|
|
71
|
-
return
|
|
82
|
+
return StreamedRow[INTERNAL].create(this.#placeRow(number, values), this, number);
|
|
72
83
|
}
|
|
73
84
|
addRows(rows) {
|
|
74
85
|
this.#assertOpen();
|
|
75
86
|
if (!this.#eager)
|
|
76
|
-
return this.#sheet.addRows(rows).map((cells) =>
|
|
87
|
+
return this.#sheet.addRows(rows).map((cells) => StreamedRow[INTERNAL].create(cells, null, 0));
|
|
77
88
|
return rows.map((values) => this.addRow(values));
|
|
78
89
|
}
|
|
79
90
|
#nextRowNumber() {
|
|
@@ -89,7 +100,9 @@ export class WorksheetStreamWriter {
|
|
|
89
100
|
});
|
|
90
101
|
return cells;
|
|
91
102
|
}
|
|
92
|
-
#flushRow(number
|
|
103
|
+
#flushRow(number) {
|
|
104
|
+
const row = this.#sheet.getRow(number);
|
|
105
|
+
const { cells } = row;
|
|
93
106
|
for (const cell of cells) {
|
|
94
107
|
if (isSharedFormulaValue(cell.value)) {
|
|
95
108
|
throw new AuthoringError(`row ${number} of streamed sheet ${quoted(this.#sheet.name)} carries a shared-formula cell; a ` +
|
|
@@ -98,13 +111,17 @@ export class WorksheetStreamWriter {
|
|
|
98
111
|
}
|
|
99
112
|
}
|
|
100
113
|
this.#columnDefaults ??= buildColumnDefaults(this.#sheet);
|
|
101
|
-
const properties =
|
|
114
|
+
const { properties } = row;
|
|
102
115
|
this.#rowOutline.set(number, {
|
|
103
116
|
outlineLevel: properties?.outlineLevel ?? 0,
|
|
104
117
|
hidden: properties?.hidden ?? false,
|
|
105
118
|
});
|
|
106
|
-
this.#hyperlinks.push(...collectHyperlinks(cells));
|
|
107
119
|
this.#notes.push(...collectNotes(cells));
|
|
120
|
+
for (const cell of cells) {
|
|
121
|
+
const placement = formulaPlacement(cell.address, cell.col, cell.row, cell.value);
|
|
122
|
+
if (placement !== undefined)
|
|
123
|
+
this.#formulas.push(placement);
|
|
124
|
+
}
|
|
108
125
|
const { xml, attrs, minCol, maxCol } = renderRow({ number, cells, properties }, {
|
|
109
126
|
columnDefaults: this.#columnDefaults,
|
|
110
127
|
styles: this.#styles,
|
|
@@ -112,6 +129,8 @@ export class WorksheetStreamWriter {
|
|
|
112
129
|
sharedRoles: new Map(),
|
|
113
130
|
collapsedSummaries: new Set(),
|
|
114
131
|
dateEpoch: this.#dateEpoch,
|
|
132
|
+
formulaNames: formulaNamesInScope(this.#definedNames, this.#sheet.name),
|
|
133
|
+
cellMetadata: this.#cellMetadata,
|
|
115
134
|
});
|
|
116
135
|
if (xml !== '') {
|
|
117
136
|
this.#flushedRows.push({ number, xml, attrs });
|
|
@@ -127,8 +146,8 @@ export class WorksheetStreamWriter {
|
|
|
127
146
|
rows: this.#flushedRows,
|
|
128
147
|
extent: this.#extent,
|
|
129
148
|
rowOutline: this.#rowOutline,
|
|
130
|
-
hyperlinks: this.#hyperlinks,
|
|
131
149
|
notes: this.#notes,
|
|
150
|
+
formulas: this.#formulas,
|
|
132
151
|
};
|
|
133
152
|
}
|
|
134
153
|
getCell(reference) {
|
|
@@ -145,6 +164,10 @@ export class WorksheetStreamWriter {
|
|
|
145
164
|
this.#assertOpen();
|
|
146
165
|
this.#sheet.addDataValidation(sqref, rule, options);
|
|
147
166
|
}
|
|
167
|
+
addHyperlink(link) {
|
|
168
|
+
this.#assertOpen();
|
|
169
|
+
this.#sheet.addHyperlink(link);
|
|
170
|
+
}
|
|
148
171
|
addConditionalFormatting(formatting) {
|
|
149
172
|
this.#assertOpen();
|
|
150
173
|
this.#sheet.addConditionalFormatting(formatting);
|
|
@@ -174,8 +197,8 @@ export class WorksheetStreamWriter {
|
|
|
174
197
|
return this.#sheet;
|
|
175
198
|
}
|
|
176
199
|
[INTERNAL] = {
|
|
177
|
-
flushRow: (number
|
|
178
|
-
this.#flushRow(number
|
|
200
|
+
flushRow: (number) => {
|
|
201
|
+
this.#flushRow(number);
|
|
179
202
|
},
|
|
180
203
|
flushedSheet: () => this.#flushedSheet(),
|
|
181
204
|
};
|
|
@@ -191,6 +214,7 @@ export class WorkbookStreamWriter {
|
|
|
191
214
|
#writeOptions;
|
|
192
215
|
#sink;
|
|
193
216
|
#styles;
|
|
217
|
+
#cellMetadata = new WorkbookMetadataTable();
|
|
194
218
|
#eager;
|
|
195
219
|
#stream;
|
|
196
220
|
#committed = false;
|
|
@@ -220,7 +244,7 @@ export class WorkbookStreamWriter {
|
|
|
220
244
|
}
|
|
221
245
|
addWorksheet(name, options = {}) {
|
|
222
246
|
this.#assertOpen('no more worksheets can be added');
|
|
223
|
-
const sheet = WorksheetStreamWriter[INTERNAL].create(this.#workbook.addWorksheet(name, options), this.#eager, this.#styles, this.#workbook.dateEpoch);
|
|
247
|
+
const sheet = WorksheetStreamWriter[INTERNAL].create(this.#workbook.addWorksheet(name, options), this.#eager, this.#styles, this.#cellMetadata, this.#workbook.dateEpoch, this.#workbook.definedNames);
|
|
224
248
|
this.#sheets.push(sheet);
|
|
225
249
|
return sheet;
|
|
226
250
|
}
|
|
@@ -245,6 +269,7 @@ export class WorkbookStreamWriter {
|
|
|
245
269
|
const parts = buildPackageParts(this.#workbook, {
|
|
246
270
|
...this.#writeOptions,
|
|
247
271
|
styles: this.#styles,
|
|
272
|
+
cellMetadata: this.#cellMetadata,
|
|
248
273
|
flushed,
|
|
249
274
|
});
|
|
250
275
|
const bytes = await streamZipPackage(parts, (chunk) => {
|
package/dist/io/xlsx/write.d.ts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import type { Workbook } from '../../core/workbook.ts';
|
|
2
2
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
3
|
+
import { WorkbookMetadataTable } from './cell-metadata.ts';
|
|
3
4
|
import type { FlushedSheet } from './row-xml.ts';
|
|
4
5
|
import { StyleRegistry } from './styles.ts';
|
|
5
6
|
/** Options controlling how {@link writeXlsx} serialises a workbook. */
|
|
6
7
|
export interface WriteOptions {
|
|
7
8
|
/**
|
|
8
|
-
* Pool
|
|
9
|
-
* reference by index, rather than storing each
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* Pool string and rich-text cell values into a shared-strings table (`xl/sharedStrings.xml`) that
|
|
10
|
+
* cells reference by index, rather than storing each inline in its cell. Deduplicates repeated text
|
|
11
|
+
* and matches Excel's own storage; a rich value is pooled as a `<si>` of its runs, so its formatting
|
|
12
|
+
* survives. Off by default, which keeps strings inline and omits the part.
|
|
12
13
|
*/
|
|
13
14
|
readonly useSharedStrings?: boolean;
|
|
14
15
|
}
|
|
@@ -27,6 +28,12 @@ export interface InternalWriteOptions extends WriteOptions {
|
|
|
27
28
|
* so its output is unchanged.
|
|
28
29
|
*/
|
|
29
30
|
readonly styles?: StyleRegistry;
|
|
31
|
+
/**
|
|
32
|
+
* The workbook metadata to record into, in place of a fresh table, for the reason {@link styles} is
|
|
33
|
+
* shared: a row the streaming writer rendered eagerly may already point a dynamic-array formula or a
|
|
34
|
+
* rich-value error at the parts this table decides whether to emit.
|
|
35
|
+
*/
|
|
36
|
+
readonly cellMetadata?: WorkbookMetadataTable;
|
|
30
37
|
/**
|
|
31
38
|
* Per-sheet rows already serialised and evicted from the model by the streaming writer, keyed by
|
|
32
39
|
* the model worksheet. Their XML is emitted ahead of the sheet's remaining live rows and their
|
package/dist/io/xlsx/write.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { strToU8, zip, zipSync } from 'fflate';
|
|
2
|
+
import { formulaNamesInScope } from '../../core/formula.js';
|
|
3
|
+
import { pictureProperties } from '../../core/image.js';
|
|
2
4
|
import { AuthoringError, InternalError, quoted } from '../../errors.js';
|
|
3
5
|
import { isRelType } from '../../rel-type.js';
|
|
4
|
-
import {
|
|
6
|
+
import { relsPathFor, THEME_PART_PATH } from '../opc/part-paths.js';
|
|
5
7
|
import { relsPartXml } from '../opc/rels.js';
|
|
6
8
|
import { FIXED_ENTRY_MTIME } from '../opc/zip-mtime.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
9
|
+
import { RICH_VALUE_STRUCTURES_XML, WorkbookMetadataTable } from './cell-metadata.js';
|
|
10
|
+
import { collectComments, commentsXml, liveCells, vmlDrawingXml } from './comments.js';
|
|
11
|
+
import { planHyperlinks } from './hyperlinks.js';
|
|
12
|
+
import { drawingXml } from './images.js';
|
|
13
|
+
import { planMedia, planPreservedParts, RelationshipLedger, } from './package-plan.js';
|
|
14
|
+
import { APP_PROPS_PART, commentsPart, CORE_PROPS_PART, drawingPart, mediaPart, METADATA_PART, PERSONS_PART, pivotCacheDefinitionPart, pivotCacheRecordsPart, pivotTablePart, printerSettingsPart, RICH_VALUE_STRUCTURES_PART, RICH_VALUES_PART, SHARED_STRINGS_PART, STYLES_PART, tablePart, threadedCommentsPart, vmlDrawingPart, WORKBOOK_PART, worksheetPart, } from './part-names.js';
|
|
12
15
|
import { pivotCacheDefinitionXml, pivotCacheRecordsXml, pivotTableXml } from './pivot.js';
|
|
13
16
|
import { REL } from './relationships.js';
|
|
14
17
|
import { SharedStringTable } from './shared-strings.js';
|
|
@@ -16,8 +19,8 @@ import { StyleRegistry } from './styles.js';
|
|
|
16
19
|
import { tableXml } from './tables.js';
|
|
17
20
|
import { applyThemeOverrides, DEFAULT_THEME_XML } from './theme-xml.js';
|
|
18
21
|
import { personsXml, threadedCommentsXml } from './threaded-comments.js';
|
|
19
|
-
import { appPropsXml, contentTypesXml, corePropsXml,
|
|
20
|
-
import {
|
|
22
|
+
import { appPropsXml, contentTypesXml, corePropsXml, workbookXml, } from './workbook-xml.js';
|
|
23
|
+
import { worksheetXml } from './worksheet-xml.js';
|
|
21
24
|
export function writeXlsx(workbook, options = {}) {
|
|
22
25
|
return zipSync(buildPackageParts(workbook, options), { level: 6, mtime: FIXED_ENTRY_MTIME });
|
|
23
26
|
}
|
|
@@ -48,52 +51,77 @@ export function createStyleRegistry(workbook) {
|
|
|
48
51
|
styles.addTableStyle(style);
|
|
49
52
|
return styles;
|
|
50
53
|
}
|
|
54
|
+
function keptDrawingPath(sheet) {
|
|
55
|
+
return sheet.preservedReferences.find((reference) => reference.element === 'drawing')?.entryPath;
|
|
56
|
+
}
|
|
57
|
+
function drawingImages(sheet, media, drawingRels) {
|
|
58
|
+
return sheet.images.map((image) => {
|
|
59
|
+
const { number: mediaNumber, image: registered } = media.resolve(image.imageId);
|
|
60
|
+
const embedId = drawingRels.add(REL.image, mediaPart(mediaNumber, registered.extension));
|
|
61
|
+
const properties = pictureProperties(image);
|
|
62
|
+
const target = properties.hyperlink?.target;
|
|
63
|
+
if (target === undefined)
|
|
64
|
+
return { anchor: image.anchor, embedId, properties };
|
|
65
|
+
const hyperlinkId = target.startsWith('#')
|
|
66
|
+
? drawingRels.addInDocument(REL.hyperlink, target)
|
|
67
|
+
: drawingRels.addExternal(REL.hyperlink, target);
|
|
68
|
+
return { anchor: image.anchor, embedId, properties, hyperlinkId };
|
|
69
|
+
});
|
|
70
|
+
}
|
|
51
71
|
function planSheet(context) {
|
|
52
72
|
const { sheet, index, media, preserved, numbering, flushed } = context;
|
|
53
|
-
const rels = new
|
|
54
|
-
const tables = sheet.tables.map((table) =>
|
|
55
|
-
table
|
|
56
|
-
number:
|
|
57
|
-
|
|
58
|
-
}));
|
|
73
|
+
const rels = new RelationshipLedger(worksheetPart(index + 1));
|
|
74
|
+
const tables = sheet.tables.map((table) => {
|
|
75
|
+
const number = ++numbering.table;
|
|
76
|
+
return { table, number, relId: rels.add(REL.table, tablePart(number)) };
|
|
77
|
+
});
|
|
59
78
|
let drawing = null;
|
|
60
|
-
if (sheet.images.length > 0) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
drawing = { number: ++numbering.drawing, relId: rels.next(), images };
|
|
79
|
+
if (sheet.images.length > 0 && keptDrawingPath(sheet) === undefined) {
|
|
80
|
+
const number = ++numbering.drawing;
|
|
81
|
+
const path = drawingPart(number);
|
|
82
|
+
const drawingRels = new RelationshipLedger(path);
|
|
83
|
+
drawing = {
|
|
84
|
+
number,
|
|
85
|
+
relId: rels.add(REL.drawing, path),
|
|
86
|
+
images: drawingImages(sheet, media, drawingRels),
|
|
87
|
+
relationships: drawingRels.relationships,
|
|
88
|
+
};
|
|
71
89
|
}
|
|
72
90
|
const threads = sheet.commentThreads.filter((thread) => thread.comments.length > 0);
|
|
73
91
|
const sheetComments = collectComments(liveCells(sheet), threads, flushed?.notes ?? []);
|
|
74
|
-
|
|
92
|
+
let comments = null;
|
|
93
|
+
if (sheetComments.length > 0) {
|
|
94
|
+
const vmlRelId = rels.add(REL.vmlDrawing, vmlDrawingPart(index + 1));
|
|
95
|
+
rels.add(REL.comments, commentsPart(index + 1));
|
|
96
|
+
comments = { number: index + 1, comments: sheetComments, vmlRelId };
|
|
97
|
+
}
|
|
98
|
+
let threadedComments = null;
|
|
99
|
+
if (threads.length > 0) {
|
|
100
|
+
rels.add(REL.threadedComment, threadedCommentsPart(index + 1));
|
|
101
|
+
threadedComments = { number: index + 1, threads };
|
|
102
|
+
}
|
|
103
|
+
const printerData = sheet.pageSetup.printerSettings;
|
|
104
|
+
const printerSettings = printerData === undefined
|
|
75
105
|
? null
|
|
76
106
|
: {
|
|
77
107
|
number: index + 1,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
commentsRelId: rels.next(),
|
|
108
|
+
data: printerData,
|
|
109
|
+
relId: rels.add(REL.printerSettings, printerSettingsPart(index + 1)),
|
|
81
110
|
};
|
|
82
|
-
const
|
|
83
|
-
const printerData = sheet.pageSetup.printerSettings;
|
|
84
|
-
const printerSettings = printerData === undefined ? null : { number: index + 1, data: printerData, relId: rels.next() };
|
|
85
|
-
const hyperlinks = planHyperlinks([...collectHyperlinks(liveCells(sheet)), ...(flushed?.hyperlinks ?? [])].sort((a, b) => a.row - b.row || a.col - b.col), rels);
|
|
111
|
+
const hyperlinks = planHyperlinks(sheet.hyperlinks, rels);
|
|
86
112
|
let background = null;
|
|
87
113
|
if (sheet.backgroundImageId !== undefined) {
|
|
88
114
|
const { number, image } = media.resolve(sheet.backgroundImageId);
|
|
89
|
-
background = { relId: rels.
|
|
115
|
+
background = { relId: rels.add(REL.image, mediaPart(number, image.extension)) };
|
|
90
116
|
}
|
|
91
|
-
const preservedRefs = (preserved.perSheet[index] ?? []).map((reference) => ({ ...reference, relId: rels.
|
|
117
|
+
const preservedRefs = (preserved.perSheet[index] ?? []).map((reference) => ({ ...reference, relId: rels.add(reference.relType, reference.entryPath) }));
|
|
92
118
|
const pivots = sheet.pivotTables.map((table) => {
|
|
93
119
|
const number = ++numbering.pivot;
|
|
94
|
-
|
|
120
|
+
rels.add(REL.pivotTable, pivotTablePart(number));
|
|
121
|
+
return { number, cacheId: String(number), table, workbookRelId: '' };
|
|
95
122
|
});
|
|
96
123
|
return {
|
|
124
|
+
relationships: rels.relationships,
|
|
97
125
|
tables,
|
|
98
126
|
drawing,
|
|
99
127
|
comments,
|
|
@@ -130,31 +158,55 @@ function resolveSheetReferences(plan) {
|
|
|
130
158
|
slicerRelIds,
|
|
131
159
|
};
|
|
132
160
|
}
|
|
133
|
-
function
|
|
134
|
-
const { sheetCount, hasSharedStrings, hasPersons, preservedWorkbook, pivots } = context;
|
|
135
|
-
const
|
|
136
|
-
const sheetRelIds = Array.from({ length: sheetCount }, () =>
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
161
|
+
function planWorkbookRelationships(context) {
|
|
162
|
+
const { sheetCount, hasSharedStrings, hasPersons, hasCellMetadata, hasRichValues, preservedWorkbook, pivots, } = context;
|
|
163
|
+
const rels = new RelationshipLedger(WORKBOOK_PART);
|
|
164
|
+
const sheetRelIds = Array.from({ length: sheetCount }, (_, i) => rels.add(REL.worksheet, worksheetPart(i + 1)));
|
|
165
|
+
rels.add(REL.styles, STYLES_PART);
|
|
166
|
+
rels.add(REL.theme, THEME_PART_PATH);
|
|
167
|
+
if (hasSharedStrings)
|
|
168
|
+
rels.add(REL.sharedStrings, SHARED_STRINGS_PART);
|
|
169
|
+
if (hasPersons)
|
|
170
|
+
rels.add(REL.person, PERSONS_PART);
|
|
171
|
+
if (hasCellMetadata)
|
|
172
|
+
rels.add(REL.sheetMetadata, METADATA_PART);
|
|
173
|
+
if (hasRichValues) {
|
|
174
|
+
rels.add(REL.rdRichValue, RICH_VALUES_PART);
|
|
175
|
+
rels.add(REL.rdRichValueStructure, RICH_VALUE_STRUCTURES_PART);
|
|
176
|
+
}
|
|
177
|
+
const preservedWorkbookRels = preservedWorkbook.map((ref) => ({
|
|
178
|
+
...ref,
|
|
179
|
+
relId: rels.add(ref.relType, ref.entryPath),
|
|
180
|
+
}));
|
|
181
|
+
for (const pivot of pivots) {
|
|
182
|
+
pivot.workbookRelId = rels.add(REL.pivotCacheDefinition, pivotCacheDefinitionPart(pivot.number));
|
|
183
|
+
}
|
|
184
|
+
return { sheetRelIds, preservedWorkbookRels, relationships: rels.relationships };
|
|
185
|
+
}
|
|
186
|
+
function planRootRelationships(rootRefs) {
|
|
187
|
+
const rels = new RelationshipLedger('');
|
|
188
|
+
rels.add(REL.officeDocument, WORKBOOK_PART);
|
|
189
|
+
rels.add(REL.coreProps, CORE_PROPS_PART);
|
|
190
|
+
rels.add(REL.extProps, APP_PROPS_PART);
|
|
191
|
+
for (const ref of rootRefs)
|
|
192
|
+
rels.add(ref.relType, ref.entryPath);
|
|
193
|
+
return rels.relationships;
|
|
152
194
|
}
|
|
153
195
|
function planPackage(workbook, sheets, flushed) {
|
|
154
196
|
const media = planMedia(workbook, sheets);
|
|
155
|
-
const
|
|
197
|
+
const pictures = new Map();
|
|
198
|
+
let generatedDrawingCount = 0;
|
|
199
|
+
for (const sheet of sheets) {
|
|
200
|
+
if (sheet.images.length === 0)
|
|
201
|
+
continue;
|
|
202
|
+
const kept = keptDrawingPath(sheet);
|
|
203
|
+
if (kept === undefined)
|
|
204
|
+
generatedDrawingCount += 1;
|
|
205
|
+
else
|
|
206
|
+
pictures.set(kept, (ledger) => drawingImages(sheet, media, ledger));
|
|
207
|
+
}
|
|
156
208
|
const generatedPivotCount = sheets.reduce((total, sheet) => total + sheet.pivotTables.length, 0);
|
|
157
|
-
const preserved = planPreservedParts(workbook, generatedDrawingCount, media.parts.length, generatedPivotCount);
|
|
209
|
+
const preserved = planPreservedParts(workbook, generatedDrawingCount, media.parts.length, generatedPivotCount, pictures);
|
|
158
210
|
const numbering = { table: 0, drawing: 0, pivot: 0 };
|
|
159
211
|
const perSheet = sheets.map((sheet, index) => planSheet({ sheet, index, media, preserved, numbering, flushed: flushed?.get(sheet) }));
|
|
160
212
|
return {
|
|
@@ -166,7 +218,7 @@ function planPackage(workbook, sheets, flushed) {
|
|
|
166
218
|
};
|
|
167
219
|
}
|
|
168
220
|
function serialiseSheets(context) {
|
|
169
|
-
const { workbook, sheets, plan, styles, sharedStrings, flushed } = context;
|
|
221
|
+
const { workbook, sheets, plan, styles, sharedStrings, cellMetadata, flushed } = context;
|
|
170
222
|
return sheets.map((sheet, i) => {
|
|
171
223
|
const sheetPlan = plan.perSheet[i];
|
|
172
224
|
return worksheetXml({
|
|
@@ -176,25 +228,31 @@ function serialiseSheets(context) {
|
|
|
176
228
|
references: resolveSheetReferences(sheetPlan),
|
|
177
229
|
hyperlinks: sheetPlan.hyperlinks,
|
|
178
230
|
sharedStrings,
|
|
231
|
+
cellMetadata,
|
|
179
232
|
dateEpoch: workbook.dateEpoch,
|
|
233
|
+
formulaNames: formulaNamesInScope(workbook.definedNames, sheet.name),
|
|
180
234
|
active: i === workbook.activeTabIndex,
|
|
181
235
|
flushed: flushed?.get(sheet),
|
|
182
236
|
});
|
|
183
237
|
});
|
|
184
238
|
}
|
|
185
239
|
function emitPackageParts(context) {
|
|
186
|
-
const { workbook, sheets, plan, styles, sharedStrings, sheetXml } = context;
|
|
240
|
+
const { workbook, sheets, plan, styles, sharedStrings, cellMetadata, sheetXml } = context;
|
|
187
241
|
const { media, preserved, perSheet, allTables, allPivots } = plan;
|
|
188
242
|
const hasSharedStrings = sharedStrings !== null && !sharedStrings.isEmpty;
|
|
243
|
+
const hasCellMetadata = !cellMetadata.isEmpty;
|
|
244
|
+
const hasRichValues = cellMetadata.hasRichValues;
|
|
189
245
|
const commentNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.comments);
|
|
190
246
|
const drawingNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.drawing);
|
|
191
247
|
const printerSettingsNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.printerSettings);
|
|
192
248
|
const threadedCommentNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.threadedComments);
|
|
193
249
|
const persons = threadedCommentNumbers.length === 0 ? [] : workbook.persons;
|
|
194
|
-
const workbookRels =
|
|
250
|
+
const workbookRels = planWorkbookRelationships({
|
|
195
251
|
sheetCount: sheets.length,
|
|
196
252
|
hasSharedStrings,
|
|
197
253
|
hasPersons: persons.length > 0,
|
|
254
|
+
hasCellMetadata,
|
|
255
|
+
hasRichValues,
|
|
198
256
|
preservedWorkbook: preserved.workbook,
|
|
199
257
|
pivots: allPivots,
|
|
200
258
|
});
|
|
@@ -213,12 +271,14 @@ function emitPackageParts(context) {
|
|
|
213
271
|
preservedWorkbookRefs: preservedWorkbookRels,
|
|
214
272
|
threadedCommentNumbers,
|
|
215
273
|
hasPersons: persons.length > 0,
|
|
274
|
+
hasCellMetadata,
|
|
275
|
+
hasRichValues,
|
|
216
276
|
})));
|
|
217
|
-
files.add('
|
|
277
|
+
files.add(relsPathFor(''), strToU8(relsPartXml(planRootRelationships(preserved.root))));
|
|
218
278
|
files.add(CORE_PROPS_PART, strToU8(corePropsXml(workbook.properties)));
|
|
219
279
|
files.add(APP_PROPS_PART, strToU8(appPropsXml(workbook.properties)));
|
|
220
280
|
files.add(WORKBOOK_PART, strToU8(workbookXml(workbook, workbookRels, allPivots)));
|
|
221
|
-
files.add(relsPathFor(WORKBOOK_PART), strToU8(
|
|
281
|
+
files.add(relsPathFor(WORKBOOK_PART), strToU8(relsPartXml(workbookRels.relationships)));
|
|
222
282
|
files.add(STYLES_PART, strToU8(styles.toXml()));
|
|
223
283
|
if (!preserved.themeEmitted) {
|
|
224
284
|
const overrides = workbook.themeOverrides;
|
|
@@ -231,13 +291,22 @@ function emitPackageParts(context) {
|
|
|
231
291
|
}
|
|
232
292
|
if (persons.length > 0)
|
|
233
293
|
files.add(PERSONS_PART, strToU8(personsXml(persons)));
|
|
294
|
+
if (hasCellMetadata)
|
|
295
|
+
files.add(METADATA_PART, strToU8(cellMetadata.toXml()));
|
|
296
|
+
if (hasRichValues) {
|
|
297
|
+
files.add(RICH_VALUES_PART, strToU8(cellMetadata.richValuesXml()));
|
|
298
|
+
files.add(RICH_VALUE_STRUCTURES_PART, strToU8(RICH_VALUE_STRUCTURES_XML));
|
|
299
|
+
}
|
|
234
300
|
for (const part of media.parts) {
|
|
235
301
|
files.add(mediaPart(part.number, part.extension), part.data);
|
|
236
302
|
}
|
|
237
|
-
emitSheetParts(files, perSheet, sheetXml);
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
303
|
+
emitSheetParts(files, perSheet, sheetXml, (id) => workbook.getPerson(id));
|
|
304
|
+
perSheet.forEach(({ tables }, index) => {
|
|
305
|
+
const formulaNames = formulaNamesInScope(workbook.definedNames, sheets[index]?.name);
|
|
306
|
+
for (const { table, number } of tables) {
|
|
307
|
+
files.add(tablePart(number), strToU8(tableXml(table, number, formulaNames)));
|
|
308
|
+
}
|
|
309
|
+
});
|
|
241
310
|
emitPivotParts(files, allPivots);
|
|
242
311
|
emitPreservedParts(files, preserved.parts);
|
|
243
312
|
return files.toRecord();
|
|
@@ -249,6 +318,7 @@ export function buildPackageParts(workbook, options = {}) {
|
|
|
249
318
|
}
|
|
250
319
|
const sharedStrings = options.useSharedStrings ? new SharedStringTable() : null;
|
|
251
320
|
const styles = options.styles ?? createStyleRegistry(workbook);
|
|
321
|
+
const cellMetadata = options.cellMetadata ?? new WorkbookMetadataTable();
|
|
252
322
|
const plan = planPackage(workbook, sheets, options.flushed);
|
|
253
323
|
const sheetXml = serialiseSheets({
|
|
254
324
|
workbook,
|
|
@@ -256,9 +326,10 @@ export function buildPackageParts(workbook, options = {}) {
|
|
|
256
326
|
plan,
|
|
257
327
|
styles,
|
|
258
328
|
sharedStrings,
|
|
329
|
+
cellMetadata,
|
|
259
330
|
flushed: options.flushed,
|
|
260
331
|
});
|
|
261
|
-
return emitPackageParts({ workbook, sheets, plan, styles, sharedStrings, sheetXml });
|
|
332
|
+
return emitPackageParts({ workbook, sheets, plan, styles, sharedStrings, cellMetadata, sheetXml });
|
|
262
333
|
}
|
|
263
334
|
class PackageFiles {
|
|
264
335
|
#files = Object.create(null);
|
|
@@ -272,21 +343,12 @@ class PackageFiles {
|
|
|
272
343
|
return this.#files;
|
|
273
344
|
}
|
|
274
345
|
}
|
|
275
|
-
function emitSheetParts(files, perSheet, sheetXml) {
|
|
346
|
+
function emitSheetParts(files, perSheet, sheetXml, personById) {
|
|
276
347
|
perSheet.forEach((plan, i) => {
|
|
277
|
-
const {
|
|
278
|
-
const hasExternalHyperlink = hyperlinks.some((link) => link.relId !== undefined);
|
|
348
|
+
const { relationships, drawing, comments, threadedComments, printerSettings } = plan;
|
|
279
349
|
files.add(worksheetPart(i + 1), strToU8(sheetXml[i]));
|
|
280
|
-
if (
|
|
281
|
-
|
|
282
|
-
comments !== null ||
|
|
283
|
-
threadedComments !== null ||
|
|
284
|
-
printerSettings !== null ||
|
|
285
|
-
background !== null ||
|
|
286
|
-
hasExternalHyperlink ||
|
|
287
|
-
preservedRefs.length > 0 ||
|
|
288
|
-
pivots.length > 0) {
|
|
289
|
-
files.add(relsPathFor(worksheetPart(i + 1)), strToU8(worksheetRelsXml(plan)));
|
|
350
|
+
if (relationships.length > 0) {
|
|
351
|
+
files.add(relsPathFor(worksheetPart(i + 1)), strToU8(relsPartXml(relationships)));
|
|
290
352
|
}
|
|
291
353
|
if (printerSettings !== null) {
|
|
292
354
|
files.add(printerSettingsPart(printerSettings.number), printerSettings.data);
|
|
@@ -294,15 +356,14 @@ function emitSheetParts(files, perSheet, sheetXml) {
|
|
|
294
356
|
if (drawing !== null) {
|
|
295
357
|
const drawingPath = drawingPart(drawing.number);
|
|
296
358
|
files.add(drawingPath, strToU8(drawingXml(drawing.images)));
|
|
297
|
-
|
|
298
|
-
files.add(relsPathFor(drawingPath), strToU8(drawingRelsXml(targets)));
|
|
359
|
+
files.add(relsPathFor(drawingPath), strToU8(relsPartXml(drawing.relationships)));
|
|
299
360
|
}
|
|
300
361
|
if (comments !== null) {
|
|
301
362
|
files.add(commentsPart(comments.number), strToU8(commentsXml(comments.comments)));
|
|
302
363
|
files.add(vmlDrawingPart(comments.number), strToU8(vmlDrawingXml(comments.comments)));
|
|
303
364
|
}
|
|
304
365
|
if (threadedComments !== null) {
|
|
305
|
-
files.add(threadedCommentsPart(threadedComments.number), strToU8(threadedCommentsXml(threadedComments.threads)));
|
|
366
|
+
files.add(threadedCommentsPart(threadedComments.number), strToU8(threadedCommentsXml(threadedComments.threads, personById)));
|
|
306
367
|
}
|
|
307
368
|
});
|
|
308
369
|
}
|
|
@@ -311,16 +372,18 @@ function emitPivotParts(files, allPivots) {
|
|
|
311
372
|
const { number, cacheId, table } = pivot;
|
|
312
373
|
const tablePath = pivotTablePart(number);
|
|
313
374
|
const definitionPath = pivotCacheDefinitionPart(number);
|
|
375
|
+
const recordsPath = pivotCacheRecordsPart(number);
|
|
376
|
+
const tableRels = new RelationshipLedger(tablePath);
|
|
377
|
+
tableRels.add(REL.pivotCacheDefinition, definitionPath);
|
|
314
378
|
files.add(tablePath, strToU8(pivotTableXml(table, `PivotTable${number}`, cacheId)));
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
files.add(
|
|
379
|
+
files.add(relsPathFor(tablePath), strToU8(relsPartXml(tableRels.relationships)));
|
|
380
|
+
const definitionRels = new RelationshipLedger(definitionPath);
|
|
381
|
+
const recordsRelId = definitionRels.add(REL.pivotCacheRecords, recordsPath);
|
|
382
|
+
files.add(definitionPath, strToU8(pivotCacheDefinitionXml(table, recordsRelId)));
|
|
383
|
+
files.add(relsPathFor(definitionPath), strToU8(relsPartXml(definitionRels.relationships)));
|
|
384
|
+
files.add(recordsPath, strToU8(pivotCacheRecordsXml(table)));
|
|
319
385
|
}
|
|
320
386
|
}
|
|
321
|
-
function addSingleRelPart(files, from, type, to) {
|
|
322
|
-
files.add(relsPathFor(from), strToU8(relsPartXml([{ id: 'rId1', type, target: relativePartPath(from, to) }])));
|
|
323
|
-
}
|
|
324
387
|
function emitPreservedParts(files, parts) {
|
|
325
388
|
for (const part of parts) {
|
|
326
389
|
files.add(part.path, part.bytes);
|
package/dist/rel-type.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The last segment of a relationship Type (`vbaProjectSignatureAgile` in
|
|
3
|
+
* `http://schemas.microsoft.com/office/2014/relationships/vbaProjectSignatureAgile`), or the whole Type
|
|
4
|
+
* when it has no `/`: for a caller that looks the segment up rather than testing for one class.
|
|
5
|
+
*
|
|
6
|
+
* {@link isRelType} is not built on it, because a class name may span segments: the ribbon's is
|
|
7
|
+
* `ui/extensibility`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function relTypeSegment(type: string): string;
|
|
1
10
|
/**
|
|
2
11
|
* Does a relationship Type name this class of part?
|
|
3
12
|
*
|
package/dist/rel-type.js
CHANGED
package/dist/vba/bytes.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ export declare function readU32(buf: Uint8Array, at: number): number;
|
|
|
9
9
|
* `0xffff` turns that into a `dir` stream declaring 65,535 modules.
|
|
10
10
|
*/
|
|
11
11
|
export declare function writeU16(buf: Uint8Array, at: number, value: number): void;
|
|
12
|
+
/** Write a little-endian `uint32` over bytes already in `buf`, asserted rather than masked as {@link writeU16} is. */
|
|
13
|
+
export declare function writeU32(buf: Uint8Array, at: number, value: number): void;
|
|
12
14
|
/**
|
|
13
15
|
* Replace `src[start..end)` with `insert`, returning a new array.
|
|
14
16
|
*
|
package/dist/vba/bytes.js
CHANGED
|
@@ -29,6 +29,17 @@ export function writeU16(buf, at, value) {
|
|
|
29
29
|
buf[at] = value & 0xff;
|
|
30
30
|
buf[at + 1] = (value >> 8) & 0xff;
|
|
31
31
|
}
|
|
32
|
+
export function writeU32(buf, at, value) {
|
|
33
|
+
if (!Number.isInteger(value) || value < 0 || value > 0xffff_ffff) {
|
|
34
|
+
throw new VbaParseError(`${value} does not fit the uint32 at offset ${at}`);
|
|
35
|
+
}
|
|
36
|
+
if (at + 3 >= buf.length)
|
|
37
|
+
throw truncated(at, 4, buf.length);
|
|
38
|
+
buf[at] = value & 0xff;
|
|
39
|
+
buf[at + 1] = (value >>> 8) & 0xff;
|
|
40
|
+
buf[at + 2] = (value >>> 16) & 0xff;
|
|
41
|
+
buf[at + 3] = (value >>> 24) & 0xff;
|
|
42
|
+
}
|
|
32
43
|
export function spliceBytes(src, start, end, insert = EMPTY) {
|
|
33
44
|
const out = new Uint8Array(src.length - (end - start) + insert.length);
|
|
34
45
|
out.set(src.subarray(0, start), 0);
|