/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import {findEventTasks} from '../common/events'; import {patchQueueMicrotask} from '../common/queue-microtask'; import {patchTimer} from '../common/timers'; import {ArraySlice, isMix, patchMacroTask, patchMicroTask} from '../common/utils'; import {ZoneType} from '../zone-impl'; import {patchEvents} from './events'; import {patchFs} from './fs'; import {patchNodeUtil} from './node_util'; const set = 'set'; const clear = 'clear'; export function patchNode(Zone: ZoneType): void { patchNodeUtil(Zone); patchEvents(Zone); patchFs(Zone); Zone.__load_patch('node_timers', (global: any, Zone: ZoneType) => { // Timers let globalUseTimeoutFromTimer = false; try { const timers = require('timers'); let globalEqualTimersTimeout = global.setTimeout === timers.setTimeout; if (!globalEqualTimersTimeout && !isMix) { // 1. if isMix, then we are in mix environment such as Electron // we should only patch timers.setTimeout because global.setTimeout // have been patched // 2. if global.setTimeout not equal timers.setTimeout, check // whether global.setTimeout use timers.setTimeout or not const originSetTimeout = timers.setTimeout; timers.setTimeout = function () { globalUseTimeoutFromTimer = true; return originSetTimeout.apply(this, arguments); }; const detectTimeout = global.setTimeout(() => {}, 100); clearTimeout(detectTimeout); timers.setTimeout = originSetTimeout; } patchTimer(timers, set, clear, 'Timeout'); patchTimer(timers, set, clear, 'Interval'); patchTimer(timers, set, clear, 'Immediate'); } catch (error) { // timers module not exists, for example, when we using nativeScript // timers is not available } if (isMix) { // if we are in mix environment, such as Electron, // the global.setTimeout has already been patched, // so we just patch timers.setTimeout return; } if (!globalUseTimeoutFromTimer) { // 1. global setTimeout equals timers setTimeout // 2. or global don't use timers setTimeout(maybe some other library patch setTimeout) // 3. or load timers module error happens, we should patch global setTimeout patchTimer(global, set, clear, 'Timeout'); patchTimer(global, set, clear, 'Interval'); patchTimer(global, set, clear, 'Immediate'); } else { // global use timers setTimeout, but not equals // this happens when use nodejs v0.10.x, global setTimeout will // use a lazy load version of timers setTimeout // we should not double patch timer's setTimeout // so we only store the __symbol__ for consistency global[Zone.__symbol__('setTimeout')] = global.setTimeout; global[Zone.__symbol__('setInterval')] = global.setInterval; global[Zone.__symbol__('setImmediate')] = global.setImmediate; } }); // patch process related methods Zone.__load_patch('nextTick', () => { // patch nextTick as microTask patchMicroTask(process, 'nextTick', (self: any, args: any[]) => { return { name: 'process.nextTick', args: args, cbIdx: args.length > 0 && typeof args[0] === 'function' ? 0 : -1, target: process, }; }); }); Zone.__load_patch( 'handleUnhandledPromiseRejection', (global: any, Zone: ZoneType, api: _ZonePrivate) => { (Zone as any)[api.symbol('unhandledPromiseRejectionHandler')] = findProcessPromiseRejectionHandler('unhandledRejection'); (Zone as any)[api.symbol('rejectionHandledHandler')] = findProcessPromiseRejectionHandler('rejectionHandled'); // handle unhandled promise rejection function findProcessPromiseRejectionHandler(evtName: string) { return function (e: any) { const eventTasks = findEventTasks(process, evtName); eventTasks.forEach((eventTask) => { // process has added unhandledrejection event listener // trigger the event listener if (evtName === 'unhandledRejection') { eventTask.invoke(e.rejection, e.promise); } else if (evtName === 'rejectionHandled') { eventTask.invoke(e.promise); } }); }; } }, ); // Crypto Zone.__load_patch('crypto', () => { let crypto: any; try { crypto = require('crypto'); } catch (err) {} // use the generic patchMacroTask to patch crypto if (crypto) { const methodNames = ['randomBytes', 'pbkdf2']; methodNames.forEach((name) => { patchMacroTask(crypto, name, (self: any, args: any[]) => { return { name: 'crypto.' + name, args: args, cbIdx: args.length > 0 && typeof args[args.length - 1] === 'function' ? args.length - 1 : -1, target: crypto, }; }); }); } }); Zone.__load_patch('console', (global: any, Zone: ZoneType) => { const consoleMethods = [ 'dir', 'log', 'info', 'error', 'warn', 'assert', 'debug', 'timeEnd', 'trace', ]; consoleMethods.forEach((m: string) => { const originalMethod = ((console as any)[Zone.__symbol__(m)] = (console as any)[m]); if (originalMethod) { (console as any)[m] = function () { const args = ArraySlice.call(arguments); if (Zone.current === Zone.root) { return originalMethod.apply(this, args); } else { return Zone.root.run(originalMethod, this, args); } }; } }); }); Zone.__load_patch('queueMicrotask', (global: any, Zone: ZoneType, api: _ZonePrivate) => { patchQueueMicrotask(global, api); }); }