@cj-tech-master/excelts 5.1.9 → 5.1.10-canary.20260306122956.f4bcbe6

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.
@@ -3,6 +3,11 @@ import { Enums } from "./enums.js";
3
3
  import { Note } from "./note.js";
4
4
  import { escapeHtml } from "./utils/under-dash.js";
5
5
  import { slideFormula } from "./utils/shared-formula.js";
6
+ // Returns true if the value is a non-empty object (has at least one own key),
7
+ // or any truthy non-object value. Returns false for undefined, null, false, 0,
8
+ // empty string, and empty objects `{}`. This is used to prevent an empty `{}`
9
+ // style property on a row from shadowing a real style property on a column.
10
+ const hasOwnKeys = (v) => !!v && (typeof v !== "object" || Object.keys(v).length > 0);
6
11
  // Cell requirements
7
12
  // Operate inside a worksheet
8
13
  // Store and retrieve a value with a range of types: text, number, date, hyperlink, reference, formula, etc.
@@ -78,23 +83,28 @@ class Cell {
78
83
  if (numFmt) {
79
84
  style.numFmt = numFmt;
80
85
  }
81
- const font = (rowStyle && rowStyle.font) || (colStyle && colStyle.font);
86
+ const font = (rowStyle && hasOwnKeys(rowStyle.font) && rowStyle.font) ||
87
+ (colStyle && hasOwnKeys(colStyle.font) && colStyle.font);
82
88
  if (font) {
83
89
  style.font = font;
84
90
  }
85
- const alignment = (rowStyle && rowStyle.alignment) || (colStyle && colStyle.alignment);
91
+ const alignment = (rowStyle && hasOwnKeys(rowStyle.alignment) && rowStyle.alignment) ||
92
+ (colStyle && hasOwnKeys(colStyle.alignment) && colStyle.alignment);
86
93
  if (alignment) {
87
94
  style.alignment = alignment;
88
95
  }
89
- const border = (rowStyle && rowStyle.border) || (colStyle && colStyle.border);
96
+ const border = (rowStyle && hasOwnKeys(rowStyle.border) && rowStyle.border) ||
97
+ (colStyle && hasOwnKeys(colStyle.border) && colStyle.border);
90
98
  if (border) {
91
99
  style.border = border;
92
100
  }
93
- const fill = (rowStyle && rowStyle.fill) || (colStyle && colStyle.fill);
101
+ const fill = (rowStyle && hasOwnKeys(rowStyle.fill) && rowStyle.fill) ||
102
+ (colStyle && hasOwnKeys(colStyle.fill) && colStyle.fill);
94
103
  if (fill) {
95
104
  style.fill = fill;
96
105
  }
97
- const protection = (rowStyle && rowStyle.protection) || (colStyle && colStyle.protection);
106
+ const protection = (rowStyle && hasOwnKeys(rowStyle.protection) && rowStyle.protection) ||
107
+ (colStyle && hasOwnKeys(colStyle.protection) && colStyle.protection);
98
108
  if (protection) {
99
109
  style.protection = protection;
100
110
  }
@@ -1,6 +1,7 @@
1
1
  import { Enums } from "./enums.js";
2
2
  import { colCache } from "./utils/col-cache.js";
3
3
  import { Cell } from "./cell.js";
4
+ import { copyStyle } from "./utils/copy-style.js";
4
5
  class Row {
5
6
  constructor(worksheet, number) {
6
7
  this._worksheet = worksheet;
@@ -95,7 +96,7 @@ class Row {
95
96
  if (cSrc) {
96
97
  cDst = this.getCell(i);
97
98
  cDst.value = cSrc.value;
98
- cDst.style = cSrc.style;
99
+ cDst.style = copyStyle(cSrc.style) ?? {};
99
100
  cDst.comment = cSrc.comment;
100
101
  }
101
102
  else if (cDst) {
@@ -112,7 +113,7 @@ class Row {
112
113
  if (cSrc) {
113
114
  cDst = this.getCell(i + nExpand);
114
115
  cDst.value = cSrc.value;
115
- cDst.style = cSrc.style;
116
+ cDst.style = copyStyle(cSrc.style) ?? {};
116
117
  cDst.comment = cSrc.comment;
117
118
  }
118
119
  else {
@@ -207,7 +207,7 @@ class Table {
207
207
  else {
208
208
  cell.value = value;
209
209
  }
210
- assignStyle(cell, table.columns[j].style);
210
+ assignStyle(cell, table.columns[j]?.style);
211
211
  });
212
212
  });
213
213
  if (table.totalsRow) {
@@ -468,6 +468,11 @@ export interface TableColumnProperties {
468
468
  totalsRowFunction?: "none" | "average" | "countNums" | "count" | "max" | "min" | "stdDev" | "var" | "sum" | "custom";
469
469
  totalsRowFormula?: string;
470
470
  totalsRowResult?: CellFormulaValue["result"];
471
+ /**
472
+ * Formula applied to every data row in this column.
473
+ * Corresponds to the OOXML `<calculatedColumnFormula>` element.
474
+ */
475
+ calculatedColumnFormula?: string;
471
476
  style?: Partial<Style>;
472
477
  }
473
478
  export interface TableProperties {
@@ -508,10 +508,10 @@ class Worksheet {
508
508
  // now copy styles...
509
509
  for (let i = 0; i < count; i++) {
510
510
  const rDst = this._rows[rowNum + i];
511
- rDst.style = rSrc.style;
511
+ rDst.style = copyStyle(rSrc.style) ?? {};
512
512
  rDst.height = rSrc.height;
513
513
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
514
- rDst.getCell(colNumber).style = cell.style;
514
+ rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
515
515
  });
516
516
  }
517
517
  // Duplicate single-row merges from source row into each new row
@@ -599,10 +599,10 @@ class Worksheet {
599
599
  if (rSrc) {
600
600
  const rDst = this.getRow(i + nExpand);
601
601
  rDst.values = rSrc.values;
602
- rDst.style = rSrc.style;
602
+ rDst.style = copyStyle(rSrc.style) ?? {};
603
603
  rDst.height = rSrc.height;
604
604
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
605
- rDst.getCell(colNumber).style = cell.style;
605
+ rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
606
606
  });
607
607
  this._rows[i - 1] = undefined;
608
608
  }
@@ -618,10 +618,10 @@ class Worksheet {
618
618
  if (rSrc) {
619
619
  const rDst = this.getRow(i + nExpand);
620
620
  rDst.values = rSrc.values;
621
- rDst.style = rSrc.style;
621
+ rDst.style = copyStyle(rSrc.style) ?? {};
622
622
  rDst.height = rSrc.height;
623
623
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
624
- rDst.getCell(colNumber).style = cell.style;
624
+ rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
625
625
  });
626
626
  }
627
627
  else {
@@ -4,17 +4,22 @@ interface TableColumnModel {
4
4
  name: string;
5
5
  totalsRowLabel?: string;
6
6
  totalsRowFunction?: string;
7
+ totalsRowFormula?: string;
8
+ calculatedColumnFormula?: string;
7
9
  dxfId?: string;
8
10
  }
9
11
  declare class TableColumnXform extends BaseXform<TableColumnModel> {
12
+ private _childTag;
13
+ private _childText;
10
14
  constructor();
11
15
  get tag(): string;
12
16
  prepare(model: TableColumnModel, options: {
13
17
  index: number;
14
18
  }): void;
19
+ private _renderAttributes;
15
20
  render(xmlStream: any, model: TableColumnModel): void;
16
21
  parseOpen(node: any): boolean;
17
- parseText(): void;
18
- parseClose(): boolean;
22
+ parseText(text: string): void;
23
+ parseClose(name: string): boolean;
19
24
  }
20
25
  export { TableColumnXform };
@@ -2,6 +2,7 @@ import { BaseXform } from "../base-xform.js";
2
2
  class TableColumnXform extends BaseXform {
3
3
  constructor() {
4
4
  super();
5
+ this._childText = "";
5
6
  this.model = { name: "" };
6
7
  }
7
8
  get tag() {
@@ -10,15 +11,30 @@ class TableColumnXform extends BaseXform {
10
11
  prepare(model, options) {
11
12
  model.id = options.index + 1;
12
13
  }
13
- render(xmlStream, model) {
14
- xmlStream.leafNode(this.tag, {
14
+ _renderAttributes(model) {
15
+ return {
15
16
  id: model.id.toString(),
16
17
  name: model.name,
17
18
  totalsRowLabel: model.totalsRowLabel,
18
19
  // Excel doesn't output totalsRowFunction when value is 'none'
19
20
  totalsRowFunction: model.totalsRowFunction === "none" ? undefined : model.totalsRowFunction,
20
21
  dxfId: model.dxfId
21
- });
22
+ };
23
+ }
24
+ render(xmlStream, model) {
25
+ if (model.calculatedColumnFormula || model.totalsRowFormula) {
26
+ xmlStream.openNode(this.tag, this._renderAttributes(model));
27
+ if (model.calculatedColumnFormula) {
28
+ xmlStream.leafNode("calculatedColumnFormula", undefined, model.calculatedColumnFormula);
29
+ }
30
+ if (model.totalsRowFormula) {
31
+ xmlStream.leafNode("totalsRowFormula", undefined, model.totalsRowFormula);
32
+ }
33
+ xmlStream.closeNode();
34
+ }
35
+ else {
36
+ xmlStream.leafNode(this.tag, this._renderAttributes(model));
37
+ }
22
38
  }
23
39
  parseOpen(node) {
24
40
  if (node.name === this.tag) {
@@ -31,11 +47,28 @@ class TableColumnXform extends BaseXform {
31
47
  };
32
48
  return true;
33
49
  }
34
- return false;
50
+ // Recognise child elements whose text content we want to capture
51
+ if (node.name === "calculatedColumnFormula" || node.name === "totalsRowFormula") {
52
+ this._childTag = node.name;
53
+ this._childText = "";
54
+ }
55
+ return true;
56
+ }
57
+ parseText(text) {
58
+ if (this._childTag) {
59
+ this._childText += text;
60
+ }
35
61
  }
36
- parseText() { }
37
- parseClose() {
38
- return false;
62
+ parseClose(name) {
63
+ if (name === this.tag) {
64
+ return false;
65
+ }
66
+ // Closing a recognised child element — store captured text
67
+ if (this._childTag && name === this._childTag) {
68
+ this.model[this._childTag] = this._childText;
69
+ this._childTag = undefined;
70
+ }
71
+ return true;
39
72
  }
40
73
  }
41
74
  export { TableColumnXform };
@@ -6,6 +6,11 @@ const enums_1 = require("./enums.js");
6
6
  const note_1 = require("./note.js");
7
7
  const under_dash_1 = require("./utils/under-dash.js");
8
8
  const shared_formula_1 = require("./utils/shared-formula.js");
9
+ // Returns true if the value is a non-empty object (has at least one own key),
10
+ // or any truthy non-object value. Returns false for undefined, null, false, 0,
11
+ // empty string, and empty objects `{}`. This is used to prevent an empty `{}`
12
+ // style property on a row from shadowing a real style property on a column.
13
+ const hasOwnKeys = (v) => !!v && (typeof v !== "object" || Object.keys(v).length > 0);
9
14
  // Cell requirements
10
15
  // Operate inside a worksheet
11
16
  // Store and retrieve a value with a range of types: text, number, date, hyperlink, reference, formula, etc.
@@ -81,23 +86,28 @@ class Cell {
81
86
  if (numFmt) {
82
87
  style.numFmt = numFmt;
83
88
  }
84
- const font = (rowStyle && rowStyle.font) || (colStyle && colStyle.font);
89
+ const font = (rowStyle && hasOwnKeys(rowStyle.font) && rowStyle.font) ||
90
+ (colStyle && hasOwnKeys(colStyle.font) && colStyle.font);
85
91
  if (font) {
86
92
  style.font = font;
87
93
  }
88
- const alignment = (rowStyle && rowStyle.alignment) || (colStyle && colStyle.alignment);
94
+ const alignment = (rowStyle && hasOwnKeys(rowStyle.alignment) && rowStyle.alignment) ||
95
+ (colStyle && hasOwnKeys(colStyle.alignment) && colStyle.alignment);
89
96
  if (alignment) {
90
97
  style.alignment = alignment;
91
98
  }
92
- const border = (rowStyle && rowStyle.border) || (colStyle && colStyle.border);
99
+ const border = (rowStyle && hasOwnKeys(rowStyle.border) && rowStyle.border) ||
100
+ (colStyle && hasOwnKeys(colStyle.border) && colStyle.border);
93
101
  if (border) {
94
102
  style.border = border;
95
103
  }
96
- const fill = (rowStyle && rowStyle.fill) || (colStyle && colStyle.fill);
104
+ const fill = (rowStyle && hasOwnKeys(rowStyle.fill) && rowStyle.fill) ||
105
+ (colStyle && hasOwnKeys(colStyle.fill) && colStyle.fill);
97
106
  if (fill) {
98
107
  style.fill = fill;
99
108
  }
100
- const protection = (rowStyle && rowStyle.protection) || (colStyle && colStyle.protection);
109
+ const protection = (rowStyle && hasOwnKeys(rowStyle.protection) && rowStyle.protection) ||
110
+ (colStyle && hasOwnKeys(colStyle.protection) && colStyle.protection);
101
111
  if (protection) {
102
112
  style.protection = protection;
103
113
  }
@@ -4,6 +4,7 @@ exports.Row = void 0;
4
4
  const enums_1 = require("./enums.js");
5
5
  const col_cache_1 = require("./utils/col-cache.js");
6
6
  const cell_1 = require("./cell.js");
7
+ const copy_style_1 = require("./utils/copy-style.js");
7
8
  class Row {
8
9
  constructor(worksheet, number) {
9
10
  this._worksheet = worksheet;
@@ -98,7 +99,7 @@ class Row {
98
99
  if (cSrc) {
99
100
  cDst = this.getCell(i);
100
101
  cDst.value = cSrc.value;
101
- cDst.style = cSrc.style;
102
+ cDst.style = (0, copy_style_1.copyStyle)(cSrc.style) ?? {};
102
103
  cDst.comment = cSrc.comment;
103
104
  }
104
105
  else if (cDst) {
@@ -115,7 +116,7 @@ class Row {
115
116
  if (cSrc) {
116
117
  cDst = this.getCell(i + nExpand);
117
118
  cDst.value = cSrc.value;
118
- cDst.style = cSrc.style;
119
+ cDst.style = (0, copy_style_1.copyStyle)(cSrc.style) ?? {};
119
120
  cDst.comment = cSrc.comment;
120
121
  }
121
122
  else {
@@ -210,7 +210,7 @@ class Table {
210
210
  else {
211
211
  cell.value = value;
212
212
  }
213
- assignStyle(cell, table.columns[j].style);
213
+ assignStyle(cell, table.columns[j]?.style);
214
214
  });
215
215
  });
216
216
  if (table.totalsRow) {
@@ -511,10 +511,10 @@ class Worksheet {
511
511
  // now copy styles...
512
512
  for (let i = 0; i < count; i++) {
513
513
  const rDst = this._rows[rowNum + i];
514
- rDst.style = rSrc.style;
514
+ rDst.style = (0, copy_style_1.copyStyle)(rSrc.style) ?? {};
515
515
  rDst.height = rSrc.height;
516
516
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
517
- rDst.getCell(colNumber).style = cell.style;
517
+ rDst.getCell(colNumber).style = (0, copy_style_1.copyStyle)(cell.style) ?? {};
518
518
  });
519
519
  }
520
520
  // Duplicate single-row merges from source row into each new row
@@ -602,10 +602,10 @@ class Worksheet {
602
602
  if (rSrc) {
603
603
  const rDst = this.getRow(i + nExpand);
604
604
  rDst.values = rSrc.values;
605
- rDst.style = rSrc.style;
605
+ rDst.style = (0, copy_style_1.copyStyle)(rSrc.style) ?? {};
606
606
  rDst.height = rSrc.height;
607
607
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
608
- rDst.getCell(colNumber).style = cell.style;
608
+ rDst.getCell(colNumber).style = (0, copy_style_1.copyStyle)(cell.style) ?? {};
609
609
  });
610
610
  this._rows[i - 1] = undefined;
611
611
  }
@@ -621,10 +621,10 @@ class Worksheet {
621
621
  if (rSrc) {
622
622
  const rDst = this.getRow(i + nExpand);
623
623
  rDst.values = rSrc.values;
624
- rDst.style = rSrc.style;
624
+ rDst.style = (0, copy_style_1.copyStyle)(rSrc.style) ?? {};
625
625
  rDst.height = rSrc.height;
626
626
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
627
- rDst.getCell(colNumber).style = cell.style;
627
+ rDst.getCell(colNumber).style = (0, copy_style_1.copyStyle)(cell.style) ?? {};
628
628
  });
629
629
  }
630
630
  else {
@@ -5,6 +5,7 @@ const base_xform_1 = require("../base-xform.js");
5
5
  class TableColumnXform extends base_xform_1.BaseXform {
6
6
  constructor() {
7
7
  super();
8
+ this._childText = "";
8
9
  this.model = { name: "" };
9
10
  }
10
11
  get tag() {
@@ -13,15 +14,30 @@ class TableColumnXform extends base_xform_1.BaseXform {
13
14
  prepare(model, options) {
14
15
  model.id = options.index + 1;
15
16
  }
16
- render(xmlStream, model) {
17
- xmlStream.leafNode(this.tag, {
17
+ _renderAttributes(model) {
18
+ return {
18
19
  id: model.id.toString(),
19
20
  name: model.name,
20
21
  totalsRowLabel: model.totalsRowLabel,
21
22
  // Excel doesn't output totalsRowFunction when value is 'none'
22
23
  totalsRowFunction: model.totalsRowFunction === "none" ? undefined : model.totalsRowFunction,
23
24
  dxfId: model.dxfId
24
- });
25
+ };
26
+ }
27
+ render(xmlStream, model) {
28
+ if (model.calculatedColumnFormula || model.totalsRowFormula) {
29
+ xmlStream.openNode(this.tag, this._renderAttributes(model));
30
+ if (model.calculatedColumnFormula) {
31
+ xmlStream.leafNode("calculatedColumnFormula", undefined, model.calculatedColumnFormula);
32
+ }
33
+ if (model.totalsRowFormula) {
34
+ xmlStream.leafNode("totalsRowFormula", undefined, model.totalsRowFormula);
35
+ }
36
+ xmlStream.closeNode();
37
+ }
38
+ else {
39
+ xmlStream.leafNode(this.tag, this._renderAttributes(model));
40
+ }
25
41
  }
26
42
  parseOpen(node) {
27
43
  if (node.name === this.tag) {
@@ -34,11 +50,28 @@ class TableColumnXform extends base_xform_1.BaseXform {
34
50
  };
35
51
  return true;
36
52
  }
37
- return false;
53
+ // Recognise child elements whose text content we want to capture
54
+ if (node.name === "calculatedColumnFormula" || node.name === "totalsRowFormula") {
55
+ this._childTag = node.name;
56
+ this._childText = "";
57
+ }
58
+ return true;
59
+ }
60
+ parseText(text) {
61
+ if (this._childTag) {
62
+ this._childText += text;
63
+ }
38
64
  }
39
- parseText() { }
40
- parseClose() {
41
- return false;
65
+ parseClose(name) {
66
+ if (name === this.tag) {
67
+ return false;
68
+ }
69
+ // Closing a recognised child element — store captured text
70
+ if (this._childTag && name === this._childTag) {
71
+ this.model[this._childTag] = this._childText;
72
+ this._childTag = undefined;
73
+ }
74
+ return true;
42
75
  }
43
76
  }
44
77
  exports.TableColumnXform = TableColumnXform;
@@ -3,6 +3,11 @@ import { Enums } from "./enums.js";
3
3
  import { Note } from "./note.js";
4
4
  import { escapeHtml } from "./utils/under-dash.js";
5
5
  import { slideFormula } from "./utils/shared-formula.js";
6
+ // Returns true if the value is a non-empty object (has at least one own key),
7
+ // or any truthy non-object value. Returns false for undefined, null, false, 0,
8
+ // empty string, and empty objects `{}`. This is used to prevent an empty `{}`
9
+ // style property on a row from shadowing a real style property on a column.
10
+ const hasOwnKeys = (v) => !!v && (typeof v !== "object" || Object.keys(v).length > 0);
6
11
  // Cell requirements
7
12
  // Operate inside a worksheet
8
13
  // Store and retrieve a value with a range of types: text, number, date, hyperlink, reference, formula, etc.
@@ -78,23 +83,28 @@ class Cell {
78
83
  if (numFmt) {
79
84
  style.numFmt = numFmt;
80
85
  }
81
- const font = (rowStyle && rowStyle.font) || (colStyle && colStyle.font);
86
+ const font = (rowStyle && hasOwnKeys(rowStyle.font) && rowStyle.font) ||
87
+ (colStyle && hasOwnKeys(colStyle.font) && colStyle.font);
82
88
  if (font) {
83
89
  style.font = font;
84
90
  }
85
- const alignment = (rowStyle && rowStyle.alignment) || (colStyle && colStyle.alignment);
91
+ const alignment = (rowStyle && hasOwnKeys(rowStyle.alignment) && rowStyle.alignment) ||
92
+ (colStyle && hasOwnKeys(colStyle.alignment) && colStyle.alignment);
86
93
  if (alignment) {
87
94
  style.alignment = alignment;
88
95
  }
89
- const border = (rowStyle && rowStyle.border) || (colStyle && colStyle.border);
96
+ const border = (rowStyle && hasOwnKeys(rowStyle.border) && rowStyle.border) ||
97
+ (colStyle && hasOwnKeys(colStyle.border) && colStyle.border);
90
98
  if (border) {
91
99
  style.border = border;
92
100
  }
93
- const fill = (rowStyle && rowStyle.fill) || (colStyle && colStyle.fill);
101
+ const fill = (rowStyle && hasOwnKeys(rowStyle.fill) && rowStyle.fill) ||
102
+ (colStyle && hasOwnKeys(colStyle.fill) && colStyle.fill);
94
103
  if (fill) {
95
104
  style.fill = fill;
96
105
  }
97
- const protection = (rowStyle && rowStyle.protection) || (colStyle && colStyle.protection);
106
+ const protection = (rowStyle && hasOwnKeys(rowStyle.protection) && rowStyle.protection) ||
107
+ (colStyle && hasOwnKeys(colStyle.protection) && colStyle.protection);
98
108
  if (protection) {
99
109
  style.protection = protection;
100
110
  }
@@ -1,6 +1,7 @@
1
1
  import { Enums } from "./enums.js";
2
2
  import { colCache } from "./utils/col-cache.js";
3
3
  import { Cell } from "./cell.js";
4
+ import { copyStyle } from "./utils/copy-style.js";
4
5
  class Row {
5
6
  constructor(worksheet, number) {
6
7
  this._worksheet = worksheet;
@@ -95,7 +96,7 @@ class Row {
95
96
  if (cSrc) {
96
97
  cDst = this.getCell(i);
97
98
  cDst.value = cSrc.value;
98
- cDst.style = cSrc.style;
99
+ cDst.style = copyStyle(cSrc.style) ?? {};
99
100
  cDst.comment = cSrc.comment;
100
101
  }
101
102
  else if (cDst) {
@@ -112,7 +113,7 @@ class Row {
112
113
  if (cSrc) {
113
114
  cDst = this.getCell(i + nExpand);
114
115
  cDst.value = cSrc.value;
115
- cDst.style = cSrc.style;
116
+ cDst.style = copyStyle(cSrc.style) ?? {};
116
117
  cDst.comment = cSrc.comment;
117
118
  }
118
119
  else {
@@ -207,7 +207,7 @@ class Table {
207
207
  else {
208
208
  cell.value = value;
209
209
  }
210
- assignStyle(cell, table.columns[j].style);
210
+ assignStyle(cell, table.columns[j]?.style);
211
211
  });
212
212
  });
213
213
  if (table.totalsRow) {
@@ -508,10 +508,10 @@ class Worksheet {
508
508
  // now copy styles...
509
509
  for (let i = 0; i < count; i++) {
510
510
  const rDst = this._rows[rowNum + i];
511
- rDst.style = rSrc.style;
511
+ rDst.style = copyStyle(rSrc.style) ?? {};
512
512
  rDst.height = rSrc.height;
513
513
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
514
- rDst.getCell(colNumber).style = cell.style;
514
+ rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
515
515
  });
516
516
  }
517
517
  // Duplicate single-row merges from source row into each new row
@@ -599,10 +599,10 @@ class Worksheet {
599
599
  if (rSrc) {
600
600
  const rDst = this.getRow(i + nExpand);
601
601
  rDst.values = rSrc.values;
602
- rDst.style = rSrc.style;
602
+ rDst.style = copyStyle(rSrc.style) ?? {};
603
603
  rDst.height = rSrc.height;
604
604
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
605
- rDst.getCell(colNumber).style = cell.style;
605
+ rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
606
606
  });
607
607
  this._rows[i - 1] = undefined;
608
608
  }
@@ -618,10 +618,10 @@ class Worksheet {
618
618
  if (rSrc) {
619
619
  const rDst = this.getRow(i + nExpand);
620
620
  rDst.values = rSrc.values;
621
- rDst.style = rSrc.style;
621
+ rDst.style = copyStyle(rSrc.style) ?? {};
622
622
  rDst.height = rSrc.height;
623
623
  rSrc.eachCell({ includeEmpty: true }, (cell, colNumber) => {
624
- rDst.getCell(colNumber).style = cell.style;
624
+ rDst.getCell(colNumber).style = copyStyle(cell.style) ?? {};
625
625
  });
626
626
  }
627
627
  else {
@@ -2,6 +2,7 @@ import { BaseXform } from "../base-xform.js";
2
2
  class TableColumnXform extends BaseXform {
3
3
  constructor() {
4
4
  super();
5
+ this._childText = "";
5
6
  this.model = { name: "" };
6
7
  }
7
8
  get tag() {
@@ -10,15 +11,30 @@ class TableColumnXform extends BaseXform {
10
11
  prepare(model, options) {
11
12
  model.id = options.index + 1;
12
13
  }
13
- render(xmlStream, model) {
14
- xmlStream.leafNode(this.tag, {
14
+ _renderAttributes(model) {
15
+ return {
15
16
  id: model.id.toString(),
16
17
  name: model.name,
17
18
  totalsRowLabel: model.totalsRowLabel,
18
19
  // Excel doesn't output totalsRowFunction when value is 'none'
19
20
  totalsRowFunction: model.totalsRowFunction === "none" ? undefined : model.totalsRowFunction,
20
21
  dxfId: model.dxfId
21
- });
22
+ };
23
+ }
24
+ render(xmlStream, model) {
25
+ if (model.calculatedColumnFormula || model.totalsRowFormula) {
26
+ xmlStream.openNode(this.tag, this._renderAttributes(model));
27
+ if (model.calculatedColumnFormula) {
28
+ xmlStream.leafNode("calculatedColumnFormula", undefined, model.calculatedColumnFormula);
29
+ }
30
+ if (model.totalsRowFormula) {
31
+ xmlStream.leafNode("totalsRowFormula", undefined, model.totalsRowFormula);
32
+ }
33
+ xmlStream.closeNode();
34
+ }
35
+ else {
36
+ xmlStream.leafNode(this.tag, this._renderAttributes(model));
37
+ }
22
38
  }
23
39
  parseOpen(node) {
24
40
  if (node.name === this.tag) {
@@ -31,11 +47,28 @@ class TableColumnXform extends BaseXform {
31
47
  };
32
48
  return true;
33
49
  }
34
- return false;
50
+ // Recognise child elements whose text content we want to capture
51
+ if (node.name === "calculatedColumnFormula" || node.name === "totalsRowFormula") {
52
+ this._childTag = node.name;
53
+ this._childText = "";
54
+ }
55
+ return true;
56
+ }
57
+ parseText(text) {
58
+ if (this._childTag) {
59
+ this._childText += text;
60
+ }
35
61
  }
36
- parseText() { }
37
- parseClose() {
38
- return false;
62
+ parseClose(name) {
63
+ if (name === this.tag) {
64
+ return false;
65
+ }
66
+ // Closing a recognised child element — store captured text
67
+ if (this._childTag && name === this._childTag) {
68
+ this.model[this._childTag] = this._childText;
69
+ this._childTag = undefined;
70
+ }
71
+ return true;
39
72
  }
40
73
  }
41
74
  export { TableColumnXform };