source: node_modules/rollup/dist/shared/watch-cli.js@ 3d60932

Last change on this file since 3d60932 was 57e58a3, checked in by ste08 <sjovanoska@…>, 4 months ago

Initial commit

  • Property mode set to 100644
File size: 18.0 KB
Line 
1/*
2 @license
3 Rollup.js v4.34.4
4 Wed, 05 Feb 2025 21:30:40 GMT - commit 19312a762c3cda56a0f6dc80a0887a4499db2257
5
6 https://github.com/rollup/rollup
7
8 Released under the MIT License.
9*/
10'use strict';
11
12Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
13
14const index = require('./index.js');
15const promises = require('node:fs/promises');
16const process$2 = require('node:process');
17const cli = require('../bin/rollup');
18const rollup = require('./rollup.js');
19const parseAst_js = require('./parseAst.js');
20const loadConfigFile_js = require('./loadConfigFile.js');
21const node_child_process = require('node:child_process');
22const rollup_js = require('../rollup.js');
23require('path');
24require('util');
25require('fs');
26require('stream');
27require('os');
28require('./fsevents-importer.js');
29require('events');
30require('node:path');
31require('../native.js');
32require('node:perf_hooks');
33require('node:url');
34require('../getLogFilter.js');
35
36function timeZone(date = new Date()) {
37 const offset = date.getTimezoneOffset();
38 const absOffset = Math.abs(offset);
39 const hours = Math.floor(absOffset / 60);
40 const minutes = absOffset % 60;
41 const minutesOut = minutes > 0 ? ':' + ('0' + minutes).slice(-2) : '';
42 return (offset < 0 ? '+' : '-') + hours + minutesOut;
43}
44
45function dateTime(options = {}) {
46 let {
47 date = new Date(),
48 local = true,
49 showTimeZone = false,
50 showMilliseconds = false
51 } = options;
52
53 if (local) {
54 // Offset the date so it will return the correct value when getting the ISO string.
55 date = new Date(date.getTime() - (date.getTimezoneOffset() * 60000));
56 }
57
58 let end = '';
59
60 if (showTimeZone) {
61 end = ' UTC' + (local ? timeZone(date) : '');
62 }
63
64 if (showMilliseconds && date.getUTCMilliseconds() > 0) {
65 end = ` ${date.getUTCMilliseconds()}ms${end}`;
66 }
67
68 return date
69 .toISOString()
70 .replace(/T/, ' ')
71 .replace(/\..+/, end);
72}
73
74/**
75 * This is not the set of all possible signals.
76 *
77 * It IS, however, the set of all signals that trigger
78 * an exit on either Linux or BSD systems. Linux is a
79 * superset of the signal names supported on BSD, and
80 * the unknown signals just fail to register, so we can
81 * catch that easily enough.
82 *
83 * Windows signals are a different set, since there are
84 * signals that terminate Windows processes, but don't
85 * terminate (or don't even exist) on Posix systems.
86 *
87 * Don't bother with SIGKILL. It's uncatchable, which
88 * means that we can't fire any callbacks anyway.
89 *
90 * If a user does happen to register a handler on a non-
91 * fatal signal like SIGWINCH or something, and then
92 * exit, it'll end up firing `process.emit('exit')`, so
93 * the handler will be fired anyway.
94 *
95 * SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised
96 * artificially, inherently leave the process in a
97 * state from which it is not safe to try and enter JS
98 * listeners.
99 */
100const signals = [];
101signals.push('SIGHUP', 'SIGINT', 'SIGTERM');
102if (process.platform !== 'win32') {
103 signals.push('SIGALRM', 'SIGABRT', 'SIGVTALRM', 'SIGXCPU', 'SIGXFSZ', 'SIGUSR2', 'SIGTRAP', 'SIGSYS', 'SIGQUIT', 'SIGIOT'
104 // should detect profiler and enable/disable accordingly.
105 // see #21
106 // 'SIGPROF'
107 );
108}
109if (process.platform === 'linux') {
110 signals.push('SIGIO', 'SIGPOLL', 'SIGPWR', 'SIGSTKFLT');
111}
112
113// Note: since nyc uses this module to output coverage, any lines
114// that are in the direct sync flow of nyc's outputCoverage are
115// ignored, since we can never get coverage for them.
116// grab a reference to node's real process object right away
117const processOk = (process) => !!process &&
118 typeof process === 'object' &&
119 typeof process.removeListener === 'function' &&
120 typeof process.emit === 'function' &&
121 typeof process.reallyExit === 'function' &&
122 typeof process.listeners === 'function' &&
123 typeof process.kill === 'function' &&
124 typeof process.pid === 'number' &&
125 typeof process.on === 'function';
126const kExitEmitter = Symbol.for('signal-exit emitter');
127const global = globalThis;
128const ObjectDefineProperty = Object.defineProperty.bind(Object);
129// teeny special purpose ee
130class Emitter {
131 emitted = {
132 afterExit: false,
133 exit: false,
134 };
135 listeners = {
136 afterExit: [],
137 exit: [],
138 };
139 count = 0;
140 id = Math.random();
141 constructor() {
142 if (global[kExitEmitter]) {
143 return global[kExitEmitter];
144 }
145 ObjectDefineProperty(global, kExitEmitter, {
146 value: this,
147 writable: false,
148 enumerable: false,
149 configurable: false,
150 });
151 }
152 on(ev, fn) {
153 this.listeners[ev].push(fn);
154 }
155 removeListener(ev, fn) {
156 const list = this.listeners[ev];
157 const i = list.indexOf(fn);
158 /* c8 ignore start */
159 if (i === -1) {
160 return;
161 }
162 /* c8 ignore stop */
163 if (i === 0 && list.length === 1) {
164 list.length = 0;
165 }
166 else {
167 list.splice(i, 1);
168 }
169 }
170 emit(ev, code, signal) {
171 if (this.emitted[ev]) {
172 return false;
173 }
174 this.emitted[ev] = true;
175 let ret = false;
176 for (const fn of this.listeners[ev]) {
177 ret = fn(code, signal) === true || ret;
178 }
179 if (ev === 'exit') {
180 ret = this.emit('afterExit', code, signal) || ret;
181 }
182 return ret;
183 }
184}
185class SignalExitBase {
186}
187const signalExitWrap = (handler) => {
188 return {
189 onExit(cb, opts) {
190 return handler.onExit(cb, opts);
191 },
192 load() {
193 return handler.load();
194 },
195 unload() {
196 return handler.unload();
197 },
198 };
199};
200class SignalExitFallback extends SignalExitBase {
201 onExit() {
202 return () => { };
203 }
204 load() { }
205 unload() { }
206}
207class SignalExit extends SignalExitBase {
208 // "SIGHUP" throws an `ENOSYS` error on Windows,
209 // so use a supported signal instead
210 /* c8 ignore start */
211 #hupSig = process$1.platform === 'win32' ? 'SIGINT' : 'SIGHUP';
212 /* c8 ignore stop */
213 #emitter = new Emitter();
214 #process;
215 #originalProcessEmit;
216 #originalProcessReallyExit;
217 #sigListeners = {};
218 #loaded = false;
219 constructor(process) {
220 super();
221 this.#process = process;
222 // { <signal>: <listener fn>, ... }
223 this.#sigListeners = {};
224 for (const sig of signals) {
225 this.#sigListeners[sig] = () => {
226 // If there are no other listeners, an exit is coming!
227 // Simplest way: remove us and then re-send the signal.
228 // We know that this will kill the process, so we can
229 // safely emit now.
230 const listeners = this.#process.listeners(sig);
231 let { count } = this.#emitter;
232 // This is a workaround for the fact that signal-exit v3 and signal
233 // exit v4 are not aware of each other, and each will attempt to let
234 // the other handle it, so neither of them do. To correct this, we
235 // detect if we're the only handler *except* for previous versions
236 // of signal-exit, and increment by the count of listeners it has
237 // created.
238 /* c8 ignore start */
239 const p = process;
240 if (typeof p.__signal_exit_emitter__ === 'object' &&
241 typeof p.__signal_exit_emitter__.count === 'number') {
242 count += p.__signal_exit_emitter__.count;
243 }
244 /* c8 ignore stop */
245 if (listeners.length === count) {
246 this.unload();
247 const ret = this.#emitter.emit('exit', null, sig);
248 /* c8 ignore start */
249 const s = sig === 'SIGHUP' ? this.#hupSig : sig;
250 if (!ret)
251 process.kill(process.pid, s);
252 /* c8 ignore stop */
253 }
254 };
255 }
256 this.#originalProcessReallyExit = process.reallyExit;
257 this.#originalProcessEmit = process.emit;
258 }
259 onExit(cb, opts) {
260 /* c8 ignore start */
261 if (!processOk(this.#process)) {
262 return () => { };
263 }
264 /* c8 ignore stop */
265 if (this.#loaded === false) {
266 this.load();
267 }
268 const ev = opts?.alwaysLast ? 'afterExit' : 'exit';
269 this.#emitter.on(ev, cb);
270 return () => {
271 this.#emitter.removeListener(ev, cb);
272 if (this.#emitter.listeners['exit'].length === 0 &&
273 this.#emitter.listeners['afterExit'].length === 0) {
274 this.unload();
275 }
276 };
277 }
278 load() {
279 if (this.#loaded) {
280 return;
281 }
282 this.#loaded = true;
283 // This is the number of onSignalExit's that are in play.
284 // It's important so that we can count the correct number of
285 // listeners on signals, and don't wait for the other one to
286 // handle it instead of us.
287 this.#emitter.count += 1;
288 for (const sig of signals) {
289 try {
290 const fn = this.#sigListeners[sig];
291 if (fn)
292 this.#process.on(sig, fn);
293 }
294 catch (_) { }
295 }
296 this.#process.emit = (ev, ...a) => {
297 return this.#processEmit(ev, ...a);
298 };
299 this.#process.reallyExit = (code) => {
300 return this.#processReallyExit(code);
301 };
302 }
303 unload() {
304 if (!this.#loaded) {
305 return;
306 }
307 this.#loaded = false;
308 signals.forEach(sig => {
309 const listener = this.#sigListeners[sig];
310 /* c8 ignore start */
311 if (!listener) {
312 throw new Error('Listener not defined for signal: ' + sig);
313 }
314 /* c8 ignore stop */
315 try {
316 this.#process.removeListener(sig, listener);
317 /* c8 ignore start */
318 }
319 catch (_) { }
320 /* c8 ignore stop */
321 });
322 this.#process.emit = this.#originalProcessEmit;
323 this.#process.reallyExit = this.#originalProcessReallyExit;
324 this.#emitter.count -= 1;
325 }
326 #processReallyExit(code) {
327 /* c8 ignore start */
328 if (!processOk(this.#process)) {
329 return 0;
330 }
331 this.#process.exitCode = code || 0;
332 /* c8 ignore stop */
333 this.#emitter.emit('exit', this.#process.exitCode, null);
334 return this.#originalProcessReallyExit.call(this.#process, this.#process.exitCode);
335 }
336 #processEmit(ev, ...args) {
337 const og = this.#originalProcessEmit;
338 if (ev === 'exit' && processOk(this.#process)) {
339 if (typeof args[0] === 'number') {
340 this.#process.exitCode = args[0];
341 /* c8 ignore start */
342 }
343 /* c8 ignore start */
344 const ret = og.call(this.#process, ev, ...args);
345 /* c8 ignore start */
346 this.#emitter.emit('exit', this.#process.exitCode, null);
347 /* c8 ignore stop */
348 return ret;
349 }
350 else {
351 return og.call(this.#process, ev, ...args);
352 }
353 }
354}
355const process$1 = globalThis.process;
356// wrap so that we call the method on the actual handler, without
357// exporting it directly.
358const {
359/**
360 * Called when the process is exiting, whether via signal, explicit
361 * exit, or running out of stuff to do.
362 *
363 * If the global process object is not suitable for instrumentation,
364 * then this will be a no-op.
365 *
366 * Returns a function that may be used to unload signal-exit.
367 */
368onExit} = signalExitWrap(processOk(process$1) ? new SignalExit(process$1) : new SignalExitFallback());
369
370const CLEAR_SCREEN = '\u001Bc';
371function getResetScreen(configs, allowClearScreen) {
372 let clearScreen = allowClearScreen;
373 for (const config of configs) {
374 if (config.watch && config.watch.clearScreen === false) {
375 clearScreen = false;
376 }
377 }
378 if (clearScreen) {
379 return (heading) => rollup.stderr(CLEAR_SCREEN + heading);
380 }
381 let firstRun = true;
382 return (heading) => {
383 if (firstRun) {
384 rollup.stderr(heading);
385 firstRun = false;
386 }
387 };
388}
389
390function extractWatchHooks(command) {
391 if (!Array.isArray(command.watch))
392 return {};
393 return command.watch
394 .filter(value => typeof value === 'object')
395 .reduce((accumulator, keyValueOption) => ({ ...accumulator, ...keyValueOption }), {});
396}
397function createWatchHooks(command) {
398 const watchHooks = extractWatchHooks(command);
399 return function (hook) {
400 if (watchHooks[hook]) {
401 const cmd = watchHooks[hook];
402 if (!command.silent) {
403 rollup.stderr(rollup.cyan(`watch.${hook} ${rollup.bold(`$ ${cmd}`)}`));
404 }
405 try {
406 // !! important - use stderr for all writes from execSync
407 const stdio = [process.stdin, process.stderr, process.stderr];
408 node_child_process.execSync(cmd, { stdio: command.silent ? 'ignore' : stdio });
409 }
410 catch (error) {
411 rollup.stderr(error.message);
412 }
413 }
414 };
415}
416
417async function watch(command) {
418 process$2.env.ROLLUP_WATCH = 'true';
419 const isTTY = process$2.stderr.isTTY;
420 const silent = command.silent;
421 let watcher;
422 let configWatcher;
423 let resetScreen;
424 const configFile = command.config ? await cli.getConfigPath(command.config) : null;
425 const runWatchHook = createWatchHooks(command);
426 onExit(close);
427 process$2.on('uncaughtException', closeWithError);
428 async function loadConfigFromFileAndTrack(configFile) {
429 let configFileData = null;
430 let configFileRevision = 0;
431 configWatcher = index.chokidar.watch(configFile).on('change', reloadConfigFile);
432 await reloadConfigFile();
433 async function reloadConfigFile() {
434 try {
435 const newConfigFileData = await promises.readFile(configFile, 'utf8');
436 if (newConfigFileData === configFileData) {
437 return;
438 }
439 configFileRevision++;
440 const currentConfigFileRevision = configFileRevision;
441 if (configFileData) {
442 rollup.stderr(`\nReloading updated config...`);
443 }
444 configFileData = newConfigFileData;
445 const { options, warnings } = await loadConfigFile_js.loadConfigFile(configFile, command, true);
446 if (currentConfigFileRevision !== configFileRevision) {
447 return;
448 }
449 if (watcher) {
450 await watcher.close();
451 }
452 start(options, warnings);
453 }
454 catch (error) {
455 rollup.handleError(error, true);
456 }
457 }
458 }
459 if (configFile) {
460 await loadConfigFromFileAndTrack(configFile);
461 }
462 else {
463 const { options, warnings } = await cli.loadConfigFromCommand(command, true);
464 await start(options, warnings);
465 }
466 async function start(configs, warnings) {
467 watcher = rollup_js.watch(configs);
468 watcher.on('event', event => {
469 switch (event.code) {
470 case 'ERROR': {
471 warnings.flush();
472 rollup.handleError(event.error, true);
473 runWatchHook('onError');
474 break;
475 }
476 case 'START': {
477 if (!silent) {
478 if (!resetScreen) {
479 resetScreen = getResetScreen(configs, isTTY);
480 }
481 resetScreen(rollup.underline(`rollup v${rollup.version}`));
482 }
483 runWatchHook('onStart');
484 break;
485 }
486 case 'BUNDLE_START': {
487 if (!silent) {
488 let input = event.input;
489 if (typeof input !== 'string') {
490 input = Array.isArray(input)
491 ? input.join(', ')
492 : Object.values(input).join(', ');
493 }
494 rollup.stderr(rollup.cyan(`bundles ${rollup.bold(input)} → ${rollup.bold(event.output.map(parseAst_js.relativeId).join(', '))}...`));
495 }
496 runWatchHook('onBundleStart');
497 break;
498 }
499 case 'BUNDLE_END': {
500 warnings.flush();
501 if (!silent)
502 rollup.stderr(rollup.green(`created ${rollup.bold(event.output.map(parseAst_js.relativeId).join(', '))} in ${rollup.bold(cli.prettyMilliseconds(event.duration))}`));
503 runWatchHook('onBundleEnd');
504 if (event.result && event.result.getTimings) {
505 cli.printTimings(event.result.getTimings());
506 }
507 break;
508 }
509 case 'END': {
510 runWatchHook('onEnd');
511 if (!silent) {
512 rollup.stderr(`\n[${dateTime()}] waiting for changes...`);
513 }
514 }
515 }
516 if ('result' in event && event.result) {
517 event.result.close().catch(error => rollup.handleError(error, true));
518 }
519 });
520 }
521 function close(code) {
522 process$2.removeListener('uncaughtException', closeWithError);
523 // removing a non-existent listener is a no-op
524 process$2.stdin.removeListener('end', close);
525 if (configWatcher)
526 configWatcher.close();
527 Promise.resolve(watcher?.close()).finally(() => {
528 process$2.exit(typeof code === 'number' ? code : 0);
529 });
530 // Tell signal-exit that we are handling this gracefully
531 return true;
532 }
533 // return a promise that never resolves to keep the process running
534 return new Promise(() => { });
535}
536function closeWithError(error) {
537 error.name = `Uncaught ${error.name}`;
538 rollup.handleError(error);
539}
540
541exports.watch = watch;
542//# sourceMappingURL=watch-cli.js.map
Note: See TracBrowser for help on using the repository browser.