WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Internal assertion helpers.
|
||||
* @module
|
||||
* @deprecated
|
||||
*/
|
||||
import { abytes as ab, aexists as ae, anumber as an, aoutput as ao, } from "./utils.js";
|
||||
/** @deprecated Use import from `noble/hashes/utils` module */
|
||||
export const abytes = ab;
|
||||
/** @deprecated Use import from `noble/hashes/utils` module */
|
||||
export const aexists = ae;
|
||||
/** @deprecated Use import from `noble/hashes/utils` module */
|
||||
export const anumber = an;
|
||||
/** @deprecated Use import from `noble/hashes/utils` module */
|
||||
export const aoutput = ao;
|
||||
//# sourceMappingURL=_assert.js.map
|
||||
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.slugify = exports.toUpperCase = exports.toLowerCase = exports.trim = exports.normalize = exports.overwrite = exports.mime = exports.property = exports.endsWith = exports.startsWith = exports.includes = exports.uppercase = exports.lowercase = exports.regex = exports.length = exports.minLength = exports.maxLength = exports.size = exports.minSize = exports.maxSize = exports.multipleOf = exports.nonnegative = exports.nonpositive = exports.negative = exports.positive = exports.gte = exports.gt = exports.lte = exports.lt = void 0;
|
||||
var index_js_1 = require("../core/index.cjs");
|
||||
Object.defineProperty(exports, "lt", { enumerable: true, get: function () { return index_js_1._lt; } });
|
||||
Object.defineProperty(exports, "lte", { enumerable: true, get: function () { return index_js_1._lte; } });
|
||||
Object.defineProperty(exports, "gt", { enumerable: true, get: function () { return index_js_1._gt; } });
|
||||
Object.defineProperty(exports, "gte", { enumerable: true, get: function () { return index_js_1._gte; } });
|
||||
Object.defineProperty(exports, "positive", { enumerable: true, get: function () { return index_js_1._positive; } });
|
||||
Object.defineProperty(exports, "negative", { enumerable: true, get: function () { return index_js_1._negative; } });
|
||||
Object.defineProperty(exports, "nonpositive", { enumerable: true, get: function () { return index_js_1._nonpositive; } });
|
||||
Object.defineProperty(exports, "nonnegative", { enumerable: true, get: function () { return index_js_1._nonnegative; } });
|
||||
Object.defineProperty(exports, "multipleOf", { enumerable: true, get: function () { return index_js_1._multipleOf; } });
|
||||
Object.defineProperty(exports, "maxSize", { enumerable: true, get: function () { return index_js_1._maxSize; } });
|
||||
Object.defineProperty(exports, "minSize", { enumerable: true, get: function () { return index_js_1._minSize; } });
|
||||
Object.defineProperty(exports, "size", { enumerable: true, get: function () { return index_js_1._size; } });
|
||||
Object.defineProperty(exports, "maxLength", { enumerable: true, get: function () { return index_js_1._maxLength; } });
|
||||
Object.defineProperty(exports, "minLength", { enumerable: true, get: function () { return index_js_1._minLength; } });
|
||||
Object.defineProperty(exports, "length", { enumerable: true, get: function () { return index_js_1._length; } });
|
||||
Object.defineProperty(exports, "regex", { enumerable: true, get: function () { return index_js_1._regex; } });
|
||||
Object.defineProperty(exports, "lowercase", { enumerable: true, get: function () { return index_js_1._lowercase; } });
|
||||
Object.defineProperty(exports, "uppercase", { enumerable: true, get: function () { return index_js_1._uppercase; } });
|
||||
Object.defineProperty(exports, "includes", { enumerable: true, get: function () { return index_js_1._includes; } });
|
||||
Object.defineProperty(exports, "startsWith", { enumerable: true, get: function () { return index_js_1._startsWith; } });
|
||||
Object.defineProperty(exports, "endsWith", { enumerable: true, get: function () { return index_js_1._endsWith; } });
|
||||
Object.defineProperty(exports, "property", { enumerable: true, get: function () { return index_js_1._property; } });
|
||||
Object.defineProperty(exports, "mime", { enumerable: true, get: function () { return index_js_1._mime; } });
|
||||
Object.defineProperty(exports, "overwrite", { enumerable: true, get: function () { return index_js_1._overwrite; } });
|
||||
Object.defineProperty(exports, "normalize", { enumerable: true, get: function () { return index_js_1._normalize; } });
|
||||
Object.defineProperty(exports, "trim", { enumerable: true, get: function () { return index_js_1._trim; } });
|
||||
Object.defineProperty(exports, "toLowerCase", { enumerable: true, get: function () { return index_js_1._toLowerCase; } });
|
||||
Object.defineProperty(exports, "toUpperCase", { enumerable: true, get: function () { return index_js_1._toUpperCase; } });
|
||||
Object.defineProperty(exports, "slugify", { enumerable: true, get: function () { return index_js_1._slugify; } });
|
||||
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* @fileoverview Main Espree file that converts Acorn into Esprima output.
|
||||
*
|
||||
* This file contains code from the following MIT-licensed projects:
|
||||
* 1. Acorn
|
||||
* 2. Babylon
|
||||
* 3. Babel-ESLint
|
||||
*
|
||||
* This file also contains code from Esprima, which is BSD licensed.
|
||||
*
|
||||
* Acorn is Copyright 2012-2015 Acorn Contributors (https://github.com/marijnh/acorn/blob/master/AUTHORS)
|
||||
* Babylon is Copyright 2014-2015 various contributors (https://github.com/babel/babel/blob/master/packages/babylon/AUTHORS)
|
||||
* Babel-ESLint is Copyright 2014-2015 Sebastian McKenzie <sebmck@gmail.com>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Esprima is Copyright (c) jQuery Foundation, Inc. and Contributors, All Rights Reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import * as acorn from "acorn";
|
||||
import jsx from "acorn-jsx";
|
||||
import espree from "./lib/espree.js";
|
||||
import { KEYS as VisitorKeys } from "eslint-visitor-keys";
|
||||
import {
|
||||
getLatestEcmaVersion,
|
||||
getSupportedEcmaVersions,
|
||||
} from "./lib/options.js";
|
||||
|
||||
/**
|
||||
* @import { EspreeParserCtor, EspreeParserJsxCtor } from "./lib/types.js";
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Types exported from file
|
||||
// ----------------------------------------------------------------------------
|
||||
/**
|
||||
* @typedef {3|5|6|7|8|9|10|11|12|13|14|15|16|17|2015|2016|2017|2018|2019|2020|2021|2022|2023|2024|2025|2026|'latest'} EcmaVersion
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* type: string;
|
||||
* value: any;
|
||||
* start?: number;
|
||||
* end?: number;
|
||||
* loc?: acorn.SourceLocation;
|
||||
* range?: [number, number];
|
||||
* regex?: {flags: string, pattern: string};
|
||||
* }} EspreeToken
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* type: "Block" | "Hashbang" | "Line",
|
||||
* value: string,
|
||||
* range?: [number, number],
|
||||
* start?: number,
|
||||
* end?: number,
|
||||
* loc?: {
|
||||
* start: acorn.Position | undefined,
|
||||
* end: acorn.Position | undefined
|
||||
* }
|
||||
* }} EspreeComment
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* comments?: EspreeComment[]
|
||||
* } & EspreeToken[]} EspreeTokens
|
||||
*/
|
||||
|
||||
/**
|
||||
* `allowReserved` is as in `acorn.Options`
|
||||
*
|
||||
* `ecmaVersion` currently as in `acorn.Options` though optional
|
||||
*
|
||||
* `sourceType` as in `acorn.Options` but also allows `commonjs`
|
||||
*
|
||||
* `ecmaFeatures`, `range`, `loc`, `tokens` are not in `acorn.Options`
|
||||
*
|
||||
* `comment` is not in `acorn.Options` and doesn't err without it, but is used
|
||||
*/
|
||||
/**
|
||||
* @typedef {{
|
||||
* allowReserved?: boolean,
|
||||
* ecmaVersion?: EcmaVersion,
|
||||
* sourceType?: "script"|"module"|"commonjs",
|
||||
* ecmaFeatures?: {
|
||||
* jsx?: boolean,
|
||||
* globalReturn?: boolean,
|
||||
* impliedStrict?: boolean
|
||||
* },
|
||||
* range?: boolean,
|
||||
* loc?: boolean,
|
||||
* tokens?: boolean,
|
||||
* comment?: boolean,
|
||||
* }} Options
|
||||
*/
|
||||
|
||||
// To initialize lazily.
|
||||
const parsers = {
|
||||
/** @type {EspreeParserCtor|null} */
|
||||
_regular: null,
|
||||
|
||||
/** @type {EspreeParserJsxCtor|null} */
|
||||
_jsx: null,
|
||||
|
||||
/**
|
||||
* Returns regular Parser
|
||||
* @returns {EspreeParserCtor} Regular Acorn parser
|
||||
*/
|
||||
get regular() {
|
||||
if (this._regular === null) {
|
||||
const espreeParserFactory = /** @type {unknown} */ (espree());
|
||||
|
||||
this._regular = /** @type {EspreeParserCtor} */ (
|
||||
// Without conversion, types are incompatible, as
|
||||
// acorn's has a protected constructor
|
||||
/** @type {unknown} */
|
||||
(
|
||||
acorn.Parser.extend(
|
||||
/**
|
||||
* @type {(
|
||||
* BaseParser: typeof acorn.Parser
|
||||
* ) => typeof acorn.Parser}
|
||||
*/ (espreeParserFactory),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return this._regular;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns JSX Parser
|
||||
* @returns {EspreeParserJsxCtor} JSX Acorn parser
|
||||
*/
|
||||
get jsx() {
|
||||
if (this._jsx === null) {
|
||||
const espreeParserFactory = /** @type {unknown} */ (espree());
|
||||
const jsxFactory = jsx();
|
||||
|
||||
this._jsx = /** @type {EspreeParserJsxCtor} */ (
|
||||
// Without conversion, types are incompatible, as
|
||||
// acorn's has a protected constructor
|
||||
/** @type {unknown} */
|
||||
(
|
||||
acorn.Parser.extend(
|
||||
jsxFactory,
|
||||
|
||||
/** @type {(BaseParser: typeof acorn.Parser) => typeof acorn.Parser} */
|
||||
(espreeParserFactory),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return this._jsx;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the parser object based on the supplied options.
|
||||
* @param {Options} [options] The parser options.
|
||||
* @returns {EspreeParserJsxCtor|EspreeParserCtor} Regular or JSX Acorn parser
|
||||
*/
|
||||
get(options) {
|
||||
const useJsx = Boolean(
|
||||
options && options.ecmaFeatures && options.ecmaFeatures.jsx,
|
||||
);
|
||||
|
||||
return useJsx ? this.jsx : this.regular;
|
||||
},
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tokenizer
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Tokenizes the given code.
|
||||
* @param {string} code The code to tokenize.
|
||||
* @param {Options} [options] Options defining how to tokenize.
|
||||
* @returns {EspreeTokens} An array of tokens.
|
||||
* @throws {EnhancedSyntaxError} If the input code is invalid.
|
||||
* @private
|
||||
*/
|
||||
export function tokenize(code, options) {
|
||||
const Parser = parsers.get(options);
|
||||
|
||||
// Ensure to collect tokens.
|
||||
if (!options || options.tokens !== true) {
|
||||
options = Object.assign({}, options, { tokens: true }); // eslint-disable-line no-param-reassign -- stylistic choice
|
||||
}
|
||||
|
||||
return /** @type {EspreeTokens} */ (new Parser(options, code).tokenize());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Parser
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parses the given code.
|
||||
* @param {string} code The code to tokenize.
|
||||
* @param {Options} [options] Options defining how to tokenize.
|
||||
* @returns {acorn.Program} The "Program" AST node.
|
||||
* @throws {EnhancedSyntaxError} If the input code is invalid.
|
||||
*/
|
||||
export function parse(code, options) {
|
||||
const Parser = parsers.get(options);
|
||||
|
||||
return new Parser(options, code).parse();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {string} */
|
||||
export const version = "11.2.0"; // x-release-please-version
|
||||
export const name = "espree";
|
||||
|
||||
// Derive node types from VisitorKeys
|
||||
export const Syntax = /* #__PURE__ */ (function () {
|
||||
let key,
|
||||
/** @type {Record<string,string>} */
|
||||
types = {};
|
||||
|
||||
if (typeof Object.create === "function") {
|
||||
types = Object.create(null);
|
||||
}
|
||||
|
||||
for (key in VisitorKeys) {
|
||||
if (Object.hasOwn(VisitorKeys, key)) {
|
||||
types[key] = key;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof Object.freeze === "function") {
|
||||
Object.freeze(types);
|
||||
}
|
||||
|
||||
return types;
|
||||
})();
|
||||
|
||||
export const latestEcmaVersion = /* #__PURE__ */ getLatestEcmaVersion();
|
||||
|
||||
export const supportedEcmaVersions = /* #__PURE__ */ getSupportedEcmaVersions();
|
||||
|
||||
export { KEYS as VisitorKeys } from "eslint-visitor-keys";
|
||||
@@ -0,0 +1,24 @@
|
||||
/*! *****************************************************************************
|
||||
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,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
|
||||
/// <reference lib="es2017" />
|
||||
/// <reference lib="es2018.asynciterable" />
|
||||
/// <reference lib="es2018.asyncgenerator" />
|
||||
/// <reference lib="es2018.promise" />
|
||||
/// <reference lib="es2018.regexp" />
|
||||
/// <reference lib="es2018.intl" />
|
||||
@@ -0,0 +1,203 @@
|
||||
'use strict';
|
||||
|
||||
const {Readable, Writable, Duplex, Transform} = require('stream');
|
||||
|
||||
const none = Symbol.for('object-stream.none');
|
||||
const finalSymbol = Symbol.for('object-stream.final');
|
||||
const manySymbol = Symbol.for('object-stream.many');
|
||||
|
||||
const final = value => ({[finalSymbol]: value});
|
||||
const many = values => ({[manySymbol]: values});
|
||||
|
||||
const isFinal = o => o && typeof o == 'object' && finalSymbol in o;
|
||||
const isMany = o => o && typeof o == 'object' && manySymbol in o;
|
||||
|
||||
const getFinalValue = o => o[finalSymbol];
|
||||
const getManyValues = o => o[manySymbol];
|
||||
|
||||
const runAsyncGenerator = async (gen, stream) => {
|
||||
for (;;) {
|
||||
let data = gen.next();
|
||||
if (data && typeof data.then == 'function') {
|
||||
data = await data;
|
||||
}
|
||||
if (data.done) break;
|
||||
let value = data.value;
|
||||
if (value && typeof value.then == 'function') {
|
||||
value = await value;
|
||||
}
|
||||
Chain.sanitize(value, stream);
|
||||
}
|
||||
};
|
||||
|
||||
const wrapFunction = fn =>
|
||||
new Transform({
|
||||
writableObjectMode: true,
|
||||
readableObjectMode: true,
|
||||
transform(chunk, encoding, callback) {
|
||||
try {
|
||||
const result = fn.call(this, chunk, encoding);
|
||||
if (result && typeof result.then == 'function') {
|
||||
// thenable
|
||||
result.then(
|
||||
result => (Chain.sanitize(result, this), callback(null)),
|
||||
error => callback(error)
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (result && typeof result.next == 'function') {
|
||||
// generator
|
||||
runAsyncGenerator(result, this).then(
|
||||
() => callback(null),
|
||||
error => callback(error)
|
||||
);
|
||||
return;
|
||||
}
|
||||
Chain.sanitize(result, this);
|
||||
callback(null);
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const wrapArray = fns =>
|
||||
new Transform({
|
||||
writableObjectMode: true,
|
||||
readableObjectMode: true,
|
||||
transform(chunk, encoding, callback) {
|
||||
try {
|
||||
let value = chunk;
|
||||
for (let i = 0; i < fns.length; ++i) {
|
||||
const result = fns[i].call(this, value, encoding);
|
||||
if (result === Chain.none) {
|
||||
callback(null);
|
||||
return;
|
||||
}
|
||||
if (Chain.isFinal(result)) {
|
||||
value = Chain.getFinalValue(result);
|
||||
break;
|
||||
}
|
||||
value = result;
|
||||
}
|
||||
Chain.sanitize(value, this);
|
||||
callback(null);
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// is*NodeStream functions taken from https://github.com/nodejs/node/blob/master/lib/internal/streams/utils.js
|
||||
const isReadableNodeStream = obj =>
|
||||
obj &&
|
||||
typeof obj.pipe === 'function' &&
|
||||
typeof obj.on === 'function' &&
|
||||
(!obj._writableState || (typeof obj._readableState === 'object' ? obj._readableState.readable : null) !== false) && // Duplex
|
||||
(!obj._writableState || obj._readableState); // Writable has .pipe.
|
||||
|
||||
const isWritableNodeStream = obj =>
|
||||
obj &&
|
||||
typeof obj.write === 'function' &&
|
||||
typeof obj.on === 'function' &&
|
||||
(!obj._readableState || (typeof obj._writableState === 'object' ? obj._writableState.writable : null) !== false); // Duplex
|
||||
|
||||
const isDuplexNodeStream = obj =>
|
||||
obj && typeof obj.pipe === 'function' && obj._readableState && typeof obj.on === 'function' && typeof obj.write === 'function';
|
||||
|
||||
class Chain extends Duplex {
|
||||
constructor(fns, options) {
|
||||
super(options || {writableObjectMode: true, readableObjectMode: true});
|
||||
|
||||
if (!(fns instanceof Array) || !fns.length) {
|
||||
throw Error("Chain's argument should be a non-empty array.");
|
||||
}
|
||||
|
||||
this.streams = fns
|
||||
.filter(fn => fn)
|
||||
.map((fn, index, fns) => {
|
||||
if (typeof fn === 'function' || fn instanceof Array) return Chain.convertToTransform(fn);
|
||||
if (isDuplexNodeStream(fn) || (!index && isReadableNodeStream(fn)) || (index === fns.length - 1 && isWritableNodeStream(fn))) {
|
||||
return fn;
|
||||
}
|
||||
throw Error('Arguments should be functions, arrays or streams.');
|
||||
})
|
||||
.filter(s => s);
|
||||
this.input = this.streams[0];
|
||||
this.output = this.streams.reduce((output, stream) => (output && output.pipe(stream)) || stream);
|
||||
|
||||
if (!isWritableNodeStream(this.input)) {
|
||||
this._write = (_1, _2, callback) => callback(null);
|
||||
this._final = callback => callback(null); // unavailable in Node 6
|
||||
this.input.on('end', () => this.end());
|
||||
}
|
||||
|
||||
if (isReadableNodeStream(this.output)) {
|
||||
this.output.on('data', chunk => !this.push(chunk) && this.output.pause());
|
||||
this.output.on('end', () => this.push(null));
|
||||
} else {
|
||||
this._read = () => {}; // nop
|
||||
this.resume();
|
||||
this.output.on('finish', () => this.push(null));
|
||||
}
|
||||
|
||||
// connect events
|
||||
if (!options || !options.skipEvents) {
|
||||
this.streams.forEach(stream => stream.on('error', error => this.emit('error', error)));
|
||||
}
|
||||
}
|
||||
_write(chunk, encoding, callback) {
|
||||
let error = null;
|
||||
try {
|
||||
this.input.write(chunk, encoding, e => callback(e || error));
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
}
|
||||
_final(callback) {
|
||||
let error = null;
|
||||
try {
|
||||
this.input.end(null, null, e => callback(e || error));
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
}
|
||||
_read() {
|
||||
this.output.resume();
|
||||
}
|
||||
static make(fns, options) {
|
||||
return new Chain(fns, options);
|
||||
}
|
||||
static sanitize(result, stream) {
|
||||
if (Chain.isFinal(result)) {
|
||||
result = Chain.getFinalValue(result);
|
||||
} else if (Chain.isMany(result)) {
|
||||
result = Chain.getManyValues(result);
|
||||
}
|
||||
if (result !== undefined && result !== null && result !== Chain.none) {
|
||||
if (result instanceof Array) {
|
||||
result.forEach(value => value !== undefined && value !== null && stream.push(value));
|
||||
} else {
|
||||
stream.push(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
static convertToTransform(fn) {
|
||||
if (typeof fn === 'function') return wrapFunction(fn);
|
||||
if (fn instanceof Array) return fn.length ? wrapArray(fn) : null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Chain.none = none;
|
||||
Chain.final = final;
|
||||
Chain.isFinal = isFinal;
|
||||
Chain.getFinalValue = getFinalValue;
|
||||
Chain.many = many;
|
||||
Chain.isMany = isMany;
|
||||
Chain.getManyValues = getManyValues;
|
||||
|
||||
Chain.chain = Chain.make;
|
||||
Chain.make.Constructor = Chain;
|
||||
|
||||
module.exports = Chain;
|
||||
@@ -0,0 +1,828 @@
|
||||
const EventEmitter = require('events').EventEmitter
|
||||
const utils = require('./utils')
|
||||
const nodeUtils = require('util')
|
||||
const sasl = require('./crypto/sasl')
|
||||
const TypeOverrides = require('./type-overrides')
|
||||
|
||||
const ConnectionParameters = require('./connection-parameters')
|
||||
const Query = require('./query')
|
||||
const defaults = require('./defaults')
|
||||
const Connection = require('./connection')
|
||||
const crypto = require('./crypto/utils')
|
||||
|
||||
const activeQueryDeprecationNotice = nodeUtils.deprecate(
|
||||
() => {},
|
||||
'Client.activeQuery is deprecated and will be removed in pg@9.0'
|
||||
)
|
||||
|
||||
const queryQueueDeprecationNotice = nodeUtils.deprecate(
|
||||
() => {},
|
||||
'Client.queryQueue is deprecated and will be removed in pg@9.0.'
|
||||
)
|
||||
|
||||
const pgPassDeprecationNotice = nodeUtils.deprecate(
|
||||
() => {},
|
||||
'pgpass support is deprecated and will be removed in pg@9.0. ' +
|
||||
'You can provide an async function as the password property to the Client/Pool constructor that returns a password instead. Within this function you can call the pgpass module in your own code.'
|
||||
)
|
||||
|
||||
const byoPromiseDeprecationNotice = nodeUtils.deprecate(
|
||||
() => {},
|
||||
'Passing a custom Promise implementation to the Client/Pool constructor is deprecated and will be removed in pg@9.0.'
|
||||
)
|
||||
|
||||
const queryQueueLengthDeprecationNotice = nodeUtils.deprecate(
|
||||
() => {},
|
||||
'Calling client.query() when the client is already executing a query is deprecated and will be removed in pg@9.0. Use async/await or an external async flow control mechanism instead.'
|
||||
)
|
||||
|
||||
function coerceNumberOrDefault(value, defaultValue) {
|
||||
if (typeof value === 'number') {
|
||||
return Number.isFinite(value) ? value : defaultValue
|
||||
}
|
||||
if (typeof value === 'string' && value.trim() !== '') {
|
||||
const n = Number(value)
|
||||
return Number.isFinite(n) ? n : defaultValue
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
class Client extends EventEmitter {
|
||||
constructor(config) {
|
||||
super()
|
||||
|
||||
this.connectionParameters = new ConnectionParameters(config)
|
||||
this.user = this.connectionParameters.user
|
||||
this.database = this.connectionParameters.database
|
||||
this.port = this.connectionParameters.port
|
||||
this.host = this.connectionParameters.host
|
||||
|
||||
// "hiding" the password so it doesn't show up in stack traces
|
||||
// or if the client is console.logged
|
||||
Object.defineProperty(this, 'password', {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
value: this.connectionParameters.password,
|
||||
})
|
||||
|
||||
this.replication = this.connectionParameters.replication
|
||||
|
||||
const c = config || {}
|
||||
|
||||
if (c.Promise) {
|
||||
byoPromiseDeprecationNotice()
|
||||
}
|
||||
this._Promise = c.Promise || global.Promise
|
||||
this._types = new TypeOverrides(c.types)
|
||||
this._ending = false
|
||||
this._ended = false
|
||||
this._connecting = false
|
||||
this._connected = false
|
||||
this._connectionError = false
|
||||
this._queryable = true
|
||||
this._activeQuery = null
|
||||
this._txStatus = null
|
||||
|
||||
this.enableChannelBinding = Boolean(c.enableChannelBinding) // set true to use SCRAM-SHA-256-PLUS when offered
|
||||
this.scramMaxIterations = coerceNumberOrDefault(c.scramMaxIterations, sasl.DEFAULT_MAX_SCRAM_ITERATIONS)
|
||||
this.connection =
|
||||
c.connection ||
|
||||
new Connection({
|
||||
stream: c.stream,
|
||||
ssl: this.connectionParameters.ssl,
|
||||
sslNegotiation: this.connectionParameters.sslnegotiation,
|
||||
keepAlive: c.keepAlive || false,
|
||||
keepAliveInitialDelayMillis: c.keepAliveInitialDelayMillis || 0,
|
||||
encoding: this.connectionParameters.client_encoding || 'utf8',
|
||||
})
|
||||
this._queryQueue = []
|
||||
this._sentQueryQueue = []
|
||||
this.pipeline = Boolean(c.pipeline)
|
||||
this.binary = c.binary || defaults.binary
|
||||
this.processID = null
|
||||
this.secretKey = null
|
||||
this.ssl = this.connectionParameters.ssl || false
|
||||
this.sslNegotiation = this.connectionParameters.sslnegotiation || 'postgres'
|
||||
// As with Password, make SSL->Key (the private key) non-enumerable.
|
||||
// It won't show up in stack traces
|
||||
// or if the client is console.logged
|
||||
if (this.ssl && this.ssl.key) {
|
||||
Object.defineProperty(this.ssl, 'key', {
|
||||
enumerable: false,
|
||||
})
|
||||
}
|
||||
|
||||
this._connectionTimeoutMillis = c.connectionTimeoutMillis || 0
|
||||
}
|
||||
|
||||
get activeQuery() {
|
||||
activeQueryDeprecationNotice()
|
||||
return this._activeQuery
|
||||
}
|
||||
|
||||
set activeQuery(val) {
|
||||
activeQueryDeprecationNotice()
|
||||
this._activeQuery = val
|
||||
}
|
||||
|
||||
_getActiveQuery() {
|
||||
return this._activeQuery
|
||||
}
|
||||
|
||||
_errorAllQueries(err) {
|
||||
const enqueueError = (query) => {
|
||||
process.nextTick(() => {
|
||||
query.handleError(err, this.connection)
|
||||
})
|
||||
}
|
||||
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery) {
|
||||
enqueueError(activeQuery)
|
||||
this._activeQuery = null
|
||||
}
|
||||
|
||||
this._sentQueryQueue.forEach(enqueueError)
|
||||
this._sentQueryQueue.length = 0
|
||||
|
||||
this._queryQueue.forEach(enqueueError)
|
||||
this._queryQueue.length = 0
|
||||
}
|
||||
|
||||
_connect(callback) {
|
||||
const self = this
|
||||
const con = this.connection
|
||||
this._connectionCallback = callback
|
||||
|
||||
if (this._connecting || this._connected) {
|
||||
const err = new Error('Client has already been connected. You cannot reuse a client.')
|
||||
process.nextTick(() => {
|
||||
callback(err)
|
||||
})
|
||||
return
|
||||
}
|
||||
this._connecting = true
|
||||
|
||||
if (this._connectionTimeoutMillis > 0) {
|
||||
this.connectionTimeoutHandle = setTimeout(() => {
|
||||
con._ending = true
|
||||
con.stream.destroy(new Error('timeout expired'))
|
||||
}, this._connectionTimeoutMillis)
|
||||
|
||||
if (this.connectionTimeoutHandle.unref) {
|
||||
this.connectionTimeoutHandle.unref()
|
||||
}
|
||||
}
|
||||
|
||||
if (this.host && this.host.indexOf('/') === 0) {
|
||||
con.connect(this.host + '/.s.PGSQL.' + this.port)
|
||||
} else {
|
||||
con.connect(this.port, this.host)
|
||||
}
|
||||
|
||||
// once connection is established send startup message
|
||||
con.on('connect', function () {
|
||||
if (self.ssl) {
|
||||
// With direct SSL negotiation the connection upgrades to TLS without an
|
||||
// SSLRequest packet, so the startup message is sent after 'sslconnect'.
|
||||
if (self.sslNegotiation !== 'direct') {
|
||||
con.requestSsl()
|
||||
}
|
||||
} else {
|
||||
con.startup(self.getStartupConf())
|
||||
}
|
||||
})
|
||||
|
||||
con.on('sslconnect', function () {
|
||||
con.startup(self.getStartupConf())
|
||||
})
|
||||
|
||||
this._attachListeners(con)
|
||||
|
||||
con.once('end', () => {
|
||||
const error = this._ending ? new Error('Connection terminated') : new Error('Connection terminated unexpectedly')
|
||||
|
||||
clearTimeout(this.connectionTimeoutHandle)
|
||||
this._errorAllQueries(error)
|
||||
this._ended = true
|
||||
|
||||
if (!this._ending) {
|
||||
// if the connection is ended without us calling .end()
|
||||
// on this client then we have an unexpected disconnection
|
||||
// treat this as an error unless we've already emitted an error
|
||||
// during connection.
|
||||
if (this._connecting && !this._connectionError) {
|
||||
if (this._connectionCallback) {
|
||||
this._connectionCallback(error)
|
||||
} else {
|
||||
this._handleErrorEvent(error)
|
||||
}
|
||||
} else if (!this._connectionError) {
|
||||
this._handleErrorEvent(error)
|
||||
}
|
||||
}
|
||||
|
||||
process.nextTick(() => {
|
||||
this.emit('end')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
connect(callback) {
|
||||
if (callback) {
|
||||
this._connect(callback)
|
||||
return
|
||||
}
|
||||
|
||||
return new this._Promise((resolve, reject) => {
|
||||
this._connect((error) => {
|
||||
if (error) {
|
||||
reject(error)
|
||||
} else {
|
||||
resolve(this)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
_attachListeners(con) {
|
||||
// password request handling
|
||||
con.on('authenticationCleartextPassword', this._handleAuthCleartextPassword.bind(this))
|
||||
// password request handling
|
||||
con.on('authenticationMD5Password', this._handleAuthMD5Password.bind(this))
|
||||
// password request handling (SASL)
|
||||
con.on('authenticationSASL', this._handleAuthSASL.bind(this))
|
||||
con.on('authenticationSASLContinue', this._handleAuthSASLContinue.bind(this))
|
||||
con.on('authenticationSASLFinal', this._handleAuthSASLFinal.bind(this))
|
||||
con.on('backendKeyData', this._handleBackendKeyData.bind(this))
|
||||
con.on('error', this._handleErrorEvent.bind(this))
|
||||
con.on('errorMessage', this._handleErrorMessage.bind(this))
|
||||
con.on('readyForQuery', this._handleReadyForQuery.bind(this))
|
||||
con.on('notice', this._handleNotice.bind(this))
|
||||
con.on('rowDescription', this._handleRowDescription.bind(this))
|
||||
con.on('dataRow', this._handleDataRow.bind(this))
|
||||
con.on('portalSuspended', this._handlePortalSuspended.bind(this))
|
||||
con.on('emptyQuery', this._handleEmptyQuery.bind(this))
|
||||
con.on('commandComplete', this._handleCommandComplete.bind(this))
|
||||
con.on('parseComplete', this._handleParseComplete.bind(this))
|
||||
con.on('copyInResponse', this._handleCopyInResponse.bind(this))
|
||||
con.on('copyData', this._handleCopyData.bind(this))
|
||||
con.on('notification', this._handleNotification.bind(this))
|
||||
}
|
||||
|
||||
_getPassword(cb) {
|
||||
const con = this.connection
|
||||
if (typeof this.password === 'function') {
|
||||
this._Promise
|
||||
.resolve()
|
||||
.then(() => this.password(this.connectionParameters))
|
||||
.then((pass) => {
|
||||
if (pass !== undefined) {
|
||||
if (typeof pass !== 'string') {
|
||||
con.emit('error', new TypeError('Password must be a string'))
|
||||
return
|
||||
}
|
||||
this.connectionParameters.password = this.password = pass
|
||||
} else {
|
||||
this.connectionParameters.password = this.password = null
|
||||
}
|
||||
cb()
|
||||
})
|
||||
.catch((err) => {
|
||||
con.emit('error', err)
|
||||
})
|
||||
} else if (this.password !== null) {
|
||||
cb()
|
||||
} else {
|
||||
try {
|
||||
const pgPass = require('pgpass')
|
||||
pgPass(this.connectionParameters, (pass) => {
|
||||
if (undefined !== pass) {
|
||||
pgPassDeprecationNotice()
|
||||
this.connectionParameters.password = this.password = pass
|
||||
}
|
||||
cb()
|
||||
})
|
||||
} catch (e) {
|
||||
this.emit('error', e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_handleAuthCleartextPassword(msg) {
|
||||
this._getPassword(() => {
|
||||
this.connection.password(this.password)
|
||||
})
|
||||
}
|
||||
|
||||
_handleAuthMD5Password(msg) {
|
||||
this._getPassword(async () => {
|
||||
try {
|
||||
const hashedPassword = await crypto.postgresMd5PasswordHash(this.user, this.password, msg.salt)
|
||||
this.connection.password(hashedPassword)
|
||||
} catch (e) {
|
||||
this.emit('error', e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_handleAuthSASL(msg) {
|
||||
this._getPassword(() => {
|
||||
try {
|
||||
this.saslSession = sasl.startSession(
|
||||
msg.mechanisms,
|
||||
this.enableChannelBinding && this.connection.stream,
|
||||
this.scramMaxIterations
|
||||
)
|
||||
this.connection.sendSASLInitialResponseMessage(this.saslSession.mechanism, this.saslSession.response)
|
||||
} catch (err) {
|
||||
this.connection.emit('error', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async _handleAuthSASLContinue(msg) {
|
||||
try {
|
||||
await sasl.continueSession(
|
||||
this.saslSession,
|
||||
this.password,
|
||||
msg.data,
|
||||
this.enableChannelBinding && this.connection.stream
|
||||
)
|
||||
this.connection.sendSCRAMClientFinalMessage(this.saslSession.response)
|
||||
} catch (err) {
|
||||
this.connection.emit('error', err)
|
||||
}
|
||||
}
|
||||
|
||||
_handleAuthSASLFinal(msg) {
|
||||
try {
|
||||
sasl.finalizeSession(this.saslSession, msg.data)
|
||||
this.saslSession = null
|
||||
} catch (err) {
|
||||
this.connection.emit('error', err)
|
||||
}
|
||||
}
|
||||
|
||||
_handleBackendKeyData(msg) {
|
||||
this.processID = msg.processID
|
||||
this.secretKey = msg.secretKey
|
||||
}
|
||||
|
||||
_handleReadyForQuery(msg) {
|
||||
if (this._connecting) {
|
||||
this._connecting = false
|
||||
this._connected = true
|
||||
clearTimeout(this.connectionTimeoutHandle)
|
||||
|
||||
// process possible callback argument to Client#connect
|
||||
if (this._connectionCallback) {
|
||||
this._connectionCallback(null, this)
|
||||
// remove callback for proper error handling
|
||||
// after the connect event
|
||||
this._connectionCallback = null
|
||||
}
|
||||
this.emit('connect')
|
||||
}
|
||||
const activeQuery = this._getActiveQuery()
|
||||
this._activeQuery = null
|
||||
this._txStatus = msg?.status ?? null
|
||||
this.readyForQuery = true
|
||||
if (activeQuery) {
|
||||
activeQuery.handleReadyForQuery(this.connection)
|
||||
}
|
||||
this._pulseQueryQueue()
|
||||
}
|
||||
|
||||
// if we receive an error event or error message
|
||||
// during the connection process we handle it here
|
||||
_handleErrorWhileConnecting(err) {
|
||||
if (this._connectionError) {
|
||||
// TODO(bmc): this is swallowing errors - we shouldn't do this
|
||||
return
|
||||
}
|
||||
this._connectionError = true
|
||||
clearTimeout(this.connectionTimeoutHandle)
|
||||
if (this._connectionCallback) {
|
||||
return this._connectionCallback(err)
|
||||
}
|
||||
this.emit('error', err)
|
||||
}
|
||||
|
||||
// if we're connected and we receive an error event from the connection
|
||||
// this means the socket is dead - do a hard abort of all queries and emit
|
||||
// the socket error on the client as well
|
||||
_handleErrorEvent(err) {
|
||||
if (this._connecting) {
|
||||
return this._handleErrorWhileConnecting(err)
|
||||
}
|
||||
this._queryable = false
|
||||
this._errorAllQueries(err)
|
||||
this.emit('error', err)
|
||||
}
|
||||
|
||||
// handle error messages from the postgres backend
|
||||
_handleErrorMessage(msg) {
|
||||
if (this._connecting) {
|
||||
return this._handleErrorWhileConnecting(msg)
|
||||
}
|
||||
const activeQuery = this._getActiveQuery()
|
||||
|
||||
if (!activeQuery) {
|
||||
this._handleErrorEvent(msg)
|
||||
return
|
||||
}
|
||||
|
||||
this._activeQuery = null
|
||||
if (activeQuery.name) {
|
||||
delete this.connection.submittedNamedStatements[activeQuery.name]
|
||||
}
|
||||
activeQuery.handleError(msg, this.connection)
|
||||
}
|
||||
|
||||
_handleRowDescription(msg) {
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery == null) {
|
||||
const error = new Error('Received unexpected rowDescription message from backend.')
|
||||
this._handleErrorEvent(error)
|
||||
return
|
||||
}
|
||||
// delegate rowDescription to active query
|
||||
activeQuery.handleRowDescription(msg)
|
||||
}
|
||||
|
||||
_handleDataRow(msg) {
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery == null) {
|
||||
const error = new Error('Received unexpected dataRow message from backend.')
|
||||
this._handleErrorEvent(error)
|
||||
return
|
||||
}
|
||||
// delegate dataRow to active query
|
||||
activeQuery.handleDataRow(msg)
|
||||
}
|
||||
|
||||
_handlePortalSuspended(msg) {
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery == null) {
|
||||
const error = new Error('Received unexpected portalSuspended message from backend.')
|
||||
this._handleErrorEvent(error)
|
||||
return
|
||||
}
|
||||
// delegate portalSuspended to active query
|
||||
activeQuery.handlePortalSuspended(this.connection)
|
||||
}
|
||||
|
||||
_handleEmptyQuery(msg) {
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery == null) {
|
||||
const error = new Error('Received unexpected emptyQuery message from backend.')
|
||||
this._handleErrorEvent(error)
|
||||
return
|
||||
}
|
||||
// delegate emptyQuery to active query
|
||||
activeQuery.handleEmptyQuery(this.connection)
|
||||
}
|
||||
|
||||
_handleCommandComplete(msg) {
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery == null) {
|
||||
const error = new Error('Received unexpected commandComplete message from backend.')
|
||||
this._handleErrorEvent(error)
|
||||
return
|
||||
}
|
||||
// delegate commandComplete to active query
|
||||
activeQuery.handleCommandComplete(msg, this.connection)
|
||||
}
|
||||
|
||||
_handleParseComplete() {
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery == null) {
|
||||
const error = new Error('Received unexpected parseComplete message from backend.')
|
||||
this._handleErrorEvent(error)
|
||||
return
|
||||
}
|
||||
// if a prepared statement has a name and properly parses
|
||||
// we track that its already been executed so we don't parse
|
||||
// it again on the same client
|
||||
if (activeQuery.name) {
|
||||
this.connection.parsedStatements[activeQuery.name] = activeQuery.text
|
||||
delete this.connection.submittedNamedStatements[activeQuery.name]
|
||||
}
|
||||
}
|
||||
|
||||
_handleCopyInResponse(msg) {
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery == null) {
|
||||
const error = new Error('Received unexpected copyInResponse message from backend.')
|
||||
this._handleErrorEvent(error)
|
||||
return
|
||||
}
|
||||
activeQuery.handleCopyInResponse(this.connection)
|
||||
}
|
||||
|
||||
_handleCopyData(msg) {
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery == null) {
|
||||
const error = new Error('Received unexpected copyData message from backend.')
|
||||
this._handleErrorEvent(error)
|
||||
return
|
||||
}
|
||||
activeQuery.handleCopyData(msg, this.connection)
|
||||
}
|
||||
|
||||
_handleNotification(msg) {
|
||||
this.emit('notification', msg)
|
||||
}
|
||||
|
||||
_handleNotice(msg) {
|
||||
this.emit('notice', msg)
|
||||
}
|
||||
|
||||
getStartupConf() {
|
||||
const params = this.connectionParameters
|
||||
|
||||
const data = {
|
||||
user: params.user,
|
||||
database: params.database,
|
||||
}
|
||||
|
||||
const appName = params.application_name || params.fallback_application_name
|
||||
if (appName) {
|
||||
data.application_name = appName
|
||||
}
|
||||
if (params.replication) {
|
||||
data.replication = '' + params.replication
|
||||
}
|
||||
if (params.statement_timeout) {
|
||||
data.statement_timeout = String(parseInt(params.statement_timeout, 10))
|
||||
}
|
||||
if (params.lock_timeout) {
|
||||
data.lock_timeout = String(parseInt(params.lock_timeout, 10))
|
||||
}
|
||||
if (params.idle_in_transaction_session_timeout) {
|
||||
data.idle_in_transaction_session_timeout = String(parseInt(params.idle_in_transaction_session_timeout, 10))
|
||||
}
|
||||
if (params.options) {
|
||||
data.options = params.options
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
cancel(client, query) {
|
||||
if (client.activeQuery === query) {
|
||||
const con = this.connection
|
||||
|
||||
if (this.host && this.host.indexOf('/') === 0) {
|
||||
con.connect(this.host + '/.s.PGSQL.' + this.port)
|
||||
} else {
|
||||
con.connect(this.port, this.host)
|
||||
}
|
||||
|
||||
// once connection is established send cancel message
|
||||
con.on('connect', function () {
|
||||
con.cancel(client.processID, client.secretKey)
|
||||
})
|
||||
} else if (client._queryQueue.indexOf(query) !== -1) {
|
||||
client._queryQueue.splice(client._queryQueue.indexOf(query), 1)
|
||||
} else if (client._sentQueryQueue.indexOf(query) !== -1) {
|
||||
// Query already sent on wire — can't remove it without corrupting the
|
||||
// pipeline. No-op the callback so the result is silently discarded.
|
||||
query.callback = () => {}
|
||||
}
|
||||
}
|
||||
|
||||
setTypeParser(oid, format, parseFn) {
|
||||
return this._types.setTypeParser(oid, format, parseFn)
|
||||
}
|
||||
|
||||
getTypeParser(oid, format) {
|
||||
return this._types.getTypeParser(oid, format)
|
||||
}
|
||||
|
||||
// escapeIdentifier and escapeLiteral moved to utility functions & exported
|
||||
// on PG
|
||||
// re-exported here for backwards compatibility
|
||||
escapeIdentifier(str) {
|
||||
return utils.escapeIdentifier(str)
|
||||
}
|
||||
|
||||
escapeLiteral(str) {
|
||||
return utils.escapeLiteral(str)
|
||||
}
|
||||
|
||||
_pulseQueryQueue() {
|
||||
if (this.pipeline) {
|
||||
this._pulsePipelinedQueryQueue()
|
||||
return
|
||||
}
|
||||
if (this.readyForQuery === true) {
|
||||
this._activeQuery = this._queryQueue.shift()
|
||||
const activeQuery = this._getActiveQuery()
|
||||
if (activeQuery) {
|
||||
this.readyForQuery = false
|
||||
this.hasExecuted = true
|
||||
|
||||
const queryError = activeQuery.submit(this.connection)
|
||||
if (queryError) {
|
||||
process.nextTick(() => {
|
||||
activeQuery.handleError(queryError, this.connection)
|
||||
this.readyForQuery = true
|
||||
this._pulseQueryQueue()
|
||||
})
|
||||
}
|
||||
} else if (this.hasExecuted) {
|
||||
this._activeQuery = null
|
||||
this.emit('drain')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_pulsePipelinedQueryQueue() {
|
||||
if (!this._connected || !this._queryable) {
|
||||
return
|
||||
}
|
||||
while (this._queryQueue.length > 0) {
|
||||
const query = this._queryQueue.shift()
|
||||
this.hasExecuted = true
|
||||
const queryError = query.submit(this.connection)
|
||||
if (queryError) {
|
||||
process.nextTick(() => {
|
||||
query.handleError(queryError, this.connection)
|
||||
})
|
||||
continue
|
||||
}
|
||||
this._sentQueryQueue.push(query)
|
||||
}
|
||||
if (this.readyForQuery && !this._activeQuery && this._sentQueryQueue.length > 0) {
|
||||
this._activeQuery = this._sentQueryQueue.shift()
|
||||
this.readyForQuery = false
|
||||
}
|
||||
if (!this._activeQuery && this._sentQueryQueue.length === 0 && this._queryQueue.length === 0 && this.hasExecuted) {
|
||||
this.emit('drain')
|
||||
}
|
||||
}
|
||||
|
||||
query(config, values, callback) {
|
||||
// can take in strings, config object or query object
|
||||
let query
|
||||
let result
|
||||
|
||||
if (config == null) {
|
||||
throw new TypeError('Client was passed a null or undefined query')
|
||||
}
|
||||
|
||||
if (typeof config.submit === 'function') {
|
||||
result = query = config
|
||||
if (!query.callback) {
|
||||
if (typeof values === 'function') {
|
||||
query.callback = values
|
||||
} else if (callback) {
|
||||
query.callback = callback
|
||||
}
|
||||
}
|
||||
} else {
|
||||
query = new Query(config, values, callback)
|
||||
if (!query.callback) {
|
||||
result = new this._Promise((resolve, reject) => {
|
||||
query.callback = (err, res) => (err ? reject(err) : resolve(res))
|
||||
}).catch((err) => {
|
||||
// replace the stack trace that leads to `TCP.onStreamRead` with one that leads back to the
|
||||
// application that created the query
|
||||
Error.captureStackTrace(err)
|
||||
throw err
|
||||
})
|
||||
} else if (typeof query.callback !== 'function') {
|
||||
throw new TypeError('callback is not a function')
|
||||
}
|
||||
}
|
||||
|
||||
const readTimeout = config.query_timeout || this.connectionParameters.query_timeout
|
||||
if (readTimeout) {
|
||||
const queryCallback = query.callback || (() => {})
|
||||
|
||||
const readTimeoutTimer = setTimeout(() => {
|
||||
const error = new Error('Query read timeout')
|
||||
|
||||
process.nextTick(() => {
|
||||
query.handleError(error, this.connection)
|
||||
})
|
||||
|
||||
queryCallback(error)
|
||||
|
||||
// we already returned an error,
|
||||
// just do nothing if query completes
|
||||
query.callback = () => {}
|
||||
|
||||
// Remove from queue (only safe if not yet sent)
|
||||
const index = this._queryQueue.indexOf(query)
|
||||
if (index > -1) {
|
||||
this._queryQueue.splice(index, 1)
|
||||
} else if (this.pipeline) {
|
||||
// Query already sent — the pipeline is blocked until it completes.
|
||||
// Destroy the connection to unblock all remaining pipelined queries.
|
||||
this.connection.stream.destroy()
|
||||
return
|
||||
}
|
||||
|
||||
this._pulseQueryQueue()
|
||||
}, readTimeout)
|
||||
|
||||
query.callback = (err, res) => {
|
||||
clearTimeout(readTimeoutTimer)
|
||||
queryCallback(err, res)
|
||||
}
|
||||
}
|
||||
|
||||
if (this.binary && !query.binary) {
|
||||
query.binary = true
|
||||
}
|
||||
|
||||
if (query._result && !query._result._types) {
|
||||
query._result._types = this._types
|
||||
}
|
||||
|
||||
if (!this._queryable) {
|
||||
process.nextTick(() => {
|
||||
query.handleError(new Error('Client has encountered a connection error and is not queryable'), this.connection)
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
if (this._ending) {
|
||||
process.nextTick(() => {
|
||||
query.handleError(new Error('Client was closed and is not queryable'), this.connection)
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
if (this._queryQueue.length > 0 && !this.pipeline) {
|
||||
queryQueueLengthDeprecationNotice()
|
||||
}
|
||||
this._queryQueue.push(query)
|
||||
this._pulseQueryQueue()
|
||||
return result
|
||||
}
|
||||
|
||||
ref() {
|
||||
this.connection.ref()
|
||||
}
|
||||
|
||||
unref() {
|
||||
this.connection.unref()
|
||||
}
|
||||
|
||||
getTransactionStatus() {
|
||||
return this._txStatus
|
||||
}
|
||||
|
||||
end(cb) {
|
||||
this._ending = true
|
||||
|
||||
// if we have never connected, then end is a noop, callback immediately
|
||||
if (!this.connection._connecting || this._ended) {
|
||||
if (cb) {
|
||||
cb()
|
||||
return
|
||||
} else {
|
||||
return this._Promise.resolve()
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._queryable) {
|
||||
// socket is dead — force close
|
||||
this.connection.stream.destroy()
|
||||
} else if (
|
||||
this.pipeline &&
|
||||
(this._getActiveQuery() || this._sentQueryQueue.length > 0 || this._queryQueue.length > 0)
|
||||
) {
|
||||
// pipelined queries are already on the wire (or queued to send) and will
|
||||
// complete normally; wait for drain then do a graceful goodbye
|
||||
this.once('drain', () => this.connection.end())
|
||||
} else if (this._getActiveQuery()) {
|
||||
// non-pipeline: a hung query could block end forever — force disconnect
|
||||
this.connection.stream.destroy()
|
||||
} else {
|
||||
this.connection.end()
|
||||
}
|
||||
|
||||
if (cb) {
|
||||
this.connection.once('end', cb)
|
||||
} else {
|
||||
return new this._Promise((resolve) => {
|
||||
this.connection.once('end', resolve)
|
||||
})
|
||||
}
|
||||
}
|
||||
get queryQueue() {
|
||||
queryQueueDeprecationNotice()
|
||||
return this._queryQueue
|
||||
}
|
||||
}
|
||||
|
||||
// expose a Query constructor
|
||||
Client.Query = Query
|
||||
|
||||
module.exports = Client
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
|
||||
export type Options = [
|
||||
{
|
||||
ignoreStringArrays?: boolean;
|
||||
}
|
||||
];
|
||||
export type MessageIds = 'requireCompare';
|
||||
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"requireCompare", Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,48 @@
|
||||
'use strict'
|
||||
|
||||
const parse = require('./parse')
|
||||
const constants = require('../internal/constants')
|
||||
const SemVer = require('../classes/semver')
|
||||
|
||||
const truncate = (version, truncation, options) => {
|
||||
if (!constants.RELEASE_TYPES.includes(truncation)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const clonedVersion = cloneInputVersion(version, options)
|
||||
return clonedVersion && doTruncation(clonedVersion, truncation)
|
||||
}
|
||||
|
||||
const cloneInputVersion = (version, options) => {
|
||||
const versionStringToParse = (
|
||||
version instanceof SemVer ? version.version : version
|
||||
)
|
||||
|
||||
return parse(versionStringToParse, options)
|
||||
}
|
||||
|
||||
const doTruncation = (version, truncation) => {
|
||||
if (isPrerelease(truncation)) {
|
||||
return version.version
|
||||
}
|
||||
|
||||
version.prerelease = []
|
||||
|
||||
switch (truncation) {
|
||||
case 'major':
|
||||
version.minor = 0
|
||||
version.patch = 0
|
||||
break
|
||||
case 'minor':
|
||||
version.patch = 0
|
||||
break
|
||||
}
|
||||
|
||||
return version.format()
|
||||
}
|
||||
|
||||
const isPrerelease = (type) => {
|
||||
return type.startsWith('pre')
|
||||
}
|
||||
|
||||
module.exports = truncate
|
||||
@@ -0,0 +1,25 @@
|
||||
import './types.d-BjI5eAwu.js';
|
||||
|
||||
type Key = string | symbol;
|
||||
type CreateMockInstanceProcedure = (options?: {
|
||||
prototypeMembers?: (string | symbol)[];
|
||||
name?: string | symbol;
|
||||
originalImplementation?: (...args: any[]) => any;
|
||||
keepMembersImplementation?: boolean;
|
||||
}) => any;
|
||||
interface MockObjectOptions {
|
||||
type: "automock" | "autospy";
|
||||
globalConstructors: GlobalConstructors;
|
||||
createMockInstance: CreateMockInstanceProcedure;
|
||||
}
|
||||
declare function mockObject(options: MockObjectOptions, object: Record<Key, any>, mockExports?: Record<Key, any>): Record<Key, any>;
|
||||
interface GlobalConstructors {
|
||||
Object: ObjectConstructor;
|
||||
Function: FunctionConstructor;
|
||||
RegExp: RegExpConstructor;
|
||||
Array: ArrayConstructor;
|
||||
Map: MapConstructor;
|
||||
}
|
||||
|
||||
export { mockObject as m };
|
||||
export type { CreateMockInstanceProcedure as C, GlobalConstructors as G, MockObjectOptions as M };
|
||||
@@ -0,0 +1,192 @@
|
||||
'use strict'
|
||||
|
||||
const { format } = require('node:util')
|
||||
|
||||
/**
|
||||
* @namespace processWarning
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents a warning item with details.
|
||||
* @typedef {Function} WarningItem
|
||||
* @param {*} [a] Possible message interpolation value.
|
||||
* @param {*} [b] Possible message interpolation value.
|
||||
* @param {*} [c] Possible message interpolation value.
|
||||
* @property {string} name - The name of the warning.
|
||||
* @property {string} code - The code associated with the warning.
|
||||
* @property {string} message - The warning message.
|
||||
* @property {boolean} emitted - Indicates if the warning has been emitted.
|
||||
* @property {function} format - Formats the warning message.
|
||||
* @returns {boolean} emit - Indicates if the warning has been emitted by this call.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Options for creating a process warning.
|
||||
* @typedef {Object} ProcessWarningOptions
|
||||
* @property {string} name - The name of the warning.
|
||||
* @property {string} code - The code associated with the warning.
|
||||
* @property {string} message - The warning message.
|
||||
* @property {boolean} [unlimited=false] - If true, allows unlimited emissions of the warning.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the process warning functionality.
|
||||
* @typedef {Object} ProcessWarning
|
||||
* @property {function} createWarning - Creates a warning item.
|
||||
* @property {function} createDeprecation - Creates a deprecation warning item.
|
||||
* @property {function} spyWarning - Spy a warning item.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Represents the spy data.
|
||||
* @typedef {Object} WarningSpyData
|
||||
* @property {object} calls - Arguments of WarningItem calls with.
|
||||
* @property {function} callCount - Number of counts called the WarningItem.
|
||||
* @property {function} reset - Reset the calls data and state of WarningItem.
|
||||
* @property {function} restore - Remove spy from WarningItem.
|
||||
*/
|
||||
|
||||
const kWarningFn = Symbol('process-warning.fn')
|
||||
const kWarningSpyData = Symbol('process-warning.spyData')
|
||||
|
||||
/**
|
||||
* Spy a warning item.
|
||||
* @function
|
||||
* @memberof processWarning
|
||||
* @param {WarningItem} warning - The warning item to spy.
|
||||
* @returns {WarningSpyData} The created spy data.
|
||||
*/
|
||||
function spyWarning (warning) {
|
||||
// Do not double spy the same warning
|
||||
if (warning[kWarningSpyData] === null) {
|
||||
const warningFn = warning[kWarningFn]
|
||||
warning[kWarningFn] = function (a, b, c) {
|
||||
const args = []
|
||||
// since warning always call by fn(a, b, c)
|
||||
// it need to remove the trailing undefined arguments
|
||||
if (c) {
|
||||
args.push(a, b, c)
|
||||
} else if (b) {
|
||||
args.push(a, b)
|
||||
} else if (a) {
|
||||
args.push(a)
|
||||
}
|
||||
warning[kWarningSpyData].calls.push({
|
||||
arguments: args,
|
||||
result: warningFn(a, b, c)
|
||||
})
|
||||
}
|
||||
const spyData = {
|
||||
calls: [],
|
||||
callCount () {
|
||||
return spyData.calls.length
|
||||
},
|
||||
reset () {
|
||||
warning.emitted = false
|
||||
spyData.calls.length = 0
|
||||
},
|
||||
restore () {
|
||||
spyData.reset()
|
||||
warning[kWarningFn] = warningFn
|
||||
warning[kWarningSpyData] = null
|
||||
}
|
||||
}
|
||||
warning[kWarningSpyData] = spyData
|
||||
}
|
||||
|
||||
return warning[kWarningSpyData]
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a deprecation warning item.
|
||||
* @function
|
||||
* @memberof processWarning
|
||||
* @param {ProcessWarningOptions} params - Options for creating the warning.
|
||||
* @returns {WarningItem} The created deprecation warning item.
|
||||
*/
|
||||
function createDeprecation (params) {
|
||||
return createWarning({ ...params, name: 'DeprecationWarning' })
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a warning item.
|
||||
* @function
|
||||
* @memberof processWarning
|
||||
* @param {ProcessWarningOptions} params - Options for creating the warning.
|
||||
* @returns {WarningItem} The created warning item.
|
||||
* @throws {Error} Throws an error if name, code, or message is empty, or if opts.unlimited is not a boolean.
|
||||
*/
|
||||
function createWarning ({ name, code, message, unlimited = false } = {}) {
|
||||
if (!name) throw new Error('Warning name must not be empty')
|
||||
if (!code) throw new Error('Warning code must not be empty')
|
||||
if (!message) throw new Error('Warning message must not be empty')
|
||||
if (typeof unlimited !== 'boolean') throw new Error('Warning opts.unlimited must be a boolean')
|
||||
|
||||
code = code.toUpperCase()
|
||||
|
||||
const warningFn = unlimited === true
|
||||
? function (a, b, c) {
|
||||
warning.emitted = true
|
||||
process.emitWarning(warning.format(a, b, c), warning.name, warning.code)
|
||||
return true
|
||||
}
|
||||
: function (a, b, c) {
|
||||
if (warning.emitted === true && warning.unlimited !== true) {
|
||||
return false
|
||||
}
|
||||
warning.emitted = true
|
||||
process.emitWarning(warning.format(a, b, c), warning.name, warning.code)
|
||||
return true
|
||||
}
|
||||
|
||||
const warningContainer = {
|
||||
[name]: function (a, b, c) {
|
||||
return warning[kWarningFn](a, b, c)
|
||||
}
|
||||
}
|
||||
|
||||
const warning = warningContainer[name]
|
||||
|
||||
warning.emitted = false
|
||||
warning.message = message
|
||||
warning.unlimited = unlimited
|
||||
warning.code = code
|
||||
warning[kWarningFn] = warningFn
|
||||
warning[kWarningSpyData] = null
|
||||
|
||||
/**
|
||||
* Formats the warning message.
|
||||
* @param {*} [a] Possible message interpolation value.
|
||||
* @param {*} [b] Possible message interpolation value.
|
||||
* @param {*} [c] Possible message interpolation value.
|
||||
* @returns {string} The formatted warning message.
|
||||
*/
|
||||
warning.format = function (a, b, c) {
|
||||
let formatted
|
||||
if (a && b && c) {
|
||||
formatted = format(message, a, b, c)
|
||||
} else if (a && b) {
|
||||
formatted = format(message, a, b)
|
||||
} else if (a) {
|
||||
formatted = format(message, a)
|
||||
} else {
|
||||
formatted = message
|
||||
}
|
||||
return formatted
|
||||
}
|
||||
|
||||
return warning
|
||||
}
|
||||
|
||||
/**
|
||||
* Module exports containing the process warning functionality.
|
||||
* @namespace
|
||||
* @property {function} createWarning - Creates a warning item.
|
||||
* @property {function} createDeprecation - Creates a deprecation warning item.
|
||||
* @property {function} spyWarning - Spy a warning item.
|
||||
* @property {ProcessWarning} processWarning - Represents the process warning functionality.
|
||||
*/
|
||||
const out = { createWarning, createDeprecation, spyWarning }
|
||||
module.exports = out
|
||||
module.exports.default = out
|
||||
module.exports.processWarning = out
|
||||
@@ -0,0 +1,72 @@
|
||||
import { expect, test } from "vitest";
|
||||
import { z } from "../../../../index.js";
|
||||
import fr from "../../../locales/fr.js";
|
||||
|
||||
test("French locale - type name translations in too_small errors", () => {
|
||||
z.config(fr());
|
||||
|
||||
const stringResult = z.string().min(5).safeParse("abc");
|
||||
expect(stringResult.success).toBe(false);
|
||||
if (!stringResult.success) {
|
||||
expect(stringResult.error.issues[0].message).toBe("Trop petit : chaîne doit avoir >=5 caractères");
|
||||
}
|
||||
|
||||
const numberResult = z.number().min(10).safeParse(5);
|
||||
expect(numberResult.success).toBe(false);
|
||||
if (!numberResult.success) {
|
||||
expect(numberResult.error.issues[0].message).toBe("Trop petit : nombre doit être >=10");
|
||||
}
|
||||
|
||||
const arrayResult = z.array(z.string()).min(3).safeParse(["a", "b"]);
|
||||
expect(arrayResult.success).toBe(false);
|
||||
if (!arrayResult.success) {
|
||||
expect(arrayResult.error.issues[0].message).toBe("Trop petit : tableau doit avoir >=3 éléments");
|
||||
}
|
||||
|
||||
const setResult = z
|
||||
.set(z.string())
|
||||
.min(2)
|
||||
.safeParse(new Set(["a"]));
|
||||
expect(setResult.success).toBe(false);
|
||||
if (!setResult.success) {
|
||||
expect(setResult.error.issues[0].message).toBe("Trop petit : ensemble doit avoir >=2 éléments");
|
||||
}
|
||||
});
|
||||
|
||||
test("French locale - type name translations in too_big errors", () => {
|
||||
z.config(fr());
|
||||
|
||||
const stringResult = z.string().max(3).safeParse("abcde");
|
||||
expect(stringResult.success).toBe(false);
|
||||
if (!stringResult.success) {
|
||||
expect(stringResult.error.issues[0].message).toBe("Trop grand : chaîne doit avoir <=3 caractères");
|
||||
}
|
||||
|
||||
const numberResult = z.number().max(10).safeParse(15);
|
||||
expect(numberResult.success).toBe(false);
|
||||
if (!numberResult.success) {
|
||||
expect(numberResult.error.issues[0].message).toBe("Trop grand : nombre doit être <=10");
|
||||
}
|
||||
|
||||
const arrayResult = z.array(z.string()).max(2).safeParse(["a", "b", "c"]);
|
||||
expect(arrayResult.success).toBe(false);
|
||||
if (!arrayResult.success) {
|
||||
expect(arrayResult.error.issues[0].message).toBe("Trop grand : tableau doit avoir <=2 éléments");
|
||||
}
|
||||
});
|
||||
|
||||
test("French locale - type name translations in invalid_type errors", () => {
|
||||
z.config(fr());
|
||||
|
||||
const stringResult = z.string().safeParse(123);
|
||||
expect(stringResult.success).toBe(false);
|
||||
if (!stringResult.success) {
|
||||
expect(stringResult.error.issues[0].message).toBe("Entrée invalide : chaîne attendu, nombre reçu");
|
||||
}
|
||||
|
||||
const arrayResult = z.array(z.string()).safeParse({});
|
||||
expect(arrayResult.success).toBe(false);
|
||||
if (!arrayResult.success) {
|
||||
expect(arrayResult.error.issues[0].message).toBe("Entrée invalide : tableau attendu, objet reçu");
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,309 @@
|
||||
# Acorn
|
||||
|
||||
A tiny, fast JavaScript parser written in JavaScript.
|
||||
|
||||
## Community
|
||||
|
||||
Acorn is open source software released under an
|
||||
[MIT license](https://github.com/acornjs/acorn/blob/master/acorn/LICENSE).
|
||||
|
||||
You are welcome to
|
||||
[report bugs](https://github.com/acornjs/acorn/issues) or create pull
|
||||
requests on [github](https://github.com/acornjs/acorn).
|
||||
|
||||
## Installation
|
||||
|
||||
The easiest way to install acorn is from [`npm`](https://www.npmjs.com/):
|
||||
|
||||
```sh
|
||||
npm install acorn
|
||||
```
|
||||
|
||||
Alternately, you can download the source and build acorn yourself:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/acornjs/acorn.git
|
||||
cd acorn
|
||||
npm install
|
||||
```
|
||||
## Importing acorn
|
||||
|
||||
ESM as well as CommonJS is supported for all 3: `acorn`, `acorn-walk` and `acorn-loose`.
|
||||
|
||||
ESM example for `acorn`:
|
||||
|
||||
```js
|
||||
import * as acorn from "acorn"
|
||||
```
|
||||
|
||||
CommonJS example for `acorn`:
|
||||
|
||||
```js
|
||||
let acorn = require("acorn")
|
||||
```
|
||||
|
||||
ESM is preferred, as it allows better editor auto-completions by offering TypeScript support.
|
||||
For this reason, following examples will use ESM imports.
|
||||
|
||||
## Interface
|
||||
|
||||
**parse**`(input, options)` is the main interface to the library. The
|
||||
`input` parameter is a string, `options` must be an object setting
|
||||
some of the options listed below. The return value will be an abstract
|
||||
syntax tree object as specified by the [ESTree
|
||||
spec](https://github.com/estree/estree).
|
||||
|
||||
```javascript
|
||||
import * as acorn from "acorn"
|
||||
console.log(acorn.parse("1 + 1", {ecmaVersion: 2020}))
|
||||
```
|
||||
|
||||
When encountering a syntax error, the parser will raise a
|
||||
`SyntaxError` object with a meaningful message. The error object will
|
||||
have a `pos` property that indicates the string offset at which the
|
||||
error occurred, and a `loc` object that contains a `{line, column}`
|
||||
object referring to that same position.
|
||||
|
||||
Options are provided by in a second argument, which should be an
|
||||
object containing any of these fields (only `ecmaVersion` is
|
||||
required):
|
||||
|
||||
- **ecmaVersion**: Indicates the ECMAScript version to parse. Can be a
|
||||
number, either in year (`2022`) or plain version number (`6`) form,
|
||||
or `"latest"` (the latest the library supports). This influences
|
||||
support for strict mode, the set of reserved words, and support for
|
||||
new syntax features.
|
||||
|
||||
**NOTE**: Only 'stage 4' (finalized) ECMAScript features are being
|
||||
implemented by Acorn. Other proposed new features must be
|
||||
implemented through plugins.
|
||||
|
||||
- **sourceType**: Indicate the mode the code should be parsed in. Can be
|
||||
either `"script"`, `"module"` or `"commonjs"`. This influences global strict mode
|
||||
and parsing of `import` and `export` declarations.
|
||||
|
||||
**NOTE**: If set to `"module"`, then static `import` / `export` syntax
|
||||
will be valid, even if `ecmaVersion` is less than 6. If set to `"commonjs"`,
|
||||
it is the same as `"script"` except that the top-level scope behaves like a function.
|
||||
|
||||
- **strict**: When set to true, enable strict parsing mode even if
|
||||
`sourceType` is `"script"`.
|
||||
|
||||
- **onInsertedSemicolon**: If given a callback, that callback will be
|
||||
called whenever a missing semicolon is inserted by the parser. The
|
||||
callback will be given the character offset of the point where the
|
||||
semicolon is inserted as argument, and if `locations` is on, also a
|
||||
`{line, column}` object representing this position.
|
||||
|
||||
- **onTrailingComma**: Like `onInsertedSemicolon`, but for trailing
|
||||
commas.
|
||||
|
||||
- **allowReserved**: If `false`, using a reserved word will generate
|
||||
an error. Defaults to `true` for `ecmaVersion` 3, `false` for higher
|
||||
versions. When given the value `"never"`, reserved words and
|
||||
keywords can also not be used as property names (as in Internet
|
||||
Explorer's old parser).
|
||||
|
||||
- **allowReturnOutsideFunction**: By default, a return statement at
|
||||
the top level raises an error. Set this to `true` to accept such
|
||||
code.
|
||||
|
||||
- **allowImportExportEverywhere**: By default, `import` and `export`
|
||||
declarations can only appear at a program's top level. Setting this
|
||||
option to `true` allows them anywhere where a statement is allowed,
|
||||
and also allows `import.meta` expressions to appear in scripts
|
||||
(when `sourceType` is not `"module"`).
|
||||
|
||||
- **allowAwaitOutsideFunction**: If `false`, `await` expressions can
|
||||
only appear inside `async` functions. Defaults to `true` in modules
|
||||
for `ecmaVersion` 2022 and later, `false` for lower versions.
|
||||
Setting this option to `true` allows to have top-level `await`
|
||||
expressions. They are still not allowed in non-`async` functions,
|
||||
though. Setting this option to `true` is not allowed when `sourceType: "commonjs"`.
|
||||
|
||||
- **allowSuperOutsideMethod**: By default, `super` outside a method
|
||||
raises an error. Set this to `true` to accept such code.
|
||||
|
||||
- **allowHashBang**: When this is enabled, if the code starts with the
|
||||
characters `#!` (as in a shellscript), the first line will be
|
||||
treated as a comment. Defaults to true when `ecmaVersion` >= 2023.
|
||||
|
||||
- **checkPrivateFields**: By default, the parser will verify that
|
||||
private properties are only used in places where they are valid and
|
||||
have been declared. Set this to false to turn such checks off.
|
||||
|
||||
- **locations**: When `true`, each node has a `loc` object attached
|
||||
with `start` and `end` subobjects, each of which contains the
|
||||
one-based line and zero-based column numbers in `{line, column}`
|
||||
form. Default is `false`.
|
||||
|
||||
- **startLocation**: An optional `{line, column}` object to use for
|
||||
the start of the parse. This is mostly useful when using
|
||||
`parseExpressionAt` with `locations: true`, to prevent the parser
|
||||
from having to determine the line position at the start position.
|
||||
|
||||
- **onToken**: If a function is passed for this option, each found
|
||||
token will be passed in same format as tokens returned from
|
||||
`tokenizer().getToken()`.
|
||||
|
||||
If array is passed, each found token is pushed to it.
|
||||
|
||||
Note that you are not allowed to call the parser from the
|
||||
callback—that will corrupt its internal state.
|
||||
|
||||
- **onComment**: If a function is passed for this option, whenever a
|
||||
comment is encountered the function will be called with the
|
||||
following parameters:
|
||||
|
||||
- `block`: `true` if the comment is a block comment, false if it
|
||||
is a line comment.
|
||||
- `text`: The content of the comment.
|
||||
- `start`: Character offset of the start of the comment.
|
||||
- `end`: Character offset of the end of the comment.
|
||||
|
||||
When the `locations` options is on, the `{line, column}` locations
|
||||
of the comment’s start and end are passed as two additional
|
||||
parameters.
|
||||
|
||||
If array is passed for this option, each found comment is pushed
|
||||
to it as object in Esprima format:
|
||||
|
||||
```javascript
|
||||
{
|
||||
"type": "Line" | "Block",
|
||||
"value": "comment text",
|
||||
"start": Number,
|
||||
"end": Number,
|
||||
// If `locations` option is on:
|
||||
"loc": {
|
||||
"start": {line: Number, column: Number}
|
||||
"end": {line: Number, column: Number}
|
||||
},
|
||||
// If `ranges` option is on:
|
||||
"range": [Number, Number]
|
||||
}
|
||||
```
|
||||
|
||||
Note that you are not allowed to call the parser from the
|
||||
callback—that will corrupt its internal state.
|
||||
|
||||
- **ranges**: Nodes have their start and end characters offsets
|
||||
recorded in `start` and `end` properties (directly on the node,
|
||||
rather than the `loc` object, which holds line/column data. To also
|
||||
add a
|
||||
[semi-standardized](https://bugzilla.mozilla.org/show_bug.cgi?id=745678)
|
||||
`range` property holding a `[start, end]` array with the same
|
||||
numbers, set the `ranges` option to `true`.
|
||||
|
||||
- **program**: It is possible to parse multiple files into a single
|
||||
AST by passing the tree produced by parsing the first file as the
|
||||
`program` option in subsequent parses. This will add the toplevel
|
||||
forms of the parsed file to the "Program" (top) node of an existing
|
||||
parse tree.
|
||||
|
||||
- **sourceFile**: When the `locations` option is `true`, you can pass
|
||||
this option to add a `source` attribute in every node’s `loc`
|
||||
object. Note that the contents of this option are not examined or
|
||||
processed in any way; you are free to use whatever format you
|
||||
choose.
|
||||
|
||||
- **directSourceFile**: Like `sourceFile`, but a `sourceFile` property
|
||||
will be added (regardless of the `location` option) directly to the
|
||||
nodes, rather than the `loc` object.
|
||||
|
||||
- **preserveParens**: If this option is `true`, parenthesized expressions
|
||||
are represented by (non-standard) `ParenthesizedExpression` nodes
|
||||
that have a single `expression` property containing the expression
|
||||
inside parentheses.
|
||||
|
||||
**parseExpressionAt**`(input, offset, options)` will parse a single
|
||||
expression in a string, and return its AST. It will not complain if
|
||||
there is more of the string left after the expression.
|
||||
|
||||
**tokenizer**`(input, options)` returns an object with a `getToken`
|
||||
method that can be called repeatedly to get the next token, a `{start,
|
||||
end, type, value}` object (with added `loc` property when the
|
||||
`locations` option is enabled and `range` property when the `ranges`
|
||||
option is enabled). When the token's type is `tokTypes.eof`, you
|
||||
should stop calling the method, since it will keep returning that same
|
||||
token forever.
|
||||
|
||||
Note that tokenizing JavaScript without parsing it is, in modern
|
||||
versions of the language, not really possible due to the way syntax is
|
||||
overloaded in ways that can only be disambiguated by the parse
|
||||
context. This package applies a bunch of heuristics to try and do a
|
||||
reasonable job, but you are advised to use `parse` with the `onToken`
|
||||
option instead of this.
|
||||
|
||||
In ES6 environment, returned result can be used as any other
|
||||
protocol-compliant iterable:
|
||||
|
||||
```javascript
|
||||
for (let token of acorn.tokenizer(str)) {
|
||||
// iterate over the tokens
|
||||
}
|
||||
|
||||
// transform code to array of tokens:
|
||||
var tokens = [...acorn.tokenizer(str)]
|
||||
```
|
||||
|
||||
**tokTypes** holds an object mapping names to the token type objects
|
||||
that end up in the `type` properties of tokens.
|
||||
|
||||
**getLineInfo**`(input, offset)` can be used to get a `{line,
|
||||
column}` object for a given program string and offset.
|
||||
|
||||
### The `Parser` class
|
||||
|
||||
Instances of the **`Parser`** class contain all the state and logic
|
||||
that drives a parse. It has static methods `parse`,
|
||||
`parseExpressionAt`, and `tokenizer` that match the top-level
|
||||
functions by the same name.
|
||||
|
||||
When extending the parser with plugins, you need to call these methods
|
||||
on the extended version of the class. To extend a parser with plugins,
|
||||
you can use its static `extend` method.
|
||||
|
||||
```javascript
|
||||
var acorn = require("acorn")
|
||||
var jsx = require("acorn-jsx")
|
||||
var JSXParser = acorn.Parser.extend(jsx())
|
||||
JSXParser.parse("foo(<bar/>)", {ecmaVersion: 2020})
|
||||
```
|
||||
|
||||
The `extend` method takes any number of plugin values, and returns a
|
||||
new `Parser` class that includes the extra parser logic provided by
|
||||
the plugins.
|
||||
|
||||
## Command line interface
|
||||
|
||||
The `bin/acorn` utility can be used to parse a file from the command
|
||||
line. It accepts as arguments its input file and the following
|
||||
options:
|
||||
|
||||
- `--ecma3|--ecma5|--ecma6|--ecma7|--ecma8|--ecma9|--ecma10`: Sets the ECMAScript version
|
||||
to parse. Default is version 9.
|
||||
|
||||
- `--module`: Sets the parsing mode to `"module"`. Is set to `"script"` otherwise.
|
||||
|
||||
- `--locations`: Attaches a "loc" object to each node with "start" and
|
||||
"end" subobjects, each of which contains the one-based line and
|
||||
zero-based column numbers in `{line, column}` form.
|
||||
|
||||
- `--allow-hash-bang`: If the code starts with the characters #! (as
|
||||
in a shellscript), the first line will be treated as a comment.
|
||||
|
||||
- `--allow-await-outside-function`: Allows top-level `await` expressions.
|
||||
See the `allowAwaitOutsideFunction` option for more information.
|
||||
|
||||
- `--compact`: No whitespace is used in the AST output.
|
||||
|
||||
- `--silent`: Do not output the AST, just return the exit status.
|
||||
|
||||
- `--help`: Print the usage information and quit.
|
||||
|
||||
The utility spits out the syntax tree as JSON data.
|
||||
|
||||
## Existing plugins
|
||||
|
||||
- [`acorn-jsx`](https://github.com/RReverser/acorn-jsx): Parse [Facebook JSX syntax extensions](https://github.com/facebook/jsx)
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Internal webcrypto alias.
|
||||
* We prefer WebCrypto aka globalThis.crypto, which exists in node.js 16+.
|
||||
* Falls back to Node.js built-in crypto for Node.js <=v14.
|
||||
* See utils.ts for details.
|
||||
* @module
|
||||
*/
|
||||
// @ts-ignore
|
||||
import * as nc from 'node:crypto';
|
||||
export const crypto = nc && typeof nc === 'object' && 'webcrypto' in nc
|
||||
? nc.webcrypto
|
||||
: nc && typeof nc === 'object' && 'randomBytes' in nc
|
||||
? nc
|
||||
: undefined;
|
||||
//# sourceMappingURL=cryptoNode.js.map
|
||||
@@ -0,0 +1,11 @@
|
||||
"use strict";
|
||||
// THIS CODE WAS AUTOMATICALLY GENERATED
|
||||
// DO NOT EDIT THIS CODE BY HAND
|
||||
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
|
||||
// npx nx generate-lib repo
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.webworker_asynciterable = void 0;
|
||||
exports.webworker_asynciterable = {
|
||||
libs: [],
|
||||
variables: [],
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
module.exports = function generate_comment(it, $keyword, $ruleType) {
|
||||
var out = ' ';
|
||||
var $schema = it.schema[$keyword];
|
||||
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
||||
var $breakOnError = !it.opts.allErrors;
|
||||
var $comment = it.util.toQuotedString($schema);
|
||||
if (it.opts.$comment === true) {
|
||||
out += ' console.log(' + ($comment) + ');';
|
||||
} else if (typeof it.opts.$comment == 'function') {
|
||||
out += ' self._opts.$comment(' + ($comment) + ', ' + (it.util.toQuotedString($errSchemaPath)) + ', validate.root.schema);';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const util_1 = require("../util");
|
||||
const getESLintCoreRule_1 = require("../util/getESLintCoreRule");
|
||||
const baseRule = (0, getESLintCoreRule_1.getESLintCoreRule)('no-unused-expressions');
|
||||
const defaultOptions = [
|
||||
{
|
||||
allowShortCircuit: false,
|
||||
allowTaggedTemplates: false,
|
||||
allowTernary: false,
|
||||
},
|
||||
];
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'no-unused-expressions',
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
defaultOptions,
|
||||
docs: {
|
||||
description: 'Disallow unused expressions',
|
||||
extendsBaseRule: true,
|
||||
recommended: 'recommended',
|
||||
},
|
||||
hasSuggestions: baseRule.meta.hasSuggestions,
|
||||
messages: baseRule.meta.messages,
|
||||
schema: baseRule.meta.schema,
|
||||
},
|
||||
defaultOptions,
|
||||
create(context, [{ allowShortCircuit = false, allowTernary = false }]) {
|
||||
const rules = baseRule.create(context);
|
||||
function isValidExpression(node) {
|
||||
if (allowShortCircuit && node.type === utils_1.AST_NODE_TYPES.LogicalExpression) {
|
||||
return isValidExpression(node.right);
|
||||
}
|
||||
if (allowTernary && node.type === utils_1.AST_NODE_TYPES.ConditionalExpression) {
|
||||
return (isValidExpression(node.alternate) &&
|
||||
isValidExpression(node.consequent));
|
||||
}
|
||||
return ((node.type === utils_1.AST_NODE_TYPES.ChainExpression &&
|
||||
node.expression.type === utils_1.AST_NODE_TYPES.CallExpression) ||
|
||||
node.type === utils_1.AST_NODE_TYPES.ImportExpression);
|
||||
}
|
||||
return {
|
||||
ExpressionStatement(node) {
|
||||
if (node.directive || isValidExpression(node.expression)) {
|
||||
return;
|
||||
}
|
||||
const expressionType = node.expression.type;
|
||||
if (expressionType ===
|
||||
utils_1.TSESTree.AST_NODE_TYPES.TSInstantiationExpression ||
|
||||
expressionType === utils_1.TSESTree.AST_NODE_TYPES.TSAsExpression ||
|
||||
expressionType === utils_1.TSESTree.AST_NODE_TYPES.TSNonNullExpression ||
|
||||
expressionType === utils_1.TSESTree.AST_NODE_TYPES.TSTypeAssertion) {
|
||||
rules.ExpressionStatement({
|
||||
...node,
|
||||
expression: node.expression.expression,
|
||||
});
|
||||
return;
|
||||
}
|
||||
rules.ExpressionStatement(node);
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
function _isNativeFunction(t) {
|
||||
try {
|
||||
return -1 !== Function.toString.call(t).indexOf("[native code]");
|
||||
} catch (n) {
|
||||
return "function" == typeof t;
|
||||
}
|
||||
}
|
||||
module.exports = _isNativeFunction, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,374 @@
|
||||
import { expect, test } from "vitest";
|
||||
import * as z from "zod/v4";
|
||||
|
||||
test("continuability", () => {
|
||||
/**
|
||||
* | $ZodGUID
|
||||
| $ZodUUID
|
||||
| $ZodEmail
|
||||
| $ZodURL
|
||||
| $ZodEmoji
|
||||
| $ZodNanoID
|
||||
| $ZodCUID
|
||||
| $ZodCUID2
|
||||
| $ZodULID
|
||||
| $ZodXID
|
||||
| $ZodKSUID
|
||||
| $ZodISODateTime
|
||||
| $ZodISODate
|
||||
| $ZodISOTime
|
||||
| $ZodISODuration
|
||||
| $ZodIPv4
|
||||
| $ZodIPv6
|
||||
| $ZodCIDRv4
|
||||
| $ZodCIDRv6
|
||||
| $ZodBase64
|
||||
| $ZodBase64URL
|
||||
| $ZodE164
|
||||
| $ZodJWT;
|
||||
*/
|
||||
expect(
|
||||
z
|
||||
.email()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "email",
|
||||
"message": "Invalid email address",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.uuid()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "uuid",
|
||||
"message": "Invalid UUID",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.url()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "url",
|
||||
"message": "Invalid URL",
|
||||
"path": [],
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.jwt()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "jwt",
|
||||
"message": "Invalid JWT",
|
||||
"path": [],
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.cidrv4()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "cidrv4",
|
||||
"message": "Invalid IPv4 range",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\/([0-9]|[1-2][0-9]|3[0-2])$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.cidrv6()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "cidrv6",
|
||||
"message": "Invalid IPv6 range",
|
||||
"path": [],
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.ipv4()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "ipv4",
|
||||
"message": "Invalid IPv4 address",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.ipv6()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "ipv6",
|
||||
"message": "Invalid IPv6 address",
|
||||
"path": [],
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.mac()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "mac",
|
||||
"message": "Invalid MAC address",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}$|^(?:[0-9a-f]{2}:){5}[0-9a-f]{2}$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.emoji()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "emoji",
|
||||
"message": "Invalid emoji",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$/u",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.nanoid()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "nanoid",
|
||||
"message": "Invalid nanoid",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^[a-zA-Z0-9_-]{21}$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.cuid()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "cuid",
|
||||
"message": "Invalid cuid",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^[cC][0-9a-z]{6,}$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.cuid2()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "cuid2",
|
||||
"message": "Invalid cuid2",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^[0-9a-z]+$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.ulid()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "ulid",
|
||||
"message": "Invalid ULID",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.xid()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "xid",
|
||||
"message": "Invalid XID",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^[0-9a-vA-V]{20}$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(
|
||||
z
|
||||
.ksuid()
|
||||
.refine(() => false)
|
||||
.safeParse("invalid_value").error!.issues
|
||||
).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"code": "invalid_format",
|
||||
"format": "ksuid",
|
||||
"message": "Invalid KSUID",
|
||||
"origin": "string",
|
||||
"path": [],
|
||||
"pattern": "/^[A-Za-z0-9]{27}$/",
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "Invalid input",
|
||||
"path": [],
|
||||
},
|
||||
]
|
||||
`);
|
||||
});
|
||||
@@ -0,0 +1,127 @@
|
||||
import * as BufferLayout from '@solana/buffer-layout';
|
||||
|
||||
import {Signer} from '../keypair';
|
||||
import assert from '../utils/assert';
|
||||
import {VersionedMessage} from '../message/versioned';
|
||||
import {SIGNATURE_LENGTH_IN_BYTES} from './constants';
|
||||
import * as shortvec from '../utils/shortvec-encoding';
|
||||
import * as Layout from '../layout';
|
||||
import {sign} from '../utils/ed25519';
|
||||
import {PublicKey} from '../publickey';
|
||||
import {guardedSplice} from '../utils/guarded-array-utils';
|
||||
|
||||
export type TransactionVersion = 'legacy' | 0;
|
||||
|
||||
/**
|
||||
* Versioned transaction class
|
||||
*/
|
||||
export class VersionedTransaction {
|
||||
signatures: Array<Uint8Array>;
|
||||
message: VersionedMessage;
|
||||
|
||||
get version(): TransactionVersion {
|
||||
return this.message.version;
|
||||
}
|
||||
|
||||
constructor(message: VersionedMessage, signatures?: Array<Uint8Array>) {
|
||||
if (signatures !== undefined) {
|
||||
assert(
|
||||
signatures.length === message.header.numRequiredSignatures,
|
||||
'Expected signatures length to be equal to the number of required signatures',
|
||||
);
|
||||
this.signatures = signatures;
|
||||
} else {
|
||||
const defaultSignatures = [];
|
||||
for (let i = 0; i < message.header.numRequiredSignatures; i++) {
|
||||
defaultSignatures.push(new Uint8Array(SIGNATURE_LENGTH_IN_BYTES));
|
||||
}
|
||||
this.signatures = defaultSignatures;
|
||||
}
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
serialize(): Uint8Array {
|
||||
const serializedMessage = this.message.serialize();
|
||||
|
||||
const encodedSignaturesLength = Array<number>();
|
||||
shortvec.encodeLength(encodedSignaturesLength, this.signatures.length);
|
||||
|
||||
const transactionLayout = BufferLayout.struct<{
|
||||
encodedSignaturesLength: Uint8Array;
|
||||
signatures: Array<Uint8Array>;
|
||||
serializedMessage: Uint8Array;
|
||||
}>([
|
||||
BufferLayout.blob(
|
||||
encodedSignaturesLength.length,
|
||||
'encodedSignaturesLength',
|
||||
),
|
||||
BufferLayout.seq(
|
||||
Layout.signature(),
|
||||
this.signatures.length,
|
||||
'signatures',
|
||||
),
|
||||
BufferLayout.blob(serializedMessage.length, 'serializedMessage'),
|
||||
]);
|
||||
|
||||
const serializedTransaction = new Uint8Array(2048);
|
||||
const serializedTransactionLength = transactionLayout.encode(
|
||||
{
|
||||
encodedSignaturesLength: new Uint8Array(encodedSignaturesLength),
|
||||
signatures: this.signatures,
|
||||
serializedMessage,
|
||||
},
|
||||
serializedTransaction,
|
||||
);
|
||||
|
||||
return serializedTransaction.slice(0, serializedTransactionLength);
|
||||
}
|
||||
|
||||
static deserialize(serializedTransaction: Uint8Array): VersionedTransaction {
|
||||
let byteArray = [...serializedTransaction];
|
||||
|
||||
const signatures = [];
|
||||
const signaturesLength = shortvec.decodeLength(byteArray);
|
||||
for (let i = 0; i < signaturesLength; i++) {
|
||||
signatures.push(
|
||||
new Uint8Array(guardedSplice(byteArray, 0, SIGNATURE_LENGTH_IN_BYTES)),
|
||||
);
|
||||
}
|
||||
|
||||
const message = VersionedMessage.deserialize(new Uint8Array(byteArray));
|
||||
return new VersionedTransaction(message, signatures);
|
||||
}
|
||||
|
||||
sign(signers: Array<Signer>) {
|
||||
const messageData = this.message.serialize();
|
||||
const signerPubkeys = this.message.staticAccountKeys.slice(
|
||||
0,
|
||||
this.message.header.numRequiredSignatures,
|
||||
);
|
||||
for (const signer of signers) {
|
||||
const signerIndex = signerPubkeys.findIndex(pubkey =>
|
||||
pubkey.equals(signer.publicKey),
|
||||
);
|
||||
assert(
|
||||
signerIndex >= 0,
|
||||
`Cannot sign with non signer key ${signer.publicKey.toBase58()}`,
|
||||
);
|
||||
this.signatures[signerIndex] = sign(messageData, signer.secretKey);
|
||||
}
|
||||
}
|
||||
|
||||
addSignature(publicKey: PublicKey, signature: Uint8Array) {
|
||||
assert(signature.byteLength === 64, 'Signature must be 64 bytes long');
|
||||
const signerPubkeys = this.message.staticAccountKeys.slice(
|
||||
0,
|
||||
this.message.header.numRequiredSignatures,
|
||||
);
|
||||
const signerIndex = signerPubkeys.findIndex(pubkey =>
|
||||
pubkey.equals(publicKey),
|
||||
);
|
||||
assert(
|
||||
signerIndex >= 0,
|
||||
`Can not add signature; \`${publicKey.toBase58()}\` is not required to sign this transaction`,
|
||||
);
|
||||
this.signatures[signerIndex] = signature;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"coercions.d.ts","sourceRoot":"","sources":["../../src/structs/coercions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAM,OAAO,EAAE,MAAM,cAAc,CAAA;AAIlD;;;;;;;;;GASG;AAEH,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAC5B,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACpB,SAAS,EAAE,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,EACzB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAClB,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CASd;AAED;;;;;GAKG;AAEH,wBAAgB,SAAS,CAAC,CAAC,EAAE,CAAC,EAC5B,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACpB,QAAQ,EAAE,GAAG,EACb,OAAO,GAAE;IACP,MAAM,CAAC,EAAE,OAAO,CAAA;CACZ,GACL,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CA0Bd;AAED;;;;;GAKG;AAEH,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAEhE"}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
|
||||
function _throw(e) {
|
||||
throw e;
|
||||
}
|
||||
export { _throw as _ };
|
||||
@@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const {Transform} = require('stream');
|
||||
const {next} = require('./asFun');
|
||||
const {sanitize} = require('../index');
|
||||
|
||||
const comp = (...fns) => {
|
||||
fns = fns.filter(fn => fn);
|
||||
return fns.length
|
||||
? new Transform({
|
||||
writableObjectMode: true,
|
||||
readableObjectMode: true,
|
||||
transform(chunk, encoding, callback) {
|
||||
next(chunk, fns, 0, value => sanitize(value, this)).then(() => callback(null), error => callback(error));
|
||||
}
|
||||
})
|
||||
: null;
|
||||
};
|
||||
|
||||
module.exports = comp;
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { StringReader, StringWriter } from './strings.cts';
|
||||
export declare const comma: number;
|
||||
export declare const semicolon: number;
|
||||
export declare function decodeInteger(reader: StringReader, relative: number): number;
|
||||
export declare function encodeInteger(builder: StringWriter, num: number, relative: number): number;
|
||||
export declare function hasMoreVlq(reader: StringReader, max: number): boolean;
|
||||
//# sourceMappingURL=vlq.d.ts.map
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Reference in New Issue
Block a user