reamkit 1.12.0 → 1.14.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/dist/esm/core/document-model/types.d.ts +3 -0
- package/dist/esm/core/ir/sheet.d.ts +49 -3
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +80 -1
- package/dist/esm/excel/comments-parser.d.ts +4 -0
- package/dist/esm/excel/comments-parser.js +104 -0
- package/dist/esm/excel/conditional-format.d.ts +2 -2
- package/dist/esm/excel/conditional-format.js +113 -11
- package/dist/esm/excel/form-control-parser.d.ts +6 -0
- package/dist/esm/excel/form-control-parser.js +29 -0
- package/dist/esm/excel/header-footer.d.ts +2 -0
- package/dist/esm/excel/header-footer.js +127 -0
- package/dist/esm/excel/index.d.ts +1 -1
- package/dist/esm/excel/print-model.d.ts +7 -2
- package/dist/esm/excel/print-model.js +218 -19
- package/dist/esm/excel/shared-strings-parser.d.ts +6 -1
- package/dist/esm/excel/shared-strings-parser.js +91 -12
- package/dist/esm/excel/sheet-drawing.d.ts +13 -1
- package/dist/esm/excel/sheet-drawing.js +47 -14
- package/dist/esm/excel/sheet-shape-parser.d.ts +4 -0
- package/dist/esm/excel/sheet-shape-parser.js +96 -0
- package/dist/esm/excel/sheet-to-flow.js +130 -3
- package/dist/esm/excel/slicer-parser.d.ts +15 -0
- package/dist/esm/excel/slicer-parser.js +76 -0
- package/dist/esm/excel/styles-parser.js +37 -0
- package/dist/esm/excel/table-parser.d.ts +10 -0
- package/dist/esm/excel/table-parser.js +36 -4
- package/dist/esm/excel/worksheet-parser.js +181 -1
- package/dist/esm/excel/xlsx-reader.js +203 -17
- package/dist/esm/excel/xlsx-writer.js +19 -3
- package/dist/esm/html/html-writer.js +4 -0
- package/dist/esm/layout/styled-layout.js +72 -1
- package/dist/esm/pptx/slide-parser.d.ts +4 -2
- package/dist/esm/pptx/slide-parser.js +1 -1
- package/package.json +1 -1
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { pt } from "../core/ir/units.js";
|
|
2
2
|
import { EMPTY_STYLE_SHEET, resolveBodyStyles } from "../core/style-cascade/resolver.js";
|
|
3
3
|
import "../core/style-cascade/index.js";
|
|
4
|
-
import { resolvePrintArea, resolvePrintTitleRows, sectionFromWorksheet, worksheetToBody } from "./print-model.js";
|
|
4
|
+
import { resolvePrintArea, resolvePrintTitleRows, sectionFromWorksheet, slicerTable, worksheetToBody } from "./print-model.js";
|
|
5
|
+
import { buildHeaderFooterContent } from "./header-footer.js";
|
|
5
6
|
//#region src/excel/sheet-to-flow.ts
|
|
7
|
+
var HEADER_REL = "_xlsxHeaderDefault";
|
|
8
|
+
var FOOTER_REL = "_xlsxFooterDefault";
|
|
6
9
|
function projectSheetDoc(sheet) {
|
|
7
10
|
const body = [];
|
|
8
11
|
let firstSheetSection;
|
|
12
|
+
const headersFooters = /* @__PURE__ */ new Map();
|
|
9
13
|
const sheetGrids = new Map(sheet.sheets.map((s) => [s.name, s.grid]));
|
|
10
14
|
for (let sheetIdx = 0; sheetIdx < sheet.sheets.length; sheetIdx++) {
|
|
11
15
|
const ws = sheet.sheets[sheetIdx];
|
|
12
|
-
if (sheetIdx === 0) firstSheetSection = sectionFromWorksheet(ws.grid);
|
|
16
|
+
if (sheetIdx === 0) firstSheetSection = withHeaderFooter(sectionFromWorksheet(ws.grid), ws, headersFooters);
|
|
13
17
|
if (sheetIdx > 0) body.push({
|
|
14
18
|
kind: "paragraph",
|
|
15
19
|
paragraph: {
|
|
@@ -24,7 +28,9 @@ function projectSheetDoc(sheet) {
|
|
|
24
28
|
...printArea ? { printArea } : {},
|
|
25
29
|
...titleRows ? { titleRows } : {},
|
|
26
30
|
gridLines,
|
|
27
|
-
sheetGrids
|
|
31
|
+
sheetGrids,
|
|
32
|
+
...ws.hyperlinks ? { hyperlinks: ws.hyperlinks } : {},
|
|
33
|
+
...sheet.sharedStringRuns ? { sharedStringRuns: sheet.sharedStringRuns } : {}
|
|
28
34
|
}));
|
|
29
35
|
for (const ref of ws.charts ?? []) body.push({
|
|
30
36
|
kind: "chart",
|
|
@@ -35,6 +41,25 @@ function projectSheetDoc(sheet) {
|
|
|
35
41
|
paragraphProperties: {}
|
|
36
42
|
}
|
|
37
43
|
});
|
|
44
|
+
for (const img of ws.images ?? []) body.push({
|
|
45
|
+
kind: "image",
|
|
46
|
+
image: {
|
|
47
|
+
resource: img.resourceId,
|
|
48
|
+
width: pt(img.widthPt),
|
|
49
|
+
height: pt(img.heightPt),
|
|
50
|
+
paragraphProperties: {}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
for (const shape of ws.shapes ?? []) body.push({
|
|
54
|
+
kind: "shape",
|
|
55
|
+
shape
|
|
56
|
+
});
|
|
57
|
+
for (const slicer of ws.slicers ?? []) body.push({
|
|
58
|
+
kind: "table",
|
|
59
|
+
table: slicerTable(slicer)
|
|
60
|
+
});
|
|
61
|
+
if (ws.comments && ws.comments.length > 0) body.push(...commentBlocks(ws.comments));
|
|
62
|
+
if (ws.formControls && ws.formControls.length > 0) body.push(...formControlBlocks(ws.formControls));
|
|
38
63
|
}
|
|
39
64
|
return {
|
|
40
65
|
kind: "flow",
|
|
@@ -44,8 +69,110 @@ function projectSheetDoc(sheet) {
|
|
|
44
69
|
styles: EMPTY_STYLE_SHEET,
|
|
45
70
|
resources: sheet.resources,
|
|
46
71
|
...sheet.chartData && sheet.chartData.size > 0 ? { charts: sheet.chartData } : {},
|
|
72
|
+
...headersFooters.size > 0 ? { headersFooters } : {},
|
|
47
73
|
...sheet.info ? { info: sheet.info } : {}
|
|
48
74
|
};
|
|
49
75
|
}
|
|
76
|
+
function commentBlocks(comments) {
|
|
77
|
+
const out = [{
|
|
78
|
+
kind: "paragraph",
|
|
79
|
+
paragraph: {
|
|
80
|
+
properties: {},
|
|
81
|
+
runs: [{
|
|
82
|
+
text: "Comments",
|
|
83
|
+
properties: { bold: true }
|
|
84
|
+
}]
|
|
85
|
+
}
|
|
86
|
+
}];
|
|
87
|
+
for (const c of comments) {
|
|
88
|
+
const body = c.text.replace(/\s+/g, " ").trim();
|
|
89
|
+
const label = c.author ? `${c.ref} — ${c.author}: ` : `${c.ref}: `;
|
|
90
|
+
out.push({
|
|
91
|
+
kind: "paragraph",
|
|
92
|
+
paragraph: {
|
|
93
|
+
properties: {},
|
|
94
|
+
runs: [{
|
|
95
|
+
text: label,
|
|
96
|
+
properties: { bold: true }
|
|
97
|
+
}, ...body.length > 0 ? [{
|
|
98
|
+
text: body,
|
|
99
|
+
properties: {}
|
|
100
|
+
}] : []]
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
}
|
|
106
|
+
function formControlBlocks(controls) {
|
|
107
|
+
const out = [{
|
|
108
|
+
kind: "paragraph",
|
|
109
|
+
paragraph: {
|
|
110
|
+
properties: {},
|
|
111
|
+
runs: [{
|
|
112
|
+
text: "Form controls",
|
|
113
|
+
properties: { bold: true }
|
|
114
|
+
}]
|
|
115
|
+
}
|
|
116
|
+
}];
|
|
117
|
+
for (const c of controls) out.push({
|
|
118
|
+
kind: "paragraph",
|
|
119
|
+
paragraph: {
|
|
120
|
+
properties: {},
|
|
121
|
+
runs: [{
|
|
122
|
+
text: formControlLabel(c),
|
|
123
|
+
properties: {}
|
|
124
|
+
}]
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
function formControlLabel(c) {
|
|
130
|
+
const name = c.name ?? c.objectType ?? "Control";
|
|
131
|
+
switch ((c.objectType ?? "").toLowerCase()) {
|
|
132
|
+
case "checkbox": return `${c.checked ? "[x]" : "[ ]"} ${name}`;
|
|
133
|
+
case "radio": return `${c.checked ? "(o)" : "( )"} ${name}`;
|
|
134
|
+
case "buttons": return `[ ${name} ]`;
|
|
135
|
+
case "spin":
|
|
136
|
+
case "scroll": return c.value !== void 0 ? `${name} (value ${c.value})` : name;
|
|
137
|
+
case "drop":
|
|
138
|
+
case "list": return `${name} (list)`;
|
|
139
|
+
default: return c.objectType ? `${name} (${c.objectType})` : name;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function withHeaderFooter(section, ws, headersFooters) {
|
|
143
|
+
const hf = ws.grid.headerFooter;
|
|
144
|
+
if (!hf || !hf.oddHeader && !hf.oddFooter) return section;
|
|
145
|
+
const headers = [];
|
|
146
|
+
const footers = [];
|
|
147
|
+
if (hf.oddHeader) {
|
|
148
|
+
const content = buildHeaderFooterContent(hf.oddHeader, ws.name);
|
|
149
|
+
if (content.length > 0) {
|
|
150
|
+
headersFooters.set(HEADER_REL, resolveBodyStyles(content, EMPTY_STYLE_SHEET));
|
|
151
|
+
headers.push({
|
|
152
|
+
type: "default",
|
|
153
|
+
relationshipId: HEADER_REL
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (hf.oddFooter) {
|
|
158
|
+
const content = buildHeaderFooterContent(hf.oddFooter, ws.name);
|
|
159
|
+
if (content.length > 0) {
|
|
160
|
+
headersFooters.set(FOOTER_REL, resolveBodyStyles(content, EMPTY_STYLE_SHEET));
|
|
161
|
+
footers.push({
|
|
162
|
+
type: "default",
|
|
163
|
+
relationshipId: FOOTER_REL
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (headers.length === 0 && footers.length === 0) return section;
|
|
168
|
+
return {
|
|
169
|
+
...section ?? {
|
|
170
|
+
headers: [],
|
|
171
|
+
footers: []
|
|
172
|
+
},
|
|
173
|
+
headers,
|
|
174
|
+
footers
|
|
175
|
+
};
|
|
176
|
+
}
|
|
50
177
|
//#endregion
|
|
51
178
|
export { projectSheetDoc };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface SlicerDef {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly cacheName: string;
|
|
4
|
+
readonly caption: string;
|
|
5
|
+
readonly columnCount: number;
|
|
6
|
+
readonly styleName?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SlicerCacheDef {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly sourceName?: string;
|
|
11
|
+
readonly tableId?: number;
|
|
12
|
+
readonly columnId?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function parseSlicerPart(data: Uint8Array): Array<SlicerDef>;
|
|
15
|
+
export declare function parseSlicerCachePart(data: Uint8Array): SlicerCacheDef | undefined;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { XMLParser } from "fast-xml-parser";
|
|
2
|
+
//#region src/excel/slicer-parser.ts
|
|
3
|
+
var decoder = new TextDecoder("utf-8");
|
|
4
|
+
var parser = new XMLParser({
|
|
5
|
+
ignoreAttributes: false,
|
|
6
|
+
attributeNamePrefix: "@_",
|
|
7
|
+
parseAttributeValue: false,
|
|
8
|
+
parseTagValue: false,
|
|
9
|
+
removeNSPrefix: true
|
|
10
|
+
});
|
|
11
|
+
function parseSlicerPart(data) {
|
|
12
|
+
const root = asObj(parser.parse(decoder.decode(data))["slicers"]);
|
|
13
|
+
if (!root) return [];
|
|
14
|
+
const out = [];
|
|
15
|
+
for (const s of asArray(root["slicer"])) {
|
|
16
|
+
const o = asObj(s);
|
|
17
|
+
if (!o) continue;
|
|
18
|
+
const name = strAttr(o, "name");
|
|
19
|
+
const cacheName = strAttr(o, "cache");
|
|
20
|
+
if (!name || !cacheName) continue;
|
|
21
|
+
const caption = strAttr(o, "caption") ?? name;
|
|
22
|
+
const styleName = strAttr(o, "style");
|
|
23
|
+
out.push({
|
|
24
|
+
name,
|
|
25
|
+
cacheName,
|
|
26
|
+
caption,
|
|
27
|
+
columnCount: Math.max(1, numAttr(o, "columnCount") ?? 1),
|
|
28
|
+
...styleName ? { styleName } : {}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
function parseSlicerCachePart(data) {
|
|
34
|
+
const root = asObj(parser.parse(decoder.decode(data))["slicerCacheDefinition"]);
|
|
35
|
+
if (!root) return void 0;
|
|
36
|
+
const name = strAttr(root, "name");
|
|
37
|
+
if (!name) return void 0;
|
|
38
|
+
const sourceName = strAttr(root, "sourceName");
|
|
39
|
+
let tableId;
|
|
40
|
+
let columnId;
|
|
41
|
+
const extLst = asObj(root["extLst"]);
|
|
42
|
+
if (extLst) for (const ext of asArray(extLst["ext"])) {
|
|
43
|
+
const e = asObj(ext);
|
|
44
|
+
const inner = e ? asObj(e["slicerCacheDefinition"]) : void 0;
|
|
45
|
+
const tsc = inner ? asObj(inner["tableSlicerCache"]) : void 0;
|
|
46
|
+
if (tsc) {
|
|
47
|
+
tableId = numAttr(tsc, "tableId");
|
|
48
|
+
columnId = numAttr(tsc, "column");
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
name,
|
|
54
|
+
...sourceName ? { sourceName } : {},
|
|
55
|
+
...tableId !== void 0 ? { tableId } : {},
|
|
56
|
+
...columnId !== void 0 ? { columnId } : {}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function asObj(v) {
|
|
60
|
+
return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
61
|
+
}
|
|
62
|
+
function asArray(v) {
|
|
63
|
+
return Array.isArray(v) ? v : v === void 0 || v === null ? [] : [v];
|
|
64
|
+
}
|
|
65
|
+
function strAttr(obj, name) {
|
|
66
|
+
const v = obj[`@_${name}`];
|
|
67
|
+
return typeof v === "string" ? v : void 0;
|
|
68
|
+
}
|
|
69
|
+
function numAttr(obj, name) {
|
|
70
|
+
const v = strAttr(obj, name);
|
|
71
|
+
if (v === void 0) return void 0;
|
|
72
|
+
const n = Number(v);
|
|
73
|
+
return Number.isFinite(n) ? n : void 0;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { parseSlicerCachePart, parseSlicerPart };
|
|
@@ -101,6 +101,12 @@ function parseBorders(root) {
|
|
|
101
101
|
if (right) border.right = right;
|
|
102
102
|
if (bottom) border.bottom = bottom;
|
|
103
103
|
if (left) border.left = left;
|
|
104
|
+
const diagonal = parseBorderEdge(asObject(obj["diagonal"]));
|
|
105
|
+
if (diagonal) {
|
|
106
|
+
border.diagonal = diagonal;
|
|
107
|
+
if (boolAttr(obj, "diagonalUp")) border.diagonalUp = true;
|
|
108
|
+
if (boolAttr(obj, "diagonalDown")) border.diagonalDown = true;
|
|
109
|
+
}
|
|
104
110
|
out.push(border);
|
|
105
111
|
}
|
|
106
112
|
return out;
|
|
@@ -169,6 +175,13 @@ function parseFills(root) {
|
|
|
169
175
|
if (fg) fill.fgColorHex = fg;
|
|
170
176
|
if (bg) fill.bgColorHex = bg;
|
|
171
177
|
}
|
|
178
|
+
if (!fill.patternType) {
|
|
179
|
+
const avg = averageGradientColor(asObject(obj["gradientFill"]));
|
|
180
|
+
if (avg) {
|
|
181
|
+
fill.patternType = "solid";
|
|
182
|
+
fill.fgColorHex = avg;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
172
185
|
out.push(fill);
|
|
173
186
|
}
|
|
174
187
|
return out;
|
|
@@ -205,6 +218,11 @@ function parseCellXfs(root) {
|
|
|
205
218
|
if (h) a.horizontal = h;
|
|
206
219
|
if (v) a.vertical = v;
|
|
207
220
|
if (wrap !== void 0) a.wrapText = wrap;
|
|
221
|
+
const indent = numAttr(align, "indent");
|
|
222
|
+
if (indent !== void 0 && indent > 0) a.indent = indent;
|
|
223
|
+
const rotation = numAttr(align, "textRotation");
|
|
224
|
+
if (rotation !== void 0 && rotation !== 0) a.textRotation = rotation;
|
|
225
|
+
if (boolAttr(align, "shrinkToFit")) a.shrinkToFit = true;
|
|
208
226
|
if (Object.keys(a).length > 0) xf.alignment = a;
|
|
209
227
|
}
|
|
210
228
|
out.push(xf);
|
|
@@ -250,6 +268,25 @@ function childToggle(obj, childName) {
|
|
|
250
268
|
if (val === void 0) return true;
|
|
251
269
|
return !(val === "false" || val === "0");
|
|
252
270
|
}
|
|
271
|
+
function averageGradientColor(gf) {
|
|
272
|
+
if (!gf) return void 0;
|
|
273
|
+
let r = 0;
|
|
274
|
+
let g = 0;
|
|
275
|
+
let b = 0;
|
|
276
|
+
let n = 0;
|
|
277
|
+
for (const s of asArray(gf["stop"])) {
|
|
278
|
+
const so = asObject(s);
|
|
279
|
+
const hex = so ? colorOf(asObject(so["color"])) : void 0;
|
|
280
|
+
if (!hex) continue;
|
|
281
|
+
r += parseInt(hex.slice(0, 2), 16);
|
|
282
|
+
g += parseInt(hex.slice(2, 4), 16);
|
|
283
|
+
b += parseInt(hex.slice(4, 6), 16);
|
|
284
|
+
n++;
|
|
285
|
+
}
|
|
286
|
+
if (n === 0) return void 0;
|
|
287
|
+
const h = (x) => Math.round(x / n).toString(16).padStart(2, "0").toUpperCase();
|
|
288
|
+
return `${h(r)}${h(g)}${h(b)}`;
|
|
289
|
+
}
|
|
253
290
|
function colorOf(node) {
|
|
254
291
|
if (!node) return void 0;
|
|
255
292
|
const rgb = strAttr(node, "rgb");
|
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
import { ExcelTable } from '../core/spreadsheet-model/index.js';
|
|
2
|
+
export interface TableFilterColumn {
|
|
3
|
+
readonly colId: number;
|
|
4
|
+
readonly values: ReadonlyArray<string>;
|
|
5
|
+
}
|
|
6
|
+
export interface ParsedTablePart {
|
|
7
|
+
readonly table: ExcelTable;
|
|
8
|
+
readonly id?: number;
|
|
9
|
+
readonly filters: ReadonlyArray<TableFilterColumn>;
|
|
10
|
+
}
|
|
2
11
|
export declare function parseTablePart(data: Uint8Array): ExcelTable | undefined;
|
|
12
|
+
export declare function parseTablePartFull(data: Uint8Array): ParsedTablePart | undefined;
|
|
@@ -9,7 +9,7 @@ var parser = new XMLParser({
|
|
|
9
9
|
parseTagValue: false,
|
|
10
10
|
removeNSPrefix: true
|
|
11
11
|
});
|
|
12
|
-
function
|
|
12
|
+
function parseTablePartFull(data) {
|
|
13
13
|
const t = asObj(parser.parse(decoder.decode(data))["table"]);
|
|
14
14
|
if (!t) return void 0;
|
|
15
15
|
const refStr = strAttr(t, "ref");
|
|
@@ -18,7 +18,8 @@ function parseTablePart(data) {
|
|
|
18
18
|
const si = asObj(t["tableStyleInfo"]);
|
|
19
19
|
const name = strAttr(t, "name");
|
|
20
20
|
const styleName = si ? strAttr(si, "name") : void 0;
|
|
21
|
-
|
|
21
|
+
const af = asObj(t["autoFilter"]);
|
|
22
|
+
const table = {
|
|
22
23
|
ref,
|
|
23
24
|
...name ? { name } : {},
|
|
24
25
|
...styleName ? { styleName } : {},
|
|
@@ -27,9 +28,40 @@ function parseTablePart(data) {
|
|
|
27
28
|
showColumnStripes: si ? boolAttr(si, "showColumnStripes") : false,
|
|
28
29
|
showFirstColumn: si ? boolAttr(si, "showFirstColumn") : false,
|
|
29
30
|
showLastColumn: si ? boolAttr(si, "showLastColumn") : false,
|
|
30
|
-
autoFilter:
|
|
31
|
+
autoFilter: af !== void 0
|
|
32
|
+
};
|
|
33
|
+
const id = numAttr(t, "id");
|
|
34
|
+
return {
|
|
35
|
+
table,
|
|
36
|
+
...id !== void 0 ? { id } : {},
|
|
37
|
+
filters: parseFilterColumns(af)
|
|
31
38
|
};
|
|
32
39
|
}
|
|
40
|
+
function parseFilterColumns(af) {
|
|
41
|
+
if (!af) return [];
|
|
42
|
+
const out = [];
|
|
43
|
+
for (const fc of asArray(af["filterColumn"])) {
|
|
44
|
+
const col = asObj(fc);
|
|
45
|
+
if (!col) continue;
|
|
46
|
+
const colId = numAttr(col, "colId");
|
|
47
|
+
if (colId === void 0) continue;
|
|
48
|
+
const filters = asObj(col["filters"]);
|
|
49
|
+
if (!filters) continue;
|
|
50
|
+
const values = [];
|
|
51
|
+
for (const f of asArray(filters["filter"])) {
|
|
52
|
+
const v = asObj(f) ? strAttr(asObj(f), "val") : void 0;
|
|
53
|
+
if (v !== void 0) values.push(v);
|
|
54
|
+
}
|
|
55
|
+
out.push({
|
|
56
|
+
colId,
|
|
57
|
+
values
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
function asArray(v) {
|
|
63
|
+
return Array.isArray(v) ? v : v === void 0 || v === null ? [] : [v];
|
|
64
|
+
}
|
|
33
65
|
function asObj(v) {
|
|
34
66
|
return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
35
67
|
}
|
|
@@ -48,4 +80,4 @@ function boolAttr(obj, name) {
|
|
|
48
80
|
return v === "1" || v === "true";
|
|
49
81
|
}
|
|
50
82
|
//#endregion
|
|
51
|
-
export {
|
|
83
|
+
export { parseTablePartFull };
|
|
@@ -37,6 +37,10 @@ function parseWorksheet(data) {
|
|
|
37
37
|
const drawingNode = wsObj["drawing"];
|
|
38
38
|
const drawingRelId = drawingNode && typeof drawingNode === "object" ? strAttr(drawingNode, "id") : void 0;
|
|
39
39
|
const conditionalFormats = parseConditionalFormatting(wsObj);
|
|
40
|
+
const dataValidations = parseDataValidations(wsObj);
|
|
41
|
+
const hyperlinks = parseHyperlinks(wsObj);
|
|
42
|
+
const headerFooter = parseHeaderFooter(wsObj);
|
|
43
|
+
const formControls = parseFormControls(wsObj);
|
|
40
44
|
const sparklines = parseSparklines(wsObj);
|
|
41
45
|
const tablePartRelIds = parseTableParts(wsObj);
|
|
42
46
|
const printModel = {
|
|
@@ -49,6 +53,10 @@ function parseWorksheet(data) {
|
|
|
49
53
|
...pane ? { pane } : {},
|
|
50
54
|
...drawingRelId !== void 0 ? { drawingRelId } : {},
|
|
51
55
|
...conditionalFormats.length > 0 ? { conditionalFormats } : {},
|
|
56
|
+
...dataValidations.length > 0 ? { dataValidations } : {},
|
|
57
|
+
...hyperlinks.length > 0 ? { hyperlinks } : {},
|
|
58
|
+
...headerFooter ? { headerFooter } : {},
|
|
59
|
+
...formControls.length > 0 ? { formControls } : {},
|
|
52
60
|
...sparklines.length > 0 ? { sparklines } : {},
|
|
53
61
|
...tablePartRelIds.length > 0 ? { tablePartRelIds } : {}
|
|
54
62
|
};
|
|
@@ -298,6 +306,95 @@ function parseConditionalFormatting(ws) {
|
|
|
298
306
|
}
|
|
299
307
|
return out;
|
|
300
308
|
}
|
|
309
|
+
var DV_TYPES = new Set([
|
|
310
|
+
"none",
|
|
311
|
+
"whole",
|
|
312
|
+
"decimal",
|
|
313
|
+
"list",
|
|
314
|
+
"date",
|
|
315
|
+
"time",
|
|
316
|
+
"textLength",
|
|
317
|
+
"custom"
|
|
318
|
+
]);
|
|
319
|
+
function parseDataValidations(ws) {
|
|
320
|
+
const node = asObjectNode(ws["dataValidations"]);
|
|
321
|
+
if (!node) return [];
|
|
322
|
+
const out = [];
|
|
323
|
+
for (const dv of toArray(node["dataValidation"])) {
|
|
324
|
+
const obj = asObjectNode(dv);
|
|
325
|
+
if (!obj) continue;
|
|
326
|
+
const sqref = strAttr(obj, "sqref");
|
|
327
|
+
if (!sqref) continue;
|
|
328
|
+
const ranges = parseSqref(sqref);
|
|
329
|
+
if (ranges.length === 0) continue;
|
|
330
|
+
const typeRaw = strAttr(obj, "type");
|
|
331
|
+
const type = typeRaw && DV_TYPES.has(typeRaw) ? typeRaw : "none";
|
|
332
|
+
const operator = strAttr(obj, "operator");
|
|
333
|
+
const errorStyle = strAttr(obj, "errorStyle");
|
|
334
|
+
const formula1 = formulaText(obj["formula1"]);
|
|
335
|
+
const formula2 = formulaText(obj["formula2"]);
|
|
336
|
+
const promptTitle = strAttr(obj, "promptTitle");
|
|
337
|
+
const prompt = strAttr(obj, "prompt");
|
|
338
|
+
const errorTitle = strAttr(obj, "errorTitle");
|
|
339
|
+
const error = strAttr(obj, "error");
|
|
340
|
+
out.push({
|
|
341
|
+
type,
|
|
342
|
+
ranges,
|
|
343
|
+
...operator !== void 0 ? { operator } : {},
|
|
344
|
+
...boolAttr(obj, "allowBlank") ? { allowBlank: true } : {},
|
|
345
|
+
...boolAttr(obj, "showDropDown") ? { showDropDown: true } : {},
|
|
346
|
+
...boolAttr(obj, "showInputMessage") ? { showInputMessage: true } : {},
|
|
347
|
+
...boolAttr(obj, "showErrorMessage") ? { showErrorMessage: true } : {},
|
|
348
|
+
...errorStyle !== void 0 ? { errorStyle } : {},
|
|
349
|
+
...formula1 !== void 0 ? { formula1 } : {},
|
|
350
|
+
...formula2 !== void 0 ? { formula2 } : {},
|
|
351
|
+
...promptTitle !== void 0 ? { promptTitle } : {},
|
|
352
|
+
...prompt !== void 0 ? { prompt } : {},
|
|
353
|
+
...errorTitle !== void 0 ? { errorTitle } : {},
|
|
354
|
+
...error !== void 0 ? { error } : {}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
return out;
|
|
358
|
+
}
|
|
359
|
+
function boolAttr(obj, key) {
|
|
360
|
+
const raw = strAttr(obj, key);
|
|
361
|
+
return raw === "1" || raw === "true";
|
|
362
|
+
}
|
|
363
|
+
function parseHeaderFooter(ws) {
|
|
364
|
+
const node = asObjectNode(ws["headerFooter"]);
|
|
365
|
+
if (!node) return void 0;
|
|
366
|
+
const oddHeader = formulaText(node["oddHeader"]);
|
|
367
|
+
const oddFooter = formulaText(node["oddFooter"]);
|
|
368
|
+
if (!oddHeader && !oddFooter) return void 0;
|
|
369
|
+
return {
|
|
370
|
+
...oddHeader ? { oddHeader } : {},
|
|
371
|
+
...oddFooter ? { oddFooter } : {}
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function parseHyperlinks(ws) {
|
|
375
|
+
const node = asObjectNode(ws["hyperlinks"]);
|
|
376
|
+
if (!node) return [];
|
|
377
|
+
const out = [];
|
|
378
|
+
for (const h of toArray(node["hyperlink"])) {
|
|
379
|
+
const obj = asObjectNode(h);
|
|
380
|
+
if (!obj) continue;
|
|
381
|
+
const ref = strAttr(obj, "ref");
|
|
382
|
+
if (!ref) continue;
|
|
383
|
+
const relId = strAttr(obj, "id");
|
|
384
|
+
const location = strAttr(obj, "location");
|
|
385
|
+
if (relId === void 0 && location === void 0) continue;
|
|
386
|
+
const display = strAttr(obj, "display");
|
|
387
|
+
const tooltip = strAttr(obj, "tooltip");
|
|
388
|
+
out.push({
|
|
389
|
+
ref,
|
|
390
|
+
...relId !== void 0 ? { relId } : {},
|
|
391
|
+
...location !== void 0 ? { location } : {},
|
|
392
|
+
...display !== void 0 ? { display } : {},
|
|
393
|
+
...tooltip !== void 0 ? { tooltip } : {}
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return out;
|
|
397
|
+
}
|
|
301
398
|
function parseSqref(sqref) {
|
|
302
399
|
const out = [];
|
|
303
400
|
for (const token of sqref.split(/\s+/)) {
|
|
@@ -324,14 +421,73 @@ var CF_OPERATORS = new Set([
|
|
|
324
421
|
]);
|
|
325
422
|
function parseCfRule(obj) {
|
|
326
423
|
const priority = parseNumericAttr(obj, "priority") ?? 0;
|
|
327
|
-
|
|
424
|
+
const type = strAttr(obj, "type");
|
|
425
|
+
switch (type) {
|
|
328
426
|
case "cellIs": return parseCellIsRule(obj, priority);
|
|
329
427
|
case "colorScale": return parseColorScaleRule(obj, priority);
|
|
330
428
|
case "dataBar": return parseDataBarRule(obj, priority);
|
|
331
429
|
case "iconSet": return parseIconSetRule(obj, priority);
|
|
430
|
+
case "top10": return parseTop10Rule(obj, priority);
|
|
431
|
+
case "aboveAverage": return parseAboveAverageRule(obj, priority);
|
|
432
|
+
case "duplicateValues":
|
|
433
|
+
case "uniqueValues": return parseDupUniqueRule(type, obj, priority);
|
|
434
|
+
case "containsText":
|
|
435
|
+
case "notContainsText":
|
|
436
|
+
case "beginsWith":
|
|
437
|
+
case "endsWith": return parseTextRule(type, obj, priority);
|
|
332
438
|
default: return;
|
|
333
439
|
}
|
|
334
440
|
}
|
|
441
|
+
function parseTop10Rule(obj, priority) {
|
|
442
|
+
const dxfId = parseNumericAttr(obj, "dxfId");
|
|
443
|
+
if (dxfId === void 0) return void 0;
|
|
444
|
+
return {
|
|
445
|
+
type: "top10",
|
|
446
|
+
priority,
|
|
447
|
+
rank: parseNumericAttr(obj, "rank") ?? 10,
|
|
448
|
+
percent: boolAttr(obj, "percent"),
|
|
449
|
+
bottom: boolAttr(obj, "bottom"),
|
|
450
|
+
dxfId
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
function parseAboveAverageRule(obj, priority) {
|
|
454
|
+
const dxfId = parseNumericAttr(obj, "dxfId");
|
|
455
|
+
if (dxfId === void 0) return void 0;
|
|
456
|
+
const aboveRaw = strAttr(obj, "aboveAverage");
|
|
457
|
+
const aboveAverage = aboveRaw === void 0 ? true : aboveRaw === "1" || aboveRaw === "true";
|
|
458
|
+
const stdDev = parseNumericAttr(obj, "stdDev");
|
|
459
|
+
return {
|
|
460
|
+
type: "aboveAverage",
|
|
461
|
+
priority,
|
|
462
|
+
aboveAverage,
|
|
463
|
+
equalAverage: boolAttr(obj, "equalAverage"),
|
|
464
|
+
...stdDev !== void 0 ? { stdDev } : {},
|
|
465
|
+
dxfId
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function parseDupUniqueRule(type, obj, priority) {
|
|
469
|
+
const dxfId = parseNumericAttr(obj, "dxfId");
|
|
470
|
+
if (dxfId === void 0) return void 0;
|
|
471
|
+
return {
|
|
472
|
+
type,
|
|
473
|
+
priority,
|
|
474
|
+
dxfId
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
function parseTextRule(type, obj, priority) {
|
|
478
|
+
const dxfId = parseNumericAttr(obj, "dxfId");
|
|
479
|
+
if (dxfId === void 0) return void 0;
|
|
480
|
+
const text = strAttr(obj, "text");
|
|
481
|
+
if (text === void 0) return void 0;
|
|
482
|
+
const formula = formulaText(obj["formula"]);
|
|
483
|
+
return {
|
|
484
|
+
type,
|
|
485
|
+
priority,
|
|
486
|
+
text,
|
|
487
|
+
dxfId,
|
|
488
|
+
...formula !== void 0 ? { formula } : {}
|
|
489
|
+
};
|
|
490
|
+
}
|
|
335
491
|
function parseIconSetRule(obj, priority) {
|
|
336
492
|
const is = obj["iconSet"];
|
|
337
493
|
if (!is || typeof is !== "object") return void 0;
|
|
@@ -489,6 +645,30 @@ function parseSparklines(ws) {
|
|
|
489
645
|
}
|
|
490
646
|
return out;
|
|
491
647
|
}
|
|
648
|
+
function parseFormControls(ws) {
|
|
649
|
+
const out = [];
|
|
650
|
+
const seen = /* @__PURE__ */ new Set();
|
|
651
|
+
collectControls(asObjectNode(ws["controls"]), out, seen);
|
|
652
|
+
for (const ext of toArray(asObjectNode(ws["extLst"])?.["ext"])) collectControls(asObjectNode(asObjectNode(ext)?.["controls"]), out, seen);
|
|
653
|
+
return out;
|
|
654
|
+
}
|
|
655
|
+
function collectControls(node, out, seen) {
|
|
656
|
+
if (!node) return;
|
|
657
|
+
const direct = toArray(node["control"]);
|
|
658
|
+
const fromChoice = toArray(asObjectNode(node["AlternateContent"])?.["Choice"]).flatMap((c) => toArray(asObjectNode(c)?.["control"]));
|
|
659
|
+
for (const c of [...direct, ...fromChoice]) {
|
|
660
|
+
const obj = asObjectNode(c);
|
|
661
|
+
if (!obj) continue;
|
|
662
|
+
const relId = strAttr(obj, "id");
|
|
663
|
+
if (!relId || seen.has(relId)) continue;
|
|
664
|
+
seen.add(relId);
|
|
665
|
+
const name = strAttr(obj, "name");
|
|
666
|
+
out.push({
|
|
667
|
+
relId,
|
|
668
|
+
...name ? { name } : {}
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
}
|
|
492
672
|
function asObjectNode(v) {
|
|
493
673
|
return v && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
494
674
|
}
|