@office-kit/xlsx 0.11.1 → 0.13.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 (75) hide show
  1. package/README.md +4 -1
  2. package/dist/cell/cell.d.ts +44 -9
  3. package/dist/cell/index.d.ts +1 -1
  4. package/dist/{cell-BucgGwl3.mjs → cell-Df3cKRIl.mjs} +72 -30
  5. package/dist/cell-Df3cKRIl.mjs.map +1 -0
  6. package/dist/{cell-style-DuvS_Lsg.mjs → cell-style-BFmJOmcx.mjs} +130 -93
  7. package/dist/cell-style-BFmJOmcx.mjs.map +1 -0
  8. package/dist/cell.mjs +2 -2
  9. package/dist/{coordinate-96Ecci4d.mjs → coordinate-Bt5Gni2I.mjs} +19 -8
  10. package/dist/coordinate-Bt5Gni2I.mjs.map +1 -0
  11. package/dist/{defined-names-CviWmtQg.mjs → defined-names-Ctu3F6ls.mjs} +4 -3
  12. package/dist/defined-names-Ctu3F6ls.mjs.map +1 -0
  13. package/dist/{differential-DvKU8fJt.mjs → differential-H9SjEeIU.mjs} +2 -2
  14. package/dist/{differential-DvKU8fJt.mjs.map → differential-H9SjEeIU.mjs.map} +1 -1
  15. package/dist/{drawing-BxzLuryn.mjs → drawing-ZJ3h4VHD.mjs} +2 -2
  16. package/dist/{drawing-BxzLuryn.mjs.map → drawing-ZJ3h4VHD.mjs.map} +1 -1
  17. package/dist/drawing.mjs +1 -1
  18. package/dist/{inference-BrI9uIY4.mjs → inference-BMvv9cUY.mjs} +18 -3
  19. package/dist/inference-BMvv9cUY.mjs.map +1 -0
  20. package/dist/io/save.d.ts +15 -3
  21. package/dist/io.mjs +2 -2
  22. package/dist/{load-Bghb1YHY.mjs → load-CJdGh50R.mjs} +6 -6
  23. package/dist/{load-Bghb1YHY.mjs.map → load-CJdGh50R.mjs.map} +1 -1
  24. package/dist/node.mjs +1 -1
  25. package/dist/{save-Bqcf8w3g.mjs → save-CjarR7Rp.mjs} +10 -8
  26. package/dist/save-CjarR7Rp.mjs.map +1 -0
  27. package/dist/streaming/write-only.d.ts +18 -14
  28. package/dist/streaming.mjs +21 -51
  29. package/dist/streaming.mjs.map +1 -1
  30. package/dist/styles/cell-style.d.ts +78 -32
  31. package/dist/styles/fonts.d.ts +10 -1
  32. package/dist/styles/index.d.ts +3 -3
  33. package/dist/styles/stylesheet.d.ts +26 -0
  34. package/dist/styles.mjs +4 -4
  35. package/dist/{stylesheet-writer-HxaX7bGy.mjs → stylesheet-writer-D7Uug85X.mjs} +31 -18
  36. package/dist/stylesheet-writer-D7Uug85X.mjs.map +1 -0
  37. package/dist/{table-1P8we2gS.mjs → table-Ccro4rrz.mjs} +11 -9
  38. package/dist/table-Ccro4rrz.mjs.map +1 -0
  39. package/dist/utils/coordinate.d.ts +30 -4
  40. package/dist/utils/formula-text.d.ts +7 -0
  41. package/dist/utils/index.d.ts +1 -1
  42. package/dist/utils.mjs +2 -2
  43. package/dist/workbook/calc-properties.d.ts +8 -1
  44. package/dist/workbook/index.d.ts +1 -1
  45. package/dist/{workbook-BlZVXiyG.mjs → workbook-B15-T4cs.mjs} +6 -6
  46. package/dist/{workbook-BlZVXiyG.mjs.map → workbook-B15-T4cs.mjs.map} +1 -1
  47. package/dist/workbook.mjs +45 -3
  48. package/dist/workbook.mjs.map +1 -1
  49. package/dist/worksheet/cell-range.d.ts +10 -3
  50. package/dist/worksheet/data-validations.d.ts +1 -1
  51. package/dist/worksheet/index.d.ts +3 -3
  52. package/dist/worksheet/table-validate.d.ts +7 -0
  53. package/dist/worksheet/table.d.ts +4 -1
  54. package/dist/worksheet/views.d.ts +5 -0
  55. package/dist/worksheet/worksheet.d.ts +106 -65
  56. package/dist/worksheet/writer.d.ts +7 -0
  57. package/dist/{worksheet-C5Ensf_j.mjs → worksheet-4xW-i8j9.mjs} +235 -51
  58. package/dist/worksheet-4xW-i8j9.mjs.map +1 -0
  59. package/dist/worksheet.mjs +3 -3
  60. package/dist/{writer-IyFccCRJ.mjs → writer-Z7cF_CBk.mjs} +60 -8
  61. package/dist/writer-Z7cF_CBk.mjs.map +1 -0
  62. package/dist/zip/index.d.ts +1 -1
  63. package/dist/zip/writer.d.ts +20 -1
  64. package/dist/zip.mjs +1 -1
  65. package/package.json +1 -1
  66. package/dist/cell-BucgGwl3.mjs.map +0 -1
  67. package/dist/cell-style-DuvS_Lsg.mjs.map +0 -1
  68. package/dist/coordinate-96Ecci4d.mjs.map +0 -1
  69. package/dist/defined-names-CviWmtQg.mjs.map +0 -1
  70. package/dist/inference-BrI9uIY4.mjs.map +0 -1
  71. package/dist/save-Bqcf8w3g.mjs.map +0 -1
  72. package/dist/stylesheet-writer-HxaX7bGy.mjs.map +0 -1
  73. package/dist/table-1P8we2gS.mjs.map +0 -1
  74. package/dist/worksheet-C5Ensf_j.mjs.map +0 -1
  75. package/dist/writer-IyFccCRJ.mjs.map +0 -1
package/README.md CHANGED
@@ -262,7 +262,10 @@ common surprise for direct ports:
262
262
  that hides a real bug elsewhere).
263
263
  - **`setCell(ws, row, col, value)`** is the @office-kit/xlsx equivalent of
264
264
  openpyxl's `ws.cell(row=r, column=c, value=v)`. Coordinates are
265
- 1-based on both sides.
265
+ 1-based on both sides. `value` is mandatory: openpyxl's no-value
266
+ `ws.cell(row=r, column=c)` returns the cell without touching it, whereas
267
+ `setCell` writes whatever you pass. Use `ensureCell(ws, row, col)` for the
268
+ get-or-create behaviour.
266
269
  - **`makeBorder({ left: makeSide({ style: 'thin' }) })`** is the
267
270
  @office-kit/xlsx equivalent of openpyxl's
268
271
  `Border(left=Side(style='thin'))`. Same with `makeFill`, `makeFont`,
@@ -71,19 +71,51 @@ export declare function setCellValue(c: Cell, value: CellValue): void;
71
71
  * path.
72
72
  */
73
73
  export declare function bindValue(c: Cell, value: number | string | boolean | Date | null): void;
74
- /** Plain `=A1+B1` style formula. Cached value is optional but recommended for round-trip. */
74
+ /**
75
+ * Build a formula cell value. Hand it to `setCell` when the write already
76
+ * carries a style id, so placing a formatted formula stays a single call;
77
+ * {@link setFormula} is the same thing applied to a cell you already hold.
78
+ *
79
+ * A leading `=` is stripped, so `'=SUM(A1:A3)'` and `'SUM(A1:A3)'` are
80
+ * interchangeable.
81
+ *
82
+ * A cached value is optional. Without one, Excel, LibreOffice and Google
83
+ * Sheets compute the result on open, but viewers that never calculate (Quick
84
+ * Look, Outlook and SharePoint previews, most thumbnailers) render the cell
85
+ * empty. Supply one whenever the producer can compute it.
86
+ */
87
+ export declare function makeFormula(formula: string, opts?: {
88
+ cachedValue?: FormulaValue['cachedValue'];
89
+ }): FormulaValue;
90
+ /**
91
+ * Build an array (CSE) formula value spanning `ref`. Belongs on the top-left
92
+ * cell of the range, since Excel reads `ref` to know how far the result
93
+ * spreads.
94
+ */
95
+ export declare function makeArrayFormula(ref: string, formula: string, opts?: {
96
+ cachedValue?: FormulaValue['cachedValue'];
97
+ }): FormulaValue;
98
+ /**
99
+ * Build a shared-formula value. The first cell in the group carries the
100
+ * formula text + `ref`; subsequent cells with the same `si` carry only the
101
+ * index, and Excel reconstructs their text by shifting the references, so
102
+ * their `formula` is legitimately empty.
103
+ */
104
+ export declare function makeSharedFormula(si: number, formula?: string, ref?: string, opts?: {
105
+ cachedValue?: FormulaValue['cachedValue'];
106
+ }): FormulaValue;
107
+ /**
108
+ * Plain `A1+B1` style formula, applied in place. Same value as
109
+ * {@link makeFormula}, for a cell you already hold.
110
+ */
75
111
  export declare function setFormula(c: Cell, formula: string, opts?: {
76
112
  cachedValue?: FormulaValue['cachedValue'];
77
113
  }): void;
78
- /** Array (CSE) formula spanning a `ref` range. */
114
+ /** Array (CSE) formula spanning a `ref` range, applied in place. */
79
115
  export declare function setArrayFormula(c: Cell, ref: string, formula: string, opts?: {
80
116
  cachedValue?: FormulaValue['cachedValue'];
81
117
  }): void;
82
- /**
83
- * Shared formula. The first cell in the group carries the formula text + ref;
84
- * subsequent cells with the same `si` carry only the index and Excel
85
- * reconstructs the formula via reference shifting.
86
- */
118
+ /** Shared formula, applied in place. See {@link makeSharedFormula}. */
87
119
  export declare function setSharedFormula(c: Cell, si: number, formula?: string, ref?: string, opts?: {
88
120
  cachedValue?: FormulaValue['cachedValue'];
89
121
  }): void;
@@ -115,10 +147,13 @@ export interface DataTableFormulaOpts {
115
147
  cachedValue?: FormulaValue['cachedValue'];
116
148
  }
117
149
  /**
118
- * Set a data-table formula on a cell. Preserves all the dt-specific attributes
150
+ * Build a data-table formula value. Preserves all the dt-specific attributes
119
151
  * so the writer can re-emit `<f t="dataTable" r1="..." />` verbatim and Excel
120
- * keeps treating the cell as a Data Table cell.
152
+ * keeps treating the cell as a Data Table cell. Excel writes these with no
153
+ * formula text at all, so `formula` may be empty.
121
154
  */
155
+ export declare function makeDataTableFormula(formula: string, opts: DataTableFormulaOpts): FormulaValue;
156
+ /** Data-table formula, applied in place. See {@link makeDataTableFormula}. */
122
157
  export declare function setDataTableFormula(c: Cell, formula: string, opts: DataTableFormulaOpts): void;
123
158
  /** Build a `{ kind: 'error', code }` cell value. */
124
159
  export declare function makeErrorValue(code: ExcelErrorCode): {
@@ -1,4 +1,4 @@
1
1
  export type { Cell, CellValue, CellValueAsStringOptions, DataTableFormulaOpts, ExcelErrorCode, FormulaKind, FormulaValue, MergedCell, } from './cell.js';
2
- export { bindValue, cellValueAsBoolean, cellValueAsDate, cellValueAsNumber, cellValueAsPrimitive, cellValueAsString, getCachedFormulaValue, getCoordinate, getFormulaText, isDurationValue, isEmptyCell, isErrorCell, isErrorValue, isFormulaCell, isFormulaValue, isMergedCell, isRichTextCell, isRichTextValue, makeCell, makeDurationValue, makeErrorValue, setArrayFormula, setCellValue, setDataTableFormula, setFormula, setSharedFormula, } from './cell.js';
2
+ export { bindValue, cellValueAsBoolean, cellValueAsDate, cellValueAsNumber, cellValueAsPrimitive, cellValueAsString, getCachedFormulaValue, getCoordinate, getFormulaText, isDurationValue, isEmptyCell, isErrorCell, isErrorValue, isFormulaCell, isFormulaValue, isMergedCell, isRichTextCell, isRichTextValue, makeArrayFormula, makeCell, makeDataTableFormula, makeDurationValue, makeErrorValue, makeFormula, makeSharedFormula, setArrayFormula, setCellValue, setDataTableFormula, setFormula, setSharedFormula, } from './cell.js';
3
3
  export type { InlineFont, InlineUnderline, InlineVertAlign, RichText, TextRun, } from './rich-text.js';
4
4
  export { makeRichText, makeTextRun, richTextToString } from './rich-text.js';
@@ -1,6 +1,6 @@
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-96Ecci4d.mjs";
3
- import { t as ERROR_CODES } from "./inference-BrI9uIY4.mjs";
2
+ import { a as columnLetterFromIndex, n as MAX_ROW, t as MAX_COL } from "./coordinate-Bt5Gni2I.mjs";
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) {
6
6
  if (typeof text !== "string") throw new OpenXmlSchemaError("makeTextRun: text must be a string");
@@ -61,8 +61,8 @@ function setCellValue(c, value) {
61
61
  */
62
62
  function bindValue(c, value) {
63
63
  if (typeof value === "string") {
64
- if (value.length > 0 && value.charCodeAt(0) === 61) {
65
- setFormula(c, value.slice(1));
64
+ if (startsWithEquals(value)) {
65
+ setFormula(c, value);
66
66
  return;
67
67
  }
68
68
  if (ERROR_CODES.has(value)) {
@@ -77,51 +77,89 @@ function bindValue(c, value) {
77
77
  }
78
78
  c.value = value;
79
79
  }
80
- /** Plain `=A1+B1` style formula. Cached value is optional but recommended for round-trip. */
81
- function setFormula(c, formula, opts) {
82
- c.value = {
80
+ const requireFormulaText = (fn, formula) => {
81
+ const text = normalizeFormulaText(formula);
82
+ if (text.length === 0) throw new OpenXmlSchemaError(`${fn}: formula text must not be empty (got ${JSON.stringify(formula)})`);
83
+ return text;
84
+ };
85
+ /**
86
+ * Build a formula cell value. Hand it to `setCell` when the write already
87
+ * carries a style id, so placing a formatted formula stays a single call;
88
+ * {@link setFormula} is the same thing applied to a cell you already hold.
89
+ *
90
+ * A leading `=` is stripped, so `'=SUM(A1:A3)'` and `'SUM(A1:A3)'` are
91
+ * interchangeable.
92
+ *
93
+ * A cached value is optional. Without one, Excel, LibreOffice and Google
94
+ * Sheets compute the result on open, but viewers that never calculate (Quick
95
+ * Look, Outlook and SharePoint previews, most thumbnailers) render the cell
96
+ * empty. Supply one whenever the producer can compute it.
97
+ */
98
+ function makeFormula(formula, opts) {
99
+ return Object.freeze({
83
100
  kind: "formula",
84
101
  t: "normal",
85
- formula,
102
+ formula: requireFormulaText("makeFormula", formula),
86
103
  ...opts?.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {}
87
- };
104
+ });
88
105
  }
89
- /** Array (CSE) formula spanning a `ref` range. */
90
- function setArrayFormula(c, ref, formula, opts) {
91
- c.value = {
106
+ /**
107
+ * Build an array (CSE) formula value spanning `ref`. Belongs on the top-left
108
+ * cell of the range, since Excel reads `ref` to know how far the result
109
+ * spreads.
110
+ */
111
+ function makeArrayFormula(ref, formula, opts) {
112
+ return Object.freeze({
92
113
  kind: "formula",
93
114
  t: "array",
94
- formula,
115
+ formula: requireFormulaText("makeArrayFormula", formula),
95
116
  ref,
96
117
  ...opts?.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {}
97
- };
118
+ });
98
119
  }
99
120
  /**
100
- * Shared formula. The first cell in the group carries the formula text + ref;
101
- * subsequent cells with the same `si` carry only the index and Excel
102
- * reconstructs the formula via reference shifting.
121
+ * Build a shared-formula value. The first cell in the group carries the
122
+ * formula text + `ref`; subsequent cells with the same `si` carry only the
123
+ * index, and Excel reconstructs their text by shifting the references, so
124
+ * their `formula` is legitimately empty.
103
125
  */
104
- function setSharedFormula(c, si, formula, ref, opts) {
105
- if (!Number.isInteger(si) || si < 0) throw new OpenXmlSchemaError(`setSharedFormula: si must be a non-negative integer; got ${si}`);
106
- c.value = {
126
+ function makeSharedFormula(si, formula, ref, opts) {
127
+ if (!Number.isInteger(si) || si < 0) throw new OpenXmlSchemaError(`makeSharedFormula: si must be a non-negative integer; got ${si}`);
128
+ return Object.freeze({
107
129
  kind: "formula",
108
130
  t: "shared",
109
- formula: formula ?? "",
131
+ formula: formula === void 0 ? "" : normalizeFormulaText(formula),
110
132
  si,
111
133
  ...ref !== void 0 ? { ref } : {},
112
134
  ...opts?.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {}
113
- };
135
+ });
136
+ }
137
+ /**
138
+ * Plain `A1+B1` style formula, applied in place. Same value as
139
+ * {@link makeFormula}, for a cell you already hold.
140
+ */
141
+ function setFormula(c, formula, opts) {
142
+ c.value = makeFormula(formula, opts);
143
+ }
144
+ /** Array (CSE) formula spanning a `ref` range, applied in place. */
145
+ function setArrayFormula(c, ref, formula, opts) {
146
+ c.value = makeArrayFormula(ref, formula, opts);
147
+ }
148
+ /** Shared formula, applied in place. See {@link makeSharedFormula}. */
149
+ function setSharedFormula(c, si, formula, ref, opts) {
150
+ c.value = makeSharedFormula(si, formula, ref, opts);
114
151
  }
115
152
  /**
116
- * Set a data-table formula on a cell. Preserves all the dt-specific attributes
153
+ * Build a data-table formula value. Preserves all the dt-specific attributes
117
154
  * so the writer can re-emit `<f t="dataTable" r1="..." />` verbatim and Excel
118
- * keeps treating the cell as a Data Table cell.
155
+ * keeps treating the cell as a Data Table cell. Excel writes these with no
156
+ * formula text at all, so `formula` may be empty.
119
157
  */
120
- function setDataTableFormula(c, formula, opts) {
121
- c.value = {
158
+ function makeDataTableFormula(formula, opts) {
159
+ return Object.freeze({
122
160
  kind: "formula",
123
161
  t: "dataTable",
124
- formula,
162
+ formula: normalizeFormulaText(formula),
125
163
  ref: opts.ref,
126
164
  ...opts.r1 !== void 0 ? { r1: opts.r1 } : {},
127
165
  ...opts.r2 !== void 0 ? { r2: opts.r2 } : {},
@@ -132,7 +170,11 @@ function setDataTableFormula(c, formula, opts) {
132
170
  ...opts.aca !== void 0 ? { aca: opts.aca } : {},
133
171
  ...opts.ca !== void 0 ? { ca: opts.ca } : {},
134
172
  ...opts.cachedValue !== void 0 ? { cachedValue: opts.cachedValue } : {}
135
- };
173
+ });
174
+ }
175
+ /** Data-table formula, applied in place. See {@link makeDataTableFormula}. */
176
+ function setDataTableFormula(c, formula, opts) {
177
+ c.value = makeDataTableFormula(formula, opts);
136
178
  }
137
179
  /** Build a `{ kind: 'error', code }` cell value. */
138
180
  function makeErrorValue(code) {
@@ -315,6 +357,6 @@ function cellValueAsPrimitive(v) {
315
357
  return null;
316
358
  }
317
359
  //#endregion
318
- export { setCellValue as C, makeRichText as D, setSharedFormula as E, makeTextRun as O, setArrayFormula as S, setFormula as T, isRichTextCell as _, cellValueAsPrimitive as a, makeDurationValue as b, getCoordinate as c, isEmptyCell as d, isErrorCell as f, isMergedCell as g, isFormulaValue as h, cellValueAsNumber as i, richTextToString 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, setDataTableFormula as w, makeErrorValue as x, makeCell as y };
360
+ 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 };
319
361
 
320
- //# sourceMappingURL=cell-BucgGwl3.mjs.map
362
+ //# sourceMappingURL=cell-Df3cKRIl.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cell-Df3cKRIl.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 /** 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.\n */\nexport function makeFormula(\n formula: string,\n opts?: { cachedValue?: FormulaValue['cachedValue'] },\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 });\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?: { cachedValue?: FormulaValue['cachedValue'] },\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 });\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?: { cachedValue?: FormulaValue['cachedValue'] },\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 });\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?: { cachedValue?: FormulaValue['cachedValue'] }): 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?: { cachedValue?: FormulaValue['cachedValue'] },\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?: { cachedValue?: FormulaValue['cachedValue'] },\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}\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 });\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 { _n as colorToHex, bt as setCell, sn as parseRange, wn as makeColor } from "./worksheet-C5Ensf_j.mjs";
2
+ import { Tn as makeColor, cn as parseRange, vn as colorToHex, y as ensureCell } from "./worksheet-4xW-i8j9.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;
@@ -655,6 +655,44 @@ function defaultCellXf() {
655
655
  numFmtId: 0
656
656
  });
657
657
  }
658
+ /**
659
+ * Resolve a style spec to the CellXf fields it sets, registering each component
660
+ * in its pool. The result is a patch, not a whole xf: axes absent from `spec`
661
+ * are absent here too, so a caller can either spread it over
662
+ * {@link defaultCellXf} for a complete style or over an existing xf to merge.
663
+ *
664
+ * Every path that turns a user-facing style spec into an xf goes through this,
665
+ * so a new axis on {@link CellStyleSpec} reaches the modelled writer and the
666
+ * streaming write-only writer together.
667
+ */
668
+ function buildXfPatch(ss, spec) {
669
+ const patch = {};
670
+ if (spec.font !== void 0) {
671
+ patch.fontId = addFont(ss, spec.font);
672
+ patch.applyFont = true;
673
+ }
674
+ if (spec.fill !== void 0) {
675
+ patch.fillId = addFill(ss, spec.fill);
676
+ patch.applyFill = true;
677
+ }
678
+ if (spec.border !== void 0) {
679
+ patch.borderId = addBorder(ss, spec.border);
680
+ patch.applyBorder = true;
681
+ }
682
+ if (spec.alignment !== void 0) {
683
+ patch.alignment = spec.alignment;
684
+ patch.applyAlignment = true;
685
+ }
686
+ if (spec.protection !== void 0) {
687
+ patch.protection = spec.protection;
688
+ patch.applyProtection = true;
689
+ }
690
+ if (spec.numberFormat !== void 0) {
691
+ patch.numFmtId = addNumFmt(ss, spec.numberFormat);
692
+ patch.applyNumberFormat = true;
693
+ }
694
+ return patch;
695
+ }
658
696
  //#endregion
659
697
  //#region src/styles/named-styles.ts
660
698
  /**
@@ -1023,6 +1061,12 @@ function applyXfPatch(wb, c, patch) {
1023
1061
  };
1024
1062
  c.styleId = addCellXf(wb.styles, next);
1025
1063
  }
1064
+ /**
1065
+ * Replace the cell's font outright. `font` has to be complete: anything it
1066
+ * omits is omitted from the `<font>` record too, and each viewer then falls
1067
+ * back to its own default rather than the workbook's. Reach for {@link
1068
+ * patchCellFont} unless you really mean "this font and nothing inherited".
1069
+ */
1026
1070
  function setCellFont(wb, c, font) {
1027
1071
  applyXfPatch(wb, c, {
1028
1072
  fontId: addFont(wb.styles, font),
@@ -1133,42 +1177,54 @@ function cloneCellStyle(sourceWb, source, targetWb, target) {
1133
1177
  return target.styleId;
1134
1178
  }
1135
1179
  /**
1136
- * Build a single CellXf id from a multi-axis style spec, then apply it to every
1180
+ * Register a style and return its `styleId`. `setCell` and `setCellByCoord`
1181
+ * take it as their last argument, `appendRow` and `appendRows` take it inside
1182
+ * `{ styleIds: [...] }`:
1183
+ *
1184
+ * ```ts
1185
+ * const INT = registerCellStyle(wb, { numberFormat: '#,##0' });
1186
+ * setCell(ws, 2, 3, 1234, INT);
1187
+ * appendRow(ws, ['de', 71_579], { styleIds: [undefined, INT] });
1188
+ * ```
1189
+ *
1190
+ * Build each distinct look once and let the write carry the formatting,
1191
+ * instead of running a styling pass over every cell afterwards.
1192
+ *
1193
+ * The id names a **complete** style, not a patch: an axis missing from `spec`
1194
+ * resolves to slot 0 of that pool, so it renders as the workbook default even
1195
+ * when the target cell previously had something there. {@link setCellStyle} is
1196
+ * the patch-an-existing-cell counterpart.
1197
+ *
1198
+ * "Workbook default" means slot 0 literally. On a workbook from
1199
+ * `createWorkbook` that is the neutral font / no fill / no border. A workbook
1200
+ * loaded from another producer may hold anything in slot 0, since nothing in
1201
+ * ECMA-376 reserves it, so pass the axis explicitly when the look has to be
1202
+ * neutral regardless of what the file arrived with.
1203
+ */
1204
+ function registerCellStyle(wb, spec) {
1205
+ reserveDefaultXfSlot(wb);
1206
+ return addCellXf(wb.styles, {
1207
+ ...defaultCellXf(),
1208
+ ...buildXfPatch(wb.styles, spec)
1209
+ });
1210
+ }
1211
+ /**
1212
+ * Build a single CellXf from a multi-axis style spec, then merge it into every
1137
1213
  * cell in `range`. The xf is registered once per style shape, so a 1000-cell
1138
- * range allocates one xf much faster than looping `setCellStyle` per cell.
1214
+ * range allocates one xf, which is much faster than looping `setCellStyle` per
1215
+ * cell.
1216
+ *
1217
+ * Each cell keeps the axes `spec` leaves out, which is what separates this from
1218
+ * {@link registerCellStyle}: the id that returns is a whole style, this is a
1219
+ * patch over whatever each cell already carried.
1139
1220
  */
1140
- function setRangeStyle(wb, ws, range, opts) {
1141
- const patch = {};
1142
- if (opts.font !== void 0) {
1143
- patch.fontId = addFont(wb.styles, opts.font);
1144
- patch.applyFont = true;
1145
- }
1146
- if (opts.fill !== void 0) {
1147
- patch.fillId = addFill(wb.styles, opts.fill);
1148
- patch.applyFill = true;
1149
- }
1150
- if (opts.border !== void 0) {
1151
- patch.borderId = addBorder(wb.styles, opts.border);
1152
- patch.applyBorder = true;
1153
- }
1154
- if (opts.alignment !== void 0) {
1155
- patch.alignment = opts.alignment;
1156
- patch.applyAlignment = true;
1157
- }
1158
- if (opts.protection !== void 0) {
1159
- patch.protection = opts.protection;
1160
- patch.applyProtection = true;
1161
- }
1162
- if (opts.numberFormat !== void 0) {
1163
- patch.numFmtId = addNumFmt(wb.styles, opts.numberFormat);
1164
- patch.applyNumberFormat = true;
1165
- }
1221
+ function setRangeStyle(wb, ws, range, spec) {
1222
+ const patch = buildXfPatch(wb.styles, spec);
1166
1223
  if (Object.keys(patch).length === 0) return;
1167
1224
  reserveDefaultXfSlot(wb);
1168
1225
  const { minRow, maxRow, minCol, maxCol } = parseRange(range);
1169
1226
  for (let r = minRow; r <= maxRow; r++) for (let c = minCol; c <= maxCol; c++) {
1170
- let cell = ws.rows.get(r)?.get(c);
1171
- if (!cell) cell = setCell(ws, r, c);
1227
+ const cell = ensureCell(ws, r, c);
1172
1228
  const next = {
1173
1229
  ...currentXf(wb.styles, cell),
1174
1230
  ...patch
@@ -1177,37 +1233,14 @@ function setRangeStyle(wb, ws, range, opts) {
1177
1233
  }
1178
1234
  }
1179
1235
  /**
1180
- * Combined cell-style setter. Each axis is independent pass any subset and
1181
- * the corresponding `applyXxx` flags get set on the underlying CellXf. Avoids
1236
+ * Combined cell-style setter, patching the cell's existing xf. Each axis is
1237
+ * independent, so pass any subset and the corresponding `applyXxx` flags get set
1238
+ * on the underlying CellXf. Avoids
1182
1239
  * 5+ separate stylesheet round-trips when a caller wants to style a single cell
1183
1240
  * across multiple axes (Excel dedupes the resulting xf record on every call).
1184
1241
  */
1185
- function setCellStyle(wb, c, opts) {
1186
- const patch = {};
1187
- if (opts.font !== void 0) {
1188
- patch.fontId = addFont(wb.styles, opts.font);
1189
- patch.applyFont = true;
1190
- }
1191
- if (opts.fill !== void 0) {
1192
- patch.fillId = addFill(wb.styles, opts.fill);
1193
- patch.applyFill = true;
1194
- }
1195
- if (opts.border !== void 0) {
1196
- patch.borderId = addBorder(wb.styles, opts.border);
1197
- patch.applyBorder = true;
1198
- }
1199
- if (opts.alignment !== void 0) {
1200
- patch.alignment = opts.alignment;
1201
- patch.applyAlignment = true;
1202
- }
1203
- if (opts.protection !== void 0) {
1204
- patch.protection = opts.protection;
1205
- patch.applyProtection = true;
1206
- }
1207
- if (opts.numberFormat !== void 0) {
1208
- patch.numFmtId = addNumFmt(wb.styles, opts.numberFormat);
1209
- patch.applyNumberFormat = true;
1210
- }
1242
+ function setCellStyle(wb, c, spec) {
1243
+ const patch = buildXfPatch(wb.styles, spec);
1211
1244
  if (Object.keys(patch).length === 0) return;
1212
1245
  applyXfPatch(wb, c, patch);
1213
1246
  }
@@ -1238,7 +1271,12 @@ function setRangeBackgroundColor(wb, ws, range, color) {
1238
1271
  fgColor: typeof color === "string" ? makeColor({ rgb: color }) : makeColor(color)
1239
1272
  }) });
1240
1273
  }
1241
- /** Range-level shortcut for `setCellFont` (full Font replacement). */
1274
+ /**
1275
+ * Range-level shortcut for `setCellFont`. Replaces the whole Font on every cell
1276
+ * in the range; there is no range-level merge, so build the complete font you
1277
+ * want rather than passing `makeFont({ bold: true })` and losing the workbook
1278
+ * default.
1279
+ */
1242
1280
  function setRangeFont(wb, ws, range, font) {
1243
1281
  setRangeStyle(wb, ws, range, { font });
1244
1282
  }
@@ -1274,11 +1312,7 @@ function setRangeProtection(wb, ws, range, protection) {
1274
1312
  function setRangeWrapText(wb, ws, range, on = true) {
1275
1313
  reserveDefaultXfSlot(wb);
1276
1314
  const { minRow, maxRow, minCol, maxCol } = parseRange(range);
1277
- for (let r = minRow; r <= maxRow; r++) for (let c = minCol; c <= maxCol; c++) {
1278
- let cell = ws.rows.get(r)?.get(c);
1279
- if (!cell) cell = setCell(ws, r, c);
1280
- wrapCellText(wb, cell, on);
1281
- }
1315
+ for (let r = minRow; r <= maxRow; r++) for (let c = minCol; c <= maxCol; c++) wrapCellText(wb, ensureCell(ws, r, c), on);
1282
1316
  }
1283
1317
  /**
1284
1318
  * Range-level Alignment setter. Two modes:
@@ -1302,27 +1336,42 @@ function setRangeAlignment(wb, ws, range, alignment, mode = "merge") {
1302
1336
  return;
1303
1337
  }
1304
1338
  for (let r = minRow; r <= maxRow; r++) for (let c = minCol; c <= maxCol; c++) {
1305
- let cell = ws.rows.get(r)?.get(c);
1306
- if (!cell) cell = setCell(ws, r, c);
1339
+ const cell = ensureCell(ws, r, c);
1307
1340
  const cur = currentXf(wb.styles, cell).alignment;
1308
1341
  setCellAlignment(wb, cell, mergeAlignment(cur, alignment));
1309
1342
  }
1310
1343
  }
1311
- const mergeFont = (current, patch) => makeFont({
1312
- ...current,
1313
- ...patch
1314
- });
1344
+ /**
1345
+ * Merge `patch` over the cell's current font, so the fields left out keep the
1346
+ * value they already had (the workbook default, on an unstyled cell). This is
1347
+ * the way to change several font fields at once: `setCellFont(wb, c,
1348
+ * makeFont({ bold: true }))` is a legal call that registers a font carrying no
1349
+ * name and no size, and Excel, LibreOffice and Sheets each substitute a
1350
+ * different one.
1351
+ *
1352
+ * A field set to `undefined` is removed rather than kept, so
1353
+ * `patchCellFont(wb, c, { underline: undefined })` un-underlines a cell while
1354
+ * leaving the rest of its font alone. Omitting the key keeps the current value.
1355
+ *
1356
+ * The single-field setters below are this function with one field filled in.
1357
+ */
1358
+ function patchCellFont(wb, c, patch) {
1359
+ setCellFont(wb, c, makeFont({
1360
+ ...getCellFont(wb, c),
1361
+ ...patch
1362
+ }));
1363
+ }
1315
1364
  /** Toggle bold on a cell. Preserves other font fields. */
1316
1365
  function setBold(wb, c, on = true) {
1317
- setCellFont(wb, c, mergeFont(getCellFont(wb, c), { bold: on }));
1366
+ patchCellFont(wb, c, { bold: on });
1318
1367
  }
1319
1368
  /** Toggle italic on a cell. */
1320
1369
  function setItalic(wb, c, on = true) {
1321
- setCellFont(wb, c, mergeFont(getCellFont(wb, c), { italic: on }));
1370
+ patchCellFont(wb, c, { italic: on });
1322
1371
  }
1323
1372
  /** Toggle strike-through on a cell. */
1324
1373
  function setStrikethrough(wb, c, on = true) {
1325
- setCellFont(wb, c, mergeFont(getCellFont(wb, c), { strike: on }));
1374
+ patchCellFont(wb, c, { strike: on });
1326
1375
  }
1327
1376
  /**
1328
1377
  * Set the underline style. Pass `false` to drop underline; pass `'single' |
@@ -1330,32 +1379,22 @@ function setStrikethrough(wb, c, on = true) {
1330
1379
  * `true` for the most common single-line.
1331
1380
  */
1332
1381
  function setUnderline(wb, c, style = "single") {
1333
- const { underline: _drop, ...rest } = getCellFont(wb, c);
1334
- if (style === false) {
1335
- setCellFont(wb, c, makeFont(rest));
1336
- return;
1337
- }
1338
- const u = style === true ? "single" : style;
1339
- setCellFont(wb, c, makeFont({
1340
- ...rest,
1341
- underline: u
1342
- }));
1382
+ patchCellFont(wb, c, { underline: style === false ? void 0 : style === true ? "single" : style });
1343
1383
  }
1344
1384
  /** Set the font size in points (e.g. 14). Preserves other fields. */
1345
1385
  function setFontSize(wb, c, size) {
1346
- setCellFont(wb, c, mergeFont(getCellFont(wb, c), { size }));
1386
+ patchCellFont(wb, c, { size });
1347
1387
  }
1348
1388
  /** Set the font family name (e.g. "Arial"). Preserves other fields. */
1349
1389
  function setFontName(wb, c, name) {
1350
- setCellFont(wb, c, mergeFont(getCellFont(wb, c), { name }));
1390
+ patchCellFont(wb, c, { name });
1351
1391
  }
1352
1392
  /**
1353
1393
  * Set the font color. Accepts a hex string ("FFAA0033") or a partial `Color`
1354
1394
  * object (`{ theme: 4, tint: 0.4 }`). Preserves other font fields.
1355
1395
  */
1356
1396
  function setFontColor(wb, c, color) {
1357
- const colorObj = typeof color === "string" ? makeColor({ rgb: color }) : makeColor(color);
1358
- setCellFont(wb, c, mergeFont(getCellFont(wb, c), { color: colorObj }));
1397
+ patchCellFont(wb, c, { color: typeof color === "string" ? makeColor({ rgb: color }) : makeColor(color) });
1359
1398
  }
1360
1399
  const mergeAlignment = (current, patch) => {
1361
1400
  return makeAlignment({
@@ -1570,12 +1609,10 @@ function setRangeBorderBox(wb, ws, range, opts = { style: "thin" }) {
1570
1609
  if (bottom !== void 0) sides.bottom = bottom;
1571
1610
  if (left !== void 0) sides.left = left;
1572
1611
  if (right !== void 0) sides.right = right;
1573
- let cell = ws.rows.get(r)?.get(col);
1574
- if (!cell) cell = setCell(ws, r, col);
1575
- setCellBorder(wb, cell, makeBorder(sides));
1612
+ setCellBorder(wb, ensureCell(ws, r, col), makeBorder(sides));
1576
1613
  }
1577
1614
  }
1578
1615
  //#endregion
1579
- export { ensureBuiltinStyle as $, setCellFill as A, makeNumberFormat as At, setRangeBackgroundColor as B, makeGradientFill as Bt, setCellAsCurrency as C, FORMAT_TEXT as Ct, setCellBackgroundColor as D, isBuiltinFormat as Dt, setCellAsPercent as E, classifyDateFormat as Et, setFontColor as F, fontToCss as Ft, setRangeStyle as G, makeBorder as Gt, setRangeFont as H, makePatternFill as Ht, setFontName as I, makeFont as It, setUnderline as J, VERTICAL_ALIGNMENTS as Jt, setRangeWrapText as K, makeSide as Kt, setFontSize as L, PATTERN_TYPES as Lt, setCellNumberFormat as M, FONT_SCHEMES as Mt, setCellProtection as N, UNDERLINE_STYLES as Nt, setCellBorder as O, isDateFormat as Ot, setCellStyle as P, VERT_ALIGNS as Pt, addNamedStyle as Q, setItalic as R, fillToCss as Rt, setCellAlignment as S, FORMAT_PERCENTAGE_00 as St, setCellAsNumber as T, builtinFormatId as Tt, setRangeNumberFormat as U, SIDE_STYLES as Ut, setRangeBorderBox as V, makeGradientStop as Vt, setRangeProtection as W, borderToCss as Wt, makeProtection as X, makeAlignment as Xt, wrapCellText as Y, alignmentToCss as Yt, BUILTIN_NAMED_STYLES as Z, stableStringify as Zt, getCellNumberFormat as _, FORMAT_DATE_YYYYMMDD2 as _t, cellStyleToCss as a, addNumFmt as at, rotateCellText as b, FORMAT_NUMBER_00 as bt, clearCellStyle as c, listCellStyleXfs as ct, copyCellStyle as d, listFonts as dt, addBorder as et, formatAsHeader as f, makeStylesheet as ft, getCellFont as g, FORMAT_DATE_TIMEDELTA as gt, getCellFill as h, FORMAT_DATE_DATETIME as ht, applyNamedStyle as i, addFont as it, setCellFont as j, DEFAULT_FONT as jt, setCellBorderAll as k, isTimedeltaFormat as kt, clearRangeStyle as l, listCellXfs as lt, getCellBorder as m, BUILTIN_FORMATS_MAX_SIZE as mt, alignCellVertical as n, addCellXf as nt, centerCell as o, defaultCellXf as ot, getCellAlignment as p, BUILTIN_FORMATS as pt, setStrikethrough as q, HORIZONTAL_ALIGNMENTS as qt, applyBuiltinStyle as r, addFill as rt, clearCellBackground as s, listBorders as st, alignCellHorizontal as t, addCellStyleXf as tt, cloneCellStyle as u, listFills as ut, getCellProtection as v, FORMAT_GENERAL as vt, setCellAsDate as w, builtinFormatCode as wt, setBold as x, FORMAT_PERCENTAGE as xt, indentCell as y, FORMAT_NUMBER as yt, setRangeAlignment as z, makeFill as zt };
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 };
1580
1617
 
1581
- //# sourceMappingURL=cell-style-DuvS_Lsg.mjs.map
1618
+ //# sourceMappingURL=cell-style-BFmJOmcx.mjs.map