2019-05-31 15:56:07 +00:00
|
|
|
/**
|
|
|
|
|
* @license
|
2020-05-19 19:08:49 +00:00
|
|
|
* Copyright Google LLC All Rights Reserved.
|
2019-05-31 15:56:07 +00:00
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by an MIT-style license that can be
|
2024-09-20 15:23:15 +00:00
|
|
|
* found in the LICENSE file at https://angular.dev/license
|
2019-05-31 15:56:07 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import {findEventTasks} from '../common/events';
|
2023-05-25 15:44:17 +00:00
|
|
|
import {patchQueueMicrotask} from '../common/queue-microtask';
|
2019-05-31 15:56:07 +00:00
|
|
|
import {patchTimer} from '../common/timers';
|
|
|
|
|
import {ArraySlice, isMix, patchMacroTask, patchMicroTask} from '../common/utils';
|
2023-12-08 02:24:29 +00:00
|
|
|
import {ZoneType} from '../zone-impl';
|
|
|
|
|
|
|
|
|
|
import {patchEvents} from './events';
|
|
|
|
|
import {patchFs} from './fs';
|
|
|
|
|
import {patchNodeUtil} from './node_util';
|
2019-05-31 15:56:07 +00:00
|
|
|
|
|
|
|
|
const set = 'set';
|
|
|
|
|
const clear = 'clear';
|
|
|
|
|
|
2023-12-08 02:24:29 +00:00
|
|
|
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;
|
2019-05-31 15:56:07 +00:00
|
|
|
}
|
2023-12-08 02:24:29 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
});
|
2019-05-31 15:56:07 +00:00
|
|
|
|
2023-12-08 02:24:29 +00:00
|
|
|
// 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,
|
|
|
|
|
};
|
|
|
|
|
});
|
2019-05-31 15:56:07 +00:00
|
|
|
});
|
|
|
|
|
|
2023-12-08 02:24:29 +00:00
|
|
|
Zone.__load_patch(
|
|
|
|
|
'handleUnhandledPromiseRejection',
|
|
|
|
|
(global: any, Zone: ZoneType, api: _ZonePrivate) => {
|
|
|
|
|
(Zone as any)[api.symbol('unhandledPromiseRejectionHandler')] =
|
|
|
|
|
findProcessPromiseRejectionHandler('unhandledRejection');
|
2019-05-31 15:56:07 +00:00
|
|
|
|
2023-12-08 02:24:29 +00:00
|
|
|
(Zone as any)[api.symbol('rejectionHandledHandler')] =
|
|
|
|
|
findProcessPromiseRejectionHandler('rejectionHandled');
|
2019-05-31 15:56:07 +00:00
|
|
|
|
2023-12-08 02:24:29 +00:00
|
|
|
// 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);
|
2024-04-19 16:53:49 +00:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
2019-05-31 15:56:07 +00:00
|
|
|
|
2023-12-08 02:24:29 +00:00
|
|
|
// Crypto
|
|
|
|
|
Zone.__load_patch('crypto', () => {
|
|
|
|
|
let crypto: any;
|
|
|
|
|
try {
|
|
|
|
|
crypto = require('crypto');
|
|
|
|
|
} catch (err) {}
|
2019-05-31 15:56:07 +00:00
|
|
|
|
2023-12-08 02:24:29 +00:00
|
|
|
// 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,
|
|
|
|
|
};
|
|
|
|
|
});
|
2019-05-31 15:56:07 +00:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-05-25 15:44:17 +00:00
|
|
|
|
2023-12-08 02:24:29 +00:00
|
|
|
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);
|
|
|
|
|
});
|
|
|
|
|
}
|