@niicojs/excel 0.3.4 → 0.3.5

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.
@@ -18,21 +18,38 @@ export class SharedStrings {
18
18
  private stringToIndex: Map<string, number> = new Map();
19
19
  private _dirty = false;
20
20
  private _totalCount = 0;
21
+ private _rawXml: string | null = null;
22
+ private _parsed = false;
21
23
 
22
24
  /**
23
25
  * Parse shared strings from XML content
24
26
  */
25
27
  static parse(xml: string): SharedStrings {
26
28
  const ss = new SharedStrings();
27
- const parsed = parseXml(xml);
29
+ ss._rawXml = xml;
30
+ ss._parse();
31
+ return ss;
32
+ }
33
+
34
+ private _parse(): void {
35
+ if (this._parsed) return;
36
+ if (!this._rawXml) {
37
+ this._parsed = true;
38
+ return;
39
+ }
40
+
41
+ const parsed = parseXml(this._rawXml);
28
42
  const sst = findElement(parsed, 'sst');
29
- if (!sst) return ss;
43
+ if (!sst) {
44
+ this._parsed = true;
45
+ return;
46
+ }
30
47
 
31
48
  const countAttr = getAttr(sst, 'count');
32
49
  if (countAttr) {
33
50
  const total = parseInt(countAttr, 10);
34
51
  if (Number.isFinite(total) && total >= 0) {
35
- ss._totalCount = total;
52
+ this._totalCount = total;
36
53
  }
37
54
  }
38
55
 
@@ -40,17 +57,17 @@ export class SharedStrings {
40
57
  for (const child of children) {
41
58
  if ('si' in child) {
42
59
  const siChildren = getChildren(child, 'si');
43
- const text = ss.extractText(siChildren);
44
- ss.entries.push({ text, node: child });
45
- ss.stringToIndex.set(text, ss.entries.length - 1);
60
+ const text = this.extractText(siChildren);
61
+ this.entries.push({ text, node: child });
62
+ this.stringToIndex.set(text, this.entries.length - 1);
46
63
  }
47
64
  }
48
65
 
49
- if (ss._totalCount === 0 && ss.entries.length > 0) {
50
- ss._totalCount = ss.entries.length;
66
+ if (this._totalCount === 0 && this.entries.length > 0) {
67
+ this._totalCount = this.entries.length;
51
68
  }
52
69
 
53
- return ss;
70
+ this._parsed = true;
54
71
  }
55
72
 
56
73
  /**
@@ -90,6 +107,7 @@ export class SharedStrings {
90
107
  * Get a string by index
91
108
  */
92
109
  getString(index: number): string | undefined {
110
+ this._parse();
93
111
  return this.entries[index]?.text;
94
112
  }
95
113
 
@@ -98,6 +116,7 @@ export class SharedStrings {
98
116
  * If the string already exists, returns the existing index
99
117
  */
100
118
  addString(str: string): number {
119
+ this._parse();
101
120
  const existing = this.stringToIndex.get(str);
102
121
  if (existing !== undefined) {
103
122
  this._totalCount++;
@@ -120,6 +139,7 @@ export class SharedStrings {
120
139
  * Check if the shared strings table has been modified
121
140
  */
122
141
  get dirty(): boolean {
142
+ this._parse();
123
143
  return this._dirty;
124
144
  }
125
145
 
@@ -127,6 +147,7 @@ export class SharedStrings {
127
147
  * Get the count of strings
128
148
  */
129
149
  get count(): number {
150
+ this._parse();
130
151
  return this.entries.length;
131
152
  }
132
153
 
@@ -134,6 +155,7 @@ export class SharedStrings {
134
155
  * Get total usage count of shared strings
135
156
  */
136
157
  get totalCount(): number {
158
+ this._parse();
137
159
  return Math.max(this._totalCount, this.entries.length);
138
160
  }
139
161
 
@@ -141,6 +163,7 @@ export class SharedStrings {
141
163
  * Get all unique shared strings in insertion order.
142
164
  */
143
165
  getAllStrings(): string[] {
166
+ this._parse();
144
167
  return this.entries.map((entry) => entry.text);
145
168
  }
146
169
 
@@ -148,6 +171,7 @@ export class SharedStrings {
148
171
  * Generate XML for the shared strings table
149
172
  */
150
173
  toXml(): string {
174
+ this._parse();
151
175
  const siElements: XmlNode[] = [];
152
176
  for (const entry of this.entries) {
153
177
  if (entry.node) {
package/src/styles.ts CHANGED
@@ -80,6 +80,8 @@ export class Styles {
80
80
  private _borders: StyleBorder[] = [];
81
81
  private _cellXfs: CellXf[] = []; // Cell formats (combined style index)
82
82
  private _xmlNodes: XmlNode[] | null = null;
83
+ private _rawXml: string | null = null;
84
+ private _parsed = false;
83
85
  private _dirty = false;
84
86
 
85
87
  // Cache for style deduplication
@@ -146,10 +148,30 @@ export class Styles {
146
148
  */
147
149
  static parse(xml: string): Styles {
148
150
  const styles = new Styles();
149
- styles._xmlNodes = parseXml(xml);
151
+ styles._rawXml = xml;
152
+ styles._parse();
153
+ return styles;
154
+ }
150
155
 
151
- const styleSheet = findElement(styles._xmlNodes, 'styleSheet');
152
- if (!styleSheet) return styles;
156
+ private _parse(): void {
157
+ if (this._parsed) return;
158
+ if (!this._rawXml) {
159
+ this._parsed = true;
160
+ return;
161
+ }
162
+
163
+ this._xmlNodes = parseXml(this._rawXml);
164
+
165
+ if (!this._xmlNodes) {
166
+ this._parsed = true;
167
+ return;
168
+ }
169
+
170
+ const styleSheet = findElement(this._xmlNodes, 'styleSheet');
171
+ if (!styleSheet) {
172
+ this._parsed = true;
173
+ return;
174
+ }
153
175
 
154
176
  const children = getChildren(styleSheet, 'styleSheet');
155
177
 
@@ -160,7 +182,7 @@ export class Styles {
160
182
  if ('numFmt' in child) {
161
183
  const id = parseInt(getAttr(child, 'numFmtId') || '0', 10);
162
184
  const code = getAttr(child, 'formatCode') || '';
163
- styles._numFmts.set(id, code);
185
+ this._numFmts.set(id, code);
164
186
  }
165
187
  }
166
188
  }
@@ -170,7 +192,7 @@ export class Styles {
170
192
  if (fonts) {
171
193
  for (const child of getChildren(fonts, 'fonts')) {
172
194
  if ('font' in child) {
173
- styles._fonts.push(styles._parseFont(child));
195
+ this._fonts.push(this._parseFont(child));
174
196
  }
175
197
  }
176
198
  }
@@ -180,7 +202,7 @@ export class Styles {
180
202
  if (fills) {
181
203
  for (const child of getChildren(fills, 'fills')) {
182
204
  if ('fill' in child) {
183
- styles._fills.push(styles._parseFill(child));
205
+ this._fills.push(this._parseFill(child));
184
206
  }
185
207
  }
186
208
  }
@@ -190,7 +212,7 @@ export class Styles {
190
212
  if (borders) {
191
213
  for (const child of getChildren(borders, 'borders')) {
192
214
  if ('border' in child) {
193
- styles._borders.push(styles._parseBorder(child));
215
+ this._borders.push(this._parseBorder(child));
194
216
  }
195
217
  }
196
218
  }
@@ -200,12 +222,12 @@ export class Styles {
200
222
  if (cellXfs) {
201
223
  for (const child of getChildren(cellXfs, 'cellXfs')) {
202
224
  if ('xf' in child) {
203
- styles._cellXfs.push(styles._parseCellXf(child));
225
+ this._cellXfs.push(this._parseCellXf(child));
204
226
  }
205
227
  }
206
228
  }
207
229
 
208
- return styles;
230
+ this._parsed = true;
209
231
  }
210
232
 
211
233
  /**
@@ -213,6 +235,7 @@ export class Styles {
213
235
  */
214
236
  static createDefault(): Styles {
215
237
  const styles = new Styles();
238
+ styles._parsed = true;
216
239
 
217
240
  // Default font (Calibri 11)
218
241
  styles._fonts.push({
@@ -366,6 +389,7 @@ export class Styles {
366
389
  * Get a style by index
367
390
  */
368
391
  getStyle(index: number): CellStyle {
392
+ this._parse();
369
393
  const cached = this._styleObjectCache.get(index);
370
394
  if (cached) return { ...cached };
371
395
 
@@ -440,6 +464,7 @@ export class Styles {
440
464
  * Uses caching to deduplicate identical styles
441
465
  */
442
466
  createStyle(style: CellStyle): number {
467
+ this._parse();
443
468
  const key = this._getStyleKey(style);
444
469
  const cached = this._styleCache.get(key);
445
470
  if (cached !== undefined) {
@@ -489,6 +514,7 @@ export class Styles {
489
514
  * Clone an existing style by index, optionally overriding fields.
490
515
  */
491
516
  cloneStyle(index: number, overrides: Partial<CellStyle> = {}): number {
517
+ this._parse();
492
518
  const baseStyle = this.getStyle(index);
493
519
  return this.createStyle({ ...baseStyle, ...overrides });
494
520
  }
@@ -602,6 +628,7 @@ export class Styles {
602
628
  * @param format - The number format string (e.g., '0.00', '#,##0', '$#,##0.00')
603
629
  */
604
630
  getOrCreateNumFmtId(format: string): number {
631
+ this._parse();
605
632
  this._dirty = true;
606
633
  return this._findOrCreateNumFmt(format);
607
634
  }
@@ -610,6 +637,7 @@ export class Styles {
610
637
  * Check if styles have been modified
611
638
  */
612
639
  get dirty(): boolean {
640
+ this._parse();
613
641
  return this._dirty;
614
642
  }
615
643
 
@@ -617,6 +645,7 @@ export class Styles {
617
645
  * Generate XML for styles
618
646
  */
619
647
  toXml(): string {
648
+ this._parse();
620
649
  const children: XmlNode[] = [];
621
650
 
622
651
  // Number formats