@shbernal/ts-xlsx 3.1.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 +30 -23
- package/dist/bytes.d.ts +3 -2
- package/dist/core/address.d.ts +36 -0
- package/dist/core/address.js +47 -9
- package/dist/core/array-formula-ranges.d.ts +33 -0
- package/dist/core/array-formula-ranges.js +62 -0
- package/dist/core/color-resolution.js +2 -2
- package/dist/core/column.js +3 -2
- package/dist/core/comment-thread.d.ts +7 -3
- package/dist/core/conditional-formatting-overlay.d.ts +9 -0
- package/dist/core/conditional-formatting-overlay.js +28 -1
- package/dist/core/conditional-formatting.d.ts +98 -10
- package/dist/core/conditional-formatting.js +42 -1
- package/dist/core/data-validation-overlay.d.ts +5 -0
- package/dist/core/data-validation-overlay.js +15 -0
- package/dist/core/data-validation.d.ts +16 -0
- package/dist/core/data-validation.js +15 -0
- package/dist/core/date-format.js +14 -4
- package/dist/core/date.js +1 -1
- 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 +51 -18
- package/dist/core/formula.js +77 -86
- 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 +28 -0
- package/dist/core/grid-edits.js +193 -25
- package/dist/core/hyperlink.d.ts +39 -0
- package/dist/core/hyperlink.js +88 -0
- package/dist/core/image.d.ts +36 -5
- package/dist/core/image.js +9 -0
- package/dist/core/internal.d.ts +3 -1
- package/dist/core/limits.d.ts +5 -3
- package/dist/core/merge.d.ts +13 -0
- package/dist/core/merge.js +15 -1
- package/dist/core/page-setup.d.ts +26 -11
- package/dist/core/pivot-table.d.ts +49 -10
- package/dist/core/pivot-table.js +55 -21
- package/dist/core/protection.d.ts +66 -4
- package/dist/core/protection.js +4 -0
- package/dist/core/row.js +3 -2
- package/dist/core/structured-reference.d.ts +7 -0
- package/dist/core/structured-reference.js +7 -0
- package/dist/core/table.d.ts +38 -8
- package/dist/core/table.js +37 -7
- package/dist/core/theme.d.ts +2 -0
- package/dist/core/theme.js +4 -1
- package/dist/core/value.d.ts +51 -28
- package/dist/core/value.js +15 -12
- package/dist/core/workbook-styles.d.ts +17 -1
- package/dist/core/workbook-styles.js +4 -0
- package/dist/core/workbook-theme.js +5 -3
- package/dist/core/workbook.d.ts +20 -3
- package/dist/core/workbook.js +26 -5
- package/dist/core/worksheet-merges.d.ts +9 -4
- package/dist/core/worksheet-merges.js +17 -11
- package/dist/core/worksheet-model.d.ts +1 -1
- package/dist/core/worksheet-model.js +4 -0
- package/dist/core/worksheet-pictures.d.ts +3 -3
- package/dist/core/worksheet-pictures.js +7 -6
- package/dist/core/worksheet.d.ts +110 -21
- package/dist/core/worksheet.js +174 -49
- package/dist/entries/core.d.ts +7 -5
- package/dist/entries/core.js +4 -3
- package/dist/entries/errors.d.ts +1 -0
- package/dist/entries/errors.js +1 -0
- package/dist/errors.js +1 -1
- 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 +14 -2
- package/dist/io/csv/delimiter.js +12 -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 +46 -24
- package/dist/io/csv/write.d.ts +10 -3
- package/dist/io/csv/write.js +16 -7
- package/dist/io/opc/part-paths.js +4 -4
- package/dist/io/opc/read-opc.d.ts +4 -0
- package/dist/io/opc/read-opc.js +10 -4
- 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/{xlsx → read-policy}/column-budget.js +4 -8
- 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/xlsb/formula.js +4 -2
- package/dist/io/xlsb/ptg-functions.js +110 -0
- package/dist/io/xlsb/read-metadata.d.ts +7 -0
- package/dist/io/xlsb/read-metadata.js +69 -0
- package/dist/io/xlsb/read-worksheet.d.ts +6 -0
- package/dist/io/xlsb/read-worksheet.js +95 -37
- package/dist/io/xlsb/read.js +26 -8
- package/dist/io/xlsb/record-types.d.ts +13 -0
- package/dist/io/xlsb/record-types.js +13 -0
- 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 +20 -12
- package/dist/io/xlsx/cell-accumulator.js +49 -19
- 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 +16 -4
- package/dist/io/xlsx/cell-value.js +38 -21
- package/dist/io/xlsx/color-xml.js +1 -1
- 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 +3 -28
- package/dist/io/xlsx/comments.js +3 -65
- package/dist/io/xlsx/conditional-formatting.d.ts +42 -25
- package/dist/io/xlsx/conditional-formatting.js +424 -129
- package/dist/io/xlsx/data-validation.d.ts +12 -7
- package/dist/io/xlsx/data-validation.js +41 -29
- package/dist/io/xlsx/edit-vba.js +43 -36
- package/dist/io/xlsx/hyperlinks.d.ts +16 -50
- package/dist/io/xlsx/hyperlinks.js +8 -37
- package/dist/io/xlsx/images.d.ts +49 -16
- package/dist/io/xlsx/images.js +145 -44
- package/dist/io/xlsx/namespaces.d.ts +8 -0
- package/dist/io/xlsx/namespaces.js +4 -0
- package/dist/io/xlsx/package-plan.d.ts +48 -15
- package/dist/io/xlsx/package-plan.js +46 -9
- 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 +23 -22
- 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 +2 -2
- package/dist/io/xlsx/read-parts.js +44 -37
- package/dist/io/xlsx/read-pivot.js +9 -3
- package/dist/io/xlsx/read-rich-runs.d.ts +8 -5
- package/dist/io/xlsx/read-rich-runs.js +18 -1
- package/dist/io/xlsx/read-rows.d.ts +18 -7
- package/dist/io/xlsx/read-rows.js +47 -37
- package/dist/io/xlsx/read-styles.d.ts +0 -25
- package/dist/io/xlsx/read-styles.js +39 -34
- package/dist/io/xlsx/read-workbook-xml.d.ts +6 -0
- package/dist/io/xlsx/read-workbook-xml.js +9 -4
- package/dist/io/xlsx/read-worksheet.d.ts +8 -3
- package/dist/io/xlsx/read-worksheet.js +45 -23
- package/dist/io/xlsx/read.d.ts +0 -4
- package/dist/io/xlsx/read.js +17 -21
- package/dist/io/xlsx/relationships.d.ts +3 -0
- package/dist/io/xlsx/relationships.js +4 -0
- package/dist/io/xlsx/row-position.d.ts +3 -1
- package/dist/io/xlsx/row-xml.d.ts +18 -7
- package/dist/io/xlsx/row-xml.js +54 -35
- package/dist/io/xlsx/sheet-properties.js +68 -42
- 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 +0 -2
- package/dist/io/xlsx/style-elements.js +9 -29
- package/dist/io/xlsx/styles.d.ts +5 -0
- package/dist/io/xlsx/styles.js +11 -5
- package/dist/io/xlsx/tables.d.ts +10 -2
- package/dist/io/xlsx/tables.js +49 -42
- package/dist/io/xlsx/theme-xml.d.ts +6 -0
- package/dist/io/xlsx/theme-xml.js +16 -19
- package/dist/io/xlsx/threaded-comments.d.ts +6 -1
- package/dist/io/xlsx/threaded-comments.js +14 -7
- package/dist/io/xlsx/workbook-xml.d.ts +13 -24
- package/dist/io/xlsx/workbook-xml.js +15 -33
- package/dist/io/xlsx/worksheet-xml.d.ts +5 -2
- package/dist/io/xlsx/worksheet-xml.js +37 -69
- package/dist/io/xlsx/write-stream.d.ts +28 -6
- package/dist/io/xlsx/write-stream.js +42 -17
- package/dist/io/xlsx/write.d.ts +11 -4
- package/dist/io/xlsx/write.js +153 -90
- package/dist/rel-type.d.ts +9 -0
- package/dist/rel-type.js +3 -0
- package/dist/vba/bytes.d.ts +2 -0
- package/dist/vba/bytes.js +11 -0
- package/dist/vba/cfb-format.d.ts +47 -0
- package/dist/vba/cfb-format.js +34 -0
- package/dist/vba/cfb-writer.d.ts +1 -2
- package/dist/vba/cfb-writer.js +33 -36
- package/dist/vba/cfb.d.ts +9 -4
- package/dist/vba/cfb.js +55 -43
- package/dist/vba/dir-records.d.ts +6 -0
- package/dist/vba/dir-records.js +10 -2
- package/dist/vba/errors.d.ts +4 -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 +15 -6
- package/dist/vba/project-editor.js +102 -87
- package/dist/vba/project.d.ts +4 -0
- package/dist/vba/project.js +12 -6
- package/dist/vba/vba-encoding.d.ts +4 -10
- package/dist/vba/vba-encoding.js +2 -15
- package/dist/xml/xml-read.d.ts +29 -1
- package/dist/xml/xml-read.js +56 -0
- package/dist/xml/xml-scan.d.ts +13 -0
- package/dist/xml/xml-scan.js +58 -7
- package/dist/xml/xml.d.ts +33 -1
- package/dist/xml/xml.js +22 -0
- package/package.json +5 -4
- package/skills/ts-xlsx-upstream/SKILL.md +21 -13
- package/dist/core/modern-functions.d.ts +0 -1
- package/dist/io/xlsx/cell-style-resolution.d.ts +0 -25
- package/dist/io/xlsx/cell-style-resolution.js +0 -29
- package/dist/io/xlsx/column-budget.d.ts +0 -26
- package/dist/io/xlsx/read-repair.d.ts +0 -26
- package/dist/io/xlsx/read-repair.js +0 -39
|
@@ -2,7 +2,11 @@ import { type AutoFilter } from './autofilter.ts';
|
|
|
2
2
|
import { Cell } from './cell.ts';
|
|
3
3
|
import type { ConditionalFormattingOverlay } from './conditional-formatting-overlay.ts';
|
|
4
4
|
import type { DataValidationOverlay } from './data-validation-overlay.ts';
|
|
5
|
+
import { type SheetSplice } from './formula-references.ts';
|
|
6
|
+
import type { HyperlinkOverlay } from './hyperlink.ts';
|
|
5
7
|
import { type AnchoredImage } from './image.ts';
|
|
8
|
+
import type { PageBreak } from './page-setup.ts';
|
|
9
|
+
import { type ParsedPivotTable, type PivotTable } from './pivot-table.ts';
|
|
6
10
|
import type { Table } from './table.ts';
|
|
7
11
|
import { type CellValue } from './value.ts';
|
|
8
12
|
import type { WorksheetComments } from './worksheet-comments.ts';
|
|
@@ -22,10 +26,22 @@ interface GridStorage {
|
|
|
22
26
|
readonly columns: Map<number, ColumnProperties>;
|
|
23
27
|
readonly merges: WorksheetMerges;
|
|
24
28
|
readonly tables: Table[];
|
|
29
|
+
readonly pivotTables: readonly PivotTable[];
|
|
30
|
+
readonly loadedPivotTables: ParsedPivotTable[];
|
|
25
31
|
readonly images: AnchoredImage[];
|
|
26
32
|
readonly dataValidations: DataValidationOverlay;
|
|
27
33
|
readonly conditionalFormattings: ConditionalFormattingOverlay;
|
|
34
|
+
readonly hyperlinks: HyperlinkOverlay;
|
|
35
|
+
/** The sheet's name, which an unqualified reference in one of its formulas means. */
|
|
36
|
+
readonly sheetName: () => string;
|
|
37
|
+
/**
|
|
38
|
+
* What moves the formulas outside this sheet that name it: every other sheet's, and the workbook's
|
|
39
|
+
* defined names. `undefined` for a sheet no workbook holds.
|
|
40
|
+
*/
|
|
41
|
+
readonly formulaHost: () => ((edit: SheetSplice) => void) | undefined;
|
|
28
42
|
readonly comments: WorksheetComments;
|
|
43
|
+
readonly rowBreaks: PageBreak[];
|
|
44
|
+
readonly columnBreaks: PageBreak[];
|
|
29
45
|
readonly autoFilter: AutoFilterSlot;
|
|
30
46
|
}
|
|
31
47
|
export declare class GridEdits {
|
|
@@ -33,5 +49,17 @@ export declare class GridEdits {
|
|
|
33
49
|
constructor(storage: GridStorage);
|
|
34
50
|
spliceRows(start: number, count: number, inserted: Map<number, Cell>[]): void;
|
|
35
51
|
spliceColumns(start: number, count: number, inserts: CellValue[][]): void;
|
|
52
|
+
/**
|
|
53
|
+
* Move the references this sheet's formulas make to the sheet a splice changed, which may be this
|
|
54
|
+
* sheet or another: every cell formula, and every data validation's and conditional format's formula.
|
|
55
|
+
*
|
|
56
|
+
* A shared formula is described once, by its master, and each clone is that text translated to where
|
|
57
|
+
* the clone sits. A splice usually keeps that true, since the master, the clone and what they refer to
|
|
58
|
+
* all move together, but not always: an insert between the cells one clone refers to and the cells its
|
|
59
|
+
* master does grows one reference and not the other, and a delete can take the master and leave the
|
|
60
|
+
* clone. A clone the moved master no longer describes stops sharing and becomes a formula of its own,
|
|
61
|
+
* spelled as it was rewritten; the rest of the group keeps sharing.
|
|
62
|
+
*/
|
|
63
|
+
spliceFormulas(edit: SheetSplice): void;
|
|
36
64
|
}
|
|
37
65
|
export {};
|
package/dist/core/grid-edits.js
CHANGED
|
@@ -1,36 +1,54 @@
|
|
|
1
|
-
import { boundedRect, decodeRange, encodeAddress, encodeRect, tryDecodeCellRef } from './address.js';
|
|
1
|
+
import { boundedRect, decodeRange, encodeAddress, encodeRange, encodeRect, tryDecodeCellRef, tryDecodeRange, } from './address.js';
|
|
2
2
|
import { shiftAutoFilter } from './autofilter.js';
|
|
3
3
|
import { Cell, copyCellContent } from './cell.js';
|
|
4
4
|
import { replaceContents } from './containers.js';
|
|
5
|
-
import {
|
|
5
|
+
import { spliceFormula, translateFormula } from './formula-references.js';
|
|
6
|
+
import { isDeletedSpan, shiftIndex, shiftPoint, shiftRect } from './grid-shift.js';
|
|
6
7
|
import { isOneCellAnchor } from './image.js';
|
|
8
|
+
import { INTERNAL } from './internal.js';
|
|
9
|
+
import { splicePivotSource } from './pivot-table.js';
|
|
7
10
|
import { positionalPlacements } from './row-input.js';
|
|
8
|
-
import { isSharedFormulaValue } from './value.js';
|
|
11
|
+
import { isArrayFormulaValue, isDataTableFormulaValue, isFormulaValue, isSharedFormulaValue, } from './value.js';
|
|
9
12
|
export class GridEdits {
|
|
10
13
|
#rows;
|
|
11
14
|
#rowProperties;
|
|
12
15
|
#columns;
|
|
13
16
|
#merges;
|
|
14
17
|
#tables;
|
|
18
|
+
#pivotTables;
|
|
19
|
+
#loadedPivotTables;
|
|
15
20
|
#images;
|
|
16
21
|
#dataValidations;
|
|
17
22
|
#conditionalFormattings;
|
|
23
|
+
#hyperlinks;
|
|
18
24
|
#comments;
|
|
25
|
+
#rowBreaks;
|
|
26
|
+
#columnBreaks;
|
|
19
27
|
#autoFilter;
|
|
28
|
+
#sheetName;
|
|
29
|
+
#formulaHost;
|
|
20
30
|
constructor(storage) {
|
|
21
31
|
this.#rows = storage.rows;
|
|
22
32
|
this.#rowProperties = storage.rowProperties;
|
|
23
33
|
this.#columns = storage.columns;
|
|
24
34
|
this.#merges = storage.merges;
|
|
25
35
|
this.#tables = storage.tables;
|
|
36
|
+
this.#pivotTables = storage.pivotTables;
|
|
37
|
+
this.#loadedPivotTables = storage.loadedPivotTables;
|
|
26
38
|
this.#images = storage.images;
|
|
27
39
|
this.#dataValidations = storage.dataValidations;
|
|
28
40
|
this.#conditionalFormattings = storage.conditionalFormattings;
|
|
41
|
+
this.#hyperlinks = storage.hyperlinks;
|
|
29
42
|
this.#comments = storage.comments;
|
|
43
|
+
this.#rowBreaks = storage.rowBreaks;
|
|
44
|
+
this.#columnBreaks = storage.columnBreaks;
|
|
30
45
|
this.#autoFilter = storage.autoFilter;
|
|
46
|
+
this.#sheetName = storage.sheetName;
|
|
47
|
+
this.#formulaHost = storage.formulaHost;
|
|
31
48
|
}
|
|
32
49
|
spliceRows(start, count, inserted) {
|
|
33
50
|
const splice = { axis: 'row', start, count, delta: inserted.length - count };
|
|
51
|
+
this.#moveFormulaReferences(splice);
|
|
34
52
|
const shifted = new Map();
|
|
35
53
|
for (const [row, cols] of this.#rows) {
|
|
36
54
|
if (row < start)
|
|
@@ -46,15 +64,11 @@ export class GridEdits {
|
|
|
46
64
|
this.#rows.clear();
|
|
47
65
|
for (const [row, cols] of shifted)
|
|
48
66
|
this.#rows.set(row, cols);
|
|
49
|
-
this.#
|
|
50
|
-
this.#shiftMerges(splice);
|
|
51
|
-
this.#shiftTables(splice);
|
|
52
|
-
this.#shiftImages(splice);
|
|
53
|
-
this.#reanchorSharedFormulas(splice);
|
|
54
|
-
this.#shiftRangeBoundOverlays(splice);
|
|
67
|
+
this.#shiftAnchored(splice, this.#rowProperties);
|
|
55
68
|
}
|
|
56
69
|
spliceColumns(start, count, inserts) {
|
|
57
70
|
const splice = { axis: 'col', start, count, delta: inserts.length - count };
|
|
71
|
+
this.#moveFormulaReferences(splice);
|
|
58
72
|
const shiftedRows = new Map();
|
|
59
73
|
for (const [row, cols] of this.#rows) {
|
|
60
74
|
const shifted = new Map();
|
|
@@ -85,16 +99,114 @@ export class GridEdits {
|
|
|
85
99
|
});
|
|
86
100
|
for (const [row, cols] of shiftedRows)
|
|
87
101
|
this.#rows.set(row, cols);
|
|
88
|
-
this.#
|
|
102
|
+
this.#shiftAnchored(splice, this.#columns);
|
|
103
|
+
}
|
|
104
|
+
#moveFormulaReferences(splice) {
|
|
105
|
+
const edit = { sheet: this.#sheetName(), splice };
|
|
106
|
+
this.spliceFormulas(edit);
|
|
107
|
+
this.#formulaHost()?.(edit);
|
|
108
|
+
}
|
|
109
|
+
spliceFormulas(edit) {
|
|
110
|
+
const home = this.#sheetName();
|
|
111
|
+
const { splice } = edit;
|
|
112
|
+
const rewrite = (formula) => spliceFormula(formula, home, edit);
|
|
113
|
+
const cellsMove = home.toLowerCase() === edit.sheet.toLowerCase();
|
|
114
|
+
const after = (cell) => {
|
|
115
|
+
if (!cellsMove)
|
|
116
|
+
return cell;
|
|
117
|
+
return splice.axis === 'row'
|
|
118
|
+
? { col: cell.col, row: shiftIndex(cell.row, splice) }
|
|
119
|
+
: { col: shiftIndex(cell.col, splice), row: cell.row };
|
|
120
|
+
};
|
|
121
|
+
const taken = (cell) => {
|
|
122
|
+
const line = splice.axis === 'row' ? cell.row : cell.col;
|
|
123
|
+
return cellsMove && isDeletedSpan(line, line, splice);
|
|
124
|
+
};
|
|
125
|
+
const masters = new Map();
|
|
126
|
+
for (const cols of this.#rows.values()) {
|
|
127
|
+
for (const cell of cols.values()) {
|
|
128
|
+
const value = cell.value;
|
|
129
|
+
if (isArrayFormulaValue(value)) {
|
|
130
|
+
const rewritten = rewrite(value.formula);
|
|
131
|
+
if (rewritten !== value.formula)
|
|
132
|
+
cell.value = { ...value, formula: rewritten };
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (!isFormulaValue(value))
|
|
136
|
+
continue;
|
|
137
|
+
masters.set(encodeAddress(cell.col, cell.row), {
|
|
138
|
+
cell,
|
|
139
|
+
formula: value.formula,
|
|
140
|
+
rewritten: rewrite(value.formula),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
for (const cols of this.#rows.values()) {
|
|
145
|
+
for (const cell of cols.values()) {
|
|
146
|
+
const value = cell.value;
|
|
147
|
+
if (!isSharedFormulaValue(value))
|
|
148
|
+
continue;
|
|
149
|
+
const master = masters.get(value.sharedFormula);
|
|
150
|
+
if (master === undefined) {
|
|
151
|
+
if (value.formula === undefined)
|
|
152
|
+
continue;
|
|
153
|
+
const rewritten = rewrite(value.formula);
|
|
154
|
+
if (rewritten !== value.formula)
|
|
155
|
+
cell.value = { ...value, formula: rewritten };
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const source = value.formula ??
|
|
159
|
+
translateFormula(master.formula, cell.col - master.cell.col, cell.row - master.cell.row);
|
|
160
|
+
const rewritten = rewrite(source);
|
|
161
|
+
const from = after(master.cell);
|
|
162
|
+
const to = after(cell);
|
|
163
|
+
const described = !taken(master.cell) &&
|
|
164
|
+
translateFormula(master.rewritten, to.col - from.col, to.row - from.row) === rewritten;
|
|
165
|
+
if (described) {
|
|
166
|
+
if (value.formula !== undefined && rewritten !== value.formula) {
|
|
167
|
+
cell.value = { ...value, formula: rewritten };
|
|
168
|
+
}
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
cell.value =
|
|
172
|
+
value.result === undefined
|
|
173
|
+
? { formula: rewritten }
|
|
174
|
+
: { formula: rewritten, result: value.result };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
for (const { cell, formula, rewritten } of masters.values()) {
|
|
178
|
+
const value = cell.value;
|
|
179
|
+
if (rewritten !== formula && isFormulaValue(value))
|
|
180
|
+
cell.value = { ...value, formula: rewritten };
|
|
181
|
+
}
|
|
182
|
+
this.#dataValidations.mapFormulas(rewrite);
|
|
183
|
+
this.#conditionalFormattings.mapFormulas(rewrite);
|
|
184
|
+
for (const table of this.#tables)
|
|
185
|
+
table[INTERNAL].rewriteFormulas(rewrite);
|
|
186
|
+
for (const pivot of this.#pivotTables)
|
|
187
|
+
pivot[INTERNAL].spliceSource(edit);
|
|
188
|
+
for (const [index, loaded] of this.#loadedPivotTables.entries()) {
|
|
189
|
+
const { source } = loaded;
|
|
190
|
+
if (source.kind !== 'worksheet' || source.inAnotherWorkbook)
|
|
191
|
+
continue;
|
|
192
|
+
const ref = splicePivotSource(source.sheet, source.ref, edit);
|
|
193
|
+
if (ref !== source.ref)
|
|
194
|
+
this.#loadedPivotTables[index] = { ...loaded, source: { ...source, ref } };
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
#shiftAnchored(splice, lineProperties) {
|
|
198
|
+
this.#shiftLineProperties(lineProperties, splice);
|
|
199
|
+
this.#shiftPageBreaks(splice);
|
|
89
200
|
this.#shiftMerges(splice);
|
|
90
201
|
this.#shiftTables(splice);
|
|
91
202
|
this.#shiftImages(splice);
|
|
92
|
-
this.#
|
|
203
|
+
this.#reanchorValueReferences(splice);
|
|
93
204
|
this.#shiftRangeBoundOverlays(splice);
|
|
94
205
|
}
|
|
95
206
|
#shiftRangeBoundOverlays(splice) {
|
|
96
207
|
this.#dataValidations.shift(splice);
|
|
97
208
|
this.#conditionalFormattings.shift(splice);
|
|
209
|
+
this.#hyperlinks.shift(splice);
|
|
98
210
|
this.#comments.shift(splice);
|
|
99
211
|
const filter = this.#autoFilter.get();
|
|
100
212
|
if (filter !== undefined)
|
|
@@ -114,22 +226,13 @@ export class GridEdits {
|
|
|
114
226
|
}
|
|
115
227
|
return moved;
|
|
116
228
|
}
|
|
117
|
-
#
|
|
229
|
+
#reanchorValueReferences(splice) {
|
|
118
230
|
for (const cols of this.#rows.values()) {
|
|
119
231
|
for (const cell of cols.values()) {
|
|
120
232
|
const value = cell.value;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (master === undefined)
|
|
125
|
-
continue;
|
|
126
|
-
const anchored = splice.axis === 'row'
|
|
127
|
-
? encodeAddress(master.col, shiftIndex(master.row, splice))
|
|
128
|
-
: encodeAddress(shiftIndex(master.col, splice), master.row);
|
|
129
|
-
if (anchored === value.sharedFormula)
|
|
130
|
-
continue;
|
|
131
|
-
const reanchored = { ...value, sharedFormula: anchored };
|
|
132
|
-
cell.value = reanchored;
|
|
233
|
+
const moved = reanchoredValue(value, splice);
|
|
234
|
+
if (moved !== value)
|
|
235
|
+
cell.value = moved;
|
|
133
236
|
}
|
|
134
237
|
}
|
|
135
238
|
}
|
|
@@ -144,6 +247,17 @@ export class GridEdits {
|
|
|
144
247
|
for (const [index, value] of shifted)
|
|
145
248
|
map.set(index, value);
|
|
146
249
|
}
|
|
250
|
+
#shiftPageBreaks(splice) {
|
|
251
|
+
const breaks = splice.axis === 'row' ? this.#rowBreaks : this.#columnBreaks;
|
|
252
|
+
const moved = breaks.flatMap((brk) => {
|
|
253
|
+
const line = brk.id + 1;
|
|
254
|
+
if (isDeletedSpan(line, line, splice))
|
|
255
|
+
return [];
|
|
256
|
+
const id = shiftIndex(line, splice) - 1;
|
|
257
|
+
return [id === brk.id ? brk : { ...brk, id }];
|
|
258
|
+
});
|
|
259
|
+
replaceContents(breaks, moved);
|
|
260
|
+
}
|
|
147
261
|
#shiftMerges(splice) {
|
|
148
262
|
const merges = [];
|
|
149
263
|
const rects = [];
|
|
@@ -178,8 +292,62 @@ export class GridEdits {
|
|
|
178
292
|
const anchor = isOneCellAnchor(image.anchor)
|
|
179
293
|
? { ...image.anchor, from }
|
|
180
294
|
: { ...image.anchor, from, to: shiftAnchor(image.anchor.to) };
|
|
181
|
-
return {
|
|
295
|
+
return { ...image, anchor };
|
|
182
296
|
});
|
|
183
297
|
replaceContents(this.#images, moved);
|
|
184
298
|
}
|
|
185
299
|
}
|
|
300
|
+
function reanchoredValue(value, splice) {
|
|
301
|
+
if (isSharedFormulaValue(value)) {
|
|
302
|
+
const master = tryDecodeCellRef(value.sharedFormula);
|
|
303
|
+
if (master === undefined)
|
|
304
|
+
return value;
|
|
305
|
+
const anchored = splice.axis === 'row'
|
|
306
|
+
? encodeAddress(master.col, shiftIndex(master.row, splice))
|
|
307
|
+
: encodeAddress(shiftIndex(master.col, splice), master.row);
|
|
308
|
+
return anchored === value.sharedFormula ? value : { ...value, sharedFormula: anchored };
|
|
309
|
+
}
|
|
310
|
+
if (isArrayFormulaValue(value)) {
|
|
311
|
+
const ref = shiftedRange(value.ref, splice) ?? value.ref;
|
|
312
|
+
return ref === value.ref ? value : { ...value, ref };
|
|
313
|
+
}
|
|
314
|
+
if (isDataTableFormulaValue(value)) {
|
|
315
|
+
const ref = shiftedRange(value.ref, splice) ?? value.ref;
|
|
316
|
+
const r1 = inputAfter(value.r1, value.r1Deleted, splice);
|
|
317
|
+
const r2 = inputAfter(value.r2, value.r2Deleted, splice);
|
|
318
|
+
if (ref === value.ref && r1.same && r2.same)
|
|
319
|
+
return value;
|
|
320
|
+
return {
|
|
321
|
+
...value,
|
|
322
|
+
ref,
|
|
323
|
+
...(r1.ref === undefined ? {} : { r1: r1.ref }),
|
|
324
|
+
...(r2.ref === undefined ? {} : { r2: r2.ref }),
|
|
325
|
+
...(r1.deleted ? { r1Deleted: true } : {}),
|
|
326
|
+
...(r2.deleted ? { r2Deleted: true } : {}),
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
return value;
|
|
330
|
+
}
|
|
331
|
+
function shiftedRange(ref, splice) {
|
|
332
|
+
const decoded = tryDecodeRange(ref);
|
|
333
|
+
const rect = decoded === undefined ? undefined : boundedRect(decoded);
|
|
334
|
+
if (rect === undefined)
|
|
335
|
+
return ref;
|
|
336
|
+
const moved = shiftRect(rect, splice);
|
|
337
|
+
if (moved === undefined)
|
|
338
|
+
return undefined;
|
|
339
|
+
return sameRect(moved, rect) ? ref : encodeRange(moved);
|
|
340
|
+
}
|
|
341
|
+
function inputAfter(ref, deleted, splice) {
|
|
342
|
+
const cell = ref === undefined || deleted === true ? undefined : tryDecodeCellRef(ref);
|
|
343
|
+
if (cell === undefined)
|
|
344
|
+
return { ref, deleted: deleted === true, same: true };
|
|
345
|
+
const moved = shiftPoint(cell, splice);
|
|
346
|
+
if (moved === undefined)
|
|
347
|
+
return { ref, deleted: true, same: false };
|
|
348
|
+
const same = moved.row === cell.row && moved.col === cell.col;
|
|
349
|
+
return { ref: same ? ref : encodeAddress(moved.col, moved.row), deleted: false, same };
|
|
350
|
+
}
|
|
351
|
+
function sameRect(a, b) {
|
|
352
|
+
return a.top === b.top && a.left === b.left && a.bottom === b.bottom && a.right === b.right;
|
|
353
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type AxisSplice } from './grid-shift.ts';
|
|
2
|
+
/** A hyperlink and the cells it covers. */
|
|
3
|
+
export interface Hyperlink {
|
|
4
|
+
/** The cells the link covers: one cell (`'B2'`) or a rectangle of cells (`'D1:H1'`). */
|
|
5
|
+
readonly ref: string;
|
|
6
|
+
/**
|
|
7
|
+
* Where the link goes: a URL or a path, or a `#`-prefixed place in this workbook such as
|
|
8
|
+
* `#Summary!A1` or `#TaxRate`.
|
|
9
|
+
*/
|
|
10
|
+
readonly target: string;
|
|
11
|
+
/** The text shown when the pointer rests on the link. */
|
|
12
|
+
readonly tooltip?: string;
|
|
13
|
+
}
|
|
14
|
+
/** The links on one sheet, in the order they were added, each with the rectangle it covers. */
|
|
15
|
+
export declare class HyperlinkOverlay {
|
|
16
|
+
#private;
|
|
17
|
+
/**
|
|
18
|
+
* Add a link, replacing one over the same cells. The `ref` is stored in its canonical spelling.
|
|
19
|
+
*
|
|
20
|
+
* @throws {SyntaxError} if `ref` is not a reference.
|
|
21
|
+
* @throws {AuthoringError} if `ref` names a whole row or column rather than cells.
|
|
22
|
+
*/
|
|
23
|
+
add(link: Hyperlink): void;
|
|
24
|
+
/** Remove the link whose `ref` names exactly these cells, and report whether there was one. */
|
|
25
|
+
remove(ref: string): boolean;
|
|
26
|
+
/** The links on the sheet, in the order they were added. */
|
|
27
|
+
get entries(): readonly Hyperlink[];
|
|
28
|
+
/** The link covering the 1-based `col`/`row`, the last added of any that do, or `undefined`. */
|
|
29
|
+
at(col: number, row: number): Hyperlink | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Move every link through a row or column splice. A link grows when lines are inserted inside it and
|
|
32
|
+
* shrinks when some of its lines are deleted, and one the delete takes whole goes with it.
|
|
33
|
+
*/
|
|
34
|
+
shift(splice: AxisSplice): void;
|
|
35
|
+
/** Give row `to` a copy of every link that lies wholly within row `from`, as a row copy does. */
|
|
36
|
+
copyRow(from: number, to: number): void;
|
|
37
|
+
/** Drop every link, leaving the overlay empty. */
|
|
38
|
+
clear(): void;
|
|
39
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { AuthoringError, quoted } from '../errors.js';
|
|
2
|
+
import { boundedRect, decodeRange, encodeAddress, encodeRect, tryDecodeRange, } from './address.js';
|
|
3
|
+
import { replaceContents } from './containers.js';
|
|
4
|
+
import { shiftRect } from './grid-shift.js';
|
|
5
|
+
export class HyperlinkOverlay {
|
|
6
|
+
#entries = [];
|
|
7
|
+
#rects = [];
|
|
8
|
+
add(link) {
|
|
9
|
+
const rect = boundedRect(decodeRange(link.ref));
|
|
10
|
+
if (rect === undefined) {
|
|
11
|
+
throw new AuthoringError(`hyperlink range ${quoted(link.ref)} names a whole row or column, not cells`);
|
|
12
|
+
}
|
|
13
|
+
const stored = storedLink(link, refOf(rect));
|
|
14
|
+
this.#removeRef(stored.ref);
|
|
15
|
+
this.#entries.push(stored);
|
|
16
|
+
this.#rects.push(rect);
|
|
17
|
+
}
|
|
18
|
+
remove(ref) {
|
|
19
|
+
const decoded = tryDecodeRange(ref);
|
|
20
|
+
const rect = decoded === undefined ? undefined : boundedRect(decoded);
|
|
21
|
+
return rect !== undefined && this.#removeRef(refOf(rect));
|
|
22
|
+
}
|
|
23
|
+
get entries() {
|
|
24
|
+
return this.#entries;
|
|
25
|
+
}
|
|
26
|
+
at(col, row) {
|
|
27
|
+
for (let index = this.#entries.length - 1; index >= 0; index--) {
|
|
28
|
+
const rect = this.#rects[index];
|
|
29
|
+
if (rect !== undefined &&
|
|
30
|
+
col >= rect.left &&
|
|
31
|
+
col <= rect.right &&
|
|
32
|
+
row >= rect.top &&
|
|
33
|
+
row <= rect.bottom) {
|
|
34
|
+
return this.#entries[index];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
shift(splice) {
|
|
40
|
+
const entries = [];
|
|
41
|
+
const rects = [];
|
|
42
|
+
this.#entries.forEach((entry, index) => {
|
|
43
|
+
const rect = this.#rects[index];
|
|
44
|
+
const moved = rect === undefined ? undefined : shiftRect(rect, splice);
|
|
45
|
+
if (moved === undefined)
|
|
46
|
+
return;
|
|
47
|
+
const ref = refOf(moved);
|
|
48
|
+
entries.push(ref === entry.ref ? entry : storedLink(entry, ref));
|
|
49
|
+
rects.push(moved);
|
|
50
|
+
});
|
|
51
|
+
replaceContents(this.#entries, entries);
|
|
52
|
+
replaceContents(this.#rects, rects);
|
|
53
|
+
}
|
|
54
|
+
copyRow(from, to) {
|
|
55
|
+
const copies = this.#entries.flatMap((entry, index) => {
|
|
56
|
+
const rect = this.#rects[index];
|
|
57
|
+
return rect === undefined || rect.top !== from || rect.bottom !== from
|
|
58
|
+
? []
|
|
59
|
+
: [storedLink(entry, refOf({ ...rect, top: to, bottom: to }))];
|
|
60
|
+
});
|
|
61
|
+
for (const copy of copies)
|
|
62
|
+
this.add(copy);
|
|
63
|
+
}
|
|
64
|
+
clear() {
|
|
65
|
+
this.#entries.length = 0;
|
|
66
|
+
this.#rects.length = 0;
|
|
67
|
+
}
|
|
68
|
+
#removeRef(ref) {
|
|
69
|
+
const index = this.#entries.findIndex((entry) => entry.ref === ref);
|
|
70
|
+
if (index === -1)
|
|
71
|
+
return false;
|
|
72
|
+
this.#entries.splice(index, 1);
|
|
73
|
+
this.#rects.splice(index, 1);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function refOf(rect) {
|
|
78
|
+
return rect.top === rect.bottom && rect.left === rect.right
|
|
79
|
+
? encodeAddress(rect.left, rect.top)
|
|
80
|
+
: encodeRect(rect);
|
|
81
|
+
}
|
|
82
|
+
function storedLink(link, ref) {
|
|
83
|
+
return {
|
|
84
|
+
ref,
|
|
85
|
+
target: link.target,
|
|
86
|
+
...(link.tooltip === undefined ? {} : { tooltip: link.tooltip }),
|
|
87
|
+
};
|
|
88
|
+
}
|
package/dist/core/image.d.ts
CHANGED
|
@@ -14,8 +14,9 @@ export interface AnchorPoint {
|
|
|
14
14
|
* DPI-independent by construction: a pixel extent is a fixed physical size regardless of screen. */
|
|
15
15
|
export declare const PX_TO_EMU = 9525;
|
|
16
16
|
/** How a two-cell-anchored image tracks edits to the cells it spans. `twoCell` moves and resizes with
|
|
17
|
-
* them; `oneCell` moves but keeps its size; `absolute` is pinned to the page and does neither.
|
|
18
|
-
*
|
|
17
|
+
* them; `oneCell` moves but keeps its size; `absolute` is pinned to the page and does neither. The
|
|
18
|
+
* schema default, which a file omitting the attribute means, is `twoCell`; an image authored here
|
|
19
|
+
* without one is written as `oneCell`, which is this library's own default. */
|
|
19
20
|
export type ImageEditAs = 'oneCell' | 'twoCell' | 'absolute';
|
|
20
21
|
/** Narrow a raw `<xdr:twoCellAnchor editAs>` token to a known {@link ImageEditAs}. */
|
|
21
22
|
export declare const isImageEditAs: (value: string) => value is ImageEditAs;
|
|
@@ -57,12 +58,42 @@ export type RowHeightLookup = (row: number) => number | undefined;
|
|
|
57
58
|
* the column's size. An already-integer point keeps a zero offset (unless one was given). The two
|
|
58
59
|
* lookups supply each column/row's size; a size they leave `undefined` falls back to Excel's default. */
|
|
59
60
|
export declare function resolveAnchorPoint(point: AnchorPoint, columnWidth: ColumnWidthLookup, rowHeight: RowHeightLookup): AnchorPoint;
|
|
60
|
-
/**
|
|
61
|
-
|
|
61
|
+
/**
|
|
62
|
+
* How much of a picture is cut away at each edge, as a fraction of the picture's own size: `0.1` crops
|
|
63
|
+
* a tenth, and a negative value pads the picture out. An absent edge is not cropped.
|
|
64
|
+
*/
|
|
65
|
+
export interface ImageCrop {
|
|
66
|
+
readonly left?: number;
|
|
67
|
+
readonly top?: number;
|
|
68
|
+
readonly right?: number;
|
|
69
|
+
readonly bottom?: number;
|
|
70
|
+
}
|
|
71
|
+
/** Where clicking a picture goes: a URL, or a `#`-prefixed place in this workbook (`#Sheet1!C3`), as a
|
|
72
|
+
* sheet hyperlink's `target` spells one. */
|
|
73
|
+
export interface ImageHyperlink {
|
|
74
|
+
readonly target: string;
|
|
75
|
+
/** The text shown when the pointer rests on the picture. */
|
|
76
|
+
readonly tooltip?: string;
|
|
77
|
+
}
|
|
78
|
+
/** What a picture says about itself beyond which image it shows and where. */
|
|
79
|
+
export interface PictureProperties {
|
|
80
|
+
/** Alternative text: what a screen reader says in place of the picture. */
|
|
81
|
+
readonly description?: string;
|
|
82
|
+
/** The picture's title, shown with its alternative text. */
|
|
83
|
+
readonly title?: string;
|
|
84
|
+
readonly crop?: ImageCrop;
|
|
85
|
+
readonly hyperlink?: ImageHyperlink;
|
|
86
|
+
}
|
|
87
|
+
/** An image pinned to a worksheet: which workbook media it shows (`imageId`), where, and the picture's
|
|
88
|
+
* own properties. */
|
|
89
|
+
export interface AnchoredImage extends PictureProperties {
|
|
62
90
|
/** Index into the workbook's media registry (the id {@link Workbook.addImage} returned). */
|
|
63
91
|
readonly imageId: number;
|
|
64
92
|
readonly anchor: ImageAnchor;
|
|
65
93
|
}
|
|
94
|
+
/** The {@link PictureProperties} a value carries, and nothing else, so an image can be re-pinned or carried
|
|
95
|
+
* to another workbook without its alternative text, crop or link being left behind. */
|
|
96
|
+
export declare function pictureProperties(picture: PictureProperties): PictureProperties;
|
|
66
97
|
/** A picture's bytes and its file kind, as held in the workbook's media registry. */
|
|
67
98
|
export interface WorkbookImage {
|
|
68
99
|
/** Lower-case file extension without a dot: `"png"`, `"jpeg"`, `"gif"`. Drives the media part's
|
|
@@ -85,7 +116,7 @@ export declare function normalizeImageExtension(extension: string | undefined, d
|
|
|
85
116
|
* itself is what lets an anchor cross that boundary, which is why the transfer form carries bytes
|
|
86
117
|
* where the stored form carries an id.
|
|
87
118
|
*/
|
|
88
|
-
export interface PortableImage {
|
|
119
|
+
export interface PortableImage extends PictureProperties {
|
|
89
120
|
readonly image: WorkbookImage;
|
|
90
121
|
readonly anchor: ImageAnchor;
|
|
91
122
|
}
|
package/dist/core/image.js
CHANGED
|
@@ -19,6 +19,15 @@ export function resolveAnchorPoint(point, columnWidth, rowHeight) {
|
|
|
19
19
|
const rowOff = (point.rowOff ?? 0) + Math.round((point.row - row) * rowHeightEmu);
|
|
20
20
|
return { col, row, colOff, rowOff };
|
|
21
21
|
}
|
|
22
|
+
export function pictureProperties(picture) {
|
|
23
|
+
const { description, title, crop, hyperlink } = picture;
|
|
24
|
+
return {
|
|
25
|
+
...(description === undefined ? {} : { description }),
|
|
26
|
+
...(title === undefined ? {} : { title }),
|
|
27
|
+
...(crop === undefined ? {} : { crop: { ...crop } }),
|
|
28
|
+
...(hyperlink === undefined ? {} : { hyperlink: { ...hyperlink } }),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
22
31
|
const IMAGE_MAGIC = [
|
|
23
32
|
{ ext: 'png', sig: [0x89, 0x50, 0x4e, 0x47] },
|
|
24
33
|
{ ext: 'jpeg', sig: [0xff, 0xd8, 0xff] },
|
package/dist/core/internal.d.ts
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* the same key, on the static side and the instance side respectively, because that class has the
|
|
7
7
|
* identical problem one layer up. Its constructor took the writer's style registry and its
|
|
8
8
|
* `flushedSheet()` returned the writer's flushed-row record, so seven internal types were named by a
|
|
9
|
-
* published signature and none of them was a type a consumer could write down.
|
|
9
|
+
* published signature and none of them was a type a consumer could write down. `StreamedRow` is
|
|
10
|
+
* constructed through the same static key, because a row built outside its writer could commit, and
|
|
11
|
+
* so evict, a row number that writer never handed out.
|
|
10
12
|
*/
|
|
11
13
|
export declare const INTERNAL: unique symbol;
|
|
12
14
|
/**
|
package/dist/core/limits.d.ts
CHANGED
|
@@ -46,8 +46,10 @@ export declare const MAX_TABLE_NAME_LENGTH = 255;
|
|
|
46
46
|
* Excel's table-name grammar: start with a letter, underscore, or backslash; every later character a
|
|
47
47
|
* letter, digit, period, or underscore. Unicode letters and digits are allowed.
|
|
48
48
|
*
|
|
49
|
-
* Excel
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* The pattern is the grammar only. Excel also refuses a name that reads as a reference: an A1 cell on
|
|
50
|
+
* the grid (`T1`), an R1C1 reference (`R`, `C`, `RC`, `R1C1`, `R1X`), or `TRUE`/`FALSE`, in any case.
|
|
51
|
+
* No regular expression states that honestly, because "on the grid" is a bound on the column letters
|
|
52
|
+
* and the row number, so `Worksheet.addTable` checks it separately and a name passing this pattern
|
|
53
|
+
* can still be refused.
|
|
52
54
|
*/
|
|
53
55
|
export declare const TABLE_NAME_PATTERN: RegExp;
|
package/dist/core/merge.d.ts
CHANGED
|
@@ -3,6 +3,19 @@ import type { Cell } from './cell.ts';
|
|
|
3
3
|
import { type AxisSplice } from './grid-shift.ts';
|
|
4
4
|
/** A merged region, as the {@link GridRect} every range-shaped thing in the library is. */
|
|
5
5
|
export type MergeRect = GridRect;
|
|
6
|
+
/**
|
|
7
|
+
* Each merged range that overlaps a table, paired with the first table it overlaps. Excel forbids a
|
|
8
|
+
* merge inside a table: the writer refuses that geometry and the reader drops the merge, the repair
|
|
9
|
+
* Excel makes on load. Both used to spell the overlap test out by hand. The answer is a list of its
|
|
10
|
+
* own, so the reader can unmerge while it walks it rather than the live `sheet.merges`. An unbounded
|
|
11
|
+
* whole-row/column merge carries no rectangle and overlaps nothing.
|
|
12
|
+
*/
|
|
13
|
+
export declare function mergesOverlappingTables<T extends {
|
|
14
|
+
readonly region: GridRect;
|
|
15
|
+
}>(merges: readonly string[], tables: readonly T[]): {
|
|
16
|
+
readonly merge: string;
|
|
17
|
+
readonly table: T;
|
|
18
|
+
}[];
|
|
6
19
|
/**
|
|
7
20
|
* Drop any value already sitting in a merge's covered non-anchor cells, keeping only the top-left
|
|
8
21
|
* anchor, the collapse Excel performs on merge. A leftover covered value would serialise as a
|
package/dist/core/merge.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
|
-
import { encodeCornerRef, tryDecodeRange } from './address.js';
|
|
1
|
+
import { boundedRect, decodeRange, encodeCornerRef, rectsOverlap, tryDecodeRange, } from './address.js';
|
|
2
2
|
import { shiftSpan } from './grid-shift.js';
|
|
3
|
+
export function mergesOverlappingTables(merges, tables) {
|
|
4
|
+
const overlapping = [];
|
|
5
|
+
if (tables.length === 0)
|
|
6
|
+
return overlapping;
|
|
7
|
+
for (const merge of merges) {
|
|
8
|
+
const rect = boundedRect(decodeRange(merge));
|
|
9
|
+
if (rect === undefined)
|
|
10
|
+
continue;
|
|
11
|
+
const table = tables.find((candidate) => rectsOverlap(rect, candidate.region));
|
|
12
|
+
if (table !== undefined)
|
|
13
|
+
overlapping.push({ merge, table });
|
|
14
|
+
}
|
|
15
|
+
return overlapping;
|
|
16
|
+
}
|
|
3
17
|
export function clearCoveredValues(rows, rect) {
|
|
4
18
|
for (const [row, cols] of rows) {
|
|
5
19
|
if (row < rect.top || row > rect.bottom)
|