未验证 提交 81905a86 编写于 作者: C Chris Knight 提交者: GitHub

feat: Event emitter node polyfill (#3944)

上级 e1105a15
......@@ -16,7 +16,7 @@ deno standard library as it's a compatiblity module.
- [ ] crypto
- [ ] dgram
- [ ] dns
- [ ] events
- [x] events
- [x] fs _partly_
- [ ] http
- [ ] http2
......
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
// Copyright (c) 2019 Denolibs authors. All rights reserved. MIT license.
// 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.
import { validateIntegerRange } from "./util.ts";
export interface WrappedFunction extends Function {
listener: Function;
}
/**
* See also https://nodejs.org/api/events.html
*/
export default class EventEmitter {
public static defaultMaxListeners = 10;
private maxListeners: number | undefined;
private _events: Map<string | symbol, Array<Function | WrappedFunction>>;
public constructor() {
this._events = new Map();
}
private _addListener(
eventName: string | symbol,
listener: Function | WrappedFunction,
prepend: boolean
): this {
this.emit("newListener", eventName, listener);
if (this._events.has(eventName)) {
const listeners = this._events.get(eventName) as Array<
Function | WrappedFunction
>;
if (prepend) {
listeners.unshift(listener);
} else {
listeners.push(listener);
}
} else {
this._events.set(eventName, [listener]);
}
const max = this.getMaxListeners();
if (max > 0 && this.listenerCount(eventName) > max) {
const warning = new Error(
`Possible EventEmitter memory leak detected.
${this.listenerCount(eventName)} ${eventName.toString()} listeners.
Use emitter.setMaxListeners() to increase limit`
);
warning.name = "MaxListenersExceededWarning";
console.warn(warning);
}
return this;
}
/** Alias for emitter.on(eventName, listener). */
public addListener(
eventName: string | symbol,
listener: Function | WrappedFunction
): this {
return this._addListener(eventName, listener, false);
}
/**
* Synchronously calls each of the listeners registered for the event named
* eventName, in the order they were registered, passing the supplied
* arguments to each.
* @return true if the event had listeners, false otherwise
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
public emit(eventName: string | symbol, ...args: any[]): boolean {
if (this._events.has(eventName)) {
const listeners = (this._events.get(eventName) as Function[]).slice(); // We copy with slice() so array is not mutated during emit
for (const listener of listeners) {
try {
listener.apply(this, args);
} catch (err) {
this.emit("error", err);
}
}
return true;
} else if (eventName === "error") {
const errMsg = args.length > 0 ? args[0] : Error("Unhandled error.");
throw errMsg;
}
return false;
}
/**
* Returns an array listing the events for which the emitter has
* registered listeners.
*/
public eventNames(): [string | symbol] {
return Array.from(this._events.keys()) as [string | symbol];
}
/**
* Returns the current max listener value for the EventEmitter which is
* either set by emitter.setMaxListeners(n) or defaults to
* EventEmitter.defaultMaxListeners.
*/
public getMaxListeners(): number {
return this.maxListeners || EventEmitter.defaultMaxListeners;
}
/**
* Returns the number of listeners listening to the event named
* eventName.
*/
public listenerCount(eventName: string | symbol): number {
if (this._events.has(eventName)) {
return (this._events.get(eventName) as Function[]).length;
} else {
return 0;
}
}
private _listeners(
target: EventEmitter,
eventName: string | symbol,
unwrap: boolean
): Function[] {
if (!target._events.has(eventName)) {
return [];
}
const eventListeners: Function[] = target._events.get(
eventName
) as Function[];
return unwrap
? this.unwrapListeners(eventListeners)
: eventListeners.slice(0);
}
private unwrapListeners(arr: Function[]): Function[] {
const unwrappedListeners: Function[] = new Array(arr.length) as Function[];
for (let i = 0; i < arr.length; i++) {
unwrappedListeners[i] = arr[i]["listener"] || arr[i];
}
return unwrappedListeners;
}
/** Returns a copy of the array of listeners for the event named eventName.*/
public listeners(eventName: string | symbol): Function[] {
return this._listeners(this, eventName, true);
}
/**
* Returns a copy of the array of listeners for the event named eventName,
* including any wrappers (such as those created by .once()).
*/
public rawListeners(
eventName: string | symbol
): Array<Function | WrappedFunction> {
return this._listeners(this, eventName, false);
}
/** Alias for emitter.removeListener(). */
public off(eventName: string | symbol, listener: Function): this {
return this.removeListener(eventName, listener);
}
/**
* Adds the listener function to the end of the listeners array for the event
* named eventName. No checks are made to see if the listener has already
* been added. Multiple calls passing the same combination of eventName and
* listener will result in the listener being added, and called, multiple
* times.
*/
public on(
eventName: string | symbol,
listener: Function | WrappedFunction
): this {
return this.addListener(eventName, listener);
}
/**
* Adds a one-time listener function for the event named eventName. The next
* time eventName is triggered, this listener is removed and then invoked.
*/
public once(eventName: string | symbol, listener: Function): this {
const wrapped: WrappedFunction = this.onceWrap(eventName, listener);
this.on(eventName, wrapped);
return this;
}
// Wrapped function that calls EventEmitter.removeListener(eventName, self) on execution.
private onceWrap(
eventName: string | symbol,
listener: Function
): WrappedFunction {
const wrapper = function(
this: {
eventName: string | symbol;
listener: Function;
rawListener: Function;
context: EventEmitter;
},
...args: any[] // eslint-disable-line @typescript-eslint/no-explicit-any
): void {
this.context.removeListener(this.eventName, this.rawListener);
this.listener.apply(this.context, args);
};
const wrapperContext = {
eventName: eventName,
listener: listener,
rawListener: wrapper,
context: this
};
const wrapped = wrapper.bind(wrapperContext);
wrapperContext.rawListener = wrapped;
wrapped.listener = listener;
return wrapped as WrappedFunction;
}
/**
* Adds the listener function to the beginning of the listeners array for the
* event named eventName. No checks are made to see if the listener has
* already been added. Multiple calls passing the same combination of
* eventName and listener will result in the listener being added, and
* called, multiple times.
*/
public prependListener(
eventName: string | symbol,
listener: Function | WrappedFunction
): this {
return this._addListener(eventName, listener, true);
}
/**
* Adds a one-time listener function for the event named eventName to the
* beginning of the listeners array. The next time eventName is triggered,
* this listener is removed, and then invoked.
*/
public prependOnceListener(
eventName: string | symbol,
listener: Function
): this {
const wrapped: WrappedFunction = this.onceWrap(eventName, listener);
this.prependListener(eventName, wrapped);
return this;
}
/** Removes all listeners, or those of the specified eventName. */
public removeAllListeners(eventName?: string | symbol): this {
if (this._events === undefined) {
return this;
}
if (this._events.has(eventName)) {
const listeners = (this._events.get(eventName) as Array<
Function | WrappedFunction
>).slice(); // Create a copy; We use it AFTER it's deleted.
this._events.delete(eventName);
for (const listener of listeners) {
this.emit("removeListener", eventName, listener);
}
} else {
const eventList: [string | symbol] = this.eventNames();
eventList.map((value: string | symbol) => {
this.removeAllListeners(value);
});
}
return this;
}
/**
* Removes the specified listener from the listener array for the event
* named eventName.
*/
public removeListener(eventName: string | symbol, listener: Function): this {
if (this._events.has(eventName)) {
const arr: Array<Function | WrappedFunction> = this._events.get(
eventName
);
let listenerIndex = -1;
for (let i = arr.length - 1; i >= 0; i--) {
// arr[i]["listener"] is the reference to the listener inside a bound 'once' wrapper
if (arr[i] == listener || arr[i]["listener"] == listener) {
listenerIndex = i;
break;
}
}
if (listenerIndex >= 0) {
arr.splice(listenerIndex, 1);
this.emit("removeListener", eventName, listener);
if (arr.length === 0) {
this._events.delete(eventName);
}
}
}
return this;
}
/**
* By default EventEmitters will print a warning if more than 10 listeners
* are added for a particular event. This is a useful default that helps
* finding memory leaks. Obviously, not all events should be limited to just
* 10 listeners. The emitter.setMaxListeners() method allows the limit to be
* modified for this specific EventEmitter instance. The value can be set to
* Infinity (or 0) to indicate an unlimited number of listeners.
*/
public setMaxListeners(n: number): this {
validateIntegerRange(n, "maxListeners", 0);
this.maxListeners = n;
return this;
}
}
/**
* Creates a Promise that is fulfilled when the EventEmitter emits the given
* event or that is rejected when the EventEmitter emits 'error'. The Promise
* will resolve with an array of all the arguments emitted to the given event.
*/
export function once(
emitter: EventEmitter | EventTarget,
name: string
// eslint-disable-next-line @typescript-eslint/no-explicit-any
): Promise<any[]> {
return new Promise((resolve, reject) => {
if (emitter instanceof EventTarget) {
// EventTarget does not have `error` event semantics like Node
// EventEmitters, we do not listen to `error` events here.
emitter.addEventListener(
name,
(...args) => {
resolve(args);
},
{ once: true, passive: false, capture: false }
);
return;
} else if (emitter instanceof EventEmitter) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const eventListener = (...args: any[]): void => {
if (errorListener !== undefined) {
emitter.removeListener("error", errorListener);
}
resolve(args);
};
let errorListener: Function;
// Adding an error listener is not optional because
// if an error is thrown on an event emitter we cannot
// guarantee that the actual event we are waiting will
// be fired. The result could be a silent way to create
// memory or file descriptor leaks, which is something
// we should avoid.
if (name !== "error") {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
errorListener = (err: any): void => {
emitter.removeListener(name, eventListener);
reject(err);
};
emitter.once("error", errorListener);
}
emitter.once(name, eventListener);
return;
}
});
}
import { test } from "../testing/mod.ts";
import {
assert,
assertEquals,
fail,
assertThrows
} from "../testing/asserts.ts";
import EventEmitter, { WrappedFunction, once } from "./events.ts";
const shouldNeverBeEmitted: Function = () => {
fail("Should never be called");
};
test({
name:
'When adding a new event, "eventListener" event is fired before adding the listener',
fn() {
let eventsFired = [];
const testEmitter = new EventEmitter();
testEmitter.on("newListener", event => {
if (event !== "newListener") {
eventsFired.push("newListener");
}
});
testEmitter.on("event", () => {
eventsFired.push("event");
});
assertEquals(eventsFired, ["newListener"]);
eventsFired = [];
testEmitter.emit("event");
assertEquals(eventsFired, ["event"]);
}
});
test({
name:
'When removing a listenert, "removeListener" event is fired after removal',
fn() {
const eventsFired = [];
const testEmitter = new EventEmitter();
testEmitter.on("removeListener", () => {
eventsFired.push("removeListener");
});
const eventFunction = function(): void {
eventsFired.push("event");
};
testEmitter.on("event", eventFunction);
assertEquals(eventsFired, []);
testEmitter.removeListener("event", eventFunction);
assertEquals(eventsFired, ["removeListener"]);
}
});
test({
name:
"Default max listeners is 10, but can be changed by direct assignment only",
fn() {
assertEquals(EventEmitter.defaultMaxListeners, 10);
new EventEmitter().setMaxListeners(20);
assertEquals(EventEmitter.defaultMaxListeners, 10);
EventEmitter.defaultMaxListeners = 20;
assertEquals(EventEmitter.defaultMaxListeners, 20);
EventEmitter.defaultMaxListeners = 10; //reset back to original value
}
});
test({
name: "addListener adds a listener, and listener count is correct",
fn() {
const testEmitter = new EventEmitter();
testEmitter.on("event", shouldNeverBeEmitted);
assertEquals(1, testEmitter.listenerCount("event"));
testEmitter.on("event", shouldNeverBeEmitted);
assertEquals(2, testEmitter.listenerCount("event"));
}
});
test({
name: "Emitted events are called synchronously in the order they were added",
fn() {
const testEmitter = new EventEmitter();
const eventsFired = [];
testEmitter.on("event", oneArg => {
eventsFired.push("event(" + oneArg + ")");
});
testEmitter.on("event", (oneArg, twoArg) => {
eventsFired.push("event(" + oneArg + ", " + twoArg + ")");
});
testEmitter.on("non-event", shouldNeverBeEmitted);
testEmitter.on("event", (oneArg, twoArg, threeArg) => {
eventsFired.push(
"event(" + oneArg + ", " + twoArg + ", " + threeArg + ")"
);
});
testEmitter.emit("event", 1, 2, 3);
assertEquals(eventsFired, ["event(1)", "event(1, 2)", "event(1, 2, 3)"]);
}
});
test({
name: "Registered event names are returned as strings or Sybols",
fn() {
const testEmitter = new EventEmitter();
testEmitter.on("event", shouldNeverBeEmitted);
testEmitter.on("event", shouldNeverBeEmitted);
const sym = Symbol("symbol");
testEmitter.on(sym, shouldNeverBeEmitted);
assertEquals(testEmitter.eventNames(), ["event", sym]);
}
});
test({
name: "You can set and get max listeners",
fn() {
const testEmitter = new EventEmitter();
assertEquals(testEmitter.getMaxListeners(), 10);
testEmitter.setMaxListeners(20);
assertEquals(testEmitter.getMaxListeners(), 20);
}
});
test({
name: "You can retrieve registered functions for an event",
fn() {
const testEmitter = new EventEmitter();
testEmitter.on("someOtherEvent", shouldNeverBeEmitted);
testEmitter.on("event", shouldNeverBeEmitted);
const testFunction = (): void => {};
testEmitter.on("event", testFunction);
assertEquals(testEmitter.listeners("event"), [
shouldNeverBeEmitted,
testFunction
]);
}
});
test({
name: "Off is alias for removeListener",
fn() {
const testEmitter = new EventEmitter();
testEmitter.on("event", shouldNeverBeEmitted);
assertEquals(testEmitter.listenerCount("event"), 1);
testEmitter.off("event", shouldNeverBeEmitted);
assertEquals(testEmitter.listenerCount("event"), 0);
}
});
test({
name: "Event registration can be chained",
fn() {
const testEmitter = new EventEmitter();
testEmitter
.on("event", shouldNeverBeEmitted)
.on("event", shouldNeverBeEmitted);
assertEquals(testEmitter.listenerCount("event"), 2);
}
});
test({
name: "Events can be registered to only fire once",
fn() {
let eventsFired = [];
const testEmitter = new EventEmitter();
//prove multiple emits on same event first (when registered with 'on')
testEmitter.on("multiple event", () => {
eventsFired.push("multiple event");
});
testEmitter.emit("multiple event");
testEmitter.emit("multiple event");
assertEquals(eventsFired, ["multiple event", "multiple event"]);
//now prove multiple events registered via 'once' only emit once
eventsFired = [];
testEmitter.once("single event", () => {
eventsFired.push("single event");
});
testEmitter.emit("single event");
testEmitter.emit("single event");
assertEquals(eventsFired, ["single event"]);
}
});
test({
name:
"You can inject a listener into the start of the stack, rather than at the end",
fn() {
const eventsFired = [];
const testEmitter = new EventEmitter();
testEmitter.on("event", () => {
eventsFired.push("first");
});
testEmitter.on("event", () => {
eventsFired.push("second");
});
testEmitter.prependListener("event", () => {
eventsFired.push("third");
});
testEmitter.emit("event");
assertEquals(eventsFired, ["third", "first", "second"]);
}
});
test({
name: 'You can prepend a "once" listener',
fn() {
const eventsFired = [];
const testEmitter = new EventEmitter();
testEmitter.on("event", () => {
eventsFired.push("first");
});
testEmitter.on("event", () => {
eventsFired.push("second");
});
testEmitter.prependOnceListener("event", () => {
eventsFired.push("third");
});
testEmitter.emit("event");
testEmitter.emit("event");
assertEquals(eventsFired, ["third", "first", "second", "first", "second"]);
}
});
test({
name: "Remove all listeners, which can also be chained",
fn() {
const testEmitter = new EventEmitter();
testEmitter.on("event", shouldNeverBeEmitted);
testEmitter.on("event", shouldNeverBeEmitted);
testEmitter.on("other event", shouldNeverBeEmitted);
testEmitter.on("other event", shouldNeverBeEmitted);
testEmitter.once("other event", shouldNeverBeEmitted);
assertEquals(testEmitter.listenerCount("event"), 2);
assertEquals(testEmitter.listenerCount("other event"), 3);
testEmitter.removeAllListeners("event").removeAllListeners("other event");
assertEquals(testEmitter.listenerCount("event"), 0);
assertEquals(testEmitter.listenerCount("other event"), 0);
}
});
test({
name: "Remove individual listeners, which can also be chained",
fn() {
const testEmitter = new EventEmitter();
testEmitter.on("event", shouldNeverBeEmitted);
testEmitter.on("event", shouldNeverBeEmitted);
testEmitter.once("other event", shouldNeverBeEmitted);
assertEquals(testEmitter.listenerCount("event"), 2);
assertEquals(testEmitter.listenerCount("other event"), 1);
testEmitter.removeListener("other event", shouldNeverBeEmitted);
assertEquals(testEmitter.listenerCount("event"), 2);
assertEquals(testEmitter.listenerCount("other event"), 0);
testEmitter
.removeListener("event", shouldNeverBeEmitted)
.removeListener("event", shouldNeverBeEmitted);
assertEquals(testEmitter.listenerCount("event"), 0);
assertEquals(testEmitter.listenerCount("other event"), 0);
}
});
test({
name: "It is OK to try to remove non-existant listener",
fn() {
const testEmitter = new EventEmitter();
const madeUpEvent = (): void => {
fail("Should never be called");
};
testEmitter.on("event", shouldNeverBeEmitted);
assertEquals(testEmitter.listenerCount("event"), 1);
testEmitter.removeListener("event", madeUpEvent);
testEmitter.removeListener("non-existant event", madeUpEvent);
assertEquals(testEmitter.listenerCount("event"), 1);
}
});
test({
name: "all listeners complete execution even if removed before execution",
fn() {
const testEmitter = new EventEmitter();
let eventsProcessed = [];
const listenerB = (): number => eventsProcessed.push("B");
const listenerA = (): void => {
eventsProcessed.push("A");
testEmitter.removeListener("event", listenerB);
};
testEmitter.on("event", listenerA);
testEmitter.on("event", listenerB);
testEmitter.emit("event");
assertEquals(eventsProcessed, ["A", "B"]);
eventsProcessed = [];
testEmitter.emit("event");
assertEquals(eventsProcessed, ["A"]);
}
});
test({
name: 'Raw listener will return event listener or wrapped "once" function',
fn() {
const testEmitter = new EventEmitter();
const eventsProcessed = [];
const listenerA = (): number => eventsProcessed.push("A");
const listenerB = (): number => eventsProcessed.push("B");
testEmitter.on("event", listenerA);
testEmitter.once("once-event", listenerB);
const rawListenersForEvent = testEmitter.rawListeners("event");
const rawListenersForOnceEvent = testEmitter.rawListeners("once-event");
assertEquals(rawListenersForEvent.length, 1);
assertEquals(rawListenersForOnceEvent.length, 1);
assertEquals(rawListenersForEvent[0], listenerA);
assertEquals(
(rawListenersForOnceEvent[0] as WrappedFunction).listener,
listenerB
);
}
});
test({
name:
"Once wrapped raw listeners may be executed multiple times, until the wrapper is executed",
fn() {
const testEmitter = new EventEmitter();
let eventsProcessed = [];
const listenerA = (): number => eventsProcessed.push("A");
testEmitter.once("once-event", listenerA);
const rawListenersForOnceEvent = testEmitter.rawListeners("once-event");
const wrappedFn: WrappedFunction = rawListenersForOnceEvent[0] as WrappedFunction;
wrappedFn.listener();
wrappedFn.listener();
wrappedFn.listener();
assertEquals(eventsProcessed, ["A", "A", "A"]);
eventsProcessed = [];
wrappedFn(); // executing the wrapped listener function will remove it from the event
assertEquals(eventsProcessed, ["A"]);
assertEquals(testEmitter.listeners("once-event").length, 0);
}
});
test({
name: "Can add once event listener to EventEmitter via standalone function",
async fn() {
const ee: EventEmitter = new EventEmitter();
setTimeout(() => {
ee.emit("event", 42, "foo");
}, 0);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const valueArr: any[] = await once(ee, "event");
assertEquals(valueArr, [42, "foo"]);
}
});
test({
name: "Can add once event listener to EventTarget via standalone function",
async fn() {
const et: EventTarget = new EventTarget();
setTimeout(() => {
const event: Event = new Event("event", { composed: true });
et.dispatchEvent(event);
}, 0);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const eventObj: any[] = await once(et, "event");
assert(!eventObj[0].isTrusted);
}
});
test({
name: "Only valid integers are allowed for max listeners",
fn() {
const ee: EventEmitter = new EventEmitter();
ee.setMaxListeners(0);
assertThrows(
() => {
ee.setMaxListeners(-1);
},
Error,
"must be >= 0"
);
assertThrows(
() => {
ee.setMaxListeners(3.45);
},
Error,
"must be 'an integer'"
);
}
});
......@@ -26,6 +26,7 @@ import * as nodeUtil from "./util.ts";
import * as nodePath from "./path.ts";
import * as nodeTimers from "./timers.ts";
import * as nodeOs from "./os.ts";
import * as nodeEvents from "./events.ts";
import * as path from "../path/mod.ts";
import { assert } from "../testing/asserts.ts";
......@@ -579,11 +580,14 @@ function createNativeModule(id: string, exports: any): Module {
mod.loaded = true;
return mod;
}
nativeModulePolyfill.set("fs", createNativeModule("fs", nodeFS));
nativeModulePolyfill.set("util", createNativeModule("util", nodeUtil));
nativeModulePolyfill.set("events", createNativeModule("events", nodeEvents));
nativeModulePolyfill.set("os", createNativeModule("os", nodeOs));
nativeModulePolyfill.set("path", createNativeModule("path", nodePath));
nativeModulePolyfill.set("timers", createNativeModule("timers", nodeTimers));
nativeModulePolyfill.set("os", createNativeModule("os", nodeOs));
nativeModulePolyfill.set("util", createNativeModule("util", nodeUtil));
function loadNativeModule(
_filename: string,
request: string
......
......@@ -19,6 +19,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
import { notImplemented } from "./_utils.ts";
import { validateIntegerRange } from "./util.ts";
import { EOL as fsEOL } from "../fs/eol.ts";
const SEE_GITHUB_ISSUE = "See https://github.com/denoland/deno/issues/3802";
......@@ -117,7 +118,7 @@ export function freemem(): number {
/** Not yet implemented */
export function getPriority(pid = 0): number {
validateInt32(pid, "pid");
validateIntegerRange(pid, "pid");
notImplemented(SEE_GITHUB_ISSUE);
}
......@@ -162,8 +163,8 @@ export function setPriority(pid: number, priority?: number): void {
priority = pid;
pid = 0;
}
validateInt32(pid, "pid");
validateInt32(priority, "priority", -20, 19);
validateIntegerRange(pid, "pid");
validateIntegerRange(priority, "priority", -20, 19);
notImplemented(SEE_GITHUB_ISSUE);
}
......@@ -211,20 +212,3 @@ export const constants = {
};
export const EOL = Deno.build.os == "win" ? fsEOL.CRLF : fsEOL.LF;
const validateInt32 = (
value: number,
name: string,
min = -2147483648,
max = 2147483647
): void => {
// The defaults for min and max correspond to the limits of 32-bit integers.
if (!Number.isInteger(value)) {
throw new Error(`${name} must be 'an integer' but was ${value}`);
}
if (value < min || value > max) {
throw new Error(
`${name} must be >= ${min} && <= ${max}. Value was ${value}`
);
}
};
......@@ -45,3 +45,20 @@ export function isFunction(value: unknown): boolean {
export function isRegExp(value: unknown): boolean {
return value instanceof RegExp;
}
export function validateIntegerRange(
value: number,
name: string,
min = -2147483648,
max = 2147483647
): void {
// The defaults for min and max correspond to the limits of 32-bit integers.
if (!Number.isInteger(value)) {
throw new Error(`${name} must be 'an integer' but was ${value}`);
}
if (value < min || value > max) {
throw new Error(
`${name} must be >= ${min} && <= ${max}. Value was ${value}`
);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册