@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
package/README.md CHANGED
@@ -80,6 +80,10 @@ Honest list:
80
80
  projects.
81
81
  - **`.xlsx` only**: no `.xls` (BIFF), `.xlsb`, `.ods`, or `.csv`. Use
82
82
  SheetJS for those.
83
+ - **Transitional OOXML only**: a file saved through Excel's "Strict Open XML
84
+ Spreadsheet" entry is ISO 29500 **strict**, and reading it is not
85
+ implemented. `loadWorkbook` and `loadWorkbookStream` name the format and tell
86
+ you to re-save it as "Excel Workbook (.xlsx)" instead of mis-reading it.
83
87
  - **Node 22+ required**: relies on built-in `Web Streams`, `Blob`, and
84
88
  `fetch`. Node 18 / 20 (EOL) are not supported.
85
89
  - **Browser stress-test history is shorter** than ExcelJS's. If you ship
@@ -169,18 +173,61 @@ see the [Recipes](https://baseballyama.github.io/@office-kit/xlsx/docs/recipes).
169
173
 
170
174
  ```ts
171
175
  import { loadWorkbook, workbookToBytes } from '@office-kit/xlsx/io';
176
+ import { getSheetByIndex } from '@office-kit/xlsx/workbook';
172
177
  import { setCell } from '@office-kit/xlsx/worksheet';
173
178
  import { fromBuffer } from '@office-kit/xlsx/node';
174
179
  import { readFile, writeFile } from 'node:fs/promises';
175
180
 
176
181
  const wb = await loadWorkbook(fromBuffer(await readFile('input.xlsx')));
177
- const sheet = wb.sheets[0];
178
- if (sheet?.kind === 'worksheet') {
179
- setCell(sheet.sheet, /* row */ 1, /* col */ 1, 'Hello from @office-kit/xlsx');
182
+ const sheet = getSheetByIndex(wb, 0);
183
+ if (sheet) {
184
+ setCell(sheet, /* row */ 1, /* col */ 1, 'Hello from @office-kit/xlsx');
180
185
  }
181
186
  await writeFile('output.xlsx', await workbookToBytes(wb));
182
187
  ```
183
188
 
189
+ `getSheetByIndex` returns `undefined` for an out-of-range index and for a tab
190
+ holding a chartsheet rather than a worksheet, so the one check above covers
191
+ both. Look sheets up by name with `getSheet(wb, 'Sheet1')`.
192
+
193
+ ### Two answers to "where does the data end"
194
+
195
+ A sheet often carries formatting past its content: someone formats 200 rows and
196
+ types into 4. Excel keeps the two readings of that sheet apart, and so does
197
+ this library.
198
+
199
+ `getCellExtent` counts every cell the file materialises, including one that
200
+ exists only to carry a style. That is Excel's used range and the `<dimension>`
201
+ element Excel writes, and its max corner is what bounds `iterRows` /
202
+ `iterValues` by default. `getValueExtent` counts only the cells holding a
203
+ value, which is what a caller mapping rows to records means by "the data".
204
+ Spread its box into the iteration to be bounded by it:
205
+
206
+ ```ts
207
+ import { getCellExtent, getValueExtent, iterValues } from '@office-kit/xlsx/worksheet';
208
+
209
+ getCellExtent(ws)?.maxRow; // 200, the used range
210
+ getValueExtent(ws)?.maxRow; // 4
211
+
212
+ const box = getValueExtent(ws);
213
+ if (box) {
214
+ for (const row of iterValues(ws, box)) {
215
+ // four rows, not 200, starting at the first row that holds a value
216
+ }
217
+ }
218
+ ```
219
+
220
+ A cell counts towards the value extent when its `value` is neither `null` nor
221
+ `''`, so formatting, a hyperlink, a comment and the empty strings a CSV
222
+ converter leaves behind all stay outside the box. `getValueExtent` is
223
+ `undefined` for a sheet with no values at all, which is the `if` above.
224
+
225
+ Iteration pads the same way under either box: every yielded row has the full
226
+ width, position `i` is column `minCol + i` throughout, and a position with no
227
+ cell is `null`. Blank rows inside the box are still yielded, so drop them with
228
+ `filter((row) => row.some((v) => v !== null))` when only rows carrying
229
+ something are wanted.
230
+
184
231
  ### Read directly from disk (Node)
185
232
 
186
233
  ```ts
@@ -283,7 +330,20 @@ front**. A 200 MB compressed xlsx therefore needs ~200 MB resident, plus the
283
330
  inflate window + SAX state per active iterator — not the multi-GB inflated
284
331
  worksheet payload. Band queries (`minRow > 1`) build a row-offset index once
285
332
  per sheet, which does materialise that sheet's inflated bytes; subsequent
286
- band queries reuse the cached index.
333
+ band queries reuse the cached index. A sheet whose `<row>` elements omit their
334
+ optional `r` attribute cannot be indexed by row number, so its band queries
335
+ keep streaming the sheet and retain nothing.
336
+
337
+ The two readers differ on damaged input, deliberately. Handed a cell it cannot
338
+ interpret (`<c t="b"><v>yes</v></c>`, an unknown error code, a shared-string
339
+ index past the end of the table) `loadWorkbook` throws an `OpenXmlSchemaError`,
340
+ on the grounds that a wrong value is worse than a failed load.
341
+ `loadWorkbookStream` reads that cell as empty and keeps going, because an
342
+ iterator that throws on row 900,000 leaves you no way to finish the pass.
343
+ Structural problems (a missing part, no `officeDocument` relationship, an
344
+ unknown sheet name) throw in both, and so does XML inside `<sheetData>` that is
345
+ not well-formed: an unclosed `<row>`, a stray `</c>`, an undefined entity
346
+ reference. Outside `<sheetData>` the same input is still read leniently.
287
347
 
288
348
  ### Migrating from openpyxl
289
349
 
@@ -308,6 +368,25 @@ common surprise for direct ports:
308
368
  etc. — every style primitive has a `make*` constructor under
309
369
  `@office-kit/xlsx/styles`.
310
370
 
371
+ ### Migrating from SheetJS
372
+
373
+ SheetJS covers a dozen formats through one loosely typed worksheet object;
374
+ @office-kit/xlsx covers `.xlsx` / `.xlsm` through a typed model. The two
375
+ differences a port hits first:
376
+
377
+ - **There is no `cell.w`.** SheetJS caches a formatted string on the cell.
378
+ Here the text is computed on demand: `getCellDisplayText(wb, cell)` from
379
+ `@office-kit/xlsx/styles` puts the value through the cell's number format,
380
+ so `0.5` under `0.0%` reads `50.0%`. `cellValueAsString` answers the other
381
+ question, what the value is in JavaScript terms, and never sees the format.
382
+ - **There is no `cellDates` load option.** A date cell holds the serial the
383
+ file stores, and `getCellDate(wb, cell)` reads it under the cell's format
384
+ and the workbook epoch. Keeping it out of the loader keeps the value model
385
+ from depending on how the file was opened.
386
+
387
+ See [migrating from SheetJS](docs/migrate-from-sheetjs.md) for the full API
388
+ map, including the formats that stay out of scope.
389
+
311
390
  ## What's supported
312
391
 
313
392
  - ✅ Cell values: number, string (sharedStrings), boolean, error, formulas
@@ -328,6 +407,12 @@ common surprise for direct ports:
328
407
  extras and per-sheet rels chain are preserved end-to-end.
329
408
  - ✅ Encrypted xlsx detection (CFB Compound Document magic): clear error
330
409
  pointing at `msoffcrypto-tool` for decryption.
410
+ - ✅ ISO 29500 strict detection: a file saved from Excel as "Strict Open XML
411
+ Spreadsheet" carries the `.xlsx` extension but a different namespace family,
412
+ so `loadWorkbook` and `loadWorkbookStream` throw an
413
+ `OpenXmlNotImplementedError` naming the format and saying to re-save it as
414
+ "Excel Workbook (.xlsx)". Converter output that mixes the two families is
415
+ caught per part. Reading strict packages is not implemented.
331
416
  - ✅ ZIP64 write — partial: workbooks with > 65 535 entries get a ZIP64 EOCD
332
417
  record + locator spliced into the final chunk. Read works too. **Limit:**
333
418
  individual entry sizes and the central-directory offset must still fit in
@@ -9,6 +9,8 @@ export interface FormulaValue {
9
9
  readonly t: FormulaKind;
10
10
  /** Cached value Excel last computed for the cell, used when `data_only` reads it back. */
11
11
  readonly cachedValue?: number | string | boolean;
12
+ /** Mark an Excel error token as an error result. Without this, strings stay text, including "#N/A". */
13
+ readonly cachedValueType?: 'error';
12
14
  /** Range string (`"A1:A10"`) for array / shared / dataTable formulas. */
13
15
  readonly ref?: string;
14
16
  /** Shared-formula index. */
@@ -82,43 +84,33 @@ export declare function bindValue(c: Cell, value: number | string | boolean | Da
82
84
  * A cached value is optional. Without one, Excel, LibreOffice and Google
83
85
  * Sheets compute the result on open, but viewers that never calculate (Quick
84
86
  * Look, Outlook and SharePoint previews, most thumbnailers) render the cell
85
- * empty. Supply one whenever the producer can compute it.
87
+ * empty. Supply one whenever the producer can compute it. For an Excel error,
88
+ * supply `{ cachedValue: '#N/A', cachedValueType: 'error' }`; without the type,
89
+ * the same token is a string result.
86
90
  */
87
- export declare function makeFormula(formula: string, opts?: {
88
- cachedValue?: FormulaValue['cachedValue'];
89
- }): FormulaValue;
91
+ export declare function makeFormula(formula: string, opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>): FormulaValue;
90
92
  /**
91
93
  * Build an array (CSE) formula value spanning `ref`. Belongs on the top-left
92
94
  * cell of the range, since Excel reads `ref` to know how far the result
93
95
  * spreads.
94
96
  */
95
- export declare function makeArrayFormula(ref: string, formula: string, opts?: {
96
- cachedValue?: FormulaValue['cachedValue'];
97
- }): FormulaValue;
97
+ export declare function makeArrayFormula(ref: string, formula: string, opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>): FormulaValue;
98
98
  /**
99
99
  * Build a shared-formula value. The first cell in the group carries the
100
100
  * formula text + `ref`; subsequent cells with the same `si` carry only the
101
101
  * index, and Excel reconstructs their text by shifting the references, so
102
102
  * their `formula` is legitimately empty.
103
103
  */
104
- export declare function makeSharedFormula(si: number, formula?: string, ref?: string, opts?: {
105
- cachedValue?: FormulaValue['cachedValue'];
106
- }): FormulaValue;
104
+ export declare function makeSharedFormula(si: number, formula?: string, ref?: string, opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>): FormulaValue;
107
105
  /**
108
106
  * Plain `A1+B1` style formula, applied in place. Same value as
109
107
  * {@link makeFormula}, for a cell you already hold.
110
108
  */
111
- export declare function setFormula(c: Cell, formula: string, opts?: {
112
- cachedValue?: FormulaValue['cachedValue'];
113
- }): void;
109
+ export declare function setFormula(c: Cell, formula: string, opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>): void;
114
110
  /** Array (CSE) formula spanning a `ref` range, applied in place. */
115
- export declare function setArrayFormula(c: Cell, ref: string, formula: string, opts?: {
116
- cachedValue?: FormulaValue['cachedValue'];
117
- }): void;
111
+ export declare function setArrayFormula(c: Cell, ref: string, formula: string, opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>): void;
118
112
  /** Shared formula, applied in place. See {@link makeSharedFormula}. */
119
- export declare function setSharedFormula(c: Cell, si: number, formula?: string, ref?: string, opts?: {
120
- cachedValue?: FormulaValue['cachedValue'];
121
- }): void;
113
+ export declare function setSharedFormula(c: Cell, si: number, formula?: string, ref?: string, opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>): void;
122
114
  /**
123
115
  * Excel data-table formula (`<f t="dataTable">`). These appear as the "What-if
124
116
  * Analysis → Data Table" feature output: a 1- or 2-variable sensitivity grid
@@ -145,6 +137,7 @@ export interface DataTableFormulaOpts {
145
137
  aca?: boolean;
146
138
  ca?: boolean;
147
139
  cachedValue?: FormulaValue['cachedValue'];
140
+ cachedValueType?: FormulaValue['cachedValueType'];
148
141
  }
149
142
  /**
150
143
  * Build a data-table formula value. Preserves all the dt-specific attributes
@@ -1,5 +1,5 @@
1
1
  import { o as OpenXmlSchemaError } from "./exceptions-D-CFwxgm.mjs";
2
- import { a as columnLetterFromIndex, n as MAX_ROW, t as MAX_COL } from "./coordinate-Bt5Gni2I.mjs";
2
+ import { a as columnLetterFromIndex, n as MAX_ROW, t as MAX_COL } from "./coordinate-CxC88uBk.mjs";
3
3
  import { i as startsWithEquals, r as normalizeFormulaText, t as ERROR_CODES } from "./inference-BMvv9cUY.mjs";
4
4
  //#region src/cell/rich-text.ts
5
5
  function makeTextRun(text, font) {
@@ -93,14 +93,17 @@ const requireFormulaText = (fn, formula) => {
93
93
  * A cached value is optional. Without one, Excel, LibreOffice and Google
94
94
  * Sheets compute the result on open, but viewers that never calculate (Quick
95
95
  * Look, Outlook and SharePoint previews, most thumbnailers) render the cell
96
- * empty. Supply one whenever the producer can compute it.
96
+ * empty. Supply one whenever the producer can compute it. For an Excel error,
97
+ * supply `{ cachedValue: '#N/A', cachedValueType: 'error' }`; without the type,
98
+ * the same token is a string result.
97
99
  */
98
100
  function makeFormula(formula, opts) {
99
101
  return Object.freeze({
100
102
  kind: "formula",
101
103
  t: "normal",
102
104
  formula: requireFormulaText("makeFormula", formula),
103
- ...opts?.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {}
105
+ ...opts?.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {},
106
+ ...opts?.cachedValueType !== void 0 ? { cachedValueType: opts.cachedValueType } : {}
104
107
  });
105
108
  }
106
109
  /**
@@ -114,7 +117,8 @@ function makeArrayFormula(ref, formula, opts) {
114
117
  t: "array",
115
118
  formula: requireFormulaText("makeArrayFormula", formula),
116
119
  ref,
117
- ...opts?.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {}
120
+ ...opts?.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {},
121
+ ...opts?.cachedValueType !== void 0 ? { cachedValueType: opts.cachedValueType } : {}
118
122
  });
119
123
  }
120
124
  /**
@@ -131,7 +135,8 @@ function makeSharedFormula(si, formula, ref, opts) {
131
135
  formula: formula === void 0 ? "" : normalizeFormulaText(formula),
132
136
  si,
133
137
  ...ref !== void 0 ? { ref } : {},
134
- ...opts?.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {}
138
+ ...opts?.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {},
139
+ ...opts?.cachedValueType !== void 0 ? { cachedValueType: opts.cachedValueType } : {}
135
140
  });
136
141
  }
137
142
  /**
@@ -169,7 +174,8 @@ function makeDataTableFormula(formula, opts) {
169
174
  ...opts.del2 !== void 0 ? { del2: opts.del2 } : {},
170
175
  ...opts.aca !== void 0 ? { aca: opts.aca } : {},
171
176
  ...opts.ca !== void 0 ? { ca: opts.ca } : {},
172
- ...opts.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {}
177
+ ...opts.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {},
178
+ ...opts.cachedValueType !== void 0 ? { cachedValueType: opts.cachedValueType } : {}
173
179
  });
174
180
  }
175
181
  /** Data-table formula, applied in place. See {@link makeDataTableFormula}. */
@@ -359,4 +365,4 @@ function cellValueAsPrimitive(v) {
359
365
  //#endregion
360
366
  export { setSharedFormula as A, makeErrorValue as C, setCellValue as D, setArrayFormula as E, makeTextRun as M, richTextToString as N, setDataTableFormula as O, makeDurationValue as S, makeSharedFormula as T, isRichTextCell as _, cellValueAsPrimitive as a, makeCell as b, getCoordinate as c, isEmptyCell as d, isErrorCell as f, isMergedCell as g, isFormulaValue as h, cellValueAsNumber as i, makeRichText as j, setFormula as k, getFormulaText as l, isFormulaCell as m, cellValueAsBoolean as n, cellValueAsString as o, isErrorValue as p, cellValueAsDate as r, getCachedFormulaValue as s, bindValue as t, isDurationValue as u, isRichTextValue as v, makeFormula as w, makeDataTableFormula as x, makeArrayFormula as y };
361
367
 
362
- //# sourceMappingURL=cell-Df3cKRIl.mjs.map
368
+ //# sourceMappingURL=cell-B5OUUdfI.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell-B5OUUdfI.mjs","names":[],"sources":["../src/cell/rich-text.ts","../src/cell/cell.ts"],"sourcesContent":["// Inline rich-text runs.\n//\n// A rich-text cell value is `{ kind: 'rich-text', runs }`. Each run is\n// a string segment with an optional InlineFont describing the in-line\n// formatting (font name, size, bold / italic / underline, colour, …).\n// Run-level fields use OOXML's short attribute names (`sz`, `b`, `i`,\n// `u`) so the writer can splice them into `<rPr>` directly without\n// renaming.\n\nimport type { Color } from '../styles/colors.js';\nimport { OpenXmlSchemaError } from '../utils/exceptions.js';\n\n/** Underline styles per openpyxl's cell-level NestedNoneSet. */\nexport type InlineUnderline = 'single' | 'double' | 'singleAccounting' | 'doubleAccounting';\n\nexport type InlineVertAlign = 'baseline' | 'superscript' | 'subscript';\n\nexport interface InlineFont {\n readonly name?: string;\n readonly sz?: number;\n readonly b?: boolean;\n readonly i?: boolean;\n readonly u?: InlineUnderline;\n readonly strike?: boolean;\n readonly outline?: boolean;\n readonly shadow?: boolean;\n readonly condense?: boolean;\n readonly extend?: boolean;\n readonly vertAlign?: InlineVertAlign;\n readonly color?: Color;\n readonly family?: number;\n readonly charset?: number;\n readonly scheme?: 'major' | 'minor';\n}\n\nexport interface TextRun {\n readonly text: string;\n readonly font?: InlineFont;\n}\n\n/** A frozen array of TextRuns. The shared cell value shape under `kind: 'rich-text'`. */\nexport type RichText = ReadonlyArray<TextRun>;\n\nexport function makeTextRun(text: string, font?: InlineFont): TextRun {\n if (typeof text !== 'string') {\n throw new OpenXmlSchemaError('makeTextRun: text must be a string');\n }\n return Object.freeze(font !== undefined ? { text, font } : { text });\n}\n\nexport function makeRichText(runs: ReadonlyArray<TextRun | { text: string; font?: InlineFont }>): RichText {\n const out = runs.map((r) => (Object.isFrozen(r) ? (r as TextRun) : makeTextRun(r.text, r.font)));\n return Object.freeze(out);\n}\n\n/**\n * Concatenate the plain-text content of a rich-text value (rich-text\n * read paths often want the raw text without formatting).\n */\nexport function richTextToString(rt: RichText): string {\n let out = '';\n for (const r of rt) out += r.text;\n return out;\n}\n","// Cell value model. Mirrors openpyxl/openpyxl/cell/cell.py.\n//\n// A Cell is a plain mutable object: the worksheet stores millions of these, so\n// per-cell freezes / spreads aren't viable on the hot path. The public surface\n// stays small — makeCell + getCoordinate + targeted setters — and uses\n// discriminated unions for the special CellValue shapes (formula, rich text,\n// duration, error).\n\nimport { columnLetterFromIndex, MAX_COL, MAX_ROW } from '../utils/coordinate.js';\nimport { OpenXmlSchemaError } from '../utils/exceptions.js';\nimport { normalizeFormulaText, startsWithEquals } from '../utils/formula-text.js';\nimport { ERROR_CODES } from '../utils/inference.js';\nimport { type RichText, richTextToString } from './rich-text.js';\n\n/** Excel error tokens. */\nexport type ExcelErrorCode = '#NULL!' | '#DIV/0!' | '#VALUE!' | '#REF!' | '#NAME?' | '#NUM!' | '#N/A' | '#GETTING_DATA';\n\n/** Formula sub-kind — drives the OOXML `<f t=\"…\">` attribute. */\nexport type FormulaKind = 'normal' | 'array' | 'shared' | 'dataTable';\n\nexport interface FormulaValue {\n readonly kind: 'formula';\n readonly formula: string;\n readonly t: FormulaKind;\n /** Cached value Excel last computed for the cell, used when `data_only` reads it back. */\n readonly cachedValue?: number | string | boolean;\n /** Mark an Excel error token as an error result. Without this, strings stay text, including \"#N/A\". */\n readonly cachedValueType?: 'error';\n /** Range string (`\"A1:A10\"`) for array / shared / dataTable formulas. */\n readonly ref?: string;\n /** Shared-formula index. */\n readonly si?: number;\n /** Data-table specific fields (mirrors openpyxl DataTableFormula). */\n readonly r1?: string;\n readonly r2?: string;\n readonly dt2D?: boolean;\n readonly dtr?: boolean;\n readonly del1?: boolean;\n readonly del2?: boolean;\n readonly aca?: boolean;\n readonly ca?: boolean;\n}\n\nexport type CellValue =\n | number\n | string\n | boolean\n | Date\n | { kind: 'duration'; ms: number }\n | { kind: 'error'; code: ExcelErrorCode }\n | { kind: 'rich-text'; runs: RichText }\n | FormulaValue\n | null;\n\nexport interface Cell {\n /** 1-based row index. */\n row: number;\n /** 1-based column index. */\n col: number;\n /** Effective cell value. `null` represents an empty cell. */\n value: CellValue;\n /** Index into Workbook.styles.cellXfs. 0 = default. */\n styleId: number;\n /** Optional reference to a Hyperlink registered on the worksheet. */\n hyperlinkId?: number;\n /** Optional reference to a Comment registered on the worksheet. */\n commentId?: number;\n}\n\n/** Marker subtype for the placeholder cells inside a merged range (top-left holds the value). */\nexport interface MergedCell extends Cell {\n merged: true;\n}\n\nconst validateCoord = (row: number, col: number): void => {\n if (!Number.isInteger(row) || row < 1 || row > MAX_ROW) {\n throw new OpenXmlSchemaError(`Cell row ${row} out of range [1, ${MAX_ROW}]`);\n }\n if (!Number.isInteger(col) || col < 1 || col > MAX_COL) {\n throw new OpenXmlSchemaError(`Cell col ${col} out of range [1, ${MAX_COL}]`);\n }\n};\n\n/** Build a fresh Cell. Validates coordinates against the OOXML grid bounds. */\nexport function makeCell(row: number, col: number, value: CellValue = null, styleId = 0): Cell {\n validateCoord(row, col);\n return { row, col, value, styleId };\n}\n\n/** Format a Cell's coordinate as the canonical \"A1\" string. */\nexport function getCoordinate(c: Cell): string {\n return `${columnLetterFromIndex(c.col)}${c.row}`;\n}\n\n/**\n * Direct value setter. No type inference, no validation beyond the union — the\n * caller is in charge. Use {@link bindValue} for the \"do what I mean\" path.\n */\nexport function setCellValue(c: Cell, value: CellValue): void {\n c.value = value;\n}\n\n/**\n * \"Smart\" setter: infers the cell value from a JS runtime value.\n * - `string` starting with `=` → formula\n * - `string` matching an Excel error token → error variant\n * - other primitives / Date / null pass through verbatim\n *\n * Intentionally not the default — explicit is clearer for typed code, and\n * inferring on every write costs measurable time on the worksheet write hot\n * path.\n */\nexport function bindValue(c: Cell, value: number | string | boolean | Date | null): void {\n if (typeof value === 'string') {\n if (startsWithEquals(value)) {\n setFormula(c, value);\n return;\n }\n if (ERROR_CODES.has(value)) {\n c.value = { kind: 'error', code: value as ExcelErrorCode };\n return;\n }\n c.value = value;\n return;\n }\n c.value = value;\n}\n\n// ---- formula values --------------------------------------------------------\n\n// A `<f>` with no text is the shape Excel reports as damaged, and `'='` on its\n// own normalises to exactly that, so the kinds whose text is required reject it\n// here rather than at save time.\nconst requireFormulaText = (fn: string, formula: string): string => {\n const text = normalizeFormulaText(formula);\n if (text.length === 0) {\n throw new OpenXmlSchemaError(`${fn}: formula text must not be empty (got ${JSON.stringify(formula)})`);\n }\n return text;\n};\n\n/**\n * Build a formula cell value. Hand it to `setCell` when the write already\n * carries a style id, so placing a formatted formula stays a single call;\n * {@link setFormula} is the same thing applied to a cell you already hold.\n *\n * A leading `=` is stripped, so `'=SUM(A1:A3)'` and `'SUM(A1:A3)'` are\n * interchangeable.\n *\n * A cached value is optional. Without one, Excel, LibreOffice and Google\n * Sheets compute the result on open, but viewers that never calculate (Quick\n * Look, Outlook and SharePoint previews, most thumbnailers) render the cell\n * empty. Supply one whenever the producer can compute it. For an Excel error,\n * supply `{ cachedValue: '#N/A', cachedValueType: 'error' }`; without the type,\n * the same token is a string result.\n */\nexport function makeFormula(\n formula: string,\n opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>,\n): FormulaValue {\n return Object.freeze({\n kind: 'formula',\n t: 'normal',\n formula: requireFormulaText('makeFormula', formula),\n ...(opts?.cachedValue !== undefined ? { cachedValue: opts.cachedValue } : {}),\n ...(opts?.cachedValueType !== undefined ? { cachedValueType: opts.cachedValueType } : {}),\n });\n}\n\n/**\n * Build an array (CSE) formula value spanning `ref`. Belongs on the top-left\n * cell of the range, since Excel reads `ref` to know how far the result\n * spreads.\n */\nexport function makeArrayFormula(\n ref: string,\n formula: string,\n opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>,\n): FormulaValue {\n return Object.freeze({\n kind: 'formula',\n t: 'array',\n formula: requireFormulaText('makeArrayFormula', formula),\n ref,\n ...(opts?.cachedValue !== undefined ? { cachedValue: opts.cachedValue } : {}),\n ...(opts?.cachedValueType !== undefined ? { cachedValueType: opts.cachedValueType } : {}),\n });\n}\n\n/**\n * Build a shared-formula value. The first cell in the group carries the\n * formula text + `ref`; subsequent cells with the same `si` carry only the\n * index, and Excel reconstructs their text by shifting the references, so\n * their `formula` is legitimately empty.\n */\nexport function makeSharedFormula(\n si: number,\n formula?: string,\n ref?: string,\n opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>,\n): FormulaValue {\n if (!Number.isInteger(si) || si < 0) {\n throw new OpenXmlSchemaError(`makeSharedFormula: si must be a non-negative integer; got ${si}`);\n }\n return Object.freeze({\n kind: 'formula',\n t: 'shared',\n formula: formula === undefined ? '' : normalizeFormulaText(formula),\n si,\n ...(ref !== undefined ? { ref } : {}),\n ...(opts?.cachedValue !== undefined ? { cachedValue: opts.cachedValue } : {}),\n ...(opts?.cachedValueType !== undefined ? { cachedValueType: opts.cachedValueType } : {}),\n });\n}\n\n/**\n * Plain `A1+B1` style formula, applied in place. Same value as\n * {@link makeFormula}, for a cell you already hold.\n */\nexport function setFormula(c: Cell, formula: string, opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>): void {\n c.value = makeFormula(formula, opts);\n}\n\n/** Array (CSE) formula spanning a `ref` range, applied in place. */\nexport function setArrayFormula(\n c: Cell,\n ref: string,\n formula: string,\n opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>,\n): void {\n c.value = makeArrayFormula(ref, formula, opts);\n}\n\n/** Shared formula, applied in place. See {@link makeSharedFormula}. */\nexport function setSharedFormula(\n c: Cell,\n si: number,\n formula?: string,\n ref?: string,\n opts?: Pick<FormulaValue, 'cachedValue' | 'cachedValueType'>,\n): void {\n c.value = makeSharedFormula(si, formula, ref, opts);\n}\n\n/**\n * Excel data-table formula (`<f t=\"dataTable\">`). These appear as the \"What-if\n * Analysis → Data Table\" feature output: a 1- or 2-variable sensitivity grid\n * where the formula references one or two input cells. The wire format mirrors\n * openpyxl's `DataTableFormula`:\n *\n * - `ref` — inclusive cell range the formula spans.\n * - `r1`, `r2`— input cell coordinates (\"$A$1\" etc.).\n * - `dt2D` — true for two-variable tables (uses both r1 and r2).\n * - `dtr` — row-direction flag (true) vs column-direction (false).\n * - `del1`/`del2` — Excel marks one of these true when the\n * corresponding input cell has been deleted; the formula keeps round-tripping\n * so Excel can show the warning state.\n * - `aca`/`ca` — alwaysCalculate / calculate flags.\n */\nexport interface DataTableFormulaOpts {\n ref: string;\n r1?: string;\n r2?: string;\n dt2D?: boolean;\n dtr?: boolean;\n del1?: boolean;\n del2?: boolean;\n aca?: boolean;\n ca?: boolean;\n cachedValue?: FormulaValue['cachedValue'];\n cachedValueType?: FormulaValue['cachedValueType'];\n}\n\n/**\n * Build a data-table formula value. Preserves all the dt-specific attributes\n * so the writer can re-emit `<f t=\"dataTable\" r1=\"...\" />` verbatim and Excel\n * keeps treating the cell as a Data Table cell. Excel writes these with no\n * formula text at all, so `formula` may be empty.\n */\nexport function makeDataTableFormula(formula: string, opts: DataTableFormulaOpts): FormulaValue {\n return Object.freeze({\n kind: 'formula',\n t: 'dataTable',\n formula: normalizeFormulaText(formula),\n ref: opts.ref,\n ...(opts.r1 !== undefined ? { r1: opts.r1 } : {}),\n ...(opts.r2 !== undefined ? { r2: opts.r2 } : {}),\n ...(opts.dt2D !== undefined ? { dt2D: opts.dt2D } : {}),\n ...(opts.dtr !== undefined ? { dtr: opts.dtr } : {}),\n ...(opts.del1 !== undefined ? { del1: opts.del1 } : {}),\n ...(opts.del2 !== undefined ? { del2: opts.del2 } : {}),\n ...(opts.aca !== undefined ? { aca: opts.aca } : {}),\n ...(opts.ca !== undefined ? { ca: opts.ca } : {}),\n ...(opts.cachedValue !== undefined ? { cachedValue: opts.cachedValue } : {}),\n ...(opts.cachedValueType !== undefined ? { cachedValueType: opts.cachedValueType } : {}),\n });\n}\n\n/** Data-table formula, applied in place. See {@link makeDataTableFormula}. */\nexport function setDataTableFormula(c: Cell, formula: string, opts: DataTableFormulaOpts): void {\n c.value = makeDataTableFormula(formula, opts);\n}\n\n// ---- value-shape helpers ---------------------------------------------------\n\n/** Build a `{ kind: 'error', code }` cell value. */\nexport function makeErrorValue(code: ExcelErrorCode): { kind: 'error'; code: ExcelErrorCode } {\n if (!ERROR_CODES.has(code)) {\n throw new OpenXmlSchemaError(`makeErrorValue: unknown error code \"${code}\"`);\n }\n return Object.freeze({ kind: 'error', code });\n}\n\n/** Build a `{ kind: 'duration', ms }` cell value. */\nexport function makeDurationValue(ms: number): { kind: 'duration'; ms: number } {\n if (!Number.isFinite(ms)) {\n throw new OpenXmlSchemaError(`makeDurationValue: ms \"${ms}\" is not finite`);\n }\n return Object.freeze({ kind: 'duration', ms });\n}\n\n/** True iff `c.value` is the formula variant. */\nexport function isFormulaCell(c: Cell): boolean {\n return isFormulaValue(c.value);\n}\n\n/** True iff `c.value` is the rich-text variant. */\nexport function isRichTextCell(c: Cell): boolean {\n return isRichTextValue(c.value);\n}\n\n/** Returns true iff the cell has no content. */\nexport function isEmptyCell(c: Cell): boolean {\n return c.value === null;\n}\n\n/**\n * Type guard for `MergedCell` — true iff the cell is a placeholder for a\n * merged-range covered cell (the top-left of a merged range holds the value;\n * the rest are `MergedCell`). Use this to filter merge-placeholders out of\n * value-walking loops.\n */\nexport function isMergedCell(c: Cell): c is MergedCell {\n return (c as MergedCell).merged === true;\n}\n\n/** Returns true iff the cell holds an Excel error value (`#REF!`, `#NAME?`, …). */\nexport function isErrorCell(c: Cell): boolean {\n return isErrorValue(c.value);\n}\n\n/**\n * Get the formula text from a formula-bearing cell, or `undefined` for\n * non-formula cells. Equivalent to: isFormulaValue(c.value) ? c.value.formula :\n * undefined but spares callers the type-narrow + member access.\n */\nexport function getFormulaText(c: Cell): string | undefined {\n return isFormulaValue(c.value) ? c.value.formula : undefined;\n}\n\n/**\n * Get the cached value Excel last computed for a formula cell, or `undefined`\n * for non-formula / uncached cells. Useful for `data_only` read paths that want\n * the displayed result without re-evaluating.\n */\nexport function getCachedFormulaValue(c: Cell): number | string | boolean | undefined {\n return isFormulaValue(c.value) ? c.value.cachedValue : undefined;\n}\n\n// ---- value-level type guards + coercion ----------------------------------\n\n/** True iff `v` is the formula variant. */\nexport function isFormulaValue(v: CellValue): v is FormulaValue {\n return typeof v === 'object' && v !== null && (v as { kind?: string }).kind === 'formula';\n}\n\n/** True iff `v` is the rich-text variant. */\nexport function isRichTextValue(v: CellValue): v is { kind: 'rich-text'; runs: RichText } {\n return typeof v === 'object' && v !== null && (v as { kind?: string }).kind === 'rich-text';\n}\n\n/** True iff `v` is the error variant. */\nexport function isErrorValue(v: CellValue): v is { kind: 'error'; code: ExcelErrorCode } {\n return typeof v === 'object' && v !== null && (v as { kind?: string }).kind === 'error';\n}\n\n/** True iff `v` is the duration variant. */\nexport function isDurationValue(v: CellValue): v is { kind: 'duration'; ms: number } {\n return typeof v === 'object' && v !== null && (v as { kind?: string }).kind === 'duration';\n}\n\nexport interface CellValueAsStringOptions {\n /** Renderer for `Date` cells. Defaults to `d => d.toISOString()`. */\n dateFormat?: (value: Date) => string;\n /** Replacement for the `null` cell value. Defaults to `''`. */\n emptyText?: string;\n}\n\n/**\n * Coerce a CellValue to its plain-string display form. Numbers / booleans\n * convert via `String`; rich text concatenates run text; formulas yield the\n * cached value (or empty string when uncached); errors yield their Excel token;\n * durations yield `\"<ms> ms\"` with no formatting; Dates yield\n * `Date.toISOString()`; `null` yields `\"\"`.\n *\n * Pass `opts.dateFormat` to override the Date renderer (e.g. a locale-specific\n * format) and `opts.emptyText` to substitute a different placeholder for\n * `null` cells.\n */\nexport function cellValueAsString(v: CellValue, opts?: CellValueAsStringOptions): string {\n const emptyText = opts?.emptyText ?? '';\n if (v === null) return emptyText;\n if (typeof v === 'string') return v;\n if (typeof v === 'number' || typeof v === 'boolean') return String(v);\n if (v instanceof Date) return opts?.dateFormat ? opts.dateFormat(v) : v.toISOString();\n if (isRichTextValue(v)) return richTextToString(v.runs);\n if (isFormulaValue(v)) {\n if (v.cachedValue === undefined) return '';\n return typeof v.cachedValue === 'string' ? v.cachedValue : String(v.cachedValue);\n }\n if (isErrorValue(v)) return v.code;\n if (isDurationValue(v)) return `${v.ms} ms`;\n return '';\n}\n\n/**\n * Coerce a CellValue to `boolean | undefined`. Booleans pass through; `'TRUE'`\n * / `'true'` and `'FALSE'` / `'false'` (case-insensitive) parse to true /\n * false; numbers yield `false` for 0 and `true` for any other finite value\n * (matching Excel's truthy-number coercion); formula cells return their cached\n * boolean if any. Everything else (null, Date, error, duration, rich-text,\n * non-bool strings) yields `undefined`.\n */\nexport function cellValueAsBoolean(v: CellValue): boolean | undefined {\n if (typeof v === 'boolean') return v;\n if (typeof v === 'number') {\n if (!Number.isFinite(v)) return undefined;\n return v !== 0;\n }\n if (typeof v === 'string') {\n const lc = v.toLowerCase();\n if (lc === 'true') return true;\n if (lc === 'false') return false;\n return undefined;\n }\n if (isFormulaValue(v) && typeof v.cachedValue === 'boolean') return v.cachedValue;\n return undefined;\n}\n\n/**\n * Coerce a CellValue to a `Date` when one is meaningful. Pass-through for\n * `Date`-typed values; ISO-8601 strings (anything `new Date(s)` parses to a\n * finite time) round-trip; durations are interpreted as `new Date(ms)`.\n * Numbers, booleans, formulas, errors, rich text, and null all return\n * `undefined` — this helper does **not** apply the Excel-serial-to-Date\n * conversion (use `excelToDate` for that).\n */\nexport function cellValueAsDate(v: CellValue): Date | undefined {\n if (v instanceof Date) return v;\n if (typeof v === 'string') {\n if (v === '') return undefined;\n const t = Date.parse(v);\n if (!Number.isFinite(t)) return undefined;\n return new Date(t);\n }\n if (isDurationValue(v)) return new Date(v.ms);\n return undefined;\n}\n\n/**\n * Coerce a CellValue to a number when one is meaningful. Booleans yield 0/1;\n * numeric strings parse via `Number(s)`; rich-text concats then parses;\n * formulas with a numeric cached value pass through. Returns `undefined` when\n * there's no sensible numeric reading (text strings, errors, dates, durations,\n * null, empty).\n */\nexport function cellValueAsNumber(v: CellValue): number | undefined {\n if (v === null) return undefined;\n if (typeof v === 'number') return Number.isFinite(v) ? v : undefined;\n if (typeof v === 'boolean') return v ? 1 : 0;\n if (typeof v === 'string') {\n if (v === '') return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n }\n if (isFormulaValue(v) && typeof v.cachedValue === 'number') return v.cachedValue;\n return undefined;\n}\n\n/**\n * Map a CellValue to the most natural JS primitive for display / export.\n * Unlike `cellValueAsString`/`cellValueAsNumber`/etc., which each force a\n * single target type and return `undefined` when the value can't be coerced,\n * this returns whatever primitive best represents the union variant:\n *\n * - `null` → `null`\n * - `string` / `number` / `boolean` / `Date` → passthrough\n * - rich text → joined run text (`string`)\n * - formula → recursive on `cachedValue` (`null` when uncached)\n * - error → error code (`string`)\n * - duration → `ms` (`number`)\n */\nexport function cellValueAsPrimitive(v: CellValue): string | number | boolean | Date | null {\n if (v === null) return null;\n if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') return v;\n if (v instanceof Date) return v;\n if (isRichTextValue(v)) return richTextToString(v.runs);\n if (isFormulaValue(v)) {\n return v.cachedValue === undefined ? null : v.cachedValue;\n }\n if (isErrorValue(v)) return v.code;\n if (isDurationValue(v)) return v.ms;\n return null;\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { o as OpenXmlSchemaError } from "./exceptions-D-CFwxgm.mjs";
2
- import { Dn as makeColor, bn as colorToHex, un as parseRange, y as ensureCell } from "./worksheet-B2NOQ6dM.mjs";
2
+ import { Sn as colorToHex, fn as parseRange, kn as makeColor, y as ensureCell } from "./worksheet-DLMyDD7W.mjs";
3
3
  //#region src/utils/stable-stringify.ts
4
4
  const sortKeysReplacer = (_key, value) => {
5
5
  if (value === null || typeof value !== "object" || Array.isArray(value)) return value;
@@ -494,7 +494,14 @@ function builtinFormatId(code) {
494
494
  function isBuiltinFormat(code) {
495
495
  return REVERSE.has(code);
496
496
  }
497
- const STRIP_RE = new RegExp(`\\[(BLACK|BLUE|CYAN|GREEN|MAGENTA|RED|WHITE|YELLOW)\\]|"[^"]*"|\\[(?!hh?\\]|mm?\\]|ss?\\])[^\\]]*\\]`, "g");
497
+ /**
498
+ * The colour names Excel accepts in a bracket group (`[Red]`), as the regex
499
+ * alternation `STRIP_RE` needs them. The format-code parser needs the same
500
+ * names to tell a colour apart from a comparison or a calendar modifier, so
501
+ * they live here once.
502
+ */
503
+ const FORMAT_COLOR_NAMES = "BLACK|BLUE|CYAN|GREEN|MAGENTA|RED|WHITE|YELLOW";
504
+ const STRIP_RE = new RegExp(`${`\\[(${FORMAT_COLOR_NAMES})\\]`}|"[^"]*"|\\[(?!hh?\\]|mm?\\]|ss?\\])[^\\]]*\\]`, "g");
498
505
  const DATE_TOKEN_RE = /(?<![_\\])[dmhysDMHYS]/;
499
506
  const TIMEDELTA_RE = /\[hh?\](:mm(:ss(\.0*)?)?)?|\[mm?\](:ss(\.0*)?)?|\[ss?\](\.0*)?/i;
500
507
  /**
@@ -1613,6 +1620,6 @@ function setRangeBorderBox(wb, ws, range, opts = { style: "thin" }) {
1613
1620
  }
1614
1621
  }
1615
1622
  //#endregion
1616
- export { BUILTIN_NAMED_STYLES as $, makeAlignment as $t, setCellBorder as A, isBuiltinFormat as At, setItalic as B, PATTERN_TYPES as Bt, setBold as C, FORMAT_NUMBER_00 as Ct, setCellAsNumber as D, builtinFormatCode as Dt, setCellAsDate as E, FORMAT_TEXT as Et, setCellProtection as F, FONT_SCHEMES as Ft, setRangeNumberFormat as G, makePatternFill as Gt, setRangeBackgroundColor as H, makeFill as Ht, setCellStyle as I, UNDERLINE_STYLES as It, setRangeWrapText as J, makeBorder as Jt, setRangeProtection as K, SIDE_STYLES as Kt, setFontColor as L, VERT_ALIGNS as Lt, setCellFill as M, isTimedeltaFormat as Mt, setCellFont as N, makeNumberFormat as Nt, setCellAsPercent as O, builtinFormatId as Ot, setCellNumberFormat as P, DEFAULT_FONT as Pt, makeProtection as Q, alignmentToCss as Qt, setFontName as R, fontToCss as Rt, rotateCellText as S, FORMAT_NUMBER as St, setCellAsCurrency as T, FORMAT_PERCENTAGE_00 as Tt, setRangeBorderBox as U, makeGradientFill as Ut, setRangeAlignment as V, fillToCss as Vt, setRangeFont as W, makeGradientStop as Wt, setUnderline as X, HORIZONTAL_ALIGNMENTS as Xt, setStrikethrough as Y, makeSide as Yt, wrapCellText as Z, VERTICAL_ALIGNMENTS as Zt, getCellNumberFormat as _, BUILTIN_FORMATS_MAX_SIZE as _t, cellStyleToCss as a, addFill as at, patchCellFont as b, FORMAT_DATE_YYYYMMDD2 as bt, clearCellStyle as c, buildXfPatch as ct, copyCellStyle as d, listCellStyleXfs as dt, stableStringify as en, addNamedStyle as et, formatAsHeader as f, listCellXfs as ft, getCellFont as g, BUILTIN_FORMATS as gt, getCellFill as h, makeStylesheet as ht, applyNamedStyle as i, addCellXf as it, setCellBorderAll as j, isDateFormat as jt, setCellBackgroundColor as k, classifyDateFormat as kt, clearRangeStyle as l, defaultCellXf as lt, getCellBorder as m, listFonts as mt, alignCellVertical as n, addBorder as nt, centerCell as o, addFont as ot, getCellAlignment as p, listFills as pt, setRangeStyle as q, borderToCss as qt, applyBuiltinStyle as r, addCellStyleXf as rt, clearCellBackground as s, addNumFmt as st, alignCellHorizontal as t, ensureBuiltinStyle as tt, cloneCellStyle as u, listBorders as ut, getCellProtection as v, FORMAT_DATE_DATETIME as vt, setCellAlignment as w, FORMAT_PERCENTAGE as wt, registerCellStyle as x, FORMAT_GENERAL as xt, indentCell as y, FORMAT_DATE_TIMEDELTA as yt, setFontSize as z, makeFont as zt };
1623
+ export { BUILTIN_NAMED_STYLES as $, alignmentToCss as $t, setCellBorder as A, classifyDateFormat as At, setItalic as B, makeFont as Bt, setBold as C, FORMAT_NUMBER as Ct, setCellAsNumber as D, FORMAT_TEXT as Dt, setCellAsDate as E, FORMAT_PERCENTAGE_00 as Et, setCellProtection as F, DEFAULT_FONT as Ft, setRangeNumberFormat as G, makeGradientStop as Gt, setRangeBackgroundColor as H, fillToCss as Ht, setCellStyle as I, FONT_SCHEMES as It, setRangeWrapText as J, borderToCss as Jt, setRangeProtection as K, makePatternFill as Kt, setFontColor as L, UNDERLINE_STYLES as Lt, setCellFill as M, isDateFormat as Mt, setCellFont as N, isTimedeltaFormat as Nt, setCellAsPercent as O, builtinFormatCode as Ot, setCellNumberFormat as P, makeNumberFormat as Pt, makeProtection as Q, VERTICAL_ALIGNMENTS as Qt, setFontName as R, VERT_ALIGNS as Rt, rotateCellText as S, FORMAT_GENERAL as St, setCellAsCurrency as T, FORMAT_PERCENTAGE as Tt, setRangeBorderBox as U, makeFill as Ut, setRangeAlignment as V, PATTERN_TYPES as Vt, setRangeFont as W, makeGradientFill as Wt, setUnderline as X, makeSide as Xt, setStrikethrough as Y, makeBorder as Yt, wrapCellText as Z, HORIZONTAL_ALIGNMENTS as Zt, getCellNumberFormat as _, BUILTIN_FORMATS_MAX_SIZE as _t, cellStyleToCss as a, addFill as at, patchCellFont as b, FORMAT_DATE_TIMEDELTA as bt, clearCellStyle as c, buildXfPatch as ct, copyCellStyle as d, listCellStyleXfs as dt, makeAlignment as en, addNamedStyle as et, formatAsHeader as f, listCellXfs as ft, getCellFont as g, BUILTIN_FORMATS as gt, getCellFill as h, makeStylesheet as ht, applyNamedStyle as i, addCellXf as it, setCellBorderAll as j, isBuiltinFormat as jt, setCellBackgroundColor as k, builtinFormatId as kt, clearRangeStyle as l, defaultCellXf as lt, getCellBorder as m, listFonts as mt, alignCellVertical as n, addBorder as nt, centerCell as o, addFont as ot, getCellAlignment as p, listFills as pt, setRangeStyle as q, SIDE_STYLES as qt, applyBuiltinStyle as r, addCellStyleXf as rt, clearCellBackground as s, addNumFmt as st, alignCellHorizontal as t, stableStringify as tn, ensureBuiltinStyle as tt, cloneCellStyle as u, listBorders as ut, getCellProtection as v, FORMAT_COLOR_NAMES as vt, setCellAlignment as w, FORMAT_NUMBER_00 as wt, registerCellStyle as x, FORMAT_DATE_YYYYMMDD2 as xt, indentCell as y, FORMAT_DATE_DATETIME as yt, setFontSize as z, fontToCss as zt };
1617
1624
 
1618
- //# sourceMappingURL=cell-style-CNsET6WU.mjs.map
1625
+ //# sourceMappingURL=cell-style-CbB4nXTY.mjs.map