@shbernal/ts-xlsx 1.2.0 → 2.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 +5 -0
- package/dist/core/address.d.ts +49 -2
- package/dist/core/address.js +31 -3
- package/dist/core/autofilter.d.ts +2 -2
- package/dist/core/cell.d.ts +17 -16
- package/dist/core/cell.js +3 -7
- package/dist/core/color-resolution.d.ts +7 -7
- package/dist/core/column.d.ts +8 -9
- package/dist/core/column.js +2 -4
- package/dist/core/comment-thread.d.ts +32 -23
- package/dist/core/comment-thread.js +4 -4
- package/dist/core/conditional-formatting-overlay.d.ts +1 -1
- package/dist/core/conditional-formatting.d.ts +3 -3
- package/dist/core/data-validation-overlay.d.ts +1 -1
- package/dist/core/data-validation.d.ts +3 -3
- package/dist/core/date.d.ts +3 -3
- package/dist/core/formula.d.ts +6 -6
- package/dist/core/grid-edits.js +3 -3
- package/dist/core/image.d.ts +37 -2
- package/dist/core/image.js +6 -0
- package/dist/core/internal.d.ts +9 -1
- package/dist/core/limits.d.ts +4 -4
- package/dist/core/merge.d.ts +6 -12
- package/dist/core/merge.js +0 -3
- package/dist/core/page-setup.d.ts +4 -4
- package/dist/core/pivot-table.d.ts +2 -4
- package/dist/core/pivot-table.js +5 -5
- package/dist/core/preserved.d.ts +3 -3
- package/dist/core/protection.d.ts +4 -4
- package/dist/core/range.d.ts +16 -14
- package/dist/core/range.js +5 -5
- package/dist/core/row-input.d.ts +2 -8
- package/dist/core/row-input.js +2 -2
- package/dist/core/row.d.ts +7 -8
- package/dist/core/row.js +2 -4
- package/dist/core/style.d.ts +14 -14
- package/dist/core/table-style.d.ts +9 -9
- package/dist/core/table-style.js +1 -1
- package/dist/core/table.d.ts +30 -42
- package/dist/core/table.js +16 -10
- package/dist/core/theme.d.ts +13 -43
- package/dist/core/theme.js +2 -148
- package/dist/core/value.d.ts +7 -7
- package/dist/core/workbook-protection.d.ts +2 -2
- package/dist/core/workbook-styles.d.ts +26 -0
- package/dist/core/workbook-styles.js +48 -0
- package/dist/core/workbook-theme.d.ts +25 -0
- package/dist/core/workbook-theme.js +49 -0
- package/dist/core/workbook-vba.d.ts +17 -0
- package/dist/core/workbook-vba.js +79 -0
- package/dist/core/workbook.d.ts +141 -83
- package/dist/core/workbook.js +74 -133
- package/dist/core/worksheet-comments.d.ts +9 -0
- package/dist/core/worksheet-comments.js +52 -0
- package/dist/core/worksheet-model.d.ts +4 -4
- package/dist/core/worksheet-model.js +1 -0
- package/dist/core/worksheet-pictures.d.ts +29 -0
- package/dist/core/worksheet-pictures.js +42 -0
- package/dist/core/worksheet.d.ts +94 -77
- package/dist/core/worksheet.js +36 -95
- package/dist/customui/errors.d.ts +1 -1
- package/dist/customui/ribbon.d.ts +3 -3
- package/dist/entries/core.d.ts +4 -4
- package/dist/entries/core.js +1 -1
- package/dist/entries/vba.d.ts +1 -1
- package/dist/entries/vba.js +1 -1
- package/dist/entries/xlsx.d.ts +1 -0
- package/dist/entries/xlsx.js +1 -0
- package/dist/errors.d.ts +12 -12
- package/dist/io/csv/read.js +1 -2
- package/dist/io/csv/write.d.ts +8 -3
- package/dist/io/csv/write.js +17 -2
- package/dist/io/opc/errors.d.ts +6 -6
- package/dist/io/opc/inflate.d.ts +1 -1
- package/dist/io/opc/namespaces.d.ts +1 -1
- package/dist/io/opc/read-opc.d.ts +19 -3
- package/dist/io/opc/read-opc.js +14 -8
- package/dist/io/opc/read-options.d.ts +2 -2
- package/dist/io/opc/sniff-format.d.ts +2 -2
- package/dist/io/opc/zip-mtime.d.ts +5 -0
- package/dist/io/opc/zip-mtime.js +1 -0
- package/dist/io/style/xf-style.d.ts +38 -6
- package/dist/io/style/xf-style.js +22 -0
- package/dist/io/xlsb/errors.d.ts +1 -1
- package/dist/io/xlsb/formula.d.ts +4 -4
- package/dist/io/xlsb/primitives.d.ts +8 -8
- package/dist/io/xlsb/ptg-functions.d.ts +1 -1
- package/dist/io/xlsb/read-styles.js +2 -20
- package/dist/io/xlsb/read.d.ts +2 -2
- package/dist/io/xlsx/cell-accumulator.d.ts +25 -6
- package/dist/io/xlsx/cell-accumulator.js +111 -30
- package/dist/io/xlsx/cell-value.d.ts +2 -2
- package/dist/io/xlsx/cell-value.js +3 -3
- package/dist/io/xlsx/color-xml.js +11 -17
- package/dist/io/xlsx/comments.d.ts +5 -5
- package/dist/io/xlsx/comments.js +13 -6
- package/dist/io/xlsx/conditional-formatting.d.ts +3 -3
- package/dist/io/xlsx/conditional-formatting.js +7 -16
- package/dist/io/xlsx/data-validation.d.ts +2 -2
- package/dist/io/xlsx/data-validation.js +1 -1
- package/dist/io/xlsx/edit-vba.js +2 -1
- package/dist/io/xlsx/errors.d.ts +3 -3
- package/dist/io/xlsx/hyperlinks.d.ts +4 -2
- package/dist/io/xlsx/hyperlinks.js +5 -5
- package/dist/io/xlsx/images.d.ts +1 -1
- package/dist/io/xlsx/images.js +8 -8
- package/dist/io/xlsx/namespaces.d.ts +2 -2
- package/dist/io/xlsx/package-plan.js +5 -2
- package/dist/io/xlsx/read-pivot.js +2 -5
- package/dist/io/xlsx/read-rows.d.ts +13 -13
- package/dist/io/xlsx/read-rows.js +19 -55
- package/dist/io/xlsx/read-shared-strings.js +7 -5
- package/dist/io/xlsx/read-styles.d.ts +3 -3
- package/dist/io/xlsx/read-styles.js +40 -65
- package/dist/io/xlsx/read-worksheet.js +67 -115
- package/dist/io/xlsx/read.d.ts +3 -5
- package/dist/io/xlsx/read.js +94 -71
- package/dist/io/xlsx/rich-runs.d.ts +1 -1
- package/dist/io/xlsx/rich-runs.js +1 -1
- package/dist/io/xlsx/rich-text.d.ts +1 -1
- package/dist/io/xlsx/shared-strings.d.ts +2 -2
- package/dist/io/xlsx/sheet-properties.js +5 -4
- package/dist/io/xlsx/styles.d.ts +8 -9
- package/dist/io/xlsx/styles.js +4 -3
- package/dist/io/xlsx/tables.d.ts +2 -2
- package/dist/io/xlsx/tables.js +8 -13
- package/dist/io/xlsx/theme-xml.d.ts +37 -0
- package/dist/io/xlsx/theme-xml.js +142 -0
- package/dist/io/xlsx/threaded-comments.d.ts +18 -27
- package/dist/io/xlsx/threaded-comments.js +9 -21
- package/dist/io/xlsx/workbook-xml.d.ts +1 -1
- package/dist/io/xlsx/workbook-xml.js +6 -2
- package/dist/io/xlsx/worksheet-xml.d.ts +2 -2
- package/dist/io/xlsx/worksheet-xml.js +7 -12
- package/dist/io/xlsx/write-stream.d.ts +15 -15
- package/dist/io/xlsx/write-stream.js +5 -3
- package/dist/io/xlsx/write.d.ts +12 -7
- package/dist/io/xlsx/write.js +10 -6
- package/dist/io/xlsx/x14-ext.d.ts +1 -1
- package/dist/vba/bytes.d.ts +12 -0
- package/dist/vba/bytes.js +40 -0
- package/dist/vba/cfb-writer.d.ts +1 -1
- package/dist/vba/cfb.d.ts +1 -1
- package/dist/vba/cfb.js +15 -51
- package/dist/vba/codepage.d.ts +2 -2
- package/dist/vba/errors.d.ts +2 -2
- package/dist/vba/index.d.ts +2 -2
- package/dist/vba/index.js +2 -2
- package/dist/vba/ms-ovba.d.ts +1 -1
- package/dist/vba/ms-ovba.js +1 -3
- package/dist/vba/project-editor.d.ts +9 -9
- package/dist/vba/project-editor.js +2 -11
- package/dist/vba/project.d.ts +5 -5
- package/dist/vba/project.js +1 -10
- package/dist/vba/vba-encoding.d.ts +1 -1
- package/dist/xml/errors.d.ts +1 -1
- package/dist/xml/xml-read.d.ts +38 -9
- package/dist/xml/xml-read.js +23 -0
- package/dist/xml/xml.d.ts +31 -9
- package/dist/xml/xml.js +23 -3
- package/package.json +41 -35
|
@@ -20,12 +20,12 @@ export interface CommentCell {
|
|
|
20
20
|
* in `threads`. A comment anchors to its cell regardless of the cell's value, so a note (or a thread) on
|
|
21
21
|
* an otherwise-empty cell is collected too.
|
|
22
22
|
*
|
|
23
|
-
* `threads` is the conversations the *package* will carry, not simply the ones the sheet holds
|
|
23
|
+
* `threads` is the conversations the *package* will carry, not simply the ones the sheet holds. The
|
|
24
24
|
* caller decides, because a fallback beside a thread whose `threadedComment` part is missing is worse
|
|
25
25
|
* than no fallback at all: verified against desktop Excel, such a comment shows as neither a thread nor
|
|
26
26
|
* a note, so the text disappears entirely.
|
|
27
27
|
*
|
|
28
|
-
* Ordered by cell, row-major, the way Excel writes the list
|
|
28
|
+
* Ordered by cell, row-major, the way Excel writes the list, so a fallback lands interleaved among the
|
|
29
29
|
* notes rather than appended after them, and the VML shapes follow the same order.
|
|
30
30
|
*/
|
|
31
31
|
export declare function collectComments(sheet: Worksheet, threads: readonly CommentThread[]): CommentCell[];
|
|
@@ -35,13 +35,13 @@ export declare function collectComments(sheet: Worksheet, threads: readonly Comm
|
|
|
35
35
|
* Authors are laid out the way Excel lays them out: one synthetic `tc={headId}` entry per threaded
|
|
36
36
|
* conversation first, then a single anonymous author shared by every note (the model carries no note
|
|
37
37
|
* author). Each comment points at its own author by index, and a fallback additionally carries the
|
|
38
|
-
* `xr:uid` naming its thread
|
|
38
|
+
* `xr:uid` naming its thread: the pair that keeps Excel treating the cell as threaded.
|
|
39
39
|
*/
|
|
40
40
|
export declare function commentsXml(comments: readonly CommentCell[]): string;
|
|
41
41
|
/** The `xl/drawings/vmlDrawing{n}.vml` companion: one hidden text-box shape per comment, in the same
|
|
42
42
|
* order as the comments part. Anchor coordinates place the box a couple of cells down-and-right of its
|
|
43
43
|
* owner; Excel refines them on open, so the values are a sensible starting geometry rather than a
|
|
44
|
-
* pixel-exact layout. A thread's fallback shape is `ObjectType="Note"` like any other
|
|
44
|
+
* pixel-exact layout. A thread's fallback shape is `ObjectType="Note"` like any other: Excel draws the
|
|
45
45
|
* threaded-comment card itself and only needs the shape to exist. */
|
|
46
46
|
export declare function vmlDrawingXml(comments: readonly CommentCell[]): string;
|
|
47
47
|
/** One `<comment>` read back from a comments part. */
|
|
@@ -63,7 +63,7 @@ export declare function parseComments(xml: string): Map<string, ParsedComment>;
|
|
|
63
63
|
* Apply a parsed comments part onto a sheet's cells as notes, addressing each by its A1 reference.
|
|
64
64
|
*
|
|
65
65
|
* A thread's legacy fallback is not a note and does not become one: its text is boilerplate wrapping a
|
|
66
|
-
* copy of the conversation, so surfacing it as `cell.note` hands the caller garbage
|
|
66
|
+
* copy of the conversation, so surfacing it as `cell.note` hands the caller garbage, and on write it
|
|
67
67
|
* would be re-emitted as a plain note, destroying the `tc=`/`xr:uid` binding and leaving Excel unable to
|
|
68
68
|
* see the thread at all.
|
|
69
69
|
*
|
package/dist/io/xlsx/comments.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { tryDecodeCellRef } from '../../core/address.js';
|
|
2
|
+
import { decodeSpreadsheetText, localName, numInteger, parseXml } from '../../xml/xml-read.js';
|
|
2
3
|
import { escapeAttr, escapeText, textElement, XML_DECLARATION } from '../../xml/xml.js';
|
|
3
|
-
import { localName, parseXml } from '../../xml/xml-read.js';
|
|
4
4
|
import { MARKUP_COMPATIBILITY_NS, REVISION_NS, SPREADSHEETML_NS } from './namespaces.js';
|
|
5
5
|
export function collectComments(sheet, threads) {
|
|
6
6
|
const fallbacks = threadFallbacks(threads);
|
|
@@ -19,10 +19,16 @@ function threadFallbacks(threads) {
|
|
|
19
19
|
const fallbacks = [];
|
|
20
20
|
for (const thread of threads) {
|
|
21
21
|
const head = thread.comments[0];
|
|
22
|
-
const
|
|
23
|
-
if (head === undefined ||
|
|
22
|
+
const cell = tryDecodeCellRef(thread.ref);
|
|
23
|
+
if (head === undefined || cell === undefined)
|
|
24
24
|
continue;
|
|
25
|
-
fallbacks.push({
|
|
25
|
+
fallbacks.push({
|
|
26
|
+
ref: thread.ref,
|
|
27
|
+
row: cell.row,
|
|
28
|
+
col: cell.col,
|
|
29
|
+
text: fallbackText(thread),
|
|
30
|
+
threadId: head.id,
|
|
31
|
+
});
|
|
26
32
|
}
|
|
27
33
|
return fallbacks;
|
|
28
34
|
}
|
|
@@ -125,10 +131,11 @@ export function parseComments(xml) {
|
|
|
125
131
|
buffer = '';
|
|
126
132
|
}
|
|
127
133
|
else if (local === 'text') {
|
|
134
|
+
buffer = decodeSpreadsheetText(buffer);
|
|
128
135
|
capture = undefined;
|
|
129
136
|
}
|
|
130
137
|
else if (local === 'comment' && currentRef !== undefined) {
|
|
131
|
-
const threadId = threadIdOf(authors[
|
|
138
|
+
const threadId = threadIdOf(authors[numInteger(currentAuthorId, 0) ?? -1]);
|
|
132
139
|
comments.set(currentRef, {
|
|
133
140
|
text: buffer,
|
|
134
141
|
...(threadId !== undefined ? { threadId } : {}),
|
|
@@ -17,15 +17,15 @@ export declare function conditionalFormattingsExtXml(formattings: readonly Condi
|
|
|
17
17
|
/**
|
|
18
18
|
* Parse a worksheet's conditional formatting into the model. The classic `<conditionalFormatting>`
|
|
19
19
|
* blocks supply every rule; the x14 extension (`<x14:conditionalFormatting>` inside `<extLst>`) is
|
|
20
|
-
* read only to enrich a classic data bar with the facets the classic element cannot carry
|
|
21
|
-
* gradient flag and the negative-fill and axis colours
|
|
20
|
+
* read only to enrich a classic data bar with the facets the classic element cannot carry (the
|
|
21
|
+
* gradient flag and the negative-fill and axis colours) matched by the shared id the two ends link
|
|
22
22
|
* on. An extension rule with no classic counterpart (a rule that lives only in x14) is ignored, so it
|
|
23
23
|
* is never half-read into a broken classic rule.
|
|
24
24
|
*/
|
|
25
25
|
export declare function parseConditionalFormattings(xml: string): ConditionalFormatting[];
|
|
26
26
|
/**
|
|
27
27
|
* Extract the differential-style (`<dxf>`) fragments from styles.xml, each verbatim. Preserving the
|
|
28
|
-
* raw XML
|
|
28
|
+
* raw XML, rather than reparsing and re-serialising, is what keeps a foreign dxf's number format a
|
|
29
29
|
* real format code on re-write instead of a coerced `"[object Object]"`, and keeps every conditional
|
|
30
30
|
* formatting's `dxfId` index pointing at the same style it did in the source file.
|
|
31
31
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { boolPresent, boolStrict, coerceNumericLiteral, localName, numFinite, numInteger, parseXml, } from '../../xml/xml-read.js';
|
|
1
2
|
import { boolAttr, escapeAttr, escapeText, stripFormulaEquals } from '../../xml/xml.js';
|
|
2
|
-
import { boolStrict, coerceNumericLiteral, localName, parseXml } from '../../xml/xml-read.js';
|
|
3
3
|
import { colorAttrs, parseColor } from './color-xml.js';
|
|
4
4
|
import { CF_EXT_URI, DATABAR_LINK_EXT_URI, XM_NS } from './namespaces.js';
|
|
5
5
|
import { x14Ext } from './x14-ext.js';
|
|
@@ -176,7 +176,7 @@ export function parseConditionalFormattings(xml) {
|
|
|
176
176
|
x14ExtId = attrs.id;
|
|
177
177
|
}
|
|
178
178
|
else if (x14Ext !== undefined && ln === 'dataBar') {
|
|
179
|
-
x14Ext.gradient = attrs.gradient
|
|
179
|
+
x14Ext.gradient = boolPresent(attrs.gradient);
|
|
180
180
|
}
|
|
181
181
|
else if (x14Ext !== undefined && ln === 'negativeFillColor') {
|
|
182
182
|
x14Ext.negativeFillColor = parseColor(attrs);
|
|
@@ -288,16 +288,16 @@ export function parseDxfs(stylesXml) {
|
|
|
288
288
|
function newDraft(attrs) {
|
|
289
289
|
return {
|
|
290
290
|
type: attrs.type ?? '',
|
|
291
|
-
priority:
|
|
291
|
+
priority: numFinite(attrs.priority),
|
|
292
292
|
stopIfTrue: boolStrict(attrs.stopIfTrue),
|
|
293
293
|
operator: attrs.operator,
|
|
294
294
|
text: attrs.text,
|
|
295
295
|
timePeriod: attrs.timePeriod,
|
|
296
|
-
rank:
|
|
297
|
-
stdDev:
|
|
296
|
+
rank: numFinite(attrs.rank),
|
|
297
|
+
stdDev: numFinite(attrs.stdDev),
|
|
298
298
|
percent: boolStrict(attrs.percent),
|
|
299
299
|
bottom: boolStrict(attrs.bottom),
|
|
300
|
-
aboveAverage: attrs.aboveAverage === undefined ? undefined : attrs.aboveAverage
|
|
300
|
+
aboveAverage: attrs.aboveAverage === undefined ? undefined : boolPresent(attrs.aboveAverage),
|
|
301
301
|
equalAverage: boolStrict(attrs.equalAverage),
|
|
302
302
|
dxfId: parseIndexAttr(attrs.dxfId),
|
|
303
303
|
iconSet: undefined,
|
|
@@ -308,17 +308,8 @@ function newDraft(attrs) {
|
|
|
308
308
|
x14Id: undefined,
|
|
309
309
|
};
|
|
310
310
|
}
|
|
311
|
-
function parseFiniteAttr(value) {
|
|
312
|
-
if (value === undefined)
|
|
313
|
-
return undefined;
|
|
314
|
-
const n = Number(value);
|
|
315
|
-
return Number.isFinite(n) ? n : undefined;
|
|
316
|
-
}
|
|
317
311
|
function parseIndexAttr(value) {
|
|
318
|
-
|
|
319
|
-
return undefined;
|
|
320
|
-
const n = Number(value);
|
|
321
|
-
return Number.isInteger(n) && n >= 0 ? value : undefined;
|
|
312
|
+
return numInteger(value, 0) === undefined ? undefined : value;
|
|
322
313
|
}
|
|
323
314
|
function finalizeRule(draft) {
|
|
324
315
|
const rule = { type: draft.type };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { DataValidationEntry } from '../../core/data-validation.ts';
|
|
2
2
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
3
3
|
/** The standard `<dataValidations>` element for the rules stored in the legacy form, or '' when the
|
|
4
|
-
* sheet has none of them
|
|
4
|
+
* sheet has none of them, so a sheet with only extended (or no) validations stays byte-clean here.
|
|
5
5
|
* The extended rules are emitted separately by {@link dataValidationsExtXml}. */
|
|
6
6
|
export declare function dataValidationsXml(entries: readonly DataValidationEntry[]): string;
|
|
7
7
|
/** The `<ext>` carrying the extended (`<x14:dataValidation>`) rules, or '' when the sheet declares
|
|
8
8
|
* none. Emitted bare (no `<extLst>` wrapper) so the worksheet serialiser can gather it into a single
|
|
9
|
-
* `<extLst>` beside the conditional-formatting extension
|
|
9
|
+
* `<extLst>` beside the conditional-formatting extension: a worksheet may carry at most one. */
|
|
10
10
|
export declare function dataValidationsExtXml(entries: readonly DataValidationEntry[]): string;
|
|
11
11
|
/** Parse every standard `<dataValidation>` out of a worksheet part into range-bound rules. */
|
|
12
12
|
export declare function parseDataValidations(xml: string): DataValidationEntry[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { escapeAttr, escapeText, stripFormulaEquals } from '../../xml/xml.js';
|
|
2
1
|
import { boolStrict, coerceNumericLiteral, localName, parseXml } from '../../xml/xml-read.js';
|
|
2
|
+
import { escapeAttr, escapeText, stripFormulaEquals } from '../../xml/xml.js';
|
|
3
3
|
import { DATA_VALIDATION_EXT_URI, XM_NS } from './namespaces.js';
|
|
4
4
|
import { x14Ext } from './x14-ext.js';
|
|
5
5
|
const TYPED = new Set(['whole', 'decimal', 'date', 'time', 'textLength']);
|
package/dist/io/xlsx/edit-vba.js
CHANGED
|
@@ -3,6 +3,7 @@ import { VbaAuthorError } from '../../vba/errors.js';
|
|
|
3
3
|
import { addVbaReference, removeVbaModule, } from '../../vba/project-editor.js';
|
|
4
4
|
import { relsPathFor } from '../opc/part-paths.js';
|
|
5
5
|
import { parseRelationshipRecords, relationshipTargetByType, resolveRelativePart, resolveWorkbookPart, } from '../opc/read-opc.js';
|
|
6
|
+
import { FIXED_ENTRY_MTIME } from '../opc/zip-mtime.js';
|
|
6
7
|
const OFFICE_DOCUMENT_REL = 'officeDocument';
|
|
7
8
|
const VBA_PROJECT_REL = 'vbaProject';
|
|
8
9
|
const VBA_SIGNATURE_REL_INFIX = 'vbaProjectSignature';
|
|
@@ -21,7 +22,7 @@ function applyToVbaProjectPart(xlsx, apply) {
|
|
|
21
22
|
}
|
|
22
23
|
files[binPath] = apply(bin);
|
|
23
24
|
dropStaleSignature(files, binPath);
|
|
24
|
-
return zipSync(files);
|
|
25
|
+
return zipSync(files, { mtime: FIXED_ENTRY_MTIME });
|
|
25
26
|
}
|
|
26
27
|
function locateVbaProjectPart(files) {
|
|
27
28
|
const rootRels = textPart(files, '_rels/.rels');
|
package/dist/io/xlsx/errors.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { XlsxError } from '../../errors.ts';
|
|
2
2
|
/**
|
|
3
3
|
* Thrown when an `.xlsx` package's XML content is well-formed but does not describe a workbook this
|
|
4
|
-
* library can act on
|
|
4
|
+
* library can act on: a `xl/workbook.xml` that declares no worksheets, say.
|
|
5
5
|
*
|
|
6
6
|
* It sits between two neighbours. {@link XmlParseError} reports that the *markup* did not parse;
|
|
7
7
|
* {@link UnsupportedFormatError} reports that the *container* is not one we read at all. This one
|
|
8
8
|
* fires when both of those were fine and the document itself is nonetheless not a workbook.
|
|
9
9
|
*
|
|
10
|
-
* The reader is deliberately lenient about content it does not recognise
|
|
11
|
-
* skipped, not fatal
|
|
10
|
+
* The reader is deliberately lenient about content it does not recognise (an unknown element is
|
|
11
|
+
* skipped, not fatal) so this is rare by design, and reaching it means something a workbook cannot
|
|
12
12
|
* do without being corrupt.
|
|
13
13
|
*/
|
|
14
14
|
export declare class XlsxParseError extends XlsxError {
|
|
@@ -37,6 +37,8 @@ interface ParsedHyperlink {
|
|
|
37
37
|
/** Parse every `<hyperlink>` element out of a worksheet part. */
|
|
38
38
|
export declare function parseSheetHyperlinks(xml: string): ParsedHyperlink[];
|
|
39
39
|
/** Fold parsed hyperlinks onto a sheet's cells, wrapping each cell's existing value (its visible
|
|
40
|
-
* label) into a {@link HyperlinkValue}. `
|
|
41
|
-
|
|
40
|
+
* label) into a {@link HyperlinkValue}. `targetOf` resolves a relationship id to its raw Target: a
|
|
41
|
+
* URL for the external links hyperlinks almost always are, so it must stay unresolved against the
|
|
42
|
+
* package rather than being handed over as a part path. */
|
|
43
|
+
export declare function applyHyperlinks(sheet: Worksheet, links: readonly ParsedHyperlink[], targetOf: (relId: string) => string | undefined): void;
|
|
42
44
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { decodeRange } from '../../core/address.js';
|
|
2
2
|
import { isHyperlinkValue, isRichTextValue } from '../../core/value.js';
|
|
3
|
-
import { escapeAttr } from '../../xml/xml.js';
|
|
4
3
|
import { localName, parseXml } from '../../xml/xml-read.js';
|
|
4
|
+
import { escapeAttr } from '../../xml/xml.js';
|
|
5
5
|
export function collectHyperlinks(sheet) {
|
|
6
6
|
const links = [];
|
|
7
7
|
for (const { cells } of sheet.rows()) {
|
|
@@ -59,9 +59,9 @@ export function parseSheetHyperlinks(xml) {
|
|
|
59
59
|
});
|
|
60
60
|
return links;
|
|
61
61
|
}
|
|
62
|
-
export function applyHyperlinks(sheet, links,
|
|
62
|
+
export function applyHyperlinks(sheet, links, targetOf) {
|
|
63
63
|
for (const link of links) {
|
|
64
|
-
const target = resolveTarget(link,
|
|
64
|
+
const target = resolveTarget(link, targetOf);
|
|
65
65
|
if (target === undefined)
|
|
66
66
|
continue;
|
|
67
67
|
const decoded = decodeRefSafe(link.ref);
|
|
@@ -88,9 +88,9 @@ function decodeRefSafe(ref) {
|
|
|
88
88
|
return undefined;
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
|
-
function resolveTarget(link,
|
|
91
|
+
function resolveTarget(link, targetOf) {
|
|
92
92
|
if (link.rid !== undefined) {
|
|
93
|
-
const base =
|
|
93
|
+
const base = targetOf(link.rid);
|
|
94
94
|
if (base === undefined)
|
|
95
95
|
return undefined;
|
|
96
96
|
return link.location !== undefined ? `${base}#${link.location}` : base;
|
package/dist/io/xlsx/images.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface ParsedImageAnchor {
|
|
|
27
27
|
* Anchors that are not pictures (a chart, a shape) carry no `<a:blip r:embed>` and are skipped, so a
|
|
28
28
|
* mixed drawing yields only its images. */
|
|
29
29
|
export declare function parseDrawing(xml: string): ParsedImageAnchor[];
|
|
30
|
-
/** Whether a drawing part holds anchor content beyond plain pictures
|
|
30
|
+
/** Whether a drawing part holds anchor content beyond plain pictures: a chart, shape, connector, or
|
|
31
31
|
* group. Excel packs every one of a sheet's anchors into a single drawing part, so a sheet with both a
|
|
32
32
|
* picture and a chart yields a mixed drawing; modeling only its pictures and re-serialising from them
|
|
33
33
|
* would drop the chart. The reader uses this to fall back to whole-drawing byte-preservation instead. */
|
package/dist/io/xlsx/images.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isOneCellAnchor, } from '../../core/image.js';
|
|
2
|
+
import { localName, numFinite, parseXml } from '../../xml/xml-read.js';
|
|
2
3
|
import { XML_DECLARATION } from '../../xml/xml.js';
|
|
3
|
-
import { localName, parseXml } from '../../xml/xml-read.js';
|
|
4
4
|
import { RELATIONSHIPS_NS } from '../opc/namespaces.js';
|
|
5
5
|
import { relationship, relationshipsPart } from '../opc/rels.js';
|
|
6
6
|
import { DRAWINGML_NS, XDR_NS } from './namespaces.js';
|
|
@@ -99,8 +99,8 @@ export function parseDrawing(xml) {
|
|
|
99
99
|
picDepth++;
|
|
100
100
|
}
|
|
101
101
|
else if (local === 'xfrm' && picDepth > 0) {
|
|
102
|
-
const rot =
|
|
103
|
-
if (
|
|
102
|
+
const rot = numFinite(attrs.rot);
|
|
103
|
+
if (rot !== undefined && rot !== 0)
|
|
104
104
|
rotation = rot;
|
|
105
105
|
}
|
|
106
106
|
else if (local === 'from') {
|
|
@@ -110,9 +110,9 @@ export function parseDrawing(xml) {
|
|
|
110
110
|
target = to;
|
|
111
111
|
}
|
|
112
112
|
else if (local === 'ext' && picDepth === 0) {
|
|
113
|
-
const cx =
|
|
114
|
-
const cy =
|
|
115
|
-
if (
|
|
113
|
+
const cx = numFinite(attrs.cx, 0);
|
|
114
|
+
const cy = numFinite(attrs.cy, 0);
|
|
115
|
+
if (cx !== undefined && cy !== undefined)
|
|
116
116
|
ext = { cx, cy };
|
|
117
117
|
}
|
|
118
118
|
else if (local === 'blip') {
|
|
@@ -132,8 +132,8 @@ export function parseDrawing(xml) {
|
|
|
132
132
|
onClose(name) {
|
|
133
133
|
const local = localName(name);
|
|
134
134
|
if (target !== null && coord === local && COORDINATES.has(local)) {
|
|
135
|
-
const value =
|
|
136
|
-
if (
|
|
135
|
+
const value = numFinite(text);
|
|
136
|
+
if (value !== undefined)
|
|
137
137
|
setCoordinate(target, local, value);
|
|
138
138
|
coord = '';
|
|
139
139
|
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* container rather than the spreadsheet inside it, and live in `../opc/namespaces.ts`.
|
|
11
11
|
*/
|
|
12
12
|
/**
|
|
13
|
-
* SpreadsheetML main namespace
|
|
13
|
+
* SpreadsheetML main namespace: the default `xmlns` of the workbook,
|
|
14
14
|
* worksheet, styles, sharedStrings, comments, table and pivot parts.
|
|
15
15
|
*/
|
|
16
16
|
export declare const SPREADSHEETML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
|
|
@@ -25,7 +25,7 @@ export declare const MARKUP_COMPATIBILITY_NS = "http://schemas.openxmlformats.or
|
|
|
25
25
|
*/
|
|
26
26
|
export declare const REVISION_NS = "http://schemas.microsoft.com/office/spreadsheetml/2014/revision";
|
|
27
27
|
/**
|
|
28
|
-
* The 2018 threaded-comments namespace, shared by both parts of the feature
|
|
28
|
+
* The 2018 threaded-comments namespace, shared by both parts of the feature: a sheet's
|
|
29
29
|
* `threadedComment{n}.xml` and the workbook's `person.xml`. Note the plural `threadedcomments`, all
|
|
30
30
|
* lower-case: Excel matches the URI exactly and reads neither part under any other spelling.
|
|
31
31
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AuthoringError } from '../../errors.js';
|
|
2
2
|
import { extensionOf, relativePartPath, relsPathFor, THEME_PART_PATH } from '../opc/part-paths.js';
|
|
3
3
|
import { preservedRelsXml } from '../opc/rels.js';
|
|
4
|
+
import { applyThemeOverrides } from './theme-xml.js';
|
|
4
5
|
export class SheetRelIds {
|
|
5
6
|
#next = 1;
|
|
6
7
|
next() {
|
|
@@ -75,10 +76,12 @@ export function planPreservedParts(workbook, generatedDrawingCount, generatedMed
|
|
|
75
76
|
? []
|
|
76
77
|
: [{ id: rel.id, type: rel.type, target: relativePartPath(newPath, target) }];
|
|
77
78
|
});
|
|
78
|
-
const
|
|
79
|
+
const overrides = newPath === THEME_PART_PATH ? workbook.themeOverrides : undefined;
|
|
79
80
|
emitted.set(newPath, {
|
|
80
81
|
path: newPath,
|
|
81
|
-
bytes:
|
|
82
|
+
bytes: overrides === undefined
|
|
83
|
+
? part.bytes
|
|
84
|
+
: new TextEncoder().encode(applyThemeOverrides(new TextDecoder().decode(part.bytes), overrides)),
|
|
82
85
|
contentType: part.contentType,
|
|
83
86
|
relsPath: rels.length === 0 ? null : relsPathFor(newPath),
|
|
84
87
|
relsXml: rels.length === 0 ? null : preservedRelsXml(rels),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { pivotMetricFromSubtotal, } from '../../core/pivot-table.js';
|
|
2
|
-
import { localName, parseXml } from '../../xml/xml-read.js';
|
|
2
|
+
import { localName, numInteger, parseXml } from '../../xml/xml-read.js';
|
|
3
3
|
export function parsePivotTable(tableXml, cacheXml) {
|
|
4
4
|
const { fields, source } = parsePivotCacheDefinition(cacheXml);
|
|
5
5
|
const def = parsePivotTableDefinition(tableXml);
|
|
@@ -97,8 +97,5 @@ function sourceKind(type) {
|
|
|
97
97
|
return SOURCE_KINDS.has(type) ? type : 'unknown';
|
|
98
98
|
}
|
|
99
99
|
function toIndex(value) {
|
|
100
|
-
|
|
101
|
-
return -1;
|
|
102
|
-
const index = Number(value);
|
|
103
|
-
return Number.isInteger(index) && index >= 0 ? index : -1;
|
|
100
|
+
return numInteger(value, 0) ?? -1;
|
|
104
101
|
}
|
|
@@ -8,7 +8,7 @@ export interface ReadSheetRowsOptions extends ReadXlsxOptions {
|
|
|
8
8
|
readonly sheet?: string | number;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* The resolved style facets of a streamed cell
|
|
11
|
+
* The resolved style facets of a streamed cell: its own `<c s>` cell format, flattened exactly as
|
|
12
12
|
* the buffered reader resolves it. Present only when the cell carries a format; a consumer can copy
|
|
13
13
|
* these straight onto a writer cell to preserve its look through a streaming read→write.
|
|
14
14
|
*/
|
|
@@ -19,7 +19,7 @@ export interface StreamedCell {
|
|
|
19
19
|
readonly col: number;
|
|
20
20
|
/** Canonical A1 address (`"B3"`). */
|
|
21
21
|
readonly address: string;
|
|
22
|
-
/** The decoded value
|
|
22
|
+
/** The decoded value, identical to what `readXlsx` would produce for the same cell. */
|
|
23
23
|
readonly value: CellValue;
|
|
24
24
|
/** The cell's resolved style facets, or absent when the cell carries no format of its own. */
|
|
25
25
|
readonly style?: StreamedCellStyle;
|
|
@@ -39,14 +39,14 @@ export interface StreamedRow {
|
|
|
39
39
|
*
|
|
40
40
|
* The two summaries are resolved lazily: reading either accessor drives a full scan of the sheet if
|
|
41
41
|
* its rows have not already been consumed, so their order relative to `rows()` never matters. (When
|
|
42
|
-
* rows *are* consumed first
|
|
42
|
+
* rows *are* consumed first, the streaming idiom, the accessors reuse that pass and re-scan
|
|
43
43
|
* nothing.)
|
|
44
44
|
*/
|
|
45
45
|
export interface StreamedSheet {
|
|
46
|
-
/** The worksheet's declared name, joined from the workbook part
|
|
46
|
+
/** The worksheet's declared name, joined from the workbook part. Never a positional placeholder. */
|
|
47
47
|
readonly name: string;
|
|
48
48
|
/** Stream this sheet's rows, one at a time, in sheet order. */
|
|
49
|
-
rows(): Generator<StreamedRow>;
|
|
49
|
+
rows(): Generator<StreamedRow, void, undefined>;
|
|
50
50
|
/** 1-based indices of columns the sheet declares hidden, ascending. */
|
|
51
51
|
readonly hiddenColumns: readonly number[];
|
|
52
52
|
/** The sheet's merged ranges, as canonical A1 range strings, in declaration order. */
|
|
@@ -55,31 +55,31 @@ export interface StreamedSheet {
|
|
|
55
55
|
/**
|
|
56
56
|
* Stream a worksheet's rows from an `.xlsx` package, yielding each in sheet order without building
|
|
57
57
|
* the workbook model. Only rows the sheet actually declares are yielded, and within a row only its
|
|
58
|
-
* non-empty cells
|
|
58
|
+
* non-empty cells: a blank or style-only cell contributes nothing, matching the intent of a data
|
|
59
59
|
* read.
|
|
60
60
|
*
|
|
61
61
|
* @param data The raw `.xlsx` bytes.
|
|
62
62
|
* @param options Sheet selector and the inflate bound (see {@link ReadSheetRowsOptions}).
|
|
63
63
|
* @throws {UnsupportedFormatError} if the input is not a readable `.xlsx` package (a legacy `.xls`, a
|
|
64
|
-
* binary `.xlsb`, or an unrecognised/non-ZIP blob
|
|
65
|
-
* @throws {PackageReadError} if the input is a ZIP that cannot be unpacked
|
|
64
|
+
* binary `.xlsb`, or an unrecognised/non-ZIP blob; branch on `.format`).
|
|
65
|
+
* @throws {PackageReadError} if the input is a ZIP that cannot be unpacked: a corrupt or
|
|
66
66
|
* truncated archive, or one exceeding the inflate bound (a probable zip bomb).
|
|
67
67
|
* @throws {XlsxParseError} if the package's workbook part declares no worksheets.
|
|
68
68
|
* @throws {RangeError} / {@link AuthoringError} if `options.sheet` selects a position, or a name,
|
|
69
69
|
* that no worksheet has.
|
|
70
70
|
*/
|
|
71
|
-
export declare function readSheetRows(data: Uint8Array, options?: ReadSheetRowsOptions): Generator<StreamedRow>;
|
|
71
|
+
export declare function readSheetRows(data: Uint8Array, options?: ReadSheetRowsOptions): Generator<StreamedRow, void, undefined>;
|
|
72
72
|
/**
|
|
73
73
|
* Stream every worksheet of an `.xlsx` package in workbook order, without building the workbook
|
|
74
74
|
* model. Each yielded {@link StreamedSheet} carries the declared sheet name and lets the caller
|
|
75
|
-
* stream that sheet's rows and read its hidden-column and merge summaries
|
|
75
|
+
* stream that sheet's rows and read its hidden-column and merge summaries: the streaming analogue
|
|
76
76
|
* of walking `readXlsx(data).worksheets`.
|
|
77
77
|
*
|
|
78
78
|
* @param data The raw `.xlsx` bytes.
|
|
79
79
|
* @param options The inflate bound (see {@link ReadXlsxOptions}).
|
|
80
80
|
* @throws {UnsupportedFormatError} if the input is not a readable `.xlsx` package (a legacy `.xls`, a
|
|
81
|
-
* binary `.xlsb`, or an unrecognised/non-ZIP blob
|
|
82
|
-
* @throws {PackageReadError} if the input is a ZIP that cannot be unpacked
|
|
81
|
+
* binary `.xlsb`, or an unrecognised/non-ZIP blob; branch on `.format`).
|
|
82
|
+
* @throws {PackageReadError} if the input is a ZIP that cannot be unpacked: a corrupt or
|
|
83
83
|
* truncated archive, or one exceeding the inflate bound (a probable zip bomb).
|
|
84
84
|
*/
|
|
85
|
-
export declare function readWorkbookStream(data: Uint8Array, options?: ReadXlsxOptions): Generator<StreamedSheet>;
|
|
85
|
+
export declare function readWorkbookStream(data: Uint8Array, options?: ReadXlsxOptions): Generator<StreamedSheet, void, undefined>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { MAX_COLUMN } from '../../core/address.js';
|
|
1
|
+
import { MAX_COLUMN, MAX_ROW } from '../../core/address.js';
|
|
2
2
|
import { AuthoringError } from '../../errors.js';
|
|
3
|
-
import { boolStrict, closeEmptyElements, localName, xmlEvents } from '../../xml/xml-read.js';
|
|
3
|
+
import { boolStrict, closeEmptyElements, localName, numInteger, xmlEvents, } from '../../xml/xml-read.js';
|
|
4
4
|
import { packageAccessors } from '../opc/read-opc.js';
|
|
5
5
|
import { inflateSpreadsheetPackage, unsupportedWorkbookPart } from '../opc/sniff-format.js';
|
|
6
6
|
import { CellAccumulator } from './cell-accumulator.js';
|
|
7
7
|
import { XlsxParseError } from './errors.js';
|
|
8
|
-
import { DEFAULT_MAX_UNCOMPRESSED, parseRelationships, parseStyleTable, parseWorkbookSheets, resolveWorkbookPart, } from './read.js';
|
|
9
8
|
import { parseSharedStrings } from './read-shared-strings.js';
|
|
9
|
+
import { DEFAULT_MAX_UNCOMPRESSED, parseRelationships, parseStyleTable, parseWorkbookSheets, resolveWorkbookPart, } from './read.js';
|
|
10
10
|
export function* readSheetRows(data, options = {}) {
|
|
11
11
|
const pkg = openPackage(data, options.maxUncompressedBytes);
|
|
12
12
|
const chosen = pickSheet(pkg.sheets, options.sheet);
|
|
@@ -102,13 +102,11 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
102
102
|
let rowNumber = 0;
|
|
103
103
|
let lastRow = 0;
|
|
104
104
|
let rowHidden = false;
|
|
105
|
+
let rowInGrid = true;
|
|
105
106
|
let cells = [];
|
|
106
|
-
const cell = new CellAccumulator();
|
|
107
|
-
let inInlineString = false;
|
|
108
|
-
let capture = false;
|
|
109
|
-
let text = '';
|
|
107
|
+
const cell = new CellAccumulator({ richRuns: false });
|
|
110
108
|
const finalizeCell = () => {
|
|
111
|
-
if (cell.ref === '' || cell.col < 0)
|
|
109
|
+
if (cell.ref === '' || cell.col < 0 || !rowInGrid)
|
|
112
110
|
return;
|
|
113
111
|
const style = cell.styleIndex >= 0 ? xfStyles[cell.styleIndex] : undefined;
|
|
114
112
|
const value = cell.decode(sharedStrings, style);
|
|
@@ -119,19 +117,18 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
119
117
|
};
|
|
120
118
|
for (const event of closeEmptyElements(xmlEvents(xml), CELL_EMPTY_CLOSE)) {
|
|
121
119
|
if (event.kind === 'text') {
|
|
122
|
-
|
|
123
|
-
text += event.text;
|
|
120
|
+
cell.appendChunk(event.text);
|
|
124
121
|
continue;
|
|
125
122
|
}
|
|
126
123
|
if (event.kind === 'open') {
|
|
127
124
|
const local = localName(event.name);
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
if (cell.openElement(local, event.attrs, event.selfClosing))
|
|
126
|
+
continue;
|
|
130
127
|
switch (local) {
|
|
131
128
|
case 'row': {
|
|
132
|
-
|
|
133
|
-
rowNumber = Number.isInteger(declared) && declared >= 1 ? declared : lastRow + 1;
|
|
129
|
+
rowNumber = numInteger(event.attrs.r, 1) ?? lastRow + 1;
|
|
134
130
|
lastRow = rowNumber;
|
|
131
|
+
rowInGrid = rowNumber <= MAX_ROW;
|
|
135
132
|
rowHidden = boolStrict(event.attrs.hidden);
|
|
136
133
|
cells = [];
|
|
137
134
|
break;
|
|
@@ -143,60 +140,27 @@ function* scanSheet(xml, sharedStrings, xfStyles, hiddenColumns, merges) {
|
|
|
143
140
|
if (event.attrs.ref !== undefined)
|
|
144
141
|
merges.push(event.attrs.ref);
|
|
145
142
|
break;
|
|
146
|
-
case 'c':
|
|
147
|
-
cell.beginCell(event.attrs);
|
|
148
|
-
break;
|
|
149
|
-
case 'is':
|
|
150
|
-
inInlineString = true;
|
|
151
|
-
cell.beginInlineString();
|
|
152
|
-
break;
|
|
153
|
-
case 'f':
|
|
154
|
-
capture = true;
|
|
155
|
-
cell.beginFormula(event.attrs, event.selfClosing);
|
|
156
|
-
break;
|
|
157
|
-
case 'v':
|
|
158
|
-
case 't':
|
|
159
|
-
capture = true;
|
|
160
|
-
break;
|
|
161
143
|
default:
|
|
162
144
|
break;
|
|
163
145
|
}
|
|
164
|
-
if (event.selfClosing && (local === 'f' || local === 'v'))
|
|
165
|
-
capture = false;
|
|
166
146
|
continue;
|
|
167
147
|
}
|
|
168
148
|
const local = localName(event.name);
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
cell.setValue(text);
|
|
175
|
-
break;
|
|
176
|
-
case 't':
|
|
177
|
-
cell.appendText(text, inInlineString);
|
|
178
|
-
break;
|
|
179
|
-
case 'is':
|
|
180
|
-
inInlineString = false;
|
|
181
|
-
break;
|
|
182
|
-
case 'c':
|
|
183
|
-
finalizeCell();
|
|
184
|
-
break;
|
|
185
|
-
case 'row':
|
|
149
|
+
const claimed = cell.closeElement(local);
|
|
150
|
+
if (claimed === 'cell')
|
|
151
|
+
finalizeCell();
|
|
152
|
+
else if (claimed === 'other' && local === 'row') {
|
|
153
|
+
if (rowInGrid)
|
|
186
154
|
yield { number: rowNumber, hidden: rowHidden, cells };
|
|
187
|
-
break;
|
|
188
|
-
default:
|
|
189
|
-
break;
|
|
190
155
|
}
|
|
191
|
-
capture = false;
|
|
192
156
|
}
|
|
193
157
|
}
|
|
194
158
|
function collectHiddenColumn(attrs, hiddenColumns) {
|
|
195
159
|
if (attrs.hidden !== '1' && attrs.hidden !== 'true')
|
|
196
160
|
return;
|
|
197
|
-
const min =
|
|
198
|
-
const max =
|
|
199
|
-
if (
|
|
161
|
+
const min = numInteger(attrs.min, 1);
|
|
162
|
+
const max = numInteger(attrs.max, 1);
|
|
163
|
+
if (min === undefined || max === undefined)
|
|
200
164
|
return;
|
|
201
165
|
const last = Math.min(max, MAX_COLUMN);
|
|
202
166
|
for (let index = min; index <= last; index++)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { localName, parseXml } from '../../xml/xml-read.js';
|
|
1
|
+
import { decodeSpreadsheetText, localName, parseXml } from '../../xml/xml-read.js';
|
|
2
2
|
import { RunAccumulator } from './rich-runs.js';
|
|
3
3
|
export function parseSharedStrings(xml) {
|
|
4
4
|
if (xml === '')
|
|
@@ -15,7 +15,7 @@ export function parseSharedStrings(xml) {
|
|
|
15
15
|
switch (local) {
|
|
16
16
|
case 'si':
|
|
17
17
|
plain = '';
|
|
18
|
-
runs.
|
|
18
|
+
runs.beginContainer();
|
|
19
19
|
isRich = false;
|
|
20
20
|
break;
|
|
21
21
|
case 'r':
|
|
@@ -41,11 +41,13 @@ export function parseSharedStrings(xml) {
|
|
|
41
41
|
onClose(name) {
|
|
42
42
|
const local = localName(name);
|
|
43
43
|
switch (local) {
|
|
44
|
-
case 't':
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
case 't': {
|
|
45
|
+
const decoded = decodeSpreadsheetText(text);
|
|
46
|
+
if (!runs.appendText(decoded))
|
|
47
|
+
plain += decoded;
|
|
47
48
|
capture = false;
|
|
48
49
|
break;
|
|
50
|
+
}
|
|
49
51
|
case 'r':
|
|
50
52
|
runs.endRun();
|
|
51
53
|
break;
|
|
@@ -9,7 +9,7 @@ export declare function applyFontChild(draft: FontDraft, local: string, attrs: X
|
|
|
9
9
|
/**
|
|
10
10
|
* Extract the custom indexed-color palette (`<colors><indexedColors>`) from styles.xml as verbatim
|
|
11
11
|
* `<rgbColor rgb="…"/>` fragments, or an empty list when the file rides the default palette. Kept raw
|
|
12
|
-
*
|
|
12
|
+
* rather than parsed into RGB and re-serialised, so the exact entries (count, order, casing) a
|
|
13
13
|
* source file declared survive a round-trip and every `indexed="…"` reference keeps its RGB.
|
|
14
14
|
*/
|
|
15
15
|
export declare function parseIndexedColors(stylesXml: string): string[];
|
|
@@ -25,8 +25,8 @@ export declare function parseMruColors(stylesXml: string): string[];
|
|
|
25
25
|
* container's nominated `defaultTableStyle`/`defaultPivotStyle`. See {@link TableStyleTable} for why
|
|
26
26
|
* the definitions stay raw while the two names are decoded.
|
|
27
27
|
*
|
|
28
|
-
* A file with no such block
|
|
29
|
-
* only defaults to state
|
|
28
|
+
* A file with no such block, or with the self-closing `count="0"` container Excel writes when it has
|
|
29
|
+
* only defaults to state, yields an empty {@link TableStyleTable.styles} and whichever names it did
|
|
30
30
|
* carry.
|
|
31
31
|
*/
|
|
32
32
|
export declare function parseTableStyles(stylesXml: string): TableStyleTable;
|