xls-codec 4.9.0 → 4.11.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.
- package/README.md +43 -19
- package/dist/biff/ptg-functions.cjs +3 -0
- package/dist/biff/ptg-functions.d.cts +3 -1
- package/dist/biff/ptg-functions.d.ts +3 -1
- package/dist/biff/ptg-functions.js +3 -1
- package/dist/biff/ptg-writer.cjs +546 -0
- package/dist/biff/ptg-writer.d.cts +7 -0
- package/dist/biff/ptg-writer.d.ts +7 -0
- package/dist/biff/ptg-writer.js +545 -0
- package/dist/biff/string-writer.cjs +6 -0
- package/dist/biff/string-writer.d.cts +3 -1
- package/dist/biff/string-writer.d.ts +3 -1
- package/dist/biff/string-writer.js +6 -1
- package/dist/content.cjs +1 -1
- package/dist/content.d.cts +1 -1
- package/dist/content.d.ts +1 -1
- package/dist/content.js +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/workbook/comment-writer.cjs +75 -0
- package/dist/workbook/comment-writer.d.cts +10 -0
- package/dist/workbook/comment-writer.d.ts +10 -0
- package/dist/workbook/comment-writer.js +74 -0
- package/dist/workbook/encryption.cjs +67 -20
- package/dist/workbook/encryption.d.cts +2 -2
- package/dist/workbook/encryption.d.ts +2 -2
- package/dist/workbook/encryption.js +68 -21
- package/dist/workbook/sheet-writer.cjs +50 -2
- package/dist/workbook/sheet-writer.d.cts +1 -1
- package/dist/workbook/sheet-writer.d.ts +1 -1
- package/dist/workbook/sheet-writer.js +50 -2
- package/dist/written-cells.cjs +3 -3
- package/dist/written-cells.d.cts +2 -2
- package/dist/written-cells.d.ts +2 -2
- package/dist/written-cells.js +3 -3
- package/package.json +2 -2
|
@@ -8,8 +8,11 @@ const require_serial = require("../serial.cjs");
|
|
|
8
8
|
const require_biff_builder = require("../biff/builder.cjs");
|
|
9
9
|
const require_biff_record_writer = require("../biff/record-writer.cjs");
|
|
10
10
|
const require_biff_bof_writer = require("../biff/bof-writer.cjs");
|
|
11
|
+
const require_biff_string_writer = require("../biff/string-writer.cjs");
|
|
11
12
|
const require_workbook_globals_writer = require("./globals-writer.cjs");
|
|
13
|
+
const require_biff_ptg_writer = require("../biff/ptg-writer.cjs");
|
|
12
14
|
const require_written_cells = require("../written-cells.cjs");
|
|
15
|
+
const require_workbook_comment_writer = require("./comment-writer.cjs");
|
|
13
16
|
//#region src/workbook/sheet-writer.ts
|
|
14
17
|
/** BIFF8's own 16-bit row index and 8-bit column index ceilings ([MS-XLS] 2.4.221's Rw structure and 2.4.53's Col256U structure): 65536 rows (0-65535), 256 columns (0-255) -- unlike xlsx's much larger grid. A cell outside this range cannot be expressed in BIFF8 at all, so it is refused rather than silently truncated into a wrapped index. */
|
|
15
18
|
const MAX_ROW_INDEX = 65535;
|
|
@@ -241,7 +244,50 @@ function writeCellValueRecord(cell, xfIndex, ctx) {
|
|
|
241
244
|
return require_biff_record_writer.writeRecord(513, cellHeader(cell, xfIndex).build());
|
|
242
245
|
}
|
|
243
246
|
}
|
|
244
|
-
/**
|
|
247
|
+
/** [MS-XLS] 2.4.127's own FormulaValue tag vocabulary, restated here from workbook/sheet.ts's own read-side constants (not shared across the read/write boundary, matching this package's existing per-direction module convention): a cached result that is not a plain number tags byte 6-7 as 0xFFFF and names its own kind in byte 0. */
|
|
248
|
+
const FORMULA_VALUE_TAGGED = 65535;
|
|
249
|
+
const FORMULA_VALUE_STRING = 0;
|
|
250
|
+
const FORMULA_VALUE_BOOLEAN = 1;
|
|
251
|
+
const FORMULA_VALUE_ERROR = 2;
|
|
252
|
+
/** The 8-byte FormulaValue field for a cached result that is not a plain number: byte 0 names which of string/boolean/error it is, byte 2 carries a boolean's own 0/1 or an error's own BIFF8 code, and the trailing u16 is the FORMULA_VALUE_TAGGED marker every reader checks for before trusting the field as a literal IEEE 754 double. */
|
|
253
|
+
function taggedFormulaValueBytes(tag, valueByte) {
|
|
254
|
+
return new require_biff_builder.RecordBuilder().u8(tag).u8(0).u8(valueByte).u8(0).u16(0).u16(FORMULA_VALUE_TAGGED).build();
|
|
255
|
+
}
|
|
256
|
+
/** The Formula record's own 8-byte FormulaValue field for `cell.value` -- a plain little-endian f64 of the cell's own numeric/temporal serial for every numeric-shaped kind, or one of the tagged shapes above for a string, boolean, or error result. `empty` has no BIFF8 encoding that this package's own reader reads back as `empty` (a tagged-blank result reads back as an empty STRING, not an empty cell -- see workbook/sheet.ts's own taggedFormulaValue), so a formula whose value resolves to `empty` is refused outright rather than written as something the round trip would silently change the kind of. */
|
|
257
|
+
function formulaValueBytes(cell) {
|
|
258
|
+
const value = cell.value;
|
|
259
|
+
switch (value.kind) {
|
|
260
|
+
case "number":
|
|
261
|
+
case "percentage":
|
|
262
|
+
case "currency": return new require_biff_builder.RecordBuilder().f64(value.value).build();
|
|
263
|
+
case "date": return new require_biff_builder.RecordBuilder().f64(require_serial.isoDateToSerial(value.value, false)).build();
|
|
264
|
+
case "time": return new require_biff_builder.RecordBuilder().f64(require_serial.isoTimeToSerial(value.value)).build();
|
|
265
|
+
case "dateTime": return new require_biff_builder.RecordBuilder().f64(require_serial.isoDateTimeToSerial(value.value, false)).build();
|
|
266
|
+
case "boolean": return taggedFormulaValueBytes(FORMULA_VALUE_BOOLEAN, value.value ? 1 : 0);
|
|
267
|
+
case "error": {
|
|
268
|
+
const code = require_biff_errors.errorCodeOf(value.value);
|
|
269
|
+
if (code === void 0) throw new require_biff_write_errors.BiffWriteError(`cell at row ${cell.row}, column ${cell.column} carries a formula whose cached result is error text ${JSON.stringify(value.value)}, which is not one of the eight error values [MS-XLS] 2.5.10 defines`);
|
|
270
|
+
return taggedFormulaValueBytes(FORMULA_VALUE_ERROR, code);
|
|
271
|
+
}
|
|
272
|
+
case "string": return taggedFormulaValueBytes(FORMULA_VALUE_STRING, 0);
|
|
273
|
+
case "empty": throw new require_biff_write_errors.BiffWriteError(`cell at row ${cell.row}, column ${cell.column} carries a formula whose value resolves to an empty cell, which this writer cannot express as a Formula record's cached result`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/** Formula ([MS-XLS] 2.4.127): a Cell, the 8-byte FormulaValue above, a flags word and a 4-byte calculation cache this writer has no data for (both written zero -- see the module comment on RECORD_CALCCOUNT and friends for the same "nothing this schema models" reasoning), then a CellParsedFormula -- a two-byte cce and that many bytes of compiled Ptg tokens from biff/ptg-writer.ts's own compileFormulaText. Never carries an RgbExtra trailer: this writer's formula compiler refuses any construct (an array-constant literal, a shared/array formula) that would need one, so cce always accounts for the whole of rgce. A string-kind result is followed by a String record ([MS-XLS] 2.4.268) carrying the cached text, exactly as workbook/sheet.ts's own reader expects to find it. */
|
|
277
|
+
function writeFormulaRecords(cell, xfIndex) {
|
|
278
|
+
const formula = cell.formula;
|
|
279
|
+
if (formula === void 0) throw new require_biff_write_errors.BiffWriteError(`internal error: writeFormulaRecords was called for the cell at row ${cell.row}, column ${cell.column}, which carries no formula`);
|
|
280
|
+
const rgce = require_biff_ptg_writer.compileFormulaText(formula);
|
|
281
|
+
const data = cellHeader(cell, xfIndex).bytes(formulaValueBytes(cell)).u16(0).u32(0).u16(rgce.length).bytes(rgce).build();
|
|
282
|
+
const records = [require_biff_record_writer.writeRecord(6, data)];
|
|
283
|
+
if (cell.value.kind === "string") records.push(require_biff_record_writer.writeRecord(519, require_biff_string_writer.writeXLUnicodeString(cell.value.value)));
|
|
284
|
+
return records;
|
|
285
|
+
}
|
|
286
|
+
/** The one or two records one cell contributes to the worksheet substream's cell table -- a Formula record (plus its String result, for a string-kind cell) when the cell carries a formula, the plain value record from writeCellValueRecord otherwise. */
|
|
287
|
+
function writeCellRecords(cell, xfIndex, ctx) {
|
|
288
|
+
return cell.formula !== void 0 ? writeFormulaRecords(cell, xfIndex) : [writeCellValueRecord(cell, xfIndex, ctx)];
|
|
289
|
+
}
|
|
290
|
+
/** Builds one worksheet's own substream: BOF, the print-settings records, Dimensions, ColInfo per column, Row + value-cell records per populated or declared row (in ascending row then column order), MergeCells if the sheet declares any, comment records for cells carrying one, EOF. */
|
|
245
291
|
function buildWorksheetSubstream(sheet, ctx) {
|
|
246
292
|
for (const cell of sheet.cells) checkedCellPosition(cell);
|
|
247
293
|
const writtenCells = sheet.cells.filter(require_written_cells.writesCellRecord);
|
|
@@ -265,11 +311,13 @@ function buildWorksheetSubstream(sheet, ctx) {
|
|
|
265
311
|
pieces.push(writeRowRecord(rowIndex, cellsInRow, declaredRows.get(rowIndex)));
|
|
266
312
|
for (const cell of cellsInRow) {
|
|
267
313
|
const xfIndex = ctx.xfIndexForCell(cell);
|
|
268
|
-
pieces.push(
|
|
314
|
+
pieces.push(...writeCellRecords(cell, xfIndex, ctx));
|
|
269
315
|
}
|
|
270
316
|
}
|
|
271
317
|
const merges = mergedRangesOf(sheet.cells);
|
|
272
318
|
if (merges.length > 0) pieces.push(writeMergeCellsRecord(merges));
|
|
319
|
+
const commentedCells = sheet.cells.filter((cell) => cell.comment !== void 0);
|
|
320
|
+
if (commentedCells.length > 0) pieces.push(...require_workbook_comment_writer.writeSheetComments(commentedCells));
|
|
273
321
|
pieces.push(require_biff_record_writer.writeRecord(10, /* @__PURE__ */ new Uint8Array(0)));
|
|
274
322
|
return require_biff_record_writer.concatRecords(...pieces);
|
|
275
323
|
}
|
|
@@ -6,7 +6,7 @@ interface SheetWriteContext {
|
|
|
6
6
|
/** The shared string table index for a string cell's own text; every string a sheet writes must already be registered in the workbook-wide table before this is called. */
|
|
7
7
|
sstIndexFor(text: string): number;
|
|
8
8
|
}
|
|
9
|
-
/** Builds one worksheet's own substream: BOF, the print-settings records, Dimensions, ColInfo per column, Row + value-cell records per populated or declared row (in ascending row then column order), MergeCells if the sheet declares any, EOF. */
|
|
9
|
+
/** Builds one worksheet's own substream: BOF, the print-settings records, Dimensions, ColInfo per column, Row + value-cell records per populated or declared row (in ascending row then column order), MergeCells if the sheet declares any, comment records for cells carrying one, EOF. */
|
|
10
10
|
declare function buildWorksheetSubstream(sheet: ContentSheet, ctx: SheetWriteContext): Uint8Array<ArrayBuffer>;
|
|
11
11
|
//#endregion
|
|
12
12
|
export { SheetWriteContext, buildWorksheetSubstream };
|
|
@@ -6,7 +6,7 @@ interface SheetWriteContext {
|
|
|
6
6
|
/** The shared string table index for a string cell's own text; every string a sheet writes must already be registered in the workbook-wide table before this is called. */
|
|
7
7
|
sstIndexFor(text: string): number;
|
|
8
8
|
}
|
|
9
|
-
/** Builds one worksheet's own substream: BOF, the print-settings records, Dimensions, ColInfo per column, Row + value-cell records per populated or declared row (in ascending row then column order), MergeCells if the sheet declares any, EOF. */
|
|
9
|
+
/** Builds one worksheet's own substream: BOF, the print-settings records, Dimensions, ColInfo per column, Row + value-cell records per populated or declared row (in ascending row then column order), MergeCells if the sheet declares any, comment records for cells carrying one, EOF. */
|
|
10
10
|
declare function buildWorksheetSubstream(sheet: ContentSheet, ctx: SheetWriteContext): Uint8Array<ArrayBuffer>;
|
|
11
11
|
//#endregion
|
|
12
12
|
export { SheetWriteContext, buildWorksheetSubstream };
|
|
@@ -7,8 +7,11 @@ import { isoDateTimeToSerial, isoDateToSerial, isoTimeToSerial } from "../serial
|
|
|
7
7
|
import { RecordBuilder } from "../biff/builder.js";
|
|
8
8
|
import { concatRecords, writeRecord } from "../biff/record-writer.js";
|
|
9
9
|
import { writeBofData } from "../biff/bof-writer.js";
|
|
10
|
+
import { writeXLUnicodeString } from "../biff/string-writer.js";
|
|
10
11
|
import { GENERAL_CELL_XF_INDEX } from "./globals-writer.js";
|
|
12
|
+
import { compileFormulaText } from "../biff/ptg-writer.js";
|
|
11
13
|
import { cellCarriesFormatting, writesCellRecord } from "../written-cells.js";
|
|
14
|
+
import { writeSheetComments } from "./comment-writer.js";
|
|
12
15
|
//#region src/workbook/sheet-writer.ts
|
|
13
16
|
/** BIFF8's own 16-bit row index and 8-bit column index ceilings ([MS-XLS] 2.4.221's Rw structure and 2.4.53's Col256U structure): 65536 rows (0-65535), 256 columns (0-255) -- unlike xlsx's much larger grid. A cell outside this range cannot be expressed in BIFF8 at all, so it is refused rather than silently truncated into a wrapped index. */
|
|
14
17
|
const MAX_ROW_INDEX = 65535;
|
|
@@ -240,7 +243,50 @@ function writeCellValueRecord(cell, xfIndex, ctx) {
|
|
|
240
243
|
return writeRecord(513, cellHeader(cell, xfIndex).build());
|
|
241
244
|
}
|
|
242
245
|
}
|
|
243
|
-
/**
|
|
246
|
+
/** [MS-XLS] 2.4.127's own FormulaValue tag vocabulary, restated here from workbook/sheet.ts's own read-side constants (not shared across the read/write boundary, matching this package's existing per-direction module convention): a cached result that is not a plain number tags byte 6-7 as 0xFFFF and names its own kind in byte 0. */
|
|
247
|
+
const FORMULA_VALUE_TAGGED = 65535;
|
|
248
|
+
const FORMULA_VALUE_STRING = 0;
|
|
249
|
+
const FORMULA_VALUE_BOOLEAN = 1;
|
|
250
|
+
const FORMULA_VALUE_ERROR = 2;
|
|
251
|
+
/** The 8-byte FormulaValue field for a cached result that is not a plain number: byte 0 names which of string/boolean/error it is, byte 2 carries a boolean's own 0/1 or an error's own BIFF8 code, and the trailing u16 is the FORMULA_VALUE_TAGGED marker every reader checks for before trusting the field as a literal IEEE 754 double. */
|
|
252
|
+
function taggedFormulaValueBytes(tag, valueByte) {
|
|
253
|
+
return new RecordBuilder().u8(tag).u8(0).u8(valueByte).u8(0).u16(0).u16(FORMULA_VALUE_TAGGED).build();
|
|
254
|
+
}
|
|
255
|
+
/** The Formula record's own 8-byte FormulaValue field for `cell.value` -- a plain little-endian f64 of the cell's own numeric/temporal serial for every numeric-shaped kind, or one of the tagged shapes above for a string, boolean, or error result. `empty` has no BIFF8 encoding that this package's own reader reads back as `empty` (a tagged-blank result reads back as an empty STRING, not an empty cell -- see workbook/sheet.ts's own taggedFormulaValue), so a formula whose value resolves to `empty` is refused outright rather than written as something the round trip would silently change the kind of. */
|
|
256
|
+
function formulaValueBytes(cell) {
|
|
257
|
+
const value = cell.value;
|
|
258
|
+
switch (value.kind) {
|
|
259
|
+
case "number":
|
|
260
|
+
case "percentage":
|
|
261
|
+
case "currency": return new RecordBuilder().f64(value.value).build();
|
|
262
|
+
case "date": return new RecordBuilder().f64(isoDateToSerial(value.value, false)).build();
|
|
263
|
+
case "time": return new RecordBuilder().f64(isoTimeToSerial(value.value)).build();
|
|
264
|
+
case "dateTime": return new RecordBuilder().f64(isoDateTimeToSerial(value.value, false)).build();
|
|
265
|
+
case "boolean": return taggedFormulaValueBytes(FORMULA_VALUE_BOOLEAN, value.value ? 1 : 0);
|
|
266
|
+
case "error": {
|
|
267
|
+
const code = errorCodeOf(value.value);
|
|
268
|
+
if (code === void 0) throw new BiffWriteError(`cell at row ${cell.row}, column ${cell.column} carries a formula whose cached result is error text ${JSON.stringify(value.value)}, which is not one of the eight error values [MS-XLS] 2.5.10 defines`);
|
|
269
|
+
return taggedFormulaValueBytes(FORMULA_VALUE_ERROR, code);
|
|
270
|
+
}
|
|
271
|
+
case "string": return taggedFormulaValueBytes(FORMULA_VALUE_STRING, 0);
|
|
272
|
+
case "empty": throw new BiffWriteError(`cell at row ${cell.row}, column ${cell.column} carries a formula whose value resolves to an empty cell, which this writer cannot express as a Formula record's cached result`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/** Formula ([MS-XLS] 2.4.127): a Cell, the 8-byte FormulaValue above, a flags word and a 4-byte calculation cache this writer has no data for (both written zero -- see the module comment on RECORD_CALCCOUNT and friends for the same "nothing this schema models" reasoning), then a CellParsedFormula -- a two-byte cce and that many bytes of compiled Ptg tokens from biff/ptg-writer.ts's own compileFormulaText. Never carries an RgbExtra trailer: this writer's formula compiler refuses any construct (an array-constant literal, a shared/array formula) that would need one, so cce always accounts for the whole of rgce. A string-kind result is followed by a String record ([MS-XLS] 2.4.268) carrying the cached text, exactly as workbook/sheet.ts's own reader expects to find it. */
|
|
276
|
+
function writeFormulaRecords(cell, xfIndex) {
|
|
277
|
+
const formula = cell.formula;
|
|
278
|
+
if (formula === void 0) throw new BiffWriteError(`internal error: writeFormulaRecords was called for the cell at row ${cell.row}, column ${cell.column}, which carries no formula`);
|
|
279
|
+
const rgce = compileFormulaText(formula);
|
|
280
|
+
const data = cellHeader(cell, xfIndex).bytes(formulaValueBytes(cell)).u16(0).u32(0).u16(rgce.length).bytes(rgce).build();
|
|
281
|
+
const records = [writeRecord(6, data)];
|
|
282
|
+
if (cell.value.kind === "string") records.push(writeRecord(519, writeXLUnicodeString(cell.value.value)));
|
|
283
|
+
return records;
|
|
284
|
+
}
|
|
285
|
+
/** The one or two records one cell contributes to the worksheet substream's cell table -- a Formula record (plus its String result, for a string-kind cell) when the cell carries a formula, the plain value record from writeCellValueRecord otherwise. */
|
|
286
|
+
function writeCellRecords(cell, xfIndex, ctx) {
|
|
287
|
+
return cell.formula !== void 0 ? writeFormulaRecords(cell, xfIndex) : [writeCellValueRecord(cell, xfIndex, ctx)];
|
|
288
|
+
}
|
|
289
|
+
/** Builds one worksheet's own substream: BOF, the print-settings records, Dimensions, ColInfo per column, Row + value-cell records per populated or declared row (in ascending row then column order), MergeCells if the sheet declares any, comment records for cells carrying one, EOF. */
|
|
244
290
|
function buildWorksheetSubstream(sheet, ctx) {
|
|
245
291
|
for (const cell of sheet.cells) checkedCellPosition(cell);
|
|
246
292
|
const writtenCells = sheet.cells.filter(writesCellRecord);
|
|
@@ -264,11 +310,13 @@ function buildWorksheetSubstream(sheet, ctx) {
|
|
|
264
310
|
pieces.push(writeRowRecord(rowIndex, cellsInRow, declaredRows.get(rowIndex)));
|
|
265
311
|
for (const cell of cellsInRow) {
|
|
266
312
|
const xfIndex = ctx.xfIndexForCell(cell);
|
|
267
|
-
pieces.push(
|
|
313
|
+
pieces.push(...writeCellRecords(cell, xfIndex, ctx));
|
|
268
314
|
}
|
|
269
315
|
}
|
|
270
316
|
const merges = mergedRangesOf(sheet.cells);
|
|
271
317
|
if (merges.length > 0) pieces.push(writeMergeCellsRecord(merges));
|
|
318
|
+
const commentedCells = sheet.cells.filter((cell) => cell.comment !== void 0);
|
|
319
|
+
if (commentedCells.length > 0) pieces.push(...writeSheetComments(commentedCells));
|
|
272
320
|
pieces.push(writeRecord(10, /* @__PURE__ */ new Uint8Array(0)));
|
|
273
321
|
return concatRecords(...pieces);
|
|
274
322
|
}
|
package/dist/written-cells.cjs
CHANGED
|
@@ -14,12 +14,12 @@ function cellCarriesFormatting(cell) {
|
|
|
14
14
|
return borders.left !== void 0 || borders.right !== void 0 || borders.top !== void 0 || borders.bottom !== void 0;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Whether the writer emits a cell record for this cell: a value record for anything carrying a value, or a Blank record for an `empty`-kind cell whose formatting is the only thing it has to say.
|
|
17
|
+
* Whether the writer emits a cell record for this cell: a value record for anything carrying a value, a Formula record for anything carrying a formula, or a Blank record for an `empty`-kind cell whose formatting is the only thing it has to say.
|
|
18
18
|
*
|
|
19
|
-
* An unformatted empty cell is written as nothing at all, which is what round-trips: content.ts's reader drops an unformatted blank cell, and a merged range's empty anchor is reconstructed from the MergeCells record alone. A formatted one is not that case -- its fill, borders, and alignment live only in the XF a cell record points at, so writing nothing for it discards them.
|
|
19
|
+
* An unformatted empty cell with no formula is written as nothing at all, which is what round-trips: content.ts's reader drops an unformatted blank cell, and a merged range's empty anchor is reconstructed from the MergeCells record alone. A formatted one is not that case -- its fill, borders, and alignment live only in the XF a cell record points at, so writing nothing for it discards them. A formula is the identical case one level up: it lives only in a Formula record, so a cell carrying one is never dropped regardless of what its own cached `value` resolves to, even where that value alone would otherwise not have earned a record.
|
|
20
20
|
*/
|
|
21
21
|
function writesCellRecord(cell) {
|
|
22
|
-
return cell.value.kind !== "empty" || cellCarriesFormatting(cell);
|
|
22
|
+
return cell.value.kind !== "empty" || cellCarriesFormatting(cell) || cell.formula !== void 0;
|
|
23
23
|
}
|
|
24
24
|
//#endregion
|
|
25
25
|
exports.cellCarriesFormatting = cellCarriesFormatting;
|
package/dist/written-cells.d.cts
CHANGED
|
@@ -7,9 +7,9 @@ import { ContentSheetCell } from "document-schema.js";
|
|
|
7
7
|
*/
|
|
8
8
|
declare function cellCarriesFormatting(cell: ContentSheetCell): boolean;
|
|
9
9
|
/**
|
|
10
|
-
* Whether the writer emits a cell record for this cell: a value record for anything carrying a value, or a Blank record for an `empty`-kind cell whose formatting is the only thing it has to say.
|
|
10
|
+
* Whether the writer emits a cell record for this cell: a value record for anything carrying a value, a Formula record for anything carrying a formula, or a Blank record for an `empty`-kind cell whose formatting is the only thing it has to say.
|
|
11
11
|
*
|
|
12
|
-
* An unformatted empty cell is written as nothing at all, which is what round-trips: content.ts's reader drops an unformatted blank cell, and a merged range's empty anchor is reconstructed from the MergeCells record alone. A formatted one is not that case -- its fill, borders, and alignment live only in the XF a cell record points at, so writing nothing for it discards them.
|
|
12
|
+
* An unformatted empty cell with no formula is written as nothing at all, which is what round-trips: content.ts's reader drops an unformatted blank cell, and a merged range's empty anchor is reconstructed from the MergeCells record alone. A formatted one is not that case -- its fill, borders, and alignment live only in the XF a cell record points at, so writing nothing for it discards them. A formula is the identical case one level up: it lives only in a Formula record, so a cell carrying one is never dropped regardless of what its own cached `value` resolves to, even where that value alone would otherwise not have earned a record.
|
|
13
13
|
*/
|
|
14
14
|
declare function writesCellRecord(cell: ContentSheetCell): boolean;
|
|
15
15
|
//#endregion
|
package/dist/written-cells.d.ts
CHANGED
|
@@ -7,9 +7,9 @@ import { ContentSheetCell } from "document-schema.js";
|
|
|
7
7
|
*/
|
|
8
8
|
declare function cellCarriesFormatting(cell: ContentSheetCell): boolean;
|
|
9
9
|
/**
|
|
10
|
-
* Whether the writer emits a cell record for this cell: a value record for anything carrying a value, or a Blank record for an `empty`-kind cell whose formatting is the only thing it has to say.
|
|
10
|
+
* Whether the writer emits a cell record for this cell: a value record for anything carrying a value, a Formula record for anything carrying a formula, or a Blank record for an `empty`-kind cell whose formatting is the only thing it has to say.
|
|
11
11
|
*
|
|
12
|
-
* An unformatted empty cell is written as nothing at all, which is what round-trips: content.ts's reader drops an unformatted blank cell, and a merged range's empty anchor is reconstructed from the MergeCells record alone. A formatted one is not that case -- its fill, borders, and alignment live only in the XF a cell record points at, so writing nothing for it discards them.
|
|
12
|
+
* An unformatted empty cell with no formula is written as nothing at all, which is what round-trips: content.ts's reader drops an unformatted blank cell, and a merged range's empty anchor is reconstructed from the MergeCells record alone. A formatted one is not that case -- its fill, borders, and alignment live only in the XF a cell record points at, so writing nothing for it discards them. A formula is the identical case one level up: it lives only in a Formula record, so a cell carrying one is never dropped regardless of what its own cached `value` resolves to, even where that value alone would otherwise not have earned a record.
|
|
13
13
|
*/
|
|
14
14
|
declare function writesCellRecord(cell: ContentSheetCell): boolean;
|
|
15
15
|
//#endregion
|
package/dist/written-cells.js
CHANGED
|
@@ -13,12 +13,12 @@ function cellCarriesFormatting(cell) {
|
|
|
13
13
|
return borders.left !== void 0 || borders.right !== void 0 || borders.top !== void 0 || borders.bottom !== void 0;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* Whether the writer emits a cell record for this cell: a value record for anything carrying a value, or a Blank record for an `empty`-kind cell whose formatting is the only thing it has to say.
|
|
16
|
+
* Whether the writer emits a cell record for this cell: a value record for anything carrying a value, a Formula record for anything carrying a formula, or a Blank record for an `empty`-kind cell whose formatting is the only thing it has to say.
|
|
17
17
|
*
|
|
18
|
-
* An unformatted empty cell is written as nothing at all, which is what round-trips: content.ts's reader drops an unformatted blank cell, and a merged range's empty anchor is reconstructed from the MergeCells record alone. A formatted one is not that case -- its fill, borders, and alignment live only in the XF a cell record points at, so writing nothing for it discards them.
|
|
18
|
+
* An unformatted empty cell with no formula is written as nothing at all, which is what round-trips: content.ts's reader drops an unformatted blank cell, and a merged range's empty anchor is reconstructed from the MergeCells record alone. A formatted one is not that case -- its fill, borders, and alignment live only in the XF a cell record points at, so writing nothing for it discards them. A formula is the identical case one level up: it lives only in a Formula record, so a cell carrying one is never dropped regardless of what its own cached `value` resolves to, even where that value alone would otherwise not have earned a record.
|
|
19
19
|
*/
|
|
20
20
|
function writesCellRecord(cell) {
|
|
21
|
-
return cell.value.kind !== "empty" || cellCarriesFormatting(cell);
|
|
21
|
+
return cell.value.kind !== "empty" || cellCarriesFormatting(cell) || cell.formula !== void 0;
|
|
22
22
|
}
|
|
23
23
|
//#endregion
|
|
24
24
|
export { cellCarriesFormatting, writesCellRecord };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xls-codec",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.0",
|
|
4
4
|
"description": "Hand-written reader for the legacy Excel Binary File Format (.xls, BIFF8) as specified by [MS-XLS], mapping a workbook's record stream onto the shared document-schema.js spreadsheet model - the .xls codec for the documents.js family.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
},
|
|
71
71
|
"packageManager": "pnpm@11.6.0",
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"archive-codec": "1.
|
|
73
|
+
"archive-codec": "1.10.0",
|
|
74
74
|
"document-schema.js": "7.5.0",
|
|
75
75
|
"excel-number-format": "1.1.1"
|
|
76
76
|
},
|