diff --git a/index.d.ts b/index.d.ts index bfe65f50..c2722e92 100644 --- a/index.d.ts +++ b/index.d.ts @@ -242,7 +242,7 @@ declare class SyncCodec { } /** - * Represents an intance used to compress data. + * Represents an instance used to compress data. */ declare class ZipDeflate extends SyncCodec { /** @@ -599,7 +599,7 @@ export class SplitDataWriter implements Initializable, WritableWriter { /** * Creates the {@link SplitDataWriter} instance * - * @param writerGenerator A generator of Writer isntances. + * @param writerGenerator A generator of Writer instances. * @param maxSize The maximum size of the data written into {@link Writer} instances (default: 4GB). */ constructor( @@ -616,6 +616,40 @@ export class SplitDataWriter implements Initializable, WritableWriter { */ export class Uint8ArrayWriter extends Writer {} +/** + * Represents an instance used to create an unzipped stream. + * + * @example + * This example will take a zip file, decompress it and then recompress each file in it, saving it to disk. + * ``` + * for await (const entry of (await fetch(urlToZippedFile)).body.pipeThrough(new ZipWriterStream())) + * if (entry.readable) { + * console.log(entry.filename) + * entry.readable + * .pipeThrough(ZipReaderStream().transform(entry.filename)) + * .pipeTo((await Deno.create(entry.filename + '.zip')).writable) + * } + * ``` + */ +export class ZipReaderStream { + /** + * Creates the stream. + * + * @param options The options. + */ + constructor (options?: ZipReaderConstructorOptions); + + /** + * The readable stream. + */ + readable: ReadableStream & { readable?: ReadableStream; }>; + + /** + * The writable stream. + */ + writable: WritableStream; +} + /** * Represents an instance used to read a zip file. * @@ -688,7 +722,7 @@ export class ZipReader { * Returns a generator used to iterate on all the entries in the zip file * * @param options The options. - * @returns An asynchrounous generator of {@link Entry} instances. + * @returns An asynchronous generator of {@link Entry} instances. */ getEntriesGenerator( options?: ZipReaderGetEntriesOptions, @@ -947,6 +981,86 @@ interface EntryGetDataOptions interface EntryGetDataCheckPasswordOptions extends EntryGetDataOptions, ZipReaderCheckPasswordOptions {} +/** + * Represents an instance used to create a zipped stream. + * + * @example + * This example creates a zipped file called numbers.txt.zip containing the numbers 0 - 1000 each on their own line. + * ``` + * const readable = ReadableStream.from((function* () { + * for (let i = 0; i < 1000; ++i) + * yield i + '\n' + * })()) + * + * readable + * .pipeThrough(new ZipWriterStream().transform('numbers.txt')) + * .pipeTo((await Deno.create('numbers.txt.zip')).writable) + * ``` + * + * @example + * This example creates a zipped file called Archive.zip containing two files called numbers.txt and letters.txt + * ``` + * const readable1 = ReadableStream.from((function* () { + * for (let i = 0; i < 1000; ++i) + * yield i + '\n' + * })()) + * const readable2 = ReadableStream.from((function* () { + * const letters = 'abcdefghijklmnopqrstuvwxyz'.split('') + * while (letters.length) + * yield letters.shift() + '\n' + * })()) + * + * const zipper = new ZipWriterStream() + * zipper.readable.pipeTo((await Deno.create('Archive.zip')).writable) + * readable1.pipeTo(zipper.writable('numbers.txt')) + * readable2.pipeTo(zipper.writable('letters.txt')) + * zipper.close() + * ``` + */ +export class ZipWriterStream { + /** + * Creates the stream. + * + * @param options The options. + */ + constructor (options?: ZipWriterConstructorOptions); + + /** + * The readable stream. + */ + readable: ReadableStream; + + /** + * The ZipWriter property. + */ + zipWriter: ZipWriter + + /** + * Returns an object containing a readable and writable property for the .pipeThrough method + * + * @param path The name of the stream when unzipped. + * @returns An object containing readable and writable properties + */ + transform(path: string): { readable: ReadableStream, writable: WritableStream; }; + + /** + * Returns a WritableStream for the .pipeTo method + * + * @param path The directory path of where the stream should exist in the zipped stream. + * @returns A WritableStream. + */ + writable(path: string): WritableStream; + + /** + * Writes the entries directory, writes the global comment, and returns the content of the zipped file. + * + * @param comment The global comment of the zip file. + * @param options The options. + * @returns The content of the zip file. + */ + close(comment?: Uint8Array, options?: ZipWriterCloseOptions): Promise; +} + /** * Represents an instance used to create a zip file. * @@ -1324,7 +1438,7 @@ declare class ZipEntry { /** * Set the name of the entry * - * @param name The new name of the netry. + * @param name The new name of the entry. */ rename(name: string): void; } @@ -1487,7 +1601,7 @@ export class ZipDirectoryEntry extends ZipEntry { options?: ZipWriterAddDataOptions, ): ZipFileEntry; /** - * Adds aentry entry with content provided as a `Blob` instance + * Adds a entry entry with content provided as a `Blob` instance * * @param name The relative filename of the entry. * @param blob The `Blob` instance. @@ -1500,7 +1614,7 @@ export class ZipDirectoryEntry extends ZipEntry { options?: ZipWriterAddDataOptions, ): ZipFileEntry; /** - * Adds aentry entry with content provided as a Data URI `string` encoded in Base64 + * Adds a entry entry with content provided as a Data URI `string` encoded in Base64 * * @param name The relative filename of the entry. * @param dataURI The Data URI `string` encoded in Base64. @@ -1539,7 +1653,7 @@ export class ZipDirectoryEntry extends ZipEntry { options?: HttpOptions & ZipWriterAddDataOptions, ): ZipFileEntry; /** - * Adds aentry entry with content provided via a `ReadableStream` instance + * Adds a entry entry with content provided via a `ReadableStream` instance * * @param name The relative filename of the entry. * @param readable The `ReadableStream` instance. diff --git a/index.js b/index.js index 43820c6c..8784bd90 100644 --- a/index.js +++ b/index.js @@ -9,8 +9,8 @@ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products @@ -42,6 +42,8 @@ export { initShimAsyncCodec, ZipReader, ZipWriter, + ZipReaderStream, + ZipWriterStream, Reader, Writer, TextReader, @@ -83,4 +85,4 @@ export { ERR_SPLIT_ZIP_FILE, ERR_ITERATOR_COMPLETED_TOO_SOON } from "./lib/zip-fs.js"; -export { getMimeType, terminateWorkers }; \ No newline at end of file +export { getMimeType, terminateWorkers }; diff --git a/lib/core/zip-reader.js b/lib/core/zip-reader.js index 8d76bcbb..2c3f534e 100644 --- a/lib/core/zip-reader.js +++ b/lib/core/zip-reader.js @@ -7,8 +7,8 @@ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products @@ -209,7 +209,7 @@ class ZipReader { } if (directoryDataOffset >= reader.size) { prependedDataLength = reader.size - directoryDataOffset - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH; - directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH; + directoryDataOffset = reader.size - directoryDataLength - END_OF_CENTRAL_DIR_LENGTH; } if (expectedLastDiskNumber != lastDiskNumber) { throw new Error(ERR_SPLIT_ZIP_FILE); @@ -326,8 +326,38 @@ class ZipReader { } } +class ZipReaderStream { + readable; + writable; + constructor (options = {}) { + const { readable, writable } = new TransformStream(); + const gen = new ZipReader(readable, options).getEntriesGenerator(); + this.readable = new ReadableStream({ + async pull(controller) { + const { done, value } = await gen.next(); + if (done) + return controller.close(); + const chunk = { + ...value, + readable: (function () { + const { readable, writable } = new TransformStream(); + if (value.getData) { + value.getData(writable); + return readable; + } + })() + }; + delete chunk.getData; + controller.enqueue(chunk); + } + }); + this.writable = writable; + } +} + export { ZipReader, + ZipReaderStream, ERR_BAD_FORMAT, ERR_EOCDR_NOT_FOUND, ERR_EOCDR_ZIP64_NOT_FOUND, @@ -721,4 +751,4 @@ function setUint32(view, offset, value) { function getDataView(array) { return new DataView(array.buffer); -} \ No newline at end of file +} diff --git a/lib/core/zip-writer.js b/lib/core/zip-writer.js index 78778f8a..573bd2ee 100644 --- a/lib/core/zip-writer.js +++ b/lib/core/zip-writer.js @@ -7,8 +7,8 @@ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products @@ -176,8 +176,37 @@ class ZipWriter { } } +class ZipWriterStream { + readable; + zipWriter; + constructor (options = {}) { + const { readable, writable } = new TransformStream(); + this.readable = readable; + this.zipWriter = new ZipWriter(writable, options); + } + + transform(path) { + const { readable, writable } = new TransformStream({ + flush: () => { this.zipWriter.close(); } + }); + this.zipWriter.add(path, readable); + return { readable: this.readable, writable }; + } + + writable(path) { + const { readable, writable } = new TransformStream(); + this.zipWriter.add(path, readable); + return writable; + } + + close(comment = undefined, options = {}) { + return this.zipWriter.close(comment, options); + } +} + export { ZipWriter, + ZipWriterStream, ERR_DUPLICATED_NAME, ERR_INVALID_COMMENT, ERR_INVALID_ENTRY_NAME, @@ -1148,4 +1177,4 @@ function getLength(...arrayLikes) { let result = 0; arrayLikes.forEach(arrayLike => arrayLike && (result += arrayLike.length)); return result; -} \ No newline at end of file +} diff --git a/lib/zip-fs.js b/lib/zip-fs.js index d66a95ae..204b4049 100644 --- a/lib/zip-fs.js +++ b/lib/zip-fs.js @@ -7,8 +7,8 @@ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The names of the authors may not be used to endorse or promote products @@ -50,4 +50,4 @@ export { getMimeType, initShimAsyncCodec, terminateWorkers -}; \ No newline at end of file +};