WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
// Generated by LiveScript 1.6.0
|
||||
(function(){
|
||||
var reject, special, tokenRegex;
|
||||
reject = require('prelude-ls').reject;
|
||||
function consumeOp(tokens, op){
|
||||
if (tokens[0] === op) {
|
||||
return tokens.shift();
|
||||
} else {
|
||||
throw new Error("Expected '" + op + "', but got '" + tokens[0] + "' instead in " + JSON.stringify(tokens) + ".");
|
||||
}
|
||||
}
|
||||
function maybeConsumeOp(tokens, op){
|
||||
if (tokens[0] === op) {
|
||||
return tokens.shift();
|
||||
}
|
||||
}
|
||||
function consumeList(tokens, arg$, hasDelimiters){
|
||||
var open, close, result, untilTest;
|
||||
open = arg$[0], close = arg$[1];
|
||||
if (hasDelimiters) {
|
||||
consumeOp(tokens, open);
|
||||
}
|
||||
result = [];
|
||||
untilTest = "," + (hasDelimiters ? close : '');
|
||||
while (tokens.length && (hasDelimiters && tokens[0] !== close)) {
|
||||
result.push(consumeElement(tokens, untilTest));
|
||||
maybeConsumeOp(tokens, ',');
|
||||
}
|
||||
if (hasDelimiters) {
|
||||
consumeOp(tokens, close);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function consumeArray(tokens, hasDelimiters){
|
||||
return consumeList(tokens, ['[', ']'], hasDelimiters);
|
||||
}
|
||||
function consumeTuple(tokens, hasDelimiters){
|
||||
return consumeList(tokens, ['(', ')'], hasDelimiters);
|
||||
}
|
||||
function consumeFields(tokens, hasDelimiters){
|
||||
var result, untilTest, key;
|
||||
if (hasDelimiters) {
|
||||
consumeOp(tokens, '{');
|
||||
}
|
||||
result = {};
|
||||
untilTest = "," + (hasDelimiters ? '}' : '');
|
||||
while (tokens.length && (!hasDelimiters || tokens[0] !== '}')) {
|
||||
key = consumeValue(tokens, ':');
|
||||
consumeOp(tokens, ':');
|
||||
result[key] = consumeElement(tokens, untilTest);
|
||||
maybeConsumeOp(tokens, ',');
|
||||
}
|
||||
if (hasDelimiters) {
|
||||
consumeOp(tokens, '}');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function consumeValue(tokens, untilTest){
|
||||
var out;
|
||||
untilTest == null && (untilTest = '');
|
||||
out = '';
|
||||
while (tokens.length && -1 === untilTest.indexOf(tokens[0])) {
|
||||
out += tokens.shift();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function consumeElement(tokens, untilTest){
|
||||
switch (tokens[0]) {
|
||||
case '[':
|
||||
return consumeArray(tokens, true);
|
||||
case '(':
|
||||
return consumeTuple(tokens, true);
|
||||
case '{':
|
||||
return consumeFields(tokens, true);
|
||||
default:
|
||||
return consumeValue(tokens, untilTest);
|
||||
}
|
||||
}
|
||||
function consumeTopLevel(tokens, types, options){
|
||||
var ref$, type, structure, origTokens, result, finalResult, x$, y$;
|
||||
ref$ = types[0], type = ref$.type, structure = ref$.structure;
|
||||
origTokens = tokens.concat();
|
||||
if (!options.explicit && types.length === 1 && ((!type && structure) || (type === 'Array' || type === 'Object'))) {
|
||||
result = structure === 'array' || type === 'Array'
|
||||
? consumeArray(tokens, tokens[0] === '[')
|
||||
: structure === 'tuple'
|
||||
? consumeTuple(tokens, tokens[0] === '(')
|
||||
: consumeFields(tokens, tokens[0] === '{');
|
||||
finalResult = tokens.length ? consumeElement(structure === 'array' || type === 'Array'
|
||||
? (x$ = origTokens, x$.unshift('['), x$.push(']'), x$)
|
||||
: (y$ = origTokens, y$.unshift('('), y$.push(')'), y$)) : result;
|
||||
} else {
|
||||
finalResult = consumeElement(tokens);
|
||||
}
|
||||
return finalResult;
|
||||
}
|
||||
special = /\[\]\(\)}{:,/.source;
|
||||
tokenRegex = RegExp('("(?:\\\\"|[^"])*")|(\'(?:\\\\\'|[^\'])*\')|(/(?:\\\\/|[^/])*/[a-zA-Z]*)|(#.*#)|([' + special + '])|([^\\s' + special + '](?:\\s*[^\\s' + special + ']+)*)|\\s*');
|
||||
module.exports = function(types, string, options){
|
||||
var tokens, node;
|
||||
options == null && (options = {});
|
||||
if (!options.explicit && types.length === 1 && types[0].type === 'String') {
|
||||
return string;
|
||||
}
|
||||
tokens = reject(not$, string.split(tokenRegex));
|
||||
node = consumeTopLevel(tokens, types, options);
|
||||
if (!node) {
|
||||
throw new Error("Error parsing '" + string + "'.");
|
||||
}
|
||||
return node;
|
||||
};
|
||||
function not$(x){ return !x; }
|
||||
}).call(this);
|
||||
@@ -0,0 +1,160 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.montgomery = montgomery;
|
||||
/**
|
||||
* Montgomery curve methods. It's not really whole montgomery curve,
|
||||
* just bunch of very specific methods for X25519 / X448 from
|
||||
* [RFC 7748](https://www.rfc-editor.org/rfc/rfc7748)
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
const utils_ts_1 = require("../utils.js");
|
||||
const modular_ts_1 = require("./modular.js");
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
const _2n = BigInt(2);
|
||||
function validateOpts(curve) {
|
||||
(0, utils_ts_1._validateObject)(curve, {
|
||||
adjustScalarBytes: 'function',
|
||||
powPminus2: 'function',
|
||||
});
|
||||
return Object.freeze({ ...curve });
|
||||
}
|
||||
function montgomery(curveDef) {
|
||||
const CURVE = validateOpts(curveDef);
|
||||
const { P, type, adjustScalarBytes, powPminus2, randomBytes: rand } = CURVE;
|
||||
const is25519 = type === 'x25519';
|
||||
if (!is25519 && type !== 'x448')
|
||||
throw new Error('invalid type');
|
||||
const randomBytes_ = rand || utils_ts_1.randomBytes;
|
||||
const montgomeryBits = is25519 ? 255 : 448;
|
||||
const fieldLen = is25519 ? 32 : 56;
|
||||
const Gu = is25519 ? BigInt(9) : BigInt(5);
|
||||
// RFC 7748 #5:
|
||||
// The constant a24 is (486662 - 2) / 4 = 121665 for curve25519/X25519 and
|
||||
// (156326 - 2) / 4 = 39081 for curve448/X448
|
||||
// const a = is25519 ? 156326n : 486662n;
|
||||
const a24 = is25519 ? BigInt(121665) : BigInt(39081);
|
||||
// RFC: x25519 "the resulting integer is of the form 2^254 plus
|
||||
// eight times a value between 0 and 2^251 - 1 (inclusive)"
|
||||
// x448: "2^447 plus four times a value between 0 and 2^445 - 1 (inclusive)"
|
||||
const minScalar = is25519 ? _2n ** BigInt(254) : _2n ** BigInt(447);
|
||||
const maxAdded = is25519
|
||||
? BigInt(8) * _2n ** BigInt(251) - _1n
|
||||
: BigInt(4) * _2n ** BigInt(445) - _1n;
|
||||
const maxScalar = minScalar + maxAdded + _1n; // (inclusive)
|
||||
const modP = (n) => (0, modular_ts_1.mod)(n, P);
|
||||
const GuBytes = encodeU(Gu);
|
||||
function encodeU(u) {
|
||||
return (0, utils_ts_1.numberToBytesLE)(modP(u), fieldLen);
|
||||
}
|
||||
function decodeU(u) {
|
||||
const _u = (0, utils_ts_1.ensureBytes)('u coordinate', u, fieldLen);
|
||||
// RFC: When receiving such an array, implementations of X25519
|
||||
// (but not X448) MUST mask the most significant bit in the final byte.
|
||||
if (is25519)
|
||||
_u[31] &= 127; // 0b0111_1111
|
||||
// RFC: Implementations MUST accept non-canonical values and process them as
|
||||
// if they had been reduced modulo the field prime. The non-canonical
|
||||
// values are 2^255 - 19 through 2^255 - 1 for X25519 and 2^448 - 2^224
|
||||
// - 1 through 2^448 - 1 for X448.
|
||||
return modP((0, utils_ts_1.bytesToNumberLE)(_u));
|
||||
}
|
||||
function decodeScalar(scalar) {
|
||||
return (0, utils_ts_1.bytesToNumberLE)(adjustScalarBytes((0, utils_ts_1.ensureBytes)('scalar', scalar, fieldLen)));
|
||||
}
|
||||
function scalarMult(scalar, u) {
|
||||
const pu = montgomeryLadder(decodeU(u), decodeScalar(scalar));
|
||||
// Some public keys are useless, of low-order. Curve author doesn't think
|
||||
// it needs to be validated, but we do it nonetheless.
|
||||
// https://cr.yp.to/ecdh.html#validate
|
||||
if (pu === _0n)
|
||||
throw new Error('invalid private or public key received');
|
||||
return encodeU(pu);
|
||||
}
|
||||
// Computes public key from private. By doing scalar multiplication of base point.
|
||||
function scalarMultBase(scalar) {
|
||||
return scalarMult(scalar, GuBytes);
|
||||
}
|
||||
// cswap from RFC7748 "example code"
|
||||
function cswap(swap, x_2, x_3) {
|
||||
// dummy = mask(swap) AND (x_2 XOR x_3)
|
||||
// Where mask(swap) is the all-1 or all-0 word of the same length as x_2
|
||||
// and x_3, computed, e.g., as mask(swap) = 0 - swap.
|
||||
const dummy = modP(swap * (x_2 - x_3));
|
||||
x_2 = modP(x_2 - dummy); // x_2 = x_2 XOR dummy
|
||||
x_3 = modP(x_3 + dummy); // x_3 = x_3 XOR dummy
|
||||
return { x_2, x_3 };
|
||||
}
|
||||
/**
|
||||
* Montgomery x-only multiplication ladder.
|
||||
* @param pointU u coordinate (x) on Montgomery Curve 25519
|
||||
* @param scalar by which the point would be multiplied
|
||||
* @returns new Point on Montgomery curve
|
||||
*/
|
||||
function montgomeryLadder(u, scalar) {
|
||||
(0, utils_ts_1.aInRange)('u', u, _0n, P);
|
||||
(0, utils_ts_1.aInRange)('scalar', scalar, minScalar, maxScalar);
|
||||
const k = scalar;
|
||||
const x_1 = u;
|
||||
let x_2 = _1n;
|
||||
let z_2 = _0n;
|
||||
let x_3 = u;
|
||||
let z_3 = _1n;
|
||||
let swap = _0n;
|
||||
for (let t = BigInt(montgomeryBits - 1); t >= _0n; t--) {
|
||||
const k_t = (k >> t) & _1n;
|
||||
swap ^= k_t;
|
||||
({ x_2, x_3 } = cswap(swap, x_2, x_3));
|
||||
({ x_2: z_2, x_3: z_3 } = cswap(swap, z_2, z_3));
|
||||
swap = k_t;
|
||||
const A = x_2 + z_2;
|
||||
const AA = modP(A * A);
|
||||
const B = x_2 - z_2;
|
||||
const BB = modP(B * B);
|
||||
const E = AA - BB;
|
||||
const C = x_3 + z_3;
|
||||
const D = x_3 - z_3;
|
||||
const DA = modP(D * A);
|
||||
const CB = modP(C * B);
|
||||
const dacb = DA + CB;
|
||||
const da_cb = DA - CB;
|
||||
x_3 = modP(dacb * dacb);
|
||||
z_3 = modP(x_1 * modP(da_cb * da_cb));
|
||||
x_2 = modP(AA * BB);
|
||||
z_2 = modP(E * (AA + modP(a24 * E)));
|
||||
}
|
||||
({ x_2, x_3 } = cswap(swap, x_2, x_3));
|
||||
({ x_2: z_2, x_3: z_3 } = cswap(swap, z_2, z_3));
|
||||
const z2 = powPminus2(z_2); // `Fp.pow(x, P - _2n)` is much slower equivalent
|
||||
return modP(x_2 * z2); // Return x_2 * (z_2^(p - 2))
|
||||
}
|
||||
const lengths = {
|
||||
secretKey: fieldLen,
|
||||
publicKey: fieldLen,
|
||||
seed: fieldLen,
|
||||
};
|
||||
const randomSecretKey = (seed = randomBytes_(fieldLen)) => {
|
||||
(0, utils_ts_1.abytes)(seed, lengths.seed);
|
||||
return seed;
|
||||
};
|
||||
function keygen(seed) {
|
||||
const secretKey = randomSecretKey(seed);
|
||||
return { secretKey, publicKey: scalarMultBase(secretKey) };
|
||||
}
|
||||
const utils = {
|
||||
randomSecretKey,
|
||||
randomPrivateKey: randomSecretKey,
|
||||
};
|
||||
return {
|
||||
keygen,
|
||||
getSharedSecret: (secretKey, publicKey) => scalarMult(secretKey, publicKey),
|
||||
getPublicKey: (secretKey) => scalarMultBase(secretKey),
|
||||
scalarMult,
|
||||
scalarMultBase,
|
||||
utils,
|
||||
GuBytes: GuBytes.slice(),
|
||||
lengths,
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=montgomery.js.map
|
||||
@@ -0,0 +1,70 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.extractNameForMember = extractNameForMember;
|
||||
exports.extractNameForMemberExpression = extractNameForMemberExpression;
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const types_1 = require("./types");
|
||||
function extractComputedName(computedName) {
|
||||
if (computedName.type === utils_1.AST_NODE_TYPES.Literal) {
|
||||
const name = computedName.value?.toString() ?? 'null';
|
||||
return {
|
||||
codeName: name,
|
||||
key: (0, types_1.publicKey)(name),
|
||||
nameNode: computedName,
|
||||
};
|
||||
}
|
||||
if (computedName.type === utils_1.AST_NODE_TYPES.TemplateLiteral &&
|
||||
computedName.expressions.length === 0) {
|
||||
const name = computedName.quasis[0].value.raw;
|
||||
return {
|
||||
codeName: name,
|
||||
key: (0, types_1.publicKey)(name),
|
||||
nameNode: computedName,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function extractNonComputedName(nonComputedName) {
|
||||
const name = nonComputedName.name;
|
||||
if (nonComputedName.type === utils_1.AST_NODE_TYPES.PrivateIdentifier) {
|
||||
return {
|
||||
codeName: `#${name}`,
|
||||
key: (0, types_1.privateKey)(nonComputedName),
|
||||
nameNode: nonComputedName,
|
||||
};
|
||||
}
|
||||
return {
|
||||
codeName: name,
|
||||
key: (0, types_1.publicKey)(name),
|
||||
nameNode: nonComputedName,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Extracts the string name for a member.
|
||||
* @returns `null` if the name cannot be extracted due to it being computed.
|
||||
*/
|
||||
function extractNameForMember(node) {
|
||||
if (node.type === utils_1.AST_NODE_TYPES.TSParameterProperty) {
|
||||
const identifier = node.parameter.type === utils_1.AST_NODE_TYPES.Identifier
|
||||
? node.parameter
|
||||
: node.parameter.left;
|
||||
return extractNonComputedName(identifier);
|
||||
}
|
||||
if (node.computed) {
|
||||
return extractComputedName(node.key);
|
||||
}
|
||||
if (node.key.type === utils_1.AST_NODE_TYPES.Literal) {
|
||||
return extractComputedName(node.key);
|
||||
}
|
||||
return extractNonComputedName(node.key);
|
||||
}
|
||||
/**
|
||||
* Extracts the string property name for a member.
|
||||
* @returns `null` if the name cannot be extracted due to it being a computed.
|
||||
*/
|
||||
function extractNameForMemberExpression(node) {
|
||||
if (node.computed) {
|
||||
return extractComputedName(node.property);
|
||||
}
|
||||
return extractNonComputedName(node.property);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function byteLength(b64: string): number;
|
||||
export function toByteArray(b64: string): Uint8Array;
|
||||
export function fromByteArray(uint8: Uint8Array): string;
|
||||
@@ -0,0 +1,221 @@
|
||||
'use strict';
|
||||
|
||||
const events = require('events');
|
||||
const utils = require('../utils');
|
||||
|
||||
/**
|
||||
* Constructor for a Jayson Client
|
||||
* @class Client
|
||||
* @extends require('events').EventEmitter
|
||||
* @param {Server} [server] An instance of Server (a object with a "call" method")
|
||||
* @param {Object} [options]
|
||||
* @param {Function} [options.reviver] Reviver function for JSON
|
||||
* @param {Function} [options.replacer] Replacer function for JSON
|
||||
* @param {Number} [options.version=2] JSON-RPC version to use (1|2)
|
||||
* @param {Boolean} [options.notificationIdNull=false] When true, version 2 requests will set id to null instead of omitting it
|
||||
* @param {Function} [options.generator] Function to use for generating request IDs
|
||||
* @return {Client}
|
||||
*/
|
||||
const Client = function(server, options) {
|
||||
if(arguments.length === 1 && utils.isPlainObject(server)) {
|
||||
options = server;
|
||||
server = null;
|
||||
}
|
||||
|
||||
if(!(this instanceof Client)) {
|
||||
return new Client(server, options);
|
||||
}
|
||||
|
||||
const defaults = {
|
||||
reviver: null,
|
||||
replacer: null,
|
||||
generator: utils.generateId,
|
||||
version: 2,
|
||||
notificationIdNull: false,
|
||||
};
|
||||
|
||||
this.options = utils.merge(defaults, options || {});
|
||||
|
||||
if(server) {
|
||||
this.server = server;
|
||||
}
|
||||
};
|
||||
require('util').inherits(Client, events.EventEmitter);
|
||||
|
||||
module.exports = Client;
|
||||
|
||||
/**
|
||||
* HTTP client constructor
|
||||
* @type ClientHttp
|
||||
* @static
|
||||
*/
|
||||
Client.http = require('./http');
|
||||
|
||||
/**
|
||||
* HTTPS client constructor
|
||||
* @type ClientHttps
|
||||
* @static
|
||||
*/
|
||||
Client.https = require('./https');
|
||||
|
||||
/**
|
||||
* TCP client constructor
|
||||
* @type ClientTcp
|
||||
* @static
|
||||
*/
|
||||
Client.tcp = require('./tcp');
|
||||
|
||||
/**
|
||||
* TLS client constructor
|
||||
* @type ClientTls
|
||||
* @static
|
||||
*/
|
||||
Client.tls = require('./tls');
|
||||
|
||||
/**
|
||||
* Browser client constructor
|
||||
* @type ClientBrowser
|
||||
* @static
|
||||
*/
|
||||
Client.browser = require('./browser');
|
||||
|
||||
/**
|
||||
* Websocket client constructor
|
||||
* @type ClientWebsocket
|
||||
* @static
|
||||
*/
|
||||
Client.websocket = require('./websocket');
|
||||
|
||||
/**
|
||||
* Creates a request and dispatches it if given a callback.
|
||||
* @param {String|Array} method A batch request if passed an Array, or a method name if passed a String
|
||||
* @param {Array|Object} params Parameters for the method
|
||||
* @param {String|Number} [id] Optional id. If undefined an id will be generated. If null it creates a notification request
|
||||
* @param {Function} [callback] Request callback. If specified, executes the request rather than only returning it.
|
||||
* @throws {TypeError} Invalid parameters
|
||||
* @return {Object} JSON-RPC 1.0 or 2.0 compatible request
|
||||
*/
|
||||
Client.prototype.request = function(method, params, id, callback) {
|
||||
const self = this;
|
||||
let request = null;
|
||||
|
||||
// is this a batch request?
|
||||
const isBatch = Array.isArray(method) && typeof(params) === 'function';
|
||||
|
||||
if (this.options.version === 1 && isBatch) {
|
||||
throw new TypeError('JSON-RPC 1.0 does not support batching');
|
||||
}
|
||||
|
||||
// is this a raw request?
|
||||
const isRaw = !isBatch && method && typeof(method) === 'object' && typeof(params) === 'function';
|
||||
|
||||
if(isBatch || isRaw) {
|
||||
callback = params;
|
||||
request = method;
|
||||
} else {
|
||||
if(typeof(id) === 'function') {
|
||||
callback = id;
|
||||
// specifically undefined because "null" is a notification request
|
||||
id = undefined;
|
||||
}
|
||||
|
||||
const hasCallback = typeof(callback) === 'function';
|
||||
|
||||
try {
|
||||
request = utils.request(method, params, id, {
|
||||
generator: this.options.generator,
|
||||
version: this.options.version,
|
||||
notificationIdNull: this.options.notificationIdNull,
|
||||
});
|
||||
} catch(err) {
|
||||
if(hasCallback) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
|
||||
// no callback means we should just return a raw request before sending
|
||||
if(!hasCallback) {
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.emit('request', request);
|
||||
|
||||
this._request(request, function(err, response) {
|
||||
self.emit('response', request, response);
|
||||
self._parseResponse(err, response, callback);
|
||||
});
|
||||
|
||||
// always return the raw request
|
||||
return request;
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes a request on a directly bound server
|
||||
* @param {Object} request A JSON-RPC 1.0 or 2.0 request
|
||||
* @param {Function} callback Request callback that will receive the server response as the second argument
|
||||
* @private
|
||||
*/
|
||||
Client.prototype._request = function(request, callback) {
|
||||
const self = this;
|
||||
|
||||
// serializes the request as a JSON string so that we get a copy and can run the replacer as intended
|
||||
utils.JSON.stringify(request, this.options, function(err, message) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
self.server.call(message, function(error, success) {
|
||||
const response = error || success;
|
||||
callback(null, response);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses a response from a server, taking care of sugaring
|
||||
* @param {Object} err Error to pass on that is unrelated to the actual response
|
||||
* @param {Object} response JSON-RPC 1.0 or 2.0 response
|
||||
* @param {Function} callback Callback that will receive different arguments depending on the amount of parameters
|
||||
* @private
|
||||
*/
|
||||
Client.prototype._parseResponse = function(err, response, callback) {
|
||||
if(err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!response || typeof(response) !== 'object') {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if(callback.length === 3) {
|
||||
// if callback length is 3, we split callback arguments on error and response
|
||||
|
||||
// is batch response?
|
||||
if(Array.isArray(response)) {
|
||||
|
||||
// necessary to split strictly on validity according to spec here
|
||||
const isError = function(res) { return typeof(res.error) !== 'undefined'; };
|
||||
const isNotError = function(res) { return !isError(res); };
|
||||
|
||||
callback(null, response.filter(isError), response.filter(isNotError));
|
||||
return;
|
||||
} else {
|
||||
|
||||
// split regardless of validity
|
||||
callback(null, response.error, response.result);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
callback(null, response);
|
||||
};
|
||||
@@ -0,0 +1,259 @@
|
||||
import BN from 'bn.js';
|
||||
import bs58 from 'bs58';
|
||||
import {Buffer} from 'buffer';
|
||||
import {sha256} from '@noble/hashes/sha256';
|
||||
|
||||
import {isOnCurve} from './utils/ed25519';
|
||||
import {Struct, SOLANA_SCHEMA} from './utils/borsh-schema';
|
||||
import {toBuffer} from './utils/to-buffer';
|
||||
|
||||
/**
|
||||
* Maximum length of derived pubkey seed
|
||||
*/
|
||||
export const MAX_SEED_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* Size of public key in bytes
|
||||
*/
|
||||
export const PUBLIC_KEY_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* Value to be converted into public key
|
||||
*/
|
||||
export type PublicKeyInitData =
|
||||
| number
|
||||
| string
|
||||
| Uint8Array
|
||||
| Array<number>
|
||||
| PublicKeyData;
|
||||
|
||||
/**
|
||||
* JSON object representation of PublicKey class
|
||||
*/
|
||||
export type PublicKeyData = {
|
||||
/** @internal */
|
||||
_bn: BN;
|
||||
};
|
||||
|
||||
function isPublicKeyData(value: PublicKeyInitData): value is PublicKeyData {
|
||||
return (value as PublicKeyData)._bn !== undefined;
|
||||
}
|
||||
|
||||
// local counter used by PublicKey.unique()
|
||||
let uniquePublicKeyCounter = 1;
|
||||
|
||||
/**
|
||||
* A public key
|
||||
*/
|
||||
export class PublicKey extends Struct {
|
||||
/** @internal */
|
||||
_bn: BN;
|
||||
|
||||
/**
|
||||
* Create a new PublicKey object
|
||||
* @param value ed25519 public key as buffer or base-58 encoded string
|
||||
*/
|
||||
constructor(value: PublicKeyInitData) {
|
||||
super({});
|
||||
if (isPublicKeyData(value)) {
|
||||
this._bn = value._bn;
|
||||
} else {
|
||||
if (typeof value === 'string') {
|
||||
// assume base 58 encoding by default
|
||||
const decoded = bs58.decode(value);
|
||||
if (decoded.length != PUBLIC_KEY_LENGTH) {
|
||||
throw new Error(`Invalid public key input`);
|
||||
}
|
||||
this._bn = new BN(decoded);
|
||||
} else {
|
||||
this._bn = new BN(value);
|
||||
}
|
||||
|
||||
if (this._bn.byteLength() > PUBLIC_KEY_LENGTH) {
|
||||
throw new Error(`Invalid public key input`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique PublicKey for tests and benchmarks using a counter
|
||||
*/
|
||||
static unique(): PublicKey {
|
||||
const key = new PublicKey(uniquePublicKeyCounter);
|
||||
uniquePublicKeyCounter += 1;
|
||||
return new PublicKey(key.toBuffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Default public key value. The base58-encoded string representation is all ones (as seen below)
|
||||
* The underlying BN number is 32 bytes that are all zeros
|
||||
*/
|
||||
static default: PublicKey = new PublicKey('11111111111111111111111111111111');
|
||||
|
||||
/**
|
||||
* Checks if two publicKeys are equal
|
||||
*/
|
||||
equals(publicKey: PublicKey): boolean {
|
||||
return this._bn.eq(publicKey._bn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base-58 representation of the public key
|
||||
*/
|
||||
toBase58(): string {
|
||||
return bs58.encode(this.toBytes());
|
||||
}
|
||||
|
||||
toJSON(): string {
|
||||
return this.toBase58();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the byte array representation of the public key in big endian
|
||||
*/
|
||||
toBytes(): Uint8Array {
|
||||
const buf = this.toBuffer();
|
||||
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Buffer representation of the public key in big endian
|
||||
*/
|
||||
toBuffer(): Buffer {
|
||||
const b = this._bn.toArrayLike(Buffer);
|
||||
if (b.length === PUBLIC_KEY_LENGTH) {
|
||||
return b;
|
||||
}
|
||||
|
||||
const zeroPad = Buffer.alloc(32);
|
||||
b.copy(zeroPad, 32 - b.length);
|
||||
return zeroPad;
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag](): string {
|
||||
return `PublicKey(${this.toString()})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the base-58 representation of the public key
|
||||
*/
|
||||
toString(): string {
|
||||
return this.toBase58();
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a public key from another key, a seed, and a program ID.
|
||||
* The program ID will also serve as the owner of the public key, giving
|
||||
* it permission to write data to the account.
|
||||
*/
|
||||
/* eslint-disable require-await */
|
||||
static async createWithSeed(
|
||||
fromPublicKey: PublicKey,
|
||||
seed: string,
|
||||
programId: PublicKey,
|
||||
): Promise<PublicKey> {
|
||||
const buffer = Buffer.concat([
|
||||
fromPublicKey.toBuffer(),
|
||||
Buffer.from(seed),
|
||||
programId.toBuffer(),
|
||||
]);
|
||||
const publicKeyBytes = sha256(buffer);
|
||||
return new PublicKey(publicKeyBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a program address from seeds and a program ID.
|
||||
*/
|
||||
/* eslint-disable require-await */
|
||||
static createProgramAddressSync(
|
||||
seeds: Array<Buffer | Uint8Array>,
|
||||
programId: PublicKey,
|
||||
): PublicKey {
|
||||
let buffer = Buffer.alloc(0);
|
||||
seeds.forEach(function (seed) {
|
||||
if (seed.length > MAX_SEED_LENGTH) {
|
||||
throw new TypeError(`Max seed length exceeded`);
|
||||
}
|
||||
buffer = Buffer.concat([buffer, toBuffer(seed)]);
|
||||
});
|
||||
buffer = Buffer.concat([
|
||||
buffer,
|
||||
programId.toBuffer(),
|
||||
Buffer.from('ProgramDerivedAddress'),
|
||||
]);
|
||||
const publicKeyBytes = sha256(buffer);
|
||||
if (isOnCurve(publicKeyBytes)) {
|
||||
throw new Error(`Invalid seeds, address must fall off the curve`);
|
||||
}
|
||||
return new PublicKey(publicKeyBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Async version of createProgramAddressSync
|
||||
* For backwards compatibility
|
||||
*
|
||||
* @deprecated Use {@link createProgramAddressSync} instead
|
||||
*/
|
||||
/* eslint-disable require-await */
|
||||
static async createProgramAddress(
|
||||
seeds: Array<Buffer | Uint8Array>,
|
||||
programId: PublicKey,
|
||||
): Promise<PublicKey> {
|
||||
return this.createProgramAddressSync(seeds, programId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a valid program address
|
||||
*
|
||||
* Valid program addresses must fall off the ed25519 curve. This function
|
||||
* iterates a nonce until it finds one that when combined with the seeds
|
||||
* results in a valid program address.
|
||||
*/
|
||||
static findProgramAddressSync(
|
||||
seeds: Array<Buffer | Uint8Array>,
|
||||
programId: PublicKey,
|
||||
): [PublicKey, number] {
|
||||
let nonce = 255;
|
||||
let address;
|
||||
while (nonce != 0) {
|
||||
try {
|
||||
const seedsWithNonce = seeds.concat(Buffer.from([nonce]));
|
||||
address = this.createProgramAddressSync(seedsWithNonce, programId);
|
||||
} catch (err) {
|
||||
if (err instanceof TypeError) {
|
||||
throw err;
|
||||
}
|
||||
nonce--;
|
||||
continue;
|
||||
}
|
||||
return [address, nonce];
|
||||
}
|
||||
throw new Error(`Unable to find a viable program address nonce`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Async version of findProgramAddressSync
|
||||
* For backwards compatibility
|
||||
*
|
||||
* @deprecated Use {@link findProgramAddressSync} instead
|
||||
*/
|
||||
static async findProgramAddress(
|
||||
seeds: Array<Buffer | Uint8Array>,
|
||||
programId: PublicKey,
|
||||
): Promise<[PublicKey, number]> {
|
||||
return this.findProgramAddressSync(seeds, programId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a pubkey is on the ed25519 curve.
|
||||
*/
|
||||
static isOnCurve(pubkeyData: PublicKeyInitData): boolean {
|
||||
const pubkey = new PublicKey(pubkeyData);
|
||||
return isOnCurve(pubkey.toBytes());
|
||||
}
|
||||
}
|
||||
|
||||
SOLANA_SCHEMA.set(PublicKey, {
|
||||
kind: 'struct',
|
||||
fields: [['_bn', 'u256']],
|
||||
});
|
||||
@@ -0,0 +1,153 @@
|
||||
'use strict';
|
||||
|
||||
const {Transform} = require('stream');
|
||||
|
||||
const noCommaAfter = {startObject: 1, startArray: 1, endKey: 1, keyValue: 1},
|
||||
noSpaceAfter = {endObject: 1, endArray: 1, '': 1},
|
||||
noSpaceBefore = {startObject: 1, startArray: 1},
|
||||
depthIncrement = {startObject: 1, startArray: 1},
|
||||
depthDecrement = {endObject: 1, endArray: 1},
|
||||
values = {startKey: 'keyValue', startString: 'stringValue', startNumber: 'numberValue'},
|
||||
stopNames = {startKey: 'endKey', startString: 'endString', startNumber: 'endNumber'},
|
||||
symbols = {
|
||||
startObject: '{',
|
||||
endObject: '}',
|
||||
startArray: '[',
|
||||
endArray: ']',
|
||||
startKey: '"',
|
||||
endKey: '":',
|
||||
startString: '"',
|
||||
endString: '"',
|
||||
startNumber: '',
|
||||
endNumber: '',
|
||||
nullValue: 'null',
|
||||
trueValue: 'true',
|
||||
falseValue: 'false'
|
||||
};
|
||||
|
||||
const skipValue = endName =>
|
||||
function (chunk, encoding, callback) {
|
||||
if (chunk.name === endName) {
|
||||
this._transform = this._prev_transform;
|
||||
}
|
||||
callback(null);
|
||||
};
|
||||
|
||||
const replaceSymbols = {'\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t', '"': '\\"', '\\': '\\\\'};
|
||||
const sanitizeString = value =>
|
||||
value.replace(/[\b\f\n\r\t\"\\\u0000-\u001F\u007F-\u009F]/g, match =>
|
||||
replaceSymbols.hasOwnProperty(match) ? replaceSymbols[match] : '\\u' + ('0000' + match.charCodeAt(0).toString(16)).slice(-4)
|
||||
);
|
||||
|
||||
const doNothing = () => {};
|
||||
|
||||
class Stringer extends Transform {
|
||||
static make(options) {
|
||||
return new Stringer(options);
|
||||
}
|
||||
|
||||
constructor(options) {
|
||||
super(Object.assign({}, options, {writableObjectMode: true, readableObjectMode: false}));
|
||||
|
||||
this._values = {};
|
||||
if (options) {
|
||||
'useValues' in options && (this._values.keyValue = this._values.stringValue = this._values.numberValue = options.useValues);
|
||||
'useKeyValues' in options && (this._values.keyValue = options.useKeyValues);
|
||||
'useStringValues' in options && (this._values.stringValue = options.useStringValues);
|
||||
'useNumberValues' in options && (this._values.numberValue = options.useNumberValues);
|
||||
this._makeArray = options.makeArray;
|
||||
}
|
||||
|
||||
this._prev = '';
|
||||
this._depth = 0;
|
||||
|
||||
if (this._makeArray) {
|
||||
this._transform = this._arrayTransform;
|
||||
this._flush = this._arrayFlush;
|
||||
}
|
||||
}
|
||||
|
||||
_arrayTransform(chunk, encoding, callback) {
|
||||
// it runs once
|
||||
delete this._transform;
|
||||
this._transform({name: 'startArray'}, encoding, doNothing);
|
||||
this._transform(chunk, encoding, callback);
|
||||
}
|
||||
|
||||
_arrayFlush(callback) {
|
||||
if (this._transform === this._arrayTransform) {
|
||||
delete this._transform;
|
||||
this._transform({name: 'startArray'}, null, doNothing);
|
||||
}
|
||||
this._transform({name: 'endArray'}, null, callback);
|
||||
}
|
||||
|
||||
_transform(chunk, _, callback) {
|
||||
if (this._values[chunk.name]) {
|
||||
if (this._depth && noCommaAfter[this._prev] !== 1) this.push(',');
|
||||
switch (chunk.name) {
|
||||
case 'keyValue':
|
||||
this.push('"' + sanitizeString(chunk.value) + '":');
|
||||
break;
|
||||
case 'stringValue':
|
||||
this.push('"' + sanitizeString(chunk.value) + '"');
|
||||
break;
|
||||
case 'numberValue':
|
||||
this.push(chunk.value);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// filter out values
|
||||
switch (chunk.name) {
|
||||
case 'endObject':
|
||||
case 'endArray':
|
||||
case 'endKey':
|
||||
case 'endString':
|
||||
case 'endNumber':
|
||||
this.push(symbols[chunk.name]);
|
||||
break;
|
||||
case 'stringChunk':
|
||||
this.push(sanitizeString(chunk.value));
|
||||
break;
|
||||
case 'numberChunk':
|
||||
this.push(chunk.value);
|
||||
break;
|
||||
case 'keyValue':
|
||||
case 'stringValue':
|
||||
case 'numberValue':
|
||||
// skip completely
|
||||
break;
|
||||
case 'startKey':
|
||||
case 'startString':
|
||||
case 'startNumber':
|
||||
if (this._values[values[chunk.name]]) {
|
||||
this._prev_transform = this._transform;
|
||||
this._transform = skipValue(stopNames[chunk.name]);
|
||||
return callback(null);
|
||||
}
|
||||
// intentional fall down
|
||||
default:
|
||||
// case 'startObject': case 'startArray': case 'startKey': case 'startString':
|
||||
// case 'startNumber': case 'nullValue': case 'trueValue': case 'falseValue':
|
||||
if (this._depth) {
|
||||
if (noCommaAfter[this._prev] !== 1) this.push(',');
|
||||
} else {
|
||||
if (noSpaceAfter[this._prev] !== 1 && noSpaceBefore[chunk.name] !== 1) this.push(' ');
|
||||
}
|
||||
this.push(symbols[chunk.name]);
|
||||
break;
|
||||
}
|
||||
if (depthIncrement[chunk.name]) {
|
||||
++this._depth;
|
||||
} else if (depthDecrement[chunk.name]) {
|
||||
--this._depth;
|
||||
}
|
||||
}
|
||||
this._prev = chunk.name;
|
||||
callback(null);
|
||||
}
|
||||
}
|
||||
Stringer.stringer = Stringer.make;
|
||||
Stringer.make.Constructor = Stringer;
|
||||
|
||||
module.exports = Stringer;
|
||||
@@ -0,0 +1,320 @@
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
/////////////////////////////
|
||||
/// Windows Script Host APIS
|
||||
/////////////////////////////
|
||||
|
||||
interface ActiveXObject {
|
||||
new (s: string): any;
|
||||
}
|
||||
declare var ActiveXObject: ActiveXObject;
|
||||
|
||||
interface ITextWriter {
|
||||
Write(s: string): void;
|
||||
WriteLine(s: string): void;
|
||||
Close(): void;
|
||||
}
|
||||
|
||||
interface TextStreamBase {
|
||||
/**
|
||||
* The column number of the current character position in an input stream.
|
||||
*/
|
||||
Column: number;
|
||||
|
||||
/**
|
||||
* The current line number in an input stream.
|
||||
*/
|
||||
Line: number;
|
||||
|
||||
/**
|
||||
* Closes a text stream.
|
||||
* It is not necessary to close standard streams; they close automatically when the process ends. If
|
||||
* you close a standard stream, be aware that any other pointers to that standard stream become invalid.
|
||||
*/
|
||||
Close(): void;
|
||||
}
|
||||
|
||||
interface TextStreamWriter extends TextStreamBase {
|
||||
/**
|
||||
* Sends a string to an output stream.
|
||||
*/
|
||||
Write(s: string): void;
|
||||
|
||||
/**
|
||||
* Sends a specified number of blank lines (newline characters) to an output stream.
|
||||
*/
|
||||
WriteBlankLines(intLines: number): void;
|
||||
|
||||
/**
|
||||
* Sends a string followed by a newline character to an output stream.
|
||||
*/
|
||||
WriteLine(s: string): void;
|
||||
}
|
||||
|
||||
interface TextStreamReader extends TextStreamBase {
|
||||
/**
|
||||
* Returns a specified number of characters from an input stream, starting at the current pointer position.
|
||||
* Does not return until the ENTER key is pressed.
|
||||
* Can only be used on a stream in reading mode; causes an error in writing or appending mode.
|
||||
*/
|
||||
Read(characters: number): string;
|
||||
|
||||
/**
|
||||
* Returns all characters from an input stream.
|
||||
* Can only be used on a stream in reading mode; causes an error in writing or appending mode.
|
||||
*/
|
||||
ReadAll(): string;
|
||||
|
||||
/**
|
||||
* Returns an entire line from an input stream.
|
||||
* Although this method extracts the newline character, it does not add it to the returned string.
|
||||
* Can only be used on a stream in reading mode; causes an error in writing or appending mode.
|
||||
*/
|
||||
ReadLine(): string;
|
||||
|
||||
/**
|
||||
* Skips a specified number of characters when reading from an input text stream.
|
||||
* Can only be used on a stream in reading mode; causes an error in writing or appending mode.
|
||||
* @param characters Positive number of characters to skip forward. (Backward skipping is not supported.)
|
||||
*/
|
||||
Skip(characters: number): void;
|
||||
|
||||
/**
|
||||
* Skips the next line when reading from an input text stream.
|
||||
* Can only be used on a stream in reading mode, not writing or appending mode.
|
||||
*/
|
||||
SkipLine(): void;
|
||||
|
||||
/**
|
||||
* Indicates whether the stream pointer position is at the end of a line.
|
||||
*/
|
||||
AtEndOfLine: boolean;
|
||||
|
||||
/**
|
||||
* Indicates whether the stream pointer position is at the end of a stream.
|
||||
*/
|
||||
AtEndOfStream: boolean;
|
||||
}
|
||||
|
||||
declare var WScript: {
|
||||
/**
|
||||
* Outputs text to either a message box (under WScript.exe) or the command console window followed by
|
||||
* a newline (under CScript.exe).
|
||||
*/
|
||||
Echo(s: any): void;
|
||||
|
||||
/**
|
||||
* Exposes the write-only error output stream for the current script.
|
||||
* Can be accessed only while using CScript.exe.
|
||||
*/
|
||||
StdErr: TextStreamWriter;
|
||||
|
||||
/**
|
||||
* Exposes the write-only output stream for the current script.
|
||||
* Can be accessed only while using CScript.exe.
|
||||
*/
|
||||
StdOut: TextStreamWriter;
|
||||
Arguments: { length: number; Item(n: number): string; };
|
||||
|
||||
/**
|
||||
* The full path of the currently running script.
|
||||
*/
|
||||
ScriptFullName: string;
|
||||
|
||||
/**
|
||||
* Forces the script to stop immediately, with an optional exit code.
|
||||
*/
|
||||
Quit(exitCode?: number): number;
|
||||
|
||||
/**
|
||||
* The Windows Script Host build version number.
|
||||
*/
|
||||
BuildVersion: number;
|
||||
|
||||
/**
|
||||
* Fully qualified path of the host executable.
|
||||
*/
|
||||
FullName: string;
|
||||
|
||||
/**
|
||||
* Gets/sets the script mode - interactive(true) or batch(false).
|
||||
*/
|
||||
Interactive: boolean;
|
||||
|
||||
/**
|
||||
* The name of the host executable (WScript.exe or CScript.exe).
|
||||
*/
|
||||
Name: string;
|
||||
|
||||
/**
|
||||
* Path of the directory containing the host executable.
|
||||
*/
|
||||
Path: string;
|
||||
|
||||
/**
|
||||
* The filename of the currently running script.
|
||||
*/
|
||||
ScriptName: string;
|
||||
|
||||
/**
|
||||
* Exposes the read-only input stream for the current script.
|
||||
* Can be accessed only while using CScript.exe.
|
||||
*/
|
||||
StdIn: TextStreamReader;
|
||||
|
||||
/**
|
||||
* Windows Script Host version
|
||||
*/
|
||||
Version: string;
|
||||
|
||||
/**
|
||||
* Connects a COM object's event sources to functions named with a given prefix, in the form prefix_event.
|
||||
*/
|
||||
ConnectObject(objEventSource: any, strPrefix: string): void;
|
||||
|
||||
/**
|
||||
* Creates a COM object.
|
||||
* @param strProgiID
|
||||
* @param strPrefix Function names in the form prefix_event will be bound to this object's COM events.
|
||||
*/
|
||||
CreateObject(strProgID: string, strPrefix?: string): any;
|
||||
|
||||
/**
|
||||
* Disconnects a COM object from its event sources.
|
||||
*/
|
||||
DisconnectObject(obj: any): void;
|
||||
|
||||
/**
|
||||
* Retrieves an existing object with the specified ProgID from memory, or creates a new one from a file.
|
||||
* @param strPathname Fully qualified path to the file containing the object persisted to disk.
|
||||
* For objects in memory, pass a zero-length string.
|
||||
* @param strProgID
|
||||
* @param strPrefix Function names in the form prefix_event will be bound to this object's COM events.
|
||||
*/
|
||||
GetObject(strPathname: string, strProgID?: string, strPrefix?: string): any;
|
||||
|
||||
/**
|
||||
* Suspends script execution for a specified length of time, then continues execution.
|
||||
* @param intTime Interval (in milliseconds) to suspend script execution.
|
||||
*/
|
||||
Sleep(intTime: number): void;
|
||||
};
|
||||
|
||||
/**
|
||||
* WSH is an alias for WScript under Windows Script Host
|
||||
*/
|
||||
declare var WSH: typeof WScript;
|
||||
|
||||
/**
|
||||
* Represents an Automation SAFEARRAY
|
||||
*/
|
||||
declare class SafeArray<T = any> {
|
||||
private constructor();
|
||||
private SafeArray_typekey: SafeArray<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows enumerating over a COM collection, which may not have indexed item access.
|
||||
*/
|
||||
interface Enumerator<T = any> {
|
||||
/**
|
||||
* Returns true if the current item is the last one in the collection, or the collection is empty,
|
||||
* or the current item is undefined.
|
||||
*/
|
||||
atEnd(): boolean;
|
||||
|
||||
/**
|
||||
* Returns the current item in the collection
|
||||
*/
|
||||
item(): T;
|
||||
|
||||
/**
|
||||
* Resets the current item in the collection to the first item. If there are no items in the collection,
|
||||
* the current item is set to undefined.
|
||||
*/
|
||||
moveFirst(): void;
|
||||
|
||||
/**
|
||||
* Moves the current item to the next item in the collection. If the enumerator is at the end of
|
||||
* the collection or the collection is empty, the current item is set to undefined.
|
||||
*/
|
||||
moveNext(): void;
|
||||
}
|
||||
|
||||
interface EnumeratorConstructor {
|
||||
new <T = any>(safearray: SafeArray<T>): Enumerator<T>;
|
||||
new <T = any>(collection: { Item(index: any): T; }): Enumerator<T>;
|
||||
new <T = any>(collection: any): Enumerator<T>;
|
||||
}
|
||||
|
||||
declare var Enumerator: EnumeratorConstructor;
|
||||
|
||||
/**
|
||||
* Enables reading from a COM safe array, which might have an alternate lower bound, or multiple dimensions.
|
||||
*/
|
||||
interface VBArray<T = any> {
|
||||
/**
|
||||
* Returns the number of dimensions (1-based).
|
||||
*/
|
||||
dimensions(): number;
|
||||
|
||||
/**
|
||||
* Takes an index for each dimension in the array, and returns the item at the corresponding location.
|
||||
*/
|
||||
getItem(dimension1Index: number, ...dimensionNIndexes: number[]): T;
|
||||
|
||||
/**
|
||||
* Returns the smallest available index for a given dimension.
|
||||
* @param dimension 1-based dimension (defaults to 1)
|
||||
*/
|
||||
lbound(dimension?: number): number;
|
||||
|
||||
/**
|
||||
* Returns the largest available index for a given dimension.
|
||||
* @param dimension 1-based dimension (defaults to 1)
|
||||
*/
|
||||
ubound(dimension?: number): number;
|
||||
|
||||
/**
|
||||
* Returns a Javascript array with all the elements in the VBArray. If there are multiple dimensions,
|
||||
* each successive dimension is appended to the end of the array.
|
||||
* Example: [[1,2,3],[4,5,6]] becomes [1,2,3,4,5,6]
|
||||
*/
|
||||
toArray(): T[];
|
||||
}
|
||||
|
||||
interface VBArrayConstructor {
|
||||
new <T = any>(safeArray: SafeArray<T>): VBArray<T>;
|
||||
}
|
||||
|
||||
declare var VBArray: VBArrayConstructor;
|
||||
|
||||
/**
|
||||
* Automation date (VT_DATE)
|
||||
*/
|
||||
declare class VarDate {
|
||||
private constructor();
|
||||
private VarDate_typekey: VarDate;
|
||||
}
|
||||
|
||||
interface DateConstructor {
|
||||
new (vd: VarDate): Date;
|
||||
}
|
||||
|
||||
interface Date {
|
||||
getVarDate: () => VarDate;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
var checkPrivateRedeclaration = require("./checkPrivateRedeclaration.js");
|
||||
function _classPrivateMethodInitSpec(e, a) {
|
||||
checkPrivateRedeclaration(e, a), a.add(e);
|
||||
}
|
||||
module.exports = _classPrivateMethodInitSpec, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"reg": {
|
||||
"name": "reg",
|
||||
"browser": "Chrome Mobile 55.0.2883 (Android 6.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 294647.6540008401,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.024928682964508394,
|
||||
"rhz": 0.7543996843123166,
|
||||
"sampleSize": 152
|
||||
},
|
||||
"fn if": {
|
||||
"name": "fn if",
|
||||
"browser": "Chrome Mobile 55.0.2883 (Android 6.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 172908.7333875609,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.016138250187070446,
|
||||
"rhz": 0.44270603248056595,
|
||||
"sampleSize": 150
|
||||
},
|
||||
"fn if reverse": {
|
||||
"name": "fn if reverse",
|
||||
"browser": "Chrome Mobile 55.0.2883 (Android 6.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 124965.18805848437,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.027301864775113205,
|
||||
"rhz": 0.31995400995482254,
|
||||
"sampleSize": 147
|
||||
},
|
||||
"escape31": {
|
||||
"name": "escape31",
|
||||
"browser": "Chrome Mobile 55.0.2883 (Android 6.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 188347.98186648387,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.026531318695469853,
|
||||
"rhz": 0.48223583704668577,
|
||||
"sampleSize": 144
|
||||
},
|
||||
"native": {
|
||||
"name": "native",
|
||||
"browser": "Chrome Mobile 55.0.2883 (Android 6.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 390572.3453071566,
|
||||
"success": true,
|
||||
"fastest": true,
|
||||
"rme": 0.024051025167801422,
|
||||
"rhz": 1,
|
||||
"sampleSize": 149
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"name": "source-map-js",
|
||||
"description": "Generates and consumes source maps",
|
||||
"version": "1.2.1",
|
||||
"homepage": "https://github.com/7rulnik/source-map-js",
|
||||
"author": "Valentin 7rulnik Semirulnik <v7rulnik@gmail.com>",
|
||||
"contributors": [
|
||||
"Nick Fitzgerald <nfitzgerald@mozilla.com>",
|
||||
"Tobias Koppers <tobias.koppers@googlemail.com>",
|
||||
"Duncan Beevers <duncan@dweebd.com>",
|
||||
"Stephen Crane <scrane@mozilla.com>",
|
||||
"Ryan Seddon <seddon.ryan@gmail.com>",
|
||||
"Miles Elam <miles.elam@deem.com>",
|
||||
"Mihai Bazon <mihai.bazon@gmail.com>",
|
||||
"Michael Ficarra <github.public.email@michael.ficarra.me>",
|
||||
"Todd Wolfson <todd@twolfson.com>",
|
||||
"Alexander Solovyov <alexander@solovyov.net>",
|
||||
"Felix Gnass <fgnass@gmail.com>",
|
||||
"Conrad Irwin <conrad.irwin@gmail.com>",
|
||||
"usrbincc <usrbincc@yahoo.com>",
|
||||
"David Glasser <glasser@davidglasser.net>",
|
||||
"Chase Douglas <chase@newrelic.com>",
|
||||
"Evan Wallace <evan.exe@gmail.com>",
|
||||
"Heather Arthur <fayearthur@gmail.com>",
|
||||
"Hugh Kennedy <hughskennedy@gmail.com>",
|
||||
"David Glasser <glasser@davidglasser.net>",
|
||||
"Simon Lydell <simon.lydell@gmail.com>",
|
||||
"Jmeas Smith <jellyes2@gmail.com>",
|
||||
"Michael Z Goddard <mzgoddard@gmail.com>",
|
||||
"azu <azu@users.noreply.github.com>",
|
||||
"John Gozde <john@gozde.ca>",
|
||||
"Adam Kirkton <akirkton@truefitinnovation.com>",
|
||||
"Chris Montgomery <christopher.montgomery@dowjones.com>",
|
||||
"J. Ryan Stinnett <jryans@gmail.com>",
|
||||
"Jack Herrington <jherrington@walmartlabs.com>",
|
||||
"Chris Truter <jeffpalentine@gmail.com>",
|
||||
"Daniel Espeset <daniel@danielespeset.com>",
|
||||
"Jamie Wong <jamie.lf.wong@gmail.com>",
|
||||
"Eddy Bruël <ejpbruel@mozilla.com>",
|
||||
"Hawken Rives <hawkrives@gmail.com>",
|
||||
"Gilad Peleg <giladp007@gmail.com>",
|
||||
"djchie <djchie.dev@gmail.com>",
|
||||
"Gary Ye <garysye@gmail.com>",
|
||||
"Nicolas Lalevée <nicolas.lalevee@hibnet.org>"
|
||||
],
|
||||
"repository": "7rulnik/source-map-js",
|
||||
"main": "./source-map.js",
|
||||
"files": [
|
||||
"source-map.js",
|
||||
"source-map.d.ts",
|
||||
"lib/"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"license": "BSD-3-Clause",
|
||||
"scripts": {
|
||||
"test": "npm run build && node test/run-tests.js",
|
||||
"build": "webpack --color",
|
||||
"toc": "doctoc --title '## Table of Contents' README.md && doctoc --title '## Table of Contents' CONTRIBUTING.md"
|
||||
},
|
||||
"devDependencies": {
|
||||
"clean-publish": "^3.1.0",
|
||||
"doctoc": "^0.15.0",
|
||||
"webpack": "^1.12.0"
|
||||
},
|
||||
"clean-publish": {
|
||||
"cleanDocs": true
|
||||
},
|
||||
"typings": "source-map.d.ts"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { RAL } from '../common/api';
|
||||
interface RIL extends RAL {
|
||||
readonly stream: {
|
||||
readonly asReadableStream: (stream: NodeJS.ReadableStream) => RAL.ReadableStream;
|
||||
readonly asWritableStream: (stream: NodeJS.WritableStream) => RAL.WritableStream;
|
||||
};
|
||||
}
|
||||
declare function RIL(): RIL;
|
||||
declare namespace RIL {
|
||||
function install(): void;
|
||||
}
|
||||
export default RIL;
|
||||
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ParameterDefinition = void 0;
|
||||
const DefinitionBase_1 = require("./DefinitionBase");
|
||||
const DefinitionType_1 = require("./DefinitionType");
|
||||
class ParameterDefinition extends DefinitionBase_1.DefinitionBase {
|
||||
/**
|
||||
* Whether the parameter definition is a part of a rest parameter.
|
||||
*/
|
||||
isTypeDefinition = false;
|
||||
isVariableDefinition = true;
|
||||
rest;
|
||||
constructor(name, node, rest) {
|
||||
super(DefinitionType_1.DefinitionType.Parameter, name, node, null);
|
||||
this.rest = rest;
|
||||
}
|
||||
}
|
||||
exports.ParameterDefinition = ParameterDefinition;
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"name": "glob-parent",
|
||||
"version": "6.0.2",
|
||||
"description": "Extract the non-magic parent path from a glob string.",
|
||||
"author": "Gulp Team <team@gulpjs.com> (https://gulpjs.com/)",
|
||||
"contributors": [
|
||||
"Elan Shanker (https://github.com/es128)",
|
||||
"Blaine Bublitz <blaine.bublitz@gmail.com>"
|
||||
],
|
||||
"repository": "gulpjs/glob-parent",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"LICENSE",
|
||||
"index.js"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"pretest": "npm run lint",
|
||||
"test": "nyc mocha --async-only"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^7.0.0",
|
||||
"eslint-config-gulp": "^5.0.0",
|
||||
"expect": "^26.0.1",
|
||||
"mocha": "^7.1.2",
|
||||
"nyc": "^15.0.1"
|
||||
},
|
||||
"nyc": {
|
||||
"reporter": [
|
||||
"lcov",
|
||||
"text-summary"
|
||||
]
|
||||
},
|
||||
"prettier": {
|
||||
"singleQuote": true
|
||||
},
|
||||
"keywords": [
|
||||
"glob",
|
||||
"parent",
|
||||
"strip",
|
||||
"path",
|
||||
"dirname",
|
||||
"directory",
|
||||
"base",
|
||||
"wildcard"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import { _ as _overload_yield } from "./_overload_yield.js";
|
||||
|
||||
function _async_generator_delegate(inner) {
|
||||
var iter = {}, waiting = false;
|
||||
|
||||
function pump(key, value) {
|
||||
waiting = true;
|
||||
value = new Promise(function(resolve) {
|
||||
resolve(inner[key](value));
|
||||
});
|
||||
|
||||
return { done: false, value: new _overload_yield(value, /* kind: delegate */ 1) };
|
||||
}
|
||||
|
||||
iter[(typeof Symbol !== "undefined" && Symbol.iterator) || "@@iterator"] = function() {
|
||||
return this;
|
||||
};
|
||||
|
||||
iter.next = function(value) {
|
||||
if (waiting) {
|
||||
waiting = false;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return pump("next", value);
|
||||
};
|
||||
|
||||
if (typeof inner.throw === "function") {
|
||||
iter.throw = function(value) {
|
||||
if (waiting) {
|
||||
waiting = false;
|
||||
throw value;
|
||||
}
|
||||
|
||||
return pump("throw", value);
|
||||
};
|
||||
}
|
||||
if (typeof inner.return === "function") {
|
||||
iter.return = function(value) {
|
||||
if (waiting) {
|
||||
waiting = false;
|
||||
return value;
|
||||
}
|
||||
return pump("return", value);
|
||||
};
|
||||
}
|
||||
|
||||
return iter;
|
||||
}
|
||||
export { _async_generator_delegate as _ };
|
||||
@@ -0,0 +1,113 @@
|
||||
import MockAgent from './mock-agent'
|
||||
|
||||
declare class SnapshotRecorder {
|
||||
constructor (options?: SnapshotRecorder.Options)
|
||||
|
||||
record (requestOpts: any, response: any): Promise<void>
|
||||
findSnapshot (requestOpts: any): SnapshotRecorder.Snapshot | undefined
|
||||
loadSnapshots (filePath?: string): Promise<void>
|
||||
saveSnapshots (filePath?: string): Promise<void>
|
||||
clear (): void
|
||||
getSnapshots (): SnapshotRecorder.Snapshot[]
|
||||
size (): number
|
||||
resetCallCounts (): void
|
||||
deleteSnapshot (requestOpts: any): boolean
|
||||
getSnapshotInfo (requestOpts: any): SnapshotRecorder.SnapshotInfo | null
|
||||
replaceSnapshots (snapshotData: SnapshotRecorder.SnapshotData[]): void
|
||||
destroy (): void
|
||||
}
|
||||
|
||||
declare namespace SnapshotRecorder {
|
||||
type SnapshotRecorderMode = 'record' | 'playback' | 'update'
|
||||
|
||||
export interface Options {
|
||||
snapshotPath?: string
|
||||
mode?: SnapshotRecorderMode
|
||||
maxSnapshots?: number
|
||||
autoFlush?: boolean
|
||||
flushInterval?: number
|
||||
matchHeaders?: string[]
|
||||
ignoreHeaders?: string[]
|
||||
excludeHeaders?: string[]
|
||||
matchBody?: boolean
|
||||
normalizeBody?: (body: string | Buffer | null | undefined) => string
|
||||
matchQuery?: boolean
|
||||
normalizeQuery?: (query: URLSearchParams) => string
|
||||
caseSensitive?: boolean
|
||||
shouldRecord?: (requestOpts: any) => boolean
|
||||
shouldPlayback?: (requestOpts: any) => boolean
|
||||
excludeUrls?: (string | RegExp)[]
|
||||
}
|
||||
|
||||
export interface Snapshot {
|
||||
request: {
|
||||
method: string
|
||||
url: string
|
||||
headers: Record<string, string>
|
||||
body?: string
|
||||
}
|
||||
responses: {
|
||||
statusCode: number
|
||||
headers: Record<string, string>
|
||||
body: string
|
||||
trailers: Record<string, string>
|
||||
}[]
|
||||
callCount: number
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
export interface SnapshotInfo {
|
||||
hash: string
|
||||
request: {
|
||||
method: string
|
||||
url: string
|
||||
headers: Record<string, string>
|
||||
body?: string
|
||||
}
|
||||
responseCount: number
|
||||
callCount: number
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
export interface SnapshotData {
|
||||
hash: string
|
||||
snapshot: Snapshot
|
||||
}
|
||||
}
|
||||
|
||||
declare class SnapshotAgent extends MockAgent {
|
||||
constructor (options?: SnapshotAgent.Options)
|
||||
|
||||
saveSnapshots (filePath?: string): Promise<void>
|
||||
loadSnapshots (filePath?: string): Promise<void>
|
||||
getRecorder (): SnapshotRecorder
|
||||
getMode (): SnapshotRecorder.SnapshotRecorderMode
|
||||
clearSnapshots (): void
|
||||
resetCallCounts (): void
|
||||
deleteSnapshot (requestOpts: any): boolean
|
||||
getSnapshotInfo (requestOpts: any): SnapshotRecorder.SnapshotInfo | null
|
||||
replaceSnapshots (snapshotData: SnapshotRecorder.SnapshotData[]): void
|
||||
}
|
||||
|
||||
declare namespace SnapshotAgent {
|
||||
export interface Options extends MockAgent.Options {
|
||||
mode?: SnapshotRecorder.SnapshotRecorderMode
|
||||
snapshotPath?: string
|
||||
maxSnapshots?: number
|
||||
autoFlush?: boolean
|
||||
flushInterval?: number
|
||||
matchHeaders?: string[]
|
||||
ignoreHeaders?: string[]
|
||||
excludeHeaders?: string[]
|
||||
matchBody?: boolean
|
||||
normalizeBody?: (body: string | Buffer | null | undefined) => string
|
||||
matchQuery?: boolean
|
||||
normalizeQuery?: (query: URLSearchParams) => string
|
||||
caseSensitive?: boolean
|
||||
shouldRecord?: (requestOpts: any) => boolean
|
||||
shouldPlayback?: (requestOpts: any) => boolean
|
||||
excludeUrls?: (string | RegExp)[]
|
||||
}
|
||||
}
|
||||
|
||||
export { SnapshotAgent, SnapshotRecorder }
|
||||
@@ -0,0 +1,6 @@
|
||||
import _typeof from "./typeof.js";
|
||||
function _checkInRHS(e) {
|
||||
if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? _typeof(e) : "null"));
|
||||
return e;
|
||||
}
|
||||
export { _checkInRHS as default };
|
||||
@@ -0,0 +1,139 @@
|
||||
import Container, {
|
||||
ContainerProps,
|
||||
ContainerWithChildren
|
||||
} from './container.js'
|
||||
|
||||
declare namespace AtRule {
|
||||
export interface AtRuleRaws extends Record<string, unknown> {
|
||||
/**
|
||||
* The space symbols after the last child of the node to the end of the node.
|
||||
*/
|
||||
after?: string
|
||||
|
||||
/**
|
||||
* The space between the at-rule name and its parameters.
|
||||
*/
|
||||
afterName?: string
|
||||
|
||||
/**
|
||||
* The space symbols before the node. It also stores `*`
|
||||
* and `_` symbols before the declaration (IE hack).
|
||||
*/
|
||||
before?: string
|
||||
|
||||
/**
|
||||
* The symbols between the last parameter and `{` for rules.
|
||||
*/
|
||||
between?: string
|
||||
|
||||
/**
|
||||
* The rule’s selector with comments.
|
||||
*/
|
||||
params?: {
|
||||
raw: string
|
||||
value: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains `true` if the last child has an (optional) semicolon.
|
||||
*/
|
||||
semicolon?: boolean
|
||||
}
|
||||
|
||||
export interface AtRuleProps extends ContainerProps {
|
||||
/** Name of the at-rule. */
|
||||
name: string
|
||||
/** Parameters following the name of the at-rule. */
|
||||
params?: number | string
|
||||
/** Information used to generate byte-to-byte equal node string as it was in the origin input. */
|
||||
raws?: AtRuleRaws
|
||||
}
|
||||
|
||||
export { AtRule_ as default }
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an at-rule.
|
||||
*
|
||||
* ```js
|
||||
* Once (root, { AtRule }) {
|
||||
* let media = new AtRule({ name: 'media', params: 'print' })
|
||||
* media.append(…)
|
||||
* root.append(media)
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If it’s followed in the CSS by a `{}` block, this node will have
|
||||
* a nodes property representing its children.
|
||||
*
|
||||
* ```js
|
||||
* const root = postcss.parse('@charset "UTF-8"; @media print {}')
|
||||
*
|
||||
* const charset = root.first
|
||||
* charset.type //=> 'atrule'
|
||||
* charset.nodes //=> undefined
|
||||
*
|
||||
* const media = root.last
|
||||
* media.nodes //=> []
|
||||
* ```
|
||||
*/
|
||||
declare class AtRule_ extends Container {
|
||||
/**
|
||||
* An array containing the layer’s children.
|
||||
*
|
||||
* ```js
|
||||
* const root = postcss.parse('@layer example { a { color: black } }')
|
||||
* const layer = root.first
|
||||
* layer.nodes.length //=> 1
|
||||
* layer.nodes[0].selector //=> 'a'
|
||||
* ```
|
||||
*
|
||||
* Can be `undefinded` if the at-rule has no body.
|
||||
*
|
||||
* ```js
|
||||
* const root = postcss.parse('@layer a, b, c;')
|
||||
* const layer = root.first
|
||||
* layer.nodes //=> undefined
|
||||
* ```
|
||||
*/
|
||||
nodes: Container['nodes'] | undefined
|
||||
parent: ContainerWithChildren | undefined
|
||||
|
||||
raws: AtRule.AtRuleRaws
|
||||
type: 'atrule'
|
||||
/**
|
||||
* The at-rule’s name immediately follows the `@`.
|
||||
*
|
||||
* ```js
|
||||
* const root = postcss.parse('@media print {}')
|
||||
* const media = root.first
|
||||
* media.name //=> 'media'
|
||||
* ```
|
||||
*/
|
||||
get name(): string
|
||||
set name(value: string)
|
||||
|
||||
/**
|
||||
* The at-rule’s parameters, the values that follow the at-rule’s name
|
||||
* but precede any `{}` block.
|
||||
*
|
||||
* ```js
|
||||
* const root = postcss.parse('@media print, screen {}')
|
||||
* const media = root.first
|
||||
* media.params //=> 'print, screen'
|
||||
* ```
|
||||
*/
|
||||
get params(): string
|
||||
|
||||
set params(value: string)
|
||||
|
||||
constructor(defaults?: AtRule.AtRuleProps)
|
||||
assign(overrides: AtRule.AtRuleProps | object): this
|
||||
clone(overrides?: Partial<AtRule.AtRuleProps>): this
|
||||
cloneAfter(overrides?: Partial<AtRule.AtRuleProps>): this
|
||||
cloneBefore(overrides?: Partial<AtRule.AtRuleProps>): this
|
||||
}
|
||||
|
||||
declare class AtRule extends AtRule_ {}
|
||||
|
||||
export = AtRule
|
||||
@@ -0,0 +1,496 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/v4";
|
||||
|
||||
test("successful validation", () => {
|
||||
const testTuple = z.tuple([z.string(), z.number()]);
|
||||
expectTypeOf<typeof testTuple._output>().toEqualTypeOf<[string, number]>();
|
||||
|
||||
const val = testTuple.parse(["asdf", 1234]);
|
||||
expect(val).toEqual(val);
|
||||
|
||||
const r1 = testTuple.safeParse(["asdf", "asdf"]);
|
||||
expect(r1.success).toEqual(false);
|
||||
expect(r1.error!).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"expected": "number",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
1
|
||||
],
|
||||
"message": "Invalid input: expected number, received string"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
|
||||
const r2 = testTuple.safeParse(["asdf", 1234, true]);
|
||||
expect(r2.success).toEqual(false);
|
||||
expect(r2.error!).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "too_big",
|
||||
"maximum": 2,
|
||||
"inclusive": true,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
"message": "Too big: expected array to have <=2 items"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
|
||||
const r3 = testTuple.safeParse({});
|
||||
expect(r3.success).toEqual(false);
|
||||
expect(r3.error!).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"expected": "tuple",
|
||||
"code": "invalid_type",
|
||||
"path": [],
|
||||
"message": "Invalid input: expected tuple, received object"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("async validation", async () => {
|
||||
const testTuple = z
|
||||
.tuple([z.string().refine(async () => true), z.number().refine(async () => true)])
|
||||
.refine(async () => true);
|
||||
expectTypeOf<typeof testTuple._output>().toEqualTypeOf<[string, number]>();
|
||||
|
||||
const val = await testTuple.parseAsync(["asdf", 1234]);
|
||||
expect(val).toEqual(val);
|
||||
|
||||
const r1 = await testTuple.safeParseAsync(["asdf", "asdf"]);
|
||||
expect(r1.success).toEqual(false);
|
||||
expect(r1.error!).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"expected": "number",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
1
|
||||
],
|
||||
"message": "Invalid input: expected number, received string"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
|
||||
const r2 = await testTuple.safeParseAsync(["asdf", 1234, true]);
|
||||
expect(r2.success).toEqual(false);
|
||||
expect(r2.error!).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"code": "too_big",
|
||||
"maximum": 2,
|
||||
"inclusive": true,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
"message": "Too big: expected array to have <=2 items"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
|
||||
const r3 = await testTuple.safeParseAsync({});
|
||||
expect(r3.success).toEqual(false);
|
||||
expect(r3.error!).toMatchInlineSnapshot(`
|
||||
[ZodError: [
|
||||
{
|
||||
"expected": "tuple",
|
||||
"code": "invalid_type",
|
||||
"path": [],
|
||||
"message": "Invalid input: expected tuple, received object"
|
||||
}
|
||||
]]
|
||||
`);
|
||||
});
|
||||
|
||||
test("tuple with optional elements", () => {
|
||||
const myTuple = z.tuple([z.string(), z.number().optional(), z.string().optional()]).rest(z.boolean());
|
||||
expectTypeOf<typeof myTuple._output>().toEqualTypeOf<
|
||||
[string, (number | undefined)?, (string | undefined)?, ...boolean[]]
|
||||
>();
|
||||
|
||||
const goodData = [["asdf"], ["asdf", 1234], ["asdf", 1234, "asdf"], ["asdf", 1234, "asdf", true, false, true]];
|
||||
for (const data of goodData) {
|
||||
expect(myTuple.parse(data)).toEqual(data);
|
||||
}
|
||||
|
||||
const badData = [
|
||||
["asdf", "asdf"],
|
||||
["asdf", 1234, "asdf", "asdf"],
|
||||
["asdf", 1234, "asdf", true, false, "asdf"],
|
||||
];
|
||||
for (const data of badData) {
|
||||
expect(() => myTuple.parse(data)).toThrow();
|
||||
}
|
||||
});
|
||||
|
||||
test("tuple with optional elements followed by required", () => {
|
||||
const myTuple = z.tuple([z.string(), z.number().optional(), z.string()]).rest(z.boolean());
|
||||
expectTypeOf<typeof myTuple._output>().toEqualTypeOf<[string, number | undefined, string, ...boolean[]]>();
|
||||
|
||||
const goodData = [
|
||||
["asdf", 1234, "asdf"],
|
||||
["asdf", 1234, "asdf", true, false, true],
|
||||
];
|
||||
for (const data of goodData) {
|
||||
expect(myTuple.parse(data)).toEqual(data);
|
||||
}
|
||||
|
||||
const badData = [
|
||||
["asdf"],
|
||||
["asdf", 1234],
|
||||
["asdf", 1234, "asdf", "asdf"],
|
||||
["asdf", 1234, "asdf", true, false, "asdf"],
|
||||
];
|
||||
for (const data of badData) {
|
||||
expect(() => myTuple.parse(data)).toThrow();
|
||||
}
|
||||
});
|
||||
|
||||
test("tuple with all optional elements", () => {
|
||||
const allOptionalTuple = z.tuple([z.string().optional(), z.number().optional(), z.boolean().optional()]);
|
||||
expectTypeOf<typeof allOptionalTuple._output>().toEqualTypeOf<
|
||||
[(string | undefined)?, (number | undefined)?, (boolean | undefined)?]
|
||||
>();
|
||||
|
||||
// Empty array should be valid (all items optional)
|
||||
expect(allOptionalTuple.parse([])).toEqual([]);
|
||||
|
||||
// Partial arrays should be valid
|
||||
expect(allOptionalTuple.parse(["hello"])).toEqual(["hello"]);
|
||||
expect(allOptionalTuple.parse(["hello", 42])).toEqual(["hello", 42]);
|
||||
|
||||
// Full array should be valid
|
||||
expect(allOptionalTuple.parse(["hello", 42, true])).toEqual(["hello", 42, true]);
|
||||
|
||||
// Array that's too long should fail
|
||||
expect(() => allOptionalTuple.parse(["hello", 42, true, "extra"])).toThrow();
|
||||
});
|
||||
|
||||
test("tuple fills defaults for missing trailing elements", () => {
|
||||
// Issue #5229: trailing `.default()`/`.prefault()` elements should be
|
||||
// filled in when the input array is shorter than the tuple.
|
||||
const t = z.tuple([z.string(), z.string().default("bravo")]);
|
||||
expectTypeOf<typeof t._output>().toEqualTypeOf<[string, string]>();
|
||||
expectTypeOf<typeof t._input>().toEqualTypeOf<[string, (string | undefined)?]>();
|
||||
|
||||
expect(t.parse(["alpha", "charlie"])).toEqual(["alpha", "charlie"]);
|
||||
expect(t.parse(["alpha"])).toEqual(["alpha", "bravo"]);
|
||||
|
||||
// Multiple trailing defaults
|
||||
const multi = z.tuple([z.string(), z.number().default(42), z.boolean().default(true)]);
|
||||
expect(multi.parse(["hello"])).toEqual(["hello", 42, true]);
|
||||
expect(multi.parse(["hello", 100])).toEqual(["hello", 100, true]);
|
||||
expect(multi.parse(["hello", 100, false])).toEqual(["hello", 100, false]);
|
||||
|
||||
// Prefault parity
|
||||
expect(z.tuple([z.string(), z.string().prefault("delta")]).parse(["alpha"])).toEqual(["alpha", "delta"]);
|
||||
|
||||
// Defaults wrapped in modifiers: `optout` propagates through these, so the
|
||||
// fix is not type-name specific.
|
||||
expect(z.tuple([z.string(), z.string().default("x").nullable()]).parse(["alpha"])).toEqual(["alpha", "x"]);
|
||||
expect(z.tuple([z.string(), z.string().default("x").readonly()]).parse(["alpha"])).toEqual(["alpha", "x"]);
|
||||
expect(z.tuple([z.string(), z.string().default("x").catch("y")]).parse(["alpha"])).toEqual(["alpha", "x"]);
|
||||
expect(z.tuple([z.string(), z.string().default("x").pipe(z.string())]).parse(["alpha"])).toEqual(["alpha", "x"]);
|
||||
});
|
||||
|
||||
test("tuple fills defaults under async parse", async () => {
|
||||
const t = z.tuple([z.string(), z.string().default("zulu")]);
|
||||
await expect(t.parseAsync(["alpha"])).resolves.toEqual(["alpha", "zulu"]);
|
||||
});
|
||||
|
||||
test("tuple keeps length-1 array for missing `.optional()` elements", () => {
|
||||
// Backwards compat: a trailing `.optional()` element that is omitted from
|
||||
// the input must NOT be filled with `undefined` — the result stays length-1.
|
||||
// Only schemas that produce a defined value get materialized.
|
||||
const t = z.tuple([z.string(), z.string().optional()]);
|
||||
const out = t.parse(["alpha"]);
|
||||
expect(out).toEqual(["alpha"]);
|
||||
expect(out.length).toEqual(1);
|
||||
|
||||
// `z.undefined()` is NOT a synonym for `.optional()` — its value type is
|
||||
// *must be undefined*, so the slot is required input. Omitting it triggers
|
||||
// a single `too_small` (no element-level errors, matching v3's abort
|
||||
// semantics); passing explicit `undefined` succeeds and is preserved.
|
||||
expect(z.tuple([z.string(), z.undefined()]).safeParse(["alpha"]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(z.tuple([z.string(), z.undefined()]).parse(["alpha", undefined])).toHaveLength(2);
|
||||
|
||||
// `.optional().nullable()` still trims — `.optional()` propagates the
|
||||
// optin/optout flags through the nullable wrapper.
|
||||
expect(z.tuple([z.string(), z.string().optional().nullable()]).parse(["alpha"])).toHaveLength(1);
|
||||
|
||||
// Multiple trailing optionals trim the same way — we don't fill the tail
|
||||
// with literal `undefined`s.
|
||||
const many = z.tuple([z.string(), z.string().optional(), z.string().optional(), z.string().optional()]);
|
||||
expect(many.parse(["alpha"])).toEqual(["alpha"]);
|
||||
expect(many.parse(["alpha", "beta"])).toEqual(["alpha", "beta"]);
|
||||
|
||||
// Explicit `undefined` inside `input.length` IS preserved — only slots
|
||||
// past the input get trimmed.
|
||||
const r = many.parse(["alpha", undefined]);
|
||||
expect(r.length).toEqual(2);
|
||||
expect(1 in r).toEqual(true);
|
||||
|
||||
// Trailing optionals after a default that fires are still trimmed.
|
||||
expect(
|
||||
z.tuple([z.string(), z.string().default("d"), z.string().optional(), z.string().optional()]).parse(["alpha"])
|
||||
).toEqual(["alpha", "d"]);
|
||||
});
|
||||
|
||||
test("tuple result is dense when optional precedes a default", () => {
|
||||
// `.optional()` before a `.default()` must produce an explicit `undefined`
|
||||
// (not a sparse hole), otherwise `1 in r`, `JSON.stringify`, `Object.keys`,
|
||||
// and iteration all behave wrong.
|
||||
const t = z.tuple([z.string(), z.string().optional(), z.string().default("z")]);
|
||||
const r = t.parse(["alpha"]);
|
||||
expect(r).toEqual(["alpha", undefined, "z"]);
|
||||
expect(r.length).toEqual(3);
|
||||
expect(1 in r).toEqual(true);
|
||||
expect(JSON.stringify(r)).toEqual('["alpha",null,"z"]');
|
||||
|
||||
// Trailing optional after a default is still dropped (no later default
|
||||
// forces it to materialize).
|
||||
expect(z.tuple([z.string(), z.string().default("d"), z.string().optional()]).parse(["alpha"])).toEqual([
|
||||
"alpha",
|
||||
"d",
|
||||
]);
|
||||
|
||||
// Multiple interleaved optional/default — every slot up to the last
|
||||
// default must be present and dense.
|
||||
const interleaved = z.tuple([
|
||||
z.string(),
|
||||
z.string().optional(),
|
||||
z.string().default("d"),
|
||||
z.string().optional(),
|
||||
z.string().default("e"),
|
||||
]);
|
||||
const out = interleaved.parse(["alpha"]);
|
||||
expect(out).toEqual(["alpha", undefined, "d", undefined, "e"]);
|
||||
expect(1 in out && 3 in out).toEqual(true);
|
||||
});
|
||||
|
||||
test("tuple truncates absent optional rejections only when the output tail is optional", () => {
|
||||
// An absent optional-output slot can only be swallowed when every later
|
||||
// output slot is optional too. If a later default would make the output tail
|
||||
// required, truncating would violate the tuple's output type.
|
||||
const refusesUndefined = z
|
||||
.string()
|
||||
.optional()
|
||||
.refine((s) => s !== undefined, "must not be undefined");
|
||||
|
||||
const trailingDefault = z.tuple([z.string(), refusesUndefined, z.string().default("d")]);
|
||||
const r1 = trailingDefault.safeParse(["alpha"]);
|
||||
expect(r1.success).toBe(false);
|
||||
expect(r1.error!.issues[0].path).toEqual([1]);
|
||||
|
||||
// Optional slots BEFORE the rejected one still cannot hide a later required
|
||||
// output slot.
|
||||
const beforeReject = z.tuple([z.string(), z.string().optional(), refusesUndefined, z.string().default("d")]);
|
||||
const r2 = beforeReject.safeParse(["alpha"]);
|
||||
expect(r2.success).toBe(false);
|
||||
expect(r2.error!.issues[0].path).toEqual([2]);
|
||||
|
||||
// No default after — truncate still applies, no spurious issue surfaces.
|
||||
const noTrailingDefault = z.tuple([z.string(), refusesUndefined]);
|
||||
const r3 = noTrailingDefault.safeParse(["alpha"]);
|
||||
expect(r3.success).toBe(true);
|
||||
expect(r3.data).toEqual(["alpha"]);
|
||||
});
|
||||
|
||||
test("tuple rejects absent optional before required output under async parse", async () => {
|
||||
const refusesUndefined = z
|
||||
.string()
|
||||
.optional()
|
||||
.refine(async (s) => s !== undefined, "must not be undefined");
|
||||
|
||||
const schema = z.tuple([z.string(), refusesUndefined, z.string().default("d")]);
|
||||
const r = await schema.safeParseAsync(["alpha"]);
|
||||
expect(r.success).toBe(false);
|
||||
expect(r.error!.issues[0].path).toEqual([1]);
|
||||
});
|
||||
|
||||
test("tuple rejects absent exact optional before defaulted output", () => {
|
||||
const schema = z.tuple([z.string(), z.string().exactOptional(), z.string().default("fallback")]);
|
||||
expectTypeOf<typeof schema._output>().toEqualTypeOf<[string, string, string]>();
|
||||
|
||||
const missingExact = schema.safeParse(["alpha"]);
|
||||
expect(missingExact.success).toBe(false);
|
||||
expect(missingExact.error!.issues[0].path).toEqual([1]);
|
||||
|
||||
expect(schema.parse(["alpha", "bravo"])).toEqual(["alpha", "bravo", "fallback"]);
|
||||
expect(schema.safeParse(["alpha", undefined]).success).toBe(false);
|
||||
|
||||
// With no later required output slot, exact optional still behaves like an
|
||||
// omitted tuple tail and truncates cleanly.
|
||||
expect(z.tuple([z.string(), z.string().exactOptional(), z.string().optional()]).parse(["alpha"])).toEqual(["alpha"]);
|
||||
});
|
||||
|
||||
test("tuple preserves explicit undefined inside input even for optional-out schemas", () => {
|
||||
// The trim only runs for slots PAST `input.length`. An explicit `undefined`
|
||||
// value supplied by the caller at index < input.length must survive, even
|
||||
// when the schema produces undefined as a valid output (e.g.
|
||||
// `z.string().or(z.undefined())`, `z.string().optional()`, `z.undefined()`).
|
||||
const orUndefined = z.tuple([z.string(), z.string().or(z.undefined())]);
|
||||
const r1 = orUndefined.parse(["alpha", undefined]);
|
||||
expect(r1.length).toEqual(2);
|
||||
expect(r1[1]).toBeUndefined();
|
||||
expect(1 in r1).toEqual(true);
|
||||
expect(JSON.stringify(r1)).toEqual('["alpha",null]');
|
||||
|
||||
// Same for `.optional()`.
|
||||
const opt = z.tuple([z.string(), z.string().optional()]);
|
||||
const r2 = opt.parse(["alpha", undefined]);
|
||||
expect(r2.length).toEqual(2);
|
||||
expect(1 in r2).toEqual(true);
|
||||
|
||||
// Same for `z.undefined()` literal.
|
||||
const lit = z.tuple([z.string(), z.undefined()]);
|
||||
const r3 = lit.parse(["alpha", undefined]);
|
||||
expect(r3.length).toEqual(2);
|
||||
expect(1 in r3).toEqual(true);
|
||||
|
||||
// Mid-tuple explicit undefined surrounded by defined values is also kept.
|
||||
const mid = z.tuple([z.string(), z.string().or(z.undefined()), z.string()]);
|
||||
const r4 = mid.parse(["alpha", undefined, "gamma"]);
|
||||
expect(r4).toEqual(["alpha", undefined, "gamma"]);
|
||||
expect(r4.length).toEqual(3);
|
||||
expect(1 in r4).toEqual(true);
|
||||
});
|
||||
|
||||
test("tuple does NOT break when a required slot fails past input length", () => {
|
||||
// A required slot (no `.optional()` chain, so optout !== "optional") past
|
||||
// input length must still surface an issue rather than silently swallowing
|
||||
// it. Otherwise we'd accept arbitrarily short tuples for required-tail
|
||||
// schemas. The precheck collapses this into a single `too_small`.
|
||||
const schema = z.tuple([z.string(), z.string()]);
|
||||
expect(schema.safeParse(["alpha"]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test("tuple with rest schema", () => {
|
||||
const myTuple = z.tuple([z.string(), z.number()]).rest(z.boolean());
|
||||
expect(myTuple.parse(["asdf", 1234, true, false, true])).toEqual(["asdf", 1234, true, false, true]);
|
||||
|
||||
expect(myTuple.parse(["asdf", 1234])).toEqual(["asdf", 1234]);
|
||||
|
||||
expect(() => myTuple.parse(["asdf", 1234, "asdf"])).toThrow();
|
||||
type t1 = z.output<typeof myTuple>;
|
||||
|
||||
expectTypeOf<t1>().toEqualTypeOf<[string, number, ...boolean[]]>();
|
||||
});
|
||||
|
||||
test("sparse array input", () => {
|
||||
const schema = z.tuple([z.string(), z.number()]);
|
||||
expect(() => schema.parse(new Array(2))).toThrow();
|
||||
});
|
||||
|
||||
test("under-length tuple emits a single too_small with optStart minimum", () => {
|
||||
const allRequired = z.tuple([z.string(), z.string()]);
|
||||
expect(allRequired.safeParse(["a"]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(allRequired.safeParse([]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=2 items",
|
||||
"minimum": 2,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
const trailingOptional = z.tuple([z.string(), z.number().optional()]);
|
||||
expect(trailingOptional.safeParse([]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=1 items",
|
||||
"minimum": 1,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
const interiorOptional = z.tuple([z.string(), z.number().optional(), z.string()]);
|
||||
expect(interiorOptional.safeParse(["a", 1]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_small",
|
||||
"inclusive": true,
|
||||
"message": "Too small: expected array to have >=3 items",
|
||||
"minimum": 3,
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test("too_big tuple still surfaces element-wise type errors for present indices", () => {
|
||||
const schema = z.tuple([z.string(), z.number()]);
|
||||
expect(schema.safeParse([1, "x", "extra"]).error!.issues).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "too_big",
|
||||
"inclusive": true,
|
||||
"maximum": 2,
|
||||
"message": "Too big: expected array to have <=2 items",
|
||||
"origin": "array",
|
||||
"path": [],
|
||||
},
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"message": "Invalid input: expected string, received number",
|
||||
"path": [
|
||||
0,
|
||||
],
|
||||
},
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "number",
|
||||
"message": "Invalid input: expected number, received string",
|
||||
"path": [
|
||||
1,
|
||||
],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"hash-to-curve.d.ts","sourceRoot":"","sources":["../../src/abstract/hash-to-curve.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,sEAAsE;AACtE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAUzC,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAsB,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,UAAU,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,KAAK,GAAG,KAAK,CAAC;IACtB,IAAI,EAAE,KAAK,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX,CAAC;AACF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,KAAK,GAAG,KAAK,CAAC;IACtB,IAAI,EAAE,KAAK,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,IAAI,GAAG,OAAO,CAAC;AAmC3B;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,cAAc,EACnB,UAAU,EAAE,MAAM,EAClB,CAAC,EAAE,KAAK,GACP,UAAU,CAqBZ;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,cAAc,EACnB,UAAU,EAAE,MAAM,EAClB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,KAAK,GACP,UAAU,CAqBZ;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,EAAE,CAoC1F;AAED,MAAM,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK;IAAE,CAAC,EAAE,CAAC,CAAC;IAAC,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AACnD,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;AAC9C,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAgBnF;AAED,sFAAsF;AACtF,MAAM,WAAW,QAAQ,CAAC,CAAC,CAAE,SAAQ,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACrD,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;IACtC,aAAa,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC7B,cAAc,IAAI,IAAI,CAAC;CACxB;AAED,MAAM,WAAW,mBAAmB,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC3E,UAAU,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;CAC7C;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC;AAIjE,MAAM,MAAM,YAAY,GAAG;IAAE,GAAG,EAAE,cAAc,CAAA;CAAE,CAAC;AACnD,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC;AAEpF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;AACxC,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC9D,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI;IAC7B,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAC1B,YAAY,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,KAAK,MAAM,CAAC;CAClE,CAAC;AACF;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG;IAC5C,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAC5B,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IACzB,QAAQ,EAAE,OAAO,GAAG;QAAE,SAAS,CAAC,EAAE,cAAc,CAAA;KAAE,CAAC;CACpD,CAAC;AAEF,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;AAErC,eAAO,MAAM,WAAW,EAAE,UAAyC,CAAC;AAEpE,kGAAkG;AAClG,wBAAgB,YAAY,CAAC,CAAC,EAC5B,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAC7B,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EACzB,QAAQ,EAAE,OAAO,GAAG;IAAE,SAAS,CAAC,EAAE,cAAc,CAAA;CAAE,GACjD,SAAS,CAAC,CAAC,CAAC,CA8Cd"}
|
||||
@@ -0,0 +1,23 @@
|
||||
MIT License
|
||||
|
||||
Copyright Julian Gruber <julian@juliangruber.com>
|
||||
|
||||
TypeScript port Copyright Isaac Z. Schlueter <i@izs.me>
|
||||
|
||||
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 @@
|
||||
{"version":3,"file":"escape.d.ts","sourceRoot":"","sources":["../../src/escape.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAElD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,MAAM,GACjB,GAAG,MAAM,EACT,2CAGG,IAAI,CAAC,gBAAgB,EAAE,sBAAsB,GAAG,eAAe,CAAM,WAazE,CAAA"}
|
||||
@@ -0,0 +1,166 @@
|
||||
# Changes
|
||||
|
||||
|
||||
## 2.0.2
|
||||
|
||||
* Rename bin to `node-which`
|
||||
|
||||
## 2.0.1
|
||||
|
||||
* generate changelog and publish on version bump
|
||||
* enforce 100% test coverage
|
||||
* Promise interface
|
||||
|
||||
## 2.0.0
|
||||
|
||||
* Parallel tests, modern JavaScript, and drop support for node < 8
|
||||
|
||||
## 1.3.1
|
||||
|
||||
* update deps
|
||||
* update travis
|
||||
|
||||
## v1.3.0
|
||||
|
||||
* Add nothrow option to which.sync
|
||||
* update tap
|
||||
|
||||
## v1.2.14
|
||||
|
||||
* appveyor: drop node 5 and 0.x
|
||||
* travis-ci: add node 6, drop 0.x
|
||||
|
||||
## v1.2.13
|
||||
|
||||
* test: Pass missing option to pass on windows
|
||||
* update tap
|
||||
* update isexe to 2.0.0
|
||||
* neveragain.tech pledge request
|
||||
|
||||
## v1.2.12
|
||||
|
||||
* Removed unused require
|
||||
|
||||
## v1.2.11
|
||||
|
||||
* Prevent changelog script from being included in package
|
||||
|
||||
## v1.2.10
|
||||
|
||||
* Use env.PATH only, not env.Path
|
||||
|
||||
## v1.2.9
|
||||
|
||||
* fix for paths starting with ../
|
||||
* Remove unused `is-absolute` module
|
||||
|
||||
## v1.2.8
|
||||
|
||||
* bullet items in changelog that contain (but don't start with) #
|
||||
|
||||
## v1.2.7
|
||||
|
||||
* strip 'update changelog' changelog entries out of changelog
|
||||
|
||||
## v1.2.6
|
||||
|
||||
* make the changelog bulleted
|
||||
|
||||
## v1.2.5
|
||||
|
||||
* make a changelog, and keep it up to date
|
||||
* don't include tests in package
|
||||
* Properly handle relative-path executables
|
||||
* appveyor
|
||||
* Attach error code to Not Found error
|
||||
* Make tests pass on Windows
|
||||
|
||||
## v1.2.4
|
||||
|
||||
* Fix typo
|
||||
|
||||
## v1.2.3
|
||||
|
||||
* update isexe, fix regression in pathExt handling
|
||||
|
||||
## v1.2.2
|
||||
|
||||
* update deps, use isexe module, test windows
|
||||
|
||||
## v1.2.1
|
||||
|
||||
* Sometimes windows PATH entries are quoted
|
||||
* Fixed a bug in the check for group and user mode bits. This bug was introduced during refactoring for supporting strict mode.
|
||||
* doc cli
|
||||
|
||||
## v1.2.0
|
||||
|
||||
* Add support for opt.all and -as cli flags
|
||||
* test the bin
|
||||
* update travis
|
||||
* Allow checking for multiple programs in bin/which
|
||||
* tap 2
|
||||
|
||||
## v1.1.2
|
||||
|
||||
* travis
|
||||
* Refactored and fixed undefined error on Windows
|
||||
* Support strict mode
|
||||
|
||||
## v1.1.1
|
||||
|
||||
* test +g exes against secondary groups, if available
|
||||
* Use windows exe semantics on cygwin & msys
|
||||
* cwd should be first in path on win32, not last
|
||||
* Handle lower-case 'env.Path' on Windows
|
||||
* Update docs
|
||||
* use single-quotes
|
||||
|
||||
## v1.1.0
|
||||
|
||||
* Add tests, depend on is-absolute
|
||||
|
||||
## v1.0.9
|
||||
|
||||
* which.js: root is allowed to execute files owned by anyone
|
||||
|
||||
## v1.0.8
|
||||
|
||||
* don't use graceful-fs
|
||||
|
||||
## v1.0.7
|
||||
|
||||
* add license to package.json
|
||||
|
||||
## v1.0.6
|
||||
|
||||
* isc license
|
||||
|
||||
## 1.0.5
|
||||
|
||||
* Awful typo
|
||||
|
||||
## 1.0.4
|
||||
|
||||
* Test for path absoluteness properly
|
||||
* win: Allow '' as a pathext if cmd has a . in it
|
||||
|
||||
## 1.0.3
|
||||
|
||||
* Remove references to execPath
|
||||
* Make `which.sync()` work on Windows by honoring the PATHEXT variable.
|
||||
* Make `isExe()` always return true on Windows.
|
||||
* MIT
|
||||
|
||||
## 1.0.2
|
||||
|
||||
* Only files can be exes
|
||||
|
||||
## 1.0.1
|
||||
|
||||
* Respect the PATHEXT env for win32 support
|
||||
* should 0755 the bin
|
||||
* binary
|
||||
* guts
|
||||
* package
|
||||
* 1st
|
||||
@@ -0,0 +1,124 @@
|
||||
import { type ZodErrorMap, ZodIssueCode } from "../ZodError.js";
|
||||
import { util, ZodParsedType } from "../helpers/util.js";
|
||||
|
||||
const errorMap: ZodErrorMap = (issue, _ctx) => {
|
||||
let message: string;
|
||||
switch (issue.code) {
|
||||
case ZodIssueCode.invalid_type:
|
||||
if (issue.received === ZodParsedType.undefined) {
|
||||
message = "Required";
|
||||
} else {
|
||||
message = `Expected ${issue.expected}, received ${issue.received}`;
|
||||
}
|
||||
break;
|
||||
case ZodIssueCode.invalid_literal:
|
||||
message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util.jsonStringifyReplacer)}`;
|
||||
break;
|
||||
case ZodIssueCode.unrecognized_keys:
|
||||
message = `Unrecognized key(s) in object: ${util.joinValues(issue.keys, ", ")}`;
|
||||
break;
|
||||
case ZodIssueCode.invalid_union:
|
||||
message = `Invalid input`;
|
||||
break;
|
||||
case ZodIssueCode.invalid_union_discriminator:
|
||||
message = `Invalid discriminator value. Expected ${util.joinValues(issue.options)}`;
|
||||
break;
|
||||
case ZodIssueCode.invalid_enum_value:
|
||||
message = `Invalid enum value. Expected ${util.joinValues(issue.options)}, received '${issue.received}'`;
|
||||
break;
|
||||
case ZodIssueCode.invalid_arguments:
|
||||
message = `Invalid function arguments`;
|
||||
break;
|
||||
case ZodIssueCode.invalid_return_type:
|
||||
message = `Invalid function return type`;
|
||||
break;
|
||||
case ZodIssueCode.invalid_date:
|
||||
message = `Invalid date`;
|
||||
break;
|
||||
case ZodIssueCode.invalid_string:
|
||||
if (typeof issue.validation === "object") {
|
||||
if ("includes" in issue.validation) {
|
||||
message = `Invalid input: must include "${issue.validation.includes}"`;
|
||||
|
||||
if (typeof issue.validation.position === "number") {
|
||||
message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`;
|
||||
}
|
||||
} else if ("startsWith" in issue.validation) {
|
||||
message = `Invalid input: must start with "${issue.validation.startsWith}"`;
|
||||
} else if ("endsWith" in issue.validation) {
|
||||
message = `Invalid input: must end with "${issue.validation.endsWith}"`;
|
||||
} else {
|
||||
util.assertNever(issue.validation);
|
||||
}
|
||||
} else if (issue.validation !== "regex") {
|
||||
message = `Invalid ${issue.validation}`;
|
||||
} else {
|
||||
message = "Invalid";
|
||||
}
|
||||
break;
|
||||
case ZodIssueCode.too_small:
|
||||
if (issue.type === "array")
|
||||
message = `Array must contain ${
|
||||
issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`
|
||||
} ${issue.minimum} element(s)`;
|
||||
else if (issue.type === "string")
|
||||
message = `String must contain ${
|
||||
issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`
|
||||
} ${issue.minimum} character(s)`;
|
||||
else if (issue.type === "number")
|
||||
message = `Number must be ${
|
||||
issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `
|
||||
}${issue.minimum}`;
|
||||
else if (issue.type === "bigint")
|
||||
message = `Number must be ${
|
||||
issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `
|
||||
}${issue.minimum}`;
|
||||
else if (issue.type === "date")
|
||||
message = `Date must be ${
|
||||
issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `
|
||||
}${new Date(Number(issue.minimum))}`;
|
||||
else message = "Invalid input";
|
||||
break;
|
||||
case ZodIssueCode.too_big:
|
||||
if (issue.type === "array")
|
||||
message = `Array must contain ${
|
||||
issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`
|
||||
} ${issue.maximum} element(s)`;
|
||||
else if (issue.type === "string")
|
||||
message = `String must contain ${
|
||||
issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`
|
||||
} ${issue.maximum} character(s)`;
|
||||
else if (issue.type === "number")
|
||||
message = `Number must be ${
|
||||
issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`
|
||||
} ${issue.maximum}`;
|
||||
else if (issue.type === "bigint")
|
||||
message = `BigInt must be ${
|
||||
issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`
|
||||
} ${issue.maximum}`;
|
||||
else if (issue.type === "date")
|
||||
message = `Date must be ${
|
||||
issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`
|
||||
} ${new Date(Number(issue.maximum))}`;
|
||||
else message = "Invalid input";
|
||||
break;
|
||||
case ZodIssueCode.custom:
|
||||
message = `Invalid input`;
|
||||
break;
|
||||
case ZodIssueCode.invalid_intersection_types:
|
||||
message = `Intersection results could not be merged`;
|
||||
break;
|
||||
case ZodIssueCode.not_multiple_of:
|
||||
message = `Number must be a multiple of ${issue.multipleOf}`;
|
||||
break;
|
||||
case ZodIssueCode.not_finite:
|
||||
message = "Number must be finite";
|
||||
break;
|
||||
default:
|
||||
message = _ctx.defaultError;
|
||||
util.assertNever(issue);
|
||||
}
|
||||
return { message };
|
||||
};
|
||||
|
||||
export default errorMap;
|
||||
@@ -0,0 +1,515 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const fs = require('fs')
|
||||
const proxyquire = require('proxyquire')
|
||||
const SonicBoom = require('../')
|
||||
const { file, runTests } = require('./helper')
|
||||
|
||||
runTests(buildTests)
|
||||
|
||||
function buildTests (test, sync) {
|
||||
// Reset the umask for testing
|
||||
process.umask(0o000)
|
||||
|
||||
test('write things to a file descriptor', (t) => {
|
||||
t.plan(6)
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, sync })
|
||||
|
||||
stream.on('ready', () => {
|
||||
t.pass('ready emitted')
|
||||
})
|
||||
|
||||
t.ok(stream.write('hello world\n'))
|
||||
t.ok(stream.write('something else\n'))
|
||||
|
||||
stream.end()
|
||||
|
||||
stream.on('finish', () => {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, 'hello world\nsomething else\n')
|
||||
})
|
||||
})
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('write things in a streaming fashion', (t) => {
|
||||
t.plan(8)
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, sync })
|
||||
|
||||
stream.once('drain', () => {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, 'hello world\n')
|
||||
t.ok(stream.write('something else\n'))
|
||||
})
|
||||
|
||||
stream.once('drain', () => {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, 'hello world\nsomething else\n')
|
||||
stream.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.ok(stream.write('hello world\n'))
|
||||
|
||||
stream.on('finish', () => {
|
||||
t.pass('finish emitted')
|
||||
})
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('can be piped into', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, sync })
|
||||
const source = fs.createReadStream(__filename, { encoding: 'utf8' })
|
||||
|
||||
source.pipe(stream)
|
||||
|
||||
stream.on('finish', () => {
|
||||
fs.readFile(__filename, 'utf8', (err, expected) => {
|
||||
t.error(err)
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, expected)
|
||||
})
|
||||
})
|
||||
})
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('write things to a file', (t) => {
|
||||
t.plan(6)
|
||||
|
||||
const dest = file()
|
||||
const stream = new SonicBoom({ dest, sync })
|
||||
|
||||
stream.on('ready', () => {
|
||||
t.pass('ready emitted')
|
||||
})
|
||||
|
||||
t.ok(stream.write('hello world\n'))
|
||||
t.ok(stream.write('something else\n'))
|
||||
|
||||
stream.end()
|
||||
|
||||
stream.on('finish', () => {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, 'hello world\nsomething else\n')
|
||||
})
|
||||
})
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('minLength', (t) => {
|
||||
t.plan(8)
|
||||
|
||||
const dest = file()
|
||||
const stream = new SonicBoom({ dest, minLength: 4096, sync })
|
||||
|
||||
stream.on('ready', () => {
|
||||
t.pass('ready emitted')
|
||||
})
|
||||
|
||||
t.ok(stream.write('hello world\n'))
|
||||
t.ok(stream.write('something else\n'))
|
||||
|
||||
const fail = t.fail
|
||||
stream.on('drain', fail)
|
||||
|
||||
// bad use of timer
|
||||
// TODO refactor
|
||||
setTimeout(function () {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, '')
|
||||
|
||||
stream.end()
|
||||
|
||||
stream.on('finish', () => {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, 'hello world\nsomething else\n')
|
||||
})
|
||||
})
|
||||
})
|
||||
}, 100)
|
||||
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('write later on recoverable error', (t) => {
|
||||
t.plan(8)
|
||||
|
||||
const fakeFs = Object.create(fs)
|
||||
const SonicBoom = proxyquire('../', {
|
||||
fs: fakeFs
|
||||
})
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, minLength: 0, sync })
|
||||
|
||||
stream.on('ready', () => {
|
||||
t.pass('ready emitted')
|
||||
})
|
||||
stream.on('error', () => {
|
||||
t.pass('error emitted')
|
||||
})
|
||||
|
||||
if (sync) {
|
||||
fakeFs.writeSync = function (fd, buf, enc) {
|
||||
t.pass('fake fs.writeSync called')
|
||||
throw new Error('recoverable error')
|
||||
}
|
||||
} else {
|
||||
fakeFs.write = function (fd, buf, ...args) {
|
||||
t.pass('fake fs.write called')
|
||||
setTimeout(() => args.pop()(new Error('recoverable error')), 0)
|
||||
}
|
||||
}
|
||||
|
||||
t.ok(stream.write('hello world\n'))
|
||||
|
||||
setTimeout(() => {
|
||||
if (sync) {
|
||||
fakeFs.writeSync = fs.writeSync
|
||||
} else {
|
||||
fakeFs.write = fs.write
|
||||
}
|
||||
|
||||
t.ok(stream.write('something else\n'))
|
||||
|
||||
stream.end()
|
||||
stream.on('finish', () => {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, 'hello world\nsomething else\n')
|
||||
})
|
||||
})
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
}, 0)
|
||||
})
|
||||
|
||||
test('emit write events', (t) => {
|
||||
t.plan(7)
|
||||
|
||||
const dest = file()
|
||||
const stream = new SonicBoom({ dest, sync })
|
||||
|
||||
stream.on('ready', () => {
|
||||
t.pass('ready emitted')
|
||||
})
|
||||
|
||||
let length = 0
|
||||
stream.on('write', (bytes) => {
|
||||
length += bytes
|
||||
})
|
||||
|
||||
t.ok(stream.write('hello world\n'))
|
||||
t.ok(stream.write('something else\n'))
|
||||
|
||||
stream.end()
|
||||
|
||||
stream.on('finish', () => {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, 'hello world\nsomething else\n')
|
||||
t.equal(length, 27)
|
||||
})
|
||||
})
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('write multi-byte characters string over than maxWrite', (t) => {
|
||||
const fakeFs = Object.create(fs)
|
||||
const MAX_WRITE = 65535
|
||||
fakeFs.write = function (fd, buf, ...args) {
|
||||
// only write byteLength === MAX_WRITE
|
||||
const _buf = Buffer.from(buf).subarray(0, MAX_WRITE)
|
||||
fs.writeSync(fd, _buf)
|
||||
setImmediate(args[args.length - 1], null, MAX_WRITE)
|
||||
fakeFs.write = function (fd, buf, ...args) {
|
||||
fs.write(fd, buf, ...args)
|
||||
}
|
||||
}
|
||||
const SonicBoom = proxyquire('../', {
|
||||
fs: fakeFs
|
||||
})
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, minLength: 0, sync, maxWrite: MAX_WRITE })
|
||||
let buf = Buffer.alloc(MAX_WRITE).fill('x')
|
||||
buf = '🌲' + buf.toString()
|
||||
stream.write(buf)
|
||||
stream.end()
|
||||
|
||||
stream.on('finish', () => {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, buf)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
stream.on('error', () => {
|
||||
t.pass('error emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('partial writes must preserve split utf8 characters', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
const fakeFs = Object.create(fs)
|
||||
const SonicBoom = proxyquire('../', {
|
||||
fs: fakeFs
|
||||
})
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, minLength: 0, sync })
|
||||
|
||||
const input = 'hello🌍world'
|
||||
let calls = 0
|
||||
|
||||
if (sync) {
|
||||
fakeFs.writeSync = function (fd, buf, enc) {
|
||||
calls++
|
||||
if (calls === 1) {
|
||||
const first = Buffer.from(buf).subarray(0, 7)
|
||||
fs.writeSync(fd, first)
|
||||
return 7
|
||||
}
|
||||
return fs.writeSync(fd, buf)
|
||||
}
|
||||
} else {
|
||||
fakeFs.write = function (fd, buf, ...args) {
|
||||
calls++
|
||||
const cb = args[args.length - 1]
|
||||
if (calls === 1) {
|
||||
const first = Buffer.from(buf).subarray(0, 7)
|
||||
fs.write(fd, first, (err, n) => cb(err, n))
|
||||
return
|
||||
}
|
||||
fs.write(fd, buf, cb)
|
||||
}
|
||||
}
|
||||
|
||||
stream.write(input)
|
||||
stream.end()
|
||||
|
||||
stream.on('close', () => {
|
||||
const data = fs.readFileSync(dest, 'utf8')
|
||||
t.equal(calls, 2)
|
||||
t.equal(data, input)
|
||||
t.equal(data.includes('<27>'), false)
|
||||
t.equal(data.includes('🌍'), true)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
test('write buffers that are not totally written', (t) => {
|
||||
t.plan(9)
|
||||
|
||||
const fakeFs = Object.create(fs)
|
||||
fakeFs.write = function (fd, buf, ...args) {
|
||||
t.pass('fake fs.write called')
|
||||
fakeFs.write = function (fd, buf, ...args) {
|
||||
t.pass('calling real fs.write, ' + buf)
|
||||
fs.write(fd, buf, ...args)
|
||||
}
|
||||
process.nextTick(args[args.length - 1], null, 0)
|
||||
}
|
||||
const SonicBoom = proxyquire('../', {
|
||||
fs: fakeFs
|
||||
})
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, minLength: 0, sync: false })
|
||||
|
||||
stream.on('ready', () => {
|
||||
t.pass('ready emitted')
|
||||
})
|
||||
|
||||
t.ok(stream.write('hello world\n'))
|
||||
t.ok(stream.write('something else\n'))
|
||||
|
||||
stream.end()
|
||||
|
||||
stream.on('finish', () => {
|
||||
fs.readFile(dest, 'utf8', (err, data) => {
|
||||
t.error(err)
|
||||
t.equal(data, 'hello world\nsomething else\n')
|
||||
})
|
||||
})
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('write enormously large buffers async', (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, minLength: 0, sync: false })
|
||||
|
||||
const buf = Buffer.alloc(1024).fill('x').toString() // 1 MB
|
||||
let length = 0
|
||||
|
||||
for (let i = 0; i < 1024 * 512; i++) {
|
||||
length += buf.length
|
||||
stream.write(buf)
|
||||
}
|
||||
|
||||
stream.end()
|
||||
|
||||
stream.on('finish', () => {
|
||||
fs.stat(dest, (err, stat) => {
|
||||
t.error(err)
|
||||
t.equal(stat.size, length)
|
||||
})
|
||||
})
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('make sure `maxWrite` is passed', (t) => {
|
||||
t.plan(1)
|
||||
const dest = file()
|
||||
const stream = new SonicBoom({ dest, maxLength: 65536 })
|
||||
t.equal(stream.maxLength, 65536)
|
||||
})
|
||||
|
||||
test('write enormously large buffers async atomicly', (t) => {
|
||||
const fakeFs = Object.create(fs)
|
||||
const SonicBoom = proxyquire('../', {
|
||||
fs: fakeFs
|
||||
})
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, minLength: 0, sync: false })
|
||||
|
||||
const buf = Buffer.alloc(1023).fill('x').toString()
|
||||
|
||||
fakeFs.write = function (fd, _buf, ...args) {
|
||||
if (_buf.length % buf.length !== 0) {
|
||||
t.fail('write called with wrong buffer size')
|
||||
}
|
||||
|
||||
setImmediate(args[args.length - 1], null, _buf.length)
|
||||
}
|
||||
|
||||
for (let i = 0; i < 1024 * 512; i++) {
|
||||
stream.write(buf)
|
||||
}
|
||||
|
||||
setImmediate(() => {
|
||||
for (let i = 0; i < 1024 * 512; i++) {
|
||||
stream.write(buf)
|
||||
}
|
||||
|
||||
stream.end()
|
||||
})
|
||||
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test('write should not drop new data if buffer is not full', (t) => {
|
||||
t.plan(2)
|
||||
const fakeFs = Object.create(fs)
|
||||
const SonicBoom = proxyquire('../', {
|
||||
fs: fakeFs
|
||||
})
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, minLength: 101, maxLength: 102, sync: false })
|
||||
|
||||
const buf = Buffer.alloc(100).fill('x').toString()
|
||||
|
||||
fakeFs.write = function (fd, _buf, ...args) {
|
||||
t.equal(_buf.length, buf.length + 2)
|
||||
setImmediate(args[args.length - 1], null, _buf.length)
|
||||
fakeFs.write = () => t.error('shouldnt call write again')
|
||||
stream.end()
|
||||
}
|
||||
|
||||
stream.on('drop', (data) => {
|
||||
t.error('should not drop')
|
||||
})
|
||||
|
||||
stream.write(buf)
|
||||
stream.write('aa')
|
||||
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
|
||||
test('write should drop new data if buffer is full', (t) => {
|
||||
t.plan(3)
|
||||
const fakeFs = Object.create(fs)
|
||||
const SonicBoom = proxyquire('../', {
|
||||
fs: fakeFs
|
||||
})
|
||||
|
||||
const dest = file()
|
||||
const fd = fs.openSync(dest, 'w')
|
||||
const stream = new SonicBoom({ fd, minLength: 101, maxLength: 102, sync: false })
|
||||
|
||||
const buf = Buffer.alloc(100).fill('x').toString()
|
||||
|
||||
fakeFs.write = function (fd, _buf, ...args) {
|
||||
t.equal(_buf.length, buf.length)
|
||||
setImmediate(args[args.length - 1], null, _buf.length)
|
||||
fakeFs.write = () => t.error('shouldnt call write more than once')
|
||||
}
|
||||
|
||||
stream.on('drop', (data) => {
|
||||
t.equal(data.length, 3)
|
||||
stream.end()
|
||||
})
|
||||
|
||||
stream.write(buf)
|
||||
stream.write('aaa')
|
||||
|
||||
stream.on('close', () => {
|
||||
t.pass('close emitted')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { TSESTree } from '@typescript-eslint/types';
|
||||
import type { ScopeManager } from '../ScopeManager';
|
||||
import type { Scope } from './Scope';
|
||||
import { ScopeBase } from './ScopeBase';
|
||||
import { ScopeType } from './ScopeType';
|
||||
export declare class MappedTypeScope extends ScopeBase<ScopeType.mappedType, TSESTree.TSMappedType, Scope> {
|
||||
constructor(scopeManager: ScopeManager, upperScope: MappedTypeScope['upper'], block: MappedTypeScope['block']);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user