diff --git a/CHANGELOG.md b/CHANGELOG.md index 85ae0acb..bbe69803 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 7.1 + +- Update minipass to v7.1.0 +- Update the type definitions of `write()` and `end()` methods on + `Unpack` and `Parser` classes to be compatible with the + NodeJS.WritableStream type in the latest versions of + `@types/node`. + ## 7.0 - Rewrite in TypeScript, provide ESM and CommonJS hybrid diff --git a/package.json b/package.json index 6705d89a..d5d7ecf0 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", - "minipass": "^7.0.4", + "minipass": "^7.1.0", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" @@ -49,7 +49,8 @@ ], "tap": { "coverage-map": "map.js", - "timeout": 0 + "timeout": 0, + "typecheck": true }, "prettier": { "experimentalTernaries": true, diff --git a/src/parse.ts b/src/parse.ts index f260568d..a4afeee0 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -402,9 +402,35 @@ export class Parser extends EE implements Warner { this.warn('TAR_ABORT', error, { recoverable: false }) } - write(chunk: Buffer) { + write( + buffer: Uint8Array | string, + cb?: (err?: Error | null) => void, + ): boolean + write( + str: string, + encoding?: BufferEncoding, + cb?: (err?: Error | null) => void, + ): boolean + write( + chunk: Buffer | string, + encoding?: BufferEncoding | (() => any), + cb?: () => any, + ): boolean { + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from( + chunk, + /* c8 ignore next */ + typeof encoding === 'string' ? encoding : 'utf8', + ) + } if (this[ABORTED]) { - return + /* c8 ignore next */ + cb?.() + return false } // first write, might be gzipped @@ -418,6 +444,8 @@ export class Parser extends EE implements Warner { } if (chunk.length < gzipHeader.length) { this[BUFFER] = chunk + /* c8 ignore next */ + cb?.() return true } @@ -443,6 +471,8 @@ export class Parser extends EE implements Warner { this.brotli = true } else { this[BUFFER] = chunk + /* c8 ignore next */ + cb?.() return true } } else { @@ -474,8 +504,9 @@ export class Parser extends EE implements Warner { this[CONSUMECHUNK]() }) this[WRITING] = true - const ret = this[UNZIP][ended ? 'end' : 'write'](chunk) + const ret = !!this[UNZIP][ended ? 'end' : 'write'](chunk) this[WRITING] = false + cb?.() return ret } } @@ -499,6 +530,8 @@ export class Parser extends EE implements Warner { this[READENTRY]?.once('drain', () => this.emit('drain')) } + /* c8 ignore next */ + cb?.() return ret } @@ -614,7 +647,27 @@ export class Parser extends EE implements Warner { } } - end(chunk?: Buffer) { + end(cb?: () => void): this + end(data: string | Buffer, cb?: () => void): this + end(str: string, encoding?: BufferEncoding, cb?: () => void): this + end( + chunk?: string | Buffer | (() => void), + encoding?: BufferEncoding | (() => void), + cb?: () => void, + ) { + if (typeof chunk === 'function') { + cb = chunk + encoding = undefined + chunk = undefined + } + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from(chunk, encoding) + } + if (cb) this.once('finish', cb) if (!this[ABORTED]) { if (this[UNZIP]) { /* c8 ignore start */ @@ -629,5 +682,6 @@ export class Parser extends EE implements Warner { this[MAYBEEND]() } } + return this } } diff --git a/src/write-entry.ts b/src/write-entry.ts index 714faeb0..cfb797a4 100644 --- a/src/write-entry.ts +++ b/src/write-entry.ts @@ -54,8 +54,8 @@ const PREFIX = Symbol('prefix') export class WriteEntry extends Minipass< - Minipass.ContiguousData, Buffer, + Minipass.ContiguousData, WarnEvent > implements Warner @@ -454,12 +454,12 @@ export class WriteEntry } } - const writeBuf = + const chunk = this.offset === 0 && bytesRead === this.buf.length ? this.buf : this.buf.subarray(this.offset, this.offset + bytesRead) - const flushed = this.write(writeBuf) + const flushed = this.write(chunk) if (!flushed) { this[AWAITDRAIN](() => this[ONDRAIN]()) } else { @@ -471,8 +471,34 @@ export class WriteEntry this.once('drain', cb) } - write(writeBuf: Buffer) { - if (this.blockRemain < writeBuf.length) { + write( + buffer: Buffer | string, + cb?: () => void, + ): boolean + write( + str: Buffer | string, + encoding?: BufferEncoding | null, + cb?: () => void, + ): boolean + write( + chunk: Buffer | string, + encoding?: BufferEncoding | (() => any) | null, + cb?: () => any, + ): boolean { + /* c8 ignore start - just junk to comply with NodeJS.WritableStream */ + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from( + chunk, + typeof encoding === 'string' ? encoding : 'utf8', + ) + } + /* c8 ignore stop */ + + if (this.blockRemain < chunk.length) { const er = Object.assign( new Error('writing more data than expected'), { @@ -481,11 +507,11 @@ export class WriteEntry ) return this.emit('error', er) } - this.remain -= writeBuf.length - this.blockRemain -= writeBuf.length - this.pos += writeBuf.length - this.offset += writeBuf.length - return super.write(writeBuf) + this.remain -= chunk.length + this.blockRemain -= chunk.length + this.pos += chunk.length + this.offset += chunk.length + return super.write(chunk, null, cb) } [ONDRAIN]() { @@ -568,7 +594,7 @@ export class WriteEntrySync extends WriteEntry implements Warner { } export class WriteEntryTar - extends Minipass + extends Minipass implements Warner { blockLen: number = 0 @@ -731,20 +757,68 @@ export class WriteEntryTar return modeFix(mode, this.type === 'Directory', this.portable) } - write(data: Buffer) { - const writeLen = data.length + write( + buffer: Buffer | string, + cb?: () => void, + ): boolean + write( + str: Buffer | string, + encoding?: BufferEncoding | null, + cb?: () => void, + ): boolean + write( + chunk: Buffer | string, + encoding?: BufferEncoding | (() => any) | null, + cb?: () => any, + ): boolean { + /* c8 ignore start - just junk to comply with NodeJS.WritableStream */ + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from( + chunk, + typeof encoding === 'string' ? encoding : 'utf8', + ) + } + /* c8 ignore stop */ + const writeLen = chunk.length if (writeLen > this.blockRemain) { throw new Error('writing more to entry than is appropriate') } this.blockRemain -= writeLen - return super.write(data) + return super.write(chunk, cb) } - end() { + end(cb?: () => void): this + end(chunk: Buffer | string, cb?: () => void): this + end(chunk: Buffer | string, encoding?: BufferEncoding, cb?: () => void): this + end( + chunk?: Buffer | string | (() => void), + encoding?: BufferEncoding | (() => void), + cb?: () => void + ): this { if (this.blockRemain) { super.write(Buffer.alloc(this.blockRemain)) } - return super.end() + /* c8 ignore start - just junk to comply with NodeJS.WritableStream */ + if (typeof chunk === 'function') { + cb = chunk + encoding = undefined + chunk = undefined + } + if (typeof encoding === 'function') { + cb = encoding + encoding = undefined + } + if (typeof chunk === 'string') { + chunk = Buffer.from(chunk, encoding ?? 'utf8') + } + if (cb) this.once('finish', cb) + chunk ? super.end(chunk, cb) : super.end(cb) + /* c8 ignore stop */ + return this } } diff --git a/test/parse.js b/test/parse.js index db60ce0c..978caacd 100644 --- a/test/parse.js +++ b/test/parse.js @@ -126,6 +126,7 @@ t.test('fixture tests', t => { }) t.test('uncompressed all at once', t => { + // this one writes it as a string const p = new Parser({ maxMetaEntrySize: maxMeta, filter: @@ -135,7 +136,7 @@ t.test('fixture tests', t => { strict: strict, }) trackEvents(t, expect, p) - p.end(tardata) + p.end(tardata.toString('hex'), 'hex', () => {}) }) t.test( @@ -185,7 +186,7 @@ t.test('fixture tests', t => { strict: strict, }) trackEvents(t, expect, p) - p.end(zlib.gzipSync(tardata)) + p.end(zlib.gzipSync(tardata), () => {}) }) t.test('gzipped all at once, filename .tbr', t => { @@ -199,7 +200,8 @@ t.test('fixture tests', t => { file: 'example.tbr', }) trackEvents(t, expect, p) - p.end(zlib.gzipSync(tardata)) + p.write(zlib.gzipSync(tardata), () => {}) + p.end(() => {}) }) t.test('gzipped byte at a time', t => { @@ -304,7 +306,8 @@ t.test('fixture tests', t => { strict: strict, }) trackEvents(t, expect, p, true) - p.write(tardata.subarray(0, Math.floor(tardata.length / 2))) + const first = tardata.subarray(0, Math.floor(tardata.length / 2)) + p.write(first.toString('hex'), 'hex') process.nextTick(() => p.end(tardata.subarray(Math.floor(tardata.length / 2))), ) diff --git a/test/writable-assignment-check.ts b/test/writable-assignment-check.ts new file mode 100644 index 00000000..46e81595 --- /dev/null +++ b/test/writable-assignment-check.ts @@ -0,0 +1,14 @@ +import { Unpack } from "../src/unpack.js"; +import { WriteEntry } from "../src/write-entry.js"; +import { Parser } from '../src/parse.js' +import { fileURLToPath } from 'url' + +let tester: NodeJS.WritableStream +tester = new Parser() +tester = new Unpack() +tester = new WriteEntry(fileURLToPath(import.meta.url)) + +tester + +import { pass } from 'tap' +pass(`just making sure TS doesn't complain`)