reamkit 1.32.0 → 1.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/core/crypto/offcrypto.js +56 -12
- package/dist/esm/core/drawingml/chart-geometry.d.ts +21 -11
- package/dist/esm/core/drawingml/chart-geometry.js +205 -69
- package/dist/esm/core/drawingml/chart-parser.d.ts +19 -0
- package/dist/esm/core/drawingml/chart-parser.js +60 -23
- package/dist/esm/core/number-format.d.ts +40 -15
- package/dist/esm/core/number-format.js +280 -73
- package/dist/esm/core/opc/tag-scan.d.ts +15 -0
- package/dist/esm/core/opc/tag-scan.js +41 -0
- package/dist/esm/core/opc/xml-entities.js +39 -2
- package/dist/esm/excel/formula/functions.js +37 -14
- package/dist/esm/excel/print-model.js +14 -3
- package/dist/esm/excel/vml-drawing.js +1 -1
- package/dist/esm/excel/xlsx-reader.js +39 -5
- package/dist/esm/layout/styled-layout.js +1 -1
- package/dist/esm/markdown/markdown-writer.js +58 -7
- package/dist/esm/pdf-reader/annot-draw.js +2 -2
- package/dist/esm/pdf-reader/annots.js +3 -1
- package/dist/esm/pdf-reader/font.js +1 -1
- package/dist/esm/pdf-reader/layout.js +1 -1
- package/dist/esm/word/document-parser.js +1 -1
- package/dist/esm/word/docx-reader.js +13 -8
- package/dist/esm/word/docx-to-pdf.js +3 -3
- package/dist/esm/word/font-table.js +89 -10
- package/dist/esm/word/numbering-parser.js +1 -1
- package/package.json +3 -3
|
@@ -25,6 +25,27 @@ var TYPE_OF_TAG = {
|
|
|
25
25
|
"c:scatterChart": "scatter"
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
28
|
+
* The most points a chart keeps, all its series together: as many as a sheet
|
|
29
|
+
* has rows, the longest range a series can name. A chart part states its own
|
|
30
|
+
* point counts — a cache's `c:ptCount`, each point's `idx`, the range of a
|
|
31
|
+
* `c:f` — and taken at their word, a count of two billion in a part a few
|
|
32
|
+
* hundred bytes long asked for a dense array that ran the process out of
|
|
33
|
+
* memory, and one past 2³² − 1 threw.
|
|
34
|
+
*/
|
|
35
|
+
var MOST_CHART_POINTS = 1048576;
|
|
36
|
+
/**
|
|
37
|
+
* How many points each of a chart's `seriesCount` series keeps: an even share
|
|
38
|
+
* of {@link MOST_CHART_POINTS}, so that the bound holds for the chart and not
|
|
39
|
+
* series by series — two thousand series, each declaring a sheet's worth of
|
|
40
|
+
* points, are two billion. A series' points past its share are not read.
|
|
41
|
+
*
|
|
42
|
+
* @param seriesCount How many series the chart has.
|
|
43
|
+
* @returns The points each keeps, at least one.
|
|
44
|
+
*/
|
|
45
|
+
function pointsPerSeries(seriesCount) {
|
|
46
|
+
return Math.max(1, Math.floor(MOST_CHART_POINTS / Math.max(1, seriesCount)));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
28
49
|
* Parse a DrawingML chart part (chart1.xml) into a {@link Chart}, reading the
|
|
29
50
|
* CACHED data (`c:numCache` / `c:strCache`) rather than the embedded spreadsheet
|
|
30
51
|
* — the cache holds the last-computed categories and values, exactly what Word
|
|
@@ -48,6 +69,7 @@ function parseChart(chartXml, resolveColor, resolveImage) {
|
|
|
48
69
|
const type = group ? TYPE_OF_TAG[poTag(group)] ?? "unknown" : "unknown";
|
|
49
70
|
const groupAxIds = (g) => poChildren(g).filter((c) => poIs(c, "c:axId")).map((c) => poAttr(c, "val") ?? "");
|
|
50
71
|
const primaryAxIds = new Set(group ? groupAxIds(group) : []);
|
|
72
|
+
const most = pointsPerSeries(groups.reduce((n, g) => n + poChildren(g).filter((c) => poIs(c, "c:ser")).length, 0));
|
|
51
73
|
const serNodes = [];
|
|
52
74
|
const series = [];
|
|
53
75
|
let secondaryValAxId;
|
|
@@ -58,7 +80,7 @@ function parseChart(chartXml, resolveColor, resolveImage) {
|
|
|
58
80
|
for (const s of poChildren(g).filter((c) => poIs(c, "c:ser"))) {
|
|
59
81
|
serNodes.push(s);
|
|
60
82
|
series.push({
|
|
61
|
-
...parseSeries(s, resolveColor),
|
|
83
|
+
...parseSeries(s, resolveColor, most),
|
|
62
84
|
...groupType === type ? {} : { type: groupType },
|
|
63
85
|
...secondary ? { secondaryAxis: true } : {}
|
|
64
86
|
});
|
|
@@ -75,8 +97,8 @@ function parseChart(chartXml, resolveColor, resolveImage) {
|
|
|
75
97
|
for (const s of serNodes) {
|
|
76
98
|
const cat = poChildren(s).find((c) => poIs(c, "c:cat"));
|
|
77
99
|
if (cat) {
|
|
78
|
-
const levels = multiLevelCategories(cat);
|
|
79
|
-
categories = levels ? levels.categories : denseStrings(cat);
|
|
100
|
+
const levels = multiLevelCategories(cat, most);
|
|
101
|
+
categories = levels ? levels.categories : denseStrings(cat, most);
|
|
80
102
|
categoryGroups = levels?.groups;
|
|
81
103
|
categoriesRef ??= refFormula(cat);
|
|
82
104
|
break;
|
|
@@ -165,11 +187,11 @@ function parseChart(chartXml, resolveColor, resolveImage) {
|
|
|
165
187
|
...numberFormat ? { numberFormat } : {}
|
|
166
188
|
};
|
|
167
189
|
}
|
|
168
|
-
function parseSeries(ser, resolveColor) {
|
|
190
|
+
function parseSeries(ser, resolveColor, most) {
|
|
169
191
|
const valNode = poChildren(ser).find((c) => poIs(c, "c:val")) ?? poChildren(ser).find((c) => poIs(c, "c:yVal"));
|
|
170
|
-
const values = valNode ? denseNumbers(valNode) : [];
|
|
192
|
+
const values = valNode ? denseNumbers(valNode, most) : [];
|
|
171
193
|
const xValNode = poChildren(ser).find((c) => poIs(c, "c:xVal"));
|
|
172
|
-
const xValues = xValNode ? denseNumbers(xValNode) : void 0;
|
|
194
|
+
const xValues = xValNode ? denseNumbers(xValNode, most) : void 0;
|
|
173
195
|
const name = seriesName(ser);
|
|
174
196
|
const colorHex = fillColorOf(poChildren(ser).find((c) => poIs(c, "c:spPr")), resolveColor);
|
|
175
197
|
const pointColors = dataPointColors(ser, resolveColor);
|
|
@@ -375,7 +397,7 @@ function cachedTitleText(title) {
|
|
|
375
397
|
const tx = poChildren(title).find((c) => poIs(c, "c:tx"));
|
|
376
398
|
const ref = tx ? poChildren(tx).find((c) => poIs(c, "c:strRef")) : void 0;
|
|
377
399
|
if (!ref) return void 0;
|
|
378
|
-
const cached = denseStrings(ref).filter((t) => t.length > 0);
|
|
400
|
+
const cached = denseStrings(ref, MOST_CHART_POINTS).filter((t) => t.length > 0);
|
|
379
401
|
return cached.length > 0 ? cached.join(" ") : void 0;
|
|
380
402
|
}
|
|
381
403
|
function axisTitle(plotArea, axTag) {
|
|
@@ -509,24 +531,36 @@ function ptCountOf(container) {
|
|
|
509
531
|
const pc = cache ? poChildren(cache).find((c) => poIs(c, "c:ptCount")) : void 0;
|
|
510
532
|
return pc ? poIntAttr(pc, "val") ?? 0 : 0;
|
|
511
533
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
534
|
+
/** Whether `n` can index a point: a whole number from zero. */
|
|
535
|
+
var isPointIndex = (n) => Number.isInteger(n) && n >= 0;
|
|
536
|
+
/**
|
|
537
|
+
* How many slots `count` points and those at `indexes` take — the count, or
|
|
538
|
+
* past it the last of them, and never more than `most`. A count or an index
|
|
539
|
+
* that is no whole number (2.5) asked for an array of no possible length and
|
|
540
|
+
* threw; it counts for nothing.
|
|
541
|
+
*/
|
|
542
|
+
function denseLength(count, indexes, most) {
|
|
543
|
+
let length = isPointIndex(count) ? count : 0;
|
|
544
|
+
for (const idx of indexes) if (isPointIndex(idx)) length = Math.max(length, idx + 1);
|
|
545
|
+
return Math.min(length, most);
|
|
516
546
|
}
|
|
517
|
-
|
|
547
|
+
/** A cache's values by point index, gaps 0, at most `most` of them. */
|
|
548
|
+
function denseNumbers(container, most) {
|
|
518
549
|
const pts = readPts(container);
|
|
519
|
-
const
|
|
550
|
+
const length = denseLength(ptCountOf(container), pts.map((p) => p.idx), most);
|
|
551
|
+
const arr = new Array(length).fill(0);
|
|
520
552
|
for (const p of pts) {
|
|
521
553
|
const n = Number(p.v);
|
|
522
|
-
if (Number.isFinite(n)) arr[p.idx] = n;
|
|
554
|
+
if (Number.isFinite(n) && isPointIndex(p.idx) && p.idx < length) arr[p.idx] = n;
|
|
523
555
|
}
|
|
524
556
|
return arr;
|
|
525
557
|
}
|
|
526
|
-
|
|
558
|
+
/** A cache's texts by point index, gaps empty, at most `most` of them. */
|
|
559
|
+
function denseStrings(container, most) {
|
|
527
560
|
const pts = readPts(container);
|
|
528
|
-
const
|
|
529
|
-
|
|
561
|
+
const length = denseLength(ptCountOf(container), pts.map((p) => p.idx), most);
|
|
562
|
+
const arr = new Array(length).fill("");
|
|
563
|
+
for (const p of pts) if (isPointIndex(p.idx) && p.idx < length) arr[p.idx] = p.v;
|
|
530
564
|
return arr;
|
|
531
565
|
}
|
|
532
566
|
/**
|
|
@@ -537,11 +571,12 @@ function denseStrings(container) {
|
|
|
537
571
|
* names, both columns of them in turn: WithChartSheet.xlsx's six bars stood in
|
|
538
572
|
* the first six of sixteen slots under a jumble of years and measure names.
|
|
539
573
|
*
|
|
540
|
-
* @param cat
|
|
574
|
+
* @param cat The `c:cat` element.
|
|
575
|
+
* @param most The most categories it keeps (see {@link pointsPerSeries}).
|
|
541
576
|
* @returns The innermost labels and the outer levels' groups, or undefined
|
|
542
577
|
* for a category axis of one level.
|
|
543
578
|
*/
|
|
544
|
-
function multiLevelCategories(cat) {
|
|
579
|
+
function multiLevelCategories(cat, most) {
|
|
545
580
|
const cache = poFindDescendant(cat, "c:multiLvlStrCache");
|
|
546
581
|
if (!cache) return void 0;
|
|
547
582
|
const count = poIntAttr(poChildren(cache).find((c) => poIs(c, "c:ptCount")) ?? cache, "val") ?? 0;
|
|
@@ -553,11 +588,13 @@ function multiLevelCategories(cat) {
|
|
|
553
588
|
};
|
|
554
589
|
}));
|
|
555
590
|
if (!inner) return void 0;
|
|
556
|
-
const
|
|
557
|
-
|
|
591
|
+
const length = denseLength(count, inner.map((p) => p.start), most);
|
|
592
|
+
const categories = new Array(length).fill("");
|
|
593
|
+
const kept = (p) => isPointIndex(p.start) && p.start < length;
|
|
594
|
+
for (const p of inner) if (kept(p)) categories[p.start] = p.label;
|
|
558
595
|
return {
|
|
559
596
|
categories,
|
|
560
|
-
groups: outer.map((level) =>
|
|
597
|
+
groups: outer.map((level) => level.filter(kept).sort((a, b) => a.start - b.start))
|
|
561
598
|
};
|
|
562
599
|
}
|
|
563
600
|
function isLegendPos(v) {
|
|
@@ -636,4 +673,4 @@ var SCATTER_STYLES = new Set([
|
|
|
636
673
|
]);
|
|
637
674
|
var REL_CHART_COLOR_STYLE = "http://schemas.microsoft.com/office/2011/relationships/chartColorStyle";
|
|
638
675
|
//#endregion
|
|
639
|
-
export { parseChart, withChartColorStyle };
|
|
676
|
+
export { parseChart, pointsPerSeries, withChartColorStyle };
|
|
@@ -50,25 +50,50 @@ export declare function excelSerialToDate(serial: number, date1904: boolean): Da
|
|
|
50
50
|
*/
|
|
51
51
|
export declare function excelSerialFromUtcParts(year: number, month0: number, day: number, date1904: boolean): number;
|
|
52
52
|
/**
|
|
53
|
-
* A General number
|
|
53
|
+
* A General number in its column: the most precise of the ways General may
|
|
54
|
+
* write it ({@link generalRenderings}) that `fits`.
|
|
54
55
|
*
|
|
55
|
-
* General is not a fixed format: a spreadsheet shows as many
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
56
|
+
* General is not a fixed format: a spreadsheet shows as many places as the
|
|
57
|
+
* column has room for and ROUNDS to that, so 4.3900875881221957 in a column
|
|
58
|
+
* eight characters wide reads 4.390088. We rendered every stored digit and let
|
|
59
|
+
* the cell clip it, which turns the same value into 4.390087 — off by one in
|
|
60
|
+
* the last place shown, with nothing to say a digit was cut. A number too wide
|
|
61
|
+
* for every way of writing it comes back in its finest, and the cell fills
|
|
62
|
+
* with `#` (CellProperties.hashOnOverflow); one under 1 always fits as `0` or
|
|
63
|
+
* `-0`, which is what Excel prints in a column too narrow for anything else.
|
|
60
64
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* than count characters against the column's width in the document's unit.
|
|
66
|
-
* Counted that way we produced nine digits for a column that holds nine of
|
|
67
|
-
* Excel's and eight of ours, and the layout clipped the ninth — the very
|
|
68
|
-
* truncation this exists to prevent. Fewer digits than the reference shows is a
|
|
69
|
-
* coarser number; a clipped one is a different number.
|
|
65
|
+
* `fits` decides whether a rendering has room. The print model asks it in the
|
|
66
|
+
* document's own terms — the column's width less the padding it carries, in
|
|
67
|
+
* the font's widest digits — because that is the room Excel gives up places
|
|
68
|
+
* against, whatever face the page is drawn in.
|
|
70
69
|
*
|
|
71
70
|
* @param rawValue The cell's stored value.
|
|
72
71
|
* @param fits Whether a rendering will fit the cell.
|
|
73
72
|
*/
|
|
74
73
|
export declare function generalToWidth(rawValue: string, fits: (text: string) => boolean): string;
|
|
74
|
+
/**
|
|
75
|
+
* Every way General may write `value` in `chars` characters, the most precise
|
|
76
|
+
* first. One rule, measured in Excel's own PDF on chart axes, which give it
|
|
77
|
+
* nine characters with the sign among them, and in cells, eleven with the
|
|
78
|
+
* sign apart (2026-10-01/02):
|
|
79
|
+
*
|
|
80
|
+
* - the number as it is, its first 15 significant digits, where that fits:
|
|
81
|
+
* 0.000012345, 0.0000003, 12345678901;
|
|
82
|
+
* - else rounded to fewer places or written in scientific notation, whichever
|
|
83
|
+
* keeps the finer last digit — 0.123456789, not 1.23457E-01; 1.23457E-10,
|
|
84
|
+
* not 0; 4E-04, not 0, in a column five characters wide — and of two as
|
|
85
|
+
* fine, the plain one down to 0.0001 and the scientific one below it: 0.0001
|
|
86
|
+
* for 0.000123456 but 1E-05 for 1.00049E-05;
|
|
87
|
+
* - a whole part longer than the room only in scientific notation, and never
|
|
88
|
+
* with the zeros a mantissa or a fraction ends in: 1E+10, 2.5E+12.
|
|
89
|
+
*
|
|
90
|
+
* The digits are the 15 of {@link decimalOf}, rounded half away from zero, so
|
|
91
|
+
* 1.2345E-05 is 1.235E-05, where `toExponential` rounded the binary double
|
|
92
|
+
* down to 1.234E-05.
|
|
93
|
+
*
|
|
94
|
+
* @param value The number.
|
|
95
|
+
* @param chars How many characters General has.
|
|
96
|
+
* @param signCounts Whether a minus sign takes one of them.
|
|
97
|
+
* @returns The renderings, sign included, finest first.
|
|
98
|
+
*/
|
|
99
|
+
export declare function generalRenderings(value: number, chars: number, signCounts?: boolean): Generator<string, void, undefined>;
|