UNPKG

turbowatch

Version:

Extremely fast file change detector and task orchestrator for Node.js.

169 lines 6.61 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.watch = void 0; const TurboWatcher_1 = require("./backends/TurboWatcher"); const generateShortId_1 = require("./generateShortId"); const Logger_1 = require("./Logger"); const subscribe_1 = require("./subscribe"); const testExpression_1 = require("./testExpression"); const serialize_error_1 = require("serialize-error"); const throttle_debounce_1 = require("throttle-debounce"); const log = Logger_1.Logger.child({ namespace: 'watch', }); const watch = (configurationInput) => { var _a, _b, _c, _d, _e; const { cwd, project, triggers, debounce: userDebounce, Watcher, } = { // as far as I can tell, this is a bug in unicorn/no-unused-properties // https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2051 // eslint-disable-next-line unicorn/no-unused-properties debounce: { wait: 1000, }, // eslint-disable-next-line unicorn/no-unused-properties Watcher: TurboWatcher_1.TurboWatcher, ...configurationInput, }; const abortController = new AbortController(); const abortSignal = abortController.signal; let discoveredFileCount = 0; const indexingIntervalId = setInterval(() => { log.trace('indexed %d %s...', discoveredFileCount, discoveredFileCount === 1 ? 'file' : 'files'); }, 5000); const subscriptions = []; const watcher = new Watcher(project); let shuttingDown = false; const shutdown = async () => { if (shuttingDown) { return; } shuttingDown = true; // eslint-disable-next-line promise/prefer-await-to-then await watcher.close(); clearInterval(indexingIntervalId); abortController.abort(); for (const subscription of subscriptions) { const { activeTask } = subscription; if (activeTask === null || activeTask === void 0 ? void 0 : activeTask.promise) { await (activeTask === null || activeTask === void 0 ? void 0 : activeTask.promise); } } for (const subscription of subscriptions) { const { teardown } = subscription; if (teardown) { await teardown(); } } }; if (abortSignal) { abortSignal.addEventListener('abort', () => { shutdown(); }, { once: true, }); } for (const trigger of triggers) { subscriptions.push((0, subscribe_1.subscribe)({ abortSignal, cwd, expression: trigger.expression, id: (0, generateShortId_1.generateShortId)(), initialRun: (_a = trigger.initialRun) !== null && _a !== void 0 ? _a : true, interruptible: (_b = trigger.interruptible) !== null && _b !== void 0 ? _b : true, name: trigger.name, onChange: trigger.onChange, onTeardown: trigger.onTeardown, persistent: (_c = trigger.persistent) !== null && _c !== void 0 ? _c : false, retry: (_d = trigger.retry) !== null && _d !== void 0 ? _d : { retries: 0, }, throttleOutput: (_e = trigger.throttleOutput) !== null && _e !== void 0 ? _e : { delay: 1000 }, })); } let queuedFileChangeEvents = []; const evaluateSubscribers = (0, throttle_debounce_1.debounce)(userDebounce.wait, () => { const currentFileChangeEvents = queuedFileChangeEvents; queuedFileChangeEvents = []; for (const subscription of subscriptions) { const relevantEvents = currentFileChangeEvents.filter((fileChangeEvent) => { return (0, testExpression_1.testExpression)(subscription.expression, fileChangeEvent.filename); }); if (relevantEvents.length) { if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) { return; } void subscription.trigger(relevantEvents); } } }, { noLeading: true, }); let ready = false; const discoveredFiles = []; watcher.on('change', ({ filename }) => { if (ready) { queuedFileChangeEvents.push({ filename, }); evaluateSubscribers(); } else { if (discoveredFiles.length < 10) { discoveredFiles.push(filename); } discoveredFileCount++; } }); return new Promise((resolve, reject) => { watcher.on('error', (error) => { log.error({ error: (0, serialize_error_1.serializeError)(error), }, 'could not watch project'); if (ready) { shutdown(); } else { reject(error); } }); watcher.on('ready', () => { ready = true; clearInterval(indexingIntervalId); if (discoveredFiles.length > 10) { log.trace({ files: discoveredFiles.slice(0, 10).map((file) => { return file; }), }, 'discovered %d files in %s; showing first 10', discoveredFileCount, project); } else if (discoveredFiles.length > 0) { log.trace({ files: discoveredFiles.map((file) => { return file; }), }, 'discovered %d %s in %s', discoveredFileCount, discoveredFiles.length === 1 ? 'file' : 'files', project); } log.info('triggering initial runs'); const initialRuns = []; for (const subscription of subscriptions) { if (subscription.initialRun && !subscription.persistent) { initialRuns.push(subscription.trigger([])); } } // eslint-disable-next-line promise/prefer-await-to-then void Promise.allSettled(initialRuns).then(() => { for (const subscription of subscriptions) { if (subscription.initialRun && subscription.persistent) { void subscription.trigger([]); } } log.info('ready for file changes'); resolve({ shutdown, }); }); }); }); }; exports.watch = watch; //# sourceMappingURL=watch.js.map