@reportwright/engine 0.12.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/dist/index.js CHANGED
@@ -395,6 +395,7 @@ function special(cp) {
395
395
  if (cp >= 8192 && cp <= 8303) return cp >= 8203 && cp <= 8207 || cp >= 8234 && cp <= 8238 || cp >= 8288;
396
396
  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;
397
397
  }
398
+ var FORMAT_CHAR = /^\p{Cf}$/u;
398
399
  var cjk = (cp) => cp >= 11904 && cp <= 40959 || cp >= 44032 && cp <= 55215 || cp >= 63744 && cp <= 64255 || cp >= 65280 && cp <= 65519 || cp >= 131072 && cp <= 262143;
399
400
  var NO_START = new Set("、。,.・:;?!ー)」』】〕〉》〗〙〟’”}⦆ぁぃぅぇぉっゃゅょゎゕゖァィゥェォッャュョヮヵヶ々〻‐゠–〜~…‥,.!?:;)]}%ゝゞヽヾ゛゜ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ。」、・ー%]⦆");
400
401
  var NO_END = new Set("(「『【〔〈《〖〘〝‘“{⦅([{[「$¥£");
@@ -790,7 +791,7 @@ var TextMeasurer = class {
790
791
  }
791
792
  /** The font for one character: the chosen one, else the bundled fallback for its script, else the one before. */
792
793
  pick(cp, key, prev) {
793
- if (cp < 32 || this.has(key, cp)) return key;
794
+ if (cp < 32 || this.has(key, cp) || FORMAT_CHAR.test(String.fromCodePoint(cp))) return key;
794
795
  const fb = fallbackKey(cp, key);
795
796
  if (fb && !this.store.failed.has(fb)) {
796
797
  if (!this.store.has(fb)) {
@@ -4422,9 +4423,23 @@ function nodeRequest(url, init, trusted) {
4422
4423
  for (let i = 0; i < res.rawHeaders.length; i += 2) pairs2.push([res.rawHeaders[i], res.rawHeaders[i + 1]]);
4423
4424
  const none = [101, 204, 205, 304].includes(res.statusCode) || (init.method || "GET").toUpperCase() === "HEAD";
4424
4425
  if (none) res.resume();
4425
- resolve(new Response(none ? null : stream.Readable.toWeb(res), { status: res.statusCode, statusText: res.statusMessage, headers: (
4426
+ const enc = String(res.headers["content-encoding"] || "").trim().toLowerCase();
4427
+ let body = res, decoded = false;
4428
+ if (!none && enc && enc !== "identity") {
4429
+ const zlib = nodeMod("node:zlib");
4430
+ const dec2 = enc === "gzip" || enc === "x-gzip" ? zlib.createGunzip() : enc === "deflate" ? zlib.createInflate() : enc === "br" ? zlib.createBrotliDecompress() : null;
4431
+ if (!dec2) {
4432
+ res.resume();
4433
+ return reject(Object.assign(new Error(`the response is encoded as "${enc}", which the data fetch cannot decode`), { status: 415 }));
4434
+ }
4435
+ body = stream.pipeline(res, dec2, () => {
4436
+ });
4437
+ decoded = true;
4438
+ }
4439
+ const kept = decoded ? pairs2.filter(([k]) => !/^(content-encoding|content-length)$/i.test(k)) : pairs2;
4440
+ resolve(new Response(none ? null : stream.Readable.toWeb(body), { status: res.statusCode, statusText: res.statusMessage, headers: (
4426
4441
  /** @type {any} */
4427
- pairs2
4442
+ kept
4428
4443
  ) }));
4429
4444
  });
4430
4445
  req.on("error", reject);
@@ -4443,7 +4458,7 @@ function redirectRequest(from, to, req, status) {
4443
4458
  }
4444
4459
  function guardedFetch(opt, base) {
4445
4460
  const allow = (opt.allowHosts || []).map((h) => String(h).toLowerCase().replace(/^\[|\]$/g, ""));
4446
- const node2 = inNode();
4461
+ const node3 = !opt.viaBase && inNode();
4447
4462
  return (
4448
4463
  /** @type {any} */
4449
4464
  (async (input, init = {}) => {
@@ -4451,7 +4466,7 @@ function guardedFetch(opt, base) {
4451
4466
  let req = { ...init };
4452
4467
  for (let hop = 0; ; hop++) {
4453
4468
  const trusted = allow.includes(url.hostname.replace(/^\[|\]$/g, "").toLowerCase());
4454
- const res = node2 ? await nodeRequest(url, req, trusted) : await base(url.href, { ...req, redirect: "manual" });
4469
+ const res = node3 ? await nodeRequest(url, req, trusted) : await base(url.href, { ...req, redirect: "manual" });
4455
4470
  if (res.type === "opaqueredirect") throw new Error(`${url.host} redirects; a redirect cannot be checked here (pass your own fetch to render)`);
4456
4471
  const loc = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
4457
4472
  if (!loc) return res;
@@ -5335,7 +5350,10 @@ function fetcherFor(opt) {
5335
5350
  return boundedFetch(f4, opt);
5336
5351
  }
5337
5352
  function checkHostSource(src, url, opt) {
5338
- if (opt.fetch || opt.unsafeFetch) return;
5353
+ const rule = opt.fetch ? opt.fetch.hostRule : opt.unsafeFetch ? null : opt;
5354
+ if (!rule) return;
5355
+ const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(String(url).trim());
5356
+ 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 });
5339
5357
  const t = String(src.url ?? "").trim();
5340
5358
  if (/^\/(?![/\\])/.test(t)) return;
5341
5359
  const m = /^https?:\/\/([^/?#\\]*)/i.exec(t);
@@ -5346,7 +5364,7 @@ function checkHostSource(src, url, opt) {
5346
5364
  host = new URL(url).hostname.replace(/^\[|\]$/g, "").toLowerCase();
5347
5365
  } catch {
5348
5366
  }
5349
- if (whole && host && (opt.allowHosts || []).map((h) => String(h).toLowerCase()).includes(host)) return;
5367
+ if (whole && host && (rule.allowHosts || []).map((h) => String(h).toLowerCase()).includes(host)) return;
5350
5368
  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 });
5351
5369
  }
5352
5370
  async function loadSources(def, opt) {
@@ -5841,7 +5859,7 @@ var BASE_STYLE = {
5841
5859
  radius: 0
5842
5860
  };
5843
5861
  function resolveStyle(layers, ctx) {
5844
- let node2 = null, allStatic = true;
5862
+ let node3 = null, allStatic = true;
5845
5863
  for (const l of layers) {
5846
5864
  if (!l || typeof l !== "object") continue;
5847
5865
  if (hasDynamic(l)) {
@@ -5858,10 +5876,10 @@ function resolveStyle(layers, ctx) {
5858
5876
  next = { map: /* @__PURE__ */ new WeakMap(), value: null };
5859
5877
  map.set(l, next);
5860
5878
  }
5861
- node2 = next;
5879
+ node3 = next;
5862
5880
  map = next.map;
5863
5881
  }
5864
- if (node2?.value) return node2.value;
5882
+ if (node3?.value) return node3.value;
5865
5883
  }
5866
5884
  const out = {};
5867
5885
  for (const l of layers) {
@@ -5872,7 +5890,7 @@ function resolveStyle(layers, ctx) {
5872
5890
  out[k] = isDynamic(v) ? safe(v, ctx) : v;
5873
5891
  }
5874
5892
  }
5875
- if (allStatic && node2) node2.value = Object.freeze(out);
5893
+ if (allStatic && node3) node3.value = Object.freeze(out);
5876
5894
  return out;
5877
5895
  }
5878
5896
  var CACHE = /* @__PURE__ */ new WeakMap();
@@ -6504,6 +6522,11 @@ function niceScale(min, max, ticks = 5) {
6504
6522
  const step3 = niceNum(range / Math.max(1, ticks - 1), true);
6505
6523
  return { lo: Math.floor(min / step3) * step3, hi: Math.ceil(max / step3) * step3, step: step3 };
6506
6524
  }
6525
+ function niceScaleSpan(min, max, ticks = 5) {
6526
+ if (!Number.isFinite(min) || !Number.isFinite(max) || !(max > min)) return niceScale(min, max, ticks);
6527
+ const step3 = niceNum((max - min) / Math.max(1, ticks - 1), true);
6528
+ return { lo: Math.floor(min / step3) * step3, hi: Math.ceil(max / step3) * step3, step: step3 };
6529
+ }
6507
6530
  function niceNum(x, round) {
6508
6531
  const e2 = Math.floor(Math.log10(x));
6509
6532
  const f4 = x / 10 ** e2;
@@ -6826,10 +6849,10 @@ function paintGauge(g) {
6826
6849
  if (!(hi > lo)) hi = lo + 1;
6827
6850
  const shape = Object.hasOwn(GAUGE_SHAPES, item.gaugeShape) ? item.gaugeShape : "half";
6828
6851
  const indicator = GAUGE_INDICATORS.includes(item.gaugeIndicator) ? item.gaugeIndicator : "needle";
6829
- const [start, sweep] = GAUGE_SHAPES[shape];
6852
+ const [start, sweep2] = GAUGE_SHAPES[shape];
6830
6853
  const frac = (x) => Math.max(0, Math.min(1, (x - lo) / (hi - lo)));
6831
- const ang = (x) => start + frac(x) * sweep;
6832
- const end = start + sweep - (shape === "full" ? 1e-4 : 0);
6854
+ const ang = (x) => start + frac(x) * sweep2;
6855
+ const end = start + sweep2 - (shape === "full" ? 1e-4 : 0);
6833
6856
  const cx = X + W2 / 2, H = bottom - top;
6834
6857
  let R2, cy;
6835
6858
  if (shape === "full") {
@@ -6886,7 +6909,7 @@ function paintGauge(g) {
6886
6909
  text2(fmtV(t), p.x, p.y + fs * 0.3, { align: "center", size: fs * 0.8, color: "#6b7280" });
6887
6910
  });
6888
6911
  } else if (shape !== "full") {
6889
- const e0 = at(start, R2 - th / 2), e1 = at(start + sweep, R2 - th / 2);
6912
+ const e0 = at(start, R2 - th / 2), e1 = at(start + sweep2, R2 - th / 2);
6890
6913
  text2(fmtV(lo), e0.x, e0.y + fs * 1.3, { align: "center", color: "#6b7280" });
6891
6914
  text2(fmtV(hi), e1.x, e1.y + fs * 1.3, { align: "center", color: "#6b7280" });
6892
6915
  }
@@ -7460,7 +7483,7 @@ var byName = (lc, pal) => (name) => {
7460
7483
  };
7461
7484
  function chartData(item, ctx, lc, pal = paletteOf(item.palette)) {
7462
7485
  let rows = item.dataSet ? related(lc.dataSets[item.dataSet] || [], ctx) : ctx.aggRows || [];
7463
- if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name}: the data set "${item.dataSet}" does not exist`);
7486
+ if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name || item.type}: the data set "${item.dataSet}" does not exist`);
7464
7487
  if (item.filters?.length) rows = applyFilters(rows, item.filters, ctx);
7465
7488
  if (item.sort?.length) rows = applySort(rows, item.sort, ctx);
7466
7489
  const who = item.name || "Chart";
@@ -7748,13 +7771,15 @@ function valueAxis(spec, lo, hi, minPos, { includeZero = true, len = 100, fs = 7
7748
7771
  lo = lo < 0 ? -1 : 0;
7749
7772
  hi = 1;
7750
7773
  }
7774
+ let padded = false;
7751
7775
  if (pad2 > 0 && hi > lo) {
7752
7776
  const d = (hi - lo) * pad2;
7753
- if (smin == null) lo -= d;
7754
- if (smax == null) hi += d;
7777
+ if (smin == null) lo = lo >= 0 && lo - d < 0 ? 0 : lo - d;
7778
+ if (smax == null) hi = hi <= 0 && hi + d > 0 ? 0 : hi + d;
7779
+ padded = true;
7755
7780
  }
7756
7781
  const want = len < fs * 6 ? 3 : 5;
7757
- const sc = niceScale(smin ?? lo, smax ?? hi, want);
7782
+ const sc = padded && smin == null && smax == null && (lo >= 0 || hi <= 0) ? niceScaleSpan(lo, hi, want) : niceScale(smin ?? lo, smax ?? hi, want);
7758
7783
  let a = sc.lo, b = sc.hi, ticks;
7759
7784
  if (smin != null || smax != null) {
7760
7785
  a = smin ?? sc.lo;
@@ -8182,31 +8207,27 @@ function rowPoints(type, g) {
8182
8207
  rows = rows.slice(0, cap);
8183
8208
  }
8184
8209
  const blank2 = (v) => v == null || v === "";
8185
- const missing = /* @__PURE__ */ new Set();
8210
+ const drawn = /* @__PURE__ */ new Set();
8186
8211
  const sets = data.series.map((s, si) => {
8187
8212
  const pts2 = [];
8188
8213
  rows.forEach((r, ri) => {
8189
8214
  c.fields = r;
8190
8215
  const rx = safe2(item.xValue, c, lc, who), ry = safe2(s.def.value || "=0", { ...c, aggRows: [r] }, lc, who);
8191
- if (blank2(rx) || blank2(ry)) {
8192
- missing.add(ri);
8193
- return;
8194
- }
8216
+ if (blank2(rx) || blank2(ry)) return;
8195
8217
  const x = Number(rx), y = Number(ry);
8196
- if (!Number.isFinite(x) || !Number.isFinite(y)) {
8197
- missing.add(ri);
8198
- return;
8199
- }
8218
+ if (!Number.isFinite(x) || !Number.isFinite(y)) return;
8200
8219
  let size = 1;
8201
8220
  if (type === "bubble") {
8202
8221
  size = Number(safe2(s.def.size || "=1", { ...c, aggRows: [r] }, lc, who));
8203
8222
  if (!Number.isFinite(size) || size <= 0) return;
8204
8223
  }
8205
8224
  pts2.push({ x, y, size });
8225
+ drawn.add(ri);
8206
8226
  });
8207
8227
  return { s, pts: pts2, i: si };
8208
8228
  });
8209
- if (missing.size) lc.warn(`${who}: ${missing.size} of ${rows.length} rows have no x or y value and are not drawn`);
8229
+ const missing = rows.length - drawn.size;
8230
+ if (missing > 0) lc.warn(`${who}: ${missing} of ${rows.length} rows have no x or y value and are not drawn`);
8210
8231
  return sets;
8211
8232
  }
8212
8233
  function paintXY(type, g) {
@@ -10096,7 +10117,7 @@ function buildTree(groups, rows, ctx, lc, who, axis, state) {
10096
10117
  for (const n5 of frontier) {
10097
10118
  const bs = sortBuckets(groupRows(n5.rows, g.expr || "=''", ctx, lc, who), g, ctx, lc, who);
10098
10119
  n5.children = bs.map((b) => {
10099
- const node2 = { key: b.key, text: b.text, label: "", rows: b.rows, level: l, parent: n5, children: null, path: `${n5.path}/${b.text}`, open: true, lo: 0, hi: 0, toggle: null };
10120
+ const node3 = { key: b.key, text: b.text, label: "", rows: b.rows, level: l, parent: n5, children: null, path: `${n5.path}/${b.text}`, open: true, lo: 0, hi: 0, toggle: null };
10100
10121
  if (g.label) {
10101
10122
  let v;
10102
10123
  try {
@@ -10105,14 +10126,14 @@ function buildTree(groups, rows, ctx, lc, who, axis, state) {
10105
10126
  lc.warn(`${who}: ${e2.message}`);
10106
10127
  v = "#Error";
10107
10128
  }
10108
- node2.label = toText(v, g.format || null, ctx);
10109
- } else node2.label = toText(b.key, g.format || null, ctx);
10129
+ node3.label = toText(v, g.format || null, ctx);
10130
+ } else node3.label = toText(b.key, g.format || null, ctx);
10110
10131
  if (g.collapsible && l < groups.length - 1) {
10111
- const key = `${who}|${axis}${l}|${node2.path}`;
10112
- node2.open = state?.toggles?.[key] ?? !g.initiallyCollapsed;
10113
- node2.toggle = { key, open: node2.open };
10132
+ const key = `${who}|${axis}${l}|${node3.path}`;
10133
+ node3.open = state?.toggles?.[key] ?? !g.initiallyCollapsed;
10134
+ node3.toggle = { key, open: node3.open };
10114
10135
  }
10115
- return node2;
10136
+ return node3;
10116
10137
  });
10117
10138
  if (g.parent && axis === "r") {
10118
10139
  if (l === groups.length - 1) recurse(n5, g, l);
@@ -10264,14 +10285,14 @@ function buildPivot(item, rows, ctx, lc) {
10264
10285
  const withClick = (cell, click, n5, chain, groups, axis) => click ? Object.assign(cell, click, { ctx: headCtx(n5, chain, groups, axis) }) : cell;
10265
10286
  const isPct = (v) => v.show === "percentOfTotal" || v.show === "percentOfRow" || v.show === "percentOfColumn";
10266
10287
  const denCache = /* @__PURE__ */ new Map();
10267
- const den = (vi, kind, node2, scopes) => {
10268
- let m = denCache.get(node2);
10288
+ const den = (vi, kind, node3, scopes) => {
10289
+ let m = denCache.get(node3);
10269
10290
  if (!m) {
10270
10291
  m = /* @__PURE__ */ new Map();
10271
- denCache.set(node2, m);
10292
+ denCache.set(node3, m);
10272
10293
  }
10273
10294
  const k = `${vi}|${kind}`;
10274
- if (!m.has(k)) m.set(k, evalAgg(vals[vi].value || "=Count(Fields)", node2.rows, scopes));
10295
+ if (!m.has(k)) m.set(k, evalAgg(vals[vi].value || "=Count(Fields)", node3.rows, scopes));
10275
10296
  return m.get(k);
10276
10297
  };
10277
10298
  const cols = [];
@@ -10626,7 +10647,7 @@ function hidden(item, ctx, lc) {
10626
10647
  const r = evalSafe(item.hidden, ctx, lc, item.name || item.type);
10627
10648
  h = !r.err && truthy(r.v);
10628
10649
  }
10629
- return item.name && lc.state?.toggles?.[`item:${item.name}`] ? !h : h;
10650
+ return item.name && lc.state?.toggles?.[`item:${item.name || item.type}`] ? !h : h;
10630
10651
  }
10631
10652
  var SHRINK_DEFAULTS = { minFontSize: 4, step: 0.5 };
10632
10653
  function rotationOf(item) {
@@ -10962,7 +10983,7 @@ register("table", {
10962
10983
  else {
10963
10984
  rows = item.dataSet && lc.dataSets[item.dataSet] || [];
10964
10985
  rows = related(rows, tctx);
10965
- if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name || "Table"}: the data set "${item.dataSet}" does not exist`);
10986
+ if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name || item.type}: the data set "${item.dataSet}" does not exist`);
10966
10987
  if (item.filters?.length) rows = applyFilters(rows, item.filters, tctx);
10967
10988
  const sort = lc.state?.sort?.[item.name] || item.sort;
10968
10989
  if (sort?.length) rows = applySort(rows, sort, tctx);
@@ -10978,11 +10999,11 @@ register("table", {
10978
10999
  if (overflow === "shrink" && room > 0) {
10979
11000
  const k = room / designedW;
10980
11001
  cols = cols.map((c) => ({ ...c, width: (Number(c.width) || 0) * k }));
10981
- lc.warn(`${item.name || "Table"}: its columns are ${Math.round(designedW)}pt wide, wider than the page (${Math.round(room)}pt), so they are narrowed to fit`);
11002
+ 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`);
10982
11003
  } else if (overflow === "clip" || overflow === "paginate" && lc.fixed) {
10983
- lc.warn(`${item.name || "Table"}: 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);
11004
+ 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);
10984
11005
  } else if (overflow === "paginate" && item.overflow !== "paginate") {
10985
- lc.warn(`${item.name || "Table"}: its columns are ${Math.round(designedW)}pt wide, wider than the page (${Math.round(room)}pt), so they continue on the next pages`);
11006
+ 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`);
10986
11007
  }
10987
11008
  const colX = [];
10988
11009
  let acc = item.x;
@@ -10992,6 +11013,7 @@ register("table", {
10992
11013
  }
10993
11014
  const width = acc - item.x;
10994
11015
  const region = { name: item.name, columns: cols.map((c) => c.width), rows: [] };
11016
+ if (lc.tablesSeen) lc.tablesSeen.n++;
10995
11017
  const tableScope = { rows, index: -1, run: [] };
10996
11018
  const scopes = { ...tctx.scopes || {}, [item.name]: tableScope };
10997
11019
  const groupChains = {};
@@ -11015,7 +11037,7 @@ register("table", {
11015
11037
  const covered = (ci) => cover[ci] !== null;
11016
11038
  const cellsAt = /* @__PURE__ */ new WeakMap();
11017
11039
  const layRow = (row, ctx, kind, extra) => {
11018
- if (row.hidden != null && row.hidden !== false && row.hidden !== "" && hidden({ hidden: row.hidden, name: `${item.name || "Table"} row` }, ctx, lc)) {
11040
+ if (row.hidden != null && row.hidden !== false && row.hidden !== "" && hidden({ hidden: row.hidden, name: `${item.name || item.type} row` }, ctx, lc)) {
11019
11041
  if (openSpans.length) {
11020
11042
  for (const s of openSpans) s.left--;
11021
11043
  for (const s of openSpans) if (s.left <= 0) closeSpan(s);
@@ -11049,7 +11071,7 @@ register("table", {
11049
11071
  else try {
11050
11072
  v = evalValue(cell.value ?? "", cctx);
11051
11073
  } catch (e2) {
11052
- lc.warn(`${item.name || "Table"} cell: ${e2.message}`);
11074
+ lc.warn(`${item.name || item.type} cell: ${e2.message}`);
11053
11075
  v = "#Error";
11054
11076
  }
11055
11077
  let text2 = textOf(v, st, cctx, lc);
@@ -11092,7 +11114,7 @@ register("table", {
11092
11114
  cells.forEach((c, k) => {
11093
11115
  if (c.cell.visual?.type) {
11094
11116
  items.push(...paintBox({ x: c.x, y: 0, w: c.w, h, st: c.st, tl: null, m: lc.m }));
11095
- 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 }));
11117
+ 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 }));
11096
11118
  return;
11097
11119
  }
11098
11120
  if (c.nested) {
@@ -11147,7 +11169,7 @@ register("table", {
11147
11169
  };
11148
11170
  const layoutInCell = (inner, x, cw, st, cctx, row) => {
11149
11171
  const pd = padding(st);
11150
- 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]) };
11172
+ 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]) };
11151
11173
  const scopeRows2 = cctx.aggIndex != null ? [cctx.fields] : cctx.aggRows || [];
11152
11174
  const current = item.dataSet ? { ...cctx.current || {}, [item.dataSet]: scopeRows2 } : cctx.current;
11153
11175
  const child = {
@@ -11167,7 +11189,7 @@ register("table", {
11167
11189
  const reads = (it.dataSet && it.dataSet !== item.dataSet ? child.ctxFor(it).aggRows?.length : scopeRows2.length) || 1;
11168
11190
  if (budget.left < reads) {
11169
11191
  budget.left = 0;
11170
- lc.warn(`${item.name}: more than ${CELL_ITEM_UNITS} rows of items inside cells; the rest are left empty`);
11192
+ lc.warn(`${item.name || item.type}: more than ${CELL_ITEM_UNITS} rows of items inside cells; the rest are left empty`);
11171
11193
  return { items: [], height: 0 };
11172
11194
  }
11173
11195
  budget.left -= reads;
@@ -11211,7 +11233,7 @@ register("table", {
11211
11233
  u.items.splice(at < 0 ? u.items.length : at, 0, ...add2);
11212
11234
  });
11213
11235
  if (s.tl.needed > s.units[0].height + GROW_TOLERANCE || s.st.verticalAlign && s.st.verticalAlign !== "top") {
11214
- const id = `${item.name}:span:${lc.nextId()}`;
11236
+ const id = `${item.name || item.type}:span:${lc.nextId()}`;
11215
11237
  for (const u of s.units) u.block ||= id;
11216
11238
  } else {
11217
11239
  let above = s.units[0].height;
@@ -11253,7 +11275,7 @@ register("table", {
11253
11275
  const groups = item.groups || [];
11254
11276
  let rowNo = lc.win?.rowOffset || 0;
11255
11277
  const groupTables = [];
11256
- const tableKey = `${item.name}#${lc.nextId()}`;
11278
+ const tableKey = `${item.name || item.type}#${lc.nextId()}`;
11257
11279
  const emit = (level, grows, ctx, chain, keyPath) => {
11258
11280
  if (level === groups.length) {
11259
11281
  for (let i = 0; i < grows.length; i++) {
@@ -11315,7 +11337,7 @@ register("table", {
11315
11337
  kids = /* @__PURE__ */ new Map();
11316
11338
  roots = [];
11317
11339
  for (const b of buckets) {
11318
- const pk = evalSafe(g.parent, { ...ctx, fields: b.rows[0], aggRows: b.rows, aggIndex: void 0 }, lc, `${item.name} group parent`).v;
11340
+ const pk = evalSafe(g.parent, { ...ctx, fields: b.rows[0], aggRows: b.rows, aggIndex: void 0 }, lc, `${item.name || item.type} group parent`).v;
11319
11341
  const pr = pk == null || pk === "" ? null : byText.get(pk instanceof Date ? String(pk.getTime()) : String(pk));
11320
11342
  if (!pr || pr === b) roots.push(b);
11321
11343
  else {
@@ -11336,7 +11358,7 @@ register("table", {
11336
11358
  for (const b of buckets) if (!recOf.has(b)) rec(b, 0);
11337
11359
  }
11338
11360
  const shown2 = /* @__PURE__ */ new Set();
11339
- const node2 = (bk, bi, sibs, depth, parentPath) => {
11361
+ const node3 = (bk, bi, sibs, depth, parentPath) => {
11340
11362
  if (lc.rowBudget?.cut || shown2.has(bk)) return;
11341
11363
  shown2.add(bk);
11342
11364
  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) } : {} };
@@ -11347,7 +11369,7 @@ register("table", {
11347
11369
  if (g.indent) gctx.indent = (ctx.indent || 0) + depth * Number(g.indent);
11348
11370
  }
11349
11371
  const path = `${parentPath}/${bk.text}`;
11350
- const tkey = `${item.name}|${level}|${path}`;
11372
+ const tkey = `${item.name || item.type}|${level}|${path}`;
11351
11373
  const dflt = kids && g.expandLevels != null ? depth < Number(g.expandLevels) : !g.initiallyCollapsed;
11352
11374
  const open = !g.collapsible ? true : lc.state?.toggles?.[tkey] ?? dflt;
11353
11375
  const start = units.length;
@@ -11369,8 +11391,8 @@ register("table", {
11369
11391
  const ch = kids?.get(bk) || [];
11370
11392
  if (open) {
11371
11393
  emit(level + 1, bk.rows, gctx, [...chain, sc], path);
11372
- 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`);
11373
- else ch.forEach((c, ci) => node2(c, ci, ch, depth + 1, path));
11394
+ 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`);
11395
+ else ch.forEach((c, ci) => node3(c, ci, ch, depth + 1, path));
11374
11396
  } else {
11375
11397
  const rs = recOf.get(bk) || bk.rows;
11376
11398
  for (const s of [...chain, sc]) {
@@ -11398,7 +11420,7 @@ register("table", {
11398
11420
  if (g.newSection) units[start].sectionStart = true;
11399
11421
  if (g.pageBreak === "after" && bi < sibs.length - 1) units[units.length - 1].breakAfter = true;
11400
11422
  if (g.keepTogether) {
11401
- const id = `${item.name}:g${level}:${path}:${lc.nextId()}`;
11423
+ const id = `${item.name || item.type}:g${level}:${path}:${lc.nextId()}`;
11402
11424
  for (let k = start; k < units.length; k++) if (!units[k].block) {
11403
11425
  units[k].block = id;
11404
11426
  if (cont) units[k].blockOpen = true;
@@ -11415,12 +11437,12 @@ register("table", {
11415
11437
  for (const c of kids?.get(x) || []) st.push(c);
11416
11438
  }
11417
11439
  };
11418
- roots.forEach((bk, bi) => node2(bk, bi, roots, 0, keyPath));
11440
+ roots.forEach((bk, bi) => node3(bk, bi, roots, 0, keyPath));
11419
11441
  if (kids) {
11420
11442
  const rest = buckets.filter((b) => !shown2.has(b));
11421
11443
  if (rest.length) {
11422
- 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`);
11423
- rest.forEach((bk, bi) => node2(bk, bi, rest, 0, keyPath));
11444
+ 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`);
11445
+ rest.forEach((bk, bi) => node3(bk, bi, rest, 0, keyPath));
11424
11446
  }
11425
11447
  }
11426
11448
  };
@@ -11447,7 +11469,7 @@ register("table", {
11447
11469
  units[units.length - 1].breakAfter = true;
11448
11470
  }
11449
11471
  if (item.bookmark && units.length) {
11450
- const b = evalSafe(item.bookmark, base, lc, `${item.name || "Table"} bookmark`).v;
11472
+ const b = evalSafe(item.bookmark, base, lc, `${item.name || item.type} bookmark`).v;
11451
11473
  if (b != null && b !== "" && b !== "#Error") units[0].items.unshift({ t: "bookmark", label: String(b), x: item.x, y: 0, level: item.bookmarkLevel ?? 0 });
11452
11474
  }
11453
11475
  if (!lc.fixed) lc.regions?.push(region);
@@ -11542,7 +11564,7 @@ register("container", {
11542
11564
  const ctx = lc.ctxFor(item);
11543
11565
  if (hidden(item, ctx, lc)) return { height: 0, units: [] };
11544
11566
  const res = lc.layoutItems(item.items, lc, { dx: item.x });
11545
- return frame2(item, lc, ctx, res, item.keepTogether !== false ? `c:${item.name}:${lc.nextId()}` : null);
11567
+ return frame2(item, lc, ctx, res, item.keepTogether !== false ? `c:${item.name || item.type}:${lc.nextId()}` : null);
11546
11568
  }
11547
11569
  });
11548
11570
  function frame2(item, lc, ctx, res, blockId0) {
@@ -11599,7 +11621,7 @@ register("list", {
11599
11621
  let rows = item.dataSet && lc.dataSets[item.dataSet] || [];
11600
11622
  if (item.inheritRows && item.dataSet && ctx.current?.[item.dataSet]) rows = ctx.current[item.dataSet];
11601
11623
  else rows = related(rows, ctx);
11602
- if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name}: the data set "${item.dataSet}" does not exist`);
11624
+ if (item.dataSet && !lc.dataSets[item.dataSet]) lc.warn(`${item.name || item.type}: the data set "${item.dataSet}" does not exist`);
11603
11625
  if (item.filters?.length) rows = applyFilters(rows, item.filters, ctx);
11604
11626
  if (item.sort?.length) rows = applySort(rows, item.sort, ctx);
11605
11627
  const reps = item.groupBy ? groupRows(rows, item.groupBy, ctx, lc, item.name, item.groupAdjacent === true).map((b) => b.rows) : rows.map((r) => [r]);
@@ -11628,7 +11650,7 @@ register("list", {
11628
11650
  } };
11629
11651
  const k = i % ncol;
11630
11652
  const res = lc.layoutItems(item.items, child, { dx: item.x + k * (item.w + gap) });
11631
- 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);
11653
+ 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);
11632
11654
  if (ncol > 1) {
11633
11655
  if (k === 0) {
11634
11656
  cells = { top: y, height: 0, items: [], x0: item.x, x1: item.x + ncol * item.w + (ncol - 1) * gap, block: void 0 };
@@ -12099,7 +12121,7 @@ register("subreport", {
12099
12121
  if (hidden(item, ctx, lc)) return { height: 0, units: [] };
12100
12122
  const params = {};
12101
12123
  for (const [k, v] of Object.entries(item.params || {})) {
12102
- const r = evalSafe(v, ctx, lc, `${item.name} parameter ${k}`);
12124
+ const r = evalSafe(v, ctx, lc, `${item.name || item.type} parameter ${k}`);
12103
12125
  params[k] = r.v instanceof Date ? isoDate(r.v, ctx.timeZone) : r.v;
12104
12126
  }
12105
12127
  const key = `${item.report}|${JSON.stringify(params)}`;
@@ -12118,10 +12140,10 @@ register("subreport", {
12118
12140
  const res = sub.results.get(key);
12119
12141
  if (!res) return placeholder(`Subreport "${item.report}" did not load`);
12120
12142
  if (res.error) {
12121
- lc.warn(`${item.name}: ${res.error}`);
12143
+ lc.warn(`${item.name || item.type}: ${res.error}`);
12122
12144
  return placeholder(`Subreport "${item.report}": ${res.error}`);
12123
12145
  }
12124
- const block = item.keepTogether ? `s:${item.name}:${lc.nextId()}` : void 0;
12146
+ const block = item.keepTogether ? `s:${item.name || item.type}:${lc.nextId()}` : void 0;
12125
12147
  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 }));
12126
12148
  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()}` }));
12127
12149
  for (const r of res.regions || []) lc.regions?.push(r);
@@ -15136,6 +15158,7 @@ var SCHEMA_ALIAS = "reportwright/report@1";
15136
15158
  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\
15137
15159
  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\
15138
15160
  ormat showValues labelPosition symbology quietZone report params text toggle initiallyCollapsed collapsible expandLevels repeatColumns columnGap rowHeaderWidth anim animation visual comment notes description".split(" "));
15161
+ var NO_SERIES_CHARTS = /* @__PURE__ */ new Set(["gantt"]);
15139
15162
  function looksLikeLink(it) {
15140
15163
  if (it.type !== "textbox" || it.action && it.action.type && it.action.type !== "none") return false;
15141
15164
  const st = it.style && typeof it.style === "object" ? it.style : {};
@@ -15264,6 +15287,9 @@ function validate(def) {
15264
15287
  if (p?.hidden && p.required && (p.default == null || p.default === "") && !p.nullable) {
15265
15288
  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`);
15266
15289
  }
15290
+ if (p?.required && p.nullable && !p.multi && (p.default == null || p.default === "")) {
15291
+ 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`);
15292
+ }
15267
15293
  if (p?.type === "date" && typeof p.default === "string" && p.default.trim() && !p.default.startsWith("=") && !toDate(p.default)) {
15268
15294
  warnings.push(`Parameter "${p.name}": its default "${p.default}" is not a date; write it as 2026-12-31 (year-month-day)`);
15269
15295
  }
@@ -15344,7 +15370,7 @@ function validate(def) {
15344
15370
  warnings.push(`${label}: there is no named style "${it.styleName}"${g ? ` (did you mean "${g}"?)` : ""}; it is ignored`);
15345
15371
  }
15346
15372
  if (Array.isArray(it.sort)) sortIssues(it.sort, label, warnings);
15347
- if (it.type === "chart" && Array.isArray(it.series) && !it.series.length) warnings.push(`${label}: the chart has no series, so it draws nothing; add one, e.g. series: [{ "name": "Value", "value": "=Sum(Fields.Amount)" }]`);
15373
+ 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)" }]`);
15348
15374
  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`);
15349
15375
  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`);
15350
15376
  const own = ownKeys(it.type);
@@ -15387,6 +15413,9 @@ function validate(def) {
15387
15413
  const n5 = Array.isArray(it.columns) ? it.columns.length : 0;
15388
15414
  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]])];
15389
15415
  for (const [part2, rows] of rowsOf) (Array.isArray(rows) ? rows : []).forEach((row, ri) => {
15416
+ const cells = Array.isArray(row?.cells) ? row.cells : [];
15417
+ const placed = cells.length < n5 && cells.some((c) => Number(c?.colSpan) > 1) ? cells.reduce((s, c) => s + Math.max(1, Math.floor(Number(c?.colSpan)) || 1), 0) : cells.length;
15418
+ if (placed < n5) warnings.push(`${label} ${part2} row ${ri + 1}: the row has ${placed} of ${n5} cells and no colSpan covers the other ${n5 - placed}; add the cells or a colSpan`);
15390
15419
  for (const [k, j] of rowCells(row?.cells, n5).covered) warnings.push(`${label} ${part2} 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)`);
15391
15420
  });
15392
15421
  }
@@ -15801,7 +15830,7 @@ function* textsOf(def, dataSets) {
15801
15830
  }
15802
15831
  }
15803
15832
  }
15804
- var NO_CJK_FONTS = "Text in Japanese/Chinese/Korean needs the optional CJK fonts: npm run fonts:cjk";
15833
+ 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";
15805
15834
  async function render(def0, opts = {}) {
15806
15835
  const t0 = Date.now();
15807
15836
  const reuseWarnings = [];
@@ -15872,6 +15901,7 @@ async function render(def0, opts = {}) {
15872
15901
  const base = { ...BASE_STYLE, ...def.styles?.base || {} };
15873
15902
  let idSeq = 0;
15874
15903
  const regions = [];
15904
+ const tablesSeen = { n: 0 };
15875
15905
  const imageBudget = opts.imageBudget || { seen: /* @__PURE__ */ new Set(), bytes: 0 };
15876
15906
  const makeLc = (globals, fixed2) => {
15877
15907
  const lc = {
@@ -15882,6 +15912,7 @@ async function render(def0, opts = {}) {
15882
15912
  fixed: fixed2,
15883
15913
  maxUnitHeight: contentH,
15884
15914
  state: opts.state || {},
15915
+ tablesSeen,
15885
15916
  regions: opts.exportData || opts.dataOnly ? regions : null,
15886
15917
  dataOnly: !!opts.dataOnly,
15887
15918
  // exportData: true: table data and cell tags (Excel, CSV, Word, HTML, accessible PDF)
@@ -15999,8 +16030,8 @@ async function render(def0, opts = {}) {
15999
16030
  u.breakBefore = false;
16000
16031
  u.breakAfter = false;
16001
16032
  }
16002
- const slices = paginate(body.units, body.tables, g.cH, warn);
16003
- parts2.push({ body, slices, g });
16033
+ const slices2 = paginate(body.units, body.tables, g.cH, warn);
16034
+ parts2.push({ body, slices: slices2, g });
16004
16035
  if (lc.rowBudget?.cut) break sections;
16005
16036
  if (!overflow.more) break;
16006
16037
  if (rep + 1 >= REUSE_LIMITS.repeats) {
@@ -16041,7 +16072,7 @@ async function render(def0, opts = {}) {
16041
16072
  const headings = [];
16042
16073
  const pages2 = [];
16043
16074
  list.forEach(({ part: part2, k, last }, n5) => {
16044
- const { body, slices, g } = part2;
16075
+ const { body, slices: slices2, g } = part2;
16045
16076
  const { pg, colCount, colW, colGap, cH } = g;
16046
16077
  const ph = parts2.length === 1 ? pageH : pg.height;
16047
16078
  const ml = pg.margins.left, mt = pg.margins.top;
@@ -16079,7 +16110,7 @@ async function render(def0, opts = {}) {
16079
16110
  band(g.hdr, mt, g.own.h ? k === 0 : isFirst, g.own.h ? last : isLast);
16080
16111
  const frozen = [];
16081
16112
  for (let c = 0; c < colCount; c++) {
16082
- const p = slices[k * colCount + c];
16113
+ const p = slices2[k * colCount + c];
16083
16114
  if (!p) break;
16084
16115
  const cx = ml + c * (colW + colGap);
16085
16116
  for (const t of p.repeat) placeItems(t.headerItems, cx, bodyTop, items);
@@ -16111,7 +16142,7 @@ async function render(def0, opts = {}) {
16111
16142
  items.length = j;
16112
16143
  const out = frozen.length ? { items, frozen } : { items };
16113
16144
  if (win) {
16114
- const u = slices[k * colCount]?.units[0];
16145
+ const u = slices2[k * colCount]?.units[0];
16115
16146
  if (u?.dataRow != null) {
16116
16147
  out.firstRow = u.dataRow;
16117
16148
  out.rowHead = !!u.rowHead;
@@ -16185,7 +16216,7 @@ async function render(def0, opts = {}) {
16185
16216
  if (m.noGlyph.size) {
16186
16217
  const cjk2 = [...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));
16187
16218
  const list = [...m.noGlyph].slice(0, 20).join(" ");
16188
- warn(cjk2 ? `${NO_CJK_FONTS} (the app), or npm i @reportwright/fonts-cjk then npx reportwright-fonts-cjk (the npm engine). 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.`);
16219
+ warn(cjk2 ? `${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.`);
16189
16220
  }
16190
16221
  if (opts.bodyOnly) return { units: result.body.units, tables: result.body.tables, height: result.body.height, regions, warnings, clipped: clipped() };
16191
16222
  if (opts.dataOnly) return {
@@ -16225,6 +16256,7 @@ async function render(def0, opts = {}) {
16225
16256
  headings: result.headings || [],
16226
16257
  pageStarts: result.pageStarts || [],
16227
16258
  regions: opts.exportData ? regions : null,
16259
+ hasTables: tablesSeen.n > 0,
16228
16260
  name: def.name || "",
16229
16261
  partial: cutRows(),
16230
16262
  timeZone: timeZone || null,
@@ -16361,7 +16393,8 @@ async function parameterOptions(def, given = {}, opts = {}) {
16361
16393
  seen.add(k);
16362
16394
  list.push({ value: v instanceof Date ? isoDate(v) : v, label: String(p.optionsFrom.label ? evalValue(p.optionsFrom.label, c) : v) });
16363
16395
  }
16364
- out[p.name] = list;
16396
+ const fixed2 = out[p.name] || [], have = new Set(fixed2.map((o) => o.value));
16397
+ out[p.name] = [...fixed2, ...list.filter((o) => !have.has(o.value))];
16365
16398
  }
16366
16399
  return out;
16367
16400
  }
@@ -17079,7 +17112,7 @@ function pathBox(d) {
17079
17112
  }
17080
17113
  return x0 === Infinity ? null : { x0, y0, x1, y1 };
17081
17114
  }
17082
- function arcExtremes(x1, y1, rx, ry, phi, large, sweep, x2, y2) {
17115
+ function arcExtremes(x1, y1, rx, ry, phi, large, sweep2, x2, y2) {
17083
17116
  rx = Math.abs(rx);
17084
17117
  ry = Math.abs(ry);
17085
17118
  if (!rx || !ry || x1 === x2 && y1 === y2) return [];
@@ -17092,7 +17125,7 @@ function arcExtremes(x1, y1, rx, ry, phi, large, sweep, x2, y2) {
17092
17125
  ry *= Math.sqrt(lam);
17093
17126
  }
17094
17127
  const num6 = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
17095
- const k = (large !== sweep ? 1 : -1) * Math.sqrt(Math.max(0, num6 / (rx * rx * y1p * y1p + ry * ry * x1p * x1p)));
17128
+ const k = (large !== sweep2 ? 1 : -1) * Math.sqrt(Math.max(0, num6 / (rx * rx * y1p * y1p + ry * ry * x1p * x1p)));
17096
17129
  const cxp = k * rx * y1p / ry, cyp = -k * ry * x1p / rx;
17097
17130
  const cx = cf * cxp - sf * cyp + (x1 + x2) / 2, cy = sf * cxp + cf * cyp + (y1 + y2) / 2;
17098
17131
  if (Math.abs(sf) > 1e-9) {
@@ -17102,8 +17135,8 @@ function arcExtremes(x1, y1, rx, ry, phi, large, sweep, x2, y2) {
17102
17135
  const ang = (ux, uy) => Math.atan2(uy, ux);
17103
17136
  const t1 = ang((x1p - cxp) / rx, (y1p - cyp) / ry);
17104
17137
  let dt2 = ang((-x1p - cxp) / rx, (-y1p - cyp) / ry) - t1;
17105
- if (sweep && dt2 < 0) dt2 += 2 * Math.PI;
17106
- else if (!sweep && dt2 > 0) dt2 -= 2 * Math.PI;
17138
+ if (sweep2 && dt2 < 0) dt2 += 2 * Math.PI;
17139
+ else if (!sweep2 && dt2 > 0) dt2 -= 2 * Math.PI;
17107
17140
  const out = [];
17108
17141
  for (let q2 = -4; q2 <= 4; q2++) {
17109
17142
  const t = q2 * Math.PI / 2, rel2 = dt2 >= 0 ? t - t1 : t1 - t;
@@ -17318,7 +17351,7 @@ function cellVisuals(items, used, tables) {
17318
17351
 
17319
17352
  // src/exporters/regions.js
17320
17353
  function needsTableData(model, what) {
17321
- if (model && model.regions === null) throw Object.assign(new Error(`${what} needs the report's table data: render it with { exportData: true }`), { code: "NO_EXPORT_DATA" });
17354
+ if (model && model.regions === null && model.hasTables !== false) throw Object.assign(new Error(`${what} needs the report's table data: render it with { exportData: true }`), { code: "NO_EXPORT_DATA" });
17322
17355
  }
17323
17356
  var needsExportData = (fmt2, o = {}) => ["xlsx", "csv", "docx", "pptx", "html", "json"].includes(fmt2) || fmt2 === "pdf" && !!(o.pdfua || o.ua || o.tagged);
17324
17357
  function mergedRegions(model) {
@@ -17770,6 +17803,10 @@ var n4 = (v) => Math.round(v * 1e4) / 1e4;
17770
17803
  var hex4 = (id) => id.toString(16).padStart(4, "0");
17771
17804
  var KAPPA = 4 * ((Math.SQRT2 - 1) / 3);
17772
17805
  var cleanText = (t) => t.replace(/\t|\u0085|\u2028|\u2029/g, " ").replace(/[\b\v]/g, "");
17806
+ var formatAt = (run, cl) => {
17807
+ const cp = run.text.codePointAt(cl);
17808
+ return cp !== void 0 && FORMAT_CHAR.test(String.fromCodePoint(cp));
17809
+ };
17773
17810
  function drawRun(c, run, x, y, size, pf, color2, spans2, texts) {
17774
17811
  const f4 = pf.embedder.font;
17775
17812
  const per = 1e3 / size;
@@ -17822,7 +17859,7 @@ function drawRun(c, run, x, y, size, pf, color2, spans2, texts) {
17822
17859
  rise = gy;
17823
17860
  }
17824
17861
  const adj = Math.round((pen - gx) * per * 1e3) / 1e3;
17825
- if (id === 0 && c.tagged) pen = gx;
17862
+ if (id === 0 && (c.tagged || formatAt(run, cl))) pen = gx;
17826
17863
  else {
17827
17864
  arr += (adj ? `${adj}` : "") + `<${hex4(id)}>`;
17828
17865
  pen = gx + adv(id) * size / f4.unitsPerEm;
@@ -17881,6 +17918,7 @@ var Content = class {
17881
17918
  this.saved = [];
17882
17919
  this.lines = null;
17883
17920
  this.tagged = false;
17921
+ this.artLines = false;
17884
17922
  }
17885
17923
  /**
17886
17924
  * The operators so far. Any other drawing reads or appends to it, so the lines waiting are drawn first: the text
@@ -17899,7 +17937,7 @@ var Content = class {
17899
17937
  * ponytail: lines move after the text drawn just after them; both are thin and do not cover each other.
17900
17938
  */
17901
17939
  line(stroke, w, dash, x1, y1, x2, y2) {
17902
- if (this.tagged) {
17940
+ if (this.tagged && !this.artLines) {
17903
17941
  this.paint(null, stroke, w, dash);
17904
17942
  this._s += `${n2(x1)} ${n2(y1)} m ${n2(x2)} ${n2(y2)} l S
17905
17943
  `;
@@ -17919,6 +17957,8 @@ var Content = class {
17919
17957
  if (!L) return;
17920
17958
  this.lines = null;
17921
17959
  this.et();
17960
+ const end = this.artLines ? "EMC\n" : "";
17961
+ if (end) this._s += "/Artifact BMC\n";
17922
17962
  this.paint(null, L.stroke, L.w, L.dash);
17923
17963
  const g = L.segs;
17924
17964
  const dy = g.length > 2 ? Math.round((g[1][1] - g[0][1]) * 100) : 0;
@@ -17927,10 +17967,10 @@ var Content = class {
17927
17967
  `;
17928
17968
  this._s += `q
17929
17969
  ${one}${`1 0 0 1 0 ${dy / 100} cm ${one}`.repeat(g.length - 1)}Q
17930
- `;
17970
+ ${end}`;
17931
17971
  return;
17932
17972
  }
17933
- this._s += g.map(([a, b, c, d]) => `${n2(a)} ${n2(b)} m ${n2(c)} ${n2(d)} l`).join(" ") + " S\n";
17973
+ this._s += g.map(([a, b, c, d]) => `${n2(a)} ${n2(b)} m ${n2(c)} ${n2(d)} l`).join(" ") + " S\n" + end;
17934
17974
  }
17935
17975
  q() {
17936
17976
  this.et();
@@ -18636,9 +18676,9 @@ function addOutline(doc, bookmarks, dest) {
18636
18676
  if (!Dest) continue;
18637
18677
  const level = Math.max(0, Math.min(9, Number(b.level) || 0));
18638
18678
  while (stack2[stack2.length - 1].level >= level) stack2.pop();
18639
- const node2 = { ref: ctx.nextRef(), level, kids: [], Title: PDFHexString5.fromText(b.label), Dest };
18640
- stack2[stack2.length - 1].kids.push(node2);
18641
- stack2.push(node2);
18679
+ const node3 = { ref: ctx.nextRef(), level, kids: [], Title: PDFHexString5.fromText(b.label), Dest };
18680
+ stack2[stack2.length - 1].kids.push(node3);
18681
+ stack2.push(node3);
18642
18682
  }
18643
18683
  if (!root.kids.length) return;
18644
18684
  const count = (n5) => n5.kids.reduce((s, k) => s + 1 + count(k), 0);
@@ -18716,6 +18756,7 @@ function createSubsetter(loadWasm) {
18716
18756
  for (const g of opt.glyphs) x.hb_set_add(gs, g);
18717
18757
  }
18718
18758
  x.hb_subset_input_pin_all_axes_to_default(input, face);
18759
+ x.hb_subset_input_pin_axis_location(input, face, tag3("wght"), opt.weight ?? 400);
18719
18760
  const sub = x.hb_subset_or_fail(face, input);
18720
18761
  if (!sub) throw new Error("HarfBuzz: subsetting failed");
18721
18762
  const res = x.hb_face_reference_blob(sub);
@@ -18735,6 +18776,7 @@ function createSubsetter(loadWasm) {
18735
18776
  }
18736
18777
 
18737
18778
  // src/exporters/htmldata.js
18779
+ var dateKey = (d, tz) => tz ? toWall(d, tz) : Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds());
18738
18780
  var MAX_DATA_ROWS = 2e4;
18739
18781
  var DATA_STRINGS = { pages: "Pages", tables: "Tables", all: "All", filter: "Filter", toggle: "Show or hide the rows of this group", sortAsc: "Sort ascending", sortDesc: "Sort descending" };
18740
18782
  function tablesData(model, o = {}) {
@@ -18757,7 +18799,7 @@ function tablesData(model, o = {}) {
18757
18799
  rows: r.rows.map((row) => ({
18758
18800
  k: row.kind,
18759
18801
  l: row.level || 0,
18760
- c: row.cells.filter((c) => c.colIndex >= 0).map((c) => [c.colIndex, String(show(c) ?? ""), c.value instanceof Date ? c.value.getTime() : typeof c.value === "number" ? c.value : String(c.value ?? "").toLowerCase(), c.span || 1])
18802
+ c: row.cells.filter((c) => c.colIndex >= 0).map((c) => [c.colIndex, String(show(c) ?? ""), c.value instanceof Date ? dateKey(c.value, model.timeZone || void 0) : typeof c.value === "number" ? c.value : String(c.value ?? "").toLowerCase(), c.span || 1])
18761
18803
  }))
18762
18804
  }));
18763
18805
  }
@@ -18889,13 +18931,29 @@ async function cspHash(text2) {
18889
18931
  }
18890
18932
 
18891
18933
  // src/exporters/html.js
18892
- function exportHtml(model, fontStore, opt = {}) {
18934
+ function exportHtml(model, options, legacyOpt) {
18935
+ const isStore = (x) => !!x && typeof x.load === "function" && typeof x.get === "function" && x.bytes instanceof Map;
18936
+ let fontStore, opt;
18937
+ if (isStore(options)) {
18938
+ if (!warnedLegacy) {
18939
+ warnedLegacy = true;
18940
+ console.warn("[reportwright] DEPRECATED: exportHtml(model, fontStore, options) is replaced by exportHtml(model, { fonts: fontStore, ...options }); the old form is removed in 0.9");
18941
+ }
18942
+ fontStore = options;
18943
+ opt = legacyOpt || {};
18944
+ } else {
18945
+ opt = /** @type {any} */
18946
+ options || {};
18947
+ fontStore = opt.fonts || opt.fontStore;
18948
+ if (!isStore(fontStore)) throw new TypeError("exportHtml(model, { fonts }): fonts must be a FontStore (defaultFontStore() or new FontStore(loader)), got " + (fontStore === void 0 ? "nothing" : typeof fontStore));
18949
+ }
18893
18950
  return withDeadline(
18894
18951
  htmlOf(model, fontStore, opt),
18895
18952
  /** @type {any} */
18896
18953
  opt.timeoutMs
18897
18954
  );
18898
18955
  }
18956
+ var warnedLegacy = false;
18899
18957
  async function htmlOf(model, fontStore, opt) {
18900
18958
  const used = /* @__PURE__ */ new Map();
18901
18959
  const layout = /* @__PURE__ */ new Set();
@@ -19643,9 +19701,22 @@ async function xlsxOf(model, opt) {
19643
19701
  }
19644
19702
 
19645
19703
  // src/exporters/docx.js
19646
- import { zipSync as zipSync3, strToU8 as strToU83 } from "fflate";
19704
+ import { Zip, ZipDeflate, strToU8 as strToU83 } from "fflate";
19647
19705
  var TW = 20;
19648
19706
  var EMU = 12700;
19707
+ var XML_CHUNK = 4 * 1024 * 1024;
19708
+ function slices(s, max) {
19709
+ const out = [];
19710
+ let i = 0;
19711
+ while (s.length - i > max) {
19712
+ const j = s.indexOf(">", i + max);
19713
+ if (j < 0) break;
19714
+ out.push(s.slice(i, j + 1));
19715
+ i = j + 1;
19716
+ }
19717
+ out.push(s.slice(i));
19718
+ return out;
19719
+ }
19649
19720
  var esc3 = (s) => String(s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
19650
19721
  var hex5 = (c) => {
19651
19722
  const m = /^#?([0-9a-f]{6})$/i.exec(String(c || "").trim());
@@ -19789,9 +19860,9 @@ async function docxOf(model, opt) {
19789
19860
  const margin = 18;
19790
19861
  const media = [];
19791
19862
  let docPr = 0;
19792
- const addMedia = (bytes, ext) => {
19863
+ const addMedia = (bytes2, ext) => {
19793
19864
  const rid = `rIdm${media.length + 1}`;
19794
- media.push({ name: `image${media.length + 1}.${ext}`, bytes, rid });
19865
+ media.push({ name: `image${media.length + 1}.${ext}`, bytes: bytes2, rid });
19795
19866
  return rid;
19796
19867
  };
19797
19868
  const pictureRun = (pic, alt) => {
@@ -19855,7 +19926,7 @@ async function docxOf(model, opt) {
19855
19926
  }
19856
19927
  for (const f4 of figs) if (!f4.used) blocks.push({ kind: "fig", y: f4.box.y, x: f4.box.x, fig: f4 });
19857
19928
  blocks.sort((a, b) => a.y - b.y || a.x - b.x);
19858
- let xml3 = "";
19929
+ let xml2 = "";
19859
19930
  for (let bi = 0; bi < blocks.length; bi++) {
19860
19931
  const b = blocks[bi];
19861
19932
  if (b.kind === "fig") {
@@ -19870,7 +19941,7 @@ async function docxOf(model, opt) {
19870
19941
  right = pic.x + pic.w;
19871
19942
  }
19872
19943
  const first = row[0];
19873
- xml3 += `<w:p><w:pPr><w:spacing w:before="0" w:after="80"/>${Math.abs(first.x - margin) > 0.5 ? `<w:ind w:left="${Math.round(Math.max(-margin, first.x - margin) * TW)}"/>` : ""}</w:pPr>${runs}</w:p>`;
19944
+ xml2 += `<w:p><w:pPr><w:spacing w:before="0" w:after="80"/>${Math.abs(first.x - margin) > 0.5 ? `<w:ind w:left="${Math.round(Math.max(-margin, first.x - margin) * TW)}"/>` : ""}</w:pPr>${runs}</w:p>`;
19874
19945
  } else if (b.kind === "table") {
19875
19946
  const pics = /* @__PURE__ */ new Map();
19876
19947
  for (const [k, v] of visuals.get(b.key) || []) {
@@ -19878,19 +19949,19 @@ async function docxOf(model, opt) {
19878
19949
  const svg = figureSvg({ items: v.items, box: v.box }, opt.fontStore);
19879
19950
  pics.set(k, pictureRun({ svg, png: await rasterize(svg, v.box.w, v.box.h, picOpt), w: v.box.w, h: v.box.h }, "Chart in a table cell"));
19880
19951
  }
19881
- xml3 += table(b.cells, b.x - margin, pics);
19882
- } else if (b.kind === "rich") xml3 += richPara(b.items, b.x - margin);
19952
+ xml2 += table(b.cells, b.x - margin, pics);
19953
+ } else if (b.kind === "rich") xml2 += richPara(b.items, b.x - margin);
19883
19954
  else {
19884
19955
  const row = [b];
19885
19956
  const top = (t) => t.it.clip?.y ?? t.y - t.it.size;
19886
19957
  while (blocks[bi + 1]?.kind === "text" && Math.abs(top(blocks[bi + 1]) - top(b)) < 3 && blocks[bi + 1].it.clip && b.it.clip) row.push(blocks[++bi]);
19887
19958
  row.sort((p, q2) => p.it.clip.x - q2.it.clip.x);
19888
19959
  const apart = row.every((r, k) => k === 0 || r.it.clip.x >= row[k - 1].it.clip.x + row[k - 1].it.clip.w - 0.5);
19889
- if (row.length > 1 && apart) xml3 += layoutRow(row, margin);
19890
- else for (const r of row) xml3 += para(r.it, (r.it.clip?.x ?? r.x) - margin, r.decor);
19960
+ if (row.length > 1 && apart) xml2 += layoutRow(row, margin);
19961
+ else for (const r of row) xml2 += para(r.it, (r.it.clip?.x ?? r.x) - margin, r.decor);
19891
19962
  }
19892
19963
  }
19893
- body.push(xml3);
19964
+ body.push(xml2);
19894
19965
  }
19895
19966
  const M = margin * TW, V = 36 * TW;
19896
19967
  const sectPr = (pg) => {
@@ -19898,17 +19969,39 @@ async function docxOf(model, opt) {
19898
19969
  return `<w:sectPr><w:pgSz w:w="${W2}" w:h="${H}"${W2 > H ? ' w:orient="landscape"' : ""}/><w:pgMar w:top="${V}" w:right="${M}" w:bottom="${V}" w:left="${M}" w:header="0" w:footer="0" w:gutter="0"/></w:sectPr>`;
19899
19970
  };
19900
19971
  const sizeOf = (pg) => `${pg.width ?? model.width}x${pg.height ?? model.height}`;
19901
- let xml2 = "";
19972
+ const zipOut = [];
19973
+ const zip = new Zip((err, data) => {
19974
+ if (err) throw err;
19975
+ zipOut.push(data);
19976
+ });
19977
+ const put = (name, bytes2) => {
19978
+ const e2 = new ZipDeflate(name, { level: 6 });
19979
+ zip.add(e2);
19980
+ e2.push(bytes2, true);
19981
+ };
19982
+ const parts = [];
19983
+ const max = opt.xmlChunk || XML_CHUNK;
19984
+ let buf = "";
19985
+ const write = (str) => {
19986
+ for (const p of slices(str, max)) {
19987
+ if (buf.length + p.length > max) {
19988
+ parts.push(buf);
19989
+ buf = "";
19990
+ }
19991
+ buf += p;
19992
+ }
19993
+ };
19994
+ write(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
19995
+ <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><w:body>`);
19902
19996
  model.pages.forEach((pg, i) => {
19903
- xml2 += body[i];
19997
+ write(body[i]);
19904
19998
  const next = model.pages[i + 1];
19905
19999
  if (!next) return;
19906
- xml2 += sizeOf(next) !== sizeOf(pg) ? `<w:p><w:pPr>${sectPr(pg)}</w:pPr></w:p>` : '<w:p><w:pPr><w:pageBreakBefore/><w:spacing w:before="0" w:after="0" w:line="20" w:lineRule="exact"/><w:rPr><w:sz w:val="2"/></w:rPr></w:pPr></w:p>';
20000
+ write(sizeOf(next) !== sizeOf(pg) ? `<w:p><w:pPr>${sectPr(pg)}</w:pPr></w:p>` : '<w:p><w:pPr><w:pageBreakBefore/><w:spacing w:before="0" w:after="0" w:line="20" w:lineRule="exact"/><w:rPr><w:sz w:val="2"/></w:rPr></w:pPr></w:p>');
19907
20001
  });
19908
20002
  const last = model.pages[model.pages.length - 1] || {};
19909
- const document2 = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
19910
- <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><w:body>${xml2}${sectPr(
19911
- last)}</w:body></w:document>`;
20003
+ write(`${sectPr(last)}</w:body></w:document>`);
20004
+ parts.push(buf);
19912
20005
  const lang = `<w:lang w:val="${esc3(opt.lang || model.locale || "en-US")}"/>`;
19913
20006
  const headings = [28, 24, 22, 20, 18, 18].map((sz, i) => `<w:style w:type="paragraph" w:styleId="Heading${i + 1}"><w:name w:val="heading ${i + 1}"/><w:basedOn w:val="Normal"/><w:next w:val="Normal"/><w:qFormat/><w:pPr><w:keepNext/><w:outlineLvl w:val="${i}"/></w:pPr><w:rPr><w:b/><w:sz w:val="${sz}"/></w:rPr></w:style>`).join("");
19914
20007
  const styles = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
@@ -19918,24 +20011,32 @@ name w:val="Normal"/></w:style>${headings}</w:styles>`;
19918
20011
  const core = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
19919
20012
  <cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:title>${esc3(opt.title || model.name || "Report")}</dc:title>${opt.author ? `<dc:creator>${esc3(opt.author)}</dc:creator>` : ""}<dcterms:created xsi:type=\
19920
20013
  "dcterms:W3CDTF">${now}</dcterms:created></cp:coreProperties>`;
19921
- const files = {
19922
- "[Content_Types].xml": strToU83(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
20014
+ put("[Content_Types].xml", strToU83(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
19923
20015
  <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Default Extension="png" ContentType="image/png"/><Default Extension="jpeg" ContentType="image/jpeg"/><Default Extension="svg" ContentType="image/svg+xml"/><Override Part\
19924
- Name="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/></Types>`),
19925
- "_rels/.rels": strToU83(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
19926
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/></Relationships>`),
19927
- "word/_rels/document.xml.rels": strToU83(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
19928
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>${media.map((m) => `<Relationship Id="${m.rid}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/${m.name}"/>`).join("")}</Relationships>`),
19929
- "word/document.xml": strToU83(document2),
19930
- "word/styles.xml": strToU83(styles),
19931
- "docProps/core.xml": strToU83(core)
19932
- };
19933
- for (const m of media) files[`word/media/${m.name}`] = m.bytes;
19934
- return zipSync3(files, { level: 6 });
20016
+ Name="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/></Types>`));
20017
+ put("_rels/.rels", strToU83(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
20018
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/></Relationships>`));
20019
+ put("word/_rels/document.xml.rels", strToU83(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
20020
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>${media.map((m) => `<Relationship Id="${m.rid}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image" Target="media/${m.name}"/>`).join("")}</Relationships>`));
20021
+ const doc = new ZipDeflate("word/document.xml", { level: 6 });
20022
+ zip.add(doc);
20023
+ for (const p of parts) doc.push(strToU83(p), false);
20024
+ doc.push(new Uint8Array(0), true);
20025
+ put("word/styles.xml", strToU83(styles));
20026
+ put("docProps/core.xml", strToU83(core));
20027
+ for (const m of media) put(`word/media/${m.name}`, m.bytes);
20028
+ zip.end();
20029
+ const total = zipOut.reduce((n5, c) => n5 + c.length, 0), bytes = new Uint8Array(total);
20030
+ let at = 0;
20031
+ for (const c of zipOut) {
20032
+ bytes.set(c, at);
20033
+ at += c.length;
20034
+ }
20035
+ return bytes;
19935
20036
  }
19936
20037
 
19937
20038
  // src/exporters/pptx.js
19938
- import { zipSync as zipSync4, strToU8 as strToU84 } from "fflate";
20039
+ import { zipSync as zipSync3, strToU8 as strToU84 } from "fflate";
19939
20040
  var EMU2 = 12700;
19940
20041
  var e = (v) => Math.round(v * EMU2);
19941
20042
  var esc4 = (s) => String(s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f￾￿]/g, "");
@@ -20118,7 +20219,7 @@ rops/core.xml"/></Relationships>`);
20118
20219
  ="svg" ContentType="image/svg+xml"/><Override PartName="/ppt/presentation.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"/><Override PartName="/ppt/slideMasters/slideMaster1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"/><Override PartName="/ppt/slideLayouts/slideLayout1.xml" ContentType="applic\
20119
20220
  ation/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/><Override PartName="/ppt/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/>${slides.map((n5) => `<Override PartName="/ppt/slides/slide${n5}.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>`).join("")}<Override PartName="/docProps/core.xml" Conte\
20120
20221
  ntType="application/vnd.openxmlformats-package.core-properties+xml"/></Types>`);
20121
- return zipSync4(files, { level: 6 });
20222
+ return zipSync3(files, { level: 6 });
20122
20223
  }
20123
20224
  var THEME = `${XML2}<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="ReportWright"><a:themeElements><a:clrScheme name="ReportWright"><a:dk1><a:srgbClr val="000000"/></a:dk1><a:lt1><a:srgbClr val="FFFFFF"/></a:lt1><a:dk2><a:srgbClr val="1F2328"/></a:dk2><a:lt2><a:srgbClr val="E7E6E6"/></a:lt2><a:accent1><a:srgbClr val="2563EB"/></a:accent1><a:accent2><a:srgbClr val="F5\
20124
20225
  9E0B"/></a:accent2><a:accent3><a:srgbClr val="16A34A"/></a:accent3><a:accent4><a:srgbClr val="DC2626"/></a:accent4><a:accent5><a:srgbClr val="7C3AED"/></a:accent5><a:accent6><a:srgbClr val="0891B2"/></a:accent6><a:hlink><a:srgbClr val="0563C1"/></a:hlink><a:folHlink><a:srgbClr val="954F72"/></a:folHlink></a:clrScheme><a:fontScheme name="ReportWright"><a:majorFont><a:latin typeface="Inter"/><a:ea t\
@@ -20573,7 +20674,7 @@ async function planStream(def0, opts) {
20573
20674
  const f4 = fold && fold(row, ci);
20574
20675
  v2 = f4 ? f4.v : evalValue(cell.value ?? "", ctx);
20575
20676
  } catch (e2) {
20576
- warn(`${item.name || "Table"} cell: ${e2.message}`);
20677
+ warn(`${item.name || item.type} cell: ${e2.message}`);
20577
20678
  v2 = "#Error";
20578
20679
  }
20579
20680
  const plain2 = textOf(v2, st, ctx, lc);
@@ -20590,7 +20691,8 @@ async function planStream(def0, opts) {
20590
20691
  return;
20591
20692
  }
20592
20693
  try {
20593
- if (src.type === "json") yield* inBatches(listAt(typeof src.data === "string" ? JSON.parse(src.data) : src.data, ds.path));
20694
+ if (src.type === "json" && typeof src.data === "string") yield* jsonRows(src.data, ds.path, { maxElementBytes: opts.maxJsonRowBytes ?? 8 * 1048576, maxWholeBytes: Infinity });
20695
+ else if (src.type === "json") yield* inBatches(listAt(src.data, ds.path));
20594
20696
  else if (src.type === "csv" && src.data) yield* inBatches(parseCsv(src.data, src));
20595
20697
  else if (src.type === "csv") {
20596
20698
  const res = await sourceResponse(src, { params, globals: {}, dataSets: {}, fields: null, functions: functionTable(def) }, opts);
@@ -20611,6 +20713,21 @@ async function planStream(def0, opts) {
20611
20713
  }
20612
20714
  }
20613
20715
  const plainOf = (fields) => fields.filter((fd) => !fd.expr);
20716
+ let seen = (
20717
+ /** @type {any[]|null} */
20718
+ null
20719
+ );
20720
+ const fieldList = async () => {
20721
+ if (ds.fields?.length) return ds.fields;
20722
+ const it = typed();
20723
+ try {
20724
+ await it.next();
20725
+ } finally {
20726
+ await it.return(void 0);
20727
+ stats.rows = 0;
20728
+ }
20729
+ return seen || [];
20730
+ };
20614
20731
  async function* typed() {
20615
20732
  let fields = ds.fields && ds.fields.length ? ds.fields : null;
20616
20733
  let head = fields ? null : [];
@@ -20656,7 +20773,7 @@ async function planStream(def0, opts) {
20656
20773
  return out;
20657
20774
  };
20658
20775
  const ready = (fs) => {
20659
- fields = fs;
20776
+ fields = seen = fs;
20660
20777
  plain2 = plainOf(fs);
20661
20778
  calc = fs.filter((fd) => fd.expr);
20662
20779
  fopts = new Map(fs.map((fd) => [fd, optFor(fd)]));
@@ -20684,23 +20801,44 @@ async function planStream(def0, opts) {
20684
20801
  const tSort = item.sort || [], dSort = ds.sort || [];
20685
20802
  const sorted = tSort.length || dSort.length;
20686
20803
  const sorter = opts.sorter || memorySorter;
20687
- async function* inOrder() {
20688
- if (!sorted) {
20804
+ const checked = (cmp) => {
20805
+ let prev = (
20806
+ /** @type {any} */
20807
+ null
20808
+ ), n5 = 0;
20809
+ return (x) => {
20810
+ n5++;
20811
+ if (prev && cmp(prev, x) > 0) throw Object.assign(new Error(`The rows are not in the report's order (row ${n5} comes before the one above it, by the table's sort or its groups), so they cannot be read as presorted. Sort them at the source, or leave presorted off.`), { status: 400 });
20812
+ prev = x;
20813
+ };
20814
+ };
20815
+ const kc = { ...tctx }, dkc = { ...setCtx };
20816
+ const keyed = (r, s) => {
20817
+ kc.fields = r;
20818
+ dkc.fields = r;
20819
+ return { t: tSort.length ? sortKeys(tSort, kc) : null, d: dSort.length ? sortKeys(dSort, dkc) : null, s, r };
20820
+ };
20821
+ const keyCmp = (a, b) => tSort.length && compareKeys(a.t, b.t, tSort, tctx) || dSort.length && compareKeys(a.d, b.d, dSort, setCtx);
20822
+ async function* inOrder(grouped = false) {
20823
+ if (!sorted || grouped && opts.presorted) {
20689
20824
  for await (const b of typed()) for (const r of b) yield r;
20690
20825
  return;
20691
20826
  }
20692
- const kc = { ...tctx }, dkc = { ...setCtx };
20693
- const s = sorter((a, b) => tSort.length && compareKeys(a.t, b.t, tSort, tctx) || dSort.length && compareKeys(a.d, b.d, dSort, setCtx) || a.s - b.s);
20827
+ const cmp = (a, b) => keyCmp(a, b) || a.s - b.s;
20828
+ const check = opts.presorted ? checked(cmp) : null;
20829
+ const s = check ? null : sorter(cmp);
20694
20830
  try {
20695
20831
  let seq = 0;
20696
20832
  for await (const b of typed()) for (const r of b) {
20697
- kc.fields = r;
20698
- dkc.fields = r;
20699
- await s.push({ t: tSort.length ? sortKeys(tSort, kc) : null, d: dSort.length ? sortKeys(dSort, dkc) : null, s: seq++, r });
20833
+ const x = keyed(r, seq++);
20834
+ if (check) {
20835
+ check(x);
20836
+ yield r;
20837
+ } else await s.push(x);
20700
20838
  }
20701
- for await (const x of s.drain()) yield x.r;
20839
+ if (s) for await (const x of s.drain()) yield x.r;
20702
20840
  } finally {
20703
- await s.close();
20841
+ await s?.close();
20704
20842
  }
20705
20843
  }
20706
20844
  async function* displayOrder() {
@@ -20711,7 +20849,7 @@ async function planStream(def0, opts) {
20711
20849
  const gc = { ...tctx }, fc = { ...tctx };
20712
20850
  const paths = groups.map(() => /* @__PURE__ */ new Map());
20713
20851
  let ord = 0, keyText = 0;
20714
- const s = sorter((a, b) => {
20852
+ const byGroup = (a, b) => {
20715
20853
  for (let l = 0; l < groups.length; l++) {
20716
20854
  const x = a.g[l], y = b.g[l];
20717
20855
  if (x[0] === y[0]) continue;
@@ -20722,11 +20860,14 @@ async function planStream(def0, opts) {
20722
20860
  }
20723
20861
  return x[0] - y[0];
20724
20862
  }
20725
- return a.s - b.s;
20726
- });
20863
+ return 0;
20864
+ };
20865
+ const cmp = (a, b) => byGroup(a, b) || a.s - b.s;
20866
+ const check = opts.presorted ? checked((a, b) => byGroup(a, b) || (sorted ? keyCmp(a.k, b.k) : 0)) : null;
20867
+ const s = check ? null : sorter(cmp);
20727
20868
  try {
20728
20869
  let seq = 0;
20729
- for await (const r of inOrder()) {
20870
+ for await (const r of inOrder(true)) {
20730
20871
  gc.fields = r;
20731
20872
  let path = "";
20732
20873
  const g = [];
@@ -20735,7 +20876,7 @@ async function planStream(def0, opts) {
20735
20876
  try {
20736
20877
  key = evalValue(groups[l].expr, gc);
20737
20878
  } catch (e2) {
20738
- warn(`${item.name} group: ${e2.message}`);
20879
+ warn(`${item.name || item.type} group: ${e2.message}`);
20739
20880
  key = "#Error";
20740
20881
  }
20741
20882
  path += `\0${groupKeyText(key, tctx)}`;
@@ -20756,12 +20897,16 @@ async function planStream(def0, opts) {
20756
20897
  foldRow(sc, fc);
20757
20898
  }
20758
20899
  }
20759
- await s.push({ g, s: seq++, r });
20900
+ const x = { g, s: seq++, r };
20901
+ if (check) {
20902
+ check({ g, k: sorted ? keyed(r, 0) : null });
20903
+ yield x;
20904
+ } else await s.push(x);
20760
20905
  }
20761
20906
  for (const m of paths) m.clear();
20762
- for await (const x of s.drain()) yield x;
20907
+ if (s) for await (const x of s.drain()) yield x;
20763
20908
  } finally {
20764
- await s.close();
20909
+ await s?.close();
20765
20910
  }
20766
20911
  }
20767
20912
  const foldCells = (rows2) => {
@@ -20812,7 +20957,7 @@ async function planStream(def0, opts) {
20812
20957
  const L = groups.length;
20813
20958
  const tableScope = openScope(L);
20814
20959
  folds.table = tableScope;
20815
- folds.groups = bands && L ? groups.map(() => /* @__PURE__ */ new Map()) : null;
20960
+ folds.groups = bands && L && !opts.presorted ? groups.map(() => /* @__PURE__ */ new Map()) : null;
20816
20961
  const scopes = new Array(L).fill(null);
20817
20962
  const dctx = { ...tctx, rowNumber: 0 };
20818
20963
  let headerDone = false, rowNo = 0, first = null, last = null;
@@ -20867,7 +21012,10 @@ async function planStream(def0, opts) {
20867
21012
  if ((rowNo & 255) === 0) overTime();
20868
21013
  dctx.fields = r;
20869
21014
  dctx.rowNumber = rowNo;
20870
- if (bands && !L) foldRow(tableScope, dctx);
21015
+ if (bands && !folds.groups) {
21016
+ foldRow(tableScope, dctx);
21017
+ for (const s of scopes) foldRow(s.folds, dctx);
21018
+ }
20871
21019
  for (const dr of item.detail || []) {
20872
21020
  const x = regionRow(dr, dctx, "detail", L);
20873
21021
  if (x) yield x;
@@ -20884,7 +21032,7 @@ async function planStream(def0, opts) {
20884
21032
  }
20885
21033
  overTime();
20886
21034
  }
20887
- return { name: item.name, columns: cols.map((c) => c.width), title: def.name || "", timeZone: timeZone || null, locale: def.locale || null, currency: def.currency || null, warnings, rows, records: inOrder, grouped: displayOrder, stats };
21035
+ return { name: item.name, columns: cols.map((c) => c.width), title: def.name || "", timeZone: timeZone || null, locale: def.locale || null, currency: def.currency || null, warnings, rows, records: inOrder, grouped: displayOrder, fieldList, stats };
20888
21036
  }
20889
21037
  function listAt(raw, path) {
20890
21038
  let { rows } = jsonPathRows(raw, path || "$");
@@ -20907,8 +21055,7 @@ async function planPaged(def0, opts = {}) {
20907
21055
  const plan2 = await planStream(def, { ...opts, format: "xlsx" });
20908
21056
  if (plan2.why !== void 0) return no(plan2.why);
20909
21057
  if ((def.dataSets || []).length !== 1) return no("more than one data set");
20910
- const ds = def.dataSets[0];
20911
- if (!ds.fields?.length) return no("undeclared fields");
21058
+ let ds = def.dataSets[0];
20912
21059
  if (opts.firstPages || opts.dataOnly) return no("first pages or table data");
20913
21060
  const sec = def.sections || {};
20914
21061
  const body = Array.isArray(sec.body) ? sec.body[0] : sec.body;
@@ -20966,6 +21113,12 @@ async function planPaged(def0, opts = {}) {
20966
21113
  }) })) })) };
20967
21114
  const gfields = gfolds.flat().map((f4) => ({ name: f4.name }));
20968
21115
  const size = Math.max(50, Number(opts.window) || WINDOW);
21116
+ if (!ds.fields?.length) {
21117
+ const fields = await /** @type {any} */
21118
+ plan2.fieldList();
21119
+ if (!fields.length) return no("undeclared fields (no rows to detect them from)");
21120
+ ds = { ...ds, fields };
21121
+ }
20969
21122
  const strip = (fields) => fields.map(({ expr, path, ...f4 }) => f4);
20970
21123
  const windowDef = (first, last, done) => {
20971
21124
  const t = { ...gtable, sort: void 0, filters: void 0 };
@@ -21151,7 +21304,8 @@ async function planPaged(def0, opts = {}) {
21151
21304
  for (let k = off + per + 1; k < bounds.length && end < 0; k++) if (bounds[k] >= 0) end = k;
21152
21305
  let e2 = -1;
21153
21306
  for (let k = end + 1; end >= 0 && k < bounds.length && e2 < 0; k++) if (bounds[k] >= 0 && bounds[k] - bounds[end] >= reach) e2 = k;
21154
- await read(end < 0 || e2 < 0 ? Infinity : bounds[e2] - base);
21307
+ if (e2 < 0) end = -1;
21308
+ await read(end < 0 ? Infinity : bounds[e2] - base);
21155
21309
  if (!ended) {
21156
21310
  const r = await next();
21157
21311
  if (r.done) {
@@ -21294,7 +21448,11 @@ async function planPaged(def0, opts = {}) {
21294
21448
  }
21295
21449
 
21296
21450
  // src/exporters/pdfstreamtags.js
21297
- function createStreamTagger(w) {
21451
+ function createStreamTagger(w, { maxElements = Infinity } = {}) {
21452
+ let count = 0;
21453
+ const made = () => {
21454
+ if (++count > maxElements) throw Object.assign(new Error(`The tagged PDF has more than ${maxElements.toLocaleString("en-US")} structure elements (tagged.maxElements). Filter the data, or export it untagged.`), { status: 413 });
21455
+ };
21298
21456
  const rootRef = w.reserve(), docRef = w.reserve();
21299
21457
  const docKids = [];
21300
21458
  let table2 = (
@@ -21339,6 +21497,7 @@ function createStreamTagger(w) {
21339
21497
  );
21340
21498
  let links = false, win = 0;
21341
21499
  const el = (S3, parent, attrs2) => {
21500
+ made();
21342
21501
  const e2 = { ref: w.reserve(), S: S3, parent, mcid: (
21343
21502
  /** @type {number[]} */
21344
21503
  []
@@ -21357,6 +21516,10 @@ function createStreamTagger(w) {
21357
21516
  `;
21358
21517
  };
21359
21518
  return {
21519
+ /** structure elements so far */
21520
+ get count() {
21521
+ return count;
21522
+ },
21360
21523
  /** a new page (window: the paged window it came from; row ids are its own) @param {number} window */
21361
21524
  page(window) {
21362
21525
  mcids = [];
@@ -21390,13 +21553,14 @@ function createStreamTagger(w) {
21390
21553
  const rk = `${win}:${c.row}`;
21391
21554
  let r = rows.get(rk);
21392
21555
  if (!r) {
21556
+ made();
21393
21557
  r = { ref: w.reserve(), kind: c.kind, cells: /* @__PURE__ */ new Map() };
21394
21558
  rows.set(rk, r);
21395
21559
  addRow(r.ref);
21396
21560
  }
21397
21561
  let cell = r.cells.get(c.col);
21398
21562
  if (!cell) {
21399
- const attrs2 = { O: "/Table", ...c.kind === "header" ? { Scope: "/Column" } : {}, ...c.span > 1 ? { ColSpan: c.span } : {} };
21563
+ const attrs2 = c.kind === "header" || c.span > 1 ? { O: "/Table", ...c.kind === "header" ? { Scope: "/Column" } : {}, ...c.span > 1 ? { ColSpan: c.span } : {} } : null;
21400
21564
  cell = el(c.kind === "header" ? "TH" : "TD", r.ref, attrs2);
21401
21565
  r.cells.set(c.col, cell);
21402
21566
  }
@@ -21428,7 +21592,7 @@ function createStreamTagger(w) {
21428
21592
  table2.cols; ) {
21429
21593
  let cell = r.cells.get(col3);
21430
21594
  if (!cell) {
21431
- cell = el(r.kind === "header" ? "TH" : "TD", r.ref, r.kind === "header" ? { O: "/Table", Scope: "/Column" } : { O: "/Table" });
21595
+ cell = el(r.kind === "header" ? "TH" : "TD", r.ref, r.kind === "header" ? { O: "/Table", Scope: "/Column" } : null);
21432
21596
  }
21433
21597
  kids.push(cell.ref);
21434
21598
  col3 += Math.max(1, cell.attrs?.ColSpan || 1);
@@ -21437,7 +21601,7 @@ function createStreamTagger(w) {
21437
21601
  void col3;
21438
21602
  kids.push(cell.ref);
21439
21603
  }
21440
- await w.objectAt(r.ref, `<< /Type /StructElem /S /TR /P ${/** @type {any} */
21604
+ await w.objectAt(r.ref, `<< /S /TR /P ${/** @type {any} */
21441
21605
  table2.ref} 0 R /K [${kids.map((k) => `${k} 0 R`).join(" ")}] >>`);
21442
21606
  }
21443
21607
  if (rows.size && [...rows.values()].some((r) => r.kind === "header")) headerDone = true;
@@ -21445,7 +21609,7 @@ function createStreamTagger(w) {
21445
21609
  const K = [...e2.mcid.map(String), ...e2.kids].join(" ");
21446
21610
  const A = e2.attrs ? ` /A << ${Object.entries(e2.attrs).map(([k, v]) => `/${k} ${v}`).join(" ")} >>` : "";
21447
21611
  const P = e2.parent === docRef ? docRef : e2.parent;
21448
- await w.objectAt(e2.ref, `<< /Type /StructElem /S /${e2.S} /P ${P} 0 R${e2.mcid.length || e2.S === "Link" ? ` /Pg ${pageRef} 0 R` : ""} /K [${K}]${A} >>`);
21612
+ await w.objectAt(e2.ref, `<< /S /${e2.S} /P ${P} 0 R${e2.mcid.length || e2.S === "Link" ? ` /Pg ${pageRef} 0 R` : ""} /K [${K}]${A} >>`);
21449
21613
  }
21450
21614
  let extra = "";
21451
21615
  if (mcids.length) {
@@ -21498,6 +21662,7 @@ var fontkit3 = (
21498
21662
  var CHUNK = 64 * 1024;
21499
21663
  var LEAF = 64;
21500
21664
  var OBJSTM = 100;
21665
+ var TAGGED_LARGE = 1e6;
21501
21666
  var IN_FLIGHT = 8;
21502
21667
  var hex42 = (id) => id.toString(16).padStart(4, "0");
21503
21668
  var num5 = (v) => String(Math.round(v * 1e3) / 1e3);
@@ -21506,12 +21671,12 @@ var esc5 = (b) => b === 40 || b === 41 || b === 92 ? "\\" + String.fromCharCode(
21506
21671
  function createPdfStream(sink, opt) {
21507
21672
  const { fontStore } = opt;
21508
21673
  let pos = 0, nextNum = 1;
21509
- let kind = new Uint8Array(4096), loc = new Uint32Array(4096), idx = new Uint8Array(4096);
21674
+ let kind = new Uint8Array(4096), loc = new Uint32Array(4096), idx = new Uint16Array(4096);
21510
21675
  const place = (n5, k, l, i = 0) => {
21511
21676
  if (n5 >= kind.length) {
21512
21677
  let L = kind.length;
21513
21678
  while (L <= n5) L *= 2;
21514
- const k2 = new Uint8Array(L), l2 = new Uint32Array(L), i2 = new Uint8Array(L);
21679
+ const k2 = new Uint8Array(L), l2 = new Uint32Array(L), i2 = new Uint16Array(L);
21515
21680
  k2.set(kind);
21516
21681
  l2.set(loc);
21517
21682
  i2.set(idx);
@@ -21790,7 +21955,7 @@ endobj
21790
21955
  const kids = level.slice(k, k + LEAF);
21791
21956
  up.push({ ref: reserve(), kids: kids.map((x) => x.ref), count: kids.reduce((s, x) => s + x.count, 0), below: kids });
21792
21957
  }
21793
- for (const node2 of up) for (const kid of node2.below) kid.parent = node2.ref;
21958
+ for (const node3 of up) for (const kid of node3.below) kid.parent = node3.ref;
21794
21959
  await writeNodes(level);
21795
21960
  level = /** @type {any} */
21796
21961
  up;
@@ -21813,21 +21978,32 @@ endobj
21813
21978
  const zs = new Zlib({ level: 6 }, (d) => {
21814
21979
  out.push(d);
21815
21980
  });
21981
+ const prev = new Uint8Array(7), row = new Uint8Array(7);
21816
21982
  for (let from = 0; from < size2; from += 65536) {
21817
- const to = Math.min(size2, from + 65536), rows = new Uint8Array((to - from) * 7);
21983
+ const to = Math.min(size2, from + 65536), rows = new Uint8Array((to - from) * 8);
21818
21984
  for (let n5 = from; n5 < to; n5++) {
21819
- const at = (n5 - from) * 7, l = loc[n5];
21985
+ row.fill(0);
21986
+ const l = loc[n5];
21820
21987
  if (n5 === 0) {
21821
- rows[at + 5] = 255;
21822
- rows[at + 6] = 255;
21823
- continue;
21988
+ row[5] = 255;
21989
+ row[6] = 255;
21990
+ } else {
21991
+ row[0] = kind[n5];
21992
+ row[1] = l >>> 24 & 255;
21993
+ row[2] = l >>> 16 & 255;
21994
+ row[3] = l >>> 8 & 255;
21995
+ row[4] = l & 255;
21996
+ if (kind[n5] === 2) {
21997
+ row[5] = idx[n5] >> 8;
21998
+ row[6] = idx[n5] & 255;
21999
+ }
22000
+ }
22001
+ const at = (n5 - from) * 8;
22002
+ rows[at] = 2;
22003
+ for (let b = 0; b < 7; b++) {
22004
+ rows[at + 1 + b] = row[b] - prev[b] & 255;
22005
+ prev[b] = row[b];
21824
22006
  }
21825
- rows[at] = kind[n5];
21826
- rows[at + 1] = l >>> 24 & 255;
21827
- rows[at + 2] = l >>> 16 & 255;
21828
- rows[at + 3] = l >>> 8 & 255;
21829
- rows[at + 4] = l & 255;
21830
- if (kind[n5] === 2) rows[at + 6] = idx[n5];
21831
22007
  }
21832
22008
  zs.push(rows, to === size2);
21833
22009
  }
@@ -21841,7 +22017,7 @@ endobj
21841
22017
  }
21842
22018
  const id = opt.id || [...globalThis.crypto.getRandomValues(new Uint8Array(16))].map((b) => b.toString(16).padStart(2, "0")).join("");
21843
22019
  await put(`${xn} 0 obj
21844
- << /Type /XRef /Size ${size2} /W [1 4 2] /Root ${catalog} 0 R /Info ${info} 0 R /ID [<${id}> <${id}>] /Filter /FlateDecode /Length ${z.length} >>
22020
+ << /Type /XRef /Size ${size2} /W [1 4 2] /DecodeParms << /Columns 7 /Predictor 12 >> /Root ${catalog} 0 R /Info ${info} 0 R /ID [<${id}> <${id}>] /Filter /FlateDecode /Length ${z.length} >>
21845
22021
  stream
21846
22022
  `);
21847
22023
  await put(z);
@@ -21914,9 +22090,9 @@ ${xref}
21914
22090
  if (!(e2.page >= 1 && e2.page <= pages)) continue;
21915
22091
  const level = Math.max(0, Math.min(9, Number(e2.level) || 0));
21916
22092
  while (stack2[stack2.length - 1].level >= level) stack2.pop();
21917
- const node2 = { ref: reserve(), level, kids: [], title: e2.title, dest: `[${pageRefs[e2.page - 1]} 0 R ${e2.top == null ? "/Fit" : `/XYZ null ${num5(e2.top)} null`}]` };
21918
- stack2[stack2.length - 1].kids.push(node2);
21919
- stack2.push(node2);
22093
+ const node3 = { ref: reserve(), level, kids: [], title: e2.title, dest: `[${pageRefs[e2.page - 1]} 0 R ${e2.top == null ? "/Fit" : `/XYZ null ${num5(e2.top)} null`}]` };
22094
+ stack2[stack2.length - 1].kids.push(node3);
22095
+ stack2.push(node3);
21920
22096
  }
21921
22097
  if (!root.kids.length) return 0;
21922
22098
  root.ref = reserve();
@@ -21999,7 +22175,8 @@ async function exportPdfStream(def, opts, sink) {
21999
22175
  sink.once("drain", ok)
22000
22176
  ));
22001
22177
  else await r3;
22002
- return { streamed: false, pages: model.pages.length, warnings: model.warnings, why: plan2.why };
22178
+ const warnings = [`The PDF was not streamed (${plan2.why}): the report was rendered whole, so its memory grows with its pages.`, ...model.warnings];
22179
+ return { streamed: false, pages: model.pages.length, warnings, why: plan2.why };
22003
22180
  }
22004
22181
  const r = await writePagedPdf(plan2, opts, sink);
22005
22182
  return { streamed: true, ...r };
@@ -22011,7 +22188,7 @@ async function writePagedPdf(plan2, opts, sink) {
22011
22188
  /** @type {any} */
22012
22189
  plan2
22013
22190
  );
22014
- const tags = opts.tagged ? createStreamTagger(w) : null;
22191
+ const tags = opts.tagged ? createStreamTagger(w, { maxElements: Number(opts.tagged.maxElements) || Infinity }) : null;
22015
22192
  const env = paintEnv(w, fontStore, { drillBase: opts.drillBase, tags });
22016
22193
  const { shaped } = env;
22017
22194
  const pool = !tags && Number(opts.parallel) > 1 ? paintPool(Number(opts.parallel), fontStore, opts, info) : null;
@@ -22057,6 +22234,7 @@ async function writePagedPdf(plan2, opts, sink) {
22057
22234
  catalog += ` /OutputIntents [${await w.object(`<< /Type /OutputIntent /S /GTS_PDFA1 /OutputConditionIdentifier (sRGB) /Info (sRGB IEC61966-2.1) /DestOutputProfile ${icc} 0 R >>`)} 0 R]`;
22058
22235
  }
22059
22236
  const res = await w.finish({ outline: outline2, catalog, info: { title: title2, author: opts.author, creationDate: when } });
22237
+ if (tags && tags.count > TAGGED_LARGE) info.warnings.push(`The tagged PDF has ${tags.count.toLocaleString("en-US")} structure elements (${res.pages.toLocaleString("en-US")} pages): readers open it, but tools that load every object of a file (qpdf, pikepdf) may run out of memory on it. tagged.maxElements caps it.`);
22060
22238
  return { pages: res.pages, warnings: info.warnings };
22061
22239
  }
22062
22240
  var lit = (v) => `(${String(v).replace(/[\\()]/g, "\\$&")})`;
@@ -22073,11 +22251,21 @@ function paintPage(pg, H, env) {
22073
22251
  const { tags } = env;
22074
22252
  if (tags) {
22075
22253
  c.tagged = true;
22254
+ c.artLines = true;
22076
22255
  tags.page(pg.win ?? 0);
22077
22256
  }
22078
22257
  for (const it of pg.items) {
22079
- const mark = tags && tags.open(it);
22080
- if (mark) {
22258
+ const mark = tags && it.t !== "line" && tags.open(it);
22259
+ const inText = mark && it.t === "text" && !it.rotate && it.lines.every((l) => !l.runs) && !(it.clip && !insideClip(it, env.vmetrics(it.font)));
22260
+ if (inText) {
22261
+ if (!c.bt) {
22262
+ c._s += "BT\n";
22263
+ c.bt = true;
22264
+ c.tx = 0;
22265
+ c.ty = 0;
22266
+ }
22267
+ c._s += mark;
22268
+ } else if (mark) {
22081
22269
  c.et();
22082
22270
  c.s += mark;
22083
22271
  }
@@ -22155,7 +22343,8 @@ function paintPage(pg, H, env) {
22155
22343
  throw new Error(`A ${it.t} item does not stream yet`);
22156
22344
  }
22157
22345
  if (it.rotate) c.Q();
22158
- if (mark) {
22346
+ if (inText) c._s += "EMC\n";
22347
+ else if (mark) {
22159
22348
  c.et();
22160
22349
  c.s += "EMC\n";
22161
22350
  }
@@ -22265,6 +22454,225 @@ function paintPool(size, fontStore, opts, info) {
22265
22454
  };
22266
22455
  }
22267
22456
 
22457
+ // src/exporters/spill.js
22458
+ var node2 = (m) => (
22459
+ /** @type {any} */
22460
+ globalThis.process.getBuiltinModule(m)
22461
+ );
22462
+ var canSpill = () => typeof /** @type {any} */
22463
+ globalThis.process?.getBuiltinModule === "function";
22464
+ var CELLS = 64;
22465
+ var spillShared = () => (
22466
+ /** @type {any} */
22467
+ globalThis.__pwSpill ||= { cells: new Int32Array(new SharedArrayBuffer(4 * CELLS)), cell: 0 }
22468
+ );
22469
+ var usedKB = () => {
22470
+ const { cells } = spillShared();
22471
+ let n5 = 0;
22472
+ for (let i = 0; i < CELLS; i++) n5 += Number(Atomics.load(cells, i));
22473
+ return n5;
22474
+ };
22475
+ var live = /* @__PURE__ */ new Set();
22476
+ var hooked = false;
22477
+ var sweep = () => {
22478
+ const fs = node2("node:fs");
22479
+ for (const d of live) {
22480
+ try {
22481
+ fs.rmSync(d, { recursive: true, force: true });
22482
+ } catch {
22483
+ }
22484
+ }
22485
+ live.clear();
22486
+ };
22487
+ function sweepStale(root, staleMs) {
22488
+ const fs = node2("node:fs"), path = node2("node:path");
22489
+ try {
22490
+ for (const n5 of fs.readdirSync(root)) {
22491
+ if (!n5.startsWith("pw-spill-")) continue;
22492
+ const d = path.join(root, n5);
22493
+ if (live.has(d)) continue;
22494
+ try {
22495
+ if (Date.now() - fs.statSync(d).mtimeMs > staleMs) fs.rmSync(d, { recursive: true, force: true });
22496
+ } catch {
22497
+ }
22498
+ }
22499
+ } catch {
22500
+ }
22501
+ }
22502
+ function spillSorter({ run = 2e4, runBytes = 24 * 1048576, frame: frame3 = 1e3, maxMB = 2048, totalMB = 8192, dir: root = node2("node:os").tmpdir(), staleMs = 18e4 } = {}) {
22503
+ const fs = node2("node:fs"), path = node2("node:path"), v8 = node2("node:v8"), { threadId } = node2("node:worker_threads");
22504
+ sweepStale(root, staleMs);
22505
+ return (cmp) => {
22506
+ let buf = [], dir = null, written = 0, held = 0, takenKB = 0;
22507
+ const runs = [];
22508
+ const flush = async () => {
22509
+ if (!buf.length) return;
22510
+ buf.sort(cmp);
22511
+ if (!dir) {
22512
+ dir = fs.mkdtempSync(path.join(root, `pw-spill-${process.pid}-${threadId}-`));
22513
+ live.add(dir);
22514
+ if (!hooked) {
22515
+ hooked = true;
22516
+ process.once("exit", sweep);
22517
+ }
22518
+ }
22519
+ const file = path.join(dir, `run-${runs.length}`);
22520
+ const fh = await fs.promises.open(file, "wx", 384);
22521
+ try {
22522
+ for (let i = 0; i < buf.length; i += frame3) {
22523
+ const body = v8.serialize(buf.slice(i, i + frame3));
22524
+ written += body.length + 4;
22525
+ if (written > maxMB * 1048576) throw Object.assign(new Error(`The sort needs more than ${maxMB} MB of temporary disk (PW_SPILL_MAX_MB). Filter the data, or sort it at the source.`), { status: 413 });
22526
+ const kb = Math.ceil(written / 1024) - takenKB;
22527
+ if (kb > 0) {
22528
+ const { cells, cell } = spillShared();
22529
+ Atomics.add(cells, cell, kb);
22530
+ takenKB += kb;
22531
+ if (usedKB() > totalMB * 1024) throw Object.assign(new Error(`The server's temporary disk for sorting is in use (PW_SPILL_TOTAL_MB, ${totalMB} MB). Try again shortly, or filter the data.`), { status: 503 });
22532
+ }
22533
+ const head = Buffer.alloc(4);
22534
+ head.writeUInt32LE(body.length);
22535
+ await fh.write(head);
22536
+ await fh.write(body);
22537
+ }
22538
+ } finally {
22539
+ await fh.close();
22540
+ }
22541
+ runs.push(file);
22542
+ buf = [];
22543
+ held = 0;
22544
+ };
22545
+ return {
22546
+ /** @param {any} r */
22547
+ async push(r) {
22548
+ buf.push(r);
22549
+ held += approx(r);
22550
+ if (buf.length >= run || held >= runBytes) await flush();
22551
+ },
22552
+ async *drain() {
22553
+ if (!runs.length) {
22554
+ const all = buf;
22555
+ buf = [];
22556
+ all.sort(cmp);
22557
+ for (let i = 0; i < all.length; i++) {
22558
+ yield all[i];
22559
+ all[i] = null;
22560
+ }
22561
+ return;
22562
+ }
22563
+ await flush();
22564
+ const readers = await Promise.all(runs.map(openRun));
22565
+ try {
22566
+ const heap = [];
22567
+ const less = (i, j) => cmp(heap[i][0], heap[j][0]) < 0;
22568
+ const swap = (i, j) => {
22569
+ const t = heap[i];
22570
+ heap[i] = heap[j];
22571
+ heap[j] = t;
22572
+ };
22573
+ const up = (i) => {
22574
+ while (i > 0) {
22575
+ const p = i - 1 >> 1;
22576
+ if (!less(i, p)) break;
22577
+ swap(i, p);
22578
+ i = p;
22579
+ }
22580
+ };
22581
+ const down = (i) => {
22582
+ for (; ; ) {
22583
+ const l = 2 * i + 1, r = l + 1;
22584
+ let m = i;
22585
+ if (l < heap.length && less(l, m)) m = l;
22586
+ if (r < heap.length && less(r, m)) m = r;
22587
+ if (m === i) return;
22588
+ swap(i, m);
22589
+ i = m;
22590
+ }
22591
+ };
22592
+ for (const rd of readers) {
22593
+ const x = await rd.next();
22594
+ if (x !== void 0) {
22595
+ heap.push([x, rd]);
22596
+ up(heap.length - 1);
22597
+ }
22598
+ }
22599
+ while (heap.length) {
22600
+ const [x, rd] = heap[0];
22601
+ yield x;
22602
+ const n5 = await rd.next();
22603
+ if (n5 === void 0) {
22604
+ const last = (
22605
+ /** @type {[any, any]} */
22606
+ heap.pop()
22607
+ );
22608
+ if (heap.length) {
22609
+ heap[0] = last;
22610
+ down(0);
22611
+ }
22612
+ } else {
22613
+ heap[0] = [n5, rd];
22614
+ down(0);
22615
+ }
22616
+ }
22617
+ } finally {
22618
+ await Promise.all(readers.map((r) => r.close()));
22619
+ }
22620
+ },
22621
+ async close() {
22622
+ buf = [];
22623
+ if (takenKB) {
22624
+ const { cells, cell } = spillShared();
22625
+ Atomics.sub(cells, cell, takenKB);
22626
+ takenKB = 0;
22627
+ }
22628
+ if (dir) {
22629
+ const d = dir;
22630
+ dir = null;
22631
+ live.delete(d);
22632
+ await fs.promises.rm(d, { recursive: true, force: true }).catch(() => {
22633
+ });
22634
+ }
22635
+ },
22636
+ /** Tests: the runs written so far. */
22637
+ get runs() {
22638
+ return runs.length;
22639
+ }
22640
+ };
22641
+ };
22642
+ }
22643
+ function approx(x, d = 0) {
22644
+ if (typeof x === "string") return 2 * x.length + 16;
22645
+ if (!x || typeof x !== "object" || d > 2) return 8;
22646
+ let n5 = 32;
22647
+ for (const k in x) n5 += approx(x[k], d + 1) + 8;
22648
+ return n5;
22649
+ }
22650
+ async function openRun(file) {
22651
+ const fs = node2("node:fs"), v8 = node2("node:v8");
22652
+ const fh = await fs.promises.open(file, "r");
22653
+ let pos = 0, batch = [], i = 0;
22654
+ const head = Buffer.alloc(4);
22655
+ return {
22656
+ async next() {
22657
+ if (i < batch.length) {
22658
+ const x = batch[i];
22659
+ batch[i++] = null;
22660
+ return x;
22661
+ }
22662
+ const h = await fh.read(head, 0, 4, pos);
22663
+ if (h.bytesRead < 4) return void 0;
22664
+ const len = head.readUInt32LE(0);
22665
+ const body = Buffer.alloc(len);
22666
+ await fh.read(body, 0, len, pos + 4);
22667
+ pos += 4 + len;
22668
+ batch = v8.deserialize(body);
22669
+ i = 0;
22670
+ return this.next();
22671
+ },
22672
+ close: () => fh.close()
22673
+ };
22674
+ }
22675
+
22268
22676
  // src/designer/tableGen.js
22269
22677
  var HEAD = { fontWeight: "bold", backgroundColor: "#f1f5f9", borderBottom: "0.75 solid #94a3b8" };
22270
22678
  var TOTAL = { fontWeight: "bold", borderTop: "0.75 solid #94a3b8" };
@@ -22455,11 +22863,11 @@ function optionsOf(fn, args, legacy) {
22455
22863
  const [model, second, third] = args;
22456
22864
  checkModel(fn, model);
22457
22865
  if (legacy === "fonts" && isFontStore(second)) {
22458
- deprecated(fn, `${fn}(model, fontStore, options) is replaced by ${fn}(model, { fonts: fontStore, ...options }); the old form is removed in 0.9`);
22866
+ deprecated(fn, `${fn}(model, fontStore, options) is replaced by ${fn}(model, { fonts: fontStore, ...options }); the old form will be removed in 1.0`);
22459
22867
  return { ...third || {}, fonts: second };
22460
22868
  }
22461
22869
  if (legacy === "excel" && second && (typeof second === "function" || typeof second.Workbook === "function")) {
22462
- deprecated(fn, `${fn}(model, ExcelJS, options) is replaced by ${fn}(model, options): ExcelJS is no longer used; the old form is removed in 0.9`);
22870
+ deprecated(fn, `${fn}(model, ExcelJS, options) is replaced by ${fn}(model, options): ExcelJS is no longer used; the old form will be removed in 1.0`);
22463
22871
  return { ...third || {} };
22464
22872
  }
22465
22873
  if (second != null && (typeof second !== "object" || Array.isArray(second))) throw new TypeError(`${fn}(model, options): options must be an object such as { fonts }, got ${Array.isArray(second) ? "an array" : typeof second}`);
@@ -22502,7 +22910,7 @@ function exportPptx2(model, options) {
22502
22910
  }
22503
22911
  var __streamPaint = { createPdfStream, paintPage, paintEnv, latin1 };
22504
22912
  async function exportPdfStream2(def, options, sink) {
22505
- const { fonts, fontStore, subset: sub, pdfa, ...rest } = (
22913
+ const { fonts, fontStore, subset: sub, pdfa, spill, ...rest } = (
22506
22914
  /** @type {any} */
22507
22915
  options || {}
22508
22916
  );
@@ -22518,7 +22926,8 @@ async function exportPdfStream2(def, options, sink) {
22518
22926
  if (!url) throw new Error("PDF/A needs an sRGB colour profile: install @reportwright/fonts, or pass pdfa: { icc: bytes }");
22519
22927
  pdfaOpt = { ...typeof pdfa === "object" ? pdfa : {}, icc: new Uint8Array(await readUrl(url)) };
22520
22928
  }
22521
- return exportPdfStream(def, { ...rest, fontStore: store, subset, pdfa: pdfaOpt, exportData: !!rest.tagged }, sink);
22929
+ const sorter = rest.sorter || (spill !== false && canSpill() ? spillSorter({ ...spill?.dir ? { dir: spill.dir } : {}, ...spill?.maxMB ? { maxMB: spill.maxMB } : {} }) : void 0);
22930
+ return exportPdfStream(def, { ...rest, sorter, fontStore: store, subset, pdfa: pdfaOpt, exportData: !!rest.tagged }, sink);
22522
22931
  }
22523
22932
  export {
22524
22933
  FontStore,