@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/xlsx/write.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { strToU8, zip, zipSync } from 'fflate';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { formulaNamesInScope } from '../../core/formula.js';
|
|
3
|
+
import { pictureProperties } from '../../core/image.js';
|
|
4
|
+
import { AuthoringError, InternalError, quoted } from '../../errors.js';
|
|
5
|
+
import { isRelType } from '../../rel-type.js';
|
|
6
|
+
import { relsPathFor, THEME_PART_PATH } from '../opc/part-paths.js';
|
|
4
7
|
import { relsPartXml } from '../opc/rels.js';
|
|
5
8
|
import { FIXED_ENTRY_MTIME } from '../opc/zip-mtime.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { RICH_VALUE_STRUCTURES_XML, WorkbookMetadataTable } from './cell-metadata.js';
|
|
10
|
+
import { collectComments, commentsXml, liveCells, vmlDrawingXml } from './comments.js';
|
|
11
|
+
import { planHyperlinks } from './hyperlinks.js';
|
|
12
|
+
import { drawingXml } from './images.js';
|
|
13
|
+
import { planMedia, planPreservedParts, RelationshipLedger, } from './package-plan.js';
|
|
14
|
+
import { APP_PROPS_PART, commentsPart, CORE_PROPS_PART, drawingPart, mediaPart, METADATA_PART, PERSONS_PART, pivotCacheDefinitionPart, pivotCacheRecordsPart, pivotTablePart, printerSettingsPart, RICH_VALUE_STRUCTURES_PART, RICH_VALUES_PART, SHARED_STRINGS_PART, STYLES_PART, tablePart, threadedCommentsPart, vmlDrawingPart, WORKBOOK_PART, worksheetPart, } from './part-names.js';
|
|
11
15
|
import { pivotCacheDefinitionXml, pivotCacheRecordsXml, pivotTableXml } from './pivot.js';
|
|
12
16
|
import { REL } from './relationships.js';
|
|
13
17
|
import { SharedStringTable } from './shared-strings.js';
|
|
@@ -15,9 +19,8 @@ import { StyleRegistry } from './styles.js';
|
|
|
15
19
|
import { tableXml } from './tables.js';
|
|
16
20
|
import { applyThemeOverrides, DEFAULT_THEME_XML } from './theme-xml.js';
|
|
17
21
|
import { personsXml, threadedCommentsXml } from './threaded-comments.js';
|
|
18
|
-
import { appPropsXml, contentTypesXml, corePropsXml,
|
|
19
|
-
import {
|
|
20
|
-
export { buildColumnDefaults, Extent, renderRow, } from './worksheet-xml.js';
|
|
22
|
+
import { appPropsXml, contentTypesXml, corePropsXml, workbookXml, } from './workbook-xml.js';
|
|
23
|
+
import { worksheetXml } from './worksheet-xml.js';
|
|
21
24
|
export function writeXlsx(workbook, options = {}) {
|
|
22
25
|
return zipSync(buildPackageParts(workbook, options), { level: 6, mtime: FIXED_ENTRY_MTIME });
|
|
23
26
|
}
|
|
@@ -48,52 +51,77 @@ export function createStyleRegistry(workbook) {
|
|
|
48
51
|
styles.addTableStyle(style);
|
|
49
52
|
return styles;
|
|
50
53
|
}
|
|
54
|
+
function keptDrawingPath(sheet) {
|
|
55
|
+
return sheet.preservedReferences.find((reference) => reference.element === 'drawing')?.entryPath;
|
|
56
|
+
}
|
|
57
|
+
function drawingImages(sheet, media, drawingRels) {
|
|
58
|
+
return sheet.images.map((image) => {
|
|
59
|
+
const { number: mediaNumber, image: registered } = media.resolve(image.imageId);
|
|
60
|
+
const embedId = drawingRels.add(REL.image, mediaPart(mediaNumber, registered.extension));
|
|
61
|
+
const properties = pictureProperties(image);
|
|
62
|
+
const target = properties.hyperlink?.target;
|
|
63
|
+
if (target === undefined)
|
|
64
|
+
return { anchor: image.anchor, embedId, properties };
|
|
65
|
+
const hyperlinkId = target.startsWith('#')
|
|
66
|
+
? drawingRels.addInDocument(REL.hyperlink, target)
|
|
67
|
+
: drawingRels.addExternal(REL.hyperlink, target);
|
|
68
|
+
return { anchor: image.anchor, embedId, properties, hyperlinkId };
|
|
69
|
+
});
|
|
70
|
+
}
|
|
51
71
|
function planSheet(context) {
|
|
52
|
-
const { sheet, index, media, preserved, numbering } = context;
|
|
53
|
-
const rels = new
|
|
54
|
-
const tables = sheet.tables.map((table) =>
|
|
55
|
-
table
|
|
56
|
-
number:
|
|
57
|
-
|
|
58
|
-
}));
|
|
72
|
+
const { sheet, index, media, preserved, numbering, flushed } = context;
|
|
73
|
+
const rels = new RelationshipLedger(worksheetPart(index + 1));
|
|
74
|
+
const tables = sheet.tables.map((table) => {
|
|
75
|
+
const number = ++numbering.table;
|
|
76
|
+
return { table, number, relId: rels.add(REL.table, tablePart(number)) };
|
|
77
|
+
});
|
|
59
78
|
let drawing = null;
|
|
60
|
-
if (sheet.images.length > 0) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
drawing = { number: ++numbering.drawing, relId: rels.next(), images };
|
|
79
|
+
if (sheet.images.length > 0 && keptDrawingPath(sheet) === undefined) {
|
|
80
|
+
const number = ++numbering.drawing;
|
|
81
|
+
const path = drawingPart(number);
|
|
82
|
+
const drawingRels = new RelationshipLedger(path);
|
|
83
|
+
drawing = {
|
|
84
|
+
number,
|
|
85
|
+
relId: rels.add(REL.drawing, path),
|
|
86
|
+
images: drawingImages(sheet, media, drawingRels),
|
|
87
|
+
relationships: drawingRels.relationships,
|
|
88
|
+
};
|
|
71
89
|
}
|
|
72
90
|
const threads = sheet.commentThreads.filter((thread) => thread.comments.length > 0);
|
|
73
|
-
const sheetComments = collectComments(sheet, threads);
|
|
74
|
-
|
|
91
|
+
const sheetComments = collectComments(liveCells(sheet), threads, flushed?.notes ?? []);
|
|
92
|
+
let comments = null;
|
|
93
|
+
if (sheetComments.length > 0) {
|
|
94
|
+
const vmlRelId = rels.add(REL.vmlDrawing, vmlDrawingPart(index + 1));
|
|
95
|
+
rels.add(REL.comments, commentsPart(index + 1));
|
|
96
|
+
comments = { number: index + 1, comments: sheetComments, vmlRelId };
|
|
97
|
+
}
|
|
98
|
+
let threadedComments = null;
|
|
99
|
+
if (threads.length > 0) {
|
|
100
|
+
rels.add(REL.threadedComment, threadedCommentsPart(index + 1));
|
|
101
|
+
threadedComments = { number: index + 1, threads };
|
|
102
|
+
}
|
|
103
|
+
const printerData = sheet.pageSetup.printerSettings;
|
|
104
|
+
const printerSettings = printerData === undefined
|
|
75
105
|
? null
|
|
76
106
|
: {
|
|
77
107
|
number: index + 1,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
commentsRelId: rels.next(),
|
|
108
|
+
data: printerData,
|
|
109
|
+
relId: rels.add(REL.printerSettings, printerSettingsPart(index + 1)),
|
|
81
110
|
};
|
|
82
|
-
const
|
|
83
|
-
const printerData = sheet.pageSetup.printerSettings;
|
|
84
|
-
const printerSettings = printerData === undefined ? null : { number: index + 1, data: printerData, relId: rels.next() };
|
|
85
|
-
const hyperlinks = planHyperlinks(collectHyperlinks(sheet), rels);
|
|
111
|
+
const hyperlinks = planHyperlinks(sheet.hyperlinks, rels);
|
|
86
112
|
let background = null;
|
|
87
113
|
if (sheet.backgroundImageId !== undefined) {
|
|
88
114
|
const { number, image } = media.resolve(sheet.backgroundImageId);
|
|
89
|
-
background = { relId: rels.
|
|
115
|
+
background = { relId: rels.add(REL.image, mediaPart(number, image.extension)) };
|
|
90
116
|
}
|
|
91
|
-
const preservedRefs = (preserved.perSheet[index] ?? []).map((reference) => ({ ...reference, relId: rels.
|
|
117
|
+
const preservedRefs = (preserved.perSheet[index] ?? []).map((reference) => ({ ...reference, relId: rels.add(reference.relType, reference.entryPath) }));
|
|
92
118
|
const pivots = sheet.pivotTables.map((table) => {
|
|
93
119
|
const number = ++numbering.pivot;
|
|
94
|
-
|
|
120
|
+
rels.add(REL.pivotTable, pivotTablePart(number));
|
|
121
|
+
return { number, cacheId: String(number), table, workbookRelId: '' };
|
|
95
122
|
});
|
|
96
123
|
return {
|
|
124
|
+
relationships: rels.relationships,
|
|
97
125
|
tables,
|
|
98
126
|
drawing,
|
|
99
127
|
comments,
|
|
@@ -119,7 +147,7 @@ function resolveSheetReferences(plan) {
|
|
|
119
147
|
const preservedDrawingRelId = refs.find((ref) => ref.element === 'drawing')?.relId ?? null;
|
|
120
148
|
const legacyDrawingHFRelId = refs.find((ref) => ref.element === 'legacyDrawingHF')?.relId ?? null;
|
|
121
149
|
const slicerRelIds = refs
|
|
122
|
-
.filter((ref) => ref.relType
|
|
150
|
+
.filter((ref) => isRelType(ref.relType, 'slicer'))
|
|
123
151
|
.map((ref) => ref.relId);
|
|
124
152
|
return {
|
|
125
153
|
drawingRelId: plan.drawing?.relId ?? preservedDrawingRelId,
|
|
@@ -130,27 +158,57 @@ function resolveSheetReferences(plan) {
|
|
|
130
158
|
slicerRelIds,
|
|
131
159
|
};
|
|
132
160
|
}
|
|
133
|
-
function
|
|
134
|
-
const { sheetCount, hasSharedStrings, hasPersons, preservedWorkbook, pivots } = context;
|
|
135
|
-
const
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
161
|
+
function planWorkbookRelationships(context) {
|
|
162
|
+
const { sheetCount, hasSharedStrings, hasPersons, hasCellMetadata, hasRichValues, preservedWorkbook, pivots, } = context;
|
|
163
|
+
const rels = new RelationshipLedger(WORKBOOK_PART);
|
|
164
|
+
const sheetRelIds = Array.from({ length: sheetCount }, (_, i) => rels.add(REL.worksheet, worksheetPart(i + 1)));
|
|
165
|
+
rels.add(REL.styles, STYLES_PART);
|
|
166
|
+
rels.add(REL.theme, THEME_PART_PATH);
|
|
167
|
+
if (hasSharedStrings)
|
|
168
|
+
rels.add(REL.sharedStrings, SHARED_STRINGS_PART);
|
|
169
|
+
if (hasPersons)
|
|
170
|
+
rels.add(REL.person, PERSONS_PART);
|
|
171
|
+
if (hasCellMetadata)
|
|
172
|
+
rels.add(REL.sheetMetadata, METADATA_PART);
|
|
173
|
+
if (hasRichValues) {
|
|
174
|
+
rels.add(REL.rdRichValue, RICH_VALUES_PART);
|
|
175
|
+
rels.add(REL.rdRichValueStructure, RICH_VALUE_STRUCTURES_PART);
|
|
176
|
+
}
|
|
177
|
+
const preservedWorkbookRels = preservedWorkbook.map((ref) => ({
|
|
139
178
|
...ref,
|
|
140
|
-
relId:
|
|
179
|
+
relId: rels.add(ref.relType, ref.entryPath),
|
|
141
180
|
}));
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
return { personsRelId, preservedWorkbookRels };
|
|
181
|
+
for (const pivot of pivots) {
|
|
182
|
+
pivot.workbookRelId = rels.add(REL.pivotCacheDefinition, pivotCacheDefinitionPart(pivot.number));
|
|
183
|
+
}
|
|
184
|
+
return { sheetRelIds, preservedWorkbookRels, relationships: rels.relationships };
|
|
147
185
|
}
|
|
148
|
-
function
|
|
186
|
+
function planRootRelationships(rootRefs) {
|
|
187
|
+
const rels = new RelationshipLedger('');
|
|
188
|
+
rels.add(REL.officeDocument, WORKBOOK_PART);
|
|
189
|
+
rels.add(REL.coreProps, CORE_PROPS_PART);
|
|
190
|
+
rels.add(REL.extProps, APP_PROPS_PART);
|
|
191
|
+
for (const ref of rootRefs)
|
|
192
|
+
rels.add(ref.relType, ref.entryPath);
|
|
193
|
+
return rels.relationships;
|
|
194
|
+
}
|
|
195
|
+
function planPackage(workbook, sheets, flushed) {
|
|
149
196
|
const media = planMedia(workbook, sheets);
|
|
150
|
-
const
|
|
151
|
-
|
|
197
|
+
const pictures = new Map();
|
|
198
|
+
let generatedDrawingCount = 0;
|
|
199
|
+
for (const sheet of sheets) {
|
|
200
|
+
if (sheet.images.length === 0)
|
|
201
|
+
continue;
|
|
202
|
+
const kept = keptDrawingPath(sheet);
|
|
203
|
+
if (kept === undefined)
|
|
204
|
+
generatedDrawingCount += 1;
|
|
205
|
+
else
|
|
206
|
+
pictures.set(kept, (ledger) => drawingImages(sheet, media, ledger));
|
|
207
|
+
}
|
|
208
|
+
const generatedPivotCount = sheets.reduce((total, sheet) => total + sheet.pivotTables.length, 0);
|
|
209
|
+
const preserved = planPreservedParts(workbook, generatedDrawingCount, media.parts.length, generatedPivotCount, pictures);
|
|
152
210
|
const numbering = { table: 0, drawing: 0, pivot: 0 };
|
|
153
|
-
const perSheet = sheets.map((sheet, index) => planSheet({ sheet, index, media, preserved, numbering }));
|
|
211
|
+
const perSheet = sheets.map((sheet, index) => planSheet({ sheet, index, media, preserved, numbering, flushed: flushed?.get(sheet) }));
|
|
154
212
|
return {
|
|
155
213
|
media,
|
|
156
214
|
preserved,
|
|
@@ -159,58 +217,99 @@ function planPackage(workbook, sheets) {
|
|
|
159
217
|
allPivots: perSheet.flatMap((plan) => plan.pivots),
|
|
160
218
|
};
|
|
161
219
|
}
|
|
162
|
-
function serialiseSheets(
|
|
220
|
+
function serialiseSheets(context) {
|
|
221
|
+
const { workbook, sheets, plan, styles, sharedStrings, cellMetadata, flushed } = context;
|
|
163
222
|
return sheets.map((sheet, i) => {
|
|
164
223
|
const sheetPlan = plan.perSheet[i];
|
|
165
|
-
return worksheetXml(
|
|
224
|
+
return worksheetXml({
|
|
225
|
+
sheet,
|
|
226
|
+
tables: sheetPlan.tables,
|
|
227
|
+
styles,
|
|
228
|
+
references: resolveSheetReferences(sheetPlan),
|
|
229
|
+
hyperlinks: sheetPlan.hyperlinks,
|
|
230
|
+
sharedStrings,
|
|
231
|
+
cellMetadata,
|
|
232
|
+
dateEpoch: workbook.dateEpoch,
|
|
233
|
+
formulaNames: formulaNamesInScope(workbook.definedNames, sheet.name),
|
|
234
|
+
active: i === workbook.activeTabIndex,
|
|
235
|
+
flushed: flushed?.get(sheet),
|
|
236
|
+
});
|
|
166
237
|
});
|
|
167
238
|
}
|
|
168
239
|
function emitPackageParts(context) {
|
|
169
|
-
const { workbook, sheets, plan, styles, sharedStrings, sheetXml } = context;
|
|
240
|
+
const { workbook, sheets, plan, styles, sharedStrings, cellMetadata, sheetXml } = context;
|
|
170
241
|
const { media, preserved, perSheet, allTables, allPivots } = plan;
|
|
171
242
|
const hasSharedStrings = sharedStrings !== null && !sharedStrings.isEmpty;
|
|
243
|
+
const hasCellMetadata = !cellMetadata.isEmpty;
|
|
244
|
+
const hasRichValues = cellMetadata.hasRichValues;
|
|
172
245
|
const commentNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.comments);
|
|
173
246
|
const drawingNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.drawing);
|
|
174
247
|
const printerSettingsNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.printerSettings);
|
|
175
248
|
const threadedCommentNumbers = numbersOf(perSheet, (sheetPlan) => sheetPlan.threadedComments);
|
|
176
249
|
const persons = threadedCommentNumbers.length === 0 ? [] : workbook.persons;
|
|
177
|
-
const
|
|
250
|
+
const workbookRels = planWorkbookRelationships({
|
|
178
251
|
sheetCount: sheets.length,
|
|
179
252
|
hasSharedStrings,
|
|
180
253
|
hasPersons: persons.length > 0,
|
|
254
|
+
hasCellMetadata,
|
|
255
|
+
hasRichValues,
|
|
181
256
|
preservedWorkbook: preserved.workbook,
|
|
182
257
|
pivots: allPivots,
|
|
183
258
|
});
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
259
|
+
const { preservedWorkbookRels } = workbookRels;
|
|
260
|
+
const files = new PackageFiles();
|
|
261
|
+
files.add('[Content_Types].xml', strToU8(contentTypesXml({
|
|
262
|
+
sheetCount: sheets.length,
|
|
263
|
+
tables: allTables,
|
|
264
|
+
commentNumbers,
|
|
265
|
+
drawingNumbers,
|
|
266
|
+
printerSettingsNumbers,
|
|
267
|
+
mediaExtensions: media.extensions,
|
|
268
|
+
hasSharedStrings,
|
|
269
|
+
preservedParts: preserved.parts,
|
|
270
|
+
pivots: allPivots,
|
|
271
|
+
preservedWorkbookRefs: preservedWorkbookRels,
|
|
272
|
+
threadedCommentNumbers,
|
|
273
|
+
hasPersons: persons.length > 0,
|
|
274
|
+
hasCellMetadata,
|
|
275
|
+
hasRichValues,
|
|
276
|
+
})));
|
|
277
|
+
files.add(relsPathFor(''), strToU8(relsPartXml(planRootRelationships(preserved.root))));
|
|
278
|
+
files.add(CORE_PROPS_PART, strToU8(corePropsXml(workbook.properties)));
|
|
279
|
+
files.add(APP_PROPS_PART, strToU8(appPropsXml(workbook.properties)));
|
|
280
|
+
files.add(WORKBOOK_PART, strToU8(workbookXml(workbook, workbookRels, allPivots)));
|
|
281
|
+
files.add(relsPathFor(WORKBOOK_PART), strToU8(relsPartXml(workbookRels.relationships)));
|
|
282
|
+
files.add(STYLES_PART, strToU8(styles.toXml()));
|
|
193
283
|
if (!preserved.themeEmitted) {
|
|
194
284
|
const overrides = workbook.themeOverrides;
|
|
195
|
-
files
|
|
285
|
+
files.add(THEME_PART_PATH, strToU8(overrides === undefined
|
|
196
286
|
? DEFAULT_THEME_XML
|
|
197
|
-
: applyThemeOverrides(DEFAULT_THEME_XML, overrides));
|
|
287
|
+
: applyThemeOverrides(DEFAULT_THEME_XML, overrides)));
|
|
198
288
|
}
|
|
199
289
|
if (hasSharedStrings) {
|
|
200
|
-
files
|
|
290
|
+
files.add(SHARED_STRINGS_PART, strToU8(sharedStrings.toXml()));
|
|
201
291
|
}
|
|
202
292
|
if (persons.length > 0)
|
|
203
|
-
files
|
|
204
|
-
|
|
205
|
-
files
|
|
293
|
+
files.add(PERSONS_PART, strToU8(personsXml(persons)));
|
|
294
|
+
if (hasCellMetadata)
|
|
295
|
+
files.add(METADATA_PART, strToU8(cellMetadata.toXml()));
|
|
296
|
+
if (hasRichValues) {
|
|
297
|
+
files.add(RICH_VALUES_PART, strToU8(cellMetadata.richValuesXml()));
|
|
298
|
+
files.add(RICH_VALUE_STRUCTURES_PART, strToU8(RICH_VALUE_STRUCTURES_XML));
|
|
206
299
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
files[tablePart(number)] = strToU8(tableXml(table, number));
|
|
300
|
+
for (const part of media.parts) {
|
|
301
|
+
files.add(mediaPart(part.number, part.extension), part.data);
|
|
210
302
|
}
|
|
303
|
+
emitSheetParts(files, perSheet, sheetXml, (id) => workbook.getPerson(id));
|
|
304
|
+
perSheet.forEach(({ tables }, index) => {
|
|
305
|
+
const formulaNames = formulaNamesInScope(workbook.definedNames, sheets[index]?.name);
|
|
306
|
+
for (const { table, number } of tables) {
|
|
307
|
+
files.add(tablePart(number), strToU8(tableXml(table, number, formulaNames)));
|
|
308
|
+
}
|
|
309
|
+
});
|
|
211
310
|
emitPivotParts(files, allPivots);
|
|
212
311
|
emitPreservedParts(files, preserved.parts);
|
|
213
|
-
return files;
|
|
312
|
+
return files.toRecord();
|
|
214
313
|
}
|
|
215
314
|
export function buildPackageParts(workbook, options = {}) {
|
|
216
315
|
const sheets = workbook.worksheets;
|
|
@@ -219,41 +318,52 @@ export function buildPackageParts(workbook, options = {}) {
|
|
|
219
318
|
}
|
|
220
319
|
const sharedStrings = options.useSharedStrings ? new SharedStringTable() : null;
|
|
221
320
|
const styles = options.styles ?? createStyleRegistry(workbook);
|
|
222
|
-
const
|
|
223
|
-
const
|
|
224
|
-
|
|
321
|
+
const cellMetadata = options.cellMetadata ?? new WorkbookMetadataTable();
|
|
322
|
+
const plan = planPackage(workbook, sheets, options.flushed);
|
|
323
|
+
const sheetXml = serialiseSheets({
|
|
324
|
+
workbook,
|
|
325
|
+
sheets,
|
|
326
|
+
plan,
|
|
327
|
+
styles,
|
|
328
|
+
sharedStrings,
|
|
329
|
+
cellMetadata,
|
|
330
|
+
flushed: options.flushed,
|
|
331
|
+
});
|
|
332
|
+
return emitPackageParts({ workbook, sheets, plan, styles, sharedStrings, cellMetadata, sheetXml });
|
|
333
|
+
}
|
|
334
|
+
class PackageFiles {
|
|
335
|
+
#files = Object.create(null);
|
|
336
|
+
add(path, bytes) {
|
|
337
|
+
if (path in this.#files) {
|
|
338
|
+
throw new InternalError(`two package parts claim the path ${quoted(path)}`);
|
|
339
|
+
}
|
|
340
|
+
this.#files[path] = bytes;
|
|
341
|
+
}
|
|
342
|
+
toRecord() {
|
|
343
|
+
return this.#files;
|
|
344
|
+
}
|
|
225
345
|
}
|
|
226
|
-
function emitSheetParts(files, perSheet, sheetXml) {
|
|
346
|
+
function emitSheetParts(files, perSheet, sheetXml, personById) {
|
|
227
347
|
perSheet.forEach((plan, i) => {
|
|
228
|
-
const {
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
drawing !== null ||
|
|
233
|
-
comments !== null ||
|
|
234
|
-
threadedComments !== null ||
|
|
235
|
-
printerSettings !== null ||
|
|
236
|
-
background !== null ||
|
|
237
|
-
hasExternalHyperlink ||
|
|
238
|
-
preservedRefs.length > 0 ||
|
|
239
|
-
pivots.length > 0) {
|
|
240
|
-
files[relsPathFor(worksheetPart(i + 1))] = strToU8(worksheetRelsXml(tables, drawing, comments, threadedComments, printerSettings, background, hyperlinks, preservedRefs, pivots));
|
|
348
|
+
const { relationships, drawing, comments, threadedComments, printerSettings } = plan;
|
|
349
|
+
files.add(worksheetPart(i + 1), strToU8(sheetXml[i]));
|
|
350
|
+
if (relationships.length > 0) {
|
|
351
|
+
files.add(relsPathFor(worksheetPart(i + 1)), strToU8(relsPartXml(relationships)));
|
|
241
352
|
}
|
|
242
353
|
if (printerSettings !== null) {
|
|
243
|
-
files
|
|
354
|
+
files.add(printerSettingsPart(printerSettings.number), printerSettings.data);
|
|
244
355
|
}
|
|
245
356
|
if (drawing !== null) {
|
|
246
357
|
const drawingPath = drawingPart(drawing.number);
|
|
247
|
-
files
|
|
248
|
-
|
|
249
|
-
files[relsPathFor(drawingPath)] = strToU8(drawingRelsXml(targets));
|
|
358
|
+
files.add(drawingPath, strToU8(drawingXml(drawing.images)));
|
|
359
|
+
files.add(relsPathFor(drawingPath), strToU8(relsPartXml(drawing.relationships)));
|
|
250
360
|
}
|
|
251
361
|
if (comments !== null) {
|
|
252
|
-
files
|
|
253
|
-
files
|
|
362
|
+
files.add(commentsPart(comments.number), strToU8(commentsXml(comments.comments)));
|
|
363
|
+
files.add(vmlDrawingPart(comments.number), strToU8(vmlDrawingXml(comments.comments)));
|
|
254
364
|
}
|
|
255
365
|
if (threadedComments !== null) {
|
|
256
|
-
files
|
|
366
|
+
files.add(threadedCommentsPart(threadedComments.number), strToU8(threadedCommentsXml(threadedComments.threads, personById)));
|
|
257
367
|
}
|
|
258
368
|
});
|
|
259
369
|
}
|
|
@@ -262,30 +372,23 @@ function emitPivotParts(files, allPivots) {
|
|
|
262
372
|
const { number, cacheId, table } = pivot;
|
|
263
373
|
const tablePath = pivotTablePart(number);
|
|
264
374
|
const definitionPath = pivotCacheDefinitionPart(number);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
files
|
|
274
|
-
files
|
|
275
|
-
{
|
|
276
|
-
id: 'rId1',
|
|
277
|
-
type: REL.pivotCacheRecords,
|
|
278
|
-
target: relativePartPath(definitionPath, pivotCacheRecordsPart(number)),
|
|
279
|
-
},
|
|
280
|
-
]));
|
|
281
|
-
files[pivotCacheRecordsPart(number)] = strToU8(pivotCacheRecordsXml(table));
|
|
375
|
+
const recordsPath = pivotCacheRecordsPart(number);
|
|
376
|
+
const tableRels = new RelationshipLedger(tablePath);
|
|
377
|
+
tableRels.add(REL.pivotCacheDefinition, definitionPath);
|
|
378
|
+
files.add(tablePath, strToU8(pivotTableXml(table, `PivotTable${number}`, cacheId)));
|
|
379
|
+
files.add(relsPathFor(tablePath), strToU8(relsPartXml(tableRels.relationships)));
|
|
380
|
+
const definitionRels = new RelationshipLedger(definitionPath);
|
|
381
|
+
const recordsRelId = definitionRels.add(REL.pivotCacheRecords, recordsPath);
|
|
382
|
+
files.add(definitionPath, strToU8(pivotCacheDefinitionXml(table, recordsRelId)));
|
|
383
|
+
files.add(relsPathFor(definitionPath), strToU8(relsPartXml(definitionRels.relationships)));
|
|
384
|
+
files.add(recordsPath, strToU8(pivotCacheRecordsXml(table)));
|
|
282
385
|
}
|
|
283
386
|
}
|
|
284
387
|
function emitPreservedParts(files, parts) {
|
|
285
388
|
for (const part of parts) {
|
|
286
|
-
files
|
|
389
|
+
files.add(part.path, part.bytes);
|
|
287
390
|
if (part.relsPath !== null && part.relsXml !== null) {
|
|
288
|
-
files
|
|
391
|
+
files.add(part.relsPath, strToU8(part.relsXml));
|
|
289
392
|
}
|
|
290
393
|
}
|
|
291
394
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The last segment of a relationship Type (`vbaProjectSignatureAgile` in
|
|
3
|
+
* `http://schemas.microsoft.com/office/2014/relationships/vbaProjectSignatureAgile`), or the whole Type
|
|
4
|
+
* when it has no `/`: for a caller that looks the segment up rather than testing for one class.
|
|
5
|
+
*
|
|
6
|
+
* {@link isRelType} is not built on it, because a class name may span segments: the ribbon's is
|
|
7
|
+
* `ui/extensibility`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function relTypeSegment(type: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Does a relationship Type name this class of part?
|
|
12
|
+
*
|
|
13
|
+
* A Type is a URI whose last segment names the part class, and the namespace in front of it varies by
|
|
14
|
+
* relationship family and by the schema version a producer wrote against. So the match is on that
|
|
15
|
+
* last segment.
|
|
16
|
+
*
|
|
17
|
+
* **The separator is the load-bearing character.** `/slicer` and `slicer` are not the same test:
|
|
18
|
+
* without the slash, `slicer` matches `slicerCache`, `table` matches `pivotTable`, and a lookup
|
|
19
|
+
* quietly gathers a part class nobody asked for. Every caller used to spell the slash itself, ten
|
|
20
|
+
* times over, with nowhere to say why it was there.
|
|
21
|
+
*/
|
|
22
|
+
export declare function isRelType(type: string, name: string): boolean;
|
|
23
|
+
/** {@link isRelType} against several part classes at once, for the predicates that partition
|
|
24
|
+
* relationships into "modeled", "preserved verbatim", and "dropped". */
|
|
25
|
+
export declare function isAnyRelType(type: string, ...names: readonly string[]): boolean;
|
package/dist/rel-type.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function relTypeSegment(type) {
|
|
2
|
+
return type.slice(type.lastIndexOf('/') + 1);
|
|
3
|
+
}
|
|
4
|
+
export function isRelType(type, name) {
|
|
5
|
+
return type.endsWith(`/${name}`);
|
|
6
|
+
}
|
|
7
|
+
export function isAnyRelType(type, ...names) {
|
|
8
|
+
return names.some((name) => isRelType(type, name));
|
|
9
|
+
}
|
package/dist/token-set.d.ts
CHANGED
|
@@ -13,3 +13,16 @@
|
|
|
13
13
|
* expression instead of as its members.
|
|
14
14
|
*/
|
|
15
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/token-set.js
CHANGED
package/dist/vba/bytes.d.ts
CHANGED
|
@@ -1,11 +1,22 @@
|
|
|
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
|
+
/** Write a little-endian `uint32` over bytes already in `buf`, asserted rather than masked as {@link writeU16} is. */
|
|
13
|
+
export declare function writeU32(buf: Uint8Array, at: number, value: number): void;
|
|
14
|
+
/**
|
|
15
|
+
* Replace `src[start..end)` with `insert`, returning a new array.
|
|
16
|
+
*
|
|
17
|
+
* The three record edits the project editor makes are all this shape: splice a MODULE record block in,
|
|
18
|
+
* cut one out, cut a PROJECTwm entry out. Each was an allocate-and-copy-around written out longhand,
|
|
19
|
+
* and each had to get the same three offsets right; saying it once means the arithmetic is checked
|
|
20
|
+
* once. Passing no `insert` is a pure deletion, and `start === end` a pure insertion.
|
|
21
|
+
*/
|
|
22
|
+
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,31 @@ 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 writeU32(buf, at, value) {
|
|
33
|
+
if (!Number.isInteger(value) || value < 0 || value > 0xffff_ffff) {
|
|
34
|
+
throw new VbaParseError(`${value} does not fit the uint32 at offset ${at}`);
|
|
35
|
+
}
|
|
36
|
+
if (at + 3 >= buf.length)
|
|
37
|
+
throw truncated(at, 4, buf.length);
|
|
38
|
+
buf[at] = value & 0xff;
|
|
39
|
+
buf[at + 1] = (value >>> 8) & 0xff;
|
|
40
|
+
buf[at + 2] = (value >>> 16) & 0xff;
|
|
41
|
+
buf[at + 3] = (value >>> 24) & 0xff;
|
|
42
|
+
}
|
|
43
|
+
export function spliceBytes(src, start, end, insert = EMPTY) {
|
|
44
|
+
const out = new Uint8Array(src.length - (end - start) + insert.length);
|
|
45
|
+
out.set(src.subarray(0, start), 0);
|
|
46
|
+
out.set(insert, start);
|
|
47
|
+
out.set(src.subarray(end), start + insert.length);
|
|
48
|
+
return out;
|
|
29
49
|
}
|
|
50
|
+
const EMPTY = new Uint8Array(0);
|