WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1 @@
|
||||
!function(e,o){"object"==typeof exports&&"undefined"!=typeof module?module.exports=o():"function"==typeof define&&define.amd?define(o):(e="undefined"!=typeof globalThis?globalThis:e||self).uuidv1=o()}(this,(function(){"use strict";var e,o=new Uint8Array(16);function t(){if(!e&&!(e="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto)||"undefined"!=typeof msCrypto&&"function"==typeof msCrypto.getRandomValues&&msCrypto.getRandomValues.bind(msCrypto)))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return e(o)}var n=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;function r(e){return"string"==typeof e&&n.test(e)}for(var i,u,s=[],a=0;a<256;++a)s.push((a+256).toString(16).substr(1));var d=0,f=0;return function(e,o,n){var a=o&&n||0,c=o||new Array(16),l=(e=e||{}).node||i,p=void 0!==e.clockseq?e.clockseq:u;if(null==l||null==p){var v=e.random||(e.rng||t)();null==l&&(l=i=[1|v[0],v[1],v[2],v[3],v[4],v[5]]),null==p&&(p=u=16383&(v[6]<<8|v[7]))}var y=void 0!==e.msecs?e.msecs:Date.now(),m=void 0!==e.nsecs?e.nsecs:f+1,g=y-d+(m-f)/1e4;if(g<0&&void 0===e.clockseq&&(p=p+1&16383),(g<0||y>d)&&void 0===e.nsecs&&(m=0),m>=1e4)throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");d=y,f=m,u=p;var h=(1e4*(268435455&(y+=122192928e5))+m)%4294967296;c[a++]=h>>>24&255,c[a++]=h>>>16&255,c[a++]=h>>>8&255,c[a++]=255&h;var w=y/4294967296*1e4&268435455;c[a++]=w>>>8&255,c[a++]=255&w,c[a++]=w>>>24&15|16,c[a++]=w>>>16&255,c[a++]=p>>>8|128,c[a++]=255&p;for(var b=0;b<6;++b)c[a+b]=l[b];return o||function(e){var o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,t=(s[e[o+0]]+s[e[o+1]]+s[e[o+2]]+s[e[o+3]]+"-"+s[e[o+4]]+s[e[o+5]]+"-"+s[e[o+6]]+s[e[o+7]]+"-"+s[e[o+8]]+s[e[o+9]]+"-"+s[e[o+10]]+s[e[o+11]]+s[e[o+12]]+s[e[o+13]]+s[e[o+14]]+s[e[o+15]]).toLowerCase();if(!r(t))throw TypeError("Stringified UUID is invalid");return t}(c)}}));
|
||||
@@ -0,0 +1,227 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const tsutils = __importStar(require("ts-api-utils"));
|
||||
const ts = __importStar(require("typescript"));
|
||||
const util_1 = require("../util");
|
||||
const astIgnoreKeys = new Set(['loc', 'parent', 'range']);
|
||||
const isSameAstNode = (actualNode, expectedNode) => {
|
||||
if (actualNode === expectedNode) {
|
||||
return true;
|
||||
}
|
||||
if (actualNode &&
|
||||
expectedNode &&
|
||||
typeof actualNode === 'object' &&
|
||||
typeof expectedNode === 'object') {
|
||||
if (Array.isArray(actualNode) && Array.isArray(expectedNode)) {
|
||||
if (actualNode.length !== expectedNode.length) {
|
||||
return false;
|
||||
}
|
||||
return !actualNode.some((nodeEle, index) => !isSameAstNode(nodeEle, expectedNode[index]));
|
||||
}
|
||||
const actualNodeKeys = Object.keys(actualNode).filter(key => !astIgnoreKeys.has(key));
|
||||
const expectedNodeKeys = Object.keys(expectedNode).filter(key => !astIgnoreKeys.has(key));
|
||||
if (actualNodeKeys.length !== expectedNodeKeys.length) {
|
||||
return false;
|
||||
}
|
||||
if (actualNodeKeys.some(actualNodeKey => !Object.hasOwn(expectedNode, actualNodeKey))) {
|
||||
return false;
|
||||
}
|
||||
if (actualNodeKeys.some(actualNodeKey => !isSameAstNode(actualNode[actualNodeKey], expectedNode[actualNodeKey]))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'no-duplicate-type-constituents',
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'Disallow duplicate constituents of union or intersection types',
|
||||
recommended: 'recommended',
|
||||
requiresTypeChecking: true,
|
||||
},
|
||||
fixable: 'code',
|
||||
messages: {
|
||||
duplicate: '{{type}} type constituent is duplicated with {{previous}}.',
|
||||
unnecessary: 'Explicit undefined is unnecessary on an optional parameter.',
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
ignoreIntersections: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to ignore `&` intersections.',
|
||||
},
|
||||
ignoreUnions: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to ignore `|` unions.',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultOptions: [
|
||||
{
|
||||
ignoreIntersections: false,
|
||||
ignoreUnions: false,
|
||||
},
|
||||
],
|
||||
create(context, [{ ignoreIntersections, ignoreUnions }]) {
|
||||
const parserServices = (0, util_1.getParserServices)(context);
|
||||
const { sourceCode } = context;
|
||||
function report(messageId, constituentNode, data) {
|
||||
const getUnionOrIntersectionToken = (where, at) => sourceCode[`getTokens${where}`](constituentNode, {
|
||||
filter: token => ['&', '|'].includes(token.value) &&
|
||||
constituentNode.parent.range[0] <= token.range[0] &&
|
||||
token.range[1] <= constituentNode.parent.range[1],
|
||||
}).at(at);
|
||||
const beforeUnionOrIntersectionToken = getUnionOrIntersectionToken('Before', -1);
|
||||
let afterUnionOrIntersectionToken;
|
||||
let bracketBeforeTokens;
|
||||
let bracketAfterTokens;
|
||||
if (beforeUnionOrIntersectionToken) {
|
||||
bracketBeforeTokens = sourceCode.getTokensBetween(beforeUnionOrIntersectionToken, constituentNode);
|
||||
bracketAfterTokens = sourceCode.getTokensAfter(constituentNode, {
|
||||
count: bracketBeforeTokens.length,
|
||||
});
|
||||
}
|
||||
else {
|
||||
afterUnionOrIntersectionToken = (0, util_1.nullThrows)(getUnionOrIntersectionToken('After', 0), util_1.NullThrowsReasons.MissingToken('union or intersection token', 'duplicate type constituent'));
|
||||
bracketAfterTokens = sourceCode.getTokensBetween(constituentNode, afterUnionOrIntersectionToken);
|
||||
bracketBeforeTokens = sourceCode.getTokensBefore(constituentNode, {
|
||||
count: bracketAfterTokens.length,
|
||||
});
|
||||
}
|
||||
context.report({
|
||||
loc: {
|
||||
start: constituentNode.loc.start,
|
||||
end: (bracketAfterTokens.at(-1) ?? constituentNode).loc.end,
|
||||
},
|
||||
node: constituentNode,
|
||||
messageId,
|
||||
data,
|
||||
fix: fixer => [
|
||||
beforeUnionOrIntersectionToken,
|
||||
...bracketBeforeTokens,
|
||||
constituentNode,
|
||||
...bracketAfterTokens,
|
||||
afterUnionOrIntersectionToken,
|
||||
].flatMap(token => (token ? fixer.remove(token) : [])),
|
||||
});
|
||||
}
|
||||
function checkDuplicateRecursively(unionOrIntersection, constituentNode, uniqueConstituents, cachedTypeMap, forEachNodeType) {
|
||||
const reportDuplicate = (previous) => {
|
||||
report('duplicate', constituentNode, {
|
||||
type: unionOrIntersection,
|
||||
previous: sourceCode.getText(previous),
|
||||
});
|
||||
};
|
||||
// Check duplicates in the AST before type lookup for better performance.
|
||||
let duplicatedPrevious = uniqueConstituents.find(ele => isSameAstNode(ele, constituentNode));
|
||||
if (duplicatedPrevious) {
|
||||
reportDuplicate(duplicatedPrevious);
|
||||
return;
|
||||
}
|
||||
const type = parserServices.getTypeAtLocation(constituentNode);
|
||||
if (tsutils.isIntrinsicErrorType(type)) {
|
||||
return;
|
||||
}
|
||||
duplicatedPrevious = cachedTypeMap.get(type);
|
||||
if (duplicatedPrevious) {
|
||||
reportDuplicate(duplicatedPrevious);
|
||||
return;
|
||||
}
|
||||
forEachNodeType?.(type, constituentNode);
|
||||
cachedTypeMap.set(type, constituentNode);
|
||||
uniqueConstituents.push(constituentNode);
|
||||
if ((unionOrIntersection === 'Union' &&
|
||||
constituentNode.type === utils_1.AST_NODE_TYPES.TSUnionType) ||
|
||||
(unionOrIntersection === 'Intersection' &&
|
||||
constituentNode.type === utils_1.AST_NODE_TYPES.TSIntersectionType)) {
|
||||
for (const constituent of constituentNode.types) {
|
||||
checkDuplicateRecursively(unionOrIntersection, constituent, uniqueConstituents, cachedTypeMap, forEachNodeType);
|
||||
}
|
||||
}
|
||||
}
|
||||
function checkDuplicate(node, forEachNodeType) {
|
||||
const cachedTypeMap = new Map();
|
||||
const uniqueConstituents = [];
|
||||
const unionOrIntersection = node.type === utils_1.AST_NODE_TYPES.TSIntersectionType
|
||||
? 'Intersection'
|
||||
: 'Union';
|
||||
for (const type of node.types) {
|
||||
checkDuplicateRecursively(unionOrIntersection, type, uniqueConstituents, cachedTypeMap, forEachNodeType);
|
||||
}
|
||||
}
|
||||
return {
|
||||
...(!ignoreIntersections && {
|
||||
TSIntersectionType(node) {
|
||||
if (node.parent.type === utils_1.AST_NODE_TYPES.TSIntersectionType) {
|
||||
return;
|
||||
}
|
||||
checkDuplicate(node);
|
||||
},
|
||||
}),
|
||||
...(!ignoreUnions && {
|
||||
TSUnionType: (node) => {
|
||||
if (node.parent.type === utils_1.AST_NODE_TYPES.TSUnionType) {
|
||||
return;
|
||||
}
|
||||
checkDuplicate(node, (constituentNodeType, constituentNode) => {
|
||||
const maybeTypeAnnotation = node.parent;
|
||||
if (maybeTypeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeAnnotation) {
|
||||
const maybeIdentifier = maybeTypeAnnotation.parent;
|
||||
if (maybeIdentifier.type === utils_1.AST_NODE_TYPES.Identifier &&
|
||||
maybeIdentifier.optional) {
|
||||
const maybeFunction = maybeIdentifier.parent;
|
||||
if ((0, util_1.isFunctionOrFunctionType)(maybeFunction) &&
|
||||
maybeFunction.params.includes(maybeIdentifier) &&
|
||||
tsutils.isTypeFlagSet(constituentNodeType, ts.TypeFlags.Undefined)) {
|
||||
report('unnecessary', constituentNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,72 @@
|
||||
# Installation
|
||||
> `npm install --save @types/esrecurse`
|
||||
|
||||
# Summary
|
||||
This package contains type definitions for esrecurse (https://github.com/estools/esrecurse).
|
||||
|
||||
# Details
|
||||
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/esrecurse.
|
||||
## [index.d.ts](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/esrecurse/index.d.ts)
|
||||
````ts
|
||||
/**
|
||||
* Options for the Visitor constructor and visit function.
|
||||
*/
|
||||
interface VisitorOptions {
|
||||
/**
|
||||
* Fallback strategy for unknown node types.
|
||||
* @default 'iteration'
|
||||
*/
|
||||
fallback?: "iteration" | ((node: any) => string[]);
|
||||
|
||||
/**
|
||||
* Custom keys for child nodes by node type.
|
||||
* @default {}
|
||||
*/
|
||||
childVisitorKeys?: Record<string, string[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A visitor class for recursively traversing ECMAScript AST.
|
||||
*/
|
||||
declare class Visitor {
|
||||
/**
|
||||
* Creates a new Visitor instance.
|
||||
* @param options Configuration options for the visitor.
|
||||
*/
|
||||
constructor(visitor?: Visitor | null, options?: VisitorOptions | null);
|
||||
|
||||
/**
|
||||
* Visits a node, invoking the appropriate handler.
|
||||
* @param node The AST node to visit.
|
||||
*/
|
||||
visit(node: any): void;
|
||||
|
||||
/**
|
||||
* Visits the children of a node based on childVisitorKeys.
|
||||
* @param node The AST node whose children to visit.
|
||||
*/
|
||||
visitChildren(node: any): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an AST node with the specified visitor.
|
||||
* @param ast The AST node to traverse.
|
||||
* @param visitor A visitor instance or visitor object.
|
||||
* @param options Configuration options for the traversal.
|
||||
*/
|
||||
declare function visit(
|
||||
ast: any,
|
||||
visitor?: Visitor | Record<string, (node: any) => void> | null,
|
||||
options?: VisitorOptions,
|
||||
): void;
|
||||
|
||||
export { visit, Visitor, type VisitorOptions };
|
||||
|
||||
````
|
||||
|
||||
### Additional Details
|
||||
* Last updated: Sat, 19 Jul 2025 03:47:05 GMT
|
||||
* Dependencies: none
|
||||
|
||||
# Credits
|
||||
These definitions were written by [Jimmy Leung](https://github.com/hkleungai).
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"moduleResolutionKind.js","sourceRoot":"","sources":["../../src/enums/moduleResolutionKind.ts"],"names":[],"mappings":"AAAA,sGAAsG;AACtG,MAAM,CAAC,IAAI,oBAAyB,CAAC;AACrC,CAAC,UAAU,oBAAoB;IAC3B,oBAAoB,CAAC,oBAAoB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC;IACtE,oBAAoB,CAAC,oBAAoB,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC;IACtE,oBAAoB,CAAC,oBAAoB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;IACpE,oBAAoB,CAAC,oBAAoB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC;IACpE,oBAAoB,CAAC,oBAAoB,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,GAAG,UAAU,CAAC;IACzE,oBAAoB,CAAC,oBAAoB,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC;AAC5E,CAAC,CAAC,CAAC,oBAAoB,IAAI,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC,CAAC"}
|
||||
@@ -0,0 +1,8 @@
|
||||
"use strict";
|
||||
|
||||
function _class_apply_descriptor_get(receiver, descriptor) {
|
||||
if (descriptor.get) return descriptor.get.call(receiver);
|
||||
|
||||
return descriptor.value;
|
||||
}
|
||||
exports._ = _class_apply_descriptor_get;
|
||||
@@ -0,0 +1,140 @@
|
||||
/* -*- Mode: js; js-indent-level: 2; -*- */
|
||||
/*
|
||||
* Copyright 2011 Mozilla Foundation and contributors
|
||||
* Licensed under the New BSD license. See LICENSE or:
|
||||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*
|
||||
* Based on the Base 64 VLQ implementation in Closure Compiler:
|
||||
* https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java
|
||||
*
|
||||
* Copyright 2011 The Closure Compiler Authors. All rights reserved.
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
var base64 = require('./base64');
|
||||
|
||||
// A single base 64 digit can contain 6 bits of data. For the base 64 variable
|
||||
// length quantities we use in the source map spec, the first bit is the sign,
|
||||
// the next four bits are the actual value, and the 6th bit is the
|
||||
// continuation bit. The continuation bit tells us whether there are more
|
||||
// digits in this value following this digit.
|
||||
//
|
||||
// Continuation
|
||||
// | Sign
|
||||
// | |
|
||||
// V V
|
||||
// 101011
|
||||
|
||||
var VLQ_BASE_SHIFT = 5;
|
||||
|
||||
// binary: 100000
|
||||
var VLQ_BASE = 1 << VLQ_BASE_SHIFT;
|
||||
|
||||
// binary: 011111
|
||||
var VLQ_BASE_MASK = VLQ_BASE - 1;
|
||||
|
||||
// binary: 100000
|
||||
var VLQ_CONTINUATION_BIT = VLQ_BASE;
|
||||
|
||||
/**
|
||||
* Converts from a two-complement value to a value where the sign bit is
|
||||
* placed in the least significant bit. For example, as decimals:
|
||||
* 1 becomes 2 (10 binary), -1 becomes 3 (11 binary)
|
||||
* 2 becomes 4 (100 binary), -2 becomes 5 (101 binary)
|
||||
*/
|
||||
function toVLQSigned(aValue) {
|
||||
return aValue < 0
|
||||
? ((-aValue) << 1) + 1
|
||||
: (aValue << 1) + 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to a two-complement value from a value where the sign bit is
|
||||
* placed in the least significant bit. For example, as decimals:
|
||||
* 2 (10 binary) becomes 1, 3 (11 binary) becomes -1
|
||||
* 4 (100 binary) becomes 2, 5 (101 binary) becomes -2
|
||||
*/
|
||||
function fromVLQSigned(aValue) {
|
||||
var isNegative = (aValue & 1) === 1;
|
||||
var shifted = aValue >> 1;
|
||||
return isNegative
|
||||
? -shifted
|
||||
: shifted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the base 64 VLQ encoded value.
|
||||
*/
|
||||
exports.encode = function base64VLQ_encode(aValue) {
|
||||
var encoded = "";
|
||||
var digit;
|
||||
|
||||
var vlq = toVLQSigned(aValue);
|
||||
|
||||
do {
|
||||
digit = vlq & VLQ_BASE_MASK;
|
||||
vlq >>>= VLQ_BASE_SHIFT;
|
||||
if (vlq > 0) {
|
||||
// There are still more digits in this value, so we must make sure the
|
||||
// continuation bit is marked.
|
||||
digit |= VLQ_CONTINUATION_BIT;
|
||||
}
|
||||
encoded += base64.encode(digit);
|
||||
} while (vlq > 0);
|
||||
|
||||
return encoded;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes the next base 64 VLQ value from the given string and returns the
|
||||
* value and the rest of the string via the out parameter.
|
||||
*/
|
||||
exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) {
|
||||
var strLen = aStr.length;
|
||||
var result = 0;
|
||||
var shift = 0;
|
||||
var continuation, digit;
|
||||
|
||||
do {
|
||||
if (aIndex >= strLen) {
|
||||
throw new Error("Expected more digits in base 64 VLQ value.");
|
||||
}
|
||||
|
||||
digit = base64.decode(aStr.charCodeAt(aIndex++));
|
||||
if (digit === -1) {
|
||||
throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1));
|
||||
}
|
||||
|
||||
continuation = !!(digit & VLQ_CONTINUATION_BIT);
|
||||
digit &= VLQ_BASE_MASK;
|
||||
result = result + (digit << shift);
|
||||
shift += VLQ_BASE_SHIFT;
|
||||
} while (continuation);
|
||||
|
||||
aOutParam.value = fromVLQSigned(result);
|
||||
aOutParam.rest = aIndex;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { TSESLint } from '@typescript-eslint/utils';
|
||||
export type MessageIds = 'defineInitializer' | 'defineInitializerSuggestion';
|
||||
declare const _default: TSESLint.RuleModule<MessageIds, [], import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,42 @@
|
||||
// @ts-ignore TS6133
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
import * as z from "zod/v3";
|
||||
|
||||
function checkErrors(a: z.ZodTypeAny, bad: any) {
|
||||
let expected: any;
|
||||
try {
|
||||
a.parse(bad);
|
||||
} catch (error) {
|
||||
expected = (error as z.ZodError).formErrors;
|
||||
}
|
||||
try {
|
||||
a.nullable().parse(bad);
|
||||
} catch (error) {
|
||||
expect((error as z.ZodError).formErrors).toEqual(expected);
|
||||
}
|
||||
}
|
||||
|
||||
test("Should have error messages appropriate for the underlying type", () => {
|
||||
checkErrors(z.string().min(2), 1);
|
||||
z.string().min(2).nullable().parse(null);
|
||||
checkErrors(z.number().gte(2), 1);
|
||||
z.number().gte(2).nullable().parse(null);
|
||||
checkErrors(z.boolean(), "");
|
||||
z.boolean().nullable().parse(null);
|
||||
checkErrors(z.null(), null);
|
||||
z.null().nullable().parse(null);
|
||||
checkErrors(z.null(), {});
|
||||
z.null().nullable().parse(null);
|
||||
checkErrors(z.object({}), 1);
|
||||
z.object({}).nullable().parse(null);
|
||||
checkErrors(z.tuple([]), 1);
|
||||
z.tuple([]).nullable().parse(null);
|
||||
checkErrors(z.unknown(), 1);
|
||||
z.unknown().nullable().parse(null);
|
||||
});
|
||||
|
||||
test("unwrap", () => {
|
||||
const unwrapped = z.string().nullable().unwrap();
|
||||
expect(unwrapped).toBeInstanceOf(z.ZodString);
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "@typescript/typescript-linux-x64",
|
||||
"version": "7.0.2",
|
||||
"license": "Apache-2.0",
|
||||
"author": "Microsoft Corp.",
|
||||
"homepage": "https://www.typescriptlang.org/",
|
||||
"description": "TypeScript is a language for application scale JavaScript development",
|
||||
"keywords": [
|
||||
"TypeScript",
|
||||
"Microsoft",
|
||||
"compiler",
|
||||
"language",
|
||||
"javascript"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/microsoft/TypeScript/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/microsoft/TypeScript.git"
|
||||
},
|
||||
"type": "module",
|
||||
"preferUnplugged": true,
|
||||
"engines": {
|
||||
"node": ">=16.20.0"
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"NOTICE.txt"
|
||||
],
|
||||
"exports": {
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"gitHead": "2bd066d87f5bafd315be9f40889d0a60b9e58e0b",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"tag": "latest"
|
||||
},
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,414 @@
|
||||
import { TransformOptions } from 'stream'
|
||||
import {
|
||||
Mode,
|
||||
bindComplete,
|
||||
parseComplete,
|
||||
closeComplete,
|
||||
noData,
|
||||
portalSuspended,
|
||||
copyDone,
|
||||
replicationStart,
|
||||
emptyQuery,
|
||||
ReadyForQueryMessage,
|
||||
CommandCompleteMessage,
|
||||
CopyDataMessage,
|
||||
CopyResponse,
|
||||
NotificationResponseMessage,
|
||||
RowDescriptionMessage,
|
||||
ParameterDescriptionMessage,
|
||||
Field,
|
||||
DataRowMessage,
|
||||
ParameterStatusMessage,
|
||||
BackendKeyDataMessage,
|
||||
DatabaseError,
|
||||
BackendMessage,
|
||||
MessageName,
|
||||
AuthenticationMD5Password,
|
||||
NoticeMessage,
|
||||
} from './messages'
|
||||
import { BufferReader } from './buffer-reader'
|
||||
|
||||
// every message is prefixed with a single byte
|
||||
const CODE_LENGTH = 1
|
||||
// every message has an int32 length which includes itself but does
|
||||
// NOT include the code in the length
|
||||
const LEN_LENGTH = 4
|
||||
|
||||
const HEADER_LENGTH = CODE_LENGTH + LEN_LENGTH
|
||||
|
||||
// A placeholder for a `BackendMessage`’s length value that will be set after construction.
|
||||
const LATEINIT_LENGTH = -1
|
||||
|
||||
export type Packet = {
|
||||
code: number
|
||||
packet: Buffer
|
||||
}
|
||||
|
||||
const emptyBuffer = Buffer.allocUnsafe(0)
|
||||
|
||||
type StreamOptions = TransformOptions & {
|
||||
mode: Mode
|
||||
}
|
||||
|
||||
const enum MessageCodes {
|
||||
DataRow = 0x44, // D
|
||||
ParseComplete = 0x31, // 1
|
||||
BindComplete = 0x32, // 2
|
||||
CloseComplete = 0x33, // 3
|
||||
CommandComplete = 0x43, // C
|
||||
ReadyForQuery = 0x5a, // Z
|
||||
NoData = 0x6e, // n
|
||||
NotificationResponse = 0x41, // A
|
||||
AuthenticationResponse = 0x52, // R
|
||||
ParameterStatus = 0x53, // S
|
||||
BackendKeyData = 0x4b, // K
|
||||
ErrorMessage = 0x45, // E
|
||||
NoticeMessage = 0x4e, // N
|
||||
RowDescriptionMessage = 0x54, // T
|
||||
ParameterDescriptionMessage = 0x74, // t
|
||||
PortalSuspended = 0x73, // s
|
||||
ReplicationStart = 0x57, // W
|
||||
EmptyQuery = 0x49, // I
|
||||
CopyIn = 0x47, // G
|
||||
CopyOut = 0x48, // H
|
||||
CopyDone = 0x63, // c
|
||||
CopyData = 0x64, // d
|
||||
}
|
||||
|
||||
export type MessageCallback = (msg: BackendMessage) => void
|
||||
|
||||
export class Parser {
|
||||
private buffer: Buffer = emptyBuffer
|
||||
private bufferLength: number = 0
|
||||
private bufferOffset: number = 0
|
||||
private reader = new BufferReader()
|
||||
private mode: Mode
|
||||
|
||||
constructor(opts?: StreamOptions) {
|
||||
if (opts?.mode === 'binary') {
|
||||
throw new Error('Binary mode not supported yet')
|
||||
}
|
||||
this.mode = opts?.mode || 'text'
|
||||
}
|
||||
|
||||
public parse(buffer: Buffer, callback: MessageCallback) {
|
||||
this.mergeBuffer(buffer)
|
||||
const bufferFullLength = this.bufferOffset + this.bufferLength
|
||||
let offset = this.bufferOffset
|
||||
while (offset + HEADER_LENGTH <= bufferFullLength) {
|
||||
// code is 1 byte long - it identifies the message type
|
||||
const code = this.buffer[offset]
|
||||
// length is 1 Uint32BE - it is the length of the message EXCLUDING the code
|
||||
const length = this.buffer.readUInt32BE(offset + CODE_LENGTH)
|
||||
const fullMessageLength = CODE_LENGTH + length
|
||||
if (fullMessageLength + offset <= bufferFullLength) {
|
||||
const message = this.handlePacket(offset + HEADER_LENGTH, code, length, this.buffer)
|
||||
callback(message)
|
||||
offset += fullMessageLength
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (offset === bufferFullLength) {
|
||||
// No more use for the buffer
|
||||
this.buffer = emptyBuffer
|
||||
this.bufferLength = 0
|
||||
this.bufferOffset = 0
|
||||
} else {
|
||||
// Adjust the cursors of remainingBuffer
|
||||
this.bufferLength = bufferFullLength - offset
|
||||
this.bufferOffset = offset
|
||||
}
|
||||
}
|
||||
|
||||
private mergeBuffer(buffer: Buffer): void {
|
||||
if (this.bufferLength > 0) {
|
||||
const newLength = this.bufferLength + buffer.byteLength
|
||||
const newFullLength = newLength + this.bufferOffset
|
||||
if (newFullLength > this.buffer.byteLength) {
|
||||
// We can't concat the new buffer with the remaining one
|
||||
let newBuffer: Buffer
|
||||
if (newLength <= this.buffer.byteLength && this.bufferOffset >= this.bufferLength) {
|
||||
// We can move the relevant part to the beginning of the buffer instead of allocating a new buffer
|
||||
newBuffer = this.buffer
|
||||
} else {
|
||||
// Allocate a new larger buffer
|
||||
let newBufferLength = this.buffer.byteLength * 2
|
||||
while (newLength >= newBufferLength) {
|
||||
newBufferLength *= 2
|
||||
}
|
||||
newBuffer = Buffer.allocUnsafe(newBufferLength)
|
||||
}
|
||||
// Move the remaining buffer to the new one
|
||||
this.buffer.copy(newBuffer, 0, this.bufferOffset, this.bufferOffset + this.bufferLength)
|
||||
this.buffer = newBuffer
|
||||
this.bufferOffset = 0
|
||||
}
|
||||
// Concat the new buffer with the remaining one
|
||||
buffer.copy(this.buffer, this.bufferOffset + this.bufferLength)
|
||||
this.bufferLength = newLength
|
||||
} else {
|
||||
this.buffer = buffer
|
||||
this.bufferOffset = 0
|
||||
this.bufferLength = buffer.byteLength
|
||||
}
|
||||
}
|
||||
|
||||
private handlePacket(offset: number, code: number, length: number, bytes: Buffer): BackendMessage {
|
||||
const { reader } = this
|
||||
|
||||
// NOTE: This undesirably retains the buffer in `this.reader` if the `parse*Message` calls below throw. However, those should only throw in the case of a protocol error, which normally results in the reader being discarded.
|
||||
reader.setBuffer(offset, bytes)
|
||||
|
||||
let message: BackendMessage
|
||||
|
||||
switch (code) {
|
||||
case MessageCodes.BindComplete:
|
||||
message = bindComplete
|
||||
break
|
||||
case MessageCodes.ParseComplete:
|
||||
message = parseComplete
|
||||
break
|
||||
case MessageCodes.CloseComplete:
|
||||
message = closeComplete
|
||||
break
|
||||
case MessageCodes.NoData:
|
||||
message = noData
|
||||
break
|
||||
case MessageCodes.PortalSuspended:
|
||||
message = portalSuspended
|
||||
break
|
||||
case MessageCodes.CopyDone:
|
||||
message = copyDone
|
||||
break
|
||||
case MessageCodes.ReplicationStart:
|
||||
message = replicationStart
|
||||
break
|
||||
case MessageCodes.EmptyQuery:
|
||||
message = emptyQuery
|
||||
break
|
||||
case MessageCodes.DataRow:
|
||||
message = parseDataRowMessage(reader)
|
||||
break
|
||||
case MessageCodes.CommandComplete:
|
||||
message = parseCommandCompleteMessage(reader)
|
||||
break
|
||||
case MessageCodes.ReadyForQuery:
|
||||
message = parseReadyForQueryMessage(reader)
|
||||
break
|
||||
case MessageCodes.NotificationResponse:
|
||||
message = parseNotificationMessage(reader)
|
||||
break
|
||||
case MessageCodes.AuthenticationResponse:
|
||||
message = parseAuthenticationResponse(reader, length)
|
||||
break
|
||||
case MessageCodes.ParameterStatus:
|
||||
message = parseParameterStatusMessage(reader)
|
||||
break
|
||||
case MessageCodes.BackendKeyData:
|
||||
message = parseBackendKeyData(reader)
|
||||
break
|
||||
case MessageCodes.ErrorMessage:
|
||||
message = parseErrorMessage(reader, 'error')
|
||||
break
|
||||
case MessageCodes.NoticeMessage:
|
||||
message = parseErrorMessage(reader, 'notice')
|
||||
break
|
||||
case MessageCodes.RowDescriptionMessage:
|
||||
message = parseRowDescriptionMessage(reader)
|
||||
break
|
||||
case MessageCodes.ParameterDescriptionMessage:
|
||||
message = parseParameterDescriptionMessage(reader)
|
||||
break
|
||||
case MessageCodes.CopyIn:
|
||||
message = parseCopyInMessage(reader)
|
||||
break
|
||||
case MessageCodes.CopyOut:
|
||||
message = parseCopyOutMessage(reader)
|
||||
break
|
||||
case MessageCodes.CopyData:
|
||||
message = parseCopyData(reader, length)
|
||||
break
|
||||
default:
|
||||
return new DatabaseError('received invalid response: ' + code.toString(16), length, 'error')
|
||||
}
|
||||
|
||||
reader.setBuffer(0, emptyBuffer)
|
||||
|
||||
message.length = length
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
||||
const parseReadyForQueryMessage = (reader: BufferReader) => {
|
||||
const status = reader.string(1)
|
||||
return new ReadyForQueryMessage(LATEINIT_LENGTH, status)
|
||||
}
|
||||
|
||||
const parseCommandCompleteMessage = (reader: BufferReader) => {
|
||||
const text = reader.cstring()
|
||||
return new CommandCompleteMessage(LATEINIT_LENGTH, text)
|
||||
}
|
||||
|
||||
const parseCopyData = (reader: BufferReader, length: number) => {
|
||||
const chunk = reader.bytes(length - 4)
|
||||
return new CopyDataMessage(LATEINIT_LENGTH, chunk)
|
||||
}
|
||||
|
||||
const parseCopyInMessage = (reader: BufferReader) => parseCopyMessage(reader, 'copyInResponse')
|
||||
|
||||
const parseCopyOutMessage = (reader: BufferReader) => parseCopyMessage(reader, 'copyOutResponse')
|
||||
|
||||
const parseCopyMessage = (reader: BufferReader, messageName: MessageName) => {
|
||||
const isBinary = reader.byte() !== 0
|
||||
const columnCount = reader.int16()
|
||||
const message = new CopyResponse(LATEINIT_LENGTH, messageName, isBinary, columnCount)
|
||||
for (let i = 0; i < columnCount; i++) {
|
||||
message.columnTypes[i] = reader.int16()
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
const parseNotificationMessage = (reader: BufferReader) => {
|
||||
const processId = reader.int32()
|
||||
const channel = reader.cstring()
|
||||
const payload = reader.cstring()
|
||||
return new NotificationResponseMessage(LATEINIT_LENGTH, processId, channel, payload)
|
||||
}
|
||||
|
||||
const parseRowDescriptionMessage = (reader: BufferReader) => {
|
||||
const fieldCount = reader.int16()
|
||||
const message = new RowDescriptionMessage(LATEINIT_LENGTH, fieldCount)
|
||||
for (let i = 0; i < fieldCount; i++) {
|
||||
message.fields[i] = parseField(reader)
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
const parseField = (reader: BufferReader) => {
|
||||
const name = reader.cstring()
|
||||
const tableID = reader.uint32()
|
||||
const columnID = reader.int16()
|
||||
const dataTypeID = reader.uint32()
|
||||
const dataTypeSize = reader.int16()
|
||||
const dataTypeModifier = reader.int32()
|
||||
const mode = reader.int16() === 0 ? 'text' : 'binary'
|
||||
return new Field(name, tableID, columnID, dataTypeID, dataTypeSize, dataTypeModifier, mode)
|
||||
}
|
||||
|
||||
const parseParameterDescriptionMessage = (reader: BufferReader) => {
|
||||
const parameterCount = reader.int16()
|
||||
const message = new ParameterDescriptionMessage(LATEINIT_LENGTH, parameterCount)
|
||||
for (let i = 0; i < parameterCount; i++) {
|
||||
// OIDs are unsigned, same as dataTypeID in parseField above
|
||||
message.dataTypeIDs[i] = reader.uint32()
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
const parseDataRowMessage = (reader: BufferReader) => {
|
||||
const fieldCount = reader.int16()
|
||||
const fields: any[] = new Array(fieldCount)
|
||||
for (let i = 0; i < fieldCount; i++) {
|
||||
const len = reader.int32()
|
||||
// a -1 for length means the value of the field is null
|
||||
fields[i] = len === -1 ? null : reader.string(len)
|
||||
}
|
||||
return new DataRowMessage(LATEINIT_LENGTH, fields)
|
||||
}
|
||||
|
||||
const parseParameterStatusMessage = (reader: BufferReader) => {
|
||||
const name = reader.cstring()
|
||||
const value = reader.cstring()
|
||||
return new ParameterStatusMessage(LATEINIT_LENGTH, name, value)
|
||||
}
|
||||
|
||||
const parseBackendKeyData = (reader: BufferReader) => {
|
||||
const processID = reader.int32()
|
||||
const secretKey = reader.int32()
|
||||
return new BackendKeyDataMessage(LATEINIT_LENGTH, processID, secretKey)
|
||||
}
|
||||
|
||||
const parseAuthenticationResponse = (reader: BufferReader, length: number) => {
|
||||
const code = reader.int32()
|
||||
// TODO(bmc): maybe better types here
|
||||
const message: BackendMessage & any = {
|
||||
name: 'authenticationOk',
|
||||
length,
|
||||
}
|
||||
|
||||
switch (code) {
|
||||
case 0: // AuthenticationOk
|
||||
break
|
||||
case 3: // AuthenticationCleartextPassword
|
||||
if (message.length === 8) {
|
||||
message.name = 'authenticationCleartextPassword'
|
||||
}
|
||||
break
|
||||
case 5: // AuthenticationMD5Password
|
||||
if (message.length === 12) {
|
||||
message.name = 'authenticationMD5Password'
|
||||
const salt = reader.bytes(4)
|
||||
return new AuthenticationMD5Password(LATEINIT_LENGTH, salt)
|
||||
}
|
||||
break
|
||||
case 10: // AuthenticationSASL
|
||||
{
|
||||
message.name = 'authenticationSASL'
|
||||
message.mechanisms = []
|
||||
let mechanism: string
|
||||
do {
|
||||
mechanism = reader.cstring()
|
||||
if (mechanism) {
|
||||
message.mechanisms.push(mechanism)
|
||||
}
|
||||
} while (mechanism)
|
||||
}
|
||||
break
|
||||
case 11: // AuthenticationSASLContinue
|
||||
message.name = 'authenticationSASLContinue'
|
||||
message.data = reader.string(length - 8)
|
||||
break
|
||||
case 12: // AuthenticationSASLFinal
|
||||
message.name = 'authenticationSASLFinal'
|
||||
message.data = reader.string(length - 8)
|
||||
break
|
||||
default:
|
||||
throw new Error('Unknown authenticationOk message type ' + code)
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
const parseErrorMessage = (reader: BufferReader, name: MessageName) => {
|
||||
const fields: Record<string, string> = {}
|
||||
let fieldType = reader.string(1)
|
||||
while (fieldType !== '\0') {
|
||||
fields[fieldType] = reader.cstring()
|
||||
fieldType = reader.string(1)
|
||||
}
|
||||
|
||||
const messageValue = fields.M
|
||||
|
||||
const message =
|
||||
name === 'notice'
|
||||
? new NoticeMessage(LATEINIT_LENGTH, messageValue)
|
||||
: new DatabaseError(messageValue, LATEINIT_LENGTH, name)
|
||||
|
||||
message.severity = fields.S
|
||||
message.code = fields.C
|
||||
message.detail = fields.D
|
||||
message.hint = fields.H
|
||||
message.position = fields.P
|
||||
message.internalPosition = fields.p
|
||||
message.internalQuery = fields.q
|
||||
message.where = fields.W
|
||||
message.schema = fields.s
|
||||
message.table = fields.t
|
||||
message.column = fields.c
|
||||
message.dataType = fields.d
|
||||
message.constraint = fields.n
|
||||
message.file = fields.F
|
||||
message.line = fields.L
|
||||
message.routine = fields.R
|
||||
return message
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const tsutils = __importStar(require("ts-api-utils"));
|
||||
const ts = __importStar(require("typescript"));
|
||||
const util_1 = require("../util");
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'restrict-plus-operands',
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Require both operands of addition to be the same type and be `bigint`, `number`, or `string`',
|
||||
recommended: {
|
||||
recommended: true,
|
||||
strict: [
|
||||
{
|
||||
allowAny: false,
|
||||
allowBoolean: false,
|
||||
allowNullish: false,
|
||||
allowNumberAndString: false,
|
||||
allowRegExp: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
requiresTypeChecking: true,
|
||||
},
|
||||
messages: {
|
||||
bigintAndNumber: "Numeric '+' operations must either be both bigints or both numbers. Got `{{left}}` + `{{right}}`.",
|
||||
invalid: "Invalid operand for a '+' operation. Operands must each be a number or {{stringLike}}. Got `{{type}}`.",
|
||||
mismatched: "Operands of '+' operations must be a number or {{stringLike}}. Got `{{left}}` + `{{right}}`.",
|
||||
},
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
allowAny: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to allow `any` typed values.',
|
||||
},
|
||||
allowBoolean: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to allow `boolean` typed values.',
|
||||
},
|
||||
allowNullish: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to allow potentially `null` or `undefined` typed values.',
|
||||
},
|
||||
allowNumberAndString: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to allow `bigint`/`number` typed values and `string` typed values to be added together.',
|
||||
},
|
||||
allowRegExp: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to allow `regexp` typed values.',
|
||||
},
|
||||
skipCompoundAssignments: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to skip compound assignments such as `+=`.',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
defaultOptions: [
|
||||
{
|
||||
allowAny: true,
|
||||
allowBoolean: true,
|
||||
allowNullish: true,
|
||||
allowNumberAndString: true,
|
||||
allowRegExp: true,
|
||||
skipCompoundAssignments: false,
|
||||
},
|
||||
],
|
||||
create(context, [{ allowAny, allowBoolean, allowNullish, allowNumberAndString, allowRegExp, skipCompoundAssignments, },]) {
|
||||
const services = (0, util_1.getParserServices)(context);
|
||||
const typeChecker = services.program.getTypeChecker();
|
||||
const stringLikes = [
|
||||
allowAny && '`any`',
|
||||
allowBoolean && '`boolean`',
|
||||
allowNullish && '`null`',
|
||||
allowRegExp && '`RegExp`',
|
||||
allowNullish && '`undefined`',
|
||||
].filter((value) => typeof value === 'string');
|
||||
const stringLike = stringLikes.length
|
||||
? stringLikes.length === 1
|
||||
? `string, allowing a string + ${stringLikes[0]}`
|
||||
: `string, allowing a string + any of: ${stringLikes.join(', ')}`
|
||||
: 'string';
|
||||
function getTypeConstrained(node) {
|
||||
return typeChecker.getBaseTypeOfLiteralType((0, util_1.getConstrainedTypeAtLocation)(services, node));
|
||||
}
|
||||
function checkPlusOperands(node) {
|
||||
const leftType = getTypeConstrained(node.left);
|
||||
const rightType = getTypeConstrained(node.right);
|
||||
if (leftType === rightType &&
|
||||
tsutils.isTypeFlagSet(leftType, ts.TypeFlags.BigIntLike |
|
||||
ts.TypeFlags.NumberLike |
|
||||
ts.TypeFlags.StringLike)) {
|
||||
return;
|
||||
}
|
||||
let hadIndividualComplaint = false;
|
||||
for (const [baseNode, baseType, otherType] of [
|
||||
[node.left, leftType, rightType],
|
||||
[node.right, rightType, leftType],
|
||||
]) {
|
||||
if (isTypeFlagSetInUnion(baseType, ts.TypeFlags.ESSymbolLike |
|
||||
ts.TypeFlags.Never |
|
||||
ts.TypeFlags.Unknown) ||
|
||||
(!allowAny && isTypeFlagSetInUnion(baseType, ts.TypeFlags.Any)) ||
|
||||
(!allowBoolean &&
|
||||
isTypeFlagSetInUnion(baseType, ts.TypeFlags.BooleanLike)) ||
|
||||
(!allowNullish &&
|
||||
(0, util_1.isTypeFlagSet)(baseType, ts.TypeFlags.Null | ts.TypeFlags.Undefined))) {
|
||||
context.report({
|
||||
node: baseNode,
|
||||
messageId: 'invalid',
|
||||
data: {
|
||||
type: typeChecker.typeToString(baseType),
|
||||
stringLike,
|
||||
},
|
||||
});
|
||||
hadIndividualComplaint = true;
|
||||
continue;
|
||||
}
|
||||
// RegExps also contain ts.TypeFlags.Any & ts.TypeFlags.Object
|
||||
for (const subBaseType of tsutils.unionConstituents(baseType)) {
|
||||
const typeName = (0, util_1.getTypeName)(typeChecker, subBaseType);
|
||||
if (typeName === 'RegExp'
|
||||
? !allowRegExp ||
|
||||
tsutils.isTypeFlagSet(otherType, ts.TypeFlags.NumberLike)
|
||||
: (!allowAny && (0, util_1.isTypeAnyType)(subBaseType)) ||
|
||||
isDeeplyObjectType(subBaseType)) {
|
||||
context.report({
|
||||
node: baseNode,
|
||||
messageId: 'invalid',
|
||||
data: {
|
||||
type: typeChecker.typeToString(subBaseType),
|
||||
stringLike,
|
||||
},
|
||||
});
|
||||
hadIndividualComplaint = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hadIndividualComplaint) {
|
||||
return;
|
||||
}
|
||||
for (const [baseType, otherType] of [
|
||||
[leftType, rightType],
|
||||
[rightType, leftType],
|
||||
]) {
|
||||
if (!allowNumberAndString &&
|
||||
isTypeFlagSetInUnion(baseType, ts.TypeFlags.StringLike) &&
|
||||
isTypeFlagSetInUnion(otherType, ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike)) {
|
||||
return context.report({
|
||||
node,
|
||||
messageId: 'mismatched',
|
||||
data: {
|
||||
left: typeChecker.typeToString(leftType),
|
||||
right: typeChecker.typeToString(rightType),
|
||||
stringLike,
|
||||
},
|
||||
});
|
||||
}
|
||||
if (isTypeFlagSetInUnion(baseType, ts.TypeFlags.NumberLike) &&
|
||||
isTypeFlagSetInUnion(otherType, ts.TypeFlags.BigIntLike)) {
|
||||
return context.report({
|
||||
node,
|
||||
messageId: 'bigintAndNumber',
|
||||
data: {
|
||||
left: typeChecker.typeToString(leftType),
|
||||
right: typeChecker.typeToString(rightType),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
"BinaryExpression[operator='+']": checkPlusOperands,
|
||||
...(!skipCompoundAssignments && {
|
||||
"AssignmentExpression[operator='+=']"(node) {
|
||||
checkPlusOperands(node);
|
||||
},
|
||||
}),
|
||||
};
|
||||
},
|
||||
});
|
||||
function isDeeplyObjectType(type) {
|
||||
return type.isIntersection()
|
||||
? tsutils.intersectionConstituents(type).every(tsutils.isObjectType)
|
||||
: tsutils.unionConstituents(type).every(tsutils.isObjectType);
|
||||
}
|
||||
function isTypeFlagSetInUnion(type, flag) {
|
||||
return tsutils
|
||||
.unionConstituents(type)
|
||||
.some(subType => tsutils.isTypeFlagSet(subType, flag));
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import type { LibDefinition } from '../variable';
|
||||
export declare const es2020_date: LibDefinition;
|
||||
@@ -0,0 +1,5 @@
|
||||
const file9 = require("./file9.js")
|
||||
|
||||
module.exports = function () {
|
||||
file9()
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import type * as ts from 'typescript/lib/tsserverlibrary';
|
||||
export declare function getParsedConfigFileFromTSServer(tsserver: typeof ts, defaultProject: string, throwOnFailure: boolean, tsconfigRootDir?: string): ts.ParsedCommandLine | undefined;
|
||||
@@ -0,0 +1,52 @@
|
||||
import type RAL from './ral';
|
||||
import { Message } from './messages';
|
||||
export interface FunctionContentEncoder {
|
||||
name: string;
|
||||
encode(input: Uint8Array): Promise<Uint8Array>;
|
||||
}
|
||||
export interface StreamContentEncoder {
|
||||
name: string;
|
||||
create(): RAL.WritableStream;
|
||||
}
|
||||
export type ContentEncoder = FunctionContentEncoder | (FunctionContentEncoder & StreamContentEncoder);
|
||||
export interface FunctionContentDecoder {
|
||||
name: string;
|
||||
decode(buffer: Uint8Array): Promise<Uint8Array>;
|
||||
}
|
||||
export interface StreamContentDecoder {
|
||||
name: string;
|
||||
create(): RAL.WritableStream;
|
||||
}
|
||||
export type ContentDecoder = FunctionContentDecoder | (FunctionContentDecoder & StreamContentDecoder);
|
||||
export interface ContentTypeEncoderOptions {
|
||||
charset: RAL.MessageBufferEncoding;
|
||||
}
|
||||
export interface FunctionContentTypeEncoder {
|
||||
name: string;
|
||||
encode(msg: Message, options: ContentTypeEncoderOptions): Promise<Uint8Array>;
|
||||
}
|
||||
export interface StreamContentTypeEncoder {
|
||||
name: string;
|
||||
create(options: ContentTypeEncoderOptions): RAL.WritableStream;
|
||||
}
|
||||
export type ContentTypeEncoder = FunctionContentTypeEncoder | (FunctionContentTypeEncoder & StreamContentTypeEncoder);
|
||||
export interface ContentTypeDecoderOptions {
|
||||
charset: RAL.MessageBufferEncoding;
|
||||
}
|
||||
export interface FunctionContentTypeDecoder {
|
||||
name: string;
|
||||
decode(buffer: Uint8Array, options: ContentTypeDecoderOptions): Promise<Message>;
|
||||
}
|
||||
export interface StreamContentTypeDecoder {
|
||||
name: string;
|
||||
create(options: ContentTypeDecoderOptions): RAL.WritableStream;
|
||||
}
|
||||
export type ContentTypeDecoder = FunctionContentTypeDecoder | (FunctionContentTypeDecoder & StreamContentTypeDecoder);
|
||||
interface Named {
|
||||
name: string;
|
||||
}
|
||||
export declare namespace Encodings {
|
||||
function getEncodingHeaderValue(encodings: Named[]): string | undefined;
|
||||
function parseEncodingHeaderValue(value: string): string[];
|
||||
}
|
||||
export {};
|
||||
@@ -0,0 +1,10 @@
|
||||
import type { TSESTree } from '../ts-estree';
|
||||
/**
|
||||
* A regular expression to match line terminators.
|
||||
* @see https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#prod-LineTerminator
|
||||
*/
|
||||
export declare const LINEBREAK_MATCHER: RegExp;
|
||||
/**
|
||||
* Determines whether two adjacent tokens are on the same line
|
||||
*/
|
||||
export declare function isTokenOnSameLine(left: TSESTree.Node | TSESTree.Token, right: TSESTree.Node | TSESTree.Token): boolean;
|
||||
@@ -0,0 +1,47 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('node:test')
|
||||
const handleCustomLevelsOpts = require('./handle-custom-levels-opts')
|
||||
|
||||
test('returns a empty object `{}` for undefined parameter', t => {
|
||||
const handledCustomLevel = handleCustomLevelsOpts()
|
||||
t.assert.deepStrictEqual(handledCustomLevel, {})
|
||||
})
|
||||
|
||||
test('returns a empty object `{}` for unknown parameter', t => {
|
||||
const handledCustomLevel = handleCustomLevelsOpts(123)
|
||||
t.assert.deepStrictEqual(handledCustomLevel, {})
|
||||
})
|
||||
|
||||
test('returns a filled object for string parameter', t => {
|
||||
const handledCustomLevel = handleCustomLevelsOpts('ok:10,warn:20,error:35')
|
||||
t.assert.deepStrictEqual(handledCustomLevel, {
|
||||
10: 'OK',
|
||||
20: 'WARN',
|
||||
35: 'ERROR',
|
||||
default: 'USERLVL'
|
||||
})
|
||||
})
|
||||
|
||||
test('returns a filled object for object parameter', t => {
|
||||
const handledCustomLevel = handleCustomLevelsOpts({
|
||||
ok: 10,
|
||||
warn: 20,
|
||||
error: 35
|
||||
})
|
||||
t.assert.deepStrictEqual(handledCustomLevel, {
|
||||
10: 'OK',
|
||||
20: 'WARN',
|
||||
35: 'ERROR',
|
||||
default: 'USERLVL'
|
||||
})
|
||||
})
|
||||
|
||||
test('defaults missing level num to first index', t => {
|
||||
const result = handleCustomLevelsOpts('ok:10,info')
|
||||
t.assert.deepStrictEqual(result, {
|
||||
10: 'OK',
|
||||
1: 'INFO',
|
||||
default: 'USERLVL'
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,40 @@
|
||||
import { w as workerInit } from '../chunks/init-threads.6kl1khcL.js';
|
||||
import { s as setupVmWorker, r as runVmTests } from '../chunks/vm.CXMd5FHa.js';
|
||||
import 'node:worker_threads';
|
||||
import '../chunks/init.k9zZ9sLh.js';
|
||||
import 'node:fs';
|
||||
import 'node:module';
|
||||
import 'node:url';
|
||||
import 'pathe';
|
||||
import 'vite/module-runner';
|
||||
import '../chunks/startVitestModuleRunner.DB-7oCpn.js';
|
||||
import '@vitest/utils/helpers';
|
||||
import '../chunks/modules.BJuCwlRJ.js';
|
||||
import '../chunks/utils.BX5Fg8C4.js';
|
||||
import '@vitest/utils/timers';
|
||||
import '../path.js';
|
||||
import 'node:path';
|
||||
import '../module-evaluator.js';
|
||||
import 'node:vm';
|
||||
import '../chunks/traces.DT5aQ62U.js';
|
||||
import '@vitest/mocker';
|
||||
import '@vitest/mocker/redirect';
|
||||
import '../chunks/index.DC7d2Pf8.js';
|
||||
import 'node:console';
|
||||
import '@vitest/utils/serialize';
|
||||
import '@vitest/utils/error';
|
||||
import 'tinyrainbow';
|
||||
import '../chunks/rpc.MzXet3jl.js';
|
||||
import '../chunks/index.Chj8NDwU.js';
|
||||
import '@vitest/utils/source-map';
|
||||
import '../chunks/inspector.CvyFGlXm.js';
|
||||
import '../chunks/evaluatedModules.Dg1zASAC.js';
|
||||
import '../chunks/console.3WNpx0tS.js';
|
||||
import 'node:stream';
|
||||
import '@vitest/utils/resolver';
|
||||
import '@vitest/utils/constants';
|
||||
|
||||
workerInit({
|
||||
runTests: runVmTests,
|
||||
setup: setupVmWorker
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
import type { LibDefinition } from '../variable';
|
||||
export declare const esnext_intl: LibDefinition;
|
||||
@@ -0,0 +1,43 @@
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
|
||||
/// <reference no-default-lib="true"/>
|
||||
|
||||
/// <reference lib="es2015.symbol" />
|
||||
/// <reference lib="es2015.iterable" />
|
||||
|
||||
interface SymbolConstructor {
|
||||
/**
|
||||
* A method that returns the default async iterator for an object. Called by the semantics of
|
||||
* the for-await-of statement.
|
||||
*/
|
||||
readonly asyncIterator: unique symbol;
|
||||
}
|
||||
|
||||
interface AsyncIterator<T, TReturn = any, TNext = undefined> {
|
||||
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
|
||||
next(...args: [] | [TNext]): Promise<IteratorResult<T, TReturn>>;
|
||||
return?(value?: TReturn | PromiseLike<TReturn>): Promise<IteratorResult<T, TReturn>>;
|
||||
throw?(e?: any): Promise<IteratorResult<T, TReturn>>;
|
||||
}
|
||||
|
||||
interface AsyncIterable<T> {
|
||||
[Symbol.asyncIterator](): AsyncIterator<T>;
|
||||
}
|
||||
|
||||
interface AsyncIterableIterator<T> extends AsyncIterator<T> {
|
||||
[Symbol.asyncIterator](): AsyncIterableIterator<T>;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"symbolFlags.d.ts","sourceRoot":"","sources":["../../src/enums/symbolFlags.ts"],"names":[],"mappings":"AACA,eAAO,IAAI,WAAW,EAAE,GAAG,CAAC"}
|
||||
@@ -0,0 +1,45 @@
|
||||
function _asyncIterator(r) {
|
||||
var n,
|
||||
t,
|
||||
o,
|
||||
e = 2;
|
||||
for ("undefined" != typeof Symbol && (t = Symbol.asyncIterator, o = Symbol.iterator); e--;) {
|
||||
if (t && null != (n = r[t])) return n.call(r);
|
||||
if (o && null != (n = r[o])) return new AsyncFromSyncIterator(n.call(r));
|
||||
t = "@@asyncIterator", o = "@@iterator";
|
||||
}
|
||||
throw new TypeError("Object is not async iterable");
|
||||
}
|
||||
function AsyncFromSyncIterator(r) {
|
||||
function AsyncFromSyncIteratorContinuation(r) {
|
||||
if (Object(r) !== r) return Promise.reject(new TypeError(r + " is not an object."));
|
||||
var n = r.done;
|
||||
return Promise.resolve(r.value).then(function (r) {
|
||||
return {
|
||||
value: r,
|
||||
done: n
|
||||
};
|
||||
});
|
||||
}
|
||||
return AsyncFromSyncIterator = function AsyncFromSyncIterator(r) {
|
||||
this.s = r, this.n = r.next;
|
||||
}, AsyncFromSyncIterator.prototype = {
|
||||
s: null,
|
||||
n: null,
|
||||
next: function next() {
|
||||
return AsyncFromSyncIteratorContinuation(this.n.apply(this.s, arguments));
|
||||
},
|
||||
"return": function _return(r) {
|
||||
var n = this.s["return"];
|
||||
return void 0 === n ? Promise.resolve({
|
||||
value: r,
|
||||
done: !0
|
||||
}) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments));
|
||||
},
|
||||
"throw": function _throw(r) {
|
||||
var n = this.s["return"];
|
||||
return void 0 === n ? Promise.reject(r) : AsyncFromSyncIteratorContinuation(n.apply(this.s, arguments));
|
||||
}
|
||||
}, new AsyncFromSyncIterator(r);
|
||||
}
|
||||
export { _asyncIterator as default };
|
||||
@@ -0,0 +1,214 @@
|
||||
# <img src="./logo.png" alt="bn.js" width="160" height="160" />
|
||||
|
||||
> BigNum in pure javascript
|
||||
|
||||
[](http://travis-ci.org/indutny/bn.js)
|
||||
|
||||
## Install
|
||||
`npm install --save bn.js`
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const BN = require('bn.js');
|
||||
|
||||
var a = new BN('dead', 16);
|
||||
var b = new BN('101010', 2);
|
||||
|
||||
var res = a.add(b);
|
||||
console.log(res.toString(10)); // 57047
|
||||
```
|
||||
|
||||
**Note**: decimals are not supported in this library.
|
||||
|
||||
## Sponsors
|
||||
|
||||
[](https://scoutapm.com/)
|
||||
My Open Source work is supported by [Scout APM](https://scoutapm.com/) and
|
||||
[other sponsors](https://github.com/sponsors/indutny).
|
||||
|
||||
## Notation
|
||||
|
||||
### Prefixes
|
||||
|
||||
There are several prefixes to instructions that affect the way they work. Here
|
||||
is the list of them in the order of appearance in the function name:
|
||||
|
||||
* `i` - perform operation in-place, storing the result in the host object (on
|
||||
which the method was invoked). Might be used to avoid number allocation costs
|
||||
* `u` - unsigned, ignore the sign of operands when performing operation, or
|
||||
always return positive value. Second case applies to reduction operations
|
||||
like `mod()`. In such cases if the result will be negative - modulo will be
|
||||
added to the result to make it positive
|
||||
|
||||
### Postfixes
|
||||
|
||||
* `n` - the argument of the function must be a plain JavaScript
|
||||
Number. Decimals are not supported. The number passed must be smaller than 0x4000000 (67_108_864). Otherwise, an error is thrown.
|
||||
* `rn` - both argument and return value of the function are plain JavaScript
|
||||
Numbers. Decimals are not supported.
|
||||
|
||||
### Examples
|
||||
|
||||
* `a.iadd(b)` - perform addition on `a` and `b`, storing the result in `a`
|
||||
* `a.umod(b)` - reduce `a` modulo `b`, returning positive value
|
||||
* `a.iushln(13)` - shift bits of `a` left by 13
|
||||
|
||||
## Instructions
|
||||
|
||||
Prefixes/postfixes are put in parens at the end of the line. `endian` - could be
|
||||
either `le` (little-endian) or `be` (big-endian).
|
||||
|
||||
### Utilities
|
||||
|
||||
* `a.clone()` - clone number
|
||||
* `a.toString(base, length)` - convert to base-string and pad with zeroes
|
||||
* `a.toNumber()` - convert to Javascript Number (limited to 53 bits)
|
||||
* `a.toJSON()` - convert to JSON compatible hex string (alias of `toString(16)`)
|
||||
* `a.toArray(endian, length)` - convert to byte `Array`, and optionally zero
|
||||
pad to length, throwing if already exceeding
|
||||
* `a.toArrayLike(type, endian, length)` - convert to an instance of `type`,
|
||||
which must behave like an `Array`
|
||||
* `a.toBuffer(endian, length)` - convert to Node.js Buffer (if available). `length` in bytes. For
|
||||
compatibility with browserify and similar tools, use this instead:
|
||||
`a.toArrayLike(Buffer, endian, length)`
|
||||
* `a.bitLength()` - get number of bits occupied
|
||||
* `a.zeroBits()` - return number of less-significant consequent zero bits
|
||||
(example: `1010000` has 4 zero bits)
|
||||
* `a.byteLength()` - return number of bytes occupied
|
||||
* `a.isNeg()` - true if the number is negative
|
||||
* `a.isEven()` - no comments
|
||||
* `a.isOdd()` - no comments
|
||||
* `a.isZero()` - no comments
|
||||
* `a.cmp(b)` - compare numbers and return `-1` (a `<` b), `0` (a `==` b), or `1` (a `>` b)
|
||||
depending on the comparison result (`ucmp`, `cmpn`)
|
||||
* `a.lt(b)` - `a` less than `b` (`n`)
|
||||
* `a.lte(b)` - `a` less than or equals `b` (`n`)
|
||||
* `a.gt(b)` - `a` greater than `b` (`n`)
|
||||
* `a.gte(b)` - `a` greater than or equals `b` (`n`)
|
||||
* `a.eq(b)` - `a` equals `b` (`n`)
|
||||
* `a.toTwos(width)` - convert to two's complement representation, where `width` is bit width
|
||||
* `a.fromTwos(width)` - convert from two's complement representation, where `width` is the bit width
|
||||
* `BN.isBN(object)` - returns true if the supplied `object` is a BN.js instance
|
||||
* `BN.max(a, b)` - return `a` if `a` bigger than `b`
|
||||
* `BN.min(a, b)` - return `a` if `a` less than `b`
|
||||
|
||||
### Arithmetics
|
||||
|
||||
* `a.neg()` - negate sign (`i`)
|
||||
* `a.abs()` - absolute value (`i`)
|
||||
* `a.add(b)` - addition (`i`, `n`, `in`)
|
||||
* `a.sub(b)` - subtraction (`i`, `n`, `in`)
|
||||
* `a.mul(b)` - multiply (`i`, `n`, `in`)
|
||||
* `a.sqr()` - square (`i`)
|
||||
* `a.pow(b)` - raise `a` to the power of `b`
|
||||
* `a.div(b)` - divide (`divn`, `idivn`)
|
||||
* `a.mod(b)` - reduct (`u`, `n`) (but no `umodn`)
|
||||
* `a.divmod(b)` - quotient and modulus obtained by dividing
|
||||
* `a.divRound(b)` - rounded division
|
||||
|
||||
### Bit operations
|
||||
|
||||
* `a.or(b)` - or (`i`, `u`, `iu`)
|
||||
* `a.and(b)` - and (`i`, `u`, `iu`, `andln`) (NOTE: `andln` is going to be replaced
|
||||
with `andn` in future)
|
||||
* `a.xor(b)` - xor (`i`, `u`, `iu`)
|
||||
* `a.setn(b, value)` - set specified bit to `value`
|
||||
* `a.shln(b)` - shift left (`i`, `u`, `iu`)
|
||||
* `a.shrn(b)` - shift right (`i`, `u`, `iu`)
|
||||
* `a.testn(b)` - test if specified bit is set
|
||||
* `a.maskn(b)` - clear bits with indexes higher or equal to `b` (`i`)
|
||||
* `a.bincn(b)` - add `1 << b` to the number
|
||||
* `a.notn(w)` - not (for the width specified by `w`) (`i`)
|
||||
|
||||
### Reduction
|
||||
|
||||
* `a.gcd(b)` - GCD
|
||||
* `a.egcd(b)` - Extended GCD results (`{ a: ..., b: ..., gcd: ... }`)
|
||||
* `a.invm(b)` - inverse `a` modulo `b`
|
||||
|
||||
## Fast reduction
|
||||
|
||||
When doing lots of reductions using the same modulo, it might be beneficial to
|
||||
use some tricks: like [Montgomery multiplication][0], or using special algorithm
|
||||
for [Mersenne Prime][1].
|
||||
|
||||
### Reduction context
|
||||
|
||||
To enable this trick one should create a reduction context:
|
||||
|
||||
```js
|
||||
var red = BN.red(num);
|
||||
```
|
||||
where `num` is just a BN instance.
|
||||
|
||||
Or:
|
||||
|
||||
```js
|
||||
var red = BN.red(primeName);
|
||||
```
|
||||
|
||||
Where `primeName` is either of these [Mersenne Primes][1]:
|
||||
|
||||
* `'k256'`
|
||||
* `'p224'`
|
||||
* `'p192'`
|
||||
* `'p25519'`
|
||||
|
||||
Or:
|
||||
|
||||
```js
|
||||
var red = BN.mont(num);
|
||||
```
|
||||
|
||||
To reduce numbers with [Montgomery trick][0]. `.mont()` is generally faster than
|
||||
`.red(num)`, but slower than `BN.red(primeName)`.
|
||||
|
||||
### Converting numbers
|
||||
|
||||
Before performing anything in reduction context - numbers should be converted
|
||||
to it. Usually, this means that one should:
|
||||
|
||||
* Convert inputs to reducted ones
|
||||
* Operate on them in reduction context
|
||||
* Convert outputs back from the reduction context
|
||||
|
||||
Here is how one may convert numbers to `red`:
|
||||
|
||||
```js
|
||||
var redA = a.toRed(red);
|
||||
```
|
||||
Where `red` is a reduction context created using instructions above
|
||||
|
||||
Here is how to convert them back:
|
||||
|
||||
```js
|
||||
var a = redA.fromRed();
|
||||
```
|
||||
|
||||
### Red instructions
|
||||
|
||||
Most of the instructions from the very start of this readme have their
|
||||
counterparts in red context:
|
||||
|
||||
* `a.redAdd(b)`, `a.redIAdd(b)`
|
||||
* `a.redSub(b)`, `a.redISub(b)`
|
||||
* `a.redShl(num)`
|
||||
* `a.redMul(b)`, `a.redIMul(b)`
|
||||
* `a.redSqr()`, `a.redISqr()`
|
||||
* `a.redSqrt()` - square root modulo reduction context's prime
|
||||
* `a.redInvm()` - modular inverse of the number
|
||||
* `a.redNeg()`
|
||||
* `a.redPow(b)` - modular exponentiation
|
||||
|
||||
### Number Size
|
||||
|
||||
Optimized for elliptic curves that work with 256-bit numbers.
|
||||
There is no limitation on the size of the numbers.
|
||||
|
||||
## LICENSE
|
||||
|
||||
This software is licensed under the MIT License.
|
||||
|
||||
[0]: https://en.wikipedia.org/wiki/Montgomery_modular_multiplication
|
||||
[1]: https://en.wikipedia.org/wiki/Mersenne_prime
|
||||
@@ -0,0 +1,4 @@
|
||||
declare const _default: import("@typescript-eslint/utils/ts-eslint").RuleModule<"shouldBeLast", [], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
@@ -0,0 +1,86 @@
|
||||
'use strict';
|
||||
module.exports = function generate_uniqueItems(it, $keyword, $ruleType) {
|
||||
var out = ' ';
|
||||
var $lvl = it.level;
|
||||
var $dataLvl = it.dataLevel;
|
||||
var $schema = it.schema[$keyword];
|
||||
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
|
||||
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
|
||||
var $breakOnError = !it.opts.allErrors;
|
||||
var $data = 'data' + ($dataLvl || '');
|
||||
var $valid = 'valid' + $lvl;
|
||||
var $isData = it.opts.$data && $schema && $schema.$data,
|
||||
$schemaValue;
|
||||
if ($isData) {
|
||||
out += ' var schema' + ($lvl) + ' = ' + (it.util.getData($schema.$data, $dataLvl, it.dataPathArr)) + '; ';
|
||||
$schemaValue = 'schema' + $lvl;
|
||||
} else {
|
||||
$schemaValue = $schema;
|
||||
}
|
||||
if (($schema || $isData) && it.opts.uniqueItems !== false) {
|
||||
if ($isData) {
|
||||
out += ' var ' + ($valid) + '; if (' + ($schemaValue) + ' === false || ' + ($schemaValue) + ' === undefined) ' + ($valid) + ' = true; else if (typeof ' + ($schemaValue) + ' != \'boolean\') ' + ($valid) + ' = false; else { ';
|
||||
}
|
||||
out += ' var i = ' + ($data) + '.length , ' + ($valid) + ' = true , j; if (i > 1) { ';
|
||||
var $itemType = it.schema.items && it.schema.items.type,
|
||||
$typeIsArray = Array.isArray($itemType);
|
||||
if (!$itemType || $itemType == 'object' || $itemType == 'array' || ($typeIsArray && ($itemType.indexOf('object') >= 0 || $itemType.indexOf('array') >= 0))) {
|
||||
out += ' outer: for (;i--;) { for (j = i; j--;) { if (equal(' + ($data) + '[i], ' + ($data) + '[j])) { ' + ($valid) + ' = false; break outer; } } } ';
|
||||
} else {
|
||||
out += ' var itemIndices = {}, item; for (;i--;) { var item = ' + ($data) + '[i]; ';
|
||||
var $method = 'checkDataType' + ($typeIsArray ? 's' : '');
|
||||
out += ' if (' + (it.util[$method]($itemType, 'item', it.opts.strictNumbers, true)) + ') continue; ';
|
||||
if ($typeIsArray) {
|
||||
out += ' if (typeof item == \'string\') item = \'"\' + item; ';
|
||||
}
|
||||
out += ' if (typeof itemIndices[item] == \'number\') { ' + ($valid) + ' = false; j = itemIndices[item]; break; } itemIndices[item] = i; } ';
|
||||
}
|
||||
out += ' } ';
|
||||
if ($isData) {
|
||||
out += ' } ';
|
||||
}
|
||||
out += ' if (!' + ($valid) + ') { ';
|
||||
var $$outStack = $$outStack || [];
|
||||
$$outStack.push(out);
|
||||
out = ''; /* istanbul ignore else */
|
||||
if (it.createErrors !== false) {
|
||||
out += ' { keyword: \'' + ('uniqueItems') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: { i: i, j: j } ';
|
||||
if (it.opts.messages !== false) {
|
||||
out += ' , message: \'should NOT have duplicate items (items ## \' + j + \' and \' + i + \' are identical)\' ';
|
||||
}
|
||||
if (it.opts.verbose) {
|
||||
out += ' , schema: ';
|
||||
if ($isData) {
|
||||
out += 'validate.schema' + ($schemaPath);
|
||||
} else {
|
||||
out += '' + ($schema);
|
||||
}
|
||||
out += ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
|
||||
}
|
||||
out += ' } ';
|
||||
} else {
|
||||
out += ' {} ';
|
||||
}
|
||||
var __err = out;
|
||||
out = $$outStack.pop();
|
||||
if (!it.compositeRule && $breakOnError) {
|
||||
/* istanbul ignore if */
|
||||
if (it.async) {
|
||||
out += ' throw new ValidationError([' + (__err) + ']); ';
|
||||
} else {
|
||||
out += ' validate.errors = [' + (__err) + ']; return false; ';
|
||||
}
|
||||
} else {
|
||||
out += ' var err = ' + (__err) + '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
|
||||
}
|
||||
out += ' } ';
|
||||
if ($breakOnError) {
|
||||
out += ' else { ';
|
||||
}
|
||||
} else {
|
||||
if ($breakOnError) {
|
||||
out += ' if (true) { ';
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* @fileoverview An object that creates fix commands for rules.
|
||||
* @author Nicholas C. Zakas
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @import { SourceRange } from "@eslint/core";
|
||||
*/
|
||||
|
||||
/* eslint class-methods-use-this: off -- Methods desired on instance */
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// none!
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text at the specified index in the source text.
|
||||
* @param {number} index The 0-based index at which to insert the new text.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
* @private
|
||||
*/
|
||||
function insertTextAt(index, text) {
|
||||
return {
|
||||
range: [index, index],
|
||||
text,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the provided text is a string.
|
||||
* @param {unknown} text The text to validate.
|
||||
* @returns {void}
|
||||
* @throws {TypeError} If `text` is not a string.
|
||||
*/
|
||||
function assertIsString(text) {
|
||||
if (typeof text !== "string") {
|
||||
throw new TypeError("'text' must be a string");
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public Interface
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Creates code fixing commands for rules.
|
||||
*/
|
||||
class RuleFixer {
|
||||
/**
|
||||
* The source code object representing the text to be fixed.
|
||||
* @type {SourceCode}
|
||||
*/
|
||||
#sourceCode;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Object} options The options for the fixer.
|
||||
* @param {SourceCode} options.sourceCode The source code object representing the text to be fixed.
|
||||
*/
|
||||
constructor({ sourceCode }) {
|
||||
this.#sourceCode = sourceCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text after the given node or token.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {ASTNode|Token} nodeOrToken The node or token to insert after.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
* @throws {TypeError} If `text` is not a string.
|
||||
*/
|
||||
insertTextAfter(nodeOrToken, text) {
|
||||
assertIsString(text);
|
||||
|
||||
const range = this.#sourceCode.getRange(nodeOrToken);
|
||||
|
||||
return this.insertTextAfterRange(range, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text after the specified range in the source text.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {SourceRange} range The range to replace, first item is start of range, second
|
||||
* is end of range.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
* @throws {TypeError} If `text` is not a string.
|
||||
*/
|
||||
insertTextAfterRange(range, text) {
|
||||
assertIsString(text);
|
||||
|
||||
return insertTextAt(range[1], text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text before the given node or token.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {ASTNode|Token} nodeOrToken The node or token to insert before.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
* @throws {TypeError} If `text` is not a string.
|
||||
*/
|
||||
insertTextBefore(nodeOrToken, text) {
|
||||
assertIsString(text);
|
||||
|
||||
const range = this.#sourceCode.getRange(nodeOrToken);
|
||||
|
||||
return this.insertTextBeforeRange(range, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that inserts text before the specified range in the source text.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {SourceRange} range The range to replace, first item is start of range, second
|
||||
* is end of range.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
* @throws {TypeError} If `text` is not a string.
|
||||
*/
|
||||
insertTextBeforeRange(range, text) {
|
||||
assertIsString(text);
|
||||
|
||||
return insertTextAt(range[0], text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that replaces text at the node or token.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {ASTNode|Token} nodeOrToken The node or token to remove.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
* @throws {TypeError} If `text` is not a string.
|
||||
*/
|
||||
replaceText(nodeOrToken, text) {
|
||||
assertIsString(text);
|
||||
|
||||
const range = this.#sourceCode.getRange(nodeOrToken);
|
||||
|
||||
return this.replaceTextRange(range, text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that replaces text at the specified range in the source text.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {SourceRange} range The range to replace, first item is start of range, second
|
||||
* is end of range.
|
||||
* @param {string} text The text to insert.
|
||||
* @returns {Object} The fix command.
|
||||
* @throws {TypeError} If `text` is not a string.
|
||||
*/
|
||||
replaceTextRange(range, text) {
|
||||
assertIsString(text);
|
||||
|
||||
return {
|
||||
range,
|
||||
text,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that removes the node or token from the source.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {ASTNode|Token} nodeOrToken The node or token to remove.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
remove(nodeOrToken) {
|
||||
const range = this.#sourceCode.getRange(nodeOrToken);
|
||||
|
||||
return this.removeRange(range);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a fix command that removes the specified range of text from the source.
|
||||
* The fix is not applied until applyFixes() is called.
|
||||
* @param {SourceRange} range The range to remove, first item is start of range, second
|
||||
* is end of range.
|
||||
* @returns {Object} The fix command.
|
||||
*/
|
||||
removeRange(range) {
|
||||
return {
|
||||
range,
|
||||
text: "",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { RuleFixer };
|
||||
@@ -0,0 +1,22 @@
|
||||
import * as core from "../core/index.js";
|
||||
import * as schemas from "./schemas.js";
|
||||
export interface ZodISODateTime extends schemas.ZodStringFormat {
|
||||
_zod: core.$ZodISODateTimeInternals;
|
||||
}
|
||||
export declare const ZodISODateTime: core.$constructor<ZodISODateTime>;
|
||||
export declare function datetime(params?: string | core.$ZodISODateTimeParams): ZodISODateTime;
|
||||
export interface ZodISODate extends schemas.ZodStringFormat {
|
||||
_zod: core.$ZodISODateInternals;
|
||||
}
|
||||
export declare const ZodISODate: core.$constructor<ZodISODate>;
|
||||
export declare function date(params?: string | core.$ZodISODateParams): ZodISODate;
|
||||
export interface ZodISOTime extends schemas.ZodStringFormat {
|
||||
_zod: core.$ZodISOTimeInternals;
|
||||
}
|
||||
export declare const ZodISOTime: core.$constructor<ZodISOTime>;
|
||||
export declare function time(params?: string | core.$ZodISOTimeParams): ZodISOTime;
|
||||
export interface ZodISODuration extends schemas.ZodStringFormat {
|
||||
_zod: core.$ZodISODurationInternals;
|
||||
}
|
||||
export declare const ZodISODuration: core.$constructor<ZodISODuration>;
|
||||
export declare function duration(params?: string | core.$ZodISODurationParams): ZodISODuration;
|
||||
@@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.RuleCreator = RuleCreator;
|
||||
const applyDefault_1 = require("./applyDefault");
|
||||
/**
|
||||
* Creates reusable function to create rules with default options and docs URLs.
|
||||
*
|
||||
* @param urlCreator Creates a documentation URL for a given rule name.
|
||||
* @returns Function to create a rule with the docs URL format.
|
||||
*/
|
||||
function RuleCreator(urlCreator) {
|
||||
// This function will get much easier to call when this is merged https://github.com/Microsoft/TypeScript/pull/26349
|
||||
// TODO - when the above PR lands; add type checking for the context.report `data` property
|
||||
return function createNamedRule({ meta, name, ...rule }) {
|
||||
const ruleWithDocs = createRule({
|
||||
meta: {
|
||||
...meta,
|
||||
docs: {
|
||||
...meta.docs,
|
||||
url: urlCreator(name),
|
||||
},
|
||||
},
|
||||
name,
|
||||
...rule,
|
||||
});
|
||||
return ruleWithDocs;
|
||||
};
|
||||
}
|
||||
function createRule({ create,
|
||||
// Keep accepting deprecated defaultOptions for backward compatibility.
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
defaultOptions, meta, name, }) {
|
||||
const resolvedDefaultOptions = (meta.defaultOptions ??
|
||||
defaultOptions ??
|
||||
[]);
|
||||
return {
|
||||
create(context) {
|
||||
const optionsWithDefault = (0, applyDefault_1.applyDefault)(resolvedDefaultOptions, context.options);
|
||||
return create(context, optionsWithDefault);
|
||||
},
|
||||
defaultOptions,
|
||||
meta,
|
||||
name,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Creates a well-typed TSESLint custom ESLint rule without a docs URL.
|
||||
*
|
||||
* @returns Well-typed TSESLint custom ESLint rule.
|
||||
* @remarks It is generally better to provide a docs URL function to RuleCreator.
|
||||
*/
|
||||
RuleCreator.withoutDocs = function withoutDocs(args) {
|
||||
return createRule(args);
|
||||
};
|
||||
@@ -0,0 +1,692 @@
|
||||
/**
|
||||
* Methods for elliptic curve multiplication by scalars.
|
||||
* Contains wNAF, pippenger.
|
||||
* @module
|
||||
*/
|
||||
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
|
||||
import { bitLen, bitMask, validateObject } from '../utils.ts';
|
||||
import { Field, FpInvertBatch, nLength, validateField, type IField } from './modular.ts';
|
||||
|
||||
const _0n = BigInt(0);
|
||||
const _1n = BigInt(1);
|
||||
|
||||
export type AffinePoint<T> = {
|
||||
x: T;
|
||||
y: T;
|
||||
} & { Z?: never };
|
||||
|
||||
// This was initialy do this way to re-use montgomery ladder in field (add->mul,double->sqr), but
|
||||
// that didn't happen and there is probably not much reason to have separate Group like this?
|
||||
export interface Group<T extends Group<T>> {
|
||||
double(): T;
|
||||
negate(): T;
|
||||
add(other: T): T;
|
||||
subtract(other: T): T;
|
||||
equals(other: T): boolean;
|
||||
multiply(scalar: bigint): T;
|
||||
toAffine?(invertedZ?: any): AffinePoint<any>;
|
||||
}
|
||||
|
||||
// We can't "abstract out" coordinates (X, Y, Z; and T in Edwards): argument names of constructor
|
||||
// are not accessible. See Typescript gh-56093, gh-41594.
|
||||
//
|
||||
// We have to use recursive types, so it will return actual point, not constained `CurvePoint`.
|
||||
// If, at any point, P is `any`, it will erase all types and replace it
|
||||
// with `any`, because of recursion, `any implements CurvePoint`,
|
||||
// but we lose all constrains on methods.
|
||||
|
||||
/** Base interface for all elliptic curve Points. */
|
||||
export interface CurvePoint<F, P extends CurvePoint<F, P>> extends Group<P> {
|
||||
/** Affine x coordinate. Different from projective / extended X coordinate. */
|
||||
x: F;
|
||||
/** Affine y coordinate. Different from projective / extended Y coordinate. */
|
||||
y: F;
|
||||
Z?: F;
|
||||
double(): P;
|
||||
negate(): P;
|
||||
add(other: P): P;
|
||||
subtract(other: P): P;
|
||||
equals(other: P): boolean;
|
||||
multiply(scalar: bigint): P;
|
||||
assertValidity(): void;
|
||||
clearCofactor(): P;
|
||||
is0(): boolean;
|
||||
isTorsionFree(): boolean;
|
||||
isSmallOrder(): boolean;
|
||||
multiplyUnsafe(scalar: bigint): P;
|
||||
/**
|
||||
* Massively speeds up `p.multiply(n)` by using precompute tables (caching). See {@link wNAF}.
|
||||
* @param isLazy calculate cache now. Default (true) ensures it's deferred to first `multiply()`
|
||||
*/
|
||||
precompute(windowSize?: number, isLazy?: boolean): P;
|
||||
/** Converts point to 2D xy affine coordinates */
|
||||
toAffine(invertedZ?: F): AffinePoint<F>;
|
||||
toBytes(): Uint8Array;
|
||||
toHex(): string;
|
||||
}
|
||||
|
||||
/** Base interface for all elliptic curve Point constructors. */
|
||||
export interface CurvePointCons<P extends CurvePoint<any, P>> {
|
||||
[Symbol.hasInstance]: (item: unknown) => boolean;
|
||||
BASE: P;
|
||||
ZERO: P;
|
||||
/** Field for basic curve math */
|
||||
Fp: IField<P_F<P>>;
|
||||
/** Scalar field, for scalars in multiply and others */
|
||||
Fn: IField<bigint>;
|
||||
/** Creates point from x, y. Does NOT validate if the point is valid. Use `.assertValidity()`. */
|
||||
fromAffine(p: AffinePoint<P_F<P>>): P;
|
||||
fromBytes(bytes: Uint8Array): P;
|
||||
fromHex(hex: Uint8Array | string): P;
|
||||
}
|
||||
|
||||
// Type inference helpers: PC - PointConstructor, P - Point, Fp - Field element
|
||||
// Short names, because we use them a lot in result types:
|
||||
// * we can't do 'P = GetCurvePoint<PC>': this is default value and doesn't constrain anything
|
||||
// * we can't do 'type X = GetCurvePoint<PC>': it won't be accesible for arguments/return types
|
||||
// * `CurvePointCons<P extends CurvePoint<any, P>>` constraints from interface definition
|
||||
// won't propagate, if `PC extends CurvePointCons<any>`: the P would be 'any', which is incorrect
|
||||
// * PC could be super specific with super specific P, which implements CurvePoint<any, P>.
|
||||
// this means we need to do stuff like
|
||||
// `function test<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(`
|
||||
// if we want type safety around P, otherwise PC_P<PC> will be any
|
||||
|
||||
/** Returns Fp type from Point (P_F<P> == P.F) */
|
||||
export type P_F<P extends CurvePoint<any, P>> = P extends CurvePoint<infer F, P> ? F : never;
|
||||
/** Returns Fp type from PointCons (PC_F<PC> == PC.P.F) */
|
||||
export type PC_F<PC extends CurvePointCons<CurvePoint<any, any>>> = PC['Fp']['ZERO'];
|
||||
/** Returns Point type from PointCons (PC_P<PC> == PC.P) */
|
||||
export type PC_P<PC extends CurvePointCons<CurvePoint<any, any>>> = PC['ZERO'];
|
||||
|
||||
// Ugly hack to get proper type inference, because in typescript fails to infer resursively.
|
||||
// The hack allows to do up to 10 chained operations without applying type erasure.
|
||||
//
|
||||
// Types which won't work:
|
||||
// * `CurvePointCons<CurvePoint<any, any>>`, will return `any` after 1 operation
|
||||
// * `CurvePointCons<any>: WeierstrassPointCons<bigint> extends CurvePointCons<any> = false`
|
||||
// * `P extends CurvePoint, PC extends CurvePointCons<P>`
|
||||
// * It can't infer P from PC alone
|
||||
// * Too many relations between F, P & PC
|
||||
// * It will infer P/F if `arg: CurvePointCons<F, P>`, but will fail if PC is generic
|
||||
// * It will work correctly if there is an additional argument of type P
|
||||
// * But generally, we don't want to parametrize `CurvePointCons` over `F`: it will complicate
|
||||
// types, making them un-inferable
|
||||
// prettier-ignore
|
||||
export type PC_ANY = CurvePointCons<
|
||||
CurvePoint<any,
|
||||
CurvePoint<any,
|
||||
CurvePoint<any,
|
||||
CurvePoint<any,
|
||||
CurvePoint<any,
|
||||
CurvePoint<any,
|
||||
CurvePoint<any,
|
||||
CurvePoint<any,
|
||||
CurvePoint<any,
|
||||
CurvePoint<any, any>
|
||||
>>>>>>>>>
|
||||
>;
|
||||
|
||||
export interface CurveLengths {
|
||||
secretKey?: number;
|
||||
publicKey?: number;
|
||||
publicKeyUncompressed?: number;
|
||||
publicKeyHasPrefix?: boolean;
|
||||
signature?: number;
|
||||
seed?: number;
|
||||
}
|
||||
export type GroupConstructor<T> = {
|
||||
BASE: T;
|
||||
ZERO: T;
|
||||
};
|
||||
/** @deprecated */
|
||||
export type ExtendedGroupConstructor<T> = GroupConstructor<T> & {
|
||||
Fp: IField<any>;
|
||||
Fn: IField<bigint>;
|
||||
fromAffine(ap: AffinePoint<any>): T;
|
||||
};
|
||||
export type Mapper<T> = (i: T[]) => T[];
|
||||
|
||||
export function negateCt<T extends { negate: () => T }>(condition: boolean, item: T): T {
|
||||
const neg = item.negate();
|
||||
return condition ? neg : item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a bunch of Projective Points but executes only one
|
||||
* inversion on all of them. Inversion is very slow operation,
|
||||
* so this improves performance massively.
|
||||
* Optimization: converts a list of projective points to a list of identical points with Z=1.
|
||||
*/
|
||||
export function normalizeZ<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(
|
||||
c: PC,
|
||||
points: P[]
|
||||
): P[] {
|
||||
const invertedZs = FpInvertBatch(
|
||||
c.Fp,
|
||||
points.map((p) => p.Z!)
|
||||
);
|
||||
return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i])));
|
||||
}
|
||||
|
||||
function validateW(W: number, bits: number) {
|
||||
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
||||
throw new Error('invalid window size, expected [1..' + bits + '], got W=' + W);
|
||||
}
|
||||
|
||||
/** Internal wNAF opts for specific W and scalarBits */
|
||||
export type WOpts = {
|
||||
windows: number;
|
||||
windowSize: number;
|
||||
mask: bigint;
|
||||
maxNumber: number;
|
||||
shiftBy: bigint;
|
||||
};
|
||||
|
||||
function calcWOpts(W: number, scalarBits: number): WOpts {
|
||||
validateW(W, scalarBits);
|
||||
const windows = Math.ceil(scalarBits / W) + 1; // W=8 33. Not 32, because we skip zero
|
||||
const windowSize = 2 ** (W - 1); // W=8 128. Not 256, because we skip zero
|
||||
const maxNumber = 2 ** W; // W=8 256
|
||||
const mask = bitMask(W); // W=8 255 == mask 0b11111111
|
||||
const shiftBy = BigInt(W); // W=8 8
|
||||
return { windows, windowSize, mask, maxNumber, shiftBy };
|
||||
}
|
||||
|
||||
function calcOffsets(n: bigint, window: number, wOpts: WOpts) {
|
||||
const { windowSize, mask, maxNumber, shiftBy } = wOpts;
|
||||
let wbits = Number(n & mask); // extract W bits.
|
||||
let nextN = n >> shiftBy; // shift number by W bits.
|
||||
|
||||
// What actually happens here:
|
||||
// const highestBit = Number(mask ^ (mask >> 1n));
|
||||
// let wbits2 = wbits - 1; // skip zero
|
||||
// if (wbits2 & highestBit) { wbits2 ^= Number(mask); // (~);
|
||||
|
||||
// split if bits > max: +224 => 256-32
|
||||
if (wbits > windowSize) {
|
||||
// we skip zero, which means instead of `>= size-1`, we do `> size`
|
||||
wbits -= maxNumber; // -32, can be maxNumber - wbits, but then we need to set isNeg here.
|
||||
nextN += _1n; // +256 (carry)
|
||||
}
|
||||
const offsetStart = window * windowSize;
|
||||
const offset = offsetStart + Math.abs(wbits) - 1; // -1 because we skip zero
|
||||
const isZero = wbits === 0; // is current window slice a 0?
|
||||
const isNeg = wbits < 0; // is current window slice negative?
|
||||
const isNegF = window % 2 !== 0; // fake random statement for noise
|
||||
const offsetF = offsetStart; // fake offset for noise
|
||||
return { nextN, offset, isZero, isNeg, isNegF, offsetF };
|
||||
}
|
||||
|
||||
function validateMSMPoints(points: any[], c: any) {
|
||||
if (!Array.isArray(points)) throw new Error('array expected');
|
||||
points.forEach((p, i) => {
|
||||
if (!(p instanceof c)) throw new Error('invalid point at index ' + i);
|
||||
});
|
||||
}
|
||||
function validateMSMScalars(scalars: any[], field: any) {
|
||||
if (!Array.isArray(scalars)) throw new Error('array of scalars expected');
|
||||
scalars.forEach((s, i) => {
|
||||
if (!field.isValid(s)) throw new Error('invalid scalar at index ' + i);
|
||||
});
|
||||
}
|
||||
|
||||
// Since points in different groups cannot be equal (different object constructor),
|
||||
// we can have single place to store precomputes.
|
||||
// Allows to make points frozen / immutable.
|
||||
const pointPrecomputes = new WeakMap<any, any[]>();
|
||||
const pointWindowSizes = new WeakMap<any, number>();
|
||||
|
||||
function getW(P: any): number {
|
||||
// To disable precomputes:
|
||||
// return 1;
|
||||
return pointWindowSizes.get(P) || 1;
|
||||
}
|
||||
|
||||
function assert0(n: bigint): void {
|
||||
if (n !== _0n) throw new Error('invalid wNAF');
|
||||
}
|
||||
|
||||
/**
|
||||
* Elliptic curve multiplication of Point by scalar. Fragile.
|
||||
* Table generation takes **30MB of ram and 10ms on high-end CPU**,
|
||||
* but may take much longer on slow devices. Actual generation will happen on
|
||||
* first call of `multiply()`. By default, `BASE` point is precomputed.
|
||||
*
|
||||
* Scalars should always be less than curve order: this should be checked inside of a curve itself.
|
||||
* Creates precomputation tables for fast multiplication:
|
||||
* - private scalar is split by fixed size windows of W bits
|
||||
* - every window point is collected from window's table & added to accumulator
|
||||
* - since windows are different, same point inside tables won't be accessed more than once per calc
|
||||
* - each multiplication is 'Math.ceil(CURVE_ORDER / 𝑊) + 1' point additions (fixed for any scalar)
|
||||
* - +1 window is neccessary for wNAF
|
||||
* - wNAF reduces table size: 2x less memory + 2x faster generation, but 10% slower multiplication
|
||||
*
|
||||
* @todo Research returning 2d JS array of windows, instead of a single window.
|
||||
* This would allow windows to be in different memory locations
|
||||
*/
|
||||
export class wNAF<PC extends PC_ANY> {
|
||||
private readonly BASE: PC_P<PC>;
|
||||
private readonly ZERO: PC_P<PC>;
|
||||
private readonly Fn: PC['Fn'];
|
||||
readonly bits: number;
|
||||
|
||||
// Parametrized with a given Point class (not individual point)
|
||||
constructor(Point: PC, bits: number) {
|
||||
this.BASE = Point.BASE;
|
||||
this.ZERO = Point.ZERO;
|
||||
this.Fn = Point.Fn;
|
||||
this.bits = bits;
|
||||
}
|
||||
|
||||
// non-const time multiplication ladder
|
||||
_unsafeLadder(elm: PC_P<PC>, n: bigint, p: PC_P<PC> = this.ZERO): PC_P<PC> {
|
||||
let d: PC_P<PC> = elm;
|
||||
while (n > _0n) {
|
||||
if (n & _1n) p = p.add(d);
|
||||
d = d.double();
|
||||
n >>= _1n;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a wNAF precomputation window. Used for caching.
|
||||
* Default window size is set by `utils.precompute()` and is equal to 8.
|
||||
* Number of precomputed points depends on the curve size:
|
||||
* 2^(𝑊−1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
|
||||
* - 𝑊 is the window size
|
||||
* - 𝑛 is the bitlength of the curve order.
|
||||
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
|
||||
* @param point Point instance
|
||||
* @param W window size
|
||||
* @returns precomputed point tables flattened to a single array
|
||||
*/
|
||||
private precomputeWindow(point: PC_P<PC>, W: number): PC_P<PC>[] {
|
||||
const { windows, windowSize } = calcWOpts(W, this.bits);
|
||||
const points: PC_P<PC>[] = [];
|
||||
let p: PC_P<PC> = point;
|
||||
let base = p;
|
||||
for (let window = 0; window < windows; window++) {
|
||||
base = p;
|
||||
points.push(base);
|
||||
// i=1, bc we skip 0
|
||||
for (let i = 1; i < windowSize; i++) {
|
||||
base = base.add(p);
|
||||
points.push(base);
|
||||
}
|
||||
p = base.double();
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
|
||||
* More compact implementation:
|
||||
* https://github.com/paulmillr/noble-secp256k1/blob/47cb1669b6e506ad66b35fe7d76132ae97465da2/index.ts#L502-L541
|
||||
* @returns real and fake (for const-time) points
|
||||
*/
|
||||
private wNAF(W: number, precomputes: PC_P<PC>[], n: bigint): { p: PC_P<PC>; f: PC_P<PC> } {
|
||||
// Scalar should be smaller than field order
|
||||
if (!this.Fn.isValid(n)) throw new Error('invalid scalar');
|
||||
// Accumulators
|
||||
let p = this.ZERO;
|
||||
let f = this.BASE;
|
||||
// This code was first written with assumption that 'f' and 'p' will never be infinity point:
|
||||
// since each addition is multiplied by 2 ** W, it cannot cancel each other. However,
|
||||
// there is negate now: it is possible that negated element from low value
|
||||
// would be the same as high element, which will create carry into next window.
|
||||
// It's not obvious how this can fail, but still worth investigating later.
|
||||
const wo = calcWOpts(W, this.bits);
|
||||
for (let window = 0; window < wo.windows; window++) {
|
||||
// (n === _0n) is handled and not early-exited. isEven and offsetF are used for noise
|
||||
const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window, wo);
|
||||
n = nextN;
|
||||
if (isZero) {
|
||||
// bits are 0: add garbage to fake point
|
||||
// Important part for const-time getPublicKey: add random "noise" point to f.
|
||||
f = f.add(negateCt(isNegF, precomputes[offsetF]));
|
||||
} else {
|
||||
// bits are 1: add to result point
|
||||
p = p.add(negateCt(isNeg, precomputes[offset]));
|
||||
}
|
||||
}
|
||||
assert0(n);
|
||||
// Return both real and fake points: JIT won't eliminate f.
|
||||
// At this point there is a way to F be infinity-point even if p is not,
|
||||
// which makes it less const-time: around 1 bigint multiply.
|
||||
return { p, f };
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
|
||||
* @param acc accumulator point to add result of multiplication
|
||||
* @returns point
|
||||
*/
|
||||
private wNAFUnsafe(
|
||||
W: number,
|
||||
precomputes: PC_P<PC>[],
|
||||
n: bigint,
|
||||
acc: PC_P<PC> = this.ZERO
|
||||
): PC_P<PC> {
|
||||
const wo = calcWOpts(W, this.bits);
|
||||
for (let window = 0; window < wo.windows; window++) {
|
||||
if (n === _0n) break; // Early-exit, skip 0 value
|
||||
const { nextN, offset, isZero, isNeg } = calcOffsets(n, window, wo);
|
||||
n = nextN;
|
||||
if (isZero) {
|
||||
// Window bits are 0: skip processing.
|
||||
// Move to next window.
|
||||
continue;
|
||||
} else {
|
||||
const item = precomputes[offset];
|
||||
acc = acc.add(isNeg ? item.negate() : item); // Re-using acc allows to save adds in MSM
|
||||
}
|
||||
}
|
||||
assert0(n);
|
||||
return acc;
|
||||
}
|
||||
|
||||
private getPrecomputes(W: number, point: PC_P<PC>, transform?: Mapper<PC_P<PC>>): PC_P<PC>[] {
|
||||
// Calculate precomputes on a first run, reuse them after
|
||||
let comp = pointPrecomputes.get(point);
|
||||
if (!comp) {
|
||||
comp = this.precomputeWindow(point, W) as PC_P<PC>[];
|
||||
if (W !== 1) {
|
||||
// Doing transform outside of if brings 15% perf hit
|
||||
if (typeof transform === 'function') comp = transform(comp);
|
||||
pointPrecomputes.set(point, comp);
|
||||
}
|
||||
}
|
||||
return comp;
|
||||
}
|
||||
|
||||
cached(
|
||||
point: PC_P<PC>,
|
||||
scalar: bigint,
|
||||
transform?: Mapper<PC_P<PC>>
|
||||
): { p: PC_P<PC>; f: PC_P<PC> } {
|
||||
const W = getW(point);
|
||||
return this.wNAF(W, this.getPrecomputes(W, point, transform), scalar);
|
||||
}
|
||||
|
||||
unsafe(point: PC_P<PC>, scalar: bigint, transform?: Mapper<PC_P<PC>>, prev?: PC_P<PC>): PC_P<PC> {
|
||||
const W = getW(point);
|
||||
if (W === 1) return this._unsafeLadder(point, scalar, prev); // For W=1 ladder is ~x2 faster
|
||||
return this.wNAFUnsafe(W, this.getPrecomputes(W, point, transform), scalar, prev);
|
||||
}
|
||||
|
||||
// We calculate precomputes for elliptic curve point multiplication
|
||||
// using windowed method. This specifies window size and
|
||||
// stores precomputed values. Usually only base point would be precomputed.
|
||||
createCache(P: PC_P<PC>, W: number): void {
|
||||
validateW(W, this.bits);
|
||||
pointWindowSizes.set(P, W);
|
||||
pointPrecomputes.delete(P);
|
||||
}
|
||||
|
||||
hasCache(elm: PC_P<PC>): boolean {
|
||||
return getW(elm) !== 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Endomorphism-specific multiplication for Koblitz curves.
|
||||
* Cost: 128 dbl, 0-256 adds.
|
||||
*/
|
||||
export function mulEndoUnsafe<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(
|
||||
Point: PC,
|
||||
point: P,
|
||||
k1: bigint,
|
||||
k2: bigint
|
||||
): { p1: P; p2: P } {
|
||||
let acc = point;
|
||||
let p1 = Point.ZERO;
|
||||
let p2 = Point.ZERO;
|
||||
while (k1 > _0n || k2 > _0n) {
|
||||
if (k1 & _1n) p1 = p1.add(acc);
|
||||
if (k2 & _1n) p2 = p2.add(acc);
|
||||
acc = acc.double();
|
||||
k1 >>= _1n;
|
||||
k2 >>= _1n;
|
||||
}
|
||||
return { p1, p2 };
|
||||
}
|
||||
|
||||
/**
|
||||
* Pippenger algorithm for multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
||||
* 30x faster vs naive addition on L=4096, 10x faster than precomputes.
|
||||
* For N=254bit, L=1, it does: 1024 ADD + 254 DBL. For L=5: 1536 ADD + 254 DBL.
|
||||
* Algorithmically constant-time (for same L), even when 1 point + scalar, or when scalar = 0.
|
||||
* @param c Curve Point constructor
|
||||
* @param fieldN field over CURVE.N - important that it's not over CURVE.P
|
||||
* @param points array of L curve points
|
||||
* @param scalars array of L scalars (aka secret keys / bigints)
|
||||
*/
|
||||
export function pippenger<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(
|
||||
c: PC,
|
||||
fieldN: IField<bigint>,
|
||||
points: P[],
|
||||
scalars: bigint[]
|
||||
): P {
|
||||
// If we split scalars by some window (let's say 8 bits), every chunk will only
|
||||
// take 256 buckets even if there are 4096 scalars, also re-uses double.
|
||||
// TODO:
|
||||
// - https://eprint.iacr.org/2024/750.pdf
|
||||
// - https://tches.iacr.org/index.php/TCHES/article/view/10287
|
||||
// 0 is accepted in scalars
|
||||
validateMSMPoints(points, c);
|
||||
validateMSMScalars(scalars, fieldN);
|
||||
const plength = points.length;
|
||||
const slength = scalars.length;
|
||||
if (plength !== slength) throw new Error('arrays of points and scalars must have equal length');
|
||||
// if (plength === 0) throw new Error('array must be of length >= 2');
|
||||
const zero = c.ZERO;
|
||||
const wbits = bitLen(BigInt(plength));
|
||||
let windowSize = 1; // bits
|
||||
if (wbits > 12) windowSize = wbits - 3;
|
||||
else if (wbits > 4) windowSize = wbits - 2;
|
||||
else if (wbits > 0) windowSize = 2;
|
||||
const MASK = bitMask(windowSize);
|
||||
const buckets = new Array(Number(MASK) + 1).fill(zero); // +1 for zero array
|
||||
const lastBits = Math.floor((fieldN.BITS - 1) / windowSize) * windowSize;
|
||||
let sum = zero;
|
||||
for (let i = lastBits; i >= 0; i -= windowSize) {
|
||||
buckets.fill(zero);
|
||||
for (let j = 0; j < slength; j++) {
|
||||
const scalar = scalars[j];
|
||||
const wbits = Number((scalar >> BigInt(i)) & MASK);
|
||||
buckets[wbits] = buckets[wbits].add(points[j]);
|
||||
}
|
||||
let resI = zero; // not using this will do small speed-up, but will lose ct
|
||||
// Skip first bucket, because it is zero
|
||||
for (let j = buckets.length - 1, sumI = zero; j > 0; j--) {
|
||||
sumI = sumI.add(buckets[j]);
|
||||
resI = resI.add(sumI);
|
||||
}
|
||||
sum = sum.add(resI);
|
||||
if (i !== 0) for (let j = 0; j < windowSize; j++) sum = sum.double();
|
||||
}
|
||||
return sum as P;
|
||||
}
|
||||
/**
|
||||
* Precomputed multi-scalar multiplication (MSM, Pa + Qb + Rc + ...).
|
||||
* @param c Curve Point constructor
|
||||
* @param fieldN field over CURVE.N - important that it's not over CURVE.P
|
||||
* @param points array of L curve points
|
||||
* @returns function which multiplies points with scaars
|
||||
*/
|
||||
export function precomputeMSMUnsafe<P extends CurvePoint<any, P>, PC extends CurvePointCons<P>>(
|
||||
c: PC,
|
||||
fieldN: IField<bigint>,
|
||||
points: P[],
|
||||
windowSize: number
|
||||
): (scalars: bigint[]) => P {
|
||||
/**
|
||||
* Performance Analysis of Window-based Precomputation
|
||||
*
|
||||
* Base Case (256-bit scalar, 8-bit window):
|
||||
* - Standard precomputation requires:
|
||||
* - 31 additions per scalar × 256 scalars = 7,936 ops
|
||||
* - Plus 255 summary additions = 8,191 total ops
|
||||
* Note: Summary additions can be optimized via accumulator
|
||||
*
|
||||
* Chunked Precomputation Analysis:
|
||||
* - Using 32 chunks requires:
|
||||
* - 255 additions per chunk
|
||||
* - 256 doublings
|
||||
* - Total: (255 × 32) + 256 = 8,416 ops
|
||||
*
|
||||
* Memory Usage Comparison:
|
||||
* Window Size | Standard Points | Chunked Points
|
||||
* ------------|-----------------|---------------
|
||||
* 4-bit | 520 | 15
|
||||
* 8-bit | 4,224 | 255
|
||||
* 10-bit | 13,824 | 1,023
|
||||
* 16-bit | 557,056 | 65,535
|
||||
*
|
||||
* Key Advantages:
|
||||
* 1. Enables larger window sizes due to reduced memory overhead
|
||||
* 2. More efficient for smaller scalar counts:
|
||||
* - 16 chunks: (16 × 255) + 256 = 4,336 ops
|
||||
* - ~2x faster than standard 8,191 ops
|
||||
*
|
||||
* Limitations:
|
||||
* - Not suitable for plain precomputes (requires 256 constant doublings)
|
||||
* - Performance degrades with larger scalar counts:
|
||||
* - Optimal for ~256 scalars
|
||||
* - Less efficient for 4096+ scalars (Pippenger preferred)
|
||||
*/
|
||||
validateW(windowSize, fieldN.BITS);
|
||||
validateMSMPoints(points, c);
|
||||
const zero = c.ZERO;
|
||||
const tableSize = 2 ** windowSize - 1; // table size (without zero)
|
||||
const chunks = Math.ceil(fieldN.BITS / windowSize); // chunks of item
|
||||
const MASK = bitMask(windowSize);
|
||||
const tables = points.map((p: P) => {
|
||||
const res = [];
|
||||
for (let i = 0, acc = p; i < tableSize; i++) {
|
||||
res.push(acc);
|
||||
acc = acc.add(p);
|
||||
}
|
||||
return res;
|
||||
});
|
||||
return (scalars: bigint[]): P => {
|
||||
validateMSMScalars(scalars, fieldN);
|
||||
if (scalars.length > points.length)
|
||||
throw new Error('array of scalars must be smaller than array of points');
|
||||
let res = zero;
|
||||
for (let i = 0; i < chunks; i++) {
|
||||
// No need to double if accumulator is still zero.
|
||||
if (res !== zero) for (let j = 0; j < windowSize; j++) res = res.double();
|
||||
const shiftBy = BigInt(chunks * windowSize - (i + 1) * windowSize);
|
||||
for (let j = 0; j < scalars.length; j++) {
|
||||
const n = scalars[j];
|
||||
const curr = Number((n >> shiftBy) & MASK);
|
||||
if (!curr) continue; // skip zero scalars chunks
|
||||
res = res.add(tables[j][curr - 1]);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: remove
|
||||
/**
|
||||
* Generic BasicCurve interface: works even for polynomial fields (BLS): P, n, h would be ok.
|
||||
* Though generator can be different (Fp2 / Fp6 for BLS).
|
||||
*/
|
||||
export type BasicCurve<T> = {
|
||||
Fp: IField<T>; // Field over which we'll do calculations (Fp)
|
||||
n: bigint; // Curve order, total count of valid points in the field
|
||||
nBitLength?: number; // bit length of curve order
|
||||
nByteLength?: number; // byte length of curve order
|
||||
h: bigint; // cofactor. we can assign default=1, but users will just ignore it w/o validation
|
||||
hEff?: bigint; // Number to multiply to clear cofactor
|
||||
Gx: T; // base point X coordinate
|
||||
Gy: T; // base point Y coordinate
|
||||
allowInfinityPoint?: boolean; // bls12-381 requires it. ZERO point is valid, but invalid pubkey
|
||||
};
|
||||
|
||||
// TODO: remove
|
||||
/** @deprecated */
|
||||
export function validateBasic<FP, T>(
|
||||
curve: BasicCurve<FP> & T
|
||||
): Readonly<
|
||||
{
|
||||
readonly nBitLength: number;
|
||||
readonly nByteLength: number;
|
||||
} & BasicCurve<FP> &
|
||||
T & {
|
||||
p: bigint;
|
||||
}
|
||||
> {
|
||||
validateField(curve.Fp);
|
||||
validateObject(
|
||||
curve,
|
||||
{
|
||||
n: 'bigint',
|
||||
h: 'bigint',
|
||||
Gx: 'field',
|
||||
Gy: 'field',
|
||||
},
|
||||
{
|
||||
nBitLength: 'isSafeInteger',
|
||||
nByteLength: 'isSafeInteger',
|
||||
}
|
||||
);
|
||||
// Set defaults
|
||||
return Object.freeze({
|
||||
...nLength(curve.n, curve.nBitLength),
|
||||
...curve,
|
||||
...{ p: curve.Fp.ORDER },
|
||||
} as const);
|
||||
}
|
||||
|
||||
export type ValidCurveParams<T> = {
|
||||
p: bigint;
|
||||
n: bigint;
|
||||
h: bigint;
|
||||
a: T;
|
||||
b?: T;
|
||||
d?: T;
|
||||
Gx: T;
|
||||
Gy: T;
|
||||
};
|
||||
|
||||
function createField<T>(order: bigint, field?: IField<T>, isLE?: boolean): IField<T> {
|
||||
if (field) {
|
||||
if (field.ORDER !== order) throw new Error('Field.ORDER must match order: Fp == p, Fn == n');
|
||||
validateField(field);
|
||||
return field;
|
||||
} else {
|
||||
return Field(order, { isLE }) as unknown as IField<T>;
|
||||
}
|
||||
}
|
||||
export type FpFn<T> = { Fp: IField<T>; Fn: IField<bigint> };
|
||||
|
||||
/** Validates CURVE opts and creates fields */
|
||||
export function _createCurveFields<T>(
|
||||
type: 'weierstrass' | 'edwards',
|
||||
CURVE: ValidCurveParams<T>,
|
||||
curveOpts: Partial<FpFn<T>> = {},
|
||||
FpFnLE?: boolean
|
||||
): FpFn<T> & { CURVE: ValidCurveParams<T> } {
|
||||
if (FpFnLE === undefined) FpFnLE = type === 'edwards';
|
||||
if (!CURVE || typeof CURVE !== 'object') throw new Error(`expected valid ${type} CURVE object`);
|
||||
for (const p of ['p', 'n', 'h'] as const) {
|
||||
const val = CURVE[p];
|
||||
if (!(typeof val === 'bigint' && val > _0n))
|
||||
throw new Error(`CURVE.${p} must be positive bigint`);
|
||||
}
|
||||
const Fp = createField(CURVE.p, curveOpts.Fp, FpFnLE);
|
||||
const Fn = createField(CURVE.n, curveOpts.Fn, FpFnLE);
|
||||
const _b: 'b' | 'd' = type === 'weierstrass' ? 'b' : 'd';
|
||||
const params = ['Gx', 'Gy', 'a', _b] as const;
|
||||
for (const p of params) {
|
||||
// @ts-ignore
|
||||
if (!Fp.isValid(CURVE[p]))
|
||||
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
|
||||
}
|
||||
CURVE = Object.freeze(Object.assign({}, CURVE));
|
||||
return { CURVE, Fp, Fn };
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* @fileoverview Rule to enforce the position of line comments
|
||||
* @author Alberto Rodríguez
|
||||
* @deprecated in ESLint v9.3.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: "9.3.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: "line-comment-position",
|
||||
url: "https://eslint.style/rules/line-comment-position",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Enforce position of line comments",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/line-comment-position",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
enum: ["above", "beside"],
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
position: {
|
||||
enum: ["above", "beside"],
|
||||
},
|
||||
ignorePattern: {
|
||||
type: "string",
|
||||
},
|
||||
applyDefaultPatterns: {
|
||||
type: "boolean",
|
||||
},
|
||||
applyDefaultIgnorePatterns: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
messages: {
|
||||
above: "Expected comment to be above code.",
|
||||
beside: "Expected comment to be beside code.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const options = context.options[0];
|
||||
|
||||
let above,
|
||||
ignorePattern,
|
||||
applyDefaultIgnorePatterns = true;
|
||||
|
||||
if (!options || typeof options === "string") {
|
||||
above = !options || options === "above";
|
||||
} else {
|
||||
above = !options.position || options.position === "above";
|
||||
ignorePattern = options.ignorePattern;
|
||||
|
||||
if (Object.hasOwn(options, "applyDefaultIgnorePatterns")) {
|
||||
applyDefaultIgnorePatterns = options.applyDefaultIgnorePatterns;
|
||||
} else {
|
||||
applyDefaultIgnorePatterns =
|
||||
options.applyDefaultPatterns !== false;
|
||||
}
|
||||
}
|
||||
|
||||
const defaultIgnoreRegExp = astUtils.COMMENTS_IGNORE_PATTERN;
|
||||
const fallThroughRegExp = /^\s*falls?\s?through/u;
|
||||
const customIgnoreRegExp = new RegExp(ignorePattern, "u");
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
Program() {
|
||||
const comments = sourceCode.getAllComments();
|
||||
|
||||
comments
|
||||
.filter(token => token.type === "Line")
|
||||
.forEach(node => {
|
||||
if (
|
||||
applyDefaultIgnorePatterns &&
|
||||
(defaultIgnoreRegExp.test(node.value) ||
|
||||
fallThroughRegExp.test(node.value))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
ignorePattern &&
|
||||
customIgnoreRegExp.test(node.value)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const previous = sourceCode.getTokenBefore(node, {
|
||||
includeComments: true,
|
||||
});
|
||||
const isOnSameLine =
|
||||
previous &&
|
||||
previous.loc.end.line === node.loc.start.line;
|
||||
|
||||
if (above) {
|
||||
if (isOnSameLine) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "above",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!isOnSameLine) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "beside",
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user