@cj-tech-master/excelts 2.0.0 → 2.0.1-canary.20251228093548.379d895
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/browser/excelts.esm.js +217 -126
- package/dist/browser/excelts.esm.js.map +1 -1
- package/dist/browser/excelts.esm.min.js +37 -34
- package/dist/browser/excelts.iife.js +217 -126
- package/dist/browser/excelts.iife.js.map +1 -1
- package/dist/browser/excelts.iife.min.js +37 -34
- package/dist/cjs/doc/pivot-table.js +37 -3
- package/dist/cjs/doc/worksheet.js +0 -1
- package/dist/cjs/stream/xlsx/worksheet-writer.js +0 -1
- package/dist/cjs/utils/datetime.js +7 -156
- package/dist/cjs/xlsx/xform/book/sheet-xform.js +3 -2
- package/dist/cjs/xlsx/xform/book/workbook-properties-xform.js +1 -1
- package/dist/cjs/xlsx/xform/core/content-types-xform.js +12 -6
- package/dist/cjs/xlsx/xform/pivot-table/cache-field.js +11 -4
- package/dist/cjs/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +4 -11
- package/dist/cjs/xlsx/xform/pivot-table/pivot-table-xform.js +124 -17
- package/dist/cjs/xlsx/xform/sheet/page-setup-xform.js +4 -3
- package/dist/cjs/xlsx/xform/sheet/row-xform.js +1 -1
- package/dist/cjs/xlsx/xform/sheet/sheet-format-properties-xform.js +6 -3
- package/dist/cjs/xlsx/xform/sheet/sheet-view-xform.js +8 -4
- package/dist/cjs/xlsx/xform/sheet/worksheet-xform.js +2 -2
- package/dist/cjs/xlsx/xform/style/font-xform.js +36 -23
- package/dist/cjs/xlsx/xform/table/auto-filter-xform.js +3 -1
- package/dist/cjs/xlsx/xform/table/table-column-xform.js +2 -1
- package/dist/cjs/xlsx/xform/table/table-xform.js +5 -9
- package/dist/esm/doc/pivot-table.js +37 -3
- package/dist/esm/doc/worksheet.js +0 -1
- package/dist/esm/stream/xlsx/worksheet-writer.js +0 -1
- package/dist/esm/utils/datetime.js +7 -153
- package/dist/esm/xlsx/xform/book/sheet-xform.js +3 -2
- package/dist/esm/xlsx/xform/book/workbook-properties-xform.js +1 -1
- package/dist/esm/xlsx/xform/core/content-types-xform.js +12 -6
- package/dist/esm/xlsx/xform/pivot-table/cache-field.js +11 -4
- package/dist/esm/xlsx/xform/pivot-table/pivot-cache-definition-xform.js +4 -11
- package/dist/esm/xlsx/xform/pivot-table/pivot-table-xform.js +124 -17
- package/dist/esm/xlsx/xform/sheet/page-setup-xform.js +4 -3
- package/dist/esm/xlsx/xform/sheet/row-xform.js +1 -1
- package/dist/esm/xlsx/xform/sheet/sheet-format-properties-xform.js +6 -3
- package/dist/esm/xlsx/xform/sheet/sheet-view-xform.js +8 -4
- package/dist/esm/xlsx/xform/sheet/worksheet-xform.js +2 -2
- package/dist/esm/xlsx/xform/style/font-xform.js +36 -23
- package/dist/esm/xlsx/xform/table/auto-filter-xform.js +3 -1
- package/dist/esm/xlsx/xform/table/table-column-xform.js +2 -1
- package/dist/esm/xlsx/xform/table/table-xform.js +5 -9
- package/dist/types/csv/csv-core.d.ts +0 -6
- package/dist/types/doc/pivot-table.d.ts +5 -1
- package/dist/types/stream/xlsx/workbook-reader.d.ts +1 -1
- package/dist/types/stream/xlsx/worksheet-reader.d.ts +1 -1
- package/dist/types/stream/xlsx/worksheet-writer.d.ts +1 -1
- package/dist/types/types.d.ts +1 -1
- package/dist/types/utils/datetime.d.ts +0 -29
- package/dist/types/xlsx/xform/pivot-table/cache-field.d.ts +5 -1
- package/dist/types/xlsx/xform/pivot-table/pivot-cache-definition-xform.d.ts +0 -5
- package/dist/types/xlsx/xform/pivot-table/pivot-table-xform.d.ts +0 -3
- package/dist/types/xlsx/xform/sheet/sheet-format-properties-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/sheet/worksheet-xform.d.ts +1 -1
- package/dist/types/xlsx/xform/style/font-xform.d.ts +1 -0
- package/dist/types/xlsx/xform/table/table-xform.d.ts +0 -4
- package/package.json +1 -1
|
@@ -55,12 +55,31 @@ class PivotTableXform extends BaseXform {
|
|
|
55
55
|
*/
|
|
56
56
|
renderNew(xmlStream, model) {
|
|
57
57
|
const { rows, columns, values, cacheFields, cacheId, applyWidthHeightFormats } = model;
|
|
58
|
-
//
|
|
59
|
-
const
|
|
58
|
+
// Build rowItems - need one <i> for each unique value in row fields, plus grand total
|
|
59
|
+
const rowItems = buildRowItems(rows, cacheFields);
|
|
60
|
+
// Build colItems - need one <i> for each unique value in col fields, plus grand total
|
|
61
|
+
const colItems = buildColItems(columns, cacheFields, values.length);
|
|
62
|
+
// Calculate pivot table dimensions
|
|
63
|
+
const rowFieldItemCount = rows.length > 0 ? cacheFields[rows[0]]?.sharedItems?.length || 0 : 0;
|
|
64
|
+
const colFieldItemCount = columns.length > 0 ? cacheFields[columns[0]]?.sharedItems?.length || 0 : 0;
|
|
65
|
+
// Location: A3 is where pivot table starts
|
|
66
|
+
// - firstHeaderRow: 1 (column headers are in first row of pivot table)
|
|
67
|
+
// - firstDataRow: 2 (data starts in second row)
|
|
68
|
+
// - firstDataCol: 1 (data starts in second column, after row labels)
|
|
69
|
+
// Calculate ref based on actual data size:
|
|
70
|
+
// - Start row: 3
|
|
71
|
+
// - Header rows: 2 (column label row + subheader row)
|
|
72
|
+
// - Data rows: rowFieldItemCount
|
|
73
|
+
// - Grand total row: 1
|
|
74
|
+
// endRow = 3 + 2 + rowFieldItemCount + 1 - 1 = 5 + rowFieldItemCount
|
|
75
|
+
// Or simplified: startRow (3) + 1 (column labels) + rowFieldItemCount (data) + 1 (grand total)
|
|
76
|
+
const endRow = 3 + 1 + rowFieldItemCount + 1; // = 5 + rowFieldItemCount
|
|
77
|
+
const endCol = 1 + colFieldItemCount + 1; // start col + data cols + grand total
|
|
78
|
+
const endColLetter = String.fromCharCode(64 + endCol);
|
|
79
|
+
const locationRef = `A3:${endColLetter}${endRow}`;
|
|
60
80
|
xmlStream.openXml(XmlStream.StdDocAttributes);
|
|
61
81
|
xmlStream.openNode(this.tag, {
|
|
62
82
|
...PivotTableXform.PIVOT_TABLE_ATTRIBUTES,
|
|
63
|
-
"xr:uid": uniqueUid,
|
|
64
83
|
name: "PivotTable2",
|
|
65
84
|
cacheId,
|
|
66
85
|
applyNumberFormats: "0",
|
|
@@ -81,23 +100,23 @@ class PivotTableXform extends BaseXform {
|
|
|
81
100
|
multipleFieldFilters: "0"
|
|
82
101
|
});
|
|
83
102
|
xmlStream.writeXml(`
|
|
84
|
-
<location ref="
|
|
103
|
+
<location ref="${locationRef}" firstHeaderRow="1" firstDataRow="2" firstDataCol="1" />
|
|
85
104
|
<pivotFields count="${cacheFields.length}">
|
|
86
105
|
${renderPivotFields(model)}
|
|
87
106
|
</pivotFields>
|
|
88
107
|
<rowFields count="${rows.length}">
|
|
89
108
|
${rows.map(rowIndex => `<field x="${rowIndex}" />`).join("\n ")}
|
|
90
109
|
</rowFields>
|
|
91
|
-
<rowItems count="
|
|
92
|
-
|
|
110
|
+
<rowItems count="${rowItems.count}">
|
|
111
|
+
${rowItems.xml}
|
|
93
112
|
</rowItems>
|
|
94
113
|
<colFields count="${columns.length === 0 ? 1 : columns.length}">
|
|
95
114
|
${columns.length === 0
|
|
96
115
|
? '<field x="-2" />'
|
|
97
116
|
: columns.map(columnIndex => `<field x="${columnIndex}" />`).join("\n ")}
|
|
98
117
|
</colFields>
|
|
99
|
-
<colItems count="
|
|
100
|
-
|
|
118
|
+
<colItems count="${colItems.count}">
|
|
119
|
+
${colItems.xml}
|
|
101
120
|
</colItems>
|
|
102
121
|
<dataFields count="${values.length}">
|
|
103
122
|
${buildDataFields(cacheFields, values, model.metric)}
|
|
@@ -137,11 +156,9 @@ class PivotTableXform extends BaseXform {
|
|
|
137
156
|
* Render loaded pivot table (preserving original structure)
|
|
138
157
|
*/
|
|
139
158
|
renderLoaded(xmlStream, model) {
|
|
140
|
-
const uniqueUid = model.uid || `{${crypto.randomUUID().toUpperCase()}}`;
|
|
141
159
|
xmlStream.openXml(XmlStream.StdDocAttributes);
|
|
142
160
|
xmlStream.openNode(this.tag, {
|
|
143
161
|
...PivotTableXform.PIVOT_TABLE_ATTRIBUTES,
|
|
144
|
-
"xr:uid": uniqueUid,
|
|
145
162
|
name: model.name || "PivotTable1",
|
|
146
163
|
cacheId: model.cacheId,
|
|
147
164
|
applyNumberFormats: model.applyNumberFormats || "0",
|
|
@@ -454,12 +471,92 @@ class PivotTableXform extends BaseXform {
|
|
|
454
471
|
}
|
|
455
472
|
}
|
|
456
473
|
PivotTableXform.PIVOT_TABLE_ATTRIBUTES = {
|
|
457
|
-
xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
458
|
-
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
|
459
|
-
"mc:Ignorable": "xr",
|
|
460
|
-
"xmlns:xr": "http://schemas.microsoft.com/office/spreadsheetml/2014/revision"
|
|
474
|
+
xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
461
475
|
};
|
|
462
476
|
// Helpers
|
|
477
|
+
/**
|
|
478
|
+
* Build rowItems XML - one item for each unique value in row fields, plus grand total.
|
|
479
|
+
* Each <i> represents a row in the pivot table.
|
|
480
|
+
* - Regular items: <i><x/></i> for index 0, <i><x v="index"/></i> for index > 0
|
|
481
|
+
* - Grand total: <i t="grand"><x/></i>
|
|
482
|
+
* Note: When v=0, the v attribute should be omitted (Excel convention)
|
|
483
|
+
*/
|
|
484
|
+
function buildRowItems(rows, cacheFields) {
|
|
485
|
+
if (rows.length === 0) {
|
|
486
|
+
// No row fields - just grand total
|
|
487
|
+
return { count: 1, xml: '<i t="grand"><x /></i>' };
|
|
488
|
+
}
|
|
489
|
+
// Get unique values count from the first row field
|
|
490
|
+
const rowFieldIndex = rows[0];
|
|
491
|
+
const sharedItems = cacheFields[rowFieldIndex]?.sharedItems || [];
|
|
492
|
+
const itemCount = sharedItems.length;
|
|
493
|
+
// Build items: one for each unique value + grand total
|
|
494
|
+
const items = [];
|
|
495
|
+
// Regular items - reference each unique value by index
|
|
496
|
+
// Note: v="0" should be omitted (Excel uses <x/> instead of <x v="0"/>)
|
|
497
|
+
for (let i = 0; i < itemCount; i++) {
|
|
498
|
+
if (i === 0) {
|
|
499
|
+
items.push("<i><x /></i>");
|
|
500
|
+
}
|
|
501
|
+
else {
|
|
502
|
+
items.push(`<i><x v="${i}" /></i>`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
// Grand total row
|
|
506
|
+
items.push('<i t="grand"><x /></i>');
|
|
507
|
+
return {
|
|
508
|
+
count: items.length,
|
|
509
|
+
xml: items.join("\n ")
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Build colItems XML - one item for each unique value in column fields, plus grand total.
|
|
514
|
+
* When there are multiple data fields (values), each column value may have sub-columns.
|
|
515
|
+
* Note: When v=0, the v attribute should be omitted (Excel convention)
|
|
516
|
+
*/
|
|
517
|
+
function buildColItems(columns, cacheFields, valueCount) {
|
|
518
|
+
if (columns.length === 0) {
|
|
519
|
+
// No column fields - columns are based on data fields (values)
|
|
520
|
+
if (valueCount > 1) {
|
|
521
|
+
// Multiple values: one column per value + grand total
|
|
522
|
+
const items = [];
|
|
523
|
+
for (let i = 0; i < valueCount; i++) {
|
|
524
|
+
if (i === 0) {
|
|
525
|
+
items.push("<i><x /></i>");
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
items.push(`<i><x v="${i}" /></i>`);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
items.push('<i t="grand"><x /></i>');
|
|
532
|
+
return { count: items.length, xml: items.join("\n ") };
|
|
533
|
+
}
|
|
534
|
+
// Single value: just grand total
|
|
535
|
+
return { count: 1, xml: '<i t="grand"><x /></i>' };
|
|
536
|
+
}
|
|
537
|
+
// Get unique values count from the first column field
|
|
538
|
+
const colFieldIndex = columns[0];
|
|
539
|
+
const sharedItems = cacheFields[colFieldIndex]?.sharedItems || [];
|
|
540
|
+
const itemCount = sharedItems.length;
|
|
541
|
+
// Build items: one for each unique value + grand total
|
|
542
|
+
const items = [];
|
|
543
|
+
// Regular items - reference each unique value by index
|
|
544
|
+
// Note: v="0" should be omitted (Excel uses <x/> instead of <x v="0"/>)
|
|
545
|
+
for (let i = 0; i < itemCount; i++) {
|
|
546
|
+
if (i === 0) {
|
|
547
|
+
items.push("<i><x /></i>");
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
items.push(`<i><x v="${i}" /></i>`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
// Grand total column
|
|
554
|
+
items.push('<i t="grand"><x /></i>');
|
|
555
|
+
return {
|
|
556
|
+
count: items.length,
|
|
557
|
+
xml: items.join("\n ")
|
|
558
|
+
};
|
|
559
|
+
}
|
|
463
560
|
/**
|
|
464
561
|
* Build dataField XML elements for all values in the pivot table.
|
|
465
562
|
* Supports multiple values when columns is empty.
|
|
@@ -497,17 +594,27 @@ function renderPivotFields(pivotTable) {
|
|
|
497
594
|
}
|
|
498
595
|
function renderPivotField(fieldType, sharedItems) {
|
|
499
596
|
// fieldType: 'row', 'column', 'value', null
|
|
500
|
-
|
|
597
|
+
// Note: defaultSubtotal="0" should only be on value fields and non-axis fields,
|
|
598
|
+
// NOT on row/column axis fields (Excel will auto-calculate subtotals for them)
|
|
501
599
|
if (fieldType === "row" || fieldType === "column") {
|
|
502
600
|
const axis = fieldType === "row" ? "axisRow" : "axisCol";
|
|
601
|
+
// Row and column fields should NOT have defaultSubtotal="0"
|
|
602
|
+
const axisAttributes = 'compact="0" outline="0" showAll="0"';
|
|
603
|
+
// items = one for each shared item + one default item
|
|
604
|
+
const itemsXml = [
|
|
605
|
+
...sharedItems.map((_item, index) => `<item x="${index}" />`),
|
|
606
|
+
'<item t="default" />' // Required default item for subtotals/grand totals
|
|
607
|
+
].join("\n ");
|
|
503
608
|
return `
|
|
504
|
-
<pivotField axis="${axis}" ${
|
|
609
|
+
<pivotField axis="${axis}" ${axisAttributes}>
|
|
505
610
|
<items count="${sharedItems.length + 1}">
|
|
506
|
-
${
|
|
611
|
+
${itemsXml}
|
|
507
612
|
</items>
|
|
508
613
|
</pivotField>
|
|
509
614
|
`;
|
|
510
615
|
}
|
|
616
|
+
// Value fields and non-axis fields should have defaultSubtotal="0"
|
|
617
|
+
const defaultAttributes = 'compact="0" outline="0" showAll="0" defaultSubtotal="0"';
|
|
511
618
|
return `
|
|
512
619
|
<pivotField
|
|
513
620
|
${fieldType === "value" ? 'dataField="1"' : ""}
|
|
@@ -48,9 +48,10 @@ class PageSetupXform extends BaseXform {
|
|
|
48
48
|
draft: booleanToXml(model.draft),
|
|
49
49
|
cellComments: cellCommentsToXml(model.cellComments),
|
|
50
50
|
errors: errorsToXml(model.errors),
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// Only output non-default values (matches Excel behavior)
|
|
52
|
+
scale: model.scale !== 100 ? model.scale : undefined,
|
|
53
|
+
fitToWidth: model.fitToWidth !== 1 ? model.fitToWidth : undefined,
|
|
54
|
+
fitToHeight: model.fitToHeight !== 1 ? model.fitToHeight : undefined,
|
|
54
55
|
firstPageNumber: model.firstPageNumber,
|
|
55
56
|
useFirstPageNumber: booleanToXml(!!model.firstPageNumber),
|
|
56
57
|
usePrinterDefaults: booleanToXml(model.usePrinterDefaults),
|
|
@@ -48,7 +48,7 @@ class RowXform extends BaseXform {
|
|
|
48
48
|
xmlStream.addAttribute("s", model.styleId);
|
|
49
49
|
xmlStream.addAttribute("customFormat", "1");
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
// Note: dyDescent is MS extension, not output by default (Excel auto-calculates)
|
|
52
52
|
if (model.outlineLevel) {
|
|
53
53
|
xmlStream.addAttribute("outlineLevel", model.outlineLevel);
|
|
54
54
|
}
|
|
@@ -7,10 +7,13 @@ class SheetFormatPropertiesXform extends BaseXform {
|
|
|
7
7
|
if (model) {
|
|
8
8
|
const attributes = {
|
|
9
9
|
defaultRowHeight: model.defaultRowHeight,
|
|
10
|
-
outlineLevelRow
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
// Only output outlineLevelRow/Col when non-zero (matches Excel behavior)
|
|
11
|
+
outlineLevelRow: model.outlineLevelRow || undefined,
|
|
12
|
+
outlineLevelCol: model.outlineLevelCol || undefined,
|
|
13
|
+
// Only output dyDescent if explicitly set (MS extension, not ECMA-376 standard)
|
|
14
|
+
"x14ac:dyDescent": model.dyDescent || undefined
|
|
13
15
|
};
|
|
16
|
+
// Only output defaultColWidth if explicitly set
|
|
14
17
|
if (model.defaultColWidth) {
|
|
15
18
|
attributes.defaultColWidth = model.defaultColWidth;
|
|
16
19
|
}
|
|
@@ -20,16 +20,20 @@ class SheetViewXform extends BaseXform {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
render(xmlStream, model) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
// Build initial attributes with correct order to match Excel output
|
|
24
|
+
const initialAttrs = {};
|
|
25
|
+
if (model.tabSelected) {
|
|
26
|
+
initialAttrs.tabSelected = "1";
|
|
27
|
+
}
|
|
28
|
+
initialAttrs.workbookViewId = model.workbookViewId || 0;
|
|
29
|
+
xmlStream.openNode("sheetView", initialAttrs);
|
|
26
30
|
const add = function (name, value, included) {
|
|
27
31
|
if (included) {
|
|
28
32
|
xmlStream.addAttribute(name, value);
|
|
29
33
|
}
|
|
30
34
|
};
|
|
31
35
|
add("rightToLeft", "1", model.rightToLeft === true);
|
|
32
|
-
|
|
36
|
+
// tabSelected is now in initialAttrs
|
|
33
37
|
add("showRuler", "0", model.showRuler === false);
|
|
34
38
|
add("showRowColHeaders", "0", model.showRowColHeaders === false);
|
|
35
39
|
add("showGridLines", "0", model.showGridLines === false);
|
|
@@ -511,7 +511,7 @@ WorkSheetXform.WORKSHEET_ATTRIBUTES = {
|
|
|
511
511
|
xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
|
512
512
|
"xmlns:r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
|
513
513
|
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
|
514
|
-
"
|
|
515
|
-
"
|
|
514
|
+
"xmlns:x14ac": "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac",
|
|
515
|
+
"mc:Ignorable": "x14ac"
|
|
516
516
|
};
|
|
517
517
|
export { WorkSheetXform };
|
|
@@ -9,35 +9,48 @@ class FontXform extends BaseXform {
|
|
|
9
9
|
constructor(options) {
|
|
10
10
|
super();
|
|
11
11
|
this.options = options || FontXform.OPTIONS;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
12
|
+
// Define properties in render order (Excel's expected order)
|
|
13
|
+
const fontProperties = [
|
|
14
|
+
{ tag: "b", prop: "bold", xform: new BooleanXform({ tag: "b", attr: "val" }) },
|
|
15
|
+
{ tag: "i", prop: "italic", xform: new BooleanXform({ tag: "i", attr: "val" }) },
|
|
16
|
+
{ tag: "u", prop: "underline", xform: new UnderlineXform() },
|
|
17
|
+
{ tag: "strike", prop: "strike", xform: new BooleanXform({ tag: "strike", attr: "val" }) },
|
|
18
|
+
{
|
|
19
|
+
tag: "condense",
|
|
20
|
+
prop: "condense",
|
|
21
|
+
xform: new BooleanXform({ tag: "condense", attr: "val" })
|
|
22
|
+
},
|
|
23
|
+
{ tag: "extend", prop: "extend", xform: new BooleanXform({ tag: "extend", attr: "val" }) },
|
|
24
|
+
{ tag: "outline", prop: "outline", xform: new BooleanXform({ tag: "outline", attr: "val" }) },
|
|
25
|
+
{ tag: "shadow", prop: "shadow", xform: new BooleanXform({ tag: "shadow", attr: "val" }) },
|
|
26
|
+
{ tag: "sz", prop: "size", xform: new IntegerXform({ tag: "sz", attr: "val" }) },
|
|
27
|
+
{ tag: "color", prop: "color", xform: new ColorXform() },
|
|
28
|
+
{
|
|
29
|
+
tag: this.options.fontNameTag,
|
|
30
|
+
prop: "name",
|
|
31
|
+
xform: new StringXform({ tag: this.options.fontNameTag, attr: "val" })
|
|
32
|
+
},
|
|
33
|
+
{ tag: "family", prop: "family", xform: new IntegerXform({ tag: "family", attr: "val" }) },
|
|
34
|
+
{ tag: "scheme", prop: "scheme", xform: new StringXform({ tag: "scheme", attr: "val" }) },
|
|
35
|
+
{ tag: "charset", prop: "charset", xform: new IntegerXform({ tag: "charset", attr: "val" }) },
|
|
36
|
+
{
|
|
37
|
+
tag: "vertAlign",
|
|
38
|
+
prop: "vertAlign",
|
|
39
|
+
xform: new StringXform({ tag: "vertAlign", attr: "val" })
|
|
40
|
+
}
|
|
41
|
+
];
|
|
42
|
+
// Build map and renderOrder from single source of truth
|
|
43
|
+
this.map = Object.fromEntries(fontProperties.map(p => [p.tag, { prop: p.prop, xform: p.xform }]));
|
|
44
|
+
this.renderOrder = fontProperties.map(p => p.tag);
|
|
32
45
|
}
|
|
33
46
|
get tag() {
|
|
34
47
|
return this.options.tagName;
|
|
35
48
|
}
|
|
36
49
|
render(xmlStream, model) {
|
|
37
|
-
const { map } = this;
|
|
50
|
+
const { map, renderOrder } = this;
|
|
38
51
|
xmlStream.openNode(this.options.tagName);
|
|
39
|
-
|
|
40
|
-
map[tag].xform.render(xmlStream, model[
|
|
52
|
+
renderOrder.forEach(tag => {
|
|
53
|
+
map[tag].xform.render(xmlStream, model[map[tag].prop]);
|
|
41
54
|
});
|
|
42
55
|
xmlStream.closeNode();
|
|
43
56
|
}
|
|
@@ -17,7 +17,9 @@ class AutoFilterXform extends BaseXform {
|
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
19
|
render(xmlStream, model) {
|
|
20
|
-
xmlStream.openNode(this.tag, {
|
|
20
|
+
xmlStream.openNode(this.tag, {
|
|
21
|
+
ref: model.autoFilterRef
|
|
22
|
+
});
|
|
21
23
|
model.columns.forEach((column) => {
|
|
22
24
|
this.map.filterColumn.render(xmlStream, column);
|
|
23
25
|
});
|
|
@@ -15,7 +15,8 @@ class TableColumnXform extends BaseXform {
|
|
|
15
15
|
id: model.id.toString(),
|
|
16
16
|
name: model.name,
|
|
17
17
|
totalsRowLabel: model.totalsRowLabel,
|
|
18
|
-
totalsRowFunction
|
|
18
|
+
// Excel doesn't output totalsRowFunction when value is 'none'
|
|
19
|
+
totalsRowFunction: model.totalsRowFunction === "none" ? undefined : model.totalsRowFunction,
|
|
19
20
|
dxfId: model.dxfId
|
|
20
21
|
});
|
|
21
22
|
}
|
|
@@ -40,8 +40,8 @@ class TableXform extends BaseXform {
|
|
|
40
40
|
displayName: model.displayName || model.name,
|
|
41
41
|
ref: model.tableRef,
|
|
42
42
|
totalsRowCount: model.totalsRow ? "1" : undefined,
|
|
43
|
-
|
|
44
|
-
headerRowCount: model.headerRow ?
|
|
43
|
+
// Excel doesn't output headerRowCount when it's 1 (default) or when there's a header row
|
|
44
|
+
headerRowCount: model.headerRow ? undefined : "0"
|
|
45
45
|
});
|
|
46
46
|
this.map.autoFilter.render(xmlStream, model);
|
|
47
47
|
this.map.tableColumns.render(xmlStream, model.columns);
|
|
@@ -62,7 +62,8 @@ class TableXform extends BaseXform {
|
|
|
62
62
|
displayName: attributes.displayName || attributes.name,
|
|
63
63
|
tableRef: attributes.ref,
|
|
64
64
|
totalsRow: attributes.totalsRowCount === "1",
|
|
65
|
-
|
|
65
|
+
// ECMA-376: headerRowCount defaults to 1, so missing attribute means has header
|
|
66
|
+
headerRow: attributes.headerRowCount !== "0"
|
|
66
67
|
};
|
|
67
68
|
break;
|
|
68
69
|
default:
|
|
@@ -120,11 +121,6 @@ class TableXform extends BaseXform {
|
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
123
|
TableXform.TABLE_ATTRIBUTES = {
|
|
123
|
-
xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
124
|
-
"xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006",
|
|
125
|
-
"mc:Ignorable": "xr xr3",
|
|
126
|
-
"xmlns:xr": "http://schemas.microsoft.com/office/spreadsheetml/2014/revision",
|
|
127
|
-
"xmlns:xr3": "http://schemas.microsoft.com/office/spreadsheetml/2016/revision3"
|
|
128
|
-
// 'xr:uid': '{00000000-000C-0000-FFFF-FFFF00000000}',
|
|
124
|
+
xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
|
129
125
|
};
|
|
130
126
|
export { TableXform };
|
|
@@ -24,12 +24,6 @@ export type RowTransformFunction<I = Row, O = Row> = ((row: I) => O | null) | ((
|
|
|
24
24
|
export type RowValidateCallback = (error?: Error | null, isValid?: boolean, reason?: string) => void;
|
|
25
25
|
/** Row validate function - sync or async */
|
|
26
26
|
export type RowValidateFunction<T = Row> = ((row: T) => boolean) | ((row: T, callback: RowValidateCallback) => void);
|
|
27
|
-
/** Validation result */
|
|
28
|
-
export interface RowValidationResult<T = Row> {
|
|
29
|
-
row: T | null;
|
|
30
|
-
isValid: boolean;
|
|
31
|
-
reason?: string;
|
|
32
|
-
}
|
|
33
27
|
/**
|
|
34
28
|
* CSV parsing options
|
|
35
29
|
*/
|
|
@@ -4,7 +4,7 @@ import type { Table } from "./table";
|
|
|
4
4
|
* This allows both Worksheet and Table to be used as pivot table data sources.
|
|
5
5
|
*/
|
|
6
6
|
export interface PivotTableSource {
|
|
7
|
-
/** Name of the source (
|
|
7
|
+
/** Name of the worksheet containing the source data (used in pivotCacheDefinition) */
|
|
8
8
|
name: string;
|
|
9
9
|
/** Get row values by 1-indexed row number */
|
|
10
10
|
getRow(rowNumber: number): {
|
|
@@ -71,6 +71,10 @@ export interface CacheField {
|
|
|
71
71
|
name: string;
|
|
72
72
|
/** Unique values for row/column fields, null for value fields */
|
|
73
73
|
sharedItems: any[] | null;
|
|
74
|
+
/** Minimum value for numeric fields */
|
|
75
|
+
minValue?: number;
|
|
76
|
+
/** Maximum value for numeric fields */
|
|
77
|
+
maxValue?: number;
|
|
74
78
|
}
|
|
75
79
|
/** Aggregation function types for pivot table data fields */
|
|
76
80
|
export type PivotTableSubtotal = "sum" | "count" | "average" | "max" | "min" | "product" | "countNums" | "stdDev" | "stdDevP" | "var" | "varP";
|
|
@@ -51,7 +51,7 @@ interface EntryPayload {
|
|
|
51
51
|
id?: string;
|
|
52
52
|
}
|
|
53
53
|
/** Parse event types */
|
|
54
|
-
export type ParseEventType = "
|
|
54
|
+
export type ParseEventType = EntryPayload["type"];
|
|
55
55
|
export interface SharedStringEvent {
|
|
56
56
|
eventType: "shared-strings";
|
|
57
57
|
value: {
|
|
@@ -10,7 +10,7 @@ export interface WorksheetHyperlink {
|
|
|
10
10
|
rId: string;
|
|
11
11
|
}
|
|
12
12
|
/** Events emitted during worksheet parsing */
|
|
13
|
-
export type WorksheetEventType = "
|
|
13
|
+
export type WorksheetEventType = RowEvent["eventType"] | HyperlinkEvent["eventType"];
|
|
14
14
|
/** Row event emitted during parsing */
|
|
15
15
|
export interface RowEvent {
|
|
16
16
|
eventType: "row";
|
package/dist/types/types.d.ts
CHANGED
|
@@ -192,7 +192,7 @@ export interface WorksheetProperties {
|
|
|
192
192
|
};
|
|
193
193
|
defaultRowHeight: number;
|
|
194
194
|
defaultColWidth?: number;
|
|
195
|
-
dyDescent
|
|
195
|
+
dyDescent?: number;
|
|
196
196
|
showGridLines: boolean;
|
|
197
197
|
}
|
|
198
198
|
export type WorksheetState = "visible" | "hidden" | "veryHidden";
|
|
@@ -6,35 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
/** Supported date format strings */
|
|
8
8
|
export type DateFormat = "YYYY-MM-DD[T]HH:mm:ssZ" | "YYYY-MM-DD[T]HH:mm:ss" | "YYYY-MM-DD[T]HH:mm:ss.SSSZ" | "YYYY-MM-DD" | "YYYY-MM-DD HH:mm:ss" | "MM-DD-YYYY" | "MM-DD-YYYY HH:mm:ss" | "MM/DD/YYYY HH:mm:ss" | "DD-MM-YYYY" | "DD-MM-YYYY HH:mm:ss" | "DD/MM/YYYY HH:mm:ss";
|
|
9
|
-
/**
|
|
10
|
-
* Quick pre-filter to reject non-date strings
|
|
11
|
-
*/
|
|
12
|
-
export declare function mightBeDate(s: string): boolean;
|
|
13
|
-
/**
|
|
14
|
-
* Parse a date string
|
|
15
|
-
*
|
|
16
|
-
* @param value - String to parse
|
|
17
|
-
* @param formats - Specific formats to try (optional, auto-detects ISO if omitted)
|
|
18
|
-
* @returns Date object or null
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* parseDate("2024-12-26") // auto-detect ISO
|
|
22
|
-
* parseDate("12-26-2024", ["MM-DD-YYYY"]) // explicit US format
|
|
23
|
-
*/
|
|
24
|
-
export declare function parseDate(value: string, formats?: DateFormat[]): Date | null;
|
|
25
|
-
/**
|
|
26
|
-
* Format a Date to string
|
|
27
|
-
*
|
|
28
|
-
* @param date - Date to format
|
|
29
|
-
* @param format - Format template (optional, defaults to ISO)
|
|
30
|
-
* @param utc - Use UTC time (default: false)
|
|
31
|
-
* @returns Formatted string or empty string if invalid
|
|
32
|
-
*
|
|
33
|
-
* @example
|
|
34
|
-
* formatDate(date) // "2024-12-26T10:30:00.000+08:00"
|
|
35
|
-
* formatDate(date, "YYYY-MM-DD", true) // "2024-12-26"
|
|
36
|
-
*/
|
|
37
|
-
export declare function formatDate(date: Date, format?: string, utc?: boolean): string;
|
|
38
9
|
/**
|
|
39
10
|
* Optimized date parser for batch processing
|
|
40
11
|
*
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
interface CacheFieldConfig {
|
|
2
2
|
name: string;
|
|
3
3
|
sharedItems: string[] | null;
|
|
4
|
+
minValue?: number;
|
|
5
|
+
maxValue?: number;
|
|
4
6
|
}
|
|
5
7
|
declare class CacheField {
|
|
6
8
|
private name;
|
|
7
9
|
private sharedItems;
|
|
8
|
-
|
|
10
|
+
private minValue?;
|
|
11
|
+
private maxValue?;
|
|
12
|
+
constructor({ name, sharedItems, minValue, maxValue }: CacheFieldConfig);
|
|
9
13
|
render(): string;
|
|
10
14
|
}
|
|
11
15
|
export { CacheField };
|
|
@@ -11,8 +11,6 @@ interface ParsedCacheDefinitionModel {
|
|
|
11
11
|
recordCount?: number;
|
|
12
12
|
rId?: string;
|
|
13
13
|
refreshOnLoad?: string;
|
|
14
|
-
refreshedBy?: string;
|
|
15
|
-
refreshedDate?: string;
|
|
16
14
|
createdVersion?: string;
|
|
17
15
|
refreshedVersion?: string;
|
|
18
16
|
minRefreshableVersion?: string;
|
|
@@ -57,9 +55,6 @@ declare class PivotCacheDefinitionXform extends BaseXform {
|
|
|
57
55
|
static PIVOT_CACHE_DEFINITION_ATTRIBUTES: {
|
|
58
56
|
xmlns: string;
|
|
59
57
|
"xmlns:r": string;
|
|
60
|
-
"xmlns:mc": string;
|
|
61
|
-
"mc:Ignorable": string;
|
|
62
|
-
"xmlns:xr": string;
|
|
63
58
|
};
|
|
64
59
|
}
|
|
65
60
|
export { PivotCacheDefinitionXform, type ParsedCacheDefinitionModel };
|
|
@@ -114,9 +114,6 @@ declare class PivotTableXform extends BaseXform {
|
|
|
114
114
|
reconcile(_model: any, _options: any): void;
|
|
115
115
|
static PIVOT_TABLE_ATTRIBUTES: {
|
|
116
116
|
xmlns: string;
|
|
117
|
-
"xmlns:mc": string;
|
|
118
|
-
"mc:Ignorable": string;
|
|
119
|
-
"xmlns:xr": string;
|
|
120
117
|
};
|
|
121
118
|
}
|
|
122
119
|
export { PivotTableXform, type ParsedPivotTableModel };
|
|
@@ -7,8 +7,8 @@ declare class WorkSheetXform extends BaseXform {
|
|
|
7
7
|
xmlns: string;
|
|
8
8
|
"xmlns:r": string;
|
|
9
9
|
"xmlns:mc": string;
|
|
10
|
-
"mc:Ignorable": string;
|
|
11
10
|
"xmlns:x14ac": string;
|
|
11
|
+
"mc:Ignorable": string;
|
|
12
12
|
};
|
|
13
13
|
constructor(options?: any);
|
|
14
14
|
prepare(model: any, options: any): void;
|
|
@@ -28,10 +28,6 @@ declare class TableXform extends BaseXform {
|
|
|
28
28
|
reconcile(model: TableModel, options: any): void;
|
|
29
29
|
static TABLE_ATTRIBUTES: {
|
|
30
30
|
xmlns: string;
|
|
31
|
-
"xmlns:mc": string;
|
|
32
|
-
"mc:Ignorable": string;
|
|
33
|
-
"xmlns:xr": string;
|
|
34
|
-
"xmlns:xr3": string;
|
|
35
31
|
};
|
|
36
32
|
}
|
|
37
33
|
export { TableXform };
|
package/package.json
CHANGED