Skip to content

Commit

Permalink
update types to comply with NodeJS.WritableStream
Browse files Browse the repository at this point in the history
Fix: #409
  • Loading branch information
isaacs committed May 4, 2024
1 parent 79a5c30 commit 6b61030
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 26 deletions.
8 changes: 8 additions & 0 deletions 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
Expand Down
5 changes: 3 additions & 2 deletions package.json
Expand Up @@ -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"
Expand All @@ -49,7 +49,8 @@
],
"tap": {
"coverage-map": "map.js",
"timeout": 0
"timeout": 0,
"typecheck": true
},
"prettier": {
"experimentalTernaries": true,
Expand Down
62 changes: 58 additions & 4 deletions src/parse.ts
Expand Up @@ -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
Expand All @@ -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
}

Expand All @@ -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 {
Expand Down Expand Up @@ -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
}
}
Expand All @@ -499,6 +530,8 @@ export class Parser extends EE implements Warner {
this[READENTRY]?.once('drain', () => this.emit('drain'))
}

/* c8 ignore next */
cb?.()
return ret
}

Expand Down Expand Up @@ -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 */
Expand All @@ -629,5 +682,6 @@ export class Parser extends EE implements Warner {
this[MAYBEEND]()
}
}
return this
}
}
106 changes: 90 additions & 16 deletions src/write-entry.ts
Expand Up @@ -54,8 +54,8 @@ const PREFIX = Symbol('prefix')

export class WriteEntry
extends Minipass<
Minipass.ContiguousData,
Buffer,
Minipass.ContiguousData,
WarnEvent
>
implements Warner
Expand Down Expand Up @@ -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 {
Expand All @@ -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'),
{
Expand All @@ -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]() {
Expand Down Expand Up @@ -568,7 +594,7 @@ export class WriteEntrySync extends WriteEntry implements Warner {
}

export class WriteEntryTar
extends Minipass<Buffer, Buffer, WarnEvent>
extends Minipass<Buffer, Buffer | string, WarnEvent>
implements Warner
{
blockLen: number = 0
Expand Down Expand Up @@ -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
}
}

Expand Down
11 changes: 7 additions & 4 deletions test/parse.js
Expand Up @@ -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:
Expand All @@ -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(
Expand Down Expand Up @@ -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 => {
Expand All @@ -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 => {
Expand Down Expand Up @@ -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))),
)
Expand Down
14 changes: 14 additions & 0 deletions 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`)

0 comments on commit 6b61030

Please sign in to comment.