"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = require("events"); const fsScandir = require("@nodelib/fs.scandir"); const fastq = require("fastq"); const common = require("./common"); const reader_1 = require("./reader"); class AsyncReader extends reader_1.default { constructor(_root, _settings) { super(_root, _settings); this._settings = _settings; this._scandir = fsScandir.scandir; this._emitter = new events_1.EventEmitter(); this._queue = fastq(this._worker.bind(this), this._settings.concurrency); this._isFatalError = false; this._isDestroyed = false; this._queue.drain = () => { if (!this._isFatalError) { this._emitter.emit('end'); } }; } read() { this._isFatalError = false; this._isDestroyed = false; setImmediate(() => { this._pushToQueue(this._root, this._settings.basePath); }); return this._emitter; } get isDestroyed() { return this._isDestroyed; } destroy() { if (this._isDestroyed) { throw new Error('The reader is already destroyed'); } this._isDestroyed = true; this._queue.killAndDrain(); } onEntry(callback) { this._emitter.on('entry', callback); } onError(callback) { this._emitter.once('error', callback); } onEnd(callback) { this._emitter.once('end', callback); } _pushToQueue(directory, base) { const queueItem = { directory, base }; this._queue.push(queueItem, (error) => { if (error !== null) { this._handleError(error); } }); } _worker(item, done) { this._scandir(item.directory, this._settings.fsScandirSettings, (error, entries) => { if (error !== null) { return done(error, undefined); } for (const entry of entries) { this._handleEntry(entry, item.base); } done(null, undefined); }); } _handleError(error) { if (this._isDestroyed || !common.isFatalError(this._settings, error)) { return; } this._isFatalError = true; this._isDestroyed = true; this._emitter.emit('error', error); } _handleEntry(entry, base) { if (this._isDestroyed || this._isFatalError) { return; } const fullpath = entry.path; if (base !== undefined) { entry.path = common.joinPathSegments(base, entry.name, this._settings.pathSegmentSeparator); } if (common.isAppliedFilter(this._settings.entryFilter, entry)) { this._emitEntry(entry); } if (entry.dirent.isDirectory() && common.isAppliedFilter(this._settings.deepFilter, entry)) { this._pushToQueue(fullpath, entry.path); } } _emitEntry(entry) { this._emitter.emit('entry', entry); } } exports.default = AsyncReader;