@node-projects/excelforge 2.3.0 → 3.0.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/.github/FUNDING.yml +4 -0
- package/MISSING.md +326 -0
- package/README.md +484 -12
- package/dist/core/SharedStrings.js +6 -2
- package/dist/core/SharedStrings.js.map +1 -1
- package/dist/core/Workbook.d.ts +41 -1
- package/dist/core/Workbook.js +773 -57
- package/dist/core/Workbook.js.map +1 -1
- package/dist/core/WorkbookReader.d.ts +18 -4
- package/dist/core/WorkbookReader.js +1386 -20
- package/dist/core/WorkbookReader.js.map +1 -1
- package/dist/core/Worksheet.d.ts +130 -2
- package/dist/core/Worksheet.js +792 -66
- package/dist/core/Worksheet.js.map +1 -1
- package/dist/core/types.d.ts +287 -5
- package/dist/core/types.js +12 -1
- package/dist/core/types.js.map +1 -1
- package/dist/features/ChartBuilder.d.ts +9 -1
- package/dist/features/ChartBuilder.js +140 -14
- package/dist/features/ChartBuilder.js.map +1 -1
- package/dist/features/CsvModule.d.ts +11 -0
- package/dist/features/CsvModule.js +137 -0
- package/dist/features/CsvModule.js.map +1 -0
- package/dist/features/Encryption.d.ts +6 -0
- package/dist/features/Encryption.js +806 -0
- package/dist/features/Encryption.js.map +1 -0
- package/dist/features/FormControlBuilder.d.ts +6 -0
- package/dist/features/FormControlBuilder.js +135 -0
- package/dist/features/FormControlBuilder.js.map +1 -0
- package/dist/features/FormulaEngine.d.ts +22 -0
- package/dist/features/FormulaEngine.js +498 -0
- package/dist/features/FormulaEngine.js.map +1 -0
- package/dist/features/HtmlModule.d.ts +21 -0
- package/dist/features/HtmlModule.js +1417 -0
- package/dist/features/HtmlModule.js.map +1 -0
- package/dist/features/JsonModule.d.ts +10 -0
- package/dist/features/JsonModule.js +76 -0
- package/dist/features/JsonModule.js.map +1 -0
- package/dist/features/PivotTableBuilder.d.ts +7 -0
- package/dist/features/PivotTableBuilder.js +170 -0
- package/dist/features/PivotTableBuilder.js.map +1 -0
- package/dist/features/Signing.d.ts +12 -0
- package/dist/features/Signing.js +318 -0
- package/dist/features/Signing.js.map +1 -0
- package/dist/features/TableBuilder.js +2 -2
- package/dist/features/TableBuilder.js.map +1 -1
- package/dist/index-min.js +579 -144
- package/dist/index.d.ts +17 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/styles/StyleRegistry.d.ts +14 -0
- package/dist/styles/StyleRegistry.js +95 -30
- package/dist/styles/StyleRegistry.js.map +1 -1
- package/dist/utils/helpers.d.ts +4 -0
- package/dist/utils/helpers.js +64 -14
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/zip.js +145 -73
- package/dist/utils/zip.js.map +1 -1
- package/dist/vba/VbaProject.d.ts +19 -0
- package/dist/vba/VbaProject.js +281 -0
- package/dist/vba/VbaProject.js.map +1 -0
- package/dist/vba/cfb.d.ts +7 -0
- package/dist/vba/cfb.js +352 -0
- package/dist/vba/cfb.js.map +1 -0
- package/dist/vba/ovba.d.ts +2 -0
- package/dist/vba/ovba.js +137 -0
- package/dist/vba/ovba.js.map +1 -0
- package/package.json +4 -3
- package/validator.cs +0 -155
- package/validatorEpplus.cs +0 -27
- package/validatorReadData.cs +0 -111
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
import { readZip, entryText } from '../utils/zipReader.js';
|
|
2
|
-
import { parseXml, child, children, localName, nodeToXml } from '../utils/xmlParser.js';
|
|
2
|
+
import { parseXml, child, children, attr, localName, nodeToXml } from '../utils/xmlParser.js';
|
|
3
3
|
import { parseCoreXml, parseAppXml, parseCustomXml, } from './properties.js';
|
|
4
|
+
import { CellError, } from './types.js';
|
|
4
5
|
import { Worksheet } from './Worksheet.js';
|
|
5
6
|
import { cellRefToIndices } from '../utils/helpers.js';
|
|
7
|
+
import { OBJ_TYPE_TO_CTRL, CHECKED_REV } from '../features/FormControlBuilder.js';
|
|
6
8
|
function parseRels(xml) {
|
|
7
9
|
const map = new Map();
|
|
8
10
|
try {
|
|
9
11
|
const root = parseXml(xml);
|
|
10
12
|
for (const c of root.children) {
|
|
11
13
|
if (localName(c.tag) === 'Relationship') {
|
|
12
|
-
|
|
14
|
+
const entry = {
|
|
13
15
|
type: c.attrs['Type'] ?? '',
|
|
14
16
|
target: c.attrs['Target'] ?? '',
|
|
15
|
-
}
|
|
17
|
+
};
|
|
18
|
+
if (c.attrs['TargetMode'])
|
|
19
|
+
entry.targetMode = c.attrs['TargetMode'];
|
|
20
|
+
map.set(c.attrs['Id'] ?? '', entry);
|
|
16
21
|
}
|
|
17
22
|
}
|
|
18
23
|
}
|
|
@@ -119,7 +124,33 @@ function parseStyles(xml) {
|
|
|
119
124
|
xfs.push(style);
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
|
-
|
|
127
|
+
const dxfs = [];
|
|
128
|
+
const dxfsNode = find(root, 'dxfs');
|
|
129
|
+
if (dxfsNode) {
|
|
130
|
+
for (const dxf of children(dxfsNode, 'dxf')) {
|
|
131
|
+
const style = {};
|
|
132
|
+
const fontNode = child(dxf, 'font');
|
|
133
|
+
if (fontNode)
|
|
134
|
+
style.font = parseFont(fontNode);
|
|
135
|
+
const fillNode = child(dxf, 'fill');
|
|
136
|
+
if (fillNode)
|
|
137
|
+
style.fill = parseFill(fillNode);
|
|
138
|
+
const borderNode = child(dxf, 'border');
|
|
139
|
+
if (borderNode)
|
|
140
|
+
style.border = parseBorder(borderNode);
|
|
141
|
+
const numFmtDxf = child(dxf, 'numFmt');
|
|
142
|
+
if (numFmtDxf) {
|
|
143
|
+
const code = numFmtDxf.attrs['formatCode'] ?? '';
|
|
144
|
+
if (code)
|
|
145
|
+
style.numberFormat = { formatCode: code };
|
|
146
|
+
}
|
|
147
|
+
const alignDxf = child(dxf, 'alignment');
|
|
148
|
+
if (alignDxf)
|
|
149
|
+
style.alignment = parseAlignment(alignDxf);
|
|
150
|
+
dxfs.push(style);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { xfs, numFmts, dxfs };
|
|
123
154
|
}
|
|
124
155
|
function find(node, localTag) {
|
|
125
156
|
if (localName(node.tag) === localTag)
|
|
@@ -166,9 +197,12 @@ function parseFont(node) {
|
|
|
166
197
|
f.vertAlign = c.attrs['val'];
|
|
167
198
|
break;
|
|
168
199
|
case 'color': {
|
|
169
|
-
const rgb = c.attrs['rgb']
|
|
200
|
+
const rgb = c.attrs['rgb'];
|
|
201
|
+
const theme = c.attrs['theme'];
|
|
170
202
|
if (rgb)
|
|
171
203
|
f.color = rgb;
|
|
204
|
+
else if (theme)
|
|
205
|
+
f.color = `theme:${theme}`;
|
|
172
206
|
break;
|
|
173
207
|
}
|
|
174
208
|
}
|
|
@@ -183,8 +217,8 @@ function parseFill(node) {
|
|
|
183
217
|
return {
|
|
184
218
|
type: 'pattern',
|
|
185
219
|
pattern: (pattern.attrs['patternType'] ?? 'none'),
|
|
186
|
-
fgColor: fg?.attrs['rgb'] ?? fg?.attrs['theme'],
|
|
187
|
-
bgColor: bg?.attrs['rgb'] ?? bg?.attrs['theme'],
|
|
220
|
+
fgColor: fg?.attrs['rgb'] ?? (fg?.attrs['theme'] ? `theme:${fg.attrs['theme']}` : undefined),
|
|
221
|
+
bgColor: bg?.attrs['rgb'] ?? (bg?.attrs['theme'] ? `theme:${bg.attrs['theme']}` : undefined),
|
|
188
222
|
};
|
|
189
223
|
}
|
|
190
224
|
const gradient = child(node, 'gradientFill');
|
|
@@ -193,7 +227,7 @@ function parseFill(node) {
|
|
|
193
227
|
const colorNode = child(s, 'color');
|
|
194
228
|
return {
|
|
195
229
|
position: parseFloat(s.attrs['position'] ?? '0'),
|
|
196
|
-
color: colorNode?.attrs['rgb'] ?? colorNode?.attrs['theme']
|
|
230
|
+
color: colorNode?.attrs['rgb'] ?? (colorNode?.attrs['theme'] ? `theme:${colorNode.attrs['theme']}` : 'FF000000'),
|
|
197
231
|
};
|
|
198
232
|
});
|
|
199
233
|
return {
|
|
@@ -214,7 +248,8 @@ function parseBorder(node) {
|
|
|
214
248
|
const color = child(n, 'color');
|
|
215
249
|
if (!style && !color)
|
|
216
250
|
return undefined;
|
|
217
|
-
|
|
251
|
+
const colorVal = color?.attrs['rgb'] ?? (color?.attrs['theme'] ? `theme:${color.attrs['theme']}` : undefined);
|
|
252
|
+
return { style: style, color: colorVal };
|
|
218
253
|
};
|
|
219
254
|
return {
|
|
220
255
|
left: parseSide('left'),
|
|
@@ -248,9 +283,22 @@ function parseSharedStrings(xml) {
|
|
|
248
283
|
const root = parseXml(xml);
|
|
249
284
|
return children(root, 'si').map(si => {
|
|
250
285
|
const t = child(si, 't');
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
286
|
+
const runs = children(si, 'r');
|
|
287
|
+
if (t && !runs.length)
|
|
288
|
+
return { text: t.text ?? '' };
|
|
289
|
+
const richRuns = runs.map(r => {
|
|
290
|
+
const runText = child(r, 't')?.text ?? '';
|
|
291
|
+
const rPr = child(r, 'rPr');
|
|
292
|
+
const run = { text: runText };
|
|
293
|
+
if (rPr)
|
|
294
|
+
run.font = parseFont(rPr);
|
|
295
|
+
return run;
|
|
296
|
+
});
|
|
297
|
+
const plainText = richRuns.map(r => r.text).join('');
|
|
298
|
+
const hasFormatting = richRuns.some(r => r.font && Object.keys(r.font).length > 0);
|
|
299
|
+
if (hasFormatting)
|
|
300
|
+
return { text: plainText, richText: richRuns };
|
|
301
|
+
return { text: plainText };
|
|
254
302
|
});
|
|
255
303
|
}
|
|
256
304
|
function parseWorksheet(xml, name, styles, sharedStrings) {
|
|
@@ -258,12 +306,17 @@ function parseWorksheet(xml, name, styles, sharedStrings) {
|
|
|
258
306
|
const root = parseXml(xml);
|
|
259
307
|
const unknownParts = [];
|
|
260
308
|
const tableRIds = [];
|
|
309
|
+
let legacyDrawingRId = '';
|
|
310
|
+
let drawingRId = '';
|
|
311
|
+
const ctrlPropRIds = [];
|
|
312
|
+
const vmCells = new Map();
|
|
261
313
|
const knownTags = new Set([
|
|
262
314
|
'sheetPr', 'dimension', 'sheetViews', 'sheetFormatPr', 'cols',
|
|
263
315
|
'sheetData', 'mergeCells', 'conditionalFormatting', 'dataValidations',
|
|
264
316
|
'sheetProtection', 'printOptions', 'pageMargins', 'pageSetup',
|
|
265
317
|
'headerFooter', 'drawing', 'tableParts', 'autoFilter',
|
|
266
318
|
'rowBreaks', 'colBreaks', 'picture', 'oleObjects', 'ctrlProps',
|
|
319
|
+
'legacyDrawing', 'AlternateContent', 'extLst',
|
|
267
320
|
]);
|
|
268
321
|
for (const node of root.children) {
|
|
269
322
|
const tag = localName(node.tag);
|
|
@@ -275,7 +328,7 @@ function parseWorksheet(xml, name, styles, sharedStrings) {
|
|
|
275
328
|
parseCols(node, ws, styles);
|
|
276
329
|
break;
|
|
277
330
|
case 'sheetData':
|
|
278
|
-
parseSheetData(node, ws, styles, sharedStrings);
|
|
331
|
+
parseSheetData(node, ws, styles, sharedStrings, vmCells);
|
|
279
332
|
break;
|
|
280
333
|
case 'mergeCells':
|
|
281
334
|
parseMerges(node, ws);
|
|
@@ -305,6 +358,60 @@ function parseWorksheet(xml, name, styles, sharedStrings) {
|
|
|
305
358
|
case 'printOptions':
|
|
306
359
|
parsePrintOptions(node, ws);
|
|
307
360
|
break;
|
|
361
|
+
case 'conditionalFormatting':
|
|
362
|
+
parseConditionalFormatting(node, ws, styles);
|
|
363
|
+
break;
|
|
364
|
+
case 'dataValidations':
|
|
365
|
+
parseDataValidations(node, ws);
|
|
366
|
+
break;
|
|
367
|
+
case 'rowBreaks':
|
|
368
|
+
for (const brk of children(node, 'brk')) {
|
|
369
|
+
const id = parseInt(brk.attrs['id'] ?? '0', 10);
|
|
370
|
+
if (id > 0)
|
|
371
|
+
ws.addRowBreak(id, brk.attrs['man'] === '1');
|
|
372
|
+
}
|
|
373
|
+
break;
|
|
374
|
+
case 'colBreaks':
|
|
375
|
+
for (const brk of children(node, 'brk')) {
|
|
376
|
+
const id = parseInt(brk.attrs['id'] ?? '0', 10);
|
|
377
|
+
if (id > 0)
|
|
378
|
+
ws.addColBreak(id, brk.attrs['man'] === '1');
|
|
379
|
+
}
|
|
380
|
+
break;
|
|
381
|
+
case 'drawing':
|
|
382
|
+
drawingRId = node.attrs['r:id'] ?? '';
|
|
383
|
+
break;
|
|
384
|
+
case 'legacyDrawing':
|
|
385
|
+
legacyDrawingRId = node.attrs['r:id'] ?? '';
|
|
386
|
+
break;
|
|
387
|
+
case 'AlternateContent': {
|
|
388
|
+
const choiceNode = node.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'Choice');
|
|
389
|
+
const controlsNode = choiceNode ? choiceNode.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'controls') : undefined;
|
|
390
|
+
if (controlsNode) {
|
|
391
|
+
for (const acNode of controlsNode.children) {
|
|
392
|
+
if (typeof acNode === 'string')
|
|
393
|
+
continue;
|
|
394
|
+
let ctrlNode;
|
|
395
|
+
if (localName(acNode.tag) === 'control') {
|
|
396
|
+
ctrlNode = acNode;
|
|
397
|
+
}
|
|
398
|
+
else if (localName(acNode.tag) === 'AlternateContent') {
|
|
399
|
+
const innerChoice = acNode.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'Choice');
|
|
400
|
+
ctrlNode = innerChoice?.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'control');
|
|
401
|
+
}
|
|
402
|
+
if (!ctrlNode)
|
|
403
|
+
continue;
|
|
404
|
+
const controlPr = ctrlNode.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'controlPr');
|
|
405
|
+
const ctrlRId = ctrlNode.attrs['r:id'] ?? controlPr?.attrs['r:id'] ?? '';
|
|
406
|
+
if (ctrlRId)
|
|
407
|
+
ctrlPropRIds.push(ctrlRId);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
case 'extLst':
|
|
413
|
+
parseSparklineExtensions(node, ws);
|
|
414
|
+
break;
|
|
308
415
|
default:
|
|
309
416
|
if (!knownTags.has(tag)) {
|
|
310
417
|
unknownParts.push(nodeToXml(node));
|
|
@@ -312,7 +419,7 @@ function parseWorksheet(xml, name, styles, sharedStrings) {
|
|
|
312
419
|
break;
|
|
313
420
|
}
|
|
314
421
|
}
|
|
315
|
-
return { ws, originalXml: xml, unknownParts, tableRIds };
|
|
422
|
+
return { ws, originalXml: xml, unknownParts, tableRIds, legacyDrawingRId, ctrlPropRIds, drawingRId, vmCells };
|
|
316
423
|
}
|
|
317
424
|
function parseSheetViews(node, ws) {
|
|
318
425
|
const sv = children(node, 'sheetView')[0];
|
|
@@ -349,7 +456,7 @@ function parseCols(node, ws, styles) {
|
|
|
349
456
|
ws.setColumn(c, def);
|
|
350
457
|
}
|
|
351
458
|
}
|
|
352
|
-
function parseSheetData(node, ws, styles, sharedStrings) {
|
|
459
|
+
function parseSheetData(node, ws, styles, sharedStrings, vmCells) {
|
|
353
460
|
for (const rowNode of children(node, 'row')) {
|
|
354
461
|
const rowIdx = parseInt(rowNode.attrs['r'] ?? '0', 10);
|
|
355
462
|
if (!rowIdx)
|
|
@@ -380,6 +487,10 @@ function parseSheetData(node, ws, styles, sharedStrings) {
|
|
|
380
487
|
const cell = {};
|
|
381
488
|
if (cellStyle)
|
|
382
489
|
cell.style = cellStyle;
|
|
490
|
+
const vmAttr = cNode.attrs['vm'];
|
|
491
|
+
if (vmAttr && vmCells) {
|
|
492
|
+
vmCells.set(ref, parseInt(vmAttr, 10));
|
|
493
|
+
}
|
|
383
494
|
if (fNode) {
|
|
384
495
|
if (fNode.attrs['t'] === 'array') {
|
|
385
496
|
cell.arrayFormula = fNode.text ?? '';
|
|
@@ -393,7 +504,15 @@ function parseSheetData(node, ws, styles, sharedStrings) {
|
|
|
393
504
|
switch (t) {
|
|
394
505
|
case 's': {
|
|
395
506
|
const idx = parseInt(raw, 10);
|
|
396
|
-
|
|
507
|
+
const ss = sharedStrings[idx];
|
|
508
|
+
if (ss) {
|
|
509
|
+
cell.value = ss.text;
|
|
510
|
+
if (ss.richText)
|
|
511
|
+
cell.richText = ss.richText;
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
cell.value = '';
|
|
515
|
+
}
|
|
397
516
|
break;
|
|
398
517
|
}
|
|
399
518
|
case 'b':
|
|
@@ -406,7 +525,7 @@ function parseSheetData(node, ws, styles, sharedStrings) {
|
|
|
406
525
|
break;
|
|
407
526
|
}
|
|
408
527
|
case 'e':
|
|
409
|
-
cell.value = raw;
|
|
528
|
+
cell.value = new CellError(raw);
|
|
410
529
|
break;
|
|
411
530
|
default: {
|
|
412
531
|
const n = parseFloat(raw);
|
|
@@ -490,6 +609,115 @@ function parsePrintOptions(node, ws) {
|
|
|
490
609
|
centerVertical: node.attrs['verticalCentered'] === '1',
|
|
491
610
|
};
|
|
492
611
|
}
|
|
612
|
+
function parseConditionalFormatting(node, ws, styles) {
|
|
613
|
+
const sqref = node.attrs['sqref'] ?? '';
|
|
614
|
+
for (const rule of children(node, 'cfRule')) {
|
|
615
|
+
const type = (rule.attrs['type'] ?? 'cellIs');
|
|
616
|
+
const cf = { sqref, type };
|
|
617
|
+
if (rule.attrs['operator'])
|
|
618
|
+
cf.operator = rule.attrs['operator'];
|
|
619
|
+
if (rule.attrs['priority'])
|
|
620
|
+
cf.priority = parseInt(rule.attrs['priority'], 10);
|
|
621
|
+
if (rule.attrs['text'])
|
|
622
|
+
cf.text = rule.attrs['text'];
|
|
623
|
+
if (rule.attrs['aboveAverage'] === '0')
|
|
624
|
+
cf.aboveAverage = false;
|
|
625
|
+
if (rule.attrs['percent'] === '1')
|
|
626
|
+
cf.percent = true;
|
|
627
|
+
if (rule.attrs['rank'])
|
|
628
|
+
cf.rank = parseInt(rule.attrs['rank'], 10);
|
|
629
|
+
if (rule.attrs['timePeriod'])
|
|
630
|
+
cf.timePeriod = rule.attrs['timePeriod'];
|
|
631
|
+
if (rule.attrs['dxfId'] !== undefined) {
|
|
632
|
+
const dxfId = parseInt(rule.attrs['dxfId'], 10);
|
|
633
|
+
if (styles.dxfs[dxfId])
|
|
634
|
+
cf.style = styles.dxfs[dxfId];
|
|
635
|
+
}
|
|
636
|
+
const formulas = children(rule, 'formula');
|
|
637
|
+
if (formulas[0]?.text)
|
|
638
|
+
cf.formula = formulas[0].text;
|
|
639
|
+
if (formulas[1]?.text)
|
|
640
|
+
cf.formula2 = formulas[1].text;
|
|
641
|
+
const csNode = child(rule, 'colorScale');
|
|
642
|
+
if (csNode) {
|
|
643
|
+
const cfvos = children(csNode, 'cfvo').map(c => ({
|
|
644
|
+
type: (c.attrs['type'] ?? 'min'),
|
|
645
|
+
val: c.attrs['val'],
|
|
646
|
+
}));
|
|
647
|
+
const colors = children(csNode, 'color').map(c => c.attrs['rgb'] ?? c.attrs['theme'] ?? '');
|
|
648
|
+
cf.colorScale = { type: 'colorScale', cfvo: cfvos, color: colors };
|
|
649
|
+
}
|
|
650
|
+
const dbNode = child(rule, 'dataBar');
|
|
651
|
+
if (dbNode) {
|
|
652
|
+
const cfvos = children(dbNode, 'cfvo');
|
|
653
|
+
const colorNode = child(dbNode, 'color');
|
|
654
|
+
cf.dataBar = {
|
|
655
|
+
type: 'dataBar',
|
|
656
|
+
showValue: dbNode.attrs['showValue'] !== '0' ? undefined : false,
|
|
657
|
+
minType: cfvos[0]?.attrs['type'],
|
|
658
|
+
minVal: cfvos[0]?.attrs['val'],
|
|
659
|
+
maxType: cfvos[1]?.attrs['type'],
|
|
660
|
+
maxVal: cfvos[1]?.attrs['val'],
|
|
661
|
+
color: colorNode?.attrs['rgb'],
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
const isNode = child(rule, 'iconSet');
|
|
665
|
+
if (isNode) {
|
|
666
|
+
const cfvos = children(isNode, 'cfvo').map(c => ({
|
|
667
|
+
type: c.attrs['type'] ?? 'percent',
|
|
668
|
+
val: c.attrs['val'],
|
|
669
|
+
}));
|
|
670
|
+
cf.iconSet = {
|
|
671
|
+
type: 'iconSet',
|
|
672
|
+
iconSet: (isNode.attrs['iconSet'] ?? '3TrafficLights1'),
|
|
673
|
+
cfvo: cfvos,
|
|
674
|
+
showValue: isNode.attrs['showValue'] === '0' ? false : undefined,
|
|
675
|
+
reverse: isNode.attrs['reverse'] === '1' ? true : undefined,
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
ws.addConditionalFormat(cf);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
function parseDataValidations(node, ws) {
|
|
682
|
+
for (const dv of children(node, 'dataValidation')) {
|
|
683
|
+
const sqref = dv.attrs['sqref'] ?? '';
|
|
684
|
+
if (!sqref)
|
|
685
|
+
continue;
|
|
686
|
+
const type = (dv.attrs['type'] ?? 'whole');
|
|
687
|
+
const val = { type };
|
|
688
|
+
if (dv.attrs['operator'])
|
|
689
|
+
val.operator = dv.attrs['operator'];
|
|
690
|
+
if (dv.attrs['allowBlank'] === '1')
|
|
691
|
+
val.allowBlank = true;
|
|
692
|
+
if (dv.attrs['showErrorMessage'] === '1')
|
|
693
|
+
val.showErrorAlert = true;
|
|
694
|
+
if (dv.attrs['errorTitle'])
|
|
695
|
+
val.errorTitle = dv.attrs['errorTitle'];
|
|
696
|
+
if (dv.attrs['error'])
|
|
697
|
+
val.error = dv.attrs['error'];
|
|
698
|
+
if (dv.attrs['showInputMessage'] === '1')
|
|
699
|
+
val.showInputMessage = true;
|
|
700
|
+
if (dv.attrs['promptTitle'])
|
|
701
|
+
val.promptTitle = dv.attrs['promptTitle'];
|
|
702
|
+
if (dv.attrs['prompt'])
|
|
703
|
+
val.prompt = dv.attrs['prompt'];
|
|
704
|
+
if (dv.attrs['showDropDown'] === '1')
|
|
705
|
+
val.showDropDown = false;
|
|
706
|
+
const f1 = child(dv, 'formula1');
|
|
707
|
+
const f2 = child(dv, 'formula2');
|
|
708
|
+
if (f1?.text) {
|
|
709
|
+
if (type === 'list' && f1.text.startsWith('"') && f1.text.endsWith('"')) {
|
|
710
|
+
val.list = f1.text.slice(1, -1).split(',');
|
|
711
|
+
}
|
|
712
|
+
else {
|
|
713
|
+
val.formula1 = f1.text;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
if (f2?.text)
|
|
717
|
+
val.formula2 = f2.text;
|
|
718
|
+
ws.addDataValidation(sqref, val);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
493
721
|
function parseTableXml(xml) {
|
|
494
722
|
try {
|
|
495
723
|
const root = parseXml(xml);
|
|
@@ -538,6 +766,873 @@ function parseTableXml(xml) {
|
|
|
538
766
|
return null;
|
|
539
767
|
}
|
|
540
768
|
}
|
|
769
|
+
const EMU_PX = 9525;
|
|
770
|
+
function parseAnchorPos(node) {
|
|
771
|
+
return {
|
|
772
|
+
col: parseInt(child(node, 'col')?.text ?? '0', 10),
|
|
773
|
+
row: parseInt(child(node, 'row')?.text ?? '0', 10),
|
|
774
|
+
colOff: parseInt(child(node, 'colOff')?.text ?? '0', 10),
|
|
775
|
+
rowOff: parseInt(child(node, 'rowOff')?.text ?? '0', 10),
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
function extToFormat(ext) {
|
|
779
|
+
const map = {
|
|
780
|
+
png: 'png', jpg: 'jpeg', jpeg: 'jpeg', gif: 'gif',
|
|
781
|
+
emf: 'emf', wmf: 'wmf', tiff: 'tiff', tif: 'tiff',
|
|
782
|
+
svg: 'svg', ico: 'ico', webp: 'webp', bmp: 'bmp',
|
|
783
|
+
};
|
|
784
|
+
return map[ext.toLowerCase()] ?? 'png';
|
|
785
|
+
}
|
|
786
|
+
function parseDrawingObjects(drawXml, drawRels, drawDir, getEntry, ws) {
|
|
787
|
+
const root = parseXml(drawXml);
|
|
788
|
+
for (const anchor of root.children) {
|
|
789
|
+
if (typeof anchor === 'string')
|
|
790
|
+
continue;
|
|
791
|
+
const tag = localName(anchor.tag);
|
|
792
|
+
if (tag !== 'twoCellAnchor' && tag !== 'oneCellAnchor' && tag !== 'absoluteAnchor')
|
|
793
|
+
continue;
|
|
794
|
+
const anchorFrom = parseDrawingAnchorFrom(anchor, tag);
|
|
795
|
+
const pic = findDescendant(anchor, 'pic');
|
|
796
|
+
if (pic) {
|
|
797
|
+
parseDrawingImage(pic, anchor, tag, anchorFrom, drawRels, drawDir, getEntry, ws);
|
|
798
|
+
continue;
|
|
799
|
+
}
|
|
800
|
+
const graphicFrame = findDescendant(anchor, 'graphicFrame');
|
|
801
|
+
if (graphicFrame) {
|
|
802
|
+
parseDrawingChart(graphicFrame, anchor, tag, drawRels, drawDir, getEntry, ws);
|
|
803
|
+
continue;
|
|
804
|
+
}
|
|
805
|
+
const oMath = findDescendant(anchor, 'oMath');
|
|
806
|
+
if (oMath) {
|
|
807
|
+
parseDrawingMathEquation(oMath, anchor, tag, anchorFrom, ws);
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
const sp = findDescendant(anchor, 'sp');
|
|
811
|
+
if (sp) {
|
|
812
|
+
parseDrawingShape(sp, anchor, tag, ws);
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
function parseDrawingChart(graphicFrame, anchor, tag, drawRels, drawDir, getEntry, ws) {
|
|
818
|
+
const chartRef = findDescendant(graphicFrame, 'chart');
|
|
819
|
+
if (!chartRef || !drawRels)
|
|
820
|
+
return;
|
|
821
|
+
const rId = chartRef.attrs['r:id'] ?? attr(chartRef, 'r:id') ?? '';
|
|
822
|
+
if (!rId)
|
|
823
|
+
return;
|
|
824
|
+
const rel = drawRels.get(rId);
|
|
825
|
+
if (!rel)
|
|
826
|
+
return;
|
|
827
|
+
const chartPath = rel.target.startsWith('/')
|
|
828
|
+
? rel.target.slice(1)
|
|
829
|
+
: resolvePath(drawDir, rel.target);
|
|
830
|
+
const chartEntry = getEntry(chartPath);
|
|
831
|
+
if (!chartEntry)
|
|
832
|
+
return;
|
|
833
|
+
const dec = new TextDecoder();
|
|
834
|
+
const chartXml = dec.decode(chartEntry.data);
|
|
835
|
+
const chartRoot = parseXml(chartXml);
|
|
836
|
+
let from = { col: 0, row: 0 };
|
|
837
|
+
let to = { col: 8, row: 15 };
|
|
838
|
+
if (tag === 'twoCellAnchor') {
|
|
839
|
+
const fromNode = child(anchor, 'from');
|
|
840
|
+
const toNode = child(anchor, 'to');
|
|
841
|
+
if (fromNode) {
|
|
842
|
+
from = {
|
|
843
|
+
col: parseInt(child(fromNode, 'col')?.text ?? '0', 10),
|
|
844
|
+
row: parseInt(child(fromNode, 'row')?.text ?? '0', 10),
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
if (toNode) {
|
|
848
|
+
to = {
|
|
849
|
+
col: parseInt(child(toNode, 'col')?.text ?? '0', 10),
|
|
850
|
+
row: parseInt(child(toNode, 'row')?.text ?? '0', 10),
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
const plotArea = findDescendant(chartRoot, 'plotArea');
|
|
855
|
+
if (!plotArea)
|
|
856
|
+
return;
|
|
857
|
+
const chartTypeMap = {
|
|
858
|
+
'barChart': 'column', 'bar3DChart': 'column',
|
|
859
|
+
'lineChart': 'line', 'line3DChart': 'line',
|
|
860
|
+
'areaChart': 'area', 'area3DChart': 'area',
|
|
861
|
+
'pieChart': 'pie', 'pie3DChart': 'pie',
|
|
862
|
+
'doughnutChart': 'doughnut',
|
|
863
|
+
'scatterChart': 'scatter',
|
|
864
|
+
'bubbleChart': 'bubble',
|
|
865
|
+
'radarChart': 'radar',
|
|
866
|
+
'stockChart': 'stock',
|
|
867
|
+
};
|
|
868
|
+
let chartType = 'column';
|
|
869
|
+
let chartGroupNode;
|
|
870
|
+
for (const plotChild of plotArea.children) {
|
|
871
|
+
if (typeof plotChild === 'string')
|
|
872
|
+
continue;
|
|
873
|
+
const localTag = localName(plotChild.tag);
|
|
874
|
+
if (chartTypeMap[localTag]) {
|
|
875
|
+
chartType = chartTypeMap[localTag];
|
|
876
|
+
chartGroupNode = plotChild;
|
|
877
|
+
if (localTag === 'barChart' || localTag === 'bar3DChart') {
|
|
878
|
+
const barDir = child(plotChild, 'barDir');
|
|
879
|
+
const barDirVal = barDir?.attrs['val'] ?? '';
|
|
880
|
+
if (barDirVal === 'bar')
|
|
881
|
+
chartType = 'bar';
|
|
882
|
+
const grouping = child(plotChild, 'grouping');
|
|
883
|
+
const grpVal = grouping?.attrs['val'] ?? '';
|
|
884
|
+
if (grpVal === 'stacked')
|
|
885
|
+
chartType = (chartType === 'bar' ? 'barStacked' : 'columnStacked');
|
|
886
|
+
if (grpVal === 'percentStacked')
|
|
887
|
+
chartType = (chartType === 'bar' ? 'barStacked100' : 'columnStacked100');
|
|
888
|
+
}
|
|
889
|
+
if (localTag === 'lineChart') {
|
|
890
|
+
const marker = findDescendant(plotChild, 'marker');
|
|
891
|
+
if (marker) {
|
|
892
|
+
const markerVal = child(marker, 'symbol')?.attrs['val'] ?? '';
|
|
893
|
+
if (markerVal && markerVal !== 'none')
|
|
894
|
+
chartType = 'lineMarker';
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (localTag === 'scatterChart') {
|
|
898
|
+
const scatterStyle = child(plotChild, 'scatterStyle');
|
|
899
|
+
if (scatterStyle?.attrs['val']?.includes('Smooth'))
|
|
900
|
+
chartType = 'scatterSmooth';
|
|
901
|
+
}
|
|
902
|
+
if (localTag === 'radarChart') {
|
|
903
|
+
const radarStyle = child(plotChild, 'radarStyle');
|
|
904
|
+
if (radarStyle?.attrs['val'] === 'filled')
|
|
905
|
+
chartType = 'radarFilled';
|
|
906
|
+
}
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
if (!chartGroupNode)
|
|
911
|
+
return;
|
|
912
|
+
const series = [];
|
|
913
|
+
for (const ser of children(chartGroupNode, 'ser')) {
|
|
914
|
+
const s = { values: '' };
|
|
915
|
+
const tx = child(ser, 'tx');
|
|
916
|
+
if (tx) {
|
|
917
|
+
const strRef = findDescendant(tx, 'strRef');
|
|
918
|
+
if (strRef) {
|
|
919
|
+
const f = child(strRef, 'f');
|
|
920
|
+
if (f?.text)
|
|
921
|
+
s.name = f.text;
|
|
922
|
+
const strCache = child(strRef, 'strCache');
|
|
923
|
+
if (strCache) {
|
|
924
|
+
const pt = findDescendant(strCache, 'pt');
|
|
925
|
+
const v = pt ? findDescendant(pt, 'v') : undefined;
|
|
926
|
+
if (v?.text)
|
|
927
|
+
s.name = v.text;
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
const v = findDescendant(tx, 'v');
|
|
931
|
+
if (v?.text && !s.name)
|
|
932
|
+
s.name = v.text;
|
|
933
|
+
}
|
|
934
|
+
const val = child(ser, 'val') || child(ser, 'yVal');
|
|
935
|
+
if (val) {
|
|
936
|
+
const numRef = findDescendant(val, 'numRef');
|
|
937
|
+
if (numRef) {
|
|
938
|
+
const f = child(numRef, 'f');
|
|
939
|
+
if (f?.text)
|
|
940
|
+
s.values = f.text;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
const cat = child(ser, 'cat') || child(ser, 'xVal');
|
|
944
|
+
if (cat) {
|
|
945
|
+
const strRef = findDescendant(cat, 'strRef');
|
|
946
|
+
const numRef = findDescendant(cat, 'numRef');
|
|
947
|
+
const ref = strRef || numRef;
|
|
948
|
+
if (ref) {
|
|
949
|
+
const f = child(ref, 'f');
|
|
950
|
+
if (f?.text)
|
|
951
|
+
s.categories = f.text;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
const spPr = child(ser, 'spPr');
|
|
955
|
+
if (spPr) {
|
|
956
|
+
const solidFill = child(spPr, 'solidFill');
|
|
957
|
+
if (solidFill) {
|
|
958
|
+
const srgb = child(solidFill, 'srgbClr');
|
|
959
|
+
if (srgb?.attrs['val'])
|
|
960
|
+
s.color = '#' + srgb.attrs['val'];
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
if (s.values)
|
|
964
|
+
series.push(s);
|
|
965
|
+
}
|
|
966
|
+
if (!series.length)
|
|
967
|
+
return;
|
|
968
|
+
let title;
|
|
969
|
+
const titleNode = child(chartRoot, 'title') || findDescendant(chartRoot, 'title');
|
|
970
|
+
if (titleNode) {
|
|
971
|
+
const aT = findDescendant(titleNode, 't');
|
|
972
|
+
if (aT?.text)
|
|
973
|
+
title = aT.text;
|
|
974
|
+
}
|
|
975
|
+
let xAxis;
|
|
976
|
+
let yAxis;
|
|
977
|
+
const catAx = findDescendant(plotArea, 'catAx') || findDescendant(plotArea, 'dateAx');
|
|
978
|
+
const valAx = findDescendant(plotArea, 'valAx');
|
|
979
|
+
if (catAx) {
|
|
980
|
+
xAxis = {};
|
|
981
|
+
const axTitle = findDescendant(catAx, 'title');
|
|
982
|
+
if (axTitle) {
|
|
983
|
+
const t = findDescendant(axTitle, 't');
|
|
984
|
+
if (t?.text)
|
|
985
|
+
xAxis.title = t.text;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
if (valAx) {
|
|
989
|
+
yAxis = {};
|
|
990
|
+
const axTitle = findDescendant(valAx, 'title');
|
|
991
|
+
if (axTitle) {
|
|
992
|
+
const t = findDescendant(axTitle, 't');
|
|
993
|
+
if (t?.text)
|
|
994
|
+
yAxis.title = t.text;
|
|
995
|
+
}
|
|
996
|
+
const gridLines = child(valAx, 'majorGridlines');
|
|
997
|
+
if (gridLines)
|
|
998
|
+
yAxis.gridLines = true;
|
|
999
|
+
}
|
|
1000
|
+
let legend = false;
|
|
1001
|
+
const legendNode = findDescendant(chartRoot, 'legend');
|
|
1002
|
+
if (legendNode) {
|
|
1003
|
+
const legendPos = child(legendNode, 'legendPos');
|
|
1004
|
+
const posVal = legendPos?.attrs['val'];
|
|
1005
|
+
legend = posVal || true;
|
|
1006
|
+
}
|
|
1007
|
+
const varyColors = child(chartGroupNode, 'varyColors');
|
|
1008
|
+
const varyColorsVal = varyColors?.attrs['val'] !== '0';
|
|
1009
|
+
const chart = { type: chartType, series, from, to };
|
|
1010
|
+
if (title)
|
|
1011
|
+
chart.title = title;
|
|
1012
|
+
if (xAxis)
|
|
1013
|
+
chart.xAxis = xAxis;
|
|
1014
|
+
if (yAxis)
|
|
1015
|
+
chart.yAxis = yAxis;
|
|
1016
|
+
if (legend !== false)
|
|
1017
|
+
chart.legend = legend;
|
|
1018
|
+
if (varyColorsVal)
|
|
1019
|
+
chart.varyColors = true;
|
|
1020
|
+
ws.addChart(chart);
|
|
1021
|
+
}
|
|
1022
|
+
function parseDrawingShape(sp, anchor, tag, ws) {
|
|
1023
|
+
let from = { col: 0, row: 0 };
|
|
1024
|
+
let to = { col: 2, row: 2 };
|
|
1025
|
+
if (tag === 'twoCellAnchor') {
|
|
1026
|
+
const fromNode = child(anchor, 'from');
|
|
1027
|
+
const toNode = child(anchor, 'to');
|
|
1028
|
+
if (fromNode) {
|
|
1029
|
+
from = {
|
|
1030
|
+
col: parseInt(child(fromNode, 'col')?.text ?? '0', 10),
|
|
1031
|
+
row: parseInt(child(fromNode, 'row')?.text ?? '0', 10),
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
if (toNode) {
|
|
1035
|
+
to = {
|
|
1036
|
+
col: parseInt(child(toNode, 'col')?.text ?? '0', 10),
|
|
1037
|
+
row: parseInt(child(toNode, 'row')?.text ?? '0', 10),
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
const spPr = findDescendant(sp, 'spPr');
|
|
1042
|
+
let shapeType = 'rect';
|
|
1043
|
+
let fillColor;
|
|
1044
|
+
let lineColor;
|
|
1045
|
+
let lineWidth;
|
|
1046
|
+
let rotation;
|
|
1047
|
+
if (spPr) {
|
|
1048
|
+
const prstGeom = findDescendant(spPr, 'prstGeom');
|
|
1049
|
+
if (prstGeom) {
|
|
1050
|
+
const prst = prstGeom.attrs['prst'] ?? '';
|
|
1051
|
+
const validTypes = new Set([
|
|
1052
|
+
'rect', 'roundRect', 'ellipse', 'triangle', 'diamond',
|
|
1053
|
+
'pentagon', 'hexagon', 'octagon', 'star5', 'star6',
|
|
1054
|
+
'rightArrow', 'leftArrow', 'upArrow', 'downArrow',
|
|
1055
|
+
'line', 'curvedConnector3', 'callout1', 'callout2',
|
|
1056
|
+
'cloud', 'heart', 'lightningBolt', 'sun', 'moon',
|
|
1057
|
+
'smileyFace', 'flowChartProcess', 'flowChartDecision',
|
|
1058
|
+
'flowChartTerminator', 'flowChartDocument',
|
|
1059
|
+
]);
|
|
1060
|
+
if (validTypes.has(prst))
|
|
1061
|
+
shapeType = prst;
|
|
1062
|
+
}
|
|
1063
|
+
const solidFill = child(spPr, 'solidFill');
|
|
1064
|
+
if (solidFill) {
|
|
1065
|
+
const srgb = child(solidFill, 'srgbClr');
|
|
1066
|
+
if (srgb?.attrs['val'])
|
|
1067
|
+
fillColor = '#' + srgb.attrs['val'];
|
|
1068
|
+
const schemeClr = child(solidFill, 'schemeClr');
|
|
1069
|
+
if (schemeClr?.attrs['val'])
|
|
1070
|
+
fillColor = 'theme:' + schemeClr.attrs['val'];
|
|
1071
|
+
}
|
|
1072
|
+
const ln = child(spPr, 'ln');
|
|
1073
|
+
if (ln) {
|
|
1074
|
+
const w = ln.attrs['w'];
|
|
1075
|
+
if (w)
|
|
1076
|
+
lineWidth = Math.round(parseInt(w, 10) / EMU_PX);
|
|
1077
|
+
const lineFill = child(ln, 'solidFill');
|
|
1078
|
+
if (lineFill) {
|
|
1079
|
+
const srgb = child(lineFill, 'srgbClr');
|
|
1080
|
+
if (srgb?.attrs['val'])
|
|
1081
|
+
lineColor = '#' + srgb.attrs['val'];
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
const xfrm = findDescendant(spPr, 'xfrm');
|
|
1085
|
+
if (xfrm?.attrs['rot'])
|
|
1086
|
+
rotation = parseInt(xfrm.attrs['rot'], 10) / 60000;
|
|
1087
|
+
}
|
|
1088
|
+
let text;
|
|
1089
|
+
let font;
|
|
1090
|
+
const txBody = findDescendant(sp, 'txBody');
|
|
1091
|
+
if (txBody) {
|
|
1092
|
+
const bodyPr = child(txBody, 'bodyPr');
|
|
1093
|
+
const prstTxWarp = bodyPr ? child(bodyPr, 'prstTxWarp') : undefined;
|
|
1094
|
+
const wordArtPreset = prstTxWarp?.attrs['prst'] ?? bodyPr?.attrs['prstTxWarp'] ?? '';
|
|
1095
|
+
const textParts = [];
|
|
1096
|
+
for (const p of children(txBody, 'p')) {
|
|
1097
|
+
for (const r of children(p, 'r')) {
|
|
1098
|
+
const t = child(r, 't');
|
|
1099
|
+
if (t?.text)
|
|
1100
|
+
textParts.push(t.text);
|
|
1101
|
+
if (!font) {
|
|
1102
|
+
const rPr = child(r, 'rPr');
|
|
1103
|
+
if (rPr) {
|
|
1104
|
+
font = {};
|
|
1105
|
+
if (rPr.attrs['sz'])
|
|
1106
|
+
font.size = parseInt(rPr.attrs['sz'], 10) / 100;
|
|
1107
|
+
if (rPr.attrs['b'] === '1')
|
|
1108
|
+
font.bold = true;
|
|
1109
|
+
if (rPr.attrs['i'] === '1')
|
|
1110
|
+
font.italic = true;
|
|
1111
|
+
const latin = findDescendant(rPr, 'latin');
|
|
1112
|
+
if (latin?.attrs['typeface'])
|
|
1113
|
+
font.name = latin.attrs['typeface'];
|
|
1114
|
+
const solidFill = child(rPr, 'solidFill');
|
|
1115
|
+
if (solidFill) {
|
|
1116
|
+
const srgb = child(solidFill, 'srgbClr');
|
|
1117
|
+
if (srgb?.attrs['val'])
|
|
1118
|
+
font.color = '#' + srgb.attrs['val'];
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
text = textParts.join('');
|
|
1125
|
+
const validWordArtPresets = new Set([
|
|
1126
|
+
'textPlain', 'textArchUp', 'textArchDown', 'textCircle',
|
|
1127
|
+
'textWave1', 'textWave2', 'textInflate', 'textDeflate',
|
|
1128
|
+
'textFadeUp', 'textFadeDown', 'textFadeLeft', 'textFadeRight',
|
|
1129
|
+
'textSlantUp', 'textSlantDown', 'textCascadeUp', 'textCascadeDown',
|
|
1130
|
+
'textChevron', 'textRingInside', 'textRingOutside', 'textStop',
|
|
1131
|
+
]);
|
|
1132
|
+
if (wordArtPreset && validWordArtPresets.has(wordArtPreset) && text) {
|
|
1133
|
+
const wa = { text, from, to };
|
|
1134
|
+
if (wordArtPreset !== 'textPlain')
|
|
1135
|
+
wa.preset = wordArtPreset;
|
|
1136
|
+
if (font)
|
|
1137
|
+
wa.font = font;
|
|
1138
|
+
if (fillColor)
|
|
1139
|
+
wa.fillColor = fillColor;
|
|
1140
|
+
if (lineColor)
|
|
1141
|
+
wa.outlineColor = lineColor;
|
|
1142
|
+
ws.addWordArt(wa);
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
const shape = { type: shapeType, from, to };
|
|
1147
|
+
if (text)
|
|
1148
|
+
shape.text = text;
|
|
1149
|
+
if (fillColor)
|
|
1150
|
+
shape.fillColor = fillColor;
|
|
1151
|
+
if (lineColor)
|
|
1152
|
+
shape.lineColor = lineColor;
|
|
1153
|
+
if (lineWidth)
|
|
1154
|
+
shape.lineWidth = lineWidth;
|
|
1155
|
+
if (font)
|
|
1156
|
+
shape.font = font;
|
|
1157
|
+
if (rotation)
|
|
1158
|
+
shape.rotation = rotation;
|
|
1159
|
+
ws.addShape(shape);
|
|
1160
|
+
}
|
|
1161
|
+
function parseSparklineExtensions(extLst, ws) {
|
|
1162
|
+
for (const ext of children(extLst, 'ext')) {
|
|
1163
|
+
const sparklineGroups = ext.children?.filter(c => typeof c !== 'string' && localName(c.tag) === 'sparklineGroups');
|
|
1164
|
+
if (!sparklineGroups?.length)
|
|
1165
|
+
continue;
|
|
1166
|
+
for (const groups of sparklineGroups) {
|
|
1167
|
+
for (const group of children(groups, 'sparklineGroup')) {
|
|
1168
|
+
const typeAttr = group.attrs['type'] ?? 'line';
|
|
1169
|
+
const spkType = typeAttr === 'column' ? 'bar' :
|
|
1170
|
+
typeAttr === 'stacked' ? 'stacked' : 'line';
|
|
1171
|
+
const colorSeries = group.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'colorSeries');
|
|
1172
|
+
const colorHigh = group.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'colorHigh');
|
|
1173
|
+
const colorLow = group.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'colorLow');
|
|
1174
|
+
const colorFirst = group.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'colorFirst');
|
|
1175
|
+
const colorLast = group.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'colorLast');
|
|
1176
|
+
const colorNegative = group.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'colorNegative');
|
|
1177
|
+
const colorMarkers = group.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'colorMarkers');
|
|
1178
|
+
const showHigh = group.attrs['high'] === '1';
|
|
1179
|
+
const showLow = group.attrs['low'] === '1';
|
|
1180
|
+
const showFirst = group.attrs['first'] === '1';
|
|
1181
|
+
const showLast = group.attrs['last'] === '1';
|
|
1182
|
+
const showNegative = group.attrs['negative'] === '1';
|
|
1183
|
+
const showMarkers = group.attrs['markers'] === '1';
|
|
1184
|
+
const lwAttr = group.attrs['lineWeight'];
|
|
1185
|
+
const lineWidth = lwAttr ? parseFloat(lwAttr) : undefined;
|
|
1186
|
+
const minAxisType = group.attrs['minAxisType'] === 'individual' ? 'individual'
|
|
1187
|
+
: group.attrs['minAxisType'] === 'custom' ? 'custom' : undefined;
|
|
1188
|
+
const maxAxisType = group.attrs['maxAxisType'] === 'individual' ? 'individual'
|
|
1189
|
+
: group.attrs['maxAxisType'] === 'custom' ? 'custom' : undefined;
|
|
1190
|
+
const sparklinesNode = group.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'sparklines');
|
|
1191
|
+
if (!sparklinesNode)
|
|
1192
|
+
continue;
|
|
1193
|
+
const sparklineNodes = sparklinesNode.children?.filter(c => typeof c !== 'string' && localName(c.tag) === 'sparkline');
|
|
1194
|
+
if (!sparklineNodes)
|
|
1195
|
+
continue;
|
|
1196
|
+
for (const spk of sparklineNodes) {
|
|
1197
|
+
const fNode = spk.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'f');
|
|
1198
|
+
const sqrefNode = spk.children?.find(c => typeof c !== 'string' && localName(c.tag) === 'sqref');
|
|
1199
|
+
const dataRange = fNode?.text ?? '';
|
|
1200
|
+
const location = sqrefNode?.text ?? '';
|
|
1201
|
+
if (!dataRange || !location)
|
|
1202
|
+
continue;
|
|
1203
|
+
const sp = { type: spkType, dataRange, location };
|
|
1204
|
+
if (colorSeries) {
|
|
1205
|
+
const rgb = colorSeries.attrs['rgb'];
|
|
1206
|
+
if (rgb)
|
|
1207
|
+
sp.color = '#' + rgb.slice(2);
|
|
1208
|
+
const theme = colorSeries.attrs['theme'];
|
|
1209
|
+
if (theme)
|
|
1210
|
+
sp.color = 'theme:' + theme;
|
|
1211
|
+
}
|
|
1212
|
+
if (colorHigh) {
|
|
1213
|
+
const rgb = colorHigh.attrs['rgb'];
|
|
1214
|
+
if (rgb)
|
|
1215
|
+
sp.highColor = '#' + rgb.slice(2);
|
|
1216
|
+
const theme = colorHigh.attrs['theme'];
|
|
1217
|
+
if (theme)
|
|
1218
|
+
sp.highColor = 'theme:' + theme;
|
|
1219
|
+
}
|
|
1220
|
+
if (colorLow) {
|
|
1221
|
+
const rgb = colorLow.attrs['rgb'];
|
|
1222
|
+
if (rgb)
|
|
1223
|
+
sp.lowColor = '#' + rgb.slice(2);
|
|
1224
|
+
const theme = colorLow.attrs['theme'];
|
|
1225
|
+
if (theme)
|
|
1226
|
+
sp.lowColor = 'theme:' + theme;
|
|
1227
|
+
}
|
|
1228
|
+
if (colorFirst) {
|
|
1229
|
+
const rgb = colorFirst.attrs['rgb'];
|
|
1230
|
+
if (rgb)
|
|
1231
|
+
sp.firstColor = '#' + rgb.slice(2);
|
|
1232
|
+
const theme = colorFirst.attrs['theme'];
|
|
1233
|
+
if (theme)
|
|
1234
|
+
sp.firstColor = 'theme:' + theme;
|
|
1235
|
+
}
|
|
1236
|
+
if (colorLast) {
|
|
1237
|
+
const rgb = colorLast.attrs['rgb'];
|
|
1238
|
+
if (rgb)
|
|
1239
|
+
sp.lastColor = '#' + rgb.slice(2);
|
|
1240
|
+
const theme = colorLast.attrs['theme'];
|
|
1241
|
+
if (theme)
|
|
1242
|
+
sp.lastColor = 'theme:' + theme;
|
|
1243
|
+
}
|
|
1244
|
+
if (colorNegative) {
|
|
1245
|
+
const rgb = colorNegative.attrs['rgb'];
|
|
1246
|
+
if (rgb)
|
|
1247
|
+
sp.negativeColor = '#' + rgb.slice(2);
|
|
1248
|
+
const theme = colorNegative.attrs['theme'];
|
|
1249
|
+
if (theme)
|
|
1250
|
+
sp.negativeColor = 'theme:' + theme;
|
|
1251
|
+
}
|
|
1252
|
+
if (colorMarkers) {
|
|
1253
|
+
const rgb = colorMarkers.attrs['rgb'];
|
|
1254
|
+
if (rgb)
|
|
1255
|
+
sp.markersColor = '#' + rgb.slice(2);
|
|
1256
|
+
const theme = colorMarkers.attrs['theme'];
|
|
1257
|
+
if (theme)
|
|
1258
|
+
sp.markersColor = 'theme:' + theme;
|
|
1259
|
+
}
|
|
1260
|
+
if (showHigh)
|
|
1261
|
+
sp.showHigh = true;
|
|
1262
|
+
if (showLow)
|
|
1263
|
+
sp.showLow = true;
|
|
1264
|
+
if (showFirst)
|
|
1265
|
+
sp.showFirst = true;
|
|
1266
|
+
if (showLast)
|
|
1267
|
+
sp.showLast = true;
|
|
1268
|
+
if (showNegative)
|
|
1269
|
+
sp.showNegative = true;
|
|
1270
|
+
if (showMarkers)
|
|
1271
|
+
sp.showMarkers = true;
|
|
1272
|
+
if (lineWidth !== undefined)
|
|
1273
|
+
sp.lineWidth = lineWidth;
|
|
1274
|
+
if (minAxisType)
|
|
1275
|
+
sp.minAxisType = minAxisType;
|
|
1276
|
+
if (maxAxisType)
|
|
1277
|
+
sp.maxAxisType = maxAxisType;
|
|
1278
|
+
ws.addSparkline(sp);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
function parseDrawingAnchorFrom(anchor, tag) {
|
|
1285
|
+
const result = {};
|
|
1286
|
+
if (tag === 'twoCellAnchor' || tag === 'oneCellAnchor') {
|
|
1287
|
+
const fromNode = child(anchor, 'from');
|
|
1288
|
+
if (fromNode) {
|
|
1289
|
+
result.from = {
|
|
1290
|
+
col: parseInt(child(fromNode, 'col')?.text ?? '0', 10),
|
|
1291
|
+
row: parseInt(child(fromNode, 'row')?.text ?? '0', 10),
|
|
1292
|
+
colOff: parseInt(child(fromNode, 'colOff')?.text ?? '0', 10),
|
|
1293
|
+
rowOff: parseInt(child(fromNode, 'rowOff')?.text ?? '0', 10),
|
|
1294
|
+
};
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
if (tag === 'oneCellAnchor') {
|
|
1298
|
+
const ext2 = findDescendant(anchor, 'ext');
|
|
1299
|
+
if (ext2) {
|
|
1300
|
+
result.width = parseInt(ext2.attrs['cx'] ?? '0', 10);
|
|
1301
|
+
result.height = parseInt(ext2.attrs['cy'] ?? '0', 10);
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
return result;
|
|
1305
|
+
}
|
|
1306
|
+
function parseDrawingImage(pic, anchor, tag, anchorInfo, drawRels, drawDir, getEntry, ws) {
|
|
1307
|
+
const blipFill = findDescendant(pic, 'blipFill');
|
|
1308
|
+
const blip = blipFill ? findDescendant(blipFill, 'blip') : undefined;
|
|
1309
|
+
const embedId = blip?.attrs['r:embed'] ?? blip?.attrs['embed'] ?? '';
|
|
1310
|
+
if (!embedId || !drawRels)
|
|
1311
|
+
return;
|
|
1312
|
+
const imgRel = drawRels.get(embedId);
|
|
1313
|
+
if (!imgRel)
|
|
1314
|
+
return;
|
|
1315
|
+
const imgPath = imgRel.target.startsWith('/')
|
|
1316
|
+
? imgRel.target.slice(1)
|
|
1317
|
+
: resolvePath(drawDir, imgRel.target);
|
|
1318
|
+
const imgEntry = getEntry(imgPath);
|
|
1319
|
+
if (!imgEntry)
|
|
1320
|
+
return;
|
|
1321
|
+
const ext = imgPath.split('.').pop() ?? 'png';
|
|
1322
|
+
const format = extToFormat(ext);
|
|
1323
|
+
const cNvPr = findDescendant(pic, 'cNvPr');
|
|
1324
|
+
const altText = cNvPr?.attrs['descr'] || undefined;
|
|
1325
|
+
const img = { data: imgEntry.data, format };
|
|
1326
|
+
if (altText)
|
|
1327
|
+
img.altText = altText;
|
|
1328
|
+
if (tag === 'twoCellAnchor') {
|
|
1329
|
+
const fromNode = child(anchor, 'from');
|
|
1330
|
+
const toNode = child(anchor, 'to');
|
|
1331
|
+
if (fromNode)
|
|
1332
|
+
img.from = parseAnchorPos(fromNode);
|
|
1333
|
+
if (toNode)
|
|
1334
|
+
img.to = parseAnchorPos(toNode);
|
|
1335
|
+
}
|
|
1336
|
+
else if (tag === 'oneCellAnchor') {
|
|
1337
|
+
if (anchorInfo.from)
|
|
1338
|
+
img.from = anchorInfo.from;
|
|
1339
|
+
if (anchorInfo.width)
|
|
1340
|
+
img.width = Math.round(anchorInfo.width / EMU_PX);
|
|
1341
|
+
if (anchorInfo.height)
|
|
1342
|
+
img.height = Math.round(anchorInfo.height / EMU_PX);
|
|
1343
|
+
}
|
|
1344
|
+
else {
|
|
1345
|
+
const posNode = child(anchor, 'pos');
|
|
1346
|
+
const ext2 = child(anchor, 'ext');
|
|
1347
|
+
if (posNode) {
|
|
1348
|
+
img.position = {
|
|
1349
|
+
x: Math.round(parseInt(posNode.attrs['x'] ?? '0', 10) / EMU_PX),
|
|
1350
|
+
y: Math.round(parseInt(posNode.attrs['y'] ?? '0', 10) / EMU_PX),
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
if (ext2) {
|
|
1354
|
+
img.width = Math.round(parseInt(ext2.attrs['cx'] ?? '0', 10) / EMU_PX);
|
|
1355
|
+
img.height = Math.round(parseInt(ext2.attrs['cy'] ?? '0', 10) / EMU_PX);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
ws.addImage(img);
|
|
1359
|
+
}
|
|
1360
|
+
function parseDrawingMathEquation(oMath, anchor, tag, anchorInfo, ws) {
|
|
1361
|
+
const elements = parseOmmlChildren(oMath);
|
|
1362
|
+
if (!elements.length)
|
|
1363
|
+
return;
|
|
1364
|
+
const from = anchorInfo.from ?? { col: 0, row: 0 };
|
|
1365
|
+
const eq = { elements, from };
|
|
1366
|
+
if (anchorInfo.width)
|
|
1367
|
+
eq.width = anchorInfo.width;
|
|
1368
|
+
if (anchorInfo.height)
|
|
1369
|
+
eq.height = anchorInfo.height;
|
|
1370
|
+
const firstRPr = findDescendant(oMath, 'rPr');
|
|
1371
|
+
if (firstRPr) {
|
|
1372
|
+
const szAttr = firstRPr.attrs['sz'];
|
|
1373
|
+
if (szAttr)
|
|
1374
|
+
eq.fontSize = parseInt(szAttr, 10) / 100;
|
|
1375
|
+
const latin = findDescendant(firstRPr, 'latin');
|
|
1376
|
+
if (latin?.attrs['typeface'])
|
|
1377
|
+
eq.fontName = latin.attrs['typeface'];
|
|
1378
|
+
}
|
|
1379
|
+
ws.addMathEquation(eq);
|
|
1380
|
+
}
|
|
1381
|
+
function parseOmmlChildren(node) {
|
|
1382
|
+
const elements = [];
|
|
1383
|
+
for (const c of node.children) {
|
|
1384
|
+
if (typeof c === 'string')
|
|
1385
|
+
continue;
|
|
1386
|
+
const el = parseOmmlElement(c);
|
|
1387
|
+
if (el)
|
|
1388
|
+
elements.push(el);
|
|
1389
|
+
}
|
|
1390
|
+
return elements;
|
|
1391
|
+
}
|
|
1392
|
+
function parseOmmlElement(node) {
|
|
1393
|
+
const tag = localName(node.tag);
|
|
1394
|
+
switch (tag) {
|
|
1395
|
+
case 'r': {
|
|
1396
|
+
const t = findDescendant(node, 't');
|
|
1397
|
+
return { type: 'text', text: t?.text ?? '' };
|
|
1398
|
+
}
|
|
1399
|
+
case 'f': {
|
|
1400
|
+
const num = child(node, 'num');
|
|
1401
|
+
const den = child(node, 'den');
|
|
1402
|
+
return {
|
|
1403
|
+
type: 'frac',
|
|
1404
|
+
base: num ? parseOmmlChildren(num) : [],
|
|
1405
|
+
argument: den ? parseOmmlChildren(den) : [],
|
|
1406
|
+
};
|
|
1407
|
+
}
|
|
1408
|
+
case 'sSup': {
|
|
1409
|
+
const e = child(node, 'e');
|
|
1410
|
+
const sup = child(node, 'sup');
|
|
1411
|
+
return {
|
|
1412
|
+
type: 'sup',
|
|
1413
|
+
base: e ? parseOmmlChildren(e) : [],
|
|
1414
|
+
argument: sup ? parseOmmlChildren(sup) : [],
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
case 'sSub': {
|
|
1418
|
+
const e = child(node, 'e');
|
|
1419
|
+
const sub = child(node, 'sub');
|
|
1420
|
+
return {
|
|
1421
|
+
type: 'sub',
|
|
1422
|
+
base: e ? parseOmmlChildren(e) : [],
|
|
1423
|
+
argument: sub ? parseOmmlChildren(sub) : [],
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
case 'sSubSup': {
|
|
1427
|
+
const e = child(node, 'e');
|
|
1428
|
+
const sub = child(node, 'sub');
|
|
1429
|
+
const sup = child(node, 'sup');
|
|
1430
|
+
return {
|
|
1431
|
+
type: 'subSup',
|
|
1432
|
+
base: e ? parseOmmlChildren(e) : [],
|
|
1433
|
+
subscript: sub ? parseOmmlChildren(sub) : [],
|
|
1434
|
+
superscript: sup ? parseOmmlChildren(sup) : [],
|
|
1435
|
+
};
|
|
1436
|
+
}
|
|
1437
|
+
case 'nary': {
|
|
1438
|
+
const naryPr = child(node, 'naryPr');
|
|
1439
|
+
const chrNode = naryPr ? child(naryPr, 'chr') : undefined;
|
|
1440
|
+
const operator = chrNode?.attrs['m:val'] ?? chrNode?.attrs['val'] ?? '∑';
|
|
1441
|
+
const sub = child(node, 'sub');
|
|
1442
|
+
const sup = child(node, 'sup');
|
|
1443
|
+
const e = child(node, 'e');
|
|
1444
|
+
return {
|
|
1445
|
+
type: 'nary',
|
|
1446
|
+
operator,
|
|
1447
|
+
lower: sub ? parseOmmlChildren(sub) : [],
|
|
1448
|
+
upper: sup ? parseOmmlChildren(sup) : [],
|
|
1449
|
+
body: e ? parseOmmlChildren(e) : [],
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
case 'rad': {
|
|
1453
|
+
const radPr = child(node, 'radPr');
|
|
1454
|
+
const degHide = radPr ? child(radPr, 'degHide') : undefined;
|
|
1455
|
+
const hideDegree = degHide?.attrs['m:val'] === '1' || degHide?.attrs['val'] === '1';
|
|
1456
|
+
const deg = child(node, 'deg');
|
|
1457
|
+
const e = child(node, 'e');
|
|
1458
|
+
return {
|
|
1459
|
+
type: 'rad',
|
|
1460
|
+
hideDegree,
|
|
1461
|
+
degree: deg ? parseOmmlChildren(deg) : [],
|
|
1462
|
+
body: e ? parseOmmlChildren(e) : [],
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1465
|
+
case 'd': {
|
|
1466
|
+
const dPr = child(node, 'dPr');
|
|
1467
|
+
const begChr = dPr ? child(dPr, 'begChr') : undefined;
|
|
1468
|
+
const endChr = dPr ? child(dPr, 'endChr') : undefined;
|
|
1469
|
+
const e = child(node, 'e');
|
|
1470
|
+
return {
|
|
1471
|
+
type: 'delim',
|
|
1472
|
+
open: begChr?.attrs['m:val'] ?? begChr?.attrs['val'] ?? '(',
|
|
1473
|
+
close: endChr?.attrs['m:val'] ?? endChr?.attrs['val'] ?? ')',
|
|
1474
|
+
body: e ? parseOmmlChildren(e) : [],
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
case 'func': {
|
|
1478
|
+
const fName = child(node, 'fName');
|
|
1479
|
+
const e = child(node, 'e');
|
|
1480
|
+
return {
|
|
1481
|
+
type: 'func',
|
|
1482
|
+
base: fName ? parseOmmlChildren(fName) : [],
|
|
1483
|
+
argument: e ? parseOmmlChildren(e) : [],
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
case 'groupChr': {
|
|
1487
|
+
const groupChrPr = child(node, 'groupChrPr');
|
|
1488
|
+
const chrNode = groupChrPr ? child(groupChrPr, 'chr') : undefined;
|
|
1489
|
+
const e = child(node, 'e');
|
|
1490
|
+
return {
|
|
1491
|
+
type: 'groupChar',
|
|
1492
|
+
operator: chrNode?.attrs['m:val'] ?? chrNode?.attrs['val'] ?? '⏟',
|
|
1493
|
+
base: e ? parseOmmlChildren(e) : [],
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
case 'acc': {
|
|
1497
|
+
const accPr = child(node, 'accPr');
|
|
1498
|
+
const chrNode = accPr ? child(accPr, 'chr') : undefined;
|
|
1499
|
+
const e = child(node, 'e');
|
|
1500
|
+
return {
|
|
1501
|
+
type: 'accent',
|
|
1502
|
+
operator: chrNode?.attrs['m:val'] ?? chrNode?.attrs['val'] ?? '̂',
|
|
1503
|
+
base: e ? parseOmmlChildren(e) : [],
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
case 'bar': {
|
|
1507
|
+
const e = child(node, 'e');
|
|
1508
|
+
return {
|
|
1509
|
+
type: 'bar',
|
|
1510
|
+
base: e ? parseOmmlChildren(e) : [],
|
|
1511
|
+
};
|
|
1512
|
+
}
|
|
1513
|
+
case 'limLow': {
|
|
1514
|
+
const e = child(node, 'e');
|
|
1515
|
+
const lim = child(node, 'lim');
|
|
1516
|
+
return {
|
|
1517
|
+
type: 'limLow',
|
|
1518
|
+
base: e ? parseOmmlChildren(e) : [],
|
|
1519
|
+
argument: lim ? parseOmmlChildren(lim) : [],
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
case 'limUpp': {
|
|
1523
|
+
const e = child(node, 'e');
|
|
1524
|
+
const lim = child(node, 'lim');
|
|
1525
|
+
return {
|
|
1526
|
+
type: 'limUpp',
|
|
1527
|
+
base: e ? parseOmmlChildren(e) : [],
|
|
1528
|
+
argument: lim ? parseOmmlChildren(lim) : [],
|
|
1529
|
+
};
|
|
1530
|
+
}
|
|
1531
|
+
case 'm': {
|
|
1532
|
+
const rows = [];
|
|
1533
|
+
for (const mr of children(node, 'mr')) {
|
|
1534
|
+
const row = [];
|
|
1535
|
+
for (const e of children(mr, 'e')) {
|
|
1536
|
+
const cellElements = parseOmmlChildren(e);
|
|
1537
|
+
if (cellElements.length === 1)
|
|
1538
|
+
row.push(cellElements[0]);
|
|
1539
|
+
else
|
|
1540
|
+
row.push({ type: 'text', text: cellElements.map(el => el.text ?? '').join('') });
|
|
1541
|
+
}
|
|
1542
|
+
rows.push(row);
|
|
1543
|
+
}
|
|
1544
|
+
return { type: 'matrix', rows };
|
|
1545
|
+
}
|
|
1546
|
+
case 'eqArr': {
|
|
1547
|
+
const rows = [];
|
|
1548
|
+
for (const e of children(node, 'e')) {
|
|
1549
|
+
rows.push(parseOmmlChildren(e));
|
|
1550
|
+
}
|
|
1551
|
+
return { type: 'eqArr', rows };
|
|
1552
|
+
}
|
|
1553
|
+
default:
|
|
1554
|
+
return null;
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
function parseCellImagesFromRichData(vmCells, getText, getEntry, ws) {
|
|
1558
|
+
const metaXml = getText('xl/metadata.xml');
|
|
1559
|
+
if (!metaXml)
|
|
1560
|
+
return;
|
|
1561
|
+
const metaRoot = parseXml(metaXml);
|
|
1562
|
+
const valueMeta = child(metaRoot, 'valueMetadata');
|
|
1563
|
+
if (!valueMeta)
|
|
1564
|
+
return;
|
|
1565
|
+
const vmBks = children(valueMeta, 'bk');
|
|
1566
|
+
const futureMeta = metaRoot.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'futureMetadata');
|
|
1567
|
+
const fmBks = futureMeta ? children(futureMeta, 'bk') : [];
|
|
1568
|
+
const rvXml = getText('xl/richData/rdrichvalue.xml');
|
|
1569
|
+
if (!rvXml)
|
|
1570
|
+
return;
|
|
1571
|
+
const rvRoot = parseXml(rvXml);
|
|
1572
|
+
const rvEntries = children(rvRoot, 'rv');
|
|
1573
|
+
const rvRelRelsXml = getText('xl/richData/_rels/richValueRel.xml.rels');
|
|
1574
|
+
if (!rvRelRelsXml)
|
|
1575
|
+
return;
|
|
1576
|
+
const rvRelRels = parseRels(rvRelRelsXml);
|
|
1577
|
+
const rvRelXml = getText('xl/richData/richValueRel.xml');
|
|
1578
|
+
if (!rvRelXml)
|
|
1579
|
+
return;
|
|
1580
|
+
const rvRelRoot = parseXml(rvRelXml);
|
|
1581
|
+
const relEntries = children(rvRelRoot, 'rel');
|
|
1582
|
+
for (const [cellRef, vmIdx] of vmCells) {
|
|
1583
|
+
const vmBk = vmBks[vmIdx - 1];
|
|
1584
|
+
if (!vmBk)
|
|
1585
|
+
continue;
|
|
1586
|
+
const rc = vmBk.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'rc');
|
|
1587
|
+
if (!rc)
|
|
1588
|
+
continue;
|
|
1589
|
+
const fmIdx = parseInt(rc.attrs['v'] ?? '-1', 10);
|
|
1590
|
+
if (fmIdx < 0)
|
|
1591
|
+
continue;
|
|
1592
|
+
const fmBk = fmBks[fmIdx];
|
|
1593
|
+
if (!fmBk)
|
|
1594
|
+
continue;
|
|
1595
|
+
const rvb = findDescendant(fmBk, 'rvb');
|
|
1596
|
+
const rvIdx = parseInt(rvb?.attrs['i'] ?? '-1', 10);
|
|
1597
|
+
if (rvIdx < 0)
|
|
1598
|
+
continue;
|
|
1599
|
+
const rv = rvEntries[rvIdx];
|
|
1600
|
+
if (!rv)
|
|
1601
|
+
continue;
|
|
1602
|
+
const vNodes = children(rv, 'v');
|
|
1603
|
+
const relIdx = parseInt(vNodes[0]?.text ?? '-1', 10);
|
|
1604
|
+
if (relIdx < 0)
|
|
1605
|
+
continue;
|
|
1606
|
+
const relEntry = relEntries[relIdx];
|
|
1607
|
+
if (!relEntry)
|
|
1608
|
+
continue;
|
|
1609
|
+
const rId = relEntry.attrs['r:id'] ?? '';
|
|
1610
|
+
const imgRel = rvRelRels.get(rId);
|
|
1611
|
+
if (!imgRel)
|
|
1612
|
+
continue;
|
|
1613
|
+
const imgPath = imgRel.target.startsWith('/')
|
|
1614
|
+
? imgRel.target.slice(1)
|
|
1615
|
+
: `xl/richData/${imgRel.target}`;
|
|
1616
|
+
const imgEntry = getEntry(imgPath);
|
|
1617
|
+
if (!imgEntry)
|
|
1618
|
+
continue;
|
|
1619
|
+
const ext = imgPath.split('.').pop() ?? 'png';
|
|
1620
|
+
const format = extToFormat(ext);
|
|
1621
|
+
ws.addCellImage({ data: imgEntry.data, format, cell: cellRef });
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
function findDescendant(node, tagName) {
|
|
1625
|
+
for (const c of node.children) {
|
|
1626
|
+
if (typeof c === 'string')
|
|
1627
|
+
continue;
|
|
1628
|
+
if (localName(c.tag) === tagName)
|
|
1629
|
+
return c;
|
|
1630
|
+
const found = findDescendant(c, tagName);
|
|
1631
|
+
if (found)
|
|
1632
|
+
return found;
|
|
1633
|
+
}
|
|
1634
|
+
return undefined;
|
|
1635
|
+
}
|
|
541
1636
|
function resolvePath(base, relative) {
|
|
542
1637
|
const parts = base.replace(/\/$/, '').split('/');
|
|
543
1638
|
for (const seg of relative.split('/')) {
|
|
@@ -581,6 +1676,26 @@ export async function readWorkbook(data) {
|
|
|
581
1676
|
const wbRoot = parseXml(wbXml);
|
|
582
1677
|
const sheetsNode = find(wbRoot, 'sheets');
|
|
583
1678
|
const sheetNodes = sheetsNode ? children(sheetsNode, 'sheet') : [];
|
|
1679
|
+
const namedRanges = [];
|
|
1680
|
+
const definedNamesNode = find(wbRoot, 'definedNames');
|
|
1681
|
+
if (definedNamesNode) {
|
|
1682
|
+
for (const dn of children(definedNamesNode, 'definedName')) {
|
|
1683
|
+
const name = dn.attrs['name'] ?? '';
|
|
1684
|
+
const ref = dn.text ?? '';
|
|
1685
|
+
if (!name || !ref)
|
|
1686
|
+
continue;
|
|
1687
|
+
const nr = { name, ref };
|
|
1688
|
+
if (dn.attrs['localSheetId'] !== undefined) {
|
|
1689
|
+
const idx = parseInt(dn.attrs['localSheetId'], 10);
|
|
1690
|
+
const scopeSheet = sheetNodes[idx];
|
|
1691
|
+
if (scopeSheet)
|
|
1692
|
+
nr.scope = scopeSheet.attrs['name'] ?? undefined;
|
|
1693
|
+
}
|
|
1694
|
+
if (dn.attrs['comment'])
|
|
1695
|
+
nr.comment = dn.attrs['comment'];
|
|
1696
|
+
namedRanges.push(nr);
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
584
1699
|
const allRels = new Map();
|
|
585
1700
|
for (const [path, entry] of zip) {
|
|
586
1701
|
if (path.includes('_rels/')) {
|
|
@@ -599,10 +1714,11 @@ export async function readWorkbook(data) {
|
|
|
599
1714
|
const sheetXml = getText(target) ?? '';
|
|
600
1715
|
if (!sheetXml)
|
|
601
1716
|
continue;
|
|
602
|
-
const { ws, originalXml, unknownParts: sheetUnknown, tableRIds } = parseWorksheet(sheetXml, name, styles, sharedStrings);
|
|
1717
|
+
const { ws, originalXml, unknownParts: sheetUnknown, tableRIds, legacyDrawingRId, ctrlPropRIds, drawingRId, vmCells } = parseWorksheet(sheetXml, name, styles, sharedStrings);
|
|
603
1718
|
ws.sheetIndex = sheets.length + 1;
|
|
604
1719
|
ws.rId = rId;
|
|
605
1720
|
const tablePaths = [];
|
|
1721
|
+
const tableXmls = [];
|
|
606
1722
|
if (tableRIds.length) {
|
|
607
1723
|
const sheetFileName = target.split('/').pop() ?? '';
|
|
608
1724
|
const sheetDir = target.substring(0, target.lastIndexOf('/') + 1);
|
|
@@ -622,17 +1738,179 @@ export async function readWorkbook(data) {
|
|
|
622
1738
|
if (table)
|
|
623
1739
|
ws.addTable(table);
|
|
624
1740
|
tablePaths.push(tblTarget);
|
|
1741
|
+
tableXmls.push(tblXml);
|
|
625
1742
|
}
|
|
626
1743
|
}
|
|
627
1744
|
ws.tableRIds = tableRIds;
|
|
628
1745
|
}
|
|
629
1746
|
}
|
|
630
|
-
|
|
1747
|
+
if (legacyDrawingRId && ctrlPropRIds.length) {
|
|
1748
|
+
const sheetFileName = target.split('/').pop() ?? '';
|
|
1749
|
+
const sheetDir = target.substring(0, target.lastIndexOf('/') + 1);
|
|
1750
|
+
const sheetRelsPath = `${sheetDir}_rels/${sheetFileName}.rels`;
|
|
1751
|
+
const sheetRels = allRels.get(sheetRelsPath);
|
|
1752
|
+
if (sheetRels) {
|
|
1753
|
+
const vmlRel = sheetRels.get(legacyDrawingRId);
|
|
1754
|
+
const vmlPath = vmlRel
|
|
1755
|
+
? (vmlRel.target.startsWith('/') ? vmlRel.target.slice(1) : resolvePath(sheetDir, vmlRel.target))
|
|
1756
|
+
: '';
|
|
1757
|
+
const vmlXml = vmlPath ? getText(vmlPath) : '';
|
|
1758
|
+
const vmlControls = [];
|
|
1759
|
+
if (vmlXml) {
|
|
1760
|
+
const vmlRoot = parseXml(vmlXml);
|
|
1761
|
+
for (const shape of vmlRoot.children) {
|
|
1762
|
+
if (typeof shape === 'string')
|
|
1763
|
+
continue;
|
|
1764
|
+
if (localName(shape.tag) !== 'shape')
|
|
1765
|
+
continue;
|
|
1766
|
+
const cd = shape.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'ClientData');
|
|
1767
|
+
if (!cd)
|
|
1768
|
+
continue;
|
|
1769
|
+
const objType = cd.attrs['ObjectType'] ?? '';
|
|
1770
|
+
if (objType === 'Note' || !objType)
|
|
1771
|
+
continue;
|
|
1772
|
+
const idStr = (shape.attrs['id'] ?? '').replace(/\D/g, '');
|
|
1773
|
+
const shapeId = parseInt(idStr, 10) || 0;
|
|
1774
|
+
vmlControls.push({ objectType: objType, shapeXml: nodeToXml(shape), clientData: cd, shapeId });
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
for (let ci = 0; ci < ctrlPropRIds.length; ci++) {
|
|
1778
|
+
const cpRel = sheetRels.get(ctrlPropRIds[ci]);
|
|
1779
|
+
if (!cpRel)
|
|
1780
|
+
continue;
|
|
1781
|
+
const cpPath = cpRel.target.startsWith('/') ? cpRel.target.slice(1) : resolvePath(sheetDir, cpRel.target);
|
|
1782
|
+
const cpXml = getText(cpPath) ?? '';
|
|
1783
|
+
const cpRoot = cpXml ? parseXml(cpXml) : null;
|
|
1784
|
+
const objType = cpRoot?.attrs['objectType'] ?? '';
|
|
1785
|
+
const typeName = (OBJ_TYPE_TO_CTRL[objType] ?? 'button');
|
|
1786
|
+
const vml = vmlControls[ci];
|
|
1787
|
+
const anchor = parseVmlAnchor(vml?.clientData);
|
|
1788
|
+
const ctrl = {
|
|
1789
|
+
type: typeName,
|
|
1790
|
+
from: anchor.from,
|
|
1791
|
+
to: anchor.to,
|
|
1792
|
+
_ctrlPropXml: cpXml || undefined,
|
|
1793
|
+
_vmlShapeXml: vml?.shapeXml,
|
|
1794
|
+
_shapeId: vml?.shapeId,
|
|
1795
|
+
};
|
|
1796
|
+
if (cpRoot) {
|
|
1797
|
+
if (cpRoot.attrs['fmlaLink'])
|
|
1798
|
+
ctrl.linkedCell = cpRoot.attrs['fmlaLink'];
|
|
1799
|
+
if (cpRoot.attrs['fmlaRange'])
|
|
1800
|
+
ctrl.inputRange = cpRoot.attrs['fmlaRange'];
|
|
1801
|
+
if (cpRoot.attrs['checked'])
|
|
1802
|
+
ctrl.checked = (CHECKED_REV[cpRoot.attrs['checked']] ?? 'unchecked');
|
|
1803
|
+
if (cpRoot.attrs['dropLines'])
|
|
1804
|
+
ctrl.dropLines = parseInt(cpRoot.attrs['dropLines'], 10);
|
|
1805
|
+
if (cpRoot.attrs['min'])
|
|
1806
|
+
ctrl.min = parseInt(cpRoot.attrs['min'], 10);
|
|
1807
|
+
if (cpRoot.attrs['max'])
|
|
1808
|
+
ctrl.max = parseInt(cpRoot.attrs['max'], 10);
|
|
1809
|
+
if (cpRoot.attrs['inc'])
|
|
1810
|
+
ctrl.inc = parseInt(cpRoot.attrs['inc'], 10);
|
|
1811
|
+
if (cpRoot.attrs['page'])
|
|
1812
|
+
ctrl.page = parseInt(cpRoot.attrs['page'], 10);
|
|
1813
|
+
if (cpRoot.attrs['val'])
|
|
1814
|
+
ctrl.val = parseInt(cpRoot.attrs['val'], 10);
|
|
1815
|
+
if (cpRoot.attrs['selType']) {
|
|
1816
|
+
const selRev = { Single: 'single', Multi: 'multi', Extend: 'extend' };
|
|
1817
|
+
ctrl.selType = (selRev[cpRoot.attrs['selType']] ?? 'single');
|
|
1818
|
+
}
|
|
1819
|
+
if (cpRoot.attrs['noThreeD'] === '1')
|
|
1820
|
+
ctrl.noThreeD = true;
|
|
1821
|
+
}
|
|
1822
|
+
if (vml?.clientData) {
|
|
1823
|
+
const macroNode = vml.clientData.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'FmlaMacro');
|
|
1824
|
+
if (macroNode)
|
|
1825
|
+
ctrl.macro = macroNode.text ?? '';
|
|
1826
|
+
}
|
|
1827
|
+
ws.addFormControl(ctrl);
|
|
1828
|
+
}
|
|
1829
|
+
ws.legacyDrawingRId = legacyDrawingRId;
|
|
1830
|
+
ws.ctrlPropRIds = ctrlPropRIds;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
if (drawingRId) {
|
|
1834
|
+
const sheetFileName = target.split('/').pop() ?? '';
|
|
1835
|
+
const sheetDir = target.substring(0, target.lastIndexOf('/') + 1);
|
|
1836
|
+
const sheetRelsPath = `${sheetDir}_rels/${sheetFileName}.rels`;
|
|
1837
|
+
const sheetRels = allRels.get(sheetRelsPath);
|
|
1838
|
+
if (sheetRels) {
|
|
1839
|
+
const drawRel = sheetRels.get(drawingRId);
|
|
1840
|
+
if (drawRel) {
|
|
1841
|
+
const drawPath = drawRel.target.startsWith('/')
|
|
1842
|
+
? drawRel.target.slice(1)
|
|
1843
|
+
: resolvePath(sheetDir, drawRel.target);
|
|
1844
|
+
const drawXml = getText(drawPath);
|
|
1845
|
+
if (drawXml) {
|
|
1846
|
+
const drawDir = drawPath.substring(0, drawPath.lastIndexOf('/') + 1);
|
|
1847
|
+
const drawFileName = drawPath.split('/').pop() ?? '';
|
|
1848
|
+
const drawRelsPath = `${drawDir}_rels/${drawFileName}.rels`;
|
|
1849
|
+
const drawRels = allRels.get(drawRelsPath);
|
|
1850
|
+
parseDrawingObjects(drawXml, drawRels, drawDir, get, ws);
|
|
1851
|
+
}
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
if (vmCells.size > 0) {
|
|
1856
|
+
parseCellImagesFromRichData(vmCells, getText, get, ws);
|
|
1857
|
+
}
|
|
1858
|
+
sheets.push({ ws, sheetId, rId, originalXml, unknownParts: sheetUnknown, tablePaths, tableXmls });
|
|
1859
|
+
}
|
|
1860
|
+
const connectionsXml = getText('xl/connections.xml') ?? '';
|
|
1861
|
+
const connections = [];
|
|
1862
|
+
if (connectionsXml) {
|
|
1863
|
+
const connRoot = parseXml(connectionsXml);
|
|
1864
|
+
for (const cn of children(connRoot, 'connection')) {
|
|
1865
|
+
const id = parseInt(cn.attrs['id'] ?? '0', 10);
|
|
1866
|
+
const name = cn.attrs['name'] ?? '';
|
|
1867
|
+
const typeNum = parseInt(cn.attrs['type'] ?? '0', 10);
|
|
1868
|
+
const type = connTypeFromNum(typeNum);
|
|
1869
|
+
if (!name || !type)
|
|
1870
|
+
continue;
|
|
1871
|
+
const conn = { id, name, type };
|
|
1872
|
+
if (cn.attrs['description'])
|
|
1873
|
+
conn.description = cn.attrs['description'];
|
|
1874
|
+
if (cn.attrs['refreshOnLoad'] === '1')
|
|
1875
|
+
conn.refreshOnLoad = true;
|
|
1876
|
+
if (cn.attrs['background'] === '1')
|
|
1877
|
+
conn.background = true;
|
|
1878
|
+
if (cn.attrs['saveData'] === '1')
|
|
1879
|
+
conn.saveData = true;
|
|
1880
|
+
if (cn.attrs['keepAlive'] === '1')
|
|
1881
|
+
conn.keepAlive = true;
|
|
1882
|
+
if (cn.attrs['interval'])
|
|
1883
|
+
conn.interval = parseInt(cn.attrs['interval'], 10);
|
|
1884
|
+
const dbPr = child(cn, 'dbPr');
|
|
1885
|
+
if (dbPr) {
|
|
1886
|
+
if (dbPr.attrs['connection'])
|
|
1887
|
+
conn.connectionString = dbPr.attrs['connection'];
|
|
1888
|
+
if (dbPr.attrs['command'])
|
|
1889
|
+
conn.command = dbPr.attrs['command'];
|
|
1890
|
+
if (dbPr.attrs['commandType'])
|
|
1891
|
+
conn.commandType = cmdTypeFromNum(parseInt(dbPr.attrs['commandType'], 10));
|
|
1892
|
+
}
|
|
1893
|
+
conn._rawXml = nodeToXml(cn);
|
|
1894
|
+
connections.push(conn);
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
const powerQueries = [];
|
|
1898
|
+
for (const [path, entry] of zip) {
|
|
1899
|
+
if (!path.startsWith('customXml/item') || path.includes('Props') || path.includes('_rels'))
|
|
1900
|
+
continue;
|
|
1901
|
+
try {
|
|
1902
|
+
const pqs = await parseDataMashup(entry.data);
|
|
1903
|
+
if (pqs.length) {
|
|
1904
|
+
powerQueries.push(...pqs);
|
|
1905
|
+
break;
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
catch { }
|
|
631
1909
|
}
|
|
632
1910
|
const handledPrefixes = new Set([
|
|
633
1911
|
'xl/workbook.xml', 'xl/styles.xml', 'xl/sharedStrings.xml',
|
|
634
1912
|
'xl/worksheets/', 'docProps/', '[Content_Types].xml',
|
|
635
|
-
'_rels/', 'xl/_rels/',
|
|
1913
|
+
'_rels/', 'xl/_rels/', 'xl/connections.xml',
|
|
636
1914
|
]);
|
|
637
1915
|
const unknownParts = new Map();
|
|
638
1916
|
for (const [path, entry] of zip) {
|
|
@@ -643,12 +1921,100 @@ export async function readWorkbook(data) {
|
|
|
643
1921
|
unknownParts.set(path, entry.data);
|
|
644
1922
|
}
|
|
645
1923
|
}
|
|
1924
|
+
const nonPrintAreaRanges = [];
|
|
1925
|
+
for (const nr of namedRanges) {
|
|
1926
|
+
if (nr.name === '_xlnm.Print_Area' && nr.scope) {
|
|
1927
|
+
const ws = sheets.find(s => s.ws.name === nr.scope);
|
|
1928
|
+
if (ws)
|
|
1929
|
+
ws.ws.printArea = nr.ref;
|
|
1930
|
+
}
|
|
1931
|
+
else {
|
|
1932
|
+
nonPrintAreaRanges.push(nr);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
646
1935
|
return {
|
|
647
1936
|
sheets, styles, stylesXml, sharedStrings, sharedXml: ssXml,
|
|
648
1937
|
workbookXml: wbXml, workbookRels,
|
|
649
1938
|
contentTypes, contentTypesXml: ctXml,
|
|
650
1939
|
core, extended, extendedUnknownRaw, custom, hasCustomProps: custom.length > 0,
|
|
1940
|
+
namedRanges: nonPrintAreaRanges, connections, connectionsXml, powerQueries,
|
|
651
1941
|
unknownParts, allRels,
|
|
652
1942
|
};
|
|
653
1943
|
}
|
|
1944
|
+
function parseVmlAnchor(clientData) {
|
|
1945
|
+
const defaultAnchor = { from: { col: 0, row: 0 }, to: { col: 2, row: 2 } };
|
|
1946
|
+
if (!clientData)
|
|
1947
|
+
return defaultAnchor;
|
|
1948
|
+
const anchorNode = clientData.children.find((c) => typeof c !== 'string' && localName(c.tag) === 'Anchor');
|
|
1949
|
+
if (!anchorNode)
|
|
1950
|
+
return defaultAnchor;
|
|
1951
|
+
const text = anchorNode.text ?? '';
|
|
1952
|
+
const parts = text.split(',').map(s => parseInt(s.trim(), 10));
|
|
1953
|
+
if (parts.length < 8 || parts.some(isNaN))
|
|
1954
|
+
return defaultAnchor;
|
|
1955
|
+
return {
|
|
1956
|
+
from: { col: parts[0], colOff: parts[1], row: parts[2], rowOff: parts[3] },
|
|
1957
|
+
to: { col: parts[4], colOff: parts[5], row: parts[6], rowOff: parts[7] },
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
const CONN_TYPE_MAP = {
|
|
1961
|
+
1: 'odbc', 2: 'dao', 3: 'file', 4: 'web', 5: 'oledb', 6: 'text', 7: 'dsp',
|
|
1962
|
+
};
|
|
1963
|
+
const CONN_TYPE_REV = Object.fromEntries(Object.entries(CONN_TYPE_MAP).map(([k, v]) => [v, Number(k)]));
|
|
1964
|
+
function connTypeFromNum(n) { return CONN_TYPE_MAP[n]; }
|
|
1965
|
+
export function connTypeToNum(t) { return CONN_TYPE_REV[t]; }
|
|
1966
|
+
const CMD_TYPE_MAP = {
|
|
1967
|
+
1: 'sql', 2: 'table', 3: 'default', 4: 'web', 5: 'oledb',
|
|
1968
|
+
};
|
|
1969
|
+
const CMD_TYPE_REV = Object.fromEntries(Object.entries(CMD_TYPE_MAP).map(([k, v]) => [v, Number(k)]));
|
|
1970
|
+
function cmdTypeFromNum(n) { return CMD_TYPE_MAP[n]; }
|
|
1971
|
+
export function cmdTypeToNum(t) { return CMD_TYPE_REV[t]; }
|
|
1972
|
+
async function parseDataMashup(data) {
|
|
1973
|
+
if (data.length < 12)
|
|
1974
|
+
return [];
|
|
1975
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1976
|
+
const version = view.getUint32(0, true);
|
|
1977
|
+
if (version !== 0)
|
|
1978
|
+
return [];
|
|
1979
|
+
const pkgLen = view.getUint32(4, true);
|
|
1980
|
+
if (pkgLen < 4 || 8 + pkgLen > data.length)
|
|
1981
|
+
return [];
|
|
1982
|
+
const pkgBytes = data.subarray(8, 8 + pkgLen);
|
|
1983
|
+
if (pkgBytes[0] !== 0x50 || pkgBytes[1] !== 0x4B)
|
|
1984
|
+
return [];
|
|
1985
|
+
const innerZip = await readZip(pkgBytes);
|
|
1986
|
+
const queries = [];
|
|
1987
|
+
for (const [path, entry] of innerZip) {
|
|
1988
|
+
if (!path.includes('/Formula/') || !path.endsWith('.m'))
|
|
1989
|
+
continue;
|
|
1990
|
+
const formula = entryText(entry);
|
|
1991
|
+
if (!formula)
|
|
1992
|
+
continue;
|
|
1993
|
+
const pathMatch = path.match(/Formulas\/([^/]+)\//);
|
|
1994
|
+
const nameFromPath = pathMatch ? pathMatch[1] : undefined;
|
|
1995
|
+
const sharedRe = /shared\s+(?:#"([^"]+)"|(\w+))\s*=/g;
|
|
1996
|
+
let m;
|
|
1997
|
+
const foundNames = new Set();
|
|
1998
|
+
while ((m = sharedRe.exec(formula)) !== null) {
|
|
1999
|
+
const qName = m[1] ?? m[2];
|
|
2000
|
+
foundNames.add(qName);
|
|
2001
|
+
}
|
|
2002
|
+
if (foundNames.size > 0) {
|
|
2003
|
+
const sectionRe = /shared\s+(?:#"([^"]+)"|(\w+))\s*=\s*([\s\S]*?)(?=,\s*shared\s|\]\s*$)/g;
|
|
2004
|
+
let sm;
|
|
2005
|
+
while ((sm = sectionRe.exec(formula)) !== null) {
|
|
2006
|
+
const qName = sm[1] ?? sm[2];
|
|
2007
|
+
const qFormula = sm[3].replace(/,\s*$/, '').trim();
|
|
2008
|
+
queries.push({ name: qName, formula: qFormula });
|
|
2009
|
+
}
|
|
2010
|
+
if (queries.length === 0) {
|
|
2011
|
+
queries.push({ name: nameFromPath ?? 'Section1', formula });
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
else if (nameFromPath) {
|
|
2015
|
+
queries.push({ name: nameFromPath, formula });
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
return queries;
|
|
2019
|
+
}
|
|
654
2020
|
//# sourceMappingURL=WorkbookReader.js.map
|