@shbernal/ts-xlsx 2.1.0 → 3.1.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 +4 -1
- package/dist/bytes.d.ts +7 -0
- package/dist/bytes.js +22 -0
- package/dist/core/address.d.ts +60 -2
- package/dist/core/address.js +40 -24
- package/dist/core/autofilter.d.ts +5 -4
- package/dist/core/autofilter.js +34 -35
- package/dist/core/axis-handle.d.ts +10 -0
- package/dist/core/axis-handle.js +17 -0
- package/dist/core/cell.d.ts +25 -0
- package/dist/core/cell.js +9 -3
- package/dist/core/clone.d.ts +29 -0
- package/dist/core/clone.js +24 -0
- package/dist/core/color-resolution.js +2 -4
- package/dist/core/column.d.ts +5 -1
- package/dist/core/column.js +34 -35
- package/dist/core/comment-thread.js +2 -1
- package/dist/core/conditional-formatting-overlay.d.ts +2 -1
- package/dist/core/conditional-formatting-overlay.js +2 -2
- package/dist/core/conditional-formatting.d.ts +14 -6
- package/dist/core/conditional-formatting.js +45 -43
- package/dist/core/containers.d.ts +12 -0
- package/dist/core/containers.js +5 -0
- package/dist/core/data-validation-overlay.d.ts +2 -1
- package/dist/core/data-validation-overlay.js +4 -4
- package/dist/core/data-validation.d.ts +9 -3
- package/dist/core/data-validation.js +21 -18
- package/dist/core/date-format.d.ts +20 -0
- package/dist/core/date-format.js +160 -0
- package/dist/core/date.d.ts +43 -8
- package/dist/core/date.js +18 -2
- package/dist/core/formula.d.ts +26 -0
- package/dist/core/formula.js +20 -4
- package/dist/core/grid-edits.d.ts +2 -3
- package/dist/core/grid-edits.js +69 -70
- package/dist/core/grid-shift.d.ts +58 -9
- package/dist/core/grid-shift.js +26 -4
- package/dist/core/image.d.ts +14 -10
- package/dist/core/image.js +9 -9
- package/dist/core/internal.d.ts +8 -2
- package/dist/core/limits.d.ts +23 -0
- package/dist/core/limits.js +4 -0
- package/dist/core/merge-index.d.ts +31 -0
- package/dist/core/merge-index.js +60 -0
- package/dist/core/merge.d.ts +5 -14
- package/dist/core/merge.js +18 -27
- package/dist/core/page-setup.d.ts +72 -2
- package/dist/core/page-setup.js +34 -8
- package/dist/core/pivot-table.d.ts +1 -1
- package/dist/core/pivot-table.js +67 -53
- package/dist/core/protection.js +2 -11
- package/dist/core/range.js +34 -30
- package/dist/core/row-input.js +2 -2
- package/dist/core/row.d.ts +5 -1
- package/dist/core/row.js +22 -23
- package/dist/core/style.d.ts +134 -75
- package/dist/core/style.js +112 -53
- package/dist/core/table-style.d.ts +1 -1
- package/dist/core/table-style.js +4 -4
- package/dist/core/table.d.ts +28 -10
- package/dist/core/table.js +54 -39
- package/dist/core/theme.js +6 -5
- package/dist/core/used-extent.d.ts +44 -0
- package/dist/core/used-extent.js +102 -0
- package/dist/core/value.d.ts +9 -0
- package/dist/core/value.js +36 -34
- package/dist/core/workbook-media.d.ts +34 -0
- package/dist/core/workbook-media.js +44 -0
- package/dist/core/workbook-styles.d.ts +67 -1
- package/dist/core/workbook-vba.js +3 -2
- package/dist/core/workbook.d.ts +23 -2
- package/dist/core/workbook.js +24 -40
- package/dist/core/worksheet-comments.d.ts +2 -1
- package/dist/core/worksheet-comments.js +20 -13
- package/dist/core/worksheet-merges.d.ts +44 -0
- package/dist/core/worksheet-merges.js +59 -0
- package/dist/core/worksheet-model.d.ts +9 -1
- package/dist/core/worksheet-model.js +24 -9
- package/dist/core/worksheet.d.ts +72 -12
- package/dist/core/worksheet.js +68 -70
- package/dist/customui/ribbon.js +6 -7
- package/dist/entries/core.d.ts +18 -13
- package/dist/entries/core.js +12 -6
- 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/csv/delimiter.d.ts +9 -0
- package/dist/io/csv/delimiter.js +6 -0
- package/dist/io/csv/read.js +11 -4
- package/dist/io/csv/write.d.ts +9 -2
- package/dist/io/csv/write.js +9 -38
- package/dist/io/opc/inflate.js +15 -1
- 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 +10 -0
- package/dist/io/opc/part-paths.js +16 -1
- package/dist/io/opc/read-opc.d.ts +69 -10
- package/dist/io/opc/read-opc.js +49 -55
- package/dist/io/opc/read-options.d.ts +5 -1
- package/dist/io/opc/rels.d.ts +1 -6
- package/dist/io/opc/rels.js +1 -4
- package/dist/io/opc/sniff-format.d.ts +3 -3
- package/dist/io/opc/sniff-format.js +2 -2
- package/dist/io/style/xf-style.d.ts +48 -2
- package/dist/io/style/xf-style.js +14 -0
- package/dist/io/xlsb/formula.d.ts +2 -2
- package/dist/io/xlsb/formula.js +49 -34
- 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 +385 -596
- package/dist/io/xlsb/read-styles.js +50 -83
- package/dist/io/xlsb/read-worksheet.d.ts +20 -1
- package/dist/io/xlsb/read-worksheet.js +73 -89
- package/dist/io/xlsb/read.d.ts +6 -3
- package/dist/io/xlsb/read.js +47 -29
- 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 +1 -5
- package/dist/io/xlsb/record-types.js +1 -5
- package/dist/io/xlsx/cell-accumulator.d.ts +9 -2
- package/dist/io/xlsx/cell-accumulator.js +32 -9
- package/dist/io/xlsx/cell-style-resolution.d.ts +25 -0
- package/dist/io/xlsx/cell-style-resolution.js +29 -0
- package/dist/io/xlsx/cell-value.d.ts +5 -3
- package/dist/io/xlsx/cell-value.js +13 -15
- package/dist/io/xlsx/color-xml.js +3 -2
- package/dist/io/xlsx/column-budget.d.ts +26 -0
- package/dist/io/xlsx/column-budget.js +22 -0
- package/dist/io/xlsx/comments.d.ts +6 -2
- package/dist/io/xlsx/comments.js +36 -31
- package/dist/io/xlsx/conditional-formatting.d.ts +9 -5
- package/dist/io/xlsx/conditional-formatting.js +51 -46
- package/dist/io/xlsx/data-validation.d.ts +9 -7
- package/dist/io/xlsx/data-validation.js +38 -35
- package/dist/io/xlsx/edit-vba.d.ts +7 -2
- package/dist/io/xlsx/edit-vba.js +15 -29
- 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 +41 -7
- package/dist/io/xlsx/hyperlinks.js +40 -28
- package/dist/io/xlsx/images.js +24 -25
- package/dist/io/xlsx/namespaces.d.ts +16 -0
- package/dist/io/xlsx/namespaces.js +7 -0
- package/dist/io/xlsx/package-plan.d.ts +23 -3
- package/dist/io/xlsx/package-plan.js +66 -25
- package/dist/io/xlsx/part-names.d.ts +41 -0
- package/dist/io/xlsx/part-names.js +46 -0
- package/dist/io/xlsx/pivot.js +8 -7
- package/dist/io/xlsx/read-parts.d.ts +59 -0
- package/dist/io/xlsx/read-parts.js +252 -0
- package/dist/io/xlsx/read-pivot.js +3 -1
- package/dist/io/xlsx/read-repair.d.ts +26 -0
- package/dist/io/xlsx/read-repair.js +39 -0
- package/dist/io/xlsx/{rich-runs.d.ts → read-rich-runs.d.ts} +1 -1
- package/dist/io/xlsx/{rich-runs.js → read-rich-runs.js} +7 -3
- package/dist/io/xlsx/read-rows.d.ts +18 -5
- package/dist/io/xlsx/read-rows.js +50 -37
- package/dist/io/xlsx/read-shared-strings.js +5 -3
- package/dist/io/xlsx/read-styles.d.ts +1 -6
- package/dist/io/xlsx/read-styles.js +65 -109
- package/dist/io/xlsx/read-workbook-xml.d.ts +36 -0
- package/dist/io/xlsx/read-workbook-xml.js +170 -0
- package/dist/io/xlsx/read-worksheet.d.ts +11 -1
- package/dist/io/xlsx/read-worksheet.js +51 -193
- package/dist/io/xlsx/read.d.ts +5 -13
- package/dist/io/xlsx/read.js +111 -436
- package/dist/io/xlsx/rich-text.js +1 -1
- package/dist/io/xlsx/row-position.d.ts +18 -0
- package/dist/io/xlsx/row-position.js +11 -0
- package/dist/io/xlsx/row-xml.d.ts +128 -0
- package/dist/io/xlsx/row-xml.js +203 -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 +166 -37
- package/dist/io/xlsx/style-elements.d.ts +43 -0
- package/dist/io/xlsx/style-elements.js +156 -0
- package/dist/io/xlsx/styles.d.ts +12 -3
- package/dist/io/xlsx/styles.js +5 -204
- package/dist/io/xlsx/tables.js +11 -14
- package/dist/io/xlsx/theme-xml.d.ts +26 -4
- package/dist/io/xlsx/theme-xml.js +107 -69
- package/dist/io/xlsx/threaded-comments.d.ts +8 -10
- package/dist/io/xlsx/threaded-comments.js +3 -1
- package/dist/io/xlsx/workbook-xml.d.ts +54 -4
- package/dist/io/xlsx/workbook-xml.js +84 -57
- package/dist/io/xlsx/worksheet-xml.d.ts +23 -70
- package/dist/io/xlsx/worksheet-xml.js +59 -242
- package/dist/io/xlsx/write-stream.d.ts +71 -16
- package/dist/io/xlsx/write-stream.js +79 -41
- package/dist/io/xlsx/write.d.ts +6 -2
- package/dist/io/xlsx/write.js +217 -153
- package/dist/rel-type.d.ts +16 -0
- package/dist/rel-type.js +6 -0
- package/dist/token-set.d.ts +28 -0
- package/dist/token-set.js +7 -0
- package/dist/vba/bytes.d.ts +14 -5
- package/dist/vba/bytes.js +16 -6
- package/dist/vba/cfb-format.d.ts +32 -0
- package/dist/vba/cfb-format.js +13 -0
- package/dist/vba/cfb-writer.d.ts +9 -0
- package/dist/vba/cfb-writer.js +28 -25
- package/dist/vba/cfb.d.ts +13 -1
- package/dist/vba/cfb.js +73 -57
- package/dist/vba/codepage.js +2 -1
- package/dist/vba/errors.d.ts +7 -0
- package/dist/vba/ms-ovba.js +79 -23
- package/dist/vba/project-editor.js +35 -40
- package/dist/vba/project.d.ts +11 -1
- package/dist/vba/project.js +40 -21
- package/dist/vba/vba-encoding.js +5 -6
- 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 +128 -81
- package/dist/xml/xml-read.js +161 -178
- package/dist/xml/xml-scan.d.ts +78 -0
- package/dist/xml/xml-scan.js +180 -0
- package/dist/xml/xml.d.ts +29 -28
- package/dist/xml/xml.js +24 -24
- package/package.json +13 -9
package/dist/io/xlsx/write.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { strToU8, zip, zipSync } from 'fflate';
|
|
2
|
-
import { AuthoringError } from '../../errors.js';
|
|
3
|
-
import {
|
|
2
|
+
import { AuthoringError, InternalError, quoted } from '../../errors.js';
|
|
3
|
+
import { isRelType } from '../../rel-type.js';
|
|
4
|
+
import { relativePartPath, relsPathFor, THEME_PART_PATH } from '../opc/part-paths.js';
|
|
4
5
|
import { relsPartXml } from '../opc/rels.js';
|
|
5
6
|
import { FIXED_ENTRY_MTIME } from '../opc/zip-mtime.js';
|
|
6
7
|
import { collectComments, commentsXml, vmlDrawingXml } from './comments.js';
|
|
7
|
-
import { collectHyperlinks, planHyperlinks } from './hyperlinks.js';
|
|
8
|
+
import { collectHyperlinks, liveCells, planHyperlinks } from './hyperlinks.js';
|
|
8
9
|
import { drawingRelsXml, drawingXml } from './images.js';
|
|
9
|
-
import { planMedia, planPreservedParts,
|
|
10
|
+
import { planMedia, planPreservedParts, RelIdAllocator, } from './package-plan.js';
|
|
11
|
+
import { APP_PROPS_PART, commentsPart, CORE_PROPS_PART, drawingPart, mediaPart, PERSONS_PART, pivotCacheDefinitionPart, pivotCacheRecordsPart, pivotTablePart, printerSettingsPart, SHARED_STRINGS_PART, STYLES_PART, tablePart, threadedCommentsPart, vmlDrawingPart, WORKBOOK_PART, worksheetPart, } from './part-names.js';
|
|
10
12
|
import { pivotCacheDefinitionXml, pivotCacheRecordsXml, pivotTableXml } from './pivot.js';
|
|
11
13
|
import { REL } from './relationships.js';
|
|
12
14
|
import { SharedStringTable } from './shared-strings.js';
|
|
@@ -14,9 +16,8 @@ import { StyleRegistry } from './styles.js';
|
|
|
14
16
|
import { tableXml } from './tables.js';
|
|
15
17
|
import { applyThemeOverrides, DEFAULT_THEME_XML } from './theme-xml.js';
|
|
16
18
|
import { personsXml, threadedCommentsXml } from './threaded-comments.js';
|
|
17
|
-
import { appPropsXml, contentTypesXml, corePropsXml,
|
|
18
|
-
import { worksheetRelsXml, worksheetXml
|
|
19
|
-
export { buildColumnDefaults, Extent, renderRow, } from './worksheet-xml.js';
|
|
19
|
+
import { appPropsXml, contentTypesXml, corePropsXml, rootRelsXml, workbookRelsXml, workbookXml, } from './workbook-xml.js';
|
|
20
|
+
import { worksheetRelsXml, worksheetXml } from './worksheet-xml.js';
|
|
20
21
|
export function writeXlsx(workbook, options = {}) {
|
|
21
22
|
return zipSync(buildPackageParts(workbook, options), { level: 6, mtime: FIXED_ENTRY_MTIME });
|
|
22
23
|
}
|
|
@@ -47,12 +48,78 @@ export function createStyleRegistry(workbook) {
|
|
|
47
48
|
styles.addTableStyle(style);
|
|
48
49
|
return styles;
|
|
49
50
|
}
|
|
51
|
+
function planSheet(context) {
|
|
52
|
+
const { sheet, index, media, preserved, numbering, flushed } = context;
|
|
53
|
+
const rels = new RelIdAllocator();
|
|
54
|
+
const tables = sheet.tables.map((table) => ({
|
|
55
|
+
table,
|
|
56
|
+
number: ++numbering.table,
|
|
57
|
+
relId: rels.next(),
|
|
58
|
+
}));
|
|
59
|
+
let drawing = null;
|
|
60
|
+
if (sheet.images.length > 0) {
|
|
61
|
+
const images = sheet.images.map((image, j) => {
|
|
62
|
+
const { number, image: registered } = media.resolve(image.imageId);
|
|
63
|
+
return {
|
|
64
|
+
anchor: image.anchor,
|
|
65
|
+
embedId: `rId${j + 1}`,
|
|
66
|
+
mediaNumber: number,
|
|
67
|
+
extension: registered.extension,
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
drawing = { number: ++numbering.drawing, relId: rels.next(), images };
|
|
71
|
+
}
|
|
72
|
+
const threads = sheet.commentThreads.filter((thread) => thread.comments.length > 0);
|
|
73
|
+
const sheetComments = collectComments(liveCells(sheet), threads, flushed?.notes ?? []);
|
|
74
|
+
const comments = sheetComments.length === 0
|
|
75
|
+
? null
|
|
76
|
+
: {
|
|
77
|
+
number: index + 1,
|
|
78
|
+
comments: sheetComments,
|
|
79
|
+
vmlRelId: rels.next(),
|
|
80
|
+
commentsRelId: rels.next(),
|
|
81
|
+
};
|
|
82
|
+
const threadedComments = threads.length === 0 ? null : { number: index + 1, threads, relId: rels.next() };
|
|
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);
|
|
86
|
+
let background = null;
|
|
87
|
+
if (sheet.backgroundImageId !== undefined) {
|
|
88
|
+
const { number, image } = media.resolve(sheet.backgroundImageId);
|
|
89
|
+
background = { relId: rels.next(), mediaNumber: number, extension: image.extension };
|
|
90
|
+
}
|
|
91
|
+
const preservedRefs = (preserved.perSheet[index] ?? []).map((reference) => ({ ...reference, relId: rels.next() }));
|
|
92
|
+
const pivots = sheet.pivotTables.map((table) => {
|
|
93
|
+
const number = ++numbering.pivot;
|
|
94
|
+
return { number, cacheId: String(number), table, sheetRelId: rels.next(), workbookRelId: '' };
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
tables,
|
|
98
|
+
drawing,
|
|
99
|
+
comments,
|
|
100
|
+
threadedComments,
|
|
101
|
+
printerSettings,
|
|
102
|
+
hyperlinks,
|
|
103
|
+
background,
|
|
104
|
+
preservedRefs,
|
|
105
|
+
pivots,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function numbersOf(plans, pick) {
|
|
109
|
+
const numbers = [];
|
|
110
|
+
for (const plan of plans) {
|
|
111
|
+
const part = pick(plan);
|
|
112
|
+
if (part !== null)
|
|
113
|
+
numbers.push(part.number);
|
|
114
|
+
}
|
|
115
|
+
return numbers;
|
|
116
|
+
}
|
|
50
117
|
function resolveSheetReferences(plan) {
|
|
51
118
|
const refs = plan.preservedRefs;
|
|
52
119
|
const preservedDrawingRelId = refs.find((ref) => ref.element === 'drawing')?.relId ?? null;
|
|
53
120
|
const legacyDrawingHFRelId = refs.find((ref) => ref.element === 'legacyDrawingHF')?.relId ?? null;
|
|
54
121
|
const slicerRelIds = refs
|
|
55
|
-
.filter((ref) => ref.relType
|
|
122
|
+
.filter((ref) => isRelType(ref.relType, 'slicer'))
|
|
56
123
|
.map((ref) => ref.relId);
|
|
57
124
|
return {
|
|
58
125
|
drawingRelId: plan.drawing?.relId ?? preservedDrawingRelId,
|
|
@@ -63,153 +130,153 @@ function resolveSheetReferences(plan) {
|
|
|
63
130
|
slicerRelIds,
|
|
64
131
|
};
|
|
65
132
|
}
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
133
|
+
function assignWorkbookRelIds(context) {
|
|
134
|
+
const { sheetCount, hasSharedStrings, hasPersons, preservedWorkbook, pivots } = context;
|
|
135
|
+
const ids = new RelIdAllocator();
|
|
136
|
+
const sheetRelIds = Array.from({ length: sheetCount }, () => ids.next());
|
|
137
|
+
const stylesRelId = ids.next();
|
|
138
|
+
const themeRelId = ids.next();
|
|
139
|
+
const sharedStringsRelId = hasSharedStrings ? ids.next() : null;
|
|
140
|
+
const personsRelId = hasPersons ? ids.next() : null;
|
|
141
|
+
const preservedWorkbookRels = preservedWorkbook.map((ref) => ({ ...ref, relId: ids.next() }));
|
|
142
|
+
for (const pivot of pivots)
|
|
143
|
+
pivot.workbookRelId = ids.next();
|
|
144
|
+
return {
|
|
145
|
+
sheetRelIds,
|
|
146
|
+
stylesRelId,
|
|
147
|
+
themeRelId,
|
|
148
|
+
sharedStringsRelId,
|
|
149
|
+
personsRelId,
|
|
150
|
+
preservedWorkbookRels,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function planPackage(workbook, sheets, flushed) {
|
|
72
154
|
const media = planMedia(workbook, sheets);
|
|
73
155
|
const generatedDrawingCount = sheets.filter((sheet) => sheet.images.length > 0).length;
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const comments = sheetComments.length === 0
|
|
101
|
-
? null
|
|
102
|
-
: {
|
|
103
|
-
number: i + 1,
|
|
104
|
-
comments: sheetComments,
|
|
105
|
-
vmlRelId: rels.next(),
|
|
106
|
-
commentsRelId: rels.next(),
|
|
107
|
-
};
|
|
108
|
-
const threadedComments = threads.length === 0 ? null : { number: i + 1, threads, relId: rels.next() };
|
|
109
|
-
const printerData = sheet.pageSetup.printerSettings;
|
|
110
|
-
const printerSettings = printerData === undefined ? null : { number: i + 1, data: printerData, relId: rels.next() };
|
|
111
|
-
const hyperlinks = planHyperlinks(collectHyperlinks(sheet), rels);
|
|
112
|
-
let background = null;
|
|
113
|
-
if (sheet.backgroundImageId !== undefined) {
|
|
114
|
-
const registered = workbook.getImage(sheet.backgroundImageId);
|
|
115
|
-
if (registered === undefined) {
|
|
116
|
-
throw new AuthoringError(`sheet "${sheet.name}" sets background image id ${sheet.backgroundImageId}, which is not registered on the workbook`);
|
|
117
|
-
}
|
|
118
|
-
background = {
|
|
119
|
-
relId: rels.next(),
|
|
120
|
-
mediaNumber: media.numberById.get(sheet.backgroundImageId),
|
|
121
|
-
extension: registered.extension,
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
const preservedRefs = (preserved.perSheet[i] ?? []).map((reference) => ({ ...reference, relId: rels.next() }));
|
|
125
|
-
const pivots = sheet.pivotTables.map((table) => {
|
|
126
|
-
const number = ++pivotNumber;
|
|
127
|
-
return { number, cacheId: String(number), table, sheetRelId: rels.next(), workbookRelId: '' };
|
|
156
|
+
const generatedPivotCount = sheets.reduce((total, sheet) => total + sheet.pivotTables.length, 0);
|
|
157
|
+
const preserved = planPreservedParts(workbook, generatedDrawingCount, media.parts.length, generatedPivotCount);
|
|
158
|
+
const numbering = { table: 0, drawing: 0, pivot: 0 };
|
|
159
|
+
const perSheet = sheets.map((sheet, index) => planSheet({ sheet, index, media, preserved, numbering, flushed: flushed?.get(sheet) }));
|
|
160
|
+
return {
|
|
161
|
+
media,
|
|
162
|
+
preserved,
|
|
163
|
+
perSheet,
|
|
164
|
+
allTables: perSheet.flatMap((plan) => plan.tables),
|
|
165
|
+
allPivots: perSheet.flatMap((plan) => plan.pivots),
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function serialiseSheets(context) {
|
|
169
|
+
const { workbook, sheets, plan, styles, sharedStrings, flushed } = context;
|
|
170
|
+
return sheets.map((sheet, i) => {
|
|
171
|
+
const sheetPlan = plan.perSheet[i];
|
|
172
|
+
return worksheetXml({
|
|
173
|
+
sheet,
|
|
174
|
+
tables: sheetPlan.tables,
|
|
175
|
+
styles,
|
|
176
|
+
references: resolveSheetReferences(sheetPlan),
|
|
177
|
+
hyperlinks: sheetPlan.hyperlinks,
|
|
178
|
+
sharedStrings,
|
|
179
|
+
dateEpoch: workbook.dateEpoch,
|
|
180
|
+
active: i === workbook.activeTabIndex,
|
|
181
|
+
flushed: flushed?.get(sheet),
|
|
128
182
|
});
|
|
129
|
-
return {
|
|
130
|
-
tables,
|
|
131
|
-
drawing,
|
|
132
|
-
comments,
|
|
133
|
-
threadedComments,
|
|
134
|
-
printerSettings,
|
|
135
|
-
hyperlinks,
|
|
136
|
-
background,
|
|
137
|
-
preservedRefs,
|
|
138
|
-
pivots,
|
|
139
|
-
};
|
|
140
|
-
});
|
|
141
|
-
const allTables = perSheet.flatMap((plan) => plan.tables);
|
|
142
|
-
const allPivots = perSheet.flatMap((plan) => plan.pivots);
|
|
143
|
-
const styles = options.styles ?? createStyleRegistry(workbook);
|
|
144
|
-
const sheetXml = sheets.map((sheet, i) => {
|
|
145
|
-
const plan = perSheet[i];
|
|
146
|
-
return worksheetXml(sheet, plan.tables, styles, resolveSheetReferences(plan), plan.hyperlinks, sharedStrings, i === workbook.activeTabIndex, options.flushed?.get(sheet));
|
|
147
183
|
});
|
|
184
|
+
}
|
|
185
|
+
function emitPackageParts(context) {
|
|
186
|
+
const { workbook, sheets, plan, styles, sharedStrings, sheetXml } = context;
|
|
187
|
+
const { media, preserved, perSheet, allTables, allPivots } = plan;
|
|
148
188
|
const hasSharedStrings = sharedStrings !== null && !sharedStrings.isEmpty;
|
|
149
|
-
const commentNumbers = perSheet
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const drawingNumbers = perSheet
|
|
154
|
-
.map((plan) => plan.drawing)
|
|
155
|
-
.filter((d) => d !== null)
|
|
156
|
-
.map((d) => d.number);
|
|
157
|
-
const printerSettingsNumbers = perSheet
|
|
158
|
-
.map((plan) => plan.printerSettings)
|
|
159
|
-
.filter((p) => p !== null)
|
|
160
|
-
.map((p) => p.number);
|
|
161
|
-
const threadedCommentNumbers = perSheet
|
|
162
|
-
.map((plan) => plan.threadedComments)
|
|
163
|
-
.filter((t) => t !== null)
|
|
164
|
-
.map((t) => t.number);
|
|
189
|
+
const commentNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.comments);
|
|
190
|
+
const drawingNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.drawing);
|
|
191
|
+
const printerSettingsNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.printerSettings);
|
|
192
|
+
const threadedCommentNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.threadedComments);
|
|
165
193
|
const persons = threadedCommentNumbers.length === 0 ? [] : workbook.persons;
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}));
|
|
173
|
-
const pivotWorkbookRelBase = workbookRelBase + preserved.workbook.length;
|
|
174
|
-
allPivots.forEach((pivot, i) => {
|
|
175
|
-
pivot.workbookRelId = `rId${pivotWorkbookRelBase + 1 + i}`;
|
|
194
|
+
const workbookRels = assignWorkbookRelIds({
|
|
195
|
+
sheetCount: sheets.length,
|
|
196
|
+
hasSharedStrings,
|
|
197
|
+
hasPersons: persons.length > 0,
|
|
198
|
+
preservedWorkbook: preserved.workbook,
|
|
199
|
+
pivots: allPivots,
|
|
176
200
|
});
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
201
|
+
const { preservedWorkbookRels } = workbookRels;
|
|
202
|
+
const files = new PackageFiles();
|
|
203
|
+
files.add('[Content_Types].xml', strToU8(contentTypesXml({
|
|
204
|
+
sheetCount: sheets.length,
|
|
205
|
+
tables: allTables,
|
|
206
|
+
commentNumbers,
|
|
207
|
+
drawingNumbers,
|
|
208
|
+
printerSettingsNumbers,
|
|
209
|
+
mediaExtensions: media.extensions,
|
|
210
|
+
hasSharedStrings,
|
|
211
|
+
preservedParts: preserved.parts,
|
|
212
|
+
pivots: allPivots,
|
|
213
|
+
preservedWorkbookRefs: preservedWorkbookRels,
|
|
214
|
+
threadedCommentNumbers,
|
|
215
|
+
hasPersons: persons.length > 0,
|
|
216
|
+
})));
|
|
217
|
+
files.add('_rels/.rels', strToU8(rootRelsXml(preserved.root)));
|
|
218
|
+
files.add(CORE_PROPS_PART, strToU8(corePropsXml(workbook.properties)));
|
|
219
|
+
files.add(APP_PROPS_PART, strToU8(appPropsXml(workbook.properties)));
|
|
220
|
+
files.add(WORKBOOK_PART, strToU8(workbookXml(workbook, workbookRels, allPivots)));
|
|
221
|
+
files.add(relsPathFor(WORKBOOK_PART), strToU8(workbookRelsXml(workbookRels, allPivots)));
|
|
222
|
+
files.add(STYLES_PART, strToU8(styles.toXml()));
|
|
186
223
|
if (!preserved.themeEmitted) {
|
|
187
224
|
const overrides = workbook.themeOverrides;
|
|
188
|
-
files
|
|
225
|
+
files.add(THEME_PART_PATH, strToU8(overrides === undefined
|
|
189
226
|
? DEFAULT_THEME_XML
|
|
190
|
-
: applyThemeOverrides(DEFAULT_THEME_XML, overrides));
|
|
227
|
+
: applyThemeOverrides(DEFAULT_THEME_XML, overrides)));
|
|
191
228
|
}
|
|
192
229
|
if (hasSharedStrings) {
|
|
193
|
-
files
|
|
230
|
+
files.add(SHARED_STRINGS_PART, strToU8(sharedStrings.toXml()));
|
|
194
231
|
}
|
|
195
232
|
if (persons.length > 0)
|
|
196
|
-
files
|
|
233
|
+
files.add(PERSONS_PART, strToU8(personsXml(persons)));
|
|
197
234
|
for (const part of media.parts) {
|
|
198
|
-
files
|
|
235
|
+
files.add(mediaPart(part.number, part.extension), part.data);
|
|
199
236
|
}
|
|
200
237
|
emitSheetParts(files, perSheet, sheetXml);
|
|
201
238
|
for (const { table, number } of allTables) {
|
|
202
|
-
files
|
|
239
|
+
files.add(tablePart(number), strToU8(tableXml(table, number)));
|
|
203
240
|
}
|
|
204
241
|
emitPivotParts(files, allPivots);
|
|
205
242
|
emitPreservedParts(files, preserved.parts);
|
|
206
|
-
return files;
|
|
243
|
+
return files.toRecord();
|
|
244
|
+
}
|
|
245
|
+
export function buildPackageParts(workbook, options = {}) {
|
|
246
|
+
const sheets = workbook.worksheets;
|
|
247
|
+
if (sheets.length === 0) {
|
|
248
|
+
throw new AuthoringError('cannot write a workbook with no worksheets: a zero-sheet package is corrupt to Excel');
|
|
249
|
+
}
|
|
250
|
+
const sharedStrings = options.useSharedStrings ? new SharedStringTable() : null;
|
|
251
|
+
const styles = options.styles ?? createStyleRegistry(workbook);
|
|
252
|
+
const plan = planPackage(workbook, sheets, options.flushed);
|
|
253
|
+
const sheetXml = serialiseSheets({
|
|
254
|
+
workbook,
|
|
255
|
+
sheets,
|
|
256
|
+
plan,
|
|
257
|
+
styles,
|
|
258
|
+
sharedStrings,
|
|
259
|
+
flushed: options.flushed,
|
|
260
|
+
});
|
|
261
|
+
return emitPackageParts({ workbook, sheets, plan, styles, sharedStrings, sheetXml });
|
|
262
|
+
}
|
|
263
|
+
class PackageFiles {
|
|
264
|
+
#files = Object.create(null);
|
|
265
|
+
add(path, bytes) {
|
|
266
|
+
if (path in this.#files) {
|
|
267
|
+
throw new InternalError(`two package parts claim the path ${quoted(path)}`);
|
|
268
|
+
}
|
|
269
|
+
this.#files[path] = bytes;
|
|
270
|
+
}
|
|
271
|
+
toRecord() {
|
|
272
|
+
return this.#files;
|
|
273
|
+
}
|
|
207
274
|
}
|
|
208
275
|
function emitSheetParts(files, perSheet, sheetXml) {
|
|
209
276
|
perSheet.forEach((plan, i) => {
|
|
210
277
|
const { tables, drawing, comments, threadedComments, printerSettings, background, hyperlinks, preservedRefs, pivots, } = plan;
|
|
211
278
|
const hasExternalHyperlink = hyperlinks.some((link) => link.relId !== undefined);
|
|
212
|
-
files
|
|
279
|
+
files.add(worksheetPart(i + 1), strToU8(sheetXml[i]));
|
|
213
280
|
if (tables.length > 0 ||
|
|
214
281
|
drawing !== null ||
|
|
215
282
|
comments !== null ||
|
|
@@ -219,49 +286,46 @@ function emitSheetParts(files, perSheet, sheetXml) {
|
|
|
219
286
|
hasExternalHyperlink ||
|
|
220
287
|
preservedRefs.length > 0 ||
|
|
221
288
|
pivots.length > 0) {
|
|
222
|
-
files
|
|
289
|
+
files.add(relsPathFor(worksheetPart(i + 1)), strToU8(worksheetRelsXml(plan)));
|
|
223
290
|
}
|
|
224
291
|
if (printerSettings !== null) {
|
|
225
|
-
files
|
|
226
|
-
printerSettings.data;
|
|
292
|
+
files.add(printerSettingsPart(printerSettings.number), printerSettings.data);
|
|
227
293
|
}
|
|
228
294
|
if (drawing !== null) {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
295
|
+
const drawingPath = drawingPart(drawing.number);
|
|
296
|
+
files.add(drawingPath, strToU8(drawingXml(drawing.images)));
|
|
297
|
+
const targets = drawing.images.map((image) => relativePartPath(drawingPath, mediaPart(image.mediaNumber, image.extension)));
|
|
298
|
+
files.add(relsPathFor(drawingPath), strToU8(drawingRelsXml(targets)));
|
|
232
299
|
}
|
|
233
300
|
if (comments !== null) {
|
|
234
|
-
files
|
|
235
|
-
files
|
|
301
|
+
files.add(commentsPart(comments.number), strToU8(commentsXml(comments.comments)));
|
|
302
|
+
files.add(vmlDrawingPart(comments.number), strToU8(vmlDrawingXml(comments.comments)));
|
|
236
303
|
}
|
|
237
304
|
if (threadedComments !== null) {
|
|
238
|
-
files
|
|
305
|
+
files.add(threadedCommentsPart(threadedComments.number), strToU8(threadedCommentsXml(threadedComments.threads)));
|
|
239
306
|
}
|
|
240
307
|
});
|
|
241
308
|
}
|
|
242
309
|
function emitPivotParts(files, allPivots) {
|
|
243
310
|
for (const pivot of allPivots) {
|
|
244
311
|
const { number, cacheId, table } = pivot;
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
]));
|
|
253
|
-
files[`xl/pivotCache/pivotCacheDefinition${number}.xml`] = strToU8(pivotCacheDefinitionXml(table));
|
|
254
|
-
files[`xl/pivotCache/_rels/pivotCacheDefinition${number}.xml.rels`] = strToU8(relsPartXml([
|
|
255
|
-
{ id: 'rId1', type: REL.pivotCacheRecords, target: `pivotCacheRecords${number}.xml` },
|
|
256
|
-
]));
|
|
257
|
-
files[`xl/pivotCache/pivotCacheRecords${number}.xml`] = strToU8(pivotCacheRecordsXml(table));
|
|
312
|
+
const tablePath = pivotTablePart(number);
|
|
313
|
+
const definitionPath = pivotCacheDefinitionPart(number);
|
|
314
|
+
files.add(tablePath, strToU8(pivotTableXml(table, `PivotTable${number}`, cacheId)));
|
|
315
|
+
addSingleRelPart(files, tablePath, REL.pivotCacheDefinition, definitionPath);
|
|
316
|
+
files.add(definitionPath, strToU8(pivotCacheDefinitionXml(table)));
|
|
317
|
+
addSingleRelPart(files, definitionPath, REL.pivotCacheRecords, pivotCacheRecordsPart(number));
|
|
318
|
+
files.add(pivotCacheRecordsPart(number), strToU8(pivotCacheRecordsXml(table)));
|
|
258
319
|
}
|
|
259
320
|
}
|
|
321
|
+
function addSingleRelPart(files, from, type, to) {
|
|
322
|
+
files.add(relsPathFor(from), strToU8(relsPartXml([{ id: 'rId1', type, target: relativePartPath(from, to) }])));
|
|
323
|
+
}
|
|
260
324
|
function emitPreservedParts(files, parts) {
|
|
261
325
|
for (const part of parts) {
|
|
262
|
-
files
|
|
326
|
+
files.add(part.path, part.bytes);
|
|
263
327
|
if (part.relsPath !== null && part.relsXml !== null) {
|
|
264
|
-
files
|
|
328
|
+
files.add(part.relsPath, strToU8(part.relsXml));
|
|
265
329
|
}
|
|
266
330
|
}
|
|
267
331
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Does a relationship Type name this class of part?
|
|
3
|
+
*
|
|
4
|
+
* A Type is a URI whose last segment names the part class, and the namespace in front of it varies by
|
|
5
|
+
* relationship family and by the schema version a producer wrote against. So the match is on that
|
|
6
|
+
* last segment.
|
|
7
|
+
*
|
|
8
|
+
* **The separator is the load-bearing character.** `/slicer` and `slicer` are not the same test:
|
|
9
|
+
* without the slash, `slicer` matches `slicerCache`, `table` matches `pivotTable`, and a lookup
|
|
10
|
+
* quietly gathers a part class nobody asked for. Every caller used to spell the slash itself, ten
|
|
11
|
+
* times over, with nowhere to say why it was there.
|
|
12
|
+
*/
|
|
13
|
+
export declare function isRelType(type: string, name: string): boolean;
|
|
14
|
+
/** {@link isRelType} against several part classes at once, for the predicates that partition
|
|
15
|
+
* relationships into "modeled", "preserved verbatim", and "dropped". */
|
|
16
|
+
export declare function isAnyRelType(type: string, ...names: readonly string[]): boolean;
|
package/dist/rel-type.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a narrowing predicate for a closed token union.
|
|
3
|
+
*
|
|
4
|
+
* `members` is keyed by the union, so the compiler refuses a foreign member and an omitted one
|
|
5
|
+
* alike. A bare list of string literals is checked one way only: it cannot name a token the union
|
|
6
|
+
* does not, but it can quietly omit one the union does, and a guard narrower than its union
|
|
7
|
+
* silently drops a token real files legitimately carry.
|
|
8
|
+
*
|
|
9
|
+
* Deriving the union from the list instead (`(typeof TOKENS)[number]`, as `table-style.ts` does)
|
|
10
|
+
* would make divergence impossible rather than merely detected, and is the better shape for a type
|
|
11
|
+
* that is not public. It is not available to a published union: the API reference renders a
|
|
12
|
+
* declaration by slicing its own source text, so a derived alias reaches the docs as that
|
|
13
|
+
* expression instead of as its members.
|
|
14
|
+
*/
|
|
15
|
+
export declare function tokenSet<T extends string>(members: Record<T, true>): (value: string) => value is T;
|
|
16
|
+
/**
|
|
17
|
+
* {@link tokenSet} for a union whose members are also needed as an ordered *list*, because a binary
|
|
18
|
+
* serialisation indexes one.
|
|
19
|
+
*
|
|
20
|
+
* The record form's whole guarantee is that a member cannot be omitted, and a list gives that up: it
|
|
21
|
+
* can name only members of the union, but it can name fewer. So a caller here owes an explicit proof
|
|
22
|
+
* of set equality in both directions, which is what `FILL_PATTERNS_IN_SCHEMA_ORDER` carries beside
|
|
23
|
+
* itself. That is a worse guarantee than the record's, taken deliberately: the alternative is the
|
|
24
|
+
* arrangement it replaced, where the union, the guard's table and the binary codec's index list were
|
|
25
|
+
* three hand-maintained copies of one enumeration and only two of them were checked against each
|
|
26
|
+
* other.
|
|
27
|
+
*/
|
|
28
|
+
export declare function tokenSetOf<T extends string>(members: readonly T[]): (value: string) => value is T;
|
package/dist/vba/bytes.d.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
export { concat } from '../bytes.ts';
|
|
1
|
+
export { concat, decodeUtf16le } from '../bytes.ts';
|
|
2
2
|
/** Read a little-endian `uint16`. @throws {VbaParseError} if the two bytes are not both in `buf`. */
|
|
3
3
|
export declare function readU16(buf: Uint8Array, at: number): number;
|
|
4
4
|
/** Read a little-endian `uint32`. @throws {VbaParseError} if the four bytes are not all in `buf`. */
|
|
5
5
|
export declare function readU32(buf: Uint8Array, at: number): number;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* Write a little-endian `uint16` over bytes already in `buf`. The value is asserted rather than
|
|
8
|
+
* masked: a caller that arrived at `-1` or `0x1_0000` has miscounted something, and silently storing
|
|
9
|
+
* `0xffff` turns that into a `dir` stream declaring 65,535 modules.
|
|
10
10
|
*/
|
|
11
|
-
export declare function
|
|
11
|
+
export declare function writeU16(buf: Uint8Array, at: number, value: number): void;
|
|
12
|
+
/**
|
|
13
|
+
* Replace `src[start..end)` with `insert`, returning a new array.
|
|
14
|
+
*
|
|
15
|
+
* The three record edits the project editor makes are all this shape: splice a MODULE record block in,
|
|
16
|
+
* cut one out, cut a PROJECTwm entry out. Each was an allocate-and-copy-around written out longhand,
|
|
17
|
+
* and each had to get the same three offsets right; saying it once means the arithmetic is checked
|
|
18
|
+
* once. Passing no `insert` is a pure deletion, and `start === end` a pure insertion.
|
|
19
|
+
*/
|
|
20
|
+
export declare function spliceBytes(src: Uint8Array, start: number, end: number, insert?: Uint8Array): Uint8Array;
|
package/dist/vba/bytes.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { concat } from '../bytes.js';
|
|
1
|
+
export { concat, decodeUtf16le } from '../bytes.js';
|
|
2
2
|
import { VbaParseError } from './errors.js';
|
|
3
3
|
function truncated(at, need, length) {
|
|
4
4
|
return new VbaParseError(`read of ${need} bytes at offset ${at} runs past the end of a ${length}-byte buffer`);
|
|
@@ -20,10 +20,20 @@ export function readU32(buf, at) {
|
|
|
20
20
|
}
|
|
21
21
|
return (b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)) >>> 0;
|
|
22
22
|
}
|
|
23
|
-
export function
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
s += String.fromCharCode(readU16(bytes, i));
|
|
23
|
+
export function writeU16(buf, at, value) {
|
|
24
|
+
if (!Number.isInteger(value) || value < 0 || value > 0xffff) {
|
|
25
|
+
throw new VbaParseError(`${value} does not fit the uint16 at offset ${at}`);
|
|
27
26
|
}
|
|
28
|
-
|
|
27
|
+
if (at + 1 >= buf.length)
|
|
28
|
+
throw truncated(at, 2, buf.length);
|
|
29
|
+
buf[at] = value & 0xff;
|
|
30
|
+
buf[at + 1] = (value >> 8) & 0xff;
|
|
31
|
+
}
|
|
32
|
+
export function spliceBytes(src, start, end, insert = EMPTY) {
|
|
33
|
+
const out = new Uint8Array(src.length - (end - start) + insert.length);
|
|
34
|
+
out.set(src.subarray(0, start), 0);
|
|
35
|
+
out.set(insert, start);
|
|
36
|
+
out.set(src.subarray(end), start + insert.length);
|
|
37
|
+
return out;
|
|
29
38
|
}
|
|
39
|
+
const EMPTY = new Uint8Array(0);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Sector chain markers ([MS-CFB] 2.2). */
|
|
2
|
+
export declare const FREESECT = 4294967295;
|
|
3
|
+
export declare const ENDOFCHAIN = 4294967294;
|
|
4
|
+
export declare const FATSECT = 4294967293;
|
|
5
|
+
export declare const DIFSECT = 4294967292;
|
|
6
|
+
/**
|
|
7
|
+
* Sector values 0xFFFFFFFA..0xFFFFFFFF are the reserved markers above, not data-sector indices, so
|
|
8
|
+
* any value at or above this ceiling is chain-terminal. A reader walking a hostile chain tests the
|
|
9
|
+
* ceiling rather than the four markers by name: an unassigned reserved value is terminal too.
|
|
10
|
+
*/
|
|
11
|
+
export declare const MAX_REGULAR_SECTOR = 4294967290;
|
|
12
|
+
/** Directory-tree links reuse the sector convention: NOSTREAM, and any value at or above
|
|
13
|
+
* {@link MAX_REGULAR_SECTOR}, mean "no such sibling or child". */
|
|
14
|
+
export declare const NOSTREAM = 4294967295;
|
|
15
|
+
/** Object types ([MS-CFB] 2.6.1). */
|
|
16
|
+
export declare const TYPE_EMPTY = 0;
|
|
17
|
+
export declare const TYPE_STORAGE = 1;
|
|
18
|
+
export declare const TYPE_STREAM = 2;
|
|
19
|
+
export declare const TYPE_ROOT = 5;
|
|
20
|
+
/**
|
|
21
|
+
* The stream size at or above which a stream lives in the regular FAT rather than the mini stream
|
|
22
|
+
* ([MS-CFB] 2.2, header offset 56). The spec fixes it at 4096, so the reader checks the header's value
|
|
23
|
+
* against this rather than believing it: a crafted 0 or 0xFFFFFFFF routes every stream through the
|
|
24
|
+
* wrong allocator, and since both destinations are bounds-checked the result is a module's source read
|
|
25
|
+
* back as something nobody wrote rather than a clean rejection.
|
|
26
|
+
*/
|
|
27
|
+
export declare const MINI_STREAM_CUTOFF = 4096;
|
|
28
|
+
/** A directory entry is a fixed 128 bytes ([MS-CFB] 2.6.1), whatever the sector size. */
|
|
29
|
+
export declare const DIR_ENTRY_SIZE = 128;
|
|
30
|
+
/** 32 UTF-16 code units including the NUL terminator. This is also why a VBA module name is capped
|
|
31
|
+
* at 31: the module is a stream, and the stream's name is the module's. */
|
|
32
|
+
export declare const MAX_NAME_CHARS = 31;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const FREESECT = 0xffffffff;
|
|
2
|
+
export const ENDOFCHAIN = 0xfffffffe;
|
|
3
|
+
export const FATSECT = 0xfffffffd;
|
|
4
|
+
export const DIFSECT = 0xfffffffc;
|
|
5
|
+
export const MAX_REGULAR_SECTOR = 0xfffffffa;
|
|
6
|
+
export const NOSTREAM = 0xffffffff;
|
|
7
|
+
export const TYPE_EMPTY = 0;
|
|
8
|
+
export const TYPE_STORAGE = 1;
|
|
9
|
+
export const TYPE_STREAM = 2;
|
|
10
|
+
export const TYPE_ROOT = 5;
|
|
11
|
+
export const MINI_STREAM_CUTOFF = 4096;
|
|
12
|
+
export const DIR_ENTRY_SIZE = 128;
|
|
13
|
+
export const MAX_NAME_CHARS = 31;
|
package/dist/vba/cfb-writer.d.ts
CHANGED
|
@@ -8,6 +8,15 @@ export interface CfbStorage {
|
|
|
8
8
|
readonly children: readonly CfbNode[];
|
|
9
9
|
}
|
|
10
10
|
export type CfbNode = CfbStream | CfbStorage;
|
|
11
|
+
/**
|
|
12
|
+
* Which arm of {@link CfbNode} a node is.
|
|
13
|
+
*
|
|
14
|
+
* Exported beside the union rather than kept private, because the discriminant is `'data' in node`
|
|
15
|
+
* and that is the sort of test callers re-spell inline: `project-editor.ts` had it three times, once
|
|
16
|
+
* negated. The name says what the test means, and the pair says that a node is one or the other.
|
|
17
|
+
*/
|
|
18
|
+
export declare function isStream(node: CfbNode): node is CfbStream;
|
|
19
|
+
export declare function isStorage(node: CfbNode): node is CfbStorage;
|
|
11
20
|
/**
|
|
12
21
|
* Encode a hierarchy of storages and streams into a v3 compound file. The Root Entry is synthesized
|
|
13
22
|
* automatically; `root` is its top-level children. Every stream becomes a directory entry reachable both
|