ooxml.js 2.5.1 → 2.6.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 (46) hide show
  1. package/README.md +1 -1
  2. package/dist/index.cjs +22 -0
  3. package/dist/index.d.cts +3 -2
  4. package/dist/index.d.ts +3 -2
  5. package/dist/index.js +3 -2
  6. package/dist/typed/docx/numbering.cjs +86 -0
  7. package/dist/typed/docx/numbering.d.cts +23 -0
  8. package/dist/typed/docx/numbering.d.ts +23 -0
  9. package/dist/typed/docx/numbering.js +83 -0
  10. package/dist/typed/docx/read.cjs +115 -15
  11. package/dist/typed/docx/read.d.cts +8 -0
  12. package/dist/typed/docx/read.d.ts +8 -0
  13. package/dist/typed/docx/read.js +117 -17
  14. package/dist/typed/docx/styles.cjs +26 -2
  15. package/dist/typed/docx/styles.js +26 -2
  16. package/dist/typed/pptx/read.cjs +5 -20
  17. package/dist/typed/pptx/read.d.cts +1 -0
  18. package/dist/typed/pptx/read.d.ts +1 -0
  19. package/dist/typed/pptx/read.js +5 -20
  20. package/dist/typed/shared/drawingml.cjs +112 -5
  21. package/dist/typed/shared/drawingml.d.cts +19 -2
  22. package/dist/typed/shared/drawingml.d.ts +19 -2
  23. package/dist/typed/shared/drawingml.js +111 -6
  24. package/dist/typed/shared/units.cjs +10 -0
  25. package/dist/typed/shared/units.d.cts +4 -1
  26. package/dist/typed/shared/units.d.ts +4 -1
  27. package/dist/typed/shared/units.js +8 -1
  28. package/dist/typed/xlsx/build.cjs +93 -60
  29. package/dist/typed/xlsx/build.js +93 -60
  30. package/dist/typed/xlsx/content.cjs +93 -22
  31. package/dist/typed/xlsx/content.js +93 -22
  32. package/dist/typed/xlsx/number-format.cjs +324 -0
  33. package/dist/typed/xlsx/number-format.d.cts +52 -0
  34. package/dist/typed/xlsx/number-format.d.ts +52 -0
  35. package/dist/typed/xlsx/number-format.js +312 -0
  36. package/dist/typed/xlsx/print-settings.cjs +1 -1
  37. package/dist/typed/xlsx/print-settings.js +1 -1
  38. package/dist/typed/xlsx/serial.cjs +109 -0
  39. package/dist/typed/xlsx/serial.d.cts +11 -0
  40. package/dist/typed/xlsx/serial.d.ts +11 -0
  41. package/dist/typed/xlsx/serial.js +102 -0
  42. package/dist/typed/xlsx/styles.cjs +73 -0
  43. package/dist/typed/xlsx/styles.d.cts +21 -0
  44. package/dist/typed/xlsx/styles.d.ts +21 -0
  45. package/dist/typed/xlsx/styles.js +69 -0
  46. package/package.json +2 -2
@@ -4,8 +4,11 @@ import "../shared/units.js";
4
4
  import { SharedStringTable } from "./shared-strings.js";
5
5
  import { cellReference, rangeReference } from "./a1.js";
6
6
  import { XLNM_PRINT_AREA, XLNM_PRINT_TITLES, buildPrintAreaValue, buildPrintTitlesValue } from "./defined-names.js";
7
+ import { BOOLEAN_NUMBER_FORMAT, DATE_NUMBER_FORMAT, DATE_TIME_NUMBER_FORMAT, PERCENTAGE_NUMBER_FORMAT, TIME_NUMBER_FORMAT, currencyNumberFormat } from "./number-format.js";
7
8
  import { pageSizeToPaperSizeCode, ptToUniversalMeasure, writeXmlBool } from "./util.js";
8
9
  import { DEFAULT_HEADER_FOOTER_MARGIN_PT } from "./print-settings.js";
10
+ import { isoDateTimeToSerial, isoDateToSerial, isoTimeToSerial } from "./serial.js";
11
+ import { CellFormatTable } from "./styles.js";
9
12
  import { ptToColumnWidthChars } from "./units.js";
10
13
  //#region src/typed/xlsx/build.ts
11
14
  const SML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
@@ -179,36 +182,46 @@ function buildSharedStringsPart(sharedStrings) {
179
182
  uniqueCount: String(entries.length)
180
183
  }, siElements));
181
184
  }
182
- function buildStylesPart() {
183
- return xmlPart(el("styleSheet", { xmlns: SML_NS }, [
184
- el("fonts", { count: "1" }, [el("font", {}, [el("sz", { val: "11" }), el("name", { val: "Calibri" })])]),
185
- el("fills", { count: "2" }, [el("fill", {}, [el("patternFill", { patternType: "none" })]), el("fill", {}, [el("patternFill", { patternType: "gray125" })])]),
186
- el("borders", { count: "1" }, [el("border", {}, [
187
- el("left"),
188
- el("right"),
189
- el("top"),
190
- el("bottom"),
191
- el("diagonal")
192
- ])]),
193
- el("cellStyleXfs", { count: "1" }, [el("xf", {
194
- numFmtId: "0",
195
- fontId: "0",
196
- fillId: "0",
197
- borderId: "0"
198
- })]),
199
- el("cellXfs", { count: "1" }, [el("xf", {
200
- numFmtId: "0",
185
+ function buildStylesPart(cellFormats) {
186
+ const children = [];
187
+ const declarations = cellFormats.declarations();
188
+ if (declarations.length > 0) {
189
+ const numFmtElements = declarations.map((declaration) => el("numFmt", {
190
+ numFmtId: String(declaration.id),
191
+ formatCode: encodeXmlText(declaration.code)
192
+ }));
193
+ children.push(el("numFmts", { count: String(numFmtElements.length) }, numFmtElements));
194
+ }
195
+ children.push(el("fonts", { count: "1" }, [el("font", {}, [el("sz", { val: "11" }), el("name", { val: "Calibri" })])]), el("fills", { count: "2" }, [el("fill", {}, [el("patternFill", { patternType: "none" })]), el("fill", {}, [el("patternFill", { patternType: "gray125" })])]), el("borders", { count: "1" }, [el("border", {}, [
196
+ el("left"),
197
+ el("right"),
198
+ el("top"),
199
+ el("bottom"),
200
+ el("diagonal")
201
+ ])]), el("cellStyleXfs", { count: "1" }, [el("xf", {
202
+ numFmtId: "0",
203
+ fontId: "0",
204
+ fillId: "0",
205
+ borderId: "0"
206
+ })]));
207
+ const xfElements = cellFormats.cellFormats().map((numFmtId) => {
208
+ const attrs = {
209
+ numFmtId: String(numFmtId),
201
210
  fontId: "0",
202
211
  fillId: "0",
203
212
  borderId: "0",
204
213
  xfId: "0"
205
- })]),
206
- el("cellStyles", { count: "1" }, [el("cellStyle", {
207
- name: "Normal",
208
- xfId: "0",
209
- builtinId: "0"
210
- })])
211
- ]));
214
+ };
215
+ if (numFmtId !== 0) attrs.applyNumberFormat = writeXmlBool(true);
216
+ return el("xf", attrs);
217
+ });
218
+ children.push(el("cellXfs", { count: String(xfElements.length) }, xfElements));
219
+ children.push(el("cellStyles", { count: "1" }, [el("cellStyle", {
220
+ name: "Normal",
221
+ xfId: "0",
222
+ builtinId: "0"
223
+ })]));
224
+ return xmlPart(el("styleSheet", { xmlns: SML_NS }, children));
212
225
  }
213
226
  function buildCorePropertiesPart(metadata) {
214
227
  const children = [];
@@ -259,37 +272,36 @@ function buildColsElement(columns) {
259
272
  return el("cols", {}, columns.map((column) => {
260
273
  const attrs = {
261
274
  min: String(column.index + 1),
262
- max: String(column.index + 1),
263
- width: ptToColumnWidthChars(column.widthPt).toFixed(2),
264
- customWidth: "true"
275
+ max: String(column.index + 1)
265
276
  };
277
+ if (column.widthPt !== void 0) {
278
+ attrs.width = ptToColumnWidthChars(column.widthPt).toFixed(2);
279
+ attrs.customWidth = "true";
280
+ }
266
281
  if (column.hidden === true) attrs.hidden = "true";
267
282
  return el("col", attrs);
268
283
  }));
269
284
  }
270
285
  function renderCellValue(value, isFormulaResult, sharedStrings) {
271
286
  switch (value.kind) {
272
- case "string":
273
- if (isFormulaResult) return {
274
- type: "str",
275
- content: encodeXmlText(value.value)
276
- };
277
- return {
278
- type: "s",
279
- content: String(sharedStrings.intern(value.value))
280
- };
281
- case "number":
282
- case "percentage":
283
- case "currency": return { content: String(value.value) };
287
+ case "string": return renderString(value.value, isFormulaResult, sharedStrings);
288
+ case "number": return { content: String(value.value) };
289
+ case "percentage": return {
290
+ content: String(value.value),
291
+ format: PERCENTAGE_NUMBER_FORMAT
292
+ };
293
+ case "currency": return {
294
+ content: String(value.value),
295
+ format: currencyNumberFormat(value.currency)
296
+ };
284
297
  case "boolean": return {
285
298
  type: "b",
286
- content: value.value ? "1" : "0"
287
- };
288
- case "date":
289
- case "time": return {
290
- type: "d",
291
- content: encodeXmlText(value.value)
299
+ content: value.value ? "1" : "0",
300
+ format: BOOLEAN_NUMBER_FORMAT
292
301
  };
302
+ case "date": return renderTemporal(isoDateToSerial(value.value), value.value, DATE_NUMBER_FORMAT, isFormulaResult, sharedStrings);
303
+ case "time": return renderTemporal(isoTimeToSerial(value.value), value.value, TIME_NUMBER_FORMAT, isFormulaResult, sharedStrings);
304
+ case "dateTime": return renderTemporal(isoDateTimeToSerial(value.value), value.value, DATE_TIME_NUMBER_FORMAT, isFormulaResult, sharedStrings);
293
305
  case "error": return {
294
306
  type: "e",
295
307
  content: encodeXmlText(value.value)
@@ -297,21 +309,39 @@ function renderCellValue(value, isFormulaResult, sharedStrings) {
297
309
  case "empty": return;
298
310
  }
299
311
  }
300
- function buildCellElement(cell, sharedStrings) {
312
+ function renderString(text, isFormulaResult, sharedStrings) {
313
+ if (isFormulaResult) return {
314
+ type: "str",
315
+ content: encodeXmlText(text)
316
+ };
317
+ return {
318
+ type: "s",
319
+ content: String(sharedStrings.intern(text))
320
+ };
321
+ }
322
+ function renderTemporal(serial, iso, format, isFormulaResult, sharedStrings) {
323
+ if (serial === void 0) return renderString(iso, isFormulaResult, sharedStrings);
324
+ return {
325
+ content: String(serial),
326
+ format
327
+ };
328
+ }
329
+ function buildCellElement(cell, sharedStrings, cellFormats) {
330
+ const children = [];
331
+ const rendered = renderCellValue(cell.value, cell.formula !== void 0, sharedStrings);
332
+ const styleIndex = rendered?.format === void 0 ? 0 : cellFormats.intern(rendered.format);
301
333
  const attrs = {
302
334
  r: cellReference(cell.row, cell.column),
303
- s: "0"
335
+ s: String(styleIndex)
304
336
  };
305
- const children = [];
306
337
  if (cell.formula !== void 0) children.push(el("f", {}, [txt(encodeXmlText(cell.formula))]));
307
- const rendered = renderCellValue(cell.value, cell.formula !== void 0, sharedStrings);
308
338
  if (rendered !== void 0) {
309
339
  if (rendered.type !== void 0) attrs.t = rendered.type;
310
340
  children.push(el("v", {}, [txt(rendered.content)]));
311
341
  }
312
342
  return el("c", attrs, children);
313
343
  }
314
- function buildSheetDataElement(sheet, sharedStrings) {
344
+ function buildSheetDataElement(sheet, sharedStrings, cellFormats) {
315
345
  const cellsByRow = /* @__PURE__ */ new Map();
316
346
  for (const cell of sheet.cells) {
317
347
  const existing = cellsByRow.get(cell.row);
@@ -325,11 +355,13 @@ function buildSheetDataElement(sheet, sharedStrings) {
325
355
  const rowInfo = rowInfoByIndex.get(rowIndex);
326
356
  const attrs = { r: String(rowIndex + 1) };
327
357
  if (rowInfo !== void 0) {
328
- attrs.ht = String(rowInfo.heightPt);
329
- attrs.customHeight = "true";
358
+ if (rowInfo.heightPt !== void 0) {
359
+ attrs.ht = String(rowInfo.heightPt);
360
+ attrs.customHeight = "true";
361
+ }
330
362
  if (rowInfo.hidden === true) attrs.hidden = "true";
331
363
  }
332
- return el("row", attrs, cells.map((cell) => buildCellElement(cell, sharedStrings)));
364
+ return el("row", attrs, cells.map((cell) => buildCellElement(cell, sharedStrings, cellFormats)));
333
365
  }));
334
366
  }
335
367
  function buildMergeCellsElement(cells) {
@@ -378,7 +410,7 @@ function buildPageSetupElement(settings) {
378
410
  attrs.paperWidth = ptToUniversalMeasure(settings.pageSize.widthPt);
379
411
  attrs.paperHeight = ptToUniversalMeasure(settings.pageSize.heightPt);
380
412
  }
381
- attrs.scale = String(settings.scale ?? 100);
413
+ attrs.scale = String(settings.scalePercent ?? 100);
382
414
  attrs.fitToWidth = String(settings.fitToPages?.width ?? 1);
383
415
  attrs.fitToHeight = String(settings.fitToPages?.height ?? 1);
384
416
  attrs.pageOrder = settings.pageOrder;
@@ -415,11 +447,11 @@ function buildBreaksElements(settings) {
415
447
  }
416
448
  return result;
417
449
  }
418
- function buildWorksheetPart(sheet, sharedStrings) {
450
+ function buildWorksheetPart(sheet, sharedStrings, cellFormats) {
419
451
  const children = [buildSheetPrElement(sheet.printSettings), el("dimension", { ref: computeDimension(sheet) })];
420
452
  const colsElement = buildColsElement(sheet.columns);
421
453
  if (colsElement !== void 0) children.push(colsElement);
422
- children.push(buildSheetDataElement(sheet, sharedStrings));
454
+ children.push(buildSheetDataElement(sheet, sharedStrings, cellFormats));
423
455
  const mergeCellsElement = buildMergeCellsElement(sheet.cells);
424
456
  if (mergeCellsElement !== void 0) children.push(mergeCellsElement);
425
457
  children.push(buildPrintOptionsElement(sheet.printSettings), buildPageMarginsElement(sheet.printSettings), buildPageSetupElement(sheet.printSettings));
@@ -435,13 +467,14 @@ function buildXlsxPackage(document) {
435
467
  if (document.kind !== "spreadsheet") throw new Error(`buildXlsxPackage: expected a ContentDocument of kind "spreadsheet", got "${document.kind}"`);
436
468
  const sheets = document.sheets;
437
469
  const sharedStrings = new SharedStringTable();
438
- const worksheetParts = sheets.map((sheet) => buildWorksheetPart(sheet, sharedStrings));
470
+ const cellFormats = new CellFormatTable();
471
+ const worksheetParts = sheets.map((sheet) => buildWorksheetPart(sheet, sharedStrings, cellFormats));
439
472
  const parts = {
440
473
  "[Content_Types].xml": buildContentTypesPart(sheets.length),
441
474
  "_rels/.rels": buildPackageRelsPart(),
442
475
  "xl/workbook.xml": buildWorkbookPart(sheets),
443
476
  "xl/_rels/workbook.xml.rels": buildWorkbookRelsPart(sheets.length),
444
- "xl/styles.xml": buildStylesPart(),
477
+ "xl/styles.xml": buildStylesPart(cellFormats),
445
478
  "xl/sharedStrings.xml": buildSharedStringsPart(sharedStrings),
446
479
  "docProps/core.xml": buildCorePropertiesPart(document.metadata),
447
480
  "docProps/app.xml": buildAppPropertiesPart(document.metadata)
@@ -4,8 +4,11 @@ const require_typed_shared_metadata = require("../shared/metadata.cjs");
4
4
  const require_typed_xlsx_shared_strings = require("./shared-strings.cjs");
5
5
  const require_typed_xlsx_a1 = require("./a1.cjs");
6
6
  const require_typed_xlsx_defined_names = require("./defined-names.cjs");
7
+ const require_typed_xlsx_number_format = require("./number-format.cjs");
7
8
  const require_typed_xlsx_util = require("./util.cjs");
8
9
  const require_typed_xlsx_print_settings = require("./print-settings.cjs");
10
+ const require_typed_xlsx_serial = require("./serial.cjs");
11
+ const require_typed_xlsx_styles = require("./styles.cjs");
9
12
  const require_typed_xlsx_units = require("./units.cjs");
10
13
  let document_schema_js = require("document-schema.js");
11
14
  //#region src/typed/xlsx/content.ts
@@ -43,12 +46,12 @@ function readColumns(worksheet) {
43
46
  const minRaw = require_typed_util.attr(col, "min");
44
47
  const min = minRaw === void 0 ? void 0 : Number.parseInt(minRaw, 10);
45
48
  if (min === void 0 || !Number.isInteger(min) || min < 1) continue;
49
+ const column = { index: min - 1 };
46
50
  const widthRaw = require_typed_util.attr(col, "width");
47
- const widthPt = widthRaw === void 0 ? 0 : require_typed_xlsx_units.columnWidthCharsToPt(Number(widthRaw));
48
- const column = {
49
- index: min - 1,
50
- widthPt: Number.isFinite(widthPt) ? widthPt : 0
51
- };
51
+ if (widthRaw !== void 0) {
52
+ const widthPt = require_typed_xlsx_units.columnWidthCharsToPt(Number(widthRaw));
53
+ if (Number.isFinite(widthPt)) column.widthPt = widthPt;
54
+ }
52
55
  if (require_typed_xlsx_util.readXmlBool(require_typed_util.attr(col, "hidden"))) column.hidden = true;
53
56
  columns.push(column);
54
57
  }
@@ -81,18 +84,88 @@ function readInlineOrSharedStringText(container) {
81
84
  }
82
85
  function deriveDisplayText(value) {
83
86
  switch (value.kind) {
84
- case "number": return String(value.value);
87
+ case "number":
88
+ case "percentage":
89
+ case "currency": return String(value.value);
85
90
  case "boolean": return value.value ? "TRUE" : "FALSE";
86
91
  case "string":
87
92
  case "error":
88
93
  case "date":
89
- case "time": return value.value;
90
- case "percentage":
91
- case "currency": return String(value.value);
94
+ case "time":
95
+ case "dateTime": return value.value;
92
96
  case "empty": return "";
93
97
  }
94
98
  }
95
- function readCellValue(cell, sharedStrings) {
99
+ const DEFAULT_CELL_STYLE_INDEX = 0;
100
+ const PLAIN_NUMBER = { kind: "number" };
101
+ function readNumericFormatContext(pkg) {
102
+ return {
103
+ classes: require_typed_xlsx_styles.readCellFormatCodes(pkg).map((code) => code === void 0 ? PLAIN_NUMBER : require_typed_xlsx_number_format.classifyNumberFormat(code)),
104
+ date1904: require_typed_xlsx_serial.readDate1904(pkg)
105
+ };
106
+ }
107
+ function numberFormatOf(cell, context) {
108
+ const raw = require_typed_util.attr(cell, "s");
109
+ const index = raw === void 0 ? DEFAULT_CELL_STYLE_INDEX : Number.parseInt(raw, 10);
110
+ return (Number.isInteger(index) ? context.classes[index] : void 0) ?? PLAIN_NUMBER;
111
+ }
112
+ function resolveNumericValue(num, cell, context) {
113
+ const format = numberFormatOf(cell, context);
114
+ switch (format.kind) {
115
+ case "percentage": return {
116
+ kind: "percentage",
117
+ value: num
118
+ };
119
+ case "currency": return format.code === void 0 ? {
120
+ kind: "currency",
121
+ value: num
122
+ } : {
123
+ kind: "currency",
124
+ value: num,
125
+ currency: format.code
126
+ };
127
+ case "date": {
128
+ const iso = require_typed_xlsx_serial.serialToIsoDate(num, context.date1904);
129
+ return iso === void 0 ? {
130
+ kind: "number",
131
+ value: num
132
+ } : {
133
+ kind: "date",
134
+ value: iso
135
+ };
136
+ }
137
+ case "time": {
138
+ const iso = require_typed_xlsx_serial.serialToIsoTime(num);
139
+ return iso === void 0 ? {
140
+ kind: "number",
141
+ value: num
142
+ } : {
143
+ kind: "time",
144
+ value: iso
145
+ };
146
+ }
147
+ case "dateTime": {
148
+ const iso = require_typed_xlsx_serial.serialToIsoDateTime(num, context.date1904);
149
+ return iso === void 0 ? {
150
+ kind: "number",
151
+ value: num
152
+ } : {
153
+ kind: "dateTime",
154
+ value: iso
155
+ };
156
+ }
157
+ case "elapsedTime": return {
158
+ kind: "number",
159
+ value: num
160
+ };
161
+ case "text":
162
+ case "number": return {
163
+ kind: "number",
164
+ value: num
165
+ };
166
+ }
167
+ }
168
+ function readCellValue(cell, sharedStrings, numericFormats) {
96
169
  const type = require_typed_util.attr(cell, "t");
97
170
  if (type === "inlineStr") {
98
171
  const is = require_typed_util.childrenWithTag(cell, "is")[0];
@@ -145,29 +218,26 @@ function readCellValue(cell, sharedStrings) {
145
218
  };
146
219
  if (type === "d") return {
147
220
  value: {
148
- kind: "date",
221
+ kind: "dateTime",
149
222
  value: raw
150
223
  },
151
224
  displayText: raw
152
225
  };
153
226
  const num = Number(raw);
154
227
  if (Number.isNaN(num)) return;
155
- const value = {
156
- kind: "number",
157
- value: num
158
- };
228
+ const value = resolveNumericValue(num, cell, numericFormats);
159
229
  return {
160
230
  value,
161
231
  displayText: deriveDisplayText(value)
162
232
  };
163
233
  }
164
- function readCell(cell, sharedStrings) {
234
+ function readCell(cell, sharedStrings, numericFormats) {
165
235
  const reference = require_typed_util.attr(cell, "r");
166
236
  const position = reference === void 0 ? void 0 : require_typed_xlsx_a1.parseCellReference(reference);
167
237
  if (position === void 0) return;
168
238
  const formulaEl = require_typed_util.childrenWithTag(cell, "f")[0];
169
239
  const formula = formulaEl === void 0 ? void 0 : require_typed_util.textContent(formulaEl);
170
- const resolved = readCellValue(cell, sharedStrings);
240
+ const resolved = readCellValue(cell, sharedStrings, numericFormats);
171
241
  if (resolved === void 0) {
172
242
  if (formula === void 0) return;
173
243
  return {
@@ -204,18 +274,18 @@ function applyMergedRanges(worksheet, cells) {
204
274
  if (rowSpan > 1) anchor.rowSpan = rowSpan;
205
275
  }
206
276
  }
207
- function readCells(worksheet, sharedStrings) {
277
+ function readCells(worksheet, sharedStrings, numericFormats) {
208
278
  const sheetData = require_typed_util.childrenWithTag(worksheet, "sheetData")[0];
209
279
  if (sheetData === void 0) return [];
210
280
  const cells = [];
211
281
  for (const row of require_typed_util.childrenWithTag(sheetData, "row")) for (const cell of require_typed_util.childrenWithTag(row, "c")) {
212
- const read = readCell(cell, sharedStrings);
282
+ const read = readCell(cell, sharedStrings, numericFormats);
213
283
  if (read !== void 0) cells.push(read);
214
284
  }
215
285
  applyMergedRanges(worksheet, cells);
216
286
  return cells;
217
287
  }
218
- function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet) {
288
+ function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, numericFormats) {
219
289
  const worksheet = require_typed_util.rootElement(pkg.parts[entry.path]);
220
290
  if (worksheet === void 0) return {
221
291
  name: entry.name,
@@ -227,7 +297,7 @@ function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet) {
227
297
  };
228
298
  return {
229
299
  name: entry.name,
230
- cells: readCells(worksheet, sharedStrings),
300
+ cells: readCells(worksheet, sharedStrings, numericFormats),
231
301
  columns: readColumns(worksheet),
232
302
  rows: readRows(worksheet),
233
303
  images: [],
@@ -245,7 +315,8 @@ function fallbackEmptyWorksheet() {
245
315
  function readXlsxContent(pkg) {
246
316
  const sharedStrings = require_typed_xlsx_shared_strings.loadSharedStrings(pkg);
247
317
  const definedNamesBySheet = require_typed_xlsx_defined_names.readDefinedNamesBySheet(pkg);
248
- const sheets = resolveSheetEntries(pkg).map((entry, sheetIndex) => readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet));
318
+ const numericFormats = readNumericFormatContext(pkg);
319
+ const sheets = resolveSheetEntries(pkg).map((entry, sheetIndex) => readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, numericFormats));
249
320
  return {
250
321
  kind: "spreadsheet",
251
322
  formatVersion: document_schema_js.CONTENT_FORMAT_VERSION,
@@ -3,8 +3,11 @@ import { readCoreProperties } from "../shared/metadata.js";
3
3
  import { loadSharedStrings } from "./shared-strings.js";
4
4
  import { parseCellReference, parseRangeReference } from "./a1.js";
5
5
  import { readDefinedNamesBySheet } from "./defined-names.js";
6
+ import { classifyNumberFormat } from "./number-format.js";
6
7
  import { readXmlBool } from "./util.js";
7
8
  import { readPrintSettings } from "./print-settings.js";
9
+ import { readDate1904, serialToIsoDate, serialToIsoDateTime, serialToIsoTime } from "./serial.js";
10
+ import { readCellFormatCodes } from "./styles.js";
8
11
  import { columnWidthCharsToPt } from "./units.js";
9
12
  import { CONTENT_FORMAT_VERSION } from "document-schema.js";
10
13
  //#region src/typed/xlsx/content.ts
@@ -42,12 +45,12 @@ function readColumns(worksheet) {
42
45
  const minRaw = attr(col, "min");
43
46
  const min = minRaw === void 0 ? void 0 : Number.parseInt(minRaw, 10);
44
47
  if (min === void 0 || !Number.isInteger(min) || min < 1) continue;
48
+ const column = { index: min - 1 };
45
49
  const widthRaw = attr(col, "width");
46
- const widthPt = widthRaw === void 0 ? 0 : columnWidthCharsToPt(Number(widthRaw));
47
- const column = {
48
- index: min - 1,
49
- widthPt: Number.isFinite(widthPt) ? widthPt : 0
50
- };
50
+ if (widthRaw !== void 0) {
51
+ const widthPt = columnWidthCharsToPt(Number(widthRaw));
52
+ if (Number.isFinite(widthPt)) column.widthPt = widthPt;
53
+ }
51
54
  if (readXmlBool(attr(col, "hidden"))) column.hidden = true;
52
55
  columns.push(column);
53
56
  }
@@ -80,18 +83,88 @@ function readInlineOrSharedStringText(container) {
80
83
  }
81
84
  function deriveDisplayText(value) {
82
85
  switch (value.kind) {
83
- case "number": return String(value.value);
86
+ case "number":
87
+ case "percentage":
88
+ case "currency": return String(value.value);
84
89
  case "boolean": return value.value ? "TRUE" : "FALSE";
85
90
  case "string":
86
91
  case "error":
87
92
  case "date":
88
- case "time": return value.value;
89
- case "percentage":
90
- case "currency": return String(value.value);
93
+ case "time":
94
+ case "dateTime": return value.value;
91
95
  case "empty": return "";
92
96
  }
93
97
  }
94
- function readCellValue(cell, sharedStrings) {
98
+ const DEFAULT_CELL_STYLE_INDEX = 0;
99
+ const PLAIN_NUMBER = { kind: "number" };
100
+ function readNumericFormatContext(pkg) {
101
+ return {
102
+ classes: readCellFormatCodes(pkg).map((code) => code === void 0 ? PLAIN_NUMBER : classifyNumberFormat(code)),
103
+ date1904: readDate1904(pkg)
104
+ };
105
+ }
106
+ function numberFormatOf(cell, context) {
107
+ const raw = attr(cell, "s");
108
+ const index = raw === void 0 ? DEFAULT_CELL_STYLE_INDEX : Number.parseInt(raw, 10);
109
+ return (Number.isInteger(index) ? context.classes[index] : void 0) ?? PLAIN_NUMBER;
110
+ }
111
+ function resolveNumericValue(num, cell, context) {
112
+ const format = numberFormatOf(cell, context);
113
+ switch (format.kind) {
114
+ case "percentage": return {
115
+ kind: "percentage",
116
+ value: num
117
+ };
118
+ case "currency": return format.code === void 0 ? {
119
+ kind: "currency",
120
+ value: num
121
+ } : {
122
+ kind: "currency",
123
+ value: num,
124
+ currency: format.code
125
+ };
126
+ case "date": {
127
+ const iso = serialToIsoDate(num, context.date1904);
128
+ return iso === void 0 ? {
129
+ kind: "number",
130
+ value: num
131
+ } : {
132
+ kind: "date",
133
+ value: iso
134
+ };
135
+ }
136
+ case "time": {
137
+ const iso = serialToIsoTime(num);
138
+ return iso === void 0 ? {
139
+ kind: "number",
140
+ value: num
141
+ } : {
142
+ kind: "time",
143
+ value: iso
144
+ };
145
+ }
146
+ case "dateTime": {
147
+ const iso = serialToIsoDateTime(num, context.date1904);
148
+ return iso === void 0 ? {
149
+ kind: "number",
150
+ value: num
151
+ } : {
152
+ kind: "dateTime",
153
+ value: iso
154
+ };
155
+ }
156
+ case "elapsedTime": return {
157
+ kind: "number",
158
+ value: num
159
+ };
160
+ case "text":
161
+ case "number": return {
162
+ kind: "number",
163
+ value: num
164
+ };
165
+ }
166
+ }
167
+ function readCellValue(cell, sharedStrings, numericFormats) {
95
168
  const type = attr(cell, "t");
96
169
  if (type === "inlineStr") {
97
170
  const is = childrenWithTag(cell, "is")[0];
@@ -144,29 +217,26 @@ function readCellValue(cell, sharedStrings) {
144
217
  };
145
218
  if (type === "d") return {
146
219
  value: {
147
- kind: "date",
220
+ kind: "dateTime",
148
221
  value: raw
149
222
  },
150
223
  displayText: raw
151
224
  };
152
225
  const num = Number(raw);
153
226
  if (Number.isNaN(num)) return;
154
- const value = {
155
- kind: "number",
156
- value: num
157
- };
227
+ const value = resolveNumericValue(num, cell, numericFormats);
158
228
  return {
159
229
  value,
160
230
  displayText: deriveDisplayText(value)
161
231
  };
162
232
  }
163
- function readCell(cell, sharedStrings) {
233
+ function readCell(cell, sharedStrings, numericFormats) {
164
234
  const reference = attr(cell, "r");
165
235
  const position = reference === void 0 ? void 0 : parseCellReference(reference);
166
236
  if (position === void 0) return;
167
237
  const formulaEl = childrenWithTag(cell, "f")[0];
168
238
  const formula = formulaEl === void 0 ? void 0 : textContent(formulaEl);
169
- const resolved = readCellValue(cell, sharedStrings);
239
+ const resolved = readCellValue(cell, sharedStrings, numericFormats);
170
240
  if (resolved === void 0) {
171
241
  if (formula === void 0) return;
172
242
  return {
@@ -203,18 +273,18 @@ function applyMergedRanges(worksheet, cells) {
203
273
  if (rowSpan > 1) anchor.rowSpan = rowSpan;
204
274
  }
205
275
  }
206
- function readCells(worksheet, sharedStrings) {
276
+ function readCells(worksheet, sharedStrings, numericFormats) {
207
277
  const sheetData = childrenWithTag(worksheet, "sheetData")[0];
208
278
  if (sheetData === void 0) return [];
209
279
  const cells = [];
210
280
  for (const row of childrenWithTag(sheetData, "row")) for (const cell of childrenWithTag(row, "c")) {
211
- const read = readCell(cell, sharedStrings);
281
+ const read = readCell(cell, sharedStrings, numericFormats);
212
282
  if (read !== void 0) cells.push(read);
213
283
  }
214
284
  applyMergedRanges(worksheet, cells);
215
285
  return cells;
216
286
  }
217
- function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet) {
287
+ function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, numericFormats) {
218
288
  const worksheet = rootElement(pkg.parts[entry.path]);
219
289
  if (worksheet === void 0) return {
220
290
  name: entry.name,
@@ -226,7 +296,7 @@ function readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet) {
226
296
  };
227
297
  return {
228
298
  name: entry.name,
229
- cells: readCells(worksheet, sharedStrings),
299
+ cells: readCells(worksheet, sharedStrings, numericFormats),
230
300
  columns: readColumns(worksheet),
231
301
  rows: readRows(worksheet),
232
302
  images: [],
@@ -244,7 +314,8 @@ function fallbackEmptyWorksheet() {
244
314
  function readXlsxContent(pkg) {
245
315
  const sharedStrings = loadSharedStrings(pkg);
246
316
  const definedNamesBySheet = readDefinedNamesBySheet(pkg);
247
- const sheets = resolveSheetEntries(pkg).map((entry, sheetIndex) => readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet));
317
+ const numericFormats = readNumericFormatContext(pkg);
318
+ const sheets = resolveSheetEntries(pkg).map((entry, sheetIndex) => readSheet(pkg, entry, sheetIndex, sharedStrings, definedNamesBySheet, numericFormats));
248
319
  return {
249
320
  kind: "spreadsheet",
250
321
  formatVersion: CONTENT_FORMAT_VERSION,