/* @license Rollup.js v4.24.0 Wed, 02 Oct 2024 09:36:48 GMT - commit d3c000f4fd453e39a354299f0cfaa6831f56d7d8 https://github.com/rollup/rollup Released under the MIT License. */ 'use strict'; Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const index = require('./index.js'); const promises = require('node:fs/promises'); const process$2 = require('node:process'); const cli = require('../bin/rollup'); const rollup = require('./rollup.js'); const parseAst_js = require('./parseAst.js'); const loadConfigFile_js = require('./loadConfigFile.js'); const node_child_process = require('node:child_process'); const rollup_js = require('../rollup.js'); require('path'); require('fs'); require('util'); require('stream'); require('os'); require('./fsevents-importer.js'); require('events'); require('node:path'); require('tty'); require('../native.js'); require('node:perf_hooks'); require('node:url'); require('../getLogFilter.js'); function timeZone(date = new Date()) { const offset = date.getTimezoneOffset(); const absOffset = Math.abs(offset); const hours = Math.floor(absOffset / 60); const minutes = absOffset % 60; const minutesOut = minutes > 0 ? ':' + ('0' + minutes).slice(-2) : ''; return (offset < 0 ? '+' : '-') + hours + minutesOut; } function dateTime(options = {}) { let { date = new Date(), local = true, showTimeZone = false, showMilliseconds = false } = options; if (local) { // Offset the date so it will return the correct value when getting the ISO string. date = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)); } let end = ''; if (showTimeZone) { end = ' UTC' + (local ? timeZone(date) : ''); } if (showMilliseconds && date.getUTCMilliseconds() > 0) { end = ` ${date.getUTCMilliseconds()}ms${end}`; } return date .toISOString() .replace(/T/, ' ') .replace(/\..+/, end); } /** * This is not the set of all possible signals. * * It IS, however, the set of all signals that trigger * an exit on either Linux or BSD systems. Linux is a * superset of the signal names supported on BSD, and * the unknown signals just fail to register, so we can * catch that easily enough. * * Windows signals are a different set, since there are * signals that terminate Windows processes, but don't * terminate (or don't even exist) on Posix systems. * * Don't bother with SIGKILL. It's uncatchable, which * means that we can't fire any callbacks anyway. * * If a user does happen to register a handler on a non- * fatal signal like SIGWINCH or something, and then * exit, it'll end up firing `process.emit('exit')`, so * the handler will be fired anyway. * * SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised * artificially, inherently leave the process in a * state from which it is not safe to try and enter JS * listeners. */ const signals = []; signals.push('SIGHUP', 'SIGINT', 'SIGTERM'); if (process.platform !== 'win32') { signals.push('SIGALRM', 'SIGABRT', 'SIGVTALRM', 'SIGXCPU', 'SIGXFSZ', 'SIGUSR2', 'SIGTRAP', 'SIGSYS', 'SIGQUIT', 'SIGIOT' // should detect profiler and enable/disable accordingly. // see #21 // 'SIGPROF' ); } if (process.platform === 'linux') { signals.push('SIGIO', 'SIGPOLL', 'SIGPWR', 'SIGSTKFLT'); } // Note: since nyc uses this module to output coverage, any lines // that are in the direct sync flow of nyc's outputCoverage are // ignored, since we can never get coverage for them. // grab a reference to node's real process object right away const processOk = (process) => !!process && typeof process === 'object' && typeof process.removeListener === 'function' && typeof process.emit === 'function' && typeof process.reallyExit === 'function' && typeof process.listeners === 'function' && typeof process.kill === 'function' && typeof process.pid === 'number' && typeof process.on === 'function'; const kExitEmitter = Symbol.for('signal-exit emitter'); const global = globalThis; const ObjectDefineProperty = Object.defineProperty.bind(Object); // teeny special purpose ee class Emitter { emitted = { afterExit: false, exit: false, }; listeners = { afterExit: [], exit: [], }; count = 0; id = Math.random(); constructor() { if (global[kExitEmitter]) { return global[kExitEmitter]; } ObjectDefineProperty(global, kExitEmitter, { value: this, writable: false, enumerable: false, configurable: false, }); } on(ev, fn) { this.listeners[ev].push(fn); } removeListener(ev, fn) { const list = this.listeners[ev]; const i = list.indexOf(fn); /* c8 ignore start */ if (i === -1) { return; } /* c8 ignore stop */ if (i === 0 && list.length === 1) { list.length = 0; } else { list.splice(i, 1); } } emit(ev, code, signal) { if (this.emitted[ev]) { return false; } this.emitted[ev] = true; let ret = false; for (const fn of this.listeners[ev]) { ret = fn(code, signal) === true || ret; } if (ev === 'exit') { ret = this.emit('afterExit', code, signal) || ret; } return ret; } } class SignalExitBase { } const signalExitWrap = (handler) => { return { onExit(cb, opts) { return handler.onExit(cb, opts); }, load() { return handler.load(); }, unload() { return handler.unload(); }, }; }; class SignalExitFallback extends SignalExitBase { onExit() { return () => { }; } load() { } unload() { } } class SignalExit extends SignalExitBase { // "SIGHUP" throws an `ENOSYS` error on Windows, // so use a supported signal instead /* c8 ignore start */ #hupSig = process$1.platform === 'win32' ? 'SIGINT' : 'SIGHUP'; /* c8 ignore stop */ #emitter = new Emitter(); #process; #originalProcessEmit; #originalProcessReallyExit; #sigListeners = {}; #loaded = false; constructor(process) { super(); this.#process = process; // { : , ... } this.#sigListeners = {}; for (const sig of signals) { this.#sigListeners[sig] = () => { // If there are no other listeners, an exit is coming! // Simplest way: remove us and then re-send the signal. // We know that this will kill the process, so we can // safely emit now. const listeners = this.#process.listeners(sig); let { count } = this.#emitter; // This is a workaround for the fact that signal-exit v3 and signal // exit v4 are not aware of each other, and each will attempt to let // the other handle it, so neither of them do. To correct this, we // detect if we're the only handler *except* for previous versions // of signal-exit, and increment by the count of listeners it has // created. /* c8 ignore start */ const p = process; if (typeof p.__signal_exit_emitter__ === 'object' && typeof p.__signal_exit_emitter__.count === 'number') { count += p.__signal_exit_emitter__.count; } /* c8 ignore stop */ if (listeners.length === count) { this.unload(); const ret = this.#emitter.emit('exit', null, sig); /* c8 ignore start */ const s = sig === 'SIGHUP' ? this.#hupSig : sig; if (!ret) process.kill(process.pid, s); /* c8 ignore stop */ } }; } this.#originalProcessReallyExit = process.reallyExit; this.#originalProcessEmit = process.emit; } onExit(cb, opts) { /* c8 ignore start */ if (!processOk(this.#process)) { return () => { }; } /* c8 ignore stop */ if (this.#loaded === false) { this.load(); } const ev = opts?.alwaysLast ? 'afterExit' : 'exit'; this.#emitter.on(ev, cb); return () => { this.#emitter.removeListener(ev, cb); if (this.#emitter.listeners['exit'].length === 0 && this.#emitter.listeners['afterExit'].length === 0) { this.unload(); } }; } load() { if (this.#loaded) { return; } this.#loaded = true; // This is the number of onSignalExit's that are in play. // It's important so that we can count the correct number of // listeners on signals, and don't wait for the other one to // handle it instead of us. this.#emitter.count += 1; for (const sig of signals) { try { const fn = this.#sigListeners[sig]; if (fn) this.#process.on(sig, fn); } catch (_) { } } this.#process.emit = (ev, ...a) => { return this.#processEmit(ev, ...a); }; this.#process.reallyExit = (code) => { return this.#processReallyExit(code); }; } unload() { if (!this.#loaded) { return; } this.#loaded = false; signals.forEach(sig => { const listener = this.#sigListeners[sig]; /* c8 ignore start */ if (!listener) { throw new Error('Listener not defined for signal: ' + sig); } /* c8 ignore stop */ try { this.#process.removeListener(sig, listener); /* c8 ignore start */ } catch (_) { } /* c8 ignore stop */ }); this.#process.emit = this.#originalProcessEmit; this.#process.reallyExit = this.#originalProcessReallyExit; this.#emitter.count -= 1; } #processReallyExit(code) { /* c8 ignore start */ if (!processOk(this.#process)) { return 0; } this.#process.exitCode = code || 0; /* c8 ignore stop */ this.#emitter.emit('exit', this.#process.exitCode, null); return this.#originalProcessReallyExit.call(this.#process, this.#process.exitCode); } #processEmit(ev, ...args) { const og = this.#originalProcessEmit; if (ev === 'exit' && processOk(this.#process)) { if (typeof args[0] === 'number') { this.#process.exitCode = args[0]; /* c8 ignore start */ } /* c8 ignore start */ const ret = og.call(this.#process, ev, ...args); /* c8 ignore start */ this.#emitter.emit('exit', this.#process.exitCode, null); /* c8 ignore stop */ return ret; } else { return og.call(this.#process, ev, ...args); } } } const process$1 = globalThis.process; // wrap so that we call the method on the actual handler, without // exporting it directly. const { /** * Called when the process is exiting, whether via signal, explicit * exit, or running out of stuff to do. * * If the global process object is not suitable for instrumentation, * then this will be a no-op. * * Returns a function that may be used to unload signal-exit. */ onExit, /** * Load the listeners. Likely you never need to call this, unless * doing a rather deep integration with signal-exit functionality. * Mostly exposed for the benefit of testing. * * @internal */ load, /** * Unload the listeners. Likely you never need to call this, unless * doing a rather deep integration with signal-exit functionality. * Mostly exposed for the benefit of testing. * * @internal */ unload, } = signalExitWrap(processOk(process$1) ? new SignalExit(process$1) : new SignalExitFallback()); const CLEAR_SCREEN = '\u001Bc'; function getResetScreen(configs, allowClearScreen) { let clearScreen = allowClearScreen; for (const config of configs) { if (config.watch && config.watch.clearScreen === false) { clearScreen = false; } } if (clearScreen) { return (heading) => rollup.stderr(CLEAR_SCREEN + heading); } let firstRun = true; return (heading) => { if (firstRun) { rollup.stderr(heading); firstRun = false; } }; } function extractWatchHooks(command) { if (!Array.isArray(command.watch)) return {}; return command.watch .filter(value => typeof value === 'object') .reduce((accumulator, keyValueOption) => ({ ...accumulator, ...keyValueOption }), {}); } function createWatchHooks(command) { const watchHooks = extractWatchHooks(command); return function (hook) { if (watchHooks[hook]) { const cmd = watchHooks[hook]; if (!command.silent) { rollup.stderr(rollup.cyan$1(`watch.${hook} ${rollup.bold(`$ ${cmd}`)}`)); } try { // !! important - use stderr for all writes from execSync const stdio = [process.stdin, process.stderr, process.stderr]; node_child_process.execSync(cmd, { stdio: command.silent ? 'ignore' : stdio }); } catch (error) { rollup.stderr(error.message); } } }; } async function watch(command) { process$2.env.ROLLUP_WATCH = 'true'; const isTTY = process$2.stderr.isTTY; const silent = command.silent; let watcher; let configWatcher; let resetScreen; const configFile = command.config ? await cli.getConfigPath(command.config) : null; const runWatchHook = createWatchHooks(command); onExit(close); process$2.on('uncaughtException', closeWithError); if (!process$2.stdin.isTTY) { process$2.stdin.on('end', close); process$2.stdin.resume(); } async function loadConfigFromFileAndTrack(configFile) { let configFileData = null; let configFileRevision = 0; configWatcher = index.chokidar.watch(configFile).on('change', reloadConfigFile); await reloadConfigFile(); async function reloadConfigFile() { try { const newConfigFileData = await promises.readFile(configFile, 'utf8'); if (newConfigFileData === configFileData) { return; } configFileRevision++; const currentConfigFileRevision = configFileRevision; if (configFileData) { rollup.stderr(`\nReloading updated config...`); } configFileData = newConfigFileData; const { options, warnings } = await loadConfigFile_js.loadConfigFile(configFile, command, true); if (currentConfigFileRevision !== configFileRevision) { return; } if (watcher) { await watcher.close(); } start(options, warnings); } catch (error) { rollup.handleError(error, true); } } } if (configFile) { await loadConfigFromFileAndTrack(configFile); } else { const { options, warnings } = await cli.loadConfigFromCommand(command, true); await start(options, warnings); } async function start(configs, warnings) { watcher = rollup_js.watch(configs); watcher.on('event', event => { switch (event.code) { case 'ERROR': { warnings.flush(); rollup.handleError(event.error, true); runWatchHook('onError'); break; } case 'START': { if (!silent) { if (!resetScreen) { resetScreen = getResetScreen(configs, isTTY); } resetScreen(rollup.underline(`rollup v${rollup.version}`)); } runWatchHook('onStart'); break; } case 'BUNDLE_START': { if (!silent) { let input = event.input; if (typeof input !== 'string') { input = Array.isArray(input) ? input.join(', ') : Object.values(input).join(', '); } rollup.stderr(rollup.cyan$1(`bundles ${rollup.bold(input)} → ${rollup.bold(event.output.map(parseAst_js.relativeId).join(', '))}...`)); } runWatchHook('onBundleStart'); break; } case 'BUNDLE_END': { warnings.flush(); if (!silent) rollup.stderr(rollup.green(`created ${rollup.bold(event.output.map(parseAst_js.relativeId).join(', '))} in ${rollup.bold(cli.prettyMilliseconds(event.duration))}`)); runWatchHook('onBundleEnd'); if (event.result && event.result.getTimings) { cli.printTimings(event.result.getTimings()); } break; } case 'END': { runWatchHook('onEnd'); if (!silent && isTTY) { rollup.stderr(`\n[${dateTime()}] waiting for changes...`); } } } if ('result' in event && event.result) { event.result.close().catch(error => rollup.handleError(error, true)); } }); } function close(code) { process$2.removeListener('uncaughtException', closeWithError); // removing a non-existent listener is a no-op process$2.stdin.removeListener('end', close); if (configWatcher) configWatcher.close(); Promise.resolve(watcher?.close()).finally(() => { process$2.exit(typeof code === 'number' ? code : 0); }); // Tell signal-exit that we are handling this gracefully return true; } // return a promise that never resolves to keep the process running return new Promise(() => { }); } function closeWithError(error) { error.name = `Uncaught ${error.name}`; rollup.handleError(error); } exports.watch = watch; //# sourceMappingURL=watch-cli.js.map