@rowsncolumns/toolkit 24.4.2 → 24.4.4
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/dist/cjs/excel-parser/cfb-decryptor.d.ts +6 -0
- package/dist/cjs/excel-parser/cfb-decryptor.d.ts.map +1 -1
- package/dist/cjs/excel-parser/cfb-decryptor.js +6 -0
- package/dist/cjs/excel-parser/helpers.d.ts +9 -1
- package/dist/cjs/excel-parser/helpers.d.ts.map +1 -1
- package/dist/cjs/excel-parser/helpers.js +37 -0
- package/dist/cjs/excel-parser/interface.d.ts +15 -2
- package/dist/cjs/excel-parser/interface.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/base/index.d.ts +2 -0
- package/dist/cjs/excel-parser/plugins/base/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/base/index.js +3 -0
- package/dist/cjs/excel-parser/plugins/ods/index.d.ts +19 -0
- package/dist/cjs/excel-parser/plugins/ods/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/ods/index.js +676 -304
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts +43 -1
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/ods/styles.js +343 -45
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts +55 -1
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xls/index.js +518 -6
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts +4 -0
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsb/index.js +33 -14
- package/dist/cjs/excel-parser/plugins/xlsx/chartex.d.ts +37 -0
- package/dist/cjs/excel-parser/plugins/xlsx/chartex.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/chartex.js +244 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts +10 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/charts.js +68 -9
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts +28 -1
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.js +155 -20
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts +70 -0
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/form-controls.js +295 -0
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts +35 -2
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/index.js +737 -257
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.js +125 -37
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts +3 -0
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.js +4 -1
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts +15 -1
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts.map +1 -1
- package/dist/cjs/excel-parser/plugins/xlsx/styles.js +102 -6
- package/dist/cjs/excel-parser/registry.d.ts +7 -0
- package/dist/cjs/excel-parser/registry.d.ts.map +1 -1
- package/dist/cjs/excel-parser/registry.js +29 -0
- package/dist/cjs/excel-parser/types.d.ts +17 -2
- package/dist/cjs/excel-parser/types.d.ts.map +1 -1
- package/dist/cjs/excel-parser/workbook.d.ts +3 -0
- package/dist/cjs/excel-parser/workbook.d.ts.map +1 -1
- package/dist/cjs/excel-parser/workbook.js +24 -14
- package/dist/cjs/excel-parser/worker.js +131 -131
- package/dist/cjs/exporter/ods/ods-export.d.ts.map +1 -1
- package/dist/cjs/exporter/ods/ods-export.js +432 -175
- package/dist/cjs/exporter/xlsx/chart-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/chart-builder.js +215 -39
- package/dist/cjs/exporter/xlsx/chartex-builder.d.ts +36 -0
- package/dist/cjs/exporter/xlsx/chartex-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/chartex-builder.js +109 -0
- package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts +61 -0
- package/dist/cjs/exporter/xlsx/form-controls-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/form-controls-builder.js +197 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.d.ts +8 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/pivot-builder.js +141 -42
- package/dist/cjs/exporter/xlsx/style-builder.js +9 -3
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts +7 -1
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.js +15 -3
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts +11 -2
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts.map +1 -1
- package/dist/cjs/exporter/xlsx/xlsx-export.js +991 -297
- package/dist/cjs/helpers/implicit-intersection.d.ts +16 -0
- package/dist/cjs/helpers/implicit-intersection.d.ts.map +1 -0
- package/dist/cjs/helpers/implicit-intersection.js +197 -0
- package/dist/cjs/print-settings.d.ts +105 -0
- package/dist/cjs/print-settings.d.ts.map +1 -0
- package/dist/cjs/print-settings.js +494 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/excel-parser/cfb-decryptor.d.ts +6 -0
- package/dist/esm/excel-parser/cfb-decryptor.d.ts.map +1 -1
- package/dist/esm/excel-parser/cfb-decryptor.js +6 -0
- package/dist/esm/excel-parser/helpers.d.ts +9 -1
- package/dist/esm/excel-parser/helpers.d.ts.map +1 -1
- package/dist/esm/excel-parser/helpers.js +34 -0
- package/dist/esm/excel-parser/interface.d.ts +15 -2
- package/dist/esm/excel-parser/interface.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/base/index.d.ts +2 -0
- package/dist/esm/excel-parser/plugins/base/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/base/index.js +3 -0
- package/dist/esm/excel-parser/plugins/ods/index.d.ts +19 -0
- package/dist/esm/excel-parser/plugins/ods/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/ods/index.js +347 -33
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts +43 -1
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/ods/styles.js +276 -2
- package/dist/esm/excel-parser/plugins/xls/index.d.ts +55 -1
- package/dist/esm/excel-parser/plugins/xls/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xls/index.js +441 -3
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts +4 -0
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsb/index.js +30 -9
- package/dist/esm/excel-parser/plugins/xlsx/chartex.d.ts +37 -0
- package/dist/esm/excel-parser/plugins/xlsx/chartex.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/chartex.js +199 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts +10 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/charts.js +69 -6
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts +28 -1
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/drawing.js +99 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts +70 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/form-controls.js +246 -0
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts +35 -2
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/index.js +454 -32
- package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/pivots.js +86 -6
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts +3 -0
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.js +2 -0
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts +15 -1
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts.map +1 -1
- package/dist/esm/excel-parser/plugins/xlsx/styles.js +92 -2
- package/dist/esm/excel-parser/registry.d.ts +7 -0
- package/dist/esm/excel-parser/registry.d.ts.map +1 -1
- package/dist/esm/excel-parser/registry.js +19 -0
- package/dist/esm/excel-parser/types.d.ts +17 -2
- package/dist/esm/excel-parser/types.d.ts.map +1 -1
- package/dist/esm/excel-parser/workbook.d.ts +3 -0
- package/dist/esm/excel-parser/workbook.d.ts.map +1 -1
- package/dist/esm/excel-parser/workbook.js +19 -10
- package/dist/esm/excel-parser/worker.js +12 -18
- package/dist/esm/exporter/ods/ods-export.d.ts.map +1 -1
- package/dist/esm/exporter/ods/ods-export.js +306 -35
- package/dist/esm/exporter/xlsx/chart-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/chart-builder.js +161 -28
- package/dist/esm/exporter/xlsx/chartex-builder.d.ts +36 -0
- package/dist/esm/exporter/xlsx/chartex-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/chartex-builder.js +97 -0
- package/dist/esm/exporter/xlsx/form-controls-builder.d.ts +61 -0
- package/dist/esm/exporter/xlsx/form-controls-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/form-controls-builder.js +173 -0
- package/dist/esm/exporter/xlsx/pivot-builder.d.ts +8 -0
- package/dist/esm/exporter/xlsx/pivot-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/pivot-builder.js +104 -19
- package/dist/esm/exporter/xlsx/style-builder.js +9 -3
- package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts +7 -1
- package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/threaded-comments-builder.js +15 -3
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts +11 -2
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts.map +1 -1
- package/dist/esm/exporter/xlsx/xlsx-export.js +675 -64
- package/dist/esm/helpers/implicit-intersection.d.ts +16 -0
- package/dist/esm/helpers/implicit-intersection.d.ts.map +1 -0
- package/dist/esm/helpers/implicit-intersection.js +184 -0
- package/dist/esm/print-settings.d.ts +105 -0
- package/dist/esm/print-settings.d.ts.map +1 -0
- package/dist/esm/print-settings.js +422 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/xlsx.d.ts +14 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
import { addressToSelection, alpha2number, number2Alpha, } from "@rowsncolumns/utils";
|
|
2
|
+
/**
|
|
3
|
+
* Shared helpers for the sheet `printSettings` facet: the builtin
|
|
4
|
+
* `_xlnm.Print_Area` / `_xlnm.Print_Titles` defined-name formulas (XLSX), the
|
|
5
|
+
* Excel header/footer code language (`&L&P of &N`), and the ODS page-layout
|
|
6
|
+
* equivalents (paper sizes, `style:print` tokens, `<text:*>` fields).
|
|
7
|
+
*/
|
|
8
|
+
export const PRINT_AREA_NAME = "_xlnm.Print_Area";
|
|
9
|
+
export const PRINT_TITLES_NAME = "_xlnm.Print_Titles";
|
|
10
|
+
export const isBuiltinPrintName = (name) => name === PRINT_AREA_NAME || name === PRINT_TITLES_NAME;
|
|
11
|
+
/** Wrap a sheet name in single quotes when a formula reference requires it. */
|
|
12
|
+
export const quoteSheetNameForRef = (name) => /^[A-Za-z_][A-Za-z0-9_.]*$/.test(name)
|
|
13
|
+
? name
|
|
14
|
+
: `'${name.replace(/'/g, "''")}'`;
|
|
15
|
+
/** Split a defined-name formula on top-level commas (quote aware). */
|
|
16
|
+
export const splitDefinedNameAreas = (formula) => {
|
|
17
|
+
const parts = [];
|
|
18
|
+
let current = "";
|
|
19
|
+
let inQuote = false;
|
|
20
|
+
for (const ch of formula) {
|
|
21
|
+
if (ch === "'")
|
|
22
|
+
inQuote = !inQuote;
|
|
23
|
+
if (ch === "," && !inQuote) {
|
|
24
|
+
parts.push(current);
|
|
25
|
+
current = "";
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
current += ch;
|
|
29
|
+
}
|
|
30
|
+
parts.push(current);
|
|
31
|
+
return parts.map((part) => part.trim()).filter(Boolean);
|
|
32
|
+
};
|
|
33
|
+
/** `'My Sheet'!$A$1:$B$2` → `{ sheetName: "My Sheet", ref: "$A$1:$B$2" }`. */
|
|
34
|
+
export const splitSheetQualifiedRef = (part) => {
|
|
35
|
+
const bang = part.lastIndexOf("!");
|
|
36
|
+
if (bang === -1)
|
|
37
|
+
return { ref: part };
|
|
38
|
+
let sheetName = part.slice(0, bang);
|
|
39
|
+
if (sheetName.startsWith("'") && sheetName.endsWith("'")) {
|
|
40
|
+
sheetName = sheetName.slice(1, -1).replace(/''/g, "'");
|
|
41
|
+
}
|
|
42
|
+
return { sheetName, ref: part.slice(bang + 1) };
|
|
43
|
+
};
|
|
44
|
+
const ROW_BAND = /^\$?(\d+):\$?(\d+)$/;
|
|
45
|
+
const COLUMN_BAND = /^\$?([A-Za-z]{1,3}):\$?([A-Za-z]{1,3})$/;
|
|
46
|
+
/**
|
|
47
|
+
* Parse a `_xlnm.Print_Area` formula into 1-based inclusive rectangles.
|
|
48
|
+
* Bands (`$1:$2`, `$A:$B`) and non-rectangular parts are rejected; the sheet
|
|
49
|
+
* name is taken from the first qualified part.
|
|
50
|
+
*/
|
|
51
|
+
export const parsePrintAreaFormula = (formula) => {
|
|
52
|
+
const ranges = [];
|
|
53
|
+
let sheetName;
|
|
54
|
+
for (const part of splitDefinedNameAreas(formula)) {
|
|
55
|
+
const split = splitSheetQualifiedRef(part);
|
|
56
|
+
sheetName ??= split.sheetName;
|
|
57
|
+
const ref = split.ref.replace(/\$/g, "");
|
|
58
|
+
if (ROW_BAND.test(ref) || COLUMN_BAND.test(ref))
|
|
59
|
+
return undefined;
|
|
60
|
+
if (!/^[A-Za-z]{1,3}\d+(:[A-Za-z]{1,3}\d+)?$/.test(ref))
|
|
61
|
+
return undefined;
|
|
62
|
+
const selection = addressToSelection(ref);
|
|
63
|
+
if (!selection)
|
|
64
|
+
return undefined;
|
|
65
|
+
ranges.push({ ...selection.range });
|
|
66
|
+
}
|
|
67
|
+
if (!ranges.length)
|
|
68
|
+
return undefined;
|
|
69
|
+
return { sheetName, ranges };
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Parse a `_xlnm.Print_Titles` formula (`'Sheet'!$A:$B,'Sheet'!$1:$2` — any
|
|
73
|
+
* order, either band alone) into the repeated row / column bands.
|
|
74
|
+
*/
|
|
75
|
+
export const parsePrintTitlesFormula = (formula) => {
|
|
76
|
+
const titles = {};
|
|
77
|
+
let sheetName;
|
|
78
|
+
for (const part of splitDefinedNameAreas(formula)) {
|
|
79
|
+
const split = splitSheetQualifiedRef(part);
|
|
80
|
+
sheetName ??= split.sheetName;
|
|
81
|
+
const rowMatch = ROW_BAND.exec(split.ref);
|
|
82
|
+
if (rowMatch) {
|
|
83
|
+
const a = parseInt(rowMatch[1], 10);
|
|
84
|
+
const b = parseInt(rowMatch[2], 10);
|
|
85
|
+
titles.rowStart = Math.min(a, b);
|
|
86
|
+
titles.rowEnd = Math.max(a, b);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const colMatch = COLUMN_BAND.exec(split.ref);
|
|
90
|
+
if (colMatch) {
|
|
91
|
+
const a = alpha2number(colMatch[1].toUpperCase());
|
|
92
|
+
const b = alpha2number(colMatch[2].toUpperCase());
|
|
93
|
+
titles.columnStart = Math.min(a, b);
|
|
94
|
+
titles.columnEnd = Math.max(a, b);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
if (titles.rowStart == null && titles.columnStart == null)
|
|
100
|
+
return undefined;
|
|
101
|
+
return { sheetName, titles };
|
|
102
|
+
};
|
|
103
|
+
// `number2Alpha` is 0-based (0 → "A"); grid column indices are 1-based.
|
|
104
|
+
const columnLetters = (columnIndex) => number2Alpha(columnIndex - 1);
|
|
105
|
+
const absoluteRangeRef = (range) => `$${columnLetters(range.startColumnIndex)}$${range.startRowIndex}:$${columnLetters(range.endColumnIndex)}$${range.endRowIndex}`;
|
|
106
|
+
/** `'Sheet'!$A$1:$D$10,'Sheet'!$F$2:$G$5` (Excel's own multi-area shape). */
|
|
107
|
+
export const buildPrintAreaFormula = (sheetName, ranges) => {
|
|
108
|
+
const valid = ranges.filter(isValidPrintRange);
|
|
109
|
+
if (!valid.length)
|
|
110
|
+
return undefined;
|
|
111
|
+
const quoted = quoteSheetNameForRef(sheetName);
|
|
112
|
+
return valid.map((range) => `${quoted}!${absoluteRangeRef(range)}`).join(",");
|
|
113
|
+
};
|
|
114
|
+
/** Columns first, then rows — the order Excel writes. */
|
|
115
|
+
export const buildPrintTitlesFormula = (sheetName, titles) => {
|
|
116
|
+
const quoted = quoteSheetNameForRef(sheetName);
|
|
117
|
+
const parts = [];
|
|
118
|
+
const { columnStart, columnEnd, rowStart, rowEnd } = titles;
|
|
119
|
+
if (columnStart != null &&
|
|
120
|
+
columnEnd != null &&
|
|
121
|
+
columnStart >= 1 &&
|
|
122
|
+
columnEnd >= columnStart) {
|
|
123
|
+
parts.push(`${quoted}!$${columnLetters(columnStart)}:$${columnLetters(columnEnd)}`);
|
|
124
|
+
}
|
|
125
|
+
if (rowStart != null &&
|
|
126
|
+
rowEnd != null &&
|
|
127
|
+
rowStart >= 1 &&
|
|
128
|
+
rowEnd >= rowStart) {
|
|
129
|
+
parts.push(`${quoted}!$${rowStart}:$${rowEnd}`);
|
|
130
|
+
}
|
|
131
|
+
return parts.length ? parts.join(",") : undefined;
|
|
132
|
+
};
|
|
133
|
+
export const isValidPrintRange = (range) => range.startRowIndex >= 1 &&
|
|
134
|
+
range.endRowIndex >= range.startRowIndex &&
|
|
135
|
+
range.startColumnIndex >= 1 &&
|
|
136
|
+
range.endColumnIndex >= range.startColumnIndex;
|
|
137
|
+
const hasAnyValue = (value) => !!value && Object.values(value).some((v) => v !== undefined && v !== null);
|
|
138
|
+
/**
|
|
139
|
+
* Drop empty sub-objects / empty arrays; returns `undefined` when nothing
|
|
140
|
+
* is left so callers can omit the facet entirely.
|
|
141
|
+
*/
|
|
142
|
+
export const compactPrintSettings = (settings) => {
|
|
143
|
+
if (!settings)
|
|
144
|
+
return undefined;
|
|
145
|
+
const out = {};
|
|
146
|
+
if (hasAnyValue(settings.pageSetup))
|
|
147
|
+
out.pageSetup = settings.pageSetup;
|
|
148
|
+
if (hasAnyValue(settings.pageMargins))
|
|
149
|
+
out.pageMargins = settings.pageMargins;
|
|
150
|
+
if (hasAnyValue(settings.printOptions))
|
|
151
|
+
out.printOptions = settings.printOptions;
|
|
152
|
+
if (hasAnyValue(settings.headerFooter))
|
|
153
|
+
out.headerFooter = settings.headerFooter;
|
|
154
|
+
if (settings.printArea?.length)
|
|
155
|
+
out.printArea = settings.printArea;
|
|
156
|
+
if (hasAnyValue(settings.printTitles))
|
|
157
|
+
out.printTitles = settings.printTitles;
|
|
158
|
+
if (settings.rowBreaks?.length)
|
|
159
|
+
out.rowBreaks = settings.rowBreaks;
|
|
160
|
+
if (settings.columnBreaks?.length)
|
|
161
|
+
out.columnBreaks = settings.columnBreaks;
|
|
162
|
+
return Object.keys(out).length ? out : undefined;
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Split an Excel header/footer code into its `&L` / `&C` / `&R` zones. Text
|
|
166
|
+
* before any zone marker belongs to the centre zone (Excel's rule). `&&`
|
|
167
|
+
* escapes are left untouched inside each zone.
|
|
168
|
+
*/
|
|
169
|
+
export const splitHeaderFooterZones = (code) => {
|
|
170
|
+
const zones = {};
|
|
171
|
+
let current = "center";
|
|
172
|
+
let buffer = "";
|
|
173
|
+
const flush = () => {
|
|
174
|
+
if (buffer)
|
|
175
|
+
zones[current] = (zones[current] ?? "") + buffer;
|
|
176
|
+
buffer = "";
|
|
177
|
+
};
|
|
178
|
+
for (let i = 0; i < code.length; i++) {
|
|
179
|
+
const ch = code[i];
|
|
180
|
+
if (ch === "&" && i + 1 < code.length) {
|
|
181
|
+
const next = code[i + 1];
|
|
182
|
+
if (next === "&") {
|
|
183
|
+
buffer += "&&";
|
|
184
|
+
i += 1;
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (next === "L" || next === "C" || next === "R") {
|
|
188
|
+
flush();
|
|
189
|
+
current = next === "L" ? "left" : next === "C" ? "center" : "right";
|
|
190
|
+
i += 1;
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
buffer += ch;
|
|
195
|
+
}
|
|
196
|
+
flush();
|
|
197
|
+
return zones;
|
|
198
|
+
};
|
|
199
|
+
export const joinHeaderFooterZones = (zones) => {
|
|
200
|
+
let out = "";
|
|
201
|
+
if (zones.left)
|
|
202
|
+
out += `&L${zones.left}`;
|
|
203
|
+
if (zones.center)
|
|
204
|
+
out += `&C${zones.center}`;
|
|
205
|
+
if (zones.right)
|
|
206
|
+
out += `&R${zones.right}`;
|
|
207
|
+
return out;
|
|
208
|
+
};
|
|
209
|
+
const FIELD_BY_CODE = {
|
|
210
|
+
P: "page",
|
|
211
|
+
N: "pages",
|
|
212
|
+
D: "date",
|
|
213
|
+
T: "time",
|
|
214
|
+
A: "sheet",
|
|
215
|
+
F: "file",
|
|
216
|
+
Z: "path",
|
|
217
|
+
};
|
|
218
|
+
const CODE_BY_FIELD = {
|
|
219
|
+
page: "&P",
|
|
220
|
+
pages: "&N",
|
|
221
|
+
date: "&D",
|
|
222
|
+
time: "&T",
|
|
223
|
+
sheet: "&A",
|
|
224
|
+
file: "&F",
|
|
225
|
+
path: "&Z",
|
|
226
|
+
};
|
|
227
|
+
/**
|
|
228
|
+
* Tokenize one zone of header/footer code into literal text and field
|
|
229
|
+
* macros. Formatting codes (`&"Font,Style"`, `&12`, `&B`, `&Kff0000`, `&G`…)
|
|
230
|
+
* have no ODS counterpart and are dropped.
|
|
231
|
+
*/
|
|
232
|
+
export const tokenizeHeaderFooterZone = (zone) => {
|
|
233
|
+
const tokens = [];
|
|
234
|
+
let text = "";
|
|
235
|
+
const pushText = () => {
|
|
236
|
+
if (text)
|
|
237
|
+
tokens.push({ type: "text", text });
|
|
238
|
+
text = "";
|
|
239
|
+
};
|
|
240
|
+
for (let i = 0; i < zone.length; i++) {
|
|
241
|
+
const ch = zone[i];
|
|
242
|
+
if (ch !== "&" || i + 1 >= zone.length) {
|
|
243
|
+
text += ch;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
const next = zone[i + 1];
|
|
247
|
+
if (next === "&") {
|
|
248
|
+
text += "&";
|
|
249
|
+
i += 1;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (next === '"') {
|
|
253
|
+
const close = zone.indexOf('"', i + 2);
|
|
254
|
+
i = close === -1 ? zone.length : close;
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (/\d/.test(next)) {
|
|
258
|
+
let j = i + 1;
|
|
259
|
+
while (j < zone.length && /\d/.test(zone[j]))
|
|
260
|
+
j++;
|
|
261
|
+
i = j - 1;
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
if (next === "K") {
|
|
265
|
+
// `&Kff0000` (6 hex) or `&K01+000` (theme + tint) — both 6 chars.
|
|
266
|
+
i += 7;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
const field = FIELD_BY_CODE[next];
|
|
270
|
+
if (field) {
|
|
271
|
+
pushText();
|
|
272
|
+
tokens.push({ type: "field", field });
|
|
273
|
+
i += 1;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
// Any other single-letter code is a formatting toggle.
|
|
277
|
+
i += 1;
|
|
278
|
+
}
|
|
279
|
+
pushText();
|
|
280
|
+
return tokens;
|
|
281
|
+
};
|
|
282
|
+
export const headerFooterZoneFromTokens = (tokens) => tokens
|
|
283
|
+
.map((token) => token.type === "text"
|
|
284
|
+
? token.text.replace(/&/g, "&&")
|
|
285
|
+
: CODE_BY_FIELD[token.field])
|
|
286
|
+
.join("");
|
|
287
|
+
/** Every header/footer text on the facet is empty / absent. */
|
|
288
|
+
export const isHeaderFooterEmpty = (hf) => !hf ||
|
|
289
|
+
(!hf.oddHeader &&
|
|
290
|
+
!hf.oddFooter &&
|
|
291
|
+
!hf.evenHeader &&
|
|
292
|
+
!hf.evenFooter &&
|
|
293
|
+
!hf.firstHeader &&
|
|
294
|
+
!hf.firstFooter &&
|
|
295
|
+
hf.differentOddEven == null &&
|
|
296
|
+
hf.differentFirst == null &&
|
|
297
|
+
hf.scaleWithDoc == null &&
|
|
298
|
+
hf.alignWithMargins == null);
|
|
299
|
+
// ── ODS equivalents ───────────────────────────────────────────────────────
|
|
300
|
+
export const INCH_TO_CM = 2.54;
|
|
301
|
+
/** ECMA-376 paper-size codes → sheet size in inches (width × height, portrait). */
|
|
302
|
+
const PAPER_SIZES_IN = {
|
|
303
|
+
1: [8.5, 11], // Letter
|
|
304
|
+
3: [11, 17], // Tabloid
|
|
305
|
+
5: [8.5, 14], // Legal
|
|
306
|
+
7: [7.25, 10.5], // Executive
|
|
307
|
+
8: [11.69, 16.54], // A3
|
|
308
|
+
9: [8.27, 11.69], // A4
|
|
309
|
+
11: [5.83, 8.27], // A5
|
|
310
|
+
// ECMA-376 ST_PaperSize: 12 = "B4 paper (250 mm by 354 mm)",
|
|
311
|
+
// 13 = "B5 paper (182 mm by 257 mm)" — the JIS B5, not ISO B5 (176 × 250).
|
|
312
|
+
12: [9.84, 13.9], // B4
|
|
313
|
+
13: [7.17, 10.12], // B5 (JIS)
|
|
314
|
+
};
|
|
315
|
+
/** Portrait page size in centimetres for a paper-size code. */
|
|
316
|
+
export const paperSizeToCm = (code) => {
|
|
317
|
+
const size = PAPER_SIZES_IN[code ?? -1];
|
|
318
|
+
if (!size)
|
|
319
|
+
return undefined;
|
|
320
|
+
return { width: size[0] * INCH_TO_CM, height: size[1] * INCH_TO_CM };
|
|
321
|
+
};
|
|
322
|
+
/** Nearest paper-size code for a page (either orientation), or undefined. */
|
|
323
|
+
export const paperSizeFromCm = (widthCm, heightCm) => {
|
|
324
|
+
const w = Math.min(widthCm, heightCm) / INCH_TO_CM;
|
|
325
|
+
const h = Math.max(widthCm, heightCm) / INCH_TO_CM;
|
|
326
|
+
for (const [code, [pw, ph]] of Object.entries(PAPER_SIZES_IN)) {
|
|
327
|
+
if (Math.abs(pw - w) < 0.05 && Math.abs(ph - h) < 0.05) {
|
|
328
|
+
return Number(code);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return undefined;
|
|
332
|
+
};
|
|
333
|
+
/** Parse an ODF length (`2.54cm`, `1in`, `72pt`, `25.4mm`) to inches. */
|
|
334
|
+
export const odsLengthToInches = (value) => {
|
|
335
|
+
if (!value)
|
|
336
|
+
return undefined;
|
|
337
|
+
const match = /^(-?[\d.]+)\s*(cm|mm|in|pt|pc|px)?$/.exec(value.trim());
|
|
338
|
+
if (!match)
|
|
339
|
+
return undefined;
|
|
340
|
+
const n = parseFloat(match[1]);
|
|
341
|
+
if (!Number.isFinite(n))
|
|
342
|
+
return undefined;
|
|
343
|
+
switch (match[2] ?? "cm") {
|
|
344
|
+
case "cm":
|
|
345
|
+
return n / INCH_TO_CM;
|
|
346
|
+
case "mm":
|
|
347
|
+
return n / (INCH_TO_CM * 10);
|
|
348
|
+
case "in":
|
|
349
|
+
return n;
|
|
350
|
+
case "pt":
|
|
351
|
+
return n / 72;
|
|
352
|
+
case "pc":
|
|
353
|
+
return n / 6;
|
|
354
|
+
case "px":
|
|
355
|
+
return n / 96;
|
|
356
|
+
default:
|
|
357
|
+
return undefined;
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
export const inchesToOdsCm = (inches) => `${(inches * INCH_TO_CM).toFixed(3).replace(/\.?0+$/, "")}cm`;
|
|
361
|
+
/**
|
|
362
|
+
* `style:print` token list. LibreOffice's default (attribute absent) is
|
|
363
|
+
* `objects charts drawings zero-values`; `grid` / `headers` map to
|
|
364
|
+
* `<printOptions gridLines headings>`.
|
|
365
|
+
*/
|
|
366
|
+
export const buildOdsPrintTokens = (options) => {
|
|
367
|
+
const tokens = ["objects", "charts", "drawings", "zero-values"];
|
|
368
|
+
if (options?.gridLines)
|
|
369
|
+
tokens.push("grid");
|
|
370
|
+
if (options?.headings)
|
|
371
|
+
tokens.push("headers");
|
|
372
|
+
return tokens.join(" ");
|
|
373
|
+
};
|
|
374
|
+
export const parseOdsPrintTokens = (value) => {
|
|
375
|
+
if (value == null)
|
|
376
|
+
return undefined;
|
|
377
|
+
const tokens = new Set(value.split(/\s+/));
|
|
378
|
+
const options = {};
|
|
379
|
+
if (tokens.has("grid"))
|
|
380
|
+
options.gridLines = true;
|
|
381
|
+
if (tokens.has("headers"))
|
|
382
|
+
options.headings = true;
|
|
383
|
+
return hasAnyValue(options) ? options : undefined;
|
|
384
|
+
};
|
|
385
|
+
export const odsTableCentering = (options) => {
|
|
386
|
+
if (options?.horizontalCentered && options?.verticalCentered)
|
|
387
|
+
return "both";
|
|
388
|
+
if (options?.horizontalCentered)
|
|
389
|
+
return "horizontal";
|
|
390
|
+
if (options?.verticalCentered)
|
|
391
|
+
return "vertical";
|
|
392
|
+
return undefined;
|
|
393
|
+
};
|
|
394
|
+
export const parseOdsTableCentering = (value) => {
|
|
395
|
+
switch (value) {
|
|
396
|
+
case "both":
|
|
397
|
+
return { horizontalCentered: true, verticalCentered: true };
|
|
398
|
+
case "horizontal":
|
|
399
|
+
return { horizontalCentered: true };
|
|
400
|
+
case "vertical":
|
|
401
|
+
return { verticalCentered: true };
|
|
402
|
+
default:
|
|
403
|
+
return {};
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
export const isPageSetupEmpty = (setup) => !hasAnyValue(setup);
|
|
407
|
+
export const isPageMarginsEmpty = (margins) => !hasAnyValue(margins);
|
|
408
|
+
/** Excel's "Normal" margins — what every untouched worksheet carries. */
|
|
409
|
+
export const DEFAULT_PAGE_MARGINS_IN = {
|
|
410
|
+
left: 0.7,
|
|
411
|
+
right: 0.7,
|
|
412
|
+
top: 0.75,
|
|
413
|
+
bottom: 0.75,
|
|
414
|
+
header: 0.3,
|
|
415
|
+
footer: 0.3,
|
|
416
|
+
};
|
|
417
|
+
/** `true` when the margins are exactly Excel's defaults (nothing to keep). */
|
|
418
|
+
export const isDefaultPageMargins = (margins) => !!margins &&
|
|
419
|
+
Object.keys(DEFAULT_PAGE_MARGINS_IN).every((key) => {
|
|
420
|
+
const value = margins[key];
|
|
421
|
+
return (value == null || Math.abs(value - DEFAULT_PAGE_MARGINS_IN[key]) < 1e-9);
|
|
422
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../../autofilter-condition.ts","../../csv-export.ts","../../csv-import-worker.ts","../../csv-import.ts","../../excel-export.ts","../../excel-import-session.ts","../../excel-import-worker.ts","../../helpers.ts","../../index.ts","../../indexed-colors.ts","../../ods-export.ts","../../parse.ts","../../power-query.ts","../../server.ts","../../theme1.ts","../../types.ts","../../vitest.config.ts","../../xlsx.d.ts","../../csv-parser/helpers.ts","../../csv-parser/types.ts","../../csv-parser/worker.ts","../../excel-parser/builtin-numfmts.ts","../../excel-parser/cfb-decryptor.ts","../../excel-parser/cfb-encryptor.ts","../../excel-parser/dv-cell-stamp.ts","../../excel-parser/helpers.ts","../../excel-parser/interface.ts","../../excel-parser/registry.ts","../../excel-parser/style-registry.ts","../../excel-parser/theme-default.ts","../../excel-parser/types.ts","../../excel-parser/utils.ts","../../excel-parser/workbook.ts","../../excel-parser/worker.ts","../../excel-parser/zip-parser-streaming.ts","../../excel-parser/zip-parser.ts","../../excel-parser/plugins/base/index.ts","../../excel-parser/plugins/ods/conditional-formatting.ts","../../excel-parser/plugins/ods/data-validations.ts","../../excel-parser/plugins/ods/formula.ts","../../excel-parser/plugins/ods/index.ts","../../excel-parser/plugins/ods/sparklines.ts","../../excel-parser/plugins/ods/styles.ts","../../excel-parser/plugins/ods/types.ts","../../excel-parser/plugins/xls/index.ts","../../excel-parser/plugins/xlsb/biff-record-reader.ts","../../excel-parser/plugins/xlsb/index.ts","../../excel-parser/plugins/xlsb/rgce-parser.ts","../../excel-parser/plugins/xlsm/index.ts","../../excel-parser/plugins/xlsx/charts.ts","../../excel-parser/plugins/xlsx/conditional-formatting.ts","../../excel-parser/plugins/xlsx/data-validations.ts","../../excel-parser/plugins/xlsx/drawing.ts","../../excel-parser/plugins/xlsx/index.ts","../../excel-parser/plugins/xlsx/numfmt.ts","../../excel-parser/plugins/xlsx/pivots.ts","../../excel-parser/plugins/xlsx/relationships.ts","../../excel-parser/plugins/xlsx/sheet-views.ts","../../excel-parser/plugins/xlsx/styles.ts","../../excel-parser/plugins/xlsx/theme.ts","../../excel-parser/plugins/xlsx/threaded-comments.ts","../../excel-parser/plugins/xlsx/value-type-detection.ts","../../exporter/invalid-data-validation.ts","../../exporter/ods/ods-export.ts","../../exporter/ods/sparkline-builder.ts","../../exporter/xlsx/chart-builder.ts","../../exporter/xlsx/chart-templates.ts","../../exporter/xlsx/future-functions.ts","../../exporter/xlsx/pivot-builder.ts","../../exporter/xlsx/power-query-builder.ts","../../exporter/xlsx/slicer-builder.ts","../../exporter/xlsx/sparkline-builder.ts","../../exporter/xlsx/style-builder.ts","../../exporter/xlsx/threaded-comments-builder.ts","../../exporter/xlsx/xlsx-export.ts","../../helpers/theme-xml-generator.ts"],"version":"5.8.3"}
|
|
1
|
+
{"root":["../../autofilter-condition.ts","../../csv-export.ts","../../csv-import-worker.ts","../../csv-import.ts","../../excel-export.ts","../../excel-import-session.ts","../../excel-import-worker.ts","../../helpers.ts","../../index.ts","../../indexed-colors.ts","../../ods-export.ts","../../parse.ts","../../power-query.ts","../../print-settings.ts","../../server.ts","../../theme1.ts","../../types.ts","../../vitest.config.ts","../../xlsx.d.ts","../../csv-parser/helpers.ts","../../csv-parser/types.ts","../../csv-parser/worker.ts","../../excel-parser/builtin-numfmts.ts","../../excel-parser/cfb-decryptor.ts","../../excel-parser/cfb-encryptor.ts","../../excel-parser/dv-cell-stamp.ts","../../excel-parser/helpers.ts","../../excel-parser/interface.ts","../../excel-parser/registry.ts","../../excel-parser/style-registry.ts","../../excel-parser/theme-default.ts","../../excel-parser/types.ts","../../excel-parser/utils.ts","../../excel-parser/workbook.ts","../../excel-parser/worker.ts","../../excel-parser/zip-parser-streaming.ts","../../excel-parser/zip-parser.ts","../../excel-parser/plugins/base/index.ts","../../excel-parser/plugins/ods/conditional-formatting.ts","../../excel-parser/plugins/ods/data-validations.ts","../../excel-parser/plugins/ods/formula.ts","../../excel-parser/plugins/ods/index.ts","../../excel-parser/plugins/ods/sparklines.ts","../../excel-parser/plugins/ods/styles.ts","../../excel-parser/plugins/ods/types.ts","../../excel-parser/plugins/xls/index.ts","../../excel-parser/plugins/xlsb/biff-record-reader.ts","../../excel-parser/plugins/xlsb/index.ts","../../excel-parser/plugins/xlsb/rgce-parser.ts","../../excel-parser/plugins/xlsm/index.ts","../../excel-parser/plugins/xlsx/chartex.ts","../../excel-parser/plugins/xlsx/charts.ts","../../excel-parser/plugins/xlsx/conditional-formatting.ts","../../excel-parser/plugins/xlsx/data-validations.ts","../../excel-parser/plugins/xlsx/drawing.ts","../../excel-parser/plugins/xlsx/form-controls.ts","../../excel-parser/plugins/xlsx/index.ts","../../excel-parser/plugins/xlsx/numfmt.ts","../../excel-parser/plugins/xlsx/pivots.ts","../../excel-parser/plugins/xlsx/relationships.ts","../../excel-parser/plugins/xlsx/sheet-views.ts","../../excel-parser/plugins/xlsx/styles.ts","../../excel-parser/plugins/xlsx/theme.ts","../../excel-parser/plugins/xlsx/threaded-comments.ts","../../excel-parser/plugins/xlsx/value-type-detection.ts","../../exporter/invalid-data-validation.ts","../../exporter/ods/ods-export.ts","../../exporter/ods/sparkline-builder.ts","../../exporter/xlsx/chart-builder.ts","../../exporter/xlsx/chart-templates.ts","../../exporter/xlsx/chartex-builder.ts","../../exporter/xlsx/form-controls-builder.ts","../../exporter/xlsx/future-functions.ts","../../exporter/xlsx/pivot-builder.ts","../../exporter/xlsx/power-query-builder.ts","../../exporter/xlsx/slicer-builder.ts","../../exporter/xlsx/sparkline-builder.ts","../../exporter/xlsx/style-builder.ts","../../exporter/xlsx/threaded-comments-builder.ts","../../exporter/xlsx/xlsx-export.ts","../../helpers/implicit-intersection.ts","../../helpers/theme-xml-generator.ts"],"version":"5.8.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rowsncolumns/toolkit",
|
|
3
|
-
"version": "24.4.
|
|
3
|
+
"version": "24.4.4",
|
|
4
4
|
"author": "Vinay M",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
"url": "https://github.com/rowsncolumns/spreadsheet/issues"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@rowsncolumns/utils": ">=9.2.
|
|
46
|
+
"@rowsncolumns/utils": ">=9.2.41",
|
|
47
47
|
"@types/lodash-es": "^4.17.12"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@noble/ciphers": "^0.5.3",
|
|
52
52
|
"@noble/hashes": "^1.4.0",
|
|
53
|
-
"@rowsncolumns/calculator": ">=7.2.
|
|
53
|
+
"@rowsncolumns/calculator": ">=7.2.32",
|
|
54
54
|
"@zip.js/zip.js": "^2.8.17",
|
|
55
55
|
"fast-xml-parser": "^5.8.0",
|
|
56
56
|
"fflate": "^0.8.2",
|
package/xlsx.d.ts
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
1
|
declare module "xlsx/xlsx.mjs" {
|
|
2
|
+
import type * as SheetJs from "xlsx";
|
|
3
|
+
|
|
4
|
+
/** SheetJS workbook reader — used for the BIFF8 (`.xls`) plugin. */
|
|
5
|
+
export const read: typeof SheetJs.read;
|
|
6
|
+
/** SheetJS workbook writer (tests build BIFF8 fixtures with it). */
|
|
7
|
+
export const write: typeof SheetJs.write;
|
|
8
|
+
export const utils: typeof SheetJs.utils;
|
|
9
|
+
export type WorkBook = SheetJs.WorkBook;
|
|
10
|
+
export type WorkSheet = SheetJs.WorkSheet;
|
|
11
|
+
export type CellObject = SheetJs.CellObject;
|
|
12
|
+
export type ColInfo = SheetJs.ColInfo;
|
|
13
|
+
export type RowInfo = SheetJs.RowInfo;
|
|
14
|
+
export type DefinedName = SheetJs.DefinedName;
|
|
15
|
+
|
|
2
16
|
export namespace CFB {
|
|
3
17
|
interface CFBEntry {
|
|
4
18
|
name: string;
|