%PDF- %PDF-
Direktori : /lib/node_modules/pm2/node_modules/vm2/lib/ |
Current File : //lib/node_modules/pm2/node_modules/vm2/lib/events.js |
// Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. // Modified by the vm2 team to make this a standalone module to be loaded into the sandbox. 'use strict'; const host = fromhost; const { Boolean, Error, String, Symbol } = globalThis; const ReflectApply = Reflect.apply; const ReflectOwnKeys = Reflect.ownKeys; const ErrorCaptureStackTrace = Error.captureStackTrace; const NumberIsNaN = Number.isNaN; const ObjectCreate = Object.create; const ObjectDefineProperty = Object.defineProperty; const ObjectDefineProperties = Object.defineProperties; const ObjectGetPrototypeOf = Object.getPrototypeOf; const SymbolFor = Symbol.for; function uncurryThis(func) { return (thiz, ...args) => ReflectApply(func, thiz, args); } const ArrayPrototypeIndexOf = uncurryThis(Array.prototype.indexOf); const ArrayPrototypeJoin = uncurryThis(Array.prototype.join); const ArrayPrototypeSlice = uncurryThis(Array.prototype.slice); const ArrayPrototypeSplice = uncurryThis(Array.prototype.splice); const ArrayPrototypeUnshift = uncurryThis(Array.prototype.unshift); const kRejection = SymbolFor('nodejs.rejection'); function inspect(obj) { return typeof obj === 'symbol' ? obj.toString() : `${obj}`; } function spliceOne(list, index) { for (; index + 1 < list.length; index++) list[index] = list[index + 1]; list.pop(); } function assert(what, message) { if (!what) throw new Error(message); } function E(key, msg, Base) { return function NodeError(...args) { const error = new Base(); const message = ReflectApply(msg, error, args); ObjectDefineProperties(error, { message: { value: message, enumerable: false, writable: true, configurable: true, }, toString: { value() { return `${this.name} [${key}]: ${this.message}`; }, enumerable: false, writable: true, configurable: true, }, }); error.code = key; return error; }; } const ERR_INVALID_ARG_TYPE = E('ERR_INVALID_ARG_TYPE', (name, expected, actual) => { assert(typeof name === 'string', "'name' must be a string"); if (!ArrayIsArray(expected)) { expected = [expected]; } let msg = 'The '; if (StringPrototypeEndsWith(name, ' argument')) { // For cases like 'first argument' msg += `${name} `; } else { const type = StringPrototypeIncludes(name, '.') ? 'property' : 'argument'; msg += `"${name}" ${type} `; } msg += 'must be '; const types = []; const instances = []; const other = []; for (const value of expected) { assert(typeof value === 'string', 'All expected entries have to be of type string'); if (ArrayPrototypeIncludes(kTypes, value)) { ArrayPrototypePush(types, StringPrototypeToLowerCase(value)); } else if (RegExpPrototypeTest(classRegExp, value)) { ArrayPrototypePush(instances, value); } else { assert(value !== 'object', 'The value "object" should be written as "Object"'); ArrayPrototypePush(other, value); } } // Special handle `object` in case other instances are allowed to outline // the differences between each other. if (instances.length > 0) { const pos = ArrayPrototypeIndexOf(types, 'object'); if (pos !== -1) { ArrayPrototypeSplice(types, pos, 1); ArrayPrototypePush(instances, 'Object'); } } if (types.length > 0) { if (types.length > 2) { const last = ArrayPrototypePop(types); msg += `one of type ${ArrayPrototypeJoin(types, ', ')}, or ${last}`; } else if (types.length === 2) { msg += `one of type ${types[0]} or ${types[1]}`; } else { msg += `of type ${types[0]}`; } if (instances.length > 0 || other.length > 0) msg += ' or '; } if (instances.length > 0) { if (instances.length > 2) { const last = ArrayPrototypePop(instances); msg += `an instance of ${ArrayPrototypeJoin(instances, ', ')}, or ${last}`; } else { msg += `an instance of ${instances[0]}`; if (instances.length === 2) { msg += ` or ${instances[1]}`; } } if (other.length > 0) msg += ' or '; } if (other.length > 0) { if (other.length > 2) { const last = ArrayPrototypePop(other); msg += `one of ${ArrayPrototypeJoin(other, ', ')}, or ${last}`; } else if (other.length === 2) { msg += `one of ${other[0]} or ${other[1]}`; } else { if (StringPrototypeToLowerCase(other[0]) !== other[0]) msg += 'an '; msg += `${other[0]}`; } } if (actual == null) { msg += `. Received ${actual}`; } else if (typeof actual === 'function' && actual.name) { msg += `. Received function ${actual.name}`; } else if (typeof actual === 'object') { if (actual.constructor && actual.constructor.name) { msg += `. Received an instance of ${actual.constructor.name}`; } else { const inspected = inspect(actual, { depth: -1 }); msg += `. Received ${inspected}`; } } else { let inspected = inspect(actual, { colors: false }); if (inspected.length > 25) inspected = `${StringPrototypeSlice(inspected, 0, 25)}...`; msg += `. Received type ${typeof actual} (${inspected})`; } return msg; }, TypeError); const ERR_INVALID_THIS = E('ERR_INVALID_THIS', s => `Value of "this" must be of type ${s}`, TypeError); const ERR_OUT_OF_RANGE = E('ERR_OUT_OF_RANGE', (str, range, input, replaceDefaultBoolean = false) => { assert(range, 'Missing "range" argument'); let msg = replaceDefaultBoolean ? str : `The value of "${str}" is out of range.`; const received = inspect(input); msg += ` It must be ${range}. Received ${received}`; return msg; }, RangeError); const ERR_UNHANDLED_ERROR = E('ERR_UNHANDLED_ERROR', err => { const msg = 'Unhandled error.'; if (err === undefined) return msg; return `${msg} (${err})`; }, Error); function validateBoolean(value, name) { if (typeof value !== 'boolean') throw new ERR_INVALID_ARG_TYPE(name, 'boolean', value); } function validateFunction(value, name) { if (typeof value !== 'function') throw new ERR_INVALID_ARG_TYPE(name, 'Function', value); } function validateString(value, name) { if (typeof value !== 'string') throw new ERR_INVALID_ARG_TYPE(name, 'string', value); } function nc(cond, e) { return cond === undefined || cond === null ? e : cond; } function oc(base, key) { return base === undefined || base === null ? undefined : base[key]; } const kCapture = Symbol('kCapture'); const kErrorMonitor = host.kErrorMonitor || Symbol('events.errorMonitor'); const kMaxEventTargetListeners = Symbol('events.maxEventTargetListeners'); const kMaxEventTargetListenersWarned = Symbol('events.maxEventTargetListenersWarned'); const kIsEventTarget = SymbolFor('nodejs.event_target'); function isEventTarget(obj) { return oc(oc(obj, 'constructor'), kIsEventTarget); } /** * Creates a new `EventEmitter` instance. * @param {{ captureRejections?: boolean; }} [opts] * @constructs {EventEmitter} */ function EventEmitter(opts) { EventEmitter.init.call(this, opts); } module.exports = EventEmitter; if (host.once) module.exports.once = host.once; if (host.on) module.exports.on = host.on; if (host.getEventListeners) module.exports.getEventListeners = host.getEventListeners; // Backwards-compat with node 0.10.x EventEmitter.EventEmitter = EventEmitter; EventEmitter.usingDomains = false; EventEmitter.captureRejectionSymbol = kRejection; ObjectDefineProperty(EventEmitter, 'captureRejections', { get() { return EventEmitter.prototype[kCapture]; }, set(value) { validateBoolean(value, 'EventEmitter.captureRejections'); EventEmitter.prototype[kCapture] = value; }, enumerable: true }); if (host.EventEmitterReferencingAsyncResource) { const kAsyncResource = Symbol('kAsyncResource'); const EventEmitterReferencingAsyncResource = host.EventEmitterReferencingAsyncResource; class EventEmitterAsyncResource extends EventEmitter { /** * @param {{ * name?: string, * triggerAsyncId?: number, * requireManualDestroy?: boolean, * }} [options] */ constructor(options = undefined) { let name; if (typeof options === 'string') { name = options; options = undefined; } else { if (new.target === EventEmitterAsyncResource) { validateString(oc(options, 'name'), 'options.name'); } name = oc(options, 'name') || new.target.name; } super(options); this[kAsyncResource] = new EventEmitterReferencingAsyncResource(this, name, options); } /** * @param {symbol,string} event * @param {...any} args * @returns {boolean} */ emit(event, ...args) { if (this[kAsyncResource] === undefined) throw new ERR_INVALID_THIS('EventEmitterAsyncResource'); const { asyncResource } = this; ArrayPrototypeUnshift(args, super.emit, this, event); return ReflectApply(asyncResource.runInAsyncScope, asyncResource, args); } /** * @returns {void} */ emitDestroy() { if (this[kAsyncResource] === undefined) throw new ERR_INVALID_THIS('EventEmitterAsyncResource'); this.asyncResource.emitDestroy(); } /** * @type {number} */ get asyncId() { if (this[kAsyncResource] === undefined) throw new ERR_INVALID_THIS('EventEmitterAsyncResource'); return this.asyncResource.asyncId(); } /** * @type {number} */ get triggerAsyncId() { if (this[kAsyncResource] === undefined) throw new ERR_INVALID_THIS('EventEmitterAsyncResource'); return this.asyncResource.triggerAsyncId(); } /** * @type {EventEmitterReferencingAsyncResource} */ get asyncResource() { if (this[kAsyncResource] === undefined) throw new ERR_INVALID_THIS('EventEmitterAsyncResource'); return this[kAsyncResource]; } } EventEmitter.EventEmitterAsyncResource = EventEmitterAsyncResource; } EventEmitter.errorMonitor = kErrorMonitor; // The default for captureRejections is false ObjectDefineProperty(EventEmitter.prototype, kCapture, { value: false, writable: true, enumerable: false }); EventEmitter.prototype._events = undefined; EventEmitter.prototype._eventsCount = 0; EventEmitter.prototype._maxListeners = undefined; // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. let defaultMaxListeners = 10; function checkListener(listener) { validateFunction(listener, 'listener'); } ObjectDefineProperty(EventEmitter, 'defaultMaxListeners', { enumerable: true, get: function() { return defaultMaxListeners; }, set: function(arg) { if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) { throw new ERR_OUT_OF_RANGE('defaultMaxListeners', 'a non-negative number', arg); } defaultMaxListeners = arg; } }); ObjectDefineProperties(EventEmitter, { kMaxEventTargetListeners: { value: kMaxEventTargetListeners, enumerable: false, configurable: false, writable: false, }, kMaxEventTargetListenersWarned: { value: kMaxEventTargetListenersWarned, enumerable: false, configurable: false, writable: false, } }); /** * Sets the max listeners. * @param {number} n * @param {EventTarget[] | EventEmitter[]} [eventTargets] * @returns {void} */ EventEmitter.setMaxListeners = function(n = defaultMaxListeners, ...eventTargets) { if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n); if (eventTargets.length === 0) { defaultMaxListeners = n; } else { for (let i = 0; i < eventTargets.length; i++) { const target = eventTargets[i]; if (isEventTarget(target)) { target[kMaxEventTargetListeners] = n; target[kMaxEventTargetListenersWarned] = false; } else if (typeof target.setMaxListeners === 'function') { target.setMaxListeners(n); } else { throw new ERR_INVALID_ARG_TYPE( 'eventTargets', ['EventEmitter', 'EventTarget'], target); } } } }; // If you're updating this function definition, please also update any // re-definitions, such as the one in the Domain module (lib/domain.js). EventEmitter.init = function(opts) { if (this._events === undefined || this._events === ObjectGetPrototypeOf(this)._events) { this._events = ObjectCreate(null); this._eventsCount = 0; } this._maxListeners = this._maxListeners || undefined; if (oc(opts, 'captureRejections')) { validateBoolean(opts.captureRejections, 'options.captureRejections'); this[kCapture] = Boolean(opts.captureRejections); } else { // Assigning the kCapture property directly saves an expensive // prototype lookup in a very sensitive hot path. this[kCapture] = EventEmitter.prototype[kCapture]; } }; function addCatch(that, promise, type, args) { if (!that[kCapture]) { return; } // Handle Promises/A+ spec, then could be a getter // that throws on second use. try { const then = promise.then; if (typeof then === 'function') { then.call(promise, undefined, function(err) { // The callback is called with nextTick to avoid a follow-up // rejection from this promise. process.nextTick(emitUnhandledRejectionOrErr, that, err, type, args); }); } } catch (err) { that.emit('error', err); } } function emitUnhandledRejectionOrErr(ee, err, type, args) { if (typeof ee[kRejection] === 'function') { ee[kRejection](err, type, ...args); } else { // We have to disable the capture rejections mechanism, otherwise // we might end up in an infinite loop. const prev = ee[kCapture]; // If the error handler throws, it is not catchable and it // will end up in 'uncaughtException'. We restore the previous // value of kCapture in case the uncaughtException is present // and the exception is handled. try { ee[kCapture] = false; ee.emit('error', err); } finally { ee[kCapture] = prev; } } } /** * Increases the max listeners of the event emitter. * @param {number} n * @returns {EventEmitter} */ EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) { throw new ERR_OUT_OF_RANGE('n', 'a non-negative number', n); } this._maxListeners = n; return this; }; function _getMaxListeners(that) { if (that._maxListeners === undefined) return EventEmitter.defaultMaxListeners; return that._maxListeners; } /** * Returns the current max listener value for the event emitter. * @returns {number} */ EventEmitter.prototype.getMaxListeners = function getMaxListeners() { return _getMaxListeners(this); }; /** * Synchronously calls each of the listeners registered * for the event. * @param {string | symbol} type * @param {...any} [args] * @returns {boolean} */ EventEmitter.prototype.emit = function emit(type, ...args) { let doError = (type === 'error'); const events = this._events; if (events !== undefined) { if (doError && events[kErrorMonitor] !== undefined) this.emit(kErrorMonitor, ...args); doError = (doError && events.error === undefined); } else if (!doError) return false; // If there is no 'error' event listener then throw. if (doError) { let er; if (args.length > 0) er = args[0]; if (er instanceof Error) { try { const capture = {}; ErrorCaptureStackTrace(capture, EventEmitter.prototype.emit); } catch (e) {} // Note: The comments on the `throw` lines are intentional, they show // up in Node's output if this results in an unhandled exception. throw er; // Unhandled 'error' event } let stringifiedEr; try { stringifiedEr = inspect(er); } catch (e) { stringifiedEr = er; } // At least give some kind of context to the user const err = new ERR_UNHANDLED_ERROR(stringifiedEr); err.context = er; throw err; // Unhandled 'error' event } const handler = events[type]; if (handler === undefined) return false; if (typeof handler === 'function') { const result = handler.apply(this, args); // We check if result is undefined first because that // is the most common case so we do not pay any perf // penalty if (result !== undefined && result !== null) { addCatch(this, result, type, args); } } else { const len = handler.length; const listeners = arrayClone(handler); for (let i = 0; i < len; ++i) { const result = listeners[i].apply(this, args); // We check if result is undefined first because that // is the most common case so we do not pay any perf // penalty. // This code is duplicated because extracting it away // would make it non-inlineable. if (result !== undefined && result !== null) { addCatch(this, result, type, args); } } } return true; }; function _addListener(target, type, listener, prepend) { let m; let events; let existing; checkListener(listener); events = target._events; if (events === undefined) { events = target._events = ObjectCreate(null); target._eventsCount = 0; } else { // To avoid recursion in the case that type === "newListener"! Before // adding it to the listeners, first emit "newListener". if (events.newListener !== undefined) { target.emit('newListener', type, nc(listener.listener, listener)); // Re-assign `events` because a newListener handler could have caused the // this._events to be assigned to a new object events = target._events; } existing = events[type]; } if (existing === undefined) { // Optimize the case of one listener. Don't need the extra array object. events[type] = listener; ++target._eventsCount; } else { if (typeof existing === 'function') { // Adding the second element, need to change to array. existing = events[type] = prepend ? [listener, existing] : [existing, listener]; // If we've already got an array, just append. } else if (prepend) { existing.unshift(listener); } else { existing.push(listener); } // Check for listener leak m = _getMaxListeners(target); if (m > 0 && existing.length > m && !existing.warned) { existing.warned = true; // No error code for this since it is a Warning // eslint-disable-next-line no-restricted-syntax const w = new Error('Possible EventEmitter memory leak detected. ' + `${existing.length} ${String(type)} listeners ` + `added to ${inspect(target, { depth: -1 })}. Use ` + 'emitter.setMaxListeners() to increase limit'); w.name = 'MaxListenersExceededWarning'; w.emitter = target; w.type = type; w.count = existing.length; process.emitWarning(w); } } return target; } /** * Adds a listener to the event emitter. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */ EventEmitter.prototype.addListener = function addListener(type, listener) { return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; /** * Adds the `listener` function to the beginning of * the listeners array. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */ EventEmitter.prototype.prependListener = function prependListener(type, listener) { return _addListener(this, type, listener, true); }; function onceWrapper() { if (!this.fired) { this.target.removeListener(this.type, this.wrapFn); this.fired = true; if (arguments.length === 0) return this.listener.call(this.target); return this.listener.apply(this.target, arguments); } } function _onceWrap(target, type, listener) { const state = { fired: false, wrapFn: undefined, target, type, listener }; const wrapped = onceWrapper.bind(state); wrapped.listener = listener; state.wrapFn = wrapped; return wrapped; } /** * Adds a one-time `listener` function to the event emitter. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */ EventEmitter.prototype.once = function once(type, listener) { checkListener(listener); this.on(type, _onceWrap(this, type, listener)); return this; }; /** * Adds a one-time `listener` function to the beginning of * the listeners array. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */ EventEmitter.prototype.prependOnceListener = function prependOnceListener(type, listener) { checkListener(listener); this.prependListener(type, _onceWrap(this, type, listener)); return this; }; /** * Removes the specified `listener` from the listeners array. * @param {string | symbol} type * @param {Function} listener * @returns {EventEmitter} */ EventEmitter.prototype.removeListener = function removeListener(type, listener) { checkListener(listener); const events = this._events; if (events === undefined) return this; const list = events[type]; if (list === undefined) return this; if (list === listener || list.listener === listener) { if (--this._eventsCount === 0) this._events = ObjectCreate(null); else { delete events[type]; if (events.removeListener) this.emit('removeListener', type, list.listener || listener); } } else if (typeof list !== 'function') { let position = -1; for (let i = list.length - 1; i >= 0; i--) { if (list[i] === listener || list[i].listener === listener) { position = i; break; } } if (position < 0) return this; if (position === 0) list.shift(); else { spliceOne(list, position); } if (list.length === 1) events[type] = list[0]; if (events.removeListener !== undefined) this.emit('removeListener', type, listener); } return this; }; EventEmitter.prototype.off = EventEmitter.prototype.removeListener; /** * Removes all listeners from the event emitter. (Only * removes listeners for a specific event name if specified * as `type`). * @param {string | symbol} [type] * @returns {EventEmitter} */ EventEmitter.prototype.removeAllListeners = function removeAllListeners(type) { const events = this._events; if (events === undefined) return this; // Not listening for removeListener, no need to emit if (events.removeListener === undefined) { if (arguments.length === 0) { this._events = ObjectCreate(null); this._eventsCount = 0; } else if (events[type] !== undefined) { if (--this._eventsCount === 0) this._events = ObjectCreate(null); else delete events[type]; } return this; } // Emit removeListener for all listeners on all events if (arguments.length === 0) { for (const key of ReflectOwnKeys(events)) { if (key === 'removeListener') continue; this.removeAllListeners(key); } this.removeAllListeners('removeListener'); this._events = ObjectCreate(null); this._eventsCount = 0; return this; } const listeners = events[type]; if (typeof listeners === 'function') { this.removeListener(type, listeners); } else if (listeners !== undefined) { // LIFO order for (let i = listeners.length - 1; i >= 0; i--) { this.removeListener(type, listeners[i]); } } return this; }; function _listeners(target, type, unwrap) { const events = target._events; if (events === undefined) return []; const evlistener = events[type]; if (evlistener === undefined) return []; if (typeof evlistener === 'function') return unwrap ? [evlistener.listener || evlistener] : [evlistener]; return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener); } /** * Returns a copy of the array of listeners for the event name * specified as `type`. * @param {string | symbol} type * @returns {Function[]} */ EventEmitter.prototype.listeners = function listeners(type) { return _listeners(this, type, true); }; /** * Returns a copy of the array of listeners and wrappers for * the event name specified as `type`. * @param {string | symbol} type * @returns {Function[]} */ EventEmitter.prototype.rawListeners = function rawListeners(type) { return _listeners(this, type, false); }; /** * Returns the number of listeners listening to the event name * specified as `type`. * @deprecated since v3.2.0 * @param {EventEmitter} emitter * @param {string | symbol} type * @returns {number} */ EventEmitter.listenerCount = function(emitter, type) { if (typeof emitter.listenerCount === 'function') { return emitter.listenerCount(type); } return emitter.listenerCount(type); }; EventEmitter.prototype.listenerCount = listenerCount; /** * Returns the number of listeners listening to event name * specified as `type`. * @param {string | symbol} type * @returns {number} */ function listenerCount(type) { const events = this._events; if (events !== undefined) { const evlistener = events[type]; if (typeof evlistener === 'function') { return 1; } else if (evlistener !== undefined) { return evlistener.length; } } return 0; } /** * Returns an array listing the events for which * the emitter has registered listeners. * @returns {any[]} */ EventEmitter.prototype.eventNames = function eventNames() { return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : []; }; function arrayClone(arr) { // At least since V8 8.3, this implementation is faster than the previous // which always used a simple for-loop switch (arr.length) { case 2: return [arr[0], arr[1]]; case 3: return [arr[0], arr[1], arr[2]]; case 4: return [arr[0], arr[1], arr[2], arr[3]]; case 5: return [arr[0], arr[1], arr[2], arr[3], arr[4]]; case 6: return [arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]]; } return ArrayPrototypeSlice(arr); } function unwrapListeners(arr) { const ret = arrayClone(arr); for (let i = 0; i < ret.length; ++i) { const orig = ret[i].listener; if (typeof orig === 'function') ret[i] = orig; } return ret; }