@niicojs/excel 0.2.5 → 0.2.6

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/dist/index.cjs CHANGED
@@ -1117,6 +1117,129 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
1117
1117
  }
1118
1118
  }
1119
1119
 
1120
+ /**
1121
+ * Excel built-in number format IDs (0-163 are reserved).
1122
+ * These formats don't need to be defined in the numFmts element.
1123
+ */ const BUILTIN_NUM_FMTS = new Map([
1124
+ [
1125
+ 'General',
1126
+ 0
1127
+ ],
1128
+ [
1129
+ '0',
1130
+ 1
1131
+ ],
1132
+ [
1133
+ '0.00',
1134
+ 2
1135
+ ],
1136
+ [
1137
+ '#,##0',
1138
+ 3
1139
+ ],
1140
+ [
1141
+ '#,##0.00',
1142
+ 4
1143
+ ],
1144
+ [
1145
+ '0%',
1146
+ 9
1147
+ ],
1148
+ [
1149
+ '0.00%',
1150
+ 10
1151
+ ],
1152
+ [
1153
+ '0.00E+00',
1154
+ 11
1155
+ ],
1156
+ [
1157
+ '# ?/?',
1158
+ 12
1159
+ ],
1160
+ [
1161
+ '# ??/??',
1162
+ 13
1163
+ ],
1164
+ [
1165
+ 'mm-dd-yy',
1166
+ 14
1167
+ ],
1168
+ [
1169
+ 'd-mmm-yy',
1170
+ 15
1171
+ ],
1172
+ [
1173
+ 'd-mmm',
1174
+ 16
1175
+ ],
1176
+ [
1177
+ 'mmm-yy',
1178
+ 17
1179
+ ],
1180
+ [
1181
+ 'h:mm AM/PM',
1182
+ 18
1183
+ ],
1184
+ [
1185
+ 'h:mm:ss AM/PM',
1186
+ 19
1187
+ ],
1188
+ [
1189
+ 'h:mm',
1190
+ 20
1191
+ ],
1192
+ [
1193
+ 'h:mm:ss',
1194
+ 21
1195
+ ],
1196
+ [
1197
+ 'm/d/yy h:mm',
1198
+ 22
1199
+ ],
1200
+ [
1201
+ '#,##0 ;(#,##0)',
1202
+ 37
1203
+ ],
1204
+ [
1205
+ '#,##0 ;[Red](#,##0)',
1206
+ 38
1207
+ ],
1208
+ [
1209
+ '#,##0.00;(#,##0.00)',
1210
+ 39
1211
+ ],
1212
+ [
1213
+ '#,##0.00;[Red](#,##0.00)',
1214
+ 40
1215
+ ],
1216
+ [
1217
+ 'mm:ss',
1218
+ 45
1219
+ ],
1220
+ [
1221
+ '[h]:mm:ss',
1222
+ 46
1223
+ ],
1224
+ [
1225
+ 'mmss.0',
1226
+ 47
1227
+ ],
1228
+ [
1229
+ '##0.0E+0',
1230
+ 48
1231
+ ],
1232
+ [
1233
+ '@',
1234
+ 49
1235
+ ]
1236
+ ]);
1237
+ /**
1238
+ * Reverse lookup: built-in format ID -> format code
1239
+ */ const BUILTIN_NUM_FMT_CODES = new Map(Array.from(BUILTIN_NUM_FMTS.entries()).map(([code, id])=>[
1240
+ id,
1241
+ code
1242
+ ]));
1120
1243
  /**
1121
1244
  * Normalize a color to ARGB format (8 hex chars).
1122
1245
  * Accepts: "#RGB", "#RRGGBB", "RGB", "RRGGBB", "AARRGGBB", "#AARRGGBB"
@@ -1307,7 +1430,8 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
1307
1430
  const font = this._fonts[xf.fontId];
1308
1431
  const fill = this._fills[xf.fillId];
1309
1432
  const border = this._borders[xf.borderId];
1310
- const numFmt = this._numFmts.get(xf.numFmtId);
1433
+ // Check custom formats first, then fall back to built-in format codes
1434
+ const numFmt = this._numFmts.get(xf.numFmtId) ?? BUILTIN_NUM_FMT_CODES.get(xf.numFmtId);
1311
1435
  const style = {};
1312
1436
  if (font) {
1313
1437
  if (font.bold) style.bold = true;
@@ -1439,16 +1563,30 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
1439
1563
  return this._borders.length - 1;
1440
1564
  }
1441
1565
  _findOrCreateNumFmt(format) {
1442
- // Check if already exists
1566
+ // Check built-in formats first (IDs 0-163)
1567
+ const builtinId = BUILTIN_NUM_FMTS.get(format);
1568
+ if (builtinId !== undefined) {
1569
+ return builtinId;
1570
+ }
1571
+ // Check if already exists in custom formats
1443
1572
  for (const [id, code] of this._numFmts){
1444
1573
  if (code === format) return id;
1445
1574
  }
1446
- // Create new (custom formats start at 164)
1447
- const id = Math.max(164, ...Array.from(this._numFmts.keys())) + 1;
1575
+ // Create new custom format (IDs 164+)
1576
+ const existingIds = Array.from(this._numFmts.keys());
1577
+ const id = existingIds.length > 0 ? Math.max(...existingIds) + 1 : 164;
1448
1578
  this._numFmts.set(id, format);
1449
1579
  return id;
1450
1580
  }
1451
1581
  /**
1582
+ * Get or create a number format ID for the given format string.
1583
+ * Returns built-in IDs (0-163) for standard formats, or creates custom IDs (164+).
1584
+ * @param format - The number format string (e.g., '0.00', '#,##0', '$#,##0.00')
1585
+ */ getOrCreateNumFmtId(format) {
1586
+ this._dirty = true;
1587
+ return this._findOrCreateNumFmt(format);
1588
+ }
1589
+ /**
1452
1590
  * Check if styles have been modified
1453
1591
  */ get dirty() {
1454
1592
  return this._dirty;
@@ -1628,6 +1766,7 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
1628
1766
  this._columnFields = [];
1629
1767
  this._valueFields = [];
1630
1768
  this._filterFields = [];
1769
+ this._styles = null;
1631
1770
  this._name = name;
1632
1771
  this._cache = cache;
1633
1772
  this._targetSheet = targetSheet;
@@ -1662,6 +1801,13 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
1662
1801
  return this._pivotTableIndex;
1663
1802
  }
1664
1803
  /**
1804
+ * Set the styles reference for number format resolution
1805
+ * @internal
1806
+ */ setStyles(styles) {
1807
+ this._styles = styles;
1808
+ return this;
1809
+ }
1810
+ /**
1665
1811
  * Add a field to the row area
1666
1812
  * @param fieldName - Name of the source field (column header)
1667
1813
  */ addRowField(fieldName) {
@@ -1696,7 +1842,8 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
1696
1842
  * @param fieldName - Name of the source field (column header)
1697
1843
  * @param aggregation - Aggregation function (sum, count, average, min, max)
1698
1844
  * @param displayName - Optional display name (defaults to "Sum of FieldName")
1699
- */ addValueField(fieldName, aggregation = 'sum', displayName) {
1845
+ * @param numberFormat - Optional number format (e.g., '$#,##0.00', '0.00%')
1846
+ */ addValueField(fieldName, aggregation = 'sum', displayName, numberFormat) {
1700
1847
  const fieldIndex = this._cache.getFieldIndex(fieldName);
1701
1848
  if (fieldIndex < 0) {
1702
1849
  throw new Error(`Field not found in source data: ${fieldName}`);
@@ -1707,7 +1854,8 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
1707
1854
  fieldIndex,
1708
1855
  axis: 'value',
1709
1856
  aggregation,
1710
- displayName: displayName || defaultName
1857
+ displayName: displayName || defaultName,
1858
+ numberFormat
1711
1859
  });
1712
1860
  return this;
1713
1861
  }
@@ -1830,17 +1978,26 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
1830
1978
  }
1831
1979
  // Data fields (values)
1832
1980
  if (this._valueFields.length > 0) {
1833
- const dataFieldNodes = this._valueFields.map((f)=>createElement('dataField', {
1981
+ const dataFieldNodes = this._valueFields.map((f)=>{
1982
+ const attrs = {
1834
1983
  name: f.displayName || f.fieldName,
1835
1984
  fld: String(f.fieldIndex),
1836
1985
  baseField: '0',
1837
1986
  baseItem: '0',
1838
1987
  subtotal: f.aggregation || 'sum'
1839
- }, []));
1988
+ };
1989
+ // Add numFmtId if format specified and styles available
1990
+ if (f.numberFormat && this._styles) {
1991
+ attrs.numFmtId = String(this._styles.getOrCreateNumFmtId(f.numberFormat));
1992
+ }
1993
+ return createElement('dataField', attrs, []);
1994
+ });
1840
1995
  children.push(createElement('dataFields', {
1841
1996
  count: String(dataFieldNodes.length)
1842
1997
  }, dataFieldNodes));
1843
1998
  }
1999
+ // Check if any value field has a number format
2000
+ const hasNumberFormats = this._valueFields.some((f)=>f.numberFormat);
1844
2001
  // Pivot table style
1845
2002
  children.push(createElement('pivotTableStyleInfo', {
1846
2003
  name: 'PivotStyleMedium9',
@@ -1855,7 +2012,7 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
1855
2012
  'xmlns:r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
1856
2013
  name: this._name,
1857
2014
  cacheId: String(this._cache.cacheId),
1858
- applyNumberFormats: '0',
2015
+ applyNumberFormats: hasNumberFormats ? '1' : '0',
1859
2016
  applyBorderFormats: '0',
1860
2017
  applyFontFormats: '0',
1861
2018
  applyPatternFormats: '0',
@@ -2789,6 +2946,8 @@ const builder = new fastXmlParser.XMLBuilder(builderOptions);
2789
2946
  // Create pivot table
2790
2947
  const pivotTableIndex = this._pivotTables.length + 1;
2791
2948
  const pivotTable = new PivotTable(config.name, cache, targetSheet, targetCell, targetAddr.row + 1, targetAddr.col, pivotTableIndex);
2949
+ // Set styles reference for number format resolution
2950
+ pivotTable.setStyles(this._styles);
2792
2951
  this._pivotTables.push(pivotTable);
2793
2952
  return pivotTable;
2794
2953
  }
package/dist/index.d.cts CHANGED
@@ -521,6 +521,12 @@ declare class Styles {
521
521
  private _findOrCreateFill;
522
522
  private _findOrCreateBorder;
523
523
  private _findOrCreateNumFmt;
524
+ /**
525
+ * Get or create a number format ID for the given format string.
526
+ * Returns built-in IDs (0-163) for standard formats, or creates custom IDs (164+).
527
+ * @param format - The number format string (e.g., '0.00', '#,##0', '$#,##0.00')
528
+ */
529
+ getOrCreateNumFmtId(format: string): number;
524
530
  /**
525
531
  * Check if styles have been modified
526
532
  */
@@ -620,6 +626,7 @@ declare class PivotTable {
620
626
  private _valueFields;
621
627
  private _filterFields;
622
628
  private _pivotTableIndex;
629
+ private _styles;
623
630
  constructor(name: string, cache: PivotCache, targetSheet: string, targetCell: string, targetRow: number, targetCol: number, pivotTableIndex: number);
624
631
  /**
625
632
  * Get the pivot table name
@@ -641,6 +648,11 @@ declare class PivotTable {
641
648
  * Get the pivot table index (for file naming)
642
649
  */
643
650
  get index(): number;
651
+ /**
652
+ * Set the styles reference for number format resolution
653
+ * @internal
654
+ */
655
+ setStyles(styles: Styles): this;
644
656
  /**
645
657
  * Add a field to the row area
646
658
  * @param fieldName - Name of the source field (column header)
@@ -656,8 +668,9 @@ declare class PivotTable {
656
668
  * @param fieldName - Name of the source field (column header)
657
669
  * @param aggregation - Aggregation function (sum, count, average, min, max)
658
670
  * @param displayName - Optional display name (defaults to "Sum of FieldName")
671
+ * @param numberFormat - Optional number format (e.g., '$#,##0.00', '0.00%')
659
672
  */
660
- addValueField(fieldName: string, aggregation?: AggregationType, displayName?: string): this;
673
+ addValueField(fieldName: string, aggregation?: AggregationType, displayName?: string, numberFormat?: string): this;
661
674
  /**
662
675
  * Add a field to the filter (page) area
663
676
  * @param fieldName - Name of the source field (column header)