@office-kit/xlsx 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +89 -4
  2. package/dist/cell/cell.d.ts +12 -19
  3. package/dist/{cell-Df3cKRIl.mjs → cell-B5OUUdfI.mjs} +13 -7
  4. package/dist/cell-B5OUUdfI.mjs.map +1 -0
  5. package/dist/{cell-style-CNsET6WU.mjs → cell-style-CbB4nXTY.mjs} +11 -4
  6. package/dist/cell-style-CbB4nXTY.mjs.map +1 -0
  7. package/dist/cell.mjs +1 -1
  8. package/dist/{coordinate-Bt5Gni2I.mjs → coordinate-CxC88uBk.mjs} +31 -2
  9. package/dist/coordinate-CxC88uBk.mjs.map +1 -0
  10. package/dist/{defined-names-Ctu3F6ls.mjs → defined-names-Cmp8rbvI.mjs} +2 -2
  11. package/dist/{defined-names-Ctu3F6ls.mjs.map → defined-names-Cmp8rbvI.mjs.map} +1 -1
  12. package/dist/{differential-BPKa7wXi.mjs → differential-QLaKEiBk.mjs} +2 -2
  13. package/dist/{differential-BPKa7wXi.mjs.map → differential-QLaKEiBk.mjs.map} +1 -1
  14. package/dist/{drawing-ZJ3h4VHD.mjs → drawing-Cv6UtInY.mjs} +2 -2
  15. package/dist/{drawing-ZJ3h4VHD.mjs.map → drawing-Cv6UtInY.mjs.map} +1 -1
  16. package/dist/drawing.mjs +1 -1
  17. package/dist/{escape-rnWSPpWY.mjs → escape-rA5UpibT.mjs} +26 -3
  18. package/dist/escape-rA5UpibT.mjs.map +1 -0
  19. package/dist/io/load.d.ts +30 -0
  20. package/dist/io.mjs +2 -2
  21. package/dist/{iterparse-DZE0zy2M.mjs → iterparse-CZoRXvZW.mjs} +2 -2
  22. package/dist/{iterparse-DZE0zy2M.mjs.map → iterparse-CZoRXvZW.mjs.map} +1 -1
  23. package/dist/{load-B1sK-LjT.mjs → load-BpnCPv1S.mjs} +84 -45
  24. package/dist/load-BpnCPv1S.mjs.map +1 -0
  25. package/dist/{manifest-pLmx7KYh.mjs → manifest-9p0ccqmR.mjs} +10 -11
  26. package/dist/manifest-9p0ccqmR.mjs.map +1 -0
  27. package/dist/node.mjs +1 -1
  28. package/dist/packaging.mjs +1 -1
  29. package/dist/{parser-By6RWZVW.mjs → parser-B1tB9YaE.mjs} +15 -5
  30. package/dist/parser-B1tB9YaE.mjs.map +1 -0
  31. package/dist/{reader-DHMxLBQV.mjs → reader-pC7bxYAs.mjs} +30 -7
  32. package/dist/reader-pC7bxYAs.mjs.map +1 -0
  33. package/dist/{save-DmdWwxmw.mjs → save-1Z3344nz.mjs} +8 -8
  34. package/dist/{save-DmdWwxmw.mjs.map → save-1Z3344nz.mjs.map} +1 -1
  35. package/dist/schema.mjs +1 -1
  36. package/dist/{serialize-BC2Wu3bR.mjs → serialize-BtxgssFK.mjs} +24 -7
  37. package/dist/serialize-BtxgssFK.mjs.map +1 -0
  38. package/dist/{serializer-C6nm0mRJ.mjs → serializer-N6XIwsgp.mjs} +3 -3
  39. package/dist/{serializer-C6nm0mRJ.mjs.map → serializer-N6XIwsgp.mjs.map} +1 -1
  40. package/dist/streaming.mjs +129 -77
  41. package/dist/streaming.mjs.map +1 -1
  42. package/dist/styles/display-text.d.ts +95 -0
  43. package/dist/styles/format-code.d.ts +125 -0
  44. package/dist/styles/index.d.ts +1 -0
  45. package/dist/styles/numbers.d.ts +7 -0
  46. package/dist/styles.mjs +1161 -4
  47. package/dist/styles.mjs.map +1 -0
  48. package/dist/{stylesheet-writer-oXSuGnJy.mjs → stylesheet-writer-BEn-0P0x.mjs} +480 -173
  49. package/dist/stylesheet-writer-BEn-0P0x.mjs.map +1 -0
  50. package/dist/{table-BrP0RwUd.mjs → table-BxOLUZs3.mjs} +2 -2
  51. package/dist/{table-BrP0RwUd.mjs.map → table-BxOLUZs3.mjs.map} +1 -1
  52. package/dist/{tree-BX-sRRVp.mjs → tree-CspNjuYl.mjs} +12 -2
  53. package/dist/tree-CspNjuYl.mjs.map +1 -0
  54. package/dist/utils/cell-number.d.ts +10 -0
  55. package/dist/utils/coordinate.d.ts +11 -0
  56. package/dist/utils/escape.d.ts +17 -0
  57. package/dist/utils/xsd-boolean.d.ts +9 -0
  58. package/dist/utils.mjs +2 -2
  59. package/dist/workbook/index.d.ts +1 -1
  60. package/dist/workbook/workbook.d.ts +9 -46
  61. package/dist/{workbook-DOTFzCpz.mjs → workbook-tG9oYtzU.mjs} +50 -13
  62. package/dist/workbook-tG9oYtzU.mjs.map +1 -0
  63. package/dist/workbook.mjs +3 -3
  64. package/dist/worksheet/index.d.ts +1 -1
  65. package/dist/worksheet/worksheet.d.ts +55 -14
  66. package/dist/{worksheet-B2NOQ6dM.mjs → worksheet-DLMyDD7W.mjs} +87 -22
  67. package/dist/worksheet-DLMyDD7W.mjs.map +1 -0
  68. package/dist/worksheet.mjs +3 -3
  69. package/dist/xml/namespaces.d.ts +7 -0
  70. package/dist/xml/parser.d.ts +12 -0
  71. package/dist/xml/strict-package.d.ts +14 -0
  72. package/dist/xml.mjs +5 -5
  73. package/dist/zip.mjs +1 -1
  74. package/package.json +1 -1
  75. package/dist/cell-Df3cKRIl.mjs.map +0 -1
  76. package/dist/cell-style-CNsET6WU.mjs.map +0 -1
  77. package/dist/coordinate-Bt5Gni2I.mjs.map +0 -1
  78. package/dist/escape-rnWSPpWY.mjs.map +0 -1
  79. package/dist/load-B1sK-LjT.mjs.map +0 -1
  80. package/dist/manifest-pLmx7KYh.mjs.map +0 -1
  81. package/dist/parser-By6RWZVW.mjs.map +0 -1
  82. package/dist/reader-DHMxLBQV.mjs.map +0 -1
  83. package/dist/serialize-BC2Wu3bR.mjs.map +0 -1
  84. package/dist/stylesheet-writer-oXSuGnJy.mjs.map +0 -1
  85. package/dist/tree-BX-sRRVp.mjs.map +0 -1
  86. package/dist/workbook-DOTFzCpz.mjs.map +0 -1
  87. package/dist/worksheet-B2NOQ6dM.mjs.map +0 -1
@@ -1,23 +1,24 @@
1
1
  import { n as OpenXmlError, o as OpenXmlSchemaError } from "./exceptions-D-CFwxgm.mjs";
2
- import { a as columnLetterFromIndex, g as tupleToCoordinate, i as columnIndexFromLetter, s as coordinateToTuple } from "./coordinate-Bt5Gni2I.mjs";
2
+ import { _ as rowNumberFromAttr, a as columnLetterFromIndex, c as derivedRowNumber, i as columnIndexFromLetter, l as formatSheetQualifiedRef, s as coordinateToTuple, v as tupleToCoordinate } from "./coordinate-CxC88uBk.mjs";
3
3
  import { r as normalizeFormulaText, t as ERROR_CODES$1 } from "./inference-BMvv9cUY.mjs";
4
- import { A as setSharedFormula, E as setArrayFormula, O as setDataTableFormula, c as getCoordinate, k as setFormula } from "./cell-Df3cKRIl.mjs";
4
+ import { A as setSharedFormula, E as setArrayFormula, N as richTextToString, O as setDataTableFormula, c as getCoordinate, k as setFormula } from "./cell-B5OUUdfI.mjs";
5
5
  import { C as makeSurface3DChart, S as makeStockChart, _ as makePie3DChart, a as makeArea3DChart, b as makeScatterChart, c as makeBarChart, d as makeBubbleSeries, f as makeChartSpace, g as makeOfPieChart, h as makeLineChart, l as makeBarSeries, m as makeLine3DChart, n as makeChartDrawing, o as makeAreaChart, p as makeDoughnutChart, s as makeBar3DChart, u as makeBubbleChart, v as makePieChart, w as makeSurfaceChart, x as makeScatterSeries, y as makeRadarChart } from "./user-shapes-DfmCGKB0.mjs";
6
6
  import { t as makeChartsheet } from "./chartsheet-C3-tqkPy.mjs";
7
- import { o as makeDrawing } from "./drawing-ZJ3h4VHD.mjs";
7
+ import { o as makeDrawing } from "./drawing-Cv6UtInY.mjs";
8
8
  import { n as VALUED_COLOR_MOD_KINDS, r as VALUELESS_COLOR_MOD_KINDS, t as SCHEME_COLOR_NAMES } from "./colors-ovWAwnZI.mjs";
9
- import { n as escapeXmlAttr$1, r as escapeXmlText$1, t as escapeCellString } from "./escape-rnWSPpWY.mjs";
10
- import { H as DRAWING_NS, I as CX_NS, T as CHART_NS, a as findChildren, bt as X14_NS, dt as SHEET_DRAWING_NS, ft as SHEET_MAIN_NS, i as findChild, jt as qname, lt as REL_NS, n as el, q as MARKUP_COMPAT_NS, w as CHART_DRAWING_NS } from "./tree-BX-sRRVp.mjs";
11
- import { t as parseXml } from "./parser-By6RWZVW.mjs";
12
- import { n as toTree, r as defineSchema, t as fromTree } from "./serialize-BC2Wu3bR.mjs";
13
- import { t as serializeXml } from "./serializer-C6nm0mRJ.mjs";
14
- import { Q as findById } from "./manifest-pLmx7KYh.mjs";
15
- import { Dn as makeColor, Zt as makeLegacyComment, cn as multiCellRangeToString, en as makeSheetView, ln as parseMultiCellRange, mn as rangeToString, nn as makeRowDimension, ot as makeWorksheet, tn as makeColumnDimension, un as parseRange, xt as setCell } from "./worksheet-B2NOQ6dM.mjs";
16
- import { Bt as PATTERN_TYPES, Ft as FONT_SCHEMES, It as UNDERLINE_STYLES, Kt as SIDE_STYLES, Lt as VERT_ALIGNS, Xt as HORIZONTAL_ALIGNMENTS, Zt as VERTICAL_ALIGNMENTS } from "./cell-style-CNsET6WU.mjs";
17
- import { C as addSharedRichText, O as parseRichString, w as addSharedString } from "./workbook-DOTFzCpz.mjs";
18
- import { a as makeCfRule, i as makeDataValidation, n as makeTableColumn, o as makeConditionalFormatting, r as makeTableDefinition } from "./table-BrP0RwUd.mjs";
9
+ import { i as escapeXmlTextVerbatim, n as escapeXmlAttr$1, r as escapeXmlText$1 } from "./escape-rA5UpibT.mjs";
10
+ import { H as DRAWING_NS, I as CX_NS, Nt as qname, T as CHART_NS, a as findChildren, dt as SHEET_DRAWING_NS, ft as SHEET_MAIN_NS, i as findChild, jt as localNameOf, lt as REL_NS, n as el, q as MARKUP_COMPAT_NS, w as CHART_DRAWING_NS, xt as X14_NS } from "./tree-CspNjuYl.mjs";
11
+ import { i as rejectDtdDeclarations, n as parseXml, t as isWhitespaceOnly } from "./parser-B1tB9YaE.mjs";
12
+ import { i as defineSchema, n as toTree, r as parseXsdBoolean, t as fromTree } from "./serialize-BtxgssFK.mjs";
13
+ import { t as serializeXml } from "./serializer-N6XIwsgp.mjs";
14
+ import { Q as findById } from "./manifest-9p0ccqmR.mjs";
15
+ import { F as assertNotStrictRoot, T as addSharedString, k as parseRichString, w as addSharedRichText } from "./workbook-tG9oYtzU.mjs";
16
+ import { $t as makeLegacyComment, Ct as setCell, ct as makeWorksheet, dn as parseMultiCellRange, fn as parseRange, gn as rangeToString, in as makeRowDimension, kn as makeColor, nn as makeSheetView, rn as makeColumnDimension, un as multiCellRangeToString } from "./worksheet-DLMyDD7W.mjs";
17
+ import { It as FONT_SCHEMES, Lt as UNDERLINE_STYLES, Qt as VERTICAL_ALIGNMENTS, Rt as VERT_ALIGNS, Vt as PATTERN_TYPES, Zt as HORIZONTAL_ALIGNMENTS, qt as SIDE_STYLES } from "./cell-style-CbB4nXTY.mjs";
18
+ import { a as makeCfRule, i as makeDataValidation, n as makeTableColumn, o as makeConditionalFormatting, r as makeTableDefinition } from "./table-BxOLUZs3.mjs";
19
19
  import { i as durationToExcel, r as dateToExcel } from "./datetime-B2ySVlXt.mjs";
20
- import { n as getDxfs } from "./differential-BPKa7wXi.mjs";
20
+ import { n as getDxfs } from "./differential-QLaKEiBk.mjs";
21
+ import { SaxesParser } from "saxes";
21
22
  //#region src/drawing/dml/effect.ts
22
23
  const PRESET_SHADOW_NAMES = [
23
24
  "shdw1",
@@ -1937,9 +1938,9 @@ const NUM_REF_TAG = `{${CHART_NS}}numRef`;
1937
1938
  const STR_REF_TAG = `{${CHART_NS}}strRef`;
1938
1939
  const NUM_CACHE_TAG = `{${CHART_NS}}numCache`;
1939
1940
  const STR_CACHE_TAG = `{${CHART_NS}}strCache`;
1940
- const F_TAG$1 = `{${CHART_NS}}f`;
1941
+ const F_TAG = `{${CHART_NS}}f`;
1941
1942
  const PT_TAG = `{${CHART_NS}}pt`;
1942
- const V_TAG$1 = `{${CHART_NS}}v`;
1943
+ const V_TAG = `{${CHART_NS}}v`;
1943
1944
  const FORMAT_CODE_TAG = `{${CHART_NS}}formatCode`;
1944
1945
  const BAR_DIR_TAG = `{${CHART_NS}}barDir`;
1945
1946
  const GROUPING_TAG = `{${CHART_NS}}grouping`;
@@ -2222,7 +2223,7 @@ const parseDataLabel = (el) => {
2222
2223
  const strRef = findChild(txEl, STR_REF_TAG);
2223
2224
  if (strRef) out.tx = {
2224
2225
  kind: "strRef",
2225
- ref: findChild(strRef, F_TAG$1)?.text ?? ""
2226
+ ref: findChild(strRef, F_TAG)?.text ?? ""
2226
2227
  };
2227
2228
  }
2228
2229
  }
@@ -2467,7 +2468,7 @@ const parseNumCache = (cacheEl) => {
2467
2468
  const values = [];
2468
2469
  const fmt = findChild(cacheEl, FORMAT_CODE_TAG)?.text;
2469
2470
  for (const pt of findChildren(cacheEl, PT_TAG)) {
2470
- const v = findChild(pt, V_TAG$1)?.text;
2471
+ const v = findChild(pt, V_TAG)?.text;
2471
2472
  if (v !== void 0) values.push(Number.parseFloat(v));
2472
2473
  }
2473
2474
  return fmt !== void 0 ? {
@@ -2478,7 +2479,7 @@ const parseNumCache = (cacheEl) => {
2478
2479
  const parseStrCache = (cacheEl) => {
2479
2480
  const values = [];
2480
2481
  for (const pt of findChildren(cacheEl, PT_TAG)) {
2481
- const v = findChild(pt, V_TAG$1)?.text;
2482
+ const v = findChild(pt, V_TAG)?.text;
2482
2483
  if (v !== void 0) values.push(v);
2483
2484
  }
2484
2485
  return values;
@@ -2488,7 +2489,7 @@ const parseNumericRef = (parent, tag) => {
2488
2489
  if (!wrap) return void 0;
2489
2490
  const numRef = findChild(wrap, NUM_REF_TAG);
2490
2491
  if (!numRef) return void 0;
2491
- const ref = findChild(numRef, F_TAG$1)?.text ?? "";
2492
+ const ref = findChild(numRef, F_TAG)?.text ?? "";
2492
2493
  const cacheEl = findChild(numRef, NUM_CACHE_TAG);
2493
2494
  if (!cacheEl) return { ref };
2494
2495
  const { values, formatCode } = parseNumCache(cacheEl);
@@ -2503,7 +2504,7 @@ const parseCategoryRef = (parent) => {
2503
2504
  if (!cat) return void 0;
2504
2505
  const numRef = findChild(cat, NUM_REF_TAG);
2505
2506
  if (numRef) {
2506
- const ref = findChild(numRef, F_TAG$1)?.text ?? "";
2507
+ const ref = findChild(numRef, F_TAG)?.text ?? "";
2507
2508
  const cacheEl = findChild(numRef, NUM_CACHE_TAG);
2508
2509
  if (!cacheEl) return {
2509
2510
  ref,
@@ -2519,7 +2520,7 @@ const parseCategoryRef = (parent) => {
2519
2520
  }
2520
2521
  const strRef = findChild(cat, STR_REF_TAG);
2521
2522
  if (strRef) {
2522
- const ref = findChild(strRef, F_TAG$1)?.text ?? "";
2523
+ const ref = findChild(strRef, F_TAG)?.text ?? "";
2523
2524
  const cacheEl = findChild(strRef, STR_CACHE_TAG);
2524
2525
  if (!cacheEl) return {
2525
2526
  ref,
@@ -4968,14 +4969,29 @@ function translateFormula(formula, origin, opts = {}) {
4968
4969
  return out;
4969
4970
  }
4970
4971
  //#endregion
4972
+ //#region src/utils/cell-number.ts
4973
+ /** How much of an offending value the error echoes. Cell text is untrusted and unbounded. */
4974
+ const MAX_QUOTED_LENGTH = 40;
4975
+ /**
4976
+ * Value of a numeric cell's `<v>`: a finite number, or `null` when the element
4977
+ * is absent or blank, which is an empty cell.
4978
+ *
4979
+ * `Number.parseFloat` answers NaN for text and ±Infinity for an exponent past
4980
+ * the double range. The writer refuses to serialise either, so a file carrying
4981
+ * one is rejected here, while the sheet and cell that hold it are still known,
4982
+ * rather than at the far end of the pipeline on save.
4983
+ */
4984
+ function parseCellNumber(raw, sheet, col, row) {
4985
+ if (raw === void 0) return null;
4986
+ const n = Number.parseFloat(raw);
4987
+ if (Number.isFinite(n)) return n;
4988
+ if (raw.trim() === "") return null;
4989
+ throw new OpenXmlSchemaError(`worksheet: <v>${raw.length <= MAX_QUOTED_LENGTH ? raw : `${raw.slice(0, MAX_QUOTED_LENGTH)}... (${raw.length} chars)`}</v> at ${formatSheetQualifiedRef(sheet, tupleToCoordinate(col, row))} is not a finite number`);
4990
+ }
4991
+ //#endregion
4971
4992
  //#region src/worksheet/reader.ts
4972
4993
  const WORKSHEET_TAG = `{${SHEET_MAIN_NS}}worksheet`;
4973
4994
  const SHEETDATA_TAG = `{${SHEET_MAIN_NS}}sheetData`;
4974
- const ROW_TAG$1 = `{${SHEET_MAIN_NS}}row`;
4975
- const C_TAG = `{${SHEET_MAIN_NS}}c`;
4976
- const V_TAG = `{${SHEET_MAIN_NS}}v`;
4977
- const F_TAG = `{${SHEET_MAIN_NS}}f`;
4978
- const IS_TAG = `{${SHEET_MAIN_NS}}is`;
4979
4995
  const MERGE_CELLS_TAG = `{${SHEET_MAIN_NS}}mergeCells`;
4980
4996
  const MERGE_CELL_TAG = `{${SHEET_MAIN_NS}}mergeCell`;
4981
4997
  const SHEET_VIEWS_TAG$1 = `{${SHEET_MAIN_NS}}sheetViews`;
@@ -5061,8 +5077,14 @@ const FIRST_FOOTER_TAG = `{${SHEET_MAIN_NS}}firstFooter`;
5061
5077
  * doesn't carry the sheet name (it lives in `workbook.xml`).
5062
5078
  */
5063
5079
  function parseWorksheetXml(bytes, title, ctx) {
5064
- const root = parseXml(bytes);
5065
- if (root.name !== WORKSHEET_TAG) throw new OpenXmlSchemaError(`parseWorksheetXml: root is "${root.name}", expected worksheet`);
5080
+ const text = typeof bytes === "string" ? bytes : XML_DECODER.decode(bytes);
5081
+ rejectDtdDeclarations(text);
5082
+ const sheetData = locateSheetData(text);
5083
+ const root = parseXml(sheetData === void 0 ? text : text.slice(0, sheetData.bodyStart) + text.slice(sheetData.bodyEnd));
5084
+ if (root.name !== WORKSHEET_TAG) {
5085
+ assertNotStrictRoot(root.name);
5086
+ throw new OpenXmlSchemaError(`parseWorksheetXml: root is "${root.name}", expected worksheet`);
5087
+ }
5066
5088
  const ws = makeWorksheet(title);
5067
5089
  const sheetPrEl = findChild(root, SHEET_PR_TAG$1);
5068
5090
  if (sheetPrEl) {
@@ -5079,13 +5101,13 @@ function parseWorksheetXml(bytes, title, ctx) {
5079
5101
  if (outlineLevelRow !== void 0) ws.outlineLevelRow = outlineLevelRow;
5080
5102
  const outlineLevelCol = parseIntegerAttr(sheetFormatEl.attrs["outlineLevelCol"]);
5081
5103
  if (outlineLevelCol !== void 0) ws.outlineLevelCol = outlineLevelCol;
5082
- const customHeight = parseBoolXmlAttr(sheetFormatEl.attrs["customHeight"]);
5104
+ const customHeight = parseXsdBoolean(sheetFormatEl.attrs["customHeight"]);
5083
5105
  if (customHeight !== void 0) ws.customHeight = customHeight;
5084
- const zeroHeight = parseBoolXmlAttr(sheetFormatEl.attrs["zeroHeight"]);
5106
+ const zeroHeight = parseXsdBoolean(sheetFormatEl.attrs["zeroHeight"]);
5085
5107
  if (zeroHeight !== void 0) ws.zeroHeight = zeroHeight;
5086
- const thickTop = parseBoolXmlAttr(sheetFormatEl.attrs["thickTop"]);
5108
+ const thickTop = parseXsdBoolean(sheetFormatEl.attrs["thickTop"]);
5087
5109
  if (thickTop !== void 0) ws.thickTop = thickTop;
5088
- const thickBottom = parseBoolXmlAttr(sheetFormatEl.attrs["thickBottom"]);
5110
+ const thickBottom = parseXsdBoolean(sheetFormatEl.attrs["thickBottom"]);
5089
5111
  if (thickBottom !== void 0) ws.thickBottom = thickBottom;
5090
5112
  const baseColWidth = parseIntegerAttr(sheetFormatEl.attrs["baseColWidth"]);
5091
5113
  if (baseColWidth !== void 0) ws.baseColWidth = baseColWidth;
@@ -5095,20 +5117,7 @@ function parseWorksheetXml(bytes, title, ctx) {
5095
5117
  const dim = parseColumnDimension(c);
5096
5118
  ws.columnDimensions.set(dim.min, dim);
5097
5119
  }
5098
- const sheetData = findChild(root, SHEETDATA_TAG);
5099
- if (sheetData) {
5100
- const sharedFormulas = /* @__PURE__ */ new Map();
5101
- for (const rowNode of findChildren(sheetData, ROW_TAG$1)) {
5102
- const rowIdx = parseRowIndex(rowNode);
5103
- maybeRecordRowDimension(ws, rowNode, rowIdx);
5104
- let nextCol = 1;
5105
- for (const cNode of findChildren(rowNode, C_TAG)) {
5106
- const coord = parseCellCoord(cNode, rowIdx, nextCol);
5107
- readCell(ws, cNode, coord, ctx, sharedFormulas);
5108
- nextCol = coord.col + 1;
5109
- }
5110
- }
5111
- }
5120
+ if (sheetData !== void 0) readSheetData(ws, text, sheetData, ctx);
5112
5121
  const protectionEl = findChild(root, SHEET_PROTECTION_TAG$1);
5113
5122
  if (protectionEl) ws.sheetProtection = parseSheetProtection$1(protectionEl);
5114
5123
  const ssEl = findChild(root, SORT_STATE_TAG);
@@ -5215,9 +5224,9 @@ function parseWorksheetXml(bytes, title, ctx) {
5215
5224
  type,
5216
5225
  properties: []
5217
5226
  };
5218
- const deleted = parseBoolXmlAttr(tagNode.attrs["deleted"]);
5227
+ const deleted = parseXsdBoolean(tagNode.attrs["deleted"]);
5219
5228
  if (deleted !== void 0) tag.deleted = deleted;
5220
- const xmlBased = parseBoolXmlAttr(tagNode.attrs["xmlBased"]);
5229
+ const xmlBased = parseXsdBoolean(tagNode.attrs["xmlBased"]);
5221
5230
  if (xmlBased !== void 0) tag.xmlBased = xmlBased;
5222
5231
  for (const prop of findChildren(tagNode, CELL_SMART_TAG_PR_TAG)) {
5223
5232
  const key = prop.attrs["key"];
@@ -5338,9 +5347,9 @@ const parseSortState = (node) => {
5338
5347
  ref,
5339
5348
  conditions: []
5340
5349
  };
5341
- const cs = parseBoolXmlAttr(node.attrs["columnSort"]);
5350
+ const cs = parseXsdBoolean(node.attrs["columnSort"]);
5342
5351
  if (cs !== void 0) out.columnSort = cs;
5343
- const cse = parseBoolXmlAttr(node.attrs["caseSensitive"]);
5352
+ const cse = parseXsdBoolean(node.attrs["caseSensitive"]);
5344
5353
  if (cse !== void 0) out.caseSensitive = cse;
5345
5354
  const sm = node.attrs["sortMethod"];
5346
5355
  if (sm && SORT_METHODS.includes(sm)) out.sortMethod = sm;
@@ -5348,7 +5357,7 @@ const parseSortState = (node) => {
5348
5357
  const cRef = sc.attrs["ref"];
5349
5358
  if (!cRef) continue;
5350
5359
  const c = { ref: cRef };
5351
- const desc = parseBoolXmlAttr(sc.attrs["descending"]);
5360
+ const desc = parseXsdBoolean(sc.attrs["descending"]);
5352
5361
  if (desc !== void 0) c.descending = desc;
5353
5362
  const sb = sc.attrs["sortBy"];
5354
5363
  if (sb && SORT_BY_VALUES.includes(sb)) c.sortBy = sb;
@@ -5388,9 +5397,9 @@ const parseScenario = (node) => {
5388
5397
  name,
5389
5398
  inputCells: []
5390
5399
  };
5391
- const locked = parseBoolXmlAttr(node.attrs["locked"]);
5400
+ const locked = parseXsdBoolean(node.attrs["locked"]);
5392
5401
  if (locked !== void 0) out.locked = locked;
5393
- const hidden = parseBoolXmlAttr(node.attrs["hidden"]);
5402
+ const hidden = parseXsdBoolean(node.attrs["hidden"]);
5394
5403
  if (hidden !== void 0) out.hidden = hidden;
5395
5404
  if (node.attrs["user"] !== void 0) out.user = node.attrs["user"];
5396
5405
  if (node.attrs["comment"] !== void 0) out.comment = node.attrs["comment"];
@@ -5408,9 +5417,9 @@ const parseScenarioInputCell = (node) => {
5408
5417
  ref,
5409
5418
  val
5410
5419
  };
5411
- const deleted = parseBoolXmlAttr(node.attrs["deleted"]);
5420
+ const deleted = parseXsdBoolean(node.attrs["deleted"]);
5412
5421
  if (deleted !== void 0) out.deleted = deleted;
5413
- const undone = parseBoolXmlAttr(node.attrs["undone"]);
5422
+ const undone = parseXsdBoolean(node.attrs["undone"]);
5414
5423
  if (undone !== void 0) out.undone = undone;
5415
5424
  const numFmtId = parseIntegerAttr(node.attrs["numFmtId"]);
5416
5425
  if (numFmtId !== void 0) out.numFmtId = numFmtId;
@@ -5433,11 +5442,11 @@ const parseDataConsolidate = (node) => {
5433
5442
  const out = {};
5434
5443
  const f = node.attrs["function"];
5435
5444
  if (f && DATA_CONSOLIDATE_FUNCTIONS.includes(f)) out.function = f;
5436
- const topLabels = parseBoolXmlAttr(node.attrs["topLabels"]);
5445
+ const topLabels = parseXsdBoolean(node.attrs["topLabels"]);
5437
5446
  if (topLabels !== void 0) out.topLabels = topLabels;
5438
- const leftLabels = parseBoolXmlAttr(node.attrs["leftLabels"]);
5447
+ const leftLabels = parseXsdBoolean(node.attrs["leftLabels"]);
5439
5448
  if (leftLabels !== void 0) out.leftLabels = leftLabels;
5440
- const link = parseBoolXmlAttr(node.attrs["link"]);
5449
+ const link = parseXsdBoolean(node.attrs["link"]);
5441
5450
  if (link !== void 0) out.link = link;
5442
5451
  if (node.attrs["startLabels"] !== void 0) out.startLabels = node.attrs["startLabels"];
5443
5452
  const refsEl = findChild(node, DATA_REFS_TAG);
@@ -5506,7 +5515,7 @@ const parseWebPublishItem = (node) => {
5506
5515
  if (node.attrs["sourceRef"] !== void 0) out.sourceRef = node.attrs["sourceRef"];
5507
5516
  if (node.attrs["sourceObject"] !== void 0) out.sourceObject = node.attrs["sourceObject"];
5508
5517
  if (node.attrs["title"] !== void 0) out.title = node.attrs["title"];
5509
- const auto = parseBoolXmlAttr(node.attrs["autoRepublish"]);
5518
+ const auto = parseXsdBoolean(node.attrs["autoRepublish"]);
5510
5519
  if (auto !== void 0) out.autoRepublish = auto;
5511
5520
  return out;
5512
5521
  };
@@ -5545,7 +5554,7 @@ const parseCustomSheetView = (node) => {
5545
5554
  "filterUnique",
5546
5555
  "showRuler"
5547
5556
  ]) {
5548
- const v = parseBoolXmlAttr(node.attrs[k]);
5557
+ const v = parseXsdBoolean(node.attrs[k]);
5549
5558
  if (v !== void 0) out[k] = v;
5550
5559
  }
5551
5560
  const stateRaw = node.attrs["state"];
@@ -5608,7 +5617,7 @@ const parseOleObject = (node) => {
5608
5617
  if (node.attrs["link"] !== void 0) out.link = node.attrs["link"];
5609
5618
  const oleUpdate = node.attrs["oleUpdate"];
5610
5619
  if (oleUpdate && OLE_UPDATE_MODES.includes(oleUpdate)) out.oleUpdate = oleUpdate;
5611
- const autoLoad = parseBoolXmlAttr(node.attrs["autoLoad"]);
5620
+ const autoLoad = parseXsdBoolean(node.attrs["autoLoad"]);
5612
5621
  if (autoLoad !== void 0) out.autoLoad = autoLoad;
5613
5622
  const objectPr = findChild(node, OBJECT_PR_TAG);
5614
5623
  if (objectPr) out.objectPr = objectPr;
@@ -5635,9 +5644,9 @@ const parsePageBreak = (node) => {
5635
5644
  if (min !== void 0) out.min = min;
5636
5645
  const max = parseIntegerAttr(node.attrs["max"]);
5637
5646
  if (max !== void 0) out.max = max;
5638
- const man = parseBoolXmlAttr(node.attrs["man"]);
5647
+ const man = parseXsdBoolean(node.attrs["man"]);
5639
5648
  if (man !== void 0) out.man = man;
5640
- const pt = parseBoolXmlAttr(node.attrs["pt"]);
5649
+ const pt = parseXsdBoolean(node.attrs["pt"]);
5641
5650
  if (pt !== void 0) out.pt = pt;
5642
5651
  return out;
5643
5652
  };
@@ -5999,24 +6008,19 @@ const parseIntegerAttr = (raw) => {
5999
6008
  const n = Number.parseInt(raw, 10);
6000
6009
  return Number.isInteger(n) ? n : void 0;
6001
6010
  };
6002
- const parseBoolXmlAttr = (raw) => {
6003
- if (raw === void 0) return void 0;
6004
- if (raw === "1" || raw === "true") return true;
6005
- if (raw === "0" || raw === "false") return false;
6006
- };
6007
6011
  const parseSheetView$1 = (node) => {
6008
6012
  const opts = { workbookViewId: parseIntegerAttr(node.attrs["workbookViewId"]) ?? 0 };
6009
- const tabSelected = parseBoolXmlAttr(node.attrs["tabSelected"]);
6013
+ const tabSelected = parseXsdBoolean(node.attrs["tabSelected"]);
6010
6014
  if (tabSelected !== void 0) opts.tabSelected = tabSelected;
6011
- const showGridLines = parseBoolXmlAttr(node.attrs["showGridLines"]);
6015
+ const showGridLines = parseXsdBoolean(node.attrs["showGridLines"]);
6012
6016
  if (showGridLines !== void 0) opts.showGridLines = showGridLines;
6013
- const showRowColHeaders = parseBoolXmlAttr(node.attrs["showRowColHeaders"]);
6017
+ const showRowColHeaders = parseXsdBoolean(node.attrs["showRowColHeaders"]);
6014
6018
  if (showRowColHeaders !== void 0) opts.showRowColHeaders = showRowColHeaders;
6015
- const showFormulas = parseBoolXmlAttr(node.attrs["showFormulas"]);
6019
+ const showFormulas = parseXsdBoolean(node.attrs["showFormulas"]);
6016
6020
  if (showFormulas !== void 0) opts.showFormulas = showFormulas;
6017
- const showZeros = parseBoolXmlAttr(node.attrs["showZeros"]);
6021
+ const showZeros = parseXsdBoolean(node.attrs["showZeros"]);
6018
6022
  if (showZeros !== void 0) opts.showZeros = showZeros;
6019
- const rightToLeft = parseBoolXmlAttr(node.attrs["rightToLeft"]);
6023
+ const rightToLeft = parseXsdBoolean(node.attrs["rightToLeft"]);
6020
6024
  if (rightToLeft !== void 0) opts.rightToLeft = rightToLeft;
6021
6025
  const view = node.attrs["view"];
6022
6026
  if (view !== void 0 && SHEET_VIEW_MODES.includes(view)) opts.view = view;
@@ -6051,62 +6055,328 @@ const parseSelection = (node) => {
6051
6055
  if (node.attrs["sqref"]) sel.sqref = node.attrs["sqref"];
6052
6056
  return sel;
6053
6057
  };
6054
- const parseRowIndex = (rowNode) => {
6055
- const rAttr = rowNode.attrs["r"];
6056
- if (rAttr === void 0) throw new OpenXmlSchemaError("worksheet: <row> missing required @r");
6057
- const r = Number.parseInt(rAttr, 10);
6058
- if (!Number.isInteger(r) || r < 1) throw new OpenXmlSchemaError(`worksheet: <row r="${rAttr}"> is not a positive integer`);
6059
- return r;
6058
+ const saxAttributes = (attrs) => {
6059
+ const out = {};
6060
+ for (const attr of Object.values(attrs)) out[qname(attr.uri, attr.local)] = attr.value;
6061
+ return out;
6062
+ };
6063
+ const XML_DECODER = new TextDecoder("utf-8", { fatal: false });
6064
+ /**
6065
+ * Spans whose content is text rather than markup. `<` is not legal in element
6066
+ * content or in an attribute value, so a comment, a CDATA section and a
6067
+ * processing instruction are the only places a worksheet can carry the literal
6068
+ * text `<sheetData` or `</sheetData>` without meaning it, and so the only thing
6069
+ * the scans below have to step over.
6070
+ */
6071
+ const OPAQUE_SPAN = String.raw`<!--[\s\S]*?-->|<!\[CDATA\[[\s\S]*?\]\]>|<\?[\s\S]*?\?>`;
6072
+ /** One of the same three openers with no terminator after it. */
6073
+ const UNTERMINATED_SPAN = String.raw`(?<unterminated><!--|<!\[CDATA\[|<\?)`;
6074
+ const OPAQUE_SPAN_RE = new RegExp(String.raw`${OPAQUE_SPAN}|${UNTERMINATED_SPAN}`, "g");
6075
+ /** Lexical tag boundaries, including quoted `>` and opaque XML spans. */
6076
+ const HEADER_TAG_RE = new RegExp(String.raw`${OPAQUE_SPAN}|<(?:(?:"[^"]*"|'[^']*'|[^'">])*)>`, "g");
6077
+ /** `>` or XML whitespace: the characters that can end an element name. */
6078
+ const NAME_END_RE = /^[\s>]$/;
6079
+ /**
6080
+ * Locate the `<sheetData>` span in a worksheet part so its rows can be walked
6081
+ * without building a node per cell.
6082
+ *
6083
+ * Parse the header to resolve the direct child's namespace, then scan for its
6084
+ * closing tag without constructing cell nodes. The scan skips comments, CDATA
6085
+ * sections and processing instructions and refuses unterminated opaque spans.
6086
+ *
6087
+ * `undefined` means "this sheet has no rows", and must not come to mean anything
6088
+ * else: no node-tree path for `<sheetData>` is left, so a span this function
6089
+ * declined to identify would drop every cell in the sheet in silence.
6090
+ */
6091
+ const locateSheetData = (text) => {
6092
+ const parser = new SaxesParser({ xmlns: true });
6093
+ const scopes = [];
6094
+ let found;
6095
+ parser.on("error", (error) => {
6096
+ throw new OpenXmlSchemaError(`worksheet: malformed header: ${error.message}`, { cause: error });
6097
+ });
6098
+ parser.on("opentag", (node) => {
6099
+ const namespaces = {
6100
+ ...scopes[scopes.length - 1],
6101
+ ...node.ns
6102
+ };
6103
+ scopes.push(namespaces);
6104
+ if (scopes.length === 2 && node.uri === "http://schemas.openxmlformats.org/spreadsheetml/2006/main" && node.local === "sheetData") found = {
6105
+ tag: node.name,
6106
+ namespaces,
6107
+ empty: node.isSelfClosing
6108
+ };
6109
+ });
6110
+ parser.on("closetag", () => {
6111
+ scopes.pop();
6112
+ });
6113
+ HEADER_TAG_RE.lastIndex = 0;
6114
+ let cursor = 0;
6115
+ for (let tag = HEADER_TAG_RE.exec(text); tag !== null; tag = HEADER_TAG_RE.exec(text)) {
6116
+ const bodyStart = tag.index + tag[0].length;
6117
+ parser.write(text.slice(cursor, bodyStart));
6118
+ cursor = bodyStart;
6119
+ if (found !== void 0) {
6120
+ if (found.empty) return void 0;
6121
+ return {
6122
+ bodyStart,
6123
+ bodyEnd: findSheetDataClose(text, found.tag, bodyStart),
6124
+ namespaces: found.namespaces
6125
+ };
6126
+ }
6127
+ }
6128
+ };
6129
+ /** An unterminated opaque span means the part is not well-formed XML. */
6130
+ const refuseUnterminatedSpan = (match) => {
6131
+ const opener = match.groups?.["unterminated"];
6132
+ if (opener === void 0) return;
6133
+ throw new OpenXmlSchemaError(`worksheet: "${opener}" is never closed`);
6134
+ };
6135
+ /**
6136
+ * Index of the `<` opening `</tag>`, skipping any candidate that sits inside an
6137
+ * opaque span. The opaque scan only ever moves forward, so a part whose rows
6138
+ * hold no comment, CDATA section or processing instruction pays for one pass
6139
+ * over the body and then never looks again.
6140
+ */
6141
+ const findSheetDataClose = (text, tag, bodyStart) => {
6142
+ const close = `</${tag}`;
6143
+ let at = bodyStart;
6144
+ let opaque = nextOpaqueSpan(text, bodyStart);
6145
+ for (;;) {
6146
+ const candidate = indexOfCloseTag(text, close, at);
6147
+ if (candidate < 0) throw new OpenXmlSchemaError(`worksheet: <${tag}> is never closed`);
6148
+ while (opaque !== void 0 && opaque.end <= candidate) opaque = nextOpaqueSpan(text, opaque.end);
6149
+ if (opaque === void 0 || opaque.start > candidate) return candidate;
6150
+ at = opaque.end;
6151
+ }
6152
+ };
6153
+ /** First span at or after `from` whose content is text rather than markup. */
6154
+ const nextOpaqueSpan = (text, from) => {
6155
+ OPAQUE_SPAN_RE.lastIndex = from;
6156
+ const span = OPAQUE_SPAN_RE.exec(text);
6157
+ if (span === null) return void 0;
6158
+ refuseUnterminatedSpan(span);
6159
+ return {
6160
+ start: span.index,
6161
+ end: span.index + span[0].length
6162
+ };
6163
+ };
6164
+ /** Index of `</tag>` or `</tag >`, never of `</tagSomethingElse>`. */
6165
+ const indexOfCloseTag = (text, close, from) => {
6166
+ for (let at = text.indexOf(close, from); at >= 0; at = text.indexOf(close, at + close.length)) if (NAME_END_RE.test(text.charAt(at + close.length))) return at;
6167
+ return -1;
6060
6168
  };
6061
- const parseCellCoord = (cNode, rowIdx, fallbackCol) => {
6062
- const rAttr = cNode.attrs["r"];
6063
- if (rAttr === void 0) return {
6169
+ /**
6170
+ * Text handed to saxes per `write()`. The parser carries a partial token across
6171
+ * writes, so the size only decides how much of the part is copied at once. One
6172
+ * write of a 16 MB span would hold the cell text twice over for the length of
6173
+ * the walk, which is the footprint this reader exists to remove.
6174
+ */
6175
+ const WRITE_CHUNK = 256 * 1024;
6176
+ const isHighSurrogate = (code) => code >= 55296 && code <= 56319;
6177
+ /**
6178
+ * Walk `<sheetData>` and place every cell, resolving inherited namespaces
6179
+ * so foreign extension elements cannot become spreadsheet cells.
6180
+ *
6181
+ * `iterSheetRows` in `../streaming/read-only.ts` walks the same element shapes
6182
+ * to a different destination, and the two have to agree on where a row or cell
6183
+ * with no `@r` lands. That agreement is asserted rather than left to whoever
6184
+ * edits one of them: see "agrees with loadWorkbook on where every cell lands"
6185
+ * in `tests/worksheet/row-without-r-attribute.test.ts`.
6186
+ */
6187
+ const readSheetData = (ws, text, span, ctx) => {
6188
+ const sharedFormulas = /* @__PURE__ */ new Map();
6189
+ let nextRow = 1;
6190
+ let rowIdx = -1;
6191
+ let rowAttrs = {};
6192
+ let nextCol = 1;
6193
+ const held = [];
6194
+ let depth = 0;
6195
+ let cell;
6196
+ let valueTag;
6197
+ let valueText;
6198
+ const inlineStack = [];
6199
+ const settleRow = (row) => {
6200
+ rowIdx = row;
6201
+ nextRow = Math.max(nextRow, row + 1);
6202
+ maybeRecordRowDimension(ws, rowAttrs, row);
6203
+ for (const heldCell of held) {
6204
+ const coord = parseCellCoord(heldCell.ref, row, nextCol);
6205
+ readCell(ws, heldCell, coord, ctx, sharedFormulas);
6206
+ nextCol = coord.col + 1;
6207
+ }
6208
+ held.length = 0;
6209
+ };
6210
+ const parser = new SaxesParser({
6211
+ fragment: true,
6212
+ xmlns: true,
6213
+ additionalNamespaces: span.namespaces
6214
+ });
6215
+ parser.on("error", (err) => {
6216
+ throw new OpenXmlSchemaError(`worksheet: malformed <sheetData>: ${err.message}`, { cause: err });
6217
+ });
6218
+ parser.on("processinginstruction", (pi) => {
6219
+ throw new OpenXmlSchemaError(`worksheet: processing instructions are not supported (saw "<?${pi.target}")`);
6220
+ });
6221
+ parser.on("opentag", (node) => {
6222
+ depth++;
6223
+ if (inlineStack.length > 0) {
6224
+ const child = el(qname(node.uri, node.local), saxAttributes(node.attributes));
6225
+ inlineStack[inlineStack.length - 1]?.children.push(child);
6226
+ inlineStack.push(child);
6227
+ return;
6228
+ }
6229
+ const local = node.local;
6230
+ if (valueTag !== void 0) throw new OpenXmlSchemaError(`worksheet: mixed content not supported (<${local}> inside <${valueTag}>${cellLabel(cell)})`);
6231
+ if (node.uri !== "http://schemas.openxmlformats.org/spreadsheetml/2006/main") return;
6232
+ if (depth === 1) {
6233
+ if (local !== "row") return;
6234
+ rowAttrs = saxAttributes(node.attributes);
6235
+ nextCol = 1;
6236
+ held.length = 0;
6237
+ const rAttr = rowAttrs["r"];
6238
+ if (rAttr === void 0) rowIdx = 0;
6239
+ else settleRow(rowNumberFromAttr(rAttr, "worksheet"));
6240
+ return;
6241
+ }
6242
+ if (rowIdx < 0) return;
6243
+ if (depth === 2) {
6244
+ if (local !== "c") return;
6245
+ const attrs = saxAttributes(node.attributes);
6246
+ cell = {
6247
+ ref: attrs["r"],
6248
+ style: attrs["s"],
6249
+ t: attrs["t"] ?? "n",
6250
+ value: void 0,
6251
+ formulaAttrs: void 0,
6252
+ formula: void 0,
6253
+ inline: void 0
6254
+ };
6255
+ return;
6256
+ }
6257
+ if (depth === 3 && cell !== void 0) {
6258
+ if (local === "v" || local === "f") {
6259
+ if (local === "f") cell.formulaAttrs = saxAttributes(node.attributes);
6260
+ valueTag = local;
6261
+ valueText = "";
6262
+ } else if (local === "is") {
6263
+ const root = el(qname(SHEET_MAIN_NS, "is"));
6264
+ cell.inline = root;
6265
+ inlineStack.push(root);
6266
+ }
6267
+ }
6268
+ });
6269
+ const addText = (chunk) => {
6270
+ if (inlineStack.length > 0) {
6271
+ const top = inlineStack[inlineStack.length - 1];
6272
+ if (top !== void 0) top.text = (top.text ?? "") + chunk;
6273
+ return;
6274
+ }
6275
+ if (valueText !== void 0) valueText += chunk;
6276
+ else if ((depth === 0 || depth === 1 && rowIdx >= 0 || depth === 2 && cell !== void 0) && !isWhitespaceOnly(chunk)) throw new OpenXmlSchemaError("worksheet: mixed content not supported (text between cell elements)");
6277
+ };
6278
+ parser.on("text", addText);
6279
+ parser.on("cdata", addText);
6280
+ parser.on("closetag", (node) => {
6281
+ depth--;
6282
+ if (inlineStack.length > 0) {
6283
+ const closed = inlineStack.pop();
6284
+ if (closed !== void 0) refuseInlineMixedContent(closed);
6285
+ return;
6286
+ }
6287
+ if (node.uri !== "http://schemas.openxmlformats.org/spreadsheetml/2006/main") return;
6288
+ const local = node.local;
6289
+ if (depth === 2 && cell !== void 0) {
6290
+ if (local === "v") cell.value = valueText ?? "";
6291
+ else if (local === "f") cell.formula = valueText ?? "";
6292
+ valueTag = void 0;
6293
+ valueText = void 0;
6294
+ return;
6295
+ }
6296
+ if (depth === 1 && cell !== void 0 && local === "c") {
6297
+ if (rowIdx === 0) if (cell.ref !== void 0) settleRow(coordinateToTuple(cell.ref).row);
6298
+ else held.push(cell);
6299
+ if (rowIdx > 0) {
6300
+ const coord = parseCellCoord(cell.ref, rowIdx, nextCol);
6301
+ readCell(ws, cell, coord, ctx, sharedFormulas);
6302
+ nextCol = coord.col + 1;
6303
+ }
6304
+ cell = void 0;
6305
+ return;
6306
+ }
6307
+ if (depth === 0 && local === "row") {
6308
+ if (rowIdx === 0) settleRow(derivedRowNumber(nextRow, "worksheet"));
6309
+ rowIdx = -1;
6310
+ }
6311
+ });
6312
+ for (let at = span.bodyStart; at < span.bodyEnd;) {
6313
+ let end = Math.min(at + WRITE_CHUNK, span.bodyEnd);
6314
+ if (end < span.bodyEnd && isHighSurrogate(text.charCodeAt(end - 1))) end++;
6315
+ parser.write(text.slice(at, end));
6316
+ at = end;
6317
+ }
6318
+ parser.close();
6319
+ };
6320
+ /** The offending cell's `@r`, for an error message that can point at it. */
6321
+ const cellLabel = (cell) => cell?.ref === void 0 ? "" : ` of <c r="${cell.ref}">`;
6322
+ /**
6323
+ * Apply `parseXml`'s mixed-content rule to an `<is>` subtree this reader builds
6324
+ * itself: text alongside child elements is refused, whitespace between them is
6325
+ * dropped.
6326
+ */
6327
+ const refuseInlineMixedContent = (node) => {
6328
+ if (node.children.length === 0 || node.text === void 0) return;
6329
+ if (!isWhitespaceOnly(node.text)) throw new OpenXmlSchemaError(`worksheet: mixed content not supported (text between elements under <${localNameOf(node.name)}>)`);
6330
+ delete node.text;
6331
+ };
6332
+ const parseCellCoord = (ref, rowIdx, fallbackCol) => {
6333
+ if (ref === void 0) return {
6064
6334
  row: rowIdx,
6065
6335
  col: fallbackCol
6066
6336
  };
6067
- const t = coordinateToTuple(rAttr);
6068
- if (t.row !== rowIdx) throw new OpenXmlSchemaError(`worksheet: <c r="${rAttr}"> row ${t.row} disagrees with <row r="${rowIdx}">`);
6337
+ const t = coordinateToTuple(ref);
6338
+ if (t.row !== rowIdx) throw new OpenXmlSchemaError(`worksheet: <c r="${ref}"> row ${t.row} disagrees with row ${rowIdx}`);
6069
6339
  return {
6070
6340
  row: t.row,
6071
6341
  col: t.col
6072
6342
  };
6073
6343
  };
6074
- const readCell = (ws, cNode, coord, ctx, sharedFormulas) => {
6075
- const t = cNode.attrs["t"] ?? "n";
6076
- const styleAttr = cNode.attrs["s"];
6077
- const styleId = styleAttr === void 0 ? 0 : parseStyleId(styleAttr);
6078
- const fNode = findChild(cNode, F_TAG);
6079
- const vNode = findChild(cNode, V_TAG);
6080
- const isNode = findChild(cNode, IS_TAG);
6081
- if (fNode) {
6344
+ const readCell = (ws, raw, coord, ctx, sharedFormulas) => {
6345
+ const t = raw.t;
6346
+ const styleId = raw.style === void 0 ? 0 : parseStyleId(raw.style);
6347
+ if (raw.formulaAttrs !== void 0) {
6082
6348
  const cell = setCell(ws, coord.row, coord.col, null, styleId);
6083
- const cachedRaw = vNode === void 0 ? void 0 : vNode.text ?? "";
6084
- const cached = decodeCachedValue(cachedRaw, t);
6085
- handleFormula(cell, fNode, coord, cached, sharedFormulas);
6349
+ const cached = decodeCachedValue(raw.value, t, ctx, ws.title, coord);
6350
+ handleFormula(cell, raw.formulaAttrs, raw.formula, coord, cached, sharedFormulas, t);
6086
6351
  return;
6087
6352
  }
6088
6353
  let value = null;
6089
6354
  switch (t) {
6090
6355
  case "n":
6091
- value = vNode?.text !== void 0 && vNode.text !== "" ? Number.parseFloat(vNode.text) : null;
6356
+ value = parseCellNumber(raw.value, ws.title, coord.col, coord.row);
6092
6357
  break;
6093
6358
  case "s": {
6094
- if (vNode?.text === void 0) throw new OpenXmlSchemaError("worksheet: <c t=\"s\"> missing <v>");
6095
- const idx = Number.parseInt(vNode.text, 10);
6096
- if (!Number.isInteger(idx) || idx < 0) throw new OpenXmlSchemaError(`worksheet: <c t="s"><v>${vNode.text}</v> is not a valid index`);
6097
- const sst = ctx.sharedStrings[idx];
6098
- if (sst === void 0) throw new OpenXmlSchemaError(`worksheet: shared-string index ${idx} out of range [0, ${ctx.sharedStrings.length})`);
6359
+ if (raw.value === void 0 || raw.value === "") throw new OpenXmlSchemaError("worksheet: <c t=\"s\"> missing <v>");
6360
+ const sst = resolveSharedString(raw.value, ctx);
6099
6361
  value = typeof sst === "string" ? sst : {
6100
6362
  kind: "rich-text",
6101
6363
  runs: sst.runs
6102
6364
  };
6103
6365
  break;
6104
6366
  }
6105
- case "b":
6106
- value = vNode?.text === "1";
6367
+ case "b": {
6368
+ const text = raw.value?.trim();
6369
+ if (text === void 0 || text === "") {
6370
+ value = null;
6371
+ break;
6372
+ }
6373
+ const parsed = parseXsdBoolean(text);
6374
+ if (parsed === void 0) throw new OpenXmlSchemaError(`worksheet: <c r="${tupleToCoordinate(coord.col, coord.row)}" t="b"><v>${clipCellText(text)}</v></c> is not a boolean`);
6375
+ value = parsed;
6107
6376
  break;
6377
+ }
6108
6378
  case "e": {
6109
- const code = vNode?.text;
6379
+ const code = raw.value;
6110
6380
  if (code === void 0 || !ERROR_CODES$1.has(code)) throw new OpenXmlSchemaError(`worksheet: unknown error code "${code}" in <c t="e">`);
6111
6381
  value = {
6112
6382
  kind: "error",
@@ -6115,15 +6385,25 @@ const readCell = (ws, cNode, coord, ctx, sharedFormulas) => {
6115
6385
  break;
6116
6386
  }
6117
6387
  case "str":
6118
- value = vNode?.text ?? "";
6388
+ value = raw.value ?? "";
6119
6389
  break;
6120
6390
  case "inlineStr":
6121
- value = readInlineString(isNode);
6391
+ value = readInlineString(raw.inline);
6122
6392
  break;
6123
6393
  default: throw new OpenXmlSchemaError(`worksheet: unknown cell type t="${t}"`);
6124
6394
  }
6125
6395
  setCell(ws, coord.row, coord.col, value, styleId);
6126
6396
  };
6397
+ const MAX_REPORTED_TEXT = 40;
6398
+ /**
6399
+ * Cell text quoted into an error message is untrusted input of unbounded
6400
+ * length, and nothing stops it from spanning lines, so keep the message one
6401
+ * short line whatever the part holds.
6402
+ */
6403
+ const clipCellText = (raw) => {
6404
+ const oneLine = raw.replace(/\s+/g, " ");
6405
+ return oneLine.length > MAX_REPORTED_TEXT ? `${oneLine.slice(0, MAX_REPORTED_TEXT)}…` : oneLine;
6406
+ };
6127
6407
  const parseStyleId = (raw) => {
6128
6408
  const n = Number.parseInt(raw, 10);
6129
6409
  if (!Number.isInteger(n) || n < 0) throw new OpenXmlSchemaError(`worksheet: <c s="${raw}"> is not a non-negative integer`);
@@ -6143,38 +6423,56 @@ const readInlineString = (isNode) => {
6143
6423
  runs: entry.runs
6144
6424
  };
6145
6425
  };
6146
- const decodeCachedValue = (raw, t) => {
6426
+ const resolveSharedString = (raw, ctx) => {
6427
+ const idx = Number.parseInt(raw, 10);
6428
+ if (!Number.isInteger(idx) || idx < 0) throw new OpenXmlSchemaError(`worksheet: <c t="s"><v>${raw}</v> is not a valid index`);
6429
+ const sst = ctx.sharedStrings[idx];
6430
+ if (sst === void 0) throw new OpenXmlSchemaError(`worksheet: shared-string index ${idx} out of range [0, ${ctx.sharedStrings.length})`);
6431
+ return sst;
6432
+ };
6433
+ const decodeCachedValue = (raw, t, ctx, sheet, coord) => {
6147
6434
  if (raw === void 0) return void 0;
6148
6435
  switch (t) {
6149
- case "n": return raw === "" ? void 0 : Number.parseFloat(raw);
6150
- case "b": return raw === "" ? void 0 : raw === "1";
6151
- case "str": return raw;
6152
- case "e": return raw;
6153
- case "s": return raw;
6436
+ case "n": return parseCellNumber(raw, sheet, coord.col, coord.row) ?? void 0;
6437
+ case "b": {
6438
+ const text = raw.trim();
6439
+ if (text === "") return void 0;
6440
+ const parsed = parseXsdBoolean(text);
6441
+ if (parsed === void 0) throw new OpenXmlSchemaError(`worksheet: <c r="${tupleToCoordinate(coord.col, coord.row)}" t="b"><v>${clipCellText(text)}</v></c> cached result is not a boolean`);
6442
+ return parsed;
6443
+ }
6444
+ case "s": {
6445
+ if (raw === "") return void 0;
6446
+ const sst = resolveSharedString(raw, ctx);
6447
+ return typeof sst === "string" ? sst : richTextToString(sst.runs);
6448
+ }
6154
6449
  default: return raw;
6155
6450
  }
6156
6451
  };
6157
- const handleFormula = (cell, fNode, coord, cached, sharedFormulas) => {
6158
- const tAttr = fNode.attrs["t"] ?? "normal";
6159
- const formula = normalizeFormulaText(fNode.text ?? "");
6160
- const opts = cached !== void 0 ? { cachedValue: cached } : void 0;
6452
+ const handleFormula = (cell, fAttrs, fText, coord, cached, sharedFormulas, cachedType) => {
6453
+ const tAttr = fAttrs["t"] ?? "normal";
6454
+ const formula = normalizeFormulaText(fText ?? "");
6455
+ const opts = cached !== void 0 ? {
6456
+ cachedValue: cached,
6457
+ ...cachedType === "e" ? { cachedValueType: "error" } : {}
6458
+ } : void 0;
6161
6459
  switch (tAttr) {
6162
6460
  case "normal":
6163
6461
  if (formula.length === 0) throw new OpenXmlSchemaError(`worksheet: <f> at ${tupleToCoordinate(coord.col, coord.row)} has no formula text`);
6164
6462
  setFormula(cell, formula, opts);
6165
6463
  return;
6166
6464
  case "array": {
6167
- const ref = fNode.attrs["ref"];
6465
+ const ref = fAttrs["ref"];
6168
6466
  if (!ref) throw new OpenXmlSchemaError("worksheet: <f t=\"array\"> missing @ref");
6169
6467
  setArrayFormula(cell, ref, formula, opts);
6170
6468
  return;
6171
6469
  }
6172
6470
  case "shared": {
6173
- const siRaw = fNode.attrs["si"];
6471
+ const siRaw = fAttrs["si"];
6174
6472
  if (siRaw === void 0) throw new OpenXmlSchemaError("worksheet: <f t=\"shared\"> missing @si");
6175
6473
  const si = Number.parseInt(siRaw, 10);
6176
6474
  if (!Number.isInteger(si) || si < 0) throw new OpenXmlSchemaError(`worksheet: <f t="shared" si="${siRaw}"> is not a valid index`);
6177
- const ref = fNode.attrs["ref"];
6475
+ const ref = fAttrs["ref"];
6178
6476
  if (formula.length > 0) {
6179
6477
  sharedFormulas.set(si, {
6180
6478
  origin: tupleToCoordinate(coord.col, coord.row),
@@ -6190,29 +6488,25 @@ const handleFormula = (cell, fNode, coord, cached, sharedFormulas) => {
6190
6488
  return;
6191
6489
  }
6192
6490
  case "dataTable": {
6193
- const ref = fNode.attrs["ref"];
6491
+ const ref = fAttrs["ref"];
6194
6492
  if (!ref) throw new OpenXmlSchemaError("worksheet: <f t=\"dataTable\"> missing @ref");
6195
6493
  setDataTableFormula(cell, formula, {
6196
6494
  ref,
6197
- ...cached !== void 0 ? { cachedValue: cached } : {},
6198
- ...fNode.attrs["r1"] !== void 0 ? { r1: fNode.attrs["r1"] } : {},
6199
- ...fNode.attrs["r2"] !== void 0 ? { r2: fNode.attrs["r2"] } : {},
6200
- ...parseDataTableBool(fNode.attrs["dt2D"]) ? { dt2D: true } : {},
6201
- ...parseDataTableBool(fNode.attrs["dtr"]) ? { dtr: true } : {},
6202
- ...parseDataTableBool(fNode.attrs["del1"]) ? { del1: true } : {},
6203
- ...parseDataTableBool(fNode.attrs["del2"]) ? { del2: true } : {},
6204
- ...parseDataTableBool(fNode.attrs["aca"]) ? { aca: true } : {},
6205
- ...parseDataTableBool(fNode.attrs["ca"]) ? { ca: true } : {}
6495
+ ...opts,
6496
+ ...fAttrs["r1"] !== void 0 ? { r1: fAttrs["r1"] } : {},
6497
+ ...fAttrs["r2"] !== void 0 ? { r2: fAttrs["r2"] } : {},
6498
+ ...parseXsdBoolean(fAttrs["dt2D"]) ? { dt2D: true } : {},
6499
+ ...parseXsdBoolean(fAttrs["dtr"]) ? { dtr: true } : {},
6500
+ ...parseXsdBoolean(fAttrs["del1"]) ? { del1: true } : {},
6501
+ ...parseXsdBoolean(fAttrs["del2"]) ? { del2: true } : {},
6502
+ ...parseXsdBoolean(fAttrs["aca"]) ? { aca: true } : {},
6503
+ ...parseXsdBoolean(fAttrs["ca"]) ? { ca: true } : {}
6206
6504
  });
6207
6505
  return;
6208
6506
  }
6209
6507
  default: throw new OpenXmlSchemaError(`worksheet: <f t="${tAttr}"> unknown formula kind`);
6210
6508
  }
6211
6509
  };
6212
- const parseDataTableBool = (raw) => {
6213
- if (raw === void 0) return false;
6214
- return raw === "1" || raw === "true";
6215
- };
6216
6510
  const parseColumnDimension = (node) => {
6217
6511
  const minRaw = node.attrs["min"];
6218
6512
  const maxRaw = node.attrs["max"];
@@ -6223,17 +6517,17 @@ const parseColumnDimension = (node) => {
6223
6517
  const opts = {};
6224
6518
  const width = parseFloatAttr(node.attrs["width"]);
6225
6519
  if (width !== void 0) opts.width = width;
6226
- const customWidth = parseBoolXmlAttr(node.attrs["customWidth"]);
6520
+ const customWidth = parseXsdBoolean(node.attrs["customWidth"]);
6227
6521
  if (customWidth !== void 0) opts.customWidth = customWidth;
6228
- const hidden = parseBoolXmlAttr(node.attrs["hidden"]);
6522
+ const hidden = parseXsdBoolean(node.attrs["hidden"]);
6229
6523
  if (hidden !== void 0) opts.hidden = hidden;
6230
- const bestFit = parseBoolXmlAttr(node.attrs["bestFit"]);
6524
+ const bestFit = parseXsdBoolean(node.attrs["bestFit"]);
6231
6525
  if (bestFit !== void 0) opts.bestFit = bestFit;
6232
6526
  const outlineLevel = parseIntegerAttr(node.attrs["outlineLevel"]);
6233
6527
  if (outlineLevel !== void 0) opts.outlineLevel = outlineLevel;
6234
6528
  const style = parseIntegerAttr(node.attrs["style"]);
6235
6529
  if (style !== void 0) opts.style = style;
6236
- const collapsed = parseBoolXmlAttr(node.attrs["collapsed"]);
6530
+ const collapsed = parseXsdBoolean(node.attrs["collapsed"]);
6237
6531
  if (collapsed !== void 0) opts.collapsed = collapsed;
6238
6532
  return {
6239
6533
  ...makeColumnDimension(min, opts),
@@ -6275,13 +6569,13 @@ const parseDataValidation = (node) => {
6275
6569
  };
6276
6570
  const operator = node.attrs["operator"];
6277
6571
  if (operator && DV_OPERATORS.includes(operator)) opts.operator = operator;
6278
- const allowBlank = parseBoolXmlAttr(node.attrs["allowBlank"]);
6572
+ const allowBlank = parseXsdBoolean(node.attrs["allowBlank"]);
6279
6573
  if (allowBlank !== void 0) opts.allowBlank = allowBlank;
6280
- const showInputMessage = parseBoolXmlAttr(node.attrs["showInputMessage"]);
6574
+ const showInputMessage = parseXsdBoolean(node.attrs["showInputMessage"]);
6281
6575
  if (showInputMessage !== void 0) opts.showInputMessage = showInputMessage;
6282
- const showErrorMessage = parseBoolXmlAttr(node.attrs["showErrorMessage"]);
6576
+ const showErrorMessage = parseXsdBoolean(node.attrs["showErrorMessage"]);
6283
6577
  if (showErrorMessage !== void 0) opts.showErrorMessage = showErrorMessage;
6284
- const showDropDown = parseBoolXmlAttr(node.attrs["showDropDown"]);
6578
+ const showDropDown = parseXsdBoolean(node.attrs["showDropDown"]);
6285
6579
  if (showDropDown !== void 0) opts.showDropDown = showDropDown;
6286
6580
  const errorTitle = node.attrs["errorTitle"];
6287
6581
  if (errorTitle !== void 0) opts.errorTitle = errorTitle;
@@ -6336,7 +6630,7 @@ const parseConditionalFormatting = (node) => {
6336
6630
  sqref: parseMultiCellRange(sqrefRaw),
6337
6631
  rules
6338
6632
  };
6339
- const pivot = parseBoolXmlAttr(node.attrs["pivot"]);
6633
+ const pivot = parseXsdBoolean(node.attrs["pivot"]);
6340
6634
  if (pivot !== void 0) opts.pivot = pivot;
6341
6635
  return makeConditionalFormatting(opts);
6342
6636
  };
@@ -6354,19 +6648,19 @@ const parseCfRule = (node) => {
6354
6648
  };
6355
6649
  const dxf = parseIntegerAttr(node.attrs["dxfId"]);
6356
6650
  if (dxf !== void 0) opts.dxfId = dxf;
6357
- const stop = parseBoolXmlAttr(node.attrs["stopIfTrue"]);
6651
+ const stop = parseXsdBoolean(node.attrs["stopIfTrue"]);
6358
6652
  if (stop !== void 0) opts.stopIfTrue = stop;
6359
6653
  if (node.attrs["operator"]) opts.operator = node.attrs["operator"];
6360
6654
  if (node.attrs["text"] !== void 0) opts.text = node.attrs["text"];
6361
- const percent = parseBoolXmlAttr(node.attrs["percent"]);
6655
+ const percent = parseXsdBoolean(node.attrs["percent"]);
6362
6656
  if (percent !== void 0) opts.percent = percent;
6363
- const bottom = parseBoolXmlAttr(node.attrs["bottom"]);
6657
+ const bottom = parseXsdBoolean(node.attrs["bottom"]);
6364
6658
  if (bottom !== void 0) opts.bottom = bottom;
6365
6659
  const rank = parseIntegerAttr(node.attrs["rank"]);
6366
6660
  if (rank !== void 0) opts.rank = rank;
6367
- const aboveAverage = parseBoolXmlAttr(node.attrs["aboveAverage"]);
6661
+ const aboveAverage = parseXsdBoolean(node.attrs["aboveAverage"]);
6368
6662
  if (aboveAverage !== void 0) opts.aboveAverage = aboveAverage;
6369
- const equalAverage = parseBoolXmlAttr(node.attrs["equalAverage"]);
6663
+ const equalAverage = parseXsdBoolean(node.attrs["equalAverage"]);
6370
6664
  if (equalAverage !== void 0) opts.equalAverage = equalAverage;
6371
6665
  const stdDev = parseIntegerAttr(node.attrs["stdDev"]);
6372
6666
  if (stdDev !== void 0) opts.stdDev = stdDev;
@@ -6399,7 +6693,7 @@ const parseAutoFilter = (node) => {
6399
6693
  const v = f.attrs["val"];
6400
6694
  if (v !== void 0) values.push(v);
6401
6695
  }
6402
- const blank = parseBoolXmlAttr(filtersEl.attrs["blank"]);
6696
+ const blank = parseXsdBoolean(filtersEl.attrs["blank"]);
6403
6697
  const fc2 = {
6404
6698
  kind: "filters",
6405
6699
  colId,
@@ -6428,19 +6722,19 @@ const parseHyperlink = (node, rels) => {
6428
6722
  if (node.attrs["display"]) opts.display = node.attrs["display"];
6429
6723
  return opts;
6430
6724
  };
6431
- const maybeRecordRowDimension = (ws, node, rowIdx) => {
6725
+ const maybeRecordRowDimension = (ws, attrs, rowIdx) => {
6432
6726
  const opts = {};
6433
- const ht = parseFloatAttr(node.attrs["ht"]);
6727
+ const ht = parseFloatAttr(attrs["ht"]);
6434
6728
  if (ht !== void 0) opts.height = ht;
6435
- const customHeight = parseBoolXmlAttr(node.attrs["customHeight"]);
6729
+ const customHeight = parseXsdBoolean(attrs["customHeight"]);
6436
6730
  if (customHeight !== void 0) opts.customHeight = customHeight;
6437
- const hidden = parseBoolXmlAttr(node.attrs["hidden"]);
6731
+ const hidden = parseXsdBoolean(attrs["hidden"]);
6438
6732
  if (hidden !== void 0) opts.hidden = hidden;
6439
- const outlineLevel = parseIntegerAttr(node.attrs["outlineLevel"]);
6733
+ const outlineLevel = parseIntegerAttr(attrs["outlineLevel"]);
6440
6734
  if (outlineLevel !== void 0) opts.outlineLevel = outlineLevel;
6441
- const collapsed = parseBoolXmlAttr(node.attrs["collapsed"]);
6735
+ const collapsed = parseXsdBoolean(attrs["collapsed"]);
6442
6736
  if (collapsed !== void 0) opts.collapsed = collapsed;
6443
- const style = parseIntegerAttr(node.attrs["s"]);
6737
+ const style = parseIntegerAttr(attrs["s"]);
6444
6738
  if (style !== void 0) opts.style = style;
6445
6739
  if (Object.keys(opts).length === 0) return;
6446
6740
  ws.rowDimensions.set(rowIdx, makeRowDimension(opts));
@@ -6638,10 +6932,7 @@ const serializeCell = (cell, ctx, stringWriter) => {
6638
6932
  }
6639
6933
  return `<c r="${ref}"${styleAttr} t="s"><v>${addSharedRichText(ctx.sharedStrings, runs)}</v></c>`;
6640
6934
  }
6641
- if (typeof value === "number") {
6642
- if (!Number.isFinite(value)) throw new OpenXmlSchemaError(`worksheet: cannot serialise non-finite number at ${ref}`);
6643
- return `<c r="${ref}"${styleAttr}><v>${serializeNumber(value)}</v></c>`;
6644
- }
6935
+ if (typeof value === "number") return `<c r="${ref}"${styleAttr}><v>${serializeNumber(value, ref)}</v></c>`;
6645
6936
  if (typeof value === "boolean") return `<c r="${ref}"${styleAttr} t="b"><v>${value ? "1" : "0"}</v></c>`;
6646
6937
  if (typeof value === "string") {
6647
6938
  if (stringWriter) {
@@ -6652,16 +6943,17 @@ const serializeCell = (cell, ctx, stringWriter) => {
6652
6943
  }
6653
6944
  if (value instanceof Date) {
6654
6945
  const serial = dateToExcel(value, { epoch: ctx.date1904 ? "mac" : "windows" });
6655
- return `<c r="${ref}"${styleAttr}><v>${serializeNumber(serial)}</v></c>`;
6946
+ return `<c r="${ref}"${styleAttr}><v>${serializeNumber(serial, ref)}</v></c>`;
6656
6947
  }
6657
6948
  if (typeof value === "object" && value !== null && value.kind === "duration") {
6658
6949
  const ms = value.ms;
6659
6950
  const serial = durationToExcel(ms);
6660
- return `<c r="${ref}"${styleAttr}><v>${serializeNumber(serial)}</v></c>`;
6951
+ return `<c r="${ref}"${styleAttr}><v>${serializeNumber(serial, ref)}</v></c>`;
6661
6952
  }
6662
6953
  throw new OpenXmlSchemaError(`worksheet: unsupported cell value kind at ${ref}: ${describeValue(value)}`);
6663
6954
  };
6664
- const serializeNumber = (n) => {
6955
+ const serializeNumber = (n, ref) => {
6956
+ if (!Number.isFinite(n)) throw new OpenXmlSchemaError(`worksheet: cannot serialise non-finite number at ${ref}`);
6665
6957
  return Number.isInteger(n) ? n.toFixed(0) : String(n);
6666
6958
  };
6667
6959
  const serializeFormulaCell = (ref, styleAttr, f) => {
@@ -6680,18 +6972,22 @@ const serializeFormulaCell = (ref, styleAttr, f) => {
6680
6972
  const fAttrStr = fAttrs.length > 0 ? ` ${fAttrs.join(" ")}` : "";
6681
6973
  const normalized = normalizeFormulaText(f.formula);
6682
6974
  if ((f.t === "normal" || f.t === "array") && normalized.length === 0) throw new OpenXmlSchemaError(`worksheet: ${f.t} formula must not be empty at ${ref}`);
6683
- const formulaText = escapeXmlText(escapeCellString(normalized));
6975
+ const formulaText = escapeXmlTextVerbatim(normalized, "worksheet: formula", ref);
6684
6976
  const fEl = formulaText.length > 0 ? `<f${fAttrStr}>${formulaText}</f>` : `<f${fAttrStr}/>`;
6685
6977
  let valueAttr = "";
6686
6978
  let vEl = "";
6687
6979
  const cached = f.cachedValue;
6688
- if (cached !== void 0) if (typeof cached === "number") vEl = `<v>${serializeNumber(cached)}</v>`;
6980
+ if (f.cachedValueType === "error") {
6981
+ if (typeof cached !== "string" || !ERROR_CODES$1.has(cached)) throw new OpenXmlSchemaError(`worksheet: invalid cached formula error at ${ref}`);
6982
+ valueAttr = " t=\"e\"";
6983
+ vEl = `<v>${cached}</v>`;
6984
+ } else if (cached !== void 0) if (typeof cached === "number") vEl = `<v>${serializeNumber(cached, ref)}</v>`;
6689
6985
  else if (typeof cached === "boolean") {
6690
6986
  valueAttr = " t=\"b\"";
6691
6987
  vEl = `<v>${cached ? "1" : "0"}</v>`;
6692
6988
  } else {
6693
6989
  valueAttr = " t=\"str\"";
6694
- const text = escapeXmlText(escapeCellString(cached));
6990
+ const text = escapeXmlTextVerbatim(cached, "worksheet: cached formula result", ref);
6695
6991
  vEl = text.length > 0 ? `<v>${text}</v>` : "<v/>";
6696
6992
  }
6697
6993
  return `<c r="${ref}"${styleAttr}${valueAttr}>${fEl}${vEl}</c>`;
@@ -6827,7 +7123,11 @@ const serializeCfRule = (rule) => {
6827
7123
  if (rule.stdDev !== void 0) attrs += ` stdDev="${rule.stdDev}"`;
6828
7124
  if (rule.timePeriod !== void 0) attrs += ` timePeriod="${rule.timePeriod}"`;
6829
7125
  const inner = [];
6830
- for (const f of rule.formulas) inner.push(`<formula>${escapeXmlText(normalizeFormulaText(f))}</formula>`);
7126
+ for (const f of rule.formulas) {
7127
+ const at = `priority ${rule.priority}`;
7128
+ const text = escapeXmlTextVerbatim(normalizeFormulaText(f), "worksheet: conditional-formatting formula", at);
7129
+ inner.push(`<formula>${text}</formula>`);
7130
+ }
6831
7131
  if (rule.innerXml) inner.push(rule.innerXml);
6832
7132
  if (inner.length === 0) return `<cfRule${attrs}/>`;
6833
7133
  return `<cfRule${attrs}>${inner.join("")}</cfRule>`;
@@ -6850,10 +7150,17 @@ const serializeDataValidation = (dv) => {
6850
7150
  if (dv.error !== void 0) attrs += ` error="${escapeXmlAttr(dv.error)}"`;
6851
7151
  if (dv.promptTitle !== void 0) attrs += ` promptTitle="${escapeXmlAttr(dv.promptTitle)}"`;
6852
7152
  if (dv.prompt !== void 0) attrs += ` prompt="${escapeXmlAttr(dv.prompt)}"`;
6853
- attrs += ` sqref="${escapeXmlAttr(multiCellRangeToString(dv.sqref))}"`;
7153
+ const sqref = multiCellRangeToString(dv.sqref);
7154
+ attrs += ` sqref="${escapeXmlAttr(sqref)}"`;
6854
7155
  const formulas = [];
6855
- if (dv.formula1 !== void 0) formulas.push(`<formula1>${escapeXmlText(normalizeFormulaText(dv.formula1))}</formula1>`);
6856
- if (dv.formula2 !== void 0) formulas.push(`<formula2>${escapeXmlText(normalizeFormulaText(dv.formula2))}</formula2>`);
7156
+ if (dv.formula1 !== void 0) {
7157
+ const text = escapeXmlTextVerbatim(normalizeFormulaText(dv.formula1), "worksheet: data-validation formula1", sqref);
7158
+ formulas.push(`<formula1>${text}</formula1>`);
7159
+ }
7160
+ if (dv.formula2 !== void 0) {
7161
+ const text = escapeXmlTextVerbatim(normalizeFormulaText(dv.formula2), "worksheet: data-validation formula2", sqref);
7162
+ formulas.push(`<formula2>${text}</formula2>`);
7163
+ }
6857
7164
  if (formulas.length === 0) return `<dataValidation${attrs}/>`;
6858
7165
  return `<dataValidation${attrs}>${formulas.join("")}</dataValidation>`;
6859
7166
  };
@@ -8736,6 +9043,6 @@ const cellXfToTree = (xf) => {
8736
9043
  return node;
8737
9044
  };
8738
9045
  //#endregion
8739
- export { chartExToBytes as C, findUserShapesRId as D, chartToBytes as E, parseChartXml as O, userShapesToBytes as S, parseChartExXml as T, parseChartsheetXml as _, parseCommentsXml as a, parseWorksheetXml as b, NumberFormatSchema as c, BorderSchema as d, AlignmentSchema as f, chartsheetToBytes as g, parseDrawingXml as h, commentsToBytes as i, FontSchema as l, drawingToBytes as m, parseTableXml as n, placeholderVmlDrawing as o, collectRawRelIds as p, tableToBytes as r, ProtectionSchema as s, stylesheetToBytes as t, fillFromTree as u, serializeCell as v, isChartExBytes as w, parseUserShapesXml as x, writeWorksheetXml as y };
9046
+ export { userShapesToBytes as C, chartToBytes as D, parseChartExXml as E, findUserShapesRId as O, parseUserShapesXml as S, isChartExBytes as T, parseChartsheetXml as _, parseCommentsXml as a, parseWorksheetXml as b, NumberFormatSchema as c, BorderSchema as d, AlignmentSchema as f, chartsheetToBytes as g, parseDrawingXml as h, commentsToBytes as i, parseChartXml as k, FontSchema as l, drawingToBytes as m, parseTableXml as n, placeholderVmlDrawing as o, collectRawRelIds as p, tableToBytes as r, ProtectionSchema as s, stylesheetToBytes as t, fillFromTree as u, serializeCell as v, chartExToBytes as w, parseCellNumber as x, writeWorksheetXml as y };
8740
9047
 
8741
- //# sourceMappingURL=stylesheet-writer-oXSuGnJy.mjs.map
9048
+ //# sourceMappingURL=stylesheet-writer-BEn-0P0x.mjs.map