WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "keyv",
|
||||
"version": "4.5.4",
|
||||
"description": "Simple key-value storage with support for multiple backends",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"build": "echo 'No build step required.'",
|
||||
"prepare": "yarn build",
|
||||
"test": "xo && c8 ava --serial",
|
||||
"test:ci": "xo && ava --serial",
|
||||
"clean": "rm -rf node_modules && rm -rf ./coverage && rm -rf ./test/testdb.sqlite"
|
||||
},
|
||||
"xo": {
|
||||
"rules": {
|
||||
"unicorn/prefer-module": 0,
|
||||
"unicorn/prefer-node-protocol": 0,
|
||||
"@typescript-eslint/consistent-type-definitions": 0,
|
||||
"unicorn/no-typeof-undefined": 0,
|
||||
"unicorn/prefer-event-target": 0
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/jaredwray/keyv.git"
|
||||
},
|
||||
"keywords": [
|
||||
"key",
|
||||
"value",
|
||||
"store",
|
||||
"cache",
|
||||
"ttl"
|
||||
],
|
||||
"author": "Jared Wray <me@jaredwray.com> (http://jaredwray.com)",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/jaredwray/keyv/issues"
|
||||
},
|
||||
"homepage": "https://github.com/jaredwray/keyv",
|
||||
"dependencies": {
|
||||
"json-buffer": "3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@keyv/test-suite": "*",
|
||||
"eslint": "^8.51.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"pify": "^5.0.0",
|
||||
"timekeeper": "^2.3.1",
|
||||
"tsd": "^0.29.0"
|
||||
},
|
||||
"tsd": {
|
||||
"directory": "test"
|
||||
},
|
||||
"types": "./src/index.d.ts",
|
||||
"files": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { FixedSizeCodec, FixedSizeDecoder, FixedSizeEncoder } from '@solana/codecs-core';
|
||||
import { NumberCodecConfig } from './common';
|
||||
/**
|
||||
* Returns an encoder for 64-bit signed integers (`i64`).
|
||||
*
|
||||
* This encoder serializes `i64` values using 8 bytes.
|
||||
* Values can be provided as either `number` or `bigint`.
|
||||
*
|
||||
* For more details, see {@link getI64Codec}.
|
||||
*
|
||||
* @param config - Optional configuration to specify endianness (little by default).
|
||||
* @returns A `FixedSizeEncoder<number | bigint, 8>` for encoding `i64` values.
|
||||
*
|
||||
* @example
|
||||
* Encoding an `i64` value.
|
||||
* ```ts
|
||||
* const encoder = getI64Encoder();
|
||||
* const bytes = encoder.encode(-42n); // 0xd6ffffffffffffff
|
||||
* ```
|
||||
*
|
||||
* @see {@link getI64Codec}
|
||||
*/
|
||||
export declare const getI64Encoder: (config?: NumberCodecConfig) => FixedSizeEncoder<bigint | number, 8>;
|
||||
/**
|
||||
* Returns a decoder for 64-bit signed integers (`i64`).
|
||||
*
|
||||
* This decoder deserializes `i64` values from 8 bytes.
|
||||
* The decoded value is always a `bigint`.
|
||||
*
|
||||
* For more details, see {@link getI64Codec}.
|
||||
*
|
||||
* @param config - Optional configuration to specify endianness (little by default).
|
||||
* @returns A `FixedSizeDecoder<bigint, 8>` for decoding `i64` values.
|
||||
*
|
||||
* @example
|
||||
* Decoding an `i64` value.
|
||||
* ```ts
|
||||
* const decoder = getI64Decoder();
|
||||
* const value = decoder.decode(new Uint8Array([
|
||||
* 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
* ])); // -42n
|
||||
* ```
|
||||
*
|
||||
* @see {@link getI64Codec}
|
||||
*/
|
||||
export declare const getI64Decoder: (config?: NumberCodecConfig) => FixedSizeDecoder<bigint, 8>;
|
||||
/**
|
||||
* Returns a codec for encoding and decoding 64-bit signed integers (`i64`).
|
||||
*
|
||||
* This codec serializes `i64` values using 8 bytes.
|
||||
* Values can be provided as either `number` or `bigint`, but the decoded value is always a `bigint`.
|
||||
*
|
||||
* @param config - Optional configuration to specify endianness (little by default).
|
||||
* @returns A `FixedSizeCodec<number | bigint, bigint, 8>` for encoding and decoding `i64` values.
|
||||
*
|
||||
* @example
|
||||
* Encoding and decoding an `i64` value.
|
||||
* ```ts
|
||||
* const codec = getI64Codec();
|
||||
* const bytes = codec.encode(-42n); // 0xd6ffffffffffffff
|
||||
* const value = codec.decode(bytes); // -42n
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* Using big-endian encoding.
|
||||
* ```ts
|
||||
* const codec = getI64Codec({ endian: Endian.Big });
|
||||
* const bytes = codec.encode(-42n); // 0xffffffffffffffd6
|
||||
* ```
|
||||
*
|
||||
* @remarks
|
||||
* This codec supports values between `-2^63` and `2^63 - 1`.
|
||||
* Since JavaScript `number` cannot safely represent values beyond `2^53 - 1`, the decoded value is always a `bigint`.
|
||||
*
|
||||
* - If you need a smaller signed integer, consider using {@link getI32Codec} or {@link getI16Codec}.
|
||||
* - If you need a larger signed integer, consider using {@link getI128Codec}.
|
||||
* - If you need unsigned integers, consider using {@link getU64Codec}.
|
||||
*
|
||||
* Separate {@link getI64Encoder} and {@link getI64Decoder} functions are available.
|
||||
*
|
||||
* ```ts
|
||||
* const bytes = getI64Encoder().encode(-42);
|
||||
* const value = getI64Decoder().decode(bytes);
|
||||
* ```
|
||||
*
|
||||
* @see {@link getI64Encoder}
|
||||
* @see {@link getI64Decoder}
|
||||
*/
|
||||
export declare const getI64Codec: (config?: NumberCodecConfig) => FixedSizeCodec<bigint | number, bigint, 8>;
|
||||
//# sourceMappingURL=i64.d.ts.map
|
||||
@@ -0,0 +1,24 @@
|
||||
"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.es2018_full = void 0;
|
||||
const dom_1 = require("./dom");
|
||||
const dom_asynciterable_1 = require("./dom.asynciterable");
|
||||
const dom_iterable_1 = require("./dom.iterable");
|
||||
const es2018_1 = require("./es2018");
|
||||
const scripthost_1 = require("./scripthost");
|
||||
const webworker_importscripts_1 = require("./webworker.importscripts");
|
||||
exports.es2018_full = {
|
||||
libs: [
|
||||
es2018_1.es2018,
|
||||
dom_1.dom,
|
||||
webworker_importscripts_1.webworker_importscripts,
|
||||
scripthost_1.scripthost,
|
||||
dom_iterable_1.dom_iterable,
|
||||
dom_asynciterable_1.dom_asynciterable,
|
||||
],
|
||||
variables: [],
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"misc.js","sourceRoot":"","sources":["../src/misc.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,sEAAsE;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EACL,cAAc,GAIf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,WAAW,EAA4B,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,6FAA6F;AAC7F,8CAA8C;AAC9C,oDAAoD;AACpD,MAAM,YAAY,GAAgB;IAChC,CAAC,EAAE,YAAY,CAAC,KAAK;IACrB,CAAC,EAAE,MAAM,CAAC,mEAAmE,CAAC;IAC9E,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC,oEAAoE,CAAC;IAC/E,CAAC,EAAE,MAAM,CAAC,oEAAoE,CAAC;IAC/E,EAAE,EAAE,MAAM,CAAC,oEAAoE,CAAC;IAChF,EAAE,EAAE,MAAM,CAAC,oEAAoE,CAAC;CACjF,CAAC;AACF,8DAA8D;AAC9D,MAAM,CAAC,MAAM,MAAM,GAAY,eAAe,CAAC,cAAc,CAAC;IAC5D,GAAG,YAAY;IACf,EAAE,EAAE,YAAY;IAChB,IAAI,EAAE,MAAM;CACb,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAgB;IACpC,CAAC,EAAE,QAAQ,CAAC,KAAK;IACjB,CAAC,EAAE,MAAM,CAAC,oEAAoE,CAAC;IAC/E,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC,mEAAmE,CAAC;IAC/E,EAAE,EAAE,MAAM,CAAC,mEAAmE,CAAC;CAChF,CAAC;AACF,gEAAgE;AAChE,MAAM,CAAC,MAAM,UAAU,GAAY,eAAe,CAAC,cAAc,CAAC;IAChE,GAAG,gBAAgB;IACnB,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,QAAQ;CACf,CAAC,CAAC;AAEH,MAAM,qBAAqB,GAAG,WAAW,CACvC,kEAAkE,CACnE,CAAC;AAEF,kEAAkE;AAClE,MAAM,UAAU,gBAAgB,CAAC,GAAe,EAAE,eAA2B;IAC3E,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;IAChC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACd,mEAAmE;IACnE,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3C,0DAA0D;IAC1D,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC1E,OAAO,CAAC,CAAC;AACX,CAAC;AAED,wCAAwC;AACxC,gCAAgC;AAChC,iFAAiF;AACjF,MAAM,UAAU,oBAAoB,CAAC,CAAa,EAAE,eAA2B;IAC7E,MAAM,GAAG,GAAG,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,EAAE,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC,CAAA,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAClE,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;AACnB,CAAC;AAED,sFAAsF;AAEtF,MAAM,CAAC,MAAM,OAAO,GAAW,MAAM,CACnC,oEAAoE,CACrE,CAAC;AACF,MAAM,CAAC,MAAM,OAAO,GAAW,MAAM,CACnC,oEAAoE,CACrE,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAa,WAAW,CAAC;IAC1C,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACZ,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC;IAClB,CAAC,EAAE,OAAO;IACV,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;IAC5B,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IACb,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACZ,IAAI,EAAE,MAAM;CACb,CAAC,CAAC;AACH;;GAEG;AACH,MAAM,CAAC,MAAM,KAAK,GAAa,WAAW,CAAC;IACzC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACZ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACZ,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC;IAClB,CAAC,EAAE,OAAO;IACV,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;IAC5B,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IACb,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IACZ,IAAI,EAAE,MAAM;CACb,CAAC,CAAC"}
|
||||
@@ -0,0 +1,251 @@
|
||||
/**
|
||||
* @fileoverview Disallows or enforces spaces inside computed properties.
|
||||
* @author Jamund Ferguson
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "11.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "computed-property-spacing",
|
||||
url: "https://eslint.style/rules/computed-property-spacing",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce consistent spacing inside computed property brackets",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/computed-property-spacing",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: [
|
||||
{
|
||||
enum: ["always", "never"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
enforceForClassMembers: {
|
||||
type: "boolean",
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpectedSpaceBefore:
|
||||
"There should be no space before '{{tokenValue}}'.",
|
||||
unexpectedSpaceAfter:
|
||||
"There should be no space after '{{tokenValue}}'.",
|
||||
|
||||
missingSpaceBefore: "A space is required before '{{tokenValue}}'.",
|
||||
missingSpaceAfter: "A space is required after '{{tokenValue}}'.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
|
||||
const enforceForClassMembers =
|
||||
!context.options[1] || context.options[1].enforceForClassMembers;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a space after the first token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @param {Token} tokenAfter The token after `token`.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoBeginningSpace(node, token, tokenAfter) {
|
||||
context.report({
|
||||
node,
|
||||
loc: { start: token.loc.end, end: tokenAfter.loc.start },
|
||||
messageId: "unexpectedSpaceAfter",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
token.range[1],
|
||||
tokenAfter.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there shouldn't be a space before the last token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @param {Token} tokenBefore The token before `token`.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportNoEndingSpace(node, token, tokenBefore) {
|
||||
context.report({
|
||||
node,
|
||||
loc: { start: tokenBefore.loc.end, end: token.loc.start },
|
||||
messageId: "unexpectedSpaceBefore",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.removeRange([
|
||||
tokenBefore.range[1],
|
||||
token.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a space after the first token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredBeginningSpace(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "missingSpaceAfter",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextAfter(token, " ");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports that there should be a space before the last token
|
||||
* @param {ASTNode} node The node to report in the event of an error.
|
||||
* @param {Token} token The token to use for the report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportRequiredEndingSpace(node, token) {
|
||||
context.report({
|
||||
node,
|
||||
loc: token.loc,
|
||||
messageId: "missingSpaceBefore",
|
||||
data: {
|
||||
tokenValue: token.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
return fixer.insertTextBefore(token, " ");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a function that checks the spacing of a node on the property name
|
||||
* that was passed in.
|
||||
* @param {string} propertyName The property on the node to check for spacing
|
||||
* @returns {Function} A function that will check spacing on a node
|
||||
*/
|
||||
function checkSpacing(propertyName) {
|
||||
return function (node) {
|
||||
if (!node.computed) {
|
||||
return;
|
||||
}
|
||||
|
||||
const property = node[propertyName];
|
||||
|
||||
const before = sourceCode.getTokenBefore(
|
||||
property,
|
||||
astUtils.isOpeningBracketToken,
|
||||
),
|
||||
first = sourceCode.getTokenAfter(before, {
|
||||
includeComments: true,
|
||||
}),
|
||||
after = sourceCode.getTokenAfter(
|
||||
property,
|
||||
astUtils.isClosingBracketToken,
|
||||
),
|
||||
last = sourceCode.getTokenBefore(after, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
if (astUtils.isTokenOnSameLine(before, first)) {
|
||||
if (propertyNameMustBeSpaced) {
|
||||
if (
|
||||
!sourceCode.isSpaceBetween(before, first) &&
|
||||
astUtils.isTokenOnSameLine(before, first)
|
||||
) {
|
||||
reportRequiredBeginningSpace(node, before);
|
||||
}
|
||||
} else {
|
||||
if (sourceCode.isSpaceBetween(before, first)) {
|
||||
reportNoBeginningSpace(node, before, first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (astUtils.isTokenOnSameLine(last, after)) {
|
||||
if (propertyNameMustBeSpaced) {
|
||||
if (
|
||||
!sourceCode.isSpaceBetween(last, after) &&
|
||||
astUtils.isTokenOnSameLine(last, after)
|
||||
) {
|
||||
reportRequiredEndingSpace(node, after);
|
||||
}
|
||||
} else {
|
||||
if (sourceCode.isSpaceBetween(last, after)) {
|
||||
reportNoEndingSpace(node, after, last);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
const listeners = {
|
||||
Property: checkSpacing("key"),
|
||||
MemberExpression: checkSpacing("property"),
|
||||
};
|
||||
|
||||
if (enforceForClassMembers) {
|
||||
listeners.MethodDefinition = listeners.PropertyDefinition =
|
||||
listeners.Property;
|
||||
}
|
||||
|
||||
return listeners;
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"cryptoNode.js","sourceRoot":"","sources":["../src/cryptoNode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,aAAa;AACb,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,MAAM,CAAC,MAAM,MAAM,GACjB,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,WAAW,IAAI,EAAE;IAC/C,CAAC,CAAE,EAAE,CAAC,SAAiB;IACvB,CAAC,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,aAAa,IAAI,EAAE;QACnD,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,SAAS,CAAC"}
|
||||
@@ -0,0 +1,2 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
@@ -0,0 +1,27 @@
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABILITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
interface MapConstructor {
|
||||
/**
|
||||
* Groups members of an iterable according to the return value of the passed callback.
|
||||
* @param items An iterable.
|
||||
* @param keySelector A callback which will be invoked for each item in items.
|
||||
*/
|
||||
groupBy<K, T>(
|
||||
items: Iterable<T>,
|
||||
keySelector: (item: T, index: number) => K,
|
||||
): Map<K, T[]>;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
var _class_apply_descriptor_destructure = require("./_class_apply_descriptor_destructure.cjs");
|
||||
var _class_extract_field_descriptor = require("./_class_extract_field_descriptor.cjs");
|
||||
|
||||
function _class_private_field_destructure(receiver, privateMap) {
|
||||
var descriptor = _class_extract_field_descriptor._(receiver, privateMap, "set");
|
||||
return _class_apply_descriptor_destructure._(receiver, descriptor);
|
||||
}
|
||||
exports._ = _class_private_field_destructure;
|
||||
@@ -0,0 +1,747 @@
|
||||
/**
|
||||
* BLS != BLS.
|
||||
* The file implements BLS (Boneh-Lynn-Shacham) signatures.
|
||||
* Used in both BLS (Barreto-Lynn-Scott) and BN (Barreto-Naehrig)
|
||||
* families of pairing-friendly curves.
|
||||
* Consists of two curves: G1 and G2:
|
||||
* - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4.
|
||||
* - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1
|
||||
* - Gt, created by bilinear (ate) pairing e(G1, G2), consists of p-th roots of unity in
|
||||
* Fq^k where k is embedding degree. Only degree 12 is currently supported, 24 is not.
|
||||
* Pairing is used to aggregate and verify signatures.
|
||||
* There are two modes of operation:
|
||||
* - Long signatures: X-byte keys + 2X-byte sigs (G1 keys + G2 sigs).
|
||||
* - Short signatures: 2X-byte keys + X-byte sigs (G2 keys + G1 sigs).
|
||||
* @module
|
||||
**/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import {
|
||||
abytes,
|
||||
ensureBytes,
|
||||
memoized,
|
||||
randomBytes,
|
||||
type CHash,
|
||||
type Hex,
|
||||
type PrivKey,
|
||||
} from '../utils.ts';
|
||||
import { normalizeZ } from './curve.ts';
|
||||
import {
|
||||
createHasher,
|
||||
type H2CHasher,
|
||||
type H2CHashOpts,
|
||||
type H2COpts,
|
||||
type H2CPointConstructor,
|
||||
type htfBasicOpts,
|
||||
type MapToCurve,
|
||||
} from './hash-to-curve.ts';
|
||||
import { getMinHashLength, mapHashToField, type IField } from './modular.ts';
|
||||
import type { Fp12, Fp12Bls, Fp2, Fp2Bls, Fp6Bls } from './tower.ts';
|
||||
import {
|
||||
_normFnElement,
|
||||
weierstrassPoints,
|
||||
type CurvePointsRes,
|
||||
type CurvePointsType,
|
||||
type WeierstrassPoint,
|
||||
type WeierstrassPointCons,
|
||||
} from './weierstrass.ts';
|
||||
|
||||
type Fp = bigint; // Can be different field?
|
||||
|
||||
// prettier-ignore
|
||||
const _0n = BigInt(0), _1n = BigInt(1), _2n = BigInt(2), _3n = BigInt(3);
|
||||
|
||||
export type TwistType = 'multiplicative' | 'divisive';
|
||||
|
||||
export type ShortSignatureCoder<Fp> = {
|
||||
fromBytes(bytes: Uint8Array): WeierstrassPoint<Fp>;
|
||||
fromHex(hex: Hex): WeierstrassPoint<Fp>;
|
||||
toBytes(point: WeierstrassPoint<Fp>): Uint8Array;
|
||||
toHex(point: WeierstrassPoint<Fp>): string;
|
||||
/** @deprecated use `toBytes` */
|
||||
toRawBytes(point: WeierstrassPoint<Fp>): Uint8Array;
|
||||
};
|
||||
|
||||
export type SignatureCoder<Fp> = {
|
||||
fromBytes(bytes: Uint8Array): WeierstrassPoint<Fp>;
|
||||
fromHex(hex: Hex): WeierstrassPoint<Fp>;
|
||||
toBytes(point: WeierstrassPoint<Fp>): Uint8Array;
|
||||
toHex(point: WeierstrassPoint<Fp>): string;
|
||||
/** @deprecated use `toBytes` */
|
||||
toRawBytes(point: WeierstrassPoint<Fp>): Uint8Array;
|
||||
};
|
||||
|
||||
export type BlsFields = {
|
||||
Fp: IField<Fp>;
|
||||
Fr: IField<bigint>;
|
||||
Fp2: Fp2Bls;
|
||||
Fp6: Fp6Bls;
|
||||
Fp12: Fp12Bls;
|
||||
};
|
||||
|
||||
export type PostPrecomputePointAddFn = (
|
||||
Rx: Fp2,
|
||||
Ry: Fp2,
|
||||
Rz: Fp2,
|
||||
Qx: Fp2,
|
||||
Qy: Fp2
|
||||
) => { Rx: Fp2; Ry: Fp2; Rz: Fp2 };
|
||||
export type PostPrecomputeFn = (
|
||||
Rx: Fp2,
|
||||
Ry: Fp2,
|
||||
Rz: Fp2,
|
||||
Qx: Fp2,
|
||||
Qy: Fp2,
|
||||
pointAdd: PostPrecomputePointAddFn
|
||||
) => void;
|
||||
export type BlsPairing = {
|
||||
Fp12: Fp12Bls;
|
||||
calcPairingPrecomputes: (p: WeierstrassPoint<Fp2>) => Precompute;
|
||||
millerLoopBatch: (pairs: [Precompute, Fp, Fp][]) => Fp12;
|
||||
pairing: (P: WeierstrassPoint<Fp>, Q: WeierstrassPoint<Fp2>, withFinalExponent?: boolean) => Fp12;
|
||||
pairingBatch: (
|
||||
pairs: { g1: WeierstrassPoint<Fp>; g2: WeierstrassPoint<Fp2> }[],
|
||||
withFinalExponent?: boolean
|
||||
) => Fp12;
|
||||
};
|
||||
// TODO: replace CurveType with this? It doesn't contain r however and has postPrecompute
|
||||
export type BlsPairingParams = {
|
||||
// NOTE: MSB is always ignored and used as marker for length,
|
||||
// otherwise leading zeros will be lost.
|
||||
// Can be different from 'X' (seed) param!
|
||||
ateLoopSize: bigint;
|
||||
xNegative: boolean;
|
||||
twistType: TwistType; // BLS12-381: Multiplicative, BN254: Divisive
|
||||
// This is super ugly hack for untwist point in BN254 after miller loop
|
||||
postPrecompute?: PostPrecomputeFn;
|
||||
};
|
||||
export type CurveType = {
|
||||
G1: CurvePointsType<Fp> & {
|
||||
ShortSignature: SignatureCoder<Fp>;
|
||||
mapToCurve: MapToCurve<Fp>;
|
||||
htfDefaults: H2COpts;
|
||||
};
|
||||
G2: CurvePointsType<Fp2> & {
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
mapToCurve: MapToCurve<Fp2>;
|
||||
htfDefaults: H2COpts;
|
||||
};
|
||||
fields: BlsFields;
|
||||
params: {
|
||||
// NOTE: MSB is always ignored and used as marker for length,
|
||||
// otherwise leading zeros will be lost.
|
||||
// Can be different from 'X' (seed) param!
|
||||
ateLoopSize: BlsPairingParams['ateLoopSize'];
|
||||
xNegative: BlsPairingParams['xNegative'];
|
||||
r: bigint; // TODO: remove
|
||||
twistType: BlsPairingParams['twistType']; // BLS12-381: Multiplicative, BN254: Divisive
|
||||
};
|
||||
htfDefaults: H2COpts;
|
||||
hash: CHash; // Because we need outputLen for DRBG
|
||||
randomBytes?: (bytesLength?: number) => Uint8Array;
|
||||
// This is super ugly hack for untwist point in BN254 after miller loop
|
||||
postPrecompute?: PostPrecomputeFn;
|
||||
};
|
||||
|
||||
type PrecomputeSingle = [Fp2, Fp2, Fp2][];
|
||||
type Precompute = PrecomputeSingle[];
|
||||
|
||||
/**
|
||||
* BLS consists of two curves: G1 and G2:
|
||||
* - G1 is a subgroup of (x, y) E(Fq) over y² = x³ + 4.
|
||||
* - G2 is a subgroup of ((x₁, x₂+i), (y₁, y₂+i)) E(Fq²) over y² = x³ + 4(1 + i) where i is √-1
|
||||
*/
|
||||
export interface BLSCurvePair {
|
||||
longSignatures: BLSSigs<bigint, Fp2>;
|
||||
shortSignatures: BLSSigs<Fp2, bigint>;
|
||||
millerLoopBatch: BlsPairing['millerLoopBatch'];
|
||||
pairing: BlsPairing['pairing'];
|
||||
pairingBatch: BlsPairing['pairingBatch'];
|
||||
G1: { Point: WeierstrassPointCons<bigint> } & H2CHasher<Fp>;
|
||||
G2: { Point: WeierstrassPointCons<Fp2> } & H2CHasher<Fp2>;
|
||||
fields: {
|
||||
Fp: IField<Fp>;
|
||||
Fp2: Fp2Bls;
|
||||
Fp6: Fp6Bls;
|
||||
Fp12: Fp12Bls;
|
||||
Fr: IField<bigint>;
|
||||
};
|
||||
utils: {
|
||||
randomSecretKey: () => Uint8Array;
|
||||
/** @deprecated use randomSecretKey */
|
||||
randomPrivateKey: () => Uint8Array;
|
||||
calcPairingPrecomputes: BlsPairing['calcPairingPrecomputes'];
|
||||
};
|
||||
}
|
||||
|
||||
export type CurveFn = BLSCurvePair & {
|
||||
/** @deprecated use `longSignatures.getPublicKey` */
|
||||
getPublicKey: (secretKey: PrivKey) => Uint8Array;
|
||||
/** @deprecated use `shortSignatures.getPublicKey` */
|
||||
getPublicKeyForShortSignatures: (secretKey: PrivKey) => Uint8Array;
|
||||
/** @deprecated use `longSignatures.sign` */
|
||||
sign: {
|
||||
(message: Hex, secretKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
|
||||
(
|
||||
message: WeierstrassPoint<Fp2>,
|
||||
secretKey: PrivKey,
|
||||
htfOpts?: htfBasicOpts
|
||||
): WeierstrassPoint<Fp2>;
|
||||
};
|
||||
/** @deprecated use `shortSignatures.sign` */
|
||||
signShortSignature: {
|
||||
(message: Hex, secretKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
|
||||
(
|
||||
message: WeierstrassPoint<Fp>,
|
||||
secretKey: PrivKey,
|
||||
htfOpts?: htfBasicOpts
|
||||
): WeierstrassPoint<Fp>;
|
||||
};
|
||||
/** @deprecated use `longSignatures.verify` */
|
||||
verify: (
|
||||
signature: Hex | WeierstrassPoint<Fp2>,
|
||||
message: Hex | WeierstrassPoint<Fp2>,
|
||||
publicKey: Hex | WeierstrassPoint<Fp>,
|
||||
htfOpts?: htfBasicOpts
|
||||
) => boolean;
|
||||
/** @deprecated use `shortSignatures.verify` */
|
||||
verifyShortSignature: (
|
||||
signature: Hex | WeierstrassPoint<Fp>,
|
||||
message: Hex | WeierstrassPoint<Fp>,
|
||||
publicKey: Hex | WeierstrassPoint<Fp2>,
|
||||
htfOpts?: htfBasicOpts
|
||||
) => boolean;
|
||||
verifyBatch: (
|
||||
signature: Hex | WeierstrassPoint<Fp2>,
|
||||
messages: (Hex | WeierstrassPoint<Fp2>)[],
|
||||
publicKeys: (Hex | WeierstrassPoint<Fp>)[],
|
||||
htfOpts?: htfBasicOpts
|
||||
) => boolean;
|
||||
/** @deprecated use `longSignatures.aggregatePublicKeys` */
|
||||
aggregatePublicKeys: {
|
||||
(publicKeys: Hex[]): Uint8Array;
|
||||
(publicKeys: WeierstrassPoint<Fp>[]): WeierstrassPoint<Fp>;
|
||||
};
|
||||
/** @deprecated use `longSignatures.aggregateSignatures` */
|
||||
aggregateSignatures: {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: WeierstrassPoint<Fp2>[]): WeierstrassPoint<Fp2>;
|
||||
};
|
||||
/** @deprecated use `shortSignatures.aggregateSignatures` */
|
||||
aggregateShortSignatures: {
|
||||
(signatures: Hex[]): Uint8Array;
|
||||
(signatures: WeierstrassPoint<Fp>[]): WeierstrassPoint<Fp>;
|
||||
};
|
||||
G1: CurvePointsRes<Fp> & H2CHasher<Fp>;
|
||||
G2: CurvePointsRes<Fp2> & H2CHasher<Fp2>;
|
||||
/** @deprecated use `longSignatures.Signature` */
|
||||
Signature: SignatureCoder<Fp2>;
|
||||
/** @deprecated use `shortSignatures.Signature` */
|
||||
ShortSignature: ShortSignatureCoder<Fp>;
|
||||
params: {
|
||||
ateLoopSize: bigint;
|
||||
r: bigint;
|
||||
twistType: TwistType;
|
||||
/** @deprecated */
|
||||
G1b: bigint;
|
||||
/** @deprecated */
|
||||
G2b: Fp2;
|
||||
};
|
||||
};
|
||||
|
||||
type BLSInput = Hex | Uint8Array;
|
||||
export interface BLSSigs<P, S> {
|
||||
getPublicKey(secretKey: PrivKey): WeierstrassPoint<P>;
|
||||
sign(hashedMessage: WeierstrassPoint<S>, secretKey: PrivKey): WeierstrassPoint<S>;
|
||||
verify(
|
||||
signature: WeierstrassPoint<S> | BLSInput,
|
||||
message: WeierstrassPoint<S>,
|
||||
publicKey: WeierstrassPoint<P> | BLSInput
|
||||
): boolean;
|
||||
verifyBatch: (
|
||||
signature: WeierstrassPoint<S> | BLSInput,
|
||||
messages: WeierstrassPoint<S>[],
|
||||
publicKeys: (WeierstrassPoint<P> | BLSInput)[]
|
||||
) => boolean;
|
||||
aggregatePublicKeys(publicKeys: (WeierstrassPoint<P> | BLSInput)[]): WeierstrassPoint<P>;
|
||||
aggregateSignatures(signatures: (WeierstrassPoint<S> | BLSInput)[]): WeierstrassPoint<S>;
|
||||
hash(message: Uint8Array, DST?: string | Uint8Array, hashOpts?: H2CHashOpts): WeierstrassPoint<S>;
|
||||
Signature: SignatureCoder<S>;
|
||||
}
|
||||
|
||||
// Not used with BLS12-381 (no sequential `11` in X). Useful for other curves.
|
||||
function NAfDecomposition(a: bigint) {
|
||||
const res = [];
|
||||
// a>1 because of marker bit
|
||||
for (; a > _1n; a >>= _1n) {
|
||||
if ((a & _1n) === _0n) res.unshift(0);
|
||||
else if ((a & _3n) === _3n) {
|
||||
res.unshift(-1);
|
||||
a += _1n;
|
||||
} else res.unshift(1);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function aNonEmpty(arr: any[]) {
|
||||
if (!Array.isArray(arr) || arr.length === 0) throw new Error('expected non-empty array');
|
||||
}
|
||||
|
||||
// This should be enough for bn254, no need to export full stuff?
|
||||
function createBlsPairing(
|
||||
fields: BlsFields,
|
||||
G1: WeierstrassPointCons<Fp>,
|
||||
G2: WeierstrassPointCons<Fp2>,
|
||||
params: BlsPairingParams
|
||||
): BlsPairing {
|
||||
const { Fp2, Fp12 } = fields;
|
||||
const { twistType, ateLoopSize, xNegative, postPrecompute } = params;
|
||||
type G1 = typeof G1.BASE;
|
||||
type G2 = typeof G2.BASE;
|
||||
// Applies sparse multiplication as line function
|
||||
let lineFunction: (c0: Fp2, c1: Fp2, c2: Fp2, f: Fp12, Px: Fp, Py: Fp) => Fp12;
|
||||
if (twistType === 'multiplicative') {
|
||||
lineFunction = (c0: Fp2, c1: Fp2, c2: Fp2, f: Fp12, Px: Fp, Py: Fp) =>
|
||||
Fp12.mul014(f, c0, Fp2.mul(c1, Px), Fp2.mul(c2, Py));
|
||||
} else if (twistType === 'divisive') {
|
||||
// NOTE: it should be [c0, c1, c2], but we use different order here to reduce complexity of
|
||||
// precompute calculations.
|
||||
lineFunction = (c0: Fp2, c1: Fp2, c2: Fp2, f: Fp12, Px: Fp, Py: Fp) =>
|
||||
Fp12.mul034(f, Fp2.mul(c2, Py), Fp2.mul(c1, Px), c0);
|
||||
} else throw new Error('bls: unknown twist type');
|
||||
|
||||
const Fp2div2 = Fp2.div(Fp2.ONE, Fp2.mul(Fp2.ONE, _2n));
|
||||
function pointDouble(ell: PrecomputeSingle, Rx: Fp2, Ry: Fp2, Rz: Fp2) {
|
||||
const t0 = Fp2.sqr(Ry); // Ry²
|
||||
const t1 = Fp2.sqr(Rz); // Rz²
|
||||
const t2 = Fp2.mulByB(Fp2.mul(t1, _3n)); // 3 * T1 * B
|
||||
const t3 = Fp2.mul(t2, _3n); // 3 * T2
|
||||
const t4 = Fp2.sub(Fp2.sub(Fp2.sqr(Fp2.add(Ry, Rz)), t1), t0); // (Ry + Rz)² - T1 - T0
|
||||
const c0 = Fp2.sub(t2, t0); // T2 - T0 (i)
|
||||
const c1 = Fp2.mul(Fp2.sqr(Rx), _3n); // 3 * Rx²
|
||||
const c2 = Fp2.neg(t4); // -T4 (-h)
|
||||
|
||||
ell.push([c0, c1, c2]);
|
||||
|
||||
Rx = Fp2.mul(Fp2.mul(Fp2.mul(Fp2.sub(t0, t3), Rx), Ry), Fp2div2); // ((T0 - T3) * Rx * Ry) / 2
|
||||
Ry = Fp2.sub(Fp2.sqr(Fp2.mul(Fp2.add(t0, t3), Fp2div2)), Fp2.mul(Fp2.sqr(t2), _3n)); // ((T0 + T3) / 2)² - 3 * T2²
|
||||
Rz = Fp2.mul(t0, t4); // T0 * T4
|
||||
return { Rx, Ry, Rz };
|
||||
}
|
||||
function pointAdd(ell: PrecomputeSingle, Rx: Fp2, Ry: Fp2, Rz: Fp2, Qx: Fp2, Qy: Fp2) {
|
||||
// Addition
|
||||
const t0 = Fp2.sub(Ry, Fp2.mul(Qy, Rz)); // Ry - Qy * Rz
|
||||
const t1 = Fp2.sub(Rx, Fp2.mul(Qx, Rz)); // Rx - Qx * Rz
|
||||
const c0 = Fp2.sub(Fp2.mul(t0, Qx), Fp2.mul(t1, Qy)); // T0 * Qx - T1 * Qy == Ry * Qx - Rx * Qy
|
||||
const c1 = Fp2.neg(t0); // -T0 == Qy * Rz - Ry
|
||||
const c2 = t1; // == Rx - Qx * Rz
|
||||
|
||||
ell.push([c0, c1, c2]);
|
||||
|
||||
const t2 = Fp2.sqr(t1); // T1²
|
||||
const t3 = Fp2.mul(t2, t1); // T2 * T1
|
||||
const t4 = Fp2.mul(t2, Rx); // T2 * Rx
|
||||
const t5 = Fp2.add(Fp2.sub(t3, Fp2.mul(t4, _2n)), Fp2.mul(Fp2.sqr(t0), Rz)); // T3 - 2 * T4 + T0² * Rz
|
||||
Rx = Fp2.mul(t1, t5); // T1 * T5
|
||||
Ry = Fp2.sub(Fp2.mul(Fp2.sub(t4, t5), t0), Fp2.mul(t3, Ry)); // (T4 - T5) * T0 - T3 * Ry
|
||||
Rz = Fp2.mul(Rz, t3); // Rz * T3
|
||||
return { Rx, Ry, Rz };
|
||||
}
|
||||
|
||||
// Pre-compute coefficients for sparse multiplication
|
||||
// Point addition and point double calculations is reused for coefficients
|
||||
// pointAdd happens only if bit set, so wNAF is reasonable. Unfortunately we cannot combine
|
||||
// add + double in windowed precomputes here, otherwise it would be single op (since X is static)
|
||||
const ATE_NAF = NAfDecomposition(ateLoopSize);
|
||||
|
||||
const calcPairingPrecomputes = memoized((point: G2) => {
|
||||
const p = point;
|
||||
const { x, y } = p.toAffine();
|
||||
// prettier-ignore
|
||||
const Qx = x, Qy = y, negQy = Fp2.neg(y);
|
||||
// prettier-ignore
|
||||
let Rx = Qx, Ry = Qy, Rz = Fp2.ONE;
|
||||
const ell: Precompute = [];
|
||||
for (const bit of ATE_NAF) {
|
||||
const cur: PrecomputeSingle = [];
|
||||
({ Rx, Ry, Rz } = pointDouble(cur, Rx, Ry, Rz));
|
||||
if (bit) ({ Rx, Ry, Rz } = pointAdd(cur, Rx, Ry, Rz, Qx, bit === -1 ? negQy : Qy));
|
||||
ell.push(cur);
|
||||
}
|
||||
if (postPrecompute) {
|
||||
const last = ell[ell.length - 1];
|
||||
postPrecompute(Rx, Ry, Rz, Qx, Qy, pointAdd.bind(null, last));
|
||||
}
|
||||
return ell;
|
||||
});
|
||||
|
||||
// Main pairing logic is here. Computes product of miller loops + final exponentiate
|
||||
// Applies calculated precomputes
|
||||
type MillerInput = [Precompute, Fp, Fp][];
|
||||
function millerLoopBatch(pairs: MillerInput, withFinalExponent: boolean = false) {
|
||||
let f12 = Fp12.ONE;
|
||||
if (pairs.length) {
|
||||
const ellLen = pairs[0][0].length;
|
||||
for (let i = 0; i < ellLen; i++) {
|
||||
f12 = Fp12.sqr(f12); // This allows us to do sqr only one time for all pairings
|
||||
// NOTE: we apply multiple pairings in parallel here
|
||||
for (const [ell, Px, Py] of pairs) {
|
||||
for (const [c0, c1, c2] of ell[i]) f12 = lineFunction(c0, c1, c2, f12, Px, Py);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xNegative) f12 = Fp12.conjugate(f12);
|
||||
return withFinalExponent ? Fp12.finalExponentiate(f12) : f12;
|
||||
}
|
||||
type PairingInput = { g1: G1; g2: G2 };
|
||||
// Calculates product of multiple pairings
|
||||
// This up to x2 faster than just `map(({g1, g2})=>pairing({g1,g2}))`
|
||||
function pairingBatch(pairs: PairingInput[], withFinalExponent: boolean = true) {
|
||||
const res: MillerInput = [];
|
||||
// Cache precomputed toAffine for all points
|
||||
normalizeZ(
|
||||
G1,
|
||||
pairs.map(({ g1 }) => g1)
|
||||
);
|
||||
normalizeZ(
|
||||
G2,
|
||||
pairs.map(({ g2 }) => g2)
|
||||
);
|
||||
for (const { g1, g2 } of pairs) {
|
||||
if (g1.is0() || g2.is0()) throw new Error('pairing is not available for ZERO point');
|
||||
// This uses toAffine inside
|
||||
g1.assertValidity();
|
||||
g2.assertValidity();
|
||||
const Qa = g1.toAffine();
|
||||
res.push([calcPairingPrecomputes(g2), Qa.x, Qa.y]);
|
||||
}
|
||||
return millerLoopBatch(res, withFinalExponent);
|
||||
}
|
||||
// Calculates bilinear pairing
|
||||
function pairing(Q: G1, P: G2, withFinalExponent: boolean = true): Fp12 {
|
||||
return pairingBatch([{ g1: Q, g2: P }], withFinalExponent);
|
||||
}
|
||||
return {
|
||||
Fp12, // NOTE: we re-export Fp12 here because pairing results are Fp12!
|
||||
millerLoopBatch,
|
||||
pairing,
|
||||
pairingBatch,
|
||||
calcPairingPrecomputes,
|
||||
};
|
||||
}
|
||||
|
||||
function createBlsSig<P, S>(
|
||||
blsPairing: BlsPairing,
|
||||
PubCurve: CurvePointsRes<P> & H2CHasher<P>,
|
||||
SigCurve: CurvePointsRes<S> & H2CHasher<S>,
|
||||
SignatureCoder: SignatureCoder<S>,
|
||||
isSigG1: boolean
|
||||
): BLSSigs<P, S> {
|
||||
const { Fp12, pairingBatch } = blsPairing;
|
||||
type PubPoint = WeierstrassPoint<P>;
|
||||
type SigPoint = WeierstrassPoint<S>;
|
||||
function normPub(point: PubPoint | BLSInput): PubPoint {
|
||||
return point instanceof PubCurve.Point ? (point as PubPoint) : PubCurve.Point.fromHex(point);
|
||||
}
|
||||
function normSig(point: SigPoint | BLSInput): SigPoint {
|
||||
return point instanceof SigCurve.Point ? (point as SigPoint) : SigCurve.Point.fromHex(point);
|
||||
}
|
||||
function amsg(m: unknown): SigPoint {
|
||||
if (!(m instanceof SigCurve.Point))
|
||||
throw new Error(`expected valid message hashed to ${!isSigG1 ? 'G2' : 'G1'} curve`);
|
||||
return m as SigPoint;
|
||||
}
|
||||
|
||||
type G1 = CurvePointsRes<Fp>['Point']['BASE'];
|
||||
type G2 = CurvePointsRes<Fp2>['Point']['BASE'];
|
||||
type PairingInput = { g1: G1; g2: G2 };
|
||||
// What matters here is what point pairing API accepts as G1 or G2, not actual size or names
|
||||
const pair: (a: PubPoint, b: SigPoint) => PairingInput = !isSigG1
|
||||
? (a: PubPoint, b: SigPoint) => ({ g1: a, g2: b }) as PairingInput
|
||||
: (a: PubPoint, b: SigPoint) => ({ g1: b, g2: a }) as PairingInput;
|
||||
return {
|
||||
// P = pk x G
|
||||
getPublicKey(secretKey: PrivKey): PubPoint {
|
||||
// TODO: replace with
|
||||
// const sec = PubCurve.Point.Fn.fromBytes(secretKey);
|
||||
const sec = _normFnElement(PubCurve.Point.Fn, secretKey);
|
||||
return PubCurve.Point.BASE.multiply(sec);
|
||||
},
|
||||
// S = pk x H(m)
|
||||
sign(message: SigPoint, secretKey: PrivKey, unusedArg?: any): SigPoint {
|
||||
if (unusedArg != null) throw new Error('sign() expects 2 arguments');
|
||||
// TODO: replace with
|
||||
// PubCurve.Point.Fn.fromBytes(secretKey)
|
||||
const sec = _normFnElement(PubCurve.Point.Fn, secretKey);
|
||||
amsg(message).assertValidity();
|
||||
return message.multiply(sec);
|
||||
},
|
||||
// Checks if pairing of public key & hash is equal to pairing of generator & signature.
|
||||
// e(P, H(m)) == e(G, S)
|
||||
// e(S, G) == e(H(m), P)
|
||||
verify(
|
||||
signature: SigPoint | BLSInput,
|
||||
message: SigPoint,
|
||||
publicKey: PubPoint | BLSInput,
|
||||
unusedArg?: any
|
||||
): boolean {
|
||||
if (unusedArg != null) throw new Error('verify() expects 3 arguments');
|
||||
signature = normSig(signature);
|
||||
publicKey = normPub(publicKey);
|
||||
const P = publicKey.negate();
|
||||
const G = PubCurve.Point.BASE;
|
||||
const Hm = amsg(message);
|
||||
const S = signature;
|
||||
// This code was changed in 1.9.x:
|
||||
// Before it was G.negate() in G2, now it's always pubKey.negate
|
||||
// e(P, -Q)===e(-P, Q)==e(P, Q)^-1. Negate can be done anywhere (as long it is done once per pair).
|
||||
// We just moving sign, but since pairing is multiplicative, we doing X * X^-1 = 1
|
||||
const exp = pairingBatch([pair(P, Hm), pair(G, S)]);
|
||||
return Fp12.eql(exp, Fp12.ONE);
|
||||
},
|
||||
// https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
|
||||
// e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
|
||||
// TODO: maybe `{message: G2Hex, publicKey: G1Hex}[]` instead?
|
||||
verifyBatch(
|
||||
signature: SigPoint | BLSInput,
|
||||
messages: SigPoint[],
|
||||
publicKeys: (PubPoint | BLSInput)[]
|
||||
): boolean {
|
||||
aNonEmpty(messages);
|
||||
if (publicKeys.length !== messages.length)
|
||||
throw new Error('amount of public keys and messages should be equal');
|
||||
const sig = normSig(signature);
|
||||
const nMessages = messages;
|
||||
const nPublicKeys = publicKeys.map(normPub);
|
||||
// NOTE: this works only for exact same object
|
||||
const messagePubKeyMap = new Map<SigPoint, PubPoint[]>();
|
||||
for (let i = 0; i < nPublicKeys.length; i++) {
|
||||
const pub = nPublicKeys[i];
|
||||
const msg = nMessages[i];
|
||||
let keys = messagePubKeyMap.get(msg);
|
||||
if (keys === undefined) {
|
||||
keys = [];
|
||||
messagePubKeyMap.set(msg, keys);
|
||||
}
|
||||
keys.push(pub);
|
||||
}
|
||||
const paired = [];
|
||||
const G = PubCurve.Point.BASE;
|
||||
try {
|
||||
for (const [msg, keys] of messagePubKeyMap) {
|
||||
const groupPublicKey = keys.reduce((acc, msg) => acc.add(msg));
|
||||
paired.push(pair(groupPublicKey, msg));
|
||||
}
|
||||
paired.push(pair(G.negate(), sig));
|
||||
return Fp12.eql(pairingBatch(paired), Fp12.ONE);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
// Adds a bunch of public key points together.
|
||||
// pk1 + pk2 + pk3 = pkA
|
||||
aggregatePublicKeys(publicKeys: (PubPoint | BLSInput)[]): PubPoint {
|
||||
aNonEmpty(publicKeys);
|
||||
publicKeys = publicKeys.map((pub) => normPub(pub));
|
||||
const agg = (publicKeys as PubPoint[]).reduce((sum, p) => sum.add(p), PubCurve.Point.ZERO);
|
||||
agg.assertValidity();
|
||||
return agg;
|
||||
},
|
||||
|
||||
// Adds a bunch of signature points together.
|
||||
// pk1 + pk2 + pk3 = pkA
|
||||
aggregateSignatures(signatures: (SigPoint | BLSInput)[]): SigPoint {
|
||||
aNonEmpty(signatures);
|
||||
signatures = signatures.map((sig) => normSig(sig));
|
||||
const agg = (signatures as SigPoint[]).reduce((sum, s) => sum.add(s), SigCurve.Point.ZERO);
|
||||
agg.assertValidity();
|
||||
return agg;
|
||||
},
|
||||
|
||||
hash(messageBytes: Uint8Array, DST?: string | Uint8Array): SigPoint {
|
||||
abytes(messageBytes);
|
||||
const opts = DST ? { DST } : undefined;
|
||||
return SigCurve.hashToCurve(messageBytes, opts) as SigPoint;
|
||||
},
|
||||
Signature: SignatureCoder,
|
||||
};
|
||||
}
|
||||
|
||||
// G1_Point: ProjConstructor<bigint>, G2_Point: ProjConstructor<Fp2>,
|
||||
export function bls(CURVE: CurveType): CurveFn {
|
||||
// Fields are specific for curve, so for now we'll need to pass them with opts
|
||||
const { Fp, Fr, Fp2, Fp6, Fp12 } = CURVE.fields;
|
||||
// Point on G1 curve: (x, y)
|
||||
const G1_ = weierstrassPoints(CURVE.G1);
|
||||
const G1 = Object.assign(
|
||||
G1_,
|
||||
createHasher(G1_.Point, CURVE.G1.mapToCurve, {
|
||||
...CURVE.htfDefaults,
|
||||
...CURVE.G1.htfDefaults,
|
||||
})
|
||||
);
|
||||
// Point on G2 curve (complex numbers): (x₁, x₂+i), (y₁, y₂+i)
|
||||
const G2_ = weierstrassPoints(CURVE.G2);
|
||||
const G2 = Object.assign(
|
||||
G2_,
|
||||
createHasher(G2_.Point as H2CPointConstructor<Fp2>, CURVE.G2.mapToCurve, {
|
||||
...CURVE.htfDefaults,
|
||||
...CURVE.G2.htfDefaults,
|
||||
})
|
||||
);
|
||||
type G1 = typeof G1.Point.BASE;
|
||||
type G2 = typeof G2.Point.BASE;
|
||||
|
||||
const pairingRes = createBlsPairing(CURVE.fields, G1.Point, G2.Point, {
|
||||
...CURVE.params,
|
||||
postPrecompute: CURVE.postPrecompute,
|
||||
});
|
||||
|
||||
const { millerLoopBatch, pairing, pairingBatch, calcPairingPrecomputes } = pairingRes;
|
||||
const longSignatures = createBlsSig(pairingRes, G1, G2, CURVE.G2.Signature, false);
|
||||
const shortSignatures = createBlsSig(pairingRes, G2, G1, CURVE.G1.ShortSignature, true);
|
||||
|
||||
const rand = CURVE.randomBytes || randomBytes;
|
||||
const randomSecretKey = (): Uint8Array => {
|
||||
const length = getMinHashLength(Fr.ORDER);
|
||||
return mapHashToField(rand(length), Fr.ORDER);
|
||||
};
|
||||
const utils = {
|
||||
randomSecretKey,
|
||||
randomPrivateKey: randomSecretKey,
|
||||
calcPairingPrecomputes,
|
||||
};
|
||||
|
||||
// LEGACY code
|
||||
type G1Hex = Hex | G1;
|
||||
type G2Hex = Hex | G2;
|
||||
|
||||
const { ShortSignature } = CURVE.G1;
|
||||
const { Signature } = CURVE.G2;
|
||||
|
||||
function normP1Hash(point: G1Hex, htfOpts?: htfBasicOpts): G1 {
|
||||
return point instanceof G1.Point
|
||||
? point
|
||||
: shortSignatures.hash(ensureBytes('point', point), htfOpts?.DST);
|
||||
}
|
||||
function normP2Hash(point: G2Hex, htfOpts?: htfBasicOpts): G2 {
|
||||
return point instanceof G2.Point
|
||||
? point
|
||||
: longSignatures.hash(ensureBytes('point', point), htfOpts?.DST);
|
||||
}
|
||||
|
||||
function getPublicKey(privateKey: PrivKey): Uint8Array {
|
||||
return longSignatures.getPublicKey(privateKey).toBytes(true);
|
||||
}
|
||||
function getPublicKeyForShortSignatures(privateKey: PrivKey): Uint8Array {
|
||||
return shortSignatures.getPublicKey(privateKey).toBytes(true);
|
||||
}
|
||||
function sign(message: Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array;
|
||||
function sign(message: G2, privateKey: PrivKey, htfOpts?: htfBasicOpts): G2;
|
||||
function sign(message: G2Hex, privateKey: PrivKey, htfOpts?: htfBasicOpts): Uint8Array | G2 {
|
||||
const Hm = normP2Hash(message, htfOpts);
|
||||
const S = longSignatures.sign(Hm, privateKey);
|
||||
return message instanceof G2.Point ? S : Signature.toBytes(S);
|
||||
}
|
||||
function signShortSignature(
|
||||
message: Hex,
|
||||
privateKey: PrivKey,
|
||||
htfOpts?: htfBasicOpts
|
||||
): Uint8Array;
|
||||
function signShortSignature(message: G1, privateKey: PrivKey, htfOpts?: htfBasicOpts): G1;
|
||||
function signShortSignature(
|
||||
message: G1Hex,
|
||||
privateKey: PrivKey,
|
||||
htfOpts?: htfBasicOpts
|
||||
): Uint8Array | G1 {
|
||||
const Hm = normP1Hash(message, htfOpts);
|
||||
const S = shortSignatures.sign(Hm, privateKey);
|
||||
return message instanceof G1.Point ? S : ShortSignature.toBytes(S);
|
||||
}
|
||||
function verify(
|
||||
signature: G2Hex,
|
||||
message: G2Hex,
|
||||
publicKey: G1Hex,
|
||||
htfOpts?: htfBasicOpts
|
||||
): boolean {
|
||||
const Hm = normP2Hash(message, htfOpts);
|
||||
return longSignatures.verify(signature, Hm, publicKey);
|
||||
}
|
||||
function verifyShortSignature(
|
||||
signature: G1Hex,
|
||||
message: G1Hex,
|
||||
publicKey: G2Hex,
|
||||
htfOpts?: htfBasicOpts
|
||||
): boolean {
|
||||
const Hm = normP1Hash(message, htfOpts);
|
||||
return shortSignatures.verify(signature, Hm, publicKey);
|
||||
}
|
||||
function aggregatePublicKeys(publicKeys: Hex[]): Uint8Array;
|
||||
function aggregatePublicKeys(publicKeys: G1[]): G1;
|
||||
function aggregatePublicKeys(publicKeys: G1Hex[]): Uint8Array | G1 {
|
||||
const agg = longSignatures.aggregatePublicKeys(publicKeys);
|
||||
return publicKeys[0] instanceof G1.Point ? agg : agg.toBytes(true);
|
||||
}
|
||||
function aggregateSignatures(signatures: Hex[]): Uint8Array;
|
||||
function aggregateSignatures(signatures: G2[]): G2;
|
||||
function aggregateSignatures(signatures: G2Hex[]): Uint8Array | G2 {
|
||||
const agg = longSignatures.aggregateSignatures(signatures);
|
||||
return signatures[0] instanceof G2.Point ? agg : Signature.toBytes(agg);
|
||||
}
|
||||
function aggregateShortSignatures(signatures: Hex[]): Uint8Array;
|
||||
function aggregateShortSignatures(signatures: G1[]): G1;
|
||||
function aggregateShortSignatures(signatures: G1Hex[]): Uint8Array | G1 {
|
||||
const agg = shortSignatures.aggregateSignatures(signatures);
|
||||
return signatures[0] instanceof G1.Point ? agg : ShortSignature.toBytes(agg);
|
||||
}
|
||||
function verifyBatch(
|
||||
signature: G2Hex,
|
||||
messages: G2Hex[],
|
||||
publicKeys: G1Hex[],
|
||||
htfOpts?: htfBasicOpts
|
||||
): boolean {
|
||||
const Hm = messages.map((m) => normP2Hash(m, htfOpts));
|
||||
return longSignatures.verifyBatch(signature, Hm, publicKeys);
|
||||
}
|
||||
|
||||
G1.Point.BASE.precompute(4);
|
||||
|
||||
return {
|
||||
longSignatures,
|
||||
shortSignatures,
|
||||
millerLoopBatch,
|
||||
pairing,
|
||||
pairingBatch,
|
||||
verifyBatch,
|
||||
fields: {
|
||||
Fr,
|
||||
Fp,
|
||||
Fp2,
|
||||
Fp6,
|
||||
Fp12,
|
||||
},
|
||||
params: {
|
||||
ateLoopSize: CURVE.params.ateLoopSize,
|
||||
twistType: CURVE.params.twistType,
|
||||
// deprecated
|
||||
r: CURVE.params.r,
|
||||
G1b: CURVE.G1.b,
|
||||
G2b: CURVE.G2.b,
|
||||
},
|
||||
utils,
|
||||
|
||||
// deprecated
|
||||
getPublicKey,
|
||||
getPublicKeyForShortSignatures,
|
||||
sign,
|
||||
signShortSignature,
|
||||
verify,
|
||||
verifyShortSignature,
|
||||
aggregatePublicKeys,
|
||||
aggregateSignatures,
|
||||
aggregateShortSignatures,
|
||||
G1,
|
||||
G2,
|
||||
Signature,
|
||||
ShortSignature,
|
||||
};
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,167 @@
|
||||
declare namespace ESTree {
|
||||
interface FlowTypeAnnotation extends Node {}
|
||||
|
||||
interface FlowBaseTypeAnnotation extends FlowTypeAnnotation {}
|
||||
|
||||
interface FlowLiteralTypeAnnotation extends FlowTypeAnnotation, Literal {}
|
||||
|
||||
interface FlowDeclaration extends Declaration {}
|
||||
|
||||
interface AnyTypeAnnotation extends FlowBaseTypeAnnotation {}
|
||||
|
||||
interface ArrayTypeAnnotation extends FlowTypeAnnotation {
|
||||
elementType: FlowTypeAnnotation;
|
||||
}
|
||||
|
||||
interface BooleanLiteralTypeAnnotation extends FlowLiteralTypeAnnotation {}
|
||||
|
||||
interface BooleanTypeAnnotation extends FlowBaseTypeAnnotation {}
|
||||
|
||||
interface ClassImplements extends Node {
|
||||
id: Identifier;
|
||||
typeParameters?: TypeParameterInstantiation | null;
|
||||
}
|
||||
|
||||
interface ClassProperty {
|
||||
key: Expression;
|
||||
value?: Expression | null;
|
||||
typeAnnotation?: TypeAnnotation | null;
|
||||
computed: boolean;
|
||||
static: boolean;
|
||||
}
|
||||
|
||||
interface DeclareClass extends FlowDeclaration {
|
||||
id: Identifier;
|
||||
typeParameters?: TypeParameterDeclaration | null;
|
||||
body: ObjectTypeAnnotation;
|
||||
extends: InterfaceExtends[];
|
||||
}
|
||||
|
||||
interface DeclareFunction extends FlowDeclaration {
|
||||
id: Identifier;
|
||||
}
|
||||
|
||||
interface DeclareModule extends FlowDeclaration {
|
||||
id: Literal | Identifier;
|
||||
body: BlockStatement;
|
||||
}
|
||||
|
||||
interface DeclareVariable extends FlowDeclaration {
|
||||
id: Identifier;
|
||||
}
|
||||
|
||||
interface FunctionTypeAnnotation extends FlowTypeAnnotation {
|
||||
params: FunctionTypeParam[];
|
||||
returnType: FlowTypeAnnotation;
|
||||
rest?: FunctionTypeParam | null;
|
||||
typeParameters?: TypeParameterDeclaration | null;
|
||||
}
|
||||
|
||||
interface FunctionTypeParam {
|
||||
name: Identifier;
|
||||
typeAnnotation: FlowTypeAnnotation;
|
||||
optional: boolean;
|
||||
}
|
||||
|
||||
interface GenericTypeAnnotation extends FlowTypeAnnotation {
|
||||
id: Identifier | QualifiedTypeIdentifier;
|
||||
typeParameters?: TypeParameterInstantiation | null;
|
||||
}
|
||||
|
||||
interface InterfaceExtends extends Node {
|
||||
id: Identifier | QualifiedTypeIdentifier;
|
||||
typeParameters?: TypeParameterInstantiation | null;
|
||||
}
|
||||
|
||||
interface InterfaceDeclaration extends FlowDeclaration {
|
||||
id: Identifier;
|
||||
typeParameters?: TypeParameterDeclaration | null;
|
||||
extends: InterfaceExtends[];
|
||||
body: ObjectTypeAnnotation;
|
||||
}
|
||||
|
||||
interface IntersectionTypeAnnotation extends FlowTypeAnnotation {
|
||||
types: FlowTypeAnnotation[];
|
||||
}
|
||||
|
||||
interface MixedTypeAnnotation extends FlowBaseTypeAnnotation {}
|
||||
|
||||
interface NullableTypeAnnotation extends FlowTypeAnnotation {
|
||||
typeAnnotation: TypeAnnotation;
|
||||
}
|
||||
|
||||
interface NumberLiteralTypeAnnotation extends FlowLiteralTypeAnnotation {}
|
||||
|
||||
interface NumberTypeAnnotation extends FlowBaseTypeAnnotation {}
|
||||
|
||||
interface StringLiteralTypeAnnotation extends FlowLiteralTypeAnnotation {}
|
||||
|
||||
interface StringTypeAnnotation extends FlowBaseTypeAnnotation {}
|
||||
|
||||
interface TupleTypeAnnotation extends FlowTypeAnnotation {
|
||||
types: FlowTypeAnnotation[];
|
||||
}
|
||||
|
||||
interface TypeofTypeAnnotation extends FlowTypeAnnotation {
|
||||
argument: FlowTypeAnnotation;
|
||||
}
|
||||
|
||||
interface TypeAlias extends FlowDeclaration {
|
||||
id: Identifier;
|
||||
typeParameters?: TypeParameterDeclaration | null;
|
||||
right: FlowTypeAnnotation;
|
||||
}
|
||||
|
||||
interface TypeAnnotation extends Node {
|
||||
typeAnnotation: FlowTypeAnnotation;
|
||||
}
|
||||
|
||||
interface TypeCastExpression extends Expression {
|
||||
expression: Expression;
|
||||
typeAnnotation: TypeAnnotation;
|
||||
}
|
||||
|
||||
interface TypeParameterDeclaration extends Node {
|
||||
params: Identifier[];
|
||||
}
|
||||
|
||||
interface TypeParameterInstantiation extends Node {
|
||||
params: FlowTypeAnnotation[];
|
||||
}
|
||||
|
||||
interface ObjectTypeAnnotation extends FlowTypeAnnotation {
|
||||
properties: ObjectTypeProperty[];
|
||||
indexers: ObjectTypeIndexer[];
|
||||
callProperties: ObjectTypeCallProperty[];
|
||||
}
|
||||
|
||||
interface ObjectTypeCallProperty extends Node {
|
||||
value: FunctionTypeAnnotation;
|
||||
static: boolean;
|
||||
}
|
||||
|
||||
interface ObjectTypeIndexer extends Node {
|
||||
id: Identifier;
|
||||
key: FlowTypeAnnotation;
|
||||
value: FlowTypeAnnotation;
|
||||
static: boolean;
|
||||
}
|
||||
|
||||
interface ObjectTypeProperty extends Node {
|
||||
key: Expression;
|
||||
value: FlowTypeAnnotation;
|
||||
optional: boolean;
|
||||
static: boolean;
|
||||
}
|
||||
|
||||
interface QualifiedTypeIdentifier extends Node {
|
||||
qualification: Identifier | QualifiedTypeIdentifier;
|
||||
id: Identifier;
|
||||
}
|
||||
|
||||
interface UnionTypeAnnotation extends FlowTypeAnnotation {
|
||||
types: FlowTypeAnnotation[];
|
||||
}
|
||||
|
||||
interface VoidTypeAnnotation extends FlowBaseTypeAnnotation {}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from './eslint-utils';
|
||||
export * from './helpers';
|
||||
export * from './misc';
|
||||
export * from './predicates';
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag use of eval() statement
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Types
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("eslint-scope").Scope} Scope */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const candidatesOfGlobalObject = Object.freeze([
|
||||
"global",
|
||||
"window",
|
||||
"globalThis",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Checks a given node is a MemberExpression node which has the specified name's
|
||||
* property.
|
||||
* @param {ASTNode} node A node to check.
|
||||
* @param {string} name A name to check.
|
||||
* @returns {boolean} `true` if the node is a MemberExpression node which has
|
||||
* the specified name's property
|
||||
*/
|
||||
function isMember(node, name) {
|
||||
return astUtils.isSpecificMemberAccess(node, null, name);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
allowIndirect: false,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description: "Disallow the use of `eval()`",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/no-eval",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allowIndirect: { type: "boolean" },
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
unexpected: "`eval` can be harmful.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const [{ allowIndirect }] = context.options;
|
||||
const sourceCode = context.sourceCode;
|
||||
let funcInfo = null;
|
||||
|
||||
/**
|
||||
* Pushes a `this` scope (non-arrow function, class static block, or class field initializer) information to the stack.
|
||||
* Top-level scopes are handled separately.
|
||||
*
|
||||
* This is used in order to check whether or not `this` binding is a
|
||||
* reference to the global object.
|
||||
* @param {ASTNode} node A node of the scope.
|
||||
* For functions, this is one of FunctionDeclaration, FunctionExpression.
|
||||
* For class static blocks, this is StaticBlock.
|
||||
* For class field initializers, this can be any node that is PropertyDefinition#value.
|
||||
* @returns {void}
|
||||
*/
|
||||
function enterThisScope(node) {
|
||||
const strict = sourceCode.getScope(node).isStrict;
|
||||
|
||||
funcInfo = {
|
||||
upper: funcInfo,
|
||||
node,
|
||||
strict,
|
||||
isTopLevelOfScript: false,
|
||||
defaultThis: false,
|
||||
initialized: strict,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops a variable scope from the stack.
|
||||
* @returns {void}
|
||||
*/
|
||||
function exitThisScope() {
|
||||
funcInfo = funcInfo.upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports a given node.
|
||||
*
|
||||
* `node` is `Identifier` or `MemberExpression`.
|
||||
* The parent of `node` might be `CallExpression`.
|
||||
*
|
||||
* The location of the report is always `eval` `Identifier` (or possibly
|
||||
* `Literal`). The type of the report is `CallExpression` if the parent is
|
||||
* `CallExpression`. Otherwise, it's the given node type.
|
||||
* @param {ASTNode} node A node to report.
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node) {
|
||||
const parent = node.parent;
|
||||
const locationNode =
|
||||
node.type === "MemberExpression" ? node.property : node;
|
||||
|
||||
const reportNode =
|
||||
parent.type === "CallExpression" && parent.callee === node
|
||||
? parent
|
||||
: node;
|
||||
|
||||
context.report({
|
||||
node: reportNode,
|
||||
loc: locationNode.loc,
|
||||
messageId: "unexpected",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports accesses of `eval` via the global object.
|
||||
* @param {Scope} globalScope The global scope.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportAccessingEvalViaGlobalObject(globalScope) {
|
||||
for (let i = 0; i < candidatesOfGlobalObject.length; ++i) {
|
||||
const name = candidatesOfGlobalObject[i];
|
||||
const variable = astUtils.getVariableByName(globalScope, name);
|
||||
|
||||
if (!variable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const references = variable.references;
|
||||
|
||||
for (let j = 0; j < references.length; ++j) {
|
||||
const identifier = references[j].identifier;
|
||||
let node = identifier.parent;
|
||||
|
||||
// To detect code like `window.window.eval`.
|
||||
while (isMember(node, name)) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
// Reports.
|
||||
if (isMember(node, "eval")) {
|
||||
report(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports all accesses of `eval` (excludes direct calls to eval).
|
||||
* @param {Scope} globalScope The global scope.
|
||||
* @returns {void}
|
||||
*/
|
||||
function reportAccessingEval(globalScope) {
|
||||
const variable = astUtils.getVariableByName(globalScope, "eval");
|
||||
|
||||
if (!variable) {
|
||||
return;
|
||||
}
|
||||
|
||||
const references = variable.references;
|
||||
|
||||
for (let i = 0; i < references.length; ++i) {
|
||||
const reference = references[i];
|
||||
const id = reference.identifier;
|
||||
|
||||
if (id.name === "eval" && !astUtils.isCallee(id)) {
|
||||
// Is accessing to eval (excludes direct calls to eval)
|
||||
report(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowIndirect) {
|
||||
// Checks only direct calls to eval. It's simple!
|
||||
return {
|
||||
"CallExpression:exit"(node) {
|
||||
const callee = node.callee;
|
||||
|
||||
/*
|
||||
* Optional call (`eval?.("code")`) is not direct eval.
|
||||
* The direct eval is only step 6.a.vi of https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation
|
||||
* But the optional call is https://tc39.es/ecma262/#sec-optional-chaining-chain-evaluation
|
||||
*/
|
||||
if (
|
||||
!node.optional &&
|
||||
astUtils.isSpecificId(callee, "eval")
|
||||
) {
|
||||
report(callee);
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
"CallExpression:exit"(node) {
|
||||
const callee = node.callee;
|
||||
|
||||
if (astUtils.isSpecificId(callee, "eval")) {
|
||||
report(callee);
|
||||
}
|
||||
},
|
||||
|
||||
Program(node) {
|
||||
const scope = sourceCode.getScope(node),
|
||||
features =
|
||||
context.languageOptions.parserOptions.ecmaFeatures ||
|
||||
{},
|
||||
strict =
|
||||
scope.isStrict ||
|
||||
node.sourceType === "module" ||
|
||||
(features.globalReturn &&
|
||||
scope.childScopes[0].isStrict),
|
||||
isTopLevelOfScript =
|
||||
node.sourceType !== "module" && !features.globalReturn;
|
||||
|
||||
funcInfo = {
|
||||
upper: null,
|
||||
node,
|
||||
strict,
|
||||
isTopLevelOfScript,
|
||||
defaultThis: true,
|
||||
initialized: true,
|
||||
};
|
||||
},
|
||||
|
||||
"Program:exit"(node) {
|
||||
const globalScope = sourceCode.getScope(node);
|
||||
|
||||
exitThisScope();
|
||||
reportAccessingEval(globalScope);
|
||||
reportAccessingEvalViaGlobalObject(globalScope);
|
||||
},
|
||||
|
||||
FunctionDeclaration: enterThisScope,
|
||||
"FunctionDeclaration:exit": exitThisScope,
|
||||
FunctionExpression: enterThisScope,
|
||||
"FunctionExpression:exit": exitThisScope,
|
||||
"PropertyDefinition > *.value": enterThisScope,
|
||||
"PropertyDefinition > *.value:exit": exitThisScope,
|
||||
StaticBlock: enterThisScope,
|
||||
"StaticBlock:exit": exitThisScope,
|
||||
|
||||
ThisExpression(node) {
|
||||
if (!isMember(node.parent, "eval")) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* `this.eval` is found.
|
||||
* Checks whether or not the value of `this` is the global object.
|
||||
*/
|
||||
if (!funcInfo.initialized) {
|
||||
funcInfo.initialized = true;
|
||||
funcInfo.defaultThis = astUtils.isDefaultThisBinding(
|
||||
funcInfo.node,
|
||||
sourceCode,
|
||||
);
|
||||
}
|
||||
|
||||
// `this` at the top level of scripts always refers to the global object
|
||||
if (
|
||||
funcInfo.isTopLevelOfScript ||
|
||||
(!funcInfo.strict && funcInfo.defaultThis)
|
||||
) {
|
||||
// `this.eval` is possible built-in `eval`.
|
||||
report(node.parent);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
export type OptionString = 'array' | 'array-simple' | 'generic';
|
||||
export type Options = [
|
||||
{
|
||||
default: OptionString;
|
||||
readonly?: OptionString;
|
||||
}
|
||||
];
|
||||
export type MessageIds = 'errorStringArray' | 'errorStringArrayReadonly' | 'errorStringArraySimple' | 'errorStringArraySimpleReadonly' | 'errorStringGeneric' | 'errorStringGenericSimple';
|
||||
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,263 @@
|
||||
/**
|
||||
* @fileoverview Rule to disallow useless backreferences in regular expressions
|
||||
* @author Milos Djermanovic
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const {
|
||||
CALL,
|
||||
CONSTRUCT,
|
||||
ReferenceTracker,
|
||||
getStringIfConstant,
|
||||
} = require("@eslint-community/eslint-utils");
|
||||
const { RegExpParser, visitRegExpAST } = require("@eslint-community/regexpp");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const parser = new RegExpParser();
|
||||
|
||||
/**
|
||||
* Finds the path from the given `regexpp` AST node to the root node.
|
||||
* @param {regexpp.Node} node Node.
|
||||
* @returns {regexpp.Node[]} Array that starts with the given node and ends with the root node.
|
||||
*/
|
||||
function getPathToRoot(node) {
|
||||
const path = [];
|
||||
let current = node;
|
||||
|
||||
do {
|
||||
path.push(current);
|
||||
current = current.parent;
|
||||
} while (current);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given `regexpp` AST node is a lookaround node.
|
||||
* @param {regexpp.Node} node Node.
|
||||
* @returns {boolean} `true` if it is a lookaround node.
|
||||
*/
|
||||
function isLookaround(node) {
|
||||
return (
|
||||
node.type === "Assertion" &&
|
||||
(node.kind === "lookahead" || node.kind === "lookbehind")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given `regexpp` AST node is a negative lookaround node.
|
||||
* @param {regexpp.Node} node Node.
|
||||
* @returns {boolean} `true` if it is a negative lookaround node.
|
||||
*/
|
||||
function isNegativeLookaround(node) {
|
||||
return isLookaround(node) && node.negate;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Disallow useless backreferences in regular expressions",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-useless-backreference",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
nested: "Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} from within that group.",
|
||||
forward:
|
||||
"Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which appears later in the pattern.",
|
||||
backward:
|
||||
"Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which appears before in the same lookbehind.",
|
||||
disjunctive:
|
||||
"Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which is in another alternative.",
|
||||
intoNegativeLookaround:
|
||||
"Backreference '{{ bref }}' will be ignored. It references group '{{ group }}'{{ otherGroups }} which is in a negative lookaround.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Checks and reports useless backreferences in the given regular expression.
|
||||
* @param {ASTNode} node Node that represents regular expression. A regex literal or RegExp constructor call.
|
||||
* @param {string} pattern Regular expression pattern.
|
||||
* @param {string} flags Regular expression flags.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkRegex(node, pattern, flags) {
|
||||
let regExpAST;
|
||||
|
||||
try {
|
||||
regExpAST = parser.parsePattern(pattern, 0, pattern.length, {
|
||||
unicode: flags.includes("u"),
|
||||
unicodeSets: flags.includes("v"),
|
||||
});
|
||||
} catch {
|
||||
// Ignore regular expressions with syntax errors
|
||||
return;
|
||||
}
|
||||
|
||||
visitRegExpAST(regExpAST, {
|
||||
onBackreferenceEnter(bref) {
|
||||
const groups = [bref.resolved].flat(),
|
||||
brefPath = getPathToRoot(bref);
|
||||
|
||||
const problems = groups.map(group => {
|
||||
const groupPath = getPathToRoot(group);
|
||||
|
||||
if (brefPath.includes(group)) {
|
||||
// group is bref's ancestor => bref is nested ('nested reference') => group hasn't matched yet when bref starts to match.
|
||||
return {
|
||||
messageId: "nested",
|
||||
group,
|
||||
};
|
||||
}
|
||||
|
||||
// Start from the root to find the lowest common ancestor.
|
||||
let i = brefPath.length - 1,
|
||||
j = groupPath.length - 1;
|
||||
|
||||
do {
|
||||
i--;
|
||||
j--;
|
||||
} while (brefPath[i] === groupPath[j]);
|
||||
|
||||
const indexOfLowestCommonAncestor = j + 1,
|
||||
groupCut = groupPath.slice(
|
||||
0,
|
||||
indexOfLowestCommonAncestor,
|
||||
),
|
||||
commonPath = groupPath.slice(
|
||||
indexOfLowestCommonAncestor,
|
||||
),
|
||||
lowestCommonLookaround =
|
||||
commonPath.find(isLookaround),
|
||||
isMatchingBackward =
|
||||
lowestCommonLookaround &&
|
||||
lowestCommonLookaround.kind === "lookbehind";
|
||||
|
||||
if (groupCut.at(-1).type === "Alternative") {
|
||||
// group's and bref's ancestor nodes below the lowest common ancestor are sibling alternatives => they're disjunctive.
|
||||
return {
|
||||
messageId: "disjunctive",
|
||||
group,
|
||||
};
|
||||
}
|
||||
if (!isMatchingBackward && bref.end <= group.start) {
|
||||
// bref is left, group is right ('forward reference') => group hasn't matched yet when bref starts to match.
|
||||
return {
|
||||
messageId: "forward",
|
||||
group,
|
||||
};
|
||||
}
|
||||
if (isMatchingBackward && group.end <= bref.start) {
|
||||
// the opposite of the previous when the regex is matching backward in a lookbehind context.
|
||||
return {
|
||||
messageId: "backward",
|
||||
group,
|
||||
};
|
||||
}
|
||||
if (groupCut.some(isNegativeLookaround)) {
|
||||
// group is in a negative lookaround which isn't bref's ancestor => group has already failed when bref starts to match.
|
||||
return {
|
||||
messageId: "intoNegativeLookaround",
|
||||
group,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
if (
|
||||
problems.length === 0 ||
|
||||
problems.some(problem => !problem)
|
||||
) {
|
||||
// If there are no problems or no problems with any group then do not report it.
|
||||
return;
|
||||
}
|
||||
|
||||
let problemsToReport;
|
||||
|
||||
// Gets problems that appear in the same disjunction.
|
||||
const problemsInSameDisjunction = problems.filter(
|
||||
problem => problem.messageId !== "disjunctive",
|
||||
);
|
||||
|
||||
if (problemsInSameDisjunction.length) {
|
||||
// Only report problems that appear in the same disjunction.
|
||||
problemsToReport = problemsInSameDisjunction;
|
||||
} else {
|
||||
// If all groups appear in different disjunctions, report it.
|
||||
problemsToReport = problems;
|
||||
}
|
||||
|
||||
const [{ messageId, group }, ...other] = problemsToReport;
|
||||
let otherGroups = "";
|
||||
|
||||
if (other.length === 1) {
|
||||
otherGroups = " and another group";
|
||||
} else if (other.length > 1) {
|
||||
otherGroups = ` and other ${other.length} groups`;
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
data: {
|
||||
bref: bref.raw,
|
||||
group: group.raw,
|
||||
otherGroups,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
"Literal[regex]"(node) {
|
||||
const { pattern, flags } = node.regex;
|
||||
|
||||
checkRegex(node, pattern, flags);
|
||||
},
|
||||
Program(node) {
|
||||
const scope = sourceCode.getScope(node),
|
||||
tracker = new ReferenceTracker(scope),
|
||||
traceMap = {
|
||||
RegExp: {
|
||||
[CALL]: true,
|
||||
[CONSTRUCT]: true,
|
||||
},
|
||||
};
|
||||
|
||||
for (const { node: refNode } of tracker.iterateGlobalReferences(
|
||||
traceMap,
|
||||
)) {
|
||||
const [patternNode, flagsNode] = refNode.arguments,
|
||||
pattern = getStringIfConstant(patternNode, scope),
|
||||
flags = getStringIfConstant(flagsNode, scope);
|
||||
|
||||
if (typeof pattern === "string") {
|
||||
checkRegex(refNode, pattern, flags || "");
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
'use strict'
|
||||
|
||||
let AtRule = require('./at-rule')
|
||||
let Comment = require('./comment')
|
||||
let Declaration = require('./declaration')
|
||||
let Input = require('./input')
|
||||
let PreviousMap = require('./previous-map')
|
||||
let Root = require('./root')
|
||||
let Rule = require('./rule')
|
||||
|
||||
function hydrateInputs(json, inputs) {
|
||||
if (!json.inputs) return inputs
|
||||
return json.inputs.map(input => {
|
||||
let inputHydrated = { ...input, __proto__: Input.prototype }
|
||||
if (inputHydrated.map) {
|
||||
inputHydrated.map = {
|
||||
...inputHydrated.map,
|
||||
__proto__: PreviousMap.prototype
|
||||
}
|
||||
}
|
||||
return inputHydrated
|
||||
})
|
||||
}
|
||||
|
||||
function constructNode(json, inputs, children) {
|
||||
let defaults = { ...json }
|
||||
delete defaults.inputs
|
||||
delete defaults.nodes
|
||||
if (defaults.source) {
|
||||
let { inputId, ...source } = defaults.source
|
||||
defaults.source = source
|
||||
if (inputId != null) {
|
||||
defaults.source.input = inputs[inputId]
|
||||
}
|
||||
}
|
||||
|
||||
let node
|
||||
if (defaults.type === 'root') {
|
||||
node = new Root(defaults)
|
||||
} else if (defaults.type === 'decl') {
|
||||
node = new Declaration(defaults)
|
||||
} else if (defaults.type === 'rule') {
|
||||
node = new Rule(defaults)
|
||||
} else if (defaults.type === 'comment') {
|
||||
node = new Comment(defaults)
|
||||
} else if (defaults.type === 'atrule') {
|
||||
node = new AtRule(defaults)
|
||||
} else {
|
||||
throw new Error('Unknown node type: ' + json.type)
|
||||
}
|
||||
|
||||
// Rehydrated children are attached after construction. Passing them
|
||||
// through the container constructor would re-run insertion spacing
|
||||
// normalization and overwrite each child's own `raws.before`.
|
||||
if (children) {
|
||||
node.nodes = children
|
||||
for (let child of children) child.parent = node
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
function fromJSON(json, inputs) {
|
||||
if (Array.isArray(json)) return json.map(n => fromJSON(n))
|
||||
|
||||
// An explicit stack instead of recursive calls to survive deeply
|
||||
// nested trees. Children are rehydrated before their parent node
|
||||
// is constructed.
|
||||
let result
|
||||
let stack = [
|
||||
{ childIndex: 0, children: [], inputs: hydrateInputs(json, inputs), json }
|
||||
]
|
||||
|
||||
while (stack.length > 0) {
|
||||
let frame = stack[stack.length - 1]
|
||||
let jsonNodes = frame.json.nodes
|
||||
|
||||
if (jsonNodes && frame.childIndex < jsonNodes.length) {
|
||||
let childJson = jsonNodes[frame.childIndex]
|
||||
frame.childIndex += 1
|
||||
stack.push({
|
||||
childIndex: 0,
|
||||
children: [],
|
||||
inputs: hydrateInputs(childJson, frame.inputs),
|
||||
json: childJson
|
||||
})
|
||||
continue
|
||||
}
|
||||
|
||||
stack.pop()
|
||||
let node = constructNode(
|
||||
frame.json,
|
||||
frame.inputs,
|
||||
jsonNodes ? frame.children : undefined
|
||||
)
|
||||
if (stack.length > 0) {
|
||||
stack[stack.length - 1].children.push(node)
|
||||
} else {
|
||||
result = node
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
module.exports = fromJSON
|
||||
fromJSON.default = fromJSON
|
||||
@@ -0,0 +1,530 @@
|
||||
'use strict';
|
||||
|
||||
const zlib = require('zlib');
|
||||
|
||||
const bufferUtil = require('./buffer-util');
|
||||
const Limiter = require('./limiter');
|
||||
const { kStatusCode } = require('./constants');
|
||||
|
||||
const FastBuffer = Buffer[Symbol.species];
|
||||
const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
|
||||
const kPerMessageDeflate = Symbol('permessage-deflate');
|
||||
const kTotalLength = Symbol('total-length');
|
||||
const kCallback = Symbol('callback');
|
||||
const kBuffers = Symbol('buffers');
|
||||
const kError = Symbol('error');
|
||||
|
||||
//
|
||||
// We limit zlib concurrency, which prevents severe memory fragmentation
|
||||
// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913
|
||||
// and https://github.com/websockets/ws/issues/1202
|
||||
//
|
||||
// Intentionally global; it's the global thread pool that's an issue.
|
||||
//
|
||||
let zlibLimiter;
|
||||
|
||||
/**
|
||||
* permessage-deflate implementation.
|
||||
*/
|
||||
class PerMessageDeflate {
|
||||
/**
|
||||
* Creates a PerMessageDeflate instance.
|
||||
*
|
||||
* @param {Object} [options] Configuration options
|
||||
* @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
|
||||
* for, or request, a custom client window size
|
||||
* @param {Boolean} [options.clientNoContextTakeover=false] Advertise/
|
||||
* acknowledge disabling of client context takeover
|
||||
* @param {Number} [options.concurrencyLimit=10] The number of concurrent
|
||||
* calls to zlib
|
||||
* @param {Boolean} [options.isServer=false] Create the instance in either
|
||||
* server or client mode
|
||||
* @param {Number} [options.maxPayload=0] The maximum allowed message length
|
||||
* @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
|
||||
* use of a custom server window size
|
||||
* @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
|
||||
* disabling of server context takeover
|
||||
* @param {Number} [options.threshold=1024] Size (in bytes) below which
|
||||
* messages should not be compressed if context takeover is disabled
|
||||
* @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on
|
||||
* deflate
|
||||
* @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
|
||||
* inflate
|
||||
*/
|
||||
constructor(options) {
|
||||
this._options = options || {};
|
||||
this._threshold =
|
||||
this._options.threshold !== undefined ? this._options.threshold : 1024;
|
||||
this._maxPayload = this._options.maxPayload | 0;
|
||||
this._isServer = !!this._options.isServer;
|
||||
this._deflate = null;
|
||||
this._inflate = null;
|
||||
|
||||
this.params = null;
|
||||
|
||||
if (!zlibLimiter) {
|
||||
const concurrency =
|
||||
this._options.concurrencyLimit !== undefined
|
||||
? this._options.concurrencyLimit
|
||||
: 10;
|
||||
zlibLimiter = new Limiter(concurrency);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {String}
|
||||
*/
|
||||
static get extensionName() {
|
||||
return 'permessage-deflate';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an extension negotiation offer.
|
||||
*
|
||||
* @return {Object} Extension parameters
|
||||
* @public
|
||||
*/
|
||||
offer() {
|
||||
const params = {};
|
||||
|
||||
if (this._options.serverNoContextTakeover) {
|
||||
params.server_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.clientNoContextTakeover) {
|
||||
params.client_no_context_takeover = true;
|
||||
}
|
||||
if (this._options.serverMaxWindowBits) {
|
||||
params.server_max_window_bits = this._options.serverMaxWindowBits;
|
||||
}
|
||||
if (this._options.clientMaxWindowBits) {
|
||||
params.client_max_window_bits = this._options.clientMaxWindowBits;
|
||||
} else if (this._options.clientMaxWindowBits == null) {
|
||||
params.client_max_window_bits = true;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept an extension negotiation offer/response.
|
||||
*
|
||||
* @param {Array} configurations The extension negotiation offers/reponse
|
||||
* @return {Object} Accepted configuration
|
||||
* @public
|
||||
*/
|
||||
accept(configurations) {
|
||||
configurations = this.normalizeParams(configurations);
|
||||
|
||||
this.params = this._isServer
|
||||
? this.acceptAsServer(configurations)
|
||||
: this.acceptAsClient(configurations);
|
||||
|
||||
return this.params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all resources used by the extension.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
cleanup() {
|
||||
if (this._inflate) {
|
||||
this._inflate.close();
|
||||
this._inflate = null;
|
||||
}
|
||||
|
||||
if (this._deflate) {
|
||||
const callback = this._deflate[kCallback];
|
||||
|
||||
this._deflate.close();
|
||||
this._deflate = null;
|
||||
|
||||
if (callback) {
|
||||
callback(
|
||||
new Error(
|
||||
'The deflate stream was closed while data was being processed'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept an extension negotiation offer.
|
||||
*
|
||||
* @param {Array} offers The extension negotiation offers
|
||||
* @return {Object} Accepted configuration
|
||||
* @private
|
||||
*/
|
||||
acceptAsServer(offers) {
|
||||
const opts = this._options;
|
||||
const accepted = offers.find((params) => {
|
||||
if (
|
||||
(opts.serverNoContextTakeover === false &&
|
||||
params.server_no_context_takeover) ||
|
||||
(params.server_max_window_bits &&
|
||||
(opts.serverMaxWindowBits === false ||
|
||||
(typeof opts.serverMaxWindowBits === 'number' &&
|
||||
opts.serverMaxWindowBits > params.server_max_window_bits))) ||
|
||||
(typeof opts.clientMaxWindowBits === 'number' &&
|
||||
(typeof params.client_max_window_bits === 'number'
|
||||
? opts.clientMaxWindowBits > params.client_max_window_bits
|
||||
: !params.client_max_window_bits))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!accepted) {
|
||||
throw new Error('None of the extension offers can be accepted');
|
||||
}
|
||||
|
||||
if (opts.serverNoContextTakeover) {
|
||||
accepted.server_no_context_takeover = true;
|
||||
}
|
||||
if (opts.clientNoContextTakeover) {
|
||||
accepted.client_no_context_takeover = true;
|
||||
}
|
||||
if (typeof opts.serverMaxWindowBits === 'number') {
|
||||
accepted.server_max_window_bits = opts.serverMaxWindowBits;
|
||||
}
|
||||
if (typeof opts.clientMaxWindowBits === 'number') {
|
||||
accepted.client_max_window_bits = opts.clientMaxWindowBits;
|
||||
} else if (
|
||||
accepted.client_max_window_bits === true ||
|
||||
opts.clientMaxWindowBits === false
|
||||
) {
|
||||
delete accepted.client_max_window_bits;
|
||||
}
|
||||
|
||||
return accepted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept the extension negotiation response.
|
||||
*
|
||||
* @param {Array} response The extension negotiation response
|
||||
* @return {Object} Accepted configuration
|
||||
* @private
|
||||
*/
|
||||
acceptAsClient(response) {
|
||||
const params = response[0];
|
||||
|
||||
if (
|
||||
this._options.clientNoContextTakeover === false &&
|
||||
params.client_no_context_takeover
|
||||
) {
|
||||
throw new Error('Unexpected parameter "client_no_context_takeover"');
|
||||
}
|
||||
|
||||
if (!params.client_max_window_bits) {
|
||||
if (typeof this._options.clientMaxWindowBits === 'number') {
|
||||
params.client_max_window_bits = this._options.clientMaxWindowBits;
|
||||
}
|
||||
} else if (
|
||||
this._options.clientMaxWindowBits === false ||
|
||||
(typeof this._options.clientMaxWindowBits === 'number' &&
|
||||
params.client_max_window_bits > this._options.clientMaxWindowBits)
|
||||
) {
|
||||
throw new Error(
|
||||
'Unexpected or invalid parameter "client_max_window_bits"'
|
||||
);
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize parameters.
|
||||
*
|
||||
* @param {Array} configurations The extension negotiation offers/reponse
|
||||
* @return {Array} The offers/response with normalized parameters
|
||||
* @private
|
||||
*/
|
||||
normalizeParams(configurations) {
|
||||
configurations.forEach((params) => {
|
||||
Object.keys(params).forEach((key) => {
|
||||
let value = params[key];
|
||||
|
||||
if (value.length > 1) {
|
||||
throw new Error(`Parameter "${key}" must have only a single value`);
|
||||
}
|
||||
|
||||
value = value[0];
|
||||
|
||||
if (key === 'client_max_window_bits') {
|
||||
if (value !== true) {
|
||||
const num = +value;
|
||||
if (!Number.isInteger(num) || num < 8 || num > 15) {
|
||||
throw new TypeError(
|
||||
`Invalid value for parameter "${key}": ${value}`
|
||||
);
|
||||
}
|
||||
value = num;
|
||||
} else if (!this._isServer) {
|
||||
throw new TypeError(
|
||||
`Invalid value for parameter "${key}": ${value}`
|
||||
);
|
||||
}
|
||||
} else if (key === 'server_max_window_bits') {
|
||||
const num = +value;
|
||||
if (!Number.isInteger(num) || num < 8 || num > 15) {
|
||||
throw new TypeError(
|
||||
`Invalid value for parameter "${key}": ${value}`
|
||||
);
|
||||
}
|
||||
value = num;
|
||||
} else if (
|
||||
key === 'client_no_context_takeover' ||
|
||||
key === 'server_no_context_takeover'
|
||||
) {
|
||||
if (value !== true) {
|
||||
throw new TypeError(
|
||||
`Invalid value for parameter "${key}": ${value}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Unknown parameter "${key}"`);
|
||||
}
|
||||
|
||||
params[key] = value;
|
||||
});
|
||||
});
|
||||
|
||||
return configurations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress data. Concurrency limited.
|
||||
*
|
||||
* @param {Buffer} data Compressed data
|
||||
* @param {Boolean} fin Specifies whether or not this is the last fragment
|
||||
* @param {Function} callback Callback
|
||||
* @public
|
||||
*/
|
||||
decompress(data, fin, callback) {
|
||||
zlibLimiter.add((done) => {
|
||||
this._decompress(data, fin, (err, result) => {
|
||||
done();
|
||||
callback(err, result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress data. Concurrency limited.
|
||||
*
|
||||
* @param {(Buffer|String)} data Data to compress
|
||||
* @param {Boolean} fin Specifies whether or not this is the last fragment
|
||||
* @param {Function} callback Callback
|
||||
* @public
|
||||
*/
|
||||
compress(data, fin, callback) {
|
||||
zlibLimiter.add((done) => {
|
||||
this._compress(data, fin, (err, result) => {
|
||||
done();
|
||||
callback(err, result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Decompress data.
|
||||
*
|
||||
* @param {Buffer} data Compressed data
|
||||
* @param {Boolean} fin Specifies whether or not this is the last fragment
|
||||
* @param {Function} callback Callback
|
||||
* @private
|
||||
*/
|
||||
_decompress(data, fin, callback) {
|
||||
const endpoint = this._isServer ? 'client' : 'server';
|
||||
|
||||
if (!this._inflate) {
|
||||
const key = `${endpoint}_max_window_bits`;
|
||||
const windowBits =
|
||||
typeof this.params[key] !== 'number'
|
||||
? zlib.Z_DEFAULT_WINDOWBITS
|
||||
: this.params[key];
|
||||
|
||||
this._inflate = zlib.createInflateRaw({
|
||||
...this._options.zlibInflateOptions,
|
||||
windowBits
|
||||
});
|
||||
this._inflate[kPerMessageDeflate] = this;
|
||||
this._inflate[kTotalLength] = 0;
|
||||
this._inflate[kBuffers] = [];
|
||||
this._inflate.on('error', inflateOnError);
|
||||
this._inflate.on('data', inflateOnData);
|
||||
}
|
||||
|
||||
this._inflate[kCallback] = callback;
|
||||
|
||||
this._inflate.write(data);
|
||||
if (fin) this._inflate.write(TRAILER);
|
||||
|
||||
this._inflate.flush(() => {
|
||||
const err = this._inflate[kError];
|
||||
|
||||
if (err) {
|
||||
this._inflate.close();
|
||||
this._inflate = null;
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = bufferUtil.concat(
|
||||
this._inflate[kBuffers],
|
||||
this._inflate[kTotalLength]
|
||||
);
|
||||
|
||||
if (this._inflate._readableState.endEmitted) {
|
||||
this._inflate.close();
|
||||
this._inflate = null;
|
||||
} else {
|
||||
this._inflate[kTotalLength] = 0;
|
||||
this._inflate[kBuffers] = [];
|
||||
|
||||
if (fin && this.params[`${endpoint}_no_context_takeover`]) {
|
||||
this._inflate.reset();
|
||||
}
|
||||
}
|
||||
|
||||
callback(null, data);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress data.
|
||||
*
|
||||
* @param {(Buffer|String)} data Data to compress
|
||||
* @param {Boolean} fin Specifies whether or not this is the last fragment
|
||||
* @param {Function} callback Callback
|
||||
* @private
|
||||
*/
|
||||
_compress(data, fin, callback) {
|
||||
const endpoint = this._isServer ? 'server' : 'client';
|
||||
|
||||
if (!this._deflate) {
|
||||
const key = `${endpoint}_max_window_bits`;
|
||||
const windowBits =
|
||||
typeof this.params[key] !== 'number'
|
||||
? zlib.Z_DEFAULT_WINDOWBITS
|
||||
: this.params[key];
|
||||
|
||||
this._deflate = zlib.createDeflateRaw({
|
||||
...this._options.zlibDeflateOptions,
|
||||
windowBits
|
||||
});
|
||||
|
||||
this._deflate[kTotalLength] = 0;
|
||||
this._deflate[kBuffers] = [];
|
||||
|
||||
this._deflate.on('data', deflateOnData);
|
||||
}
|
||||
|
||||
this._deflate[kCallback] = callback;
|
||||
|
||||
this._deflate.write(data);
|
||||
this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
|
||||
if (!this._deflate) {
|
||||
//
|
||||
// The deflate stream was closed while data was being processed.
|
||||
//
|
||||
return;
|
||||
}
|
||||
|
||||
let data = bufferUtil.concat(
|
||||
this._deflate[kBuffers],
|
||||
this._deflate[kTotalLength]
|
||||
);
|
||||
|
||||
if (fin) {
|
||||
data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);
|
||||
}
|
||||
|
||||
//
|
||||
// Ensure that the callback will not be called again in
|
||||
// `PerMessageDeflate#cleanup()`.
|
||||
//
|
||||
this._deflate[kCallback] = null;
|
||||
|
||||
this._deflate[kTotalLength] = 0;
|
||||
this._deflate[kBuffers] = [];
|
||||
|
||||
if (fin && this.params[`${endpoint}_no_context_takeover`]) {
|
||||
this._deflate.reset();
|
||||
}
|
||||
|
||||
callback(null, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PerMessageDeflate;
|
||||
|
||||
/**
|
||||
* The listener of the `zlib.DeflateRaw` stream `'data'` event.
|
||||
*
|
||||
* @param {Buffer} chunk A chunk of data
|
||||
* @private
|
||||
*/
|
||||
function deflateOnData(chunk) {
|
||||
this[kBuffers].push(chunk);
|
||||
this[kTotalLength] += chunk.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* The listener of the `zlib.InflateRaw` stream `'data'` event.
|
||||
*
|
||||
* @param {Buffer} chunk A chunk of data
|
||||
* @private
|
||||
*/
|
||||
function inflateOnData(chunk) {
|
||||
this[kTotalLength] += chunk.length;
|
||||
|
||||
if (
|
||||
this[kPerMessageDeflate]._maxPayload < 1 ||
|
||||
this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload
|
||||
) {
|
||||
this[kBuffers].push(chunk);
|
||||
return;
|
||||
}
|
||||
|
||||
this[kError] = new RangeError('Max payload size exceeded');
|
||||
this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';
|
||||
this[kError][kStatusCode] = 1009;
|
||||
this.removeListener('data', inflateOnData);
|
||||
|
||||
//
|
||||
// The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the
|
||||
// fact that in Node.js versions prior to 13.10.0, the callback for
|
||||
// `zlib.flush()` is not called if `zlib.close()` is used. Utilizing
|
||||
// `zlib.reset()` ensures that either the callback is invoked or an error is
|
||||
// emitted.
|
||||
//
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* The listener of the `zlib.InflateRaw` stream `'error'` event.
|
||||
*
|
||||
* @param {Error} err The emitted error
|
||||
* @private
|
||||
*/
|
||||
function inflateOnError(err) {
|
||||
//
|
||||
// There is no need to call `Zlib#close()` as the handle is automatically
|
||||
// closed when an error is emitted.
|
||||
//
|
||||
this[kPerMessageDeflate]._inflate = null;
|
||||
|
||||
if (this[kError]) {
|
||||
this[kCallback](this[kError]);
|
||||
return;
|
||||
}
|
||||
|
||||
err[kStatusCode] = 1007;
|
||||
this[kCallback](err);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @fileoverview A rule to disallow modifying variables of class declarations
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description: "Disallow reassigning class members",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-class-assign",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
messages: {
|
||||
class: "'{{name}}' is a class.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Finds and reports references that are non initializer and writable.
|
||||
* @param {Variable} variable A variable to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkVariable(variable) {
|
||||
astUtils
|
||||
.getModifyingReferences(variable.references)
|
||||
.forEach(reference => {
|
||||
context.report({
|
||||
node: reference.identifier,
|
||||
messageId: "class",
|
||||
data: { name: reference.identifier.name },
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and reports references that are non initializer and writable.
|
||||
* @param {ASTNode} node A ClassDeclaration/ClassExpression node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkForClass(node) {
|
||||
sourceCode.getDeclaredVariables(node).forEach(checkVariable);
|
||||
}
|
||||
|
||||
return {
|
||||
ClassDeclaration: checkForClass,
|
||||
ClassExpression: checkForClass,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import { _ as _array_like_to_array } from "./_array_like_to_array.js";
|
||||
|
||||
function _unsupported_iterable_to_array(o, minLen) {
|
||||
if (!o) return;
|
||||
if (typeof o === "string") return _array_like_to_array(o, minLen);
|
||||
|
||||
var n = Object.prototype.toString.call(o).slice(8, -1);
|
||||
|
||||
if (n === "Object" && o.constructor) n = o.constructor.name;
|
||||
if (n === "Map" || n === "Set") return Array.from(n);
|
||||
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
|
||||
}
|
||||
export { _unsupported_iterable_to_array as _ };
|
||||
@@ -0,0 +1,334 @@
|
||||
declare module 'stream' {
|
||||
import EventEmitter = require('events');
|
||||
|
||||
class internal extends EventEmitter {
|
||||
pipe<T extends NodeJS.WritableStream>(destination: T, options?: { end?: boolean | undefined; }): T;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
class Stream extends internal { }
|
||||
|
||||
interface ReadableOptions {
|
||||
highWaterMark?: number | undefined;
|
||||
encoding?: string | undefined;
|
||||
objectMode?: boolean | undefined;
|
||||
read?(this: Readable, size: number): void;
|
||||
destroy?(this: Readable, error: Error | null, callback: (error: Error | null) => void): void;
|
||||
autoDestroy?: boolean | undefined;
|
||||
}
|
||||
|
||||
class Readable extends Stream implements NodeJS.ReadableStream {
|
||||
/**
|
||||
* A utility method for creating Readable Streams out of iterators.
|
||||
*/
|
||||
static from(iterable: Iterable<any> | AsyncIterable<any>, options?: ReadableOptions): Readable;
|
||||
|
||||
readable: boolean;
|
||||
readonly readableEncoding: BufferEncoding | null;
|
||||
readonly readableEnded: boolean;
|
||||
readonly readableFlowing: boolean | null;
|
||||
readonly readableHighWaterMark: number;
|
||||
readonly readableLength: number;
|
||||
readonly readableObjectMode: boolean;
|
||||
destroyed: boolean;
|
||||
constructor(opts?: ReadableOptions);
|
||||
_read(size: number): void;
|
||||
read(size?: number): any;
|
||||
setEncoding(encoding: string): this;
|
||||
pause(): this;
|
||||
resume(): this;
|
||||
isPaused(): boolean;
|
||||
unpipe(destination?: NodeJS.WritableStream): this;
|
||||
unshift(chunk: any, encoding?: BufferEncoding): void;
|
||||
wrap(oldStream: NodeJS.ReadableStream): this;
|
||||
push(chunk: any, encoding?: string): boolean;
|
||||
_destroy(error: Error | null, callback: (error?: Error | null) => void): void;
|
||||
destroy(error?: Error): this;
|
||||
|
||||
/**
|
||||
* Event emitter
|
||||
* The defined events on documents including:
|
||||
* 1. close
|
||||
* 2. data
|
||||
* 3. end
|
||||
* 4. readable
|
||||
* 5. error
|
||||
*/
|
||||
addListener(event: "close", listener: () => void): this;
|
||||
addListener(event: "data", listener: (chunk: any) => void): this;
|
||||
addListener(event: "end", listener: () => void): this;
|
||||
addListener(event: "readable", listener: () => void): this;
|
||||
addListener(event: "error", listener: (err: Error) => void): this;
|
||||
addListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
emit(event: "close"): boolean;
|
||||
emit(event: "data", chunk: any): boolean;
|
||||
emit(event: "end"): boolean;
|
||||
emit(event: "readable"): boolean;
|
||||
emit(event: "error", err: Error): boolean;
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
|
||||
on(event: "close", listener: () => void): this;
|
||||
on(event: "data", listener: (chunk: any) => void): this;
|
||||
on(event: "end", listener: () => void): this;
|
||||
on(event: "readable", listener: () => void): this;
|
||||
on(event: "error", listener: (err: Error) => void): this;
|
||||
on(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
once(event: "close", listener: () => void): this;
|
||||
once(event: "data", listener: (chunk: any) => void): this;
|
||||
once(event: "end", listener: () => void): this;
|
||||
once(event: "readable", listener: () => void): this;
|
||||
once(event: "error", listener: (err: Error) => void): this;
|
||||
once(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
prependListener(event: "close", listener: () => void): this;
|
||||
prependListener(event: "data", listener: (chunk: any) => void): this;
|
||||
prependListener(event: "end", listener: () => void): this;
|
||||
prependListener(event: "readable", listener: () => void): this;
|
||||
prependListener(event: "error", listener: (err: Error) => void): this;
|
||||
prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
prependOnceListener(event: "close", listener: () => void): this;
|
||||
prependOnceListener(event: "data", listener: (chunk: any) => void): this;
|
||||
prependOnceListener(event: "end", listener: () => void): this;
|
||||
prependOnceListener(event: "readable", listener: () => void): this;
|
||||
prependOnceListener(event: "error", listener: (err: Error) => void): this;
|
||||
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
removeListener(event: "close", listener: () => void): this;
|
||||
removeListener(event: "data", listener: (chunk: any) => void): this;
|
||||
removeListener(event: "end", listener: () => void): this;
|
||||
removeListener(event: "readable", listener: () => void): this;
|
||||
removeListener(event: "error", listener: (err: Error) => void): this;
|
||||
removeListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
[Symbol.asyncIterator](): AsyncIterableIterator<any>;
|
||||
}
|
||||
|
||||
interface WritableOptions {
|
||||
highWaterMark?: number | undefined;
|
||||
decodeStrings?: boolean | undefined;
|
||||
defaultEncoding?: string | undefined;
|
||||
objectMode?: boolean | undefined;
|
||||
emitClose?: boolean | undefined;
|
||||
write?(this: Writable, chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
|
||||
writev?(this: Writable, chunks: Array<{ chunk: any, encoding: string }>, callback: (error?: Error | null) => void): void;
|
||||
destroy?(this: Writable, error: Error | null, callback: (error: Error | null) => void): void;
|
||||
final?(this: Writable, callback: (error?: Error | null) => void): void;
|
||||
autoDestroy?: boolean | undefined;
|
||||
}
|
||||
|
||||
class Writable extends Stream implements NodeJS.WritableStream {
|
||||
readonly writable: boolean;
|
||||
readonly writableEnded: boolean;
|
||||
readonly writableFinished: boolean;
|
||||
readonly writableHighWaterMark: number;
|
||||
readonly writableLength: number;
|
||||
readonly writableObjectMode: boolean;
|
||||
destroyed: boolean;
|
||||
constructor(opts?: WritableOptions);
|
||||
_write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
|
||||
_writev?(chunks: Array<{ chunk: any, encoding: string }>, callback: (error?: Error | null) => void): void;
|
||||
_destroy(error: Error | null, callback: (error?: Error | null) => void): void;
|
||||
_final(callback: (error?: Error | null) => void): void;
|
||||
write(chunk: any, cb?: (error: Error | null | undefined) => void): boolean;
|
||||
write(chunk: any, encoding: string, cb?: (error: Error | null | undefined) => void): boolean;
|
||||
setDefaultEncoding(encoding: string): this;
|
||||
end(cb?: () => void): this;
|
||||
end(chunk: any, cb?: () => void): this;
|
||||
end(chunk: any, encoding: string, cb?: () => void): this;
|
||||
cork(): void;
|
||||
uncork(): void;
|
||||
destroy(error?: Error): this;
|
||||
|
||||
/**
|
||||
* Event emitter
|
||||
* The defined events on documents including:
|
||||
* 1. close
|
||||
* 2. drain
|
||||
* 3. error
|
||||
* 4. finish
|
||||
* 5. pipe
|
||||
* 6. unpipe
|
||||
*/
|
||||
addListener(event: "close", listener: () => void): this;
|
||||
addListener(event: "drain", listener: () => void): this;
|
||||
addListener(event: "error", listener: (err: Error) => void): this;
|
||||
addListener(event: "finish", listener: () => void): this;
|
||||
addListener(event: "pipe", listener: (src: Readable) => void): this;
|
||||
addListener(event: "unpipe", listener: (src: Readable) => void): this;
|
||||
addListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
emit(event: "close"): boolean;
|
||||
emit(event: "drain"): boolean;
|
||||
emit(event: "error", err: Error): boolean;
|
||||
emit(event: "finish"): boolean;
|
||||
emit(event: "pipe", src: Readable): boolean;
|
||||
emit(event: "unpipe", src: Readable): boolean;
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
|
||||
on(event: "close", listener: () => void): this;
|
||||
on(event: "drain", listener: () => void): this;
|
||||
on(event: "error", listener: (err: Error) => void): this;
|
||||
on(event: "finish", listener: () => void): this;
|
||||
on(event: "pipe", listener: (src: Readable) => void): this;
|
||||
on(event: "unpipe", listener: (src: Readable) => void): this;
|
||||
on(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
once(event: "close", listener: () => void): this;
|
||||
once(event: "drain", listener: () => void): this;
|
||||
once(event: "error", listener: (err: Error) => void): this;
|
||||
once(event: "finish", listener: () => void): this;
|
||||
once(event: "pipe", listener: (src: Readable) => void): this;
|
||||
once(event: "unpipe", listener: (src: Readable) => void): this;
|
||||
once(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
prependListener(event: "close", listener: () => void): this;
|
||||
prependListener(event: "drain", listener: () => void): this;
|
||||
prependListener(event: "error", listener: (err: Error) => void): this;
|
||||
prependListener(event: "finish", listener: () => void): this;
|
||||
prependListener(event: "pipe", listener: (src: Readable) => void): this;
|
||||
prependListener(event: "unpipe", listener: (src: Readable) => void): this;
|
||||
prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
prependOnceListener(event: "close", listener: () => void): this;
|
||||
prependOnceListener(event: "drain", listener: () => void): this;
|
||||
prependOnceListener(event: "error", listener: (err: Error) => void): this;
|
||||
prependOnceListener(event: "finish", listener: () => void): this;
|
||||
prependOnceListener(event: "pipe", listener: (src: Readable) => void): this;
|
||||
prependOnceListener(event: "unpipe", listener: (src: Readable) => void): this;
|
||||
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
|
||||
removeListener(event: "close", listener: () => void): this;
|
||||
removeListener(event: "drain", listener: () => void): this;
|
||||
removeListener(event: "error", listener: (err: Error) => void): this;
|
||||
removeListener(event: "finish", listener: () => void): this;
|
||||
removeListener(event: "pipe", listener: (src: Readable) => void): this;
|
||||
removeListener(event: "unpipe", listener: (src: Readable) => void): this;
|
||||
removeListener(event: string | symbol, listener: (...args: any[]) => void): this;
|
||||
}
|
||||
|
||||
interface DuplexOptions extends ReadableOptions, WritableOptions {
|
||||
allowHalfOpen?: boolean | undefined;
|
||||
readableObjectMode?: boolean | undefined;
|
||||
writableObjectMode?: boolean | undefined;
|
||||
readableHighWaterMark?: number | undefined;
|
||||
writableHighWaterMark?: number | undefined;
|
||||
read?(this: Duplex, size: number): void;
|
||||
write?(this: Duplex, chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
|
||||
writev?(this: Duplex, chunks: Array<{ chunk: any, encoding: string }>, callback: (error?: Error | null) => void): void;
|
||||
final?(this: Duplex, callback: (error?: Error | null) => void): void;
|
||||
destroy?(this: Duplex, error: Error | null, callback: (error: Error | null) => void): void;
|
||||
}
|
||||
|
||||
// Note: Duplex extends both Readable and Writable.
|
||||
class Duplex extends Readable implements Writable {
|
||||
readonly writable: boolean;
|
||||
readonly writableEnded: boolean;
|
||||
readonly writableFinished: boolean;
|
||||
readonly writableHighWaterMark: number;
|
||||
readonly writableLength: number;
|
||||
readonly writableObjectMode: boolean;
|
||||
allowHalfOpen: boolean;
|
||||
constructor(opts?: DuplexOptions);
|
||||
_write(chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
|
||||
_writev?(chunks: Array<{ chunk: any, encoding: string }>, callback: (error?: Error | null) => void): void;
|
||||
_destroy(error: Error | null, callback: (error: Error | null) => void): void;
|
||||
_final(callback: (error?: Error | null) => void): void;
|
||||
write(chunk: any, encoding?: string, cb?: (error: Error | null | undefined) => void): boolean;
|
||||
write(chunk: any, cb?: (error: Error | null | undefined) => void): boolean;
|
||||
setDefaultEncoding(encoding: string): this;
|
||||
end(cb?: () => void): this;
|
||||
end(chunk: any, cb?: () => void): this;
|
||||
end(chunk: any, encoding?: string, cb?: () => void): this;
|
||||
cork(): void;
|
||||
uncork(): void;
|
||||
}
|
||||
|
||||
type TransformCallback = (error?: Error | null, data?: any) => void;
|
||||
|
||||
interface TransformOptions extends DuplexOptions {
|
||||
read?(this: Transform, size: number): void;
|
||||
write?(this: Transform, chunk: any, encoding: string, callback: (error?: Error | null) => void): void;
|
||||
writev?(this: Transform, chunks: Array<{ chunk: any, encoding: string }>, callback: (error?: Error | null) => void): void;
|
||||
final?(this: Transform, callback: (error?: Error | null) => void): void;
|
||||
destroy?(this: Transform, error: Error | null, callback: (error: Error | null) => void): void;
|
||||
transform?(this: Transform, chunk: any, encoding: string, callback: TransformCallback): void;
|
||||
flush?(this: Transform, callback: TransformCallback): void;
|
||||
}
|
||||
|
||||
class Transform extends Duplex {
|
||||
constructor(opts?: TransformOptions);
|
||||
_transform(chunk: any, encoding: string, callback: TransformCallback): void;
|
||||
_flush(callback: TransformCallback): void;
|
||||
}
|
||||
|
||||
class PassThrough extends Transform { }
|
||||
|
||||
interface FinishedOptions {
|
||||
error?: boolean | undefined;
|
||||
readable?: boolean | undefined;
|
||||
writable?: boolean | undefined;
|
||||
}
|
||||
function finished(stream: NodeJS.ReadableStream | NodeJS.WritableStream | NodeJS.ReadWriteStream, options: FinishedOptions, callback: (err?: NodeJS.ErrnoException | null) => void): () => void;
|
||||
function finished(stream: NodeJS.ReadableStream | NodeJS.WritableStream | NodeJS.ReadWriteStream, callback: (err?: NodeJS.ErrnoException | null) => void): () => void;
|
||||
namespace finished {
|
||||
function __promisify__(stream: NodeJS.ReadableStream | NodeJS.WritableStream | NodeJS.ReadWriteStream, options?: FinishedOptions): Promise<void>;
|
||||
}
|
||||
|
||||
function pipeline<T extends NodeJS.WritableStream>(stream1: NodeJS.ReadableStream, stream2: T, callback?: (err: NodeJS.ErrnoException | null) => void): T;
|
||||
function pipeline<T extends NodeJS.WritableStream>(stream1: NodeJS.ReadableStream, stream2: NodeJS.ReadWriteStream, stream3: T, callback?: (err: NodeJS.ErrnoException | null) => void): T;
|
||||
function pipeline<T extends NodeJS.WritableStream>(
|
||||
stream1: NodeJS.ReadableStream,
|
||||
stream2: NodeJS.ReadWriteStream,
|
||||
stream3: NodeJS.ReadWriteStream,
|
||||
stream4: T,
|
||||
callback?: (err: NodeJS.ErrnoException | null) => void,
|
||||
): T;
|
||||
function pipeline<T extends NodeJS.WritableStream>(
|
||||
stream1: NodeJS.ReadableStream,
|
||||
stream2: NodeJS.ReadWriteStream,
|
||||
stream3: NodeJS.ReadWriteStream,
|
||||
stream4: NodeJS.ReadWriteStream,
|
||||
stream5: T,
|
||||
callback?: (err: NodeJS.ErrnoException | null) => void,
|
||||
): T;
|
||||
function pipeline(
|
||||
streams: ReadonlyArray<NodeJS.ReadableStream | NodeJS.WritableStream | NodeJS.ReadWriteStream>,
|
||||
callback?: (err: NodeJS.ErrnoException | null) => void,
|
||||
): NodeJS.WritableStream;
|
||||
function pipeline(
|
||||
stream1: NodeJS.ReadableStream,
|
||||
stream2: NodeJS.ReadWriteStream | NodeJS.WritableStream,
|
||||
...streams: Array<NodeJS.ReadWriteStream | NodeJS.WritableStream | ((err: NodeJS.ErrnoException | null) => void)>,
|
||||
): NodeJS.WritableStream;
|
||||
namespace pipeline {
|
||||
function __promisify__(stream1: NodeJS.ReadableStream, stream2: NodeJS.WritableStream): Promise<void>;
|
||||
function __promisify__(stream1: NodeJS.ReadableStream, stream2: NodeJS.ReadWriteStream, stream3: NodeJS.WritableStream): Promise<void>;
|
||||
function __promisify__(stream1: NodeJS.ReadableStream, stream2: NodeJS.ReadWriteStream, stream3: NodeJS.ReadWriteStream, stream4: NodeJS.WritableStream): Promise<void>;
|
||||
function __promisify__(
|
||||
stream1: NodeJS.ReadableStream,
|
||||
stream2: NodeJS.ReadWriteStream,
|
||||
stream3: NodeJS.ReadWriteStream,
|
||||
stream4: NodeJS.ReadWriteStream,
|
||||
stream5: NodeJS.WritableStream,
|
||||
): Promise<void>;
|
||||
function __promisify__(streams: ReadonlyArray<NodeJS.ReadableStream | NodeJS.WritableStream | NodeJS.ReadWriteStream>): Promise<void>;
|
||||
function __promisify__(
|
||||
stream1: NodeJS.ReadableStream,
|
||||
stream2: NodeJS.ReadWriteStream | NodeJS.WritableStream,
|
||||
...streams: Array<NodeJS.ReadWriteStream | NodeJS.WritableStream>,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
interface Pipe {
|
||||
close(): void;
|
||||
hasRef(): boolean;
|
||||
ref(): void;
|
||||
unref(): void;
|
||||
}
|
||||
}
|
||||
|
||||
export = internal;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"reg": {
|
||||
"name": "reg",
|
||||
"browser": "Chrome 60.0.3112 (Windows 7 0.0.0)",
|
||||
"suite": "escape-short",
|
||||
"hz": 421050.7010850686,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.017587416521659537,
|
||||
"rhz": 0.3627606464390377,
|
||||
"sampleSize": 172
|
||||
},
|
||||
"fn if": {
|
||||
"name": "fn if",
|
||||
"browser": "Chrome 60.0.3112 (Windows 7 0.0.0)",
|
||||
"suite": "escape-short",
|
||||
"hz": 612197.8607722911,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.014130797234954116,
|
||||
"rhz": 0.5274454861375074,
|
||||
"sampleSize": 171
|
||||
},
|
||||
"fn if reverse": {
|
||||
"name": "fn if reverse",
|
||||
"browser": "Chrome 60.0.3112 (Windows 7 0.0.0)",
|
||||
"suite": "escape-short",
|
||||
"hz": 638820.1263584908,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.015818194070298164,
|
||||
"rhz": 0.5503821782005622,
|
||||
"sampleSize": 172
|
||||
},
|
||||
"escape31": {
|
||||
"name": "escape31",
|
||||
"browser": "Chrome 60.0.3112 (Windows 7 0.0.0)",
|
||||
"suite": "escape-short",
|
||||
"hz": 906462.1950352091,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.01609037527785378,
|
||||
"rhz": 0.7809720088248596,
|
||||
"sampleSize": 169
|
||||
},
|
||||
"native": {
|
||||
"name": "native",
|
||||
"browser": "Chrome 60.0.3112 (Windows 7 0.0.0)",
|
||||
"suite": "escape-short",
|
||||
"hz": 1160684.6145474233,
|
||||
"success": true,
|
||||
"fastest": true,
|
||||
"rme": 0.01621618746604937,
|
||||
"rhz": 1,
|
||||
"sampleSize": 171
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import _typeof from "./typeof.js";
|
||||
function setFunctionName(e, t, n) {
|
||||
"symbol" == _typeof(t) && (t = (t = t.description) ? "[" + t + "]" : "");
|
||||
try {
|
||||
Object.defineProperty(e, "name", {
|
||||
configurable: !0,
|
||||
value: n ? n + " " + t : t
|
||||
});
|
||||
} catch (e) {}
|
||||
return e;
|
||||
}
|
||||
export { setFunctionName as default };
|
||||
@@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Pino - Super fast, all natural JSON logger for Node.js</title>
|
||||
<meta name="description" content="Super fast, all natural JSON logger for Node.js">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<link rel="stylesheet" href="//unpkg.com/docsify-themeable/dist/css/theme-simple.css">
|
||||
<style>
|
||||
:root {
|
||||
--base-font-size: 16px;
|
||||
--theme-color: rgb(104, 118, 52);
|
||||
--link-color: rgb(104, 118, 52);
|
||||
--link-color--hover: rgb(137, 152, 100);
|
||||
--sidebar-name-margin: 0;
|
||||
--sidebar-name-padding: 0;
|
||||
--code-font-size: .9em;
|
||||
}
|
||||
.sidebar > h1 {
|
||||
margin-bottom: -.75em;
|
||||
margin-top: .75em;
|
||||
}
|
||||
.sidebar > h1 img {
|
||||
height: 4em;
|
||||
}
|
||||
.markdown-section a code {
|
||||
color: var(--link-color)!important;
|
||||
}
|
||||
.markdown-section code:not([class*="lang-"]):not([class*="language-"]) {
|
||||
white-space: unset
|
||||
}
|
||||
</style>
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
<script>
|
||||
window.$docsify = {
|
||||
name: 'pino',
|
||||
logo: './pino-tree.png',
|
||||
loadSidebar: 'docsify/sidebar.md',
|
||||
repo: 'https://github.com/pinojs/pino',
|
||||
auto2top: true,
|
||||
ga: 'UA-103155139-1'
|
||||
}
|
||||
</script>
|
||||
<script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
|
||||
<script src="//unpkg.com/docsify/lib/plugins/ga.min.js"></script>
|
||||
<!-- To enable syntax highlighting on TypeScript codes: -->
|
||||
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-typescript.min.js"></script>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env node
|
||||
import { performance } from 'node:perf_hooks'
|
||||
import module from 'node:module'
|
||||
|
||||
if (!import.meta.url.includes('node_modules')) {
|
||||
if (!process.env.DEBUG_DISABLE_SOURCE_MAP) {
|
||||
// eslint-disable-next-line n/no-unsupported-features/node-builtins -- only used in dev
|
||||
process.setSourceMapsEnabled(true)
|
||||
}
|
||||
|
||||
process.on('unhandledRejection', (err) => {
|
||||
throw new Error('UNHANDLED PROMISE REJECTION', { cause: err })
|
||||
})
|
||||
}
|
||||
|
||||
global.__vite_start_time = performance.now()
|
||||
|
||||
// check debug mode first before requiring the CLI.
|
||||
const debugIndex = process.argv.findIndex((arg) => /^(?:-d|--debug)$/.test(arg))
|
||||
const filterIndex = process.argv.findIndex((arg) =>
|
||||
/^(?:-f|--filter)$/.test(arg),
|
||||
)
|
||||
const profileIndex = process.argv.indexOf('--profile')
|
||||
|
||||
if (debugIndex > 0) {
|
||||
let value = process.argv[debugIndex + 1]
|
||||
if (!value || value[0] === '-') {
|
||||
value = 'vite:*'
|
||||
} else {
|
||||
// support debugging multiple flags with comma-separated list
|
||||
value = value
|
||||
.split(',')
|
||||
.map((v) => `vite:${v}`)
|
||||
.join(',')
|
||||
}
|
||||
process.env.DEBUG = `${
|
||||
process.env.DEBUG ? process.env.DEBUG + ',' : ''
|
||||
}${value}`
|
||||
|
||||
if (filterIndex > 0) {
|
||||
const filter = process.argv[filterIndex + 1]
|
||||
if (filter && filter[0] !== '-') {
|
||||
process.env.VITE_DEBUG_FILTER = filter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function start() {
|
||||
try {
|
||||
// eslint-disable-next-line n/no-unsupported-features/node-builtins -- it is supported in Node 22.8.0+ and only called if it exists
|
||||
module.enableCompileCache?.()
|
||||
// flush the cache after 10s because the cache is not flushed until process end
|
||||
// for dev server, the cache is never flushed unless manually flushed because the process.exit is called
|
||||
// also flushing the cache in SIGINT handler seems to cause the process to hang
|
||||
setTimeout(() => {
|
||||
try {
|
||||
// eslint-disable-next-line n/no-unsupported-features/node-builtins -- it is supported in Node 22.12.0+ and only called if it exists
|
||||
module.flushCompileCache?.()
|
||||
} catch {}
|
||||
}, 10 * 1000).unref()
|
||||
} catch {}
|
||||
return import('../dist/node/cli.js')
|
||||
}
|
||||
|
||||
if (profileIndex > 0) {
|
||||
process.argv.splice(profileIndex, 1)
|
||||
const next = process.argv[profileIndex]
|
||||
if (next && next[0] !== '-') {
|
||||
process.argv.splice(profileIndex, 1)
|
||||
}
|
||||
const inspector = await import('node:inspector').then((r) => r.default)
|
||||
const session = (global.__vite_profile_session = new inspector.Session())
|
||||
session.connect()
|
||||
session.post('Profiler.enable', () => {
|
||||
session.post('Profiler.start', start)
|
||||
})
|
||||
} else {
|
||||
start()
|
||||
}
|
||||
Reference in New Issue
Block a user