@shbernal/ts-xlsx 3.0.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 +34 -24
- package/dist/bytes.d.ts +10 -2
- package/dist/bytes.js +22 -0
- package/dist/core/address.d.ts +96 -2
- package/dist/core/address.js +87 -33
- package/dist/core/array-formula-ranges.d.ts +33 -0
- package/dist/core/array-formula-ranges.js +62 -0
- package/dist/core/autofilter.d.ts +4 -3
- package/dist/core/autofilter.js +31 -30
- package/dist/core/axis-handle.d.ts +2 -0
- package/dist/core/axis-handle.js +5 -2
- package/dist/core/cell.d.ts +4 -3
- package/dist/core/cell.js +4 -6
- package/dist/core/clone.d.ts +29 -0
- package/dist/core/clone.js +24 -0
- package/dist/core/color-resolution.js +4 -6
- package/dist/core/column.d.ts +1 -0
- package/dist/core/column.js +6 -2
- package/dist/core/comment-thread.d.ts +7 -3
- package/dist/core/comment-thread.js +2 -1
- package/dist/core/conditional-formatting-overlay.d.ts +11 -1
- package/dist/core/conditional-formatting-overlay.js +30 -3
- package/dist/core/conditional-formatting.d.ts +107 -11
- package/dist/core/conditional-formatting.js +76 -19
- package/dist/core/containers.d.ts +12 -0
- package/dist/core/containers.js +5 -0
- package/dist/core/data-validation-overlay.d.ts +7 -1
- package/dist/core/data-validation-overlay.js +19 -4
- package/dist/core/data-validation.d.ts +22 -0
- package/dist/core/data-validation.js +30 -4
- package/dist/core/date-format.d.ts +20 -0
- package/dist/core/date-format.js +170 -0
- package/dist/core/date.d.ts +43 -8
- package/dist/core/date.js +19 -3
- 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 +76 -17
- package/dist/core/formula.js +87 -80
- 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 +30 -3
- package/dist/core/grid-edits.js +248 -81
- package/dist/core/grid-shift.d.ts +58 -9
- package/dist/core/grid-shift.js +26 -4
- package/dist/core/hyperlink.d.ts +39 -0
- package/dist/core/hyperlink.js +88 -0
- package/dist/core/image.d.ts +49 -14
- package/dist/core/image.js +16 -5
- package/dist/core/internal.d.ts +10 -2
- package/dist/core/limits.d.ts +25 -0
- package/dist/core/limits.js +4 -0
- package/dist/core/merge.d.ts +18 -4
- package/dist/core/merge.js +33 -20
- package/dist/core/page-setup.d.ts +26 -11
- package/dist/core/pivot-table.d.ts +49 -10
- package/dist/core/pivot-table.js +112 -60
- package/dist/core/protection.d.ts +66 -4
- package/dist/core/protection.js +6 -11
- package/dist/core/range.js +34 -30
- package/dist/core/row-input.js +2 -2
- package/dist/core/row.d.ts +1 -0
- package/dist/core/row.js +6 -2
- package/dist/core/structured-reference.d.ts +7 -0
- package/dist/core/structured-reference.js +7 -0
- package/dist/core/style.d.ts +85 -70
- package/dist/core/style.js +92 -28
- package/dist/core/table-style.d.ts +1 -1
- package/dist/core/table-style.js +4 -4
- package/dist/core/table.d.ts +64 -16
- package/dist/core/table.js +87 -40
- package/dist/core/theme.d.ts +2 -0
- package/dist/core/theme.js +9 -5
- package/dist/core/value.d.ts +60 -28
- package/dist/core/value.js +48 -43
- package/dist/core/workbook-media.d.ts +34 -0
- package/dist/core/workbook-media.js +44 -0
- package/dist/core/workbook-styles.d.ts +83 -1
- package/dist/core/workbook-styles.js +4 -0
- package/dist/core/workbook-theme.js +5 -3
- package/dist/core/workbook-vba.js +3 -2
- package/dist/core/workbook.d.ts +41 -3
- package/dist/core/workbook.js +46 -41
- package/dist/core/worksheet-comments.d.ts +2 -1
- package/dist/core/worksheet-comments.js +20 -13
- package/dist/core/worksheet-merges.d.ts +49 -0
- package/dist/core/worksheet-merges.js +65 -0
- package/dist/core/worksheet-model.d.ts +10 -2
- package/dist/core/worksheet-model.js +28 -9
- package/dist/core/worksheet-pictures.d.ts +3 -3
- package/dist/core/worksheet-pictures.js +7 -6
- package/dist/core/worksheet.d.ts +165 -27
- package/dist/core/worksheet.js +206 -89
- package/dist/customui/ribbon.js +2 -1
- package/dist/entries/core.d.ts +21 -14
- package/dist/entries/core.js +14 -7
- package/dist/entries/errors.d.ts +1 -0
- package/dist/entries/errors.js +1 -0
- package/dist/entries/xlsx.d.ts +1 -1
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +22 -0
- package/dist/hex.d.ts +8 -0
- package/dist/hex.js +3 -0
- 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 +21 -0
- package/dist/io/csv/delimiter.js +18 -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 +51 -22
- package/dist/io/csv/write.d.ts +19 -5
- package/dist/io/csv/write.js +24 -44
- package/dist/io/opc/inflate.js +14 -0
- package/dist/io/opc/namespaces.d.ts +16 -0
- package/dist/io/opc/namespaces.js +4 -0
- package/dist/io/opc/part-paths.d.ts +9 -0
- package/dist/io/opc/part-paths.js +5 -5
- package/dist/io/opc/read-opc.d.ts +58 -14
- package/dist/io/opc/read-opc.js +49 -21
- package/dist/io/opc/read-options.d.ts +5 -1
- package/dist/io/opc/sniff-format.d.ts +3 -3
- package/dist/io/opc/sniff-format.js +2 -2
- 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/read-policy/column-budget.js +18 -0
- 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/style/xf-style.d.ts +23 -1
- package/dist/io/style/xf-style.js +8 -0
- package/dist/io/xlsb/formula.d.ts +2 -2
- package/dist/io/xlsb/formula.js +52 -35
- package/dist/io/xlsb/primitives.js +8 -14
- package/dist/io/xlsb/ptg-functions.d.ts +19 -10
- package/dist/io/xlsb/ptg-functions.js +495 -596
- package/dist/io/xlsb/read-metadata.d.ts +7 -0
- package/dist/io/xlsb/read-metadata.js +69 -0
- package/dist/io/xlsb/read-styles.js +45 -81
- package/dist/io/xlsb/read-worksheet.d.ts +26 -1
- package/dist/io/xlsb/read-worksheet.js +148 -106
- package/dist/io/xlsb/read.d.ts +6 -3
- package/dist/io/xlsb/read.js +70 -31
- package/dist/io/xlsb/record-stream.d.ts +30 -0
- package/dist/io/xlsb/record-stream.js +20 -0
- package/dist/io/xlsb/record-types.d.ts +14 -5
- package/dist/io/xlsb/record-types.js +14 -5
- 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 +24 -9
- package/dist/io/xlsx/cell-accumulator.js +74 -21
- 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 +19 -5
- package/dist/io/xlsx/cell-value.js +45 -30
- package/dist/io/xlsx/color-xml.js +3 -2
- 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 +9 -30
- package/dist/io/xlsx/comments.js +25 -83
- package/dist/io/xlsx/conditional-formatting.d.ts +43 -23
- package/dist/io/xlsx/conditional-formatting.js +437 -138
- package/dist/io/xlsx/data-validation.d.ts +12 -7
- package/dist/io/xlsx/data-validation.js +67 -53
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +52 -52
- package/dist/io/xlsx/font-xml.d.ts +7 -0
- package/dist/io/xlsx/font-xml.js +104 -0
- package/dist/io/xlsx/hyperlinks.d.ts +19 -21
- package/dist/io/xlsx/hyperlinks.js +12 -32
- package/dist/io/xlsx/images.d.ts +49 -16
- package/dist/io/xlsx/images.js +149 -50
- package/dist/io/xlsx/namespaces.d.ts +24 -0
- package/dist/io/xlsx/namespaces.js +11 -0
- package/dist/io/xlsx/package-plan.d.ts +60 -15
- package/dist/io/xlsx/package-plan.js +83 -18
- 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 +26 -24
- 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 +59 -0
- package/dist/io/xlsx/read-parts.js +259 -0
- package/dist/io/xlsx/read-pivot.js +11 -4
- package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +8 -5
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +24 -4
- package/dist/io/xlsx/read-rows.d.ts +35 -11
- package/dist/io/xlsx/read-rows.js +73 -49
- package/dist/io/xlsx/read-shared-strings.js +3 -2
- package/dist/io/xlsx/read-styles.d.ts +0 -30
- package/dist/io/xlsx/read-styles.js +45 -105
- package/dist/io/xlsx/read-workbook-xml.d.ts +42 -0
- package/dist/io/xlsx/read-workbook-xml.js +175 -0
- package/dist/io/xlsx/read-worksheet.d.ts +9 -3
- package/dist/io/xlsx/read-worksheet.js +70 -177
- package/dist/io/xlsx/read.d.ts +3 -14
- package/dist/io/xlsx/read.js +74 -411
- package/dist/io/xlsx/relationships.d.ts +3 -0
- package/dist/io/xlsx/relationships.js +4 -0
- package/dist/io/xlsx/rich-text.js +1 -1
- package/dist/io/xlsx/row-position.d.ts +20 -0
- package/dist/io/xlsx/row-position.js +11 -0
- package/dist/io/xlsx/row-xml.d.ts +139 -0
- package/dist/io/xlsx/row-xml.js +222 -0
- package/dist/io/xlsx/shared-formulas.js +2 -2
- package/dist/io/xlsx/sheet-properties.d.ts +10 -1
- package/dist/io/xlsx/sheet-properties.js +182 -20
- 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 +41 -0
- package/dist/io/xlsx/style-elements.js +136 -0
- package/dist/io/xlsx/styles.d.ts +17 -3
- package/dist/io/xlsx/styles.js +13 -209
- package/dist/io/xlsx/tables.d.ts +10 -2
- package/dist/io/xlsx/tables.js +55 -52
- package/dist/io/xlsx/theme-xml.d.ts +32 -4
- package/dist/io/xlsx/theme-xml.js +106 -71
- package/dist/io/xlsx/threaded-comments.d.ts +14 -11
- package/dist/io/xlsx/threaded-comments.js +16 -8
- package/dist/io/xlsx/workbook-xml.d.ts +45 -6
- package/dist/io/xlsx/workbook-xml.js +62 -54
- package/dist/io/xlsx/worksheet-xml.d.ts +26 -70
- package/dist/io/xlsx/worksheet-xml.js +69 -282
- package/dist/io/xlsx/write-stream.d.ts +90 -19
- package/dist/io/xlsx/write-stream.js +80 -25
- package/dist/io/xlsx/write.d.ts +12 -6
- package/dist/io/xlsx/write.js +226 -123
- package/dist/rel-type.d.ts +25 -0
- package/dist/rel-type.js +9 -0
- package/dist/token-set.d.ts +13 -0
- package/dist/token-set.js +4 -1
- package/dist/vba/bytes.d.ts +16 -5
- package/dist/vba/bytes.js +27 -6
- package/dist/vba/cfb-format.d.ts +55 -0
- package/dist/vba/cfb-format.js +35 -0
- package/dist/vba/cfb-writer.d.ts +8 -0
- package/dist/vba/cfb-writer.js +40 -40
- package/dist/vba/cfb.d.ts +21 -4
- package/dist/vba/cfb.js +124 -90
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/dir-records.d.ts +6 -0
- package/dist/vba/dir-records.js +10 -2
- package/dist/vba/errors.d.ts +11 -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 +66 -22
- package/dist/vba/project-editor.js +129 -119
- package/dist/vba/project.d.ts +15 -1
- package/dist/vba/project.js +38 -13
- package/dist/vba/vba-encoding.d.ts +4 -10
- package/dist/vba/vba-encoding.js +3 -17
- package/dist/xml/xml-attrs.d.ts +37 -0
- package/dist/xml/xml-attrs.js +30 -0
- package/dist/xml/xml-chars.d.ts +40 -0
- package/dist/xml/xml-chars.js +12 -0
- package/dist/xml/xml-namespaces.d.ts +31 -0
- package/dist/xml/xml-namespaces.js +50 -0
- package/dist/xml/xml-read.d.ts +101 -11
- package/dist/xml/xml-read.js +150 -18
- package/dist/xml/xml-scan.d.ts +25 -34
- package/dist/xml/xml-scan.js +69 -46
- package/dist/xml/xml.d.ts +59 -26
- package/dist/xml/xml.js +45 -23
- package/package.json +15 -9
- package/skills/ts-xlsx-upstream/SKILL.md +21 -13
- package/dist/core/modern-functions.d.ts +0 -1
package/dist/io/xlsb/read.js
CHANGED
|
@@ -1,74 +1,99 @@
|
|
|
1
|
-
import { unmangleFunctions } from '../../core/formula.js';
|
|
1
|
+
import { definedNameKeys, unmangleFunctions } from '../../core/formula.js';
|
|
2
2
|
import { INTERNAL } from '../../core/internal.js';
|
|
3
3
|
import { Workbook } from '../../core/workbook.js';
|
|
4
|
+
import { quoted } from '../../errors.js';
|
|
5
|
+
import { indexCellMetadata } from '../cell-metadata/metadata.js';
|
|
6
|
+
import { parseRichValueErrors } from '../cell-metadata/rich-values.js';
|
|
4
7
|
import { UnsupportedFormatError } from '../opc/errors.js';
|
|
5
8
|
import { openSpreadsheetPackage, packageAccessors, readPartRelationships } from '../opc/read-opc.js';
|
|
9
|
+
import { admitting, repairedSheetNames } from '../read-policy/read-repair.js';
|
|
10
|
+
import { XlsbParseError } from './errors.js';
|
|
6
11
|
import { decodeFormula } from './formula.js';
|
|
7
12
|
import { RecordReader } from './primitives.js';
|
|
13
|
+
import { parseMetadataPart } from './read-metadata.js';
|
|
8
14
|
import { parseSharedStrings } from './read-shared-strings.js';
|
|
9
15
|
import { parseStyleTable } from './read-styles.js';
|
|
10
16
|
import { parseWorksheet } from './read-worksheet.js';
|
|
11
|
-
import { readRecords } from './record-stream.js';
|
|
17
|
+
import { blockTracker, readRecords } from './record-stream.js';
|
|
12
18
|
import { BRT } from './record-types.js';
|
|
13
19
|
export const XLSB_WORKBOOK_PART = 'xl/workbook.bin';
|
|
14
20
|
export function readXlsb(data, options = {}) {
|
|
15
|
-
|
|
21
|
+
const { files, documentPath, workbookXml } = openSpreadsheetPackage(data, options.maxUncompressedBytes);
|
|
22
|
+
if (workbookXml !== undefined) {
|
|
23
|
+
throw new UnsupportedFormatError('unknown', `not a valid .xlsb package: its office document ${quoted(documentPath)} is XML, not the binary ${XLSB_WORKBOOK_PART} a .xlsb carries; read it with readXlsx`);
|
|
24
|
+
}
|
|
25
|
+
return readXlsbPackage(files, documentPath);
|
|
16
26
|
}
|
|
17
|
-
export function readXlsbPackage(files) {
|
|
27
|
+
export function readXlsbPackage(files, documentPath = XLSB_WORKBOOK_PART) {
|
|
18
28
|
const { partText, partBytes } = packageAccessors(files);
|
|
19
|
-
const workbookPart = partBytes(
|
|
29
|
+
const workbookPart = partBytes(documentPath);
|
|
20
30
|
if (workbookPart === undefined) {
|
|
21
|
-
throw new UnsupportedFormatError('unknown', `not a valid .xlsb package: ${
|
|
31
|
+
throw new UnsupportedFormatError('unknown', `not a valid .xlsb package: ${quoted(documentPath)} is missing`);
|
|
22
32
|
}
|
|
23
|
-
const rels = readPartRelationships(
|
|
24
|
-
const sharedStrings = parseSharedStrings(partBytes('xl/sharedStrings.bin'));
|
|
25
|
-
const { cellXfs, namedStyles, defaultFont } = parseStyleTable(partBytes('xl/styles.bin'));
|
|
33
|
+
const rels = readPartRelationships(documentPath, partText, partBytes);
|
|
34
|
+
const sharedStrings = parseSharedStrings(rels.relatedBytes('sharedStrings') ?? partBytes('xl/sharedStrings.bin'));
|
|
35
|
+
const { cellXfs, namedStyles, defaultFont } = parseStyleTable(rels.relatedBytes('styles') ?? partBytes('xl/styles.bin'));
|
|
26
36
|
const workbook = new Workbook();
|
|
27
37
|
if (namedStyles.length > 1)
|
|
28
38
|
workbook[INTERNAL].restoreNamedStyles(namedStyles);
|
|
29
39
|
workbook[INTERNAL].restoreDefaultFont(defaultFont);
|
|
30
40
|
const declaration = readWorkbookPart(workbookPart);
|
|
41
|
+
workbook.dateEpoch = declaration.dateEpoch;
|
|
42
|
+
const sheets = repairedSheetNames(declaration.sheets);
|
|
31
43
|
const scope = {
|
|
32
|
-
sheetNames:
|
|
44
|
+
sheetNames: sheets.map((sheet) => sheet.name),
|
|
33
45
|
externSheets: declaration.externSheets,
|
|
34
46
|
selfSupBook: declaration.selfSupBook,
|
|
35
47
|
names: declaration.names.map((name) => name.name),
|
|
36
48
|
};
|
|
37
|
-
|
|
49
|
+
const namesInWorkbook = definedNameKeys(declaration.names.filter(isWorkbookName));
|
|
50
|
+
const cellMetadata = indexCellMetadata(parseMetadataPart(rels.relatedBytes('sheetMetadata')), parseRichValueErrors(rels.relatedText('rdRichValueStructure') ?? '', rels.relatedText('rdRichValue') ?? ''));
|
|
51
|
+
for (const declared of sheets) {
|
|
38
52
|
const sheet = workbook.addWorksheet(declared.name, { state: declared.state });
|
|
39
53
|
const target = declared.relId === undefined ? undefined : rels.byId(declared.relId)?.target;
|
|
40
54
|
const part = target === undefined ? undefined : partBytes(rels.pathOf(target));
|
|
41
55
|
if (part !== undefined)
|
|
42
|
-
parseWorksheet(part,
|
|
56
|
+
parseWorksheet(part, {
|
|
57
|
+
sheet,
|
|
58
|
+
sharedStrings,
|
|
59
|
+
xfStyles: cellXfs,
|
|
60
|
+
scope,
|
|
61
|
+
dateEpoch: declaration.dateEpoch,
|
|
62
|
+
definedNames: namesInWorkbook,
|
|
63
|
+
cellMetadata,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
for (const defined of definedNames(declaration, scope, namesInWorkbook)) {
|
|
67
|
+
admitting(() => {
|
|
68
|
+
workbook.defineName(defined);
|
|
69
|
+
});
|
|
43
70
|
}
|
|
44
|
-
for (const defined of definedNames(declaration, scope))
|
|
45
|
-
workbook.defineName(defined);
|
|
46
71
|
return workbook;
|
|
47
72
|
}
|
|
73
|
+
const WORKBOOK_BLOCKS = [
|
|
74
|
+
[BRT.BeginBundleShs, BRT.EndBundleShs, 'bundle'],
|
|
75
|
+
[BRT.BeginExternals, BRT.EndExternals, 'externals'],
|
|
76
|
+
];
|
|
48
77
|
function readWorkbookPart(part) {
|
|
49
78
|
const sheets = [];
|
|
50
79
|
const names = [];
|
|
51
80
|
let externSheets = [];
|
|
52
|
-
|
|
53
|
-
let inExternals = false;
|
|
81
|
+
const blocks = blockTracker(WORKBOOK_BLOCKS);
|
|
54
82
|
let supportingBooks = 0;
|
|
55
83
|
let selfSupBook;
|
|
84
|
+
let dateEpoch = 1900;
|
|
56
85
|
for (const record of readRecords(part)) {
|
|
57
|
-
if (record.type
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
else if (record.type === BRT.BundleSh &&
|
|
86
|
+
if (blocks.boundary(record.type))
|
|
87
|
+
continue;
|
|
88
|
+
if (record.type === BRT.WbProp)
|
|
89
|
+
dateEpoch = readDateEpoch(record.data);
|
|
90
|
+
else if (record.type === BRT.BundleSh && blocks.isOpen('bundle'))
|
|
62
91
|
sheets.push(readSheet(record.data));
|
|
63
|
-
else if (record.type === BRT.BeginExternals)
|
|
64
|
-
inExternals = true;
|
|
65
|
-
else if (record.type === BRT.EndExternals)
|
|
66
|
-
inExternals = false;
|
|
67
92
|
else if (record.type === BRT.ExternSheet)
|
|
68
93
|
externSheets = readExternSheets(record.data);
|
|
69
94
|
else if (record.type === BRT.SupSelf)
|
|
70
95
|
selfSupBook = supportingBooks++;
|
|
71
|
-
else if (
|
|
96
|
+
else if (blocks.isOpen('externals'))
|
|
72
97
|
supportingBooks++;
|
|
73
98
|
else if (record.type === BRT.Name)
|
|
74
99
|
names.push(readName(record.data));
|
|
@@ -78,8 +103,14 @@ function readWorkbookPart(part) {
|
|
|
78
103
|
names,
|
|
79
104
|
externSheets,
|
|
80
105
|
selfSupBook: supportingBooks === 1 ? selfSupBook : undefined,
|
|
106
|
+
dateEpoch,
|
|
81
107
|
};
|
|
82
108
|
}
|
|
109
|
+
function readDateEpoch(data) {
|
|
110
|
+
if (data.length < 4)
|
|
111
|
+
return 1900;
|
|
112
|
+
return (new RecordReader(data).u32() & 1) === 0 ? 1900 : 1904;
|
|
113
|
+
}
|
|
83
114
|
function readSheet(data) {
|
|
84
115
|
const reader = new RecordReader(data);
|
|
85
116
|
const state = SHEET_STATES[reader.u32()] ?? 'visible';
|
|
@@ -90,9 +121,11 @@ function readSheet(data) {
|
|
|
90
121
|
function readExternSheets(data) {
|
|
91
122
|
const reader = new RecordReader(data);
|
|
92
123
|
const count = reader.u32();
|
|
124
|
+
if (count * XTI_BYTES > reader.remaining) {
|
|
125
|
+
throw new XlsbParseError(`BIFF12 externSheet table declares ${count} entries needing ${count * XTI_BYTES} bytes but ` +
|
|
126
|
+
`only ${reader.remaining} remain in the record`);
|
|
127
|
+
}
|
|
93
128
|
const entries = [];
|
|
94
|
-
if (count * XTI_BYTES > reader.remaining)
|
|
95
|
-
return entries;
|
|
96
129
|
for (let index = 0; index < count; index++) {
|
|
97
130
|
entries.push({ supBook: reader.u32(), firstSheet: reader.i32(), lastSheet: reader.i32() });
|
|
98
131
|
}
|
|
@@ -117,10 +150,10 @@ function readName(data) {
|
|
|
117
150
|
}
|
|
118
151
|
const GLOBAL_NAME_SCOPE = 0xffffffff;
|
|
119
152
|
const NAME_IS_FUNCTION = 0x00000002;
|
|
120
|
-
function definedNames(declaration, scope) {
|
|
153
|
+
function definedNames(declaration, scope, namesInWorkbook) {
|
|
121
154
|
const names = [];
|
|
122
155
|
for (const declared of declaration.names) {
|
|
123
|
-
if (declared
|
|
156
|
+
if (!isWorkbookName(declared))
|
|
124
157
|
continue;
|
|
125
158
|
const refersTo = decodeFormula(declared.rgce, declared.rgcb, scope);
|
|
126
159
|
if (refersTo === undefined)
|
|
@@ -129,10 +162,16 @@ function definedNames(declaration, scope) {
|
|
|
129
162
|
names.push({
|
|
130
163
|
name: declared.name,
|
|
131
164
|
...(sheet === undefined ? {} : { scope: sheet }),
|
|
132
|
-
refersTo: unmangleFunctions(refersTo),
|
|
165
|
+
refersTo: unmangleFunctions(refersTo, namesInWorkbook),
|
|
133
166
|
});
|
|
134
167
|
}
|
|
135
168
|
return names;
|
|
136
169
|
}
|
|
170
|
+
function isWorkbookName(declared) {
|
|
171
|
+
return (!declared.isFunction &&
|
|
172
|
+
!FORMULA_PLACEHOLDER_NAME.test(declared.name) &&
|
|
173
|
+
declared.name !== FILTER_DATABASE_NAME);
|
|
174
|
+
}
|
|
175
|
+
const FORMULA_PLACEHOLDER_NAME = /^_xl(?:fn|pm|eta)\./;
|
|
137
176
|
const FILTER_DATABASE_NAME = '_xlnm._FilterDatabase';
|
|
138
177
|
const SHEET_STATES = ['visible', 'hidden', 'veryHidden'];
|
|
@@ -12,3 +12,33 @@ export interface BiffRecord {
|
|
|
12
12
|
* end of the part.
|
|
13
13
|
*/
|
|
14
14
|
export declare function readRecords(part: Uint8Array): Generator<BiffRecord>;
|
|
15
|
+
/**
|
|
16
|
+
* Track which `Begin…`/`End…` blocks a BIFF12 record stream is currently inside.
|
|
17
|
+
*
|
|
18
|
+
* BIFF12 is flat: a collection is a `BeginFonts` record, its members, then `EndFonts`, and a reader
|
|
19
|
+
* has to carry that state itself. Two readers here did, and only one did it legibly. The style reader
|
|
20
|
+
* kept an explicit collection with start and end tables; the workbook reader re-solved it with loose
|
|
21
|
+
* booleans in an if-else chain whose *ordering was load-bearing and unstated*: move the `EndExternals`
|
|
22
|
+
* arm below the catch-all that counts records inside the externals block and the count silently goes
|
|
23
|
+
* wrong. Answering "is this record a block boundary" separately from "what does this record mean"
|
|
24
|
+
* removes that constraint rather than documenting it.
|
|
25
|
+
*
|
|
26
|
+
* Each end names the block it closes, so an `EndFonts` cannot close `<fills>` the way a bare set of
|
|
27
|
+
* end markers allowed. Blocks are tracked independently, so two that a damaged file interleaves stay
|
|
28
|
+
* separate rather than one clearing the other.
|
|
29
|
+
*
|
|
30
|
+
* A block is declared as one `[start, end, block]` triple rather than as an entry in a start table
|
|
31
|
+
* and a matching entry in an end table. The two-table form let a caller pair `BeginFills` with
|
|
32
|
+
* `EndFonts` in a way that compiles and reads plausibly, which is the very mistake the paragraph
|
|
33
|
+
* above says this exists to prevent.
|
|
34
|
+
*/
|
|
35
|
+
export declare function blockTracker<T>(blocks: readonly (readonly [number, number, T])[]): BlockTracker<T>;
|
|
36
|
+
export interface BlockTracker<T> {
|
|
37
|
+
/** Whether the stream is currently inside `block`. */
|
|
38
|
+
isOpen(block: T): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Take a record's type as a possible block boundary, returning whether it was one. A boundary
|
|
41
|
+
* carries no content of its own, so a caller that gets `true` skips the record entirely.
|
|
42
|
+
*/
|
|
43
|
+
boundary(type: number): boolean;
|
|
44
|
+
}
|
|
@@ -26,3 +26,23 @@ function byteAt(part, index) {
|
|
|
26
26
|
throw new XlsbParseError('truncated BIFF12 record header');
|
|
27
27
|
return value;
|
|
28
28
|
}
|
|
29
|
+
export function blockTracker(blocks) {
|
|
30
|
+
const starts = new Map(blocks.map(([start, , block]) => [start, block]));
|
|
31
|
+
const ends = new Map(blocks.map(([, end, block]) => [end, block]));
|
|
32
|
+
const open = new Set();
|
|
33
|
+
return {
|
|
34
|
+
isOpen: (block) => open.has(block),
|
|
35
|
+
boundary(type) {
|
|
36
|
+
const ended = ends.get(type);
|
|
37
|
+
if (ended !== undefined) {
|
|
38
|
+
open.delete(ended);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
const started = starts.get(type);
|
|
42
|
+
if (started === undefined)
|
|
43
|
+
return false;
|
|
44
|
+
open.add(started);
|
|
45
|
+
return true;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -16,7 +16,6 @@ export declare const BRT: {
|
|
|
16
16
|
readonly ColInfo: 60;
|
|
17
17
|
readonly MergeCell: 176;
|
|
18
18
|
readonly SSTItem: 19;
|
|
19
|
-
readonly BeginSst: 159;
|
|
20
19
|
readonly EndSst: 160;
|
|
21
20
|
readonly Fmt: 44;
|
|
22
21
|
readonly Font: 43;
|
|
@@ -38,6 +37,7 @@ export declare const BRT: {
|
|
|
38
37
|
readonly EndCellXFs: 618;
|
|
39
38
|
readonly BeginStyles: 619;
|
|
40
39
|
readonly EndStyles: 620;
|
|
40
|
+
readonly WbProp: 153;
|
|
41
41
|
readonly BundleSh: 156;
|
|
42
42
|
readonly BeginBundleShs: 143;
|
|
43
43
|
readonly EndBundleShs: 144;
|
|
@@ -46,10 +46,19 @@ export declare const BRT: {
|
|
|
46
46
|
readonly EndExternals: 354;
|
|
47
47
|
readonly SupSelf: 357;
|
|
48
48
|
readonly ExternSheet: 362;
|
|
49
|
-
readonly WsProp: 147;
|
|
50
|
-
readonly WsDim: 148;
|
|
51
49
|
readonly WsFmtInfo: 485;
|
|
52
|
-
readonly BeginSheetData: 145;
|
|
53
|
-
readonly EndSheetData: 146;
|
|
54
50
|
readonly ArrFmla: 426;
|
|
51
|
+
readonly SheetProtection: 535;
|
|
52
|
+
readonly SheetProtectionIso: 678;
|
|
53
|
+
readonly CellMeta: 49;
|
|
54
|
+
readonly ValueMeta: 50;
|
|
55
|
+
readonly Mdtinfo: 335;
|
|
56
|
+
readonly BeginEsfmd: 339;
|
|
57
|
+
readonly EndEsfmd: 340;
|
|
58
|
+
readonly BeginFmd: 52;
|
|
59
|
+
readonly BeginEsmdb: 337;
|
|
60
|
+
readonly EndEsmdb: 338;
|
|
61
|
+
readonly Mdb: 51;
|
|
62
|
+
readonly DynamicArrayProperties: 4097;
|
|
63
|
+
readonly RichValueBlock: 5003;
|
|
55
64
|
};
|
|
@@ -15,7 +15,6 @@ export const BRT = {
|
|
|
15
15
|
ColInfo: 60,
|
|
16
16
|
MergeCell: 176,
|
|
17
17
|
SSTItem: 19,
|
|
18
|
-
BeginSst: 159,
|
|
19
18
|
EndSst: 160,
|
|
20
19
|
Fmt: 44,
|
|
21
20
|
Font: 43,
|
|
@@ -37,6 +36,7 @@ export const BRT = {
|
|
|
37
36
|
EndCellXFs: 618,
|
|
38
37
|
BeginStyles: 619,
|
|
39
38
|
EndStyles: 620,
|
|
39
|
+
WbProp: 153,
|
|
40
40
|
BundleSh: 156,
|
|
41
41
|
BeginBundleShs: 143,
|
|
42
42
|
EndBundleShs: 144,
|
|
@@ -45,10 +45,19 @@ export const BRT = {
|
|
|
45
45
|
EndExternals: 354,
|
|
46
46
|
SupSelf: 357,
|
|
47
47
|
ExternSheet: 362,
|
|
48
|
-
WsProp: 147,
|
|
49
|
-
WsDim: 148,
|
|
50
48
|
WsFmtInfo: 485,
|
|
51
|
-
BeginSheetData: 145,
|
|
52
|
-
EndSheetData: 146,
|
|
53
49
|
ArrFmla: 426,
|
|
50
|
+
SheetProtection: 535,
|
|
51
|
+
SheetProtectionIso: 678,
|
|
52
|
+
CellMeta: 49,
|
|
53
|
+
ValueMeta: 50,
|
|
54
|
+
Mdtinfo: 335,
|
|
55
|
+
BeginEsfmd: 339,
|
|
56
|
+
EndEsfmd: 340,
|
|
57
|
+
BeginFmd: 52,
|
|
58
|
+
BeginEsmdb: 337,
|
|
59
|
+
EndEsmdb: 338,
|
|
60
|
+
Mdb: 51,
|
|
61
|
+
DynamicArrayProperties: 4097,
|
|
62
|
+
RichValueBlock: 5003,
|
|
54
63
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { AssertNever } from '../../core/internal.ts';
|
|
2
|
+
import { type SheetProtection, type SheetProtectionFlags } from '../../core/protection.ts';
|
|
3
|
+
import type { RecordReader } from './primitives.ts';
|
|
4
|
+
declare const FLAGS_IN_RECORD_ORDER: readonly ["objects", "scenarios", "formatCells", "formatColumns", "formatRows", "insertColumns", "insertRows", "insertHyperlinks", "deleteColumns", "deleteRows", "selectLockedCells", "sort", "autoFilter", "pivotTables", "selectUnlockedCells"];
|
|
5
|
+
/**
|
|
6
|
+
* The half of the proof an ordered list owes: `satisfies` covers "no invented flag", this covers "no
|
|
7
|
+
* omission". A flag left out here would be read at the wrong offset along with every flag after it.
|
|
8
|
+
*/
|
|
9
|
+
export type EveryProtectionFlagHasARecordSlot = AssertNever<Exclude<keyof SheetProtectionFlags, (typeof FLAGS_IN_RECORD_ORDER)[number]>>;
|
|
10
|
+
/** What a worksheet's protection records say, gathered as they arrive. */
|
|
11
|
+
export declare class SheetProtectionRecords {
|
|
12
|
+
#private;
|
|
13
|
+
/** Read a `BrtSheetProtection`. */
|
|
14
|
+
legacy(reader: RecordReader): void;
|
|
15
|
+
/** Read a `BrtSheetProtectionIso`. */
|
|
16
|
+
iso(reader: RecordReader): void;
|
|
17
|
+
/** The protection the records described, or `undefined` for a sheet that is not protected. */
|
|
18
|
+
result(): SheetProtection | undefined;
|
|
19
|
+
}
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { toBase64 } from '../../bytes.js';
|
|
2
|
+
import { SHEET_PROTECTION_FLAGS, } from '../../core/protection.js';
|
|
3
|
+
import { hex } from '../../hex.js';
|
|
4
|
+
const FLAGS_IN_RECORD_ORDER = [
|
|
5
|
+
'objects',
|
|
6
|
+
'scenarios',
|
|
7
|
+
'formatCells',
|
|
8
|
+
'formatColumns',
|
|
9
|
+
'formatRows',
|
|
10
|
+
'insertColumns',
|
|
11
|
+
'insertRows',
|
|
12
|
+
'insertHyperlinks',
|
|
13
|
+
'deleteColumns',
|
|
14
|
+
'deleteRows',
|
|
15
|
+
'selectLockedCells',
|
|
16
|
+
'sort',
|
|
17
|
+
'autoFilter',
|
|
18
|
+
'pivotTables',
|
|
19
|
+
'selectUnlockedCells',
|
|
20
|
+
];
|
|
21
|
+
const ALLOWED_BY_DEFAULT = new Map(SHEET_PROTECTION_FLAGS.map(({ key, defaultForbidden }) => [key, !defaultForbidden]));
|
|
22
|
+
export class SheetProtectionRecords {
|
|
23
|
+
#locked = false;
|
|
24
|
+
#flags = {};
|
|
25
|
+
#legacyPasswordHash;
|
|
26
|
+
#credential;
|
|
27
|
+
legacy(reader) {
|
|
28
|
+
const protpwd = reader.u16();
|
|
29
|
+
this.#readFlags(reader);
|
|
30
|
+
this.#legacyPasswordHash = protpwd === 0 ? undefined : hex(protpwd, 4);
|
|
31
|
+
}
|
|
32
|
+
iso(reader) {
|
|
33
|
+
const spinCount = reader.u32();
|
|
34
|
+
this.#readFlags(reader);
|
|
35
|
+
const hashValue = toBase64(reader.bytes(reader.u32()));
|
|
36
|
+
const saltValue = toBase64(reader.bytes(reader.u32()));
|
|
37
|
+
this.#credential = { algorithmName: reader.wideString(), hashValue, saltValue, spinCount };
|
|
38
|
+
}
|
|
39
|
+
result() {
|
|
40
|
+
if (!this.#locked)
|
|
41
|
+
return undefined;
|
|
42
|
+
return {
|
|
43
|
+
flags: this.#flags,
|
|
44
|
+
...(this.#credential === undefined ? {} : { credential: this.#credential }),
|
|
45
|
+
...(this.#legacyPasswordHash === undefined
|
|
46
|
+
? {}
|
|
47
|
+
: { legacyPasswordHash: this.#legacyPasswordHash }),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
#readFlags(reader) {
|
|
51
|
+
this.#locked = reader.u32() !== 0;
|
|
52
|
+
const flags = {};
|
|
53
|
+
for (const key of FLAGS_IN_RECORD_ORDER) {
|
|
54
|
+
const allowed = reader.u32() !== 0;
|
|
55
|
+
if (allowed !== ALLOWED_BY_DEFAULT.get(key))
|
|
56
|
+
flags[key] = allowed;
|
|
57
|
+
}
|
|
58
|
+
this.#flags = flags;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1,30 +1,46 @@
|
|
|
1
|
+
import type { DateEpoch } from '../../core/date.ts';
|
|
1
2
|
import type { CellValue } from '../../core/value.ts';
|
|
2
3
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
3
4
|
import { type XmlAttributes } from '../../xml/xml-scan.ts';
|
|
5
|
+
import type { CellMetadataIndex } from '../cell-metadata/metadata.ts';
|
|
4
6
|
import { type XfStyle } from '../style/xf-style.ts';
|
|
5
7
|
import { type SharedString } from './cell-value.ts';
|
|
8
|
+
/**
|
|
9
|
+
* The worksheet-body elements both readers expand from `<x/>` into an open and a close, so each
|
|
10
|
+
* commits from its close alone. A formatted-but-empty `<c/>` finalises once there, and a self-closing
|
|
11
|
+
* `<row/>` closes its row, where the streamer yields it and both readers end its style and its cells:
|
|
12
|
+
* a producer may write `<row r="2" hidden="1"/>`, and with no close the streamer lost the row and its
|
|
13
|
+
* `hidden` flag. The text-bearing `<f/>`/`<v/>`/`<t/>` stay out, so an empty one never commits text.
|
|
14
|
+
*/
|
|
15
|
+
export declare const WORKSHEET_BODY_EMPTY_CLOSES: ReadonlySet<string>;
|
|
6
16
|
export declare class CellAccumulator {
|
|
7
17
|
#private;
|
|
8
18
|
constructor(options: {
|
|
9
|
-
readonly
|
|
19
|
+
readonly dateEpoch: DateEpoch;
|
|
20
|
+
readonly definedNames: ReadonlySet<string>;
|
|
21
|
+
readonly cellMetadata: CellMetadataIndex;
|
|
10
22
|
});
|
|
11
23
|
/** This cell's `<c r>` address (`"B3"`), or '' when it carried none. */
|
|
12
24
|
get ref(): string;
|
|
13
25
|
/** This cell's own `<c s>` style index, or -1 when it carries none. */
|
|
14
26
|
get styleIndex(): number;
|
|
15
|
-
/** This cell's 1-based column, or -1 when its address was
|
|
27
|
+
/** This cell's 1-based column, or -1 when its address was unparseable. */
|
|
16
28
|
get col(): number;
|
|
17
29
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
30
|
+
* Open a `<row>`: the cells that follow belong to it, and the next one with no `r` of its own is
|
|
31
|
+
* its first column. A row past the grid opens no row, so none of its cells is placed, not even one
|
|
32
|
+
* whose own `r` names an in-grid cell. Both readers call this where they already tell the style
|
|
33
|
+
* resolver a row opened.
|
|
20
34
|
*/
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
|
|
35
|
+
openRow(number: number, inGrid: boolean): void;
|
|
36
|
+
/** Whether an in-grid `<row>` is open. */
|
|
37
|
+
get rowOpen(): boolean;
|
|
38
|
+
/** Close the `<row>`: a `<c>` before the next one belongs to no row and is not placed. */
|
|
39
|
+
closeRow(): void;
|
|
24
40
|
/**
|
|
25
41
|
* Drive one element open, and return whether it was one of the cell machine's own. Every open
|
|
26
42
|
* resets the capture state first, which is true of both readers and of every element, not just
|
|
27
|
-
* these
|
|
43
|
+
* these. A caller gathering text of its own uses a `TextCapture`, not this machine's buffer.
|
|
28
44
|
*/
|
|
29
45
|
openElement(local: string, attrs: XmlAttributes, selfClosing: boolean): boolean;
|
|
30
46
|
/** Feed one run of character data. Ignored unless something is capturing. */
|
|
@@ -37,6 +53,5 @@ export declare class CellAccumulator {
|
|
|
37
53
|
*/
|
|
38
54
|
closeElement(local: string): 'cell' | 'claimed' | 'other';
|
|
39
55
|
finalize(sheet: Worksheet, sharedStrings: readonly SharedString[], style: XfStyle | undefined): void;
|
|
40
|
-
private cachedResult;
|
|
41
56
|
decode(sharedStrings: readonly SharedString[], style: XfStyle | undefined): CellValue;
|
|
42
57
|
}
|
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
import { encodeAddress, tryDecodeCellRef } from '../../core/address.js';
|
|
2
|
-
import { translateFormula
|
|
3
|
-
import {
|
|
1
|
+
import { encodeAddress, encodeRange, MAX_COLUMN, tryDecodeAnchoredRange, tryDecodeCellRef, } from '../../core/address.js';
|
|
2
|
+
import { translateFormula } from '../../core/formula-references.js';
|
|
3
|
+
import { unmangleFunctions } from '../../core/formula.js';
|
|
4
|
+
import { numInteger } from '../../xml/xml-attrs.js';
|
|
5
|
+
import { boolStrict } from '../../xml/xml-scan.js';
|
|
4
6
|
import { applyXfToCell } from '../style/xf-style.js';
|
|
5
7
|
import { decodeCellContent, decodeFormulaResult, } from './cell-value.js';
|
|
6
|
-
import { RunAccumulator } from './rich-runs.js';
|
|
8
|
+
import { RunAccumulator } from './read-rich-runs.js';
|
|
9
|
+
export const WORKSHEET_BODY_EMPTY_CLOSES = new Set(['c', 'row']);
|
|
7
10
|
export class CellAccumulator {
|
|
8
11
|
#ref = '';
|
|
9
12
|
#type = '';
|
|
10
13
|
#style = -1;
|
|
11
14
|
#col = -1;
|
|
12
15
|
#row = -1;
|
|
16
|
+
#cellMetadataBlock = -1;
|
|
17
|
+
#valueMetadataBlock = -1;
|
|
18
|
+
#rowOpen = false;
|
|
19
|
+
#nextCol = 1;
|
|
13
20
|
#formula = '';
|
|
14
21
|
#formulaShared = false;
|
|
15
22
|
#formulaSi = -1;
|
|
16
23
|
#sharedClone = false;
|
|
17
24
|
#dataTable = null;
|
|
25
|
+
#arrayRef = undefined;
|
|
18
26
|
#valueText = '';
|
|
19
27
|
#hasFormula = false;
|
|
20
28
|
#hasValue = false;
|
|
@@ -22,8 +30,14 @@ export class CellAccumulator {
|
|
|
22
30
|
#masters = new Map();
|
|
23
31
|
#capture = false;
|
|
24
32
|
#text = '';
|
|
33
|
+
#dateEpoch;
|
|
34
|
+
#definedNames;
|
|
35
|
+
#cellMetadata;
|
|
25
36
|
constructor(options) {
|
|
26
|
-
this.#runs = new RunAccumulator({ container: 'is', readRuns:
|
|
37
|
+
this.#runs = new RunAccumulator({ container: 'is', readRuns: true });
|
|
38
|
+
this.#dateEpoch = options.dateEpoch;
|
|
39
|
+
this.#definedNames = options.definedNames;
|
|
40
|
+
this.#cellMetadata = options.cellMetadata;
|
|
27
41
|
}
|
|
28
42
|
get ref() {
|
|
29
43
|
return this.#ref;
|
|
@@ -34,13 +48,24 @@ export class CellAccumulator {
|
|
|
34
48
|
get col() {
|
|
35
49
|
return this.#col;
|
|
36
50
|
}
|
|
51
|
+
openRow(number, inGrid) {
|
|
52
|
+
this.#rowOpen = inGrid;
|
|
53
|
+
this.#row = inGrid ? number : -1;
|
|
54
|
+
this.#nextCol = 1;
|
|
55
|
+
}
|
|
56
|
+
get rowOpen() {
|
|
57
|
+
return this.#rowOpen;
|
|
58
|
+
}
|
|
59
|
+
closeRow() {
|
|
60
|
+
this.#rowOpen = false;
|
|
61
|
+
this.#row = -1;
|
|
62
|
+
}
|
|
37
63
|
#beginCell(attrs) {
|
|
38
64
|
this.#type = attrs.t ?? '';
|
|
39
65
|
this.#style = numInteger(attrs.s, 0) ?? -1;
|
|
40
|
-
|
|
41
|
-
this.#
|
|
42
|
-
this.#
|
|
43
|
-
this.#row = decoded?.row ?? -1;
|
|
66
|
+
this.#cellMetadataBlock = numInteger(attrs.cm, 1) ?? -1;
|
|
67
|
+
this.#valueMetadataBlock = numInteger(attrs.vm, 1) ?? -1;
|
|
68
|
+
this.#placeCell(attrs.r);
|
|
44
69
|
this.#formula = '';
|
|
45
70
|
this.#valueText = '';
|
|
46
71
|
this.#runs.beginContainer();
|
|
@@ -50,6 +75,25 @@ export class CellAccumulator {
|
|
|
50
75
|
this.#formulaSi = -1;
|
|
51
76
|
this.#sharedClone = false;
|
|
52
77
|
this.#dataTable = null;
|
|
78
|
+
this.#arrayRef = undefined;
|
|
79
|
+
}
|
|
80
|
+
#placeCell(ref) {
|
|
81
|
+
const decoded = this.#rowOpen && ref !== undefined ? tryDecodeCellRef(ref) : undefined;
|
|
82
|
+
if (decoded !== undefined) {
|
|
83
|
+
this.#ref = ref ?? '';
|
|
84
|
+
this.#col = decoded.col;
|
|
85
|
+
this.#row = decoded.row;
|
|
86
|
+
}
|
|
87
|
+
else if (ref === undefined && this.#rowOpen && this.#nextCol <= MAX_COLUMN) {
|
|
88
|
+
this.#col = this.#nextCol;
|
|
89
|
+
this.#ref = encodeAddress(this.#col, this.#row);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
this.#ref = '';
|
|
93
|
+
this.#col = -1;
|
|
94
|
+
}
|
|
95
|
+
if (this.#col > 0)
|
|
96
|
+
this.#nextCol = this.#col + 1;
|
|
53
97
|
}
|
|
54
98
|
#beginFormula(attrs, selfClosing) {
|
|
55
99
|
this.#formulaShared = attrs.t === 'shared';
|
|
@@ -63,8 +107,15 @@ export class CellAccumulator {
|
|
|
63
107
|
dtr: attrs.dtr,
|
|
64
108
|
r1: attrs.r1,
|
|
65
109
|
r2: attrs.r2,
|
|
110
|
+
del1: attrs.del1,
|
|
111
|
+
del2: attrs.del2,
|
|
66
112
|
};
|
|
67
113
|
}
|
|
114
|
+
if (attrs.t === 'array' && attrs.ref !== undefined && this.#col > 0) {
|
|
115
|
+
const range = tryDecodeAnchoredRange(attrs.ref, this.#col, this.#row);
|
|
116
|
+
if (range !== undefined)
|
|
117
|
+
this.#arrayRef = encodeRange(range);
|
|
118
|
+
}
|
|
68
119
|
}
|
|
69
120
|
#setFormula(text) {
|
|
70
121
|
this.#formula = text;
|
|
@@ -74,12 +125,6 @@ export class CellAccumulator {
|
|
|
74
125
|
this.#valueText = text;
|
|
75
126
|
this.#hasValue = true;
|
|
76
127
|
}
|
|
77
|
-
get capturedText() {
|
|
78
|
-
return this.#text;
|
|
79
|
-
}
|
|
80
|
-
capture() {
|
|
81
|
-
this.#capture = true;
|
|
82
|
-
}
|
|
83
128
|
openElement(local, attrs, selfClosing) {
|
|
84
129
|
this.#text = '';
|
|
85
130
|
this.#capture = false;
|
|
@@ -95,6 +140,8 @@ export class CellAccumulator {
|
|
|
95
140
|
return true;
|
|
96
141
|
case 'v':
|
|
97
142
|
this.#capture = !selfClosing;
|
|
143
|
+
if (selfClosing)
|
|
144
|
+
this.#setValue('');
|
|
98
145
|
return true;
|
|
99
146
|
default:
|
|
100
147
|
return false;
|
|
@@ -143,7 +190,9 @@ export class CellAccumulator {
|
|
|
143
190
|
...(boolStrict(this.#dataTable.dtr) ? { dataTableRow: true } : {}),
|
|
144
191
|
...(this.#dataTable.r1 !== undefined ? { r1: this.#dataTable.r1 } : {}),
|
|
145
192
|
...(this.#dataTable.r2 !== undefined ? { r2: this.#dataTable.r2 } : {}),
|
|
146
|
-
...this.
|
|
193
|
+
...(boolStrict(this.#dataTable.del1) ? { r1Deleted: true } : {}),
|
|
194
|
+
...(boolStrict(this.#dataTable.del2) ? { r2Deleted: true } : {}),
|
|
195
|
+
...this.#cachedResult(style),
|
|
147
196
|
};
|
|
148
197
|
}
|
|
149
198
|
if (this.#hasFormula && this.#formulaShared && this.#formulaSi >= 0) {
|
|
@@ -155,17 +204,17 @@ export class CellAccumulator {
|
|
|
155
204
|
const translated = translateFormula(master.formula, this.#col - master.col, this.#row - master.row);
|
|
156
205
|
return {
|
|
157
206
|
sharedFormula: encodeAddress(master.col, master.row),
|
|
158
|
-
formula: unmangleFunctions(translated),
|
|
159
|
-
...this
|
|
207
|
+
formula: unmangleFunctions(translated, this.#definedNames),
|
|
208
|
+
...this.#cachedResult(style),
|
|
160
209
|
};
|
|
161
210
|
}
|
|
162
211
|
}
|
|
163
212
|
return this.decode(sharedStrings, style);
|
|
164
213
|
}
|
|
165
|
-
cachedResult(style) {
|
|
214
|
+
#cachedResult(style) {
|
|
166
215
|
if (!this.#hasValue)
|
|
167
216
|
return {};
|
|
168
|
-
const result = decodeFormulaResult(this.#type, this.#valueText, style?.numFmt);
|
|
217
|
+
const result = decodeFormulaResult(this.#type, this.#valueText, style?.numFmt, this.#dateEpoch, this.#cellMetadata.valueErrors.get(this.#valueMetadataBlock));
|
|
169
218
|
return result === undefined ? {} : { result };
|
|
170
219
|
}
|
|
171
220
|
decode(sharedStrings, style) {
|
|
@@ -173,11 +222,15 @@ export class CellAccumulator {
|
|
|
173
222
|
type: this.#type,
|
|
174
223
|
hasFormula: this.#hasFormula,
|
|
175
224
|
formula: this.#formula,
|
|
225
|
+
arrayRef: this.#arrayRef,
|
|
226
|
+
dynamicArray: this.#cellMetadata.dynamicArrayCells.has(this.#cellMetadataBlock),
|
|
227
|
+
valueError: this.#cellMetadata.valueErrors.get(this.#valueMetadataBlock),
|
|
176
228
|
hasValue: this.#hasValue,
|
|
177
229
|
valueText: this.#valueText,
|
|
230
|
+
hasInlineString: this.#runs.opened,
|
|
178
231
|
inlineText: this.#runs.plainText,
|
|
179
232
|
richTextRuns: this.#runs.runs,
|
|
180
233
|
};
|
|
181
|
-
return decodeCellContent(raw, sharedStrings, style?.numFmt);
|
|
234
|
+
return decodeCellContent(raw, sharedStrings, style?.numFmt, this.#dateEpoch, this.#definedNames);
|
|
182
235
|
}
|
|
183
236
|
}
|