xls-codec 4.12.6 → 4.14.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 (76) hide show
  1. package/README.md +3 -1
  2. package/dist/biff/font.cjs +127 -0
  3. package/dist/biff/font.d.cts +2 -0
  4. package/dist/biff/font.d.ts +2 -0
  5. package/dist/biff/font.js +119 -0
  6. package/dist/biff/ptg-writer.cjs +1 -1
  7. package/dist/biff/ptg-writer.js +1 -1
  8. package/dist/biff/string-writer.cjs +1 -1
  9. package/dist/biff/string-writer.js +1 -1
  10. package/dist/biff/xf-writer.cjs +1 -22
  11. package/dist/biff/xf-writer.d.cts +1 -2
  12. package/dist/biff/xf-writer.d.ts +1 -2
  13. package/dist/biff/xf-writer.js +2 -22
  14. package/dist/{conditional-format-12-C3nwy1f8.d.ts → conditional-format-12-BTN59oHJ.d.ts} +2 -2
  15. package/dist/{conditional-format-12-D65-ruTq.d.cts → conditional-format-12-ZkrPfAP4.d.cts} +2 -2
  16. package/dist/{conditional-format-Cth_afMy.d.cts → conditional-format-BzTJe8Fm.d.cts} +1 -1
  17. package/dist/{conditional-format-BRMUTRP1.d.ts → conditional-format-D4U0eLcY.d.ts} +1 -1
  18. package/dist/content.cjs +52 -6
  19. package/dist/content.js +52 -6
  20. package/dist/{data-validation-BgUt8CbE.d.cts → data-validation-CTeIudWM.d.cts} +1 -1
  21. package/dist/{data-validation-Cq6iD8lB.d.ts → data-validation-Cjdk9imN.d.ts} +1 -1
  22. package/dist/defined-names-CqBJJmOJ.d.cts +39 -0
  23. package/dist/defined-names-DJZ27hRp.d.ts +39 -0
  24. package/dist/font-CBvAGxD8.d.cts +45 -0
  25. package/dist/font-DcXHYgZ2.d.ts +45 -0
  26. package/dist/index.cjs +5 -6
  27. package/dist/index.d.cts +4 -4
  28. package/dist/index.d.ts +4 -4
  29. package/dist/index.js +7 -7
  30. package/dist/workbook/chart.d.cts +1 -1
  31. package/dist/workbook/chart.d.ts +1 -1
  32. package/dist/workbook/comment-writer.cjs +1 -1
  33. package/dist/workbook/comment-writer.js +1 -1
  34. package/dist/workbook/conditional-format-12.d.cts +1 -1
  35. package/dist/workbook/conditional-format-12.d.ts +1 -1
  36. package/dist/workbook/conditional-format-ex.d.cts +3 -3
  37. package/dist/workbook/conditional-format-ex.d.ts +3 -3
  38. package/dist/workbook/conditional-format-write.cjs +1 -1
  39. package/dist/workbook/conditional-format-write.js +1 -1
  40. package/dist/workbook/conditional-format.cjs +1 -1
  41. package/dist/workbook/conditional-format.d.cts +1 -1
  42. package/dist/workbook/conditional-format.d.ts +1 -1
  43. package/dist/workbook/conditional-format.js +1 -1
  44. package/dist/workbook/data-validation-write.cjs +1 -1
  45. package/dist/workbook/data-validation-write.js +1 -1
  46. package/dist/workbook/data-validation.d.cts +1 -1
  47. package/dist/workbook/data-validation.d.ts +1 -1
  48. package/dist/workbook/defined-names.cjs +186 -0
  49. package/dist/workbook/defined-names.d.cts +2 -0
  50. package/dist/workbook/defined-names.d.ts +2 -0
  51. package/dist/workbook/defined-names.js +182 -0
  52. package/dist/workbook/drawing.d.cts +1 -1
  53. package/dist/workbook/drawing.d.ts +1 -1
  54. package/dist/workbook/globals-writer.cjs +7 -7
  55. package/dist/workbook/globals-writer.d.cts +9 -2
  56. package/dist/workbook/globals-writer.d.ts +9 -2
  57. package/dist/workbook/globals-writer.js +8 -8
  58. package/dist/workbook/globals.cjs +8 -2
  59. package/dist/workbook/globals.d.cts +6 -1
  60. package/dist/workbook/globals.d.ts +6 -1
  61. package/dist/workbook/globals.js +8 -2
  62. package/dist/workbook/print-names.cjs +1 -1
  63. package/dist/workbook/print-names.js +1 -1
  64. package/dist/workbook/sheet-writer.cjs +4 -4
  65. package/dist/workbook/sheet-writer.js +4 -4
  66. package/dist/workbook/sheet.cjs +1 -1
  67. package/dist/workbook/sheet.d.cts +4 -4
  68. package/dist/workbook/sheet.d.ts +4 -4
  69. package/dist/workbook/sheet.js +1 -1
  70. package/dist/write.cjs +56 -12
  71. package/dist/write.js +57 -13
  72. package/dist/written-cells.cjs +4 -2
  73. package/dist/written-cells.d.cts +2 -2
  74. package/dist/written-cells.d.ts +2 -2
  75. package/dist/written-cells.js +4 -2
  76. package/package.json +4 -4
@@ -1,6 +1,6 @@
1
1
  import "../biff/record-types.js";
2
- import { BiffWriteError } from "../biff/write-errors.js";
3
2
  import { RecordBuilder } from "../biff/builder.js";
3
+ import { BiffWriteError } from "../biff/write-errors.js";
4
4
  import { writeRecord } from "../biff/record-writer.js";
5
5
  import { writeXLUnicodeString } from "../biff/string-writer.js";
6
6
  import { compileFormulaText } from "../biff/ptg-writer.js";
@@ -1,2 +1,2 @@
1
- import { n as readDv, t as RawDataValidation } from "../data-validation-BgUt8CbE.cjs";
1
+ import { n as readDv, t as RawDataValidation } from "../data-validation-CTeIudWM.cjs";
2
2
  export { RawDataValidation, readDv };
@@ -1,2 +1,2 @@
1
- import { n as readDv, t as RawDataValidation } from "../data-validation-Cq6iD8lB.js";
1
+ import { n as readDv, t as RawDataValidation } from "../data-validation-Cjdk9imN.js";
2
2
  export { RawDataValidation, readDv };
@@ -0,0 +1,186 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("../biff/record-types.cjs");
3
+ const require_biff_records = require("../biff/records.cjs");
4
+ const require_biff_builder = require("../biff/builder.cjs");
5
+ const require_biff_cursor = require("../biff/cursor.cjs");
6
+ const require_biff_write_errors = require("../biff/write-errors.cjs");
7
+ const require_biff_record_writer = require("../biff/record-writer.cjs");
8
+ const require_biff_strings = require("../biff/strings.cjs");
9
+ const require_biff_ptg = require("../biff/ptg.cjs");
10
+ const require_biff_string_writer = require("../biff/string-writer.cjs");
11
+ let document_schema_js = require("document-schema.js");
12
+ //#region src/workbook/defined-names.ts
13
+ /** Lbl.grbit's fBuiltin bit -- field F of [MS-XLS] 2.4.150's own grbit layout. */
14
+ const LBL_FLAG_BUILTIN = 32;
15
+ /** [MS-XLS] 2.4.150's own built-in name table: the index a built-in name's single-character Name field carries, and the name it spells. The `_xlnm.` prefix is ECMA-376's own reserved spelling for the identical names in an xlsx (the two print ones confirmed against real LibreOffice-written markup in ooxml.js's own fixture), so a built-in rides through the shared schema under the spelling every other member of this format family already uses for it. */
16
+ const BUILTIN_NAME_SPELLINGS = [
17
+ "_xlnm.Consolidate_Area",
18
+ "_xlnm.Auto_Open",
19
+ "_xlnm.Auto_Close",
20
+ "_xlnm.Extract",
21
+ "_xlnm.Database",
22
+ "_xlnm.Criteria",
23
+ "_xlnm.Print_Area",
24
+ "_xlnm.Print_Titles",
25
+ "_xlnm.Recorder",
26
+ "_xlnm.Data_Form",
27
+ "_xlnm.Auto_Activate",
28
+ "_xlnm.Auto_Deactivate",
29
+ "_xlnm.Sheet_Title",
30
+ "_xlnm._FilterDatabase"
31
+ ];
32
+ /** The two built-in names print-names.ts owns end to end: read there onto ContentSheetPrintSettings, written there from them, and therefore skipped here rather than stated twice. */
33
+ const BUILTIN_NAME_PRINT_AREA = 6;
34
+ const BUILTIN_NAME_PRINT_TITLES = 7;
35
+ /** The `_xlnm.` prefix ECMA-376 reserves for built-in defined names, which is also the spelling this package reads them under -- so a name carrying it on write resolves back through the built-in table below, and one the table does not know is refused rather than written as a user name Excel itself forbids the prefix for. */
36
+ const XLNM_PREFIX = "_xlnm.";
37
+ /**
38
+ * Reads every Lbl record in a globals substream into a defined name, or skips it: the two print built-ins (print-names.ts owns them), a built-in index past the table above (no spelling to give it), a name whose rgce resolves to no formula text (a construct outside parseFormulaText's vocabulary, or a stream too malformed to walk -- ContentDefinedNameSchema requires refersTo, and a fabricated placeholder is not formula text), and a record whose own bytes overrun (caught per record rather than letting one malformed Lbl abort every other name, the identical per-record boundary sheet.ts's resolveFormulaText draws for a malformed cell formula).
39
+ */
40
+ function readDefinedNames(records, formulaSheets) {
41
+ const names = [];
42
+ for (const record of records) {
43
+ if (record.type !== 24) continue;
44
+ const parsed = readLblRecord(record, formulaSheets);
45
+ if (parsed !== void 0) names.push(parsed);
46
+ }
47
+ return names;
48
+ }
49
+ /** Lbl ([MS-XLS] 2.4.150): grbit, chKey, cch, cce, reserved3, itab, four reserved bytes, the Name as an XLUnicodeStringNoCch, then cce bytes of rgce (NameParsedFormula) and whatever rgcb trailer follows. */
50
+ function readLblRecord(record, formulaSheets) {
51
+ try {
52
+ const cursor = new require_biff_cursor.BlockCursor(record.blocks);
53
+ const isBuiltin = (cursor.u16() & LBL_FLAG_BUILTIN) !== 0;
54
+ cursor.skip(1);
55
+ const cch = cursor.u8();
56
+ const cce = cursor.u16();
57
+ cursor.skip(2);
58
+ const itab = cursor.u16();
59
+ cursor.skip(4);
60
+ let name;
61
+ if (isBuiltin) {
62
+ const highByte = (cursor.u8() & 1) !== 0;
63
+ if (cch !== 1 || highByte) return;
64
+ const builtinIndex = cursor.u8();
65
+ if (builtinIndex === BUILTIN_NAME_PRINT_AREA || builtinIndex === BUILTIN_NAME_PRINT_TITLES) return;
66
+ const spelling = BUILTIN_NAME_SPELLINGS[builtinIndex];
67
+ if (spelling === void 0) return;
68
+ name = spelling;
69
+ } else name = require_biff_strings.readXLUnicodeStringNoCch(cursor, cch);
70
+ const rgce = cursor.take(cce);
71
+ const rgcb = cursor.take(cursor.remainingInBlock());
72
+ const refersTo = require_biff_ptg.parseFormulaText(rgce, formulaSheets, { rgcb });
73
+ return refersTo === void 0 ? void 0 : {
74
+ name,
75
+ refersTo,
76
+ sheetIndex: itab === 0 ? void 0 : itab - 1
77
+ };
78
+ } catch (error) {
79
+ if (!(error instanceof require_biff_records.BiffFormatError)) throw error;
80
+ return;
81
+ }
82
+ }
83
+ /** The reverse of BUILTIN_NAME_SPELLINGS: an _xlnm spelling back to the built-in index a single-character Name field would carry. */
84
+ const BUILTIN_INDEX_BY_NAME = new Map(BUILTIN_NAME_SPELLINGS.map((spelling, index) => [spelling, index]));
85
+ /** A single A1-style corner, with or without its $ markers -- the identical shape biff/ptg.ts's own formatPoint produces, parsed back the other way. A `$` is honoured per coordinate rather than normalised away, because a relative coordinate in a defined name is genuine, retypeable formula semantics Excel re-interprets against the name's own scope, not a display detail. */
86
+ const REFERENCE_CORNER_RE = /^(\$?)([A-Za-z]{1,3})(\$?)([0-9]{1,5})$/;
87
+ /** A full refersTo this writer can compile: one sheet-qualified corner or corner pair, nothing more. */
88
+ const SHEET_QUALIFIED_REFERENCE_RE = /^(.*)!((?:\$?[A-Za-z]{1,3}\$?[0-9]{1,5})(?::(?:\$?[A-Za-z]{1,3}\$?[0-9]{1,5}))?)$/;
89
+ /** A user-defined name shaped like a cell reference ("A1", "$B$2", "A1:B2") is forbidden by [MS-XLS] 2.5.295's own name restrictions, since a formula using it would be indistinguishable from the reference itself. */
90
+ const CELL_REFERENCE_NAME_RE = /^\$?[A-Za-z]{1,3}\$?[0-9]{1,5}(:\$?[A-Za-z]{1,3}\$?[0-9]{1,5})?$/;
91
+ function parseCorner(text) {
92
+ const match = REFERENCE_CORNER_RE.exec(text);
93
+ if (match === null) return;
94
+ const column = (0, document_schema_js.columnLettersToIndex)(match[2] ?? "");
95
+ const row = Number.parseInt(match[4] ?? "", 10) - 1;
96
+ if (column === void 0 || row < 0) return;
97
+ return {
98
+ row,
99
+ column,
100
+ columnAbsolute: (match[1] ?? "") === "$",
101
+ rowAbsolute: (match[3] ?? "") === "$"
102
+ };
103
+ }
104
+ /** BIFF8's own grid ceilings, which a defined name's reference shares with every other reference in the format. */
105
+ const MAX_ROW_INDEX = 65535;
106
+ const MAX_COLUMN_INDEX = 255;
107
+ /** ColRelU's own relative bits ([MS-XLS] 2.5.198.105): bit 14 (0x4000) says the COLUMN coordinate is relative, bit 15 (0x8000) the ROW -- clear means absolute, exactly as biff/ptg.ts's pointFrom decodes them on read. */
108
+ const COLUMN_RELATIVE_BIT = 16384;
109
+ const ROW_RELATIVE_BIT = 32768;
110
+ /** PtgArea3d, reference class ([MS-XLS] 2.5.198.28): opcode 0x3b, the ixti, then an RgceArea -- the same token write-side print-names.ts builds for a print name's range, since a defined name has no other way to say which sheet its reference is on. */
111
+ function writeArea3dToken(ixti, first, last) {
112
+ const columnFieldOf = (corner) => corner.column | (corner.columnAbsolute ? 0 : COLUMN_RELATIVE_BIT) | (corner.rowAbsolute ? 0 : ROW_RELATIVE_BIT);
113
+ return new require_biff_builder.RecordBuilder().u8(59).u16(ixti).u16(first.row).u16(last.row).u16(columnFieldOf(first)).u16(columnFieldOf(last)).build();
114
+ }
115
+ /** Strips the single-quote wrapping a sheet label carries when the sheet name is not a bare identifier, unescaping the doubled quote inside -- the inverse of biff/ptg.ts's quoteSheetLabel. A string must actually be quoted on both ends to unwrap; a bare name is taken verbatim. */
116
+ function unquoteSheetLabel(label) {
117
+ if (label.startsWith("'") && label.endsWith("'") && label.length >= 2) return label.slice(1, -1).replaceAll("''", "'");
118
+ return label;
119
+ }
120
+ /**
121
+ * Compiles the document's defined names into the Lbl records the workbook stream carries.
122
+ *
123
+ * The refersTo vocabulary this writer can compile is exactly one sheet-qualified A1 reference -- `Sheet1!$A$1`, `Sheet1!$A$1:$B$2`, the sheet name quoted when it is not a bare identifier -- which is the shape every named range carries and the shape this package's own reader produces for one. A refersTo outside that vocabulary (a computed formula, a constant, an external-workbook reference) throws a BiffWriteError naming the construct rather than emitting a token stream this writer cannot prove round-trips, the identical refusal the cell-formula writer draws for the constructs outside its own vocabulary.
124
+ */
125
+ function definedNameEntriesFor(names, sheets) {
126
+ return names.map((defined) => {
127
+ const builtinName = defined.name.startsWith(XLNM_PREFIX) ? builtinIndexOf(defined.name) : void 0;
128
+ if (builtinName === void 0) validateUserName(defined.name);
129
+ return {
130
+ name: defined.name,
131
+ builtinName,
132
+ sheetIndex: scopeOf(defined, sheets.length),
133
+ rgce: compileRefersTo(defined, sheets).rgce
134
+ };
135
+ });
136
+ }
137
+ /** Resolves an _xlnm spelling to its built-in index, refusing the two print built-ins (print-names.ts owns them -- a document stating its print area as a names entry is stating a fact the print settings already carry, and writing both would emit the same Lbl record twice) and any spelling the table does not know. */
138
+ function builtinIndexOf(name) {
139
+ const index = BUILTIN_INDEX_BY_NAME.get(name);
140
+ if (index === void 0) throw new require_biff_write_errors.BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(name)}: the "_xlnm." prefix is reserved for built-in names, and this one is not in [MS-XLS] 2.4.150's own built-in name table`);
141
+ if (index === BUILTIN_NAME_PRINT_AREA || index === BUILTIN_NAME_PRINT_TITLES) throw new require_biff_write_errors.BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(name)}: the print built-ins are print-settings facts, stated through a sheet's printSettings (printRange/repeatRows/repeatColumns) rather than as document-level names -- writing both would emit the same Lbl record twice`);
142
+ return index;
143
+ }
144
+ /** A user-defined name must fit the record's own one-byte cch and must not be shaped like a cell reference, the one restriction of [MS-XLS] 2.5.295's own name grammar a writer can enforce without guessing at Excel's full validity table. */
145
+ function validateUserName(name) {
146
+ if (name.length < 1 || name.length > 255) throw new require_biff_write_errors.BiffWriteError(`xls-codec cannot write a defined name of ${name.length} characters: Lbl's own cch field is one byte, so a name must be 1-255 UTF-16 code units`);
147
+ if (CELL_REFERENCE_NAME_RE.test(name)) throw new require_biff_write_errors.BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(name)}: a name shaped like a cell reference is forbidden, since a formula using it would be indistinguishable from the reference itself`);
148
+ }
149
+ /** A scopeSheetIndex past the end of the document's own sheets array names a sheet that does not exist, so it is refused rather than written as an itab no BoundSheet8 answers to. */
150
+ function scopeOf(defined, sheetCount) {
151
+ if (defined.scopeSheetIndex === void 0) return;
152
+ if (defined.scopeSheetIndex >= sheetCount) throw new require_biff_write_errors.BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its scopeSheetIndex ${defined.scopeSheetIndex} is past the end of the document's own ${sheetCount}-sheet array`);
153
+ return defined.scopeSheetIndex;
154
+ }
155
+ /** Parses and compiles one entry's refersTo, throwing for anything outside the single sheet-qualified reference vocabulary documented on definedNameEntriesFor. */
156
+ function compileRefersTo(defined, sheets) {
157
+ const match = SHEET_QUALIFIED_REFERENCE_RE.exec(defined.refersTo);
158
+ if (match === null) throw new require_biff_write_errors.BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its refersTo ${JSON.stringify(defined.refersTo)} is not a sheet-qualified cell or range reference, the one vocabulary this writer compiles for a name`);
159
+ const sheetName = unquoteSheetLabel(match[1] ?? "");
160
+ const sheetIndex = sheets.findIndex((sheet) => sheet.name === sheetName);
161
+ if (sheetIndex === -1) throw new require_biff_write_errors.BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its refersTo names the sheet ${JSON.stringify(sheetName)}, which the document's own sheets do not carry`);
162
+ const [firstText, lastText] = (match[2] ?? "").split(":");
163
+ const first = parseCorner(firstText ?? "");
164
+ const last = lastText === void 0 ? first : parseCorner(lastText);
165
+ if (first === void 0 || last === void 0) throw new require_biff_write_errors.BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its refersTo ${JSON.stringify(defined.refersTo)} does not name an A1-style reference this writer can compile`);
166
+ if (first.row > MAX_ROW_INDEX || last.row > MAX_ROW_INDEX || first.column > MAX_COLUMN_INDEX || last.column > MAX_COLUMN_INDEX) throw new require_biff_write_errors.BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its refersTo ${JSON.stringify(defined.refersTo)} reaches outside BIFF8's own grid (rows 0-${MAX_ROW_INDEX}, columns 0-${MAX_COLUMN_INDEX})`);
167
+ return {
168
+ sheetIndex,
169
+ rgce: writeArea3dToken(sheetIndex, first, last)
170
+ };
171
+ }
172
+ /** One Lbl record ([MS-XLS] 2.4.150) for a planned defined name, the write-side mirror of readLblRecord above: grbit carries only fBuiltin when it is set, the Name is a compressed single character for a built-in and a real XLUnicodeStringNoCch otherwise, and itab restates the entry's scope one-based. */
173
+ function writeDefinedNameRecord(entry) {
174
+ const nameBytes = entry.builtinName === void 0 ? require_biff_string_writer.writeXLUnicodeStringNoCch(entry.name) : new require_biff_builder.RecordBuilder().u8(0).u8(entry.builtinName).build();
175
+ const data = new require_biff_builder.RecordBuilder().u16(entry.builtinName === void 0 ? 0 : LBL_FLAG_BUILTIN).u8(0).u8(entry.builtinName === void 0 ? entry.name.length : 1).u16(entry.rgce.length).u16(0).u16(entry.sheetIndex === void 0 ? 0 : entry.sheetIndex + 1).u32(0).bytes(nameBytes).bytes(entry.rgce).build();
176
+ return require_biff_record_writer.writeRecord(24, data);
177
+ }
178
+ /** Every planned defined name as its own Lbl record, in the order given. */
179
+ function writeDefinedNameRecords(entries) {
180
+ return entries.map(writeDefinedNameRecord);
181
+ }
182
+ //#endregion
183
+ exports.definedNameEntriesFor = definedNameEntriesFor;
184
+ exports.readDefinedNames = readDefinedNames;
185
+ exports.writeDefinedNameRecord = writeDefinedNameRecord;
186
+ exports.writeDefinedNameRecords = writeDefinedNameRecords;
@@ -0,0 +1,2 @@
1
+ import { a as writeDefinedNameRecord, i as readDefinedNames, n as RawDefinedName, o as writeDefinedNameRecords, r as definedNameEntriesFor, t as DefinedNamePlanEntry } from "../defined-names-CqBJJmOJ.cjs";
2
+ export { DefinedNamePlanEntry, RawDefinedName, definedNameEntriesFor, readDefinedNames, writeDefinedNameRecord, writeDefinedNameRecords };
@@ -0,0 +1,2 @@
1
+ import { a as writeDefinedNameRecord, i as readDefinedNames, n as RawDefinedName, o as writeDefinedNameRecords, r as definedNameEntriesFor, t as DefinedNamePlanEntry } from "../defined-names-DJZ27hRp.js";
2
+ export { DefinedNamePlanEntry, RawDefinedName, definedNameEntriesFor, readDefinedNames, writeDefinedNameRecord, writeDefinedNameRecords };
@@ -0,0 +1,182 @@
1
+ import "../biff/record-types.js";
2
+ import { BiffFormatError } from "../biff/records.js";
3
+ import { RecordBuilder } from "../biff/builder.js";
4
+ import { BlockCursor } from "../biff/cursor.js";
5
+ import { BiffWriteError } from "../biff/write-errors.js";
6
+ import { writeRecord } from "../biff/record-writer.js";
7
+ import { readXLUnicodeStringNoCch } from "../biff/strings.js";
8
+ import { parseFormulaText } from "../biff/ptg.js";
9
+ import { writeXLUnicodeStringNoCch } from "../biff/string-writer.js";
10
+ import { columnLettersToIndex } from "document-schema.js";
11
+ //#region src/workbook/defined-names.ts
12
+ /** Lbl.grbit's fBuiltin bit -- field F of [MS-XLS] 2.4.150's own grbit layout. */
13
+ const LBL_FLAG_BUILTIN = 32;
14
+ /** [MS-XLS] 2.4.150's own built-in name table: the index a built-in name's single-character Name field carries, and the name it spells. The `_xlnm.` prefix is ECMA-376's own reserved spelling for the identical names in an xlsx (the two print ones confirmed against real LibreOffice-written markup in ooxml.js's own fixture), so a built-in rides through the shared schema under the spelling every other member of this format family already uses for it. */
15
+ const BUILTIN_NAME_SPELLINGS = [
16
+ "_xlnm.Consolidate_Area",
17
+ "_xlnm.Auto_Open",
18
+ "_xlnm.Auto_Close",
19
+ "_xlnm.Extract",
20
+ "_xlnm.Database",
21
+ "_xlnm.Criteria",
22
+ "_xlnm.Print_Area",
23
+ "_xlnm.Print_Titles",
24
+ "_xlnm.Recorder",
25
+ "_xlnm.Data_Form",
26
+ "_xlnm.Auto_Activate",
27
+ "_xlnm.Auto_Deactivate",
28
+ "_xlnm.Sheet_Title",
29
+ "_xlnm._FilterDatabase"
30
+ ];
31
+ /** The two built-in names print-names.ts owns end to end: read there onto ContentSheetPrintSettings, written there from them, and therefore skipped here rather than stated twice. */
32
+ const BUILTIN_NAME_PRINT_AREA = 6;
33
+ const BUILTIN_NAME_PRINT_TITLES = 7;
34
+ /** The `_xlnm.` prefix ECMA-376 reserves for built-in defined names, which is also the spelling this package reads them under -- so a name carrying it on write resolves back through the built-in table below, and one the table does not know is refused rather than written as a user name Excel itself forbids the prefix for. */
35
+ const XLNM_PREFIX = "_xlnm.";
36
+ /**
37
+ * Reads every Lbl record in a globals substream into a defined name, or skips it: the two print built-ins (print-names.ts owns them), a built-in index past the table above (no spelling to give it), a name whose rgce resolves to no formula text (a construct outside parseFormulaText's vocabulary, or a stream too malformed to walk -- ContentDefinedNameSchema requires refersTo, and a fabricated placeholder is not formula text), and a record whose own bytes overrun (caught per record rather than letting one malformed Lbl abort every other name, the identical per-record boundary sheet.ts's resolveFormulaText draws for a malformed cell formula).
38
+ */
39
+ function readDefinedNames(records, formulaSheets) {
40
+ const names = [];
41
+ for (const record of records) {
42
+ if (record.type !== 24) continue;
43
+ const parsed = readLblRecord(record, formulaSheets);
44
+ if (parsed !== void 0) names.push(parsed);
45
+ }
46
+ return names;
47
+ }
48
+ /** Lbl ([MS-XLS] 2.4.150): grbit, chKey, cch, cce, reserved3, itab, four reserved bytes, the Name as an XLUnicodeStringNoCch, then cce bytes of rgce (NameParsedFormula) and whatever rgcb trailer follows. */
49
+ function readLblRecord(record, formulaSheets) {
50
+ try {
51
+ const cursor = new BlockCursor(record.blocks);
52
+ const isBuiltin = (cursor.u16() & LBL_FLAG_BUILTIN) !== 0;
53
+ cursor.skip(1);
54
+ const cch = cursor.u8();
55
+ const cce = cursor.u16();
56
+ cursor.skip(2);
57
+ const itab = cursor.u16();
58
+ cursor.skip(4);
59
+ let name;
60
+ if (isBuiltin) {
61
+ const highByte = (cursor.u8() & 1) !== 0;
62
+ if (cch !== 1 || highByte) return;
63
+ const builtinIndex = cursor.u8();
64
+ if (builtinIndex === BUILTIN_NAME_PRINT_AREA || builtinIndex === BUILTIN_NAME_PRINT_TITLES) return;
65
+ const spelling = BUILTIN_NAME_SPELLINGS[builtinIndex];
66
+ if (spelling === void 0) return;
67
+ name = spelling;
68
+ } else name = readXLUnicodeStringNoCch(cursor, cch);
69
+ const rgce = cursor.take(cce);
70
+ const rgcb = cursor.take(cursor.remainingInBlock());
71
+ const refersTo = parseFormulaText(rgce, formulaSheets, { rgcb });
72
+ return refersTo === void 0 ? void 0 : {
73
+ name,
74
+ refersTo,
75
+ sheetIndex: itab === 0 ? void 0 : itab - 1
76
+ };
77
+ } catch (error) {
78
+ if (!(error instanceof BiffFormatError)) throw error;
79
+ return;
80
+ }
81
+ }
82
+ /** The reverse of BUILTIN_NAME_SPELLINGS: an _xlnm spelling back to the built-in index a single-character Name field would carry. */
83
+ const BUILTIN_INDEX_BY_NAME = new Map(BUILTIN_NAME_SPELLINGS.map((spelling, index) => [spelling, index]));
84
+ /** A single A1-style corner, with or without its $ markers -- the identical shape biff/ptg.ts's own formatPoint produces, parsed back the other way. A `$` is honoured per coordinate rather than normalised away, because a relative coordinate in a defined name is genuine, retypeable formula semantics Excel re-interprets against the name's own scope, not a display detail. */
85
+ const REFERENCE_CORNER_RE = /^(\$?)([A-Za-z]{1,3})(\$?)([0-9]{1,5})$/;
86
+ /** A full refersTo this writer can compile: one sheet-qualified corner or corner pair, nothing more. */
87
+ const SHEET_QUALIFIED_REFERENCE_RE = /^(.*)!((?:\$?[A-Za-z]{1,3}\$?[0-9]{1,5})(?::(?:\$?[A-Za-z]{1,3}\$?[0-9]{1,5}))?)$/;
88
+ /** A user-defined name shaped like a cell reference ("A1", "$B$2", "A1:B2") is forbidden by [MS-XLS] 2.5.295's own name restrictions, since a formula using it would be indistinguishable from the reference itself. */
89
+ const CELL_REFERENCE_NAME_RE = /^\$?[A-Za-z]{1,3}\$?[0-9]{1,5}(:\$?[A-Za-z]{1,3}\$?[0-9]{1,5})?$/;
90
+ function parseCorner(text) {
91
+ const match = REFERENCE_CORNER_RE.exec(text);
92
+ if (match === null) return;
93
+ const column = columnLettersToIndex(match[2] ?? "");
94
+ const row = Number.parseInt(match[4] ?? "", 10) - 1;
95
+ if (column === void 0 || row < 0) return;
96
+ return {
97
+ row,
98
+ column,
99
+ columnAbsolute: (match[1] ?? "") === "$",
100
+ rowAbsolute: (match[3] ?? "") === "$"
101
+ };
102
+ }
103
+ /** BIFF8's own grid ceilings, which a defined name's reference shares with every other reference in the format. */
104
+ const MAX_ROW_INDEX = 65535;
105
+ const MAX_COLUMN_INDEX = 255;
106
+ /** ColRelU's own relative bits ([MS-XLS] 2.5.198.105): bit 14 (0x4000) says the COLUMN coordinate is relative, bit 15 (0x8000) the ROW -- clear means absolute, exactly as biff/ptg.ts's pointFrom decodes them on read. */
107
+ const COLUMN_RELATIVE_BIT = 16384;
108
+ const ROW_RELATIVE_BIT = 32768;
109
+ /** PtgArea3d, reference class ([MS-XLS] 2.5.198.28): opcode 0x3b, the ixti, then an RgceArea -- the same token write-side print-names.ts builds for a print name's range, since a defined name has no other way to say which sheet its reference is on. */
110
+ function writeArea3dToken(ixti, first, last) {
111
+ const columnFieldOf = (corner) => corner.column | (corner.columnAbsolute ? 0 : COLUMN_RELATIVE_BIT) | (corner.rowAbsolute ? 0 : ROW_RELATIVE_BIT);
112
+ return new RecordBuilder().u8(59).u16(ixti).u16(first.row).u16(last.row).u16(columnFieldOf(first)).u16(columnFieldOf(last)).build();
113
+ }
114
+ /** Strips the single-quote wrapping a sheet label carries when the sheet name is not a bare identifier, unescaping the doubled quote inside -- the inverse of biff/ptg.ts's quoteSheetLabel. A string must actually be quoted on both ends to unwrap; a bare name is taken verbatim. */
115
+ function unquoteSheetLabel(label) {
116
+ if (label.startsWith("'") && label.endsWith("'") && label.length >= 2) return label.slice(1, -1).replaceAll("''", "'");
117
+ return label;
118
+ }
119
+ /**
120
+ * Compiles the document's defined names into the Lbl records the workbook stream carries.
121
+ *
122
+ * The refersTo vocabulary this writer can compile is exactly one sheet-qualified A1 reference -- `Sheet1!$A$1`, `Sheet1!$A$1:$B$2`, the sheet name quoted when it is not a bare identifier -- which is the shape every named range carries and the shape this package's own reader produces for one. A refersTo outside that vocabulary (a computed formula, a constant, an external-workbook reference) throws a BiffWriteError naming the construct rather than emitting a token stream this writer cannot prove round-trips, the identical refusal the cell-formula writer draws for the constructs outside its own vocabulary.
123
+ */
124
+ function definedNameEntriesFor(names, sheets) {
125
+ return names.map((defined) => {
126
+ const builtinName = defined.name.startsWith(XLNM_PREFIX) ? builtinIndexOf(defined.name) : void 0;
127
+ if (builtinName === void 0) validateUserName(defined.name);
128
+ return {
129
+ name: defined.name,
130
+ builtinName,
131
+ sheetIndex: scopeOf(defined, sheets.length),
132
+ rgce: compileRefersTo(defined, sheets).rgce
133
+ };
134
+ });
135
+ }
136
+ /** Resolves an _xlnm spelling to its built-in index, refusing the two print built-ins (print-names.ts owns them -- a document stating its print area as a names entry is stating a fact the print settings already carry, and writing both would emit the same Lbl record twice) and any spelling the table does not know. */
137
+ function builtinIndexOf(name) {
138
+ const index = BUILTIN_INDEX_BY_NAME.get(name);
139
+ if (index === void 0) throw new BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(name)}: the "_xlnm." prefix is reserved for built-in names, and this one is not in [MS-XLS] 2.4.150's own built-in name table`);
140
+ if (index === BUILTIN_NAME_PRINT_AREA || index === BUILTIN_NAME_PRINT_TITLES) throw new BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(name)}: the print built-ins are print-settings facts, stated through a sheet's printSettings (printRange/repeatRows/repeatColumns) rather than as document-level names -- writing both would emit the same Lbl record twice`);
141
+ return index;
142
+ }
143
+ /** A user-defined name must fit the record's own one-byte cch and must not be shaped like a cell reference, the one restriction of [MS-XLS] 2.5.295's own name grammar a writer can enforce without guessing at Excel's full validity table. */
144
+ function validateUserName(name) {
145
+ if (name.length < 1 || name.length > 255) throw new BiffWriteError(`xls-codec cannot write a defined name of ${name.length} characters: Lbl's own cch field is one byte, so a name must be 1-255 UTF-16 code units`);
146
+ if (CELL_REFERENCE_NAME_RE.test(name)) throw new BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(name)}: a name shaped like a cell reference is forbidden, since a formula using it would be indistinguishable from the reference itself`);
147
+ }
148
+ /** A scopeSheetIndex past the end of the document's own sheets array names a sheet that does not exist, so it is refused rather than written as an itab no BoundSheet8 answers to. */
149
+ function scopeOf(defined, sheetCount) {
150
+ if (defined.scopeSheetIndex === void 0) return;
151
+ if (defined.scopeSheetIndex >= sheetCount) throw new BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its scopeSheetIndex ${defined.scopeSheetIndex} is past the end of the document's own ${sheetCount}-sheet array`);
152
+ return defined.scopeSheetIndex;
153
+ }
154
+ /** Parses and compiles one entry's refersTo, throwing for anything outside the single sheet-qualified reference vocabulary documented on definedNameEntriesFor. */
155
+ function compileRefersTo(defined, sheets) {
156
+ const match = SHEET_QUALIFIED_REFERENCE_RE.exec(defined.refersTo);
157
+ if (match === null) throw new BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its refersTo ${JSON.stringify(defined.refersTo)} is not a sheet-qualified cell or range reference, the one vocabulary this writer compiles for a name`);
158
+ const sheetName = unquoteSheetLabel(match[1] ?? "");
159
+ const sheetIndex = sheets.findIndex((sheet) => sheet.name === sheetName);
160
+ if (sheetIndex === -1) throw new BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its refersTo names the sheet ${JSON.stringify(sheetName)}, which the document's own sheets do not carry`);
161
+ const [firstText, lastText] = (match[2] ?? "").split(":");
162
+ const first = parseCorner(firstText ?? "");
163
+ const last = lastText === void 0 ? first : parseCorner(lastText);
164
+ if (first === void 0 || last === void 0) throw new BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its refersTo ${JSON.stringify(defined.refersTo)} does not name an A1-style reference this writer can compile`);
165
+ if (first.row > MAX_ROW_INDEX || last.row > MAX_ROW_INDEX || first.column > MAX_COLUMN_INDEX || last.column > MAX_COLUMN_INDEX) throw new BiffWriteError(`xls-codec cannot write the defined name ${JSON.stringify(defined.name)}: its refersTo ${JSON.stringify(defined.refersTo)} reaches outside BIFF8's own grid (rows 0-${MAX_ROW_INDEX}, columns 0-${MAX_COLUMN_INDEX})`);
166
+ return {
167
+ sheetIndex,
168
+ rgce: writeArea3dToken(sheetIndex, first, last)
169
+ };
170
+ }
171
+ /** One Lbl record ([MS-XLS] 2.4.150) for a planned defined name, the write-side mirror of readLblRecord above: grbit carries only fBuiltin when it is set, the Name is a compressed single character for a built-in and a real XLUnicodeStringNoCch otherwise, and itab restates the entry's scope one-based. */
172
+ function writeDefinedNameRecord(entry) {
173
+ const nameBytes = entry.builtinName === void 0 ? writeXLUnicodeStringNoCch(entry.name) : new RecordBuilder().u8(0).u8(entry.builtinName).build();
174
+ const data = new RecordBuilder().u16(entry.builtinName === void 0 ? 0 : LBL_FLAG_BUILTIN).u8(0).u8(entry.builtinName === void 0 ? entry.name.length : 1).u16(entry.rgce.length).u16(0).u16(entry.sheetIndex === void 0 ? 0 : entry.sheetIndex + 1).u32(0).bytes(nameBytes).bytes(entry.rgce).build();
175
+ return writeRecord(24, data);
176
+ }
177
+ /** Every planned defined name as its own Lbl record, in the order given. */
178
+ function writeDefinedNameRecords(entries) {
179
+ return entries.map(writeDefinedNameRecord);
180
+ }
181
+ //#endregion
182
+ export { definedNameEntriesFor, readDefinedNames, writeDefinedNameRecord, writeDefinedNameRecords };
@@ -1,5 +1,5 @@
1
- import { r as FormulaSheetContext } from "../ptg-75v7MhaA.cjs";
2
1
  import { n as Substream, t as RecordGroup } from "../substreams-XDNgDvRJ.cjs";
2
+ import { r as FormulaSheetContext } from "../ptg-75v7MhaA.cjs";
3
3
  import { BlipImage } from "../drawing/blips.cjs";
4
4
  import { RawColumn, RawRow } from "./sheet.cjs";
5
5
  import { ContentEmbeddedObject, ContentSheetCell, ContentSheetImage, LayoutMetadata } from "document-schema.js";
@@ -1,5 +1,5 @@
1
- import { r as FormulaSheetContext } from "../ptg-75v7MhaA.js";
2
1
  import { n as Substream, t as RecordGroup } from "../substreams-CgTHx5kX.js";
2
+ import { r as FormulaSheetContext } from "../ptg-75v7MhaA.js";
3
3
  import { BlipImage } from "../drawing/blips.js";
4
4
  import { RawColumn, RawRow } from "./sheet.js";
5
5
  import { ContentEmbeddedObject, ContentSheetCell, ContentSheetImage, LayoutMetadata } from "document-schema.js";
@@ -2,16 +2,15 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_biff_record_types = require("../biff/record-types.cjs");
3
3
  const require_biff_builder = require("../biff/builder.cjs");
4
4
  const require_biff_record_writer = require("../biff/record-writer.cjs");
5
+ const require_biff_font = require("../biff/font.cjs");
6
+ const require_biff_string_writer = require("../biff/string-writer.cjs");
7
+ const require_workbook_defined_names = require("./defined-names.cjs");
5
8
  const require_workbook_print_names = require("./print-names.cjs");
6
9
  const require_biff_bof_writer = require("../biff/bof-writer.cjs");
7
- const require_biff_string_writer = require("../biff/string-writer.cjs");
8
10
  const require_biff_xf_writer = require("../biff/xf-writer.cjs");
9
11
  //#region src/workbook/globals-writer.ts
10
12
  const GENERAL_FORMAT_ID = 0;
11
13
  const NORMAL_FONT_INDEX = 0;
12
- const NORMAL_FONT_NAME = "Arial";
13
- /** Excel 97-2003's own Normal-style default: 10pt, in twips (dyHeight's own unit, [MS-XLS] 2.4.122). */
14
- const NORMAL_FONT_HEIGHT_TWIPS = 200;
15
14
  /** [MS-XLS] "BuiltInStyle" istyBuiltIn values (ECMA-376 Part 1 18.8.7's cellStyle builtinId table): 0 Normal, 1 RowLevel, 2 ColLevel -- the only three this writer emits, since it never groups rows/columns into an outline. */
16
15
  const BUILTIN_STYLE_NORMAL = 0;
17
16
  const BUILTIN_STYLE_ROW_LEVEL = 1;
@@ -72,7 +71,7 @@ function buildWorkbookGlobals(plan) {
72
71
  offset += piece.length;
73
72
  };
74
73
  push(require_biff_record_writer.writeRecord(require_biff_record_types.RECORD_BOF, require_biff_bof_writer.writeBofData(5)));
75
- push(require_biff_xf_writer.writeFontRecord(NORMAL_FONT_NAME, NORMAL_FONT_HEIGHT_TWIPS));
74
+ for (const fields of plan.fonts) push(require_biff_font.writeFontRecord(fields));
76
75
  for (const code of plan.customFormats) push(require_biff_xf_writer.writeFormatRecord(code.id, code.code));
77
76
  BUILTIN_STYLES.forEach(() => {
78
77
  push(require_biff_xf_writer.writeStyleXfRecord({
@@ -85,7 +84,7 @@ function buildWorkbookGlobals(plan) {
85
84
  formatId: GENERAL_FORMAT_ID
86
85
  }));
87
86
  for (const entry of plan.cellXfEntries) push(require_biff_xf_writer.writeCellXfRecord({
88
- fontIndex: NORMAL_FONT_INDEX,
87
+ fontIndex: entry.fontIndex,
89
88
  formatId: entry.formatId,
90
89
  alignment: entry.alignment,
91
90
  verticalAlignment: entry.verticalAlignment,
@@ -105,10 +104,11 @@ function buildWorkbookGlobals(plan) {
105
104
  lbPlyPosOffsets.push(recordStart + 4);
106
105
  push(writeBoundSheet8Placeholder(name));
107
106
  }
108
- if (plan.printNames.length > 0) {
107
+ if (plan.printNames.length > 0 || plan.definedNames.length > 0) {
109
108
  push(writeSupBookRecord(plan.sheetNames.length));
110
109
  push(writeExternSheetRecord(plan.sheetNames.length));
111
110
  for (const record of require_workbook_print_names.writePrintNameRecords(plan.printNames)) push(record);
111
+ for (const record of require_workbook_defined_names.writeDefinedNameRecords(plan.definedNames)) push(record);
112
112
  }
113
113
  if (plan.sharedStrings.length > 0) push(writeSstRecord(plan.sharedStrings, plan.sharedStringTotalCount));
114
114
  push(require_biff_record_writer.writeRecord(10, /* @__PURE__ */ new Uint8Array(0)));
@@ -1,18 +1,23 @@
1
+ import { r as XfFontFields } from "../font-CBvAGxD8.cjs";
1
2
  import { E as XfDecorationFields } from "../xf-colors-aeH9Ax3Q.cjs";
2
3
  import { t as PrintNamePlanEntry } from "../print-names-B2OR0fvs.cjs";
4
+ import { t as DefinedNamePlanEntry } from "../defined-names-CqBJJmOJ.cjs";
3
5
  import { Alignment, Color } from "document-schema.js";
4
6
  //#region src/workbook/globals-writer.d.ts
5
7
  /** [MS-XLS] 2.1.7.20.3's own XFS production requires at least sixteen XF records before any cell can reference one: BUILTIN_STYLES.length built-in cell styles, then at least one cell XF -- the "General, no declared format" one every workbook needs unconditionally, written immediately after them. Derived from BUILTIN_STYLES's own length rather than restated as a literal, so the two can never drift apart. */
6
8
  declare const GENERAL_CELL_XF_INDEX: number;
7
- /** One cell XF beyond the implicit General one at GENERAL_CELL_XF_INDEX: the number-format identifier it displays through, the cell's own horizontal/vertical alignment (general/bottom, this writer's own defaults, when omitted), and -- when the cell it serves carries a background or borders -- the fill/border fields its CellXF payload packs. Undefined decoration writes the same undecorated defaults this writer always wrote before decoration existed. */
9
+ /** One cell XF beyond the implicit General one at GENERAL_CELL_XF_INDEX: the number-format identifier it displays through, the font-table index its cell's own font resolves to (0, the Normal font, for a cell stating none), the cell's own horizontal/vertical alignment (general/bottom, this writer's own defaults, when omitted), and -- when the cell it serves carries a background or borders -- the fill/border fields its CellXF payload packs. Undefined decoration writes the same undecorated defaults this writer always wrote before decoration existed. */
8
10
  interface CellXfPlanEntry {
9
11
  readonly formatId: number;
12
+ readonly fontIndex: number;
10
13
  readonly alignment?: Alignment;
11
14
  readonly verticalAlignment?: "top" | "middle" | "bottom";
12
15
  readonly decoration?: XfDecorationFields;
13
16
  }
14
17
  interface WorkbookGlobalsPlan {
15
18
  readonly sheetNames: readonly string[];
19
+ /** The workbook's font table, in the order its Font records are written: entry 0 is always the Normal font (a cell stating no font of its own references it), and every later entry is one distinct cell font the workbook's cells actually state -- write.ts's own font-interning pass assigns those. */
20
+ readonly fonts: readonly XfFontFields[];
16
21
  /** Custom number-format codes needing their own Format record, each with the identifier already assigned to it (always >= 164, [MS-XLS] 2.4.126's own custom-identifier floor). A code equal to one of the built-in table's own strings needs no Format record here -- number-format.ts's BUILTIN_NUMBER_FORMATS already covers ids 0-49 for both this package's reader and any other. */
17
22
  readonly customFormats: readonly {
18
23
  readonly id: number;
@@ -26,8 +31,10 @@ interface WorkbookGlobalsPlan {
26
31
  readonly sharedStringTotalCount: number;
27
32
  /** The workbook's own custom colour table (56 entries, icv 8 first), when write.ts's own palette-interning pass decided the workbook needs one -- undefined when every decoration colour the workbook's cells use already matches the fixed default table, in which case no Palette record is written at all and those colours resolve through the default table instead ([MS-XLS] "Icv"'s own documented fallback). */
28
33
  readonly paletteColors?: readonly Color[];
29
- /** The built-in Print_Area/Print_Titles defined names the workbook's sheets declare, one Lbl record each. Empty when no sheet declares a print range or a repeated header band, in which case no SupBook, ExternSheet, or Lbl record is written at all -- exactly like Palette above, a workbook that needs none stays as minimal as it always was. */
34
+ /** The built-in Print_Area/Print_Titles defined names the workbook's sheets declare, one Lbl record each. Empty when no sheet declares a print range or a repeated header band -- see the SupBook/ExternSheet note below for what that and `definedNames` both empty means. */
30
35
  readonly printNames: readonly PrintNamePlanEntry[];
36
+ /** The document-level defined names the workbook declares, one Lbl record each, from workbook/defined-names.ts's own compile of the document's names array. */
37
+ readonly definedNames: readonly DefinedNamePlanEntry[];
31
38
  }
32
39
  interface WorkbookGlobalsBuild {
33
40
  readonly bytes: Uint8Array<ArrayBuffer>;
@@ -1,18 +1,23 @@
1
+ import { r as XfFontFields } from "../font-DcXHYgZ2.js";
1
2
  import { E as XfDecorationFields } from "../xf-colors-kdNsiNYt.js";
2
3
  import { t as PrintNamePlanEntry } from "../print-names-BXcmmwVi.js";
4
+ import { t as DefinedNamePlanEntry } from "../defined-names-DJZ27hRp.js";
3
5
  import { Alignment, Color } from "document-schema.js";
4
6
  //#region src/workbook/globals-writer.d.ts
5
7
  /** [MS-XLS] 2.1.7.20.3's own XFS production requires at least sixteen XF records before any cell can reference one: BUILTIN_STYLES.length built-in cell styles, then at least one cell XF -- the "General, no declared format" one every workbook needs unconditionally, written immediately after them. Derived from BUILTIN_STYLES's own length rather than restated as a literal, so the two can never drift apart. */
6
8
  declare const GENERAL_CELL_XF_INDEX: number;
7
- /** One cell XF beyond the implicit General one at GENERAL_CELL_XF_INDEX: the number-format identifier it displays through, the cell's own horizontal/vertical alignment (general/bottom, this writer's own defaults, when omitted), and -- when the cell it serves carries a background or borders -- the fill/border fields its CellXF payload packs. Undefined decoration writes the same undecorated defaults this writer always wrote before decoration existed. */
9
+ /** One cell XF beyond the implicit General one at GENERAL_CELL_XF_INDEX: the number-format identifier it displays through, the font-table index its cell's own font resolves to (0, the Normal font, for a cell stating none), the cell's own horizontal/vertical alignment (general/bottom, this writer's own defaults, when omitted), and -- when the cell it serves carries a background or borders -- the fill/border fields its CellXF payload packs. Undefined decoration writes the same undecorated defaults this writer always wrote before decoration existed. */
8
10
  interface CellXfPlanEntry {
9
11
  readonly formatId: number;
12
+ readonly fontIndex: number;
10
13
  readonly alignment?: Alignment;
11
14
  readonly verticalAlignment?: "top" | "middle" | "bottom";
12
15
  readonly decoration?: XfDecorationFields;
13
16
  }
14
17
  interface WorkbookGlobalsPlan {
15
18
  readonly sheetNames: readonly string[];
19
+ /** The workbook's font table, in the order its Font records are written: entry 0 is always the Normal font (a cell stating no font of its own references it), and every later entry is one distinct cell font the workbook's cells actually state -- write.ts's own font-interning pass assigns those. */
20
+ readonly fonts: readonly XfFontFields[];
16
21
  /** Custom number-format codes needing their own Format record, each with the identifier already assigned to it (always >= 164, [MS-XLS] 2.4.126's own custom-identifier floor). A code equal to one of the built-in table's own strings needs no Format record here -- number-format.ts's BUILTIN_NUMBER_FORMATS already covers ids 0-49 for both this package's reader and any other. */
17
22
  readonly customFormats: readonly {
18
23
  readonly id: number;
@@ -26,8 +31,10 @@ interface WorkbookGlobalsPlan {
26
31
  readonly sharedStringTotalCount: number;
27
32
  /** The workbook's own custom colour table (56 entries, icv 8 first), when write.ts's own palette-interning pass decided the workbook needs one -- undefined when every decoration colour the workbook's cells use already matches the fixed default table, in which case no Palette record is written at all and those colours resolve through the default table instead ([MS-XLS] "Icv"'s own documented fallback). */
28
33
  readonly paletteColors?: readonly Color[];
29
- /** The built-in Print_Area/Print_Titles defined names the workbook's sheets declare, one Lbl record each. Empty when no sheet declares a print range or a repeated header band, in which case no SupBook, ExternSheet, or Lbl record is written at all -- exactly like Palette above, a workbook that needs none stays as minimal as it always was. */
34
+ /** The built-in Print_Area/Print_Titles defined names the workbook's sheets declare, one Lbl record each. Empty when no sheet declares a print range or a repeated header band -- see the SupBook/ExternSheet note below for what that and `definedNames` both empty means. */
30
35
  readonly printNames: readonly PrintNamePlanEntry[];
36
+ /** The document-level defined names the workbook declares, one Lbl record each, from workbook/defined-names.ts's own compile of the document's names array. */
37
+ readonly definedNames: readonly DefinedNamePlanEntry[];
31
38
  }
32
39
  interface WorkbookGlobalsBuild {
33
40
  readonly bytes: Uint8Array<ArrayBuffer>;
@@ -1,16 +1,15 @@
1
1
  import { RECORD_BOF } from "../biff/record-types.js";
2
2
  import { RecordBuilder } from "../biff/builder.js";
3
3
  import { concatRecords, writeRecord } from "../biff/record-writer.js";
4
+ import { writeFontRecord } from "../biff/font.js";
5
+ import { writeRichExtendedString, writeShortXLUnicodeString } from "../biff/string-writer.js";
6
+ import { writeDefinedNameRecords } from "./defined-names.js";
4
7
  import { writePrintNameRecords } from "./print-names.js";
5
8
  import { writeBofData } from "../biff/bof-writer.js";
6
- import { writeRichExtendedString, writeShortXLUnicodeString } from "../biff/string-writer.js";
7
- import { writeCellXfRecord, writeFontRecord, writeFormatRecord, writePaletteRecord, writeStyleRecord, writeStyleXfRecord } from "../biff/xf-writer.js";
9
+ import { writeCellXfRecord, writeFormatRecord, writePaletteRecord, writeStyleRecord, writeStyleXfRecord } from "../biff/xf-writer.js";
8
10
  //#region src/workbook/globals-writer.ts
9
11
  const GENERAL_FORMAT_ID = 0;
10
12
  const NORMAL_FONT_INDEX = 0;
11
- const NORMAL_FONT_NAME = "Arial";
12
- /** Excel 97-2003's own Normal-style default: 10pt, in twips (dyHeight's own unit, [MS-XLS] 2.4.122). */
13
- const NORMAL_FONT_HEIGHT_TWIPS = 200;
14
13
  /** [MS-XLS] "BuiltInStyle" istyBuiltIn values (ECMA-376 Part 1 18.8.7's cellStyle builtinId table): 0 Normal, 1 RowLevel, 2 ColLevel -- the only three this writer emits, since it never groups rows/columns into an outline. */
15
14
  const BUILTIN_STYLE_NORMAL = 0;
16
15
  const BUILTIN_STYLE_ROW_LEVEL = 1;
@@ -71,7 +70,7 @@ function buildWorkbookGlobals(plan) {
71
70
  offset += piece.length;
72
71
  };
73
72
  push(writeRecord(RECORD_BOF, writeBofData(5)));
74
- push(writeFontRecord(NORMAL_FONT_NAME, NORMAL_FONT_HEIGHT_TWIPS));
73
+ for (const fields of plan.fonts) push(writeFontRecord(fields));
75
74
  for (const code of plan.customFormats) push(writeFormatRecord(code.id, code.code));
76
75
  BUILTIN_STYLES.forEach(() => {
77
76
  push(writeStyleXfRecord({
@@ -84,7 +83,7 @@ function buildWorkbookGlobals(plan) {
84
83
  formatId: GENERAL_FORMAT_ID
85
84
  }));
86
85
  for (const entry of plan.cellXfEntries) push(writeCellXfRecord({
87
- fontIndex: NORMAL_FONT_INDEX,
86
+ fontIndex: entry.fontIndex,
88
87
  formatId: entry.formatId,
89
88
  alignment: entry.alignment,
90
89
  verticalAlignment: entry.verticalAlignment,
@@ -104,10 +103,11 @@ function buildWorkbookGlobals(plan) {
104
103
  lbPlyPosOffsets.push(recordStart + 4);
105
104
  push(writeBoundSheet8Placeholder(name));
106
105
  }
107
- if (plan.printNames.length > 0) {
106
+ if (plan.printNames.length > 0 || plan.definedNames.length > 0) {
108
107
  push(writeSupBookRecord(plan.sheetNames.length));
109
108
  push(writeExternSheetRecord(plan.sheetNames.length));
110
109
  for (const record of writePrintNameRecords(plan.printNames)) push(record);
110
+ for (const record of writeDefinedNameRecords(plan.definedNames)) push(record);
111
111
  }
112
112
  if (plan.sharedStrings.length > 0) push(writeSstRecord(plan.sharedStrings, plan.sharedStringTotalCount));
113
113
  push(writeRecord(10, /* @__PURE__ */ new Uint8Array(0)));