Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
index.js363 linesDownload Raw Back to esm
1import assert from 'assert';
2import { Buffer } from 'buffer';
3import { Minipass } from 'minipass';
4import * as realZlib from 'zlib';
5import { constants } from './constants.js';
6export { constants } from './constants.js';
7const OriginalBufferConcat = Buffer.concat;
8const desc = Object.getOwnPropertyDescriptor(Buffer, 'concat');
9const noop = (args) => args;
10const passthroughBufferConcat = desc?.writable === true || desc?.set !== undefined
11    ? (makeNoOp) => {
12        Buffer.concat = makeNoOp ? noop : OriginalBufferConcat;
13    }
14    : (_) => { };
15const _superWrite = Symbol('_superWrite');
16export class ZlibError extends Error {
17    code;
18    errno;
19    constructor(err, origin) {
20        super('zlib: ' + err.message, { cause: err });
21        this.code = err.code;
22        this.errno = err.errno;
23        /* c8 ignore next */
24        if (!this.code)
25            this.code = 'ZLIB_ERROR';
26        this.message = 'zlib: ' + err.message;
27        Error.captureStackTrace(this, origin ?? this.constructor);
28    }
29    get name() {
30        return 'ZlibError';
31    }
32}
33// the Zlib class they all inherit from
34// This thing manages the queue of requests, and returns
35// true or false if there is anything in the queue when
36// you call the .write() method.
37const _flushFlag = Symbol('flushFlag');
38class ZlibBase extends Minipass {
39    #sawError = false;
40    #ended = false;
41    #flushFlag;
42    #finishFlushFlag;
43    #fullFlushFlag;
44    #handle;
45    #onError;
46    get sawError() {
47        return this.#sawError;
48    }
49    get handle() {
50        return this.#handle;
51    }
52    /* c8 ignore start */
53    get flushFlag() {
54        return this.#flushFlag;
55    }
56    /* c8 ignore stop */
57    constructor(opts, mode) {
58        if (!opts || typeof opts !== 'object')
59            throw new TypeError('invalid options for ZlibBase constructor');
60        //@ts-ignore
61        super(opts);
62        /* c8 ignore start */
63        this.#flushFlag = opts.flush ?? 0;
64        this.#finishFlushFlag = opts.finishFlush ?? 0;
65        this.#fullFlushFlag = opts.fullFlushFlag ?? 0;
66        /* c8 ignore stop */
67        //@ts-ignore
68        if (typeof realZlib[mode] !== 'function') {
69            throw new TypeError('Compression method not supported: ' + mode);
70        }
71        // this will throw if any options are invalid for the class selected
72        try {
73            // @types/node doesn't know that it exports the classes, but they're there
74            //@ts-ignore
75            this.#handle = new realZlib[mode](opts);
76        }
77        catch (er) {
78            // make sure that all errors get decorated properly
79            throw new ZlibError(er, this.constructor);
80        }
81        this.#onError = err => {
82            // no sense raising multiple errors, since we abort on the first one.
83            if (this.#sawError)
84                return;
85            this.#sawError = true;
86            // there is no way to cleanly recover.
87            // continuing only obscures problems.
88            this.close();
89            this.emit('error', err);
90        };
91        this.#handle?.on('error', er => this.#onError(new ZlibError(er)));
92        this.once('end', () => this.close);
93    }
94    close() {
95        if (this.#handle) {
96            this.#handle.close();
97            this.#handle = undefined;
98            this.emit('close');
99        }
100    }
101    reset() {
102        if (!this.#sawError) {
103            assert(this.#handle, 'zlib binding closed');
104            //@ts-ignore
105            return this.#handle.reset?.();
106        }
107    }
108    flush(flushFlag) {
109        if (this.ended)
110            return;
111        if (typeof flushFlag !== 'number')
112            flushFlag = this.#fullFlushFlag;
113        this.write(Object.assign(Buffer.alloc(0), { [_flushFlag]: flushFlag }));
114    }
115    end(chunk, encoding, cb) {
116        /* c8 ignore start */
117        if (typeof chunk === 'function') {
118            cb = chunk;
119            encoding = undefined;
120            chunk = undefined;
121        }
122        if (typeof encoding === 'function') {
123            cb = encoding;
124            encoding = undefined;
125        }
126        /* c8 ignore stop */
127        if (chunk) {
128            if (encoding)
129                this.write(chunk, encoding);
130            else
131                this.write(chunk);
132        }
133        this.flush(this.#finishFlushFlag);
134        this.#ended = true;
135        return super.end(cb);
136    }
137    get ended() {
138        return this.#ended;
139    }
140    // overridden in the gzip classes to do portable writes
141    [_superWrite](data) {
142        return super.write(data);
143    }
144    write(chunk, encoding, cb) {
145        // process the chunk using the sync process
146        // then super.write() all the outputted chunks
147        if (typeof encoding === 'function')
148            (cb = encoding), (encoding = 'utf8');
149        if (typeof chunk === 'string')
150            chunk = Buffer.from(chunk, encoding);
151        if (this.#sawError)
152            return;
153        assert(this.#handle, 'zlib binding closed');
154        // _processChunk tries to .close() the native handle after it's done, so we
155        // intercept that by temporarily making it a no-op.
156        // diving into the node:zlib internals a bit here
157        const nativeHandle = this.#handle
158            ._handle;
159        const originalNativeClose = nativeHandle.close;
160        nativeHandle.close = () => { };
161        const originalClose = this.#handle.close;
162        this.#handle.close = () => { };
163        // It also calls `Buffer.concat()` at the end, which may be convenient
164        // for some, but which we are not interested in as it slows us down.
165        passthroughBufferConcat(true);
166        let result = undefined;
167        try {
168            const flushFlag = typeof chunk[_flushFlag] === 'number'
169                ? chunk[_flushFlag]
170                : this.#flushFlag;
171            result = this.#handle._processChunk(chunk, flushFlag);
172            // if we don't throw, reset it back how it was
173            passthroughBufferConcat(false);
174        }
175        catch (err) {
176            // or if we do, put Buffer.concat() back before we emit error
177            // Error events call into user code, which may call Buffer.concat()
178            passthroughBufferConcat(false);
179            this.#onError(new ZlibError(err, this.write));
180        }
181        finally {
182            if (this.#handle) {
183                // Core zlib resets `_handle` to null after attempting to close the
184                // native handle. Our no-op handler prevented actual closure, but we
185                // need to restore the `._handle` property.
186                ;
187                this.#handle._handle =
188                    nativeHandle;
189                nativeHandle.close = originalNativeClose;
190                this.#handle.close = originalClose;
191                // `_processChunk()` adds an 'error' listener. If we don't remove it
192                // after each call, these handlers start piling up.
193                this.#handle.removeAllListeners('error');
194                // make sure OUR error listener is still attached tho
195            }
196        }
197        if (this.#handle)
198            this.#handle.on('error', er => this.#onError(new ZlibError(er, this.write)));
199        let writeReturn;
200        if (result) {
201            if (Array.isArray(result) && result.length > 0) {
202                const r = result[0];
203                // The first buffer is always `handle._outBuffer`, which would be
204                // re-used for later invocations; so, we always have to copy that one.
205                writeReturn = this[_superWrite](Buffer.from(r));
206                for (let i = 1; i < result.length; i++) {
207                    writeReturn = this[_superWrite](result[i]);
208                }
209            }
210            else {
211                // either a single Buffer or an empty array
212                writeReturn = this[_superWrite](Buffer.from(result));
213            }
214        }
215        if (cb)
216            cb();
217        return writeReturn;
218    }
219}
220export class Zlib extends ZlibBase {
221    #level;
222    #strategy;
223    constructor(opts, mode) {
224        opts = opts || {};
225        opts.flush = opts.flush || constants.Z_NO_FLUSH;
226        opts.finishFlush = opts.finishFlush || constants.Z_FINISH;
227        opts.fullFlushFlag = constants.Z_FULL_FLUSH;
228        super(opts, mode);
229        this.#level = opts.level;
230        this.#strategy = opts.strategy;
231    }
232    params(level, strategy) {
233        if (this.sawError)
234            return;
235        if (!this.handle)
236            throw new Error('cannot switch params when binding is closed');
237        // no way to test this without also not supporting params at all
238        /* c8 ignore start */
239        if (!this.handle.params)
240            throw new Error('not supported in this implementation');
241        /* c8 ignore stop */
242        if (this.#level !== level || this.#strategy !== strategy) {
243            this.flush(constants.Z_SYNC_FLUSH);
244            assert(this.handle, 'zlib binding closed');
245            // .params() calls .flush(), but the latter is always async in the
246            // core zlib. We override .flush() temporarily to intercept that and
247            // flush synchronously.
248            const origFlush = this.handle.flush;
249            this.handle.flush = (flushFlag, cb) => {
250                /* c8 ignore start */
251                if (typeof flushFlag === 'function') {
252                    cb = flushFlag;
253                    flushFlag = this.flushFlag;
254                }
255                /* c8 ignore stop */
256                this.flush(flushFlag);
257                cb?.();
258            };
259            try {
260                ;
261                this.handle.params(level, strategy);
262            }
263            finally {
264                this.handle.flush = origFlush;
265            }
266            /* c8 ignore start */
267            if (this.handle) {
268                this.#level = level;
269                this.#strategy = strategy;
270            }
271            /* c8 ignore stop */
272        }
273    }
274}
275// minimal 2-byte header
276export class Deflate extends Zlib {
277    constructor(opts) {
278        super(opts, 'Deflate');
279    }
280}
281export class Inflate extends Zlib {
282    constructor(opts) {
283        super(opts, 'Inflate');
284    }
285}
286export class Gzip extends Zlib {
287    #portable;
288    constructor(opts) {
289        super(opts, 'Gzip');
290        this.#portable = opts && !!opts.portable;
291    }
292    [_superWrite](data) {
293        if (!this.#portable)
294            return super[_superWrite](data);
295        // we'll always get the header emitted in one first chunk
296        // overwrite the OS indicator byte with 0xFF
297        this.#portable = false;
298        data[9] = 255;
299        return super[_superWrite](data);
300    }
301}
302export class Gunzip extends Zlib {
303    constructor(opts) {
304        super(opts, 'Gunzip');
305    }
306}
307// raw - no header
308export class DeflateRaw extends Zlib {
309    constructor(opts) {
310        super(opts, 'DeflateRaw');
311    }
312}
313export class InflateRaw extends Zlib {
314    constructor(opts) {
315        super(opts, 'InflateRaw');
316    }
317}
318// auto-detect header.
319export class Unzip extends Zlib {
320    constructor(opts) {
321        super(opts, 'Unzip');
322    }
323}
324class Brotli extends ZlibBase {
325    constructor(opts, mode) {
326        opts = opts || {};
327        opts.flush = opts.flush || constants.BROTLI_OPERATION_PROCESS;
328        opts.finishFlush =
329            opts.finishFlush || constants.BROTLI_OPERATION_FINISH;
330        opts.fullFlushFlag = constants.BROTLI_OPERATION_FLUSH;
331        super(opts, mode);
332    }
333}
334export class BrotliCompress extends Brotli {
335    constructor(opts) {
336        super(opts, 'BrotliCompress');
337    }
338}
339export class BrotliDecompress extends Brotli {
340    constructor(opts) {
341        super(opts, 'BrotliDecompress');
342    }
343}
344class Zstd extends ZlibBase {
345    constructor(opts, mode) {
346        opts = opts || {};
347        opts.flush = opts.flush || constants.ZSTD_e_continue;
348        opts.finishFlush = opts.finishFlush || constants.ZSTD_e_end;
349        opts.fullFlushFlag = constants.ZSTD_e_flush;
350        super(opts, mode);
351    }
352}
353export class ZstdCompress extends Zstd {
354    constructor(opts) {
355        super(opts, 'ZstdCompress');
356    }
357}
358export class ZstdDecompress extends Zstd {
359    constructor(opts) {
360        super(opts, 'ZstdDecompress');
361    }
362}
363//# sourceMappingURL=index.js.map
codekingpro/portable-devtools · Team Ai