@cj-tech-master/excelts 4.2.1-canary.20260111102127.f808a37 → 4.2.1-canary.20260112134913.a3cecdd

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 (101) hide show
  1. package/dist/browser/modules/archive/io/archive-sink.d.ts +0 -1
  2. package/dist/browser/modules/archive/io/archive-sink.js +6 -38
  3. package/dist/browser/modules/archive/io/archive-source.d.ts +0 -2
  4. package/dist/browser/modules/archive/io/archive-source.js +1 -8
  5. package/dist/browser/modules/excel/utils/ooxml-validator.d.ts +48 -0
  6. package/dist/browser/modules/excel/utils/ooxml-validator.js +469 -0
  7. package/dist/browser/modules/excel/worksheet.js +5 -2
  8. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
  9. package/dist/browser/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  10. package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
  11. package/dist/browser/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
  12. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
  13. package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  14. package/dist/browser/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  15. package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
  16. package/dist/browser/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  17. package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +110 -12
  18. package/dist/browser/modules/stream/base-transform.d.ts +3 -0
  19. package/dist/browser/modules/stream/base-transform.js +34 -20
  20. package/dist/browser/modules/stream/buffered-stream.d.ts +2 -12
  21. package/dist/browser/modules/stream/chunked-builder.js +4 -4
  22. package/dist/browser/modules/stream/index.browser.d.ts +13 -19
  23. package/dist/browser/modules/stream/index.browser.js +10 -22
  24. package/dist/browser/modules/stream/index.d.ts +18 -41
  25. package/dist/browser/modules/stream/index.js +15 -44
  26. package/dist/browser/modules/stream/internal/event-utils.d.ts +17 -0
  27. package/dist/browser/modules/stream/internal/event-utils.js +40 -0
  28. package/dist/browser/modules/stream/internal/type-guards.d.ts +9 -0
  29. package/dist/browser/modules/stream/internal/type-guards.js +24 -0
  30. package/dist/browser/modules/stream/pull-stream.d.ts +5 -6
  31. package/dist/browser/modules/stream/pull-stream.js +107 -43
  32. package/dist/browser/modules/stream/shared.d.ts +1 -1
  33. package/dist/browser/modules/stream/shared.js +7 -4
  34. package/dist/browser/modules/stream/streams.browser.d.ts +4 -14
  35. package/dist/browser/modules/stream/streams.browser.js +129 -164
  36. package/dist/browser/modules/stream/streams.d.ts +4 -20
  37. package/dist/browser/modules/stream/streams.js +6 -37
  38. package/dist/browser/modules/stream/utils.js +5 -38
  39. package/dist/cjs/modules/archive/io/archive-sink.js +7 -40
  40. package/dist/cjs/modules/archive/io/archive-source.js +3 -12
  41. package/dist/cjs/modules/excel/utils/ooxml-validator.js +475 -0
  42. package/dist/cjs/modules/excel/worksheet.js +5 -2
  43. package/dist/cjs/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  44. package/dist/cjs/modules/excel/xlsx/xform/drawing/sp-xform.js +115 -0
  45. package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  46. package/dist/cjs/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  47. package/dist/cjs/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  48. package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +110 -12
  49. package/dist/cjs/modules/stream/base-transform.js +34 -20
  50. package/dist/cjs/modules/stream/chunked-builder.js +4 -4
  51. package/dist/cjs/modules/stream/index.browser.js +10 -17
  52. package/dist/cjs/modules/stream/index.js +15 -39
  53. package/dist/cjs/modules/stream/internal/event-utils.js +43 -0
  54. package/dist/cjs/modules/stream/internal/type-guards.js +30 -0
  55. package/dist/cjs/modules/stream/pull-stream.js +107 -43
  56. package/dist/cjs/modules/stream/shared.js +7 -4
  57. package/dist/cjs/modules/stream/streams.browser.js +135 -175
  58. package/dist/cjs/modules/stream/streams.js +16 -49
  59. package/dist/cjs/modules/stream/utils.js +3 -36
  60. package/dist/esm/modules/archive/io/archive-sink.js +6 -38
  61. package/dist/esm/modules/archive/io/archive-source.js +1 -8
  62. package/dist/esm/modules/excel/utils/ooxml-validator.js +469 -0
  63. package/dist/esm/modules/excel/worksheet.js +5 -2
  64. package/dist/esm/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.js +13 -1
  65. package/dist/esm/modules/excel/xlsx/xform/drawing/sp-xform.js +112 -0
  66. package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +30 -2
  67. package/dist/esm/modules/excel/xlsx/xform/drawing/vml-drawing-xform.js +11 -0
  68. package/dist/esm/modules/excel/xlsx/xform/sheet/page-setup-xform.js +16 -2
  69. package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +110 -12
  70. package/dist/esm/modules/stream/base-transform.js +34 -20
  71. package/dist/esm/modules/stream/chunked-builder.js +4 -4
  72. package/dist/esm/modules/stream/index.browser.js +10 -22
  73. package/dist/esm/modules/stream/index.js +15 -44
  74. package/dist/esm/modules/stream/internal/event-utils.js +40 -0
  75. package/dist/esm/modules/stream/internal/type-guards.js +24 -0
  76. package/dist/esm/modules/stream/pull-stream.js +107 -43
  77. package/dist/esm/modules/stream/shared.js +7 -4
  78. package/dist/esm/modules/stream/streams.browser.js +129 -164
  79. package/dist/esm/modules/stream/streams.js +6 -37
  80. package/dist/esm/modules/stream/utils.js +5 -38
  81. package/dist/iife/excelts.iife.js +325 -60
  82. package/dist/iife/excelts.iife.js.map +1 -1
  83. package/dist/iife/excelts.iife.min.js +25 -25
  84. package/dist/types/modules/archive/io/archive-sink.d.ts +0 -1
  85. package/dist/types/modules/archive/io/archive-source.d.ts +0 -2
  86. package/dist/types/modules/excel/utils/ooxml-validator.d.ts +48 -0
  87. package/dist/types/modules/excel/xlsx/xform/drawing/ctrl-prop-xform.d.ts +1 -0
  88. package/dist/types/modules/excel/xlsx/xform/drawing/sp-xform.d.ts +18 -0
  89. package/dist/types/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +6 -1
  90. package/dist/types/modules/excel/xlsx/xform/sheet/page-setup-xform.d.ts +1 -0
  91. package/dist/types/modules/stream/base-transform.d.ts +3 -0
  92. package/dist/types/modules/stream/buffered-stream.d.ts +2 -12
  93. package/dist/types/modules/stream/index.browser.d.ts +13 -19
  94. package/dist/types/modules/stream/index.d.ts +18 -41
  95. package/dist/types/modules/stream/internal/event-utils.d.ts +17 -0
  96. package/dist/types/modules/stream/internal/type-guards.d.ts +9 -0
  97. package/dist/types/modules/stream/pull-stream.d.ts +5 -6
  98. package/dist/types/modules/stream/shared.d.ts +1 -1
  99. package/dist/types/modules/stream/streams.browser.d.ts +4 -14
  100. package/dist/types/modules/stream/streams.d.ts +4 -20
  101. package/package.json +10 -10
@@ -5,6 +5,7 @@ const base_cell_anchor_xform_1 = require("./base-cell-anchor-xform.js");
5
5
  const static_xform_1 = require("../static-xform.js");
6
6
  const cell_position_xform_1 = require("./cell-position-xform.js");
7
7
  const pic_xform_1 = require("./pic-xform.js");
8
+ const sp_xform_1 = require("./sp-xform.js");
8
9
  class TwoCellAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
9
10
  constructor() {
10
11
  super();
@@ -12,6 +13,7 @@ class TwoCellAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
12
13
  "xdr:from": new cell_position_xform_1.CellPositionXform({ tag: "xdr:from" }),
13
14
  "xdr:to": new cell_position_xform_1.CellPositionXform({ tag: "xdr:to" }),
14
15
  "xdr:pic": new pic_xform_1.PicXform(),
16
+ "xdr:sp": new sp_xform_1.SpXform(),
15
17
  "xdr:clientData": new static_xform_1.StaticXform({ tag: "xdr:clientData" })
16
18
  };
17
19
  }
@@ -19,15 +21,41 @@ class TwoCellAnchorXform extends base_cell_anchor_xform_1.BaseCellAnchorXform {
19
21
  return "xdr:twoCellAnchor";
20
22
  }
21
23
  prepare(model, options) {
22
- this.map["xdr:pic"].prepare(model.picture, options);
24
+ if (model.picture) {
25
+ this.map["xdr:pic"].prepare(model.picture, options);
26
+ }
23
27
  }
24
28
  render(xmlStream, model) {
29
+ const wrapAlternateContent = !!model.alternateContent;
30
+ if (wrapAlternateContent) {
31
+ xmlStream.openNode("mc:AlternateContent", {
32
+ "xmlns:mc": "http://schemas.openxmlformats.org/markup-compatibility/2006"
33
+ });
34
+ xmlStream.openNode("mc:Choice", {
35
+ Requires: model.alternateContent?.requires,
36
+ ...(model.alternateContent?.requires === "a14"
37
+ ? {
38
+ "xmlns:a14": "http://schemas.microsoft.com/office/drawing/2010/main"
39
+ }
40
+ : {})
41
+ });
42
+ }
25
43
  xmlStream.openNode(this.tag, { editAs: model.range.editAs || "oneCell" });
26
44
  this.map["xdr:from"].render(xmlStream, model.range.tl);
27
45
  this.map["xdr:to"].render(xmlStream, model.range.br);
28
- this.map["xdr:pic"].render(xmlStream, model.picture);
46
+ if (model.picture) {
47
+ this.map["xdr:pic"].render(xmlStream, model.picture);
48
+ }
49
+ else if (model.shape) {
50
+ this.map["xdr:sp"].render(xmlStream, model.shape);
51
+ }
29
52
  this.map["xdr:clientData"].render(xmlStream, {});
30
53
  xmlStream.closeNode();
54
+ if (wrapAlternateContent) {
55
+ xmlStream.closeNode(); // mc:Choice
56
+ xmlStream.leafNode("mc:Fallback");
57
+ xmlStream.closeNode(); // mc:AlternateContent
58
+ }
31
59
  }
32
60
  parseClose(name) {
33
61
  if (this.parser) {
@@ -110,14 +110,22 @@ class VmlDrawingXform extends base_xform_1.BaseXform {
110
110
  }
111
111
  // ClientData - the core of the checkbox control
112
112
  xmlStream.openNode("x:ClientData", { ObjectType: "Checkbox" });
113
+ // Match Excel's VML patterns (similar to Note ClientData): include positioning and cell address.
114
+ // Omitting these can cause Excel to repair the sheet by dropping all legacy controls.
115
+ xmlStream.leafNode("x:MoveWithCells");
116
+ xmlStream.leafNode("x:SizeWithCells");
113
117
  // Anchor position
114
118
  xmlStream.openNode("x:Anchor");
115
119
  xmlStream.writeText(form_control_1.FormCheckbox.getVmlAnchor(control));
116
120
  xmlStream.closeNode();
121
+ // Protection / text locking
122
+ xmlStream.leafNode("x:Locked", undefined, "False");
123
+ xmlStream.leafNode("x:LockText", undefined, "True");
117
124
  // Print settings
118
125
  xmlStream.leafNode("x:PrintObject", undefined, control.print ? "True" : "False");
119
126
  xmlStream.leafNode("x:AutoFill", undefined, "False");
120
127
  xmlStream.leafNode("x:AutoLine", undefined, "False");
128
+ xmlStream.leafNode("x:TextHAlign", undefined, "Left");
121
129
  xmlStream.leafNode("x:TextVAlign", undefined, "Center");
122
130
  // Linked cell
123
131
  if (control.link) {
@@ -129,6 +137,9 @@ class VmlDrawingXform extends base_xform_1.BaseXform {
129
137
  }
130
138
  // Checked state (0 = unchecked, 1 = checked, 2 = mixed)
131
139
  xmlStream.leafNode("x:Checked", undefined, String(form_control_1.FormCheckbox.getVmlCheckedValue(control)));
140
+ // Cell address (0-based row/column)
141
+ xmlStream.leafNode("x:Row", undefined, String(control.tl.row));
142
+ xmlStream.leafNode("x:Column", undefined, String(control.tl.col));
132
143
  xmlStream.closeNode(); // x:ClientData
133
144
  xmlStream.closeNode(); // v:shape
134
145
  }
@@ -39,13 +39,27 @@ class PageSetupXform extends base_xform_1.BaseXform {
39
39
  get tag() {
40
40
  return "pageSetup";
41
41
  }
42
+ _dpiToXml(value) {
43
+ // Excel commonly omits these attributes. 4294967295 is used as a sentinel default
44
+ // when parsing missing values; it should never be serialized back out.
45
+ if (value === undefined) {
46
+ return undefined;
47
+ }
48
+ if (!Number.isFinite(value)) {
49
+ return undefined;
50
+ }
51
+ if (value === 4294967295) {
52
+ return undefined;
53
+ }
54
+ return value;
55
+ }
42
56
  render(xmlStream, model) {
43
57
  if (model) {
44
58
  const attributes = {
45
59
  paperSize: model.paperSize,
46
60
  orientation: model.orientation,
47
- horizontalDpi: model.horizontalDpi,
48
- verticalDpi: model.verticalDpi,
61
+ horizontalDpi: this._dpiToXml(model.horizontalDpi),
62
+ verticalDpi: this._dpiToXml(model.verticalDpi),
49
63
  pageOrder: pageOrderToXml(model.pageOrder),
50
64
  blackAndWhite: booleanToXml(model.blackAndWhite),
51
65
  draft: booleanToXml(model.draft),
@@ -140,6 +140,14 @@ class WorkSheetXform extends base_xform_1.BaseXform {
140
140
  options.merges = new merges_1.Merges();
141
141
  model.hyperlinks = options.hyperlinks = [];
142
142
  model.comments = options.comments = [];
143
+ // Some Excel builds are surprisingly strict when legacy form controls exist.
144
+ // Emitting a default sheetView (workbookViewId=0) matches typical Excel output
145
+ // and avoids relying on optional element handling.
146
+ if (model.formControls && model.formControls.length > 0) {
147
+ if (!model.views || model.views.length === 0) {
148
+ model.views = [{ workbookViewId: 0 }];
149
+ }
150
+ }
143
151
  options.formulae = {};
144
152
  options.siFormulae = 0;
145
153
  this.map.cols.prepare(model.cols, options);
@@ -281,6 +289,23 @@ class WorkSheetXform extends base_xform_1.BaseXform {
281
289
  // prepare form controls (legacy checkboxes)
282
290
  // Form controls share the VML file with comments, but need separate ctrlProp relationships
283
291
  if (model.formControls && model.formControls.length > 0) {
292
+ // Ensure a DrawingML drawing part exists for form controls.
293
+ // Excel often repairs sheets that have legacy controls but no <drawing> part.
294
+ let { drawing } = model;
295
+ if (!drawing) {
296
+ drawing = model.drawing = {
297
+ rId: nextRid(rels),
298
+ name: `drawing${++options.drawingsCount}`,
299
+ anchors: [],
300
+ rels: []
301
+ };
302
+ options.drawings.push(drawing);
303
+ rels.push({
304
+ Id: drawing.rId,
305
+ Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",
306
+ Target: (0, ooxml_paths_1.drawingRelTargetFromWorksheet)(drawing.name)
307
+ });
308
+ }
284
309
  // If no comments, we need to add the VML drawing relationship for form controls
285
310
  if (model.comments.length === 0) {
286
311
  rels.push({
@@ -289,6 +314,14 @@ class WorkSheetXform extends base_xform_1.BaseXform {
289
314
  Target: (0, ooxml_paths_1.vmlDrawingRelTargetFromWorksheet)(model.id)
290
315
  });
291
316
  }
317
+ // Add hidden DrawingML shapes that bridge to the VML shape ids.
318
+ // This mirrors what Excel writes when it "repairs" legacy form controls.
319
+ const toNativePos = (p) => ({
320
+ nativeCol: p.col,
321
+ nativeColOff: p.colOff,
322
+ nativeRow: p.row,
323
+ nativeRowOff: p.rowOff
324
+ });
292
325
  // Add ctrlProp relationships for each form control
293
326
  for (const control of model.formControls) {
294
327
  const globalCtrlPropId = options.formControlRefs.length + 1;
@@ -301,6 +334,22 @@ class WorkSheetXform extends base_xform_1.BaseXform {
301
334
  Target: (0, ooxml_paths_1.ctrlPropRelTargetFromWorksheet)(globalCtrlPropId)
302
335
  });
303
336
  options.formControlRefs.push(globalCtrlPropId);
337
+ const defaultName = `Check Box ${Math.max(1, control.shapeId - 1024)}`;
338
+ drawing.anchors.push({
339
+ range: {
340
+ editAs: "absolute",
341
+ tl: toNativePos(control.tl),
342
+ br: toNativePos(control.br)
343
+ },
344
+ alternateContent: { requires: "a14" },
345
+ shape: {
346
+ cNvPrId: control.shapeId,
347
+ name: control.name || defaultName,
348
+ hidden: true,
349
+ spid: `_x0000_s${control.shapeId}`,
350
+ text: control.text
351
+ }
352
+ });
304
353
  }
305
354
  }
306
355
  // prepare ext items
@@ -308,7 +357,14 @@ class WorkSheetXform extends base_xform_1.BaseXform {
308
357
  }
309
358
  render(xmlStream, model) {
310
359
  xmlStream.openXml(xml_stream_1.XmlStream.StdDocAttributes);
311
- xmlStream.openNode("worksheet", WorkSheetXform.WORKSHEET_ATTRIBUTES);
360
+ const worksheetAttrs = { ...WorkSheetXform.WORKSHEET_ATTRIBUTES };
361
+ if (model.formControls && model.formControls.length > 0) {
362
+ worksheetAttrs["xmlns:x14"] = "http://schemas.microsoft.com/office/spreadsheetml/2009/9/main";
363
+ worksheetAttrs["xmlns:xdr"] =
364
+ "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing";
365
+ worksheetAttrs["mc:Ignorable"] = `${worksheetAttrs["mc:Ignorable"]} x14`;
366
+ }
367
+ xmlStream.openNode("worksheet", worksheetAttrs);
312
368
  const sheetFormatPropertiesModel = model.properties
313
369
  ? {
314
370
  defaultRowHeight: model.properties.defaultRowHeight,
@@ -358,26 +414,68 @@ class WorkSheetXform extends base_xform_1.BaseXform {
358
414
  this.map.colBreaks.render(xmlStream, model.colBreaks);
359
415
  this.map.drawing.render(xmlStream, model.drawing); // Note: must be after rowBreaks/colBreaks
360
416
  this.map.picture.render(xmlStream, model.background); // Note: must be after drawing
361
- this.map.tableParts.render(xmlStream, model.tables);
417
+ if (model.rels) {
418
+ // Add a <legacyDrawing /> node for each VML drawing relationship (comments and/or form controls).
419
+ // NOTE: Excel is picky about worksheet child element order; legacyDrawing must come before controls.
420
+ model.rels.forEach(rel => {
421
+ if (rel.Type === rel_type_1.RelType.VmlDrawing) {
422
+ xmlStream.leafNode("legacyDrawing", { "r:id": rel.Id });
423
+ }
424
+ });
425
+ }
362
426
  // Controls section for legacy form controls (checkboxes, etc.)
363
427
  // Excel expects <controls> entries that reference ctrlProp relationships.
364
428
  if (model.formControls && model.formControls.length > 0) {
429
+ xmlStream.openNode("mc:AlternateContent");
430
+ xmlStream.openNode("mc:Choice", { Requires: "x14" });
365
431
  xmlStream.openNode("controls");
366
432
  for (const control of model.formControls) {
367
- if (control.ctrlPropRelId) {
368
- xmlStream.leafNode("control", { shapeId: control.shapeId, "r:id": control.ctrlPropRelId });
433
+ if (!control.ctrlPropRelId) {
434
+ continue;
369
435
  }
436
+ const defaultName = `Check Box ${Math.max(1, control.shapeId - 1024)}`;
437
+ xmlStream.openNode("mc:AlternateContent");
438
+ xmlStream.openNode("mc:Choice", { Requires: "x14" });
439
+ xmlStream.openNode("control", {
440
+ shapeId: control.shapeId,
441
+ "r:id": control.ctrlPropRelId,
442
+ name: control.name || defaultName
443
+ });
444
+ xmlStream.openNode("controlPr", {
445
+ locked: 0,
446
+ defaultSize: 0,
447
+ print: control.print ? 1 : 0,
448
+ autoFill: 0,
449
+ autoLine: 0,
450
+ autoPict: 0
451
+ });
452
+ xmlStream.openNode("anchor");
453
+ xmlStream.openNode("from");
454
+ xmlStream.leafNode("xdr:col", undefined, control.tl.col);
455
+ xmlStream.leafNode("xdr:colOff", undefined, control.tl.colOff);
456
+ xmlStream.leafNode("xdr:row", undefined, control.tl.row);
457
+ xmlStream.leafNode("xdr:rowOff", undefined, control.tl.rowOff);
458
+ xmlStream.closeNode();
459
+ xmlStream.openNode("to");
460
+ xmlStream.leafNode("xdr:col", undefined, control.br.col);
461
+ xmlStream.leafNode("xdr:colOff", undefined, control.br.colOff);
462
+ xmlStream.leafNode("xdr:row", undefined, control.br.row);
463
+ xmlStream.leafNode("xdr:rowOff", undefined, control.br.rowOff);
464
+ xmlStream.closeNode(); // to
465
+ xmlStream.closeNode(); // anchor
466
+ xmlStream.closeNode(); // controlPr
467
+ xmlStream.closeNode(); // control
468
+ xmlStream.closeNode(); // mc:Choice
469
+ xmlStream.leafNode("mc:Fallback");
470
+ xmlStream.closeNode(); // mc:AlternateContent
370
471
  }
371
472
  xmlStream.closeNode();
473
+ xmlStream.closeNode();
474
+ xmlStream.leafNode("mc:Fallback");
475
+ xmlStream.closeNode();
372
476
  }
373
- if (model.rels) {
374
- // Add a <legacyDrawing /> node for each VML drawing relationship (comments and/or form controls).
375
- model.rels.forEach(rel => {
376
- if (rel.Type === rel_type_1.RelType.VmlDrawing) {
377
- xmlStream.leafNode("legacyDrawing", { "r:id": rel.Id });
378
- }
379
- });
380
- }
477
+ // Table parts must come after <controls> in worksheet element order.
478
+ this.map.tableParts.render(xmlStream, model.tables);
381
479
  // extLst should be the last element in the worksheet.
382
480
  this.map.extLst.render(xmlStream, model);
383
481
  xmlStream.closeNode();
@@ -20,6 +20,8 @@ class BaseTransform extends event_emitter_1.EventEmitter {
20
20
  this._isDestroyed = false;
21
21
  this._isFinished = false;
22
22
  this._errorEmitted = false;
23
+ this._ending = false;
24
+ this._flushInProgress = false;
23
25
  this._objectMode = options.objectMode ?? false;
24
26
  this._highWaterMark = options.highWaterMark ?? 16384;
25
27
  }
@@ -48,26 +50,8 @@ class BaseTransform extends event_emitter_1.EventEmitter {
48
50
  if (chunk !== undefined) {
49
51
  this.write(chunk);
50
52
  }
51
- // Wait for buffer to drain, then flush
52
- const checkAndFlush = () => {
53
- if (this._buffer.length === this._bufferIndex && !this._isProcessing) {
54
- this.processFlush((err, data) => {
55
- if (err) {
56
- this._emitError(err);
57
- }
58
- else if (data !== undefined) {
59
- this.emit("data", data);
60
- }
61
- this._isFinished = true;
62
- this.emit("finish");
63
- this.emit("end");
64
- });
65
- }
66
- else {
67
- setTimeout(checkAndFlush, 0);
68
- }
69
- };
70
- checkAndFlush();
53
+ this._ending = true;
54
+ this._maybeFlush();
71
55
  }
72
56
  /**
73
57
  * Destroy the stream
@@ -116,13 +100,43 @@ class BaseTransform extends event_emitter_1.EventEmitter {
116
100
  }
117
101
  // Process next chunk
118
102
  this._processNext();
103
+ this._maybeFlush();
119
104
  }
120
105
  });
121
106
  }
122
107
  catch (err) {
123
108
  this._isProcessing = false;
124
109
  this._emitError(err);
110
+ this._maybeFlush();
111
+ }
112
+ }
113
+ _maybeFlush() {
114
+ if (!this._ending || this._isDestroyed || this._isFinished || this._flushInProgress) {
115
+ return;
125
116
  }
117
+ // If an error was emitted, stop flushing to avoid hanging end().
118
+ if (this._errorEmitted) {
119
+ this._isFinished = true;
120
+ this.emit("finish");
121
+ this.emit("end");
122
+ return;
123
+ }
124
+ if (this._isProcessing || this._bufferIndex < this._buffer.length) {
125
+ return;
126
+ }
127
+ this._flushInProgress = true;
128
+ this.processFlush((err, data) => {
129
+ this._flushInProgress = false;
130
+ if (err) {
131
+ this._emitError(err);
132
+ }
133
+ else if (data !== undefined) {
134
+ this.emit("data", data);
135
+ }
136
+ this._isFinished = true;
137
+ this.emit("finish");
138
+ this.emit("end");
139
+ });
126
140
  }
127
141
  /**
128
142
  * Emit error only once
@@ -48,7 +48,7 @@ class ChunkedBuilder {
48
48
  _consolidate() {
49
49
  if (this._pieces.length > 0) {
50
50
  this._chunks.push(this._pieces.join(""));
51
- this._pieces = [];
51
+ this._pieces.length = 0;
52
52
  }
53
53
  }
54
54
  /**
@@ -79,8 +79,8 @@ class ChunkedBuilder {
79
79
  * Clear all content
80
80
  */
81
81
  clear() {
82
- this._pieces = [];
83
- this._chunks = [];
82
+ this._pieces.length = 0;
83
+ this._chunks.length = 0;
84
84
  this._totalLength = 0;
85
85
  }
86
86
  /**
@@ -102,7 +102,7 @@ class ChunkedBuilder {
102
102
  // Has chunks - consolidate and join
103
103
  if (piecesLen > 0) {
104
104
  this._chunks.push(this._pieces.join(""));
105
- this._pieces = [];
105
+ this._pieces.length = 0;
106
106
  }
107
107
  if (this._chunks.length === 1) {
108
108
  return this._chunks[0];
@@ -1,17 +1,16 @@
1
1
  "use strict";
2
2
  /**
3
- * Stream Module (browser type surface)
3
+ * Stream Module (browser entry)
4
4
  *
5
- * Mirrors [src/modules/stream/index.ts] but explicitly re-exports from
6
- * ./streams.browser so we can enforce index export-surface parity.
5
+ * Mirrors the public surface of `./index.ts`, but exports the browser
6
+ * implementation from `./streams.browser`.
7
+ *
8
+ * This file is intentionally export-only (tree-shaking friendly).
7
9
  */
8
10
  Object.defineProperty(exports, "__esModule", { value: true });
9
11
  exports.consumers = exports.Writeable = exports.duplexPair = exports.setDefaultHighWaterMark = exports.getDefaultHighWaterMark = exports.isErrored = exports.isDisturbed = exports.isDestroyed = exports.isStream = exports.isDuplex = exports.isTransform = exports.isWritable = exports.isReadable = exports.promisify = exports.once = exports.finishedAll = exports.compose = exports.addAbortSignal = exports.copyStream = exports.drainStream = exports.streamToString = exports.streamToBuffer = exports.streamToUint8Array = exports.streamToPromise = exports.finished = exports.pipeline = exports.createNullWritable = exports.createEmptyReadable = exports.createDuplex = exports.createReadableFromPromise = exports.createReadableFromGenerator = exports.createReadableFromAsyncIterable = exports.createReadableFromArray = exports.createBufferedStream = exports.createPullStream = exports.createPassThrough = exports.createCollector = exports.createTransform = exports.createWritable = exports.createReadable = exports.BufferChunk = exports.StringChunk = exports.BufferedStream = exports.PullStream = exports.Collector = exports.PassThrough = exports.Duplex = exports.Transform = exports.Writable = exports.Readable = void 0;
10
12
  exports.filter = exports.transform = exports.fromBytes = exports.fromJSON = exports.fromString = exports.bytes = exports.json = exports.text = exports.collect = exports.concatUint8Arrays = exports.bufferToString = exports.toUint8Array = exports.uint8ArraySlice = exports.uint8ArrayIndexOf = exports.uint8ArrayEquals = exports.uint8ArrayToString = exports.stringToUint8Array = exports.textDecoder = exports.textEncoder = exports.TransactionalChunkedBuilder = exports.ChunkedBuilder = exports.EventEmitter = exports.promises = void 0;
11
- // =============================================================================
12
- // Native Stream Classes and Functions (browser)
13
- // =============================================================================
14
- const streams_browser_1 = require("./streams.browser.js");
13
+ var streams_browser_1 = require("./streams.browser.js");
15
14
  Object.defineProperty(exports, "Readable", { enumerable: true, get: function () { return streams_browser_1.Readable; } });
16
15
  Object.defineProperty(exports, "Writable", { enumerable: true, get: function () { return streams_browser_1.Writable; } });
17
16
  Object.defineProperty(exports, "Transform", { enumerable: true, get: function () { return streams_browser_1.Transform; } });
@@ -63,18 +62,12 @@ Object.defineProperty(exports, "duplexPair", { enumerable: true, get: function (
63
62
  Object.defineProperty(exports, "Writeable", { enumerable: true, get: function () { return streams_browser_1.normalizeWritable; } });
64
63
  Object.defineProperty(exports, "consumers", { enumerable: true, get: function () { return streams_browser_1.consumers; } });
65
64
  Object.defineProperty(exports, "promises", { enumerable: true, get: function () { return streams_browser_1.promises; } });
66
- const event_emitter_1 = require("./event-emitter.js");
65
+ var event_emitter_1 = require("./event-emitter.js");
67
66
  Object.defineProperty(exports, "EventEmitter", { enumerable: true, get: function () { return event_emitter_1.EventEmitter; } });
68
- // =============================================================================
69
- // ChunkedBuilder (platform-independent)
70
- // =============================================================================
71
- const chunked_builder_1 = require("./chunked-builder.js");
67
+ var chunked_builder_1 = require("./chunked-builder.js");
72
68
  Object.defineProperty(exports, "ChunkedBuilder", { enumerable: true, get: function () { return chunked_builder_1.ChunkedBuilder; } });
73
69
  Object.defineProperty(exports, "TransactionalChunkedBuilder", { enumerable: true, get: function () { return chunked_builder_1.TransactionalChunkedBuilder; } });
74
- // =============================================================================
75
- // Utility Functions (platform-independent)
76
- // =============================================================================
77
- const shared_1 = require("./shared.js");
70
+ var shared_1 = require("./shared.js");
78
71
  Object.defineProperty(exports, "textEncoder", { enumerable: true, get: function () { return shared_1.textEncoder; } });
79
72
  Object.defineProperty(exports, "textDecoder", { enumerable: true, get: function () { return shared_1.textDecoder; } });
80
73
  Object.defineProperty(exports, "stringToUint8Array", { enumerable: true, get: function () { return shared_1.stringToUint8Array; } });
@@ -85,7 +78,7 @@ Object.defineProperty(exports, "uint8ArraySlice", { enumerable: true, get: funct
85
78
  Object.defineProperty(exports, "toUint8Array", { enumerable: true, get: function () { return shared_1.toUint8Array; } });
86
79
  Object.defineProperty(exports, "bufferToString", { enumerable: true, get: function () { return shared_1.bufferToString; } });
87
80
  Object.defineProperty(exports, "concatUint8Arrays", { enumerable: true, get: function () { return shared_1.concatUint8Arrays; } });
88
- const utils_1 = require("./utils.js");
81
+ var utils_1 = require("./utils.js");
89
82
  Object.defineProperty(exports, "collect", { enumerable: true, get: function () { return utils_1.collect; } });
90
83
  Object.defineProperty(exports, "text", { enumerable: true, get: function () { return utils_1.text; } });
91
84
  Object.defineProperty(exports, "json", { enumerable: true, get: function () { return utils_1.json; } });
@@ -1,44 +1,26 @@
1
1
  "use strict";
2
2
  /**
3
- * Stream Module
3
+ * Stream Module (Node.js entry)
4
4
  *
5
- * Native stream implementations for Node.js and Browser.
5
+ * Public entrypoint for stream utilities and classes.
6
6
  *
7
- * - Node.js: Uses native `stream` module (Readable, Writable, Transform, Duplex, PassThrough)
8
- * - Browser: Uses Web Streams API (ReadableStream, WritableStream, TransformStream)
9
- *
10
- * Both implementations provide the same API for cross-platform compatibility.
7
+ * Notes:
8
+ * - This file is intentionally export-only (tree-shaking friendly).
9
+ * - Browser builds should import from `@stream/index.browser`.
11
10
  *
12
11
  * @example
13
- * ```typescript
14
- * import {
15
- * Readable,
16
- * Writable,
17
- * Transform,
18
- * Duplex,
19
- * PassThrough,
20
- * pipeline,
21
- * createTransform,
22
- * streamToUint8Array
23
- * } from './modules/stream';
24
- *
25
- * // Create a transform stream
26
- * const uppercase = createTransform<Uint8Array, Uint8Array>(chunk => {
27
- * const text = new TextDecoder().decode(chunk);
28
- * return new TextEncoder().encode(text.toUpperCase());
29
- * });
12
+ * ```ts
13
+ * import { pipeline, createTransform, createCollector } from "@stream";
30
14
  *
31
- * // Use pipeline for clean stream composition
32
- * await pipeline(readable, uppercase, writable);
15
+ * const upper = createTransform<Uint8Array, Uint8Array>(chunk => chunk);
16
+ * const out = createCollector<Uint8Array>();
17
+ * await pipeline(source, upper, out);
33
18
  * ```
34
19
  */
35
20
  Object.defineProperty(exports, "__esModule", { value: true });
36
21
  exports.consumers = exports.Writeable = exports.duplexPair = exports.setDefaultHighWaterMark = exports.getDefaultHighWaterMark = exports.isErrored = exports.isDisturbed = exports.isDestroyed = exports.isStream = exports.isDuplex = exports.isTransform = exports.isWritable = exports.isReadable = exports.promisify = exports.once = exports.finishedAll = exports.compose = exports.addAbortSignal = exports.copyStream = exports.drainStream = exports.streamToString = exports.streamToBuffer = exports.streamToUint8Array = exports.streamToPromise = exports.finished = exports.pipeline = exports.createNullWritable = exports.createEmptyReadable = exports.createDuplex = exports.createReadableFromPromise = exports.createReadableFromGenerator = exports.createReadableFromAsyncIterable = exports.createReadableFromArray = exports.createBufferedStream = exports.createPullStream = exports.createPassThrough = exports.createCollector = exports.createTransform = exports.createWritable = exports.createReadable = exports.BufferChunk = exports.StringChunk = exports.BufferedStream = exports.PullStream = exports.Collector = exports.PassThrough = exports.Duplex = exports.Transform = exports.Writable = exports.Readable = void 0;
37
22
  exports.filter = exports.transform = exports.fromBytes = exports.fromJSON = exports.fromString = exports.bytes = exports.json = exports.text = exports.collect = exports.concatUint8Arrays = exports.bufferToString = exports.toUint8Array = exports.uint8ArraySlice = exports.uint8ArrayIndexOf = exports.uint8ArrayEquals = exports.uint8ArrayToString = exports.stringToUint8Array = exports.textDecoder = exports.textEncoder = exports.TransactionalChunkedBuilder = exports.ChunkedBuilder = exports.EventEmitter = exports.promises = void 0;
38
- // =============================================================================
39
- // Native Stream Classes and Functions (platform-specific)
40
- // =============================================================================
41
- const streams_1 = require("./streams.js");
23
+ var streams_1 = require("./streams.js");
42
24
  Object.defineProperty(exports, "Readable", { enumerable: true, get: function () { return streams_1.Readable; } });
43
25
  Object.defineProperty(exports, "Writable", { enumerable: true, get: function () { return streams_1.Writable; } });
44
26
  Object.defineProperty(exports, "Transform", { enumerable: true, get: function () { return streams_1.Transform; } });
@@ -90,18 +72,12 @@ Object.defineProperty(exports, "duplexPair", { enumerable: true, get: function (
90
72
  Object.defineProperty(exports, "Writeable", { enumerable: true, get: function () { return streams_1.normalizeWritable; } });
91
73
  Object.defineProperty(exports, "consumers", { enumerable: true, get: function () { return streams_1.consumers; } });
92
74
  Object.defineProperty(exports, "promises", { enumerable: true, get: function () { return streams_1.promises; } });
93
- const event_emitter_1 = require("./event-emitter.js");
75
+ var event_emitter_1 = require("./event-emitter.js");
94
76
  Object.defineProperty(exports, "EventEmitter", { enumerable: true, get: function () { return event_emitter_1.EventEmitter; } });
95
- // =============================================================================
96
- // ChunkedBuilder (platform-independent)
97
- // =============================================================================
98
- const chunked_builder_1 = require("./chunked-builder.js");
77
+ var chunked_builder_1 = require("./chunked-builder.js");
99
78
  Object.defineProperty(exports, "ChunkedBuilder", { enumerable: true, get: function () { return chunked_builder_1.ChunkedBuilder; } });
100
79
  Object.defineProperty(exports, "TransactionalChunkedBuilder", { enumerable: true, get: function () { return chunked_builder_1.TransactionalChunkedBuilder; } });
101
- // =============================================================================
102
- // Utility Functions (platform-independent)
103
- // =============================================================================
104
- const shared_1 = require("./shared.js");
80
+ var shared_1 = require("./shared.js");
105
81
  Object.defineProperty(exports, "textEncoder", { enumerable: true, get: function () { return shared_1.textEncoder; } });
106
82
  Object.defineProperty(exports, "textDecoder", { enumerable: true, get: function () { return shared_1.textDecoder; } });
107
83
  Object.defineProperty(exports, "stringToUint8Array", { enumerable: true, get: function () { return shared_1.stringToUint8Array; } });
@@ -112,7 +88,7 @@ Object.defineProperty(exports, "uint8ArraySlice", { enumerable: true, get: funct
112
88
  Object.defineProperty(exports, "toUint8Array", { enumerable: true, get: function () { return shared_1.toUint8Array; } });
113
89
  Object.defineProperty(exports, "bufferToString", { enumerable: true, get: function () { return shared_1.bufferToString; } });
114
90
  Object.defineProperty(exports, "concatUint8Arrays", { enumerable: true, get: function () { return shared_1.concatUint8Arrays; } });
115
- const utils_1 = require("./utils.js");
91
+ var utils_1 = require("./utils.js");
116
92
  Object.defineProperty(exports, "collect", { enumerable: true, get: function () { return utils_1.collect; } });
117
93
  Object.defineProperty(exports, "text", { enumerable: true, get: function () { return utils_1.text; } });
118
94
  Object.defineProperty(exports, "json", { enumerable: true, get: function () { return utils_1.json; } });
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ /**
3
+ * Small event utilities for Node-style emitters.
4
+ *
5
+ * Prefer keeping this separate from the main stream implementation so other
6
+ * modules (e.g. archive) can reuse it without pulling in the whole stream API.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.onceEvent = onceEvent;
10
+ function off(emitter, event, listener) {
11
+ if (typeof emitter.off === "function") {
12
+ emitter.off(event, listener);
13
+ }
14
+ else if (typeof emitter.removeListener === "function") {
15
+ emitter.removeListener(event, listener);
16
+ }
17
+ }
18
+ /**
19
+ * Resolve when an emitter fires `event`, reject on `error`.
20
+ */
21
+ function onceEvent(emitter, event) {
22
+ return new Promise((resolve, reject) => {
23
+ const onError = (err) => {
24
+ cleanup();
25
+ reject(err instanceof Error ? err : new Error(String(err)));
26
+ };
27
+ const onDone = () => {
28
+ cleanup();
29
+ resolve();
30
+ };
31
+ const cleanup = () => {
32
+ off(emitter, "error", onError);
33
+ off(emitter, event, onDone);
34
+ };
35
+ if (typeof emitter.once === "function") {
36
+ emitter.once("error", onError);
37
+ emitter.once(event, onDone);
38
+ return;
39
+ }
40
+ emitter.on?.("error", onError);
41
+ emitter.on?.(event, onDone);
42
+ });
43
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ /**
3
+ * Lightweight runtime type guards shared across modules.
4
+ *
5
+ * Keep this file dependency-free to maximize deduping in bundled builds.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.isReadableStream = isReadableStream;
9
+ exports.isWritableStream = isWritableStream;
10
+ exports.isAsyncIterable = isAsyncIterable;
11
+ exports.isTransformStream = isTransformStream;
12
+ function isReadableStream(value) {
13
+ return !!value && typeof value === "object" && typeof value.getReader === "function";
14
+ }
15
+ function isWritableStream(value) {
16
+ return !!value && typeof value === "object" && typeof value.getWriter === "function";
17
+ }
18
+ function isAsyncIterable(value) {
19
+ return (!!value &&
20
+ (typeof value === "object" || typeof value === "function") &&
21
+ typeof value[Symbol.asyncIterator] === "function");
22
+ }
23
+ function isTransformStream(value) {
24
+ return (!!value &&
25
+ typeof value === "object" &&
26
+ !!value.readable &&
27
+ !!value.writable &&
28
+ isReadableStream(value.readable) &&
29
+ isWritableStream(value.writable));
30
+ }