@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
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ErrorCode } from '../../core/value.ts';
|
|
2
|
+
import { type CellMetadataIndex, type WorkbookMetadata } from '../cell-metadata/metadata.ts';
|
|
3
|
+
import type { PartRelationships } from '../opc/read-opc.ts';
|
|
4
|
+
/**
|
|
5
|
+
* What every `cm` and `vm` in the workbook resolves to: the metadata part and the two rich-value parts,
|
|
6
|
+
* each found through the workbook's relationships by type. Both worksheet readers resolve their cells
|
|
7
|
+
* through this one answer.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readCellMetadata(workbookRels: PartRelationships): CellMetadataIndex;
|
|
10
|
+
/** Read `xl/metadata.xml` as far as a cell's `cm` and `vm` reach into it. */
|
|
11
|
+
export declare function parseMetadataPart(xml: string): WorkbookMetadata;
|
|
12
|
+
/**
|
|
13
|
+
* Records what the cells written so far point into, so the metadata part and the rich-value parts are
|
|
14
|
+
* emitted only for a workbook that needs them. Filled during the sheet pass, as the shared-strings table
|
|
15
|
+
* is, because the streaming writer renders a row long before the package around it is assembled.
|
|
16
|
+
*/
|
|
17
|
+
export declare class WorkbookMetadataTable {
|
|
18
|
+
#private;
|
|
19
|
+
/** The `cm` a dynamic-array formula's cell is written with. Every such cell shares the one block. */
|
|
20
|
+
markDynamicArray(): number;
|
|
21
|
+
/**
|
|
22
|
+
* The `vm` a cell holding `error` is written with, beside a `<v>` of `#VALUE!`, or `undefined` for
|
|
23
|
+
* an error Excel reads literally, which needs no metadata.
|
|
24
|
+
*/
|
|
25
|
+
markRichValueError(error: ErrorCode): number | undefined;
|
|
26
|
+
/** Whether no cell points into the metadata part; the writer omits it entirely when so. */
|
|
27
|
+
get isEmpty(): boolean;
|
|
28
|
+
/** Whether a cell points at a rich value, so the rich-value parts are emitted beside the metadata. */
|
|
29
|
+
get hasRichValues(): boolean;
|
|
30
|
+
/** Serialise the `xl/metadata.xml` part, in the form Excel saves it. */
|
|
31
|
+
toXml(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Serialise `xl/richData/rdrichvalue.xml`: one rich value per error, in the order the `vm`s were handed
|
|
34
|
+
* out, each naming its `errorType` and the unknown sub-type, 0.
|
|
35
|
+
*/
|
|
36
|
+
richValuesXml(): string;
|
|
37
|
+
}
|
|
38
|
+
/** `xl/richData/rdrichvaluestructure.xml`: the one structure every rich value the writer emits has. */
|
|
39
|
+
export declare const RICH_VALUE_STRUCTURES_XML: string;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { numInteger } from '../../xml/xml-attrs.js';
|
|
2
|
+
import { parseXml } from '../../xml/xml-read.js';
|
|
3
|
+
import { boolStrict, localName } from '../../xml/xml-scan.js';
|
|
4
|
+
import { XML_DECLARATION } from '../../xml/xml.js';
|
|
5
|
+
import { DYNAMIC_ARRAY_TYPE, indexCellMetadata, RICH_VALUE_TYPE, } from '../cell-metadata/metadata.js';
|
|
6
|
+
import { ERROR_STRUCTURE, parseRichValueErrors, RICH_VALUE_ERROR_TYPES, } from '../cell-metadata/rich-values.js';
|
|
7
|
+
import { DYNAMIC_ARRAY_NS, DYNAMIC_ARRAY_PROPERTIES_EXT_URI, RICH_DATA_NS, RICH_VALUE_BLOCK_EXT_URI, SPREADSHEETML_NS, } from './namespaces.js';
|
|
8
|
+
export function readCellMetadata(workbookRels) {
|
|
9
|
+
return indexCellMetadata(parseMetadataPart(workbookRels.relatedText('sheetMetadata') ?? ''), parseRichValueErrors(workbookRels.relatedText('rdRichValueStructure') ?? '', workbookRels.relatedText('rdRichValue') ?? ''));
|
|
10
|
+
}
|
|
11
|
+
export function parseMetadataPart(xml) {
|
|
12
|
+
const typeNames = [];
|
|
13
|
+
const dynamicArrayBlocks = [];
|
|
14
|
+
const richValueBlocks = [];
|
|
15
|
+
const cellBlocks = [];
|
|
16
|
+
const valueBlocks = [];
|
|
17
|
+
let container;
|
|
18
|
+
const records = () => container === 'cells'
|
|
19
|
+
? cellBlocks.at(-1)
|
|
20
|
+
: container === 'values'
|
|
21
|
+
? valueBlocks.at(-1)
|
|
22
|
+
: undefined;
|
|
23
|
+
if (xml === '')
|
|
24
|
+
return { typeNames, dynamicArrayBlocks, richValueBlocks, cellBlocks, valueBlocks };
|
|
25
|
+
parseXml(xml, {
|
|
26
|
+
onOpen(name, attrs, selfClosing) {
|
|
27
|
+
switch (localName(name)) {
|
|
28
|
+
case 'metadataType':
|
|
29
|
+
typeNames.push(attrs.name ?? '');
|
|
30
|
+
break;
|
|
31
|
+
case 'futureMetadata':
|
|
32
|
+
container = selfClosing
|
|
33
|
+
? undefined
|
|
34
|
+
: attrs.name === DYNAMIC_ARRAY_TYPE
|
|
35
|
+
? 'dynamicArrays'
|
|
36
|
+
: attrs.name === RICH_VALUE_TYPE
|
|
37
|
+
? 'richValues'
|
|
38
|
+
: undefined;
|
|
39
|
+
break;
|
|
40
|
+
case 'cellMetadata':
|
|
41
|
+
container = selfClosing ? undefined : 'cells';
|
|
42
|
+
break;
|
|
43
|
+
case 'valueMetadata':
|
|
44
|
+
container = selfClosing ? undefined : 'values';
|
|
45
|
+
break;
|
|
46
|
+
case 'bk':
|
|
47
|
+
if (container === 'dynamicArrays')
|
|
48
|
+
dynamicArrayBlocks.push(false);
|
|
49
|
+
else if (container === 'richValues')
|
|
50
|
+
richValueBlocks.push(-1);
|
|
51
|
+
else if (container === 'cells')
|
|
52
|
+
cellBlocks.push([]);
|
|
53
|
+
else if (container === 'values')
|
|
54
|
+
valueBlocks.push([]);
|
|
55
|
+
break;
|
|
56
|
+
case 'dynamicArrayProperties':
|
|
57
|
+
if (container === 'dynamicArrays' && dynamicArrayBlocks.length > 0) {
|
|
58
|
+
dynamicArrayBlocks[dynamicArrayBlocks.length - 1] = boolStrict(attrs.fDynamic);
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case 'rvb':
|
|
62
|
+
if (container === 'richValues' && richValueBlocks.length > 0) {
|
|
63
|
+
richValueBlocks[richValueBlocks.length - 1] = numInteger(attrs.i, 0) ?? -1;
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
case 'rc': {
|
|
67
|
+
const block = records();
|
|
68
|
+
const type = numInteger(attrs.t, 1);
|
|
69
|
+
const value = numInteger(attrs.v, 0);
|
|
70
|
+
if (block !== undefined && type !== undefined && value !== undefined) {
|
|
71
|
+
block.push({ type, value });
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
onClose(name) {
|
|
80
|
+
const local = localName(name);
|
|
81
|
+
if (local === 'futureMetadata' || local === 'cellMetadata' || local === 'valueMetadata') {
|
|
82
|
+
container = undefined;
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
return { typeNames, dynamicArrayBlocks, richValueBlocks, cellBlocks, valueBlocks };
|
|
87
|
+
}
|
|
88
|
+
const METADATA_TYPE_FLAGS = 'minSupportedVersion="120000" copy="1" pasteAll="1" pasteValues="1" merge="1" splitFirst="1" ' +
|
|
89
|
+
'rowColShift="1" clearFormats="1" clearComments="1" assign="1" coerce="1"';
|
|
90
|
+
export class WorkbookMetadataTable {
|
|
91
|
+
#dynamicArrays = false;
|
|
92
|
+
#errors = new Map();
|
|
93
|
+
markDynamicArray() {
|
|
94
|
+
this.#dynamicArrays = true;
|
|
95
|
+
return 1;
|
|
96
|
+
}
|
|
97
|
+
markRichValueError(error) {
|
|
98
|
+
if (!RICH_VALUE_ERROR_TYPES.has(error))
|
|
99
|
+
return undefined;
|
|
100
|
+
const known = this.#errors.get(error);
|
|
101
|
+
if (known !== undefined)
|
|
102
|
+
return known;
|
|
103
|
+
const vm = this.#errors.size + 1;
|
|
104
|
+
this.#errors.set(error, vm);
|
|
105
|
+
return vm;
|
|
106
|
+
}
|
|
107
|
+
get isEmpty() {
|
|
108
|
+
return !this.#dynamicArrays && this.#errors.size === 0;
|
|
109
|
+
}
|
|
110
|
+
get hasRichValues() {
|
|
111
|
+
return this.#errors.size > 0;
|
|
112
|
+
}
|
|
113
|
+
toXml() {
|
|
114
|
+
const dynamic = this.#dynamicArrays;
|
|
115
|
+
const errorCount = this.#errors.size;
|
|
116
|
+
const types = [
|
|
117
|
+
...(dynamic
|
|
118
|
+
? [`<metadataType name="${DYNAMIC_ARRAY_TYPE}" ${METADATA_TYPE_FLAGS} cellMeta="1"/>`]
|
|
119
|
+
: []),
|
|
120
|
+
...(errorCount > 0
|
|
121
|
+
? [`<metadataType name="${RICH_VALUE_TYPE}" ${METADATA_TYPE_FLAGS}/>`]
|
|
122
|
+
: []),
|
|
123
|
+
];
|
|
124
|
+
const richValueType = types.length;
|
|
125
|
+
const indices = Array.from({ length: errorCount }, (_, index) => index);
|
|
126
|
+
return (XML_DECLARATION +
|
|
127
|
+
`<metadata xmlns="${SPREADSHEETML_NS}"` +
|
|
128
|
+
(errorCount > 0 ? ` xmlns:xlrd="${RICH_DATA_NS}"` : '') +
|
|
129
|
+
(dynamic ? ` xmlns:xda="${DYNAMIC_ARRAY_NS}"` : '') +
|
|
130
|
+
'>' +
|
|
131
|
+
`<metadataTypes count="${types.length}">${types.join('')}</metadataTypes>` +
|
|
132
|
+
(dynamic
|
|
133
|
+
? `<futureMetadata name="${DYNAMIC_ARRAY_TYPE}" count="1"><bk><extLst>` +
|
|
134
|
+
`<ext uri="${DYNAMIC_ARRAY_PROPERTIES_EXT_URI}">` +
|
|
135
|
+
'<xda:dynamicArrayProperties fDynamic="1" fCollapsed="0"/>' +
|
|
136
|
+
'</ext></extLst></bk></futureMetadata>'
|
|
137
|
+
: '') +
|
|
138
|
+
(errorCount > 0
|
|
139
|
+
? `<futureMetadata name="${RICH_VALUE_TYPE}" count="${errorCount}">` +
|
|
140
|
+
indices
|
|
141
|
+
.map((index) => `<bk><extLst><ext uri="${RICH_VALUE_BLOCK_EXT_URI}"><xlrd:rvb i="${index}"/></ext></extLst></bk>`)
|
|
142
|
+
.join('') +
|
|
143
|
+
'</futureMetadata>'
|
|
144
|
+
: '') +
|
|
145
|
+
(dynamic ? '<cellMetadata count="1"><bk><rc t="1" v="0"/></bk></cellMetadata>' : '') +
|
|
146
|
+
(errorCount > 0
|
|
147
|
+
? `<valueMetadata count="${errorCount}">` +
|
|
148
|
+
indices.map((index) => `<bk><rc t="${richValueType}" v="${index}"/></bk>`).join('') +
|
|
149
|
+
'</valueMetadata>'
|
|
150
|
+
: '') +
|
|
151
|
+
'</metadata>');
|
|
152
|
+
}
|
|
153
|
+
richValuesXml() {
|
|
154
|
+
const values = [...this.#errors.keys()].map((error) => `<rv s="0"><v>${RICH_VALUE_ERROR_TYPES.get(error)}</v><v>0</v></rv>`);
|
|
155
|
+
return (XML_DECLARATION +
|
|
156
|
+
`<rvData xmlns="${RICH_DATA_NS}" count="${values.length}">${values.join('')}</rvData>`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
export const RICH_VALUE_STRUCTURES_XML = XML_DECLARATION +
|
|
160
|
+
`<rvStructures xmlns="${RICH_DATA_NS}" count="1">` +
|
|
161
|
+
`<s t="${ERROR_STRUCTURE}"><k n="errorType" t="i"/><k n="subType" t="i"/></s>` +
|
|
162
|
+
'</rvStructures>';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type DateEpoch } from '../../core/date.ts';
|
|
2
|
+
import { type CellValue, type ErrorCode, type FormulaResult, type RichTextRun, type RichTextValue } from '../../core/value.ts';
|
|
2
3
|
/**
|
|
3
4
|
* One entry of the shared-strings pool. A `<si>` built from a bare `<t>` is a plain string; a `<si>`
|
|
4
5
|
* built from `<r>` runs is rich text, so a `t="s"` cell can resolve to either kind, and rich text
|
|
@@ -11,8 +12,17 @@ export interface RawCell {
|
|
|
11
12
|
readonly type: string;
|
|
12
13
|
readonly hasFormula: boolean;
|
|
13
14
|
readonly formula: string;
|
|
15
|
+
/** The range an `<f t="array">` fills when it starts at this cell, as Excel spells a `ref`. */
|
|
16
|
+
readonly arrayRef?: string | undefined;
|
|
17
|
+
/** Whether the cell's `cm` points at cell metadata marking a dynamic array. */
|
|
18
|
+
readonly dynamicArray?: boolean;
|
|
19
|
+
/** The error the cell's `vm` names through a rich value, which is the error a `t="e"` cell holds. */
|
|
20
|
+
readonly valueError?: ErrorCode | undefined;
|
|
21
|
+
/** Whether a `<v>` was present, `<v/>` included. */
|
|
14
22
|
readonly hasValue: boolean;
|
|
15
23
|
readonly valueText: string;
|
|
24
|
+
/** Whether an `<is>` was present, `<is/>` included. */
|
|
25
|
+
readonly hasInlineString: boolean;
|
|
16
26
|
readonly inlineText: string;
|
|
17
27
|
/** The formatted runs of a rich inline string, when the `<is>` held `<r>` elements rather than a
|
|
18
28
|
* bare `<t>`. Absent (or empty) for a plain inline string, which decodes to `inlineText`. */
|
|
@@ -20,13 +30,17 @@ export interface RawCell {
|
|
|
20
30
|
}
|
|
21
31
|
/**
|
|
22
32
|
* Decode a gathered cell into its model value. A formula cell becomes a `{formula, result?}`
|
|
23
|
-
* object (the on-disk `_xlfn.`/`_xlpm.` mangling stripped back to the readable name)
|
|
33
|
+
* object (the on-disk `_xlfn.`/`_xlpm.` mangling stripped back to the readable name), or an array
|
|
34
|
+
* formula over its range, dynamic when the cell's metadata says so; a plain
|
|
24
35
|
* numeric cell under a date number format becomes a {@link Date}; everything else decodes by its
|
|
25
|
-
* `t` type. `numFmt` is the cell's resolved number-format code, used only for date detection
|
|
36
|
+
* `t` type. `numFmt` is the cell's resolved number-format code, used only for date detection, and
|
|
37
|
+
* `epoch` the workbook's date system, which is what a serial under such a format counts from.
|
|
38
|
+
* `definedNames` is the workbook's defined names as `definedNameKeys` spells them, which decide whether
|
|
39
|
+
* a function passed as a value sheds its `_xleta.`.
|
|
26
40
|
*/
|
|
27
|
-
export declare function decodeCellContent(raw: RawCell, sharedStrings: readonly SharedString[], numFmt: string | undefined): CellValue;
|
|
41
|
+
export declare function decodeCellContent(raw: RawCell, sharedStrings: readonly SharedString[], numFmt: string | undefined, epoch: DateEpoch, definedNames: ReadonlySet<string>): CellValue;
|
|
28
42
|
/** Decode a formula's cached `<v>` result by its `t` type, coercing a numeric result under a date
|
|
29
43
|
* `numFmt` to a {@link Date} exactly as a bare numeric cell is, so a date-valued formula result
|
|
30
44
|
* (e.g. `TODAY()`) reads back as a Date, not a serial. Shared by the buffered reader's shared-formula
|
|
31
45
|
* clone resolution, which caches a result the same way a plain formula cell does. */
|
|
32
|
-
export declare function decodeFormulaResult(type: string, valueText: string, numFmt?:
|
|
46
|
+
export declare function decodeFormulaResult(type: string, valueText: string, numFmt: string | undefined, epoch: DateEpoch, valueError?: ErrorCode): FormulaResult | undefined;
|
|
@@ -1,58 +1,73 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { coerceDateSerial, parseDateText } from '../../core/date.js';
|
|
2
2
|
import { unmangleFunctions } from '../../core/formula.js';
|
|
3
3
|
import { isErrorCode, } from '../../core/value.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import { decodeSpreadsheetText, numFinite, numInteger } from '../../xml/xml-attrs.js';
|
|
5
|
+
import { boolTristate } from '../../xml/xml-scan.js';
|
|
6
|
+
export function decodeCellContent(raw, sharedStrings, numFmt, epoch, definedNames) {
|
|
6
7
|
if (raw.hasFormula) {
|
|
7
|
-
const stored = unmangleFunctions(raw.formula);
|
|
8
|
-
const result = raw.hasValue
|
|
9
|
-
|
|
8
|
+
const stored = unmangleFunctions(raw.formula, definedNames);
|
|
9
|
+
const result = raw.hasValue
|
|
10
|
+
? decodeFormulaResult(raw.type, raw.valueText, numFmt, epoch, raw.valueError)
|
|
11
|
+
: undefined;
|
|
12
|
+
const cached = result === undefined ? {} : { result };
|
|
13
|
+
if (raw.arrayRef !== undefined) {
|
|
14
|
+
return {
|
|
15
|
+
shareType: 'array',
|
|
16
|
+
formula: stored,
|
|
17
|
+
ref: raw.arrayRef,
|
|
18
|
+
...(raw.dynamicArray === true ? { dynamic: true } : {}),
|
|
19
|
+
...cached,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return { formula: stored, ...cached };
|
|
10
23
|
}
|
|
11
24
|
if (raw.type === 'inlineStr' && raw.richTextRuns !== undefined && raw.richTextRuns.length > 0) {
|
|
12
25
|
return { richText: raw.richTextRuns };
|
|
13
26
|
}
|
|
14
|
-
const value = decodeValue(raw
|
|
15
|
-
return
|
|
16
|
-
? serialToDate(value)
|
|
17
|
-
: value;
|
|
27
|
+
const value = decodeValue(raw, sharedStrings);
|
|
28
|
+
return coerceDateSerial(value, numFmt, epoch);
|
|
18
29
|
}
|
|
19
|
-
function decodeValue(
|
|
20
|
-
|
|
30
|
+
function decodeValue(raw, sharedStrings) {
|
|
31
|
+
const { valueText } = raw;
|
|
32
|
+
switch (raw.type) {
|
|
21
33
|
case 'inlineStr':
|
|
22
|
-
return inlineText;
|
|
34
|
+
return raw.hasInlineString ? raw.inlineText : null;
|
|
23
35
|
case 'str':
|
|
24
|
-
return decodeSpreadsheetText(valueText);
|
|
36
|
+
return raw.hasValue ? decodeSpreadsheetText(valueText) : null;
|
|
25
37
|
case 'd':
|
|
26
|
-
return
|
|
38
|
+
return parseDateText(valueText);
|
|
27
39
|
case 's': {
|
|
28
|
-
const index =
|
|
29
|
-
return
|
|
40
|
+
const index = numInteger(valueText, 0);
|
|
41
|
+
return index === undefined ? null : (sharedStrings[index] ?? null);
|
|
30
42
|
}
|
|
31
43
|
case 'b':
|
|
32
|
-
return
|
|
44
|
+
return boolTristate(valueText) ?? null;
|
|
33
45
|
case 'e':
|
|
34
|
-
|
|
35
|
-
default: {
|
|
36
|
-
if (!hasValue)
|
|
46
|
+
if (valueText === '')
|
|
37
47
|
return null;
|
|
48
|
+
return errorOf(valueText, raw.valueError);
|
|
49
|
+
default:
|
|
38
50
|
return numFinite(valueText) ?? null;
|
|
39
|
-
}
|
|
40
51
|
}
|
|
41
52
|
}
|
|
42
|
-
export function decodeFormulaResult(type, valueText, numFmt) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
export function decodeFormulaResult(type, valueText, numFmt, epoch, valueError) {
|
|
54
|
+
return coerceDateSerial(decodeResult(type, valueText, valueError), numFmt, epoch);
|
|
55
|
+
}
|
|
56
|
+
function errorOf(valueText, valueError) {
|
|
57
|
+
if (valueError !== undefined)
|
|
58
|
+
return { error: valueError };
|
|
59
|
+
return isErrorCode(valueText) ? { error: valueText } : valueText;
|
|
47
60
|
}
|
|
48
|
-
function decodeResult(type, valueText) {
|
|
61
|
+
function decodeResult(type, valueText, valueError) {
|
|
49
62
|
switch (type) {
|
|
50
63
|
case 'str':
|
|
51
64
|
return decodeSpreadsheetText(valueText);
|
|
52
65
|
case 'b':
|
|
53
|
-
return
|
|
66
|
+
return boolTristate(valueText);
|
|
54
67
|
case 'e':
|
|
55
|
-
|
|
68
|
+
if (valueText === '')
|
|
69
|
+
return undefined;
|
|
70
|
+
return errorOf(valueText, valueError);
|
|
56
71
|
default:
|
|
57
72
|
return numFinite(valueText);
|
|
58
73
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { parseArgb } from '../../core/style.js';
|
|
2
|
-
import {
|
|
2
|
+
import { quoted } from '../../errors.js';
|
|
3
|
+
import { numFinite, numInteger } from '../../xml/xml-attrs.js';
|
|
3
4
|
import { numberText } from '../../xml/xml.js';
|
|
4
5
|
function normalizeArgb(argb) {
|
|
5
6
|
const rgb = parseArgb(argb);
|
|
6
7
|
if (rgb === undefined) {
|
|
7
|
-
throw new SyntaxError(`
|
|
8
|
+
throw new SyntaxError(`invalid ARGB colour ${quoted(argb)}: expected 6 or 8 hexadecimal digits`);
|
|
8
9
|
}
|
|
9
10
|
return rgb;
|
|
10
11
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { XmlAttributes } from '../../xml/xml-scan.ts';
|
|
2
|
+
import { type ColumnRecordBudget } from '../read-policy/column-budget.ts';
|
|
3
|
+
/**
|
|
4
|
+
* The columns a `<col min max>` element actually applies to, or `undefined` for one that applies to
|
|
5
|
+
* none: unreadable bounds, or anything {@link clampColumnSpan} refuses. Both XML worksheet readers
|
|
6
|
+
* ask this, so the two cannot read one `<col>` as covering different columns.
|
|
7
|
+
*/
|
|
8
|
+
export declare function takeColumnSpan(attrs: XmlAttributes, budget: ColumnRecordBudget): {
|
|
9
|
+
first: number;
|
|
10
|
+
last: number;
|
|
11
|
+
} | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { numInteger } from '../../xml/xml-attrs.js';
|
|
2
|
+
import { clampColumnSpan } from '../read-policy/column-budget.js';
|
|
3
|
+
export function takeColumnSpan(attrs, budget) {
|
|
4
|
+
const first = numInteger(attrs.min, 1);
|
|
5
|
+
const last = numInteger(attrs.max, 1);
|
|
6
|
+
if (first === undefined || last === undefined)
|
|
7
|
+
return undefined;
|
|
8
|
+
return clampColumnSpan(first, last, budget);
|
|
9
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import type { Cell } from '../../core/cell.ts';
|
|
1
2
|
import type { CommentThread } from '../../core/comment-thread.ts';
|
|
2
3
|
import type { Worksheet } from '../../core/worksheet.ts';
|
|
3
|
-
/** A comment bound for `comments{n}.xml`, paired with the coordinates the VML anchor needs.
|
|
4
|
+
/** A comment bound for `comments{n}.xml`, paired with the coordinates the VML anchor needs.
|
|
5
|
+
*/
|
|
4
6
|
export interface CommentCell {
|
|
5
7
|
readonly ref: string;
|
|
6
8
|
/** 1-based row of the commented cell. */
|
|
@@ -28,7 +30,9 @@ export interface CommentCell {
|
|
|
28
30
|
* Ordered by cell, row-major, the way Excel writes the list, so a fallback lands interleaved among the
|
|
29
31
|
* notes rather than appended after them, and the VML shapes follow the same order.
|
|
30
32
|
*/
|
|
31
|
-
export declare function collectComments(
|
|
33
|
+
export declare function collectComments(cells: Iterable<Cell>, threads: readonly CommentThread[], alreadyCollected?: readonly CommentCell[]): CommentCell[];
|
|
34
|
+
/** The notes among a run of cells, for a writer that must ask before the cells are evicted. */
|
|
35
|
+
export declare function collectNotes(cells: Iterable<Cell>): CommentCell[];
|
|
32
36
|
/**
|
|
33
37
|
* The `xl/comments{n}.xml` part.
|
|
34
38
|
*
|
|
@@ -44,31 +48,6 @@ export declare function commentsXml(comments: readonly CommentCell[]): string;
|
|
|
44
48
|
* pixel-exact layout. A thread's fallback shape is `ObjectType="Note"` like any other: Excel draws the
|
|
45
49
|
* threaded-comment card itself and only needs the shape to exist. */
|
|
46
50
|
export declare function vmlDrawingXml(comments: readonly CommentCell[]): string;
|
|
47
|
-
/**
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* The thread head id this comment is the legacy fallback for, read off its synthetic `tc={headId}`
|
|
52
|
-
* author; absent for a user's own note.
|
|
53
|
-
*/
|
|
54
|
-
readonly threadId?: string;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Parse a `comments{n}.xml` part into a map of A1 reference → comment. Text runs within one comment are
|
|
58
|
-
* concatenated; an author-name run is Excel's own convention and is not stripped, so a note reads back
|
|
59
|
-
* as exactly the text that was written.
|
|
60
|
-
*/
|
|
61
|
-
export declare function parseComments(xml: string): Map<string, ParsedComment>;
|
|
62
|
-
/**
|
|
63
|
-
* Apply a parsed comments part onto a sheet's cells as notes, addressing each by its A1 reference.
|
|
64
|
-
*
|
|
65
|
-
* A thread's legacy fallback is not a note and does not become one: its text is boilerplate wrapping a
|
|
66
|
-
* copy of the conversation, so surfacing it as `cell.note` hands the caller garbage, and on write it
|
|
67
|
-
* would be re-emitted as a plain note, destroying the `tc=`/`xr:uid` binding and leaving Excel unable to
|
|
68
|
-
* see the thread at all.
|
|
69
|
-
*
|
|
70
|
-
* Suppressed only for a conversation the reader actually holds: a file whose thread part is missing or
|
|
71
|
-
* damaged has nothing else left, so there the boilerplate is kept rather than the content lost. Call
|
|
72
|
-
* after the sheet's threads are restored, since that is what this reads to decide.
|
|
73
|
-
*/
|
|
74
|
-
export declare function applyNotes(sheet: Worksheet, comments: ReadonlyMap<string, ParsedComment>): void;
|
|
51
|
+
/** Every cell a sheet still holds, row-major: what the writer gathers a sheet's notes from, beside the
|
|
52
|
+
* notes the streaming writer took off the rows it already flushed. */
|
|
53
|
+
export declare function liveCells(sheet: Worksheet): Generator<Cell, void, undefined>;
|
package/dist/io/xlsx/comments.js
CHANGED
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
import { tryDecodeCellRef } from '../../core/address.js';
|
|
2
|
-
import { parseXml } from '../../xml/xml-read.js';
|
|
3
|
-
import { decodeSpreadsheetText, localName, numInteger } from '../../xml/xml-scan.js';
|
|
4
2
|
import { escapeText, textAttr, textElement, XML_DECLARATION } from '../../xml/xml.js';
|
|
5
3
|
import { MARKUP_COMPATIBILITY_NS, REVISION_NS, SPREADSHEETML_NS } from './namespaces.js';
|
|
6
|
-
export function collectComments(
|
|
4
|
+
export function collectComments(cells, threads, alreadyCollected = []) {
|
|
7
5
|
const fallbacks = threadFallbacks(threads);
|
|
8
6
|
const anchored = new Set(fallbacks.map((fallback) => fallback.ref));
|
|
9
|
-
const comments = [...fallbacks];
|
|
10
|
-
for (const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
const comments = [...fallbacks, ...alreadyCollected];
|
|
8
|
+
for (const cell of cells) {
|
|
9
|
+
if (cell.note === undefined || anchored.has(cell.address))
|
|
10
|
+
continue;
|
|
11
|
+
comments.push(noteOn(cell, cell.note));
|
|
12
|
+
}
|
|
13
|
+
return comments
|
|
14
|
+
.filter((comment) => comment.threadId !== undefined || !anchored.has(comment.ref))
|
|
15
|
+
.sort((a, b) => a.row - b.row || a.col - b.col);
|
|
16
|
+
}
|
|
17
|
+
export function collectNotes(cells) {
|
|
18
|
+
const notes = [];
|
|
19
|
+
for (const cell of cells) {
|
|
20
|
+
if (cell.note !== undefined)
|
|
21
|
+
notes.push(noteOn(cell, cell.note));
|
|
16
22
|
}
|
|
17
|
-
return
|
|
23
|
+
return notes;
|
|
24
|
+
}
|
|
25
|
+
function noteOn(cell, text) {
|
|
26
|
+
return { ref: cell.address, row: cell.row, col: cell.col, text };
|
|
18
27
|
}
|
|
19
28
|
function threadFallbacks(threads) {
|
|
20
29
|
const fallbacks = [];
|
|
@@ -76,13 +85,14 @@ const VML_HEADER = '<xml xmlns:v="urn:schemas-microsoft-com:vml" ' +
|
|
|
76
85
|
'<v:shapetype id="_x0000_t202" coordsize="21600,21600" o:spt="202" ' +
|
|
77
86
|
'path="m,l,21600r21600,l21600,xe"><v:stroke joinstyle="miter"/>' +
|
|
78
87
|
'<v:path gradientshapeok="t" o:connecttype="rect"/></v:shapetype>';
|
|
88
|
+
const FIRST_SHAPE_ID = 1025;
|
|
79
89
|
export function vmlDrawingXml(comments) {
|
|
80
90
|
const shapes = comments
|
|
81
91
|
.map((comment, i) => {
|
|
82
92
|
const row0 = comment.row - 1;
|
|
83
93
|
const col0 = comment.col - 1;
|
|
84
94
|
const anchor = `${col0 + 1}, 15, ${row0}, 2, ${col0 + 3}, 15, ${row0 + 4}, 4`;
|
|
85
|
-
return (`<v:shape id="_x0000_s${
|
|
95
|
+
return (`<v:shape id="_x0000_s${FIRST_SHAPE_ID + i}" type="#_x0000_t202" ` +
|
|
86
96
|
'style="position:absolute;margin-left:59.25pt;margin-top:1.5pt;width:108pt;height:59.25pt;' +
|
|
87
97
|
`z-index:${i + 1};visibility:hidden" fillcolor="#ffffe1" o:insetmode="auto">` +
|
|
88
98
|
'<v:fill color2="#ffffe1"/><v:shadow on="t" color="black" obscured="t"/>' +
|
|
@@ -95,75 +105,7 @@ export function vmlDrawingXml(comments) {
|
|
|
95
105
|
.join('');
|
|
96
106
|
return `${VML_HEADER}${shapes}</xml>`;
|
|
97
107
|
}
|
|
98
|
-
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
const comments = new Map();
|
|
102
|
-
const authors = [];
|
|
103
|
-
let currentRef;
|
|
104
|
-
let currentAuthorId;
|
|
105
|
-
let capture;
|
|
106
|
-
let buffer = '';
|
|
107
|
-
parseXml(xml, {
|
|
108
|
-
onOpen(name, attrs) {
|
|
109
|
-
const local = localName(name);
|
|
110
|
-
if (local === 'comment') {
|
|
111
|
-
currentRef = attrs.ref;
|
|
112
|
-
currentAuthorId = attrs.authorId;
|
|
113
|
-
buffer = '';
|
|
114
|
-
}
|
|
115
|
-
else if (local === 'author') {
|
|
116
|
-
capture = 'author';
|
|
117
|
-
buffer = '';
|
|
118
|
-
}
|
|
119
|
-
else if (local === 'text') {
|
|
120
|
-
capture = 'text';
|
|
121
|
-
}
|
|
122
|
-
},
|
|
123
|
-
onText(text) {
|
|
124
|
-
if (capture !== undefined)
|
|
125
|
-
buffer += text;
|
|
126
|
-
},
|
|
127
|
-
onClose(name) {
|
|
128
|
-
const local = localName(name);
|
|
129
|
-
if (local === 'author') {
|
|
130
|
-
authors.push(buffer);
|
|
131
|
-
capture = undefined;
|
|
132
|
-
buffer = '';
|
|
133
|
-
}
|
|
134
|
-
else if (local === 'text') {
|
|
135
|
-
buffer = decodeSpreadsheetText(buffer);
|
|
136
|
-
capture = undefined;
|
|
137
|
-
}
|
|
138
|
-
else if (local === 'comment' && currentRef !== undefined) {
|
|
139
|
-
const threadId = threadIdOf(authors[numInteger(currentAuthorId, 0) ?? -1]);
|
|
140
|
-
comments.set(currentRef, {
|
|
141
|
-
text: buffer,
|
|
142
|
-
...(threadId !== undefined ? { threadId } : {}),
|
|
143
|
-
});
|
|
144
|
-
currentRef = undefined;
|
|
145
|
-
currentAuthorId = undefined;
|
|
146
|
-
}
|
|
147
|
-
},
|
|
148
|
-
}, { closeEmptyElements: COMMENT_EMPTY_CLOSES });
|
|
149
|
-
return comments;
|
|
150
|
-
}
|
|
151
|
-
function threadIdOf(author) {
|
|
152
|
-
if (author === undefined || !author.startsWith(THREAD_AUTHOR_PREFIX))
|
|
153
|
-
return undefined;
|
|
154
|
-
const id = author.slice(THREAD_AUTHOR_PREFIX.length);
|
|
155
|
-
return id === '' ? undefined : id;
|
|
156
|
-
}
|
|
157
|
-
export function applyNotes(sheet, comments) {
|
|
158
|
-
const headIds = new Set(sheet.commentThreads.flatMap((thread) => {
|
|
159
|
-
const head = thread.comments[0];
|
|
160
|
-
return head === undefined ? [] : [head.id];
|
|
161
|
-
}));
|
|
162
|
-
for (const [ref, comment] of comments) {
|
|
163
|
-
if (comment.threadId !== undefined && headIds.has(comment.threadId))
|
|
164
|
-
continue;
|
|
165
|
-
if (tryDecodeCellRef(ref) === undefined)
|
|
166
|
-
continue;
|
|
167
|
-
sheet.getCell(ref).note = comment.text;
|
|
168
|
-
}
|
|
108
|
+
export function* liveCells(sheet) {
|
|
109
|
+
for (const { cells } of sheet.rows())
|
|
110
|
+
yield* cells;
|
|
169
111
|
}
|