@reportwright/viewer 0.0.0-stage → 0.12.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/CHANGELOG.md +233 -0
- package/LICENSE +23 -0
- package/README.md +146 -2
- package/dist/chunk-2NAW3MAP.js +1284 -0
- package/dist/chunk-2NAW3MAP.js.map +6 -0
- package/dist/chunk-3D43XGIN.js +1167 -0
- package/dist/chunk-3D43XGIN.js.map +6 -0
- package/dist/chunk-5N6OFCHJ.js +1667 -0
- package/dist/chunk-5N6OFCHJ.js.map +6 -0
- package/dist/chunk-72S6DETS.js +40 -0
- package/dist/chunk-72S6DETS.js.map +6 -0
- package/dist/chunk-AH47FS6Y.js +13 -0
- package/dist/chunk-AH47FS6Y.js.map +6 -0
- package/dist/chunk-APRPSQOD.js +301 -0
- package/dist/chunk-APRPSQOD.js.map +6 -0
- package/dist/chunk-BXKUE45K.js +1284 -0
- package/dist/chunk-BXKUE45K.js.map +6 -0
- package/dist/chunk-D2NTLAKL.js +14 -0
- package/dist/chunk-D2NTLAKL.js.map +6 -0
- package/dist/chunk-E7INJHTL.js +1284 -0
- package/dist/chunk-E7INJHTL.js.map +6 -0
- package/dist/chunk-EOVGKHAS.js +20682 -0
- package/dist/chunk-EOVGKHAS.js.map +6 -0
- package/dist/chunk-FARG6X2U.js +153 -0
- package/dist/chunk-FARG6X2U.js.map +6 -0
- package/dist/chunk-FGEFSGJT.js +1284 -0
- package/dist/chunk-FGEFSGJT.js.map +6 -0
- package/dist/chunk-GJS242RR.js +1652 -0
- package/dist/chunk-GJS242RR.js.map +6 -0
- package/dist/chunk-J56FRCFU.js +1284 -0
- package/dist/chunk-J56FRCFU.js.map +6 -0
- package/dist/chunk-KJTRZJHN.js +599 -0
- package/dist/chunk-KJTRZJHN.js.map +6 -0
- package/dist/chunk-M6GENFAH.js +14806 -0
- package/dist/chunk-M6GENFAH.js.map +6 -0
- package/dist/chunk-NJWQT6VB.js +1284 -0
- package/dist/chunk-NJWQT6VB.js.map +6 -0
- package/dist/chunk-ODREGGKA.js +219 -0
- package/dist/chunk-ODREGGKA.js.map +6 -0
- package/dist/chunk-OLLMACWA.js +35 -0
- package/dist/chunk-OLLMACWA.js.map +6 -0
- package/dist/chunk-PXXMOP4N.js +1284 -0
- package/dist/chunk-PXXMOP4N.js.map +6 -0
- package/dist/chunk-RKGIVPK5.js +1284 -0
- package/dist/chunk-RKGIVPK5.js.map +6 -0
- package/dist/chunk-RYHJUQSV.js +98 -0
- package/dist/chunk-RYHJUQSV.js.map +6 -0
- package/dist/chunk-SBD55ZES.js +316 -0
- package/dist/chunk-SBD55ZES.js.map +6 -0
- package/dist/chunk-SR2TQ2ZK.js +70 -0
- package/dist/chunk-SR2TQ2ZK.js.map +6 -0
- package/dist/designer.d.ts +48 -0
- package/dist/designer.js +35865 -0
- package/dist/designer.js.map +6 -0
- package/dist/peer/chunk-2NJMXASD.js +1282 -0
- package/dist/peer/chunk-2NJMXASD.js.map +6 -0
- package/dist/peer/chunk-76ZABVTI.js +598 -0
- package/dist/peer/chunk-76ZABVTI.js.map +6 -0
- package/dist/peer/chunk-BPF3SLL4.js +1282 -0
- package/dist/peer/chunk-BPF3SLL4.js.map +6 -0
- package/dist/peer/chunk-BWVDLOVL.js +1282 -0
- package/dist/peer/chunk-BWVDLOVL.js.map +6 -0
- package/dist/peer/chunk-CXM3YSWF.js +1282 -0
- package/dist/peer/chunk-CXM3YSWF.js.map +6 -0
- package/dist/peer/chunk-DQFZ6LVB.js +1282 -0
- package/dist/peer/chunk-DQFZ6LVB.js.map +6 -0
- package/dist/peer/chunk-GBITRNHE.js +14806 -0
- package/dist/peer/chunk-GBITRNHE.js.map +6 -0
- package/dist/peer/chunk-IMQRHDR4.js +12 -0
- package/dist/peer/chunk-IMQRHDR4.js.map +6 -0
- package/dist/peer/chunk-IPU2YRL2.js +300 -0
- package/dist/peer/chunk-IPU2YRL2.js.map +6 -0
- package/dist/peer/chunk-KBT6ZGGO.js +1666 -0
- package/dist/peer/chunk-KBT6ZGGO.js.map +6 -0
- package/dist/peer/chunk-M4AGFUWE.js +97 -0
- package/dist/peer/chunk-M4AGFUWE.js.map +6 -0
- package/dist/peer/chunk-MCJPN2KL.js +152 -0
- package/dist/peer/chunk-MCJPN2KL.js.map +6 -0
- package/dist/peer/chunk-NPYKZINU.js +6040 -0
- package/dist/peer/chunk-NPYKZINU.js.map +6 -0
- package/dist/peer/chunk-PG2PNYDX.js +1282 -0
- package/dist/peer/chunk-PG2PNYDX.js.map +6 -0
- package/dist/peer/chunk-QRAJXW2D.js +1282 -0
- package/dist/peer/chunk-QRAJXW2D.js.map +6 -0
- package/dist/peer/chunk-SHVCNAUG.js +1282 -0
- package/dist/peer/chunk-SHVCNAUG.js.map +6 -0
- package/dist/peer/chunk-Y5CAHLXS.js +218 -0
- package/dist/peer/chunk-Y5CAHLXS.js.map +6 -0
- package/dist/peer/designer.js +35841 -0
- package/dist/peer/designer.js.map +6 -0
- package/dist/peer/viewer.js +1061 -0
- package/dist/peer/viewer.js.map +6 -0
- package/dist/viewer.d.ts +77 -0
- package/dist/viewer.js +1066 -0
- package/dist/viewer.js.map +6 -0
- package/package.json +76 -4
|
@@ -0,0 +1,599 @@
|
|
|
1
|
+
import {
|
|
2
|
+
currencyOf,
|
|
3
|
+
standardDate,
|
|
4
|
+
toWall
|
|
5
|
+
} from "./chunk-GJS242RR.js";
|
|
6
|
+
import {
|
|
7
|
+
withDeadline
|
|
8
|
+
} from "./chunk-D2NTLAKL.js";
|
|
9
|
+
import {
|
|
10
|
+
mergedRegions,
|
|
11
|
+
needsTableData,
|
|
12
|
+
textRows
|
|
13
|
+
} from "./chunk-SR2TQ2ZK.js";
|
|
14
|
+
import {
|
|
15
|
+
altOf,
|
|
16
|
+
figurePicture,
|
|
17
|
+
figures
|
|
18
|
+
} from "./chunk-3D43XGIN.js";
|
|
19
|
+
import "./chunk-OLLMACWA.js";
|
|
20
|
+
|
|
21
|
+
// src/exporters/xlsxchart.js
|
|
22
|
+
import { unzipSync, zipSync, strToU8, strFromU8 } from "fflate";
|
|
23
|
+
var esc = (s) => String(s ?? "").replace(/[^\t\n\r\u0020-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/gu, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
24
|
+
var NS = 'xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"';
|
|
25
|
+
var ref = (sheet, c1, r1, c2, r2) => esc(`'${String(sheet).replace(/'/g, "''")}'!$${col(c1)}$${r1}:$${col(c2)}$${r2}`);
|
|
26
|
+
var col = (c) => {
|
|
27
|
+
let s = "";
|
|
28
|
+
for (let n = c; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + (n - 1) % 26) + s;
|
|
29
|
+
return s;
|
|
30
|
+
};
|
|
31
|
+
var hex = (c) => /^#[0-9a-f]{6}/i.test(String(c || "")) ? String(c).slice(1, 7).toUpperCase() : null;
|
|
32
|
+
function chartTable(spec) {
|
|
33
|
+
if (spec.categories) {
|
|
34
|
+
const head2 = ["", ...spec.series.map((s) => s.name)];
|
|
35
|
+
return [head2, ...spec.categories.map((c, i) => [c, ...spec.series.map((s) => s.values[i] ?? null)])];
|
|
36
|
+
}
|
|
37
|
+
const n = Math.max(0, ...spec.series.map((s) => s.x.length));
|
|
38
|
+
const per = spec.type === "bubble" ? 3 : 2;
|
|
39
|
+
const head = spec.series.flatMap((s) => [`${s.name} X`, s.name, ...per === 3 ? [`${s.name} size`] : []]);
|
|
40
|
+
const rows = Array.from({ length: n }, (_, i) => spec.series.flatMap((s) => [s.x[i] ?? null, s.y[i] ?? null, ...per === 3 ? [s.size?.[i] ?? null] : []]));
|
|
41
|
+
return [head, ...rows];
|
|
42
|
+
}
|
|
43
|
+
var strCache = (vals) => `<c:strCache><c:ptCount val="${vals.length}"/>${vals.map((v, i) => `<c:pt idx="${i}"><c:v>${esc(v)}</c:v></c:pt>`).join("")}</c:strCache>`;
|
|
44
|
+
var numCache = (vals, fmt = "General") => `<c:numCache><c:formatCode>${esc(fmt)}</c:formatCode><c:ptCount val="${vals.length}"/>${vals.map((v, i) => typeof v !== "number" || !Number.isFinite(v) ? "" : `<c:pt idx="${i}"><c:v>${v}</c:v></c:pt>`).join("")}</c:numCache>`;
|
|
45
|
+
var fill = (c, line) => {
|
|
46
|
+
const h = hex(c);
|
|
47
|
+
if (!h) return "";
|
|
48
|
+
return line ? `<c:spPr><a:ln w="22225"><a:solidFill><a:srgbClr val="${h}"/></a:solidFill></a:ln></c:spPr>` : `<c:spPr><a:solidFill><a:srgbClr val="${h}"/></a:solidFill></c:spPr>`;
|
|
49
|
+
};
|
|
50
|
+
var title = (t) => t ? `<c:title><c:tx><c:rich><a:bodyPr/><a:p><a:r><a:t>${esc(t)}</a:t></a:r></a:p></c:rich></c:tx><c:overlay val="0"/></c:title>` : "";
|
|
51
|
+
function chartXml(spec, sheet) {
|
|
52
|
+
const t = spec.type;
|
|
53
|
+
const fmt = excelFormat(spec.format, "", spec.locale) || "General";
|
|
54
|
+
let plot = "", axes = "";
|
|
55
|
+
const AX = { cat: 500001, val: 500002, cat2: 500003, val2: 500004 };
|
|
56
|
+
const axIds = (two) => `<c:axId val="${two ? AX.cat2 : AX.cat}"/><c:axId val="${two ? AX.val2 : AX.val}"/>`;
|
|
57
|
+
if (spec.categories) {
|
|
58
|
+
const n = spec.categories.length;
|
|
59
|
+
const cat = `<c:cat><c:strRef><c:f>${ref(sheet, 1, 2, 1, n + 1)}</c:f>${strCache(spec.categories)}</c:strRef></c:cat>`;
|
|
60
|
+
const ser = (s, i, kind) => {
|
|
61
|
+
const c = i + 2;
|
|
62
|
+
const line = kind === "line" || kind === "radar";
|
|
63
|
+
return `<c:ser><c:idx val="${i}"/><c:order val="${i}"/><c:tx><c:strRef><c:f>${ref(sheet, c, 1, c, 1)}</c:f>${strCache([s.name])}</c:strRef></c:tx>${t === "pie" || t === "donut" ? "" : fill(s.color, line)}${line ? '<c:marker><c:symbol val="none"/></c:marker>' : ""}${cat}<c:val><c:numRef><c:f>${ref(sheet, c, 2, c, n + 1)}</c:f>${numCache(s.values, fmt)}</c:numRef></c:val>${kind === "line" ? '<\
|
|
64
|
+
c:smooth val="0"/>' : ""}</c:ser>`;
|
|
65
|
+
};
|
|
66
|
+
if (t === "pie" || t === "donut") {
|
|
67
|
+
const s = spec.series[0];
|
|
68
|
+
const pts = spec.categories.map((_, i) => `<c:dPt><c:idx val="${i}"/><c:bubble3D val="0"/>${fill(spec.colors?.[i] || PALETTE[i % PALETTE.length])}</c:dPt>`).join("");
|
|
69
|
+
const one = ser(s, 0, "pie").replace("<c:cat>", `${pts}<c:cat>`);
|
|
70
|
+
plot = t === "pie" ? `<c:pieChart><c:varyColors val="1"/>${one}<c:firstSliceAng val="0"/></c:pieChart>` : `<c:doughnutChart><c:varyColors val="1"/>${one}<c:firstSliceAng val="0"/><c:holeSize val="55"/></c:doughnutChart>`;
|
|
71
|
+
} else if (t === "radar") {
|
|
72
|
+
plot = `<c:radarChart><c:radarStyle val="marker"/><c:varyColors val="0"/>${spec.series.map((s, i) => ser(s, i, "radar")).join("")}${axIds(false)}</c:radarChart>`;
|
|
73
|
+
axes = catAx(AX.cat, AX.val, "b", false, null) + valAx(AX.val, AX.cat, "l", false, fmt, null);
|
|
74
|
+
} else {
|
|
75
|
+
const groups = /* @__PURE__ */ new Map();
|
|
76
|
+
spec.series.forEach((s, i) => {
|
|
77
|
+
const kind = t === "bar" ? "bar" : s.kind || t;
|
|
78
|
+
const k = `${kind}|${s.secondary ? 2 : 1}`;
|
|
79
|
+
if (!groups.has(k)) groups.set(k, { kind, two: !!s.secondary, list: [] });
|
|
80
|
+
groups.get(k).list.push([s, i]);
|
|
81
|
+
});
|
|
82
|
+
const grouping = spec.stacked === "percent" ? "percentStacked" : spec.stacked ? "stacked" : null;
|
|
83
|
+
for (const gr of groups.values()) {
|
|
84
|
+
const body = gr.list.map(([s, i]) => ser(s, i, gr.kind)).join("");
|
|
85
|
+
if (gr.kind === "column" || gr.kind === "bar") plot += `<c:barChart><c:barDir val="${t === "bar" ? "bar" : "col"}"/><c:grouping val="${grouping || "clustered"}"/><c:varyColors val="0"/>${body}<c:gapWidth val="80"/>${grouping ? '<c:overlap val="100"/>' : ""}${axIds(gr.two)}</c:barChart>`;
|
|
86
|
+
else if (gr.kind === "line") plot += `<c:lineChart><c:grouping val="${grouping || "standard"}"/><c:varyColors val="0"/>${body}<c:marker val="1"/>${axIds(gr.two)}</c:lineChart>`;
|
|
87
|
+
else plot += `<c:areaChart><c:grouping val="${grouping || "standard"}"/><c:varyColors val="0"/>${body}${axIds(gr.two)}</c:areaChart>`;
|
|
88
|
+
}
|
|
89
|
+
const horiz = t === "bar";
|
|
90
|
+
axes = catAx(AX.cat, AX.val, horiz ? "l" : "b", false, spec.xTitle) + valAx(AX.val, AX.cat, horiz ? "b" : "l", false, spec.stacked === "percent" ? "0%" : fmt, spec.yTitle);
|
|
91
|
+
if ([...groups.values()].some((g) => g.two)) axes += catAx(AX.cat2, AX.val2, horiz ? "r" : "t", true, null) + valAx(AX.val2, AX.cat2, horiz ? "t" : "r", true, fmt, null);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
const per = t === "bubble" ? 3 : 2;
|
|
95
|
+
const body = spec.series.map((s, i) => {
|
|
96
|
+
const c = 1 + i * per, n = s.x.length;
|
|
97
|
+
return `<c:ser><c:idx val="${i}"/><c:order val="${i}"/><c:tx><c:strRef><c:f>${ref(sheet, c + 1, 1, c + 1, 1)}</c:f>${strCache([s.name])}</c:strRef></c:tx>${t === "bubble" ? fill(s.color) : `<c:spPr><a:ln w="19050"><a:noFill/></a:ln></c:spPr><c:marker><c:symbol val="circle"/><c:size val="5"/>${fill(s.color)}</c:marker>`}<c:xVal><c:numRef><c:f>${ref(sheet, c, 2, c, n + 1)}</c:f>${numCache(s.x)}\
|
|
98
|
+
</c:numRef></c:xVal><c:yVal><c:numRef><c:f>${ref(sheet, c + 1, 2, c + 1, n + 1)}</c:f>${numCache(s.y, fmt)}</c:numRef></c:yVal>` + (t === "bubble" ? `<c:bubbleSize><c:numRef><c:f>${ref(sheet, c + 2, 2, c + 2, n + 1)}</c:f>${numCache(s.size || [])}</c:numRef></c:bubbleSize><c:bubble3D val="0"/>` : '<c:smooth val="0"/>') + "</c:ser>";
|
|
99
|
+
}).join("");
|
|
100
|
+
plot = t === "bubble" ? `<c:bubbleChart><c:varyColors val="0"/>${body}<c:bubbleScale val="100"/>${axIds(false)}</c:bubbleChart>` : `<c:scatterChart><c:scatterStyle val="lineMarker"/><c:varyColors val="0"/>${body}${axIds(false)}</c:scatterChart>`;
|
|
101
|
+
axes = valAx(AX.cat, AX.val, "b", false, "General", spec.xTitle) + valAx(AX.val, AX.cat, "l", false, fmt, spec.yTitle);
|
|
102
|
+
}
|
|
103
|
+
const legend = spec.legend && (spec.series.length > 1 || t === "pie" || t === "donut") ? '<c:legend><c:legendPos val="b"/><c:overlay val="0"/></c:legend>' : "";
|
|
104
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
105
|
+
<c:chartSpace ${NS}><c:roundedCorners val="0"/><c:chart>${title(spec.title)}<c:autoTitleDeleted val="${spec.title ? 0 : 1}"/><c:plotArea><c:layout/>${plot}${axes}</c:plotArea>${legend}<c:plotVisOnly val="1"/><c:dispBlanksAs val="gap"/></c:chart></c:chartSpace>`;
|
|
106
|
+
}
|
|
107
|
+
var axTitle = (t) => t ? title(t) : "";
|
|
108
|
+
function catAx(id, cross, pos, second, t) {
|
|
109
|
+
return `<c:catAx><c:axId val="${id}"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:delete val="${second ? 1 : 0}"/><c:axPos val="${pos}"/>${axTitle(t)}<c:numFmt formatCode="General" sourceLinked="0"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crossAx val="${cross}"/><c:crosses val="autoZero"/><c:auto val="1"/><c:lblAlgn val="ctr"/><c:lblOffs\
|
|
110
|
+
et val="100"/><c:noMultiLvlLbl val="0"/></c:catAx>`;
|
|
111
|
+
}
|
|
112
|
+
function valAx(id, cross, pos, second, fmt, t) {
|
|
113
|
+
return `<c:valAx><c:axId val="${id}"/><c:scaling><c:orientation val="minMax"/></c:scaling><c:delete val="0"/><c:axPos val="${pos}"/>${second ? "" : "<c:majorGridlines/>"}${axTitle(t)}<c:numFmt formatCode="${esc(fmt)}" sourceLinked="0"/><c:majorTickMark val="out"/><c:minorTickMark val="none"/><c:tickLblPos val="nextTo"/><c:crossAx val="${cross}"/><c:crosses val="${second ? "max" : "autoZero"}"/><\
|
|
114
|
+
c:crossBetween val="between"/></c:valAx>`;
|
|
115
|
+
}
|
|
116
|
+
var PALETTE = ["#2563eb", "#16a34a", "#f59e0b", "#dc2626", "#7c3aed", "#0891b2", "#db2777", "#65a30d", "#ea580c", "#475569"];
|
|
117
|
+
var drawingXml = (c0, r0, cols, rows) => `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
118
|
+
<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><xdr:twoCellAnchor editAs="oneCell"><xdr:from><xdr:col>${c0}</xdr:col><xdr:colOff>0</xdr:colOff><xdr:row>${r0}</xdr:row><xdr:rowOff>0</xdr:rowOff></xdr:from><xdr:to><xdr:col>${c0 + cols}</xdr:col><xdr:colOff>0</xdr:colOff><xdr:row>${r0 + rows}</x\
|
|
119
|
+
dr:row><xdr:rowOff>0</xdr:rowOff></xdr:to><xdr:graphicFrame macro=""><xdr:nvGraphicFramePr><xdr:cNvPr id="2" name="Chart 1"/><xdr:cNvGraphicFramePr/></xdr:nvGraphicFramePr><xdr:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/></xdr:xfrm><a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/chart"><c:chart xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmln\
|
|
120
|
+
s:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:id="rId1"/></a:graphicData></a:graphic></xdr:graphicFrame><xdr:clientData/></xdr:twoCellAnchor></xdr:wsDr>`;
|
|
121
|
+
var rels = (list) => `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
122
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${list.join("")}</Relationships>`;
|
|
123
|
+
var rel = (id, type, target) => `<Relationship Id="${id}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/${type}" Target="${target}"/>`;
|
|
124
|
+
function addCharts(bytes, charts) {
|
|
125
|
+
if (!charts.length) return bytes;
|
|
126
|
+
const files = unzipSync(bytes);
|
|
127
|
+
const read = (p) => files[p] ? strFromU8(files[p]) : null;
|
|
128
|
+
const write = (p, s) => {
|
|
129
|
+
files[p] = strToU8(s);
|
|
130
|
+
};
|
|
131
|
+
const wb = read("xl/workbook.xml") || "";
|
|
132
|
+
const wbRels = read("xl/_rels/workbook.xml.rels") || "";
|
|
133
|
+
const target = (rid) => {
|
|
134
|
+
const m = new RegExp(`<Relationship[^>]*Id="${rid}"[^>]*Target="([^"]+)"`).exec(wbRels) || new RegExp(`<Relationship[^>]*Target="([^"]+)"[^>]*Id="${rid}"`).exec(wbRels);
|
|
135
|
+
return m ? m[1].replace(/^\/?xl\//, "") : null;
|
|
136
|
+
};
|
|
137
|
+
const partOf = /* @__PURE__ */ new Map();
|
|
138
|
+
for (const m of wb.matchAll(/<sheet\b[^>]*>/g)) {
|
|
139
|
+
const name = /name="([^"]*)"/.exec(m[0])?.[1], rid = /r:id="([^"]*)"/.exec(m[0])?.[1];
|
|
140
|
+
if (name != null && rid) partOf.set(name.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'"), target(rid));
|
|
141
|
+
}
|
|
142
|
+
let types = read("[Content_Types].xml") || "";
|
|
143
|
+
charts.forEach((c, i) => {
|
|
144
|
+
const part = partOf.get(c.sheet);
|
|
145
|
+
if (!part) return;
|
|
146
|
+
const n = i + 1;
|
|
147
|
+
const sheetPath = `xl/${part}`, file = part.split("/").pop();
|
|
148
|
+
const relPath = `xl/worksheets/_rels/${file}.rels`;
|
|
149
|
+
write(`xl/charts/chartPW${n}.xml`, chartXml(c.spec, c.sheet));
|
|
150
|
+
write(`xl/drawings/drawingPW${n}.xml`, drawingXml(c.at.col, c.at.row, 9, 20));
|
|
151
|
+
write(`xl/drawings/_rels/drawingPW${n}.xml.rels`, rels([rel("rId1", "chart", `../charts/chartPW${n}.xml`)]));
|
|
152
|
+
const old = read(relPath);
|
|
153
|
+
const relEntry = rel("rIdPW1", "drawing", `../drawings/drawingPW${n}.xml`);
|
|
154
|
+
write(relPath, old ? old.replace("</Relationships>", `${relEntry}</Relationships>`) : rels([relEntry]));
|
|
155
|
+
let ws = read(sheetPath) || "";
|
|
156
|
+
if (!/xmlns:r=/.test(ws.slice(0, 600))) ws = ws.replace("<worksheet ", '<worksheet xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" ');
|
|
157
|
+
const before = ["<legacyDrawing", "<legacyDrawingHF", "<picture", "<oleObjects", "<controls", "<webPublishItems", "<tableParts", "<extLst", "</worksheet>"].map((t) => ws.indexOf(t)).filter((k) => k >= 0);
|
|
158
|
+
const at = Math.min(...before);
|
|
159
|
+
write(sheetPath, ws.slice(0, at) + '<drawing r:id="rIdPW1"/>' + ws.slice(at));
|
|
160
|
+
types = types.replace("</Types>", `<Override PartName="/xl/charts/chartPW${n}.xml" ContentType="application/vnd.openxmlformats-officedocument.drawingml.chart+xml"/><Override PartName="/xl/drawings/drawingPW${n}.xml" ContentType="application/vnd.openxmlformats-officedocument.drawing+xml"/></Types>`);
|
|
161
|
+
});
|
|
162
|
+
write("[Content_Types].xml", types);
|
|
163
|
+
return zipSync(files, { level: 6 });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/exporters/xlsxwriter.js
|
|
167
|
+
import { zipSync as zipSync2, strToU8 as strToU82 } from "fflate";
|
|
168
|
+
var colName = (c) => {
|
|
169
|
+
let s = "";
|
|
170
|
+
for (let n = c; n > 0; n = Math.floor((n - 1) / 26)) s = String.fromCharCode(65 + (n - 1) % 26) + s;
|
|
171
|
+
return s;
|
|
172
|
+
};
|
|
173
|
+
var XML = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n';
|
|
174
|
+
var R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
175
|
+
var rels2 = (list) => `${XML}<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${list.map(([id, type, target]) => `<Relationship Id="${id}" Type="${type.startsWith("http") ? type : `${R}/${type}`}" Target="${target}"/>`).join("")}</Relationships>`;
|
|
176
|
+
var HEADER_FILL = "FFE8EEF3";
|
|
177
|
+
var Sheet = class {
|
|
178
|
+
/** @param {Book} book @param {string} name */
|
|
179
|
+
constructor(book, name) {
|
|
180
|
+
this.book = book;
|
|
181
|
+
this.name = name;
|
|
182
|
+
this.xml = [];
|
|
183
|
+
this.widths = [];
|
|
184
|
+
this.merges = [];
|
|
185
|
+
this.images = [];
|
|
186
|
+
this.rowCount = 0;
|
|
187
|
+
this.frozenRows = 0;
|
|
188
|
+
this.outlineLevelRow = 0;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Add a row (1-based number returned). cells: one per column (null = empty).
|
|
192
|
+
* @param {(Cell|null)[]} cells @param {{ outlineLevel?: number }} [opt]
|
|
193
|
+
*/
|
|
194
|
+
addRow(cells, opt = {}) {
|
|
195
|
+
const n = ++this.rowCount;
|
|
196
|
+
let s = `<row r="${n}"${opt.outlineLevel ? ` outlineLevel="${opt.outlineLevel}" hidden="0"` : ""}>`;
|
|
197
|
+
cells.forEach((c, i) => {
|
|
198
|
+
if (c) s += this.book.cell(`${colName(i + 1)}${n}`, c);
|
|
199
|
+
});
|
|
200
|
+
this.xml.push(s + "</row>");
|
|
201
|
+
return n;
|
|
202
|
+
}
|
|
203
|
+
/** Merge (1-based, inclusive). */
|
|
204
|
+
merge(r1, c1, r2, c2) {
|
|
205
|
+
if (r2 > r1 || c2 > c1) this.merges.push(`${colName(c1)}${r1}:${colName(c2)}${r2}`);
|
|
206
|
+
}
|
|
207
|
+
/** A picture with its top-left at (col, row), 0-based, w × h pixels. */
|
|
208
|
+
addImage(bytes, ext, col2, row, w, h) {
|
|
209
|
+
this.images.push({ bytes, ext, col: col2, row, w, h });
|
|
210
|
+
}
|
|
211
|
+
/** @param {number} i */
|
|
212
|
+
toXml(i) {
|
|
213
|
+
return sheetHead(this) + this.xml.join("") + sheetTail(this.merges, this.images.length > 0);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
function sheetHead({ widths, frozenRows, outlineLevelRow }) {
|
|
217
|
+
const cols = widths.map((w, c) => w ? `<col min="${c + 1}" max="${c + 1}" width="${w}" customWidth="1"/>` : "").join("");
|
|
218
|
+
const view = frozenRows ? `<sheetViews><sheetView workbookViewId="0"><pane ySplit="${frozenRows}" topLeftCell="A${frozenRows + 1}" activePane="bottomLeft" state="frozen"/></sheetView></sheetViews>` : '<sheetViews><sheetView workbookViewId="0"/></sheetViews>';
|
|
219
|
+
return `${XML}<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="${R}"><sheetPr><outlinePr summaryBelow="1"/></sheetPr>${view}<sheetFormatPr defaultRowHeight="15"${outlineLevelRow ? ` outlineLevelRow="${outlineLevelRow}"` : ""}/>${cols ? `<cols>${cols}</cols>` : ""}<sheetData>`;
|
|
220
|
+
}
|
|
221
|
+
function sheetTail(merges, drawing = false) {
|
|
222
|
+
return `</sheetData>${merges.length ? `<mergeCells count="${merges.length}">${merges.map((m) => `<mergeCell ref="${m}"/>`).join("")}</mergeCells>` : ""}<pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/>${drawing ? `<drawing r:id="rId1"/>` : ""}</worksheet>`;
|
|
223
|
+
}
|
|
224
|
+
var Book = class {
|
|
225
|
+
constructor({ title: title2 = "Report", creator = "ReportWright" } = {}) {
|
|
226
|
+
this.title = title2;
|
|
227
|
+
this.creator = creator;
|
|
228
|
+
this.fullCalcOnLoad = false;
|
|
229
|
+
this.sheets = [];
|
|
230
|
+
this.styles = /* @__PURE__ */ new Map([["0|0|0", 0]]);
|
|
231
|
+
this.numFmts = /* @__PURE__ */ new Map();
|
|
232
|
+
}
|
|
233
|
+
/** @param {string} name */
|
|
234
|
+
addSheet(name) {
|
|
235
|
+
const s = new Sheet(this, name);
|
|
236
|
+
this.sheets.push(s);
|
|
237
|
+
return s;
|
|
238
|
+
}
|
|
239
|
+
/** cellXfs index for a style */
|
|
240
|
+
style(st) {
|
|
241
|
+
if (!st) return 0;
|
|
242
|
+
let fmt = 0;
|
|
243
|
+
if (st.numFmt) {
|
|
244
|
+
if (!this.numFmts.has(st.numFmt)) this.numFmts.set(st.numFmt, 164 + this.numFmts.size);
|
|
245
|
+
fmt = /** @type {number} */
|
|
246
|
+
this.numFmts.get(st.numFmt);
|
|
247
|
+
}
|
|
248
|
+
const key = `${fmt}|${st.bold ? 1 : 0}|${st.fill ? 1 : 0}`;
|
|
249
|
+
if (!this.styles.has(key)) this.styles.set(key, this.styles.size);
|
|
250
|
+
return (
|
|
251
|
+
/** @type {number} */
|
|
252
|
+
this.styles.get(key)
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
/** One <c> element. @param {string} ref @param {Cell} c */
|
|
256
|
+
cell(ref2, c) {
|
|
257
|
+
const s = this.style(c.style), sa = s ? ` s="${s}"` : "";
|
|
258
|
+
let v = c.v;
|
|
259
|
+
if (v instanceof Date) v = Number.isFinite(v.getTime()) ? v.getTime() / 864e5 + 25569 : null;
|
|
260
|
+
if (c.f) return `<c r="${ref2}"${sa}${typeof v === "string" ? ' t="str"' : typeof v === "boolean" ? ' t="b"' : ""}><f>${esc(c.f)}</f>${v == null ? "" : `<v>${typeof v === "boolean" ? +v : esc(v)}</v>`}</c>`;
|
|
261
|
+
if (v == null) return s ? `<c r="${ref2}"${sa}/>` : "";
|
|
262
|
+
if (typeof v === "number") return Number.isFinite(v) ? `<c r="${ref2}"${sa}><v>${v}</v></c>` : `<c r="${ref2}"${sa} t="inlineStr"><is><t>${esc(String(v))}</t></is></c>`;
|
|
263
|
+
if (typeof v === "boolean") return `<c r="${ref2}"${sa} t="b"><v>${+v}</v></c>`;
|
|
264
|
+
return `<c r="${ref2}"${sa} t="inlineStr"><is><t xml:space="preserve">${esc(typeof v === "object" ? JSON.stringify(v) : v)}</t></is></c>`;
|
|
265
|
+
}
|
|
266
|
+
stylesXml() {
|
|
267
|
+
const fmts = [...this.numFmts].map(([f, id]) => `<numFmt numFmtId="${id}" formatCode="${esc(f)}"/>`).join("");
|
|
268
|
+
const xfs = [...this.styles.keys()].map((k) => {
|
|
269
|
+
const [fmt, bold, fill2] = k.split("|").map(Number);
|
|
270
|
+
return `<xf numFmtId="${fmt || 0}" fontId="${bold ? 1 : 0}" fillId="${fill2 ? 2 : 0}" borderId="0" xfId="0"${fmt ? ' applyNumberFormat="1"' : ""}${bold ? ' applyFont="1"' : ""}${fill2 ? ' applyFill="1"' : ""}/>`;
|
|
271
|
+
}).join("");
|
|
272
|
+
return `${XML}<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">${fmts ? `<numFmts count="${this.numFmts.size}">${fmts}</numFmts>` : ""}<fonts count="2"><font><sz val="11"/><name val="Calibri"/><family val="2"/></font><font><b/><sz val="11"/><name val="Calibri"/><family val="2"/></font></fonts><fills count="3"><fill><patternFill patternType="none"/></fill><fill><pat\
|
|
273
|
+
ternFill patternType="gray125"/></fill><fill><patternFill patternType="solid"><fgColor rgb="${HEADER_FILL}"/><bgColor indexed="64"/></patternFill></fill></fills><borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="${this.styles.size}">${xfs}</cellXfs><cellSt\
|
|
274
|
+
yles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>`;
|
|
275
|
+
}
|
|
276
|
+
/** The .xlsx bytes. */
|
|
277
|
+
write() {
|
|
278
|
+
const files = {};
|
|
279
|
+
const put = (p, s) => {
|
|
280
|
+
files[p] = typeof s === "string" ? strToU82(s) : s;
|
|
281
|
+
};
|
|
282
|
+
const over = [];
|
|
283
|
+
let img = 0;
|
|
284
|
+
this.sheets.forEach((sh, i) => {
|
|
285
|
+
const n = i + 1;
|
|
286
|
+
put(`xl/worksheets/sheet${n}.xml`, sh.toXml(i));
|
|
287
|
+
sh.xml = [];
|
|
288
|
+
over.push([`/xl/worksheets/sheet${n}.xml`, "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"]);
|
|
289
|
+
if (!sh.images.length) return;
|
|
290
|
+
put(`xl/worksheets/_rels/sheet${n}.xml.rels`, rels2([["rId1", "drawing", `../drawings/drawing${n}.xml`]]));
|
|
291
|
+
const anchors = sh.images.map((im, k) => {
|
|
292
|
+
img++;
|
|
293
|
+
put(`xl/media/image${img}.${im.ext}`, im.bytes);
|
|
294
|
+
return `<xdr:oneCellAnchor><xdr:from><xdr:col>${im.col}</xdr:col><xdr:colOff>0</xdr:colOff><xdr:row>${im.row}</xdr:row><xdr:rowOff>0</xdr:rowOff></xdr:from><xdr:ext cx="${Math.round(im.w * 9525)}" cy="${Math.round(im.h * 9525)}"/><xdr:pic><xdr:nvPicPr><xdr:cNvPr id="${k + 2}" name="Picture ${k + 1}"/><xdr:cNvPicPr><a:picLocks noChangeAspect="1"/></xdr:cNvPicPr></xdr:nvPicPr><xdr:blipFill><\
|
|
295
|
+
a:blip r:embed="rId${k + 1}"/><a:stretch><a:fillRect/></a:stretch></xdr:blipFill><xdr:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${Math.round(im.w * 9525)}" cy="${Math.round(im.h * 9525)}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></xdr:spPr></xdr:pic><xdr:clientData/></xdr:oneCellAnchor>`;
|
|
296
|
+
});
|
|
297
|
+
let first = img - sh.images.length;
|
|
298
|
+
put(`xl/drawings/_rels/drawing${n}.xml.rels`, rels2(sh.images.map((im, k) => [`rId${k + 1}`, "image", `../media/image${++first}.${im.ext}`])));
|
|
299
|
+
put(`xl/drawings/drawing${n}.xml`, `${XML}<xdr:wsDr xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="${R}">${anchors.join("")}</xdr:wsDr>`);
|
|
300
|
+
over.push([`/xl/drawings/drawing${n}.xml`, "application/vnd.openxmlformats-officedocument.drawing+xml"]);
|
|
301
|
+
});
|
|
302
|
+
for (const [p, x] of this.bookParts(over)) put(p, x);
|
|
303
|
+
return zipSync2(files, { level: 6 });
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* The workbook's own parts, written after the sheets (their names, the styles they used): styles, workbook,
|
|
307
|
+
* relationships, properties and content types. over: [part, content type] of the sheets and drawings.
|
|
308
|
+
* @param {[string, string][]} over @returns {[string, string][]}
|
|
309
|
+
*/
|
|
310
|
+
bookParts(over) {
|
|
311
|
+
const out = [];
|
|
312
|
+
const put = (p, s) => out.push([p, s]);
|
|
313
|
+
put("xl/styles.xml", this.stylesXml());
|
|
314
|
+
put("xl/workbook.xml", `${XML}<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="${R}"><bookViews><workbookView/></bookViews><sheets>${this.sheets.map((s, i) => `<sheet name="${esc(s.name)}" sheetId="${i + 1}" r:id="rId${i + 1}"/>`).join("")}</sheets><calcPr calcId="171027"${this.fullCalcOnLoad ? ' fullCalcOnLoad="1"' : ""}/></workbook>`);
|
|
315
|
+
put("xl/_rels/workbook.xml.rels", rels2([...this.sheets.map((s, i) => [`rId${i + 1}`, "worksheet", `worksheets/sheet${i + 1}.xml`]), [`rId${this.sheets.length + 1}`, "styles", "styles.xml"]]));
|
|
316
|
+
put("docProps/core.xml", `${XML}<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:title>${esc(this.title)}</dc:title><dc:creator>${esc(this.creator)}</dc:creator><dcterms:created xsi:type="dcterms:W3C\
|
|
317
|
+
DTF">${(/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z")}</dcterms:created></cp:coreProperties>`);
|
|
318
|
+
put("_rels/.rels", rels2([["rId1", "officeDocument", "xl/workbook.xml"], ["rId2", "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", "docProps/core.xml"]]));
|
|
319
|
+
put("[Content_Types].xml", `${XML}<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Default Extension="png" ContentType="image/png"/><Default Extension="jpeg" ContentType="image/jpeg"/><Override PartName="/xl/workbo\
|
|
320
|
+
ok.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>${over.map(([p, t]) => `<Override PartName="${p}" ContentType="${t}\
|
|
321
|
+
"/>`).join("")}</Types>`);
|
|
322
|
+
return out;
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
// src/exporters/xlsx.js
|
|
327
|
+
var excelDate = (f) => f.replace(/'([^']*)'/g, (_, t) => /^[\s./:,-]*$/.test(t) ? t : `"${t}"`).replace(/M/g, "m").replace(/tt?/g, "AM/PM").replace(/HH?/g, "hh").replace(/f+/g, (x) => `.${"0".repeat(Math.min(3, x.length))}`).replace(/\s*zzz?/g, "");
|
|
328
|
+
var javaDateToExcel = (f) => f.replace(/'([^']*)'/g, '"$1"').replace(/E{4,}/g, "dddd").replace(/E{1,3}/g, "ddd").replace(/a+/g, "AM/PM").replace(/H+/g, "hh").replace(/M/g, "m").replace(/[kKuDwWFGzZXL]+/g, "");
|
|
329
|
+
function excelFormat(fmt, currencySymbol2 = "", locale, value) {
|
|
330
|
+
if (!fmt) return null;
|
|
331
|
+
if (fmt.startsWith("java:") || fmt.startsWith("icu:")) {
|
|
332
|
+
const p = fmt.slice(fmt.indexOf(":") + 1).replace(/\{RoundingMode=\w+\}/, "");
|
|
333
|
+
if (!p || p.startsWith("@")) return value instanceof Date ? p.includes("time") && !p.includes("date") ? "h:mm AM/PM" : "m/d/yyyy" : null;
|
|
334
|
+
if (value instanceof Date) return javaDateToExcel(p) || null;
|
|
335
|
+
if (/[‰\u2030]|E0/.test(p)) return null;
|
|
336
|
+
return p.replace(/¤+/g, `"${currencySymbol2}"`).replace(/'([^']*)'/g, '"$1"');
|
|
337
|
+
}
|
|
338
|
+
if (value instanceof Date && fmt.length === 1) {
|
|
339
|
+
const US = { d: "m/d/yyyy", D: "dddd, mmmm d, yyyy", t: "h:mm AM/PM", T: "h:mm:ss AM/PM", g: "m/d/yyyy h:mm AM/PM", G: "m/d/yyyy h:mm:ss AM/PM", M: "mmmm d", m: "mmmm d", Y: "mmmm yyyy", y: "mmmm yyyy", f: "dddd, mmmm d, yyyy h:mm AM/PM", F: "dddd, mmmm d, yyyy h:mm:ss AM/PM", s: "yyyy-mm-ddThh:mm:ss" };
|
|
340
|
+
if (!locale || /^en-US$/i.test(locale)) return US[fmt] || null;
|
|
341
|
+
const g = (k) => {
|
|
342
|
+
const p = standardDate(k, locale);
|
|
343
|
+
return p ? excelDate(p) : null;
|
|
344
|
+
};
|
|
345
|
+
const both = (a, b) => {
|
|
346
|
+
const x = g(a), y = g(b);
|
|
347
|
+
return x && y ? `${x} ${y}` : null;
|
|
348
|
+
};
|
|
349
|
+
return { g: () => both("d", "t"), G: () => both("d", "T"), f: () => both("D", "t"), F: () => both("D", "T") }[fmt]?.() ?? g(fmt) ?? US[fmt] ?? null;
|
|
350
|
+
}
|
|
351
|
+
const m = /^([CcNnFfPpDd])(\d{0,2})$/.exec(fmt);
|
|
352
|
+
if (m) {
|
|
353
|
+
const d = m[2] === "" ? 2 : Number(m[2]);
|
|
354
|
+
const dec = d ? "." + "0".repeat(d) : "";
|
|
355
|
+
const lakh = /-IN$/i.test(locale || "") ? (s) => {
|
|
356
|
+
if (typeof value === "number" && value < 0) {
|
|
357
|
+
const a = Math.abs(value);
|
|
358
|
+
return a >= 1e7 ? `${s}##\\,##\\,##\\,##0${dec}` : a >= 1e5 ? `${s}##\\,##\\,##0${dec}` : `${s}##,##0${dec}`;
|
|
359
|
+
}
|
|
360
|
+
return `[>=10000000]${s}##\\,##\\,##\\,##0${dec};[>=100000]${s}##\\,##\\,##0${dec};${s}##,##0${dec}`;
|
|
361
|
+
} : null;
|
|
362
|
+
switch (m[1].toUpperCase()) {
|
|
363
|
+
case "C":
|
|
364
|
+
return lakh ? lakh(`"${currencySymbol2}"`) : `"${currencySymbol2}"#,##0${dec}`;
|
|
365
|
+
case "N":
|
|
366
|
+
return lakh ? lakh("") : `#,##0${dec}`;
|
|
367
|
+
case "F":
|
|
368
|
+
return `0${dec}`;
|
|
369
|
+
case "P":
|
|
370
|
+
return `0${dec}%`;
|
|
371
|
+
case "D":
|
|
372
|
+
return "0".repeat(Math.max(1, d));
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (/[yMd]/.test(fmt) && !/[#0]/.test(fmt)) return excelDate(fmt);
|
|
376
|
+
if (/[#0]/.test(fmt)) return fmt;
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
function currencySymbol(iso, locale) {
|
|
380
|
+
if (!iso) return "";
|
|
381
|
+
try {
|
|
382
|
+
return new Intl.NumberFormat(locale || "en-US", { style: "currency", currency: iso }).formatToParts(1).find((p) => p.type === "currency")?.value || iso;
|
|
383
|
+
} catch {
|
|
384
|
+
return SYMBOL[iso] || iso;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
var SYMBOL = { INR: "₹", USD: "$", EUR: "€", GBP: "£", JPY: "¥" };
|
|
388
|
+
var decimalsOf = (fmt) => {
|
|
389
|
+
const m = /^[CcNnFfPp](\d{0,2})$/.exec(fmt || "");
|
|
390
|
+
if (m) return (m[1] === "" ? 2 : Number(m[1])) + (/^[Pp]/.test(fmt) ? 2 : 0);
|
|
391
|
+
const d = /\.(0+)/.exec(fmt || "");
|
|
392
|
+
return d ? d[1].length : fmt ? 0 : null;
|
|
393
|
+
};
|
|
394
|
+
function colStats() {
|
|
395
|
+
const s = {
|
|
396
|
+
vals: 0,
|
|
397
|
+
nums: 0,
|
|
398
|
+
sum: 0,
|
|
399
|
+
min: Infinity,
|
|
400
|
+
max: -Infinity,
|
|
401
|
+
first: void 0,
|
|
402
|
+
differ: false,
|
|
403
|
+
/** @param {any} v a region cell's value */
|
|
404
|
+
add(v) {
|
|
405
|
+
if (v == null || v === "") return;
|
|
406
|
+
s.vals++;
|
|
407
|
+
if (typeof v !== "number" || !Number.isFinite(v)) return;
|
|
408
|
+
if (s.nums === 0) s.first = v;
|
|
409
|
+
else if (v !== s.first) s.differ = true;
|
|
410
|
+
s.nums++;
|
|
411
|
+
s.sum += v;
|
|
412
|
+
if (v < s.min) s.min = v;
|
|
413
|
+
if (v > s.max) s.max = v;
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
return s;
|
|
417
|
+
}
|
|
418
|
+
function subtotalFn(c, st) {
|
|
419
|
+
const d = decimalsOf(c.format);
|
|
420
|
+
const tol = d == null ? 1e-9 * Math.max(1, Math.abs(c.value)) : 0.5 * 10 ** -d + 1e-9;
|
|
421
|
+
const same = (v) => Math.abs(v - c.value) <= tol;
|
|
422
|
+
if (st.nums && same(st.sum)) return 9;
|
|
423
|
+
if (same(st.vals)) return st.nums === st.vals ? 2 : 3;
|
|
424
|
+
if (st.nums > 1 && st.differ) {
|
|
425
|
+
if (same(st.sum / st.nums)) return 1;
|
|
426
|
+
if (same(st.min)) return 5;
|
|
427
|
+
if (same(st.max)) return 4;
|
|
428
|
+
}
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
function totalFormula(rows, at, c, made) {
|
|
432
|
+
const row = rows[at];
|
|
433
|
+
if (typeof c.value !== "number" || !Number.isFinite(c.value)) return null;
|
|
434
|
+
const covered = [];
|
|
435
|
+
for (let k = at - 1; k >= 0; k--) {
|
|
436
|
+
const r = rows[k];
|
|
437
|
+
if (r.kind === "header") break;
|
|
438
|
+
if (row.kind === "groupFooter" && (r.kind === "groupFooter" || r.kind === "groupHeader") && r.level <= row.level) break;
|
|
439
|
+
if (r.kind === "detail") covered.push(k);
|
|
440
|
+
}
|
|
441
|
+
if (!covered.length) return null;
|
|
442
|
+
covered.reverse();
|
|
443
|
+
const st = colStats();
|
|
444
|
+
for (const k of covered) st.add(rows[k].cells.find((x) => x.colIndex === c.colIndex)?.value);
|
|
445
|
+
const fn = subtotalFn(c, st);
|
|
446
|
+
if (!fn) return null;
|
|
447
|
+
const col2 = colName(c.colIndex + 1);
|
|
448
|
+
const runs = [];
|
|
449
|
+
for (const k of covered) {
|
|
450
|
+
const last = runs[runs.length - 1];
|
|
451
|
+
if (last && rows[k].n === last[1] + 1) last[1] = rows[k].n;
|
|
452
|
+
else runs.push([rows[k].n, rows[k].n]);
|
|
453
|
+
}
|
|
454
|
+
let refs = runs.map(([a, b]) => a === b ? `${col2}${a}` : `${col2}${a}:${col2}${b}`);
|
|
455
|
+
if (refs.length > 30) {
|
|
456
|
+
const first = covered[0], last = covered[covered.length - 1];
|
|
457
|
+
for (let k = first; k <= last; k++) {
|
|
458
|
+
if (rows[k].kind === "detail") continue;
|
|
459
|
+
const v = rows[k].cells.find((x) => x.colIndex === c.colIndex)?.value;
|
|
460
|
+
if (v != null && v !== "" && !made.has(`${k}|${c.colIndex}`)) return null;
|
|
461
|
+
}
|
|
462
|
+
refs = [`${col2}${rows[first].n}:${col2}${rows[last].n}`];
|
|
463
|
+
}
|
|
464
|
+
return `SUBTOTAL(${fn},${refs.join(",")})`;
|
|
465
|
+
}
|
|
466
|
+
function sheetNamer() {
|
|
467
|
+
const used = /* @__PURE__ */ new Set();
|
|
468
|
+
return (n, suffix = "") => {
|
|
469
|
+
let s = String(n || "Sheet").replace(/[\\/?*[\]:\u0000-\u001f\u007f\uFFFE\uFFFF]|[\uD800-\uDFFF]/g, " ").replace(/^['\s]+|['\s]+$/g, "").slice(0, 28).trim() || "Sheet";
|
|
470
|
+
if (suffix) s = `${s.slice(0, 31 - suffix.length)}${suffix}`;
|
|
471
|
+
let k = s, i = 2;
|
|
472
|
+
while (used.has(k.toLowerCase())) k = `${s.slice(0, 28)} ${i++}`;
|
|
473
|
+
used.add(k.toLowerCase());
|
|
474
|
+
return k;
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
function xlsxCell({ sym, locale, tz }) {
|
|
478
|
+
const cellValue = (v) => v === "" ? null : v instanceof Date ? new Date(toWall(v, tz)) : v;
|
|
479
|
+
return (c, header) => {
|
|
480
|
+
const nf = excelFormat(c.format, sym, locale, c.value);
|
|
481
|
+
const numFmt = nf && (typeof c.value === "number" || c.value instanceof Date) ? nf : c.value instanceof Date ? "dd mmm yyyy" : null;
|
|
482
|
+
return (
|
|
483
|
+
/** @type {any} */
|
|
484
|
+
{ v: cellValue(c.value), style: { numFmt, bold: !!(c.bold || header), fill: header } }
|
|
485
|
+
);
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
function exportXlsx(model, opt = {}, legacy = void 0) {
|
|
489
|
+
if (legacy || opt && (typeof opt === "function" || /** @type {any} */
|
|
490
|
+
opt.Workbook)) opt = legacy || {};
|
|
491
|
+
return withDeadline(
|
|
492
|
+
xlsxOf(model, opt),
|
|
493
|
+
/** @type {any} */
|
|
494
|
+
opt.timeoutMs
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
async function xlsxOf(model, opt) {
|
|
498
|
+
const { currency, title: title2, formulas = true, pictures = true, charts = true, fetchImage, rasterize, timeZone } = opt;
|
|
499
|
+
const fontStore = opt.fontStore || opt.fonts;
|
|
500
|
+
needsTableData(model, "Excel");
|
|
501
|
+
const tz = timeZone ?? model.timeZone ?? void 0;
|
|
502
|
+
const sym = currencySymbol(currency || model.currency || currencyOf(model.locale), model.locale);
|
|
503
|
+
const toCell = xlsxCell({ sym, locale: model.locale, tz });
|
|
504
|
+
const wb = new Book({ title: title2 || model.name || "Report" });
|
|
505
|
+
const regions = mergedRegions(model);
|
|
506
|
+
const sheetName = sheetNamer();
|
|
507
|
+
if (!regions.length) {
|
|
508
|
+
const ws = wb.addSheet(sheetName(title2 || "Report"));
|
|
509
|
+
model.pages.forEach((p, pi) => {
|
|
510
|
+
for (const l of textRows(p.items)) ws.addRow([{ v: pi + 1 }, { v: l }]);
|
|
511
|
+
});
|
|
512
|
+
ws.widths = [6, 80];
|
|
513
|
+
}
|
|
514
|
+
for (const r of regions) {
|
|
515
|
+
const ws = wb.addSheet(sheetName(r.name));
|
|
516
|
+
ws.widths = r.columns.map((w) => Math.max(6, Math.round(w / 5.5)));
|
|
517
|
+
let headerRows = 0;
|
|
518
|
+
const merges = [];
|
|
519
|
+
const rows = r.rows.map((row) => ({ ...row, n: 0 }));
|
|
520
|
+
const made = /* @__PURE__ */ new Map();
|
|
521
|
+
rows.forEach((row, ri) => {
|
|
522
|
+
row.n = ws.rowCount + 1;
|
|
523
|
+
const cells = new Array(r.columns.length).fill(null);
|
|
524
|
+
const header = row.kind === "header";
|
|
525
|
+
for (const c of row.cells) {
|
|
526
|
+
if (c.colIndex < 0) continue;
|
|
527
|
+
const cell = toCell(c, header);
|
|
528
|
+
if (c.span > 1 || c.rowSpan > 1) merges.push([row.n, c.colIndex + 1, row.n + Math.max(1, c.rowSpan || 1) - 1, c.colIndex + Math.max(1, c.span || 1)]);
|
|
529
|
+
if (formulas && (row.kind === "groupFooter" || row.kind === "footer") && !(c.span > 1)) {
|
|
530
|
+
const f = totalFormula(rows, ri, c, made);
|
|
531
|
+
if (f) {
|
|
532
|
+
cell.f = f;
|
|
533
|
+
made.set(`${ri}|${c.colIndex}`, f);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
cells[c.colIndex] = cell;
|
|
537
|
+
}
|
|
538
|
+
if (header) for (let i = 0; i < cells.length; i++) cells[i] || (cells[i] = { v: null, style: { fill: true } });
|
|
539
|
+
ws.addRow(cells, { outlineLevel: row.kind === "detail" && row.level > 0 ? Math.min(7, row.level) : 0 });
|
|
540
|
+
if (header) headerRows++;
|
|
541
|
+
});
|
|
542
|
+
const last = ws.rowCount, taken = /* @__PURE__ */ new Set();
|
|
543
|
+
for (const [r1, c1, r2, c2] of merges) {
|
|
544
|
+
const box = [];
|
|
545
|
+
let clash = false;
|
|
546
|
+
for (let y = r1; y <= Math.min(r2, last); y++) for (let x = c1; x <= c2; x++) {
|
|
547
|
+
const k = `${y},${x}`;
|
|
548
|
+
if (taken.has(k)) clash = true;
|
|
549
|
+
box.push(k);
|
|
550
|
+
}
|
|
551
|
+
if (clash) continue;
|
|
552
|
+
box.forEach((k) => taken.add(k));
|
|
553
|
+
ws.merge(r1, c1, Math.min(r2, last), c2);
|
|
554
|
+
}
|
|
555
|
+
ws.frozenRows = headerRows;
|
|
556
|
+
ws.outlineLevelRow = Math.min(7, r.rows.reduce((m, x) => Math.max(m, x.kind === "detail" ? x.level || 0 : 0), 0));
|
|
557
|
+
}
|
|
558
|
+
const native = [];
|
|
559
|
+
const nativeFigs = /* @__PURE__ */ new Set();
|
|
560
|
+
if (charts) {
|
|
561
|
+
for (const pg of model.pages) for (const f of figures(pg.items)) {
|
|
562
|
+
const spec = f.tag.k === "chart" ? f.items.find((it) => it.xchart)?.xchart : null;
|
|
563
|
+
if (!spec || native.length >= 100) continue;
|
|
564
|
+
const ws = wb.addSheet(sheetName(spec.title || f.tag.alt || `Chart ${native.length + 1}`));
|
|
565
|
+
const rows = chartTable(spec);
|
|
566
|
+
rows.forEach((r, ri) => ws.addRow(r.map((v) => ({ v, style: ri === 0 ? { bold: true } : void 0 }))));
|
|
567
|
+
ws.widths = rows[0].map((_, ci) => ci === 0 && spec.categories ? 18 : 12);
|
|
568
|
+
native.push({ sheet: ws.name, spec, at: { col: rows[0].length + 1, row: 1 } });
|
|
569
|
+
nativeFigs.add(f.tag);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
if (pictures) {
|
|
573
|
+
let ws = null, row = 1;
|
|
574
|
+
for (const pg of model.pages) for (const f of figures(pg.items)) {
|
|
575
|
+
if (f.tag.k === "shape" || f.tag.k === "line" || nativeFigs.has(f.tag)) continue;
|
|
576
|
+
const pic = await figurePicture(f, { fontStore, fetchImage, rasterize });
|
|
577
|
+
const bytes = pic.png || pic.jpeg;
|
|
578
|
+
if (!bytes) continue;
|
|
579
|
+
ws || (ws = wb.addSheet(sheetName("Charts")));
|
|
580
|
+
while (ws.rowCount < row - 1) ws.addRow([]);
|
|
581
|
+
ws.addRow([{ v: altOf(f.tag), style: { bold: true } }]);
|
|
582
|
+
const w = Math.round(pic.w * 4 / 3), h = Math.round(pic.h * 4 / 3);
|
|
583
|
+
ws.addImage(bytes, pic.png ? "png" : "jpeg", 0, row, w, h);
|
|
584
|
+
row += 2 + Math.ceil(h / 20);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
wb.fullCalcOnLoad = !!formulas;
|
|
588
|
+
return addCharts(wb.write(), native);
|
|
589
|
+
}
|
|
590
|
+
export {
|
|
591
|
+
colStats,
|
|
592
|
+
currencySymbol,
|
|
593
|
+
excelFormat,
|
|
594
|
+
exportXlsx,
|
|
595
|
+
sheetNamer,
|
|
596
|
+
subtotalFn,
|
|
597
|
+
xlsxCell
|
|
598
|
+
};
|
|
599
|
+
//# sourceMappingURL=chunk-KJTRZJHN.js.map
|