@zip.js/zip.js 2.8.50 → 2.8.51

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.
package/index.cjs CHANGED
@@ -8598,6 +8598,8 @@ U(setDefaultConfiguration);
8598
8598
  const ERR_ENTRY_EXISTS = "Entry filename already exists";
8599
8599
  const ERR_READABLE_CONSUMED = "Readable stream already consumed";
8600
8600
  const ERR_ABORT_EXPORT = "zipjs-abort-export";
8601
+ const ERR_ABORTED = "The operation was aborted";
8602
+ const ABORT_ERROR_NAME = "AbortError";
8601
8603
  const INFOZIP_EXTRA_FIELD_TYPE = "infozip";
8602
8604
  const INTERPRETED_EXTRA_FIELD_TYPES = new Set([
8603
8605
  EXTRAFIELD_TYPE_ZIP64,
@@ -9050,6 +9052,10 @@ class ZipDirectoryEntry extends ZipEntry {
9050
9052
  }
9051
9053
  }
9052
9054
 
9055
+ getChildren(options = {}) {
9056
+ return collectChildren(this, options.recursive);
9057
+ }
9058
+
9053
9059
  isPasswordProtected() {
9054
9060
  const children = this.children;
9055
9061
  for (let childIndex = 0; childIndex < children.length; childIndex++) {
@@ -9141,6 +9147,10 @@ class FS {
9141
9147
  return this.root.getChildByName(name);
9142
9148
  }
9143
9149
 
9150
+ getChildren(options) {
9151
+ return this.root.getChildren(options);
9152
+ }
9153
+
9144
9154
  addDirectory(name, options) {
9145
9155
  return this.root.addDirectory(name, options);
9146
9156
  }
@@ -9400,103 +9410,101 @@ function getUserExtraField(extraField) {
9400
9410
  async function exportZip(zipWriter, entry, totalSize, options, readers) {
9401
9411
  const selectedEntry = entry;
9402
9412
  const entryOffsets = new Map();
9403
- await process(zipWriter, entry);
9413
+ if (options.bufferedWrite) {
9414
+ await processChildren(entry);
9415
+ } else {
9416
+ for (const child of entry.getChildren({ recursive: true })) {
9417
+ await addChild(child);
9418
+ }
9419
+ }
9404
9420
 
9405
- async function process(zipWriter, entry) {
9406
- await exportChild();
9421
+ async function processChildren(entry) {
9422
+ const results = await Promise.allSettled(entry.children.map(async child => {
9423
+ await addChild(child);
9424
+ await processChildren(child);
9425
+ }));
9426
+ const errorResult = results.find(result => result.status == "rejected");
9427
+ if (errorResult) {
9428
+ throw errorResult.reason;
9429
+ }
9430
+ }
9407
9431
 
9408
- async function exportChild() {
9409
- if (options.bufferedWrite) {
9410
- const results = await Promise.allSettled(entry.children.map(processChild));
9411
- const errorResult = results.find(result => result.status == "rejected");
9412
- if (errorResult) {
9413
- throw errorResult.reason;
9432
+ async function addChild(child) {
9433
+ const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9434
+ const childOptions = child.options || {};
9435
+ let zipEntryOptions = {};
9436
+ if (child.data instanceof Entry) {
9437
+ const {
9438
+ externalFileAttributes,
9439
+ versionMadeBy,
9440
+ comment,
9441
+ lastModDate,
9442
+ creationDate,
9443
+ lastAccessDate,
9444
+ uncompressedSize,
9445
+ encrypted,
9446
+ zipCrypto,
9447
+ crc32,
9448
+ compressionMethod,
9449
+ extraFieldAES,
9450
+ internalFileAttributes,
9451
+ extraField,
9452
+ uid,
9453
+ gid
9454
+ } = child.data;
9455
+ zipEntryOptions = {
9456
+ externalFileAttributes,
9457
+ versionMadeBy,
9458
+ comment,
9459
+ lastModDate,
9460
+ creationDate,
9461
+ lastAccessDate,
9462
+ internalFileAttributes
9463
+ };
9464
+ const userExtraField = getUserExtraField(extraField);
9465
+ if (userExtraField) {
9466
+ zipEntryOptions.extraField = userExtraField;
9467
+ }
9468
+ if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9469
+ Object.assign(zipEntryOptions, {
9470
+ uid,
9471
+ gid,
9472
+ unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9473
+ });
9474
+ }
9475
+ if (child.passThrough) {
9476
+ let level, encryptionStrength;
9477
+ if (compressionMethod === 0) {
9478
+ level = 0;
9414
9479
  }
9415
- } else {
9416
- for (const child of entry.children) {
9417
- await processChild(child);
9480
+ if (extraFieldAES) {
9481
+ encryptionStrength = extraFieldAES.strength;
9418
9482
  }
9419
- }
9420
- }
9421
-
9422
- async function processChild(child) {
9423
- const name = options.relativePath ? child.getRelativeName(selectedEntry) : child.getFullname();
9424
- const childOptions = child.options || {};
9425
- let zipEntryOptions = {};
9426
- if (child.data instanceof Entry) {
9427
- const {
9428
- externalFileAttributes,
9429
- versionMadeBy,
9430
- comment,
9431
- lastModDate,
9432
- creationDate,
9433
- lastAccessDate,
9434
- uncompressedSize,
9483
+ zipEntryOptions = Object.assign(zipEntryOptions, {
9484
+ passThrough: true,
9435
9485
  encrypted,
9436
9486
  zipCrypto,
9437
9487
  crc32,
9438
- compressionMethod,
9439
- extraFieldAES,
9440
- internalFileAttributes,
9441
- extraField,
9442
- uid,
9443
- gid
9444
- } = child.data;
9445
- zipEntryOptions = {
9446
- externalFileAttributes,
9447
- versionMadeBy,
9448
- comment,
9449
- lastModDate,
9450
- creationDate,
9451
- lastAccessDate,
9452
- internalFileAttributes
9453
- };
9454
- const userExtraField = getUserExtraField(extraField);
9455
- if (userExtraField) {
9456
- zipEntryOptions.extraField = userExtraField;
9457
- }
9458
- if (uid !== UNDEFINED_VALUE || gid !== UNDEFINED_VALUE) {
9459
- Object.assign(zipEntryOptions, {
9460
- uid,
9461
- gid,
9462
- unixExtraFieldType: options.unixExtraFieldType || INFOZIP_EXTRA_FIELD_TYPE
9463
- });
9464
- }
9465
- if (child.passThrough) {
9466
- let level, encryptionStrength;
9467
- if (compressionMethod === 0) {
9468
- level = 0;
9469
- }
9470
- if (extraFieldAES) {
9471
- encryptionStrength = extraFieldAES.strength;
9472
- }
9473
- zipEntryOptions = Object.assign(zipEntryOptions, {
9474
- passThrough: true,
9475
- encrypted,
9476
- zipCrypto,
9477
- crc32,
9478
- uncompressedSize,
9479
- level,
9480
- encryptionStrength,
9481
- compressionMethod
9482
- });
9483
- }
9488
+ uncompressedSize,
9489
+ level,
9490
+ encryptionStrength,
9491
+ compressionMethod
9492
+ });
9484
9493
  }
9485
- await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9486
- directory: child.directory,
9487
- onprogress: async indexProgress => {
9488
- if (options.onprogress) {
9489
- entryOffsets.set(name, indexProgress);
9490
- try {
9491
- await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9492
- } catch {
9493
- // ignored
9494
- }
9494
+ }
9495
+ await zipWriter.add(name, readers.get(child), Object.assign({}, options, zipEntryOptions, childOptions, {
9496
+ directory: child.directory,
9497
+ onprogress: async indexProgress => {
9498
+ if (options.onprogress) {
9499
+ entryOffsets.set(name, indexProgress);
9500
+ try {
9501
+ await options.onprogress(Array.from(entryOffsets.values()).reduce((previousValue, currentValue) => previousValue + currentValue), totalSize);
9502
+ } catch {
9503
+ // ignored
9495
9504
  }
9496
9505
  }
9497
- }));
9498
- await process(zipWriter, child);
9499
- }
9506
+ }
9507
+ }));
9500
9508
  }
9501
9509
  }
9502
9510
 
@@ -9552,6 +9560,7 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9552
9560
  const { signal } = abortController;
9553
9561
  const releaseSignal = forwardAbort(options.signal, abortController);
9554
9562
  const exportedEntryNames = [];
9563
+ let exportAborted = false;
9555
9564
  try {
9556
9565
  await exportChildren(zipEntry, directoryHandle);
9557
9566
  } catch (error) {
@@ -9584,10 +9593,10 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9584
9593
 
9585
9594
  async function exportChild(child, parentHandle) {
9586
9595
  if (signal.aborted) {
9587
- if (isExportAborted(signal.reason)) {
9596
+ if (exportAborted || isExportAborted(signal.reason)) {
9588
9597
  return;
9589
9598
  }
9590
- throw signal.reason;
9599
+ throw signal.reason === UNDEFINED_VALUE ? new DOMException(ERR_ABORTED, ABORT_ERROR_NAME) : signal.reason;
9591
9600
  }
9592
9601
  try {
9593
9602
  if (child.directory) {
@@ -9596,22 +9605,27 @@ async function exportFileSystemHandle(zipEntry, directoryHandle, options) {
9596
9605
  } else {
9597
9606
  const fileHandle = await parentHandle.getFileHandle(child.name, { create: true });
9598
9607
  const writable = await fileHandle.createWritable();
9599
- await child.getData({ writable }, Object.assign({}, options, {
9600
- signal,
9601
- onprogress: async progress => {
9602
- if (options.onprogress) {
9603
- writtenSizes.set(child.id, progress);
9604
- try {
9605
- await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9606
- } catch {
9607
- // ignored
9608
+ try {
9609
+ await child.getData({ writable }, Object.assign({}, options, {
9610
+ signal,
9611
+ onprogress: async progress => {
9612
+ if (options.onprogress) {
9613
+ writtenSizes.set(child.id, progress);
9614
+ try {
9615
+ await options.onprogress(Array.from(writtenSizes.values()).reduce((previousValue, currentValue) => previousValue + currentValue, 0), totalSize);
9616
+ } catch {
9617
+ // ignored
9618
+ }
9608
9619
  }
9609
9620
  }
9610
- }
9611
- }));
9621
+ }));
9622
+ } catch (error) {
9623
+ throw exportAborted ? new Error(ERR_ABORT_EXPORT) : error;
9624
+ }
9612
9625
  exportedEntryNames.push(child.getRelativeName(zipEntry));
9613
9626
  }
9614
9627
  } catch (error) {
9628
+ exportAborted = true;
9615
9629
  abortController.abort(new Error(ERR_ABORT_EXPORT));
9616
9630
  try {
9617
9631
  if (error.entryName === UNDEFINED_VALUE) {
@@ -9683,6 +9697,21 @@ function resetFS(fs) {
9683
9697
  fs.root = new ZipDirectoryEntry(fs);
9684
9698
  }
9685
9699
 
9700
+ function collectChildren(directory, recursive) {
9701
+ const children = [];
9702
+ const pendingDirectories = [directory];
9703
+ let directoryIndex = 0;
9704
+ while (directoryIndex < pendingDirectories.length) {
9705
+ for (const child of pendingDirectories[directoryIndex++].children) {
9706
+ children.push(child);
9707
+ if (recursive) {
9708
+ pendingDirectories.push(child);
9709
+ }
9710
+ }
9711
+ }
9712
+ return children;
9713
+ }
9714
+
9686
9715
  function registerEntries(fs, entry) {
9687
9716
  const pendingEntries = [entry];
9688
9717
  while (pendingEntries.length) {
@@ -9801,6 +9830,7 @@ exports.BlobReader = BlobReader;
9801
9830
  exports.BlobWriter = BlobWriter;
9802
9831
  exports.Data64URIReader = Data64URIReader;
9803
9832
  exports.Data64URIWriter = Data64URIWriter;
9833
+ exports.ERR_ABORTED = ERR_ABORTED;
9804
9834
  exports.ERR_AMBIGUOUS_ARCHIVE = ERR_AMBIGUOUS_ARCHIVE;
9805
9835
  exports.ERR_BAD_FORMAT = ERR_BAD_FORMAT;
9806
9836
  exports.ERR_CENTRAL_DIRECTORY_NOT_FOUND = ERR_CENTRAL_DIRECTORY_NOT_FOUND;
package/index.d.cts CHANGED
@@ -2815,6 +2815,23 @@ export class ZipDirectoryEntry extends ZipEntry {
2815
2815
  * @returns A {@link ZipFileEntry} or a {@link ZipDirectoryEntry} instance (use the {@link ZipFileEntry#directory} and {@link ZipDirectoryEntry#directory} properties to differentiate entries).
2816
2816
  */
2817
2817
  getChildByName(name: string): ZipEntry | undefined;
2818
+ /**
2819
+ * Gets the children of the directory
2820
+ *
2821
+ * @remarks The returned array is a snapshot taken when the method is called: entries added or removed
2822
+ * afterwards are not reflected, and an entry removed while the array is being iterated is still present
2823
+ * but detached from the filesystem.
2824
+ *
2825
+ * With `recursive`, the descendants are ordered level by level, i.e. the children of a directory come
2826
+ * before the children of its subdirectories, like the result of `readdir(path, { recursive: true })` in
2827
+ * Node.js. This is also the order in which `{@link ZipDirectoryEntry}#export*()` writes them.
2828
+ *
2829
+ * Unlike {@link FS#entries}, the directory itself is not included and removed entries leave no empty slot.
2830
+ *
2831
+ * @param options The options.
2832
+ * @returns The array of {@link ZipEntry} instances.
2833
+ */
2834
+ getChildren(options?: ZipDirectoryEntryGetChildrenOptions): ZipEntry[];
2818
2835
  /**
2819
2836
  * Adds a directory
2820
2837
  *
@@ -3064,6 +3081,10 @@ export class ZipDirectoryEntry extends ZipEntry {
3064
3081
  * Running the same export again is the supported way to recover, since directories are merged and
3065
3082
  * files are overwritten.
3066
3083
  *
3084
+ * @remarks An entry flagged as a symbolic link by its {@link EntryMetaData#externalFileAttributes} is written
3085
+ * as a regular file whose content is the path of the link target, because the File System Access API cannot
3086
+ * create symbolic links.
3087
+ *
3067
3088
  * @param directoryHandle The target `FileSystemDirectoryHandle` instance.
3068
3089
  * @param options The options.
3069
3090
  * @returns A promise resolving to the target `FileSystemDirectoryHandle` instance.
@@ -3096,6 +3117,18 @@ export interface ZipDirectoryEntryImportHttpOptions
3096
3117
  extends ZipReaderConstructorOptions,
3097
3118
  HttpOptions {}
3098
3119
 
3120
+ /**
3121
+ * Represents the options passed to {@link ZipDirectoryEntry#getChildren} and {@link FS#getChildren}.
3122
+ */
3123
+ export interface ZipDirectoryEntryGetChildrenOptions {
3124
+ /**
3125
+ * `true` to return all the descendants of the directory instead of its direct children only.
3126
+ *
3127
+ * @defaultValue false
3128
+ */
3129
+ recursive?: boolean;
3130
+ }
3131
+
3099
3132
  /**
3100
3133
  * Represents the options passed to `{@link ZipDirectoryEntry}#export*()`.
3101
3134
  */
@@ -3156,6 +3189,7 @@ export interface FS
3156
3189
  extends Pick<
3157
3190
  ZipDirectoryEntry,
3158
3191
  | "getChildByName"
3192
+ | "getChildren"
3159
3193
  | "addDirectory"
3160
3194
  | "addText"
3161
3195
  | "addBlob"
@@ -3504,6 +3538,15 @@ export const ERR_ENTRY_EXISTS: string;
3504
3538
  * Readable stream already consumed error (thrown by the filesystem API when a readable stream is read more than once)
3505
3539
  */
3506
3540
  export const ERR_READABLE_CONSUMED: string;
3541
+ /**
3542
+ * Aborted operation error (thrown by {@link ZipDirectoryEntry#exportFileSystemHandle} when it is aborted via
3543
+ * {@link ZipReaderOptions#signal} on platforms which do not support the `reason` argument of
3544
+ * `AbortController#abort()`)
3545
+ *
3546
+ * @remarks The reason passed by the caller is discarded by these platforms and cannot be recovered, so a
3547
+ * `DOMException` named `AbortError` carrying this message is thrown in its place.
3548
+ */
3549
+ export const ERR_ABORTED: string;
3507
3550
  /**
3508
3551
  * Unsupported context error (thrown when {@link createSyncAccessHandleTempStream} is used outside a dedicated worker)
3509
3552
  */
package/index.d.ts CHANGED
@@ -2815,6 +2815,23 @@ export class ZipDirectoryEntry extends ZipEntry {
2815
2815
  * @returns A {@link ZipFileEntry} or a {@link ZipDirectoryEntry} instance (use the {@link ZipFileEntry#directory} and {@link ZipDirectoryEntry#directory} properties to differentiate entries).
2816
2816
  */
2817
2817
  getChildByName(name: string): ZipEntry | undefined;
2818
+ /**
2819
+ * Gets the children of the directory
2820
+ *
2821
+ * @remarks The returned array is a snapshot taken when the method is called: entries added or removed
2822
+ * afterwards are not reflected, and an entry removed while the array is being iterated is still present
2823
+ * but detached from the filesystem.
2824
+ *
2825
+ * With `recursive`, the descendants are ordered level by level, i.e. the children of a directory come
2826
+ * before the children of its subdirectories, like the result of `readdir(path, { recursive: true })` in
2827
+ * Node.js. This is also the order in which `{@link ZipDirectoryEntry}#export*()` writes them.
2828
+ *
2829
+ * Unlike {@link FS#entries}, the directory itself is not included and removed entries leave no empty slot.
2830
+ *
2831
+ * @param options The options.
2832
+ * @returns The array of {@link ZipEntry} instances.
2833
+ */
2834
+ getChildren(options?: ZipDirectoryEntryGetChildrenOptions): ZipEntry[];
2818
2835
  /**
2819
2836
  * Adds a directory
2820
2837
  *
@@ -3064,6 +3081,10 @@ export class ZipDirectoryEntry extends ZipEntry {
3064
3081
  * Running the same export again is the supported way to recover, since directories are merged and
3065
3082
  * files are overwritten.
3066
3083
  *
3084
+ * @remarks An entry flagged as a symbolic link by its {@link EntryMetaData#externalFileAttributes} is written
3085
+ * as a regular file whose content is the path of the link target, because the File System Access API cannot
3086
+ * create symbolic links.
3087
+ *
3067
3088
  * @param directoryHandle The target `FileSystemDirectoryHandle` instance.
3068
3089
  * @param options The options.
3069
3090
  * @returns A promise resolving to the target `FileSystemDirectoryHandle` instance.
@@ -3096,6 +3117,18 @@ export interface ZipDirectoryEntryImportHttpOptions
3096
3117
  extends ZipReaderConstructorOptions,
3097
3118
  HttpOptions {}
3098
3119
 
3120
+ /**
3121
+ * Represents the options passed to {@link ZipDirectoryEntry#getChildren} and {@link FS#getChildren}.
3122
+ */
3123
+ export interface ZipDirectoryEntryGetChildrenOptions {
3124
+ /**
3125
+ * `true` to return all the descendants of the directory instead of its direct children only.
3126
+ *
3127
+ * @defaultValue false
3128
+ */
3129
+ recursive?: boolean;
3130
+ }
3131
+
3099
3132
  /**
3100
3133
  * Represents the options passed to `{@link ZipDirectoryEntry}#export*()`.
3101
3134
  */
@@ -3156,6 +3189,7 @@ export interface FS
3156
3189
  extends Pick<
3157
3190
  ZipDirectoryEntry,
3158
3191
  | "getChildByName"
3192
+ | "getChildren"
3159
3193
  | "addDirectory"
3160
3194
  | "addText"
3161
3195
  | "addBlob"
@@ -3504,6 +3538,15 @@ export const ERR_ENTRY_EXISTS: string;
3504
3538
  * Readable stream already consumed error (thrown by the filesystem API when a readable stream is read more than once)
3505
3539
  */
3506
3540
  export const ERR_READABLE_CONSUMED: string;
3541
+ /**
3542
+ * Aborted operation error (thrown by {@link ZipDirectoryEntry#exportFileSystemHandle} when it is aborted via
3543
+ * {@link ZipReaderOptions#signal} on platforms which do not support the `reason` argument of
3544
+ * `AbortController#abort()`)
3545
+ *
3546
+ * @remarks The reason passed by the caller is discarded by these platforms and cannot be recovered, so a
3547
+ * `DOMException` named `AbortError` carrying this message is thrown in its place.
3548
+ */
3549
+ export const ERR_ABORTED: string;
3507
3550
  /**
3508
3551
  * Unsupported context error (thrown when {@link createSyncAccessHandleTempStream} is used outside a dedicated worker)
3509
3552
  */