xlvane 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/dist/cli.js +226 -47
- package/dist/index.d.ts +5 -4
- package/dist/index.js +3 -3
- package/dist/{node-files-B0iqSJIJ.js → node-files-CDb6TyZb.js} +1 -1
- package/dist/node.d.ts +1 -1
- package/dist/node.js +3 -3
- package/dist/{options-CwSp2pA4.js → options-Ba1iWD-Z.js} +316 -75
- package/dist/{rows-DKwlr0rg.js → rows-IWKIxHt9.js} +59 -15
- package/dist/{stream-write-BKppyMz0.js → stream-write-BGuUjlXo.js} +24 -9
- package/dist/{stream-write-GJXORYQ2.d.ts → stream-write-BVaFkgwO.d.ts} +9 -6
- package/docs/cli-json/mcp.schema.json +43 -0
- package/docs/cli-json.md +2 -1
- package/docs/errors.md +27 -0
- package/docs/exceljs-compat.md +1 -1
- package/llms-full.txt +90 -10
- package/package.json +1 -1
- package/skills/xlvane/SKILL.md +8 -3
|
@@ -50,7 +50,9 @@ const ERROR_CODES = [
|
|
|
50
50
|
"XLV_E_CSV_MALFORMED",
|
|
51
51
|
"XLV_E_NOT_SUPPORTED",
|
|
52
52
|
"XLV_E_USAGE",
|
|
53
|
-
"
|
|
53
|
+
"XLV_E_NOT_INSTALLED",
|
|
54
|
+
"XLV_E_INTERNAL",
|
|
55
|
+
"XLV_E_PATH_NOT_ALLOWED"
|
|
54
56
|
];
|
|
55
57
|
/**
|
|
56
58
|
* Every warning code xlvane can report. Warnings never stop reading; they describe something
|
|
@@ -73,13 +75,15 @@ const WARNING_CODES = [
|
|
|
73
75
|
"XLV_W_DUPLICATE_CELL",
|
|
74
76
|
"XLV_W_INVALID_VALUE",
|
|
75
77
|
"XLV_W_SHEET_PART_MISSING",
|
|
78
|
+
"XLV_W_SHEET_PART_SHARED",
|
|
76
79
|
"XLV_W_PART_MISSING",
|
|
77
80
|
"XLV_W_FORMULAS_NOT_RECALCULATED",
|
|
78
81
|
"XLV_W_INVALID_CELL_REF",
|
|
79
82
|
"XLV_W_UNUSUAL_HYPERLINK",
|
|
80
83
|
"XLV_W_THREADED_COMMENTS",
|
|
81
84
|
"XLV_W_DRAWING_CONTENT_NOT_READ",
|
|
82
|
-
"XLV_W_MERGED_CELL_WRITE"
|
|
85
|
+
"XLV_W_MERGED_CELL_WRITE",
|
|
86
|
+
"XLV_W_LIMIT_REACHED"
|
|
83
87
|
];
|
|
84
88
|
/**
|
|
85
89
|
* The only error type thrown by xlvane for problems with input files or options. It says what
|
|
@@ -332,6 +336,8 @@ function createXmlStreamParser(handler, options) {
|
|
|
332
336
|
}
|
|
333
337
|
};
|
|
334
338
|
}
|
|
339
|
+
const COMMENT_TOO_LONG = "Comment is longer than the limit.";
|
|
340
|
+
const PI_TOO_LONG = "Processing instruction is longer than the limit.";
|
|
335
341
|
/** Consumed input is dropped once at least this many characters can go (amortises copying). */
|
|
336
342
|
const COMPACT_THRESHOLD = 65536;
|
|
337
343
|
var Parser = class {
|
|
@@ -363,13 +369,23 @@ var Parser = class {
|
|
|
363
369
|
tokenAt = -1;
|
|
364
370
|
tokenFrom = 0;
|
|
365
371
|
tokenQuote = 0;
|
|
372
|
+
/** Offset of the quote that opened the attribute value being searched. */
|
|
373
|
+
tokenQuoteAt = 0;
|
|
374
|
+
/**
|
|
375
|
+
* Pieces held back while the unconsumed input is long (a long token or text run), joined to `s`
|
|
376
|
+
* once they are at least as long as it. Appending every piece to `s` and searching it again
|
|
377
|
+
* made a long token cost time quadratic in its length; joining at doubling sizes keeps the
|
|
378
|
+
* total work linear (D-H01).
|
|
379
|
+
*/
|
|
380
|
+
held = [];
|
|
381
|
+
heldLength = 0;
|
|
366
382
|
constructor(handler, options, whole) {
|
|
367
383
|
this.handler = handler;
|
|
368
384
|
this.options = options;
|
|
369
385
|
this.whole = whole;
|
|
370
386
|
}
|
|
371
387
|
get buffered() {
|
|
372
|
-
return this.s.length - this.pos + this.textBuffer.length;
|
|
388
|
+
return this.s.length - this.pos + this.heldLength + this.textBuffer.length;
|
|
373
389
|
}
|
|
374
390
|
write(chunk) {
|
|
375
391
|
if (this.ended) throw new Error("XML stream parser: write() after end().");
|
|
@@ -389,24 +405,36 @@ var Parser = class {
|
|
|
389
405
|
}
|
|
390
406
|
}
|
|
391
407
|
if (text.length === 0) return;
|
|
408
|
+
if (this.whole) {
|
|
409
|
+
this.append(text);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
this.held.push(text);
|
|
413
|
+
this.heldLength += text.length;
|
|
414
|
+
if (this.heldLength < this.s.length - this.pos) return;
|
|
415
|
+
this.appendHeld();
|
|
416
|
+
this.pump(false);
|
|
417
|
+
this.compact();
|
|
418
|
+
}
|
|
419
|
+
append(text) {
|
|
392
420
|
const from = this.s.length;
|
|
393
421
|
this.s += text;
|
|
394
422
|
this.checkCharacters(from);
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
423
|
+
}
|
|
424
|
+
appendHeld() {
|
|
425
|
+
if (this.held.length === 0) return;
|
|
426
|
+
const text = this.held.length === 1 ? this.held[0] ?? "" : this.held.join("");
|
|
427
|
+
this.held = [];
|
|
428
|
+
this.heldLength = 0;
|
|
429
|
+
this.append(text);
|
|
399
430
|
}
|
|
400
431
|
end() {
|
|
401
432
|
if (this.ended) return;
|
|
402
433
|
const tail = this.pendingHigh + (this.pendingCR ? "\n" : "");
|
|
403
434
|
this.pendingCR = false;
|
|
404
435
|
this.pendingHigh = "";
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
this.s += tail;
|
|
408
|
-
this.checkCharacters(from);
|
|
409
|
-
}
|
|
436
|
+
this.appendHeld();
|
|
437
|
+
if (tail.length > 0) this.append(tail);
|
|
410
438
|
this.ended = true;
|
|
411
439
|
this.pump(true);
|
|
412
440
|
}
|
|
@@ -428,6 +456,7 @@ var Parser = class {
|
|
|
428
456
|
if (this.tokenAt !== -1) {
|
|
429
457
|
this.tokenAt -= drop;
|
|
430
458
|
this.tokenFrom -= drop;
|
|
459
|
+
this.tokenQuoteAt -= drop;
|
|
431
460
|
}
|
|
432
461
|
}
|
|
433
462
|
/**
|
|
@@ -440,7 +469,10 @@ var Parser = class {
|
|
|
440
469
|
if (!this.declarationChecked) {
|
|
441
470
|
if (s.length - this.pos < 6 && !final) return;
|
|
442
471
|
if (s.startsWith("<?xml", this.pos) && (s.length === 5 || isWhitespace(s.charCodeAt(5)) || s.charCodeAt(5) === QUESTION)) {
|
|
443
|
-
if (!final && s.indexOf("?>", this.pos + 2) === -1)
|
|
472
|
+
if (!final && s.indexOf("?>", this.pos + 2) === -1) {
|
|
473
|
+
if (s.length - this.pos - 2 > this.options.limits.maxXmlTextLength + 1) this.limit("maxXmlTextLength", PI_TOO_LONG, this.pos);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
444
476
|
this.declarationChecked = true;
|
|
445
477
|
this.skipProcessingInstruction(true);
|
|
446
478
|
}
|
|
@@ -490,15 +522,24 @@ var Parser = class {
|
|
|
490
522
|
if (length - at >= 4 && s.startsWith("<!--", at)) {
|
|
491
523
|
const dashes = s.indexOf("--", Math.max(at + 4, this.tokenFrom));
|
|
492
524
|
done = dashes !== -1 && dashes + 2 < length;
|
|
493
|
-
if (!done)
|
|
525
|
+
if (!done) {
|
|
526
|
+
this.tokenFrom = dashes !== -1 ? dashes : Math.max(at + 4, length - 1);
|
|
527
|
+
if (length - (at + 4) > this.options.limits.maxXmlTextLength + 2) this.limit("maxXmlTextLength", COMMENT_TOO_LONG, at);
|
|
528
|
+
}
|
|
494
529
|
} else if (length - at < 9) done = false;
|
|
495
530
|
else if (s.startsWith("<![CDATA[", at)) {
|
|
496
531
|
done = s.indexOf("]]>", Math.max(at + 9, this.tokenFrom)) !== -1;
|
|
497
|
-
if (!done)
|
|
532
|
+
if (!done) {
|
|
533
|
+
this.tokenFrom = Math.max(at + 9, length - 2);
|
|
534
|
+
if (this.textBuffer.length + length - (at + 9) > this.options.limits.maxXmlTextLength + 2) this.limit("maxXmlTextLength", "Text node is longer than the limit.", at);
|
|
535
|
+
}
|
|
498
536
|
} else done = true;
|
|
499
537
|
} else if (next === QUESTION) {
|
|
500
538
|
done = s.indexOf("?>", Math.max(at + 2, this.tokenFrom)) !== -1;
|
|
501
|
-
if (!done)
|
|
539
|
+
if (!done) {
|
|
540
|
+
this.tokenFrom = Math.max(at + 2, length - 1);
|
|
541
|
+
if (length - (at + 2) > this.options.limits.maxXmlTextLength + 1) this.limit("maxXmlTextLength", PI_TOO_LONG, at);
|
|
542
|
+
}
|
|
502
543
|
} else if (next === SLASH$1) {
|
|
503
544
|
done = s.indexOf(">", Math.max(at + 2, this.tokenFrom)) !== -1;
|
|
504
545
|
if (!done) this.tokenFrom = length;
|
|
@@ -510,14 +551,17 @@ var Parser = class {
|
|
|
510
551
|
const c = s.charCodeAt(i);
|
|
511
552
|
if (quote !== 0) {
|
|
512
553
|
if (c === quote) quote = 0;
|
|
513
|
-
} else if (c === QUOTE || c === APOS)
|
|
514
|
-
|
|
554
|
+
} else if (c === QUOTE || c === APOS) {
|
|
555
|
+
quote = c;
|
|
556
|
+
this.tokenQuoteAt = i;
|
|
557
|
+
} else if (c === GT) {
|
|
515
558
|
done = true;
|
|
516
559
|
break;
|
|
517
560
|
}
|
|
518
561
|
}
|
|
519
562
|
this.tokenFrom = i;
|
|
520
563
|
this.tokenQuote = quote;
|
|
564
|
+
if (!done && quote !== 0 && i - (this.tokenQuoteAt + 1) > this.options.limits.maxXmlTextLength) this.limit("maxXmlTextLength", `Value of attribute "${this.attributeNameBefore(this.tokenQuoteAt)}" is longer than the limit.`, this.tokenQuoteAt + 1);
|
|
521
565
|
}
|
|
522
566
|
if (done) this.tokenAt = -1;
|
|
523
567
|
return done;
|
|
@@ -532,7 +576,13 @@ var Parser = class {
|
|
|
532
576
|
if (s.length - this.pos <= this.options.limits.maxXmlTextLength) return;
|
|
533
577
|
let cut = s.length;
|
|
534
578
|
const amp = s.indexOf("&", Math.max(this.pos, s.lastIndexOf(";") + 1));
|
|
535
|
-
if (amp !== -1)
|
|
579
|
+
if (amp !== -1) {
|
|
580
|
+
cut = amp;
|
|
581
|
+
if (s.length - amp > this.options.limits.maxXmlNameLength + 12) {
|
|
582
|
+
if (s.charCodeAt(amp + 1) !== HASH) this.limit("maxXmlNameLength", "Entity name is longer than the limit.", amp);
|
|
583
|
+
this.fail("\"&\" must start an entity or character reference ending with \";\".", amp);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
536
586
|
while (cut > this.pos && s.charCodeAt(cut - 1) === 93 && cut > s.length - 2) cut--;
|
|
537
587
|
if (cut <= this.pos) return;
|
|
538
588
|
if (this.segmentStart === -1) {
|
|
@@ -865,6 +915,7 @@ var Parser = class {
|
|
|
865
915
|
skipComment() {
|
|
866
916
|
const start = this.pos;
|
|
867
917
|
const end = this.s.indexOf("--", start + 4);
|
|
918
|
+
if ((end === -1 ? this.s.length : end) - (start + 4) > this.options.limits.maxXmlTextLength) this.limit("maxXmlTextLength", COMMENT_TOO_LONG, start);
|
|
868
919
|
if (end === -1) this.fail("Comment is not terminated.", start);
|
|
869
920
|
if (this.s.charCodeAt(end + 2) !== GT) this.fail("\"--\" is not allowed inside a comment.", end);
|
|
870
921
|
this.pos = end + 3;
|
|
@@ -875,6 +926,7 @@ var Parser = class {
|
|
|
875
926
|
const target = this.readName();
|
|
876
927
|
if (!declaration && target.toLowerCase() === "xml") this.fail("The XML declaration is allowed only at the very start of the document.", start);
|
|
877
928
|
const end = this.s.indexOf("?>", this.pos);
|
|
929
|
+
if ((end === -1 ? this.s.length : end) - (start + 2) > this.options.limits.maxXmlTextLength) this.limit("maxXmlTextLength", PI_TOO_LONG, start);
|
|
878
930
|
if (end === -1) this.fail("Processing instruction is not terminated.", start);
|
|
879
931
|
const c = this.s.charCodeAt(this.pos);
|
|
880
932
|
if (this.pos !== end && !isWhitespace(c)) this.fail("Invalid processing instruction target.", start);
|
|
@@ -911,6 +963,17 @@ var Parser = class {
|
|
|
911
963
|
hint: "The part is not well-formed XML. Re-save the file in a spreadsheet application; if it was generated by a program, report the problem to its authors."
|
|
912
964
|
});
|
|
913
965
|
}
|
|
966
|
+
/** The attribute name before `name = "` whose quote is at `quote` (for a message). */
|
|
967
|
+
attributeNameBefore(quote) {
|
|
968
|
+
const s = this.s;
|
|
969
|
+
let i = quote - 1;
|
|
970
|
+
while (i >= 0 && isWhitespace(s.charCodeAt(i))) i--;
|
|
971
|
+
if (s.charCodeAt(i) === EQ) i--;
|
|
972
|
+
while (i >= 0 && isWhitespace(s.charCodeAt(i))) i--;
|
|
973
|
+
const end = i + 1;
|
|
974
|
+
while (i >= 0 && end - i <= this.options.limits.maxXmlNameLength && !isWhitespace(s.charCodeAt(i)) && s.charCodeAt(i) !== 60) i--;
|
|
975
|
+
return s.slice(i + 1, end);
|
|
976
|
+
}
|
|
914
977
|
limit(limit, message, offset) {
|
|
915
978
|
const details = {
|
|
916
979
|
limit,
|
|
@@ -984,8 +1047,16 @@ function createXmlByteStreamParser(handler, options) {
|
|
|
984
1047
|
let decoder = null;
|
|
985
1048
|
/** Bytes held until the encoding is known (at most the first two). */
|
|
986
1049
|
let head = /* @__PURE__ */ new Uint8Array(0);
|
|
987
|
-
/**
|
|
988
|
-
|
|
1050
|
+
/**
|
|
1051
|
+
* Decoded pieces held until the XML declaration can be checked (null once it has been), with
|
|
1052
|
+
* their length, their first five characters and whether "?>" has been seen. Each piece is
|
|
1053
|
+
* searched once, so a long declaration costs linear time (D-H01).
|
|
1054
|
+
*/
|
|
1055
|
+
let pending = [];
|
|
1056
|
+
let pendingLength = 0;
|
|
1057
|
+
let pendingHead = "";
|
|
1058
|
+
let pendingLast = "";
|
|
1059
|
+
let declarationEnd = false;
|
|
989
1060
|
const encodingError = (cause) => new XlvError("XLV_E_XML_ENCODING", `The part is not valid ${(encoding ?? "utf-8").toUpperCase()}.`, {
|
|
990
1061
|
location: { part },
|
|
991
1062
|
hint: "Office Open XML parts must be encoded in UTF-8 or UTF-16. Re-save the file in a spreadsheet application.",
|
|
@@ -1004,9 +1075,30 @@ function createXmlByteStreamParser(handler, options) {
|
|
|
1004
1075
|
if (chunk.length > 0) text.write(chunk);
|
|
1005
1076
|
return;
|
|
1006
1077
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1078
|
+
if (chunk.length > 0) {
|
|
1079
|
+
pending.push(chunk);
|
|
1080
|
+
pendingLength += chunk.length;
|
|
1081
|
+
if (pendingHead.length < 5) pendingHead += chunk.slice(0, 5 - pendingHead.length);
|
|
1082
|
+
declarationEnd ||= (pendingLast + chunk).includes("?>");
|
|
1083
|
+
pendingLast = chunk.slice(-1);
|
|
1084
|
+
}
|
|
1085
|
+
const known = pendingLength >= 5 && (!pendingHead.startsWith("<?xml") || declarationEnd);
|
|
1086
|
+
if (!known && pendingLength - 2 > options.limits.maxXmlTextLength + 1) throw new XlvError("XLV_E_LIMIT_EXCEEDED", PI_TOO_LONG, {
|
|
1087
|
+
location: {
|
|
1088
|
+
part,
|
|
1089
|
+
line: 1,
|
|
1090
|
+
column: 1
|
|
1091
|
+
},
|
|
1092
|
+
hint: `If you trust this file, raise the limit, for example { limits: { maxXmlTextLength: ${String(options.limits.maxXmlTextLength * 4)} } }.`,
|
|
1093
|
+
details: {
|
|
1094
|
+
limit: "maxXmlTextLength",
|
|
1095
|
+
value: options.limits.maxXmlTextLength
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1098
|
+
if (!known && !final) return;
|
|
1099
|
+
const all = pending.join("");
|
|
1100
|
+
pending = null;
|
|
1101
|
+
const declared = declaredEncoding(all);
|
|
1010
1102
|
if (declared !== null) {
|
|
1011
1103
|
const normalized = declared.toLowerCase();
|
|
1012
1104
|
if (!(encoding === "utf-8" ? normalized === "utf-8" : normalized === "utf-16" || normalized === encoding)) throw new XlvError("XLV_E_XML_ENCODING", `The part declares encoding "${declared}", which is not supported.`, {
|
|
@@ -1015,8 +1107,6 @@ function createXmlByteStreamParser(handler, options) {
|
|
|
1015
1107
|
details: { encoding: declared }
|
|
1016
1108
|
});
|
|
1017
1109
|
}
|
|
1018
|
-
const all = pending;
|
|
1019
|
-
pending = null;
|
|
1020
1110
|
if (all.length > 0) text.write(all);
|
|
1021
1111
|
};
|
|
1022
1112
|
const start = (bytes) => {
|
|
@@ -3412,6 +3502,22 @@ function describe$1(value) {
|
|
|
3412
3502
|
if (typeof value === "object" || typeof value === "function") return `a value of type ${typeof value}`;
|
|
3413
3503
|
return String(value);
|
|
3414
3504
|
}
|
|
3505
|
+
/**
|
|
3506
|
+
* Checks the number of positions an output built from a sheet would have against
|
|
3507
|
+
* max(`maxCells`, OUTPUT_PER_CELL × cells read). Throws `XLV_E_LIMIT_EXCEEDED` above it.
|
|
3508
|
+
*/
|
|
3509
|
+
function checkOutputPositions(positions, cells, maxCells, what, sheet) {
|
|
3510
|
+
const budget = Math.max(maxCells, 16 * cells);
|
|
3511
|
+
if (positions <= budget) return;
|
|
3512
|
+
throw new XlvError("XLV_E_LIMIT_EXCEEDED", `${what} of sheet "${sheet}" would have ${String(positions)} positions (rows × columns) for ${String(cells)} cells, more than the limit of ${String(budget)}.`, {
|
|
3513
|
+
location: { sheet },
|
|
3514
|
+
hint: `The cells are spread over a far larger area than they fill. Pass a smaller range (for example { range: "A1:H1000" } or --range), or raise limits.maxCells if the file is trusted.`,
|
|
3515
|
+
details: {
|
|
3516
|
+
limit: "maxCells",
|
|
3517
|
+
value: budget
|
|
3518
|
+
}
|
|
3519
|
+
});
|
|
3520
|
+
}
|
|
3415
3521
|
// src/sml/numfmt.ts
|
|
3416
3522
|
/** A `Map` whose contents cannot change after construction. */
|
|
3417
3523
|
var FrozenMap = class extends Map {
|
|
@@ -8430,6 +8536,10 @@ function createRuleCollector(ctx) {
|
|
|
8430
8536
|
};
|
|
8431
8537
|
}
|
|
8432
8538
|
// src/sml/formula-shift.ts
|
|
8539
|
+
/** Number of decimal digits of a positive whole number. */
|
|
8540
|
+
const digits = (n) => n < 10 ? 1 : n < 100 ? 2 : n < 1e3 ? 3 : n < 1e4 ? 4 : n < 1e5 ? 5 : n < 1e6 ? 6 : 7;
|
|
8541
|
+
/** Number of letters of a column number from 1 to 16384 (A to XFD). */
|
|
8542
|
+
const letters = (c) => c <= 26 ? 1 : c <= 702 ? 2 : 3;
|
|
8433
8543
|
/** Error constants (§18.17.3, fact E-33). */
|
|
8434
8544
|
const ERROR_CONSTANTS = [
|
|
8435
8545
|
"#NULL!",
|
|
@@ -8773,8 +8883,17 @@ var Compiled = class {
|
|
|
8773
8883
|
maxRow = -Infinity;
|
|
8774
8884
|
minCol = Infinity;
|
|
8775
8885
|
maxCol = -Infinity;
|
|
8886
|
+
/** Length of the literal text and sheet prefixes, which do not change when moved. */
|
|
8887
|
+
literalLength = 0;
|
|
8888
|
+
/** The references, for {@link renderedLength}. */
|
|
8889
|
+
refs;
|
|
8776
8890
|
constructor(parts) {
|
|
8777
8891
|
this.parts = parts;
|
|
8892
|
+
const refs = [];
|
|
8893
|
+
for (const p of parts) if (typeof p === "string") this.literalLength += p.length;
|
|
8894
|
+
else if (p.kind === "prefix") this.literalLength += p.text.length;
|
|
8895
|
+
else refs.push(p);
|
|
8896
|
+
this.refs = refs;
|
|
8778
8897
|
const row = (r, abs) => {
|
|
8779
8898
|
if (abs) return;
|
|
8780
8899
|
if (r < this.minRow) this.minRow = r;
|
|
@@ -8805,6 +8924,15 @@ var Compiled = class {
|
|
|
8805
8924
|
if (this.minCol !== Infinity && (this.minCol + dCol < 1 || this.maxCol + dCol > 16384)) return false;
|
|
8806
8925
|
return true;
|
|
8807
8926
|
}
|
|
8927
|
+
renderedLength(dRow, dCol) {
|
|
8928
|
+
let length = this.literalLength;
|
|
8929
|
+
const col = (c, abs) => abs ? 1 + letters(c) : letters(c + dCol);
|
|
8930
|
+
const row = (r, abs) => abs ? 1 + digits(r) : digits(r + dRow);
|
|
8931
|
+
for (const p of this.refs) if (p.kind === "cell") length += col(p.col, p.colAbs) + row(p.row, p.rowAbs);
|
|
8932
|
+
else if (p.kind === "cols") length += col(p.c1, p.c1Abs) + 1 + col(p.c2, p.c2Abs);
|
|
8933
|
+
else length += row(p.r1, p.r1Abs) + 1 + row(p.r2, p.r2Abs);
|
|
8934
|
+
return length;
|
|
8935
|
+
}
|
|
8808
8936
|
render(dRow, dCol) {
|
|
8809
8937
|
let out = "";
|
|
8810
8938
|
const col = (c, abs) => (abs ? "$" : "") + columnLetters(abs ? c : c + dCol);
|
|
@@ -8943,7 +9071,7 @@ function parseWorksheet(xml, ctx) {
|
|
|
8943
9071
|
/** The cells of one row's style-only list (`[col, styleIndex, …]`), in column order. */
|
|
8944
9072
|
function styledCellsOf(row, list, make) {
|
|
8945
9073
|
const pairs = [];
|
|
8946
|
-
for (let i = 0; i + 1 < list.length; i += 2) pairs.push([list[i], list[i + 1]]);
|
|
9074
|
+
for (let i = 0; i + 1 < list.length; i += 2) if (list[i + 1] !== -1) pairs.push([list[i], list[i + 1]]);
|
|
8947
9075
|
pairs.sort((a, b) => a[0] - b[0]);
|
|
8948
9076
|
return pairs.map(([col, styleIndex]) => make(row, col, styleIndex));
|
|
8949
9077
|
}
|
|
@@ -8951,6 +9079,7 @@ function createWorksheetParser(ctx, onRow) {
|
|
|
8951
9079
|
const rows = /* @__PURE__ */ new Map();
|
|
8952
9080
|
const styleOnly = /* @__PURE__ */ new Map();
|
|
8953
9081
|
const styleOnlyMax = /* @__PURE__ */ new Map();
|
|
9082
|
+
const styleOnlyIndex = /* @__PURE__ */ new Map();
|
|
8954
9083
|
const merges = [];
|
|
8955
9084
|
const formats = ctx.formatCache;
|
|
8956
9085
|
const path = [];
|
|
@@ -8959,6 +9088,7 @@ function createWorksheetParser(ctx, onRow) {
|
|
|
8959
9088
|
let cellCount = 0;
|
|
8960
9089
|
const masters = /* @__PURE__ */ new Map();
|
|
8961
9090
|
const dependents = [];
|
|
9091
|
+
const compiled = /* @__PURE__ */ new Map();
|
|
8962
9092
|
const columns = [];
|
|
8963
9093
|
const rowInfo = /* @__PURE__ */ new Map();
|
|
8964
9094
|
let freeze = null;
|
|
@@ -9041,8 +9171,14 @@ function createWorksheetParser(ctx, onRow) {
|
|
|
9041
9171
|
if (max === void 0 || col > max) return -1;
|
|
9042
9172
|
const list = styleOnly.get(row);
|
|
9043
9173
|
if (list === void 0) return -1;
|
|
9044
|
-
|
|
9045
|
-
|
|
9174
|
+
if (list[list.length - 2] === col && list[list.length - 1] !== -1) return list.length - 2;
|
|
9175
|
+
let index = styleOnlyIndex.get(row);
|
|
9176
|
+
if (index === void 0) {
|
|
9177
|
+
index = /* @__PURE__ */ new Map();
|
|
9178
|
+
for (let i = 0; i + 1 < list.length; i += 2) if (list[i + 1] !== -1) index.set(list[i], i);
|
|
9179
|
+
styleOnlyIndex.set(row, index);
|
|
9180
|
+
}
|
|
9181
|
+
return index.get(col) ?? -1;
|
|
9046
9182
|
};
|
|
9047
9183
|
const styledCell = (row, col, styleIndex) => {
|
|
9048
9184
|
const code = numberFormat(styleIndex).code;
|
|
@@ -9223,13 +9359,16 @@ function createWorksheetParser(ctx, onRow) {
|
|
|
9223
9359
|
value: ctx.limits.maxCells
|
|
9224
9360
|
}
|
|
9225
9361
|
});
|
|
9362
|
+
styleOnlyIndex.get(p.row)?.set(p.col, styled.length);
|
|
9226
9363
|
styled.push(p.col, p.styleIndex);
|
|
9227
9364
|
if (p.col > (styleOnlyMax.get(p.row) ?? 0)) styleOnlyMax.set(p.row, p.col);
|
|
9228
9365
|
return;
|
|
9229
9366
|
}
|
|
9230
9367
|
const at = styledIndex(p.row, p.col);
|
|
9231
9368
|
if (at >= 0) {
|
|
9232
|
-
styleOnly.get(p.row)
|
|
9369
|
+
const list = styleOnly.get(p.row);
|
|
9370
|
+
if (list !== void 0) list[at + 1] = -1;
|
|
9371
|
+
styleOnlyIndex.get(p.row)?.delete(p.col);
|
|
9233
9372
|
ctx.budget.remaining++;
|
|
9234
9373
|
ctx.warnings.add("XLV_W_DUPLICATE_CELL", "The sheet defines the same cell more than once; the last definition is used.", loc(p.ref));
|
|
9235
9374
|
}
|
|
@@ -9263,6 +9402,18 @@ function createWorksheetParser(ctx, onRow) {
|
|
|
9263
9402
|
...richText === void 0 ? {} : { richText }
|
|
9264
9403
|
});
|
|
9265
9404
|
};
|
|
9405
|
+
const spendFormulaText = (chars, ref) => {
|
|
9406
|
+
ctx.budget.formulaText -= chars;
|
|
9407
|
+
if (ctx.budget.formulaText >= 0) return;
|
|
9408
|
+
throw new XlvError("XLV_E_LIMIT_EXCEEDED", "The cells that share formulas would hold more formula text than the limit allows.", {
|
|
9409
|
+
location: loc(ref),
|
|
9410
|
+
hint: `Small files can share one huge formula with many cells; the limit counts the formula of each cell that shares it. If you trust this file, raise the limit, for example { limits: { maxSharedStringChars: ${String(ctx.limits.maxSharedStringChars * 4)} } }.`,
|
|
9411
|
+
details: {
|
|
9412
|
+
limit: "maxSharedStringChars",
|
|
9413
|
+
value: ctx.limits.maxSharedStringChars
|
|
9414
|
+
}
|
|
9415
|
+
});
|
|
9416
|
+
};
|
|
9266
9417
|
const warnNotExpanded = (ref) => ctx.warnings.add("XLV_W_SHARED_FORMULA_NOT_EXPANDED", "Some cells reuse a shared formula that could not be moved to them (missing master, cell outside the master range, or formula text xlvane cannot translate safely); their formula.text is null and their cached values are available.", loc(ref));
|
|
9267
9418
|
/** Streaming: expands the pending shared formulas and hands the buffered cells on. */
|
|
9268
9419
|
const flushRows = () => {
|
|
@@ -9270,7 +9421,7 @@ function createWorksheetParser(ctx, onRow) {
|
|
|
9270
9421
|
const info = rowInfo.get(currentRow);
|
|
9271
9422
|
rowInfo.delete(currentRow);
|
|
9272
9423
|
if (rows.size === 0 && styleOnly.size === 0) return;
|
|
9273
|
-
expandSharedFormulas(rows, masters, dependents, warnNotExpanded);
|
|
9424
|
+
expandSharedFormulas(rows, masters, compiled, dependents, warnNotExpanded, spendFormulaText);
|
|
9274
9425
|
dependents.length = 0;
|
|
9275
9426
|
const out = [];
|
|
9276
9427
|
for (const r of [...rows.keys()].sort((a, b) => a - b)) {
|
|
@@ -9282,6 +9433,7 @@ function createWorksheetParser(ctx, onRow) {
|
|
|
9282
9433
|
for (const r of [...styleOnly.keys()].sort((a, b) => a - b)) styled.push(...styledCellsOf(r, styleOnly.get(r) ?? [], styledCell));
|
|
9283
9434
|
styleOnly.clear();
|
|
9284
9435
|
styleOnlyMax.clear();
|
|
9436
|
+
styleOnlyIndex.clear();
|
|
9285
9437
|
if (out.length > 0 || styled.length > 0) onRow(currentRow, out, info, styled);
|
|
9286
9438
|
};
|
|
9287
9439
|
const handler = {
|
|
@@ -9530,7 +9682,7 @@ function createWorksheetParser(ctx, onRow) {
|
|
|
9530
9682
|
};
|
|
9531
9683
|
const finish = () => {
|
|
9532
9684
|
if (onRow) flushRows();
|
|
9533
|
-
else expandSharedFormulas(rows, masters, dependents, warnNotExpanded);
|
|
9685
|
+
else expandSharedFormulas(rows, masters, compiled, dependents, warnNotExpanded, spendFormulaText);
|
|
9534
9686
|
const activeCell = selections.get(activePane);
|
|
9535
9687
|
if (activeCell !== void 0) view = Object.freeze({
|
|
9536
9688
|
...view,
|
|
@@ -9569,8 +9721,7 @@ function createWorksheetParser(ctx, onRow) {
|
|
|
9569
9721
|
* many cells costs memory only for the texts actually read. Dependents that cannot be expanded
|
|
9570
9722
|
* keep `text: null` and are reported through `warn`.
|
|
9571
9723
|
*/
|
|
9572
|
-
function expandSharedFormulas(rows, masters, dependents, warn) {
|
|
9573
|
-
const compiled = /* @__PURE__ */ new Map();
|
|
9724
|
+
function expandSharedFormulas(rows, masters, compiled, dependents, warn, spend) {
|
|
9574
9725
|
for (const d of dependents) {
|
|
9575
9726
|
const rowCells = rows.get(d.row);
|
|
9576
9727
|
const cell = rowCells?.get(d.col);
|
|
@@ -9592,6 +9743,7 @@ function expandSharedFormulas(rows, masters, dependents, warn) {
|
|
|
9592
9743
|
warn(d.ref);
|
|
9593
9744
|
continue;
|
|
9594
9745
|
}
|
|
9746
|
+
spend(formula.renderedLength(dRow, dCol), d.ref);
|
|
9595
9747
|
rowCells.set(d.col, {
|
|
9596
9748
|
...cell,
|
|
9597
9749
|
formula: lazySharedFormula(formula, dRow, dCol, d.si)
|
|
@@ -9910,6 +10062,7 @@ var NotLoaded = class extends Error {
|
|
|
9910
10062
|
this.end = end;
|
|
9911
10063
|
}
|
|
9912
10064
|
};
|
|
10065
|
+
const segmentEnd = (segment) => segment.start + segment.data.length;
|
|
9913
10066
|
/**
|
|
9914
10067
|
* Little-endian access to a file of `size` bytes, of which only some segments may be in memory
|
|
9915
10068
|
* (all of it for `openZip`; the tail, the central directory and local headers for streaming
|
|
@@ -9917,7 +10070,14 @@ var NotLoaded = class extends Error {
|
|
|
9917
10070
|
*/
|
|
9918
10071
|
var Bytes = class Bytes {
|
|
9919
10072
|
size;
|
|
10073
|
+
/** Loaded segments in order of `start` (equal starts in order of addition). */
|
|
9920
10074
|
segments = [];
|
|
10075
|
+
/**
|
|
10076
|
+
* For each index i, the segment with the largest end among segments[0..i]. A range is loaded
|
|
10077
|
+
* exactly when that segment, for the last i whose start is at or before the range's start,
|
|
10078
|
+
* reaches its end; so a lookup is one binary search (D-H01).
|
|
10079
|
+
*/
|
|
10080
|
+
reach = [];
|
|
9921
10081
|
last;
|
|
9922
10082
|
constructor(size, segments) {
|
|
9923
10083
|
this.size = size;
|
|
@@ -9934,35 +10094,40 @@ var Bytes = class Bytes {
|
|
|
9934
10094
|
start,
|
|
9935
10095
|
data
|
|
9936
10096
|
};
|
|
9937
|
-
this.
|
|
9938
|
-
this.segments.
|
|
10097
|
+
const at = this.upperBound(start);
|
|
10098
|
+
this.segments.splice(at, 0, segment);
|
|
10099
|
+
this.reach.splice(at, 0, segment);
|
|
10100
|
+
for (let i = at; i < this.segments.length; i++) {
|
|
10101
|
+
const own = this.segments[i];
|
|
10102
|
+
const before = i === 0 ? void 0 : this.reach[i - 1];
|
|
10103
|
+
this.reach[i] = before !== void 0 && segmentEnd(before) >= segmentEnd(own) ? before : own;
|
|
10104
|
+
}
|
|
9939
10105
|
this.last = segment;
|
|
9940
10106
|
}
|
|
9941
10107
|
/** Whether `[start, end)` is fully inside one loaded segment. */
|
|
9942
10108
|
has(start, end) {
|
|
9943
10109
|
return this.find(start, end) !== void 0;
|
|
9944
10110
|
}
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
-
if (last && start >= last.start && end <= last.start + last.data.length) return last;
|
|
10111
|
+
/** The number of segments whose start is at or before `start`. */
|
|
10112
|
+
upperBound(start) {
|
|
9948
10113
|
let lo = 0;
|
|
9949
|
-
let hi = this.segments.length
|
|
9950
|
-
|
|
9951
|
-
while (lo <= hi) {
|
|
10114
|
+
let hi = this.segments.length;
|
|
10115
|
+
while (lo < hi) {
|
|
9952
10116
|
const mid = lo + hi >> 1;
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
found = seg;
|
|
9956
|
-
lo = mid + 1;
|
|
9957
|
-
} else hi = mid - 1;
|
|
9958
|
-
}
|
|
9959
|
-
for (let i = found === void 0 ? -1 : this.segments.indexOf(found); i >= 0; i--) {
|
|
9960
|
-
const seg = this.segments[i];
|
|
9961
|
-
if (end <= seg.start + seg.data.length && start >= seg.start) {
|
|
9962
|
-
this.last = seg;
|
|
9963
|
-
return seg;
|
|
9964
|
-
}
|
|
10117
|
+
if (this.segments[mid].start <= start) lo = mid + 1;
|
|
10118
|
+
else hi = mid;
|
|
9965
10119
|
}
|
|
10120
|
+
return lo;
|
|
10121
|
+
}
|
|
10122
|
+
find(start, stop) {
|
|
10123
|
+
const last = this.last;
|
|
10124
|
+
if (last && start >= last.start && stop <= segmentEnd(last)) return last;
|
|
10125
|
+
const i = this.upperBound(start) - 1;
|
|
10126
|
+
if (i < 0) return void 0;
|
|
10127
|
+
const seg = this.reach[i];
|
|
10128
|
+
if (stop > segmentEnd(seg)) return void 0;
|
|
10129
|
+
this.last = seg;
|
|
10130
|
+
return seg;
|
|
9966
10131
|
}
|
|
9967
10132
|
/** The bytes `[start, end)`; throws {@link NotLoaded} if they are not in memory. */
|
|
9968
10133
|
slice(start, end) {
|
|
@@ -10501,7 +10666,8 @@ function readWorkbook(data, options) {
|
|
|
10501
10666
|
const book = analyzeWorkbook(pkg, limits, warnings);
|
|
10502
10667
|
const budget = {
|
|
10503
10668
|
remaining: limits.maxCells,
|
|
10504
|
-
sharedText: limits.maxSharedStringChars
|
|
10669
|
+
sharedText: limits.maxSharedStringChars,
|
|
10670
|
+
formulaText: limits.maxSharedStringChars
|
|
10505
10671
|
};
|
|
10506
10672
|
const formatCache = /* @__PURE__ */ new Map();
|
|
10507
10673
|
const media = /* @__PURE__ */ new Map();
|
|
@@ -10521,10 +10687,10 @@ function readWorkbook(data, options) {
|
|
|
10521
10687
|
formatCache
|
|
10522
10688
|
});
|
|
10523
10689
|
const links = data === null || entry.part === null ? [] : resolveHyperlinks(pkg, entry.part, entry.name, data, warnings);
|
|
10524
|
-
const notes = data === null || entry.part === null ? [] : readNotes(pkg, entry.part, entry.name, limits, warnings);
|
|
10690
|
+
const notes = data === null || entry.part === null ? [] : readNotes(pkg, entry.part, entry.name, limits, warnings, entry.foreignParts);
|
|
10525
10691
|
if (data !== null) attachNotes(data.rows, notes);
|
|
10526
10692
|
const sheet = new ReadSheet(entry.name, entry.index, entry.kind, entry.state, entry.part, data, entry.sheetId, links, notes, book.definedNames);
|
|
10527
|
-
if (data !== null && entry.part !== null) sheet.tables = readTables(pkg, entry.part, entry.name, limits, warnings);
|
|
10693
|
+
if (data !== null && entry.part !== null) sheet.tables = readTables(pkg, entry.part, entry.name, limits, warnings, entry.foreignParts);
|
|
10528
10694
|
if (data !== null && entry.part !== null) {
|
|
10529
10695
|
const drawing = readSheetDrawing(pkg, entry.part, entry.name, {
|
|
10530
10696
|
drawing: data.drawingRelId ?? null,
|
|
@@ -10578,29 +10744,55 @@ function resolveHyperlinks(pkg, part, sheet, data, warnings) {
|
|
|
10578
10744
|
part,
|
|
10579
10745
|
sheet
|
|
10580
10746
|
});
|
|
10747
|
+
let total = 0;
|
|
10748
|
+
for (const cells of data.rows.values()) total += cells.size;
|
|
10749
|
+
let linked = 0;
|
|
10750
|
+
let visits = 0;
|
|
10751
|
+
const maxVisits = 16 * total + 1e6;
|
|
10581
10752
|
for (const link of links) {
|
|
10753
|
+
if (linked === total) break;
|
|
10754
|
+
if (visits > maxVisits) {
|
|
10755
|
+
warnings.add("XLV_W_LIMIT_REACHED", `The sheet's hyperlinks cover far more positions than it has cells; cell.hyperlink is not set for the cells of some links. sheet.hyperlinks lists every link.`, {
|
|
10756
|
+
part,
|
|
10757
|
+
sheet
|
|
10758
|
+
});
|
|
10759
|
+
break;
|
|
10760
|
+
}
|
|
10582
10761
|
const range = parseRange(link.ref);
|
|
10583
10762
|
if (range === null) continue;
|
|
10584
10763
|
const rowSpan = range.end.row - range.start.row + 1;
|
|
10585
10764
|
const colSpan = range.end.col - range.start.col + 1;
|
|
10586
10765
|
const visit = (cells) => {
|
|
10587
10766
|
const mark = (c, cell) => {
|
|
10588
|
-
if (cell.hyperlink === void 0)
|
|
10589
|
-
|
|
10590
|
-
|
|
10591
|
-
|
|
10767
|
+
if (cell.hyperlink === void 0) {
|
|
10768
|
+
cells.set(c, {
|
|
10769
|
+
...cell,
|
|
10770
|
+
hyperlink: link
|
|
10771
|
+
});
|
|
10772
|
+
linked++;
|
|
10773
|
+
}
|
|
10592
10774
|
};
|
|
10593
|
-
if (colSpan <= cells.size)
|
|
10594
|
-
|
|
10595
|
-
|
|
10775
|
+
if (colSpan <= cells.size) {
|
|
10776
|
+
visits += colSpan;
|
|
10777
|
+
for (let c = range.start.col; c <= range.end.col; c++) {
|
|
10778
|
+
const cell = cells.get(c);
|
|
10779
|
+
if (cell) mark(c, cell);
|
|
10780
|
+
}
|
|
10781
|
+
} else {
|
|
10782
|
+
visits += cells.size;
|
|
10783
|
+
for (const [c, cell] of cells) if (c >= range.start.col && c <= range.end.col) mark(c, cell);
|
|
10596
10784
|
}
|
|
10597
|
-
else for (const [c, cell] of cells) if (c >= range.start.col && c <= range.end.col) mark(c, cell);
|
|
10598
10785
|
};
|
|
10599
|
-
if (rowSpan <= data.rows.size)
|
|
10600
|
-
|
|
10601
|
-
|
|
10786
|
+
if (rowSpan <= data.rows.size) {
|
|
10787
|
+
visits += rowSpan;
|
|
10788
|
+
for (let r = range.start.row; r <= range.end.row; r++) {
|
|
10789
|
+
const cells = data.rows.get(r);
|
|
10790
|
+
if (cells) visit(cells);
|
|
10791
|
+
}
|
|
10792
|
+
} else {
|
|
10793
|
+
visits += data.rows.size;
|
|
10794
|
+
for (const [r, cells] of data.rows) if (r >= range.start.row && r <= range.end.row) visit(cells);
|
|
10602
10795
|
}
|
|
10603
|
-
else for (const [r, cells] of data.rows) if (r >= range.start.row && r <= range.end.row) visit(cells);
|
|
10604
10796
|
}
|
|
10605
10797
|
return links;
|
|
10606
10798
|
}
|
|
@@ -10610,8 +10802,8 @@ function resolveHyperlinks(pkg, part, sheet, data, warnings) {
|
|
|
10610
10802
|
* ([MS-XLSX] §2.3.7) are reported with `XLV_W_THREADED_COMMENTS`; their legacy placeholders are
|
|
10611
10803
|
* ordinary notes.
|
|
10612
10804
|
*/
|
|
10613
|
-
function readNotes(pkg, part, sheet, limits, warnings) {
|
|
10614
|
-
const rels = pkg.relationships(part);
|
|
10805
|
+
function readNotes(pkg, part, sheet, limits, warnings, foreign = NO_PARTS) {
|
|
10806
|
+
const rels = pkg.relationships(part).filter((r) => r.external || !foreign.has(partKey(r.target)));
|
|
10615
10807
|
if (rels.some((r) => r.type === "http://schemas.microsoft.com/office/2017/10/relationships/threadedComment")) warnings.add("XLV_W_THREADED_COMMENTS", "The sheet has threaded comments (conversations); xlvane reads only the notes stored with them, whose author is \"tc={id}\" and whose text may not include the replies.", {
|
|
10616
10808
|
part,
|
|
10617
10809
|
sheet
|
|
@@ -10633,8 +10825,12 @@ function readNotes(pkg, part, sheet, limits, warnings) {
|
|
|
10633
10825
|
warnings
|
|
10634
10826
|
});
|
|
10635
10827
|
if (notes.length === 0) return notes;
|
|
10828
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10636
10829
|
for (const vml of rels) {
|
|
10637
10830
|
if (vml.external || classifyRelationship(vml.type)?.name !== "vmlDrawing") continue;
|
|
10831
|
+
const key = partKey(vml.target);
|
|
10832
|
+
if (seen.has(key)) continue;
|
|
10833
|
+
seen.add(key);
|
|
10638
10834
|
const text = pkg.readXml(vml.target);
|
|
10639
10835
|
if (text === void 0) continue;
|
|
10640
10836
|
const boxes = parseNoteBoxes(text, {
|
|
@@ -10659,10 +10855,14 @@ function readNotes(pkg, part, sheet, limits, warnings) {
|
|
|
10659
10855
|
* relationships (Part 1 §12.3.21, §18.3.1.94; TD-01), in relationship order. A missing or
|
|
10660
10856
|
* invalid part gives a warning, never an error.
|
|
10661
10857
|
*/
|
|
10662
|
-
function readTables(pkg, part, sheet, limits, warnings) {
|
|
10858
|
+
function readTables(pkg, part, sheet, limits, warnings, foreign = NO_PARTS) {
|
|
10663
10859
|
const tables = [];
|
|
10860
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10664
10861
|
for (const rel of pkg.relationships(part)) {
|
|
10665
10862
|
if (rel.external || classifyRelationship(rel.type)?.name !== "table") continue;
|
|
10863
|
+
const key = partKey(rel.target);
|
|
10864
|
+
if (seen.has(key) || foreign.has(key)) continue;
|
|
10865
|
+
seen.add(key);
|
|
10666
10866
|
if (tables.length >= 4096) {
|
|
10667
10867
|
warnings.add("XLV_W_INVALID_VALUE", `The sheet has more than ${String(MAX_TABLES_PER_SHEET)} tables; the rest are not read.`, {
|
|
10668
10868
|
part,
|
|
@@ -10701,6 +10901,13 @@ function attachNotes(rows, notes) {
|
|
|
10701
10901
|
});
|
|
10702
10902
|
}
|
|
10703
10903
|
}
|
|
10904
|
+
const NO_PARTS = /* @__PURE__ */ new Set();
|
|
10905
|
+
/** Relationship types whose parts are read per sheet, besides the worksheet itself. */
|
|
10906
|
+
const SHEET_RELATED = /* @__PURE__ */ new Set([
|
|
10907
|
+
"comments",
|
|
10908
|
+
"vmlDrawing",
|
|
10909
|
+
"table"
|
|
10910
|
+
]);
|
|
10704
10911
|
/** The Core Properties relationship of the package, if any (D-A02). */
|
|
10705
10912
|
function corePropertiesRel(pkg) {
|
|
10706
10913
|
return pkg.relationships(null).find((r) => !r.external && isCorePropertiesRel(r.type));
|
|
@@ -10774,6 +10981,7 @@ function analyzeWorkbook(pkg, limits, warnings) {
|
|
|
10774
10981
|
const externalLinkCount = rels.filter((r) => classifyRelationship(r.type)?.name === "externalLink").length;
|
|
10775
10982
|
if (externalLinkCount > 0) warnings.add("XLV_W_EXTERNAL_LINKS", `The workbook links to ${externalLinkCount} external workbook(s). xlvane never follows the links; linked values are the cached copies.`, { part: workbookPart });
|
|
10776
10983
|
const dateSystem = info.date1904 ? "1904" : "1900";
|
|
10984
|
+
const owners = /* @__PURE__ */ new Map();
|
|
10777
10985
|
const sheets = info.sheets.map((entry, index) => {
|
|
10778
10986
|
if (entry.state === "veryHidden") warnings.add("XLV_W_VERY_HIDDEN_SHEET", `Sheet "${entry.name}" is very hidden: spreadsheet applications do not offer a way to unhide it.`, { sheet: entry.name });
|
|
10779
10987
|
const rel = entry.relId === null ? void 0 : relsById.get(entry.relId);
|
|
@@ -10790,16 +10998,49 @@ function analyzeWorkbook(pkg, limits, warnings) {
|
|
|
10790
10998
|
sheetId: entry.sheetId,
|
|
10791
10999
|
kind,
|
|
10792
11000
|
state: entry.state,
|
|
10793
|
-
part: null
|
|
11001
|
+
part: null,
|
|
11002
|
+
foreignParts: NO_PARTS
|
|
11003
|
+
};
|
|
11004
|
+
}
|
|
11005
|
+
const owner = owners.get(partKey(rel.target));
|
|
11006
|
+
if (owner !== void 0) {
|
|
11007
|
+
warnings.add("XLV_W_SHEET_PART_SHARED", `Sheet "${entry.name}" has the same part as sheet "${owner}"; the part is read for "${owner}" only, and "${entry.name}" is returned without cells.`, {
|
|
11008
|
+
sheet: entry.name,
|
|
11009
|
+
part: rel.target
|
|
11010
|
+
});
|
|
11011
|
+
return {
|
|
11012
|
+
name: entry.name,
|
|
11013
|
+
index,
|
|
11014
|
+
sheetId: entry.sheetId,
|
|
11015
|
+
kind,
|
|
11016
|
+
state: entry.state,
|
|
11017
|
+
part: null,
|
|
11018
|
+
foreignParts: NO_PARTS
|
|
10794
11019
|
};
|
|
10795
11020
|
}
|
|
11021
|
+
owners.set(partKey(rel.target), entry.name);
|
|
11022
|
+
const foreign = /* @__PURE__ */ new Set();
|
|
11023
|
+
for (const r of pkg.relationships(rel.target)) {
|
|
11024
|
+
if (r.external || !SHEET_RELATED.has(classifyRelationship(r.type)?.name ?? "")) continue;
|
|
11025
|
+
const key = partKey(r.target);
|
|
11026
|
+
const first = owners.get(key);
|
|
11027
|
+
if (first === void 0) owners.set(key, entry.name);
|
|
11028
|
+
else if (first !== entry.name && !foreign.has(key)) {
|
|
11029
|
+
foreign.add(key);
|
|
11030
|
+
warnings.add("XLV_W_SHEET_PART_SHARED", `Sheet "${entry.name}" relates to the part ${r.target}, which belongs to sheet "${first}"; it is read for "${first}" only.`, {
|
|
11031
|
+
sheet: entry.name,
|
|
11032
|
+
part: r.target
|
|
11033
|
+
});
|
|
11034
|
+
}
|
|
11035
|
+
}
|
|
10796
11036
|
return {
|
|
10797
11037
|
name: entry.name,
|
|
10798
11038
|
index,
|
|
10799
11039
|
sheetId: entry.sheetId,
|
|
10800
11040
|
kind,
|
|
10801
11041
|
state: entry.state,
|
|
10802
|
-
part: rel.target
|
|
11042
|
+
part: rel.target,
|
|
11043
|
+
foreignParts: foreign
|
|
10803
11044
|
};
|
|
10804
11045
|
});
|
|
10805
11046
|
const definedNames = info.definedNames.map((n) => {
|
|
@@ -13076,4 +13317,4 @@ function openInput(input, limits, onWarning) {
|
|
|
13076
13317
|
if (onWarning !== void 0) for (const warning of workbook.warnings) onWarning(warning);
|
|
13077
13318
|
return workbook;
|
|
13078
13319
|
}
|
|
13079
|
-
export { fillXml as $,
|
|
13320
|
+
export { fillXml as $, metricsOf as $t, limitExceeded as A, EMPTY_STYLES as At, tokenize as B, resolveLimits as Bt, Bytes as C, encodeXstring as Cn, relationshipsPartName as Ct, TAIL_BYTES as D, WARNING_CODES as Dn, normalizeTable as Dt, NotLoaded as E, ERROR_CODES as En, TABLE_CONTENT_TYPE as Et, validateLocalHeaders as F, normalizeStyle as Ft, DEFAULT_FONT as G, hashPassword as Gt, X14_DV_URI as H, printNames as Ht, WarningCollector as I, stableKey as It, borderXml as J, DRAWING_CONTENT_TYPE as Jt, SheetRels as K, legacyPasswordHash as Kt, sheetNotFound as L, isDateFormat as Lt, openZip as M, READING_ORDERS as Mt, readCentralDirectory as N, checkStyleCount as Nt, checkSource as O, XlvError as On, checkDefinedName as Ot, unsupported as P, mergeStyles as Pt, createSharedStrings as Q, imageFormat as Qt, createWorksheetParser as R, DEFAULT_READ_LIMITS as Rt, workbookPartsToLoad as S, parseXml as Sn, openPackage as St, HEAD_BYTES as T, escapeText as Tn, zipNameToPartName as Tt, X14_NS as U, printXml as Ut, X14_CF_URI as V, suggest as Vt, XM_NS as W, sheetProtectionXml as Wt, cellXml as X, MediaParts as Xt, buildStyles as Y, IMAGE_CONTENT_TYPES as Yt, contentTypesXml as Z, drawingParts as Zt, isoDate as _, childrenNamed as _n, FormulaGroups as _t, DATE_FORMAT as a, MAX_COLUMNS as an, reusableBuiltinNumFmt as at, readWorkbook as b, decodeXml as bn, parseIsoDateTime as bt, NewSheet as c, formatCellRef as cn, sheetHead as ct, convertCellInput as d, parseRange as dn, sheetTail as dt, resolveImage as en, fontXml as et, createWorkbook as f, APP_PROPERTIES_PART as fn, stringItemXml as ft, inspect as g, childNamed as gn, workbookXml as gt, detectHeader as h, corePropertiesXml as hn, workbookRelsXml as ht, readOptions as i, relationshipTypes as in, noteParts as it, locateCentralDirectory as j, parseStyles as jt, corrupt as k, isXlvError as kn, checkUniqueName as kt, NewWorkbook as l, formatRange as ln, sheetRelsPartName as lt, writeWorkbook as m, appPropertiesXml as mn, textElement as mt, oneOfOption as n, SML_NS as nn, hyperlinksXml as nt, DATE_TIME_FORMAT as o, MAX_ROWS as on, rootRelsXml as ot, sortedNotes as p, CORE_PROPERTIES_PART as pn, tableParts as pt, attr as q, verifyPassword as qt, openInput as r, classifyRelationship as rn, nameTitles as rt, ERROR_VALUES as s, columnLetters as sn, rowStart as st, booleanOption as t, REL_NS as tn, formatNumber as tt, checkBookViews as u, parseCellRef as un, sheetRulesXml as ut, analyzeWorkbook as v, parseXmlTree as vn, writeZip as vt, CORRUPT_HINT as w, escapeAttr as wn, partKey as wt, toBytes as x, normalizeLineEnds as xn, parseSharedStrings as xt, readNotes as y, createXmlByteStreamParser as yn, crc32 as yt, shiftFormula as z, checkOutputPositions as zt };
|