ooxml-core 0.21.2 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/README.md +3 -4
  2. package/dist/automation/index.cjs +86 -22
  3. package/dist/automation/index.mjs +86 -22
  4. package/dist/chart/index.cjs +242 -0
  5. package/dist/chart/index.d.ts +5 -0
  6. package/dist/chart/index.d.ts.map +1 -1
  7. package/dist/chart/index.mjs +227 -1
  8. package/dist/chart/pie-best-fit.d.ts +51 -0
  9. package/dist/chart/pie-best-fit.d.ts.map +1 -0
  10. package/dist/chart/pie-label-collision.d.ts +48 -0
  11. package/dist/chart/pie-label-collision.d.ts.map +1 -0
  12. package/dist/chart/radar-geometry.d.ts +19 -0
  13. package/dist/chart/radar-geometry.d.ts.map +1 -0
  14. package/dist/chart/treemap-squarify.d.ts +31 -0
  15. package/dist/chart/treemap-squarify.d.ts.map +1 -0
  16. package/dist/chart/trendline-equation.d.ts +39 -0
  17. package/dist/chart/trendline-equation.d.ts.map +1 -0
  18. package/dist/collab/index.cjs +6 -1
  19. package/dist/collab/index.mjs +6 -1
  20. package/dist/color/contrast.d.ts +18 -0
  21. package/dist/color/contrast.d.ts.map +1 -0
  22. package/dist/color/index.cjs +33 -0
  23. package/dist/color/index.d.ts +2 -0
  24. package/dist/color/index.d.ts.map +1 -1
  25. package/dist/color/index.mjs +31 -1
  26. package/dist/color/unit-rgb.d.ts +21 -0
  27. package/dist/color/unit-rgb.d.ts.map +1 -0
  28. package/dist/docx/embedded.cjs +1 -1
  29. package/dist/docx/embedded.mjs +1 -1
  30. package/dist/docx/index.cjs +1 -1
  31. package/dist/docx/index.mjs +1 -1
  32. package/dist/docx/load/index.cjs +1 -1
  33. package/dist/docx/load/index.mjs +1 -1
  34. package/dist/geometry/align-distribute.d.ts +145 -0
  35. package/dist/geometry/align-distribute.d.ts.map +1 -0
  36. package/dist/geometry/index.cjs +318 -0
  37. package/dist/geometry/index.d.ts +2 -0
  38. package/dist/geometry/index.d.ts.map +1 -1
  39. package/dist/geometry/index.mjs +307 -1
  40. package/dist/geometry/snap-guides.d.ts +125 -0
  41. package/dist/geometry/snap-guides.d.ts.map +1 -0
  42. package/dist/index.cjs +665 -0
  43. package/dist/index.mjs +665 -0
  44. package/dist/pptx/automation/index.cjs +24 -1
  45. package/dist/pptx/automation/index.d.ts +3 -3
  46. package/dist/pptx/automation/index.mjs +24 -1
  47. package/dist/pptx/chunks/{index-JaNVJ6Tf.d.ts → index-D2y7ehZ5.d.ts} +3 -3
  48. package/dist/pptx/chunks/{index-JaNVJ6Tf.d.ts.map → index-D2y7ehZ5.d.ts.map} +1 -1
  49. package/dist/pptx/chunks/{index-DHdHU9Qr.d.ts → index-ucqKcqvI.d.ts} +10 -2
  50. package/dist/pptx/chunks/{index-DHdHU9Qr.d.ts.map → index-ucqKcqvI.d.ts.map} +1 -1
  51. package/dist/pptx/chunks/{text-operations-DUEhSW5Z.d.ts → text-operations-CR3pUJi-.d.ts} +14 -2
  52. package/dist/pptx/chunks/text-operations-CR3pUJi-.d.ts.map +1 -0
  53. package/dist/pptx/cli/index.cjs +23 -0
  54. package/dist/pptx/cli/index.d.ts +1 -1
  55. package/dist/pptx/cli/index.mjs +23 -0
  56. package/dist/pptx/converter/index.d.ts +1 -1
  57. package/dist/pptx/index.cjs +33 -3
  58. package/dist/pptx/index.d.ts +3 -3
  59. package/dist/pptx/index.mjs +33 -3
  60. package/dist/teams/index.cjs +7 -2
  61. package/dist/teams/index.mjs +7 -2
  62. package/dist/text/decimal-tab.d.ts +24 -0
  63. package/dist/text/decimal-tab.d.ts.map +1 -0
  64. package/dist/text/index.cjs +72 -0
  65. package/dist/text/index.d.ts +2 -0
  66. package/dist/text/index.d.ts.map +1 -1
  67. package/dist/text/index.mjs +68 -1
  68. package/dist/text/tab-leader.d.ts +36 -0
  69. package/dist/text/tab-leader.d.ts.map +1 -0
  70. package/dist/xlsx/edit/charts.d.ts.map +1 -1
  71. package/dist/xlsx/edit/clipboard-html-parse.d.ts.map +1 -1
  72. package/dist/xlsx/edit/fill-series.d.ts.map +1 -1
  73. package/dist/xlsx/index.cjs +85 -21
  74. package/dist/xlsx/index.mjs +85 -21
  75. package/dist/xlsx/load/csv.d.ts.map +1 -1
  76. package/dist/xlsx/load/index.cjs +17 -8
  77. package/dist/xlsx/load/index.mjs +17 -8
  78. package/dist/xlsx/numfmt/input-date.d.ts.map +1 -1
  79. package/dist/xlsx/ui/grid/cell-paint.d.ts.map +1 -1
  80. package/dist/xlsx/ui/index.cjs +86 -25
  81. package/dist/xlsx/ui/index.mjs +86 -25
  82. package/dist/xlsx/ui/selection.d.ts.map +1 -1
  83. package/dist/xlsx/write/drawing.d.ts.map +1 -1
  84. package/package.json +2 -2
  85. package/dist/pptx/chunks/text-operations-DUEhSW5Z.d.ts.map +0 -1
package/README.md CHANGED
@@ -9,7 +9,6 @@
9
9
  **Read, edit, validate and write Office Open XML documents in TypeScript.**
10
10
  One package, one XML model, every format: Word, PowerPoint, Excel and the shared building blocks beneath them. Visio VSDX parsing and bounded editing are available through `ooxml-core/visio`.
11
11
 
12
- [![license](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
13
12
  [![CI](https://github.com/ChristopherVR/ooxml/actions/workflows/ci.yml/badge.svg)](https://github.com/ChristopherVR/ooxml/actions/workflows/ci.yml)
14
13
  [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md)
15
14
 
@@ -17,7 +16,7 @@ One package, one XML model, every format: Word, PowerPoint, Excel and the shared
17
16
  [**Packages and areas**](#features-and-api-one-package-many-areas)  · 
18
17
  [**Install**](#install)  · 
19
18
  [**Examples**](#quick-start)  · 
20
- [**Contributing**](CONTRIBUTING.md)
19
+ [**Contributing**](../../CONTRIBUTING.md)
21
20
 
22
21
  </div>
23
22
 
@@ -63,7 +62,7 @@ The `chart` subpath provides shared chart data calculations (regression, quartil
63
62
  blank values and stacked series). The `text` subpath provides script-category
64
63
  segmentation primitives. These areas are DOM-free and do not import a product model.
65
64
  SVG curve flattening is available from `geometry`. See the
66
- [PowerPoint reuse audit](docs/pptx-shared-logic-audit.md) for extraction evidence
65
+ [PowerPoint reuse audit](../../docs/pptx-shared-logic-audit.md) for extraction evidence
67
66
  and remaining candidates.
68
67
 
69
68
  ## Install
@@ -110,7 +109,7 @@ const part = resolvePartPath('word/document.xml', rels.get('rId5')!.target);
110
109
 
111
110
  ## Contributing and roadmap
112
111
 
113
- `ooxml-core` is developed in the [ChristopherVR/ooxml](https://github.com/ChristopherVR/ooxml) repository, which also holds [`ooxml-ui`](https://www.npmjs.com/package/ooxml-ui), the MCP servers and the Word, Excel, Visio and OpenTeams viewers. Its README covers the repository layout, the development workflow and releases, and the [roadmap](https://github.com/ChristopherVR/ooxml/blob/main/docs/roadmap.md) says what comes next; the working agreements are in [AGENTS.md](AGENTS.md) and [CONTRIBUTING.md](CONTRIBUTING.md), and [PROVENANCE.md](PROVENANCE.md) records where each module came from.
112
+ `ooxml-core` is developed in the [ChristopherVR/ooxml](https://github.com/ChristopherVR/ooxml) repository, which also holds [`ooxml-ui`](https://www.npmjs.com/package/ooxml-ui), the MCP servers and the Word, Excel, Visio and OpenTeams viewers. Its README covers the repository layout, the development workflow and releases, and the [roadmap](https://github.com/ChristopherVR/ooxml/blob/main/docs/roadmap.md) says what comes next; the working agreements are in [AGENTS.md](../../AGENTS.md) and [CONTRIBUTING.md](../../CONTRIBUTING.md), and [PROVENANCE.md](../../PROVENANCE.md) records where each module came from.
114
113
 
115
114
  ## License
116
115
 
@@ -1404,7 +1404,7 @@ async function applyCoreProperties(zip, next, prior) {
1404
1404
  await ensureContentTypeOverride(zip, CORE_PATH, CORE_TYPE);
1405
1405
  const rels = zip.file("_rels/.rels");
1406
1406
  const relsXml = await rels?.async("string") ?? '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"></Relationships>';
1407
- if (!relsXml.includes(CORE_REL)) {
1407
+ if (!relsXml.includes(`Type="${CORE_REL}"`)) {
1408
1408
  const ids = [...relsXml.matchAll(/Id="rId(\d+)"/g)].map((match2) => Number(match2[1]));
1409
1409
  const id = `rId${Math.max(0, ...ids) + 1}`;
1410
1410
  zip.file(
@@ -11855,7 +11855,10 @@ function writeDrawing(writer, partName, objects, sourceDrawing) {
11855
11855
  let nextId = Math.max(
11856
11856
  1,
11857
11857
  ...kept.flatMap(
11858
- (xml) => [...xml.matchAll(/cNvPr[^>]*\sid="(\d+)"/g)].map((m) => Number(m[1]))
11858
+ (xml) => [...xml.matchAll(/cNvPr([^>]*)/g)].flatMap((m) => {
11859
+ const id = /\sid="(\d+)"/.exec(m[1] ?? "");
11860
+ return id ? [Number(id[1])] : [];
11861
+ })
11859
11862
  )
11860
11863
  ) + 1;
11861
11864
  let body = "";
@@ -12841,7 +12844,8 @@ function parseDay(text) {
12841
12844
  function parseDateTimeInput(text, date1904) {
12842
12845
  const time = parseTime(text);
12843
12846
  if (time) return { value: time.fraction, numFmt: time.format };
12844
- const split = /^(.+?)(?:\s+|T)(\d{1,2}:\d{1,2}(?::\d{1,2})?(?:\s*(?:am|pm|a|p))?)$/i.exec(text);
12847
+ const tail = /(?:\s{1,8}|T)(\d{1,2}:\d{1,2}(?::\d{1,2})?(?:\s{0,8}(?:am|pm|a|p))?)$/i.exec(text);
12848
+ const split = tail && tail.index > 0 ? [tail[0], text.slice(0, tail.index), tail[1]] : null;
12845
12849
  const dayText = split ? split[1] ?? "" : text;
12846
12850
  const day = parseDay(dayText);
12847
12851
  if (!day) return void 0;
@@ -12886,10 +12890,10 @@ function parseNumberInput(text) {
12886
12890
  s = s.slice(lead[0].length);
12887
12891
  if (!sign()) return void 0;
12888
12892
  } else {
12889
- const trail = /\s*([€£])$/.exec(s);
12890
- if (trail) {
12891
- currency = trail[1] ?? "";
12892
- s = s.slice(0, -trail[0].length);
12893
+ const last = s.slice(-1);
12894
+ if (last === "\u20AC" || last === "\xA3") {
12895
+ currency = last;
12896
+ s = s.slice(0, -1).trimEnd();
12893
12897
  }
12894
12898
  }
12895
12899
  let percent = false;
@@ -25586,7 +25590,7 @@ async function saveXlsx(workbook) {
25586
25590
 
25587
25591
  // xlsx/edit/context.ts
25588
25592
  function sheetAt(workbook, index2) {
25589
- const sheet = workbook.sheets[index2];
25593
+ const sheet = Number.isInteger(index2) ? workbook.sheets[index2] : void 0;
25590
25594
  if (!sheet) throw new RangeError(`No sheet at index ${index2}`);
25591
25595
  return sheet;
25592
25596
  }
@@ -26731,7 +26735,9 @@ function decodeEntities(text) {
26731
26735
  }
26732
26736
  function parseAttributes(text) {
26733
26737
  const attrs2 = /* @__PURE__ */ new Map();
26734
- for (const m of text.matchAll(/([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g))
26738
+ for (const m of text.matchAll(
26739
+ /([\w:-]{1,64})\s{0,16}=\s{0,16}(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g
26740
+ ))
26735
26741
  attrs2.set((m[1] ?? "").toLowerCase(), decodeEntities(m[2] ?? m[3] ?? m[4] ?? ""));
26736
26742
  return attrs2;
26737
26743
  }
@@ -26786,9 +26792,56 @@ function stylePatchFromCss(css, inner2) {
26786
26792
  if (numFmt) patch.numFmt = decodeNumberFormat(numFmt);
26787
26793
  return patch;
26788
26794
  }
26795
+ function removeComments(text) {
26796
+ let out = "";
26797
+ let from = 0;
26798
+ for (; ; ) {
26799
+ const open = text.indexOf("<!--", from);
26800
+ const close = open < 0 ? -1 : text.indexOf("-->", open + 4);
26801
+ if (close < 0) return out + text.slice(from);
26802
+ out += text.slice(from, open);
26803
+ from = close + 3;
26804
+ }
26805
+ }
26806
+ function removeTags(text) {
26807
+ let out = "";
26808
+ let i = 0;
26809
+ while (i < text.length) {
26810
+ const ch = text[i];
26811
+ if (ch === "<") {
26812
+ let j = i + 1;
26813
+ while (j < text.length && text[j] !== "<" && text[j] !== ">") j++;
26814
+ if (text[j] === ">") {
26815
+ i = j + 1;
26816
+ continue;
26817
+ }
26818
+ }
26819
+ out += ch;
26820
+ i++;
26821
+ }
26822
+ return out;
26823
+ }
26824
+ function stripTags(markup) {
26825
+ let previous;
26826
+ let text = markup;
26827
+ do {
26828
+ previous = text;
26829
+ text = removeTags(removeComments(text));
26830
+ } while (text !== previous);
26831
+ return removeAll(text, ["<!--", "-->"]);
26832
+ }
26833
+ function removeAll(text, tokens2) {
26834
+ let current = text;
26835
+ let previous;
26836
+ do {
26837
+ previous = current;
26838
+ for (const token of tokens2) current = current.split(token).join("");
26839
+ } while (current !== previous);
26840
+ return current;
26841
+ }
26789
26842
  function cellText(inner2) {
26790
26843
  return decodeEntities(
26791
- inner2.replace(/<!--[\s\S]*?-->/g, "").replace(/<br\s*\/?>/gi, "\0").replace(/<[^>]+>/g, "").replace(/\s+/g, " ").replace(/ ?\u0000 ?/g, "\n")
26844
+ stripTags(inner2.replace(/<br\s*\/?>/gi, "\0")).replace(/\s+/g, " ").replace(/ ?\u0000 ?/g, "\n")
26792
26845
  ).replace(/ /g, " ").trim();
26793
26846
  }
26794
26847
  function parseHtmlTable(html, base) {
@@ -26796,7 +26849,9 @@ function parseHtmlTable(html, base) {
26796
26849
  if (table2 === void 0) return void 0;
26797
26850
  const classes = /* @__PURE__ */ new Map();
26798
26851
  for (const block of html.matchAll(/<style\b[^>]*>([\s\S]*?)<\/style>/gi))
26799
- for (const rule2 of (block[1] ?? "").replace(/<!--|-->/g, "").matchAll(/\.([\w-]+)\s*\{([^}]*)\}/g))
26852
+ for (const rule2 of removeAll(block[1] ?? "", ["<!--", "-->"]).matchAll(
26853
+ /\.([\w-]+)\s*\{([^}]*)\}/g
26854
+ ))
26800
26855
  classes.set(rule2[1] ?? "", rule2[2] ?? "");
26801
26856
  const grid = [];
26802
26857
  const taken = /* @__PURE__ */ new Set();
@@ -26966,7 +27021,15 @@ function linearTrend(values2) {
26966
27021
  const slope = den ? num3 / den : 0;
26967
27022
  return (k) => Number((meanY + slope * (k - meanX)).toPrecision(15));
26968
27023
  }
26969
- var TEXT_NUMBER = /^(.*?)(\d+)(\D*)$/;
27024
+ var isDigit3 = (ch) => ch !== void 0 && ch >= "0" && ch <= "9";
27025
+ function matchTextNumber(text) {
27026
+ let end = text.length;
27027
+ while (end > 0 && !isDigit3(text[end - 1])) end--;
27028
+ if (end === 0) return null;
27029
+ let start = end;
27030
+ while (start > 0 && isDigit3(text[start - 1])) start--;
27031
+ return [text, text.slice(0, start), text.slice(start, end), text.slice(end)];
27032
+ }
26970
27033
  var QUARTER = /^(q|qtr|quarter)(\s?)([1-4])$/i;
26971
27034
  function textSeries(texts) {
26972
27035
  const lists = texts.map(listMatch);
@@ -26988,7 +27051,7 @@ function textSeries(texts) {
26988
27051
  const step = q1 ? mod(Number(q1[3]) - 1 - start, 4) || 1 : 1;
26989
27052
  return (k) => ({ kind: "value", value: `${q0[1]}${q0[2]}${mod(start + step * k, 4) + 1}` });
26990
27053
  }
26991
- const parts = texts.map((t) => TEXT_NUMBER.exec(t));
27054
+ const parts = texts.map(matchTextNumber);
26992
27055
  const p0 = parts[0];
26993
27056
  if (!p0 || !parts.every((p) => p && p[1] === p0[1] && p[3] === p0[3])) return void 0;
26994
27057
  const numbers3 = parts.map((p) => Number(p?.[2]));
@@ -27585,7 +27648,7 @@ function setAutoFilter(ctx, s, range) {
27585
27648
  const old = sheet.autoFilter;
27586
27649
  if (old) applyFilter(ctx, sheet, { range: old.range });
27587
27650
  if (r) sheet.autoFilter = { range: r };
27588
- else delete sheet.autoFilter;
27651
+ else Reflect.deleteProperty(sheet, "autoFilter");
27589
27652
  },
27590
27653
  { sheet: s, structural: true }
27591
27654
  );
@@ -28647,9 +28710,10 @@ function updateChart(ctx, s, index2, patch) {
28647
28710
  () => {
28648
28711
  const live = sheet.drawings[index2];
28649
28712
  for (const [key2, value] of Object.entries(structuredClone(patch))) {
28650
- if (key2 === "kind" || key2 === "partName") continue;
28651
- if (value === void 0) delete live[key2];
28652
- else live[key2] = value;
28713
+ if (key2 === "kind" || key2 === "partName" || key2 === "__proto__") continue;
28714
+ if (key2 === "constructor" || key2 === "prototype") continue;
28715
+ if (value === void 0) Reflect.deleteProperty(live, key2);
28716
+ else Reflect.set(live, key2, value);
28653
28717
  }
28654
28718
  },
28655
28719
  { sheet: s }
@@ -29158,7 +29222,7 @@ function setDefaultColumnWidth(ctx, s, width) {
29158
29222
  "format",
29159
29223
  [{ kind: "sheet", sheet: s }],
29160
29224
  () => {
29161
- if (width === void 0) delete sheet.defaultColWidth;
29225
+ if (width === void 0) Reflect.deleteProperty(sheet, "defaultColWidth");
29162
29226
  else sheet.defaultColWidth = width;
29163
29227
  },
29164
29228
  { sheet: s, structural: true }
@@ -29180,7 +29244,7 @@ function setPageSetup(ctx, s, patch) {
29180
29244
  () => {
29181
29245
  const next = compact2({ ...sheet.pageSetup, ...structuredClone(patch) });
29182
29246
  if (Object.keys(next).length) sheet.pageSetup = next;
29183
- else delete sheet.pageSetup;
29247
+ else Reflect.deleteProperty(sheet, "pageSetup");
29184
29248
  },
29185
29249
  { sheet: s }
29186
29250
  );
@@ -29196,7 +29260,7 @@ function setPrintOptions(ctx, s, patch) {
29196
29260
  for (const key2 of Object.keys(next))
29197
29261
  if (!next[key2]) delete next[key2];
29198
29262
  if (Object.keys(next).length) sheet.printOptions = next;
29199
- else delete sheet.printOptions;
29263
+ else Reflect.deleteProperty(sheet, "printOptions");
29200
29264
  sheet.preserved.delete("printOptions");
29201
29265
  },
29202
29266
  { sheet: s }
@@ -29802,7 +29866,7 @@ function setSheetProtection(ctx, s, protection2, password) {
29802
29866
  [{ kind: "sheet", sheet: s }],
29803
29867
  () => {
29804
29868
  if (!protection2) {
29805
- delete sheet.protection;
29869
+ Reflect.deleteProperty(sheet, "protection");
29806
29870
  return;
29807
29871
  }
29808
29872
  const next = structuredClone(protection2);
@@ -30774,7 +30838,7 @@ function setTabColor(ctx, index2, color2) {
30774
30838
  [{ kind: "sheet", sheet: index2 }],
30775
30839
  () => {
30776
30840
  if (color2) sheet.tabColor = { ...color2 };
30777
- else delete sheet.tabColor;
30841
+ else Reflect.deleteProperty(sheet, "tabColor");
30778
30842
  },
30779
30843
  { sheet: index2 }
30780
30844
  );
@@ -1398,7 +1398,7 @@ async function applyCoreProperties(zip, next, prior) {
1398
1398
  await ensureContentTypeOverride(zip, CORE_PATH, CORE_TYPE);
1399
1399
  const rels = zip.file("_rels/.rels");
1400
1400
  const relsXml = await rels?.async("string") ?? '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"></Relationships>';
1401
- if (!relsXml.includes(CORE_REL)) {
1401
+ if (!relsXml.includes(`Type="${CORE_REL}"`)) {
1402
1402
  const ids = [...relsXml.matchAll(/Id="rId(\d+)"/g)].map((match2) => Number(match2[1]));
1403
1403
  const id = `rId${Math.max(0, ...ids) + 1}`;
1404
1404
  zip.file(
@@ -11849,7 +11849,10 @@ function writeDrawing(writer, partName, objects, sourceDrawing) {
11849
11849
  let nextId = Math.max(
11850
11850
  1,
11851
11851
  ...kept.flatMap(
11852
- (xml) => [...xml.matchAll(/cNvPr[^>]*\sid="(\d+)"/g)].map((m) => Number(m[1]))
11852
+ (xml) => [...xml.matchAll(/cNvPr([^>]*)/g)].flatMap((m) => {
11853
+ const id = /\sid="(\d+)"/.exec(m[1] ?? "");
11854
+ return id ? [Number(id[1])] : [];
11855
+ })
11853
11856
  )
11854
11857
  ) + 1;
11855
11858
  let body = "";
@@ -12835,7 +12838,8 @@ function parseDay(text) {
12835
12838
  function parseDateTimeInput(text, date1904) {
12836
12839
  const time = parseTime(text);
12837
12840
  if (time) return { value: time.fraction, numFmt: time.format };
12838
- const split = /^(.+?)(?:\s+|T)(\d{1,2}:\d{1,2}(?::\d{1,2})?(?:\s*(?:am|pm|a|p))?)$/i.exec(text);
12841
+ const tail = /(?:\s{1,8}|T)(\d{1,2}:\d{1,2}(?::\d{1,2})?(?:\s{0,8}(?:am|pm|a|p))?)$/i.exec(text);
12842
+ const split = tail && tail.index > 0 ? [tail[0], text.slice(0, tail.index), tail[1]] : null;
12839
12843
  const dayText = split ? split[1] ?? "" : text;
12840
12844
  const day = parseDay(dayText);
12841
12845
  if (!day) return void 0;
@@ -12880,10 +12884,10 @@ function parseNumberInput(text) {
12880
12884
  s = s.slice(lead[0].length);
12881
12885
  if (!sign()) return void 0;
12882
12886
  } else {
12883
- const trail = /\s*([€£])$/.exec(s);
12884
- if (trail) {
12885
- currency = trail[1] ?? "";
12886
- s = s.slice(0, -trail[0].length);
12887
+ const last = s.slice(-1);
12888
+ if (last === "\u20AC" || last === "\xA3") {
12889
+ currency = last;
12890
+ s = s.slice(0, -1).trimEnd();
12887
12891
  }
12888
12892
  }
12889
12893
  let percent = false;
@@ -25580,7 +25584,7 @@ async function saveXlsx(workbook) {
25580
25584
 
25581
25585
  // xlsx/edit/context.ts
25582
25586
  function sheetAt(workbook, index2) {
25583
- const sheet = workbook.sheets[index2];
25587
+ const sheet = Number.isInteger(index2) ? workbook.sheets[index2] : void 0;
25584
25588
  if (!sheet) throw new RangeError(`No sheet at index ${index2}`);
25585
25589
  return sheet;
25586
25590
  }
@@ -26725,7 +26729,9 @@ function decodeEntities(text) {
26725
26729
  }
26726
26730
  function parseAttributes(text) {
26727
26731
  const attrs2 = /* @__PURE__ */ new Map();
26728
- for (const m of text.matchAll(/([\w:-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g))
26732
+ for (const m of text.matchAll(
26733
+ /([\w:-]{1,64})\s{0,16}=\s{0,16}(?:"([^"]*)"|'([^']*)'|([^\s>]+))/g
26734
+ ))
26729
26735
  attrs2.set((m[1] ?? "").toLowerCase(), decodeEntities(m[2] ?? m[3] ?? m[4] ?? ""));
26730
26736
  return attrs2;
26731
26737
  }
@@ -26780,9 +26786,56 @@ function stylePatchFromCss(css, inner2) {
26780
26786
  if (numFmt) patch.numFmt = decodeNumberFormat(numFmt);
26781
26787
  return patch;
26782
26788
  }
26789
+ function removeComments(text) {
26790
+ let out = "";
26791
+ let from = 0;
26792
+ for (; ; ) {
26793
+ const open = text.indexOf("<!--", from);
26794
+ const close = open < 0 ? -1 : text.indexOf("-->", open + 4);
26795
+ if (close < 0) return out + text.slice(from);
26796
+ out += text.slice(from, open);
26797
+ from = close + 3;
26798
+ }
26799
+ }
26800
+ function removeTags(text) {
26801
+ let out = "";
26802
+ let i = 0;
26803
+ while (i < text.length) {
26804
+ const ch = text[i];
26805
+ if (ch === "<") {
26806
+ let j = i + 1;
26807
+ while (j < text.length && text[j] !== "<" && text[j] !== ">") j++;
26808
+ if (text[j] === ">") {
26809
+ i = j + 1;
26810
+ continue;
26811
+ }
26812
+ }
26813
+ out += ch;
26814
+ i++;
26815
+ }
26816
+ return out;
26817
+ }
26818
+ function stripTags(markup) {
26819
+ let previous;
26820
+ let text = markup;
26821
+ do {
26822
+ previous = text;
26823
+ text = removeTags(removeComments(text));
26824
+ } while (text !== previous);
26825
+ return removeAll(text, ["<!--", "-->"]);
26826
+ }
26827
+ function removeAll(text, tokens2) {
26828
+ let current = text;
26829
+ let previous;
26830
+ do {
26831
+ previous = current;
26832
+ for (const token of tokens2) current = current.split(token).join("");
26833
+ } while (current !== previous);
26834
+ return current;
26835
+ }
26783
26836
  function cellText(inner2) {
26784
26837
  return decodeEntities(
26785
- inner2.replace(/<!--[\s\S]*?-->/g, "").replace(/<br\s*\/?>/gi, "\0").replace(/<[^>]+>/g, "").replace(/\s+/g, " ").replace(/ ?\u0000 ?/g, "\n")
26838
+ stripTags(inner2.replace(/<br\s*\/?>/gi, "\0")).replace(/\s+/g, " ").replace(/ ?\u0000 ?/g, "\n")
26786
26839
  ).replace(/ /g, " ").trim();
26787
26840
  }
26788
26841
  function parseHtmlTable(html, base) {
@@ -26790,7 +26843,9 @@ function parseHtmlTable(html, base) {
26790
26843
  if (table2 === void 0) return void 0;
26791
26844
  const classes = /* @__PURE__ */ new Map();
26792
26845
  for (const block of html.matchAll(/<style\b[^>]*>([\s\S]*?)<\/style>/gi))
26793
- for (const rule2 of (block[1] ?? "").replace(/<!--|-->/g, "").matchAll(/\.([\w-]+)\s*\{([^}]*)\}/g))
26846
+ for (const rule2 of removeAll(block[1] ?? "", ["<!--", "-->"]).matchAll(
26847
+ /\.([\w-]+)\s*\{([^}]*)\}/g
26848
+ ))
26794
26849
  classes.set(rule2[1] ?? "", rule2[2] ?? "");
26795
26850
  const grid = [];
26796
26851
  const taken = /* @__PURE__ */ new Set();
@@ -26960,7 +27015,15 @@ function linearTrend(values2) {
26960
27015
  const slope = den ? num3 / den : 0;
26961
27016
  return (k) => Number((meanY + slope * (k - meanX)).toPrecision(15));
26962
27017
  }
26963
- var TEXT_NUMBER = /^(.*?)(\d+)(\D*)$/;
27018
+ var isDigit3 = (ch) => ch !== void 0 && ch >= "0" && ch <= "9";
27019
+ function matchTextNumber(text) {
27020
+ let end = text.length;
27021
+ while (end > 0 && !isDigit3(text[end - 1])) end--;
27022
+ if (end === 0) return null;
27023
+ let start = end;
27024
+ while (start > 0 && isDigit3(text[start - 1])) start--;
27025
+ return [text, text.slice(0, start), text.slice(start, end), text.slice(end)];
27026
+ }
26964
27027
  var QUARTER = /^(q|qtr|quarter)(\s?)([1-4])$/i;
26965
27028
  function textSeries(texts) {
26966
27029
  const lists = texts.map(listMatch);
@@ -26982,7 +27045,7 @@ function textSeries(texts) {
26982
27045
  const step = q1 ? mod(Number(q1[3]) - 1 - start, 4) || 1 : 1;
26983
27046
  return (k) => ({ kind: "value", value: `${q0[1]}${q0[2]}${mod(start + step * k, 4) + 1}` });
26984
27047
  }
26985
- const parts = texts.map((t) => TEXT_NUMBER.exec(t));
27048
+ const parts = texts.map(matchTextNumber);
26986
27049
  const p0 = parts[0];
26987
27050
  if (!p0 || !parts.every((p) => p && p[1] === p0[1] && p[3] === p0[3])) return void 0;
26988
27051
  const numbers3 = parts.map((p) => Number(p?.[2]));
@@ -27579,7 +27642,7 @@ function setAutoFilter(ctx, s, range) {
27579
27642
  const old = sheet.autoFilter;
27580
27643
  if (old) applyFilter(ctx, sheet, { range: old.range });
27581
27644
  if (r) sheet.autoFilter = { range: r };
27582
- else delete sheet.autoFilter;
27645
+ else Reflect.deleteProperty(sheet, "autoFilter");
27583
27646
  },
27584
27647
  { sheet: s, structural: true }
27585
27648
  );
@@ -28641,9 +28704,10 @@ function updateChart(ctx, s, index2, patch) {
28641
28704
  () => {
28642
28705
  const live = sheet.drawings[index2];
28643
28706
  for (const [key2, value] of Object.entries(structuredClone(patch))) {
28644
- if (key2 === "kind" || key2 === "partName") continue;
28645
- if (value === void 0) delete live[key2];
28646
- else live[key2] = value;
28707
+ if (key2 === "kind" || key2 === "partName" || key2 === "__proto__") continue;
28708
+ if (key2 === "constructor" || key2 === "prototype") continue;
28709
+ if (value === void 0) Reflect.deleteProperty(live, key2);
28710
+ else Reflect.set(live, key2, value);
28647
28711
  }
28648
28712
  },
28649
28713
  { sheet: s }
@@ -29152,7 +29216,7 @@ function setDefaultColumnWidth(ctx, s, width) {
29152
29216
  "format",
29153
29217
  [{ kind: "sheet", sheet: s }],
29154
29218
  () => {
29155
- if (width === void 0) delete sheet.defaultColWidth;
29219
+ if (width === void 0) Reflect.deleteProperty(sheet, "defaultColWidth");
29156
29220
  else sheet.defaultColWidth = width;
29157
29221
  },
29158
29222
  { sheet: s, structural: true }
@@ -29174,7 +29238,7 @@ function setPageSetup(ctx, s, patch) {
29174
29238
  () => {
29175
29239
  const next = compact2({ ...sheet.pageSetup, ...structuredClone(patch) });
29176
29240
  if (Object.keys(next).length) sheet.pageSetup = next;
29177
- else delete sheet.pageSetup;
29241
+ else Reflect.deleteProperty(sheet, "pageSetup");
29178
29242
  },
29179
29243
  { sheet: s }
29180
29244
  );
@@ -29190,7 +29254,7 @@ function setPrintOptions(ctx, s, patch) {
29190
29254
  for (const key2 of Object.keys(next))
29191
29255
  if (!next[key2]) delete next[key2];
29192
29256
  if (Object.keys(next).length) sheet.printOptions = next;
29193
- else delete sheet.printOptions;
29257
+ else Reflect.deleteProperty(sheet, "printOptions");
29194
29258
  sheet.preserved.delete("printOptions");
29195
29259
  },
29196
29260
  { sheet: s }
@@ -29796,7 +29860,7 @@ function setSheetProtection(ctx, s, protection2, password) {
29796
29860
  [{ kind: "sheet", sheet: s }],
29797
29861
  () => {
29798
29862
  if (!protection2) {
29799
- delete sheet.protection;
29863
+ Reflect.deleteProperty(sheet, "protection");
29800
29864
  return;
29801
29865
  }
29802
29866
  const next = structuredClone(protection2);
@@ -30768,7 +30832,7 @@ function setTabColor(ctx, index2, color2) {
30768
30832
  [{ kind: "sheet", sheet: index2 }],
30769
30833
  () => {
30770
30834
  if (color2) sheet.tabColor = { ...color2 };
30771
- else delete sheet.tabColor;
30835
+ else Reflect.deleteProperty(sheet, "tabColor");
30772
30836
  },
30773
30837
  { sheet: index2 }
30774
30838
  );