WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
import type { Type, TypeChecker } from 'typescript';
|
||||
import type { TypeOrValueSpecifier } from '../util';
|
||||
import { isTypeAnyType, isTypeNeverType } from '../util';
|
||||
type OptionTester = (type: Type, checker: TypeChecker, recursivelyCheckType: (type: Type) => boolean) => boolean;
|
||||
declare const optionTesters: {
|
||||
type: "Any" | "Array" | "Boolean" | "Never" | "Nullish" | "Number" | "RegExp";
|
||||
option: "allowAny" | "allowArray" | "allowBoolean" | "allowNever" | "allowNullish" | "allowNumber" | "allowRegExp";
|
||||
tester: OptionTester | typeof isTypeNeverType | typeof isTypeAnyType | ((type: Type, checker: TypeChecker, recursivelyCheckType: (type: Type) => boolean) => boolean) | ((type: Type, checker: TypeChecker) => boolean);
|
||||
}[];
|
||||
export type Options = [
|
||||
{
|
||||
allow?: TypeOrValueSpecifier[];
|
||||
} & Partial<Record<(typeof optionTesters)[number]['option'], boolean>>
|
||||
];
|
||||
export type MessageId = 'invalidType';
|
||||
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidType", Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag use of implied eval via setTimeout and setInterval
|
||||
* @author James Allardice
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const { getStaticValue } = require("@eslint-community/eslint-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "Disallow the use of `eval()`-like methods",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/no-implied-eval",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
impliedEval:
|
||||
"Implied eval. Consider passing a function instead of a string.",
|
||||
execScript: "Implied eval. Do not use execScript().",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const GLOBAL_CANDIDATES = Object.freeze([
|
||||
"global",
|
||||
"window",
|
||||
"globalThis",
|
||||
"self",
|
||||
]);
|
||||
const EVAL_LIKE_FUNC_PATTERN =
|
||||
/^(?:set(?:Interval|Timeout)|execScript)$/u;
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Checks whether a node is evaluated as a string or not.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @returns {boolean} True if the node is evaluated as a string.
|
||||
*/
|
||||
function isEvaluatedString(node) {
|
||||
if (
|
||||
(node.type === "Literal" && typeof node.value === "string") ||
|
||||
node.type === "TemplateLiteral"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (node.type === "BinaryExpression" && node.operator === "+") {
|
||||
return (
|
||||
isEvaluatedString(node.left) ||
|
||||
isEvaluatedString(node.right)
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports if the `CallExpression` node has evaluated argument.
|
||||
* @param {ASTNode} node A CallExpression to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportImpliedEvalCallExpression(node) {
|
||||
const [firstArgument] = node.arguments;
|
||||
|
||||
if (firstArgument) {
|
||||
const staticValue = getStaticValue(
|
||||
firstArgument,
|
||||
sourceCode.getScope(node),
|
||||
);
|
||||
const isStaticString =
|
||||
staticValue && typeof staticValue.value === "string";
|
||||
const isString =
|
||||
isStaticString || isEvaluatedString(firstArgument);
|
||||
|
||||
if (isString) {
|
||||
const calleeName =
|
||||
node.callee.type === "Identifier"
|
||||
? node.callee.name
|
||||
: astUtils.getStaticPropertyName(node.callee);
|
||||
const isExecScript = calleeName === "execScript";
|
||||
context.report({
|
||||
node,
|
||||
messageId: isExecScript ? "execScript" : "impliedEval",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports calls of `implied eval` via the global references.
|
||||
* @param {Variable} globalVar A global variable to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportImpliedEvalViaGlobal(globalVar) {
|
||||
const { references, name } = globalVar;
|
||||
|
||||
references.forEach(ref => {
|
||||
const identifier = ref.identifier;
|
||||
let node = identifier.parent;
|
||||
|
||||
while (astUtils.isSpecificMemberAccess(node, null, name)) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
if (
|
||||
astUtils.isSpecificMemberAccess(
|
||||
node,
|
||||
null,
|
||||
EVAL_LIKE_FUNC_PATTERN,
|
||||
)
|
||||
) {
|
||||
const calleeNode =
|
||||
node.parent.type === "ChainExpression"
|
||||
? node.parent
|
||||
: node;
|
||||
const parent = calleeNode.parent;
|
||||
|
||||
if (
|
||||
parent.type === "CallExpression" &&
|
||||
parent.callee === calleeNode
|
||||
) {
|
||||
reportImpliedEvalCallExpression(parent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (
|
||||
astUtils.isSpecificId(
|
||||
node.callee,
|
||||
EVAL_LIKE_FUNC_PATTERN,
|
||||
) &&
|
||||
sourceCode.isGlobalReference(node.callee)
|
||||
) {
|
||||
reportImpliedEvalCallExpression(node);
|
||||
}
|
||||
},
|
||||
"Program:exit"(node) {
|
||||
const globalScope = sourceCode.getScope(node);
|
||||
|
||||
GLOBAL_CANDIDATES.map(candidate =>
|
||||
astUtils.getVariableByName(globalScope, candidate),
|
||||
)
|
||||
.filter(
|
||||
globalVar => !!globalVar && globalVar.defs.length === 0,
|
||||
)
|
||||
.forEach(reportImpliedEvalViaGlobal);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "../../cjs/_wrap_reg_exp.cjs",
|
||||
"module": "../../esm/_wrap_reg_exp.js"
|
||||
}
|
||||
@@ -0,0 +1,938 @@
|
||||
'use strict';
|
||||
|
||||
var WebSocketImpl = require('ws');
|
||||
var eventemitter3 = require('eventemitter3');
|
||||
var url = require('url');
|
||||
var uuid = require('uuid');
|
||||
|
||||
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
||||
|
||||
var WebSocketImpl__default = /*#__PURE__*/_interopDefault(WebSocketImpl);
|
||||
var url__default = /*#__PURE__*/_interopDefault(url);
|
||||
|
||||
// src/lib/client/websocket.ts
|
||||
function WebSocket(address, options) {
|
||||
return new WebSocketImpl__default.default(address, options);
|
||||
}
|
||||
|
||||
// src/lib/utils.ts
|
||||
var DefaultDataPack = class {
|
||||
encode(value) {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
decode(value) {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
};
|
||||
|
||||
// src/lib/client.ts
|
||||
var CommonClient = class extends eventemitter3.EventEmitter {
|
||||
address;
|
||||
rpc_id;
|
||||
queue;
|
||||
options;
|
||||
autoconnect;
|
||||
ready;
|
||||
reconnect;
|
||||
reconnect_timer_id;
|
||||
reconnect_interval;
|
||||
max_reconnects;
|
||||
rest_options;
|
||||
current_reconnects;
|
||||
generate_request_id;
|
||||
socket;
|
||||
webSocketFactory;
|
||||
dataPack;
|
||||
/**
|
||||
* Instantiate a Client class.
|
||||
* @constructor
|
||||
* @param {webSocketFactory} webSocketFactory - factory method for WebSocket
|
||||
* @param {String} address - url to a websocket server
|
||||
* @param {Object} options - ws options object with reconnect parameters
|
||||
* @param {Function} generate_request_id - custom generation request Id
|
||||
* @param {DataPack} dataPack - data pack contains encoder and decoder
|
||||
* @return {CommonClient}
|
||||
*/
|
||||
constructor(webSocketFactory, address = "ws://localhost:8080", {
|
||||
autoconnect = true,
|
||||
reconnect = true,
|
||||
reconnect_interval = 1e3,
|
||||
max_reconnects = 5,
|
||||
...rest_options
|
||||
} = {}, generate_request_id, dataPack) {
|
||||
super();
|
||||
this.webSocketFactory = webSocketFactory;
|
||||
this.queue = {};
|
||||
this.rpc_id = 0;
|
||||
this.address = address;
|
||||
this.autoconnect = autoconnect;
|
||||
this.ready = false;
|
||||
this.reconnect = reconnect;
|
||||
this.reconnect_timer_id = void 0;
|
||||
this.reconnect_interval = reconnect_interval;
|
||||
this.max_reconnects = max_reconnects;
|
||||
this.rest_options = rest_options;
|
||||
this.current_reconnects = 0;
|
||||
this.generate_request_id = generate_request_id || (() => typeof this.rpc_id === "number" ? ++this.rpc_id : Number(this.rpc_id) + 1);
|
||||
if (!dataPack) this.dataPack = new DefaultDataPack();
|
||||
else this.dataPack = dataPack;
|
||||
if (this.autoconnect)
|
||||
this._connect(this.address, {
|
||||
autoconnect: this.autoconnect,
|
||||
reconnect: this.reconnect,
|
||||
reconnect_interval: this.reconnect_interval,
|
||||
max_reconnects: this.max_reconnects,
|
||||
...this.rest_options
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Connects to a defined server if not connected already.
|
||||
* @method
|
||||
* @return {Undefined}
|
||||
*/
|
||||
connect() {
|
||||
if (this.socket) return;
|
||||
this._connect(this.address, {
|
||||
autoconnect: this.autoconnect,
|
||||
reconnect: this.reconnect,
|
||||
reconnect_interval: this.reconnect_interval,
|
||||
max_reconnects: this.max_reconnects,
|
||||
...this.rest_options
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Calls a registered RPC method on server.
|
||||
* @method
|
||||
* @param {String} method - RPC method name
|
||||
* @param {Object|Array} params - optional method parameters
|
||||
* @param {Number} timeout - RPC reply timeout value
|
||||
* @param {Object} ws_opts - options passed to ws
|
||||
* @return {Promise}
|
||||
*/
|
||||
call(method, params, timeout, ws_opts) {
|
||||
if (!ws_opts && "object" === typeof timeout) {
|
||||
ws_opts = timeout;
|
||||
timeout = null;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.ready) return reject(new Error("socket not ready"));
|
||||
const rpc_id = this.generate_request_id(method, params);
|
||||
const message = {
|
||||
jsonrpc: "2.0",
|
||||
method,
|
||||
params: params || void 0,
|
||||
id: rpc_id
|
||||
};
|
||||
this.socket.send(this.dataPack.encode(message), ws_opts, (error) => {
|
||||
if (error) return reject(error);
|
||||
this.queue[rpc_id] = { promise: [resolve, reject] };
|
||||
if (timeout) {
|
||||
this.queue[rpc_id].timeout = setTimeout(() => {
|
||||
delete this.queue[rpc_id];
|
||||
reject(new Error("reply timeout"));
|
||||
}, timeout);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Logins with the other side of the connection.
|
||||
* @method
|
||||
* @param {Object} params - Login credentials object
|
||||
* @return {Promise}
|
||||
*/
|
||||
async login(params) {
|
||||
const resp = await this.call("rpc.login", params);
|
||||
if (!resp) throw new Error("authentication failed");
|
||||
return resp;
|
||||
}
|
||||
/**
|
||||
* Fetches a list of client's methods registered on server.
|
||||
* @method
|
||||
* @return {Array}
|
||||
*/
|
||||
async listMethods() {
|
||||
return await this.call("__listMethods");
|
||||
}
|
||||
/**
|
||||
* Sends a JSON-RPC 2.0 notification to server.
|
||||
* @method
|
||||
* @param {String} method - RPC method name
|
||||
* @param {Object} params - optional method parameters
|
||||
* @return {Promise}
|
||||
*/
|
||||
notify(method, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.ready) return reject(new Error("socket not ready"));
|
||||
const message = {
|
||||
jsonrpc: "2.0",
|
||||
method,
|
||||
params
|
||||
};
|
||||
this.socket.send(this.dataPack.encode(message), (error) => {
|
||||
if (error) return reject(error);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Subscribes for a defined event.
|
||||
* @method
|
||||
* @param {String|Array} event - event name
|
||||
* @return {Undefined}
|
||||
* @throws {Error}
|
||||
*/
|
||||
async subscribe(event) {
|
||||
if (typeof event === "string") event = [event];
|
||||
const result = await this.call("rpc.on", event);
|
||||
if (typeof event === "string" && result[event] !== "ok")
|
||||
throw new Error(
|
||||
"Failed subscribing to an event '" + event + "' with: " + result[event]
|
||||
);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Unsubscribes from a defined event.
|
||||
* @method
|
||||
* @param {String|Array} event - event name
|
||||
* @return {Undefined}
|
||||
* @throws {Error}
|
||||
*/
|
||||
async unsubscribe(event) {
|
||||
if (typeof event === "string") event = [event];
|
||||
const result = await this.call("rpc.off", event);
|
||||
if (typeof event === "string" && result[event] !== "ok")
|
||||
throw new Error("Failed unsubscribing from an event with: " + result);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Closes a WebSocket connection gracefully.
|
||||
* @method
|
||||
* @param {Number} code - socket close code
|
||||
* @param {String} data - optional data to be sent before closing
|
||||
* @return {Undefined}
|
||||
*/
|
||||
close(code, data) {
|
||||
if (this.socket) this.socket.close(code || 1e3, data);
|
||||
}
|
||||
/**
|
||||
* Enable / disable automatic reconnection.
|
||||
* @method
|
||||
* @param {Boolean} reconnect - enable / disable reconnection
|
||||
* @return {Undefined}
|
||||
*/
|
||||
setAutoReconnect(reconnect) {
|
||||
this.reconnect = reconnect;
|
||||
}
|
||||
/**
|
||||
* Set the interval between reconnection attempts.
|
||||
* @method
|
||||
* @param {Number} interval - reconnection interval in milliseconds
|
||||
* @return {Undefined}
|
||||
*/
|
||||
setReconnectInterval(interval) {
|
||||
this.reconnect_interval = interval;
|
||||
}
|
||||
/**
|
||||
* Set the maximum number of reconnection attempts.
|
||||
* @method
|
||||
* @param {Number} max_reconnects - maximum reconnection attempts
|
||||
* @return {Undefined}
|
||||
*/
|
||||
setMaxReconnects(max_reconnects) {
|
||||
this.max_reconnects = max_reconnects;
|
||||
}
|
||||
/**
|
||||
* Get the current number of reconnection attempts made.
|
||||
* @method
|
||||
* @return {Number} current reconnection attempts
|
||||
*/
|
||||
getCurrentReconnects() {
|
||||
return this.current_reconnects;
|
||||
}
|
||||
/**
|
||||
* Get the maximum number of reconnection attempts.
|
||||
* @method
|
||||
* @return {Number} maximum reconnection attempts
|
||||
*/
|
||||
getMaxReconnects() {
|
||||
return this.max_reconnects;
|
||||
}
|
||||
/**
|
||||
* Check if the client is currently attempting to reconnect.
|
||||
* @method
|
||||
* @return {Boolean} true if reconnection is in progress
|
||||
*/
|
||||
isReconnecting() {
|
||||
return this.reconnect_timer_id !== void 0;
|
||||
}
|
||||
/**
|
||||
* Check if the client will attempt to reconnect on the next close event.
|
||||
* @method
|
||||
* @return {Boolean} true if reconnection will be attempted
|
||||
*/
|
||||
willReconnect() {
|
||||
return this.reconnect && (this.max_reconnects === 0 || this.current_reconnects < this.max_reconnects);
|
||||
}
|
||||
/**
|
||||
* Connection/Message handler.
|
||||
* @method
|
||||
* @private
|
||||
* @param {String} address - WebSocket API address
|
||||
* @param {Object} options - ws options object
|
||||
* @return {Undefined}
|
||||
*/
|
||||
_connect(address, options) {
|
||||
clearTimeout(this.reconnect_timer_id);
|
||||
this.socket = this.webSocketFactory(address, options);
|
||||
this.socket.addEventListener("open", () => {
|
||||
this.ready = true;
|
||||
this.emit("open");
|
||||
this.current_reconnects = 0;
|
||||
});
|
||||
this.socket.addEventListener("message", ({ data: message }) => {
|
||||
if (message instanceof ArrayBuffer)
|
||||
message = Buffer.from(message).toString();
|
||||
try {
|
||||
message = this.dataPack.decode(message);
|
||||
} catch (_error) {
|
||||
return;
|
||||
}
|
||||
if (message.notification && this.listeners(message.notification).length) {
|
||||
if (!Object.keys(message.params).length)
|
||||
return this.emit(message.notification);
|
||||
const args = [message.notification];
|
||||
if (message.params.constructor === Object) args.push(message.params);
|
||||
else
|
||||
for (let i = 0; i < message.params.length; i++)
|
||||
args.push(message.params[i]);
|
||||
return Promise.resolve().then(() => {
|
||||
this.emit.apply(this, args);
|
||||
});
|
||||
}
|
||||
if (!this.queue[message.id]) {
|
||||
if (message.method) {
|
||||
return Promise.resolve().then(() => {
|
||||
this.emit(message.method, message?.params);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ("error" in message === "result" in message)
|
||||
this.queue[message.id].promise[1](
|
||||
new Error(
|
||||
'Server response malformed. Response must include either "result" or "error", but not both.'
|
||||
)
|
||||
);
|
||||
if (this.queue[message.id].timeout)
|
||||
clearTimeout(this.queue[message.id].timeout);
|
||||
if (message.error) this.queue[message.id].promise[1](message.error);
|
||||
else this.queue[message.id].promise[0](message.result);
|
||||
delete this.queue[message.id];
|
||||
});
|
||||
this.socket.addEventListener("error", (error) => this.emit("error", error));
|
||||
this.socket.addEventListener("close", ({ code, reason }) => {
|
||||
if (this.ready)
|
||||
setTimeout(() => this.emit("close", code, reason), 0);
|
||||
this.ready = false;
|
||||
this.socket = void 0;
|
||||
if (code === 1e3) return;
|
||||
this.current_reconnects++;
|
||||
if (this.reconnect && (this.max_reconnects > this.current_reconnects || this.max_reconnects === 0))
|
||||
this.reconnect_timer_id = setTimeout(
|
||||
() => this._connect(address, options),
|
||||
this.reconnect_interval
|
||||
);
|
||||
else if (this.reconnect && this.max_reconnects > 0 && this.current_reconnects >= this.max_reconnects) {
|
||||
setTimeout(() => this.emit("max_reconnects_reached", code, reason), 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
var Server = class extends eventemitter3.EventEmitter {
|
||||
namespaces;
|
||||
dataPack;
|
||||
wss;
|
||||
/**
|
||||
* Instantiate a Server class.
|
||||
* @constructor
|
||||
* @param {Object} options - ws constructor's parameters with rpc
|
||||
* @param {DataPack} dataPack - data pack contains encoder and decoder
|
||||
* @return {Server} - returns a new Server instance
|
||||
*/
|
||||
constructor(options, dataPack) {
|
||||
super();
|
||||
this.namespaces = {};
|
||||
if (!dataPack) this.dataPack = new DefaultDataPack();
|
||||
else this.dataPack = dataPack;
|
||||
this.wss = new WebSocketImpl.WebSocketServer(options);
|
||||
this.wss.on("listening", () => this.emit("listening"));
|
||||
this.wss.on("connection", (socket, request) => {
|
||||
const u = url__default.default.parse(request.url, true);
|
||||
const ns = u.pathname;
|
||||
if (u.query.socket_id) socket._id = u.query.socket_id;
|
||||
else socket._id = uuid.v1();
|
||||
socket["_authenticated"] = false;
|
||||
socket.on("error", (error) => this.emit("socket-error", socket, error));
|
||||
socket.on("close", () => {
|
||||
this.namespaces[ns].clients.delete(socket._id);
|
||||
for (const event of Object.keys(this.namespaces[ns].events)) {
|
||||
const index = this.namespaces[ns].events[event].sockets.indexOf(
|
||||
socket._id
|
||||
);
|
||||
if (index >= 0)
|
||||
this.namespaces[ns].events[event].sockets.splice(index, 1);
|
||||
}
|
||||
this.emit("disconnection", socket);
|
||||
});
|
||||
if (!this.namespaces[ns]) this._generateNamespace(ns);
|
||||
this.namespaces[ns].clients.set(socket._id, socket);
|
||||
this.emit("connection", socket, request);
|
||||
return this._handleRPC(socket, ns);
|
||||
});
|
||||
this.wss.on("error", (error) => this.emit("error", error));
|
||||
}
|
||||
/**
|
||||
* Registers an RPC method.
|
||||
* @method
|
||||
* @param {String} name - method name
|
||||
* @param {Function} fn - a callee function
|
||||
* @param {String} ns - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Object} - returns an IMethod object
|
||||
*/
|
||||
register(name, fn, ns = "/") {
|
||||
if (!this.namespaces[ns]) this._generateNamespace(ns);
|
||||
this.namespaces[ns].rpc_methods[name] = {
|
||||
fn,
|
||||
protected: false
|
||||
};
|
||||
return {
|
||||
protected: () => this._makeProtectedMethod(name, ns),
|
||||
public: () => this._makePublicMethod(name, ns)
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Sets an auth method.
|
||||
* @method
|
||||
* @param {Function} fn - an arbitrary auth method
|
||||
* @param {String} ns - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Undefined}
|
||||
*/
|
||||
setAuth(fn, ns = "/") {
|
||||
this.register("rpc.login", fn, ns);
|
||||
}
|
||||
/**
|
||||
* Marks an RPC method as protected.
|
||||
* @method
|
||||
* @param {String} name - method name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
_makeProtectedMethod(name, ns = "/") {
|
||||
this.namespaces[ns].rpc_methods[name].protected = true;
|
||||
}
|
||||
/**
|
||||
* Marks an RPC method as public.
|
||||
* @method
|
||||
* @param {String} name - method name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
_makePublicMethod(name, ns = "/") {
|
||||
this.namespaces[ns].rpc_methods[name].protected = false;
|
||||
}
|
||||
/**
|
||||
* Marks an event as protected.
|
||||
* @method
|
||||
* @param {String} name - event name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
_makeProtectedEvent(name, ns = "/") {
|
||||
this.namespaces[ns].events[name].protected = true;
|
||||
}
|
||||
/**
|
||||
* Marks an event as public.
|
||||
* @method
|
||||
* @param {String} name - event name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
_makePublicEvent(name, ns = "/") {
|
||||
this.namespaces[ns].events[name].protected = false;
|
||||
}
|
||||
/**
|
||||
* Removes a namespace and closes all connections
|
||||
* @method
|
||||
* @param {String} ns - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Undefined}
|
||||
*/
|
||||
closeNamespace(ns) {
|
||||
const namespace = this.namespaces[ns];
|
||||
if (namespace) {
|
||||
delete namespace.rpc_methods;
|
||||
delete namespace.events;
|
||||
for (const socket of namespace.clients.values()) socket.close();
|
||||
delete this.namespaces[ns];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates a new event that can be emitted to clients.
|
||||
* @method
|
||||
* @param {String} name - event name
|
||||
* @param {String} ns - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Object} - returns an IEvent object
|
||||
*/
|
||||
event(name, ns = "/") {
|
||||
if (!this.namespaces[ns]) this._generateNamespace(ns);
|
||||
else {
|
||||
const index = this.namespaces[ns].events[name];
|
||||
if (index !== void 0)
|
||||
throw new Error(`Already registered event ${ns}${name}`);
|
||||
}
|
||||
this.namespaces[ns].events[name] = {
|
||||
sockets: [],
|
||||
protected: false
|
||||
};
|
||||
this.on(name, (...params) => {
|
||||
if (params.length === 1 && params[0] instanceof Object)
|
||||
params = params[0];
|
||||
for (const socket_id of this.namespaces[ns].events[name].sockets) {
|
||||
const socket = this.namespaces[ns].clients.get(socket_id);
|
||||
if (!socket) continue;
|
||||
socket.send(
|
||||
this.dataPack.encode({
|
||||
notification: name,
|
||||
params
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
return {
|
||||
protected: () => this._makeProtectedEvent(name, ns),
|
||||
public: () => this._makePublicEvent(name, ns)
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Returns a requested namespace object
|
||||
* @method
|
||||
* @param {String} name - namespace identifier
|
||||
* @throws {TypeError}
|
||||
* @return {Object} - namespace object
|
||||
*/
|
||||
of(name) {
|
||||
if (!this.namespaces[name]) this._generateNamespace(name);
|
||||
const self = this;
|
||||
return {
|
||||
// self.register convenience method
|
||||
register(fn_name, fn) {
|
||||
if (arguments.length !== 2)
|
||||
throw new Error("must provide exactly two arguments");
|
||||
if (typeof fn_name !== "string")
|
||||
throw new Error("name must be a string");
|
||||
if (typeof fn !== "function")
|
||||
throw new Error("handler must be a function");
|
||||
return self.register(fn_name, fn, name);
|
||||
},
|
||||
// self.event convenience method
|
||||
event(ev_name) {
|
||||
if (arguments.length !== 1)
|
||||
throw new Error("must provide exactly one argument");
|
||||
if (typeof ev_name !== "string")
|
||||
throw new Error("name must be a string");
|
||||
return self.event(ev_name, name);
|
||||
},
|
||||
// self.eventList convenience method
|
||||
get eventList() {
|
||||
return Object.keys(self.namespaces[name].events);
|
||||
},
|
||||
/**
|
||||
* Emits a specified event to this namespace.
|
||||
* @inner
|
||||
* @method
|
||||
* @param {String} event - event name
|
||||
* @param {Array} params - event parameters
|
||||
* @return {Undefined}
|
||||
*/
|
||||
emit(event, ...params) {
|
||||
const nsEvent = self.namespaces[name].events[event];
|
||||
if (nsEvent)
|
||||
for (const socket_id of nsEvent.sockets) {
|
||||
const socket = self.namespaces[name].clients.get(socket_id);
|
||||
if (!socket) continue;
|
||||
socket.send(
|
||||
self.dataPack.encode({
|
||||
notification: event,
|
||||
params
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Returns a name of this namespace.
|
||||
* @inner
|
||||
* @method
|
||||
* @kind constant
|
||||
* @return {String}
|
||||
*/
|
||||
get name() {
|
||||
return name;
|
||||
},
|
||||
/**
|
||||
* Returns a hash of websocket objects connected to this namespace.
|
||||
* @inner
|
||||
* @method
|
||||
* @return {Object}
|
||||
*/
|
||||
connected() {
|
||||
const socket_ids = [...self.namespaces[name].clients.keys()];
|
||||
return socket_ids.reduce(
|
||||
(acc, curr) => ({
|
||||
...acc,
|
||||
[curr]: self.namespaces[name].clients.get(curr)
|
||||
}),
|
||||
{}
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Returns a list of client unique identifiers connected to this namespace.
|
||||
* @inner
|
||||
* @method
|
||||
* @return {Array}
|
||||
*/
|
||||
clients() {
|
||||
return self.namespaces[name];
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Lists all created events in a given namespace. Defaults to "/".
|
||||
* @method
|
||||
* @param {String} ns - namespaces identifier
|
||||
* @readonly
|
||||
* @return {Array} - returns a list of created events
|
||||
*/
|
||||
eventList(ns = "/") {
|
||||
if (!this.namespaces[ns]) return [];
|
||||
return Object.keys(this.namespaces[ns].events);
|
||||
}
|
||||
/**
|
||||
* Creates a JSON-RPC 2.0 compliant error
|
||||
* @method
|
||||
* @param {Number} code - indicates the error type that occurred
|
||||
* @param {String} message - provides a short description of the error
|
||||
* @param {String|Object} data - details containing additional information about the error
|
||||
* @return {Object}
|
||||
*/
|
||||
createError(code, message, data) {
|
||||
return {
|
||||
code,
|
||||
message,
|
||||
data: data || null
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Closes the server and terminates all clients.
|
||||
* @method
|
||||
* @return {Promise}
|
||||
*/
|
||||
close() {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
this.wss.close();
|
||||
this.emit("close");
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Handles all WebSocket JSON RPC 2.0 requests.
|
||||
* @private
|
||||
* @param {Object} socket - ws socket instance
|
||||
* @param {String} ns - namespaces identifier
|
||||
* @return {Undefined}
|
||||
*/
|
||||
_handleRPC(socket, ns = "/") {
|
||||
socket.on("message", async (data) => {
|
||||
const msg_options = {};
|
||||
if (data instanceof ArrayBuffer) {
|
||||
msg_options.binary = true;
|
||||
data = Buffer.from(data).toString();
|
||||
}
|
||||
if (socket.readyState !== 1) return;
|
||||
let parsedData;
|
||||
try {
|
||||
parsedData = this.dataPack.decode(data);
|
||||
} catch (error) {
|
||||
return socket.send(
|
||||
this.dataPack.encode({
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32700, error.toString()),
|
||||
id: null
|
||||
}),
|
||||
msg_options
|
||||
);
|
||||
}
|
||||
if (Array.isArray(parsedData)) {
|
||||
if (!parsedData.length)
|
||||
return socket.send(
|
||||
this.dataPack.encode({
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32600, "Invalid array"),
|
||||
id: null
|
||||
}),
|
||||
msg_options
|
||||
);
|
||||
const responses = [];
|
||||
for (const message of parsedData) {
|
||||
const response2 = await this._runMethod(message, socket._id, ns);
|
||||
if (!response2) continue;
|
||||
responses.push(response2);
|
||||
}
|
||||
if (!responses.length) return;
|
||||
return socket.send(this.dataPack.encode(responses), msg_options);
|
||||
}
|
||||
const response = await this._runMethod(parsedData, socket._id, ns);
|
||||
if (!response) return;
|
||||
return socket.send(this.dataPack.encode(response), msg_options);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Runs a defined RPC method.
|
||||
* @private
|
||||
* @param {Object} message - a message received
|
||||
* @param {Object} socket_id - user's socket id
|
||||
* @param {String} ns - namespaces identifier
|
||||
* @return {Object|undefined}
|
||||
*/
|
||||
async _runMethod(message, socket_id, ns = "/") {
|
||||
if (typeof message !== "object" || message === null)
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32600),
|
||||
id: null
|
||||
};
|
||||
if (message.jsonrpc !== "2.0")
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32600, "Invalid JSON RPC version"),
|
||||
id: message.id || null
|
||||
};
|
||||
if (!message.method)
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32602, "Method not specified"),
|
||||
id: message.id || null
|
||||
};
|
||||
if (typeof message.method !== "string")
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32600, "Invalid method name"),
|
||||
id: message.id || null
|
||||
};
|
||||
if (message.params && typeof message.params === "string")
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32600),
|
||||
id: message.id || null
|
||||
};
|
||||
if (message.method === "rpc.on") {
|
||||
if (!message.params)
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32e3),
|
||||
id: message.id || null
|
||||
};
|
||||
const results = {};
|
||||
const event_names = Object.keys(this.namespaces[ns].events);
|
||||
for (const name of message.params) {
|
||||
const index = event_names.indexOf(name);
|
||||
const namespace = this.namespaces[ns];
|
||||
if (index === -1) {
|
||||
results[name] = "provided event invalid";
|
||||
continue;
|
||||
}
|
||||
if (namespace.events[event_names[index]].protected === true && namespace.clients.get(socket_id)["_authenticated"] === false) {
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32606),
|
||||
id: message.id || null
|
||||
};
|
||||
}
|
||||
const socket_index = namespace.events[event_names[index]].sockets.indexOf(socket_id);
|
||||
if (socket_index >= 0) {
|
||||
results[name] = "socket has already been subscribed to event";
|
||||
continue;
|
||||
}
|
||||
namespace.events[event_names[index]].sockets.push(socket_id);
|
||||
results[name] = "ok";
|
||||
}
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
result: results,
|
||||
id: message.id || null
|
||||
};
|
||||
} else if (message.method === "rpc.off") {
|
||||
if (!message.params)
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32e3),
|
||||
id: message.id || null
|
||||
};
|
||||
const results = {};
|
||||
for (const name of message.params) {
|
||||
if (!this.namespaces[ns].events[name]) {
|
||||
results[name] = "provided event invalid";
|
||||
continue;
|
||||
}
|
||||
const index = this.namespaces[ns].events[name].sockets.indexOf(socket_id);
|
||||
if (index === -1) {
|
||||
results[name] = "not subscribed";
|
||||
continue;
|
||||
}
|
||||
this.namespaces[ns].events[name].sockets.splice(index, 1);
|
||||
results[name] = "ok";
|
||||
}
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
result: results,
|
||||
id: message.id || null
|
||||
};
|
||||
} else if (message.method === "rpc.login") {
|
||||
if (!message.params)
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32604),
|
||||
id: message.id || null
|
||||
};
|
||||
}
|
||||
if (!this.namespaces[ns].rpc_methods[message.method]) {
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32601),
|
||||
id: message.id || null
|
||||
};
|
||||
}
|
||||
let response = null;
|
||||
if (this.namespaces[ns].rpc_methods[message.method].protected === true && this.namespaces[ns].clients.get(socket_id)["_authenticated"] === false) {
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: createError(-32605),
|
||||
id: message.id || null
|
||||
};
|
||||
}
|
||||
try {
|
||||
response = await this.namespaces[ns].rpc_methods[message.method].fn(
|
||||
message.params,
|
||||
socket_id
|
||||
);
|
||||
} catch (error) {
|
||||
if (!message.id) return;
|
||||
if (error instanceof Error)
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error: {
|
||||
code: -32e3,
|
||||
message: error.name,
|
||||
data: error.message
|
||||
},
|
||||
id: message.id
|
||||
};
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
error,
|
||||
id: message.id
|
||||
};
|
||||
}
|
||||
if (!message.id) return;
|
||||
if (message.method === "rpc.login" && response === true) {
|
||||
const s = this.namespaces[ns].clients.get(socket_id);
|
||||
if (s) {
|
||||
s["_authenticated"] = true;
|
||||
this.namespaces[ns].clients.set(socket_id, s);
|
||||
}
|
||||
}
|
||||
return {
|
||||
jsonrpc: "2.0",
|
||||
result: response,
|
||||
id: message.id
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Generate a new namespace store.
|
||||
* Also preregister some special namespace methods.
|
||||
* @private
|
||||
* @param {String} name - namespaces identifier
|
||||
* @return {undefined}
|
||||
*/
|
||||
_generateNamespace(name) {
|
||||
this.namespaces[name] = {
|
||||
rpc_methods: {
|
||||
__listMethods: {
|
||||
fn: () => Object.keys(this.namespaces[name].rpc_methods),
|
||||
protected: false
|
||||
}
|
||||
},
|
||||
clients: /* @__PURE__ */ new Map(),
|
||||
events: {}
|
||||
};
|
||||
}
|
||||
};
|
||||
var RPC_ERRORS = /* @__PURE__ */ new Map([
|
||||
[-32e3, "Event not provided"],
|
||||
[-32600, "Invalid Request"],
|
||||
[-32601, "Method not found"],
|
||||
[-32602, "Invalid params"],
|
||||
[-32603, "Internal error"],
|
||||
[-32604, "Params not found"],
|
||||
[-32605, "Method forbidden"],
|
||||
[-32606, "Event forbidden"],
|
||||
[-32700, "Parse error"]
|
||||
]);
|
||||
function createError(code, details) {
|
||||
const error = {
|
||||
code,
|
||||
message: RPC_ERRORS.get(code) || "Internal Server Error"
|
||||
};
|
||||
if (details) error["data"] = details;
|
||||
return error;
|
||||
}
|
||||
|
||||
// src/index.ts
|
||||
var Client = class extends CommonClient {
|
||||
constructor(address = "ws://localhost:8080", {
|
||||
autoconnect = true,
|
||||
reconnect = true,
|
||||
reconnect_interval = 1e3,
|
||||
max_reconnects = 5,
|
||||
...rest_options
|
||||
} = {}, generate_request_id) {
|
||||
super(
|
||||
WebSocket,
|
||||
address,
|
||||
{
|
||||
autoconnect,
|
||||
reconnect,
|
||||
reconnect_interval,
|
||||
max_reconnects,
|
||||
...rest_options
|
||||
},
|
||||
generate_request_id
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
exports.Client = Client;
|
||||
exports.CommonClient = CommonClient;
|
||||
exports.DefaultDataPack = DefaultDataPack;
|
||||
exports.Server = Server;
|
||||
exports.WebSocket = WebSocket;
|
||||
exports.createError = createError;
|
||||
//# sourceMappingURL=index.cjs.map
|
||||
//# sourceMappingURL=index.cjs.map
|
||||
@@ -0,0 +1,12 @@
|
||||
import type { TSESLint } from '@typescript-eslint/utils';
|
||||
export type Options = [
|
||||
{
|
||||
checkLiteralConstAssertions?: boolean;
|
||||
typesToIgnore?: string[];
|
||||
}
|
||||
];
|
||||
export type MessageIds = 'contextuallyUnnecessary' | 'unnecessaryAssertion';
|
||||
declare const _default: TSESLint.RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,367 @@
|
||||
/**
|
||||
* @fileoverview Restrict usage of duplicate imports.
|
||||
* @author Simen Bekkhus
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const NAMED_TYPES = ["ImportSpecifier", "ExportSpecifier"];
|
||||
const NAMESPACE_TYPES = [
|
||||
"ImportNamespaceSpecifier",
|
||||
"ExportNamespaceSpecifier",
|
||||
];
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Check if an import/export type belongs to (ImportSpecifier|ExportSpecifier) or (ImportNamespaceSpecifier|ExportNamespaceSpecifier).
|
||||
* @param {string} importExportType An import/export type to check.
|
||||
* @param {string} type Can be "named" or "namespace"
|
||||
* @returns {boolean} `true` if import/export type belongs to (ImportSpecifier|ExportSpecifier) or (ImportNamespaceSpecifier|ExportNamespaceSpecifier) and `false` if it doesn't.
|
||||
*/
|
||||
function isImportExportSpecifier(importExportType, type) {
|
||||
const arrayToCheck = type === "named" ? NAMED_TYPES : NAMESPACE_TYPES;
|
||||
|
||||
return arrayToCheck.includes(importExportType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of (import|export).
|
||||
* @param {ASTNode} node A node to get.
|
||||
* @returns {string} The type of the (import|export).
|
||||
*/
|
||||
function getImportExportType(node) {
|
||||
if (node.specifiers && node.specifiers.length > 0) {
|
||||
const nodeSpecifiers = node.specifiers;
|
||||
const index = nodeSpecifiers.findIndex(
|
||||
({ type }) =>
|
||||
isImportExportSpecifier(type, "named") ||
|
||||
isImportExportSpecifier(type, "namespace"),
|
||||
);
|
||||
const i = index > -1 ? index : 0;
|
||||
|
||||
return nodeSpecifiers[i].type;
|
||||
}
|
||||
if (node.type === "ExportAllDeclaration") {
|
||||
if (node.exported) {
|
||||
return "ExportNamespaceSpecifier";
|
||||
}
|
||||
return "ExportAll";
|
||||
}
|
||||
return "SideEffectImport";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean indicates if two (import|export) can be merged
|
||||
* @param {ASTNode} node1 A node to check.
|
||||
* @param {ASTNode} node2 A node to check.
|
||||
* @returns {boolean} `true` if two (import|export) can be merged, `false` if they can't.
|
||||
*/
|
||||
function isImportExportCanBeMerged(node1, node2) {
|
||||
const importExportType1 = getImportExportType(node1);
|
||||
const importExportType2 = getImportExportType(node2);
|
||||
|
||||
if (
|
||||
(node1.importKind === "type" || node1.exportKind === "type") &&
|
||||
(node2.importKind === "type" || node2.exportKind === "type")
|
||||
) {
|
||||
const isDefault1 = importExportType1 === "ImportDefaultSpecifier";
|
||||
const isDefault2 = importExportType2 === "ImportDefaultSpecifier";
|
||||
const isNamed1 = isImportExportSpecifier(importExportType1, "named");
|
||||
const isNamed2 = isImportExportSpecifier(importExportType2, "named");
|
||||
|
||||
if ((isDefault1 && isNamed2) || (isDefault2 && isNamed1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(importExportType1 === "ExportAll" &&
|
||||
importExportType2 !== "ExportAll" &&
|
||||
importExportType2 !== "SideEffectImport") ||
|
||||
(importExportType1 !== "ExportAll" &&
|
||||
importExportType1 !== "SideEffectImport" &&
|
||||
importExportType2 === "ExportAll")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
(isImportExportSpecifier(importExportType1, "namespace") &&
|
||||
isImportExportSpecifier(importExportType2, "named")) ||
|
||||
(isImportExportSpecifier(importExportType2, "namespace") &&
|
||||
isImportExportSpecifier(importExportType1, "named"))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean if we should report (import|export).
|
||||
* @param {ASTNode} node A node to be reported or not.
|
||||
* @param {[ASTNode]} previousNodes An array contains previous nodes of the module imported or exported.
|
||||
* @param {boolean} allowSeparateTypeImports Whether to allow separate type and value imports.
|
||||
* @returns {boolean} `true` if the (import|export) should be reported.
|
||||
*/
|
||||
function shouldReportImportExport(
|
||||
node,
|
||||
previousNodes,
|
||||
allowSeparateTypeImports,
|
||||
) {
|
||||
let i = 0;
|
||||
|
||||
while (i < previousNodes.length) {
|
||||
const previousNode = previousNodes[i];
|
||||
|
||||
if (allowSeparateTypeImports) {
|
||||
const isTypeNode =
|
||||
node.importKind === "type" || node.exportKind === "type";
|
||||
const isTypePrevious =
|
||||
previousNode.importKind === "type" ||
|
||||
previousNode.exportKind === "type";
|
||||
|
||||
if (isTypeNode !== isTypePrevious) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isImportExportCanBeMerged(node, previousNode)) {
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns array contains only nodes with declarations types equal to type.
|
||||
* @param {[{node: ASTNode, declarationType: string}]} nodes An array contains objects, each object contains a node and a declaration type.
|
||||
* @param {string} type Declaration type.
|
||||
* @returns {[ASTNode]} An array contains only nodes with declarations types equal to type.
|
||||
*/
|
||||
function getNodesByDeclarationType(nodes, type) {
|
||||
return nodes
|
||||
.filter(({ declarationType }) => declarationType === type)
|
||||
.map(({ node }) => node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the module imported or re-exported.
|
||||
* @param {ASTNode} node A node to get.
|
||||
* @returns {string} The name of the module, or empty string if no name.
|
||||
*/
|
||||
function getModule(node) {
|
||||
if (node && node.source && node.source.value) {
|
||||
return node.source.value.trim();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the (import|export) can be merged with at least one import or one export, and reports if so.
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {ASTNode} node A node to get.
|
||||
* @param {Map} modules A Map object contains as a key a module name and as value an array contains objects, each object contains a node and a declaration type.
|
||||
* @param {string} declarationType A declaration type can be an import or export.
|
||||
* @param {boolean} includeExports Whether or not to check for exports in addition to imports.
|
||||
* @param {boolean} allowSeparateTypeImports Whether to allow separate type and value imports.
|
||||
* @returns {void} No return value.
|
||||
*/
|
||||
function checkAndReport(
|
||||
context,
|
||||
node,
|
||||
modules,
|
||||
declarationType,
|
||||
includeExports,
|
||||
allowSeparateTypeImports,
|
||||
) {
|
||||
const module = getModule(node);
|
||||
|
||||
if (modules.has(module)) {
|
||||
const previousNodes = modules.get(module);
|
||||
const messagesIds = [];
|
||||
const importNodes = getNodesByDeclarationType(previousNodes, "import");
|
||||
let exportNodes;
|
||||
|
||||
if (includeExports) {
|
||||
exportNodes = getNodesByDeclarationType(previousNodes, "export");
|
||||
}
|
||||
if (declarationType === "import") {
|
||||
if (
|
||||
shouldReportImportExport(
|
||||
node,
|
||||
importNodes,
|
||||
allowSeparateTypeImports,
|
||||
)
|
||||
) {
|
||||
messagesIds.push("import");
|
||||
}
|
||||
if (includeExports) {
|
||||
if (
|
||||
shouldReportImportExport(
|
||||
node,
|
||||
exportNodes,
|
||||
allowSeparateTypeImports,
|
||||
)
|
||||
) {
|
||||
messagesIds.push("importAs");
|
||||
}
|
||||
}
|
||||
} else if (declarationType === "export") {
|
||||
if (
|
||||
shouldReportImportExport(
|
||||
node,
|
||||
exportNodes,
|
||||
allowSeparateTypeImports,
|
||||
)
|
||||
) {
|
||||
messagesIds.push("export");
|
||||
}
|
||||
if (
|
||||
shouldReportImportExport(
|
||||
node,
|
||||
importNodes,
|
||||
allowSeparateTypeImports,
|
||||
)
|
||||
) {
|
||||
messagesIds.push("exportAs");
|
||||
}
|
||||
}
|
||||
messagesIds.forEach(messageId =>
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
data: {
|
||||
module,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @callback nodeCallback
|
||||
* @param {ASTNode} node A node to handle.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns a function handling the (imports|exports) of a given file
|
||||
* @param {RuleContext} context The ESLint rule context object.
|
||||
* @param {Map} modules A Map object contains as a key a module name and as value an array contains objects, each object contains a node and a declaration type.
|
||||
* @param {string} declarationType A declaration type can be an import or export.
|
||||
* @param {boolean} includeExports Whether or not to check for exports in addition to imports.
|
||||
* @param {boolean} allowSeparateTypeImports Whether to allow separate type and value imports.
|
||||
* @returns {nodeCallback} A function passed to ESLint to handle the statement.
|
||||
*/
|
||||
function handleImportsExports(
|
||||
context,
|
||||
modules,
|
||||
declarationType,
|
||||
includeExports,
|
||||
allowSeparateTypeImports,
|
||||
) {
|
||||
return function (node) {
|
||||
const module = getModule(node);
|
||||
|
||||
if (module) {
|
||||
checkAndReport(
|
||||
context,
|
||||
node,
|
||||
modules,
|
||||
declarationType,
|
||||
includeExports,
|
||||
allowSeparateTypeImports,
|
||||
);
|
||||
const currentNode = { node, declarationType };
|
||||
let nodes = [currentNode];
|
||||
|
||||
if (modules.has(module)) {
|
||||
const previousNodes = modules.get(module);
|
||||
|
||||
nodes = [...previousNodes, currentNode];
|
||||
}
|
||||
modules.set(module, nodes);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
includeExports: false,
|
||||
allowSeparateTypeImports: false,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description: "Disallow duplicate module imports",
|
||||
dialects: ["JavaScript", "TypeScript"],
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/no-duplicate-imports",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
includeExports: {
|
||||
type: "boolean",
|
||||
},
|
||||
allowSeparateTypeImports: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
import: "'{{module}}' import is duplicated.",
|
||||
importAs: "'{{module}}' import is duplicated as export.",
|
||||
export: "'{{module}}' export is duplicated.",
|
||||
exportAs: "'{{module}}' export is duplicated as import.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [{ includeExports, allowSeparateTypeImports }] = context.options;
|
||||
const modules = new Map();
|
||||
const handlers = {
|
||||
ImportDeclaration: handleImportsExports(
|
||||
context,
|
||||
modules,
|
||||
"import",
|
||||
includeExports,
|
||||
allowSeparateTypeImports,
|
||||
),
|
||||
};
|
||||
|
||||
if (includeExports) {
|
||||
handlers.ExportNamedDeclaration = handleImportsExports(
|
||||
context,
|
||||
modules,
|
||||
"export",
|
||||
includeExports,
|
||||
allowSeparateTypeImports,
|
||||
);
|
||||
handlers.ExportAllDeclaration = handleImportsExports(
|
||||
context,
|
||||
modules,
|
||||
"export",
|
||||
includeExports,
|
||||
allowSeparateTypeImports,
|
||||
);
|
||||
}
|
||||
return handlers;
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
|
||||
// npx nx generate-lib repo
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.es2022_object = void 0;
|
||||
const base_config_1 = require("./base-config");
|
||||
exports.es2022_object = {
|
||||
libs: [],
|
||||
variables: [['ObjectConstructor', base_config_1.TYPE]],
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
import type { ZodErrorMap } from "./ZodError.cjs";
|
||||
import defaultErrorMap from "./locales/en.cjs";
|
||||
export { defaultErrorMap };
|
||||
export declare function setErrorMap(map: ZodErrorMap): void;
|
||||
export declare function getErrorMap(): ZodErrorMap;
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "pg-protocol",
|
||||
"version": "1.16.0",
|
||||
"description": "The postgres client/server binary protocol, implemented in TypeScript",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./esm/index.js",
|
||||
"require": "./dist/index.js",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./dist/*": "./dist/*.js",
|
||||
"./dist/*.js": "./dist/*.js"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.2.7",
|
||||
"@types/mocha": "^10.0.10",
|
||||
"@types/node": "^16",
|
||||
"chai": "^4.2.0",
|
||||
"mocha": "^11.7.5",
|
||||
"ts-node": "^8.5.4",
|
||||
"typescript": "^6.0.3"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha dist/**/*.test.js",
|
||||
"build": "tsc",
|
||||
"build:watch": "tsc --watch",
|
||||
"prepublish": "yarn build",
|
||||
"pretest": "yarn build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/brianc/node-postgres.git",
|
||||
"directory": "packages/pg-protocol"
|
||||
},
|
||||
"files": [
|
||||
"/dist/*{js,ts,map}",
|
||||
"/src",
|
||||
"/esm"
|
||||
],
|
||||
"gitHead": "df274d1ba9ad9d11a8f1079314faeafde7208207"
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
const bufLength = 1024 * 16;
|
||||
|
||||
// Provide a fallback for older environments.
|
||||
const td =
|
||||
typeof TextDecoder !== 'undefined'
|
||||
? /* #__PURE__ */ new TextDecoder()
|
||||
: typeof Buffer !== 'undefined'
|
||||
? {
|
||||
decode(buf: Uint8Array): string {
|
||||
const out = Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength);
|
||||
return out.toString();
|
||||
},
|
||||
}
|
||||
: {
|
||||
decode(buf: Uint8Array): string {
|
||||
let out = '';
|
||||
for (let i = 0; i < buf.length; i++) {
|
||||
out += String.fromCharCode(buf[i]);
|
||||
}
|
||||
return out;
|
||||
},
|
||||
};
|
||||
|
||||
export class StringWriter {
|
||||
pos = 0;
|
||||
private out = '';
|
||||
private buffer = new Uint8Array(bufLength);
|
||||
|
||||
write(v: number): void {
|
||||
const { buffer } = this;
|
||||
buffer[this.pos++] = v;
|
||||
if (this.pos === bufLength) {
|
||||
this.out += td.decode(buffer);
|
||||
this.pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
flush(): string {
|
||||
const { buffer, out, pos } = this;
|
||||
return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;
|
||||
}
|
||||
}
|
||||
|
||||
export class StringReader {
|
||||
pos = 0;
|
||||
declare private buffer: string;
|
||||
|
||||
constructor(buffer: string) {
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
next(): number {
|
||||
return this.buffer.charCodeAt(this.pos++);
|
||||
}
|
||||
|
||||
peek(): number {
|
||||
return this.buffer.charCodeAt(this.pos);
|
||||
}
|
||||
|
||||
indexOf(char: string): number {
|
||||
const { buffer, pos } = this;
|
||||
const idx = buffer.indexOf(char, pos);
|
||||
return idx === -1 ? buffer.length : idx;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const isObject = require('./is-object')
|
||||
|
||||
test('returns correct answer', t => {
|
||||
t.assert.strictEqual(isObject({}), true)
|
||||
t.assert.strictEqual(isObject([]), false)
|
||||
t.assert.strictEqual(isObject(42), false)
|
||||
})
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Ruben Bridgewater
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,10 @@
|
||||
function _objectWithoutPropertiesLoose(r, e) {
|
||||
if (null == r) return {};
|
||||
var t = {};
|
||||
for (var n in r) if ({}.hasOwnProperty.call(r, n)) {
|
||||
if (-1 !== e.indexOf(n)) continue;
|
||||
t[n] = r[n];
|
||||
}
|
||||
return t;
|
||||
}
|
||||
export { _objectWithoutPropertiesLoose as default };
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
import type { LibDefinition } from '../variable';
|
||||
export declare const es2015_symbol_wellknown: LibDefinition;
|
||||
@@ -0,0 +1,119 @@
|
||||
import type { $ZodStringFormats } from "../core/checks.js";
|
||||
import type * as errors from "../core/errors.js";
|
||||
import * as util from "../core/util.js";
|
||||
|
||||
const error: () => errors.$ZodErrorMap = () => {
|
||||
const Sizable: Record<string, { unit: string; verb: string }> = {
|
||||
string: { unit: "tecken", verb: "att ha" },
|
||||
file: { unit: "bytes", verb: "att ha" },
|
||||
array: { unit: "objekt", verb: "att innehålla" },
|
||||
set: { unit: "objekt", verb: "att innehålla" },
|
||||
};
|
||||
|
||||
function getSizing(origin: string): { unit: string; verb: string } | null {
|
||||
return Sizable[origin] ?? null;
|
||||
}
|
||||
|
||||
const FormatDictionary: {
|
||||
[k in $ZodStringFormats | (string & {})]?: string;
|
||||
} = {
|
||||
regex: "reguljärt uttryck",
|
||||
email: "e-postadress",
|
||||
url: "URL",
|
||||
emoji: "emoji",
|
||||
uuid: "UUID",
|
||||
uuidv4: "UUIDv4",
|
||||
uuidv6: "UUIDv6",
|
||||
nanoid: "nanoid",
|
||||
guid: "GUID",
|
||||
cuid: "cuid",
|
||||
cuid2: "cuid2",
|
||||
ulid: "ULID",
|
||||
xid: "XID",
|
||||
ksuid: "KSUID",
|
||||
datetime: "ISO-datum och tid",
|
||||
date: "ISO-datum",
|
||||
time: "ISO-tid",
|
||||
duration: "ISO-varaktighet",
|
||||
ipv4: "IPv4-intervall",
|
||||
ipv6: "IPv6-intervall",
|
||||
cidrv4: "IPv4-spektrum",
|
||||
cidrv6: "IPv6-spektrum",
|
||||
base64: "base64-kodad sträng",
|
||||
base64url: "base64url-kodad sträng",
|
||||
json_string: "JSON-sträng",
|
||||
e164: "E.164-nummer",
|
||||
jwt: "JWT",
|
||||
template_literal: "mall-literal",
|
||||
};
|
||||
|
||||
const TypeDictionary: {
|
||||
[k in errors.$ZodInvalidTypeExpected | (string & {})]?: string;
|
||||
} = {
|
||||
nan: "NaN",
|
||||
number: "antal",
|
||||
array: "lista",
|
||||
};
|
||||
|
||||
return (issue) => {
|
||||
switch (issue.code) {
|
||||
case "invalid_type": {
|
||||
const expected = TypeDictionary[issue.expected] ?? issue.expected;
|
||||
const receivedType = util.parsedType(issue.input);
|
||||
const received = TypeDictionary[receivedType] ?? receivedType;
|
||||
if (/^[A-Z]/.test(issue.expected)) {
|
||||
return `Ogiltig inmatning: förväntat instanceof ${issue.expected}, fick ${received}`;
|
||||
}
|
||||
return `Ogiltig inmatning: förväntat ${expected}, fick ${received}`;
|
||||
}
|
||||
case "invalid_value":
|
||||
if (issue.values.length === 1)
|
||||
return `Ogiltig inmatning: förväntat ${util.stringifyPrimitive(issue.values[0])}`;
|
||||
return `Ogiltigt val: förväntade en av ${util.joinValues(issue.values, "|")}`;
|
||||
case "too_big": {
|
||||
const adj = issue.inclusive ? "<=" : "<";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing) {
|
||||
return `För stor(t): förväntade ${issue.origin ?? "värdet"} att ha ${adj}${issue.maximum.toString()} ${sizing.unit ?? "element"}`;
|
||||
}
|
||||
return `För stor(t): förväntat ${issue.origin ?? "värdet"} att ha ${adj}${issue.maximum.toString()}`;
|
||||
}
|
||||
case "too_small": {
|
||||
const adj = issue.inclusive ? ">=" : ">";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing) {
|
||||
return `För lite(t): förväntade ${issue.origin ?? "värdet"} att ha ${adj}${issue.minimum.toString()} ${sizing.unit}`;
|
||||
}
|
||||
return `För lite(t): förväntade ${issue.origin ?? "värdet"} att ha ${adj}${issue.minimum.toString()}`;
|
||||
}
|
||||
case "invalid_format": {
|
||||
const _issue = issue as errors.$ZodStringFormatIssues;
|
||||
if (_issue.format === "starts_with") {
|
||||
return `Ogiltig sträng: måste börja med "${_issue.prefix}"`;
|
||||
}
|
||||
if (_issue.format === "ends_with") return `Ogiltig sträng: måste sluta med "${_issue.suffix}"`;
|
||||
if (_issue.format === "includes") return `Ogiltig sträng: måste innehålla "${_issue.includes}"`;
|
||||
if (_issue.format === "regex") return `Ogiltig sträng: måste matcha mönstret "${_issue.pattern}"`;
|
||||
return `Ogiltig(t) ${FormatDictionary[_issue.format] ?? issue.format}`;
|
||||
}
|
||||
case "not_multiple_of":
|
||||
return `Ogiltigt tal: måste vara en multipel av ${issue.divisor}`;
|
||||
case "unrecognized_keys":
|
||||
return `${issue.keys.length > 1 ? "Okända nycklar" : "Okänd nyckel"}: ${util.joinValues(issue.keys, ", ")}`;
|
||||
case "invalid_key":
|
||||
return `Ogiltig nyckel i ${issue.origin ?? "värdet"}`;
|
||||
case "invalid_union":
|
||||
return "Ogiltig input";
|
||||
case "invalid_element":
|
||||
return `Ogiltigt värde i ${issue.origin ?? "värdet"}`;
|
||||
default:
|
||||
return `Ogiltig input`;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default function (): { localeError: errors.$ZodErrorMap } {
|
||||
return {
|
||||
localeError: error(),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"pad-codec.d.ts","sourceRoot":"","sources":["../../src/pad-codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAM1D,KAAK,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AAE/B,KAAK,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AAE/B,KAAK,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAS,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAKvG;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,QAAQ,SAAS,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAKxG;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,QAAQ,SAAS,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAKvG;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,QAAQ,SAAS,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAKxG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,YAAY,CAAC,MAAM,SAAS,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE3F;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,aAAa,CAAC,MAAM,SAAS,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE5F"}
|
||||
@@ -0,0 +1,2 @@
|
||||
export declare var TypePredicateKind: any;
|
||||
//# sourceMappingURL=typePredicateKind.d.ts.map
|
||||
@@ -0,0 +1,11 @@
|
||||
var superPropBase = require("./superPropBase.js");
|
||||
function _get() {
|
||||
return module.exports = _get = "undefined" != typeof Reflect && Reflect.get ? Reflect.get.bind() : function (e, t, r) {
|
||||
var p = superPropBase(e, t);
|
||||
if (p) {
|
||||
var n = Object.getOwnPropertyDescriptor(p, t);
|
||||
return n.get ? n.get.call(arguments.length < 3 ? e : r) : n.value;
|
||||
}
|
||||
}, module.exports.__esModule = true, module.exports["default"] = module.exports, _get.apply(null, arguments);
|
||||
}
|
||||
module.exports = _get, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,27 @@
|
||||
import Pool from './pool'
|
||||
import MockAgent from './mock-agent'
|
||||
import { Interceptable, MockInterceptor } from './mock-interceptor'
|
||||
import Dispatcher from './dispatcher'
|
||||
|
||||
export default MockPool
|
||||
|
||||
/** MockPool extends the Pool API and allows one to mock requests. */
|
||||
declare class MockPool extends Pool implements Interceptable {
|
||||
constructor (origin: string, options: MockPool.Options)
|
||||
/** Intercepts any matching requests that use the same origin as this mock pool. */
|
||||
intercept (options: MockInterceptor.Options): MockInterceptor
|
||||
/** Dispatches a mocked request. */
|
||||
dispatch (options: Dispatcher.DispatchOptions, handlers: Dispatcher.DispatchHandler): boolean
|
||||
/** Closes the mock pool and gracefully waits for enqueued requests to complete. */
|
||||
close (): Promise<void>
|
||||
/** Clean up all the prepared mocks. */
|
||||
cleanMocks (): void
|
||||
}
|
||||
|
||||
declare namespace MockPool {
|
||||
/** MockPool options. */
|
||||
export interface Options extends Pool.Options {
|
||||
/** The agent to associate this MockPool with. */
|
||||
agent: MockAgent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isPromiseAggregatorMethod = isPromiseAggregatorMethod;
|
||||
const type_utils_1 = require("@typescript-eslint/type-utils");
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const misc_1 = require("./misc");
|
||||
const PROMISE_CONSTRUCTOR_ARRAY_METHODS = new Set([
|
||||
'all',
|
||||
'allSettled',
|
||||
'race',
|
||||
'any',
|
||||
]);
|
||||
function isPromiseAggregatorMethod(context, services, node) {
|
||||
if (node.callee.type !== utils_1.AST_NODE_TYPES.MemberExpression) {
|
||||
return false;
|
||||
}
|
||||
const staticAccessValue = (0, misc_1.getStaticMemberAccessValue)(node.callee, context);
|
||||
if (!PROMISE_CONSTRUCTOR_ARRAY_METHODS.has(staticAccessValue)) {
|
||||
return false;
|
||||
}
|
||||
return (0, type_utils_1.isPromiseConstructorLike)(services.program, (0, type_utils_1.getConstrainedTypeAtLocation)(services, node.callee.object));
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// @ts-ignore TS6133
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
import * as z from "zod/v3";
|
||||
|
||||
const gtFive = z.bigint().gt(BigInt(5));
|
||||
const gteFive = z.bigint().gte(BigInt(5));
|
||||
const ltFive = z.bigint().lt(BigInt(5));
|
||||
const lteFive = z.bigint().lte(BigInt(5));
|
||||
const positive = z.bigint().positive();
|
||||
const negative = z.bigint().negative();
|
||||
const nonnegative = z.bigint().nonnegative();
|
||||
const nonpositive = z.bigint().nonpositive();
|
||||
const multipleOfFive = z.bigint().multipleOf(BigInt(5));
|
||||
|
||||
test("passing validations", () => {
|
||||
z.bigint().parse(BigInt(1));
|
||||
z.bigint().parse(BigInt(0));
|
||||
z.bigint().parse(BigInt(-1));
|
||||
gtFive.parse(BigInt(6));
|
||||
gteFive.parse(BigInt(5));
|
||||
gteFive.parse(BigInt(6));
|
||||
ltFive.parse(BigInt(4));
|
||||
lteFive.parse(BigInt(5));
|
||||
lteFive.parse(BigInt(4));
|
||||
positive.parse(BigInt(3));
|
||||
negative.parse(BigInt(-2));
|
||||
nonnegative.parse(BigInt(0));
|
||||
nonnegative.parse(BigInt(7));
|
||||
nonpositive.parse(BigInt(0));
|
||||
nonpositive.parse(BigInt(-12));
|
||||
multipleOfFive.parse(BigInt(15));
|
||||
});
|
||||
|
||||
test("failing validations", () => {
|
||||
expect(() => gtFive.parse(BigInt(5))).toThrow();
|
||||
expect(() => gteFive.parse(BigInt(4))).toThrow();
|
||||
expect(() => ltFive.parse(BigInt(5))).toThrow();
|
||||
expect(() => lteFive.parse(BigInt(6))).toThrow();
|
||||
expect(() => positive.parse(BigInt(0))).toThrow();
|
||||
expect(() => positive.parse(BigInt(-2))).toThrow();
|
||||
expect(() => negative.parse(BigInt(0))).toThrow();
|
||||
expect(() => negative.parse(BigInt(3))).toThrow();
|
||||
expect(() => nonnegative.parse(BigInt(-1))).toThrow();
|
||||
expect(() => nonpositive.parse(BigInt(1))).toThrow();
|
||||
expect(() => multipleOfFive.parse(BigInt(13))).toThrow();
|
||||
});
|
||||
|
||||
test("min max getters", () => {
|
||||
expect(z.bigint().min(BigInt(5)).minValue).toEqual(BigInt(5));
|
||||
expect(z.bigint().min(BigInt(5)).min(BigInt(10)).minValue).toEqual(BigInt(10));
|
||||
|
||||
expect(z.bigint().max(BigInt(5)).maxValue).toEqual(BigInt(5));
|
||||
expect(z.bigint().max(BigInt(5)).max(BigInt(1)).maxValue).toEqual(BigInt(1));
|
||||
});
|
||||
Reference in New Issue
Block a user