@formfeed/engine 0.3.12 → 0.3.14

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/index.cjs CHANGED
@@ -30,6 +30,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // packages/engine/src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ACCESSIBILITY_HEADER_LENGTH: () => ACCESSIBILITY_HEADER_LENGTH,
34
+ ACCESSIBILITY_MAX_ELEMENTS: () => ACCESSIBILITY_MAX_ELEMENTS,
35
+ ACCESSIBILITY_MAX_FAILURES: () => ACCESSIBILITY_MAX_FAILURES,
36
+ AUDIT_CODES: () => AUDIT_CODES,
37
+ AUDIT_RULES: () => AUDIT_RULES,
38
+ AUDIT_SEVERITY: () => AUDIT_SEVERITY,
39
+ AUDIT_SNIPPET_LENGTH: () => AUDIT_SNIPPET_LENGTH,
40
+ AUDIT_TITLES: () => AUDIT_TITLES,
33
41
  CII_GUIDELINES: () => CII_GUIDELINES,
34
42
  CODE_LIST_RELEASE: () => CODE_LIST_RELEASE,
35
43
  DEFAULT_CHROME_PADDING: () => DEFAULT_CHROME_PADDING,
@@ -49,9 +57,15 @@ __export(index_exports, {
49
57
  INVOICE_DATA_KEY: () => INVOICE_DATA_KEY,
50
58
  OFFICE_FILLED_MAX_BYTES: () => OFFICE_FILLED_MAX_BYTES,
51
59
  OfficeTemplateError: () => OfficeTemplateError,
60
+ PDFUA_STANDARD: () => PDFUA_STANDARD,
52
61
  RenderError: () => RenderError,
53
62
  RenderLimitError: () => RenderLimitError,
63
+ UA_CHECKS: () => UA_CHECKS,
64
+ UA_REFUSALS: () => UA_REFUSALS,
54
65
  VAT_CATEGORIES: () => VAT_CATEGORIES,
66
+ accessibilityHeader: () => accessibilityHeader,
67
+ accessibilityHeaderValue: () => accessibilityHeaderValue,
68
+ accessibilityResult: () => accessibilityResult,
55
69
  analyzeHandlebars: () => analyzeHandlebars,
56
70
  analyzeJinja2: () => analyzeJinja2,
57
71
  analyzeLiquid: () => analyzeLiquid,
@@ -60,6 +74,8 @@ __export(index_exports, {
60
74
  apitemplateRegions: () => apitemplateRegions,
61
75
  applyRegionEdit: () => applyRegionEdit,
62
76
  assembleDocument: () => assembleDocument,
77
+ auditMessage: () => auditMessage,
78
+ auditRuntime: () => auditRuntime,
63
79
  brandCss: () => brandCss,
64
80
  builtinHelpers: () => builtinHelpers,
65
81
  canvasDocument: () => canvasDocument,
@@ -132,6 +148,7 @@ __export(index_exports, {
132
148
  isOfficeKind: () => isOfficeKind,
133
149
  isOutputFormat: () => isOutputFormat,
134
150
  isScss: () => isScss,
151
+ isUaSetting: () => isUaSetting,
135
152
  jinja2Engine: () => jinja2Engine,
136
153
  jinjaTags: () => jinjaTags,
137
154
  jsreportTemplates: () => jsreportTemplates,
@@ -173,6 +190,7 @@ __export(index_exports, {
173
190
  resolveEinvoiceOptions: () => resolveEinvoiceOptions,
174
191
  resolvePath: () => resolvePath,
175
192
  resolveTranslation: () => resolveTranslation,
193
+ resolveUa: () => resolveUa,
176
194
  scanBlocks: () => scanBlocks,
177
195
  schemaPaths: () => schemaPaths,
178
196
  shownAmounts: () => shownAmounts,
@@ -184,6 +202,8 @@ __export(index_exports, {
184
202
  splitApitemplateCss: () => splitApitemplateCss,
185
203
  starterDocument: () => starterDocument,
186
204
  starterPresentation: () => starterPresentation,
205
+ staticAudit: () => staticAudit,
206
+ staticAuditDiagnostics: () => staticAuditDiagnostics,
187
207
  strftimeToDateFns: () => strftimeToDateFns,
188
208
  svgDataUri: () => svgDataUri,
189
209
  toDate: () => toDate,
@@ -380,11 +400,11 @@ function validateEpc(input) {
380
400
  const purpose = String(input.purpose ?? "");
381
401
  if (purpose.length > 4) problems.push({ field: "purpose", code: "too_long", max: 4, actual: purpose.length });
382
402
  const reference = String(input.reference ?? "").trim();
383
- const text3 = String(input.text ?? "").trim();
384
- if (reference && text3) problems.push({ field: "reference", code: "reference_or_text" });
403
+ const text4 = String(input.text ?? "").trim();
404
+ if (reference && text4) problems.push({ field: "reference", code: "reference_or_text" });
385
405
  if (reference.length > 35)
386
406
  problems.push({ field: "reference", code: "too_long", max: 35, actual: reference.length });
387
- if (text3.length > 140) problems.push({ field: "text", code: "too_long", max: 140, actual: text3.length });
407
+ if (text4.length > 140) problems.push({ field: "text", code: "too_long", max: 140, actual: text4.length });
388
408
  const bytes = byteLength(epcPayload(input));
389
409
  if (bytes > EPC_MAX_BYTES)
390
410
  problems.push({ field: "payload", code: "too_long", max: EPC_MAX_BYTES, actual: bytes });
@@ -422,9 +442,12 @@ var barcodeTypes = {
422
442
  };
423
443
  var ownTextLayout = /* @__PURE__ */ new Set(["ean13", "ean8", "upca"]);
424
444
  function codeText(helper, value) {
425
- const text3 = value === void 0 || value === null ? "" : String(value);
426
- if (text3 === "") throw new Error(`${helper}: nothing to encode, the value is empty or missing from the data`);
427
- return text3;
445
+ const text4 = value === void 0 || value === null ? "" : String(value);
446
+ if (text4 === "")
447
+ throw new Error(
448
+ `${helper}: nothing to encode, the value is empty or missing from the data`
449
+ );
450
+ return text4;
428
451
  }
429
452
  var codeHelpers = [
430
453
  {
@@ -432,18 +455,25 @@ var codeHelpers = [
432
455
  aliases: ["qr"],
433
456
  doc: {
434
457
  signature: "qrcode(value, { size = 160, ecc = 'M', margin = 1, color, background })",
435
- description: "QR code as an SVG data URI for an <img> src.",
458
+ description: "QR code as an SVG data URI for an <img> src. Give the image an `alt` that says where the code leads: a screen reader cannot scan it.",
436
459
  examples: {
437
- jinja2: '<img src="{{ qrcode(order.url, { size: 120 }) }}">',
438
- liquid: '<img src="{{ order.url | qrcode: size: 120 }}">',
439
- handlebars: '<img src="{{qrcode order.url size=120}}">'
460
+ jinja2: '<img src="{{ qrcode(order.url, { size: 120 }) }}" alt="QR code: {{ order.url }}">',
461
+ liquid: '<img src="{{ order.url | qrcode: size: 120 }}" alt="QR code: {{ order.url }}">',
462
+ handlebars: '<img src="{{qrcode order.url size=120}}" alt="QR code: {{order.url}}">'
440
463
  },
441
464
  category: "code"
442
465
  },
443
466
  fn: (ctx, value, options) => {
444
467
  const o = options ?? {};
445
468
  const svg = qrSvg(codeText("qrcode", value), o);
446
- if (ctx.drawing) return ctx.drawing({ kind: "svg", svg, width: o.size, height: o.size, alt: "QR code" });
469
+ if (ctx.drawing)
470
+ return ctx.drawing({
471
+ kind: "svg",
472
+ svg,
473
+ width: o.size,
474
+ height: o.size,
475
+ alt: "QR code"
476
+ });
447
477
  return svgDataUri(svg);
448
478
  }
449
479
  },
@@ -451,28 +481,29 @@ var codeHelpers = [
451
481
  name: "barcode",
452
482
  doc: {
453
483
  signature: "barcode(value, { type = 'code128', height = 12, width, text = true, scale = 2 })",
454
- description: "Barcode (code128, ean13, ean8, upc, itf14, code39, datamatrix, pdf417) as an SVG data URI.",
484
+ description: "Barcode (code128, ean13, ean8, upc, itf14, code39, datamatrix, pdf417) as an SVG data URI. Give the image an `alt` with the value it encodes.",
455
485
  examples: {
456
- jinja2: `<img src="{{ barcode(item.sku, { type: 'code128' }) }}">`,
457
- liquid: `<img src="{{ item.sku | barcode: type: 'code128' }}">`,
458
- handlebars: `<img src="{{barcode item.sku type='code128'}}">`
486
+ jinja2: `<img src="{{ barcode(item.sku, { type: 'code128' }) }}" alt="Barcode {{ item.sku }}">`,
487
+ liquid: `<img src="{{ item.sku | barcode: type: 'code128' }}" alt="Barcode {{ item.sku }}">`,
488
+ handlebars: `<img src="{{barcode item.sku type='code128'}}" alt="Barcode {{item.sku}}">`
459
489
  },
460
490
  category: "code"
461
491
  },
462
492
  fn: (ctx, value, options) => {
463
493
  const o = options ?? {};
464
494
  const bcid = barcodeTypes[String(o.type ?? "code128").toLowerCase()] ?? "code128";
465
- const text3 = codeText("barcode", value);
495
+ const text4 = codeText("barcode", value);
466
496
  const svg = (0, import_bwip_js.toSVG)({
467
497
  bcid,
468
- text: text3,
498
+ text: text4,
469
499
  height: o.height ?? 12,
470
500
  ...o.width === void 0 ? {} : { width: o.width },
471
501
  scale: o.scale ?? 2,
472
502
  includetext: o.text !== false,
473
503
  ...ownTextLayout.has(bcid) ? {} : { textxalign: "center" }
474
504
  });
475
- if (ctx.drawing) return ctx.drawing({ kind: "svg", svg, alt: `Barcode ${text3}` });
505
+ if (ctx.drawing)
506
+ return ctx.drawing({ kind: "svg", svg, alt: `Barcode ${text4}` });
476
507
  return svgDataUri(svg);
477
508
  }
478
509
  },
@@ -481,11 +512,11 @@ var codeHelpers = [
481
512
  aliases: ["epc_qr", "girocode"],
482
513
  doc: {
483
514
  signature: "epcQr({ name, iban, bic?, amount?, reference?, text? }, { size })",
484
- description: "SEPA credit transfer QR code (EPC069-12 / GiroCode) that banking apps scan to prefill a payment.",
515
+ description: "SEPA credit transfer QR code (EPC069-12 / GiroCode) that banking apps scan to prefill a payment. Give the image an `alt`, and print the bank details as text as well: the code is a picture.",
485
516
  examples: {
486
- jinja2: '<img src="{{ epcQr({ name: company.name, iban: company.iban, amount: invoice.total, reference: invoice.number }) }}">',
487
- liquid: '<img src="{{ company.iban | epcQr: name: company.name, amount: invoice.total, reference: invoice.number }}">',
488
- handlebars: '<img src="{{epcQr name=company.name iban=company.iban amount=invoice.total reference=invoice.number}}">'
517
+ jinja2: '<img src="{{ epcQr({ name: company.name, iban: company.iban, amount: invoice.total, reference: invoice.number }) }}" alt="QR code to pay invoice {{ invoice.number }}">',
518
+ liquid: '<img src="{{ company.iban | epcQr: name: company.name, amount: invoice.total, reference: invoice.number }}" alt="QR code to pay invoice {{ invoice.number }}">',
519
+ handlebars: '<img src="{{epcQr name=company.name iban=company.iban amount=invoice.total reference=invoice.number}}" alt="QR code to pay invoice {{invoice.number}}">'
489
520
  },
490
521
  category: "code"
491
522
  },
@@ -504,12 +535,27 @@ var codeHelpers = [
504
535
  (EPC_FIELDS.has(key) ? payment2 : qr)[key] = value;
505
536
  const o = { ecc: "M", ...qr };
506
537
  const svg = qrSvg(epcPayload(payment2), o);
507
- if (ctx.drawing) return ctx.drawing({ kind: "svg", svg, width: o.size, height: o.size, alt: "GiroCode" });
538
+ if (ctx.drawing)
539
+ return ctx.drawing({
540
+ kind: "svg",
541
+ svg,
542
+ width: o.size,
543
+ height: o.size,
544
+ alt: "GiroCode"
545
+ });
508
546
  return svgDataUri(svg);
509
547
  }
510
548
  }
511
549
  ];
512
- var EPC_FIELDS = /* @__PURE__ */ new Set(["name", "iban", "bic", "amount", "reference", "text", "purpose"]);
550
+ var EPC_FIELDS = /* @__PURE__ */ new Set([
551
+ "name",
552
+ "iban",
553
+ "bic",
554
+ "amount",
555
+ "reference",
556
+ "text",
557
+ "purpose"
558
+ ]);
513
559
 
514
560
  // packages/engine/src/lib/helpers/format.ts
515
561
  var import_tz = require("@date-fns/tz");
@@ -527,8 +573,8 @@ var import_nl = require("n2words/nl");
527
573
  function resolveTranslation(dictionaries, locale, key) {
528
574
  const lang = locale.split("-")[0] ?? locale;
529
575
  for (const candidate of [locale, lang, "en"]) {
530
- const text3 = dictionaries?.[candidate]?.[key];
531
- if (typeof text3 === "string") return { text: text3, from: candidate };
576
+ const text4 = dictionaries?.[candidate]?.[key];
577
+ if (typeof text4 === "string") return { text: text4, from: candidate };
532
578
  }
533
579
  return { text: key, from: null };
534
580
  }
@@ -1008,9 +1054,9 @@ var formatHelpers = [
1008
1054
  category: "text"
1009
1055
  },
1010
1056
  fn: (ctx, key, params) => {
1011
- const { text: text3 } = resolveTranslation(ctx.i18n, ctx.locale, str(key));
1057
+ const { text: text4 } = resolveTranslation(ctx.i18n, ctx.locale, str(key));
1012
1058
  const p = params ?? {};
1013
- return text3.replace(/\{(\w+)\}/g, (_, name) => str(p[name]));
1059
+ return text4.replace(/\{(\w+)\}/g, (_, name) => str(p[name]));
1014
1060
  }
1015
1061
  },
1016
1062
  {
@@ -1281,7 +1327,16 @@ var collectionHelpers = [
1281
1327
  ];
1282
1328
 
1283
1329
  // packages/engine/src/lib/helpers/document.ts
1284
- var CHART_PALETTE = ["#3E63DD", "#12A594", "#E5484D", "#F76B15", "#8E4EC6", "#FFC53D", "#0090FF", "#978365"];
1330
+ var CHART_PALETTE = [
1331
+ "#3E63DD",
1332
+ "#12A594",
1333
+ "#E5484D",
1334
+ "#F76B15",
1335
+ "#8E4EC6",
1336
+ "#FFC53D",
1337
+ "#0090FF",
1338
+ "#978365"
1339
+ ];
1285
1340
  var SLICED = /* @__PURE__ */ new Set(["pie", "doughnut", "polarArea"]);
1286
1341
  var colour = (value) => typeof value === "string" && value ? value : Array.isArray(value) && value.length ? value.map(String) : void 0;
1287
1342
  function chartDataFromPlain(spec) {
@@ -1295,8 +1350,13 @@ function chartDataFromPlain(spec) {
1295
1350
  });
1296
1351
  const own = colour(s.color);
1297
1352
  const fill = SLICED.has(type) ? own ?? labels.map((_, i) => CHART_PALETTE[i % CHART_PALETTE.length]) : own ?? CHART_PALETTE[index % CHART_PALETTE.length];
1298
- const dataset = { data, backgroundColor: fill, borderColor: fill };
1299
- if (s.label !== void 0 && s.label !== null && s.label !== "") dataset["label"] = String(s.label);
1353
+ const dataset = {
1354
+ data,
1355
+ backgroundColor: fill,
1356
+ borderColor: fill
1357
+ };
1358
+ if (s.label !== void 0 && s.label !== null && s.label !== "")
1359
+ dataset["label"] = String(s.label);
1300
1360
  if (type === "line") dataset["fill"] = false;
1301
1361
  return dataset;
1302
1362
  });
@@ -1313,7 +1373,8 @@ function chartPayload(spec) {
1313
1373
  const options = { ...spec.options ?? {} };
1314
1374
  options["animation"] = false;
1315
1375
  options["responsive"] = false;
1316
- if (!isPlain(spec)) return { type: spec.type ?? "bar", data: spec.data ?? {}, options };
1376
+ if (!isPlain(spec))
1377
+ return { type: spec.type ?? "bar", data: spec.data ?? {}, options };
1317
1378
  const data = chartDataFromPlain(spec);
1318
1379
  const unnamed = data.datasets.length === 1 && data.datasets[0]?.["label"] === void 0;
1319
1380
  const plugins = asObject(options["plugins"]);
@@ -1326,7 +1387,8 @@ function chartMarkup(spec, id) {
1326
1387
  const height = toNumber(spec.height ?? 240) || 240;
1327
1388
  const payload = escapeHtml(JSON.stringify(chartPayload(spec)));
1328
1389
  const idAttr = id ? ` id="${escapeHtml(id)}"` : "";
1329
- return `<canvas class="ff-chart"${idAttr} width="${width}" height="${height}" style="width:${width}px;height:${height}px" data-ff-chart="${payload}"></canvas>`;
1390
+ const alt = typeof spec.alt === "string" && spec.alt.trim() ? ` role="img" aria-label="${escapeHtml(spec.alt.trim())}"` : "";
1391
+ return `<canvas class="ff-chart"${idAttr}${alt} width="${width}" height="${height}" style="width:${width}px;height:${height}px" data-ff-chart="${payload}"></canvas>`;
1330
1392
  }
1331
1393
  function imageMarkup(url, options = {}) {
1332
1394
  const styles = [
@@ -1347,18 +1409,21 @@ var documentHelpers = [
1347
1409
  name: "chart",
1348
1410
  html: true,
1349
1411
  doc: {
1350
- signature: "chart({ type, labels, values, label, color } | { type, labels, series } | { type, data, options }, { width, height })",
1351
- description: "Draws a Chart.js chart (bar, line, pie, doughnut, radar, \u2026) from plain data, `labels` with `values` or several `series` of `{ label, values, color }`, or from a full Chart.js `data` and `options`; animations are disabled so PDF and preview match.",
1412
+ signature: "chart({ type, labels, values, label, color } | { type, labels, series } | { type, data, options }, { width, height, alt })",
1413
+ description: "Draws a Chart.js chart (bar, line, pie, doughnut, radar, \u2026) from plain data, `labels` with `values` or several `series` of `{ label, values, color }`, or from a full Chart.js `data` and `options`; animations are disabled so PDF and preview match. `alt` says in words what the chart shows: a screen reader reads it in place of the picture, and a tagged PDF needs it.",
1352
1414
  examples: {
1353
- jinja2: "{{ chart({ type: 'line', labels: sales.labels, values: sales.quarters, width: 480 }) }}",
1354
- liquid: "{{ '' | chart: type: 'line', labels: sales.labels, values: sales.quarters, width: 480 }}",
1355
- handlebars: "{{chart type='line' labels=sales.labels values=sales.quarters width=480}}"
1415
+ jinja2: "{{ chart({ type: 'line', labels: sales.labels, values: sales.quarters, width: 480, alt: 'Sales by quarter' }) }}",
1416
+ liquid: "{{ '' | chart: type: 'line', labels: sales.labels, values: sales.quarters, width: 480, alt: 'Sales by quarter' }}",
1417
+ handlebars: "{{chart type='line' labels=sales.labels values=sales.quarters width=480 alt='Sales by quarter'}}"
1356
1418
  },
1357
1419
  category: "document"
1358
1420
  },
1359
1421
  fn: (ctx, spec, extra) => {
1360
1422
  if (ctx.mode === "office") throw new Error(officeUnsupported("chart"));
1361
- return chartMarkup({ ...asObject(spec), ...asObject(extra) });
1423
+ return chartMarkup({
1424
+ ...asObject(spec),
1425
+ ...asObject(extra)
1426
+ });
1362
1427
  }
1363
1428
  },
1364
1429
  {
@@ -1366,18 +1431,24 @@ var documentHelpers = [
1366
1431
  html: true,
1367
1432
  doc: {
1368
1433
  signature: "image(url, { width, height, fit, alt })",
1369
- description: "Places an image with fixed size and crop mode (`cover`, `contain`, `fill`); the render-worker fetches it through its cache and blocks private hosts.",
1434
+ description: "Places an image with fixed size and crop mode (`cover`, `contain`, `fill`); the render-worker fetches it through its cache and blocks private hosts. `alt` says what it shows; without one the image counts as decoration and a screen reader passes over it.",
1370
1435
  examples: {
1371
- jinja2: "{{ image(product.photo, { width: 120, height: 80, fit: 'cover' }) }}",
1372
- liquid: "{{ product.photo | image: width: 120, height: 80, fit: 'cover' }}",
1373
- handlebars: "{{image product.photo width=120 height=80 fit='cover'}}"
1436
+ jinja2: "{{ image(product.photo, { width: 120, height: 80, fit: 'cover', alt: product.name }) }}",
1437
+ liquid: "{{ product.photo | image: width: 120, height: 80, fit: 'cover', alt: product.name }}",
1438
+ handlebars: "{{image product.photo width=120 height=80 fit='cover' alt=product.name}}"
1374
1439
  },
1375
1440
  category: "document"
1376
1441
  },
1377
1442
  fn: (ctx, url, options) => {
1378
1443
  const o = asObject(options);
1379
1444
  if (ctx.drawing)
1380
- return ctx.drawing({ kind: "url", url: resolveAsset(ctx.assetBaseUrl, String(url ?? "")), width: o.width, height: o.height, alt: o.alt });
1445
+ return ctx.drawing({
1446
+ kind: "url",
1447
+ url: resolveAsset(ctx.assetBaseUrl, String(url ?? "")),
1448
+ width: o.width,
1449
+ height: o.height,
1450
+ alt: o.alt
1451
+ });
1381
1452
  return imageMarkup(String(url ?? ""), o);
1382
1453
  }
1383
1454
  }
@@ -2117,8 +2188,8 @@ var SPEC = /^(?:([\s\S])?([<>=^]))?([+\- ])?(#)?(0)?(\d+)?([,_])?(?:\.(\d+))?([b
2117
2188
  function group(digits, separator) {
2118
2189
  return digits.replace(/\B(?=(\d{3})+(?!\d))/g, separator);
2119
2190
  }
2120
- function pythonExponent(text3) {
2121
- return text3.replace(/e([+-])(\d)$/i, (m, sign, digit) => `${m[0]}${sign}0${digit}`);
2191
+ function pythonExponent(text4) {
2192
+ return text4.replace(/e([+-])(\d)$/i, (m, sign, digit) => `${m[0]}${sign}0${digit}`);
2122
2193
  }
2123
2194
  function formatNumber(value, type, precision, alternate) {
2124
2195
  if (!Number.isFinite(value)) return Number.isNaN(value) ? "nan" : "inf";
@@ -2131,20 +2202,20 @@ function formatNumber(value, type, precision, alternate) {
2131
2202
  return `${(abs2 * 100).toFixed(precision ?? 6)}%`;
2132
2203
  case "e":
2133
2204
  case "E": {
2134
- const text3 = pythonExponent(abs2.toExponential(precision ?? 6));
2135
- return type === "E" ? text3.toUpperCase() : text3;
2205
+ const text4 = pythonExponent(abs2.toExponential(precision ?? 6));
2206
+ return type === "E" ? text4.toUpperCase() : text4;
2136
2207
  }
2137
2208
  case "g":
2138
2209
  case "G": {
2139
2210
  const p = precision === 0 ? 1 : precision ?? 6;
2140
2211
  const exp = abs2 === 0 ? 0 : Math.floor(Math.log10(abs2));
2141
- let text3 = exp < -4 || exp >= p ? pythonExponent(abs2.toExponential(p - 1)) : abs2.toFixed(Math.max(0, p - 1 - exp));
2212
+ let text4 = exp < -4 || exp >= p ? pythonExponent(abs2.toExponential(p - 1)) : abs2.toFixed(Math.max(0, p - 1 - exp));
2142
2213
  if (!alternate) {
2143
- const [mantissa = "", exponent] = text3.split("e");
2214
+ const [mantissa = "", exponent] = text4.split("e");
2144
2215
  const trimmed = mantissa.includes(".") ? mantissa.replace(/0+$/, "").replace(/\.$/, "") : mantissa;
2145
- text3 = exponent === void 0 ? trimmed : `${trimmed}e${exponent}`;
2216
+ text4 = exponent === void 0 ? trimmed : `${trimmed}e${exponent}`;
2146
2217
  }
2147
- return type === "G" ? text3.toUpperCase() : text3;
2218
+ return type === "G" ? text4.toUpperCase() : text4;
2148
2219
  }
2149
2220
  case "d":
2150
2221
  case "n":
@@ -2213,35 +2284,35 @@ function lookupField(name, positional, named, next) {
2213
2284
  function pythonFormat(template, positional, named = {}) {
2214
2285
  let auto = 0;
2215
2286
  const next = () => auto++;
2216
- const render = (text3) => {
2287
+ const render = (text4) => {
2217
2288
  let out = "";
2218
- for (let i = 0; i < text3.length; i++) {
2219
- const ch = text3[i];
2289
+ for (let i = 0; i < text4.length; i++) {
2290
+ const ch = text4[i];
2220
2291
  if (ch === "}") {
2221
2292
  out += "}";
2222
- if (text3[i + 1] === "}") i++;
2293
+ if (text4[i + 1] === "}") i++;
2223
2294
  continue;
2224
2295
  }
2225
2296
  if (ch !== "{") {
2226
2297
  out += ch;
2227
2298
  continue;
2228
2299
  }
2229
- if (text3[i + 1] === "{") {
2300
+ if (text4[i + 1] === "{") {
2230
2301
  out += "{";
2231
2302
  i++;
2232
2303
  continue;
2233
2304
  }
2234
2305
  let depth = 1;
2235
2306
  let j = i + 1;
2236
- for (; j < text3.length && depth > 0; j++) {
2237
- if (text3[j] === "{") depth++;
2238
- else if (text3[j] === "}") depth--;
2307
+ for (; j < text4.length && depth > 0; j++) {
2308
+ if (text4[j] === "{") depth++;
2309
+ else if (text4[j] === "}") depth--;
2239
2310
  }
2240
2311
  if (depth > 0) {
2241
- out += text3.slice(i);
2312
+ out += text4.slice(i);
2242
2313
  break;
2243
2314
  }
2244
- const field = text3.slice(i + 1, j - 1);
2315
+ const field = text4.slice(i + 1, j - 1);
2245
2316
  const colon = field.indexOf(":");
2246
2317
  const head = colon < 0 ? field : field.slice(0, colon);
2247
2318
  const name = head.replace(/![rsa]$/, "");
@@ -4386,9 +4457,9 @@ function pick(input, ...keys) {
4386
4457
  function toLength(value) {
4387
4458
  if (value === void 0 || value === null || value === "") return void 0;
4388
4459
  if (typeof value === "number") return `${value}mm`;
4389
- const text3 = String(value).trim();
4390
- if (/^-?\d+(\.\d+)?$/.test(text3)) return `${text3}mm`;
4391
- if (/^-?\d+(\.\d+)?(mm|cm|in|px|pt)$/i.test(text3)) return text3.toLowerCase();
4460
+ const text4 = String(value).trim();
4461
+ if (/^-?\d+(\.\d+)?$/.test(text4)) return `${text4}mm`;
4462
+ if (/^-?\d+(\.\d+)?(mm|cm|in|px|pt)$/i.test(text4)) return text4.toLowerCase();
4392
4463
  return void 0;
4393
4464
  }
4394
4465
  function toMarginLength(value) {
@@ -4408,7 +4479,7 @@ function convertHeaderFooter(html) {
4408
4479
  if (typeof html !== "string" || !html.trim()) return void 0;
4409
4480
  return chromePlaceholders.reduce((out, [pattern, span]) => out.replace(pattern, span), html);
4410
4481
  }
4411
- var escapeText = (text3) => text3.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4482
+ var escapeText = (text4) => text4.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
4412
4483
  var visibleMarkup = (html) => html.replace(/<style[\s\S]*?<\/style>/gi, "").trim();
4413
4484
  function apitemplateChrome(take, kind) {
4414
4485
  const custom = take(`custom_${kind}`);
@@ -4422,7 +4493,7 @@ function apitemplateChrome(take, kind) {
4422
4493
  if (!slots.some(Boolean)) return { fromSlots: false };
4423
4494
  const sizeText = size === void 0 ? "" : String(size).trim();
4424
4495
  const fontSize2 = /^\d+(\.\d+)?$/.test(sizeText) ? `${sizeText}px` : /^\d+(\.\d+)?(px|pt|mm)$/.test(sizeText) ? sizeText : "9px";
4425
- const cells = slots.map((text3, i) => `<span style="flex:1;text-align:${["left", "center", "right"][i]}">${escapeText(text3)}</span>`).join("");
4496
+ const cells = slots.map((text4, i) => `<span style="flex:1;text-align:${["left", "center", "right"][i]}">${escapeText(text4)}</span>`).join("");
4426
4497
  const styles = customHtml.match(/<style[\s\S]*?<\/style>/gi)?.join("") ?? "";
4427
4498
  return {
4428
4499
  html: convertHeaderFooter(`${styles}<div style="display:flex;gap:4mm;font-size:${fontSize2}">${cells}</div>`),
@@ -4583,9 +4654,9 @@ function checkTemplate(engineId, html, sampleData, name, docs) {
4583
4654
  function lengthMm(value) {
4584
4655
  if (value === void 0 || value === null || value === "") return void 0;
4585
4656
  if (typeof value === "number" && Number.isFinite(value)) return `${value}mm`;
4586
- const text3 = String(value).trim();
4587
- if (/^-?\d+(\.\d+)?$/.test(text3)) return `${text3}mm`;
4588
- if (/^-?\d+(\.\d+)?(mm|cm|in|px|pt)$/i.test(text3)) return text3.toLowerCase();
4657
+ const text4 = String(value).trim();
4658
+ if (/^-?\d+(\.\d+)?$/.test(text4)) return `${text4}mm`;
4659
+ if (/^-?\d+(\.\d+)?(mm|cm|in|px|pt)$/i.test(text4)) return text4.toLowerCase();
4589
4660
  return void 0;
4590
4661
  }
4591
4662
  function toBase64(value) {
@@ -5102,11 +5173,11 @@ function inlineIncludes(source, blocks, errors, changes) {
5102
5173
  }
5103
5174
  var cssPaperFormats = { a3: "A3", a4: "A4", a5: "A5", letter: "Letter" };
5104
5175
  var isoSizes = { a0: [841, 1189], a1: [594, 841], a2: [420, 594], a6: [105, 148] };
5105
- var escapeHtml2 = (text3) => text3.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5176
+ var escapeHtml2 = (text4) => text4.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
5106
5177
  function simpleHeaderFooter(part, margin) {
5107
5178
  const cells = ["left", "center", "right"].map((side) => part[side] ?? "");
5108
5179
  if (!cells.some((c) => c.trim())) return void 0;
5109
- const cell3 = (text3, align) => `<div style="flex: 1; text-align: ${align}">${escapeHtml2(text3).replace(/\[page\]/g, '<span class="pageNumber"></span>').replace(/\[topage\]/g, '<span class="totalPages"></span>')}</div>`;
5180
+ const cell3 = (text4, align) => `<div style="flex: 1; text-align: ${align}">${escapeHtml2(text4).replace(/\[page\]/g, '<span class="pageNumber"></span>').replace(/\[topage\]/g, '<span class="totalPages"></span>')}</div>`;
5110
5181
  return `<div style="display: flex; width: 100%; font-size: 10px; padding: 0 ${margin.right} 0 ${margin.left}">${cell3(cells[0] ?? "", "left")}${cell3(cells[1] ?? "", "center")}${cell3(cells[2] ?? "", "right")}</div>`;
5111
5182
  }
5112
5183
  function mapSettings(input, kind, warnings, changes) {
@@ -5275,11 +5346,11 @@ var DOCS3 = "/migrate/jsreport";
5275
5346
  var COLLECTIONS = ["templates", "data", "assets", "components", "scripts", "folders"];
5276
5347
  function readJsreportExport(files) {
5277
5348
  const bundle = { templates: [], data: [], assets: [], components: [], scripts: [], folders: [] };
5278
- for (const [path, text3] of Object.entries(files)) {
5349
+ for (const [path, text4] of Object.entries(files)) {
5279
5350
  const normalized = path.replace(/\\/g, "/").replace(/^\.?\//, "");
5280
5351
  if (normalized === "metadata.json") {
5281
5352
  try {
5282
- bundle.version = String(JSON.parse(text3).reporterVersion ?? "");
5353
+ bundle.version = String(JSON.parse(text4).reporterVersion ?? "");
5283
5354
  } catch {
5284
5355
  }
5285
5356
  continue;
@@ -5287,7 +5358,7 @@ function readJsreportExport(files) {
5287
5358
  const collection = normalized.split("/")[0];
5288
5359
  if (!COLLECTIONS.includes(collection) || !normalized.endsWith(".json")) continue;
5289
5360
  try {
5290
- bundle[collection].push(JSON.parse(text3));
5361
+ bundle[collection].push(JSON.parse(text4));
5291
5362
  } catch {
5292
5363
  }
5293
5364
  }
@@ -5329,7 +5400,7 @@ function assetBase64(content) {
5329
5400
  }
5330
5401
  return toBase64(content);
5331
5402
  }
5332
- var escapeMustaches = (text3) => text3.replace(/\{\{/g, "\\{{");
5403
+ var escapeMustaches = (text4) => text4.replace(/\{\{/g, "\\{{");
5333
5404
  function resolveAssets(source, bundle, options, warnings, changes) {
5334
5405
  const v3 = /\{\{\{?\s*asset\s+(["'])([^"']+)\1(?:\s+(["'])([^"']+)\3)?\s*\}?\}\}/g;
5335
5406
  const v2 = /\{#asset\s+([^\s}]+)(?:\s+@encoding=(\w+))?\s*\}/g;
@@ -5570,6 +5641,7 @@ function importJsreport(bundle, ref, options = {}) {
5570
5641
  var textEditRuntime = '"use strict";(()=>{var O=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit="t"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function F(l,d={}){let m=d.clicks!==!1,g=d.live===!0,o=l.document,i=null,s=null,f=e=>{try{l.parent.postMessage(e,"*")}catch{}},v=m?o.querySelector(\'meta[name="formfeed:document"]\')?.getAttribute("content")??null:null,h=!1;l.addEventListener("blur",()=>{h=!0}),l.addEventListener("focus",()=>{h=!1});let y=o.createElement("style");y.setAttribute("data-formfeed","edit"),y.setAttribute("data-pagedjs-ignore",""),y.textContent=O,(o.head??o.documentElement).appendChild(y),m&&o.documentElement.classList.add("ff-edit-mode");let M=e=>(e&&typeof e.closest=="function"?e:null)?.closest("[data-ff-edit]")??null;o.addEventListener("click",e=>{if(!m)return;if(i&&!i.done&&i.element.contains(e.target)){e.stopImmediatePropagation();return}let t=M(e.target);t&&(e.preventDefault(),e.stopImmediatePropagation(),C(t,{x:e.clientX,y:e.clientY}))},!0);function C(e,t){i&&!i.done&&x();let n=e.getAttribute("data-ff-src")??"",r=e.getBoundingClientRect(),u=Array.from(o.querySelectorAll(`[data-ff-src="${n.replace(/"/g,"")}"]`));s={src:n,element:e,point:t},f({type:"formfeed:edit-request",src:n,doc:v,edit:e.getAttribute("data-ff-edit"),text:e.textContent??"",elements:e.childElementCount,count:u.length,index:Math.max(0,u.indexOf(e)),split:e.hasAttribute("data-split-from")||e.hasAttribute("data-split-to"),rect:{left:r.left,top:r.top,width:r.width,height:r.height}})}o.addEventListener("keydown",e=>{if(!m||i&&!i.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t==="z"||t==="y")&&(e.preventDefault(),f({type:t==="y"||e.shiftKey?"formfeed:redo":"formfeed:undo"}))}),l.addEventListener("message",e=>{if(e.source!==l.parent)return;let t=e.data;!t||typeof t.type!="string"||(t.type==="formfeed:edit-begin"?P(t):t.type==="formfeed:edit-refuse"||t.type==="formfeed:edit-end"?(s=null,i&&!i.done&&E(!1)):t.type==="formfeed:edit-open"&&B(t))});function B(e){if(!m||typeof e.src!="string"||i&&!i.done)return;let t=Array.from(o.querySelectorAll(`[data-ff-src="${e.src.replace(/"/g,"")}"][data-ff-edit]`)),n=Number.isInteger(e.index)?Number(e.index):0,r=t[n]??t[0];r&&C(r,null)}if(m){let e=()=>f({type:"formfeed:edit-ready",doc:v}),t=l;t.PagedConfig?t.formfeedEditReady=e:o.readyState==="loading"?o.addEventListener("DOMContentLoaded",e):e()}function P(e){i&&!i.done&&E(!1);let t=e.layer?o.querySelector(`[data-ff-layer="${String(e.layer).replace(/"/g,"")}"] > .ff-text`):s&&s.src===e.src?s.element:o.querySelector(`[data-ff-src="${String(e.src).replace(/"/g,"")}"]`),n=e.at,r=e.layer?n&&Number.isFinite(n.x)&&Number.isFinite(n.y)?{x:Number(n.x),y:Number(n.y)}:null:s&&s.src===e.src?s.point:null;s=null;let u=h&&!o.hasFocus();if(!t||!Array.isArray(e.items)||u){f({type:"formfeed:edit-cancel",token:String(e.token)});return}let c=Array.from(t.childNodes),b=o.createDocumentFragment();for(let a of e.items)if(a.kind==="text")b.appendChild(o.createTextNode(String(a.text)));else if(a.kind==="break")b.appendChild(o.createElement("br"));else if(a.kind==="chip"){let p=o.createElement("span");p.className="ff-chip",p.setAttribute("data-ff-chip",String(a.index)),p.setAttribute("contenteditable","false"),a.title&&(p.title=String(a.title)),p.textContent=String(a.text),b.appendChild(p)}for(let a of c)t.removeChild(a);t.appendChild(b),t.contentEditable="true",t.classList.add("ff-editing"),t.setAttribute("role","textbox"),e.label&&t.setAttribute("aria-label",String(e.label)),t.spellcheck=!0,i={token:String(e.token),element:t,saved:c,allowBreaks:e.allowBreaks===!0,badge:e.note?H(t,String(e.note)):null,done:!1},t.addEventListener("keydown",A),t.addEventListener("beforeinput",T),t.addEventListener("paste",S),t.addEventListener("drop",N),t.addEventListener("focusout",R),g&&t.addEventListener("input",k),t.focus(),e.select==="all"?I(t):K(t,r),f({type:"formfeed:edit-started",token:i.token}),typeof e.insert=="string"&&e.insert&&L(e.insert.replace(/\\r\\n?|\\n/g," "))}function L(e){if(typeof o.execCommand=="function"&&o.execCommand("insertText",!1,e))return;let t=l.getSelection(),n=t&&t.rangeCount?t.getRangeAt(0):null;n&&(n.deleteContents(),n.insertNode(o.createTextNode(e)),n.collapse(!1),g&&k())}function k(){i&&!i.done&&f({type:"formfeed:edit-input",token:i.token,items:D(i.element)})}function H(e,t){let n=o.createElement("div");n.className="ff-edit-badge",n.textContent=t;let r=e.getBoundingClientRect();return n.style.left=`${r.left+l.scrollX}px`,n.style.top=`${Math.max(0,r.top+l.scrollY-22)}px`,o.body.appendChild(n),n}function I(e){let t=l.getSelection();if(!t)return;let n=o.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}function K(e,t){let n=l.getSelection();if(!n)return;let r=null,u=o;if(t){if(u.caretRangeFromPoint)r=u.caretRangeFromPoint(t.x,t.y);else if(u.caretPositionFromPoint){let c=u.caretPositionFromPoint(t.x,t.y);c&&(r=o.createRange(),r.setStart(c.offsetNode,c.offset))}}if(!r||!e.contains(r.startContainer))r=o.createRange(),r.selectNodeContents(e),r.collapse(!1);else if(t){let c=r.startContainer,a=(c.nodeType===1?c:c.parentElement)?.closest("[data-ff-chip]")??null;if(a&&a!==e&&e.contains(a)){let p=a.getBoundingClientRect();r=o.createRange(),t.x<p.left+p.width/2?r.setStartBefore(a):r.setStartAfter(a),r.collapse(!0)}}n.removeAllRanges(),n.addRange(r)}function A(e){let t=e.key;t==="Escape"?(e.preventDefault(),E(!0)):t==="Enter"&&!e.shiftKey?(e.preventDefault(),x()):t==="Enter"?(e.preventDefault(),i?.allowBreaks&&q()):t==="Tab"?(e.preventDefault(),x()):(e.ctrlKey||e.metaKey)&&["b","i","u"].includes(t.toLowerCase())&&(e.preventDefault(),g&&i&&!e.altKey&&f({type:"formfeed:edit-style",token:i.token,key:t.toLowerCase()}))}function T(e){let t=e.inputType??"";(t.startsWith("format")||t==="insertFromDrop"||t==="insertParagraph"||t==="insertLineBreak")&&e.preventDefault()}function S(e){e.preventDefault(),L((e.clipboardData?.getData("text/plain")??"").replace(/\\r\\n?|\\n/g," "))}function N(e){e.preventDefault()}function R(){l.setTimeout(()=>{i&&!i.done&&(!o.hasFocus()||!i.element.contains(o.activeElement))&&x()},0)}function q(){let e=l.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let n=o.createElement("br");t.insertNode(n),n.nextSibling||n.parentNode?.appendChild(o.createElement("br"));let r=o.createRange();r.setStartAfter(n),r.collapse(!0),e.removeAllRanges(),e.addRange(r)}function w(e){e.done=!0;let t=e.element;t.removeEventListener("keydown",A),t.removeEventListener("beforeinput",T),t.removeEventListener("paste",S),t.removeEventListener("drop",N),t.removeEventListener("focusout",R),t.removeEventListener("input",k),t.removeAttribute("contenteditable"),t.removeAttribute("role"),t.removeAttribute("aria-label"),t.classList.remove("ff-editing"),e.badge?.remove(),i===e&&(i=null)}function x(){let e=i;if(!e||e.done)return;let t=D(e.element);w(e),f({type:"formfeed:edit-commit",token:e.token,items:t})}function E(e){let t=i;if(!t||t.done)return;let n=t.element;for(;n.firstChild;)n.removeChild(n.firstChild);for(let r of t.saved)n.appendChild(r);w(t),e&&f({type:"formfeed:edit-cancel",token:t.token})}}function D(l){let d=[],m=o=>{let i=d[d.length-1];i?.kind==="text"?i.text+=o:o&&d.push({kind:"text",text:o})},g=o=>{for(let i of Array.from(o.childNodes))if(i.nodeType===3)m(i.data);else if(i.nodeType===1){let s=i,f=s.getAttribute("data-ff-chip");f!==null?d.push({kind:"chip",index:Number(f)}):s.tagName==="BR"?d.push({kind:"break"}):((s.tagName==="DIV"||s.tagName==="P")&&d.length&&d.push({kind:"break"}),g(s))}};for(g(l);d[d.length-1]?.kind==="break";)d.pop();return d}F(window);})();';
5571
5642
  var fitRuntime = '"use strict";(()=>{function a(t,e,n){if(e===t)return t.scrollHeight<=t.clientHeight+.5&&t.scrollWidth<=t.clientWidth+.5;let o=n.getComputedStyle(t),i=t.clientHeight-(parseFloat(o.paddingTop)||0)-(parseFloat(o.paddingBottom)||0);return e.scrollHeight<=i+.5&&e.scrollWidth<=e.clientWidth+.5}function m(t,e){let n=t.firstElementChild??t;n.style.fontSize="";let o=parseFloat(e.getComputedStyle(n).fontSize)||16,i=Math.min(o,parseFloat(t.getAttribute("data-ff-fit-min")??"")||o/2);if(a(t,n,e))return o;let l=i,s=o;for(let d=0;d<14;d++){let r=(l+s)/2;n.style.fontSize=`${r}px`,a(t,n,e)?l=r:s=r}let f=Math.floor(l*100)/100;return n.style.fontSize=`${f}px`,f}function c(t){let e=()=>{for(let o of Array.from(t.document.querySelectorAll(\'[data-ff-fit="shrink"]\')))m(o,t);t.document.documentElement.setAttribute("data-ff-fit","done")};t.formfeedFit=e;let n=t.document.fonts;n?n.ready.then(e):t.addEventListener("load",e)}c(window);})();';
5572
5643
  var stageRuntime = '"use strict";(()=>{var W=`\nhtml.ff-edit-mode [data-ff-edit] { cursor: text; }\nhtml.ff-edit-mode [data-ff-edit]:hover { outline: 1px dashed rgba(37,99,235,.85); outline-offset: 2px; }\nhtml.ff-edit-mode [data-ff-edit="t"]:hover { outline-color: rgba(147,51,234,.9); }\n.ff-editing { outline: 2px solid #2563eb !important; outline-offset: 2px; cursor: text; }\n.ff-editing .ff-chip { background: rgba(37,99,235,.14) !important; box-shadow: inset 0 0 0 1px rgba(37,99,235,.45) !important; border-radius: 3px !important; padding: 0 1px !important; cursor: default; }\n.ff-edit-badge { position: absolute; z-index: 2147483647; font: 500 11px/1.4 system-ui, sans-serif !important; color: #fff !important; background: #2563eb !important; padding: 1px 6px !important; border-radius: 4px !important; pointer-events: none; white-space: nowrap; }\n`;function H(a,l={}){let f=l.clicks!==!1,p=l.live===!0,n=a.document,o=null,d=null,u=e=>{try{a.parent.postMessage(e,"*")}catch{}},m=f?n.querySelector(\'meta[name="formfeed:document"]\')?.getAttribute("content")??null:null,s=!1;a.addEventListener("blur",()=>{s=!0}),a.addEventListener("focus",()=>{s=!1});let g=n.createElement("style");g.setAttribute("data-formfeed","edit"),g.setAttribute("data-pagedjs-ignore",""),g.textContent=W,(n.head??n.documentElement).appendChild(g),f&&n.documentElement.classList.add("ff-edit-mode");let x=e=>(e&&typeof e.closest=="function"?e:null)?.closest("[data-ff-edit]")??null;n.addEventListener("click",e=>{if(!f)return;if(o&&!o.done&&o.element.contains(e.target)){e.stopImmediatePropagation();return}let t=x(e.target);t&&(e.preventDefault(),e.stopImmediatePropagation(),v(t,{x:e.clientX,y:e.clientY}))},!0);function v(e,t){o&&!o.done&&L();let r=e.getAttribute("data-ff-src")??"",i=e.getBoundingClientRect(),b=Array.from(n.querySelectorAll(`[data-ff-src="${r.replace(/"/g,"")}"]`));d={src:r,element:e,point:t},u({type:"formfeed:edit-request",src:r,doc:m,edit:e.getAttribute("data-ff-edit"),text:e.textContent??"",elements:e.childElementCount,count:b.length,index:Math.max(0,b.indexOf(e)),split:e.hasAttribute("data-split-from")||e.hasAttribute("data-split-to"),rect:{left:i.left,top:i.top,width:i.width,height:i.height}})}n.addEventListener("keydown",e=>{if(!f||o&&!o.done||!(e.ctrlKey||e.metaKey)||e.altKey)return;let t=e.key.toLowerCase();(t==="z"||t==="y")&&(e.preventDefault(),u({type:t==="y"||e.shiftKey?"formfeed:redo":"formfeed:undo"}))}),a.addEventListener("message",e=>{if(e.source!==a.parent)return;let t=e.data;!t||typeof t.type!="string"||(t.type==="formfeed:edit-begin"?B(t):t.type==="formfeed:edit-refuse"||t.type==="formfeed:edit-end"?(d=null,o&&!o.done&&S(!1)):t.type==="formfeed:edit-open"&&E(t))});function E(e){if(!f||typeof e.src!="string"||o&&!o.done)return;let t=Array.from(n.querySelectorAll(`[data-ff-src="${e.src.replace(/"/g,"")}"][data-ff-edit]`)),r=Number.isInteger(e.index)?Number(e.index):0,i=t[r]??t[0];i&&v(i,null)}if(f){let e=()=>u({type:"formfeed:edit-ready",doc:m}),t=a;t.PagedConfig?t.formfeedEditReady=e:n.readyState==="loading"?n.addEventListener("DOMContentLoaded",e):e()}function B(e){o&&!o.done&&S(!1);let t=e.layer?n.querySelector(`[data-ff-layer="${String(e.layer).replace(/"/g,"")}"] > .ff-text`):d&&d.src===e.src?d.element:n.querySelector(`[data-ff-src="${String(e.src).replace(/"/g,"")}"]`),r=e.at,i=e.layer?r&&Number.isFinite(r.x)&&Number.isFinite(r.y)?{x:Number(r.x),y:Number(r.y)}:null:d&&d.src===e.src?d.point:null;d=null;let b=s&&!n.hasFocus();if(!t||!Array.isArray(e.items)||b){u({type:"formfeed:edit-cancel",token:String(e.token)});return}let y=Array.from(t.childNodes),k=n.createDocumentFragment();for(let c of e.items)if(c.kind==="text")k.appendChild(n.createTextNode(String(c.text)));else if(c.kind==="break")k.appendChild(n.createElement("br"));else if(c.kind==="chip"){let h=n.createElement("span");h.className="ff-chip",h.setAttribute("data-ff-chip",String(c.index)),h.setAttribute("contenteditable","false"),c.title&&(h.title=String(c.title)),h.textContent=String(c.text),k.appendChild(h)}for(let c of y)t.removeChild(c);t.appendChild(k),t.contentEditable="true",t.classList.add("ff-editing"),t.setAttribute("role","textbox"),e.label&&t.setAttribute("aria-label",String(e.label)),t.spellcheck=!0,o={token:String(e.token),element:t,saved:y,allowBreaks:e.allowBreaks===!0,badge:e.note?I(t,String(e.note)):null,done:!1},t.addEventListener("keydown",T),t.addEventListener("beforeinput",N),t.addEventListener("paste",w),t.addEventListener("drop",R),t.addEventListener("focusout",F),p&&t.addEventListener("input",C),t.focus(),e.select==="all"?q(t):K(t,i),u({type:"formfeed:edit-started",token:o.token}),typeof e.insert=="string"&&e.insert&&A(e.insert.replace(/\\r\\n?|\\n/g," "))}function A(e){if(typeof n.execCommand=="function"&&n.execCommand("insertText",!1,e))return;let t=a.getSelection(),r=t&&t.rangeCount?t.getRangeAt(0):null;r&&(r.deleteContents(),r.insertNode(n.createTextNode(e)),r.collapse(!1),p&&C())}function C(){o&&!o.done&&u({type:"formfeed:edit-input",token:o.token,items:D(o.element)})}function I(e,t){let r=n.createElement("div");r.className="ff-edit-badge",r.textContent=t;let i=e.getBoundingClientRect();return r.style.left=`${i.left+a.scrollX}px`,r.style.top=`${Math.max(0,i.top+a.scrollY-22)}px`,n.body.appendChild(r),r}function q(e){let t=a.getSelection();if(!t)return;let r=n.createRange();r.selectNodeContents(e),t.removeAllRanges(),t.addRange(r)}function K(e,t){let r=a.getSelection();if(!r)return;let i=null,b=n;if(t){if(b.caretRangeFromPoint)i=b.caretRangeFromPoint(t.x,t.y);else if(b.caretPositionFromPoint){let y=b.caretPositionFromPoint(t.x,t.y);y&&(i=n.createRange(),i.setStart(y.offsetNode,y.offset))}}if(!i||!e.contains(i.startContainer))i=n.createRange(),i.selectNodeContents(e),i.collapse(!1);else if(t){let y=i.startContainer,c=(y.nodeType===1?y:y.parentElement)?.closest("[data-ff-chip]")??null;if(c&&c!==e&&e.contains(c)){let h=c.getBoundingClientRect();i=n.createRange(),t.x<h.left+h.width/2?i.setStartBefore(c):i.setStartAfter(c),i.collapse(!0)}}r.removeAllRanges(),r.addRange(i)}function T(e){let t=e.key;t==="Escape"?(e.preventDefault(),S(!0)):t==="Enter"&&!e.shiftKey?(e.preventDefault(),L()):t==="Enter"?(e.preventDefault(),o?.allowBreaks&&$()):t==="Tab"?(e.preventDefault(),L()):(e.ctrlKey||e.metaKey)&&["b","i","u"].includes(t.toLowerCase())&&(e.preventDefault(),p&&o&&!e.altKey&&u({type:"formfeed:edit-style",token:o.token,key:t.toLowerCase()}))}function N(e){let t=e.inputType??"";(t.startsWith("format")||t==="insertFromDrop"||t==="insertParagraph"||t==="insertLineBreak")&&e.preventDefault()}function w(e){e.preventDefault(),A((e.clipboardData?.getData("text/plain")??"").replace(/\\r\\n?|\\n/g," "))}function R(e){e.preventDefault()}function F(){a.setTimeout(()=>{o&&!o.done&&(!n.hasFocus()||!o.element.contains(n.activeElement))&&L()},0)}function $(){let e=a.getSelection();if(!e||!e.rangeCount)return;let t=e.getRangeAt(0);t.deleteContents();let r=n.createElement("br");t.insertNode(r),r.nextSibling||r.parentNode?.appendChild(n.createElement("br"));let i=n.createRange();i.setStartAfter(r),i.collapse(!0),e.removeAllRanges(),e.addRange(i)}function M(e){e.done=!0;let t=e.element;t.removeEventListener("keydown",T),t.removeEventListener("beforeinput",N),t.removeEventListener("paste",w),t.removeEventListener("drop",R),t.removeEventListener("focusout",F),t.removeEventListener("input",C),t.removeAttribute("contenteditable"),t.removeAttribute("role"),t.removeAttribute("aria-label"),t.classList.remove("ff-editing"),e.badge?.remove(),o===e&&(o=null)}function L(){let e=o;if(!e||e.done)return;let t=D(e.element);M(e),u({type:"formfeed:edit-commit",token:e.token,items:t})}function S(e){let t=o;if(!t||t.done)return;let r=t.element;for(;r.firstChild;)r.removeChild(r.firstChild);for(let i of t.saved)r.appendChild(i);M(t),e&&u({type:"formfeed:edit-cancel",token:t.token})}}function D(a){let l=[],f=n=>{let o=l[l.length-1];o?.kind==="text"?o.text+=n:n&&l.push({kind:"text",text:n})},p=n=>{for(let o of Array.from(n.childNodes))if(o.nodeType===3)f(o.data);else if(o.nodeType===1){let d=o,u=d.getAttribute("data-ff-chip");u!==null?l.push({kind:"chip",index:Number(u)}):d.tagName==="BR"?l.push({kind:"break"}):((d.tagName==="DIV"||d.tagName==="P")&&l.length&&l.push({kind:"break"}),p(d))}};for(p(a);l[l.length-1]?.kind==="break";)l.pop();return l}function O(a,l){return Array.from(a.querySelectorAll("[data-ff-layer]")).map(f=>{let p=f.querySelector(":scope > .ff-text"),n=!1;if(p&&f.style.height!=="auto"){let o=l.getComputedStyle(f),d=f.clientHeight-(parseFloat(o.paddingTop)||0)-(parseFloat(o.paddingBottom)||0);n=o.overflow==="hidden"&&(p.scrollHeight>d+1||p.scrollWidth>p.clientWidth+1)}return{id:f.getAttribute("data-ff-layer")??"",width:f.offsetWidth,height:f.offsetHeight,overflow:n}})}function P(a){let l=a.document,f=m=>{try{a.parent.postMessage(m,"*")}catch{}},p=m=>typeof m=="string"?l.querySelector(`[data-ff-layer="${m.replace(/"/g,"")}"]`):null,n=()=>{for(let m of Array.from(l.querySelectorAll("[data-ff-layer]")))for(let s of["left","top","width","height","transform"])m.style.removeProperty(s)},o=()=>{a.formfeedFit?.(),f({type:"formfeed:ready",layers:O(l,a)})};a.addEventListener("message",m=>{if(m.source!==a.parent)return;let s=m.data;if(!(!s||typeof s.type!="string")){if(s.type==="formfeed:layer-style"){let g=p(s.id);if(!g)return;let x=(v,E)=>{typeof E=="number"&&Number.isFinite(E)&&g.style.setProperty(v,`${E}px`)};x("left",s.left),x("top",s.top),x("width",s.width),x("height",s.height),typeof s.rotation=="number"&&Number.isFinite(s.rotation)&&g.style.setProperty("transform",s.rotation?`rotate(${s.rotation}deg)`:"none")}else if(s.type==="formfeed:layer-style-clear")n();else if(s.type==="formfeed:css"&&typeof s.css=="string"){let g=l.querySelector(\'style[data-formfeed="template"]\');g&&(g.textContent=s.css),n(),o()}}}),H(a,{clicks:!1,live:!0});let d=l.fonts,u=()=>d?void d.ready.then(o):o();l.readyState==="complete"?u():a.addEventListener("load",u)}P(window);})();';
5644
+ var auditRuntime = '"use strict";(()=>{var I={"document-title":"error","image-alt":"error","figure-name":"error","heading-order":"error","table-rows":"error","table-cell-empty":"error","masked-text":"error","filtered-text":"warning","document-language":"warning","table-headers":"warning","link-name":"warning","generated-text":"warning","fixed-text":"warning","running-text":"warning"};var S=120;var O=".formfeed-chrome, .ff-running-header, .ff-running-footer",_=".pageNumber, .totalPages, .date, .title, .url, .ff-page-no, .ff-page-total",k=new Set(["script","style","template","noscript","head"]),j=2e4,q=10,B=new Set(["page","pages","of","seite","seiten","von","p","s"]),u=t=>(t??"").replace(/\\s+/g," ").trim(),D=t=>t.replace(/\\s+/g,"").toLowerCase(),$=t=>/[\\p{L}\\p{N}]/u.test(t),Y=/^data-(ref|id|split-(from|to|original)|(previous-|next-)?break-(before|after|inside)|(align-)?last-split-element|nth-of-type|counter-.+|page(-number)?|undisplayed|after-page|following|has-notes|children|item-num)$/;function X(t){let n=t.cloneNode(!1);n.removeAttribute("data-ff-src"),n.removeAttribute("data-ff-edit");let i=t.closest(".pagedjs_page")!==null;for(let s of Array.from(n.attributes))i&&Y.test(s.name)?n.removeAttribute(s.name):s.value.length>48&&n.setAttribute(s.name,`${s.value.slice(0,40)}\\u2026`);let o=n.outerHTML.replace(new RegExp(`</${t.tagName}>$`,"i"),"");return o.length>S?`${o.slice(0,S-1)}\\u2026`:o}function F(t,n={}){let i=t.document,o=i.body,s=[],d=new Set,a=n.findings!==!1,c=(e,r,l={})=>{if(!a)return;let m=r?.closest("[data-ff-src]")?.getAttribute("data-ff-src")??null,h=r?X(r):"",g=`${e}|${m??h}|${JSON.stringify(l)}`;d.has(g)||(d.add(g),s.push({code:e,severity:I[e],src:m,snippet:h,args:l}))},f=new WeakMap,A=e=>{let r=f.get(e);if(r!==void 0)return r;let l=t.getComputedStyle(e),m=l.display==="none"||l.visibility==="hidden"||l.visibility==="collapse"||e.parentElement!==null&&e.parentElement!==i.documentElement&&A(e.parentElement);return f.set(e,m),m},p=e=>e.closest(\'[aria-hidden="true"]\')!==null,E=e=>/^(presentation|none)$/.test(e.getAttribute("role")??""),H=e=>e.closest(O)!==null,y=e=>$(e.textContent??""),x=e=>{let r=u(e.getAttribute("aria-label"));return r||u((e.getAttribute("aria-labelledby")??"").split(/\\s+/).filter(Boolean).map(l=>e.ownerDocument.getElementById(l)?.textContent??"").join(" "))},P=e=>x(e)||u(e.textContent)||u(Array.from(e.querySelectorAll("img[alt]")).map(r=>r.getAttribute("alt")).join(" "))||u(e.getAttribute("title")),T=e=>{let r=e.getAttribute("href")??"";return{href:r.startsWith("#")?r:e.href??r,name:P(e)}};u(i.title)||c("document-title",null),!u(i.documentElement.getAttribute("lang"))&&!n.locale&&c("document-language",null);let M=n.pages??(n.pageHeight&&n.pageHeight>0?Math.ceil(i.documentElement.scrollHeight/n.pageHeight):1),C=[],v=[],R={"masked-text":[],"filtered-text":[],"fixed-text":[]},w=(e,r)=>{R[e].some(l=>l.contains(r))||(R[e].push(r),c(e,r))},V=a&&ne(i),G=o?Array.from(o.querySelectorAll("*")).slice(0,j):[];for(let e of G){let r=e.tagName.toLowerCase();if(k.has(r)||H(e)||A(e))continue;if(r==="a"&&e.hasAttribute("href")){let g=T(e);C.push(g),!g.name&&!p(e)&&c("link-name",e)}if(!a)continue;let l=t.getComputedStyle(e),m=l.getPropertyValue("mask-image")||l.getPropertyValue("-webkit-mask-image");if(m&&m!=="none"&&y(e)&&w("masked-text",e),l.filter&&l.filter!=="none"&&y(e)&&w("filtered-text",e),l.position==="fixed"&&M>1&&y(e)&&w("fixed-text",e),V)for(let g of["::before","::after"]){let U=re(t.getComputedStyle(e,g).content);U&&c("generated-text",e,{text:U})}if(p(e))continue;r==="img"&&!E(e)?e.hasAttribute("alt")||x(e)||u(e.getAttribute("title"))||c("image-alt",e):(r==="canvas"||e.getAttribute("role")==="img"&&r!=="img")&&(x(e)||u(e.getAttribute("title"))||u(e.querySelector(":scope > title")?.textContent)||c("figure-name",e,{tag:r}));let h=/^h[1-6]$/.test(r)?Number(r[1]):e.getAttribute("role")==="heading"?Number(e.getAttribute("aria-level"))||2:0;h&&v.push({element:e,level:h}),r==="table"&&!E(e)&&Q(e,c)}let b=0;for(let{element:e,level:r}of v)(b===0?r!==1:r>b+1)&&c("heading-order",e,{level:r,previous:b}),b=r;let N=[],W=a&&o?D(J(o)):"",L=0;for(let e of["header","footer"])for(let r of z(i,e,n[e])){for(let l of Array.from(r.querySelectorAll("a[href]")))N.push(T(l));if(a)for(let{text:l,element:m}of K(r)){if(L>=q||W.includes(D(l)))continue;let h=s.length;c("running-text",m,{text:l.slice(0,80),part:e}),s.length>h&&L++}}return{findings:s,links:C,templateLinks:N}}function z(t,n,i){if(i!==void 0){if(!i.trim())return[];let o=new DOMParser().parseFromString(`<!doctype html><body>${i}</body>`,"text/html");return o.body?[o.body]:[]}return Array.from(t.querySelectorAll(`.ff-running-${n}, .formfeed-chrome[data-ff-chrome="${n}"]`))}function J(t){let n=[],i=o=>{if(o.nodeType===3){n.push(o.nodeValue??"");return}if(o.nodeType!==1)return;let s=o;if(!(k.has(s.tagName.toLowerCase())||s.matches(O)))for(let d of Array.from(o.childNodes))i(d)};return i(t),n.join(" ")}function K(t){let n=[],i=o=>{let s=o.tagName.toLowerCase();if(k.has(s)||o.matches(_))return;let d=Array.from(o.children).some(a=>a.matches(_));for(let a of Array.from(o.childNodes))if(a.nodeType===1)i(a);else if(a.nodeType===3&&!d)for(let c of(a.nodeValue??"").split(/\\s*[\xB7\u2022|]\\s*|\\s{2,}|\\n/)){let f=u(c);(f.toLowerCase().match(/[\\p{L}\\p{N}]+/gu)??[]).some(p=>!B.has(p))&&n.push({text:f,element:o})}};return i(t),n}function Q(t,n){let i=Array.from(t.rows);if(!(t.querySelector(\'th, [role="columnheader"], [role="rowheader"]\')!==null)){i.length>=2&&n("table-headers",t);return}let s=te(i),d=s.find(c=>c!==s[0]);d!==void 0&&n("table-rows",t,{first:s[0]??0,other:d});let a=i.flatMap(c=>Array.from(c.cells).filter(f=>f.tagName==="TD"&&ee(f)));a[0]&&n("table-cell-empty",a[0],{count:a.length})}var Z=\'img[alt]:not([alt=""]), svg, canvas, input, select, textarea, button, meter, progress\';function ee(t){return!/[^ \\t\\n\\r\\f]/.test(t.textContent??"")&&t.querySelector(Z)===null}function te(t){let n=[];return t.map(i=>{let o=[],s=0,d=()=>{for(;(n[s]??0)>0;)o[s]=n[s]-1,s++};for(let a of Array.from(i.cells)){d();let c=Math.max(1,a.rowSpan||1)-1;for(let f=Math.max(1,a.colSpan||1);f>0;f--)o[s++]=c}d();for(let a=s;a<n.length;a++)(n[a]??0)>0&&(o[a]=n[a]-1,s=a+1);return n=o,s})}function ne(t){let n=i=>{for(let o of Array.from(i??[])){let s=o;if(s.selectorText&&/::?(before|after)/.test(s.selectorText)&&s.style?.content||o.cssRules&&n(o.cssRules))return!0}return!1};for(let i of Array.from(t.styleSheets))try{if(n(i.cssRules))return!0}catch{return!0}return!1}function re(t){if(!t||t==="none"||t==="normal")return"";let n=(t.match(/"(?:[^"\\\\]|\\\\.)*"/g)??[]).map(o=>o.slice(1,-1).replace(/\\\\(.)/g,"$1"));if(/\\bcounters?\\(/.test(t))return u(t).slice(0,80);let i=u(n.join(""));return $(i)?i.slice(0,80):""}window.formfeedAudit=t=>F(window,t);})();';
5573
5645
 
5574
5646
  // packages/engine/src/lib/assemble.ts
5575
5647
  var DEFAULT_CHROME_PADDING = "0 10mm";
@@ -5824,6 +5896,23 @@ document.addEventListener('click', function (event) {
5824
5896
  }, true);
5825
5897
  </script>`;
5826
5898
  var textEditScript = `<script>${textEditRuntime.replace(/<\/script/gi, "<\\/script")}</script>`;
5899
+ function auditScript(mode) {
5900
+ return `<script>${auditRuntime.replace(/<\/script/gi, "<\\/script")}</script><script>
5901
+ (function () {
5902
+ window.formfeedRunAudit = function (pages) {
5903
+ try {
5904
+ var report = window.formfeedAudit({
5905
+ locale: true,
5906
+ pages: pages,
5907
+ pageHeight: parseFloat(getComputedStyle(document.body).minHeight) || 0,
5908
+ });
5909
+ parent.postMessage({ type: 'formfeed:audit', findings: report.findings }, '*');
5910
+ } catch (e) {}
5911
+ };
5912
+ ${mode === "flow" ? "window.addEventListener('load', function () { (document.fonts ? document.fonts.ready : Promise.resolve()).then(function () { window.formfeedRunAudit(); }); });" : ""}
5913
+ })();
5914
+ </script>`;
5915
+ }
5827
5916
  function documentMeta(options) {
5828
5917
  const name = (options.document ?? "").replace(/[^A-Za-z0-9_-]/g, "");
5829
5918
  return name ? `<meta name="formfeed:document" content="${name}">` : "";
@@ -5935,6 +6024,15 @@ function intoHead(document, markup) {
5935
6024
  ${markup}`
5936
6025
  );
5937
6026
  }
6027
+ function intoBody(document, atStart, atEnd = "") {
6028
+ const own = document.indexOf('<body class="formfeed-body');
6029
+ const open2 = own >= 0 ? own : document.search(/<body[^>]*>/);
6030
+ if (open2 < 0) return document;
6031
+ const content = document.indexOf(">", open2) + 1;
6032
+ const close = document.lastIndexOf("</body>");
6033
+ const end = close >= content ? close : document.length;
6034
+ return `${document.slice(0, content)}${atStart}${document.slice(content, end)}${atEnd}${document.slice(end)}`;
6035
+ }
5938
6036
  function chromeBoxStyle(settings, which) {
5939
6037
  const margin = settings.margin ?? {};
5940
6038
  const left = margin.left ?? "0px";
@@ -5958,12 +6056,16 @@ html { background: #e5e7eb; }
5958
6056
  body.formfeed-preview { position: relative; box-sizing: border-box; width: ${paper.width}; min-height: ${paper.height}; margin: 24px auto; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.2), 0 8px 24px rgba(0,0,0,.08); padding: ${margin.top ?? "0"} ${margin.right ?? "0"} ${margin.bottom ?? "0"} ${margin.left ?? "0"}; }
5959
6057
  .formfeed-chrome { color: #6b7280; font: 10px/1.3 system-ui, sans-serif; }
5960
6058
  </style>` : `<style data-formfeed="preview">html { background: #e5e7eb; } body.formfeed-preview { margin: 24px auto; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.2); }</style>`;
5961
- const header = headerHtml ? `<div class="formfeed-chrome" style="${pdf ? flowChromeStyle(settings, "header") : `${chromeBoxStyle(settings, "header")}margin-bottom:8px`}">${headerHtml}</div>` : "";
5962
- const footer = footerHtml ? `<div class="formfeed-chrome" style="${pdf ? flowChromeStyle(settings, "footer") : `${chromeBoxStyle(settings, "footer")}margin-top:8px`}">${pageNumberSpans(footerHtml, "1", "1")}</div>` : "";
5963
- return intoHead(
5964
- draft.document,
5965
- `${documentMeta(options)}${chrome}${options.editing ? textEditScript : ""}${inspectScript}${zoomGestureScript}${pdf ? overflowScript("flow") : ""}`
5966
- ).replace(/(<body[^>]*>)/, `$1${header}`).replace("</body>", `${footer}</body>`);
6059
+ const header = headerHtml ? `<div class="formfeed-chrome" data-ff-chrome="header" style="${pdf ? flowChromeStyle(settings, "header") : `${chromeBoxStyle(settings, "header")}margin-bottom:8px`}">${headerHtml}</div>` : "";
6060
+ const footer = footerHtml ? `<div class="formfeed-chrome" data-ff-chrome="footer" style="${pdf ? flowChromeStyle(settings, "footer") : `${chromeBoxStyle(settings, "footer")}margin-top:8px`}">${pageNumberSpans(footerHtml, "1", "1")}</div>` : "";
6061
+ return intoBody(
6062
+ intoHead(
6063
+ draft.document,
6064
+ `${documentMeta(options)}${chrome}${options.editing ? textEditScript : ""}${inspectScript}${zoomGestureScript}${pdf ? overflowScript("flow") : ""}${pdf && options.audit ? auditScript("flow") : ""}`
6065
+ ),
6066
+ header,
6067
+ footer
6068
+ );
5967
6069
  }
5968
6070
  function canvasDocument(draft) {
5969
6071
  const chrome = `<style data-formfeed="stage">html, body { background: transparent !important; margin: 0 !important; }</style>`;
@@ -5990,14 +6092,17 @@ html { background: #e5e7eb; }
5990
6092
  `;
5991
6093
  const selectorGuard = `<script>(function(){var q=DocumentFragment.prototype.querySelectorAll;DocumentFragment.prototype.querySelectorAll=function(s){try{return q.call(this,s);}catch(e){console.warn('formfeed paged preview: skipped a selector Paged.js could not use:',s);return q.call(this,':not(*)');}};})();</script>`;
5992
6094
  const boxSizingGuard = `<script>(function(){var rule='.pagedjs_pagebox *';var o=new MutationObserver(function(ms){ms.forEach(function(m){m.addedNodes.forEach(function(n){if(n.nodeName==='STYLE'&&n.textContent&&n.textContent.indexOf(rule)>=0){n.textContent=n.textContent.split(rule).join('.pagedjs_pagebox [class*="pagedjs_"]');o.disconnect();}});});});o.observe(document.documentElement,{childList:true,subtree:true});})();</script>`;
5993
- const config = `<script>window.PagedConfig = { auto: true, after: function (flow) { try { if (window.formfeedDrawCharts) window.formfeedDrawCharts(); } catch (e) {} try { if (window.formfeedFit) window.formfeedFit(); } catch (e) {} try { parent.postMessage({ type: 'formfeed:pages', pages: flow.total }, '*'); } catch (e) {} if (window.formfeedCheckOverflow) window.formfeedCheckOverflow(); try { if (window.formfeedEditReady) window.formfeedEditReady(); } catch (e) {} } };</script>`;
6095
+ const config = `<script>window.PagedConfig = { auto: true, after: function (flow) { try { if (window.formfeedDrawCharts) window.formfeedDrawCharts(); } catch (e) {} try { if (window.formfeedFit) window.formfeedFit(); } catch (e) {} try { parent.postMessage({ type: 'formfeed:pages', pages: flow.total }, '*'); } catch (e) {} if (window.formfeedCheckOverflow) window.formfeedCheckOverflow(); if (window.formfeedRunAudit) window.formfeedRunAudit(flow.total); try { if (window.formfeedEditReady) window.formfeedEditReady(); } catch (e) {} } };</script>`;
5994
6096
  const script = `<script src="${options.pagedScriptUrl}"></script>`;
5995
6097
  const header = headerHtml ? `<div class="ff-running-header">${pageNumberSpans(headerHtml, '<span class="ff-page-no"></span>', '<span class="ff-page-total"></span>')}</div>` : "";
5996
6098
  const footer = footerHtml ? `<div class="ff-running-footer">${pageNumberSpans(footerHtml, '<span class="ff-page-no"></span>', '<span class="ff-page-total"></span>')}</div>` : "";
5997
- return intoHead(
5998
- draft.document,
5999
- `${documentMeta(options)}<style data-formfeed="paged">${runningCss}</style>${selectorGuard}${boxSizingGuard}${overflowScript("paged")}${config}${script}${options.editing ? textEditScript : ""}${inspectScript}${pageNavScript}${zoomGestureScript}`
6000
- ).replace(/(<body[^>]*>)/, `$1${header}${footer}`);
6099
+ return intoBody(
6100
+ intoHead(
6101
+ draft.document,
6102
+ `${documentMeta(options)}<style data-formfeed="paged">${runningCss}</style>${selectorGuard}${boxSizingGuard}${overflowScript("paged")}${options.audit ? auditScript("paged") : ""}${config}${script}${options.editing ? textEditScript : ""}${inspectScript}${pageNavScript}${zoomGestureScript}`
6103
+ ),
6104
+ `${header}${footer}`
6105
+ );
6001
6106
  }
6002
6107
 
6003
6108
  // packages/engine/src/lib/source-scan.ts
@@ -6487,18 +6592,18 @@ function applyRegionEdit(source, engine, region, items) {
6487
6592
  const rewritten = source.slice(0, region.start) + whole + source.slice(region.end);
6488
6593
  return readsBack(rewritten, engine, region.tagStart, expected) ? { source: rewritten } : { error: "invalid" };
6489
6594
  }
6490
- function translationItems(text3) {
6595
+ function translationItems(text4) {
6491
6596
  const items = [];
6492
6597
  const names = [];
6493
6598
  let last = 0;
6494
- for (const match of text3.matchAll(/\{(\w+)\}/g)) {
6599
+ for (const match of text4.matchAll(/\{(\w+)\}/g)) {
6495
6600
  if (match.index > last)
6496
- items.push({ kind: "text", text: text3.slice(last, match.index) });
6601
+ items.push({ kind: "text", text: text4.slice(last, match.index) });
6497
6602
  items.push({ kind: "chip", index: names.length });
6498
6603
  names.push(match[1] ?? "");
6499
6604
  last = match.index + match[0].length;
6500
6605
  }
6501
- if (last < text3.length) items.push({ kind: "text", text: text3.slice(last) });
6606
+ if (last < text4.length) items.push({ kind: "text", text: text4.slice(last) });
6502
6607
  return { items, names };
6503
6608
  }
6504
6609
  function translationText(items, names) {
@@ -6742,9 +6847,9 @@ function translationCall(engine, inner) {
6742
6847
  );
6743
6848
  return match ? { key: match[2] ?? "", params: parseParams(match[3] ?? "", "=", " ") } : null;
6744
6849
  }
6745
- function parseParams(text3, assign, separator) {
6850
+ function parseParams(text4, assign, separator) {
6746
6851
  const params = {};
6747
- for (const piece of splitTopLevel(text3, separator)) {
6852
+ for (const piece of splitTopLevel(text4, separator)) {
6748
6853
  const at = piece.indexOf(assign);
6749
6854
  if (at <= 0) continue;
6750
6855
  const name = piece.slice(0, at).trim().replace(/^['"]|['"]$/g, "");
@@ -6752,12 +6857,12 @@ function parseParams(text3, assign, separator) {
6752
6857
  }
6753
6858
  return params;
6754
6859
  }
6755
- function splitTopLevel(text3, separator) {
6860
+ function splitTopLevel(text4, separator) {
6756
6861
  const pieces = [];
6757
6862
  let depth = 0;
6758
6863
  let quote2 = null;
6759
6864
  let current = "";
6760
- for (const ch of text3) {
6865
+ for (const ch of text4) {
6761
6866
  if (quote2) {
6762
6867
  if (ch === quote2) quote2 = null;
6763
6868
  } else if (ch === '"' || ch === "'") quote2 = ch;
@@ -6782,7 +6887,7 @@ function entityChar(reference) {
6782
6887
  return code === void 0 ? null : String.fromCharCode(code);
6783
6888
  }
6784
6889
  function decodeText2(raw) {
6785
- let text3 = "";
6890
+ let text4 = "";
6786
6891
  const map = [];
6787
6892
  let i = 0;
6788
6893
  while (i < raw.length) {
@@ -6792,23 +6897,23 @@ function decodeText2(raw) {
6792
6897
  const decoded = match ? entityChar(match[1] ?? "") : null;
6793
6898
  if (match && decoded !== null) {
6794
6899
  for (let u = 0; u < decoded.length; u++) map.push(i);
6795
- text3 += decoded;
6900
+ text4 += decoded;
6796
6901
  i += match[0].length;
6797
6902
  continue;
6798
6903
  }
6799
6904
  }
6800
- text3 += raw[i];
6905
+ text4 += raw[i];
6801
6906
  map.push(i);
6802
6907
  i++;
6803
6908
  }
6804
6909
  map.push(raw.length);
6805
- return { text: text3, map };
6910
+ return { text: text4, map };
6806
6911
  }
6807
- function encodeText(text3, keepNbsp, allBraces = false) {
6912
+ function encodeText(text4, keepNbsp, allBraces = false) {
6808
6913
  let out = "";
6809
- for (let k = 0; k < text3.length; k++) {
6810
- const ch = text3[k] ?? "";
6811
- const next = text3[k + 1];
6914
+ for (let k = 0; k < text4.length; k++) {
6915
+ const ch = text4[k] ?? "";
6916
+ const next = text4[k + 1];
6812
6917
  if (ch === "&") out += "&amp;";
6813
6918
  else if (ch === "<") out += "&lt;";
6814
6919
  else if (ch === ">") out += "&gt;";
@@ -6820,8 +6925,8 @@ function encodeText(text3, keepNbsp, allBraces = false) {
6820
6925
  }
6821
6926
  return out;
6822
6927
  }
6823
- function encodeTemplateText(text3) {
6824
- return encodeText(text3, true);
6928
+ function encodeTemplateText(text4) {
6929
+ return encodeText(text4, true);
6825
6930
  }
6826
6931
  function spanOf(part) {
6827
6932
  return part ? [part.start, part.end] : [0, 0];
@@ -6855,7 +6960,7 @@ function rewriteSegment(source, segStart, segEnd, parts, next, breakSpelling) {
6855
6960
  const to = map[old.length - suffix] ?? segEnd;
6856
6961
  const middle = next.slice(prefix, next.length - suffix);
6857
6962
  const keepNbsp = old.slice(prefix, old.length - suffix).includes(NBSP);
6858
- const written = middle.split(BREAK).map((text3) => encodeText(text3, keepNbsp)).join(breakSpelling);
6963
+ const written = middle.split(BREAK).map((text4) => encodeText(text4, keepNbsp)).join(breakSpelling);
6859
6964
  return source.slice(segStart, from) + written + source.slice(to, segEnd);
6860
6965
  }
6861
6966
  var isHighSurrogate = (code) => code >= 55296 && code <= 56319;
@@ -7610,11 +7715,11 @@ function googleFontsUrl(uses) {
7610
7715
 
7611
7716
  // packages/engine/src/lib/design/hash.ts
7612
7717
  function designOutputHash(html, css2) {
7613
- const text3 = `${html}\0${css2}`;
7718
+ const text4 = `${html}\0${css2}`;
7614
7719
  let a = 2166136261;
7615
7720
  let b = 16777619 ^ 2654435769;
7616
- for (let i = 0; i < text3.length; i++) {
7617
- const code = text3.charCodeAt(i);
7721
+ for (let i = 0; i < text4.length; i++) {
7722
+ const code = text4.charCodeAt(i);
7618
7723
  if (code === 13) continue;
7619
7724
  a = Math.imul(a ^ code, 16777619) >>> 0;
7620
7725
  b = Math.imul(b ^ code, 16777619) >>> 0;
@@ -7841,32 +7946,32 @@ function imageSource(source, engine) {
7841
7946
  return `{{ brand.logo.${source.brandLogo} }}`;
7842
7947
  }
7843
7948
  function layerCss(layer) {
7844
- const text3 = layer.type === "text" ? layer : null;
7949
+ const text4 = layer.type === "text" ? layer : null;
7845
7950
  const box = {
7846
7951
  left: px(layer.x),
7847
7952
  top: px(layer.y),
7848
7953
  width: px(layer.width),
7849
- height: text3?.sizing === "grow" ? void 0 : px(layer.height),
7954
+ height: text4?.sizing === "grow" ? void 0 : px(layer.height),
7850
7955
  opacity: layer.opacity < 1 ? num(layer.opacity) : void 0,
7851
7956
  transform: layer.rotation ? `rotate(${num(layer.rotation)}deg)` : void 0,
7852
7957
  "border-radius": layer.type === "shape" && layer.shape === "ellipse" ? "50%" : layer.radius ? px(layer.radius) : void 0,
7853
7958
  border: layer.stroke && layer.stroke.width > 0 ? `${px(layer.stroke.width)} solid ${paint(layer.stroke.paint)}` : void 0,
7854
- "box-shadow": layer.shadow && !text3 ? shadow(layer.shadow) : void 0
7959
+ "box-shadow": layer.shadow && !text4 ? shadow(layer.shadow) : void 0
7855
7960
  };
7856
- if (text3) {
7961
+ if (text4) {
7857
7962
  Object.assign(box, {
7858
7963
  display: "flex",
7859
7964
  "flex-direction": "column",
7860
- "justify-content": text3.valign === "middle" ? "center" : text3.valign === "bottom" ? "flex-end" : "flex-start",
7861
- overflow: text3.sizing === "grow" ? void 0 : "hidden",
7862
- padding: text3.padding ? px(text3.padding) : void 0,
7863
- background: text3.fill ? paint(text3.fill) : void 0
7965
+ "justify-content": text4.valign === "middle" ? "center" : text4.valign === "bottom" ? "flex-end" : "flex-start",
7966
+ overflow: text4.sizing === "grow" ? void 0 : "hidden",
7967
+ padding: text4.padding ? px(text4.padding) : void 0,
7968
+ background: text4.fill ? paint(text4.fill) : void 0
7864
7969
  });
7865
- const s = text3.style;
7866
- const clamp = text3.maxLines ? {
7970
+ const s = text4.style;
7971
+ const clamp = text4.maxLines ? {
7867
7972
  display: "-webkit-box",
7868
7973
  "-webkit-box-orient": "vertical",
7869
- "-webkit-line-clamp": String(text3.maxLines),
7974
+ "-webkit-line-clamp": String(text4.maxLines),
7870
7975
  overflow: "hidden"
7871
7976
  } : {};
7872
7977
  const inner = decl({
@@ -7882,7 +7987,7 @@ function layerCss(layer) {
7882
7987
  "font-style": s.italic ? "italic" : void 0,
7883
7988
  "text-transform": s.uppercase ? "uppercase" : void 0,
7884
7989
  "text-decoration": [s.underline && "underline", s.strike && "line-through"].filter(Boolean).join(" ") || void 0,
7885
- "text-shadow": text3.shadow ? shadow(text3.shadow) : void 0,
7990
+ "text-shadow": text4.shadow ? shadow(text4.shadow) : void 0,
7886
7991
  "overflow-wrap": "break-word",
7887
7992
  ...clamp
7888
7993
  });
@@ -8246,24 +8351,24 @@ var paymentMeansCodes = list2(
8246
8351
  // packages/engine/src/lib/einvoice/decimal.ts
8247
8352
  function decimalText(value) {
8248
8353
  if (typeof value === "string") {
8249
- const text4 = value.trim();
8250
- return /^-?\d+(\.\d+)?$/.test(text4) ? trimZeros(text4) : null;
8354
+ const text5 = value.trim();
8355
+ return /^-?\d+(\.\d+)?$/.test(text5) ? trimZeros(text5) : null;
8251
8356
  }
8252
8357
  if (typeof value !== "number" || !Number.isFinite(value)) return null;
8253
- const text3 = value.toPrecision(15);
8254
- return /^-?\d+(\.\d+)?$/.test(text3) ? trimZeros(text3) : null;
8358
+ const text4 = value.toPrecision(15);
8359
+ return /^-?\d+(\.\d+)?$/.test(text4) ? trimZeros(text4) : null;
8255
8360
  }
8256
- function trimZeros(text3) {
8257
- const trimmed = text3.includes(".") ? text3.replace(/0+$/, "").replace(/\.$/, "") : text3;
8361
+ function trimZeros(text4) {
8362
+ const trimmed = text4.includes(".") ? text4.replace(/0+$/, "").replace(/\.$/, "") : text4;
8258
8363
  return trimmed === "-0" ? "0" : trimmed;
8259
8364
  }
8260
- function decimalPlaces(text3) {
8261
- const dot = text3.indexOf(".");
8262
- return dot === -1 ? 0 : text3.length - dot - 1;
8365
+ function decimalPlaces(text4) {
8366
+ const dot = text4.indexOf(".");
8367
+ return dot === -1 ? 0 : text4.length - dot - 1;
8263
8368
  }
8264
- function toUnits(text3, scale) {
8265
- const negative = text3.startsWith("-");
8266
- const [whole = "0", fraction = ""] = (negative ? text3.slice(1) : text3).split(
8369
+ function toUnits(text4, scale) {
8370
+ const negative = text4.startsWith("-");
8371
+ const [whole = "0", fraction = ""] = (negative ? text4.slice(1) : text4).split(
8267
8372
  "."
8268
8373
  );
8269
8374
  const units = BigInt(whole + fraction.padEnd(scale, "0").slice(0, scale));
@@ -8274,13 +8379,13 @@ function fromUnits(units, scale, places = scale) {
8274
8379
  const digits = (negative ? -units : units).toString().padStart(scale + 1, "0");
8275
8380
  const whole = digits.slice(0, digits.length - scale);
8276
8381
  const fraction = digits.slice(digits.length - scale).padEnd(places, "0");
8277
- const text3 = places > 0 ? `${whole}.${fraction.slice(0, places)}` : whole;
8278
- return negative && /[1-9]/.test(text3) ? `-${text3}` : text3;
8382
+ const text4 = places > 0 ? `${whole}.${fraction.slice(0, places)}` : whole;
8383
+ return negative && /[1-9]/.test(text4) ? `-${text4}` : text4;
8279
8384
  }
8280
- function withPlaces(text3, min) {
8281
- const places = decimalPlaces(text3);
8282
- if (places >= min) return text3;
8283
- return places === 0 ? `${text3}.${"0".repeat(min)}` : text3 + "0".repeat(min - places);
8385
+ function withPlaces(text4, min) {
8386
+ const places = decimalPlaces(text4);
8387
+ if (places >= min) return text4;
8388
+ return places === 0 ? `${text4}.${"0".repeat(min)}` : text4 + "0".repeat(min - places);
8284
8389
  }
8285
8390
  function divideRounded(value, divisor) {
8286
8391
  const negative = value < 0n !== divisor < 0n;
@@ -8702,37 +8807,37 @@ function valueAt(data, path) {
8702
8807
  }
8703
8808
  function normalise(input, add2, options) {
8704
8809
  const amount2 = (value, path) => {
8705
- const text3 = decimalText(value);
8706
- if (text3 === null) {
8810
+ const text4 = decimalText(value);
8811
+ if (text4 === null) {
8707
8812
  add2("not_a_number", path, `_invoice.${path} is not a number`);
8708
8813
  return "0";
8709
8814
  }
8710
- if (decimalPlaces(text3) > 2) {
8815
+ if (decimalPlaces(text4) > 2) {
8711
8816
  add2(
8712
8817
  "decimals",
8713
8818
  path,
8714
8819
  `_invoice.${path} has more than 2 decimals; an amount of the invoice is exact to the cent`,
8715
8820
  {
8716
- args: { max: 2, value: text3 }
8821
+ args: { max: 2, value: text4 }
8717
8822
  }
8718
8823
  );
8719
8824
  return "0";
8720
8825
  }
8721
- return text3;
8826
+ return text4;
8722
8827
  };
8723
8828
  const number = (value, path, max2) => {
8724
- const text3 = decimalText(value);
8725
- if (text3 === null) {
8829
+ const text4 = decimalText(value);
8830
+ if (text4 === null) {
8726
8831
  add2("not_a_number", path, `_invoice.${path} is not a number`);
8727
8832
  return "0";
8728
8833
  }
8729
- if (decimalPlaces(text3) > max2) {
8834
+ if (decimalPlaces(text4) > max2) {
8730
8835
  add2("decimals", path, `_invoice.${path} has more than ${max2} decimals`, {
8731
- args: { max: max2, value: text3 }
8836
+ args: { max: max2, value: text4 }
8732
8837
  });
8733
8838
  return "0";
8734
8839
  }
8735
- return text3;
8840
+ return text4;
8736
8841
  };
8737
8842
  const optionalAmount = (value, path) => value === void 0 ? void 0 : amount2(value, path);
8738
8843
  const date2 = (value, path) => {
@@ -9110,7 +9215,7 @@ function defined(value) {
9110
9215
  Object.entries(value).filter(([, v]) => v !== void 0)
9111
9216
  );
9112
9217
  }
9113
- var cents = (text3) => text3 === void 0 ? 0n : toUnits(text3, 2);
9218
+ var cents = (text4) => text4 === void 0 ? 0n : toUnits(text4, 2);
9114
9219
  var money = (value) => fromUnits(value, 2);
9115
9220
  var rateKey = (tax) => `${tax.category}|${tax.rate ?? ""}`;
9116
9221
  function rules(invoice, add2) {
@@ -9570,14 +9675,14 @@ var CII_GUIDELINES = {
9570
9675
  en16931: "urn:cen.eu:en16931:2017"
9571
9676
  };
9572
9677
  var EINVOICE_XML_NAME = "factur-x.xml";
9573
- function leaf(name, text3, attributes) {
9574
- if (text3 === void 0 || text3 === "") return void 0;
9678
+ function leaf(name, text4, attributes) {
9679
+ if (text4 === void 0 || text4 === "") return void 0;
9575
9680
  const kept = Object.entries(attributes ?? {}).filter(
9576
9681
  (entry) => entry[1] !== void 0
9577
9682
  );
9578
9683
  return {
9579
9684
  name,
9580
- text: text3,
9685
+ text: text4,
9581
9686
  ...kept.length > 0 ? { attributes: Object.fromEntries(kept) } : {}
9582
9687
  };
9583
9688
  }
@@ -9834,14 +9939,14 @@ function invoiceToCii(invoice, options) {
9834
9939
  ${serialise(root, 0)}`;
9835
9940
  }
9836
9941
  var xmlCharacter = (code) => code === 9 || code === 10 || code === 13 || code >= 32 && !(code >= 55296 && code <= 57343) && code !== 65534 && code !== 65535;
9837
- function carried(text3) {
9942
+ function carried(text4) {
9838
9943
  let out = "";
9839
- for (const character of text3)
9944
+ for (const character of text4)
9840
9945
  if (xmlCharacter(character.codePointAt(0) ?? 0)) out += character;
9841
9946
  return out;
9842
9947
  }
9843
- var escapeText2 = (text3) => carried(text3).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
9844
- var escapeAttribute2 = (text3) => escapeText2(text3).replace(/"/g, "&quot;");
9948
+ var escapeText2 = (text4) => carried(text4).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
9949
+ var escapeAttribute2 = (text4) => escapeText2(text4).replace(/"/g, "&quot;");
9845
9950
  function serialise(element, depth) {
9846
9951
  const indent = " ".repeat(depth);
9847
9952
  const attributes = Object.entries(element.attributes ?? {}).map(([name, value]) => ` ${name}="${escapeAttribute2(value)}"`).join("");
@@ -9875,7 +9980,7 @@ var DASHES = /* @__PURE__ */ new Set([45, 8208, 8209, 8210, 8211, 8722]);
9875
9980
  var INVISIBLE = /* @__PURE__ */ new Set([173, 8203, 8204, 8205, 8288, 65279]);
9876
9981
  var isDigit = (code) => code >= DIGIT_0 && code <= DIGIT_9;
9877
9982
  var MAX_GROUPS = 6;
9878
- function shownAmounts(text3) {
9983
+ function shownAmounts(text4) {
9879
9984
  const found = /* @__PURE__ */ new Set();
9880
9985
  let run2 = "";
9881
9986
  const flush = () => {
@@ -9899,7 +10004,7 @@ function shownAmounts(text3) {
9899
10004
  }
9900
10005
  }
9901
10006
  };
9902
- for (const character of text3) {
10007
+ for (const character of text4) {
9903
10008
  const code = character.codePointAt(0) ?? 0;
9904
10009
  if (INVISIBLE.has(code)) continue;
9905
10010
  if (isDigit(code)) run2 += character;
@@ -9939,9 +10044,9 @@ function toCents(whole, fraction) {
9939
10044
  if (whole.length > 18 || /[1-9]/.test(fraction.slice(2))) return null;
9940
10045
  return BigInt(whole) * 100n + BigInt((fraction + "00").slice(0, 2));
9941
10046
  }
9942
- function squeeze(text3) {
10047
+ function squeeze(text4) {
9943
10048
  let out = "";
9944
- for (const character of text3) {
10049
+ for (const character of text4) {
9945
10050
  const code = character.codePointAt(0) ?? 0;
9946
10051
  if (INVISIBLE.has(code) || /\s/.test(character) || SPACES.has(code))
9947
10052
  continue;
@@ -9949,8 +10054,8 @@ function squeeze(text3) {
9949
10054
  }
9950
10055
  return out;
9951
10056
  }
9952
- function displayCheck(text3, invoice) {
9953
- const whole = typeof text3 === "string" ? text3 : text3.join("\n");
10057
+ function displayCheck(text4, invoice) {
10058
+ const whole = typeof text4 === "string" ? text4 : text4.join("\n");
9954
10059
  const amounts = shownAmounts(whole);
9955
10060
  const squeezed = squeeze(whole);
9956
10061
  const values = [];
@@ -10016,97 +10121,97 @@ function invoicePathSegments(path) {
10016
10121
  }
10017
10122
  return segments;
10018
10123
  }
10019
- function locateJsonPath(text3, path) {
10020
- let offset = skipSpace(text3, 0);
10021
- if (offset >= text3.length) return null;
10124
+ function locateJsonPath(text4, path) {
10125
+ let offset = skipSpace(text4, 0);
10126
+ if (offset >= text4.length) return null;
10022
10127
  let best = { offset, depth: 0 };
10023
10128
  try {
10024
10129
  for (let depth = 0; depth < path.length; depth += 1) {
10025
10130
  const segment = path[depth];
10026
- const found = typeof segment === "number" ? arrayItem(text3, offset, segment) : objectMember(text3, offset, String(segment));
10131
+ const found = typeof segment === "number" ? arrayItem(text4, offset, segment) : objectMember(text4, offset, String(segment));
10027
10132
  if (!found) break;
10028
10133
  best = { offset: found.at, depth: depth + 1 };
10029
10134
  offset = found.value;
10030
10135
  }
10031
10136
  } catch {
10032
10137
  }
10033
- return { ...positionAt(text3, best.offset), depth: best.depth };
10138
+ return { ...positionAt(text4, best.offset), depth: best.depth };
10034
10139
  }
10035
- function positionAt(text3, offset) {
10140
+ function positionAt(text4, offset) {
10036
10141
  let line2 = 1;
10037
10142
  let lineStart = 0;
10038
10143
  for (let i = 0; i < offset; i += 1)
10039
- if (text3.charCodeAt(i) === 10) {
10144
+ if (text4.charCodeAt(i) === 10) {
10040
10145
  line2 += 1;
10041
10146
  lineStart = i + 1;
10042
10147
  }
10043
10148
  return { line: line2, column: offset - lineStart + 1 };
10044
10149
  }
10045
- function skipSpace(text3, from) {
10150
+ function skipSpace(text4, from) {
10046
10151
  let i = from;
10047
- while (i < text3.length && /\s/.test(text3[i] ?? "")) i += 1;
10152
+ while (i < text4.length && /\s/.test(text4[i] ?? "")) i += 1;
10048
10153
  return i;
10049
10154
  }
10050
- function stringEnd(text3, from) {
10051
- if (text3[from] !== '"') throw new Error("string");
10052
- for (let i = from + 1; i < text3.length; i += 1) {
10053
- if (text3[i] === "\\") i += 1;
10054
- else if (text3[i] === '"') return i + 1;
10155
+ function stringEnd(text4, from) {
10156
+ if (text4[from] !== '"') throw new Error("string");
10157
+ for (let i = from + 1; i < text4.length; i += 1) {
10158
+ if (text4[i] === "\\") i += 1;
10159
+ else if (text4[i] === '"') return i + 1;
10055
10160
  }
10056
10161
  throw new Error("string");
10057
10162
  }
10058
- function valueEnd(text3, from) {
10059
- const start = skipSpace(text3, from);
10060
- const first = text3[start];
10061
- if (first === '"') return stringEnd(text3, start);
10163
+ function valueEnd(text4, from) {
10164
+ const start = skipSpace(text4, from);
10165
+ const first = text4[start];
10166
+ if (first === '"') return stringEnd(text4, start);
10062
10167
  if (first === "{" || first === "[") {
10063
10168
  const close = first === "{" ? "}" : "]";
10064
- let i2 = skipSpace(text3, start + 1);
10065
- if (text3[i2] === close) return i2 + 1;
10169
+ let i2 = skipSpace(text4, start + 1);
10170
+ if (text4[i2] === close) return i2 + 1;
10066
10171
  for (; ; ) {
10067
10172
  if (first === "{") {
10068
- i2 = skipSpace(text3, stringEnd(text3, skipSpace(text3, i2)));
10069
- if (text3[i2] !== ":") throw new Error("colon");
10173
+ i2 = skipSpace(text4, stringEnd(text4, skipSpace(text4, i2)));
10174
+ if (text4[i2] !== ":") throw new Error("colon");
10070
10175
  i2 += 1;
10071
10176
  }
10072
- i2 = skipSpace(text3, valueEnd(text3, i2));
10073
- if (text3[i2] === close) return i2 + 1;
10074
- if (text3[i2] !== ",") throw new Error("comma");
10177
+ i2 = skipSpace(text4, valueEnd(text4, i2));
10178
+ if (text4[i2] === close) return i2 + 1;
10179
+ if (text4[i2] !== ",") throw new Error("comma");
10075
10180
  i2 += 1;
10076
10181
  }
10077
10182
  }
10078
10183
  let i = start;
10079
- while (i < text3.length && !/[\s,\]}]/.test(text3[i] ?? "")) i += 1;
10184
+ while (i < text4.length && !/[\s,\]}]/.test(text4[i] ?? "")) i += 1;
10080
10185
  if (i === start) throw new Error("value");
10081
10186
  return i;
10082
10187
  }
10083
- function objectMember(text3, from, key) {
10084
- const start = skipSpace(text3, from);
10085
- if (text3[start] !== "{") return null;
10086
- let i = skipSpace(text3, start + 1);
10087
- while (text3[i] !== "}") {
10088
- const at = skipSpace(text3, i);
10089
- const end = stringEnd(text3, at);
10090
- const colon = skipSpace(text3, end);
10091
- if (text3[colon] !== ":") throw new Error("colon");
10092
- const value = skipSpace(text3, colon + 1);
10093
- if (JSON.parse(text3.slice(at, end)) === key) return { at, value };
10094
- i = skipSpace(text3, valueEnd(text3, value));
10095
- if (text3[i] === ",") i = skipSpace(text3, i + 1);
10096
- else if (text3[i] !== "}") throw new Error("comma");
10188
+ function objectMember(text4, from, key) {
10189
+ const start = skipSpace(text4, from);
10190
+ if (text4[start] !== "{") return null;
10191
+ let i = skipSpace(text4, start + 1);
10192
+ while (text4[i] !== "}") {
10193
+ const at = skipSpace(text4, i);
10194
+ const end = stringEnd(text4, at);
10195
+ const colon = skipSpace(text4, end);
10196
+ if (text4[colon] !== ":") throw new Error("colon");
10197
+ const value = skipSpace(text4, colon + 1);
10198
+ if (JSON.parse(text4.slice(at, end)) === key) return { at, value };
10199
+ i = skipSpace(text4, valueEnd(text4, value));
10200
+ if (text4[i] === ",") i = skipSpace(text4, i + 1);
10201
+ else if (text4[i] !== "}") throw new Error("comma");
10097
10202
  }
10098
10203
  return null;
10099
10204
  }
10100
- function arrayItem(text3, from, index) {
10101
- const start = skipSpace(text3, from);
10102
- if (text3[start] !== "[") return null;
10103
- let i = skipSpace(text3, start + 1);
10104
- for (let n = 0; text3[i] !== "]"; n += 1) {
10105
- const at = skipSpace(text3, i);
10205
+ function arrayItem(text4, from, index) {
10206
+ const start = skipSpace(text4, from);
10207
+ if (text4[start] !== "[") return null;
10208
+ let i = skipSpace(text4, start + 1);
10209
+ for (let n = 0; text4[i] !== "]"; n += 1) {
10210
+ const at = skipSpace(text4, i);
10106
10211
  if (n === index) return { at, value: at };
10107
- i = skipSpace(text3, valueEnd(text3, at));
10108
- if (text3[i] === ",") i = skipSpace(text3, i + 1);
10109
- else if (text3[i] !== "]") throw new Error("comma");
10212
+ i = skipSpace(text4, valueEnd(text4, at));
10213
+ if (text4[i] === ",") i = skipSpace(text4, i + 1);
10214
+ else if (text4[i] !== "]") throw new Error("comma");
10110
10215
  }
10111
10216
  return null;
10112
10217
  }
@@ -10219,8 +10324,8 @@ var ENTITIES = {
10219
10324
  agrave: 224,
10220
10325
  ccedil: 231
10221
10326
  };
10222
- function decodeEntities(text3) {
10223
- return text3.replace(
10327
+ function decodeEntities(text4) {
10328
+ return text4.replace(
10224
10329
  /&(#x[0-9a-f]+|#\d+|[a-z][a-z0-9]*);/gi,
10225
10330
  (whole, reference) => {
10226
10331
  const code = reference.startsWith("#") ? reference[1] === "x" || reference[1] === "X" ? Number.parseInt(reference.slice(2), 16) : Number.parseInt(reference.slice(1), 10) : ENTITIES[reference];
@@ -10346,6 +10451,320 @@ function einvoiceXml(data, options) {
10346
10451
  };
10347
10452
  }
10348
10453
 
10454
+ // packages/engine/src/lib/accessibility/index.ts
10455
+ var PDFUA_STANDARD = "PDF/UA-1";
10456
+ var UA_CHECKS = ["strict", "report"];
10457
+ function resolveUa(setting) {
10458
+ if (setting === true) return { check: "strict" };
10459
+ if (!setting || typeof setting !== "object" || Array.isArray(setting))
10460
+ return null;
10461
+ const check = setting.check;
10462
+ return { check: check === "report" ? "report" : "strict" };
10463
+ }
10464
+ var UA_REFUSALS = {
10465
+ office: "pdf.ua is not available for Word and PowerPoint templates yet",
10466
+ merge: "pdf.ua cannot be combined with post.merge_after: the tags of merged documents do not survive the merge"
10467
+ };
10468
+ function isUaSetting(value) {
10469
+ if (value === null || typeof value === "boolean") return true;
10470
+ if (typeof value !== "object" || Array.isArray(value)) return false;
10471
+ const entries = Object.entries(value);
10472
+ return entries.every(
10473
+ ([key, entry]) => key === "check" && UA_CHECKS.includes(entry)
10474
+ );
10475
+ }
10476
+ var AUDIT_CODES = [
10477
+ "document-title",
10478
+ "image-alt",
10479
+ "figure-name",
10480
+ "heading-order",
10481
+ "table-rows",
10482
+ "table-cell-empty",
10483
+ "masked-text",
10484
+ "filtered-text",
10485
+ "document-language",
10486
+ "table-headers",
10487
+ "link-name",
10488
+ "generated-text",
10489
+ "fixed-text",
10490
+ "running-text"
10491
+ ];
10492
+ var AUDIT_SEVERITY = {
10493
+ "document-title": "error",
10494
+ "image-alt": "error",
10495
+ "figure-name": "error",
10496
+ "heading-order": "error",
10497
+ "table-rows": "error",
10498
+ "table-cell-empty": "error",
10499
+ "masked-text": "error",
10500
+ "filtered-text": "warning",
10501
+ "document-language": "warning",
10502
+ "table-headers": "warning",
10503
+ "link-name": "warning",
10504
+ "generated-text": "warning",
10505
+ "fixed-text": "warning",
10506
+ "running-text": "warning"
10507
+ };
10508
+ var AUDIT_RULES = {
10509
+ "document-title": ["7.1-9", "7.1-10"],
10510
+ "image-alt": ["7.3-1"],
10511
+ "figure-name": ["7.3-1"],
10512
+ "heading-order": ["7.4.2-1"],
10513
+ "table-rows": ["7.2-43"],
10514
+ "table-cell-empty": ["7.2-43"],
10515
+ "masked-text": ["7.20-2"],
10516
+ "filtered-text": [],
10517
+ "document-language": [],
10518
+ "table-headers": [],
10519
+ "link-name": [],
10520
+ "generated-text": [],
10521
+ "fixed-text": [],
10522
+ "running-text": []
10523
+ };
10524
+ var AUDIT_TITLES = {
10525
+ "document-title": "No document title",
10526
+ "image-alt": "Image without an alt attribute",
10527
+ "figure-name": "Figure without a name",
10528
+ "heading-order": "Heading level skipped",
10529
+ "table-rows": "Table rows of different lengths",
10530
+ "table-cell-empty": "Empty table cell",
10531
+ "masked-text": "Text under a CSS mask",
10532
+ "filtered-text": "Text under a CSS filter",
10533
+ "document-language": "No language stated",
10534
+ "table-headers": "Table without header cells",
10535
+ "link-name": "Link without a name",
10536
+ "generated-text": "Text generated by CSS",
10537
+ "fixed-text": "Fixed text on every page",
10538
+ "running-text": "Only in the header or footer"
10539
+ };
10540
+ var AUDIT_SNIPPET_LENGTH = 120;
10541
+ var text3 = (value) => String(value ?? "");
10542
+ function auditMessage(finding2) {
10543
+ const args = finding2.args;
10544
+ switch (finding2.code) {
10545
+ case "document-title":
10546
+ return "The document has no title. A PDF viewer shows the title in its title bar and a screen reader says it first: set pdf.metadata.title, or give the page a <title>.";
10547
+ case "image-alt":
10548
+ return 'The image has no alt attribute. Say what it shows, or write alt="" if it is decoration.';
10549
+ case "figure-name":
10550
+ return `The ${text3(args["tag"])} has no text alternative. Give it an aria-label that says what it shows; the chart helper takes alt.`;
10551
+ case "heading-order":
10552
+ return args["previous"] === 0 ? `The first heading is an h${text3(args["level"])}. Start with an h1 and size it with CSS.` : `This h${text3(args["level"])} follows an h${text3(args["previous"])}, so a heading level is skipped. Make it an h${Number(args["previous"]) + 1} and size it with CSS.`;
10553
+ case "table-rows":
10554
+ return `The rows of this table span different numbers of columns (${text3(args["first"])} and ${text3(args["other"])}). Even them out with colspan.`;
10555
+ case "table-cell-empty":
10556
+ return Number(args["count"]) > 1 ? `${text3(args["count"])} cells of this table are empty. Chromium writes no cell for an empty td, so their rows come out shorter than the others: put a non-breaking space (&nbsp;) or a dash into each.` : "This table cell is empty. Chromium writes no cell for an empty td, so its row comes out shorter than the others: put a non-breaking space (&nbsp;) or a dash into it.";
10557
+ case "masked-text":
10558
+ return "This element has a CSS mask and holds text. Chromium then writes the text in a way PDF/UA-1 does not allow, and no repair reaches it: mask an element without text instead.";
10559
+ case "filtered-text":
10560
+ return "This element has a CSS filter and holds text. The filter turns the text into a picture, which nobody can have read out or select.";
10561
+ case "document-language":
10562
+ return "The document names no language. Set lang on the html element, or the locale in the settings.";
10563
+ case "table-headers":
10564
+ return "The table has no header cells. Use th for the titles of its columns or rows, or a screen reader says the cells without them.";
10565
+ case "link-name":
10566
+ return "The link has no text. A screen reader says its address instead: give it text, an aria-label, or an image with alt.";
10567
+ case "generated-text":
10568
+ return `\u201C${text3(args["text"])}\u201D comes from CSS (::before or ::after). Generated text is not read out: write it into the template.`;
10569
+ case "fixed-text":
10570
+ return "This element is position: fixed, so it is printed on every page and read once per page, one after the other.";
10571
+ case "running-text":
10572
+ return `\u201C${text3(args["text"])}\u201D stands only in the ${text3(args["part"])}. A screen reader skips page headers and footers, so say it in the body too.`;
10573
+ }
10574
+ }
10575
+ var ACCESSIBILITY_MAX_FAILURES = 20;
10576
+ var ACCESSIBILITY_MAX_ELEMENTS = 5;
10577
+ var elementOf = (finding2) => finding2.code === "running-text" || finding2.code === "generated-text" ? text3(finding2.args["text"]) : finding2.snippet;
10578
+ function accessibilityResult(options, verdict, findings) {
10579
+ const failures = verdict.failures.map((failure) => {
10580
+ const about = findings.filter(
10581
+ (finding2) => AUDIT_RULES[finding2.code].includes(failure.rule)
10582
+ );
10583
+ const first = about[0];
10584
+ return {
10585
+ rule: failure.rule,
10586
+ ...first ? { code: first.code } : {},
10587
+ count: failure.checks,
10588
+ message: first ? auditMessage(first) : failure.description.replace(/\s+/g, " ").trim(),
10589
+ elements: [...new Set(about.map(elementOf).filter(Boolean))].slice(
10590
+ 0,
10591
+ ACCESSIBILITY_MAX_ELEMENTS
10592
+ )
10593
+ };
10594
+ });
10595
+ const warnings = [];
10596
+ for (const finding2 of findings) {
10597
+ if (finding2.severity !== "warning") continue;
10598
+ let warning = warnings.find((entry) => entry.code === finding2.code);
10599
+ if (!warning)
10600
+ warnings.push(warning = { code: finding2.code, count: 0, elements: [] });
10601
+ warning.count++;
10602
+ const element = elementOf(finding2);
10603
+ if (element && warning.elements.length < ACCESSIBILITY_MAX_ELEMENTS && !warning.elements.includes(element))
10604
+ warning.elements.push(element);
10605
+ }
10606
+ return {
10607
+ standard: PDFUA_STANDARD,
10608
+ check: options.check,
10609
+ conformant: verdict.compliant,
10610
+ validator: verdict.validator,
10611
+ rules: verdict.rules,
10612
+ failures: failures.slice(0, ACCESSIBILITY_MAX_FAILURES),
10613
+ warnings,
10614
+ ...failures.length > ACCESSIBILITY_MAX_FAILURES ? { truncated: true } : {}
10615
+ };
10616
+ }
10617
+ function accessibilityHeader(result) {
10618
+ return result.conformant ? "conformant" : "not-conformant";
10619
+ }
10620
+ var ACCESSIBILITY_HEADER_LENGTH = 8e3;
10621
+ function accessibilityHeaderValue(result, limit = ACCESSIBILITY_HEADER_LENGTH) {
10622
+ const encode = (report2) => encodeURIComponent(JSON.stringify(report2));
10623
+ const keep = (report2, elements) => ({
10624
+ ...report2,
10625
+ truncated: true,
10626
+ failures: report2.failures.map((failure) => ({
10627
+ ...failure,
10628
+ elements: failure.elements.slice(0, elements)
10629
+ })),
10630
+ warnings: report2.warnings.map((warning) => ({
10631
+ ...warning,
10632
+ elements: warning.elements.slice(0, elements)
10633
+ }))
10634
+ });
10635
+ let value = encode(result);
10636
+ if (value.length <= limit) return value;
10637
+ for (const elements of [1, 0]) {
10638
+ value = encode(keep(result, elements));
10639
+ if (value.length <= limit) return value;
10640
+ }
10641
+ let report = keep(result, 0);
10642
+ while (report.failures.length + report.warnings.length > 0) {
10643
+ report = report.warnings.length ? { ...report, warnings: report.warnings.slice(0, -1) } : { ...report, failures: report.failures.slice(0, -1) };
10644
+ value = encode(report);
10645
+ if (value.length <= limit) return value;
10646
+ }
10647
+ return value;
10648
+ }
10649
+
10650
+ // packages/engine/src/lib/accessibility/static.ts
10651
+ var finding = (code, src, snippet) => ({
10652
+ code,
10653
+ severity: AUDIT_SEVERITY[code],
10654
+ src,
10655
+ snippet,
10656
+ args: {}
10657
+ });
10658
+ var NAMING = /* @__PURE__ */ new Set(["alt", "aria-label", "aria-labelledby", "title"]);
10659
+ function imageIsNamed(attributes, scanner, base) {
10660
+ const n = attributes.length;
10661
+ let i = 0;
10662
+ let named = false;
10663
+ while (i < n) {
10664
+ const ch = attributes[i];
10665
+ if (/[\s/>]/.test(ch)) {
10666
+ i++;
10667
+ continue;
10668
+ }
10669
+ if (ch === "{" && scanner.skipTemplate(base + i) !== null) return null;
10670
+ const start = i;
10671
+ while (i < n && !/[\s=/>]/.test(attributes[i])) i++;
10672
+ const name = attributes.slice(start, i).toLowerCase();
10673
+ while (i < n && /\s/.test(attributes[i])) i++;
10674
+ let value = "";
10675
+ if (attributes[i] === "=") {
10676
+ i++;
10677
+ while (i < n && /\s/.test(attributes[i])) i++;
10678
+ const quote2 = attributes[i];
10679
+ if (quote2 === '"' || quote2 === "'") {
10680
+ const end = scanner.skipTo(base + i + 1, quote2) - base;
10681
+ value = attributes.slice(i + 1, Math.max(i + 1, end - 1));
10682
+ i = end;
10683
+ } else {
10684
+ const from = i;
10685
+ while (i < n && !/[\s>]/.test(attributes[i])) i++;
10686
+ value = attributes.slice(from, i);
10687
+ }
10688
+ }
10689
+ if (NAMING.has(name)) named = true;
10690
+ else if (name === "aria-hidden" && value.trim() !== "false") named = true;
10691
+ else if (name === "role" && /^(presentation|none)$/.test(value.trim()))
10692
+ named = true;
10693
+ }
10694
+ return named;
10695
+ }
10696
+ function staticAuditDiagnostics(input, ua) {
10697
+ return staticAudit(input).map((found) => {
10698
+ const at = /^body:(\d+):(\d+)$/.exec(found.src ?? "");
10699
+ return {
10700
+ severity: found.severity === "error" && ua.check === "strict" ? "error" : "warning",
10701
+ code: `accessibility-${found.code}`,
10702
+ message: auditMessage(found),
10703
+ ...at ? { location: { line: Number(at[1]), column: Number(at[2]) } } : {}
10704
+ };
10705
+ });
10706
+ }
10707
+ function staticAudit(input) {
10708
+ const findings = [];
10709
+ if (!input.title?.trim() && !/<title[\s>]/i.test(input.head ?? ""))
10710
+ findings.push(finding("document-title", null, ""));
10711
+ const source = input.html;
10712
+ const scanner = new Scanner(source, input.engine);
10713
+ const lines = lineStarts(source);
10714
+ const n = source.length;
10715
+ let i = 0;
10716
+ while (i < n) {
10717
+ const ch = source[i];
10718
+ if (ch === "{") {
10719
+ i = scanner.skipTemplate(i) ?? i + 1;
10720
+ continue;
10721
+ }
10722
+ if (ch !== "<") {
10723
+ i++;
10724
+ continue;
10725
+ }
10726
+ if (source.startsWith("<!--", i)) {
10727
+ i = scanner.skipTo(i + 4, "-->");
10728
+ continue;
10729
+ }
10730
+ const next = source[i + 1];
10731
+ if (next === "!" || next === "?") {
10732
+ i = scanner.tagEnd(i + 2);
10733
+ continue;
10734
+ }
10735
+ if (next === "/") {
10736
+ i += 2;
10737
+ continue;
10738
+ }
10739
+ tagName.lastIndex = i + 1;
10740
+ const name = tagName.exec(source)?.[0];
10741
+ if (!name) {
10742
+ i++;
10743
+ continue;
10744
+ }
10745
+ const nameEnd = i + 1 + name.length;
10746
+ const end = scanner.tagEnd(nameEnd);
10747
+ if (name.toLowerCase() === "img") {
10748
+ const named = imageIsNamed(source.slice(nameEnd, end), scanner, nameEnd);
10749
+ if (named === false) {
10750
+ const { line: line2, column } = locate(lines, i);
10751
+ const tag = source.slice(i, end).replace(/\s+/g, " ");
10752
+ findings.push(
10753
+ finding(
10754
+ "image-alt",
10755
+ `body:${line2}:${column}`,
10756
+ tag.length > AUDIT_SNIPPET_LENGTH ? `${tag.slice(0, AUDIT_SNIPPET_LENGTH - 1)}\u2026` : tag
10757
+ )
10758
+ );
10759
+ }
10760
+ }
10761
+ i = end;
10762
+ if (rawTextElements.has(name.toLowerCase()) && source[end - 1] === ">")
10763
+ i = scanner.skipToClosingTag(end, name);
10764
+ }
10765
+ return findings;
10766
+ }
10767
+
10349
10768
  // packages/engine/src/lib/office/errors.ts
10350
10769
  var OfficeError = class extends Error {
10351
10770
  constructor(code, message, details = {}) {
@@ -11665,12 +12084,12 @@ function assertWellFormed(tokens, part) {
11665
12084
  }
11666
12085
  var FORBIDDEN = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
11667
12086
  var ENTITY = /&(?:#x[0-9A-Fa-f]+|#\d+|amp|lt|gt|quot|apos);/y;
11668
- function checkText(text3, part) {
11669
- if (FORBIDDEN.test(text3)) throw invalid2("a character XML does not allow", part);
11670
- if (text3.includes("<")) throw invalid2("unescaped < in text", part);
11671
- for (let i = text3.indexOf("&"); i !== -1; i = text3.indexOf("&", i + 1)) {
12087
+ function checkText(text4, part) {
12088
+ if (FORBIDDEN.test(text4)) throw invalid2("a character XML does not allow", part);
12089
+ if (text4.includes("<")) throw invalid2("unescaped < in text", part);
12090
+ for (let i = text4.indexOf("&"); i !== -1; i = text4.indexOf("&", i + 1)) {
11672
12091
  ENTITY.lastIndex = i;
11673
- if (!ENTITY.test(text3)) throw invalid2(`invalid entity reference near "${text3.slice(i, i + 12)}"`, part);
12092
+ if (!ENTITY.test(text4)) throw invalid2(`invalid entity reference near "${text4.slice(i, i + 12)}"`, part);
11674
12093
  }
11675
12094
  }
11676
12095
  function checkAttributes(raw, part) {
@@ -11705,13 +12124,13 @@ function decodeText3(raw) {
11705
12124
  }
11706
12125
  });
11707
12126
  }
11708
- function escapeText3(text3) {
11709
- return text3.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
12127
+ function escapeText3(text4) {
12128
+ return text4.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
11710
12129
  }
11711
12130
  var FORBIDDEN_GLOBAL = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g;
11712
- function stripForbidden(text3) {
12131
+ function stripForbidden(text4) {
11713
12132
  let removed = 0;
11714
- const out = text3.replace(FORBIDDEN_GLOBAL, () => {
12133
+ const out = text4.replace(FORBIDDEN_GLOBAL, () => {
11715
12134
  removed++;
11716
12135
  return "";
11717
12136
  });
@@ -11962,13 +12381,13 @@ function placeDrawings(xml2, pattern, markupFor) {
11962
12381
  pattern.lastIndex = 0;
11963
12382
  if (pattern.test(t.raw)) {
11964
12383
  const segments = t.raw.split(pattern);
11965
- let text3 = segments[0];
12384
+ let text4 = segments[0];
11966
12385
  for (let s = 1; s < segments.length; s += 2) {
11967
12386
  const index = Number(segments[s]);
11968
- text3 += `</w:t></w:r><w:r>${runProps}${markupFor(index)}</w:r>${runOpen}${runProps}<w:t xml:space="preserve">` + segments[s + 1];
12387
+ text4 += `</w:t></w:r><w:r>${runProps}${markupFor(index)}</w:r>${runOpen}${runProps}<w:t xml:space="preserve">` + segments[s + 1];
11969
12388
  }
11970
12389
  out[textOpen] = withPreserve(out[textOpen]);
11971
- out.push(text3);
12390
+ out.push(text4);
11972
12391
  continue;
11973
12392
  }
11974
12393
  }
@@ -12223,11 +12642,11 @@ function fromTemplateOutput(output, template, part) {
12223
12642
  let last = 0;
12224
12643
  let inText = false;
12225
12644
  const emit = (segment) => {
12226
- const { text: text3, removed } = stripForbidden(segment);
12645
+ const { text: text4, removed } = stripForbidden(segment);
12227
12646
  removedCharacters += removed;
12228
- if (!inText && text3.trim() !== "")
12229
- throw new OfficeError("office_document_invalid", `${part ?? "part"}: text outside a text element: "${text3.trim().slice(0, 40)}"`);
12230
- xml2 += escapeText3(text3);
12647
+ if (!inText && text4.trim() !== "")
12648
+ throw new OfficeError("office_document_invalid", `${part ?? "part"}: text outside a text element: "${text4.trim().slice(0, 40)}"`);
12649
+ xml2 += escapeText3(text4);
12231
12650
  };
12232
12651
  for (const m of output.matchAll(placeholder)) {
12233
12652
  emit(output.slice(last, m.index));
@@ -12269,15 +12688,15 @@ function layoutText(xml2, flavour, part) {
12269
12688
  out.push(token2.raw);
12270
12689
  continue;
12271
12690
  }
12272
- const text3 = token2.raw.replace(/\r\n?/g, "\n");
12691
+ const text4 = token2.raw.replace(/\r\n?/g, "\n");
12273
12692
  if (flavour === "wordprocessing") {
12274
- const pieces = text3.split(/(\n|\t)/);
12275
- if (pieces.length > 1 || /^\s|\s$/.test(text3)) out[textOpenIndex] = preserveSpace(out[textOpenIndex]);
12693
+ const pieces = text4.split(/(\n|\t)/);
12694
+ if (pieces.length > 1 || /^\s|\s$/.test(text4)) out[textOpenIndex] = preserveSpace(out[textOpenIndex]);
12276
12695
  out.push(
12277
12696
  pieces.map((p) => p === "\n" ? '</w:t><w:br/><w:t xml:space="preserve">' : p === " " ? '</w:t><w:tab/><w:t xml:space="preserve">' : p).join("")
12278
12697
  );
12279
12698
  } else {
12280
- out.push(text3.split("\n").join(`</a:t></a:r><a:br>${runProperties}</a:br><a:r>${runProperties}<a:t>`));
12699
+ out.push(text4.split("\n").join(`</a:t></a:r><a:br>${runProperties}</a:br><a:r>${runProperties}<a:t>`));
12281
12700
  }
12282
12701
  }
12283
12702
  return out.join("");
@@ -12310,17 +12729,17 @@ var AUTOCORRECTED = [
12310
12729
  [/\u200B|\u200C|\u200D|\uFEFF/g, ""]
12311
12730
  ];
12312
12731
  function normaliseTags(template, part) {
12313
- const { text: text3, origin, placeholders } = stripPlaceholders(template);
12732
+ const { text: text4, origin, placeholders } = stripPlaceholders(template);
12314
12733
  const sourceRange = (from, to) => [
12315
12734
  origin[from] ?? template.source.length,
12316
12735
  (origin[to - 1] ?? template.source.length - 1) + 1
12317
12736
  ];
12318
12737
  const diagnostics = [];
12319
12738
  const edits = [];
12320
- for (const tag of findTags(text3)) {
12739
+ for (const tag of findTags(text4)) {
12321
12740
  const inside = placeholders.filter((p) => p.at > tag.start && p.at < tag.end);
12322
12741
  const paragraph2 = paragraphOf(template, placeholders, tag.start);
12323
- const raw = text3.slice(tag.start, tag.end);
12742
+ const raw = text4.slice(tag.start, tag.end);
12324
12743
  const unsafe = inside.filter((p) => {
12325
12744
  const piece = template.markup[p.index];
12326
12745
  return !piece || piece.paragraphBoundary || piece.containerBoundary;
@@ -12374,8 +12793,8 @@ function normaliseTags(template, part) {
12374
12793
  return { template: { ...template, source: applyEdits(template.source, edits) }, diagnostics };
12375
12794
  }
12376
12795
  var ENTITIES2 = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'" };
12377
- function decodeEntities2(text3) {
12378
- return text3.replace(/&(#x[0-9a-f]+|#\d+|amp|lt|gt|quot|apos);/gi, (whole, name) => {
12796
+ function decodeEntities2(text4) {
12797
+ return text4.replace(/&(#x[0-9a-f]+|#\d+|amp|lt|gt|quot|apos);/gi, (whole, name) => {
12379
12798
  if (name[0] !== "#") return ENTITIES2[name.toLowerCase()] ?? whole;
12380
12799
  const code = name[1] === "x" || name[1] === "X" ? parseInt(name.slice(2), 16) : parseInt(name.slice(1), 10);
12381
12800
  return Number.isFinite(code) ? String.fromCodePoint(code) : whole;
@@ -12383,28 +12802,28 @@ function decodeEntities2(text3) {
12383
12802
  }
12384
12803
  function stripPlaceholders(template) {
12385
12804
  const pattern = placeholderPattern(template.nonce);
12386
- let text3 = "";
12805
+ let text4 = "";
12387
12806
  const origin = [];
12388
12807
  const placeholders = [];
12389
12808
  let last = 0;
12390
12809
  for (const m of template.source.matchAll(pattern)) {
12391
12810
  for (let i = last; i < (m.index ?? 0); i++) {
12392
- text3 += template.source[i];
12811
+ text4 += template.source[i];
12393
12812
  origin.push(i);
12394
12813
  }
12395
- placeholders.push({ index: Number(m[1]), at: text3.length, from: m.index ?? 0, to: (m.index ?? 0) + m[0].length });
12814
+ placeholders.push({ index: Number(m[1]), at: text4.length, from: m.index ?? 0, to: (m.index ?? 0) + m[0].length });
12396
12815
  last = (m.index ?? 0) + m[0].length;
12397
12816
  }
12398
12817
  for (let i = last; i < template.source.length; i++) {
12399
- text3 += template.source[i];
12818
+ text4 += template.source[i];
12400
12819
  origin.push(i);
12401
12820
  }
12402
- return { text: text3, origin, placeholders };
12821
+ return { text: text4, origin, placeholders };
12403
12822
  }
12404
12823
  function listTags(template, part) {
12405
- const { text: text3, placeholders } = stripPlaceholders(template);
12406
- return findTags(text3).map((tag) => {
12407
- const raw = text3.slice(tag.start, tag.end);
12824
+ const { text: text4, placeholders } = stripPlaceholders(template);
12825
+ return findTags(text4).map((tag) => {
12826
+ const raw = text4.slice(tag.start, tag.end);
12408
12827
  const kind = raw.startsWith("{#") ? "comment" : raw.startsWith("{%") || /^\{\{~?\s*[#/^]/.test(raw) || /^\{\{~?\s*else\b/.test(raw) ? "block" : "output";
12409
12828
  return { part, paragraph: paragraphOf(template, placeholders, tag.start), text: raw.replace(/\s+/g, " ").trim(), kind };
12410
12829
  });
@@ -12425,15 +12844,15 @@ function undoAutocorrect(tag) {
12425
12844
  for (const [pattern, replacement] of AUTOCORRECTED) out = out.replace(pattern, replacement);
12426
12845
  return out;
12427
12846
  }
12428
- function findTags(text3) {
12847
+ function findTags(text4) {
12429
12848
  const tags = [];
12430
- for (let i = 0; i < text3.length - 1; i++) {
12431
- const opener = OPENERS.find((o) => text3.startsWith(o, i));
12849
+ for (let i = 0; i < text4.length - 1; i++) {
12850
+ const opener = OPENERS.find((o) => text4.startsWith(o, i));
12432
12851
  if (!opener) continue;
12433
12852
  const closer = CLOSERS[opener];
12434
- const end = text3.indexOf(closer, i + opener.length);
12853
+ const end = text4.indexOf(closer, i + opener.length);
12435
12854
  if (end === -1) continue;
12436
- const stop = end + closer.length + (opener === "{{" && text3[end + closer.length] === "}" ? 1 : 0);
12855
+ const stop = end + closer.length + (opener === "{{" && text4[end + closer.length] === "}" ? 1 : 0);
12437
12856
  tags.push({ start: i, end: stop });
12438
12857
  i = stop - 1;
12439
12858
  }
@@ -12463,8 +12882,8 @@ var CONTENT = /* @__PURE__ */ new Set(["w:drawing", "w:pict", "w:object", "w:fld
12463
12882
  var JINJA_OPEN = /^(for|if|unless|case|capture|raw|with|macro|call|filter|block|tablerow|comment|autoescape)\b/;
12464
12883
  var JINJA_CLOSE = /^end(for|if|unless|case|capture|raw|with|macro|call|filter|block|tablerow|comment|autoescape)\b/;
12465
12884
  var JINJA_MIDDLE = /^(else|elif|elsif|when)\b/;
12466
- function blockRole(text3) {
12467
- const t = text3.trim();
12885
+ function blockRole(text4) {
12886
+ const t = text4.trim();
12468
12887
  let m = /^\{%-?\s*([\s\S]*?)\s*-?%\}$/.exec(t);
12469
12888
  if (m && !t.slice(2, -2).includes("%}")) {
12470
12889
  const body = m[1] ?? "";
@@ -12496,14 +12915,14 @@ function dropTaggedFallbacks(xml2, part) {
12496
12915
  if (t.kind === "open" && t.name === "mc:Fallback" && !t.selfClosing) {
12497
12916
  let depth = 1;
12498
12917
  let j = i + 1;
12499
- let text3 = "";
12918
+ let text4 = "";
12500
12919
  for (; j < tokens.length && depth > 0; j++) {
12501
12920
  const u = tokens[j];
12502
12921
  if (u.kind === "open" && u.name === "mc:Fallback" && !u.selfClosing) depth++;
12503
12922
  else if (u.kind === "close" && u.name === "mc:Fallback") depth--;
12504
- else if (u.kind === "text") text3 += decodeText3(u.raw);
12923
+ else if (u.kind === "text") text4 += decodeText3(u.raw);
12505
12924
  }
12506
- if (/\{\{|\{%|\{#/.test(text3)) {
12925
+ if (/\{\{|\{%|\{#/.test(text4)) {
12507
12926
  i = j - 1;
12508
12927
  continue;
12509
12928
  }
@@ -12576,9 +12995,9 @@ function applyStructure(xml2, part) {
12576
12995
  for (const [span, s] of structural) {
12577
12996
  if (rowOf.has(span)) continue;
12578
12997
  const keep = s.info.sectionProperties;
12579
- let text3 = element(s.tag);
12580
- if (keep) text3 = s.role === "open" ? `<w:p>${keep}</w:p>${text3}` : `${text3}<w:p>${keep}</w:p>`;
12581
- replacements.push({ start: span.start, end: span.end, text: text3 });
12998
+ let text4 = element(s.tag);
12999
+ if (keep) text4 = s.role === "open" ? `<w:p>${keep}</w:p>${text4}` : `${text4}<w:p>${keep}</w:p>`;
13000
+ replacements.push({ start: span.start, end: span.end, text: text4 });
12582
13001
  const holder = span.parent && BODIES.has(span.parent.name) ? span.parent : null;
12583
13002
  if (holder && !keep) cellsEmptied.set(holder, (cellsEmptied.get(holder) ?? 0) + 1);
12584
13003
  }
@@ -12632,7 +13051,7 @@ function collectParagraphs(tokens, root) {
12632
13051
  const out = [];
12633
13052
  const walk3 = (span) => {
12634
13053
  if (PARAGRAPH.has(span.name)) {
12635
- let text3 = "";
13054
+ let text4 = "";
12636
13055
  let hasContent = false;
12637
13056
  let sectionProperties = null;
12638
13057
  let inText = false;
@@ -12643,10 +13062,10 @@ function collectParagraphs(tokens, root) {
12643
13062
  else if (CONTENT.has(t.name)) hasContent = true;
12644
13063
  else if (t.name === "w:sectPr") sectionProperties = "";
12645
13064
  } else if (t.kind === "close" && TEXT.has(t.name)) inText = false;
12646
- else if (t.kind === "text" && inText) text3 += decodeText3(t.raw);
13065
+ else if (t.kind === "text" && inText) text4 += decodeText3(t.raw);
12647
13066
  }
12648
13067
  if (sectionProperties !== null) sectionProperties = propertiesOf(tokens, span);
12649
- out.push({ span, number: out.length + 1, text: text3, hasContent, sectionProperties });
13068
+ out.push({ span, number: out.length + 1, text: text4, hasContent, sectionProperties });
12650
13069
  }
12651
13070
  for (const child2 of span.children) walk3(child2);
12652
13071
  };
@@ -12754,7 +13173,7 @@ function placeSlidePictures(xml2, pattern, drawingFor, pictureMarkup, slide) {
12754
13173
  for (const container of containers) {
12755
13174
  const indexes = [];
12756
13175
  const edits = [];
12757
- let text3 = "";
13176
+ let text4 = "";
12758
13177
  let inText = false;
12759
13178
  for (let i = container.start + 1; i < container.end; i++) {
12760
13179
  const t = tokens[i];
@@ -12763,7 +13182,7 @@ function placeSlidePictures(xml2, pattern, drawingFor, pictureMarkup, slide) {
12763
13182
  else if (t.kind === "text" && inText) {
12764
13183
  pattern.lastIndex = 0;
12765
13184
  if (!pattern.test(t.raw)) {
12766
- text3 += decodeText3(t.raw);
13185
+ text4 += decodeText3(t.raw);
12767
13186
  continue;
12768
13187
  }
12769
13188
  const segments = t.raw.split(pattern);
@@ -12772,7 +13191,7 @@ function placeSlidePictures(xml2, pattern, drawingFor, pictureMarkup, slide) {
12772
13191
  if (s % 2 === 1) indexes.push(Number(segments[s]));
12773
13192
  else kept += segments[s];
12774
13193
  }
12775
- text3 += decodeText3(kept);
13194
+ text4 += decodeText3(kept);
12776
13195
  edits.push({ at: i, raw: kept });
12777
13196
  }
12778
13197
  }
@@ -12791,7 +13210,7 @@ function placeSlidePictures(xml2, pattern, drawingFor, pictureMarkup, slide) {
12791
13210
  }
12792
13211
  const autoFit = tokens.slice(container.start, container.end).some((t) => t.kind === "open" && t.name === "a:spAutoFit");
12793
13212
  const placed = layoutPictures(pictures, box, autoFit).map((b, i) => pictureMarkup(pictures[i], b)).join("");
12794
- const onlyPictures = container.name === "p:sp" && text3.trim() === "";
13213
+ const onlyPictures = container.name === "p:sp" && text4.trim() === "";
12795
13214
  if (onlyPictures) replacements.push({ start: container.start, end: container.end, text: placed });
12796
13215
  else {
12797
13216
  for (const edit of edits) replacements.push({ start: edit.at, end: edit.at, text: edit.raw });
@@ -13064,8 +13483,8 @@ function starterTags(engine) {
13064
13483
  codeFit: engine === "liquid" ? "{{ offer.url | qrcode }}" : "{{ qrcode(offer.url) }}"
13065
13484
  };
13066
13485
  }
13067
- var paragraph = (text3, style2, bold = false) => `<w:p>${style2 ? `<w:pPr><w:pStyle w:val="${style2}"/></w:pPr>` : ""}<w:r>${bold ? "<w:rPr><w:b/></w:rPr>" : ""}<w:t xml:space="preserve">${escapeText3(text3)}</w:t></w:r></w:p>`;
13068
- var cell = (text3, width, bold = false) => `<w:tc><w:tcPr><w:tcW w:w="${width}" w:type="dxa"/></w:tcPr>${paragraph(text3, void 0, bold)}</w:tc>`;
13486
+ var paragraph = (text4, style2, bold = false) => `<w:p>${style2 ? `<w:pPr><w:pStyle w:val="${style2}"/></w:pPr>` : ""}<w:r>${bold ? "<w:rPr><w:b/></w:rPr>" : ""}<w:t xml:space="preserve">${escapeText3(text4)}</w:t></w:r></w:p>`;
13487
+ var cell = (text4, width, bold = false) => `<w:tc><w:tcPr><w:tcW w:w="${width}" w:type="dxa"/></w:tcPr>${paragraph(text4, void 0, bold)}</w:tc>`;
13069
13488
  var row = (cells) => `<w:tr>${cells}</w:tr>`;
13070
13489
  function starterDocument(engine) {
13071
13490
  const t = starterTags(engine);
@@ -13108,7 +13527,7 @@ function starterDocument(engine) {
13108
13527
  ["word/document.xml", `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:w="${W}"><w:body>${body}</w:body></w:document>`]
13109
13528
  ];
13110
13529
  return {
13111
- bytes: writeZip(files.map(([name, text3]) => ({ name, data: encoder2.encode(text3) }))),
13530
+ bytes: writeZip(files.map(([name, text4]) => ({ name, data: encoder2.encode(text4) }))),
13112
13531
  sampleData: starterSampleData()
13113
13532
  };
13114
13533
  }
@@ -13136,15 +13555,15 @@ var CM = 36e4;
13136
13555
  var FONT = "Carlito";
13137
13556
  var ACCENT = "0F766E";
13138
13557
  var emptyTree = '<p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr/>';
13139
- var run = (text3, size, options = {}) => `<a:r><a:rPr lang="en-GB" sz="${size * 100}"${options.bold ? ' b="1"' : ""} dirty="0">${options.color ? `<a:solidFill><a:srgbClr val="${options.color}"/></a:solidFill>` : ""}<a:latin typeface="${FONT}"/></a:rPr><a:t>${escapeText3(text3)}</a:t></a:r>`;
13140
- var para = (text3, size, options = {}) => `<a:p>${run(text3, size, options)}</a:p>`;
13558
+ var run = (text4, size, options = {}) => `<a:r><a:rPr lang="en-GB" sz="${size * 100}"${options.bold ? ' b="1"' : ""} dirty="0">${options.color ? `<a:solidFill><a:srgbClr val="${options.color}"/></a:solidFill>` : ""}<a:latin typeface="${FONT}"/></a:rPr><a:t>${escapeText3(text4)}</a:t></a:r>`;
13559
+ var para = (text4, size, options = {}) => `<a:p>${run(text4, size, options)}</a:p>`;
13141
13560
  function textBox(id, name, x, y, cx, cy, paragraphs) {
13142
13561
  return `<p:sp><p:nvSpPr><p:cNvPr id="${id}" name="${name}"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr><p:spPr><a:xfrm><a:off x="${x}" y="${y}"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/></p:spPr><p:txBody><a:bodyPr wrap="square" rtlCol="0"><a:noAutofit/></a:bodyPr><a:lstStyle/>${paragraphs}</p:txBody></p:sp>`;
13143
13562
  }
13144
- function cell2(text3, header) {
13563
+ function cell2(text4, header) {
13145
13564
  const fill = header ? `<a:solidFill><a:srgbClr val="${ACCENT}"/></a:solidFill>` : "<a:noFill/>";
13146
13565
  const line2 = `<a:lnB w="6350"><a:solidFill><a:srgbClr val="BFBFBF"/></a:solidFill></a:lnB>`;
13147
- return `<a:tc><a:txBody><a:bodyPr/><a:lstStyle/>${para(text3, 14, header ? { bold: true, color: "FFFFFF" } : {})}</a:txBody><a:tcPr marL="91440" marR="91440" marT="45720" marB="45720">${line2}${fill}</a:tcPr></a:tc>`;
13566
+ return `<a:tc><a:txBody><a:bodyPr/><a:lstStyle/>${para(text4, 14, header ? { bold: true, color: "FFFFFF" } : {})}</a:txBody><a:tcPr marL="91440" marR="91440" marT="45720" marB="45720">${line2}${fill}</a:tcPr></a:tc>`;
13148
13567
  }
13149
13568
  var tableRow = (a, b, header = false) => `<a:tr h="${Math.round(0.9 * CM)}">${cell2(a, header)}${cell2(b, header)}</a:tr>`;
13150
13569
  function table2(id, x, y, rows) {
@@ -13234,7 +13653,7 @@ function starterPresentation(engine) {
13234
13653
  ];
13235
13654
  const encoder2 = new TextEncoder();
13236
13655
  return {
13237
- bytes: writeZip(files.map(([name, text3]) => ({ name, data: encoder2.encode(text3) }))),
13656
+ bytes: writeZip(files.map(([name, text4]) => ({ name, data: encoder2.encode(text4) }))),
13238
13657
  sampleData: starterSampleData()
13239
13658
  };
13240
13659
  }