@cj-tech-master/excelts 7.5.0 → 7.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 (31) hide show
  1. package/dist/browser/modules/excel/stream/hyperlink-reader.js +1 -1
  2. package/dist/browser/modules/excel/stream/workbook-reader.browser.js +2 -2
  3. package/dist/browser/modules/excel/stream/worksheet-reader.js +1 -1
  4. package/dist/browser/modules/excel/xlsx/xform/base-xform.js +1 -1
  5. package/dist/browser/modules/xml/dom.js +2 -1
  6. package/dist/browser/modules/xml/index.d.ts +1 -1
  7. package/dist/browser/modules/xml/sax.d.ts +41 -0
  8. package/dist/browser/modules/xml/sax.js +265 -76
  9. package/dist/browser/modules/xml/to-object.js +2 -1
  10. package/dist/browser/modules/xml/types.d.ts +24 -0
  11. package/dist/cjs/modules/excel/stream/hyperlink-reader.js +1 -1
  12. package/dist/cjs/modules/excel/stream/workbook-reader.browser.js +2 -2
  13. package/dist/cjs/modules/excel/stream/worksheet-reader.js +1 -1
  14. package/dist/cjs/modules/excel/xlsx/xform/base-xform.js +1 -1
  15. package/dist/cjs/modules/xml/dom.js +2 -1
  16. package/dist/cjs/modules/xml/sax.js +265 -76
  17. package/dist/cjs/modules/xml/to-object.js +2 -1
  18. package/dist/esm/modules/excel/stream/hyperlink-reader.js +1 -1
  19. package/dist/esm/modules/excel/stream/workbook-reader.browser.js +2 -2
  20. package/dist/esm/modules/excel/stream/worksheet-reader.js +1 -1
  21. package/dist/esm/modules/excel/xlsx/xform/base-xform.js +1 -1
  22. package/dist/esm/modules/xml/dom.js +2 -1
  23. package/dist/esm/modules/xml/sax.js +265 -76
  24. package/dist/esm/modules/xml/to-object.js +2 -1
  25. package/dist/iife/excelts.iife.js +196 -54
  26. package/dist/iife/excelts.iife.js.map +1 -1
  27. package/dist/iife/excelts.iife.min.js +44 -44
  28. package/dist/types/modules/xml/index.d.ts +1 -1
  29. package/dist/types/modules/xml/sax.d.ts +41 -0
  30. package/dist/types/modules/xml/types.d.ts +24 -0
  31. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @cj-tech-master/excelts v7.5.0
2
+ * @cj-tech-master/excelts v7.6.0
3
3
  * TypeScript Excel Workbook Manager - Read and Write xlsx and csv Files.
4
4
  * (c) 2026 cjnoname
5
5
  * Released under the MIT License
@@ -11429,6 +11429,8 @@ var ExcelTS = (function(exports) {
11429
11429
  const QUESTION = 63;
11430
11430
  const OPEN_BRACKET = 91;
11431
11431
  const CLOSE_BRACKET = 93;
11432
+ const REPLACEMENT_CHAR = 65533;
11433
+ const REPLACEMENT_STR = "�";
11432
11434
  const ASCII_CHARS = /* @__PURE__ */ (() => {
11433
11435
  const t = new Array(128);
11434
11436
  for (let i = 0; i < 128; i++) t[i] = String.fromCharCode(i);
@@ -11557,6 +11559,7 @@ var ExcelTS = (function(exports) {
11557
11559
  this.xmlns = options?.xmlns ?? false;
11558
11560
  this.maxDepth = options?.maxDepth !== void 0 ? options.maxDepth : 256;
11559
11561
  this.maxEntityExpansions = options?.maxEntityExpansions !== void 0 ? options.maxEntityExpansions : 1e4;
11562
+ this.invalidCharHandling = options?.invalidCharHandling ?? "error";
11560
11563
  this._init();
11561
11564
  }
11562
11565
  get closed() {
@@ -11650,55 +11653,150 @@ var ExcelTS = (function(exports) {
11650
11653
  close() {
11651
11654
  return this.write(null);
11652
11655
  }
11653
- getCode() {
11654
- const { chunk, i } = this;
11655
- this.prevI = i;
11656
- this.i = i + 1;
11657
- if (i >= chunk.length) return -1;
11658
- const code = chunk.charCodeAt(i);
11659
- if (code >= 32 && code <= 126) {
11660
- if (this.trackPosition) this.column++;
11661
- return code;
11662
- }
11663
- if (code === TAB) {
11664
- if (this.trackPosition) this.column++;
11665
- return code;
11656
+ /**
11657
+ * Handle an invalid XML character according to the configured strategy.
11658
+ *
11659
+ * Used by `handleTextInRoot()` fast path which manages its own text accumulation
11660
+ * and cannot use the `getCode()` loop approach.
11661
+ *
11662
+ * - `"error"`: call `fail()` and return the original code.
11663
+ * - `"skip"`: return `REPLACEMENT_CHAR` as a sentinel (caller handles skip).
11664
+ * - `"replace"`: return `REPLACEMENT_CHAR`.
11665
+ *
11666
+ * Note: For `getCode()`, invalid char handling is inlined to avoid recursion.
11667
+ *
11668
+ * @param code - The invalid character code point.
11669
+ * @param kind - Optional description (e.g. "lone surrogate") for error messages.
11670
+ * @returns The code point to use.
11671
+ */
11672
+ handleInvalidChar(code, kind) {
11673
+ switch (this.invalidCharHandling) {
11674
+ case "replace": return REPLACEMENT_CHAR;
11675
+ case "skip": return -2;
11676
+ default: {
11677
+ const label = kind ? `invalid XML character: ${kind} 0x${code.toString(16)}` : `invalid XML character: 0x${code.toString(16)}`;
11678
+ this.fail(label);
11679
+ return code;
11680
+ }
11666
11681
  }
11667
- if (code === CR) {
11668
- if (chunk.charCodeAt(i + 1) === NL) this.i = i + 2;
11669
- if (this.trackPosition) {
11670
- this.line++;
11671
- this.column = 0;
11672
- this.positionAtNewLine = this.position;
11682
+ }
11683
+ /**
11684
+ * Handle an invalid character inside the `handleTextInRoot()` fast loop.
11685
+ *
11686
+ * Unlike `handleInvalidChar()` (which returns a code point for `getCode()`),
11687
+ * this method manages the text accumulation state (`this.text`, `start`) that
11688
+ * the fast text loop relies on.
11689
+ *
11690
+ * - `"error"`: call `fail()`, leave text accumulation unchanged (char stays in output).
11691
+ * - `"skip"`: flush text up to the invalid char, skip it, return new `start`.
11692
+ * - `"replace"`: flush text up to the invalid char, append U+FFFD, return new `start`.
11693
+ *
11694
+ * @returns The updated `start` index for the text accumulation loop.
11695
+ */
11696
+ handleInvalidCharInText(code, handler, start, kind) {
11697
+ switch (this.invalidCharHandling) {
11698
+ case "skip":
11699
+ if (handler && start < this.prevI) this.text += this.chunk.slice(start, this.prevI);
11700
+ return this.i;
11701
+ case "replace":
11702
+ if (handler) {
11703
+ if (start < this.prevI) this.text += this.chunk.slice(start, this.prevI);
11704
+ this.text += REPLACEMENT_STR;
11705
+ }
11706
+ return this.i;
11707
+ default: {
11708
+ const label = kind ? `invalid XML character: ${kind} 0x${code.toString(16)}` : `invalid XML character: 0x${code.toString(16)}`;
11709
+ this.fail(label);
11710
+ return start;
11673
11711
  }
11674
- return NL;
11675
11712
  }
11676
- if (code === NL) {
11677
- if (this.trackPosition) {
11678
- this.line++;
11679
- this.column = 0;
11680
- this.positionAtNewLine = this.position;
11713
+ }
11714
+ /**
11715
+ * Handle an invalid character inside `sAttribValueQuoted()`.
11716
+ *
11717
+ * Same pattern as `handleInvalidCharInText()` but for attribute value
11718
+ * accumulation (always uses `this.text`, no conditional handler check).
11719
+ *
11720
+ * @returns The updated `start` index.
11721
+ */
11722
+ handleInvalidCharInAttr(code, start, kind) {
11723
+ switch (this.invalidCharHandling) {
11724
+ case "skip":
11725
+ if (start < this.prevI) this.text += this.chunk.slice(start, this.prevI);
11726
+ return this.i;
11727
+ case "replace":
11728
+ if (start < this.prevI) this.text += this.chunk.slice(start, this.prevI);
11729
+ this.text += REPLACEMENT_STR;
11730
+ return this.i;
11731
+ default: {
11732
+ const label = kind ? `invalid XML character: ${kind} 0x${code.toString(16)}` : `invalid XML character: 0x${code.toString(16)}`;
11733
+ this.fail(label);
11734
+ return start;
11681
11735
  }
11682
- return NL;
11683
11736
  }
11684
- if (code >= 55296 && code <= 56319) {
11685
- const next = chunk.charCodeAt(i + 1);
11686
- if (next >= 56320 && next <= 57343) {
11687
- this.i = i + 2;
11737
+ }
11738
+ getCode() {
11739
+ for (;;) {
11740
+ const { chunk } = this;
11741
+ const i = this.i;
11742
+ this.prevI = i;
11743
+ this.i = i + 1;
11744
+ if (i >= chunk.length) return -1;
11745
+ const code = chunk.charCodeAt(i);
11746
+ if (code >= 32 && code <= 126) {
11688
11747
  if (this.trackPosition) this.column++;
11689
- return 65536 + ((code - 55296) * 1024 + (next - 56320));
11748
+ return code;
11749
+ }
11750
+ if (code === TAB) {
11751
+ if (this.trackPosition) this.column++;
11752
+ return code;
11753
+ }
11754
+ if (code === CR) {
11755
+ if (chunk.charCodeAt(i + 1) === NL) this.i = i + 2;
11756
+ if (this.trackPosition) {
11757
+ this.line++;
11758
+ this.column = 0;
11759
+ this.positionAtNewLine = this.position;
11760
+ }
11761
+ return NL;
11762
+ }
11763
+ if (code === NL) {
11764
+ if (this.trackPosition) {
11765
+ this.line++;
11766
+ this.column = 0;
11767
+ this.positionAtNewLine = this.position;
11768
+ }
11769
+ return NL;
11770
+ }
11771
+ if (code >= 55296 && code <= 56319) {
11772
+ const next = chunk.charCodeAt(i + 1);
11773
+ if (next >= 56320 && next <= 57343) {
11774
+ this.i = i + 2;
11775
+ if (this.trackPosition) this.column++;
11776
+ return 65536 + ((code - 55296) * 1024 + (next - 56320));
11777
+ }
11778
+ const result = this.handleInvalidChar(code, "lone surrogate");
11779
+ if (result !== -2) return result;
11780
+ continue;
11781
+ }
11782
+ if (code >= 56320 && code <= 57343) {
11783
+ const result = this.handleInvalidChar(code, "lone surrogate");
11784
+ if (result !== -2) return result;
11785
+ continue;
11786
+ }
11787
+ if (code >= 128) {
11788
+ if (this.trackPosition) this.column++;
11789
+ if (code === 65534 || code === 65535) {
11790
+ const result = this.handleInvalidChar(code);
11791
+ if (result !== -2) return result;
11792
+ continue;
11793
+ }
11794
+ return code;
11690
11795
  }
11691
- this.fail("invalid XML character: lone surrogate 0x" + code.toString(16));
11692
- }
11693
- if (code >= 56320 && code <= 57343) this.fail("invalid XML character: lone surrogate 0x" + code.toString(16));
11694
- if (code >= 128) {
11695
11796
  if (this.trackPosition) this.column++;
11696
- if (code === 65534 || code === 65535) this.fail("invalid XML character: 0x" + code.toString(16));
11697
- return code;
11797
+ const result = this.handleInvalidChar(code);
11798
+ if (result !== -2) return result;
11698
11799
  }
11699
- if (this.trackPosition) this.column++;
11700
- this.fail("invalid XML character: 0x" + code.toString(16));
11701
- return code;
11702
11800
  }
11703
11801
  unget() {
11704
11802
  this.i = this.prevI;
@@ -11863,14 +11961,14 @@ var ExcelTS = (function(exports) {
11863
11961
  if (next >= 56320 && next <= 57343) this.i += 2;
11864
11962
  else {
11865
11963
  this.i++;
11866
- this.fail("invalid XML character: lone surrogate 0x" + code.toString(16));
11964
+ start = this.handleInvalidCharInText(code, handler, start, "lone surrogate");
11867
11965
  }
11868
11966
  } else if (code >= 56320 && code <= 57343) {
11869
11967
  this.i++;
11870
- this.fail("invalid XML character: lone surrogate 0x" + code.toString(16));
11968
+ start = this.handleInvalidCharInText(code, handler, start, "lone surrogate");
11871
11969
  } else if (code === 65534 || code === 65535) {
11872
11970
  this.i++;
11873
- this.fail("invalid XML character: 0x" + code.toString(16));
11971
+ start = this.handleInvalidCharInText(code, handler, start);
11874
11972
  } else this.i++;
11875
11973
  if (this.trackPosition) this.column++;
11876
11974
  continue;
@@ -11878,7 +11976,7 @@ var ExcelTS = (function(exports) {
11878
11976
  this.prevI = this.i;
11879
11977
  this.i++;
11880
11978
  if (this.trackPosition) this.column++;
11881
- this.fail("invalid XML character: 0x" + code.toString(16));
11979
+ start = this.handleInvalidCharInText(code, handler, start);
11882
11980
  }
11883
11981
  if (handler && start < this.i) this.text += chunk.slice(start, this.i);
11884
11982
  }
@@ -11887,12 +11985,28 @@ var ExcelTS = (function(exports) {
11887
11985
  let { i: start } = this;
11888
11986
  const handler = this._handlers.text;
11889
11987
  let nonSpace = false;
11988
+ const isSkip = this.invalidCharHandling === "skip";
11989
+ const isReplace = this.invalidCharHandling === "replace";
11890
11990
  while (true) {
11991
+ const iBeforeGet = this.i;
11891
11992
  const c = this.getCode();
11892
11993
  if (c === -1) {
11893
- if (handler && start < this.i) this.text += chunk.slice(start, this.i);
11994
+ if (handler && start < iBeforeGet) this.text += chunk.slice(start, iBeforeGet);
11894
11995
  break;
11895
11996
  }
11997
+ if (isSkip && this.prevI > iBeforeGet) {
11998
+ if (handler && start < iBeforeGet) this.text += chunk.slice(start, iBeforeGet);
11999
+ start = this.prevI;
12000
+ }
12001
+ if (isReplace && c === REPLACEMENT_CHAR && chunk.charCodeAt(this.prevI) !== REPLACEMENT_CHAR) {
12002
+ if (handler) {
12003
+ if (start < this.prevI) this.text += chunk.slice(start, this.prevI);
12004
+ this.text += REPLACEMENT_STR;
12005
+ }
12006
+ start = this.i;
12007
+ nonSpace = true;
12008
+ continue;
12009
+ }
11896
12010
  if (c === LESS) {
11897
12011
  if (handler) {
11898
12012
  const slice = chunk.slice(start, this.prevI);
@@ -12174,10 +12288,29 @@ var ExcelTS = (function(exports) {
12174
12288
  start = this.i;
12175
12289
  continue;
12176
12290
  }
12177
- if (this.getCode() === -1) {
12178
- this.text += chunk.slice(start, this.i);
12179
- return;
12291
+ if (code >= 128) {
12292
+ this.prevI = this.i;
12293
+ if (code >= 55296 && code <= 56319) {
12294
+ const next = chunk.charCodeAt(this.i + 1);
12295
+ if (next >= 56320 && next <= 57343) this.i += 2;
12296
+ else {
12297
+ this.i++;
12298
+ start = this.handleInvalidCharInAttr(code, start, "lone surrogate");
12299
+ }
12300
+ } else if (code >= 56320 && code <= 57343) {
12301
+ this.i++;
12302
+ start = this.handleInvalidCharInAttr(code, start, "lone surrogate");
12303
+ } else if (code === 65534 || code === 65535) {
12304
+ this.i++;
12305
+ start = this.handleInvalidCharInAttr(code, start);
12306
+ } else this.i++;
12307
+ if (this.trackPosition) this.column++;
12308
+ continue;
12180
12309
  }
12310
+ this.prevI = this.i;
12311
+ this.i++;
12312
+ if (this.trackPosition) this.column++;
12313
+ start = this.handleInvalidCharInAttr(code, start);
12181
12314
  }
12182
12315
  this.text += chunk.slice(start, this.i);
12183
12316
  }
@@ -12688,7 +12821,7 @@ var ExcelTS = (function(exports) {
12688
12821
  * Use this instead of parse(parseSax(stream)) for hot paths.
12689
12822
  */
12690
12823
  async parseStreamDirect(stream) {
12691
- const parser = new SaxParser();
12824
+ const parser = new SaxParser({ invalidCharHandling: "skip" });
12692
12825
  const decoder = new TextDecoder("utf-8", { fatal: true });
12693
12826
  let done = false;
12694
12827
  let finalModel;
@@ -38161,7 +38294,10 @@ onmessage = async (ev) => {
38161
38294
  let c = null;
38162
38295
  let current = null;
38163
38296
  let worksheetEvents = null;
38164
- const parser = new SaxParser({ position: false });
38297
+ const parser = new SaxParser({
38298
+ position: false,
38299
+ invalidCharHandling: "skip"
38300
+ });
38165
38301
  parser.on("opentag", (node) => {
38166
38302
  if (emitSheet) switch (node.name) {
38167
38303
  case "cols":
@@ -38380,7 +38516,10 @@ onmessage = async (ev) => {
38380
38516
  return;
38381
38517
  }
38382
38518
  try {
38383
- const parser = new SaxParser({ position: false });
38519
+ const parser = new SaxParser({
38520
+ position: false,
38521
+ invalidCharHandling: "skip"
38522
+ });
38384
38523
  const decoder = new TextDecoder("utf-8", { fatal: true });
38385
38524
  parser.on("opentag", (node) => {
38386
38525
  if (node.name !== "Relationship") return;
@@ -38558,7 +38697,10 @@ onmessage = async (ev) => {
38558
38697
  let inRichText = false;
38559
38698
  if (this.options.sharedStrings === "cache") {
38560
38699
  const sharedStrings = this.sharedStrings;
38561
- const parser = new SaxParser({ position: false });
38700
+ const parser = new SaxParser({
38701
+ position: false,
38702
+ invalidCharHandling: "skip"
38703
+ });
38562
38704
  parser.on("opentag", (node) => {
38563
38705
  switch (node.name) {
38564
38706
  case "b":
@@ -38652,7 +38794,7 @@ onmessage = async (ev) => {
38652
38794
  await saxStream(parser, iterateStream(entry));
38653
38795
  return;
38654
38796
  }
38655
- const emitParser = new SaxParser();
38797
+ const emitParser = new SaxParser({ invalidCharHandling: "skip" });
38656
38798
  const emitDecoder = new TextDecoder("utf-8", { fatal: true });
38657
38799
  let pendingEmits = [];
38658
38800
  emitParser.on("opentag", (node) => {