@cj-tech-master/excelts 6.1.0 → 6.1.1

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 (36) hide show
  1. package/dist/browser/modules/csv/worker/worker-script.generated.d.ts +1 -1
  2. package/dist/browser/modules/csv/worker/worker-script.generated.js +1 -1
  3. package/dist/browser/modules/excel/stream/sheet-rels-writer.d.ts +2 -1
  4. package/dist/browser/modules/excel/stream/sheet-rels-writer.js +10 -1
  5. package/dist/browser/modules/excel/stream/workbook-writer.browser.js +2 -1
  6. package/dist/browser/modules/excel/stream/worksheet-reader.d.ts +2 -1
  7. package/dist/browser/modules/excel/stream/worksheet-reader.js +4 -1
  8. package/dist/browser/modules/excel/workbook.browser.js +2 -1
  9. package/dist/browser/modules/excel/worksheet.js +2 -1
  10. package/dist/browser/modules/excel/xlsx/xform/sheet/hyperlink-xform.d.ts +8 -3
  11. package/dist/browser/modules/excel/xlsx/xform/sheet/hyperlink-xform.js +20 -10
  12. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +11 -1
  13. package/dist/cjs/modules/csv/worker/worker-script.generated.js +1 -1
  14. package/dist/cjs/modules/excel/stream/sheet-rels-writer.js +10 -1
  15. package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +2 -1
  16. package/dist/cjs/modules/excel/stream/worksheet-reader.js +4 -1
  17. package/dist/cjs/modules/excel/workbook.browser.js +2 -1
  18. package/dist/cjs/modules/excel/worksheet.js +2 -1
  19. package/dist/cjs/modules/excel/xlsx/xform/sheet/hyperlink-xform.js +20 -9
  20. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +11 -1
  21. package/dist/esm/modules/csv/worker/worker-script.generated.js +1 -1
  22. package/dist/esm/modules/excel/stream/sheet-rels-writer.js +10 -1
  23. package/dist/esm/modules/excel/stream/workbook-writer.browser.js +2 -1
  24. package/dist/esm/modules/excel/stream/worksheet-reader.js +4 -1
  25. package/dist/esm/modules/excel/workbook.browser.js +2 -1
  26. package/dist/esm/modules/excel/worksheet.js +2 -1
  27. package/dist/esm/modules/excel/xlsx/xform/sheet/hyperlink-xform.js +20 -10
  28. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +11 -1
  29. package/dist/iife/excelts.iife.js +77 -72
  30. package/dist/iife/excelts.iife.js.map +1 -1
  31. package/dist/iife/excelts.iife.min.js +34 -34
  32. package/dist/types/modules/csv/worker/worker-script.generated.d.ts +1 -1
  33. package/dist/types/modules/excel/stream/sheet-rels-writer.d.ts +2 -1
  34. package/dist/types/modules/excel/stream/worksheet-reader.d.ts +2 -1
  35. package/dist/types/modules/excel/xlsx/xform/sheet/hyperlink-xform.d.ts +8 -3
  36. package/package.json +13 -13
@@ -138,7 +138,8 @@ class Worksheet {
138
138
  }
139
139
  name = name.substring(0, 31);
140
140
  }
141
- if (this._workbook.worksheets.find(ws => ws && ws.name.toLowerCase() === name.toLowerCase())) {
141
+ const nameLower = name.toLowerCase();
142
+ if (this._workbook.worksheets.find(ws => ws && ws !== this && ws.name.toLowerCase() === nameLower)) {
142
143
  throw new WorksheetNameError(`Worksheet name already exists: ${name}`);
143
144
  }
144
145
  this._name = name;
@@ -4,15 +4,17 @@ class HyperlinkXform extends BaseXform {
4
4
  return "hyperlink";
5
5
  }
6
6
  render(xmlStream, model) {
7
- if (this.isInternalLink(model)) {
7
+ if (model.target && isInternalLink(model.target)) {
8
+ // Internal link: use location attribute only (no relationship)
9
+ // Strip the leading "#" — OOXML location attribute is without "#"
8
10
  xmlStream.leafNode("hyperlink", {
9
11
  ref: model.address,
10
- "r:id": model.rId,
11
12
  tooltip: model.tooltip,
12
- location: model.target
13
+ location: model.target.slice(1)
13
14
  });
14
15
  }
15
16
  else {
17
+ // External link: use r:id relationship reference
16
18
  xmlStream.leafNode("hyperlink", {
17
19
  ref: model.address,
18
20
  "r:id": model.rId,
@@ -27,9 +29,13 @@ class HyperlinkXform extends BaseXform {
27
29
  rId: node.attributes["r:id"],
28
30
  tooltip: node.attributes.tooltip
29
31
  };
30
- // This is an internal link
32
+ // Internal link: location attribute stores the target without "#"
33
+ // Normalize: always store as "#Location" in the model regardless of
34
+ // whether the source had a leading "#" (our old buggy output) or not
35
+ // (correct OOXML from Excel or the fixed writer).
31
36
  if (node.attributes.location) {
32
- this.model.target = node.attributes.location;
37
+ const loc = node.attributes.location;
38
+ this.model.target = loc.startsWith("#") ? loc : `#${loc}`;
33
39
  }
34
40
  return true;
35
41
  }
@@ -39,9 +45,13 @@ class HyperlinkXform extends BaseXform {
39
45
  parseClose() {
40
46
  return false;
41
47
  }
42
- isInternalLink(model) {
43
- // @example: Sheet2!D3, return true
44
- return !!(model.target && /^[^!]+![a-zA-Z]+[\d]+$/.test(model.target));
45
- }
46
48
  }
47
- export { HyperlinkXform };
49
+ /**
50
+ * Internal hyperlinks start with "#" (e.g. "#Sheet2!A1").
51
+ * This matches Excel's convention and the OOXML spec where internal links
52
+ * use the `location` attribute instead of a relationship.
53
+ */
54
+ function isInternalLink(target) {
55
+ return target.startsWith("#");
56
+ }
57
+ export { HyperlinkXform, isInternalLink };
@@ -3,11 +3,11 @@ import { XmlStream } from "../../../utils/xml-stream.js";
3
3
  import { RelType } from "../../rel-type.js";
4
4
  import { Merges } from "./merges.js";
5
5
  import { BaseXform } from "../base-xform.js";
6
+ import { isInternalLink, HyperlinkXform } from "./hyperlink-xform.js";
6
7
  import { ListXform } from "../list-xform.js";
7
8
  import { RowXform } from "./row-xform.js";
8
9
  import { ColXform } from "./col-xform.js";
9
10
  import { DimensionXform } from "./dimension-xform.js";
10
- import { HyperlinkXform } from "./hyperlink-xform.js";
11
11
  import { MergeCellXform } from "./merge-cell-xform.js";
12
12
  import { DataValidationsXform } from "./data-validations-xform.js";
13
13
  import { SheetPropertiesXform } from "./sheet-properties-xform.js";
@@ -158,6 +158,11 @@ class WorkSheetXform extends BaseXform {
158
158
  return `rId${r.length + 1}`;
159
159
  }
160
160
  model.hyperlinks.forEach(hyperlink => {
161
+ // Internal links (e.g. "#Sheet2!A1") use the location attribute only,
162
+ // no relationship is needed in the .rels file.
163
+ if (isInternalLink(hyperlink.target)) {
164
+ return;
165
+ }
161
166
  const rId = nextRid(rels);
162
167
  hyperlink.rId = rId;
163
168
  rels.push({
@@ -594,8 +599,13 @@ class WorkSheetXform extends BaseXform {
594
599
  }, {});
595
600
  options.hyperlinkMap = (model.hyperlinks ?? []).reduce((h, hyperlink) => {
596
601
  if (hyperlink.rId) {
602
+ // External link: resolve target from relationship
597
603
  h[hyperlink.address] = rels[hyperlink.rId].Target;
598
604
  }
605
+ else if (hyperlink.target) {
606
+ // Internal link: target was restored from location attribute (with "#" prefix)
607
+ h[hyperlink.address] = hyperlink.target;
608
+ }
599
609
  return h;
600
610
  }, {});
601
611
  options.formulae = {};
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @cj-tech-master/excelts v6.1.0
2
+ * @cj-tech-master/excelts v6.1.1
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
@@ -5000,8 +5000,12 @@ var ExcelTS = (function(exports) {
5000
5000
  if (name === "History") throw new WorksheetNameError("The name \"History\" is protected. Please use a different name.");
5001
5001
  if (/[*?:/\\[\]]/.test(name)) throw new WorksheetNameError(`Worksheet name ${name} cannot include any of the following characters: * ? : \\ / [ ]`);
5002
5002
  if (/(^')|('$)/.test(name)) throw new WorksheetNameError(`The first or last character of worksheet name cannot be a single quotation mark: ${name}`);
5003
- if (name && name.length > 31) name = name.substring(0, 31);
5004
- if (this._workbook.worksheets.find((ws) => ws && ws.name.toLowerCase() === name.toLowerCase())) throw new WorksheetNameError(`Worksheet name already exists: ${name}`);
5003
+ if (name && name.length > 31) {
5004
+ console.warn(`Worksheet name ${name} exceeds 31 chars. This will be truncated`);
5005
+ name = name.substring(0, 31);
5006
+ }
5007
+ const nameLower = name.toLowerCase();
5008
+ if (this._workbook.worksheets.find((ws) => ws && ws !== this && ws.name.toLowerCase() === nameLower)) throw new WorksheetNameError(`Worksheet name already exists: ${name}`);
5005
5009
  this._name = name;
5006
5010
  }
5007
5011
  /**
@@ -10812,6 +10816,52 @@ var ExcelTS = (function(exports) {
10812
10816
  }
10813
10817
  };
10814
10818
  //#endregion
10819
+ //#region src/modules/excel/xlsx/xform/sheet/hyperlink-xform.ts
10820
+ var HyperlinkXform = class extends BaseXform {
10821
+ get tag() {
10822
+ return "hyperlink";
10823
+ }
10824
+ render(xmlStream, model) {
10825
+ if (model.target && isInternalLink(model.target)) xmlStream.leafNode("hyperlink", {
10826
+ ref: model.address,
10827
+ tooltip: model.tooltip,
10828
+ location: model.target.slice(1)
10829
+ });
10830
+ else xmlStream.leafNode("hyperlink", {
10831
+ ref: model.address,
10832
+ "r:id": model.rId,
10833
+ tooltip: model.tooltip
10834
+ });
10835
+ }
10836
+ parseOpen(node) {
10837
+ if (node.name === "hyperlink") {
10838
+ this.model = {
10839
+ address: node.attributes.ref,
10840
+ rId: node.attributes["r:id"],
10841
+ tooltip: node.attributes.tooltip
10842
+ };
10843
+ if (node.attributes.location) {
10844
+ const loc = node.attributes.location;
10845
+ this.model.target = loc.startsWith("#") ? loc : `#${loc}`;
10846
+ }
10847
+ return true;
10848
+ }
10849
+ return false;
10850
+ }
10851
+ parseText() {}
10852
+ parseClose() {
10853
+ return false;
10854
+ }
10855
+ };
10856
+ /**
10857
+ * Internal hyperlinks start with "#" (e.g. "#Sheet2!A1").
10858
+ * This matches Excel's convention and the OOXML spec where internal links
10859
+ * use the `location` attribute instead of a relationship.
10860
+ */
10861
+ function isInternalLink(target) {
10862
+ return target.startsWith("#");
10863
+ }
10864
+ //#endregion
10815
10865
  //#region src/modules/excel/xlsx/xform/sheet/cell-xform.ts
10816
10866
  function getValueType(v) {
10817
10867
  if (v === null || v === void 0) return Enums.ValueType.Null;
@@ -11338,45 +11388,6 @@ var ExcelTS = (function(exports) {
11338
11388
  }
11339
11389
  };
11340
11390
  //#endregion
11341
- //#region src/modules/excel/xlsx/xform/sheet/hyperlink-xform.ts
11342
- var HyperlinkXform = class extends BaseXform {
11343
- get tag() {
11344
- return "hyperlink";
11345
- }
11346
- render(xmlStream, model) {
11347
- if (this.isInternalLink(model)) xmlStream.leafNode("hyperlink", {
11348
- ref: model.address,
11349
- "r:id": model.rId,
11350
- tooltip: model.tooltip,
11351
- location: model.target
11352
- });
11353
- else xmlStream.leafNode("hyperlink", {
11354
- ref: model.address,
11355
- "r:id": model.rId,
11356
- tooltip: model.tooltip
11357
- });
11358
- }
11359
- parseOpen(node) {
11360
- if (node.name === "hyperlink") {
11361
- this.model = {
11362
- address: node.attributes.ref,
11363
- rId: node.attributes["r:id"],
11364
- tooltip: node.attributes.tooltip
11365
- };
11366
- if (node.attributes.location) this.model.target = node.attributes.location;
11367
- return true;
11368
- }
11369
- return false;
11370
- }
11371
- parseText() {}
11372
- parseClose() {
11373
- return false;
11374
- }
11375
- isInternalLink(model) {
11376
- return !!(model.target && /^[^!]+![a-zA-Z]+[\d]+$/.test(model.target));
11377
- }
11378
- };
11379
- //#endregion
11380
11391
  //#region src/modules/excel/xlsx/xform/sheet/merge-cell-xform.ts
11381
11392
  var MergeCellXform = class extends BaseXform {
11382
11393
  get tag() {
@@ -13646,6 +13657,7 @@ var ExcelTS = (function(exports) {
13646
13657
  return `rId${r.length + 1}`;
13647
13658
  }
13648
13659
  model.hyperlinks.forEach((hyperlink) => {
13660
+ if (isInternalLink(hyperlink.target)) return;
13649
13661
  const rId = nextRid(rels);
13650
13662
  hyperlink.rId = rId;
13651
13663
  rels.push({
@@ -13992,6 +14004,7 @@ var ExcelTS = (function(exports) {
13992
14004
  }, {});
13993
14005
  options.hyperlinkMap = (model.hyperlinks ?? []).reduce((h, hyperlink) => {
13994
14006
  if (hyperlink.rId) h[hyperlink.address] = rels[hyperlink.rId].Target;
14007
+ else if (hyperlink.target) h[hyperlink.address] = hyperlink.target;
13995
14008
  return h;
13996
14009
  }, {});
13997
14010
  options.formulae = {};
@@ -15504,10 +15517,7 @@ var ExcelTS = (function(exports) {
15504
15517
  case "m": return "<m />";
15505
15518
  case "d": return `<d v="${formatDateForExcel(value.value)}" />`;
15506
15519
  case "e": return `<e v="${xmlEncode(value.value)}" />`;
15507
- default: {
15508
- const _exhaustive = value;
15509
- throw new Error(`Unhandled record value type: ${_exhaustive.type}`);
15510
- }
15520
+ default: throw new Error(`Unhandled record value type: ${value.type}`);
15511
15521
  }
15512
15522
  }
15513
15523
  renderTableNew(sourceBodyRows, cacheFields) {
@@ -19670,7 +19680,6 @@ var ExcelTS = (function(exports) {
19670
19680
  createStreamFormatChecker("decompression", "gzip");
19671
19681
  createStreamFormatChecker("compression", "deflate");
19672
19682
  createStreamFormatChecker("decompression", "deflate");
19673
- new Uint8Array([120, 1]), new Uint8Array([120, 1]), new Uint8Array([120, 94]), new Uint8Array([120, 94]), new Uint8Array([120, 94]), new Uint8Array([120, 94]), new Uint8Array([120, 156]), new Uint8Array([120, 218]), new Uint8Array([120, 218]), new Uint8Array([120, 218]);
19674
19683
  //#endregion
19675
19684
  //#region src/modules/archive/shared/errors.ts
19676
19685
  /**
@@ -19771,10 +19780,9 @@ var ExcelTS = (function(exports) {
19771
19780
  function resolvePoolOptions(options) {
19772
19781
  const maxWorkers = options?.maxWorkers ?? DEFAULT_POOL_OPTIONS.maxWorkers;
19773
19782
  const minWorkers = options?.minWorkers ?? DEFAULT_POOL_OPTIONS.minWorkers;
19774
- const validatedMinWorkers = Math.min(minWorkers, maxWorkers);
19775
19783
  return {
19776
19784
  maxWorkers: Math.max(1, maxWorkers),
19777
- minWorkers: Math.max(0, validatedMinWorkers),
19785
+ minWorkers: Math.max(0, Math.min(minWorkers, maxWorkers)),
19778
19786
  idleTimeout: Math.max(0, options?.idleTimeout ?? DEFAULT_POOL_OPTIONS.idleTimeout),
19779
19787
  useTransferables: options?.useTransferables ?? DEFAULT_POOL_OPTIONS.useTransferables,
19780
19788
  workerUrl: options?.workerUrl
@@ -21121,18 +21129,6 @@ self.onmessage = async function(event) {
21121
21129
  function decompressSync(data) {
21122
21130
  return inflateRaw(data);
21123
21131
  }
21124
- new Uint8Array([
21125
- 31,
21126
- 139,
21127
- 8,
21128
- 0,
21129
- 0,
21130
- 0,
21131
- 0,
21132
- 0,
21133
- 0,
21134
- 255
21135
- ]);
21136
21132
  //#endregion
21137
21133
  //#region src/modules/archive/compression/streaming-compress.browser.ts
21138
21134
  /**
@@ -29911,6 +29907,13 @@ self.onmessage = async function(event) {
29911
29907
  return this._hyperlinksProxy || (this._hyperlinksProxy = new HyperlinksProxy(this));
29912
29908
  }
29913
29909
  addHyperlink(hyperlink) {
29910
+ if (isInternalLink(hyperlink.target)) {
29911
+ this._hyperlinks.push({
29912
+ address: hyperlink.address,
29913
+ target: hyperlink.target
29914
+ });
29915
+ return;
29916
+ }
29914
29917
  const relationship = {
29915
29918
  Target: hyperlink.target,
29916
29919
  Type: RelType.Hyperlink,
@@ -30710,7 +30713,10 @@ self.onmessage = async function(event) {
30710
30713
  getWorksheet(id) {
30711
30714
  if (id === void 0) return this._worksheets.find(() => true);
30712
30715
  if (typeof id === "number") return this._worksheets[id];
30713
- if (typeof id === "string") return this._worksheets.find((ws) => ws?.name === id);
30716
+ if (typeof id === "string") {
30717
+ const idLower = id.toLowerCase();
30718
+ return this._worksheets.find((ws) => ws?.name?.toLowerCase() === idLower);
30719
+ }
30714
30720
  }
30715
30721
  addStyles() {
30716
30722
  return new Promise((resolve) => {
@@ -32389,9 +32395,11 @@ onmessage = async (ev) => {
32389
32395
  break;
32390
32396
  case "hyperlink":
32391
32397
  if (inHyperlinks) {
32398
+ const loc = node.attributes.location;
32392
32399
  const hyperlink = {
32393
32400
  ref: node.attributes.ref,
32394
- rId: node.attributes["r:id"]
32401
+ rId: node.attributes["r:id"],
32402
+ target: loc ? loc.startsWith("#") ? loc : `#${loc}` : void 0
32395
32403
  };
32396
32404
  if (emitHyperlinks) (worksheetEvents ||= []).push({
32397
32405
  eventType: "hyperlink",
@@ -33528,10 +33536,7 @@ onmessage = async (ev) => {
33528
33536
  modified: true,
33529
33537
  extras: row.splice(expectedCols)
33530
33538
  };
33531
- default: {
33532
- const _never = columnMore;
33533
- throw new Error(`Unknown columnMore strategy: ${_never}`);
33534
- }
33539
+ default: throw new Error(`Unknown columnMore strategy: ${columnMore}`);
33535
33540
  }
33536
33541
  switch (columnLess) {
33537
33542
  case "error": return {
@@ -33547,10 +33552,7 @@ onmessage = async (ev) => {
33547
33552
  errorCode: "TooFewFields",
33548
33553
  modified: true
33549
33554
  };
33550
- default: {
33551
- const _never = columnLess;
33552
- throw new Error(`Unknown columnLess strategy: ${_never}`);
33553
- }
33555
+ default: throw new Error(`Unknown columnLess strategy: ${columnLess}`);
33554
33556
  }
33555
33557
  }
33556
33558
  /**
@@ -37149,7 +37151,10 @@ onmessage = async (ev) => {
37149
37151
  getWorksheet(id) {
37150
37152
  if (id === void 0) return this._worksheets.find(Boolean);
37151
37153
  if (typeof id === "number") return this._worksheets[id];
37152
- if (typeof id === "string") return this._worksheets.find((worksheet) => worksheet && worksheet.name === id);
37154
+ if (typeof id === "string") {
37155
+ const idLower = id.toLowerCase();
37156
+ return this._worksheets.find((worksheet) => worksheet && worksheet.name.toLowerCase() === idLower);
37157
+ }
37153
37158
  }
37154
37159
  /**
37155
37160
  * Return a clone of worksheets in order