@reportwright/viewer 0.11.0 → 0.12.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/CHANGELOG.md +81 -0
- package/README.md +27 -5
- package/dist/{chunk-KJTRZJHN.js → chunk-2BPBQMH2.js} +4 -3
- package/dist/chunk-2BPBQMH2.js.map +6 -0
- package/dist/{chunk-ODREGGKA.js → chunk-3D2KFKG2.js} +5 -4
- package/dist/chunk-3D2KFKG2.js.map +6 -0
- package/dist/chunk-6TPZ7G74.js +494 -0
- package/dist/chunk-6TPZ7G74.js.map +6 -0
- package/dist/chunk-BRB34AJ2.js +16 -0
- package/dist/{chunk-APRPSQOD.js → chunk-DPVJEFKP.js} +28 -9
- package/dist/chunk-DPVJEFKP.js.map +6 -0
- package/dist/{chunk-RYHJUQSV.js → chunk-DXHLIJEY.js} +2 -2
- package/dist/{chunk-SR2TQ2ZK.js → chunk-F6RMRXIN.js} +2 -2
- package/dist/chunk-F6RMRXIN.js.map +6 -0
- package/dist/{chunk-3D43XGIN.js → chunk-M6AYND5G.js} +8 -638
- package/dist/chunk-M6AYND5G.js.map +6 -0
- package/dist/{chunk-HAMBWF6C.js → chunk-NR2G4TMG.js} +39 -31
- package/dist/chunk-NR2G4TMG.js.map +6 -0
- package/dist/{chunk-66QZ3RDV.js → chunk-PGP3QA6L.js} +526 -508
- package/dist/chunk-PGP3QA6L.js.map +6 -0
- package/dist/{chunk-N5WHQ4DM.js → chunk-Q6MMPKQA.js} +14 -9
- package/dist/chunk-Q6MMPKQA.js.map +6 -0
- package/dist/{chunk-SBD55ZES.js → chunk-S2IUUI6N.js} +76 -32
- package/dist/chunk-S2IUUI6N.js.map +6 -0
- package/dist/chunk-ULKEEARQ.js +553 -0
- package/dist/chunk-ULKEEARQ.js.map +6 -0
- package/dist/{chunk-WQOBRZAL.js → chunk-VNOWPSE6.js} +579 -1484
- package/dist/chunk-VNOWPSE6.js.map +6 -0
- package/dist/chunk-Z7MKH66Z.js +642 -0
- package/dist/chunk-Z7MKH66Z.js.map +6 -0
- package/dist/designer.d.ts +10 -3
- package/dist/designer.js +28 -18
- package/dist/designer.js.map +1 -1
- package/dist/engine.worker.js +71 -0
- package/dist/engine.worker.js.map +6 -0
- package/dist/peer/chunk-2FZTYEDE.js +15 -0
- package/dist/peer/{chunk-776OR56A.js → chunk-6I2EAAVN.js} +39 -31
- package/dist/peer/chunk-6I2EAAVN.js.map +6 -0
- package/dist/peer/{chunk-IPU2YRL2.js → chunk-BMAXIBP2.js} +28 -9
- package/dist/peer/chunk-BMAXIBP2.js.map +6 -0
- package/dist/peer/chunk-BQFI3DHK.js +494 -0
- package/dist/peer/chunk-BQFI3DHK.js.map +6 -0
- package/dist/peer/{chunk-76ZABVTI.js → chunk-R4VX5UC7.js} +4 -3
- package/dist/peer/{chunk-5X4ZSSJT.js → chunk-TSC4RAH3.js} +526 -508
- package/dist/peer/chunk-TSC4RAH3.js.map +6 -0
- package/dist/peer/{chunk-M4AGFUWE.js → chunk-V42KN7HD.js} +2 -2
- package/dist/peer/{chunk-Y5CAHLXS.js → chunk-WQGENQZO.js} +5 -4
- package/dist/peer/{chunk-EKWTFHVE.js → chunk-WSNRD2AQ.js} +14 -9
- package/dist/peer/chunk-WSNRD2AQ.js.map +6 -0
- package/dist/peer/designer.js +28 -18
- package/dist/peer/designer.js.map +1 -1
- package/dist/peer/engine.worker.js +70 -0
- package/dist/peer/engine.worker.js.map +6 -0
- package/dist/peer/viewer.js +12 -5
- package/dist/peer/viewer.js.map +1 -1
- package/dist/viewer.d.ts +9 -1
- package/dist/viewer.js +12 -5
- package/dist/viewer.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-3D43XGIN.js.map +0 -6
- package/dist/chunk-66QZ3RDV.js.map +0 -6
- package/dist/chunk-AH47FS6Y.js +0 -13
- package/dist/chunk-APRPSQOD.js.map +0 -6
- package/dist/chunk-HAMBWF6C.js.map +0 -6
- package/dist/chunk-N5WHQ4DM.js.map +0 -6
- package/dist/chunk-SBD55ZES.js.map +0 -6
- package/dist/chunk-SR2TQ2ZK.js.map +0 -6
- package/dist/chunk-WQOBRZAL.js.map +0 -6
- package/dist/peer/chunk-5X4ZSSJT.js.map +0 -6
- package/dist/peer/chunk-6YO42ALN.js +0 -14777
- package/dist/peer/chunk-6YO42ALN.js.map +0 -6
- package/dist/peer/chunk-76ZABVTI.js.map +0 -6
- package/dist/peer/chunk-776OR56A.js.map +0 -6
- package/dist/peer/chunk-EKWTFHVE.js.map +0 -6
- package/dist/peer/chunk-IMQRHDR4.js +0 -12
- package/dist/peer/chunk-IPU2YRL2.js.map +0 -6
- package/dist/peer/chunk-Y5CAHLXS.js.map +0 -6
- /package/dist/{chunk-AH47FS6Y.js.map → chunk-BRB34AJ2.js.map} +0 -0
- /package/dist/{chunk-RYHJUQSV.js.map → chunk-DXHLIJEY.js.map} +0 -0
- /package/dist/peer/{chunk-IMQRHDR4.js.map → chunk-2FZTYEDE.js.map} +0 -0
- /package/dist/{chunk-KJTRZJHN.js.map → peer/chunk-R4VX5UC7.js.map} +0 -0
- /package/dist/peer/{chunk-M4AGFUWE.js.map → chunk-V42KN7HD.js.map} +0 -0
- /package/dist/{chunk-ODREGGKA.js.map → peer/chunk-WQGENQZO.js.map} +0 -0
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
TextMeasurer,
|
|
3
|
+
finishText
|
|
4
|
+
} from "./chunk-ULKEEARQ.js";
|
|
5
|
+
import {
|
|
6
|
+
safeUrl
|
|
7
|
+
} from "./chunk-72S6DETS.js";
|
|
1
8
|
import {
|
|
2
9
|
ExprError,
|
|
3
10
|
capText,
|
|
@@ -19,115 +26,392 @@ import {
|
|
|
19
26
|
validTimeZone
|
|
20
27
|
} from "./chunk-GJS242RR.js";
|
|
21
28
|
import {
|
|
22
|
-
safeUrl
|
|
23
|
-
} from "./chunk-72S6DETS.js";
|
|
24
|
-
import {
|
|
25
|
-
ALL_FONT_KEYS,
|
|
26
29
|
CORE_FONT_KEY,
|
|
27
|
-
DEFAULT_FAMILY,
|
|
28
30
|
FontStore,
|
|
29
31
|
OPTIONAL_KEYS,
|
|
30
32
|
PRELOAD_KEYS,
|
|
31
33
|
PX,
|
|
32
34
|
SHAPER,
|
|
33
|
-
fallbackKey,
|
|
34
|
-
fontCss,
|
|
35
|
-
fontFamilyCss,
|
|
36
|
-
fontFile,
|
|
37
|
-
fontKeysOf,
|
|
38
35
|
fontsFor,
|
|
39
36
|
fontsForDef,
|
|
40
37
|
imageInfo,
|
|
41
38
|
resolveFontKey,
|
|
42
|
-
resolveImageSrc
|
|
43
|
-
|
|
44
|
-
} from "./chunk-3D43XGIN.js";
|
|
39
|
+
resolveImageSrc
|
|
40
|
+
} from "./chunk-Z7MKH66Z.js";
|
|
45
41
|
|
|
46
|
-
// src/
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
// src/engine/data/guard.js
|
|
43
|
+
var FETCH_DEFAULTS = { timeoutMs: 3e4, maxBytes: 64 * 1048576, hops: 5 };
|
|
44
|
+
var V4 = [
|
|
45
|
+
["0.0.0.0", 8],
|
|
46
|
+
["10.0.0.0", 8],
|
|
47
|
+
["100.64.0.0", 10],
|
|
48
|
+
["127.0.0.0", 8],
|
|
49
|
+
["169.254.0.0", 16],
|
|
50
|
+
["172.16.0.0", 12],
|
|
51
|
+
["192.0.0.0", 24],
|
|
52
|
+
["192.0.2.0", 24],
|
|
53
|
+
["192.168.0.0", 16],
|
|
54
|
+
["198.18.0.0", 15],
|
|
55
|
+
["198.51.100.0", 24],
|
|
56
|
+
["203.0.113.0", 24],
|
|
57
|
+
["224.0.0.0", 3]
|
|
58
|
+
].map(([a, p]) => [v4num(String(a)), Number(p)]);
|
|
59
|
+
function v4num(ip) {
|
|
60
|
+
return ip.split(".").reduce((n, x) => n * 256 + Number(x), 0);
|
|
61
|
+
}
|
|
62
|
+
function privateV4(ip) {
|
|
63
|
+
const n = v4num(ip);
|
|
64
|
+
return V4.some(([a, p]) => Math.floor(n / 2 ** (32 - p)) === Math.floor(a / 2 ** (32 - p)));
|
|
65
|
+
}
|
|
66
|
+
function groups6(ip) {
|
|
67
|
+
const [h, t = ""] = ip.split("::");
|
|
68
|
+
const a = h ? h.split(":") : [], b = t ? t.split(":") : [];
|
|
69
|
+
if (b.length && b[b.length - 1].includes(".")) {
|
|
70
|
+
const q = b.pop().split(".").map(Number);
|
|
71
|
+
b.push((q[0] << 8 | q[1]).toString(16), (q[2] << 8 | q[3]).toString(16));
|
|
72
|
+
}
|
|
73
|
+
return [...a, ...Array(Math.max(0, 8 - a.length - b.length)).fill("0"), ...b].map((x) => parseInt(x, 16) || 0);
|
|
74
|
+
}
|
|
75
|
+
function privateV6(ip) {
|
|
76
|
+
const g = groups6(ip);
|
|
77
|
+
const v4 = () => `${g[6] >> 8}.${g[6] & 255}.${g[7] >> 8}.${g[7] & 255}`;
|
|
78
|
+
if (g.slice(0, 6).every((x) => x === 0)) return true;
|
|
79
|
+
if (g.slice(0, 5).every((x) => x === 0) && g[5] === 65535) return privateV4(v4());
|
|
80
|
+
if (g[0] === 100 && g[1] === 65435) return g[2] === 1 || privateV4(v4());
|
|
81
|
+
if (g[0] === 8194 || g[0] === 8193 && g[1] === 0) return true;
|
|
82
|
+
if ((g[0] & 65024) === 64512 || (g[0] & 65472) === 65152 || (g[0] & 65472) === 65216 || (g[0] & 65280) === 65280) return true;
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
function privateHost(host) {
|
|
86
|
+
const h = host.replace(/^\[|\]$/g, "").toLowerCase();
|
|
87
|
+
if (h.includes(":")) return privateV6(h);
|
|
88
|
+
if (/^\d+\.\d+\.\d+\.\d+$/.test(h)) return privateV4(h);
|
|
89
|
+
return h === "localhost" || h.endsWith(".localhost") || h.endsWith(".local") || h.endsWith(".internal");
|
|
90
|
+
}
|
|
91
|
+
var refuse = (host) => Object.assign(new Error(`"${host}" is a private or local address; a data source may not reach it (pass allowHosts: ["${host}"] to render to allow it)`), { status: 403, code: "EPRIVATE" });
|
|
92
|
+
function nodeMod(name) {
|
|
93
|
+
const p = (
|
|
94
|
+
/** @type {any} */
|
|
95
|
+
globalThis.process
|
|
96
|
+
);
|
|
97
|
+
if (!p?.versions?.node) return null;
|
|
98
|
+
if (!p.getBuiltinModule) throw Object.assign(new Error("The engine's fetch guard needs Node 20.16 or later (process.getBuiltinModule); or pass your own fetch to render"), { status: 500 });
|
|
99
|
+
return p.getBuiltinModule(name);
|
|
100
|
+
}
|
|
101
|
+
var inNode = () => !!/** @type {any} */
|
|
102
|
+
globalThis.process?.versions?.node;
|
|
103
|
+
var addrHost = (a) => a.family === 6 || String(a.address).includes(":") ? `[${a.address}]` : String(a.address);
|
|
104
|
+
function checkUrl(input, allow) {
|
|
105
|
+
let u;
|
|
49
106
|
try {
|
|
50
|
-
|
|
107
|
+
u = new URL(input);
|
|
51
108
|
} catch {
|
|
52
|
-
|
|
109
|
+
throw Object.assign(new Error(`Not a URL: ${String(input).slice(0, 200)}`), { status: 400 });
|
|
53
110
|
}
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
111
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") throw Object.assign(new Error(`Only http and https URLs can be fetched, not ${u.protocol}`), { status: 400 });
|
|
112
|
+
if (u.username || u.password) throw Object.assign(new Error("A user name or password in a data URL is not allowed"), { status: 400 });
|
|
113
|
+
const host = u.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
114
|
+
if (!host) throw Object.assign(new Error("A data URL needs a host"), { status: 400 });
|
|
115
|
+
if (allow.includes(host)) return u;
|
|
116
|
+
let bad = true;
|
|
117
|
+
try {
|
|
118
|
+
bad = privateHost(u.hostname);
|
|
119
|
+
} catch {
|
|
120
|
+
}
|
|
121
|
+
if (bad) throw refuse(host);
|
|
122
|
+
return u;
|
|
58
123
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
124
|
+
function nodeRequest(url, init, trusted) {
|
|
125
|
+
const http = nodeMod("node:http"), https = nodeMod("node:https"), dns = nodeMod("node:dns"), stream = nodeMod("node:stream");
|
|
126
|
+
const lookup = (name, o, cb) => dns.lookup(name, { ...o, all: true }, (err, list) => {
|
|
127
|
+
if (err || !Array.isArray(list) || !list.length) return cb(err || refuse(name));
|
|
128
|
+
let bad = true;
|
|
129
|
+
try {
|
|
130
|
+
bad = !trusted && list.some((a) => privateHost(addrHost(a)));
|
|
131
|
+
} catch {
|
|
132
|
+
}
|
|
133
|
+
if (bad) return cb(refuse(name));
|
|
134
|
+
return o.all ? cb(null, list) : cb(null, list[0].address, list[0].family);
|
|
135
|
+
});
|
|
136
|
+
const headers = Object.fromEntries(new Headers(init.headers || {}));
|
|
137
|
+
headers["accept-encoding"] = "identity";
|
|
138
|
+
return new Promise((resolve, reject) => {
|
|
139
|
+
const req = (url.protocol === "https:" ? https : http).request(url, { method: init.method || "GET", headers, lookup, signal: init.signal }, (res) => {
|
|
140
|
+
const pairs = [];
|
|
141
|
+
for (let i = 0; i < res.rawHeaders.length; i += 2) pairs.push([res.rawHeaders[i], res.rawHeaders[i + 1]]);
|
|
142
|
+
const none = [101, 204, 205, 304].includes(res.statusCode) || (init.method || "GET").toUpperCase() === "HEAD";
|
|
143
|
+
if (none) res.resume();
|
|
144
|
+
const enc = String(res.headers["content-encoding"] || "").trim().toLowerCase();
|
|
145
|
+
let body = res, decoded = false;
|
|
146
|
+
if (!none && enc && enc !== "identity") {
|
|
147
|
+
const zlib = nodeMod("node:zlib");
|
|
148
|
+
const dec2 = enc === "gzip" || enc === "x-gzip" ? zlib.createGunzip() : enc === "deflate" ? zlib.createInflate() : enc === "br" ? zlib.createBrotliDecompress() : null;
|
|
149
|
+
if (!dec2) {
|
|
150
|
+
res.resume();
|
|
151
|
+
return reject(Object.assign(new Error(`the response is encoded as "${enc}", which the data fetch cannot decode`), { status: 415 }));
|
|
152
|
+
}
|
|
153
|
+
body = stream.pipeline(res, dec2, () => {
|
|
154
|
+
});
|
|
155
|
+
decoded = true;
|
|
156
|
+
}
|
|
157
|
+
const kept = decoded ? pairs.filter(([k]) => !/^(content-encoding|content-length)$/i.test(k)) : pairs;
|
|
158
|
+
resolve(new Response(none ? null : stream.Readable.toWeb(body), { status: res.statusCode, statusText: res.statusMessage, headers: (
|
|
159
|
+
/** @type {any} */
|
|
160
|
+
kept
|
|
161
|
+
) }));
|
|
162
|
+
});
|
|
163
|
+
req.on("error", reject);
|
|
164
|
+
req.end(init.body ?? void 0);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
var CROSS_ORIGIN_KEEP = /* @__PURE__ */ new Set(["accept", "accept-language", "content-type"]);
|
|
168
|
+
function redirectRequest(from, to, req, status) {
|
|
169
|
+
if (from.protocol === "https:" && to.protocol !== "https:") throw Object.assign(new Error(`${from.host} redirects from https to http; not followed`), { status: 403 });
|
|
170
|
+
const headers = new Headers(req.headers || {});
|
|
171
|
+
if (to.origin !== from.origin) {
|
|
172
|
+
for (const k of [...headers.keys()]) if (!CROSS_ORIGIN_KEEP.has(k)) headers.delete(k);
|
|
173
|
+
}
|
|
174
|
+
const get = status === 303 || (status === 301 || status === 302) && (req.method || "GET").toUpperCase() !== "GET";
|
|
175
|
+
return get ? { ...req, method: "GET", body: void 0, headers } : { ...req, headers };
|
|
176
|
+
}
|
|
177
|
+
function guardedFetch(opt, base) {
|
|
178
|
+
const allow = (opt.allowHosts || []).map((h) => String(h).toLowerCase().replace(/^\[|\]$/g, ""));
|
|
179
|
+
const node = !opt.viaBase && inNode();
|
|
63
180
|
return (
|
|
64
181
|
/** @type {any} */
|
|
65
|
-
(async (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
for (let
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
await
|
|
182
|
+
(async (input, init = {}) => {
|
|
183
|
+
let url = checkUrl(String(input), allow);
|
|
184
|
+
let req = { ...init };
|
|
185
|
+
for (let hop = 0; ; hop++) {
|
|
186
|
+
const trusted = allow.includes(url.hostname.replace(/^\[|\]$/g, "").toLowerCase());
|
|
187
|
+
const res = node ? await nodeRequest(url, req, trusted) : await base(url.href, { ...req, redirect: "manual" });
|
|
188
|
+
if (res.type === "opaqueredirect") throw new Error(`${url.host} redirects; a redirect cannot be checked here (pass your own fetch to render)`);
|
|
189
|
+
const loc = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
|
|
190
|
+
if (!loc) return res;
|
|
191
|
+
await res.body?.cancel().catch(() => {
|
|
192
|
+
});
|
|
193
|
+
if (hop >= FETCH_DEFAULTS.hops) throw new Error(`Too many redirects from ${url.host}`);
|
|
194
|
+
const next = checkUrl(new URL(loc, url).href, allow);
|
|
195
|
+
req = redirectRequest(url, next, req, res.status);
|
|
196
|
+
url = next;
|
|
75
197
|
}
|
|
76
198
|
})
|
|
77
199
|
);
|
|
78
200
|
}
|
|
79
|
-
function
|
|
80
|
-
const
|
|
81
|
-
const
|
|
201
|
+
function boundedFetch(f4, opt) {
|
|
202
|
+
const ms0 = Number(opt.fetchTimeoutMs) > 0 ? Number(opt.fetchTimeoutMs) : FETCH_DEFAULTS.timeoutMs;
|
|
203
|
+
const max = Number(opt.maxFetchBytes) > 0 ? Number(opt.maxFetchBytes) : FETCH_DEFAULTS.maxBytes;
|
|
82
204
|
return (
|
|
83
205
|
/** @type {any} */
|
|
84
206
|
(async (input, init = {}) => {
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
207
|
+
const ms = Math.max(1, Math.min(ms0, opt.deadline ? opt.deadline - Date.now() : Infinity));
|
|
208
|
+
const ctl = new AbortController();
|
|
209
|
+
const timer = setTimeout(() => ctl.abort(Object.assign(new Error(`The data request took longer than ${Math.round(ms)} ms`), { status: 504 })), ms);
|
|
210
|
+
const signal = init.signal ? anySignal([init.signal, ctl.signal]) : ctl.signal;
|
|
211
|
+
let res;
|
|
212
|
+
const stop = new Promise((_, rej) => signal.addEventListener("abort", () => rej(signal.reason), { once: true }));
|
|
213
|
+
stop.catch(() => {
|
|
214
|
+
});
|
|
89
215
|
try {
|
|
90
|
-
|
|
91
|
-
} catch {
|
|
92
|
-
|
|
216
|
+
res = await Promise.race([f4(input, { ...init, signal }), stop]);
|
|
217
|
+
} catch (e) {
|
|
218
|
+
clearTimeout(timer);
|
|
219
|
+
throw ctl.signal.aborted ? ctl.signal.reason : fetchFailure(e, input);
|
|
93
220
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
221
|
+
if (!res.body || /** @type {any} */
|
|
222
|
+
init.pwStream) {
|
|
223
|
+
clearTimeout(timer);
|
|
224
|
+
return res;
|
|
97
225
|
}
|
|
98
|
-
|
|
99
|
-
|
|
226
|
+
let n = 0;
|
|
227
|
+
const reader = res.body.getReader();
|
|
228
|
+
const body = new ReadableStream({
|
|
229
|
+
async pull(c) {
|
|
230
|
+
try {
|
|
231
|
+
const { done, value } = await reader.read();
|
|
232
|
+
if (done) {
|
|
233
|
+
clearTimeout(timer);
|
|
234
|
+
c.close();
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
n += value.byteLength;
|
|
238
|
+
if (n > max) {
|
|
239
|
+
clearTimeout(timer);
|
|
240
|
+
reader.cancel().catch(() => {
|
|
241
|
+
});
|
|
242
|
+
c.error(Object.assign(new Error(`The data response is larger than ${Math.round(max / 1048576)} MB (maxFetchBytes)`), { status: 413 }));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
c.enqueue(value);
|
|
246
|
+
} catch (e) {
|
|
247
|
+
clearTimeout(timer);
|
|
248
|
+
c.error(ctl.signal.aborted ? ctl.signal.reason : e);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
cancel(r) {
|
|
252
|
+
clearTimeout(timer);
|
|
253
|
+
return reader.cancel(r);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
return new Response(body, { status: res.status, statusText: res.statusText, headers: res.headers });
|
|
100
257
|
})
|
|
101
258
|
);
|
|
102
259
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
260
|
+
var CAUSES = {
|
|
261
|
+
ENOTFOUND: "the host name did not resolve",
|
|
262
|
+
EAI_AGAIN: "DNS lookup timed out",
|
|
263
|
+
ECONNREFUSED: "connection refused",
|
|
264
|
+
ECONNRESET: "connection reset",
|
|
265
|
+
EPIPE: "connection closed",
|
|
266
|
+
UND_ERR_SOCKET: "connection closed early",
|
|
267
|
+
ETIMEDOUT: "timed out",
|
|
268
|
+
UND_ERR_CONNECT_TIMEOUT: "connect timed out",
|
|
269
|
+
EPROTO: "TLS error",
|
|
270
|
+
ERR_TLS_CERT_ALTNAME_INVALID: "TLS certificate does not match the host",
|
|
271
|
+
DEPTH_ZERO_SELF_SIGNED_CERT: "TLS certificate is self-signed",
|
|
272
|
+
SELF_SIGNED_CERT_IN_CHAIN: "TLS certificate chain is untrusted",
|
|
273
|
+
UNABLE_TO_VERIFY_LEAF_SIGNATURE: "TLS certificate chain is untrusted",
|
|
274
|
+
CERT_HAS_EXPIRED: "TLS certificate has expired"
|
|
275
|
+
};
|
|
276
|
+
function redactUrl(s) {
|
|
277
|
+
const str = String(s);
|
|
278
|
+
const q = str.search(/[?#]/);
|
|
279
|
+
const base = (q >= 0 ? str.slice(0, q) : str).replace(/^([a-z][\w+.-]*:\/\/)[^/?#]*@/i, "$1");
|
|
280
|
+
return q >= 0 ? `${base}${str[q]}…` : base;
|
|
281
|
+
}
|
|
282
|
+
function fetchFailure(e, input) {
|
|
283
|
+
if (!e || e.status) return e;
|
|
284
|
+
const code = String(e.cause?.code || e.code || "");
|
|
285
|
+
if (!code && e.message !== "fetch failed") return e;
|
|
286
|
+
const why = CAUSES[code] || (/^ERR_TLS|CERT_|SSL/.test(code) ? "TLS error" : "");
|
|
287
|
+
const at = redactUrl(input?.href ?? input);
|
|
288
|
+
return Object.assign(new Error(`the request to ${at} failed${why ? `: ${why}` : ""}${code ? ` (${code})` : ""}`), { code: e.code });
|
|
289
|
+
}
|
|
290
|
+
function anySignal(list) {
|
|
291
|
+
const S3 = (
|
|
292
|
+
/** @type {any} */
|
|
293
|
+
AbortSignal
|
|
294
|
+
);
|
|
295
|
+
if (S3.any) return S3.any(list);
|
|
296
|
+
const c = new AbortController();
|
|
297
|
+
for (const s of list) {
|
|
298
|
+
if (s.aborted) c.abort(s.reason);
|
|
299
|
+
else s.addEventListener("abort", () => c.abort(s.reason), { once: true });
|
|
300
|
+
}
|
|
301
|
+
return c.signal;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// src/viewer/dataFetch.js
|
|
305
|
+
function sqlCall(body, sqlPreview) {
|
|
306
|
+
let b;
|
|
307
|
+
try {
|
|
308
|
+
b = JSON.parse(String(body));
|
|
309
|
+
} catch {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
if (!b || typeof b !== "object" || Array.isArray(b)) return false;
|
|
313
|
+
const keys = Object.keys(b);
|
|
314
|
+
if (typeof b.report === "string" && typeof b.source === "string") return keys.every((k) => ["report", "source", "params"].includes(k));
|
|
315
|
+
return sqlPreview && typeof b.query === "string" && keys.every((k) => ["connection", "query", "params"].includes(k));
|
|
316
|
+
}
|
|
317
|
+
var policy = { allowHosts: [], unsafeFetch: false, fetch: null };
|
|
318
|
+
function setFetchPolicy({ allowHosts, unsafeFetch = false, fetch: f4 = null } = {}) {
|
|
319
|
+
policy = { allowHosts: (allowHosts || []).map((h) => String(h).toLowerCase().replace(/^\[|\]$/g, "")), unsafeFetch: !!unsafeFetch, fetch: typeof f4 === "function" ? f4 : null };
|
|
320
|
+
}
|
|
321
|
+
var POLICY_KEYS = ["allowHosts", "unsafeFetch", "allowPrivate"];
|
|
322
|
+
function policyKeysIn(def) {
|
|
323
|
+
const has = (o) => POLICY_KEYS.filter((k) => o && typeof o === "object" && Object.hasOwn(o, k));
|
|
324
|
+
return [...has(def), ...(Array.isArray(def?.dataSources) ? def.dataSources : []).flatMap((s) => has(s).map((k) => `${s.name}.${k}`))];
|
|
325
|
+
}
|
|
326
|
+
var fetchPolicy = () => policy;
|
|
327
|
+
function failed(e, url) {
|
|
328
|
+
if (e?.status || !(e instanceof TypeError)) return e;
|
|
329
|
+
return Object.assign(new Error(`the request to ${redactUrl(url)} failed (${e.message}): the server may not allow this page to read it (CORS: it must send Access-Control-Allow-Origin), the network or the server may be down, or the browser blocked it (a content security policy or an extension)`), { cause: e });
|
|
330
|
+
}
|
|
331
|
+
var DATA = [/^\/api\/sample\//, /^\/api\/data\/proxy$/];
|
|
332
|
+
var OURS = /^\/(?:$|api(?:\/|$)|admin(?:\/|$)|designer(?:\/|$)|viewer(?:\/|$)|login(?:\/|$)|embed(?:\/|$)|_next(?:\/|$))/i;
|
|
333
|
+
var BUSY = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
334
|
+
function withRetry(f4, { onRetry, retries = 3, wait = (ms) => new Promise((r) => setTimeout(r, ms)) } = {}) {
|
|
335
|
+
return (
|
|
336
|
+
/** @type {any} */
|
|
337
|
+
(async (url, init = {}) => {
|
|
338
|
+
const method = String(init.method || "GET").toUpperCase();
|
|
339
|
+
const read = method === "GET" || method === "HEAD" || method === "POST" && /\/api\/data\/sql$/.test(new URL(String(url), "http://x").pathname);
|
|
340
|
+
for (let attempt = 1; ; attempt++) {
|
|
341
|
+
const res = await f4(url, init);
|
|
342
|
+
if (!read || !BUSY.has(res.status) || attempt > retries) return res;
|
|
343
|
+
const after = Number(res.headers?.get?.("retry-after"));
|
|
344
|
+
const ms = Number.isFinite(after) && after >= 0 ? Math.min(1e4, after * 1e3) : Math.round(400 * 2 ** (attempt - 1) * (0.75 + Math.random() * 0.5));
|
|
345
|
+
onRetry?.({ attempt, max: retries, status: res.status });
|
|
346
|
+
await wait(ms);
|
|
347
|
+
}
|
|
348
|
+
})
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
function reportFetch(base, f0 = policy.fetch || ((...a) => fetch(...a)), { sqlPreview = false, onRetry, retries = 3, wait } = {}) {
|
|
352
|
+
const self = new URL(base).origin;
|
|
353
|
+
const { allowHosts, unsafeFetch } = policy;
|
|
354
|
+
const send = (url, init) => f0(url, init).catch((e) => {
|
|
355
|
+
throw failed(e, url);
|
|
356
|
+
});
|
|
357
|
+
const f4 = withRetry(send, { onRetry, retries, wait });
|
|
358
|
+
const guarded = unsafeFetch ? f4 : guardedFetch({ allowHosts, viaBase: true }, f4);
|
|
359
|
+
const other = (url, init) => guarded(url, init).catch((e) => {
|
|
360
|
+
if (e?.code === "EPRIVATE") e.message = e.message.replace(/pass allowHosts: (\[[^\]]*\]) to render/, "mountViewer({ allowHosts: $1 })");
|
|
361
|
+
else if (e && typeof e === "object") e.message = String(e.message).replace("(pass your own fetch to render)", "(a browser cannot see where it leads: use the URL it redirects to, or render on the server)");
|
|
362
|
+
throw e;
|
|
363
|
+
});
|
|
364
|
+
const out = (
|
|
365
|
+
/** @type {any} */
|
|
366
|
+
(async (input, init = {}) => {
|
|
367
|
+
const u = new URL(String(input instanceof Request ? input.url : input), base);
|
|
368
|
+
const method = String(init.method || "GET").toUpperCase();
|
|
369
|
+
if (u.origin !== self) return other(u.href, { ...init, credentials: "omit" });
|
|
370
|
+
let path;
|
|
371
|
+
try {
|
|
372
|
+
path = decodeURIComponent(u.pathname).replace(/\/{2,}/g, "/");
|
|
373
|
+
} catch {
|
|
374
|
+
path = null;
|
|
375
|
+
}
|
|
376
|
+
const read = path !== null && ["GET", "HEAD"].includes(method) && !/%2f|%5c/i.test(u.pathname) && (DATA.some((r) => r.test(path)) || !OURS.test(path));
|
|
377
|
+
if (!read && !(method === "POST" && u.pathname === "/api/data/sql" && sqlCall(init.body, sqlPreview))) {
|
|
378
|
+
throw Object.assign(new Error(`A data source may only read data from this ReportWright server (sample data, the data proxy, saved SQL), not ${method} ${path}.`), { status: 403 });
|
|
379
|
+
}
|
|
380
|
+
const ours = DATA.some((r) => r.test(u.pathname)) || u.pathname === "/api/data/sql";
|
|
381
|
+
return f4(u.href, { ...init, credentials: ours ? "same-origin" : "omit", redirect: "error" });
|
|
382
|
+
})
|
|
383
|
+
);
|
|
384
|
+
if (!unsafeFetch) out.hostRule = { allowHosts };
|
|
385
|
+
return out;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// src/engine/expr/evaluate.js
|
|
389
|
+
var ROOTS = { fields: "Fields", parameters: "Parameters", globals: "Globals", parent: "Parent", theme: "Theme", partproperties: "PartProperties" };
|
|
390
|
+
var astCache = /* @__PURE__ */ new Map();
|
|
391
|
+
function compile(src) {
|
|
392
|
+
let a = astCache.get(src);
|
|
393
|
+
if (!a) {
|
|
394
|
+
a = parse(src);
|
|
395
|
+
if (astCache.size > 5e3) astCache.clear();
|
|
396
|
+
astCache.set(src, a);
|
|
397
|
+
}
|
|
398
|
+
return a;
|
|
399
|
+
}
|
|
400
|
+
var tplCache = /* @__PURE__ */ new Map();
|
|
401
|
+
function parseValue(v) {
|
|
402
|
+
if (typeof v !== "string") return { kind: "lit", v };
|
|
403
|
+
let p = tplCache.get(v);
|
|
404
|
+
if (p) {
|
|
405
|
+
if (p.kind === "err") throw p.error;
|
|
406
|
+
return p;
|
|
407
|
+
}
|
|
408
|
+
try {
|
|
409
|
+
p = parseFresh(v);
|
|
410
|
+
} catch (e) {
|
|
411
|
+
if (!(e instanceof ExprError)) throw e;
|
|
412
|
+
p = { kind: "err", error: e };
|
|
413
|
+
}
|
|
414
|
+
if (tplCache.size > 5e3) tplCache.clear();
|
|
131
415
|
tplCache.set(v, p);
|
|
132
416
|
if (p.kind === "err") throw p.error;
|
|
133
417
|
return p;
|
|
@@ -1735,321 +2019,73 @@ var METHODS = {
|
|
|
1735
2019
|
trim: "trim",
|
|
1736
2020
|
trimstart: "trimstart",
|
|
1737
2021
|
trimend: "trimend",
|
|
1738
|
-
startswith: "startswith",
|
|
1739
|
-
endswith: "endswith",
|
|
1740
|
-
indexof: "indexof",
|
|
1741
|
-
lastindexof: "lastindexof",
|
|
1742
|
-
contains: "contains",
|
|
1743
|
-
replace: "replace",
|
|
1744
|
-
split: "split",
|
|
1745
|
-
tostring: "tostring"
|
|
1746
|
-
};
|
|
1747
|
-
function netFormat(f4, args, ctx) {
|
|
1748
|
-
let out = "";
|
|
1749
|
-
for (let i = 0; i < f4.length; i++) {
|
|
1750
|
-
const c = f4[i];
|
|
1751
|
-
if (c === "{" && f4[i + 1] === "{") {
|
|
1752
|
-
out += "{";
|
|
1753
|
-
i++;
|
|
1754
|
-
continue;
|
|
1755
|
-
}
|
|
1756
|
-
if (c === "}" && f4[i + 1] === "}") {
|
|
1757
|
-
out += "}";
|
|
1758
|
-
i++;
|
|
1759
|
-
continue;
|
|
1760
|
-
}
|
|
1761
|
-
if (c === "}") throw new ExprError('String.Format: a "}" without its "{"');
|
|
1762
|
-
if (c !== "{") {
|
|
1763
|
-
out += c;
|
|
1764
|
-
continue;
|
|
1765
|
-
}
|
|
1766
|
-
const e = f4.indexOf("}", i);
|
|
1767
|
-
if (e < 0) throw new ExprError('String.Format: a "{" without its "}"');
|
|
1768
|
-
const m = /^\s*(\d{1,3})\s*(?:,\s*(-?\d{1,4}))?\s*(?::([^}]*))?$/.exec(f4.slice(i + 1, e));
|
|
1769
|
-
if (!m) throw new ExprError(`String.Format: "{${f4.slice(i + 1, e).slice(0, 20)}}" is not a placeholder`);
|
|
1770
|
-
const k = Number(m[1]);
|
|
1771
|
-
if (k >= args.length) throw new ExprError(`String.Format: {${k}} has no argument`);
|
|
1772
|
-
let t = toText(args[k], m[3] || null, ctx);
|
|
1773
|
-
const w = m[2] ? Number(m[2]) : 0;
|
|
1774
|
-
if (Math.abs(w) > t.length) t = w < 0 ? t.padEnd(-w) : t.padStart(w);
|
|
1775
|
-
capText("String.Format", out.length + t.length + f4.length - e);
|
|
1776
|
-
out += t;
|
|
1777
|
-
i = e;
|
|
1778
|
-
}
|
|
1779
|
-
return out;
|
|
1780
|
-
}
|
|
1781
|
-
function callCustom(n, name, ctx) {
|
|
1782
|
-
if (n.obj && n.obj.type === "id" && n.obj.name.toLowerCase() === "string" && name === "format") {
|
|
1783
|
-
if (!n.args.length) throw new ExprError("String.Format needs a format", n.p);
|
|
1784
|
-
const [f5, ...rest] = n.args.map((a) => evaluate(a, ctx));
|
|
1785
|
-
return netFormat(S(f5), rest, ctx);
|
|
1786
|
-
}
|
|
1787
|
-
const viaValue = n.obj && !(n.obj.type === "id" && n.obj.name.toLowerCase() === "code");
|
|
1788
|
-
if (viaValue && Object.hasOwn(METHODS, name)) {
|
|
1789
|
-
return FUNCTIONS[METHODS[name]](ctx, evaluate(n.obj, ctx), ...n.args.map((a) => evaluate(a, ctx)));
|
|
1790
|
-
}
|
|
1791
|
-
if (viaValue && n.name in Object.prototype) throw new ExprError(`The value has no member ${n.name}`, n.p);
|
|
1792
|
-
const viaCode = !!n.obj;
|
|
1793
|
-
if (viaCode && !(n.obj.type === "id" && n.obj.name.toLowerCase() === "code")) throw new ExprError(`"${n.name}(…)" after "." is not supported; report functions are called as Code.${n.name}(…)`, n.p);
|
|
1794
|
-
const table = ctx.functions;
|
|
1795
|
-
const f4 = table?.byName.get(name);
|
|
1796
|
-
if (!f4 || !viaCode && builtin(name)) throw new ExprError(viaCode ? `The report has no function "${n.name}"` : `Unknown function "${n.name}"`, n.p);
|
|
1797
|
-
const params = Array.isArray(f4.params) ? f4.params : [];
|
|
1798
|
-
if (n.args.length !== params.length) throw new ExprError(`${f4.name} needs ${params.length} argument${params.length === 1 ? "" : "s"}`, n.p);
|
|
1799
|
-
const depth = (ctx.fnDepth || 0) + 1;
|
|
1800
|
-
if (depth > MAX_FN_DEPTH) throw new ExprError(`${f4.name}: functions call each other more than ${MAX_FN_DEPTH} deep`, n.p);
|
|
1801
|
-
if (++table.count.n > MAX_FN_CALLS) throw new ExprError(`Report functions were called more than 1,000,000 times in this render`, n.p);
|
|
1802
|
-
const locals = /* @__PURE__ */ Object.create(null);
|
|
1803
|
-
for (let i = 0; i < params.length; i++) locals[String(params[i]).toLowerCase()] = evaluate(n.args[i], ctx);
|
|
1804
|
-
return evaluate(compile(String(f4.body).replace(/^=/, "")), Object.assign({}, ctx, { locals, fnDepth: depth }));
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
// src/engine/data/guard.js
|
|
1808
|
-
var FETCH_DEFAULTS = { timeoutMs: 3e4, maxBytes: 64 * 1048576, hops: 5 };
|
|
1809
|
-
var V4 = [
|
|
1810
|
-
["0.0.0.0", 8],
|
|
1811
|
-
["10.0.0.0", 8],
|
|
1812
|
-
["100.64.0.0", 10],
|
|
1813
|
-
["127.0.0.0", 8],
|
|
1814
|
-
["169.254.0.0", 16],
|
|
1815
|
-
["172.16.0.0", 12],
|
|
1816
|
-
["192.0.0.0", 24],
|
|
1817
|
-
["192.0.2.0", 24],
|
|
1818
|
-
["192.168.0.0", 16],
|
|
1819
|
-
["198.18.0.0", 15],
|
|
1820
|
-
["198.51.100.0", 24],
|
|
1821
|
-
["203.0.113.0", 24],
|
|
1822
|
-
["224.0.0.0", 3]
|
|
1823
|
-
].map(([a, p]) => [v4num(String(a)), Number(p)]);
|
|
1824
|
-
function v4num(ip) {
|
|
1825
|
-
return ip.split(".").reduce((n, x) => n * 256 + Number(x), 0);
|
|
1826
|
-
}
|
|
1827
|
-
function privateV4(ip) {
|
|
1828
|
-
const n = v4num(ip);
|
|
1829
|
-
return V4.some(([a, p]) => Math.floor(n / 2 ** (32 - p)) === Math.floor(a / 2 ** (32 - p)));
|
|
1830
|
-
}
|
|
1831
|
-
function groups6(ip) {
|
|
1832
|
-
const [h, t = ""] = ip.split("::");
|
|
1833
|
-
const a = h ? h.split(":") : [], b = t ? t.split(":") : [];
|
|
1834
|
-
if (b.length && b[b.length - 1].includes(".")) {
|
|
1835
|
-
const q = b.pop().split(".").map(Number);
|
|
1836
|
-
b.push((q[0] << 8 | q[1]).toString(16), (q[2] << 8 | q[3]).toString(16));
|
|
1837
|
-
}
|
|
1838
|
-
return [...a, ...Array(Math.max(0, 8 - a.length - b.length)).fill("0"), ...b].map((x) => parseInt(x, 16) || 0);
|
|
1839
|
-
}
|
|
1840
|
-
function privateV6(ip) {
|
|
1841
|
-
const g = groups6(ip);
|
|
1842
|
-
const v4 = () => `${g[6] >> 8}.${g[6] & 255}.${g[7] >> 8}.${g[7] & 255}`;
|
|
1843
|
-
if (g.slice(0, 6).every((x) => x === 0)) return true;
|
|
1844
|
-
if (g.slice(0, 5).every((x) => x === 0) && g[5] === 65535) return privateV4(v4());
|
|
1845
|
-
if (g[0] === 100 && g[1] === 65435) return g[2] === 1 || privateV4(v4());
|
|
1846
|
-
if (g[0] === 8194 || g[0] === 8193 && g[1] === 0) return true;
|
|
1847
|
-
if ((g[0] & 65024) === 64512 || (g[0] & 65472) === 65152 || (g[0] & 65472) === 65216 || (g[0] & 65280) === 65280) return true;
|
|
1848
|
-
return false;
|
|
1849
|
-
}
|
|
1850
|
-
function privateHost(host) {
|
|
1851
|
-
const h = host.replace(/^\[|\]$/g, "").toLowerCase();
|
|
1852
|
-
if (h.includes(":")) return privateV6(h);
|
|
1853
|
-
if (/^\d+\.\d+\.\d+\.\d+$/.test(h)) return privateV4(h);
|
|
1854
|
-
return h === "localhost" || h.endsWith(".localhost") || h.endsWith(".local") || h.endsWith(".internal");
|
|
1855
|
-
}
|
|
1856
|
-
var refuse = (host) => Object.assign(new Error(`"${host}" is a private or local address; a data source may not reach it (pass allowHosts: ["${host}"] to render to allow it)`), { status: 403, code: "EPRIVATE" });
|
|
1857
|
-
function nodeMod(name) {
|
|
1858
|
-
const p = (
|
|
1859
|
-
/** @type {any} */
|
|
1860
|
-
globalThis.process
|
|
1861
|
-
);
|
|
1862
|
-
if (!p?.versions?.node) return null;
|
|
1863
|
-
if (!p.getBuiltinModule) throw Object.assign(new Error("The engine's fetch guard needs Node 20.16 or later (process.getBuiltinModule); or pass your own fetch to render"), { status: 500 });
|
|
1864
|
-
return p.getBuiltinModule(name);
|
|
1865
|
-
}
|
|
1866
|
-
var inNode = () => !!/** @type {any} */
|
|
1867
|
-
globalThis.process?.versions?.node;
|
|
1868
|
-
var addrHost = (a) => a.family === 6 || String(a.address).includes(":") ? `[${a.address}]` : String(a.address);
|
|
1869
|
-
function checkUrl(input, allow) {
|
|
1870
|
-
let u;
|
|
1871
|
-
try {
|
|
1872
|
-
u = new URL(input);
|
|
1873
|
-
} catch {
|
|
1874
|
-
throw Object.assign(new Error(`Not a URL: ${String(input).slice(0, 200)}`), { status: 400 });
|
|
1875
|
-
}
|
|
1876
|
-
if (u.protocol !== "http:" && u.protocol !== "https:") throw Object.assign(new Error(`Only http and https URLs can be fetched, not ${u.protocol}`), { status: 400 });
|
|
1877
|
-
if (u.username || u.password) throw Object.assign(new Error("A user name or password in a data URL is not allowed"), { status: 400 });
|
|
1878
|
-
const host = u.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
1879
|
-
if (!host) throw Object.assign(new Error("A data URL needs a host"), { status: 400 });
|
|
1880
|
-
if (allow.includes(host)) return u;
|
|
1881
|
-
let bad = true;
|
|
1882
|
-
try {
|
|
1883
|
-
bad = privateHost(u.hostname);
|
|
1884
|
-
} catch {
|
|
1885
|
-
}
|
|
1886
|
-
if (bad) throw refuse(host);
|
|
1887
|
-
return u;
|
|
1888
|
-
}
|
|
1889
|
-
function nodeRequest(url, init, trusted) {
|
|
1890
|
-
const http = nodeMod("node:http"), https = nodeMod("node:https"), dns = nodeMod("node:dns"), stream = nodeMod("node:stream");
|
|
1891
|
-
const lookup = (name, o, cb) => dns.lookup(name, { ...o, all: true }, (err, list) => {
|
|
1892
|
-
if (err || !Array.isArray(list) || !list.length) return cb(err || refuse(name));
|
|
1893
|
-
let bad = true;
|
|
1894
|
-
try {
|
|
1895
|
-
bad = !trusted && list.some((a) => privateHost(addrHost(a)));
|
|
1896
|
-
} catch {
|
|
1897
|
-
}
|
|
1898
|
-
if (bad) return cb(refuse(name));
|
|
1899
|
-
return o.all ? cb(null, list) : cb(null, list[0].address, list[0].family);
|
|
1900
|
-
});
|
|
1901
|
-
const headers = Object.fromEntries(new Headers(init.headers || {}));
|
|
1902
|
-
headers["accept-encoding"] = "identity";
|
|
1903
|
-
return new Promise((resolve, reject) => {
|
|
1904
|
-
const req = (url.protocol === "https:" ? https : http).request(url, { method: init.method || "GET", headers, lookup, signal: init.signal }, (res) => {
|
|
1905
|
-
const pairs = [];
|
|
1906
|
-
for (let i = 0; i < res.rawHeaders.length; i += 2) pairs.push([res.rawHeaders[i], res.rawHeaders[i + 1]]);
|
|
1907
|
-
const none = [101, 204, 205, 304].includes(res.statusCode) || (init.method || "GET").toUpperCase() === "HEAD";
|
|
1908
|
-
if (none) res.resume();
|
|
1909
|
-
resolve(new Response(none ? null : stream.Readable.toWeb(res), { status: res.statusCode, statusText: res.statusMessage, headers: (
|
|
1910
|
-
/** @type {any} */
|
|
1911
|
-
pairs
|
|
1912
|
-
) }));
|
|
1913
|
-
});
|
|
1914
|
-
req.on("error", reject);
|
|
1915
|
-
req.end(init.body ?? void 0);
|
|
1916
|
-
});
|
|
1917
|
-
}
|
|
1918
|
-
var CROSS_ORIGIN_KEEP = /* @__PURE__ */ new Set(["accept", "accept-language", "content-type"]);
|
|
1919
|
-
function redirectRequest(from, to, req, status) {
|
|
1920
|
-
if (from.protocol === "https:" && to.protocol !== "https:") throw Object.assign(new Error(`${from.host} redirects from https to http; not followed`), { status: 403 });
|
|
1921
|
-
const headers = new Headers(req.headers || {});
|
|
1922
|
-
if (to.origin !== from.origin) {
|
|
1923
|
-
for (const k of [...headers.keys()]) if (!CROSS_ORIGIN_KEEP.has(k)) headers.delete(k);
|
|
1924
|
-
}
|
|
1925
|
-
const get = status === 303 || (status === 301 || status === 302) && (req.method || "GET").toUpperCase() !== "GET";
|
|
1926
|
-
return get ? { ...req, method: "GET", body: void 0, headers } : { ...req, headers };
|
|
1927
|
-
}
|
|
1928
|
-
function guardedFetch(opt, base) {
|
|
1929
|
-
const allow = (opt.allowHosts || []).map((h) => String(h).toLowerCase().replace(/^\[|\]$/g, ""));
|
|
1930
|
-
const node = inNode();
|
|
1931
|
-
return (
|
|
1932
|
-
/** @type {any} */
|
|
1933
|
-
(async (input, init = {}) => {
|
|
1934
|
-
let url = checkUrl(String(input), allow);
|
|
1935
|
-
let req = { ...init };
|
|
1936
|
-
for (let hop = 0; ; hop++) {
|
|
1937
|
-
const trusted = allow.includes(url.hostname.replace(/^\[|\]$/g, "").toLowerCase());
|
|
1938
|
-
const res = node ? await nodeRequest(url, req, trusted) : await base(url.href, { ...req, redirect: "manual" });
|
|
1939
|
-
if (res.type === "opaqueredirect") throw new Error(`${url.host} redirects; a redirect cannot be checked here (pass your own fetch to render)`);
|
|
1940
|
-
const loc = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
|
|
1941
|
-
if (!loc) return res;
|
|
1942
|
-
await res.body?.cancel().catch(() => {
|
|
1943
|
-
});
|
|
1944
|
-
if (hop >= FETCH_DEFAULTS.hops) throw new Error(`Too many redirects from ${url.host}`);
|
|
1945
|
-
const next = checkUrl(new URL(loc, url).href, allow);
|
|
1946
|
-
req = redirectRequest(url, next, req, res.status);
|
|
1947
|
-
url = next;
|
|
1948
|
-
}
|
|
1949
|
-
})
|
|
1950
|
-
);
|
|
1951
|
-
}
|
|
1952
|
-
function boundedFetch(f4, opt) {
|
|
1953
|
-
const ms0 = Number(opt.fetchTimeoutMs) > 0 ? Number(opt.fetchTimeoutMs) : FETCH_DEFAULTS.timeoutMs;
|
|
1954
|
-
const max = Number(opt.maxFetchBytes) > 0 ? Number(opt.maxFetchBytes) : FETCH_DEFAULTS.maxBytes;
|
|
1955
|
-
return (
|
|
1956
|
-
/** @type {any} */
|
|
1957
|
-
(async (input, init = {}) => {
|
|
1958
|
-
const ms = Math.max(1, Math.min(ms0, opt.deadline ? opt.deadline - Date.now() : Infinity));
|
|
1959
|
-
const ctl = new AbortController();
|
|
1960
|
-
const timer = setTimeout(() => ctl.abort(Object.assign(new Error(`The data request took longer than ${Math.round(ms)} ms`), { status: 504 })), ms);
|
|
1961
|
-
const signal = init.signal ? anySignal([init.signal, ctl.signal]) : ctl.signal;
|
|
1962
|
-
let res;
|
|
1963
|
-
const stop = new Promise((_, rej) => signal.addEventListener("abort", () => rej(signal.reason), { once: true }));
|
|
1964
|
-
stop.catch(() => {
|
|
1965
|
-
});
|
|
1966
|
-
try {
|
|
1967
|
-
res = await Promise.race([f4(input, { ...init, signal }), stop]);
|
|
1968
|
-
} catch (e) {
|
|
1969
|
-
clearTimeout(timer);
|
|
1970
|
-
throw ctl.signal.aborted ? ctl.signal.reason : fetchFailure(e, input);
|
|
1971
|
-
}
|
|
1972
|
-
if (!res.body || /** @type {any} */
|
|
1973
|
-
init.pwStream) {
|
|
1974
|
-
clearTimeout(timer);
|
|
1975
|
-
return res;
|
|
1976
|
-
}
|
|
1977
|
-
let n = 0;
|
|
1978
|
-
const reader = res.body.getReader();
|
|
1979
|
-
const body = new ReadableStream({
|
|
1980
|
-
async pull(c) {
|
|
1981
|
-
try {
|
|
1982
|
-
const { done, value } = await reader.read();
|
|
1983
|
-
if (done) {
|
|
1984
|
-
clearTimeout(timer);
|
|
1985
|
-
c.close();
|
|
1986
|
-
return;
|
|
1987
|
-
}
|
|
1988
|
-
n += value.byteLength;
|
|
1989
|
-
if (n > max) {
|
|
1990
|
-
clearTimeout(timer);
|
|
1991
|
-
reader.cancel().catch(() => {
|
|
1992
|
-
});
|
|
1993
|
-
c.error(Object.assign(new Error(`The data response is larger than ${Math.round(max / 1048576)} MB (maxFetchBytes)`), { status: 413 }));
|
|
1994
|
-
return;
|
|
1995
|
-
}
|
|
1996
|
-
c.enqueue(value);
|
|
1997
|
-
} catch (e) {
|
|
1998
|
-
clearTimeout(timer);
|
|
1999
|
-
c.error(ctl.signal.aborted ? ctl.signal.reason : e);
|
|
2000
|
-
}
|
|
2001
|
-
},
|
|
2002
|
-
cancel(r) {
|
|
2003
|
-
clearTimeout(timer);
|
|
2004
|
-
return reader.cancel(r);
|
|
2005
|
-
}
|
|
2006
|
-
});
|
|
2007
|
-
return new Response(body, { status: res.status, statusText: res.statusText, headers: res.headers });
|
|
2008
|
-
})
|
|
2009
|
-
);
|
|
2010
|
-
}
|
|
2011
|
-
var CAUSES = {
|
|
2012
|
-
ENOTFOUND: "the host name did not resolve",
|
|
2013
|
-
EAI_AGAIN: "DNS lookup timed out",
|
|
2014
|
-
ECONNREFUSED: "connection refused",
|
|
2015
|
-
ECONNRESET: "connection reset",
|
|
2016
|
-
EPIPE: "connection closed",
|
|
2017
|
-
UND_ERR_SOCKET: "connection closed early",
|
|
2018
|
-
ETIMEDOUT: "timed out",
|
|
2019
|
-
UND_ERR_CONNECT_TIMEOUT: "connect timed out",
|
|
2020
|
-
EPROTO: "TLS error",
|
|
2021
|
-
ERR_TLS_CERT_ALTNAME_INVALID: "TLS certificate does not match the host",
|
|
2022
|
-
DEPTH_ZERO_SELF_SIGNED_CERT: "TLS certificate is self-signed",
|
|
2023
|
-
SELF_SIGNED_CERT_IN_CHAIN: "TLS certificate chain is untrusted",
|
|
2024
|
-
UNABLE_TO_VERIFY_LEAF_SIGNATURE: "TLS certificate chain is untrusted",
|
|
2025
|
-
CERT_HAS_EXPIRED: "TLS certificate has expired"
|
|
2022
|
+
startswith: "startswith",
|
|
2023
|
+
endswith: "endswith",
|
|
2024
|
+
indexof: "indexof",
|
|
2025
|
+
lastindexof: "lastindexof",
|
|
2026
|
+
contains: "contains",
|
|
2027
|
+
replace: "replace",
|
|
2028
|
+
split: "split",
|
|
2029
|
+
tostring: "tostring"
|
|
2026
2030
|
};
|
|
2027
|
-
function
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2031
|
+
function netFormat(f4, args, ctx) {
|
|
2032
|
+
let out = "";
|
|
2033
|
+
for (let i = 0; i < f4.length; i++) {
|
|
2034
|
+
const c = f4[i];
|
|
2035
|
+
if (c === "{" && f4[i + 1] === "{") {
|
|
2036
|
+
out += "{";
|
|
2037
|
+
i++;
|
|
2038
|
+
continue;
|
|
2039
|
+
}
|
|
2040
|
+
if (c === "}" && f4[i + 1] === "}") {
|
|
2041
|
+
out += "}";
|
|
2042
|
+
i++;
|
|
2043
|
+
continue;
|
|
2044
|
+
}
|
|
2045
|
+
if (c === "}") throw new ExprError('String.Format: a "}" without its "{"');
|
|
2046
|
+
if (c !== "{") {
|
|
2047
|
+
out += c;
|
|
2048
|
+
continue;
|
|
2049
|
+
}
|
|
2050
|
+
const e = f4.indexOf("}", i);
|
|
2051
|
+
if (e < 0) throw new ExprError('String.Format: a "{" without its "}"');
|
|
2052
|
+
const m = /^\s*(\d{1,3})\s*(?:,\s*(-?\d{1,4}))?\s*(?::([^}]*))?$/.exec(f4.slice(i + 1, e));
|
|
2053
|
+
if (!m) throw new ExprError(`String.Format: "{${f4.slice(i + 1, e).slice(0, 20)}}" is not a placeholder`);
|
|
2054
|
+
const k = Number(m[1]);
|
|
2055
|
+
if (k >= args.length) throw new ExprError(`String.Format: {${k}} has no argument`);
|
|
2056
|
+
let t = toText(args[k], m[3] || null, ctx);
|
|
2057
|
+
const w = m[2] ? Number(m[2]) : 0;
|
|
2058
|
+
if (Math.abs(w) > t.length) t = w < 0 ? t.padEnd(-w) : t.padStart(w);
|
|
2059
|
+
capText("String.Format", out.length + t.length + f4.length - e);
|
|
2060
|
+
out += t;
|
|
2061
|
+
i = e;
|
|
2062
|
+
}
|
|
2063
|
+
return out;
|
|
2040
2064
|
}
|
|
2041
|
-
function
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
if (S3.any) return S3.any(list);
|
|
2047
|
-
const c = new AbortController();
|
|
2048
|
-
for (const s of list) {
|
|
2049
|
-
if (s.aborted) c.abort(s.reason);
|
|
2050
|
-
else s.addEventListener("abort", () => c.abort(s.reason), { once: true });
|
|
2065
|
+
function callCustom(n, name, ctx) {
|
|
2066
|
+
if (n.obj && n.obj.type === "id" && n.obj.name.toLowerCase() === "string" && name === "format") {
|
|
2067
|
+
if (!n.args.length) throw new ExprError("String.Format needs a format", n.p);
|
|
2068
|
+
const [f5, ...rest] = n.args.map((a) => evaluate(a, ctx));
|
|
2069
|
+
return netFormat(S(f5), rest, ctx);
|
|
2051
2070
|
}
|
|
2052
|
-
|
|
2071
|
+
const viaValue = n.obj && !(n.obj.type === "id" && n.obj.name.toLowerCase() === "code");
|
|
2072
|
+
if (viaValue && Object.hasOwn(METHODS, name)) {
|
|
2073
|
+
return FUNCTIONS[METHODS[name]](ctx, evaluate(n.obj, ctx), ...n.args.map((a) => evaluate(a, ctx)));
|
|
2074
|
+
}
|
|
2075
|
+
if (viaValue && n.name in Object.prototype) throw new ExprError(`The value has no member ${n.name}`, n.p);
|
|
2076
|
+
const viaCode = !!n.obj;
|
|
2077
|
+
if (viaCode && !(n.obj.type === "id" && n.obj.name.toLowerCase() === "code")) throw new ExprError(`"${n.name}(…)" after "." is not supported; report functions are called as Code.${n.name}(…)`, n.p);
|
|
2078
|
+
const table = ctx.functions;
|
|
2079
|
+
const f4 = table?.byName.get(name);
|
|
2080
|
+
if (!f4 || !viaCode && builtin(name)) throw new ExprError(viaCode ? `The report has no function "${n.name}"` : `Unknown function "${n.name}"`, n.p);
|
|
2081
|
+
const params = Array.isArray(f4.params) ? f4.params : [];
|
|
2082
|
+
if (n.args.length !== params.length) throw new ExprError(`${f4.name} needs ${params.length} argument${params.length === 1 ? "" : "s"}`, n.p);
|
|
2083
|
+
const depth = (ctx.fnDepth || 0) + 1;
|
|
2084
|
+
if (depth > MAX_FN_DEPTH) throw new ExprError(`${f4.name}: functions call each other more than ${MAX_FN_DEPTH} deep`, n.p);
|
|
2085
|
+
if (++table.count.n > MAX_FN_CALLS) throw new ExprError(`Report functions were called more than 1,000,000 times in this render`, n.p);
|
|
2086
|
+
const locals = /* @__PURE__ */ Object.create(null);
|
|
2087
|
+
for (let i = 0; i < params.length; i++) locals[String(params[i]).toLowerCase()] = evaluate(n.args[i], ctx);
|
|
2088
|
+
return evaluate(compile(String(f4.body).replace(/^=/, "")), Object.assign({}, ctx, { locals, fnDepth: depth }));
|
|
2053
2089
|
}
|
|
2054
2090
|
|
|
2055
2091
|
// src/importers/xml.js
|
|
@@ -2850,7 +2886,10 @@ function fetcherFor(opt) {
|
|
|
2850
2886
|
return boundedFetch(f4, opt);
|
|
2851
2887
|
}
|
|
2852
2888
|
function checkHostSource(src, url, opt) {
|
|
2853
|
-
|
|
2889
|
+
const rule = opt.fetch ? opt.fetch.hostRule : opt.unsafeFetch ? null : opt;
|
|
2890
|
+
if (!rule) return;
|
|
2891
|
+
const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(String(url).trim());
|
|
2892
|
+
if (scheme && !/^https?$/i.test(scheme[1])) throw Object.assign(new Error(`Only http and https URLs can be fetched, not ${scheme[1].toLowerCase()}:`), { status: 400 });
|
|
2854
2893
|
const t = String(src.url ?? "").trim();
|
|
2855
2894
|
if (/^\/(?![/\\])/.test(t)) return;
|
|
2856
2895
|
const m = /^https?:\/\/([^/?#\\]*)/i.exec(t);
|
|
@@ -2861,7 +2900,7 @@ function checkHostSource(src, url, opt) {
|
|
|
2861
2900
|
host = new URL(url).hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
2862
2901
|
} catch {
|
|
2863
2902
|
}
|
|
2864
|
-
if (whole && host && (
|
|
2903
|
+
if (whole && host && (rule.allowHosts || []).map((h) => String(h).toLowerCase()).includes(host)) return;
|
|
2865
2904
|
throw Object.assign(new Error("its host is made by a parameter or an expression: write the scheme and host out (parameters may fill the path and query), or make the whole URL a parameter and list its host in allowHosts"), { status: 403 });
|
|
2866
2905
|
}
|
|
2867
2906
|
async function loadSources(def, opt) {
|
|
@@ -3142,18 +3181,18 @@ function buildDataSets(def, sources, baseCtx) {
|
|
|
3142
3181
|
});
|
|
3143
3182
|
if (calc.length) {
|
|
3144
3183
|
const c = { ...baseCtx, dataSets: { ...baseCtx.dataSets || {}, ...sets }, fields: null };
|
|
3145
|
-
const
|
|
3184
|
+
const failed2 = /* @__PURE__ */ new Set();
|
|
3146
3185
|
for (const r of rows) {
|
|
3147
3186
|
c.fields = r;
|
|
3148
3187
|
for (const fd of calc) {
|
|
3149
|
-
if (
|
|
3188
|
+
if (failed2.has(fd.name)) {
|
|
3150
3189
|
r[fd.name] = null;
|
|
3151
3190
|
continue;
|
|
3152
3191
|
}
|
|
3153
3192
|
try {
|
|
3154
3193
|
r[fd.name] = coerce(evalValue(fd.expr, c), fd.type, opts.get(fd));
|
|
3155
3194
|
} catch (e) {
|
|
3156
|
-
|
|
3195
|
+
failed2.add(fd.name);
|
|
3157
3196
|
r[fd.name] = null;
|
|
3158
3197
|
baseCtx.warn?.(`Data set "${ds.name}", field "${fd.name}": ${e.message}`);
|
|
3159
3198
|
}
|
|
@@ -3701,543 +3740,6 @@ function normBox(v) {
|
|
|
3701
3740
|
return [a[0], a[1], a[2], a[3]];
|
|
3702
3741
|
}
|
|
3703
3742
|
|
|
3704
|
-
// src/engine/text/measure.js
|
|
3705
|
-
import bidiFactory from "bidi-js";
|
|
3706
|
-
var bidi = bidiFactory();
|
|
3707
|
-
function special(cp) {
|
|
3708
|
-
if (cp < 1424) return false;
|
|
3709
|
-
if (cp <= 7423) return true;
|
|
3710
|
-
if (cp >= 8192 && cp <= 8303) return cp >= 8203 && cp <= 8207 || cp >= 8234 && cp <= 8238 || cp >= 8288;
|
|
3711
|
-
return cp >= 11904 && cp <= 42191 || cp >= 43056 && cp <= 44031 || cp >= 44032 && cp <= 55215 || cp >= 63744 && cp <= 64255 || cp >= 64285 && cp <= 65023 || cp >= 65024 && cp <= 65039 || cp >= 65072 && cp <= 65103 || cp >= 65136 && cp <= 65278 || cp >= 65280 && cp <= 65519 || cp >= 65536;
|
|
3712
|
-
}
|
|
3713
|
-
var cjk = (cp) => cp >= 11904 && cp <= 40959 || cp >= 44032 && cp <= 55215 || cp >= 63744 && cp <= 64255 || cp >= 65280 && cp <= 65519 || cp >= 131072 && cp <= 262143;
|
|
3714
|
-
var NO_START = new Set("、。,.・:;?!ー)」』】〕〉》〗〙〟’”}⦆ぁぃぅぇぉっゃゅょゎゕゖァィゥェォッャュョヮヵヶ々〻‐゠–〜~…‥,.!?:;)]}%ゝゞヽヾ゛゜ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ。」、・ー%]⦆");
|
|
3715
|
-
var NO_END = new Set("(「『【〔〈《〖〘〝‘“{⦅([{[「$¥£");
|
|
3716
|
-
var MAYBE = /[^\u0000-\u058f]/;
|
|
3717
|
-
var RTL_OR_CONTROLS = /[-ࣿיִ-﷿ﹰ---]|[\uD802\uD803\uD83A]/;
|
|
3718
|
-
var SCRIPTS = [
|
|
3719
|
-
"Latin",
|
|
3720
|
-
"Greek",
|
|
3721
|
-
"Cyrillic",
|
|
3722
|
-
"Armenian",
|
|
3723
|
-
"Hebrew",
|
|
3724
|
-
"Arabic",
|
|
3725
|
-
"Syriac",
|
|
3726
|
-
"Thaana",
|
|
3727
|
-
"Devanagari",
|
|
3728
|
-
"Bengali",
|
|
3729
|
-
"Gurmukhi",
|
|
3730
|
-
"Gujarati",
|
|
3731
|
-
"Oriya",
|
|
3732
|
-
"Tamil",
|
|
3733
|
-
"Telugu",
|
|
3734
|
-
"Kannada",
|
|
3735
|
-
"Malayalam",
|
|
3736
|
-
"Sinhala",
|
|
3737
|
-
"Thai",
|
|
3738
|
-
"Lao",
|
|
3739
|
-
"Tibetan",
|
|
3740
|
-
"Myanmar",
|
|
3741
|
-
"Georgian",
|
|
3742
|
-
"Hangul",
|
|
3743
|
-
"Ethiopic",
|
|
3744
|
-
"Khmer",
|
|
3745
|
-
"Mongolian",
|
|
3746
|
-
"Han",
|
|
3747
|
-
"Hiragana",
|
|
3748
|
-
"Katakana",
|
|
3749
|
-
"Bopomofo"
|
|
3750
|
-
].map((s) => (
|
|
3751
|
-
/** @type {[string, RegExp]} */
|
|
3752
|
-
[s, new RegExp(`\\p{Script=${s}}`, "u")]
|
|
3753
|
-
));
|
|
3754
|
-
var SIMPLE = /* @__PURE__ */ new Set(["Latin", "Greek", "Cyrillic", "Armenian", "Georgian", "Hangul", "Han", "Hiragana", "Katakana", "Bopomofo", "Common"]);
|
|
3755
|
-
var STICKY = /[\p{M}\p{Cf}]/u;
|
|
3756
|
-
var SPACE = /\s/u;
|
|
3757
|
-
var scriptCache = /* @__PURE__ */ new Map();
|
|
3758
|
-
function scriptOf(cp) {
|
|
3759
|
-
let s = scriptCache.get(cp);
|
|
3760
|
-
if (s === void 0) {
|
|
3761
|
-
const ch = String.fromCodePoint(cp);
|
|
3762
|
-
s = "Common";
|
|
3763
|
-
for (const [name, re] of SCRIPTS) if (re.test(ch)) {
|
|
3764
|
-
s = name;
|
|
3765
|
-
break;
|
|
3766
|
-
}
|
|
3767
|
-
if (scriptCache.size >= 2e4) scriptCache.clear();
|
|
3768
|
-
scriptCache.set(cp, s);
|
|
3769
|
-
}
|
|
3770
|
-
return s;
|
|
3771
|
-
}
|
|
3772
|
-
var INTL = typeof Intl !== "undefined" && typeof Intl.Segmenter === "function";
|
|
3773
|
-
var GRAPHEMES = INTL ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
|
|
3774
|
-
var JOINS = /[\p{M}\u200c\u200d\ufe00-\ufe0f]/u;
|
|
3775
|
-
function clusters(s, intl = true) {
|
|
3776
|
-
if (intl && GRAPHEMES) return [...GRAPHEMES.segment(s)].map((x) => x.segment);
|
|
3777
|
-
const out = [];
|
|
3778
|
-
for (const ch of s) {
|
|
3779
|
-
if (out.length && (JOINS.test(ch) || out[out.length - 1].endsWith(""))) out[out.length - 1] += ch;
|
|
3780
|
-
else out.push(ch);
|
|
3781
|
-
}
|
|
3782
|
-
return out;
|
|
3783
|
-
}
|
|
3784
|
-
var graphemes = (s) => clusters(s);
|
|
3785
|
-
var SA = /[\u0e00-\u0eff\u1000-\u109f\u1780-\u17ff\u19e0-\u19ff\u1a20-\u1aaf\ua9e0-\ua9ff\uaa60-\uaadf]/;
|
|
3786
|
-
var WORDS = INTL ? new Intl.Segmenter(void 0, { granularity: "word" }) : null;
|
|
3787
|
-
function saBreaks(text, segmenter = WORDS) {
|
|
3788
|
-
const out = /* @__PURE__ */ new Set();
|
|
3789
|
-
if (!segmenter) return out;
|
|
3790
|
-
for (const { index } of segmenter.segment(text)) {
|
|
3791
|
-
if (index > 0 && (SA.test(text[index]) || SA.test(text[index - 1]))) out.add(index);
|
|
3792
|
-
}
|
|
3793
|
-
return out;
|
|
3794
|
-
}
|
|
3795
|
-
var TextMeasurer = class {
|
|
3796
|
-
/** @param {import('./fonts.js').FontStore} store */
|
|
3797
|
-
constructor(store) {
|
|
3798
|
-
this.store = store;
|
|
3799
|
-
this.faces = /* @__PURE__ */ new Map();
|
|
3800
|
-
this.boxes = /* @__PURE__ */ new WeakMap();
|
|
3801
|
-
this.boxCount = 0;
|
|
3802
|
-
this.looks = /* @__PURE__ */ new WeakMap();
|
|
3803
|
-
this.cover = /* @__PURE__ */ new Map();
|
|
3804
|
-
this.cache = /* @__PURE__ */ new Map();
|
|
3805
|
-
this.missing = /* @__PURE__ */ new Set();
|
|
3806
|
-
this.noGlyph = /* @__PURE__ */ new Set();
|
|
3807
|
-
}
|
|
3808
|
-
/**
|
|
3809
|
-
* The key to measure with: `key` when loaded; else (not loaded yet, or failed) the bundled face of the same weight
|
|
3810
|
-
* and style when that is loaded, else the core regular face. A key not yet loaded is asked for in the next pass.
|
|
3811
|
-
*/
|
|
3812
|
-
usable(key) {
|
|
3813
|
-
if (this.store.has(key)) return key;
|
|
3814
|
-
if (!this.store.failed.has(key)) this.missing.add(key);
|
|
3815
|
-
const c = fontCss(key);
|
|
3816
|
-
const same2 = resolveFontKey(DEFAULT_FAMILY, c.weight, c.style);
|
|
3817
|
-
return this.store.has(same2) ? same2 : CORE_FONT_KEY;
|
|
3818
|
-
}
|
|
3819
|
-
/**
|
|
3820
|
-
* A loaded face's numbers, read once: fontkit's getters (unitsPerEm, ascent…) decode tables on every read.
|
|
3821
|
-
* adv: advances per code point (-1 = not on the fast path); words: fast-path units per string (a table repeats them).
|
|
3822
|
-
* @param {string} key a loaded key
|
|
3823
|
-
*/
|
|
3824
|
-
face(key) {
|
|
3825
|
-
let f4 = this.faces.get(key);
|
|
3826
|
-
if (!f4) {
|
|
3827
|
-
const font = this.store.get(key);
|
|
3828
|
-
f4 = { font, upm: font.unitsPerEm, ascent: font.ascent, descent: font.descent, adv: /* @__PURE__ */ new Map(), words: /* @__PURE__ */ new Map(), met: /* @__PURE__ */ new Map() };
|
|
3829
|
-
this.faces.set(key, f4);
|
|
3830
|
-
}
|
|
3831
|
-
return f4;
|
|
3832
|
-
}
|
|
3833
|
-
/** Font units of `text` on the fast path, or -1 when it needs the complex path. */
|
|
3834
|
-
fast(text, key) {
|
|
3835
|
-
const f4 = this.face(key);
|
|
3836
|
-
const hit = f4.words.get(text);
|
|
3837
|
-
if (hit !== void 0) return hit;
|
|
3838
|
-
const m = f4.adv, font = f4.font;
|
|
3839
|
-
let units = 0;
|
|
3840
|
-
for (let i = 0; i < text.length; i++) {
|
|
3841
|
-
let cp = text.charCodeAt(i);
|
|
3842
|
-
if (cp >= 55296 && cp <= 56319) {
|
|
3843
|
-
const lo = text.charCodeAt(i + 1);
|
|
3844
|
-
if (lo >= 56320 && lo <= 57343) {
|
|
3845
|
-
cp = (cp - 55296) * 1024 + lo - 56320 + 65536;
|
|
3846
|
-
i++;
|
|
3847
|
-
}
|
|
3848
|
-
}
|
|
3849
|
-
let a = m.get(cp);
|
|
3850
|
-
if (a === void 0) {
|
|
3851
|
-
a = special(cp) || cp >= 32 && !font.hasGlyphForCodePoint(cp) ? -1 : font.glyphForCodePoint(cp).advanceWidth || 0;
|
|
3852
|
-
m.set(cp, a);
|
|
3853
|
-
}
|
|
3854
|
-
if (a < 0) {
|
|
3855
|
-
units = -1;
|
|
3856
|
-
break;
|
|
3857
|
-
}
|
|
3858
|
-
units += a;
|
|
3859
|
-
}
|
|
3860
|
-
if (text.length <= 256) {
|
|
3861
|
-
if (f4.words.size >= 5e4) f4.words.clear();
|
|
3862
|
-
f4.words.set(text, units);
|
|
3863
|
-
}
|
|
3864
|
-
return units;
|
|
3865
|
-
}
|
|
3866
|
-
/**
|
|
3867
|
-
* Advance width in points. @param {string} text @param {string} key @param {number} size
|
|
3868
|
-
* @param {'ltr'|'rtl'} [dir] paragraph direction (default: from the first strong character)
|
|
3869
|
-
*/
|
|
3870
|
-
width(text, key, size, dir) {
|
|
3871
|
-
const k = this.store.has(key) ? key : this.usable(key);
|
|
3872
|
-
const u = this.fast(text, k);
|
|
3873
|
-
if (u >= 0) return u * size / this.face(k).upm;
|
|
3874
|
-
return this.layout(text, k, dir).w * size;
|
|
3875
|
-
}
|
|
3876
|
-
/**
|
|
3877
|
-
* Where underline and strike-through go, from the font's own tables (post and OS/2), in points:
|
|
3878
|
-
* y offsets of the stroke centre from the baseline (positive = down, as on the page) and thicknesses.
|
|
3879
|
-
* A font without the tables falls back to proportions of its descent and x-height.
|
|
3880
|
-
* @param {string} key @param {number} size
|
|
3881
|
-
*/
|
|
3882
|
-
decoration(key, size) {
|
|
3883
|
-
const f4 = this.store.get(this.usable(key));
|
|
3884
|
-
const u = f4.unitsPerEm, os2 = f4["OS/2"] || {};
|
|
3885
|
-
const ut = f4.underlineThickness > 0 ? f4.underlineThickness : u / 14;
|
|
3886
|
-
const up = f4.underlinePosition < 0 ? f4.underlinePosition : f4.descent / 2;
|
|
3887
|
-
const st = os2.yStrikeoutSize > 0 ? os2.yStrikeoutSize : ut;
|
|
3888
|
-
const sp = os2.yStrikeoutPosition > 0 ? os2.yStrikeoutPosition : (f4.xHeight > 0 ? f4.xHeight : f4.ascent * 0.5) / 2 + st / 2;
|
|
3889
|
-
const k = size / u;
|
|
3890
|
-
return { underlineY: -(up - ut / 2) * k, underlineWidth: ut * k, strikeY: -(sp - st / 2) * k, strikeWidth: st * k };
|
|
3891
|
-
}
|
|
3892
|
-
/**
|
|
3893
|
-
* Superscript and subscript from the font's OS/2 table, in em: the size of the small text and how far its
|
|
3894
|
-
* baseline moves (rise up for superscript, drop down for subscript). Fonts without the values get the
|
|
3895
|
-
* proportions most fonts use.
|
|
3896
|
-
* @param {string} key
|
|
3897
|
-
*/
|
|
3898
|
-
script(key) {
|
|
3899
|
-
const f4 = this.store.get(this.usable(key));
|
|
3900
|
-
const u = f4.unitsPerEm, o = f4["OS/2"] || {};
|
|
3901
|
-
const frac = (v, d) => v > 0 && v < u * 2 ? v / u : d;
|
|
3902
|
-
return { supScale: frac(o.ySuperscriptYSize, 0.65), supRise: frac(o.ySuperscriptYOffset, 0.35), subScale: frac(o.ySubscriptYSize, 0.65), subDrop: frac(o.ySubscriptYOffset, 0.15) };
|
|
3903
|
-
}
|
|
3904
|
-
/** @param {string} key @param {number} size */
|
|
3905
|
-
metrics(key, size) {
|
|
3906
|
-
const f4 = this.face(this.usable(key));
|
|
3907
|
-
let r = f4.met.get(size);
|
|
3908
|
-
if (!r) {
|
|
3909
|
-
r = Object.freeze({ ascent: f4.ascent * size / f4.upm, descent: -f4.descent * size / f4.upm });
|
|
3910
|
-
f4.met.set(size, r);
|
|
3911
|
-
}
|
|
3912
|
-
return r;
|
|
3913
|
-
}
|
|
3914
|
-
/**
|
|
3915
|
-
* The visually ordered runs of one line, or null when the line is simple (draw `text` as it is).
|
|
3916
|
-
* @param {string} text @param {string} key @param {number} size @param {'ltr'|'rtl'} [dir]
|
|
3917
|
-
* @returns {Run[]|null}
|
|
3918
|
-
*/
|
|
3919
|
-
runs(text, key, size, dir) {
|
|
3920
|
-
if (!dir && !MAYBE.test(text)) return null;
|
|
3921
|
-
const k = this.usable(key);
|
|
3922
|
-
if (this.fast(text, k) >= 0) return null;
|
|
3923
|
-
return this.layout(text, k, dir).runs.map((r) => ({
|
|
3924
|
-
...r,
|
|
3925
|
-
x: r.x * size,
|
|
3926
|
-
w: r.w * size,
|
|
3927
|
-
glyphs: r.glyphs.map((v, i) => i % 4 === 1 || i % 4 === 2 ? v * size : v)
|
|
3928
|
-
}));
|
|
3929
|
-
}
|
|
3930
|
-
/** Paragraph direction of text that needs shaping, bidi or CJK breaks, else undefined. */
|
|
3931
|
-
direction(text, key) {
|
|
3932
|
-
if (!MAYBE.test(text)) return void 0;
|
|
3933
|
-
const k = this.usable(key);
|
|
3934
|
-
if (this.fast(text, k) >= 0) return void 0;
|
|
3935
|
-
return this.layout(text, k, void 0).rtl ? "rtl" : "ltr";
|
|
3936
|
-
}
|
|
3937
|
-
/**
|
|
3938
|
-
* Greedy line breaking. Simple paragraphs break at spaces (a word longer than the line breaks by
|
|
3939
|
-
* character), exactly as before. Others also break between CJK characters (kinsoku applied), never
|
|
3940
|
-
* inside a grapheme cluster (a conjunct, a letter and its marks), and remember their direction.
|
|
3941
|
-
* @param {string} text @param {string} key @param {number} size @param {number} maxWidth
|
|
3942
|
-
* @returns {{text: string, width: number, dir?: 'ltr'|'rtl'}[]}
|
|
3943
|
-
*/
|
|
3944
|
-
wrap(text, key, size, maxWidth) {
|
|
3945
|
-
const out = [];
|
|
3946
|
-
const k = this.usable(key);
|
|
3947
|
-
const sp = this.width(" ", k, size);
|
|
3948
|
-
const str = String(text);
|
|
3949
|
-
for (const para of str.includes("\n") ? str.split(/\r?\n/) : [str]) {
|
|
3950
|
-
const dir = this.direction(para, k);
|
|
3951
|
-
if (dir) {
|
|
3952
|
-
this.wrapComplex(para, k, size, maxWidth, dir, sp, out);
|
|
3953
|
-
continue;
|
|
3954
|
-
}
|
|
3955
|
-
if (!para.includes(" ")) {
|
|
3956
|
-
const ww = this.width(para, k, size);
|
|
3957
|
-
if (ww <= maxWidth || maxWidth <= 0) {
|
|
3958
|
-
out.push({ text: para, width: ww, end: true });
|
|
3959
|
-
continue;
|
|
3960
|
-
}
|
|
3961
|
-
}
|
|
3962
|
-
const words = para.split(/ +/);
|
|
3963
|
-
let line2 = "", lw = 0;
|
|
3964
|
-
const push = () => {
|
|
3965
|
-
out.push({ text: line2, width: lw });
|
|
3966
|
-
line2 = "";
|
|
3967
|
-
lw = 0;
|
|
3968
|
-
};
|
|
3969
|
-
for (let wi = 0; wi < words.length; wi++) {
|
|
3970
|
-
const w = words[wi];
|
|
3971
|
-
if (w === "" && wi > 0) continue;
|
|
3972
|
-
const ww = this.width(w, k, size);
|
|
3973
|
-
if (line2 === "") {
|
|
3974
|
-
if (ww <= maxWidth || maxWidth <= 0) {
|
|
3975
|
-
line2 = w;
|
|
3976
|
-
lw = ww;
|
|
3977
|
-
continue;
|
|
3978
|
-
}
|
|
3979
|
-
} else if (lw + sp + ww <= maxWidth) {
|
|
3980
|
-
line2 += " " + w;
|
|
3981
|
-
lw += sp + ww;
|
|
3982
|
-
continue;
|
|
3983
|
-
} else {
|
|
3984
|
-
push();
|
|
3985
|
-
if (ww <= maxWidth) {
|
|
3986
|
-
line2 = w;
|
|
3987
|
-
lw = ww;
|
|
3988
|
-
continue;
|
|
3989
|
-
}
|
|
3990
|
-
}
|
|
3991
|
-
let after = -1;
|
|
3992
|
-
for (const ch of w) {
|
|
3993
|
-
const cw = this.width(ch, k, size);
|
|
3994
|
-
if (lw + cw > maxWidth && line2 !== "") {
|
|
3995
|
-
if (after > 0 && after < line2.length) {
|
|
3996
|
-
const rest = line2.slice(after);
|
|
3997
|
-
line2 = line2.slice(0, after);
|
|
3998
|
-
lw = this.width(line2, k, size);
|
|
3999
|
-
push();
|
|
4000
|
-
line2 = rest;
|
|
4001
|
-
lw = this.width(rest, k, size);
|
|
4002
|
-
} else push();
|
|
4003
|
-
after = -1;
|
|
4004
|
-
}
|
|
4005
|
-
line2 += ch;
|
|
4006
|
-
lw += cw;
|
|
4007
|
-
if ((ch === "/" || ch === "-") && line2.length > 1) after = line2.length;
|
|
4008
|
-
}
|
|
4009
|
-
}
|
|
4010
|
-
push();
|
|
4011
|
-
out[out.length - 1].end = true;
|
|
4012
|
-
}
|
|
4013
|
-
return out;
|
|
4014
|
-
}
|
|
4015
|
-
/** @param {string} para @param {string} key @param {number} size @param {number} maxWidth @param {'ltr'|'rtl'} dir @param {number} sp @param {any[]} out */
|
|
4016
|
-
wrapComplex(para, key, size, maxWidth, dir, sp, out) {
|
|
4017
|
-
const tokens = [];
|
|
4018
|
-
const sa = SA.test(para) ? saBreaks(para) : null;
|
|
4019
|
-
let cur = "", space = false, prev = "", at = 0;
|
|
4020
|
-
for (const ch of para) {
|
|
4021
|
-
const i = at;
|
|
4022
|
-
at += ch.length;
|
|
4023
|
-
if (ch === " ") {
|
|
4024
|
-
if (cur) {
|
|
4025
|
-
tokens.push({ text: cur, space });
|
|
4026
|
-
cur = "";
|
|
4027
|
-
}
|
|
4028
|
-
space = tokens.length > 0;
|
|
4029
|
-
prev = "";
|
|
4030
|
-
continue;
|
|
4031
|
-
}
|
|
4032
|
-
const cp = (
|
|
4033
|
-
/** @type {number} */
|
|
4034
|
-
ch.codePointAt(0)
|
|
4035
|
-
);
|
|
4036
|
-
const pcp = prev ? (
|
|
4037
|
-
/** @type {number} */
|
|
4038
|
-
prev.codePointAt(0)
|
|
4039
|
-
) : 0;
|
|
4040
|
-
if (cur && (sa?.has(i) || (cjk(cp) || cjk(pcp)) && !NO_START.has(ch) && !NO_END.has(prev) && !STICKY.test(ch))) {
|
|
4041
|
-
tokens.push({ text: cur, space });
|
|
4042
|
-
cur = "";
|
|
4043
|
-
space = false;
|
|
4044
|
-
}
|
|
4045
|
-
cur += ch;
|
|
4046
|
-
prev = ch;
|
|
4047
|
-
}
|
|
4048
|
-
if (cur) tokens.push({ text: cur, space });
|
|
4049
|
-
let line2 = "", lw = 0;
|
|
4050
|
-
const push = () => {
|
|
4051
|
-
out.push({ text: line2, width: this.width(line2, key, size, dir), dir });
|
|
4052
|
-
line2 = "";
|
|
4053
|
-
lw = 0;
|
|
4054
|
-
};
|
|
4055
|
-
for (const t of tokens) {
|
|
4056
|
-
const tw = this.width(t.text, key, size, dir);
|
|
4057
|
-
const gap = line2 && t.space ? sp : 0;
|
|
4058
|
-
if (line2 === "" ? tw <= maxWidth || maxWidth <= 0 : lw + gap + tw <= maxWidth) {
|
|
4059
|
-
line2 += (line2 && t.space ? " " : "") + t.text;
|
|
4060
|
-
lw += gap + tw;
|
|
4061
|
-
continue;
|
|
4062
|
-
}
|
|
4063
|
-
if (line2) push();
|
|
4064
|
-
if (tw <= maxWidth) {
|
|
4065
|
-
line2 = t.text;
|
|
4066
|
-
lw = tw;
|
|
4067
|
-
continue;
|
|
4068
|
-
}
|
|
4069
|
-
for (const g of graphemes(t.text)) {
|
|
4070
|
-
const gw = this.width(g, key, size, dir);
|
|
4071
|
-
if (lw + gw > maxWidth && line2 !== "") push();
|
|
4072
|
-
line2 += g;
|
|
4073
|
-
lw += gw;
|
|
4074
|
-
}
|
|
4075
|
-
}
|
|
4076
|
-
push();
|
|
4077
|
-
}
|
|
4078
|
-
/** Cut a line so it fits, then add "…". */
|
|
4079
|
-
ellipsize(text, key, size, maxWidth, dir) {
|
|
4080
|
-
const ell = "…";
|
|
4081
|
-
if (this.width(text, key, size, dir) <= maxWidth) return text;
|
|
4082
|
-
const ew = this.width(ell, key, size);
|
|
4083
|
-
if (this.direction(text, key)) {
|
|
4084
|
-
const gs = graphemes(text);
|
|
4085
|
-
while (gs.length && this.width(gs.join(""), key, size, dir) + ew > maxWidth) gs.pop();
|
|
4086
|
-
return gs.join("").trimEnd() + ell;
|
|
4087
|
-
}
|
|
4088
|
-
let s = text;
|
|
4089
|
-
while (s.length && this.width(s, key, size) + ew > maxWidth) s = s.slice(0, -1);
|
|
4090
|
-
return s.trimEnd() + ell;
|
|
4091
|
-
}
|
|
4092
|
-
/** Does this font have a glyph for the character? */
|
|
4093
|
-
has(key, cp) {
|
|
4094
|
-
let m = this.cover.get(key);
|
|
4095
|
-
if (!m) {
|
|
4096
|
-
m = /* @__PURE__ */ new Map();
|
|
4097
|
-
this.cover.set(key, m);
|
|
4098
|
-
}
|
|
4099
|
-
let h = m.get(cp);
|
|
4100
|
-
if (h === void 0) {
|
|
4101
|
-
h = !!this.store.get(key).hasGlyphForCodePoint(cp);
|
|
4102
|
-
m.set(cp, h);
|
|
4103
|
-
}
|
|
4104
|
-
return h;
|
|
4105
|
-
}
|
|
4106
|
-
/** The font for one character: the chosen one, else the bundled fallback for its script, else the one before. */
|
|
4107
|
-
pick(cp, key, prev) {
|
|
4108
|
-
if (cp < 32 || this.has(key, cp)) return key;
|
|
4109
|
-
const fb = fallbackKey(cp, key);
|
|
4110
|
-
if (fb && !this.store.failed.has(fb)) {
|
|
4111
|
-
if (!this.store.has(fb)) {
|
|
4112
|
-
this.missing.add(fb);
|
|
4113
|
-
return key;
|
|
4114
|
-
}
|
|
4115
|
-
if (this.has(fb, cp)) return fb;
|
|
4116
|
-
}
|
|
4117
|
-
if (prev && prev !== key && this.has(prev, cp)) return prev;
|
|
4118
|
-
if (!this.missing.size) this.noGlyph.add(String.fromCodePoint(cp));
|
|
4119
|
-
return key;
|
|
4120
|
-
}
|
|
4121
|
-
/**
|
|
4122
|
-
* Bidi levels, a font per character, runs (one font, level, script, and space or not), shaping,
|
|
4123
|
-
* then visual order. Cached at size 1.
|
|
4124
|
-
* @param {string} text @param {string} key a loaded key @param {'ltr'|'rtl'|undefined} dir
|
|
4125
|
-
* @returns {{ w: number, rtl: boolean, runs: Run[] }}
|
|
4126
|
-
*/
|
|
4127
|
-
layout(text, key, dir) {
|
|
4128
|
-
const ck = `${key}${dir || ""}${text}`;
|
|
4129
|
-
const hit = this.cache.get(ck);
|
|
4130
|
-
if (hit) return hit;
|
|
4131
|
-
let levels = null, rtl = dir === "rtl";
|
|
4132
|
-
if (dir === "rtl" || RTL_OR_CONTROLS.test(text)) {
|
|
4133
|
-
const e = bidi.getEmbeddingLevels(text, dir);
|
|
4134
|
-
levels = e.levels;
|
|
4135
|
-
rtl = ((e.paragraphs[0]?.level ?? 0) & 1) === 1;
|
|
4136
|
-
}
|
|
4137
|
-
const segs = [];
|
|
4138
|
-
let cur = null, prevFont = "";
|
|
4139
|
-
for (let i = 0; i < text.length; ) {
|
|
4140
|
-
const cp = (
|
|
4141
|
-
/** @type {number} */
|
|
4142
|
-
text.codePointAt(i)
|
|
4143
|
-
);
|
|
4144
|
-
const n = cp > 65535 ? 2 : 1;
|
|
4145
|
-
const ch = text.slice(i, i + n);
|
|
4146
|
-
const font = STICKY.test(ch) && prevFont ? prevFont : this.pick(cp, key, prevFont);
|
|
4147
|
-
const level = levels ? levels[i] : 0;
|
|
4148
|
-
const ws = SPACE.test(ch);
|
|
4149
|
-
const script = scriptOf(cp);
|
|
4150
|
-
if (!cur || font !== cur.font || level !== cur.level || ws !== cur.ws || script !== "Common" && cur.script !== "Common" && script !== cur.script) {
|
|
4151
|
-
cur = { start: i, end: i + n, font, level, script, ws };
|
|
4152
|
-
segs.push(cur);
|
|
4153
|
-
} else {
|
|
4154
|
-
cur.end = i + n;
|
|
4155
|
-
if (cur.script === "Common") cur.script = script;
|
|
4156
|
-
}
|
|
4157
|
-
prevFont = font;
|
|
4158
|
-
i += n;
|
|
4159
|
-
}
|
|
4160
|
-
const runs = segs.map((s) => this.shapeRun(text.slice(s.start, s.end), s.font, (s.level & 1) === 1, s.script));
|
|
4161
|
-
const order = runs.map((r, i) => ({ r, level: segs[i].level }));
|
|
4162
|
-
let max = 0, minOdd = Infinity;
|
|
4163
|
-
for (const o of order) {
|
|
4164
|
-
max = Math.max(max, o.level);
|
|
4165
|
-
if (o.level & 1) minOdd = Math.min(minOdd, o.level);
|
|
4166
|
-
}
|
|
4167
|
-
for (let l = max; l >= minOdd; l--) {
|
|
4168
|
-
for (let i = 0; i < order.length; ) {
|
|
4169
|
-
if (order[i].level < l) {
|
|
4170
|
-
i++;
|
|
4171
|
-
continue;
|
|
4172
|
-
}
|
|
4173
|
-
let j = i;
|
|
4174
|
-
while (j < order.length && order[j].level >= l) j++;
|
|
4175
|
-
const rev = order.slice(i, j).reverse();
|
|
4176
|
-
order.splice(i, j - i, ...rev);
|
|
4177
|
-
i = j;
|
|
4178
|
-
}
|
|
4179
|
-
}
|
|
4180
|
-
let x = 0;
|
|
4181
|
-
for (const o of order) {
|
|
4182
|
-
o.r.x = x;
|
|
4183
|
-
x += o.r.w;
|
|
4184
|
-
}
|
|
4185
|
-
const out = { w: x, rtl, runs: order.map((o) => o.r) };
|
|
4186
|
-
if (this.cache.size > 2e4) this.cache.clear();
|
|
4187
|
-
this.cache.set(ck, out);
|
|
4188
|
-
return out;
|
|
4189
|
-
}
|
|
4190
|
-
/** One run at size 1: HarfBuzz for complex scripts and right-to-left text, else character-map glyphs. @returns {Run} */
|
|
4191
|
-
shapeRun(text, key, rtl, script) {
|
|
4192
|
-
const complex = !SIMPLE.has(script);
|
|
4193
|
-
const store = this.store;
|
|
4194
|
-
const glyphs = [];
|
|
4195
|
-
let pen = 0;
|
|
4196
|
-
if ((complex || rtl) && store.shaper) {
|
|
4197
|
-
const hf = store.hbFont(key);
|
|
4198
|
-
const g = store.shaper.shape(hf, text, rtl, !complex);
|
|
4199
|
-
for (let i = 0; i < g.length; i += 5) {
|
|
4200
|
-
glyphs.push(g[i], (pen + g[i + 2]) / hf.upem, g[i + 3] / hf.upem, g[i + 4]);
|
|
4201
|
-
pen += g[i + 1];
|
|
4202
|
-
}
|
|
4203
|
-
return { font: key, x: 0, w: pen / hf.upem, text, ...rtl ? { rtl } : {}, ...complex ? { shaped: true } : {}, glyphs };
|
|
4204
|
-
}
|
|
4205
|
-
if ((complex || rtl) && !store.failed.has(SHAPER)) this.missing.add(SHAPER);
|
|
4206
|
-
else if (complex || rtl) this.unshaped = true;
|
|
4207
|
-
const f4 = store.get(key);
|
|
4208
|
-
const list = [];
|
|
4209
|
-
for (let i = 0; i < text.length; ) {
|
|
4210
|
-
const cp = (
|
|
4211
|
-
/** @type {number} */
|
|
4212
|
-
text.codePointAt(i)
|
|
4213
|
-
);
|
|
4214
|
-
const g = f4.glyphForCodePoint(cp);
|
|
4215
|
-
list.push([g.id, g.advanceWidth || 0, i]);
|
|
4216
|
-
i += cp > 65535 ? 2 : 1;
|
|
4217
|
-
}
|
|
4218
|
-
if (rtl) list.reverse();
|
|
4219
|
-
for (const [id, a, c] of list) {
|
|
4220
|
-
glyphs.push(id, pen / f4.unitsPerEm, 0, c);
|
|
4221
|
-
pen += a;
|
|
4222
|
-
}
|
|
4223
|
-
return { font: key, x: 0, w: pen / f4.unitsPerEm, text, ...rtl ? { rtl } : {}, glyphs };
|
|
4224
|
-
}
|
|
4225
|
-
};
|
|
4226
|
-
function finishText(items, m) {
|
|
4227
|
-
for (const it of items) {
|
|
4228
|
-
if (it.t === "field") {
|
|
4229
|
-
finishText(it.draw, m);
|
|
4230
|
-
continue;
|
|
4231
|
-
}
|
|
4232
|
-
if (it.t !== "text") continue;
|
|
4233
|
-
it.font = m.usable(it.font);
|
|
4234
|
-
for (const l of it.lines) {
|
|
4235
|
-
const r = m.runs(l.text, it.font, it.size, l.dir);
|
|
4236
|
-
if (r) l.runs = r;
|
|
4237
|
-
}
|
|
4238
|
-
}
|
|
4239
|
-
}
|
|
4240
|
-
|
|
4241
3743
|
// src/engine/style.js
|
|
4242
3744
|
var BASE_STYLE = {
|
|
4243
3745
|
fontFamily: "Inter",
|
|
@@ -4669,6 +4171,11 @@ function niceScale(min, max, ticks = 5) {
|
|
|
4669
4171
|
const step3 = niceNum(range / Math.max(1, ticks - 1), true);
|
|
4670
4172
|
return { lo: Math.floor(min / step3) * step3, hi: Math.ceil(max / step3) * step3, step: step3 };
|
|
4671
4173
|
}
|
|
4174
|
+
function niceScaleSpan(min, max, ticks = 5) {
|
|
4175
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || !(max > min)) return niceScale(min, max, ticks);
|
|
4176
|
+
const step3 = niceNum((max - min) / Math.max(1, ticks - 1), true);
|
|
4177
|
+
return { lo: Math.floor(min / step3) * step3, hi: Math.ceil(max / step3) * step3, step: step3 };
|
|
4178
|
+
}
|
|
4672
4179
|
function niceNum(x, round) {
|
|
4673
4180
|
const e = Math.floor(Math.log10(x));
|
|
4674
4181
|
const f4 = x / 10 ** e;
|
|
@@ -5625,7 +5132,7 @@ var byName2 = (lc, pal) => (name) => {
|
|
|
5625
5132
|
};
|
|
5626
5133
|
function chartData(item, ctx, lc, pal = paletteOf(item.palette)) {
|
|
5627
5134
|
let rows = item.dataSet ? related(lc.dataSets[item.dataSet] || [], ctx) : ctx.aggRows || [];
|
|
5628
|
-
if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name}: the data set "${item.dataSet}" does not exist`);
|
|
5135
|
+
if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name || item.type}: the data set "${item.dataSet}" does not exist`);
|
|
5629
5136
|
if (item.filters?.length) rows = applyFilters(rows, item.filters, ctx);
|
|
5630
5137
|
if (item.sort?.length) rows = applySort(rows, item.sort, ctx);
|
|
5631
5138
|
const who = item.name || "Chart";
|
|
@@ -5913,13 +5420,15 @@ function valueAxis(spec, lo, hi, minPos, { includeZero = true, len = 100, fs = 7
|
|
|
5913
5420
|
lo = lo < 0 ? -1 : 0;
|
|
5914
5421
|
hi = 1;
|
|
5915
5422
|
}
|
|
5423
|
+
let padded = false;
|
|
5916
5424
|
if (pad2 > 0 && hi > lo) {
|
|
5917
5425
|
const d = (hi - lo) * pad2;
|
|
5918
|
-
if (smin == null) lo
|
|
5919
|
-
if (smax == null) hi
|
|
5426
|
+
if (smin == null) lo = lo >= 0 && lo - d < 0 ? 0 : lo - d;
|
|
5427
|
+
if (smax == null) hi = hi <= 0 && hi + d > 0 ? 0 : hi + d;
|
|
5428
|
+
padded = true;
|
|
5920
5429
|
}
|
|
5921
5430
|
const want = len < fs * 6 ? 3 : 5;
|
|
5922
|
-
const sc = niceScale(smin ?? lo, smax ?? hi, want);
|
|
5431
|
+
const sc = padded && smin == null && smax == null && (lo >= 0 || hi <= 0) ? niceScaleSpan(lo, hi, want) : niceScale(smin ?? lo, smax ?? hi, want);
|
|
5923
5432
|
let a = sc.lo, b = sc.hi, ticks;
|
|
5924
5433
|
if (smin != null || smax != null) {
|
|
5925
5434
|
a = smin ?? sc.lo;
|
|
@@ -6347,31 +5856,27 @@ function rowPoints(type, g) {
|
|
|
6347
5856
|
rows = rows.slice(0, cap);
|
|
6348
5857
|
}
|
|
6349
5858
|
const blank2 = (v) => v == null || v === "";
|
|
6350
|
-
const
|
|
5859
|
+
const drawn = /* @__PURE__ */ new Set();
|
|
6351
5860
|
const sets = data.series.map((s, si) => {
|
|
6352
5861
|
const pts = [];
|
|
6353
5862
|
rows.forEach((r, ri) => {
|
|
6354
5863
|
c.fields = r;
|
|
6355
5864
|
const rx = safe2(item.xValue, c, lc, who), ry = safe2(s.def.value || "=0", { ...c, aggRows: [r] }, lc, who);
|
|
6356
|
-
if (blank2(rx) || blank2(ry))
|
|
6357
|
-
missing.add(ri);
|
|
6358
|
-
return;
|
|
6359
|
-
}
|
|
5865
|
+
if (blank2(rx) || blank2(ry)) return;
|
|
6360
5866
|
const x = Number(rx), y = Number(ry);
|
|
6361
|
-
if (!Number.isFinite(x) || !Number.isFinite(y))
|
|
6362
|
-
missing.add(ri);
|
|
6363
|
-
return;
|
|
6364
|
-
}
|
|
5867
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return;
|
|
6365
5868
|
let size = 1;
|
|
6366
5869
|
if (type === "bubble") {
|
|
6367
5870
|
size = Number(safe2(s.def.size || "=1", { ...c, aggRows: [r] }, lc, who));
|
|
6368
5871
|
if (!Number.isFinite(size) || size <= 0) return;
|
|
6369
5872
|
}
|
|
6370
5873
|
pts.push({ x, y, size });
|
|
5874
|
+
drawn.add(ri);
|
|
6371
5875
|
});
|
|
6372
5876
|
return { s, pts, i: si };
|
|
6373
5877
|
});
|
|
6374
|
-
|
|
5878
|
+
const missing = rows.length - drawn.size;
|
|
5879
|
+
if (missing > 0) lc.warn(`${who}: ${missing} of ${rows.length} rows have no x or y value and are not drawn`);
|
|
6375
5880
|
return sets;
|
|
6376
5881
|
}
|
|
6377
5882
|
function paintXY(type, g) {
|
|
@@ -7652,12 +7157,12 @@ function parseRich(html, opt = {}) {
|
|
|
7652
7157
|
i = e + 1;
|
|
7653
7158
|
continue;
|
|
7654
7159
|
}
|
|
7655
|
-
const
|
|
7656
|
-
if (!
|
|
7657
|
-
i =
|
|
7658
|
-
const name =
|
|
7160
|
+
const tag3 = readTag(s, i);
|
|
7161
|
+
if (!tag3) break;
|
|
7162
|
+
i = tag3.end;
|
|
7163
|
+
const name = tag3.name;
|
|
7659
7164
|
if (!name) continue;
|
|
7660
|
-
if (!
|
|
7165
|
+
if (!tag3.close && SKIP.has(name)) {
|
|
7661
7166
|
const e = low.indexOf(`</${name}`, i);
|
|
7662
7167
|
if (e < 0) break;
|
|
7663
7168
|
const g = s.indexOf(">", e);
|
|
@@ -7666,7 +7171,7 @@ function parseRich(html, opt = {}) {
|
|
|
7666
7171
|
continue;
|
|
7667
7172
|
}
|
|
7668
7173
|
if (name === "br") {
|
|
7669
|
-
if (
|
|
7174
|
+
if (tag3.close) continue;
|
|
7670
7175
|
if (++nBreaks > RICH_LIMITS.maxBreaks) {
|
|
7671
7176
|
cutAt(`${RICH_LIMITS.maxBreaks} line breaks`);
|
|
7672
7177
|
continue;
|
|
@@ -7679,7 +7184,7 @@ function parseRich(html, opt = {}) {
|
|
|
7679
7184
|
if (unknown.size < 20) unknown.add(name.slice(0, 20));
|
|
7680
7185
|
continue;
|
|
7681
7186
|
}
|
|
7682
|
-
if (
|
|
7187
|
+
if (tag3.close) {
|
|
7683
7188
|
if (ignored > 0) {
|
|
7684
7189
|
ignored--;
|
|
7685
7190
|
continue;
|
|
@@ -7697,7 +7202,7 @@ function parseRich(html, opt = {}) {
|
|
|
7697
7202
|
stack2.length = k;
|
|
7698
7203
|
continue;
|
|
7699
7204
|
}
|
|
7700
|
-
if (
|
|
7205
|
+
if (tag3.self && name !== "li") continue;
|
|
7701
7206
|
if (stack2.length > RICH_LIMITS.maxDepth) {
|
|
7702
7207
|
ignored++;
|
|
7703
7208
|
if (!deepWarned) {
|
|
@@ -7731,7 +7236,7 @@ function parseRich(html, opt = {}) {
|
|
|
7731
7236
|
st.script = "sub";
|
|
7732
7237
|
break;
|
|
7733
7238
|
case "a": {
|
|
7734
|
-
const h = decode2(
|
|
7239
|
+
const h = decode2(tag3.attrs.href ?? "");
|
|
7735
7240
|
const ok = safeHref(h);
|
|
7736
7241
|
if (ok) st.href = ok;
|
|
7737
7242
|
else if (h) warn(`Rich text: the link "${h.slice(0, 40)}" is not allowed (only http, https, mailto and / links); its text is kept.`);
|
|
@@ -7743,7 +7248,7 @@ function parseRich(html, opt = {}) {
|
|
|
7743
7248
|
st.fontWeight = "bold";
|
|
7744
7249
|
}
|
|
7745
7250
|
}
|
|
7746
|
-
if (
|
|
7251
|
+
if (tag3.attrs.style) applyCss(tag3.attrs.style, st);
|
|
7747
7252
|
if (BLOCK.has(name)) {
|
|
7748
7253
|
flush();
|
|
7749
7254
|
if (name === "ul" || name === "ol") lists.push({ ordered: name === "ol", n: 0 });
|
|
@@ -8792,7 +8297,7 @@ function hidden(item, ctx, lc) {
|
|
|
8792
8297
|
const r = evalSafe(item.hidden, ctx, lc, item.name || item.type);
|
|
8793
8298
|
h = !r.err && truthy(r.v);
|
|
8794
8299
|
}
|
|
8795
|
-
return item.name && lc.state?.toggles?.[`item:${item.name}`] ? !h : h;
|
|
8300
|
+
return item.name && lc.state?.toggles?.[`item:${item.name || item.type}`] ? !h : h;
|
|
8796
8301
|
}
|
|
8797
8302
|
var SHRINK_DEFAULTS = { minFontSize: 4, step: 0.5 };
|
|
8798
8303
|
function rotationOf(item) {
|
|
@@ -9128,7 +8633,7 @@ register("table", {
|
|
|
9128
8633
|
else {
|
|
9129
8634
|
rows = item.dataSet && lc.dataSets[item.dataSet] || [];
|
|
9130
8635
|
rows = related(rows, tctx);
|
|
9131
|
-
if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name ||
|
|
8636
|
+
if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name || item.type}: the data set "${item.dataSet}" does not exist`);
|
|
9132
8637
|
if (item.filters?.length) rows = applyFilters(rows, item.filters, tctx);
|
|
9133
8638
|
const sort = lc.state?.sort?.[item.name] || item.sort;
|
|
9134
8639
|
if (sort?.length) rows = applySort(rows, sort, tctx);
|
|
@@ -9144,11 +8649,11 @@ register("table", {
|
|
|
9144
8649
|
if (overflow === "shrink" && room > 0) {
|
|
9145
8650
|
const k = room / designedW;
|
|
9146
8651
|
cols = cols.map((c) => ({ ...c, width: (Number(c.width) || 0) * k }));
|
|
9147
|
-
lc.warn(`${item.name ||
|
|
8652
|
+
lc.warn(`${item.name || item.type}: its columns are ${Math.round(designedW)}pt wide, wider than the page (${Math.round(room)}pt), so they are narrowed to fit`);
|
|
9148
8653
|
} else if (overflow === "clip" || overflow === "paginate" && lc.fixed) {
|
|
9149
|
-
lc.warn(`${item.name ||
|
|
8654
|
+
lc.warn(`${item.name || item.type}: its columns are ${Math.round(designedW)}pt wide, wider than the page (${Math.round(room)}pt), so the columns past the page edge are cut`, true);
|
|
9150
8655
|
} else if (overflow === "paginate" && item.overflow !== "paginate") {
|
|
9151
|
-
lc.warn(`${item.name ||
|
|
8656
|
+
lc.warn(`${item.name || item.type}: its columns are ${Math.round(designedW)}pt wide, wider than the page (${Math.round(room)}pt), so they continue on the next pages`);
|
|
9152
8657
|
}
|
|
9153
8658
|
const colX = [];
|
|
9154
8659
|
let acc = item.x;
|
|
@@ -9158,13 +8663,14 @@ register("table", {
|
|
|
9158
8663
|
}
|
|
9159
8664
|
const width = acc - item.x;
|
|
9160
8665
|
const region = { name: item.name, columns: cols.map((c) => c.width), rows: [] };
|
|
8666
|
+
if (lc.tablesSeen) lc.tablesSeen.n++;
|
|
9161
8667
|
const tableScope = { rows, index: -1, run: [] };
|
|
9162
8668
|
const scopes = { ...tctx.scopes || {}, [item.name]: tableScope };
|
|
9163
8669
|
const groupChains = {};
|
|
9164
8670
|
(item.groups || []).forEach((g, i) => {
|
|
9165
8671
|
if (g.name) groupChains[g.name] = { rows, keys: item.groups.slice(0, i + 1).map((x) => x.expr) };
|
|
9166
8672
|
});
|
|
9167
|
-
const base = { ...tctx, aggRows: rows, aggIndex: void 0, fields: rows[0] || null, scopes, region: tableScope, group: void 0, groupChains: { ...tctx.groupChains || {}, ...groupChains } };
|
|
8673
|
+
const base = { ...tctx, aggRows: rows, aggIndex: void 0, fields: lc.win?.first || rows[0] || null, scopes, region: tableScope, group: void 0, groupChains: { ...tctx.groupChains || {}, ...groupChains } };
|
|
9168
8674
|
const units = [];
|
|
9169
8675
|
let y = 0;
|
|
9170
8676
|
let repeatH = 0;
|
|
@@ -9181,7 +8687,7 @@ register("table", {
|
|
|
9181
8687
|
const covered = (ci) => cover[ci] !== null;
|
|
9182
8688
|
const cellsAt = /* @__PURE__ */ new WeakMap();
|
|
9183
8689
|
const layRow = (row, ctx, kind, extra) => {
|
|
9184
|
-
if (row.hidden != null && row.hidden !== false && row.hidden !== "" && hidden({ hidden: row.hidden, name: `${item.name ||
|
|
8690
|
+
if (row.hidden != null && row.hidden !== false && row.hidden !== "" && hidden({ hidden: row.hidden, name: `${item.name || item.type} row` }, ctx, lc)) {
|
|
9185
8691
|
if (openSpans.length) {
|
|
9186
8692
|
for (const s of openSpans) s.left--;
|
|
9187
8693
|
for (const s of openSpans) if (s.left <= 0) closeSpan(s);
|
|
@@ -9215,7 +8721,7 @@ register("table", {
|
|
|
9215
8721
|
else try {
|
|
9216
8722
|
v = evalValue(cell.value ?? "", cctx);
|
|
9217
8723
|
} catch (e) {
|
|
9218
|
-
lc.warn(`${item.name ||
|
|
8724
|
+
lc.warn(`${item.name || item.type} cell: ${e.message}`);
|
|
9219
8725
|
v = "#Error";
|
|
9220
8726
|
}
|
|
9221
8727
|
let text = textOf(v, st, cctx, lc);
|
|
@@ -9258,7 +8764,7 @@ register("table", {
|
|
|
9258
8764
|
cells.forEach((c, k) => {
|
|
9259
8765
|
if (c.cell.visual?.type) {
|
|
9260
8766
|
items.push(...paintBox({ x: c.x, y: 0, w: c.w, h, st: c.st, tl: null, m: lc.m }));
|
|
9261
|
-
if (first) items.push(...paintVisual(c.cell.visual, { x: c.x, y: 0, w: c.w, h }, c.ctx, lc, c.st, `${item.name} cell`, { cell: true }));
|
|
8767
|
+
if (first) items.push(...paintVisual(c.cell.visual, { x: c.x, y: 0, w: c.w, h }, c.ctx, lc, c.st, `${item.name || item.type} cell`, { cell: true }));
|
|
9262
8768
|
return;
|
|
9263
8769
|
}
|
|
9264
8770
|
if (c.nested) {
|
|
@@ -9267,8 +8773,8 @@ register("table", {
|
|
|
9267
8773
|
else if (first) items.push(...c.nested.items);
|
|
9268
8774
|
return;
|
|
9269
8775
|
}
|
|
9270
|
-
const
|
|
9271
|
-
paintBoxAt(c.x, 0, c.w, h, c.st, lines ? { ...c.tl, lines: lines[k] } : c.tl, c.numeric, lc.m, true, items,
|
|
8776
|
+
const tag3 = lc.regions ? { table: item.name, row: rowId, col: colIdx[c.ci], span: c.span, kind, cols: colWidths, bg: c.st.backgroundColor || null } : null;
|
|
8777
|
+
paintBoxAt(c.x, 0, c.w, h, c.st, lines ? { ...c.tl, lines: lines[k] } : c.tl, c.numeric, lc.m, true, items, tag3);
|
|
9272
8778
|
if (first) cellLinks(items, c, h, kind, extra?.level);
|
|
9273
8779
|
});
|
|
9274
8780
|
if (first) {
|
|
@@ -9313,7 +8819,7 @@ register("table", {
|
|
|
9313
8819
|
};
|
|
9314
8820
|
const layoutInCell = (inner, x, cw, st, cctx, row) => {
|
|
9315
8821
|
const pd = padding(st);
|
|
9316
|
-
const it = { ...inner, name: inner.name || `${item.name}_cell`, x: x + pd[3], y: 0, w: Math.max(1, cw - pd[1] - pd[3]), h: Number(inner.h) || Math.max(1, (row.height || 18) - pd[0] - pd[2]) };
|
|
8822
|
+
const it = { ...inner, name: inner.name || `${item.name || item.type}_cell`, x: x + pd[3], y: 0, w: Math.max(1, cw - pd[1] - pd[3]), h: Number(inner.h) || Math.max(1, (row.height || 18) - pd[0] - pd[2]) };
|
|
9317
8823
|
const scopeRows2 = cctx.aggIndex != null ? [cctx.fields] : cctx.aggRows || [];
|
|
9318
8824
|
const current = item.dataSet ? { ...cctx.current || {}, [item.dataSet]: scopeRows2 } : cctx.current;
|
|
9319
8825
|
const child = {
|
|
@@ -9333,7 +8839,7 @@ register("table", {
|
|
|
9333
8839
|
const reads = (it.dataSet && it.dataSet !== item.dataSet ? child.ctxFor(it).aggRows?.length : scopeRows2.length) || 1;
|
|
9334
8840
|
if (budget.left < reads) {
|
|
9335
8841
|
budget.left = 0;
|
|
9336
|
-
lc.warn(`${item.name}: more than ${CELL_ITEM_UNITS} rows of items inside cells; the rest are left empty`);
|
|
8842
|
+
lc.warn(`${item.name || item.type}: more than ${CELL_ITEM_UNITS} rows of items inside cells; the rest are left empty`);
|
|
9337
8843
|
return { items: [], height: 0 };
|
|
9338
8844
|
}
|
|
9339
8845
|
budget.left -= reads;
|
|
@@ -9367,8 +8873,8 @@ register("table", {
|
|
|
9367
8873
|
const st = k === 0 && n === 1 ? s.st : { ...s.st, ...k > 0 ? { borderTop: "none" } : {}, ...k < n - 1 ? { borderBottom: "none" } : {} };
|
|
9368
8874
|
const add2 = paintBox({ x: s.x, y: 0, w: s.w, h: u.height, st, tl: null, m: lc.m });
|
|
9369
8875
|
if (k === 0) {
|
|
9370
|
-
const
|
|
9371
|
-
const text = paintBox({ x: s.x, y: 0, w: s.w, h: H, st: { ...s.st, ...NO_BOX }, tl: s.tl, numeric: s.numeric, m: lc.m, cell:
|
|
8876
|
+
const tag3 = lc.regions ? { table: item.name, row: u.rowId, col: colX.indexOf(s.x), span: s.cols, rowSpan: n, kind, cols: colWidths, bg: s.st.backgroundColor || null } : null;
|
|
8877
|
+
const text = paintBox({ x: s.x, y: 0, w: s.w, h: H, st: { ...s.st, ...NO_BOX }, tl: s.tl, numeric: s.numeric, m: lc.m, cell: tag3 });
|
|
9372
8878
|
add2.splice(s.st.backgroundColor ? 1 : 0, 0, ...text);
|
|
9373
8879
|
cellLinks(add2, s, u.height, kind, s.level);
|
|
9374
8880
|
if (s.toggle) add2.push(toggleLink(s, s.w, u.height));
|
|
@@ -9377,7 +8883,7 @@ register("table", {
|
|
|
9377
8883
|
u.items.splice(at < 0 ? u.items.length : at, 0, ...add2);
|
|
9378
8884
|
});
|
|
9379
8885
|
if (s.tl.needed > s.units[0].height + GROW_TOLERANCE || s.st.verticalAlign && s.st.verticalAlign !== "top") {
|
|
9380
|
-
const id = `${item.name}:span:${lc.nextId()}`;
|
|
8886
|
+
const id = `${item.name || item.type}:span:${lc.nextId()}`;
|
|
9381
8887
|
for (const u of s.units) u.block || (u.block = id);
|
|
9382
8888
|
} else {
|
|
9383
8889
|
let above = s.units[0].height;
|
|
@@ -9402,7 +8908,8 @@ register("table", {
|
|
|
9402
8908
|
openSpans = [];
|
|
9403
8909
|
};
|
|
9404
8910
|
const fl = base.bandRows === "first-last";
|
|
9405
|
-
const
|
|
8911
|
+
const first0 = lc.win?.first || rows[0];
|
|
8912
|
+
const headerUnits = (item.header || []).map((r) => layRow(r, fl && rows.length ? { ...base, pendingRows: [first0] } : base, "header")).filter(Boolean);
|
|
9406
8913
|
endBand();
|
|
9407
8914
|
const headerHeight = headerUnits.reduce((s, u) => s + u.height, 0);
|
|
9408
8915
|
if (item.repeatHeader !== false) repeatH = headerHeight;
|
|
@@ -9416,9 +8923,9 @@ register("table", {
|
|
|
9416
8923
|
y += tl.needed;
|
|
9417
8924
|
}
|
|
9418
8925
|
const groups = item.groups || [];
|
|
9419
|
-
let rowNo = 0;
|
|
8926
|
+
let rowNo = lc.win?.rowOffset || 0;
|
|
9420
8927
|
const groupTables = [];
|
|
9421
|
-
const tableKey = `${item.name}#${lc.nextId()}`;
|
|
8928
|
+
const tableKey = `${item.name || item.type}#${lc.nextId()}`;
|
|
9422
8929
|
const emit = (level, grows, ctx, chain, keyPath) => {
|
|
9423
8930
|
if (level === groups.length) {
|
|
9424
8931
|
for (let i = 0; i < grows.length; i++) {
|
|
@@ -9436,9 +8943,16 @@ register("table", {
|
|
|
9436
8943
|
const dctx = { ...ctx, fields: grows[i], aggRows: grows, aggIndex: i, rowNumber: rowNo };
|
|
9437
8944
|
const u0 = units.length;
|
|
9438
8945
|
for (const r of item.detail || []) layRow(r, dctx, "detail", { level: groups.length });
|
|
9439
|
-
if (
|
|
8946
|
+
if (lc.win && units[u0]) {
|
|
8947
|
+
units[u0].rowHead = true;
|
|
8948
|
+
for (let k = u0; k < units.length; k++) units[k].dataRow = rowNo;
|
|
8949
|
+
}
|
|
8950
|
+
if (groups.length && item.widowControl !== false) for (let k = u0; k < units.length; k++) {
|
|
8951
|
+
units[k].grp = tableKey + keyPath;
|
|
8952
|
+
if (ctx.__before) units[k].grpBefore = ctx.__before;
|
|
8953
|
+
}
|
|
9440
8954
|
const every = Math.trunc(Number(item.pageBreakEvery)) || 0;
|
|
9441
|
-
if (every > 0 && rowNo > 1 && (rowNo - 1) % every === 0 && units[u0]) units[u0].breakBefore = true;
|
|
8955
|
+
if (every > 0 && rowNo > (lc.win?.rowOffset || 0) + 1 && (rowNo - 1) % every === 0 && units[u0]) units[u0].breakBefore = true;
|
|
9442
8956
|
endBand();
|
|
9443
8957
|
}
|
|
9444
8958
|
return;
|
|
@@ -9473,7 +8987,7 @@ register("table", {
|
|
|
9473
8987
|
kids = /* @__PURE__ */ new Map();
|
|
9474
8988
|
roots = [];
|
|
9475
8989
|
for (const b of buckets) {
|
|
9476
|
-
const pk = evalSafe(g.parent, { ...ctx, fields: b.rows[0], aggRows: b.rows, aggIndex: void 0 }, lc, `${item.name} group parent`).v;
|
|
8990
|
+
const pk = evalSafe(g.parent, { ...ctx, fields: b.rows[0], aggRows: b.rows, aggIndex: void 0 }, lc, `${item.name || item.type} group parent`).v;
|
|
9477
8991
|
const pr = pk == null || pk === "" ? null : byText.get(pk instanceof Date ? String(pk.getTime()) : String(pk));
|
|
9478
8992
|
if (!pr || pr === b) roots.push(b);
|
|
9479
8993
|
else {
|
|
@@ -9495,24 +9009,29 @@ register("table", {
|
|
|
9495
9009
|
}
|
|
9496
9010
|
const shown = /* @__PURE__ */ new Set();
|
|
9497
9011
|
const node = (bk, bi, sibs, depth, parentPath) => {
|
|
9498
|
-
var _a;
|
|
9499
9012
|
if (lc.rowBudget?.cut || shown.has(bk)) return;
|
|
9500
9013
|
shown.add(bk);
|
|
9501
9014
|
const sc = { rows: bk.rows, index: -1, run: [], number: bi + 1, prevRows: bi > 0 ? sibs[bi - 1].rows : null, siblings: sibRows(sibs), ...kids ? { level: depth, recRows: recOf.get(bk) } : {} };
|
|
9502
|
-
const
|
|
9015
|
+
const cont = bi === 0 && (level === 0 || ctx.__cont) ? lc.win?.cont?.[level] : null;
|
|
9016
|
+
const gctx = { ...ctx, fields: cont ? cont.first : bk.rows[0], aggRows: bk.rows, aggIndex: void 0, scopes: { ...ctx.scopes, [gname]: sc }, groupKey: bk.key, group: sc, __cont: !!cont, __before: cont && level === groups.length - 1 ? cont.before : 0 };
|
|
9503
9017
|
if (kids) {
|
|
9504
9018
|
gctx.level = depth;
|
|
9505
9019
|
if (g.indent) gctx.indent = (ctx.indent || 0) + depth * Number(g.indent);
|
|
9506
9020
|
}
|
|
9507
9021
|
const path = `${parentPath}/${bk.text}`;
|
|
9508
|
-
const tkey = `${item.name}|${level}|${path}`;
|
|
9022
|
+
const tkey = `${item.name || item.type}|${level}|${path}`;
|
|
9509
9023
|
const dflt = kids && g.expandLevels != null ? depth < Number(g.expandLevels) : !g.initiallyCollapsed;
|
|
9510
9024
|
const open = !g.collapsible ? true : lc.state?.toggles?.[tkey] ?? dflt;
|
|
9511
9025
|
const start = units.length;
|
|
9512
|
-
const hctx = g.header?.length ? { ...gctx, pendingRows: fl ? [bk.rows[0]] : recOf.get(bk) || bk.rows } : gctx;
|
|
9513
|
-
const hu = (g.header || []).map((r, ri) => layRow(r, hctx, "groupHeader", { level, ...ri === 0 && g.collapsible ? { toggle: { key: tkey, open } } : {} })).filter(Boolean);
|
|
9026
|
+
const hctx = g.header?.length ? { ...gctx, pendingRows: fl ? [cont ? cont.first : bk.rows[0]] : recOf.get(bk) || bk.rows } : gctx;
|
|
9027
|
+
const hu = (cont && !g.repeatHeader ? [] : g.header || []).map((r, ri) => layRow(r, hctx, "groupHeader", { level, ...ri === 0 && g.collapsible ? { toggle: { key: tkey, open } } : {} })).filter(Boolean);
|
|
9514
9028
|
endBand();
|
|
9515
9029
|
const before = units.length;
|
|
9030
|
+
if (lc.win && !cont && before > start) {
|
|
9031
|
+
for (let k = start; k < before; k++) units[k].dataRow = rowNo + 1;
|
|
9032
|
+
units[start].rowHead = true;
|
|
9033
|
+
units[start].headLevel = level;
|
|
9034
|
+
}
|
|
9516
9035
|
const rep = g.repeatHeader && before > start && !lc.fixed ? [...ctx.__rep || [], (() => {
|
|
9517
9036
|
const hdr = units.slice(start, before), h0 = hdr[0].top, its = [];
|
|
9518
9037
|
for (const u of hdr) for (const it of shiftLocal(u.items.filter((i) => i.t !== "link" && i.t !== "bookmark"), u.top - h0)) its.push(it);
|
|
@@ -9522,7 +9041,7 @@ register("table", {
|
|
|
9522
9041
|
const ch = kids?.get(bk) || [];
|
|
9523
9042
|
if (open) {
|
|
9524
9043
|
emit(level + 1, bk.rows, gctx, [...chain, sc], path);
|
|
9525
|
-
if (ch.length && depth + 1 >= MAX_TREE_DEPTH) lc.warn(`${item.name}: the group "${gname}" is more than ${MAX_TREE_DEPTH} levels deep; deeper rows are listed at the top level`);
|
|
9044
|
+
if (ch.length && depth + 1 >= MAX_TREE_DEPTH) lc.warn(`${item.name || item.type}: the group "${gname}" is more than ${MAX_TREE_DEPTH} levels deep; deeper rows are listed at the top level`);
|
|
9526
9045
|
else ch.forEach((c, ci) => node(c, ci, ch, depth + 1, path));
|
|
9527
9046
|
} else {
|
|
9528
9047
|
const rs = recOf.get(bk) || bk.rows;
|
|
@@ -9551,8 +9070,11 @@ register("table", {
|
|
|
9551
9070
|
if (g.newSection) units[start].sectionStart = true;
|
|
9552
9071
|
if (g.pageBreak === "after" && bi < sibs.length - 1) units[units.length - 1].breakAfter = true;
|
|
9553
9072
|
if (g.keepTogether) {
|
|
9554
|
-
const id = `${item.name}:g${level}:${path}:${lc.nextId()}`;
|
|
9555
|
-
for (let k = start; k < units.length; k++) (
|
|
9073
|
+
const id = `${item.name || item.type}:g${level}:${path}:${lc.nextId()}`;
|
|
9074
|
+
for (let k = start; k < units.length; k++) if (!units[k].block) {
|
|
9075
|
+
units[k].block = id;
|
|
9076
|
+
if (cont) units[k].blockOpen = true;
|
|
9077
|
+
}
|
|
9556
9078
|
}
|
|
9557
9079
|
}
|
|
9558
9080
|
};
|
|
@@ -9569,7 +9091,7 @@ register("table", {
|
|
|
9569
9091
|
if (kids) {
|
|
9570
9092
|
const rest = buckets.filter((b) => !shown.has(b));
|
|
9571
9093
|
if (rest.length) {
|
|
9572
|
-
lc.warn(`${item.name}: ${rest.length} rows of the group "${gname}" have no root (a cycle or too deep); they are listed at the top level`);
|
|
9094
|
+
lc.warn(`${item.name || item.type}: ${rest.length} rows of the group "${gname}" have no root (a cycle or too deep); they are listed at the top level`);
|
|
9573
9095
|
rest.forEach((bk, bi) => node(bk, bi, rest, 0, keyPath));
|
|
9574
9096
|
}
|
|
9575
9097
|
}
|
|
@@ -9597,7 +9119,7 @@ register("table", {
|
|
|
9597
9119
|
units[units.length - 1].breakAfter = true;
|
|
9598
9120
|
}
|
|
9599
9121
|
if (item.bookmark && units.length) {
|
|
9600
|
-
const b = evalSafe(item.bookmark, base, lc, `${item.name ||
|
|
9122
|
+
const b = evalSafe(item.bookmark, base, lc, `${item.name || item.type} bookmark`).v;
|
|
9601
9123
|
if (b != null && b !== "" && b !== "#Error") units[0].items.unshift({ t: "bookmark", label: String(b), x: item.x, y: 0, level: item.bookmarkLevel ?? 0 });
|
|
9602
9124
|
}
|
|
9603
9125
|
if (!lc.fixed) lc.regions?.push(region);
|
|
@@ -9692,7 +9214,7 @@ register("container", {
|
|
|
9692
9214
|
const ctx = lc.ctxFor(item);
|
|
9693
9215
|
if (hidden(item, ctx, lc)) return { height: 0, units: [] };
|
|
9694
9216
|
const res = lc.layoutItems(item.items, lc, { dx: item.x });
|
|
9695
|
-
return frame2(item, lc, ctx, res, item.keepTogether !== false ? `c:${item.name}:${lc.nextId()}` : null);
|
|
9217
|
+
return frame2(item, lc, ctx, res, item.keepTogether !== false ? `c:${item.name || item.type}:${lc.nextId()}` : null);
|
|
9696
9218
|
}
|
|
9697
9219
|
});
|
|
9698
9220
|
function frame2(item, lc, ctx, res, blockId0) {
|
|
@@ -9749,7 +9271,7 @@ register("list", {
|
|
|
9749
9271
|
let rows = item.dataSet && lc.dataSets[item.dataSet] || [];
|
|
9750
9272
|
if (item.inheritRows && item.dataSet && ctx.current?.[item.dataSet]) rows = ctx.current[item.dataSet];
|
|
9751
9273
|
else rows = related(rows, ctx);
|
|
9752
|
-
if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name}: the data set "${item.dataSet}" does not exist`);
|
|
9274
|
+
if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name || item.type}: the data set "${item.dataSet}" does not exist`);
|
|
9753
9275
|
if (item.filters?.length) rows = applyFilters(rows, item.filters, ctx);
|
|
9754
9276
|
if (item.sort?.length) rows = applySort(rows, item.sort, ctx);
|
|
9755
9277
|
const reps = item.groupBy ? groupRows(rows, item.groupBy, ctx, lc, item.name, item.groupAdjacent === true).map((b) => b.rows) : rows.map((r) => [r]);
|
|
@@ -9778,7 +9300,7 @@ register("list", {
|
|
|
9778
9300
|
} };
|
|
9779
9301
|
const k = i % ncol;
|
|
9780
9302
|
const res = lc.layoutItems(item.items, child, { dx: item.x + k * (item.w + gap) });
|
|
9781
|
-
const fr = frame2({ ...item, x: item.x + k * (item.w + gap), name: `${item.name}[${i + 1}]` }, child, rctx, res, item.keepTogether !== false ? `l:${item.name}:${i}:${lc.nextId()}` : null);
|
|
9303
|
+
const fr = frame2({ ...item, x: item.x + k * (item.w + gap), name: `${item.name || item.type}[${i + 1}]` }, child, rctx, res, item.keepTogether !== false ? `l:${item.name || item.type}:${i}:${lc.nextId()}` : null);
|
|
9782
9304
|
if (ncol > 1) {
|
|
9783
9305
|
if (k === 0) {
|
|
9784
9306
|
cells = { top: y, height: 0, items: [], x0: item.x, x1: item.x + ncol * item.w + (ncol - 1) * gap, block: void 0 };
|
|
@@ -10249,7 +9771,7 @@ register("subreport", {
|
|
|
10249
9771
|
if (hidden(item, ctx, lc)) return { height: 0, units: [] };
|
|
10250
9772
|
const params = {};
|
|
10251
9773
|
for (const [k, v] of Object.entries(item.params || {})) {
|
|
10252
|
-
const r = evalSafe(v, ctx, lc, `${item.name} parameter ${k}`);
|
|
9774
|
+
const r = evalSafe(v, ctx, lc, `${item.name || item.type} parameter ${k}`);
|
|
10253
9775
|
params[k] = r.v instanceof Date ? isoDate(r.v, ctx.timeZone) : r.v;
|
|
10254
9776
|
}
|
|
10255
9777
|
const key = `${item.report}|${JSON.stringify(params)}`;
|
|
@@ -10268,10 +9790,10 @@ register("subreport", {
|
|
|
10268
9790
|
const res = sub.results.get(key);
|
|
10269
9791
|
if (!res) return placeholder(`Subreport "${item.report}" did not load`);
|
|
10270
9792
|
if (res.error) {
|
|
10271
|
-
lc.warn(`${item.name}: ${res.error}`);
|
|
9793
|
+
lc.warn(`${item.name || item.type}: ${res.error}`);
|
|
10272
9794
|
return placeholder(`Subreport "${item.report}": ${res.error}`);
|
|
10273
9795
|
}
|
|
10274
|
-
const block = item.keepTogether ? `s:${item.name}:${lc.nextId()}` : void 0;
|
|
9796
|
+
const block = item.keepTogether ? `s:${item.name || item.type}:${lc.nextId()}` : void 0;
|
|
10275
9797
|
const units = res.units.map((u) => ({ ...u, items: shiftItems(u.items, item.x, 0), ...u.cont ? { cont: shiftItems(u.cont, item.x, 0) } : {}, x0: (u.x0 ?? 0) + item.x, x1: (u.x1 ?? item.w) + item.x, block: u.block || block, tableId: void 0 }));
|
|
10276
9798
|
const tables = res.tables.map((t) => ({ ...t, x0: t.x0 + item.x, x1: t.x1 + item.x, headerItems: shiftItems(t.headerItems, item.x, 0), id: `sub${lc.nextId()}` }));
|
|
10277
9799
|
for (const r of res.regions || []) lc.regions?.push(r);
|
|
@@ -10478,7 +10000,8 @@ function paginate(units, tables, pageH, warn, stats) {
|
|
|
10478
10000
|
if (b) {
|
|
10479
10001
|
b.top = Math.min(b.top, u.top);
|
|
10480
10002
|
b.bottom = Math.max(b.bottom, u.top + u.height);
|
|
10481
|
-
|
|
10003
|
+
if (u.blockOpen) b.open = true;
|
|
10004
|
+
} else blockMap.set(u.block, { top: u.top, bottom: u.top + u.height, open: !!u.blockOpen });
|
|
10482
10005
|
}
|
|
10483
10006
|
const blockUnits = /* @__PURE__ */ new Map();
|
|
10484
10007
|
for (const u of units) if (u.block) {
|
|
@@ -10486,18 +10009,18 @@ function paginate(units, tables, pageH, warn, stats) {
|
|
|
10486
10009
|
if (!l) blockUnits.set(u.block, l = []);
|
|
10487
10010
|
l.push(u);
|
|
10488
10011
|
}
|
|
10489
|
-
const blocks = [...blockMap.values()].filter((b) => b.bottom - b.top <= pageH + EPS2);
|
|
10012
|
+
const blocks = [...blockMap.values()].filter((b) => !b.open && b.bottom - b.top <= pageH + EPS2);
|
|
10490
10013
|
for (const b of blocks) cand.push(b.top, b.bottom);
|
|
10491
10014
|
cand.sort((a, b) => a - b);
|
|
10492
10015
|
const grpRows = /* @__PURE__ */ new Map();
|
|
10493
10016
|
for (const u of units) if (u.grp) {
|
|
10494
10017
|
let g = grpRows.get(u.grp);
|
|
10495
|
-
if (!g) grpRows.set(u.grp, g = { tops: /* @__PURE__ */ new Set(), first: u.top, last: 0, block: u.block || null });
|
|
10018
|
+
if (!g) grpRows.set(u.grp, g = { tops: /* @__PURE__ */ new Set(), first: u.top, last: 0, block: u.block || null, before: u.grpBefore || 0 });
|
|
10496
10019
|
g.tops.add(u.top);
|
|
10497
10020
|
g.last = Math.max(g.last, u.top + u.height);
|
|
10498
10021
|
if (g.block !== (u.block || null)) g.block = void 0;
|
|
10499
10022
|
}
|
|
10500
|
-
const widowGroups = [...grpRows.values()].map((g) => ({ first: g.first, last: g.last, tops: [...g.tops].sort((a, b) => a - b), block: g.block })).filter((g) => g.
|
|
10023
|
+
const widowGroups = [...grpRows.values()].map((g) => ({ first: g.first, last: g.last, tops: [...g.tops].sort((a, b) => a - b), block: g.block, before: g.before, n: g.tops.size + g.before })).filter((g) => g.n >= 4 || !g.before && g.n >= 2 && g.last - g.first <= pageH + EPS2).sort((a, b) => a.first - b.first);
|
|
10501
10024
|
const wFirst = widowGroups.map((g) => g.first);
|
|
10502
10025
|
const wMaxLast = [];
|
|
10503
10026
|
widowGroups.forEach((g, i) => wMaxLast.push(Math.max(i ? wMaxLast[i - 1] : -Infinity, g.last)));
|
|
@@ -10524,9 +10047,9 @@ function paginate(units, tables, pageH, warn, stats) {
|
|
|
10524
10047
|
tick(1);
|
|
10525
10048
|
const g = widowGroups[i];
|
|
10526
10049
|
if (g.last <= y + EPS2 || g.block && !withBlocks) continue;
|
|
10527
|
-
if (g.
|
|
10528
|
-
const above = rowsAbove(g.tops, y);
|
|
10529
|
-
if (above < 2 || g.
|
|
10050
|
+
if (g.n < 4) return false;
|
|
10051
|
+
const above = g.before + rowsAbove(g.tops, y);
|
|
10052
|
+
if (above < 2 || g.n - above < 2) return false;
|
|
10530
10053
|
}
|
|
10531
10054
|
return true;
|
|
10532
10055
|
};
|
|
@@ -10581,7 +10104,7 @@ function paginate(units, tables, pageH, warn, stats) {
|
|
|
10581
10104
|
if (u.block) {
|
|
10582
10105
|
const bl = blockMap.get(u.block);
|
|
10583
10106
|
if (movedBlocks.has(bl)) continue;
|
|
10584
|
-
if (!bl || bl.bottom - bl.top > room + EPS2 || bl.top <= top2 + EPS2) return null;
|
|
10107
|
+
if (!bl || bl.open || bl.bottom - bl.top > room + EPS2 || bl.top <= top2 + EPS2) return null;
|
|
10585
10108
|
movedBlocks.add(bl);
|
|
10586
10109
|
for (const m of blockUnits.get(u.block)) if (!placed.has(m)) moved.push(m);
|
|
10587
10110
|
continue;
|
|
@@ -10763,7 +10286,7 @@ function layoutItems(items, lc, { dx = 0 } = {}) {
|
|
|
10763
10286
|
const own = L.res.table ? { id: lc.nextId(), ...L.res.table } : null;
|
|
10764
10287
|
const us = L.res.units;
|
|
10765
10288
|
const alt = it.alt || L.res.alt;
|
|
10766
|
-
const
|
|
10289
|
+
const tag3 = alt || it.headingLevel || FIGURES.has(it.type) ? { k: it.type, id: lc.nextId(), alt: alt ? String(alt).slice(0, 2e3) : void 0, h: Number(it.headingLevel) || void 0 } : null;
|
|
10767
10290
|
for (let k = 0; k < us.length; k++) {
|
|
10768
10291
|
const u = us[k];
|
|
10769
10292
|
u.x0 = u.x0 ?? x0;
|
|
@@ -10772,7 +10295,7 @@ function layoutItems(items, lc, { dx = 0 } = {}) {
|
|
|
10772
10295
|
u.tableId = own ? own.id : u.tableId;
|
|
10773
10296
|
u.breakBefore = u.breakBefore || k === 0 && !!it.pageBreakBefore;
|
|
10774
10297
|
u.breakAfter = u.breakAfter || k === us.length - 1 && !!it.pageBreakAfter;
|
|
10775
|
-
if (
|
|
10298
|
+
if (tag3) for (const d of u.items) d.tag ?? (d.tag = tag3);
|
|
10776
10299
|
units.push(u);
|
|
10777
10300
|
}
|
|
10778
10301
|
if (own) tables.push({ ...own, top, bottom: top + L.res.height, x0, x1 });
|
|
@@ -13321,6 +12844,7 @@ var SCHEMA_ALIAS = "reportwright/report@1";
|
|
|
13321
12844
|
var ITEM_KEYS = new Set("id type name x y w h style styleName items hidden layer locked label alt value dataSet canGrow canShrink action bookmark tooltip keepTogether pageBreakBefore pageBreakAfter pageBreakBetween newSection filters sort groups groupBy groupAdjacent inheritRows columns header detail footer repeatHeader widowControl noRowsText pageBreakEvery cells rows rowGroup rowGroups columnGro\
|
|
13322
12845
|
up columnGroups values value valueFormat rowSort columnSort rowTotals columnTotals cellStyle headerStyle totalStyle corner partProps library part properties overflow overflowTo src fit headingLevel rotate shrinkToFit minFontSize shrinkStep tocDots tocLink tocPage format chartType series seriesGroup category title legend palette stacked valueAxis xTitle maxCategories outliers categorySort categoryF\
|
|
13323
12846
|
ormat showValues labelPosition symbology quietZone report params text toggle initiallyCollapsed collapsible expandLevels repeatColumns columnGap rowHeaderWidth anim animation visual comment notes description".split(" "));
|
|
12847
|
+
var NO_SERIES_CHARTS = /* @__PURE__ */ new Set(["gantt"]);
|
|
13324
12848
|
function looksLikeLink(it) {
|
|
13325
12849
|
if (it.type !== "textbox" || it.action && it.action.type && it.action.type !== "none") return false;
|
|
13326
12850
|
const st = it.style && typeof it.style === "object" ? it.style : {};
|
|
@@ -13449,6 +12973,9 @@ function validate(def) {
|
|
|
13449
12973
|
if (p?.hidden && p.required && (p.default == null || p.default === "") && !p.nullable) {
|
|
13450
12974
|
warnings.push(`Parameter "${p.name}" is hidden and required but has no default: only a URL, the API or a drill-through can set it`);
|
|
13451
12975
|
}
|
|
12976
|
+
if (p?.required && p.nullable && !p.multi && (p.default == null || p.default === "")) {
|
|
12977
|
+
warnings.push(`Parameter "${p.name}" is required and nullable with no default: when no value is given it is null and the report can draw blank; give it a default, or drop "nullable" to require a value`);
|
|
12978
|
+
}
|
|
13452
12979
|
if (p?.type === "date" && typeof p.default === "string" && p.default.trim() && !p.default.startsWith("=") && !toDate(p.default)) {
|
|
13453
12980
|
warnings.push(`Parameter "${p.name}": its default "${p.default}" is not a date; write it as 2026-12-31 (year-month-day)`);
|
|
13454
12981
|
}
|
|
@@ -13529,7 +13056,7 @@ function validate(def) {
|
|
|
13529
13056
|
warnings.push(`${label}: there is no named style "${it.styleName}"${g ? ` (did you mean "${g}"?)` : ""}; it is ignored`);
|
|
13530
13057
|
}
|
|
13531
13058
|
if (Array.isArray(it.sort)) sortIssues(it.sort, label, warnings);
|
|
13532
|
-
if (it.type === "chart" && Array.isArray(it.series) &&
|
|
13059
|
+
if (it.type === "chart" && !NO_SERIES_CHARTS.has(it.chartType) && !(Array.isArray(it.series) && it.series.length)) warnings.push(`${label}: the chart has no series, so it plots a count of its rows; add one, e.g. series: [{ "name": "Value", "value": "=Sum(Fields.Amount)" }]`);
|
|
13533
13060
|
if (it.type === "image" && typeof it.src === "string" && !it.src.startsWith("=") && LOCAL_IMAGE.test(it.src.trim())) warnings.push(`${label}: "${it.src}" is a local file path, which a browser cannot load; embed the image (images: { name: "data:image/png;base64,..." } and src: "embedded:name") or use an https:// address`);
|
|
13534
13061
|
if (it.style != null && (typeof it.style !== "object" || Array.isArray(it.style))) warnings.push(`${label}: "style" must be an object of style properties, such as { "fontWeight": "bold" }; ${JSON.stringify(it.style).slice(0, 40)} is ignored`);
|
|
13535
13062
|
const own = ownKeys(it.type);
|
|
@@ -13572,6 +13099,9 @@ function validate(def) {
|
|
|
13572
13099
|
const n = Array.isArray(it.columns) ? it.columns.length : 0;
|
|
13573
13100
|
const rowsOf = [["header", it.header], ["detail", it.detail], ["footer", it.footer], ...(it.groups || []).flatMap((g, gi) => [[`group ${gi + 1} header`, g?.header], [`group ${gi + 1} footer`, g?.footer]])];
|
|
13574
13101
|
for (const [part, rows] of rowsOf) (Array.isArray(rows) ? rows : []).forEach((row, ri) => {
|
|
13102
|
+
const cells = Array.isArray(row?.cells) ? row.cells : [];
|
|
13103
|
+
const placed = cells.length < n && cells.some((c) => Number(c?.colSpan) > 1) ? cells.reduce((s, c) => s + Math.max(1, Math.floor(Number(c?.colSpan)) || 1), 0) : cells.length;
|
|
13104
|
+
if (placed < n) warnings.push(`${label} ${part} row ${ri + 1}: the row has ${placed} of ${n} cells and no colSpan covers the other ${n - placed}; add the cells or a colSpan`);
|
|
13575
13105
|
for (const [k, j] of rowCells(row?.cells, n).covered) warnings.push(`${label} ${part} row ${ri + 1}: cell ${k} is covered by colSpan of cell ${j}, so it is not drawn (leave it null, or omit the spanned cells: a row with fewer cells than columns places each cell after the previous one's span)`);
|
|
13576
13106
|
});
|
|
13577
13107
|
}
|
|
@@ -13670,7 +13200,7 @@ function* textsOf(def, dataSets) {
|
|
|
13670
13200
|
}
|
|
13671
13201
|
}
|
|
13672
13202
|
}
|
|
13673
|
-
var NO_CJK_FONTS = "Text in Japanese/Chinese/Korean needs the optional CJK fonts: npm run fonts:cjk";
|
|
13203
|
+
var NO_CJK_FONTS = "Text in Japanese/Chinese/Korean needs the optional CJK fonts: npm i @reportwright/fonts-cjk, then npx reportwright-fonts-cjk (npm); in the app, npm run fonts:cjk";
|
|
13674
13204
|
async function render(def0, opts = {}) {
|
|
13675
13205
|
const t0 = Date.now();
|
|
13676
13206
|
const reuseWarnings = [];
|
|
@@ -13741,6 +13271,7 @@ async function render(def0, opts = {}) {
|
|
|
13741
13271
|
const base = { ...BASE_STYLE, ...def.styles?.base || {} };
|
|
13742
13272
|
let idSeq = 0;
|
|
13743
13273
|
const regions = [];
|
|
13274
|
+
const tablesSeen = { n: 0 };
|
|
13744
13275
|
const imageBudget = opts.imageBudget || { seen: /* @__PURE__ */ new Set(), bytes: 0 };
|
|
13745
13276
|
const makeLc = (globals, fixed) => {
|
|
13746
13277
|
const lc = {
|
|
@@ -13751,6 +13282,7 @@ async function render(def0, opts = {}) {
|
|
|
13751
13282
|
fixed,
|
|
13752
13283
|
maxUnitHeight: contentH,
|
|
13753
13284
|
state: opts.state || {},
|
|
13285
|
+
tablesSeen,
|
|
13754
13286
|
regions: opts.exportData || opts.dataOnly ? regions : null,
|
|
13755
13287
|
dataOnly: !!opts.dataOnly,
|
|
13756
13288
|
// exportData: true: table data and cell tags (Excel, CSV, Word, HTML, accessible PDF)
|
|
@@ -13770,14 +13302,16 @@ async function render(def0, opts = {}) {
|
|
|
13770
13302
|
ctxFor: (item) => {
|
|
13771
13303
|
const ds = item.dataSet || defaultDs;
|
|
13772
13304
|
const rows = ds && dataSets[ds] || [];
|
|
13773
|
-
return { ...baseCtx, globals, fields: rows[0] || null, aggRows: rows };
|
|
13305
|
+
return { ...baseCtx, globals, fields: (opts.pageWindow?.first && ds === defaultDs ? opts.pageWindow.first : rows[0]) || null, aggRows: rows };
|
|
13774
13306
|
},
|
|
13775
13307
|
subreports: null,
|
|
13776
13308
|
bodyWidth: opts.bodyWidth ?? page.bodyWidth,
|
|
13777
13309
|
images: def.images || {},
|
|
13778
13310
|
imageBudget,
|
|
13779
|
-
cellItems: { left: 1e5 }
|
|
13311
|
+
cellItems: { left: 1e5 },
|
|
13780
13312
|
// rows of items inside table cells, for the whole render (items/index.js)
|
|
13313
|
+
win: opts.pageWindow || null
|
|
13314
|
+
// paged.js: units carry their row number (dataRow, rowHead), rows and groups continue
|
|
13781
13315
|
};
|
|
13782
13316
|
return lc;
|
|
13783
13317
|
};
|
|
@@ -13916,12 +13450,14 @@ async function render(def0, opts = {}) {
|
|
|
13916
13450
|
const bodyTop = mt + g.hH;
|
|
13917
13451
|
const items = [];
|
|
13918
13452
|
const cut = lc.rowBudget?.cut;
|
|
13919
|
-
const
|
|
13453
|
+
const win = opts.pageWindow, off = win ? win.offset : 0, all = win ? win.total ?? "…" : null;
|
|
13454
|
+
const globals = { ...baseCtx.globals, PageNumber: n - secStart[n] + 1 + (secStart[n] ? 0 : off), TotalPages: cut ? "…" : all ?? secLen.get(secStart[n]), OverallPageNumber: n + 1 + off, OverallTotalPages: cut ? "…" : all ?? total };
|
|
13455
|
+
const isFirst = n + off === 0, isLast = n === total - 1 && (!win || win.final);
|
|
13920
13456
|
const plc = makeLc(globals, true);
|
|
13921
|
-
const band = (section, y0,
|
|
13457
|
+
const band = (section, y0, isFirst2, isLast2) => {
|
|
13922
13458
|
if (!section) return;
|
|
13923
|
-
if (
|
|
13924
|
-
if (
|
|
13459
|
+
if (isFirst2 && section.printOnFirstPage === false) return;
|
|
13460
|
+
if (isLast2 && section.printOnLastPage === false) return;
|
|
13925
13461
|
const capped2 = () => warn(`The page headers and footers would draw more than ${BAND_ITEMS.toLocaleString("en-US")} items in this report; they are left out of the later pages. Make them lighter, or the report shorter.`);
|
|
13926
13462
|
if (bandWork.left <= 0) {
|
|
13927
13463
|
capped2();
|
|
@@ -13942,7 +13478,7 @@ async function render(def0, opts = {}) {
|
|
|
13942
13478
|
for (const u of r.units) if (c.paged) placeItems(u.items, ml, y0 + u.top, items);
|
|
13943
13479
|
else for (const it of shiftItems(u.items, ml, y0 + u.top)) items.push(it);
|
|
13944
13480
|
};
|
|
13945
|
-
band(g.hdr, mt, g.own.h ? k === 0 :
|
|
13481
|
+
band(g.hdr, mt, g.own.h ? k === 0 : isFirst, g.own.h ? last : isLast);
|
|
13946
13482
|
const frozen = [];
|
|
13947
13483
|
for (let c = 0; c < colCount; c++) {
|
|
13948
13484
|
const p = slices[k * colCount + c];
|
|
@@ -13952,30 +13488,38 @@ async function render(def0, opts = {}) {
|
|
|
13952
13488
|
for (const t of body.tables) {
|
|
13953
13489
|
if (!(t.top < p.bottom - EPS4 && t.bottom > p.top + EPS4)) continue;
|
|
13954
13490
|
const cont = p.repeat.includes(t);
|
|
13955
|
-
let
|
|
13491
|
+
let off2 = 0;
|
|
13956
13492
|
if (!cont) {
|
|
13957
|
-
for (const r of p.repeat) if (t.x0 < r.x1 - EPS4 && r.x0 < t.x1 - EPS4)
|
|
13493
|
+
for (const r of p.repeat) if (t.x0 < r.x1 - EPS4 && r.x0 < t.x1 - EPS4) off2 = Math.max(off2, r.headerHeight);
|
|
13958
13494
|
}
|
|
13959
|
-
const y = cont ? bodyTop : bodyTop +
|
|
13960
|
-
frozen.push({ x: cx + t.x0, y, w: t.x1 - t.x0, h: t.headerHeight, end: bodyTop + (cont ? t.headerHeight :
|
|
13495
|
+
const y = cont ? bodyTop : bodyTop + off2 + t.top - p.top;
|
|
13496
|
+
frozen.push({ x: cx + t.x0, y, w: t.x1 - t.x0, h: t.headerHeight, end: bodyTop + (cont ? t.headerHeight : off2) + Math.min(t.bottom, p.bottom) - p.top });
|
|
13961
13497
|
}
|
|
13962
13498
|
for (const u of p.units) {
|
|
13963
|
-
let
|
|
13964
|
-
for (const t of p.repeat) if (u.x0 < t.x1 - EPS4 && t.x0 < u.x1 - EPS4)
|
|
13965
|
-
if (u.atBottom)
|
|
13966
|
-
if (u.cont && u.top <= p.top + EPS4) placeItems(u.cont, cx, bodyTop +
|
|
13967
|
-
placeItems(u.items, cx, bodyTop +
|
|
13499
|
+
let off2 = 0;
|
|
13500
|
+
for (const t of p.repeat) if (u.x0 < t.x1 - EPS4 && t.x0 < u.x1 - EPS4) off2 = Math.max(off2, t.headerHeight);
|
|
13501
|
+
if (u.atBottom) off2 += Math.max(0, cH - off2 - (p.bottom - p.top));
|
|
13502
|
+
if (u.cont && u.top <= p.top + EPS4) placeItems(u.cont, cx, bodyTop + off2, items);
|
|
13503
|
+
placeItems(u.items, cx, bodyTop + off2 + (u.top - p.top), items);
|
|
13968
13504
|
}
|
|
13969
13505
|
}
|
|
13970
|
-
band(g.ftr, ph - pg.margins.bottom - g.fH, g.own.f ? k === 0 :
|
|
13506
|
+
band(g.ftr, ph - pg.margins.bottom - g.fH, g.own.f ? k === 0 : isFirst, g.own.f ? last : isLast);
|
|
13971
13507
|
let j = 0;
|
|
13972
13508
|
for (let i = 0; i < items.length; i++) {
|
|
13973
13509
|
const it = items[i];
|
|
13974
|
-
if (it.t === "bookmark") (it.heading ? headings : bookmarks2).push({ label: it.label, page: n + 1, y: it.y, level: it.level || 0, ...secStart[n] ? { shown: n - secStart[n] + 1 } : {} });
|
|
13510
|
+
if (it.t === "bookmark") (it.heading ? headings : bookmarks2).push({ label: it.label, page: n + 1 + off, y: it.y, level: it.level || 0, ...secStart[n] ? { shown: n - secStart[n] + 1 } : {} });
|
|
13975
13511
|
else items[j++] = it;
|
|
13976
13512
|
}
|
|
13977
13513
|
items.length = j;
|
|
13978
13514
|
const out = frozen.length ? { items, frozen } : { items };
|
|
13515
|
+
if (win) {
|
|
13516
|
+
const u = slices[k * colCount]?.units[0];
|
|
13517
|
+
if (u?.dataRow != null) {
|
|
13518
|
+
out.firstRow = u.dataRow;
|
|
13519
|
+
out.rowHead = !!u.rowHead;
|
|
13520
|
+
if (u.headLevel != null) out.headLevel = u.headLevel;
|
|
13521
|
+
}
|
|
13522
|
+
}
|
|
13979
13523
|
if (pg.width !== first.width || ph !== pageH) {
|
|
13980
13524
|
out.width = pg.width;
|
|
13981
13525
|
out.height = ph;
|
|
@@ -14041,9 +13585,9 @@ async function render(def0, opts = {}) {
|
|
|
14041
13585
|
for (const k of store.failed) if (k !== SHAPER && !OPTIONAL_KEYS.includes(k)) warn(`The font "${k}" did not load, so its text is drawn in a bundled face instead.`);
|
|
14042
13586
|
if (m.unshaped) warn("The text shaper (harfbuzz.wasm) did not load, so Arabic, Hebrew, Indic and Thai text is not shaped (letters unjoined, marks misplaced). A font loader must map each key with fontFile(key).");
|
|
14043
13587
|
if (m.noGlyph.size) {
|
|
14044
|
-
const
|
|
13588
|
+
const cjk = [...m.noGlyph].some((c) => /[\u1100-\u11ff\u2600-\u27bf\u2b00-\u2bff\u3000-\u9fff\uac00-\ud7af\uf900-\ufaff\uff00-\uffef]|[\u{1f000}-\u{1faff}]/u.test(c));
|
|
14045
13589
|
const list = [...m.noGlyph].slice(0, 20).join(" ");
|
|
14046
|
-
warn(
|
|
13590
|
+
warn(cjk ? `${NO_CJK_FONTS}. Until then these characters show as boxes: ${list}.` : `No font has these characters, so they show as boxes: ${list}. Upload a font that has them and use it for this text.`);
|
|
14047
13591
|
}
|
|
14048
13592
|
if (opts.bodyOnly) return { units: result.body.units, tables: result.body.tables, height: result.body.height, regions, warnings, clipped: clipped() };
|
|
14049
13593
|
if (opts.dataOnly) return {
|
|
@@ -14083,6 +13627,7 @@ async function render(def0, opts = {}) {
|
|
|
14083
13627
|
headings: result.headings || [],
|
|
14084
13628
|
pageStarts: result.pageStarts || [],
|
|
14085
13629
|
regions: opts.exportData ? regions : null,
|
|
13630
|
+
hasTables: tablesSeen.n > 0,
|
|
14086
13631
|
name: def.name || "",
|
|
14087
13632
|
partial: cutRows(),
|
|
14088
13633
|
timeZone: timeZone || null,
|
|
@@ -14219,7 +13764,8 @@ async function parameterOptions(def, given = {}, opts = {}) {
|
|
|
14219
13764
|
seen.add(k);
|
|
14220
13765
|
list.push({ value: v instanceof Date ? isoDate(v) : v, label: String(p.optionsFrom.label ? evalValue(p.optionsFrom.label, c) : v) });
|
|
14221
13766
|
}
|
|
14222
|
-
out[p.name] =
|
|
13767
|
+
const fixed = out[p.name] || [], have = new Set(fixed.map((o) => o.value));
|
|
13768
|
+
out[p.name] = [...fixed, ...list.filter((o) => !have.has(o.value))];
|
|
14223
13769
|
}
|
|
14224
13770
|
return out;
|
|
14225
13771
|
}
|
|
@@ -14267,440 +13813,16 @@ function resolveParameters(def, given, o = {}) {
|
|
|
14267
13813
|
return out;
|
|
14268
13814
|
}
|
|
14269
13815
|
|
|
14270
|
-
// src/exporters/subset.js
|
|
14271
|
-
var HB_MEMORY_MODE_WRITABLE = 2;
|
|
14272
|
-
var HB_SUBSET_SETS_DROP_TABLE_TAG = 3;
|
|
14273
|
-
var HB_SUBSET_SETS_LAYOUT_FEATURE_TAG = 6;
|
|
14274
|
-
var HB_SUBSET_FLAGS_RETAIN_GIDS = 2;
|
|
14275
|
-
var HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 64;
|
|
14276
|
-
var tag3 = (s) => [...s].reduce((a, c) => (a << 8) + c.charCodeAt(0), 0) >>> 0;
|
|
14277
|
-
function createSubsetter(loadWasm) {
|
|
14278
|
-
let hbP = null;
|
|
14279
|
-
const hb = () => hbP || (hbP = (async () => {
|
|
14280
|
-
const bytes = await loadWasm();
|
|
14281
|
-
const { instance } = await WebAssembly.instantiate(bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes), {});
|
|
14282
|
-
const x = (
|
|
14283
|
-
/** @type {any} */
|
|
14284
|
-
instance.exports
|
|
14285
|
-
);
|
|
14286
|
-
x._initialize?.();
|
|
14287
|
-
return x;
|
|
14288
|
-
})());
|
|
14289
|
-
return async function subset(font, codePoints, opt = {}) {
|
|
14290
|
-
const x = await hb();
|
|
14291
|
-
const heap = () => new Uint8Array(x.memory.buffer);
|
|
14292
|
-
const input = x.hb_subset_input_create_or_fail();
|
|
14293
|
-
if (!input) throw new Error("HarfBuzz: no subset input");
|
|
14294
|
-
const buf = x.malloc(font.byteLength);
|
|
14295
|
-
heap().set(font, buf);
|
|
14296
|
-
const blob = x.hb_blob_create(buf, font.byteLength, HB_MEMORY_MODE_WRITABLE, 0, 0);
|
|
14297
|
-
const face = x.hb_face_create(blob, 0);
|
|
14298
|
-
x.hb_blob_destroy(blob);
|
|
14299
|
-
try {
|
|
14300
|
-
if (!opt.layout) {
|
|
14301
|
-
x.hb_set_clear(x.hb_subset_input_set(input, HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
|
|
14302
|
-
const drop = x.hb_subset_input_set(input, HB_SUBSET_SETS_DROP_TABLE_TAG);
|
|
14303
|
-
for (const t of ["GSUB", "GPOS", "GDEF", "kern", "morx", "mort"]) x.hb_set_add(drop, tag3(t));
|
|
14304
|
-
}
|
|
14305
|
-
x.hb_subset_input_set_flags(input, x.hb_subset_input_get_flags(input) | HB_SUBSET_FLAGS_NOTDEF_OUTLINE);
|
|
14306
|
-
const uni = x.hb_subset_input_unicode_set(input);
|
|
14307
|
-
for (const cp of codePoints) x.hb_set_add(uni, cp);
|
|
14308
|
-
if (opt.glyphs) {
|
|
14309
|
-
x.hb_subset_input_set_flags(input, x.hb_subset_input_get_flags(input) | HB_SUBSET_FLAGS_RETAIN_GIDS);
|
|
14310
|
-
const gs = x.hb_subset_input_glyph_set(input);
|
|
14311
|
-
for (const g of opt.glyphs) x.hb_set_add(gs, g);
|
|
14312
|
-
}
|
|
14313
|
-
x.hb_subset_input_pin_all_axes_to_default(input, face);
|
|
14314
|
-
const sub = x.hb_subset_or_fail(face, input);
|
|
14315
|
-
if (!sub) throw new Error("HarfBuzz: subsetting failed");
|
|
14316
|
-
const res = x.hb_face_reference_blob(sub);
|
|
14317
|
-
const off = x.hb_blob_get_data(res, 0);
|
|
14318
|
-
const len = x.hb_blob_get_length(res);
|
|
14319
|
-
const out = heap().slice(off, off + len);
|
|
14320
|
-
x.hb_blob_destroy(res);
|
|
14321
|
-
x.hb_face_destroy(sub);
|
|
14322
|
-
if (!len) throw new Error("HarfBuzz: empty subset");
|
|
14323
|
-
return out;
|
|
14324
|
-
} finally {
|
|
14325
|
-
x.hb_subset_input_destroy(input);
|
|
14326
|
-
x.hb_face_destroy(face);
|
|
14327
|
-
x.free(buf);
|
|
14328
|
-
}
|
|
14329
|
-
};
|
|
14330
|
-
}
|
|
14331
|
-
|
|
14332
|
-
// src/viewer/engineClient.js
|
|
14333
|
-
var assetBase = "";
|
|
14334
|
-
function setAssetBase(url) {
|
|
14335
|
-
assetBase = String(url || "").replace(/\/$/, "");
|
|
14336
|
-
mainStore = null;
|
|
14337
|
-
}
|
|
14338
|
-
var origin = () => assetBase || window.location.origin;
|
|
14339
|
-
var fontsUrl = null;
|
|
14340
|
-
var standalone = false;
|
|
14341
|
-
function setStandalone({ standalone: on = false, fontsUrl: f4 = null } = {}) {
|
|
14342
|
-
standalone = !!on;
|
|
14343
|
-
fontsUrl = f4 ? String(f4).replace(/\/?$/, "/") : null;
|
|
14344
|
-
mainStore = null;
|
|
14345
|
-
fontList = null;
|
|
14346
|
-
fontBytes.clear();
|
|
14347
|
-
}
|
|
14348
|
-
var fontsBase = () => fontsUrl || `${assetBase}/fonts/`;
|
|
14349
|
-
var besideFonts = (file) => fontsUrl ? new URL(`../${file}`, new URL(fontsUrl, typeof location !== "undefined" ? location.href : void 0)).href : `${assetBase}/${file}`;
|
|
14350
|
-
var subsetter = createSubsetter(async () => (await fetch(besideFonts("harfbuzz-subset.wasm"))).arrayBuffer());
|
|
14351
|
-
var worker = null;
|
|
14352
|
-
var workerBroken = false;
|
|
14353
|
-
var seq = 0;
|
|
14354
|
-
var waiting = /* @__PURE__ */ new Map();
|
|
14355
|
-
var mainStore = null;
|
|
14356
|
-
var bundledFonts = null;
|
|
14357
|
-
var bundledList = null;
|
|
14358
|
-
function setBundledFonts(map, list) {
|
|
14359
|
-
bundledFonts = map || null;
|
|
14360
|
-
bundledList = list || null;
|
|
14361
|
-
mainStore = null;
|
|
14362
|
-
fontList = null;
|
|
14363
|
-
}
|
|
14364
|
-
var b64ToBuffer = (b64) => {
|
|
14365
|
-
const s = atob(b64);
|
|
14366
|
-
const u = new Uint8Array(s.length);
|
|
14367
|
-
for (let i = 0; i < s.length; i++) u[i] = s.charCodeAt(i);
|
|
14368
|
-
return u.buffer;
|
|
14369
|
-
};
|
|
14370
|
-
var fontBytes = /* @__PURE__ */ new Map();
|
|
14371
|
-
var fetchFont = (k) => {
|
|
14372
|
-
if (!fontBytes.has(k)) {
|
|
14373
|
-
const p = (async () => {
|
|
14374
|
-
const r = await fetch(`${fontsBase()}${fontFile(k)}`);
|
|
14375
|
-
if (!r.ok) throw new Error(`Font "${k}" did not load (HTTP ${r.status})`);
|
|
14376
|
-
return r.arrayBuffer();
|
|
14377
|
-
})();
|
|
14378
|
-
p.catch(() => fontBytes.delete(k));
|
|
14379
|
-
fontBytes.set(k, p);
|
|
14380
|
-
}
|
|
14381
|
-
return fontBytes.get(k);
|
|
14382
|
-
};
|
|
14383
|
-
var getFont = async (k) => {
|
|
14384
|
-
if (bundledFonts?.[k]) return b64ToBuffer(bundledFonts[k]);
|
|
14385
|
-
return (await fetchFont(k)).slice(0);
|
|
14386
|
-
};
|
|
14387
|
-
function fontStore() {
|
|
14388
|
-
if (!mainStore) mainStore = new FontStore(getFont);
|
|
14389
|
-
return mainStore;
|
|
14390
|
-
}
|
|
14391
|
-
var makeWorker = true ? null : () => new Worker(new URL("../worker/engine.worker.js", import.meta.url), { type: "module" });
|
|
14392
|
-
var fontList = null;
|
|
14393
|
-
function customFonts(refresh = false) {
|
|
14394
|
-
if (!fontList || refresh) {
|
|
14395
|
-
fontList = (bundledList ? Promise.resolve(bundledList) : standalone ? Promise.resolve([]) : fetch(`${assetBase}/api/fonts`).then((r) => r.ok ? r.json() : []).catch(() => [])).then((list) => {
|
|
14396
|
-
setCustomFonts(list);
|
|
14397
|
-
return list;
|
|
14398
|
-
});
|
|
14399
|
-
}
|
|
14400
|
-
return fontList;
|
|
14401
|
-
}
|
|
14402
|
-
var faces = /* @__PURE__ */ new Map();
|
|
14403
|
-
function loadReportFonts(keys) {
|
|
14404
|
-
if (typeof document === "undefined" || !document.fonts || typeof FontFace === "undefined") return Promise.resolve([]);
|
|
14405
|
-
return Promise.all(keys.filter((k) => k !== SHAPER).map((k) => {
|
|
14406
|
-
if (!faces.has(k)) {
|
|
14407
|
-
const bytes = bundledFonts?.[k] ? Promise.resolve(b64ToBuffer(bundledFonts[k])) : fetchFont(k).then((b) => b.slice(0));
|
|
14408
|
-
faces.set(k, bytes.then((src) => {
|
|
14409
|
-
const face = new FontFace(fontFamilyCss(k), src, { display: "block" });
|
|
14410
|
-
document.fonts.add(face);
|
|
14411
|
-
return face.load();
|
|
14412
|
-
}).then(() => null, (error) => {
|
|
14413
|
-
faces.delete(k);
|
|
14414
|
-
return { key: k, error };
|
|
14415
|
-
}));
|
|
14416
|
-
}
|
|
14417
|
-
return faces.get(k);
|
|
14418
|
-
})).then((results) => results.filter(Boolean));
|
|
14419
|
-
}
|
|
14420
|
-
var loadModelFonts = (model) => loadReportFonts([.../* @__PURE__ */ new Set([...ALL_FONT_KEYS, ...fontKeysOf(model)])]);
|
|
14421
|
-
function getWorker() {
|
|
14422
|
-
if (!makeWorker || workerBroken || typeof Worker === "undefined" || assetBase || bundledFonts) return null;
|
|
14423
|
-
if (worker) return worker;
|
|
14424
|
-
try {
|
|
14425
|
-
worker = makeWorker();
|
|
14426
|
-
worker.onmessage = (e) => {
|
|
14427
|
-
const w = waiting.get(e.data.id);
|
|
14428
|
-
if (!w) return;
|
|
14429
|
-
if (e.data.partial) {
|
|
14430
|
-
w.onPartial?.(e.data.model);
|
|
14431
|
-
return;
|
|
14432
|
-
}
|
|
14433
|
-
if (e.data.retry) {
|
|
14434
|
-
w.onRetry?.(e.data.retry);
|
|
14435
|
-
return;
|
|
14436
|
-
}
|
|
14437
|
-
waiting.delete(e.data.id);
|
|
14438
|
-
if (e.data.ok) w.resolve(e.data.model);
|
|
14439
|
-
else w.reject(Object.assign(new Error(e.data.error.message), e.data.error));
|
|
14440
|
-
};
|
|
14441
|
-
worker.onerror = () => {
|
|
14442
|
-
workerBroken = true;
|
|
14443
|
-
worker = null;
|
|
14444
|
-
for (const [, w] of waiting) w.retry();
|
|
14445
|
-
waiting.clear();
|
|
14446
|
-
};
|
|
14447
|
-
} catch {
|
|
14448
|
-
workerBroken = true;
|
|
14449
|
-
worker = null;
|
|
14450
|
-
}
|
|
14451
|
-
return worker;
|
|
14452
|
-
}
|
|
14453
|
-
var bundled = /* @__PURE__ */ new Map();
|
|
14454
|
-
function registerReports(map) {
|
|
14455
|
-
for (const [k, v] of Object.entries(map || {})) bundled.set(k, v);
|
|
14456
|
-
}
|
|
14457
|
-
var loadReport = async (rid) => {
|
|
14458
|
-
if (bundled.has(rid)) return structuredClone(bundled.get(rid));
|
|
14459
|
-
if (standalone) throw new Error(`Report "${rid}" is not loaded: pass it in reports: { "${rid}": definition }, or set server (a self-hosted ReportWright server)`);
|
|
14460
|
-
const r = await fetch(`${assetBase}/api/reports/${encodeURIComponent(rid)}`);
|
|
14461
|
-
if (!r.ok) throw new Error(`Report "${rid}" not found`);
|
|
14462
|
-
return r.json();
|
|
14463
|
-
};
|
|
14464
|
-
var fetchReport = loadReport;
|
|
14465
|
-
async function renderMain(def, params, state, reportId, exportData = false, onRetry = void 0, dataOnly = false) {
|
|
14466
|
-
await customFonts();
|
|
14467
|
-
return render(def, { parameters: params, state, reportId, exportData, dataOnly, fontStore: fontStore(), baseUrl: origin(), loadReport, fetch: reportFetch(origin(), void 0, { onRetry }) });
|
|
14468
|
-
}
|
|
14469
|
-
async function renderReport(def, params = {}, state = {}, reportId = void 0, { onPartial, exportData = false, onRetry, dataOnly = false } = {}) {
|
|
14470
|
-
const w = getWorker();
|
|
14471
|
-
if (!w) return renderMain(def, params, state, reportId, exportData, onRetry, dataOnly);
|
|
14472
|
-
const fonts = await customFonts();
|
|
14473
|
-
return new Promise((resolve, reject) => {
|
|
14474
|
-
const id = ++seq;
|
|
14475
|
-
waiting.set(id, { resolve, reject, onPartial, onRetry, retry: () => renderMain(def, params, state, reportId, exportData, onRetry, dataOnly).then(resolve, reject) });
|
|
14476
|
-
w.postMessage({ id, def, params, state, reportId, fonts, firstPages: onPartial && !dataOnly ? 2 : 0, exportData, dataOnly });
|
|
14477
|
-
});
|
|
14478
|
-
}
|
|
14479
|
-
var usingWorker = () => !!worker && !workerBroken;
|
|
14480
|
-
async function iccProfile() {
|
|
14481
|
-
const r = await fetch(fontsUrl ? besideFonts("icc/sRGB-v2-magic.icc") : `${origin()}/icc/sRGB-v2-magic.icc`);
|
|
14482
|
-
if (!r.ok) throw new Error(`the PDF/A colour profile did not load (HTTP ${r.status})`);
|
|
14483
|
-
return new Uint8Array(await r.arrayBuffer());
|
|
14484
|
-
}
|
|
14485
|
-
async function pdfBlob(model, title, o = {}) {
|
|
14486
|
-
const store = fontStore();
|
|
14487
|
-
await customFonts();
|
|
14488
|
-
await store.load(fontKeysOf(model));
|
|
14489
|
-
const { exportPdf } = await import("./chunk-66QZ3RDV.js");
|
|
14490
|
-
const bytes = await exportPdf(model, store, {
|
|
14491
|
-
title,
|
|
14492
|
-
subset: subsetter,
|
|
14493
|
-
tagged: o.tagged,
|
|
14494
|
-
drillBase: origin(),
|
|
14495
|
-
// drill-through links open this viewer, as in the HTML export
|
|
14496
|
-
pdfa: o.pdfa ? { icc: await iccProfile() } : void 0,
|
|
14497
|
-
// a report's image: a GET under the same rules as its data (no cookies to our other routes or to other sites)
|
|
14498
|
-
fetchImage: async (src) => {
|
|
14499
|
-
try {
|
|
14500
|
-
const r = await reportFetch(origin())(src);
|
|
14501
|
-
return r.ok ? new Uint8Array(await r.arrayBuffer()) : null;
|
|
14502
|
-
} catch {
|
|
14503
|
-
return null;
|
|
14504
|
-
}
|
|
14505
|
-
}
|
|
14506
|
-
});
|
|
14507
|
-
return new Blob([bytes], { type: "application/pdf" });
|
|
14508
|
-
}
|
|
14509
|
-
|
|
14510
|
-
// src/viewer/logic.js
|
|
14511
|
-
var TOOLBAR_GROUP_KEYS = {
|
|
14512
|
-
export: (i) => i.group === "export" && i.id !== "print",
|
|
14513
|
-
search: (i) => i.group === "search",
|
|
14514
|
-
zoom: (i) => i.group === "zoom",
|
|
14515
|
-
navigation: (i) => i.group === "paging"
|
|
14516
|
-
};
|
|
14517
|
-
var TOOLBAR_ID_KEYS = { sidebar: ["thumbnails", "documentMap"] };
|
|
14518
|
-
function arrangeToolbar(builtIns, { hide = [], add: add2 = [] } = {}) {
|
|
14519
|
-
if (!hide.length && !add2.length) return builtIns;
|
|
14520
|
-
const out = [...builtIns];
|
|
14521
|
-
const taken = new Set(builtIns.map((i) => i.id));
|
|
14522
|
-
for (const a of add2) {
|
|
14523
|
-
if (!a || !a.id || taken.has(a.id)) continue;
|
|
14524
|
-
taken.add(a.id);
|
|
14525
|
-
const at = out.findIndex((i) => i.id === a.after);
|
|
14526
|
-
const item = { ...a, custom: true, group: at >= 0 ? out[at].group : `custom:${a.id}` };
|
|
14527
|
-
if (at >= 0) out.splice(at + 1, 0, item);
|
|
14528
|
-
else out.push(item);
|
|
14529
|
-
}
|
|
14530
|
-
const hiddenIds = /* @__PURE__ */ new Set();
|
|
14531
|
-
const hiddenBy = [];
|
|
14532
|
-
for (const k of hide) {
|
|
14533
|
-
if (Object.hasOwn(TOOLBAR_GROUP_KEYS, k)) hiddenBy.push(TOOLBAR_GROUP_KEYS[k]);
|
|
14534
|
-
else for (const id of Object.hasOwn(TOOLBAR_ID_KEYS, k) ? TOOLBAR_ID_KEYS[k] : [k]) hiddenIds.add(id);
|
|
14535
|
-
}
|
|
14536
|
-
let kept = out.filter((i) => i.custom || !(hiddenIds.has(i.id) || hiddenBy.some((f4) => f4(i))));
|
|
14537
|
-
if (!kept.some((i) => i.format)) kept = kept.filter((i) => i.custom || i.id !== "exportOptions");
|
|
14538
|
-
return kept;
|
|
14539
|
-
}
|
|
14540
|
-
function galleyDefinition(def) {
|
|
14541
|
-
const pg = resolvePage(def.page);
|
|
14542
|
-
if (pg.pageless) return def;
|
|
14543
|
-
const m = pg.margins;
|
|
14544
|
-
return { ...def, page: { size: "Pageless", width: pg.width, margins: [m.top, m.right, m.bottom, m.left] } };
|
|
14545
|
-
}
|
|
14546
|
-
function frozenAt(page, y) {
|
|
14547
|
-
for (const r of page?.frozen || []) if (y > r.y && y < r.end - r.h) return r;
|
|
14548
|
-
return null;
|
|
14549
|
-
}
|
|
14550
|
-
var escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14551
|
-
function findText(model, q, { matchCase = false, wholeWord = false } = {}) {
|
|
14552
|
-
if (!q || !model) return [];
|
|
14553
|
-
const W2 = "[\\p{L}\\p{M}\\p{N}_]";
|
|
14554
|
-
const re = new RegExp(wholeWord ? `(?<!${W2})${escapeRe(q)}(?!${W2})` : escapeRe(q), `u${matchCase ? "" : "i"}`);
|
|
14555
|
-
const out = [];
|
|
14556
|
-
model.pages.forEach((pg, pi) => {
|
|
14557
|
-
const rows = /* @__PURE__ */ new Map();
|
|
14558
|
-
pg.items.forEach((it, k) => {
|
|
14559
|
-
if (it.t !== "text") return;
|
|
14560
|
-
for (const l of it.lines) {
|
|
14561
|
-
const key = it.rich ? `r${it.rich.id}${it.rich.l}` : `${k}${l.y}`;
|
|
14562
|
-
const r = rows.get(key);
|
|
14563
|
-
if (r) r.lines.push(l);
|
|
14564
|
-
else rows.set(key, { rich: !!it.rich, size: it.size, lines: [l] });
|
|
14565
|
-
}
|
|
14566
|
-
});
|
|
14567
|
-
for (const { rich, size, lines: row } of rows.values()) {
|
|
14568
|
-
row.sort((a, b) => a.x - b.x);
|
|
14569
|
-
const text = row.map((l) => l.text).join(rich ? "" : " ");
|
|
14570
|
-
if (!re.test(text)) continue;
|
|
14571
|
-
const x0 = row[0].x, last = row[row.length - 1];
|
|
14572
|
-
const x1 = last.x + (last.w || size * last.text.length * 0.5);
|
|
14573
|
-
const y = Math.max(...row.map((l) => l.y));
|
|
14574
|
-
out.push({ page: pi, x: x0 - 1, y: y - size * 0.95, w: x1 - x0 + 2, h: size * 1.25, text });
|
|
14575
|
-
}
|
|
14576
|
-
});
|
|
14577
|
-
return out;
|
|
14578
|
-
}
|
|
14579
|
-
function rangeValue(a, b, p) {
|
|
14580
|
-
if (a === "" && b === "") return "";
|
|
14581
|
-
const lo = a !== "" ? a : String(p.min ?? b);
|
|
14582
|
-
const hi = b !== "" ? b : String(p.max ?? a);
|
|
14583
|
-
return `${lo},${hi}`;
|
|
14584
|
-
}
|
|
14585
|
-
function pathBox(d) {
|
|
14586
|
-
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity, cx = 0, cy = 0;
|
|
14587
|
-
const add2 = (x, y) => {
|
|
14588
|
-
cx = x;
|
|
14589
|
-
cy = y;
|
|
14590
|
-
if (x < x0) x0 = x;
|
|
14591
|
-
if (x > x1) x1 = x;
|
|
14592
|
-
if (y < y0) y0 = y;
|
|
14593
|
-
if (y > y1) y1 = y;
|
|
14594
|
-
};
|
|
14595
|
-
for (const [, c, args] of String(d || "").matchAll(/([MLHVCSQTAZ])([^MLHVCSQTAZ]*)/gi)) {
|
|
14596
|
-
const n = (args.match(/-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?/gi) || []).map(Number);
|
|
14597
|
-
const C = c.toUpperCase();
|
|
14598
|
-
if (C === "H") n.forEach((x) => add2(x, cy));
|
|
14599
|
-
else if (C === "V") n.forEach((y) => add2(cx, y));
|
|
14600
|
-
else if (C === "A") for (let i = 0; i + 6 < n.length; i += 7) add2(n[i + 5], n[i + 6]);
|
|
14601
|
-
else if (C !== "Z") for (let i = 0; i + 1 < n.length; i += 2) add2(n[i], n[i + 1]);
|
|
14602
|
-
}
|
|
14603
|
-
return x0 <= x1 ? { x: x0, y: y0, w: x1 - x0, h: y1 - y0 } : null;
|
|
14604
|
-
}
|
|
14605
|
-
var itemsOf = (page) => (page?.items || []).flatMap((i) => i.t === "field" ? i.draw || [] : [i]);
|
|
14606
|
-
function pageLinks(page) {
|
|
14607
|
-
const items = itemsOf(page);
|
|
14608
|
-
const texts = items.filter((i) => i.t === "text");
|
|
14609
|
-
const out = [];
|
|
14610
|
-
for (const it of items) {
|
|
14611
|
-
if (it.t !== "link" || !it.action) continue;
|
|
14612
|
-
let box = { x: it.x, y: it.y, w: it.w, h: it.h };
|
|
14613
|
-
if (it.d) {
|
|
14614
|
-
const b = pathBox(it.d);
|
|
14615
|
-
if (!b) continue;
|
|
14616
|
-
box = { ...b, x: b.x + (it.x - (it.x0 ?? it.x)), y: b.y + (it.y - (it.y0 ?? it.y)) };
|
|
14617
|
-
}
|
|
14618
|
-
if (!(box.w > 0 && box.h > 0)) continue;
|
|
14619
|
-
const words = [];
|
|
14620
|
-
for (const t of texts) for (const l of t.lines || []) {
|
|
14621
|
-
const top = l.y - (t.size || 9) * 0.9, w = l.w || (t.size || 9) * String(l.text).length * 0.5;
|
|
14622
|
-
if (l.x < box.x + box.w && l.x + w > box.x && top < box.y + box.h && l.y > box.y) words.push(String(l.text));
|
|
14623
|
-
}
|
|
14624
|
-
out.push({ action: it.action, ...box, path: !!it.d, tip: it.tip ? String(it.tip) : "", text: words.join(" ").replace(/^[▶▼]\s*/, "").replace(/\s*[↑↓]$/, "").trim() });
|
|
14625
|
-
}
|
|
14626
|
-
return out.sort((a, b) => Math.abs(a.y - b.y) > 2 ? a.y - b.y : a.x - b.x);
|
|
14627
|
-
}
|
|
14628
|
-
function readingText(page) {
|
|
14629
|
-
const rows = /* @__PURE__ */ new Map();
|
|
14630
|
-
for (const it of itemsOf(page)) {
|
|
14631
|
-
if (it.t !== "text") continue;
|
|
14632
|
-
for (const l of it.lines || []) {
|
|
14633
|
-
const k = Math.round(l.y);
|
|
14634
|
-
const r = rows.get(k);
|
|
14635
|
-
if (r) r.push(l);
|
|
14636
|
-
else rows.set(k, [l]);
|
|
14637
|
-
}
|
|
14638
|
-
}
|
|
14639
|
-
return [...rows.entries()].sort((a, b) => a[0] - b[0]).map(([, ls]) => ls.sort((a, b) => a.x - b.x).map((l) => l.text).join(" ").trim()).filter(Boolean);
|
|
14640
|
-
}
|
|
14641
|
-
var EXPORT_DEFAULTS = { pdfua: false, pdfa: false, formulas: true, html: "tables" };
|
|
14642
|
-
function exportOptionsFrom(stored) {
|
|
14643
|
-
const { v, ...rest } = stored && typeof stored === "object" ? stored : {};
|
|
14644
|
-
if (v !== 2) delete rest.html;
|
|
14645
|
-
return { ...EXPORT_DEFAULTS, ...rest };
|
|
14646
|
-
}
|
|
14647
|
-
function pruneSnapshot(snapshot, defs) {
|
|
14648
|
-
const text = defs.map((d) => JSON.stringify(d)).join("\n");
|
|
14649
|
-
const seen = /* @__PURE__ */ new Map();
|
|
14650
|
-
const used = (k) => {
|
|
14651
|
-
let u = seen.get(k);
|
|
14652
|
-
if (u === void 0) {
|
|
14653
|
-
u = text.includes(JSON.stringify(k).slice(1, -1));
|
|
14654
|
-
seen.set(k, u);
|
|
14655
|
-
}
|
|
14656
|
-
return u;
|
|
14657
|
-
};
|
|
14658
|
-
const walk = (x) => {
|
|
14659
|
-
if (Array.isArray(x)) return x.map(walk);
|
|
14660
|
-
if (!x || typeof x !== "object") return x;
|
|
14661
|
-
const o = {};
|
|
14662
|
-
for (const [k, y] of Object.entries(x)) if (y && typeof y === "object" || used(k)) o[k] = walk(y);
|
|
14663
|
-
return o;
|
|
14664
|
-
};
|
|
14665
|
-
return Object.fromEntries(Object.entries(snapshot).map(([url, x]) => [url, walk(x)]));
|
|
14666
|
-
}
|
|
14667
|
-
var SERVER_PDF_ROWS = 2e4;
|
|
14668
|
-
var SERVER_PDF_PAGES = 800;
|
|
14669
|
-
function serverPdfUrl(model, { reportId, params = {}, origin: origin2, timeZone, dirty = false }) {
|
|
14670
|
-
if (!reportId || dirty || !model) return null;
|
|
14671
|
-
const rows = Object.values(model.stats?.rows || {}).reduce((a, n) => a + (Number(n) || 0), 0);
|
|
14672
|
-
if (rows <= SERVER_PDF_ROWS && (model.pages?.length || 0) <= SERVER_PDF_PAGES) return null;
|
|
14673
|
-
const q = new URLSearchParams();
|
|
14674
|
-
for (const [k, v0] of Object.entries(params)) {
|
|
14675
|
-
const v = Array.isArray(v0) ? v0.length > 1 ? void 0 : v0[0] : v0;
|
|
14676
|
-
if (v === void 0 && Array.isArray(v0)) return null;
|
|
14677
|
-
if (v == null) continue;
|
|
14678
|
-
q.set(k, v instanceof Date ? v.toISOString() : String(v));
|
|
14679
|
-
}
|
|
14680
|
-
if (timeZone) q.set("timeZone", timeZone);
|
|
14681
|
-
const s = q.toString();
|
|
14682
|
-
return `${origin2}/api/reports/${encodeURIComponent(reportId)}/pdf${s ? `?${s}` : ""}`;
|
|
14683
|
-
}
|
|
14684
|
-
function paramChoices(def, fetched) {
|
|
14685
|
-
const out = { ...fetched };
|
|
14686
|
-
for (const p of def?.parameters || []) {
|
|
14687
|
-
if (!Array.isArray(p.options) || !p.optionsFrom || !Array.isArray(fetched?.[p.name])) continue;
|
|
14688
|
-
const fixed = p.options.map((o) => typeof o === "object" && o ? { value: o.value, label: String(o.label ?? o.value) } : { value: o, label: String(o) });
|
|
14689
|
-
const seen = new Set(fixed.map((o) => String(o.value)));
|
|
14690
|
-
out[p.name] = [...fixed, ...fetched[p.name].filter((o) => !seen.has(String(o.value)))];
|
|
14691
|
-
}
|
|
14692
|
-
return out;
|
|
14693
|
-
}
|
|
14694
|
-
|
|
14695
13816
|
export {
|
|
13817
|
+
setFetchPolicy,
|
|
13818
|
+
policyKeysIn,
|
|
13819
|
+
fetchPolicy,
|
|
14696
13820
|
reportFetch,
|
|
14697
13821
|
PAGE_SIZES,
|
|
14698
13822
|
toPt,
|
|
14699
13823
|
fromPt,
|
|
14700
13824
|
resolvePage,
|
|
14701
13825
|
normBox,
|
|
14702
|
-
TextMeasurer,
|
|
14703
|
-
finishText,
|
|
14704
13826
|
isDynamic,
|
|
14705
13827
|
evalValue,
|
|
14706
13828
|
toText,
|
|
@@ -14745,33 +13867,6 @@ export {
|
|
|
14745
13867
|
NO_CJK_FONTS,
|
|
14746
13868
|
render,
|
|
14747
13869
|
parameterOptions,
|
|
14748
|
-
resolveParameters
|
|
14749
|
-
setAssetBase,
|
|
14750
|
-
origin,
|
|
14751
|
-
setStandalone,
|
|
14752
|
-
fontsBase,
|
|
14753
|
-
subsetter,
|
|
14754
|
-
setBundledFonts,
|
|
14755
|
-
fontStore,
|
|
14756
|
-
customFonts,
|
|
14757
|
-
loadReportFonts,
|
|
14758
|
-
loadModelFonts,
|
|
14759
|
-
registerReports,
|
|
14760
|
-
fetchReport,
|
|
14761
|
-
renderReport,
|
|
14762
|
-
usingWorker,
|
|
14763
|
-
pdfBlob,
|
|
14764
|
-
arrangeToolbar,
|
|
14765
|
-
galleyDefinition,
|
|
14766
|
-
frozenAt,
|
|
14767
|
-
findText,
|
|
14768
|
-
rangeValue,
|
|
14769
|
-
pageLinks,
|
|
14770
|
-
readingText,
|
|
14771
|
-
EXPORT_DEFAULTS,
|
|
14772
|
-
exportOptionsFrom,
|
|
14773
|
-
pruneSnapshot,
|
|
14774
|
-
serverPdfUrl,
|
|
14775
|
-
paramChoices
|
|
13870
|
+
resolveParameters
|
|
14776
13871
|
};
|
|
14777
|
-
//# sourceMappingURL=chunk-
|
|
13872
|
+
//# sourceMappingURL=chunk-VNOWPSE6.js.map
|