WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
"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 });
|
||||
exports.visitorKeys = void 0;
|
||||
const eslintVisitorKeys = __importStar(require("eslint-visitor-keys"));
|
||||
/*
|
||||
********************************** IMPORTANT NOTE ********************************
|
||||
* *
|
||||
* The key arrays should be sorted in the order in which you would want to visit *
|
||||
* the child keys. *
|
||||
* *
|
||||
* DO NOT SORT THEM ALPHABETICALLY! *
|
||||
* *
|
||||
* They should be sorted in the order that they appear in the source code. *
|
||||
* For example: *
|
||||
* *
|
||||
* class Foo extends Bar { prop: 1 } *
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ClassDeclaration *
|
||||
* ^^^ id ^^^ superClass *
|
||||
* ^^^^^^^^^^^ body *
|
||||
* *
|
||||
* It would be incorrect to provide the visitor keys ['body', 'id', 'superClass'] *
|
||||
* because the body comes AFTER everything else in the source code. *
|
||||
* Instead the correct ordering would be ['id', 'superClass', 'body']. *
|
||||
* *
|
||||
**********************************************************************************
|
||||
*/
|
||||
const SharedVisitorKeys = (() => {
|
||||
const FunctionType = ['typeParameters', 'params', 'returnType'];
|
||||
const AnonymousFunction = [...FunctionType, 'body'];
|
||||
const AbstractPropertyDefinition = [
|
||||
'decorators',
|
||||
'key',
|
||||
'typeAnnotation',
|
||||
];
|
||||
return {
|
||||
AbstractPropertyDefinition: ['decorators', 'key', 'typeAnnotation'],
|
||||
AnonymousFunction,
|
||||
AsExpression: ['expression', 'typeAnnotation'],
|
||||
ClassDeclaration: [
|
||||
'decorators',
|
||||
'id',
|
||||
'typeParameters',
|
||||
'superClass',
|
||||
'superTypeArguments',
|
||||
'implements',
|
||||
'body',
|
||||
],
|
||||
Function: ['id', ...AnonymousFunction],
|
||||
FunctionType,
|
||||
PropertyDefinition: [...AbstractPropertyDefinition, 'value'],
|
||||
};
|
||||
})();
|
||||
const additionalKeys = {
|
||||
AccessorProperty: SharedVisitorKeys.PropertyDefinition,
|
||||
ArrayPattern: ['decorators', 'elements', 'typeAnnotation'],
|
||||
ArrowFunctionExpression: SharedVisitorKeys.AnonymousFunction,
|
||||
AssignmentPattern: ['decorators', 'left', 'right', 'typeAnnotation'],
|
||||
CallExpression: ['callee', 'typeArguments', 'arguments'],
|
||||
ClassDeclaration: SharedVisitorKeys.ClassDeclaration,
|
||||
ClassExpression: SharedVisitorKeys.ClassDeclaration,
|
||||
Decorator: ['expression'],
|
||||
ExportAllDeclaration: ['exported', 'source', 'attributes'],
|
||||
ExportNamedDeclaration: ['declaration', 'specifiers', 'source', 'attributes'],
|
||||
FunctionDeclaration: SharedVisitorKeys.Function,
|
||||
FunctionExpression: SharedVisitorKeys.Function,
|
||||
Identifier: ['decorators', 'typeAnnotation'],
|
||||
ImportAttribute: ['key', 'value'],
|
||||
ImportDeclaration: ['specifiers', 'source', 'attributes'],
|
||||
ImportExpression: ['source', 'options'],
|
||||
JSXClosingFragment: [],
|
||||
JSXOpeningElement: ['name', 'typeArguments', 'attributes'],
|
||||
JSXOpeningFragment: [],
|
||||
JSXSpreadChild: ['expression'],
|
||||
MethodDefinition: ['decorators', 'key', 'value'],
|
||||
NewExpression: ['callee', 'typeArguments', 'arguments'],
|
||||
ObjectPattern: ['decorators', 'properties', 'typeAnnotation'],
|
||||
PropertyDefinition: SharedVisitorKeys.PropertyDefinition,
|
||||
RestElement: ['decorators', 'argument', 'typeAnnotation'],
|
||||
StaticBlock: ['body'],
|
||||
TaggedTemplateExpression: ['tag', 'typeArguments', 'quasi'],
|
||||
TSAbstractAccessorProperty: SharedVisitorKeys.AbstractPropertyDefinition,
|
||||
TSAbstractKeyword: [],
|
||||
TSAbstractMethodDefinition: ['key', 'value'],
|
||||
TSAbstractPropertyDefinition: SharedVisitorKeys.AbstractPropertyDefinition,
|
||||
TSAnyKeyword: [],
|
||||
TSArrayType: ['elementType'],
|
||||
TSAsExpression: SharedVisitorKeys.AsExpression,
|
||||
TSAsyncKeyword: [],
|
||||
TSBigIntKeyword: [],
|
||||
TSBooleanKeyword: [],
|
||||
TSCallSignatureDeclaration: SharedVisitorKeys.FunctionType,
|
||||
TSClassImplements: ['expression', 'typeArguments'],
|
||||
TSConditionalType: ['checkType', 'extendsType', 'trueType', 'falseType'],
|
||||
TSConstructorType: SharedVisitorKeys.FunctionType,
|
||||
TSConstructSignatureDeclaration: SharedVisitorKeys.FunctionType,
|
||||
TSDeclareFunction: SharedVisitorKeys.Function,
|
||||
TSDeclareKeyword: [],
|
||||
TSEmptyBodyFunctionExpression: ['id', ...SharedVisitorKeys.FunctionType],
|
||||
TSEnumBody: ['members'],
|
||||
TSEnumDeclaration: ['id', 'body'],
|
||||
TSEnumMember: ['id', 'initializer'],
|
||||
TSExportAssignment: ['expression'],
|
||||
TSExportKeyword: [],
|
||||
TSExternalModuleReference: ['expression'],
|
||||
TSFunctionType: SharedVisitorKeys.FunctionType,
|
||||
TSImportEqualsDeclaration: ['id', 'moduleReference'],
|
||||
TSImportType: ['source', 'options', 'qualifier', 'typeArguments'],
|
||||
TSIndexedAccessType: ['objectType', 'indexType'],
|
||||
TSIndexSignature: ['parameters', 'typeAnnotation'],
|
||||
TSInferType: ['typeParameter'],
|
||||
TSInstantiationExpression: ['expression', 'typeArguments'],
|
||||
TSInterfaceBody: ['body'],
|
||||
TSInterfaceDeclaration: ['id', 'typeParameters', 'extends', 'body'],
|
||||
TSInterfaceHeritage: ['expression', 'typeArguments'],
|
||||
TSIntersectionType: ['types'],
|
||||
TSIntrinsicKeyword: [],
|
||||
TSLiteralType: ['literal'],
|
||||
TSMappedType: ['key', 'constraint', 'nameType', 'typeAnnotation'],
|
||||
TSMethodSignature: ['key', 'typeParameters', 'params', 'returnType'],
|
||||
TSModuleBlock: ['body'],
|
||||
TSModuleDeclaration: ['id', 'body'],
|
||||
TSNamedTupleMember: ['label', 'elementType'],
|
||||
TSNamespaceExportDeclaration: ['id'],
|
||||
TSNeverKeyword: [],
|
||||
TSNonNullExpression: ['expression'],
|
||||
TSNullKeyword: [],
|
||||
TSNumberKeyword: [],
|
||||
TSObjectKeyword: [],
|
||||
TSOptionalType: ['typeAnnotation'],
|
||||
TSParameterProperty: ['decorators', 'parameter'],
|
||||
TSPrivateKeyword: [],
|
||||
TSPropertySignature: ['key', 'typeAnnotation'],
|
||||
TSProtectedKeyword: [],
|
||||
TSPublicKeyword: [],
|
||||
TSQualifiedName: ['left', 'right'],
|
||||
TSReadonlyKeyword: [],
|
||||
TSRestType: ['typeAnnotation'],
|
||||
TSSatisfiesExpression: SharedVisitorKeys.AsExpression,
|
||||
TSStaticKeyword: [],
|
||||
TSStringKeyword: [],
|
||||
TSSymbolKeyword: [],
|
||||
TSTemplateLiteralType: ['quasis', 'types'],
|
||||
TSThisType: [],
|
||||
TSTupleType: ['elementTypes'],
|
||||
TSTypeAliasDeclaration: ['id', 'typeParameters', 'typeAnnotation'],
|
||||
TSTypeAnnotation: ['typeAnnotation'],
|
||||
TSTypeAssertion: ['typeAnnotation', 'expression'],
|
||||
TSTypeLiteral: ['members'],
|
||||
TSTypeOperator: ['typeAnnotation'],
|
||||
TSTypeParameter: ['name', 'constraint', 'default'],
|
||||
TSTypeParameterDeclaration: ['params'],
|
||||
TSTypeParameterInstantiation: ['params'],
|
||||
TSTypePredicate: ['parameterName', 'typeAnnotation'],
|
||||
TSTypeQuery: ['exprName', 'typeArguments'],
|
||||
TSTypeReference: ['typeName', 'typeArguments'],
|
||||
TSUndefinedKeyword: [],
|
||||
TSUnionType: ['types'],
|
||||
TSUnknownKeyword: [],
|
||||
TSVoidKeyword: [],
|
||||
};
|
||||
exports.visitorKeys = eslintVisitorKeys.unionWith(additionalKeys);
|
||||
@@ -0,0 +1,107 @@
|
||||
import * as util from "../core/util.js";
|
||||
const error = () => {
|
||||
const Sizable = {
|
||||
string: { unit: "文字", verb: "である" },
|
||||
file: { unit: "バイト", verb: "である" },
|
||||
array: { unit: "要素", verb: "である" },
|
||||
set: { unit: "要素", verb: "である" },
|
||||
};
|
||||
function getSizing(origin) {
|
||||
return Sizable[origin] ?? null;
|
||||
}
|
||||
const FormatDictionary = {
|
||||
regex: "入力値",
|
||||
email: "メールアドレス",
|
||||
url: "URL",
|
||||
emoji: "絵文字",
|
||||
uuid: "UUID",
|
||||
uuidv4: "UUIDv4",
|
||||
uuidv6: "UUIDv6",
|
||||
nanoid: "nanoid",
|
||||
guid: "GUID",
|
||||
cuid: "cuid",
|
||||
cuid2: "cuid2",
|
||||
ulid: "ULID",
|
||||
xid: "XID",
|
||||
ksuid: "KSUID",
|
||||
datetime: "ISO日時",
|
||||
date: "ISO日付",
|
||||
time: "ISO時刻",
|
||||
duration: "ISO期間",
|
||||
ipv4: "IPv4アドレス",
|
||||
ipv6: "IPv6アドレス",
|
||||
cidrv4: "IPv4範囲",
|
||||
cidrv6: "IPv6範囲",
|
||||
base64: "base64エンコード文字列",
|
||||
base64url: "base64urlエンコード文字列",
|
||||
json_string: "JSON文字列",
|
||||
e164: "E.164番号",
|
||||
jwt: "JWT",
|
||||
template_literal: "入力値",
|
||||
};
|
||||
const TypeDictionary = {
|
||||
nan: "NaN",
|
||||
number: "数値",
|
||||
array: "配列",
|
||||
};
|
||||
return (issue) => {
|
||||
switch (issue.code) {
|
||||
case "invalid_type": {
|
||||
const expected = TypeDictionary[issue.expected] ?? issue.expected;
|
||||
const receivedType = util.parsedType(issue.input);
|
||||
const received = TypeDictionary[receivedType] ?? receivedType;
|
||||
if (/^[A-Z]/.test(issue.expected)) {
|
||||
return `無効な入力: instanceof ${issue.expected}が期待されましたが、${received}が入力されました`;
|
||||
}
|
||||
return `無効な入力: ${expected}が期待されましたが、${received}が入力されました`;
|
||||
}
|
||||
case "invalid_value":
|
||||
if (issue.values.length === 1)
|
||||
return `無効な入力: ${util.stringifyPrimitive(issue.values[0])}が期待されました`;
|
||||
return `無効な選択: ${util.joinValues(issue.values, "、")}のいずれかである必要があります`;
|
||||
case "too_big": {
|
||||
const adj = issue.inclusive ? "以下である" : "より小さい";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing)
|
||||
return `大きすぎる値: ${issue.origin ?? "値"}は${issue.maximum.toString()}${sizing.unit ?? "要素"}${adj}必要があります`;
|
||||
return `大きすぎる値: ${issue.origin ?? "値"}は${issue.maximum.toString()}${adj}必要があります`;
|
||||
}
|
||||
case "too_small": {
|
||||
const adj = issue.inclusive ? "以上である" : "より大きい";
|
||||
const sizing = getSizing(issue.origin);
|
||||
if (sizing)
|
||||
return `小さすぎる値: ${issue.origin}は${issue.minimum.toString()}${sizing.unit}${adj}必要があります`;
|
||||
return `小さすぎる値: ${issue.origin}は${issue.minimum.toString()}${adj}必要があります`;
|
||||
}
|
||||
case "invalid_format": {
|
||||
const _issue = issue;
|
||||
if (_issue.format === "starts_with")
|
||||
return `無効な文字列: "${_issue.prefix}"で始まる必要があります`;
|
||||
if (_issue.format === "ends_with")
|
||||
return `無効な文字列: "${_issue.suffix}"で終わる必要があります`;
|
||||
if (_issue.format === "includes")
|
||||
return `無効な文字列: "${_issue.includes}"を含む必要があります`;
|
||||
if (_issue.format === "regex")
|
||||
return `無効な文字列: パターン${_issue.pattern}に一致する必要があります`;
|
||||
return `無効な${FormatDictionary[_issue.format] ?? issue.format}`;
|
||||
}
|
||||
case "not_multiple_of":
|
||||
return `無効な数値: ${issue.divisor}の倍数である必要があります`;
|
||||
case "unrecognized_keys":
|
||||
return `認識されていないキー${issue.keys.length > 1 ? "群" : ""}: ${util.joinValues(issue.keys, "、")}`;
|
||||
case "invalid_key":
|
||||
return `${issue.origin}内の無効なキー`;
|
||||
case "invalid_union":
|
||||
return "無効な入力";
|
||||
case "invalid_element":
|
||||
return `${issue.origin}内の無効な値`;
|
||||
default:
|
||||
return `無効な入力`;
|
||||
}
|
||||
};
|
||||
};
|
||||
export default function () {
|
||||
return {
|
||||
localeError: error(),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag when a function has too many parameters
|
||||
* @author Ilya Volodin
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const { upperCaseFirst } = require("../shared/string-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Enforce a maximum number of parameters in function definitions",
|
||||
dialects: ["JavaScript", "TypeScript"],
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/max-params",
|
||||
},
|
||||
|
||||
schema: [
|
||||
{
|
||||
oneOf: [
|
||||
{
|
||||
type: "integer",
|
||||
minimum: 0,
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
maximum: {
|
||||
type: "integer",
|
||||
minimum: 0,
|
||||
},
|
||||
max: {
|
||||
type: "integer",
|
||||
minimum: 0,
|
||||
},
|
||||
countVoidThis: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Whether to count a `this` declaration when the type is `void`.",
|
||||
},
|
||||
countThis: {
|
||||
enum: ["never", "except-void", "always"],
|
||||
description:
|
||||
"Whether to count a `this` declaration.",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
not: { required: ["countVoidThis", "countThis"] },
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
defaultOptions: [3],
|
||||
|
||||
messages: {
|
||||
exceed: "{{name}} has too many parameters ({{count}}). Maximum allowed is {{max}}.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
const option = context.options[0];
|
||||
let numParams = 3;
|
||||
let countThis = "except-void";
|
||||
|
||||
if (typeof option === "object") {
|
||||
if (
|
||||
Object.hasOwn(option, "maximum") ||
|
||||
Object.hasOwn(option, "max")
|
||||
) {
|
||||
numParams = option.maximum || option.max;
|
||||
}
|
||||
|
||||
countThis = option.countThis;
|
||||
if (!countThis && Object.hasOwn(option, "countVoidThis")) {
|
||||
countThis = option.countVoidThis ? "always" : "except-void";
|
||||
}
|
||||
countThis ||= "except-void";
|
||||
}
|
||||
if (typeof option === "number") {
|
||||
numParams = option;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a function to see if it has too many parameters.
|
||||
* @param {ASTNode} node The node to check.
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
function checkFunction(node) {
|
||||
const thisParam =
|
||||
node.params.length > 0 &&
|
||||
node.params[0].type === "Identifier" &&
|
||||
node.params[0].name === "this"
|
||||
? node.params[0]
|
||||
: null;
|
||||
|
||||
let effectiveParamCount = node.params.length;
|
||||
if (thisParam) {
|
||||
if (countThis === "never") {
|
||||
effectiveParamCount = node.params.length - 1;
|
||||
} else if (
|
||||
countThis === "except-void" &&
|
||||
thisParam.typeAnnotation?.typeAnnotation.type ===
|
||||
"TSVoidKeyword"
|
||||
) {
|
||||
effectiveParamCount = node.params.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (effectiveParamCount > numParams) {
|
||||
context.report({
|
||||
loc: astUtils.getFunctionHeadLoc(node, sourceCode),
|
||||
node,
|
||||
messageId: "exceed",
|
||||
data: {
|
||||
name: upperCaseFirst(
|
||||
astUtils.getFunctionNameWithKind(node),
|
||||
),
|
||||
count: effectiveParamCount,
|
||||
max: numParams,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
FunctionDeclaration: checkFunction,
|
||||
ArrowFunctionExpression: checkFunction,
|
||||
FunctionExpression: checkFunction,
|
||||
TSDeclareFunction: checkFunction,
|
||||
TSFunctionType: checkFunction,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/*! *****************************************************************************
|
||||
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.iterable" />
|
||||
/// <reference lib="es2015.symbol" />
|
||||
|
||||
interface SymbolConstructor {
|
||||
/**
|
||||
* A regular expression method that matches the regular expression against a string. Called
|
||||
* by the String.prototype.matchAll method.
|
||||
*/
|
||||
readonly matchAll: unique symbol;
|
||||
}
|
||||
|
||||
interface RegExp {
|
||||
/**
|
||||
* Matches a string with this regular expression, and returns an iterable of matches
|
||||
* containing the results of that search.
|
||||
* @param string A string to search within.
|
||||
*/
|
||||
[Symbol.matchAll](str: string): IterableIterator<RegExpMatchArray>;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/api/async/types.ts"],"names":[],"mappings":""}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,28 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.addCandidateTSConfigRootDir = addCandidateTSConfigRootDir;
|
||||
exports.clearCandidateTSConfigRootDirs = clearCandidateTSConfigRootDirs;
|
||||
exports.getInferredTSConfigRootDir = getInferredTSConfigRootDir;
|
||||
const candidateTSConfigRootDirs = new Set();
|
||||
function addCandidateTSConfigRootDir(candidate) {
|
||||
candidateTSConfigRootDirs.add(candidate);
|
||||
}
|
||||
function clearCandidateTSConfigRootDirs() {
|
||||
candidateTSConfigRootDirs.clear();
|
||||
}
|
||||
function getInferredTSConfigRootDir() {
|
||||
const entries = [...candidateTSConfigRootDirs];
|
||||
switch (entries.length) {
|
||||
case 0:
|
||||
return process.cwd();
|
||||
case 1:
|
||||
return entries[0];
|
||||
default:
|
||||
throw new Error([
|
||||
'No tsconfigRootDir was set, and multiple candidate TSConfigRootDirs are present:',
|
||||
...entries.map(candidate => ` - ${candidate}`),
|
||||
"You'll need to explicitly set tsconfigRootDir in your parser options.",
|
||||
'See: https://tseslint.com/parser-tsconfigrootdir',
|
||||
].join('\n'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
"use strict";
|
||||
/**
|
||||
* Audited & minimal JS implementation of hash functions, MACs and KDFs. Check out individual modules.
|
||||
* @module
|
||||
* @example
|
||||
```js
|
||||
import {
|
||||
sha256, sha384, sha512, sha224, sha512_224, sha512_256
|
||||
} from '@noble/hashes/sha2';
|
||||
import {
|
||||
sha3_224, sha3_256, sha3_384, sha3_512,
|
||||
keccak_224, keccak_256, keccak_384, keccak_512,
|
||||
shake128, shake256
|
||||
} from '@noble/hashes/sha3';
|
||||
import {
|
||||
cshake128, cshake256,
|
||||
turboshake128, turboshake256,
|
||||
kmac128, kmac256,
|
||||
tuplehash256, parallelhash256,
|
||||
k12, m14, keccakprg
|
||||
} from '@noble/hashes/sha3-addons';
|
||||
import { blake3 } from '@noble/hashes/blake3';
|
||||
import { blake2b, blake2s } from '@noble/hashes/blake2';
|
||||
import { hmac } from '@noble/hashes/hmac';
|
||||
import { hkdf } from '@noble/hashes/hkdf';
|
||||
import { pbkdf2, pbkdf2Async } from '@noble/hashes/pbkdf2';
|
||||
import { scrypt, scryptAsync } from '@noble/hashes/scrypt';
|
||||
import { md5, ripemd160, sha1 } from '@noble/hashes/legacy';
|
||||
import * as utils from '@noble/hashes/utils';
|
||||
```
|
||||
*/
|
||||
throw new Error('root module cannot be imported: import submodules instead. Check out README');
|
||||
//# sourceMappingURL=index.js.map
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "../../cjs/_interop_require_default.cjs",
|
||||
"module": "../../esm/_interop_require_default.js"
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Code generated by Herebyfile.mjs generate:enums from internal/ast/tokenflags.go. DO NOT EDIT.
|
||||
export var TokenFlags;
|
||||
(function (TokenFlags) {
|
||||
TokenFlags[TokenFlags["None"] = 0] = "None";
|
||||
TokenFlags[TokenFlags["PrecedingLineBreak"] = 1] = "PrecedingLineBreak";
|
||||
TokenFlags[TokenFlags["PrecedingJSDocComment"] = 2] = "PrecedingJSDocComment";
|
||||
TokenFlags[TokenFlags["Unterminated"] = 4] = "Unterminated";
|
||||
TokenFlags[TokenFlags["ExtendedUnicodeEscape"] = 8] = "ExtendedUnicodeEscape";
|
||||
TokenFlags[TokenFlags["Scientific"] = 16] = "Scientific";
|
||||
TokenFlags[TokenFlags["Octal"] = 32] = "Octal";
|
||||
TokenFlags[TokenFlags["HexSpecifier"] = 64] = "HexSpecifier";
|
||||
TokenFlags[TokenFlags["BinarySpecifier"] = 128] = "BinarySpecifier";
|
||||
TokenFlags[TokenFlags["OctalSpecifier"] = 256] = "OctalSpecifier";
|
||||
TokenFlags[TokenFlags["ContainsSeparator"] = 512] = "ContainsSeparator";
|
||||
TokenFlags[TokenFlags["UnicodeEscape"] = 1024] = "UnicodeEscape";
|
||||
TokenFlags[TokenFlags["ContainsInvalidEscape"] = 2048] = "ContainsInvalidEscape";
|
||||
TokenFlags[TokenFlags["HexEscape"] = 4096] = "HexEscape";
|
||||
TokenFlags[TokenFlags["ContainsLeadingZero"] = 8192] = "ContainsLeadingZero";
|
||||
TokenFlags[TokenFlags["ContainsInvalidSeparator"] = 16384] = "ContainsInvalidSeparator";
|
||||
TokenFlags[TokenFlags["PrecedingJSDocLeadingAsterisks"] = 32768] = "PrecedingJSDocLeadingAsterisks";
|
||||
TokenFlags[TokenFlags["SingleQuote"] = 65536] = "SingleQuote";
|
||||
TokenFlags[TokenFlags["PrecedingJSDocWithDeprecated"] = 131072] = "PrecedingJSDocWithDeprecated";
|
||||
TokenFlags[TokenFlags["PrecedingJSDocWithSeeOrLink"] = 262144] = "PrecedingJSDocWithSeeOrLink";
|
||||
TokenFlags[TokenFlags["BinaryOrOctalSpecifier"] = 384] = "BinaryOrOctalSpecifier";
|
||||
TokenFlags[TokenFlags["WithSpecifier"] = 448] = "WithSpecifier";
|
||||
TokenFlags[TokenFlags["StringLiteralFlags"] = 72716] = "StringLiteralFlags";
|
||||
TokenFlags[TokenFlags["NumericLiteralFlags"] = 25584] = "NumericLiteralFlags";
|
||||
TokenFlags[TokenFlags["TemplateLiteralLikeFlags"] = 7180] = "TemplateLiteralLikeFlags";
|
||||
TokenFlags[TokenFlags["RegularExpressionLiteralFlags"] = 4] = "RegularExpressionLiteralFlags";
|
||||
TokenFlags[TokenFlags["IsInvalid"] = 26656] = "IsInvalid";
|
||||
})(TokenFlags || (TokenFlags = {}));
|
||||
//# sourceMappingURL=tokenFlags.enum.js.map
|
||||
@@ -0,0 +1,10 @@
|
||||
function _toSetter(t, e, n) {
|
||||
e || (e = []);
|
||||
var r = e.length++;
|
||||
return Object.defineProperty({}, "_", {
|
||||
set: function set(o) {
|
||||
e[r] = o, t.apply(n, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
export { _toSetter as default };
|
||||
@@ -0,0 +1,355 @@
|
||||
function getDefaultExportFromCjs (x) {
|
||||
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
||||
}
|
||||
|
||||
var eventemitter3 = {exports: {}};
|
||||
|
||||
var hasRequiredEventemitter3;
|
||||
|
||||
function requireEventemitter3 () {
|
||||
if (hasRequiredEventemitter3) return eventemitter3.exports;
|
||||
hasRequiredEventemitter3 = 1;
|
||||
(function (module) {
|
||||
|
||||
var has = Object.prototype.hasOwnProperty
|
||||
, prefix = '~';
|
||||
|
||||
/**
|
||||
* Constructor to create a storage for our `EE` objects.
|
||||
* An `Events` instance is a plain object whose properties are event names.
|
||||
*
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
function Events() {}
|
||||
|
||||
//
|
||||
// We try to not inherit from `Object.prototype`. In some engines creating an
|
||||
// instance in this way is faster than calling `Object.create(null)` directly.
|
||||
// If `Object.create(null)` is not supported we prefix the event names with a
|
||||
// character to make sure that the built-in object properties are not
|
||||
// overridden or used as an attack vector.
|
||||
//
|
||||
if (Object.create) {
|
||||
Events.prototype = Object.create(null);
|
||||
|
||||
//
|
||||
// This hack is needed because the `__proto__` property is still inherited in
|
||||
// some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.
|
||||
//
|
||||
if (!new Events().__proto__) prefix = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Representation of a single event listener.
|
||||
*
|
||||
* @param {Function} fn The listener function.
|
||||
* @param {*} context The context to invoke the listener with.
|
||||
* @param {Boolean} [once=false] Specify if the listener is a one-time listener.
|
||||
* @constructor
|
||||
* @private
|
||||
*/
|
||||
function EE(fn, context, once) {
|
||||
this.fn = fn;
|
||||
this.context = context;
|
||||
this.once = once || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for a given event.
|
||||
*
|
||||
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
|
||||
* @param {(String|Symbol)} event The event name.
|
||||
* @param {Function} fn The listener function.
|
||||
* @param {*} context The context to invoke the listener with.
|
||||
* @param {Boolean} once Specify if the listener is a one-time listener.
|
||||
* @returns {EventEmitter}
|
||||
* @private
|
||||
*/
|
||||
function addListener(emitter, event, fn, context, once) {
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('The listener must be a function');
|
||||
}
|
||||
|
||||
var listener = new EE(fn, context || emitter, once)
|
||||
, evt = prefix ? prefix + event : event;
|
||||
|
||||
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
|
||||
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
|
||||
else emitter._events[evt] = [emitter._events[evt], listener];
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear event by name.
|
||||
*
|
||||
* @param {EventEmitter} emitter Reference to the `EventEmitter` instance.
|
||||
* @param {(String|Symbol)} evt The Event name.
|
||||
* @private
|
||||
*/
|
||||
function clearEvent(emitter, evt) {
|
||||
if (--emitter._eventsCount === 0) emitter._events = new Events();
|
||||
else delete emitter._events[evt];
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal `EventEmitter` interface that is molded against the Node.js
|
||||
* `EventEmitter` interface.
|
||||
*
|
||||
* @constructor
|
||||
* @public
|
||||
*/
|
||||
function EventEmitter() {
|
||||
this._events = new Events();
|
||||
this._eventsCount = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array listing the events for which the emitter has registered
|
||||
* listeners.
|
||||
*
|
||||
* @returns {Array}
|
||||
* @public
|
||||
*/
|
||||
EventEmitter.prototype.eventNames = function eventNames() {
|
||||
var names = []
|
||||
, events
|
||||
, name;
|
||||
|
||||
if (this._eventsCount === 0) return names;
|
||||
|
||||
for (name in (events = this._events)) {
|
||||
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
|
||||
}
|
||||
|
||||
if (Object.getOwnPropertySymbols) {
|
||||
return names.concat(Object.getOwnPropertySymbols(events));
|
||||
}
|
||||
|
||||
return names;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the listeners registered for a given event.
|
||||
*
|
||||
* @param {(String|Symbol)} event The event name.
|
||||
* @returns {Array} The registered listeners.
|
||||
* @public
|
||||
*/
|
||||
EventEmitter.prototype.listeners = function listeners(event) {
|
||||
var evt = prefix ? prefix + event : event
|
||||
, handlers = this._events[evt];
|
||||
|
||||
if (!handlers) return [];
|
||||
if (handlers.fn) return [handlers.fn];
|
||||
|
||||
for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {
|
||||
ee[i] = handlers[i].fn;
|
||||
}
|
||||
|
||||
return ee;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the number of listeners listening to a given event.
|
||||
*
|
||||
* @param {(String|Symbol)} event The event name.
|
||||
* @returns {Number} The number of listeners.
|
||||
* @public
|
||||
*/
|
||||
EventEmitter.prototype.listenerCount = function listenerCount(event) {
|
||||
var evt = prefix ? prefix + event : event
|
||||
, listeners = this._events[evt];
|
||||
|
||||
if (!listeners) return 0;
|
||||
if (listeners.fn) return 1;
|
||||
return listeners.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calls each of the listeners registered for a given event.
|
||||
*
|
||||
* @param {(String|Symbol)} event The event name.
|
||||
* @returns {Boolean} `true` if the event had listeners, else `false`.
|
||||
* @public
|
||||
*/
|
||||
EventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
|
||||
var evt = prefix ? prefix + event : event;
|
||||
|
||||
if (!this._events[evt]) return false;
|
||||
|
||||
var listeners = this._events[evt]
|
||||
, len = arguments.length
|
||||
, args
|
||||
, i;
|
||||
|
||||
if (listeners.fn) {
|
||||
if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);
|
||||
|
||||
switch (len) {
|
||||
case 1: return listeners.fn.call(listeners.context), true;
|
||||
case 2: return listeners.fn.call(listeners.context, a1), true;
|
||||
case 3: return listeners.fn.call(listeners.context, a1, a2), true;
|
||||
case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;
|
||||
case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
|
||||
case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
|
||||
}
|
||||
|
||||
for (i = 1, args = new Array(len -1); i < len; i++) {
|
||||
args[i - 1] = arguments[i];
|
||||
}
|
||||
|
||||
listeners.fn.apply(listeners.context, args);
|
||||
} else {
|
||||
var length = listeners.length
|
||||
, j;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);
|
||||
|
||||
switch (len) {
|
||||
case 1: listeners[i].fn.call(listeners[i].context); break;
|
||||
case 2: listeners[i].fn.call(listeners[i].context, a1); break;
|
||||
case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;
|
||||
case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;
|
||||
default:
|
||||
if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {
|
||||
args[j - 1] = arguments[j];
|
||||
}
|
||||
|
||||
listeners[i].fn.apply(listeners[i].context, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a listener for a given event.
|
||||
*
|
||||
* @param {(String|Symbol)} event The event name.
|
||||
* @param {Function} fn The listener function.
|
||||
* @param {*} [context=this] The context to invoke the listener with.
|
||||
* @returns {EventEmitter} `this`.
|
||||
* @public
|
||||
*/
|
||||
EventEmitter.prototype.on = function on(event, fn, context) {
|
||||
return addListener(this, event, fn, context, false);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a one-time listener for a given event.
|
||||
*
|
||||
* @param {(String|Symbol)} event The event name.
|
||||
* @param {Function} fn The listener function.
|
||||
* @param {*} [context=this] The context to invoke the listener with.
|
||||
* @returns {EventEmitter} `this`.
|
||||
* @public
|
||||
*/
|
||||
EventEmitter.prototype.once = function once(event, fn, context) {
|
||||
return addListener(this, event, fn, context, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the listeners of a given event.
|
||||
*
|
||||
* @param {(String|Symbol)} event The event name.
|
||||
* @param {Function} fn Only remove the listeners that match this function.
|
||||
* @param {*} context Only remove the listeners that have this context.
|
||||
* @param {Boolean} once Only remove one-time listeners.
|
||||
* @returns {EventEmitter} `this`.
|
||||
* @public
|
||||
*/
|
||||
EventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {
|
||||
var evt = prefix ? prefix + event : event;
|
||||
|
||||
if (!this._events[evt]) return this;
|
||||
if (!fn) {
|
||||
clearEvent(this, evt);
|
||||
return this;
|
||||
}
|
||||
|
||||
var listeners = this._events[evt];
|
||||
|
||||
if (listeners.fn) {
|
||||
if (
|
||||
listeners.fn === fn &&
|
||||
(!once || listeners.once) &&
|
||||
(!context || listeners.context === context)
|
||||
) {
|
||||
clearEvent(this, evt);
|
||||
}
|
||||
} else {
|
||||
for (var i = 0, events = [], length = listeners.length; i < length; i++) {
|
||||
if (
|
||||
listeners[i].fn !== fn ||
|
||||
(once && !listeners[i].once) ||
|
||||
(context && listeners[i].context !== context)
|
||||
) {
|
||||
events.push(listeners[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Reset the array, or remove it completely if we have no more listeners.
|
||||
//
|
||||
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
|
||||
else clearEvent(this, evt);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove all listeners, or those of the specified event.
|
||||
*
|
||||
* @param {(String|Symbol)} [event] The event name.
|
||||
* @returns {EventEmitter} `this`.
|
||||
* @public
|
||||
*/
|
||||
EventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {
|
||||
var evt;
|
||||
|
||||
if (event) {
|
||||
evt = prefix ? prefix + event : event;
|
||||
if (this._events[evt]) clearEvent(this, evt);
|
||||
} else {
|
||||
this._events = new Events();
|
||||
this._eventsCount = 0;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
//
|
||||
// Alias methods names because people roll like that.
|
||||
//
|
||||
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
|
||||
EventEmitter.prototype.addListener = EventEmitter.prototype.on;
|
||||
|
||||
//
|
||||
// Expose the prefix.
|
||||
//
|
||||
EventEmitter.prefixed = prefix;
|
||||
|
||||
//
|
||||
// Allow `EventEmitter` to be imported as module namespace.
|
||||
//
|
||||
EventEmitter.EventEmitter = EventEmitter;
|
||||
|
||||
//
|
||||
// Expose the module.
|
||||
//
|
||||
{
|
||||
module.exports = EventEmitter;
|
||||
}
|
||||
} (eventemitter3));
|
||||
return eventemitter3.exports;
|
||||
}
|
||||
|
||||
var eventemitter3Exports = requireEventemitter3();
|
||||
var EventEmitter = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
|
||||
|
||||
export { EventEmitter, EventEmitter as default };
|
||||
@@ -0,0 +1,63 @@
|
||||
// Type definitions for sonic-boom 0.7
|
||||
// Definitions by: Alex Ferrando <https://github.com/alferpal>
|
||||
// Igor Savin <https://github.com/kibertoad>
|
||||
/// <reference types="node"/>
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
export default SonicBoom;
|
||||
export type SonicBoomOpts = {
|
||||
fd?: number | string | symbol
|
||||
dest?: string | number
|
||||
maxLength?: number
|
||||
minLength?: number
|
||||
maxWrite?: number
|
||||
periodicFlush?: number
|
||||
sync?: boolean
|
||||
fsync?: boolean
|
||||
append?: boolean
|
||||
mode?: string | number
|
||||
mkdir?: boolean
|
||||
contentMode?: 'buffer' | 'utf8'
|
||||
retryEAGAIN?: (err: Error, writeBufferLen: number, remainingBufferLen: number) => boolean
|
||||
}
|
||||
|
||||
export class SonicBoom extends EventEmitter {
|
||||
/**
|
||||
* @param [fileDescriptor] File path or numerical file descriptor
|
||||
* relative protocol is enabled. Default: process.stdout
|
||||
* @returns a new sonic-boom instance
|
||||
*/
|
||||
constructor(opts: SonicBoomOpts)
|
||||
|
||||
/**
|
||||
* Writes the string to the file. It will return false to signal the producer to slow down.
|
||||
*/
|
||||
write(string: string): boolean;
|
||||
|
||||
/**
|
||||
* Writes the current buffer to the file if a write was not in progress.
|
||||
* Do nothing if minLength is zero or if it is already writing.
|
||||
*/
|
||||
flush(cb?: (err?: Error) => unknown): void;
|
||||
|
||||
/**
|
||||
* Reopen the file in place, useful for log rotation.
|
||||
*/
|
||||
reopen(fileDescriptor?: string | number): void;
|
||||
|
||||
/**
|
||||
* Flushes the buffered data synchronously. This is a costly operation.
|
||||
*/
|
||||
flushSync(): void;
|
||||
|
||||
/**
|
||||
* Closes the stream, the data will be flushed down asynchronously
|
||||
*/
|
||||
end(): void;
|
||||
|
||||
/**
|
||||
* Closes the stream immediately, the data is not flushed.
|
||||
*/
|
||||
destroy(): void;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"for + if": {
|
||||
"name": "for + if",
|
||||
"browser": "IE 10.0.0 (Windows 7 0.0.0)",
|
||||
"suite": "itar-short",
|
||||
"hz": 267177.37118361465,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.027664987498672043,
|
||||
"rhz": 0.8851453953349694,
|
||||
"sampleSize": 209
|
||||
},
|
||||
"while + if": {
|
||||
"name": "while + if",
|
||||
"browser": "IE 10.0.0 (Windows 7 0.0.0)",
|
||||
"suite": "itar-short",
|
||||
"hz": 240946.1863334928,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.024334312597545857,
|
||||
"rhz": 0.7982427793633902,
|
||||
"sampleSize": 212
|
||||
},
|
||||
"array join": {
|
||||
"name": "array join",
|
||||
"browser": "IE 10.0.0 (Windows 7 0.0.0)",
|
||||
"suite": "itar-short",
|
||||
"hz": 301845.7448818401,
|
||||
"success": true,
|
||||
"fastest": true,
|
||||
"rme": 0.025510367215445445,
|
||||
"rhz": 1,
|
||||
"sampleSize": 211
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,422 @@
|
||||
_I'm transitioning to a full-time open source career. Your support would be greatly appreciated 🙌_
|
||||
<a href="https://polar.sh/tinylibs/subscriptions"><picture><source media="(prefers-color-scheme: dark)" srcset="https://polar.sh/embed/tiers.svg?org=tinylibs&darkmode"><img alt="Subscription Tiers on Polar" src="https://polar.sh/embed/tiers.svg?org=tinylibs"></picture></a>
|
||||
|
||||
# Tinybench 🔎
|
||||
|
||||
[](https://github.com/tinylibs/tinybench/actions/workflows/test.yml)
|
||||
[](https://www.npmjs.com/package/tinybench)
|
||||
|
||||
Benchmark your code easily with Tinybench, a simple, tiny and light-weight `7KB` (`2KB` minified and gzipped)
|
||||
benchmarking library!
|
||||
You can run your benchmarks in multiple JavaScript runtimes, Tinybench is
|
||||
completely based on the Web APIs with proper timing using `process.hrtime` or
|
||||
`performance.now`.
|
||||
|
||||
- Accurate and precise timing based on the environment
|
||||
- `Event` and `EventTarget` compatible events
|
||||
- Statistically analyzed values
|
||||
- Calculated Percentiles
|
||||
- Fully detailed results
|
||||
- No dependencies
|
||||
|
||||
_In case you need more tiny libraries like tinypool or tinyspy, please consider submitting an [RFC](https://github.com/tinylibs/rfcs)_
|
||||
|
||||
## Installing
|
||||
|
||||
```bash
|
||||
$ npm install -D tinybench
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
You can start benchmarking by instantiating the `Bench` class and adding
|
||||
benchmark tasks to it.
|
||||
|
||||
```js
|
||||
import { Bench } from 'tinybench';
|
||||
|
||||
const bench = new Bench({ time: 100 });
|
||||
|
||||
bench
|
||||
.add('faster task', () => {
|
||||
console.log('I am faster')
|
||||
})
|
||||
.add('slower task', async () => {
|
||||
await new Promise(r => setTimeout(r, 1)) // we wait 1ms :)
|
||||
console.log('I am slower')
|
||||
})
|
||||
.todo('unimplemented bench')
|
||||
|
||||
await bench.warmup(); // make results more reliable, ref: https://github.com/tinylibs/tinybench/pull/50
|
||||
await bench.run();
|
||||
|
||||
console.table(bench.table());
|
||||
|
||||
// Output:
|
||||
// ┌─────────┬───────────────┬──────────┬────────────────────┬───────────┬─────────┐
|
||||
// │ (index) │ Task Name │ ops/sec │ Average Time (ns) │ Margin │ Samples │
|
||||
// ├─────────┼───────────────┼──────────┼────────────────────┼───────────┼─────────┤
|
||||
// │ 0 │ 'faster task' │ '41,621' │ 24025.791819761525 │ '±20.50%' │ 4257 │
|
||||
// │ 1 │ 'slower task' │ '828' │ 1207382.7838323202 │ '±7.07%' │ 83 │
|
||||
// └─────────┴───────────────┴──────────┴────────────────────┴───────────┴─────────┘
|
||||
|
||||
console.table(
|
||||
bench.table((task) => ({'Task name': task.name}))
|
||||
);
|
||||
|
||||
// Output:
|
||||
// ┌─────────┬───────────────────────┐
|
||||
// │ (index) │ Task name │
|
||||
// ├─────────┼───────────────────────┤
|
||||
// │ 0 │ 'unimplemented bench' │
|
||||
// └─────────┴───────────────────────┘
|
||||
```
|
||||
|
||||
The `add` method accepts a task name and a task function, so it can benchmark
|
||||
it! This method returns a reference to the Bench instance, so it's possible to
|
||||
use it to create an another task for that instance.
|
||||
|
||||
Note that the task name should always be unique in an instance, because Tinybench stores the tasks based
|
||||
on their names in a `Map`.
|
||||
|
||||
Also note that `tinybench` does not log any result by default. You can extract the relevant stats
|
||||
from `bench.tasks` or any other API after running the benchmark, and process them however you want.
|
||||
|
||||
## Docs
|
||||
|
||||
### `Bench`
|
||||
|
||||
The Benchmark instance for keeping track of the benchmark tasks and controlling
|
||||
them.
|
||||
|
||||
Options:
|
||||
|
||||
```ts
|
||||
export type Options = {
|
||||
/**
|
||||
* time needed for running a benchmark task (milliseconds) @default 500
|
||||
*/
|
||||
time?: number;
|
||||
|
||||
/**
|
||||
* number of times that a task should run if even the time option is finished @default 10
|
||||
*/
|
||||
iterations?: number;
|
||||
|
||||
/**
|
||||
* function to get the current timestamp in milliseconds
|
||||
*/
|
||||
now?: () => number;
|
||||
|
||||
/**
|
||||
* An AbortSignal for aborting the benchmark
|
||||
*/
|
||||
signal?: AbortSignal;
|
||||
|
||||
/**
|
||||
* Throw if a task fails (events will not work if true)
|
||||
*/
|
||||
throws?: boolean;
|
||||
|
||||
/**
|
||||
* warmup time (milliseconds) @default 100ms
|
||||
*/
|
||||
warmupTime?: number;
|
||||
|
||||
/**
|
||||
* warmup iterations @default 5
|
||||
*/
|
||||
warmupIterations?: number;
|
||||
|
||||
/**
|
||||
* setup function to run before each benchmark task (cycle)
|
||||
*/
|
||||
setup?: Hook;
|
||||
|
||||
/**
|
||||
* teardown function to run after each benchmark task (cycle)
|
||||
*/
|
||||
teardown?: Hook;
|
||||
};
|
||||
|
||||
export type Hook = (task: Task, mode: "warmup" | "run") => void | Promise<void>;
|
||||
```
|
||||
|
||||
- `async run()`: run the added tasks that were registered using the `add` method
|
||||
- `async runConcurrently(threshold: number = Infinity, mode: "bench" | "task" = "bench")`: similar to the `run` method but runs concurrently rather than sequentially. See the [Concurrency](#Concurrency) section.
|
||||
- `async warmup()`: warm up the benchmark tasks
|
||||
- `async warmupConcurrently(threshold: number = Infinity, mode: "bench" | "task" = "bench")`: warm up the benchmark tasks concurrently
|
||||
- `reset()`: reset each task and remove its result
|
||||
- `add(name: string, fn: Fn, opts?: FnOpts)`: add a benchmark task to the task map
|
||||
- `Fn`: `() => any | Promise<any>`
|
||||
- `FnOpts`: `{}`: a set of optional functions run during the benchmark lifecycle that can be used to set up or tear down test data or fixtures without affecting the timing of each task
|
||||
- `beforeAll?: () => any | Promise<any>`: invoked once before iterations of `fn` begin
|
||||
- `beforeEach?: () => any | Promise<any>`: invoked before each time `fn` is executed
|
||||
- `afterEach?: () => any | Promise<any>`: invoked after each time `fn` is executed
|
||||
- `afterAll?: () => any | Promise<any>`: invoked once after all iterations of `fn` have finished
|
||||
- `remove(name: string)`: remove a benchmark task from the task map
|
||||
- `table()`: table of the tasks results
|
||||
- `get results(): (TaskResult | undefined)[]`: (getter) tasks results as an array
|
||||
- `get tasks(): Task[]`: (getter) tasks as an array
|
||||
- `getTask(name: string): Task | undefined`: get a task based on the name
|
||||
- `todo(name: string, fn?: Fn, opts: FnOptions)`: add a benchmark todo to the todo map
|
||||
- `get todos(): Task[]`: (getter) tasks todos as an array
|
||||
|
||||
### `Task`
|
||||
|
||||
A class that represents each benchmark task in Tinybench. It keeps track of the
|
||||
results, name, Bench instance, the task function and the number of times the task
|
||||
function has been executed.
|
||||
|
||||
- `constructor(bench: Bench, name: string, fn: Fn, opts: FnOptions = {})`
|
||||
- `bench: Bench`
|
||||
- `name: string`: task name
|
||||
- `fn: Fn`: the task function
|
||||
- `opts: FnOptions`: Task options
|
||||
- `runs: number`: the number of times the task function has been executed
|
||||
- `result?: TaskResult`: the result object
|
||||
- `async run()`: run the current task and write the results in `Task.result` object
|
||||
- `async warmup()`: warm up the current task
|
||||
- `setResult(result: Partial<TaskResult>)`: change the result object values
|
||||
- `reset()`: reset the task to make the `Task.runs` a zero-value and remove the `Task.result` object
|
||||
|
||||
```ts
|
||||
export interface FnOptions {
|
||||
/**
|
||||
* An optional function that is run before iterations of this task begin
|
||||
*/
|
||||
beforeAll?: (this: Task) => void | Promise<void>;
|
||||
|
||||
/**
|
||||
* An optional function that is run before each iteration of this task
|
||||
*/
|
||||
beforeEach?: (this: Task) => void | Promise<void>;
|
||||
|
||||
/**
|
||||
* An optional function that is run after each iteration of this task
|
||||
*/
|
||||
afterEach?: (this: Task) => void | Promise<void>;
|
||||
|
||||
/**
|
||||
* An optional function that is run after all iterations of this task end
|
||||
*/
|
||||
afterAll?: (this: Task) => void | Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
## `TaskResult`
|
||||
|
||||
the benchmark task result object.
|
||||
|
||||
```ts
|
||||
export type TaskResult = {
|
||||
|
||||
/*
|
||||
* the last error that was thrown while running the task
|
||||
*/
|
||||
error?: unknown;
|
||||
|
||||
/**
|
||||
* The amount of time in milliseconds to run the benchmark task (cycle).
|
||||
*/
|
||||
totalTime: number;
|
||||
|
||||
/**
|
||||
* the minimum value in the samples
|
||||
*/
|
||||
min: number;
|
||||
/**
|
||||
* the maximum value in the samples
|
||||
*/
|
||||
max: number;
|
||||
|
||||
/**
|
||||
* the number of operations per second
|
||||
*/
|
||||
hz: number;
|
||||
|
||||
/**
|
||||
* how long each operation takes (ms)
|
||||
*/
|
||||
period: number;
|
||||
|
||||
/**
|
||||
* task samples of each task iteration time (ms)
|
||||
*/
|
||||
samples: number[];
|
||||
|
||||
/**
|
||||
* samples mean/average (estimate of the population mean)
|
||||
*/
|
||||
mean: number;
|
||||
|
||||
/**
|
||||
* samples variance (estimate of the population variance)
|
||||
*/
|
||||
variance: number;
|
||||
|
||||
/**
|
||||
* samples standard deviation (estimate of the population standard deviation)
|
||||
*/
|
||||
sd: number;
|
||||
|
||||
/**
|
||||
* standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean)
|
||||
*/
|
||||
sem: number;
|
||||
|
||||
/**
|
||||
* degrees of freedom
|
||||
*/
|
||||
df: number;
|
||||
|
||||
/**
|
||||
* critical value of the samples
|
||||
*/
|
||||
critical: number;
|
||||
|
||||
/**
|
||||
* margin of error
|
||||
*/
|
||||
moe: number;
|
||||
|
||||
/**
|
||||
* relative margin of error
|
||||
*/
|
||||
rme: number;
|
||||
|
||||
/**
|
||||
* p75 percentile
|
||||
*/
|
||||
p75: number;
|
||||
|
||||
/**
|
||||
* p99 percentile
|
||||
*/
|
||||
p99: number;
|
||||
|
||||
/**
|
||||
* p995 percentile
|
||||
*/
|
||||
p995: number;
|
||||
|
||||
/**
|
||||
* p999 percentile
|
||||
*/
|
||||
p999: number;
|
||||
};
|
||||
```
|
||||
|
||||
### `Events`
|
||||
|
||||
Both the `Task` and `Bench` objects extend the `EventTarget` object, so you can attach listeners to different types of events
|
||||
in each class instance using the universal `addEventListener` and
|
||||
`removeEventListener`.
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Bench events
|
||||
*/
|
||||
export type BenchEvents =
|
||||
| "abort" // when a signal aborts
|
||||
| "complete" // when running a benchmark finishes
|
||||
| "error" // when the benchmark task throws
|
||||
| "reset" // when the reset function gets called
|
||||
| "start" // when running the benchmarks gets started
|
||||
| "warmup" // when the benchmarks start getting warmed up (before start)
|
||||
| "cycle" // when running each benchmark task gets done (cycle)
|
||||
| "add" // when a Task gets added to the Bench
|
||||
| "remove" // when a Task gets removed of the Bench
|
||||
| "todo"; // when a todo Task gets added to the Bench
|
||||
|
||||
/**
|
||||
* task events
|
||||
*/
|
||||
export type TaskEvents =
|
||||
| "abort"
|
||||
| "complete"
|
||||
| "error"
|
||||
| "reset"
|
||||
| "start"
|
||||
| "warmup"
|
||||
| "cycle";
|
||||
```
|
||||
|
||||
For instance:
|
||||
|
||||
```js
|
||||
// runs on each benchmark task's cycle
|
||||
bench.addEventListener("cycle", (e) => {
|
||||
const task = e.task!;
|
||||
});
|
||||
|
||||
// runs only on this benchmark task's cycle
|
||||
task.addEventListener("cycle", (e) => {
|
||||
const task = e.task!;
|
||||
});
|
||||
```
|
||||
|
||||
### `BenchEvent`
|
||||
|
||||
```ts
|
||||
export type BenchEvent = Event & {
|
||||
task: Task | null;
|
||||
};
|
||||
```
|
||||
|
||||
### `process.hrtime`
|
||||
if you want more accurate results for nodejs with `process.hrtime`, then import
|
||||
the `hrtimeNow` function from the library and pass it to the `Bench` options.
|
||||
|
||||
```ts
|
||||
import { hrtimeNow } from 'tinybench';
|
||||
```
|
||||
It may make your benchmarks slower, check #42.
|
||||
|
||||
## Concurrency
|
||||
|
||||
- When `mode` is set to `null` (default), concurrency is disabled.
|
||||
- When `mode` is set to 'task', each task's iterations (calls of a task function) run concurrently.
|
||||
- When `mode` is set to 'bench', different tasks within the bench run concurrently. Concurrent cycles.
|
||||
|
||||
```ts
|
||||
// options way (recommended)
|
||||
bench.threshold = 10 // The maximum number of concurrent tasks to run. Defaults to Infinity.
|
||||
bench.concurrency = "task" // The concurrency mode to determine how tasks are run.
|
||||
// await bench.warmup()
|
||||
await bench.run()
|
||||
|
||||
// standalone method way
|
||||
// await bench.warmupConcurrently(10, "task")
|
||||
await bench.runConcurrently(10, "task") // with runConcurrently, mode is set to 'bench' by default
|
||||
```
|
||||
|
||||
## Prior art
|
||||
|
||||
- [Benchmark.js](https://github.com/bestiejs/benchmark.js)
|
||||
- [Mitata](https://github.com/evanwashere/mitata/)
|
||||
- [Bema](https://github.com/prisma-labs/bema)
|
||||
|
||||
## Authors
|
||||
|
||||
| <a href="https://github.com/Aslemammad"> <img width='150' src="https://avatars.githubusercontent.com/u/37929992?v=4" /><br> Mohammad Bagher </a> |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
|
||||
## Credits
|
||||
|
||||
| <a href="https://github.com/uzlopak"> <img width='150' src="https://avatars.githubusercontent.com/u/5059100?v=4" /><br> Uzlopak </a> | <a href="https://github.com/poyoho"> <img width='150' src="https://avatars.githubusercontent.com/u/36070057?v=4" /><br> poyoho </a> |
|
||||
| ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|
||||
## Contributing
|
||||
|
||||
Feel free to create issues/discussions and then PRs for the project!
|
||||
|
||||
## Sponsors
|
||||
|
||||
Your sponsorship can make a huge difference in continuing our work in open source!
|
||||
|
||||
<p align="center">
|
||||
<a href="https://cdn.jsdelivr.net/gh/aslemammad/static/sponsors.svg">
|
||||
<img src='https://cdn.jsdelivr.net/gh/aslemammad/static/sponsors.svg'/>
|
||||
</a>
|
||||
</p>
|
||||
@@ -0,0 +1,246 @@
|
||||
var Sinon = require("sinon")
|
||||
var stringify = require("..")
|
||||
function jsonify(obj) { return JSON.stringify(obj, null, 2) }
|
||||
|
||||
describe("Stringify", function() {
|
||||
it("must stringify circular objects", function() {
|
||||
var obj = {name: "Alice"}
|
||||
obj.self = obj
|
||||
var json = stringify(obj, null, 2)
|
||||
json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"}))
|
||||
})
|
||||
|
||||
it("must stringify circular objects with intermediaries", function() {
|
||||
var obj = {name: "Alice"}
|
||||
obj.identity = {self: obj}
|
||||
var json = stringify(obj, null, 2)
|
||||
json.must.eql(jsonify({name: "Alice", identity: {self: "[Circular ~]"}}))
|
||||
})
|
||||
|
||||
it("must stringify circular objects deeper", function() {
|
||||
var obj = {name: "Alice", child: {name: "Bob"}}
|
||||
obj.child.self = obj.child
|
||||
|
||||
stringify(obj, null, 2).must.eql(jsonify({
|
||||
name: "Alice",
|
||||
child: {name: "Bob", self: "[Circular ~.child]"}
|
||||
}))
|
||||
})
|
||||
|
||||
it("must stringify circular objects deeper with intermediaries", function() {
|
||||
var obj = {name: "Alice", child: {name: "Bob"}}
|
||||
obj.child.identity = {self: obj.child}
|
||||
|
||||
stringify(obj, null, 2).must.eql(jsonify({
|
||||
name: "Alice",
|
||||
child: {name: "Bob", identity: {self: "[Circular ~.child]"}}
|
||||
}))
|
||||
})
|
||||
|
||||
it("must stringify circular objects in an array", function() {
|
||||
var obj = {name: "Alice"}
|
||||
obj.self = [obj, obj]
|
||||
|
||||
stringify(obj, null, 2).must.eql(jsonify({
|
||||
name: "Alice", self: ["[Circular ~]", "[Circular ~]"]
|
||||
}))
|
||||
})
|
||||
|
||||
it("must stringify circular objects deeper in an array", function() {
|
||||
var obj = {name: "Alice", children: [{name: "Bob"}, {name: "Eve"}]}
|
||||
obj.children[0].self = obj.children[0]
|
||||
obj.children[1].self = obj.children[1]
|
||||
|
||||
stringify(obj, null, 2).must.eql(jsonify({
|
||||
name: "Alice",
|
||||
children: [
|
||||
{name: "Bob", self: "[Circular ~.children.0]"},
|
||||
{name: "Eve", self: "[Circular ~.children.1]"}
|
||||
]
|
||||
}))
|
||||
})
|
||||
|
||||
it("must stringify circular arrays", function() {
|
||||
var obj = []
|
||||
obj.push(obj)
|
||||
obj.push(obj)
|
||||
var json = stringify(obj, null, 2)
|
||||
json.must.eql(jsonify(["[Circular ~]", "[Circular ~]"]))
|
||||
})
|
||||
|
||||
it("must stringify circular arrays with intermediaries", function() {
|
||||
var obj = []
|
||||
obj.push({name: "Alice", self: obj})
|
||||
obj.push({name: "Bob", self: obj})
|
||||
|
||||
stringify(obj, null, 2).must.eql(jsonify([
|
||||
{name: "Alice", self: "[Circular ~]"},
|
||||
{name: "Bob", self: "[Circular ~]"}
|
||||
]))
|
||||
})
|
||||
|
||||
it("must stringify repeated objects in objects", function() {
|
||||
var obj = {}
|
||||
var alice = {name: "Alice"}
|
||||
obj.alice1 = alice
|
||||
obj.alice2 = alice
|
||||
|
||||
stringify(obj, null, 2).must.eql(jsonify({
|
||||
alice1: {name: "Alice"},
|
||||
alice2: {name: "Alice"}
|
||||
}))
|
||||
})
|
||||
|
||||
it("must stringify repeated objects in arrays", function() {
|
||||
var alice = {name: "Alice"}
|
||||
var obj = [alice, alice]
|
||||
var json = stringify(obj, null, 2)
|
||||
json.must.eql(jsonify([{name: "Alice"}, {name: "Alice"}]))
|
||||
})
|
||||
|
||||
it("must call given decycler and use its output", function() {
|
||||
var obj = {}
|
||||
obj.a = obj
|
||||
obj.b = obj
|
||||
|
||||
var decycle = Sinon.spy(function() { return decycle.callCount })
|
||||
var json = stringify(obj, null, 2, decycle)
|
||||
json.must.eql(jsonify({a: 1, b: 2}, null, 2))
|
||||
|
||||
decycle.callCount.must.equal(2)
|
||||
decycle.thisValues[0].must.equal(obj)
|
||||
decycle.args[0][0].must.equal("a")
|
||||
decycle.args[0][1].must.equal(obj)
|
||||
decycle.thisValues[1].must.equal(obj)
|
||||
decycle.args[1][0].must.equal("b")
|
||||
decycle.args[1][1].must.equal(obj)
|
||||
})
|
||||
|
||||
it("must call replacer and use its output", function() {
|
||||
var obj = {name: "Alice", child: {name: "Bob"}}
|
||||
|
||||
var replacer = Sinon.spy(bangString)
|
||||
var json = stringify(obj, replacer, 2)
|
||||
json.must.eql(jsonify({name: "Alice!", child: {name: "Bob!"}}))
|
||||
|
||||
replacer.callCount.must.equal(4)
|
||||
replacer.args[0][0].must.equal("")
|
||||
replacer.args[0][1].must.equal(obj)
|
||||
replacer.thisValues[1].must.equal(obj)
|
||||
replacer.args[1][0].must.equal("name")
|
||||
replacer.args[1][1].must.equal("Alice")
|
||||
replacer.thisValues[2].must.equal(obj)
|
||||
replacer.args[2][0].must.equal("child")
|
||||
replacer.args[2][1].must.equal(obj.child)
|
||||
replacer.thisValues[3].must.equal(obj.child)
|
||||
replacer.args[3][0].must.equal("name")
|
||||
replacer.args[3][1].must.equal("Bob")
|
||||
})
|
||||
|
||||
it("must call replacer after describing circular references", function() {
|
||||
var obj = {name: "Alice"}
|
||||
obj.self = obj
|
||||
|
||||
var replacer = Sinon.spy(bangString)
|
||||
var json = stringify(obj, replacer, 2)
|
||||
json.must.eql(jsonify({name: "Alice!", self: "[Circular ~]!"}))
|
||||
|
||||
replacer.callCount.must.equal(3)
|
||||
replacer.args[0][0].must.equal("")
|
||||
replacer.args[0][1].must.equal(obj)
|
||||
replacer.thisValues[1].must.equal(obj)
|
||||
replacer.args[1][0].must.equal("name")
|
||||
replacer.args[1][1].must.equal("Alice")
|
||||
replacer.thisValues[2].must.equal(obj)
|
||||
replacer.args[2][0].must.equal("self")
|
||||
replacer.args[2][1].must.equal("[Circular ~]")
|
||||
})
|
||||
|
||||
it("must call given decycler and use its output for nested objects",
|
||||
function() {
|
||||
var obj = {}
|
||||
obj.a = obj
|
||||
obj.b = {self: obj}
|
||||
|
||||
var decycle = Sinon.spy(function() { return decycle.callCount })
|
||||
var json = stringify(obj, null, 2, decycle)
|
||||
json.must.eql(jsonify({a: 1, b: {self: 2}}))
|
||||
|
||||
decycle.callCount.must.equal(2)
|
||||
decycle.args[0][0].must.equal("a")
|
||||
decycle.args[0][1].must.equal(obj)
|
||||
decycle.args[1][0].must.equal("self")
|
||||
decycle.args[1][1].must.equal(obj)
|
||||
})
|
||||
|
||||
it("must use decycler's output when it returned null", function() {
|
||||
var obj = {a: "b"}
|
||||
obj.self = obj
|
||||
obj.selves = [obj, obj]
|
||||
|
||||
function decycle() { return null }
|
||||
stringify(obj, null, 2, decycle).must.eql(jsonify({
|
||||
a: "b",
|
||||
self: null,
|
||||
selves: [null, null]
|
||||
}))
|
||||
})
|
||||
|
||||
it("must use decycler's output when it returned undefined", function() {
|
||||
var obj = {a: "b"}
|
||||
obj.self = obj
|
||||
obj.selves = [obj, obj]
|
||||
|
||||
function decycle() {}
|
||||
stringify(obj, null, 2, decycle).must.eql(jsonify({
|
||||
a: "b",
|
||||
selves: [null, null]
|
||||
}))
|
||||
})
|
||||
|
||||
it("must throw given a decycler that returns a cycle", function() {
|
||||
var obj = {}
|
||||
obj.self = obj
|
||||
var err
|
||||
function identity(key, value) { return value }
|
||||
try { stringify(obj, null, 2, identity) } catch (ex) { err = ex }
|
||||
err.must.be.an.instanceof(TypeError)
|
||||
})
|
||||
|
||||
describe(".getSerialize", function() {
|
||||
it("must stringify circular objects", function() {
|
||||
var obj = {a: "b"}
|
||||
obj.circularRef = obj
|
||||
obj.list = [obj, obj]
|
||||
|
||||
var json = JSON.stringify(obj, stringify.getSerialize(), 2)
|
||||
json.must.eql(jsonify({
|
||||
"a": "b",
|
||||
"circularRef": "[Circular ~]",
|
||||
"list": ["[Circular ~]", "[Circular ~]"]
|
||||
}))
|
||||
})
|
||||
|
||||
// This is the behavior as of Mar 3, 2015.
|
||||
// The serializer function keeps state inside the returned function and
|
||||
// so far I'm not sure how to not do that. JSON.stringify's replacer is not
|
||||
// called _after_ serialization.
|
||||
xit("must return a function that could be called twice", function() {
|
||||
var obj = {name: "Alice"}
|
||||
obj.self = obj
|
||||
|
||||
var json
|
||||
var serializer = stringify.getSerialize()
|
||||
|
||||
json = JSON.stringify(obj, serializer, 2)
|
||||
json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"}))
|
||||
|
||||
json = JSON.stringify(obj, serializer, 2)
|
||||
json.must.eql(jsonify({name: "Alice", self: "[Circular ~]"}))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function bangString(key, value) {
|
||||
return typeof value == "string" ? value + "!" : value
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
import * as BufferLayout from '@solana/buffer-layout';
|
||||
|
||||
import {
|
||||
encodeData,
|
||||
decodeData,
|
||||
InstructionType,
|
||||
IInstructionInputData,
|
||||
} from '../instruction';
|
||||
import {PublicKey} from '../publickey';
|
||||
import {TransactionInstruction} from '../transaction';
|
||||
import {u64} from '../utils/bigint';
|
||||
|
||||
/**
|
||||
* Compute Budget Instruction class
|
||||
*/
|
||||
export class ComputeBudgetInstruction {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
* Decode a compute budget instruction and retrieve the instruction type.
|
||||
*/
|
||||
static decodeInstructionType(
|
||||
instruction: TransactionInstruction,
|
||||
): ComputeBudgetInstructionType {
|
||||
this.checkProgramId(instruction.programId);
|
||||
|
||||
const instructionTypeLayout = BufferLayout.u8('instruction');
|
||||
const typeIndex = instructionTypeLayout.decode(instruction.data);
|
||||
|
||||
let type: ComputeBudgetInstructionType | undefined;
|
||||
for (const [ixType, layout] of Object.entries(
|
||||
COMPUTE_BUDGET_INSTRUCTION_LAYOUTS,
|
||||
)) {
|
||||
if (layout.index == typeIndex) {
|
||||
type = ixType as ComputeBudgetInstructionType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
throw new Error(
|
||||
'Instruction type incorrect; not a ComputeBudgetInstruction',
|
||||
);
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode request units compute budget instruction and retrieve the instruction params.
|
||||
*/
|
||||
static decodeRequestUnits(
|
||||
instruction: TransactionInstruction,
|
||||
): RequestUnitsParams {
|
||||
this.checkProgramId(instruction.programId);
|
||||
const {units, additionalFee} = decodeData(
|
||||
COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits,
|
||||
instruction.data,
|
||||
);
|
||||
return {units, additionalFee};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode request heap frame compute budget instruction and retrieve the instruction params.
|
||||
*/
|
||||
static decodeRequestHeapFrame(
|
||||
instruction: TransactionInstruction,
|
||||
): RequestHeapFrameParams {
|
||||
this.checkProgramId(instruction.programId);
|
||||
const {bytes} = decodeData(
|
||||
COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame,
|
||||
instruction.data,
|
||||
);
|
||||
return {bytes};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode set compute unit limit compute budget instruction and retrieve the instruction params.
|
||||
*/
|
||||
static decodeSetComputeUnitLimit(
|
||||
instruction: TransactionInstruction,
|
||||
): SetComputeUnitLimitParams {
|
||||
this.checkProgramId(instruction.programId);
|
||||
const {units} = decodeData(
|
||||
COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit,
|
||||
instruction.data,
|
||||
);
|
||||
return {units};
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode set compute unit price compute budget instruction and retrieve the instruction params.
|
||||
*/
|
||||
static decodeSetComputeUnitPrice(
|
||||
instruction: TransactionInstruction,
|
||||
): SetComputeUnitPriceParams {
|
||||
this.checkProgramId(instruction.programId);
|
||||
const {microLamports} = decodeData(
|
||||
COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice,
|
||||
instruction.data,
|
||||
);
|
||||
return {microLamports};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
static checkProgramId(programId: PublicKey) {
|
||||
if (!programId.equals(ComputeBudgetProgram.programId)) {
|
||||
throw new Error(
|
||||
'invalid instruction; programId is not ComputeBudgetProgram',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An enumeration of valid ComputeBudgetInstructionType's
|
||||
*/
|
||||
export type ComputeBudgetInstructionType =
|
||||
// FIXME
|
||||
// It would be preferable for this type to be `keyof ComputeBudgetInstructionInputData`
|
||||
// but Typedoc does not transpile `keyof` expressions.
|
||||
// See https://github.com/TypeStrong/typedoc/issues/1894
|
||||
| 'RequestUnits'
|
||||
| 'RequestHeapFrame'
|
||||
| 'SetComputeUnitLimit'
|
||||
| 'SetComputeUnitPrice';
|
||||
|
||||
type ComputeBudgetInstructionInputData = {
|
||||
RequestUnits: IInstructionInputData & Readonly<RequestUnitsParams>;
|
||||
RequestHeapFrame: IInstructionInputData & Readonly<RequestHeapFrameParams>;
|
||||
SetComputeUnitLimit: IInstructionInputData &
|
||||
Readonly<SetComputeUnitLimitParams>;
|
||||
SetComputeUnitPrice: IInstructionInputData &
|
||||
Readonly<SetComputeUnitPriceParams>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Request units instruction params
|
||||
*/
|
||||
export interface RequestUnitsParams {
|
||||
/** Units to request for transaction-wide compute */
|
||||
units: number;
|
||||
/** Prioritization fee lamports */
|
||||
additionalFee: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request heap frame instruction params
|
||||
*/
|
||||
export type RequestHeapFrameParams = {
|
||||
/** Requested transaction-wide program heap size in bytes. Must be multiple of 1024. Applies to each program, including CPIs. */
|
||||
bytes: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set compute unit limit instruction params
|
||||
*/
|
||||
export interface SetComputeUnitLimitParams {
|
||||
/** Transaction-wide compute unit limit */
|
||||
units: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set compute unit price instruction params
|
||||
*/
|
||||
export interface SetComputeUnitPriceParams {
|
||||
/** Transaction compute unit price used for prioritization fees */
|
||||
microLamports: number | bigint;
|
||||
}
|
||||
|
||||
/**
|
||||
* An enumeration of valid ComputeBudget InstructionType's
|
||||
* @internal
|
||||
*/
|
||||
export const COMPUTE_BUDGET_INSTRUCTION_LAYOUTS = Object.freeze<{
|
||||
[Instruction in ComputeBudgetInstructionType]: InstructionType<
|
||||
ComputeBudgetInstructionInputData[Instruction]
|
||||
>;
|
||||
}>({
|
||||
RequestUnits: {
|
||||
index: 0,
|
||||
layout: BufferLayout.struct<
|
||||
ComputeBudgetInstructionInputData['RequestUnits']
|
||||
>([
|
||||
BufferLayout.u8('instruction'),
|
||||
BufferLayout.u32('units'),
|
||||
BufferLayout.u32('additionalFee'),
|
||||
]),
|
||||
},
|
||||
RequestHeapFrame: {
|
||||
index: 1,
|
||||
layout: BufferLayout.struct<
|
||||
ComputeBudgetInstructionInputData['RequestHeapFrame']
|
||||
>([BufferLayout.u8('instruction'), BufferLayout.u32('bytes')]),
|
||||
},
|
||||
SetComputeUnitLimit: {
|
||||
index: 2,
|
||||
layout: BufferLayout.struct<
|
||||
ComputeBudgetInstructionInputData['SetComputeUnitLimit']
|
||||
>([BufferLayout.u8('instruction'), BufferLayout.u32('units')]),
|
||||
},
|
||||
SetComputeUnitPrice: {
|
||||
index: 3,
|
||||
layout: BufferLayout.struct<
|
||||
ComputeBudgetInstructionInputData['SetComputeUnitPrice']
|
||||
>([BufferLayout.u8('instruction'), u64('microLamports')]),
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Factory class for transaction instructions to interact with the Compute Budget program
|
||||
*/
|
||||
export class ComputeBudgetProgram {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
* Public key that identifies the Compute Budget program
|
||||
*/
|
||||
static programId: PublicKey = new PublicKey(
|
||||
'ComputeBudget111111111111111111111111111111',
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated Instead, call {@link setComputeUnitLimit} and/or {@link setComputeUnitPrice}
|
||||
*/
|
||||
static requestUnits(params: RequestUnitsParams): TransactionInstruction {
|
||||
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits;
|
||||
const data = encodeData(type, params);
|
||||
return new TransactionInstruction({
|
||||
keys: [],
|
||||
programId: this.programId,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
static requestHeapFrame(
|
||||
params: RequestHeapFrameParams,
|
||||
): TransactionInstruction {
|
||||
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame;
|
||||
const data = encodeData(type, params);
|
||||
return new TransactionInstruction({
|
||||
keys: [],
|
||||
programId: this.programId,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
static setComputeUnitLimit(
|
||||
params: SetComputeUnitLimitParams,
|
||||
): TransactionInstruction {
|
||||
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit;
|
||||
const data = encodeData(type, params);
|
||||
return new TransactionInstruction({
|
||||
keys: [],
|
||||
programId: this.programId,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
static setComputeUnitPrice(
|
||||
params: SetComputeUnitPriceParams,
|
||||
): TransactionInstruction {
|
||||
const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitPrice;
|
||||
const data = encodeData(type, {
|
||||
microLamports: BigInt(params.microLamports),
|
||||
});
|
||||
return new TransactionInstruction({
|
||||
keys: [],
|
||||
programId: this.programId,
|
||||
data,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
var _typeof = require("./typeof.js")["default"];
|
||||
var checkInRHS = require("./checkInRHS.js");
|
||||
var setFunctionName = require("./setFunctionName.js");
|
||||
var toPropertyKey = require("./toPropertyKey.js");
|
||||
function applyDecs2305(e, t, r, n, o, a) {
|
||||
function i(e, t, r) {
|
||||
return function (n, o) {
|
||||
return r && r(n), e[t].call(n, o);
|
||||
};
|
||||
}
|
||||
function c(e, t) {
|
||||
for (var r = 0; r < e.length; r++) e[r].call(t);
|
||||
return t;
|
||||
}
|
||||
function s(e, t, r, n) {
|
||||
if ("function" != typeof e && (n || void 0 !== e)) throw new TypeError(t + " must " + (r || "be") + " a function" + (n ? "" : " or undefined"));
|
||||
return e;
|
||||
}
|
||||
function applyDec(e, t, r, n, o, a, c, u, l, f, p, d, h) {
|
||||
function m(e) {
|
||||
if (!h(e)) throw new TypeError("Attempted to access private element on non-instance");
|
||||
}
|
||||
var y,
|
||||
v = t[0],
|
||||
g = t[3],
|
||||
b = !u;
|
||||
if (!b) {
|
||||
r || Array.isArray(v) || (v = [v]);
|
||||
var w = {},
|
||||
S = [],
|
||||
A = 3 === o ? "get" : 4 === o || d ? "set" : "value";
|
||||
f ? (p || d ? w = {
|
||||
get: setFunctionName(function () {
|
||||
return g(this);
|
||||
}, n, "get"),
|
||||
set: function set(e) {
|
||||
t[4](this, e);
|
||||
}
|
||||
} : w[A] = g, p || setFunctionName(w[A], n, 2 === o ? "" : A)) : p || (w = Object.getOwnPropertyDescriptor(e, n));
|
||||
}
|
||||
for (var P = e, j = v.length - 1; j >= 0; j -= r ? 2 : 1) {
|
||||
var D = v[j],
|
||||
E = r ? v[j - 1] : void 0,
|
||||
I = {},
|
||||
O = {
|
||||
kind: ["field", "accessor", "method", "getter", "setter", "class"][o],
|
||||
name: n,
|
||||
metadata: a,
|
||||
addInitializer: function (e, t) {
|
||||
if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
|
||||
s(t, "An initializer", "be", !0), c.push(t);
|
||||
}.bind(null, I)
|
||||
};
|
||||
try {
|
||||
if (b) (y = s(D.call(E, P, O), "class decorators", "return")) && (P = y);else {
|
||||
var k, F;
|
||||
O["static"] = l, O["private"] = f, f ? 2 === o ? k = function k(e) {
|
||||
return m(e), w.value;
|
||||
} : (o < 4 && (k = i(w, "get", m)), 3 !== o && (F = i(w, "set", m))) : (k = function k(e) {
|
||||
return e[n];
|
||||
}, (o < 2 || 4 === o) && (F = function F(e, t) {
|
||||
e[n] = t;
|
||||
}));
|
||||
var N = O.access = {
|
||||
has: f ? h.bind() : function (e) {
|
||||
return n in e;
|
||||
}
|
||||
};
|
||||
if (k && (N.get = k), F && (N.set = F), P = D.call(E, d ? {
|
||||
get: w.get,
|
||||
set: w.set
|
||||
} : w[A], O), d) {
|
||||
if ("object" == _typeof(P) && P) (y = s(P.get, "accessor.get")) && (w.get = y), (y = s(P.set, "accessor.set")) && (w.set = y), (y = s(P.init, "accessor.init")) && S.push(y);else if (void 0 !== P) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
|
||||
} else s(P, (p ? "field" : "method") + " decorators", "return") && (p ? S.push(P) : w[A] = P);
|
||||
}
|
||||
} finally {
|
||||
I.v = !0;
|
||||
}
|
||||
}
|
||||
return (p || d) && u.push(function (e, t) {
|
||||
for (var r = S.length - 1; r >= 0; r--) t = S[r].call(e, t);
|
||||
return t;
|
||||
}), p || b || (f ? d ? u.push(i(w, "get"), i(w, "set")) : u.push(2 === o ? w[A] : i.call.bind(w[A])) : Object.defineProperty(e, n, w)), P;
|
||||
}
|
||||
function u(e, t) {
|
||||
return Object.defineProperty(e, Symbol.metadata || Symbol["for"]("Symbol.metadata"), {
|
||||
configurable: !0,
|
||||
enumerable: !0,
|
||||
value: t
|
||||
});
|
||||
}
|
||||
if (arguments.length >= 6) var l = a[Symbol.metadata || Symbol["for"]("Symbol.metadata")];
|
||||
var f = Object.create(null == l ? null : l),
|
||||
p = function (e, t, r, n) {
|
||||
var o,
|
||||
a,
|
||||
i = [],
|
||||
s = function s(t) {
|
||||
return checkInRHS(t) === e;
|
||||
},
|
||||
u = new Map();
|
||||
function l(e) {
|
||||
e && i.push(c.bind(null, e));
|
||||
}
|
||||
for (var f = 0; f < t.length; f++) {
|
||||
var p = t[f];
|
||||
if (Array.isArray(p)) {
|
||||
var d = p[1],
|
||||
h = p[2],
|
||||
m = p.length > 3,
|
||||
y = 16 & d,
|
||||
v = !!(8 & d),
|
||||
g = 0 == (d &= 7),
|
||||
b = h + "/" + v;
|
||||
if (!g && !m) {
|
||||
var w = u.get(b);
|
||||
if (!0 === w || 3 === w && 4 !== d || 4 === w && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h);
|
||||
u.set(b, !(d > 2) || d);
|
||||
}
|
||||
applyDec(v ? e : e.prototype, p, y, m ? "#" + h : toPropertyKey(h), d, n, v ? a = a || [] : o = o || [], i, v, m, g, 1 === d, v && m ? s : r);
|
||||
}
|
||||
}
|
||||
return l(o), l(a), i;
|
||||
}(e, t, o, f);
|
||||
return r.length || u(e, f), {
|
||||
e: p,
|
||||
get c() {
|
||||
var t = [];
|
||||
return r.length && [u(applyDec(e, [r], n, e.name, 5, f, t), f), c.bind(null, t, e)];
|
||||
}
|
||||
};
|
||||
}
|
||||
module.exports = applyDecs2305, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "cross-spawn",
|
||||
"version": "7.0.6",
|
||||
"description": "Cross platform child_process#spawn and child_process#spawnSync",
|
||||
"keywords": [
|
||||
"spawn",
|
||||
"spawnSync",
|
||||
"windows",
|
||||
"cross-platform",
|
||||
"path-ext",
|
||||
"shebang",
|
||||
"cmd",
|
||||
"execute"
|
||||
],
|
||||
"author": "André Cruz <andre@moxy.studio>",
|
||||
"homepage": "https://github.com/moxystudio/node-cross-spawn",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:moxystudio/node-cross-spawn.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"test": "jest --env node --coverage",
|
||||
"prerelease": "npm t && npm run lint",
|
||||
"release": "standard-version",
|
||||
"postrelease": "git push --follow-tags origin HEAD && npm publish"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.js": [
|
||||
"eslint --fix",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"commitlint": {
|
||||
"extends": [
|
||||
"@commitlint/config-conventional"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^8.1.0",
|
||||
"@commitlint/config-conventional": "^8.1.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-jest": "^24.9.0",
|
||||
"babel-preset-moxy": "^3.1.0",
|
||||
"eslint": "^5.16.0",
|
||||
"eslint-config-moxy": "^7.1.0",
|
||||
"husky": "^3.0.5",
|
||||
"jest": "^24.9.0",
|
||||
"lint-staged": "^9.2.5",
|
||||
"mkdirp": "^0.5.1",
|
||||
"rimraf": "^3.0.0",
|
||||
"standard-version": "^9.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import type { LibDefinition } from '../variable';
|
||||
export declare const es2019_full: LibDefinition;
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"name": "@typescript-eslint/parser",
|
||||
"version": "8.67.0",
|
||||
"description": "An ESLint custom parser which leverages TypeScript ESTree",
|
||||
"files": [
|
||||
"dist",
|
||||
"!**/*.tsbuildinfo"
|
||||
],
|
||||
"type": "commonjs",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/typescript-eslint/typescript-eslint.git",
|
||||
"directory": "packages/parser"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/typescript-eslint/typescript-eslint/issues"
|
||||
},
|
||||
"homepage": "https://typescript-eslint.io/packages/parser",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"ast",
|
||||
"ecmascript",
|
||||
"javascript",
|
||||
"typescript",
|
||||
"parser",
|
||||
"syntax",
|
||||
"eslint"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^4.4.3",
|
||||
"@typescript-eslint/typescript-estree": "8.67.0",
|
||||
"@typescript-eslint/visitor-keys": "8.67.0",
|
||||
"@typescript-eslint/types": "8.67.0",
|
||||
"@typescript-eslint/scope-manager": "8.67.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript/native": "npm:typescript@^7.0.2",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"eslint": "^10.0.0",
|
||||
"glob": "^11.1.0",
|
||||
"rimraf": "^5.0.10",
|
||||
"typescript": ">=4.8.4 <6.1.0",
|
||||
"vitest": "^4.0.18"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"nx": {
|
||||
"name": "parser",
|
||||
"includedScripts": [
|
||||
"clean"
|
||||
],
|
||||
"targets": {
|
||||
"lint": {
|
||||
"command": "eslint"
|
||||
},
|
||||
"typecheck:tsgo": {},
|
||||
"attw-check": {}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm exec nx build",
|
||||
"clean": "rimraf dist/ coverage/",
|
||||
"format": "pnpm -w run format",
|
||||
"lint": "pnpm -w exec nx lint",
|
||||
"test": "pnpm -w exec nx test",
|
||||
"typecheck": "pnpm -w exec nx typecheck",
|
||||
"typecheck:tsgo": "pnpm -w exec nx typecheck:tsgo",
|
||||
"attw-check": "pnpm -w exec nx attw-check"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* RFC 7914 Scrypt KDF. Can be used to create a key from password and salt.
|
||||
* @module
|
||||
*/
|
||||
import { pbkdf2 } from './pbkdf2.ts';
|
||||
import { sha256 } from './sha2.ts';
|
||||
// prettier-ignore
|
||||
import {
|
||||
anumber, asyncLoop,
|
||||
checkOpts, clean,
|
||||
type KDFInput, rotl,
|
||||
swap32IfBE,
|
||||
u32
|
||||
} from './utils.ts';
|
||||
|
||||
// The main Scrypt loop: uses Salsa extensively.
|
||||
// Six versions of the function were tried, this is the fastest one.
|
||||
// prettier-ignore
|
||||
function XorAndSalsa(
|
||||
prev: Uint32Array,
|
||||
pi: number,
|
||||
input: Uint32Array,
|
||||
ii: number,
|
||||
out: Uint32Array,
|
||||
oi: number
|
||||
) {
|
||||
// Based on https://cr.yp.to/salsa20.html
|
||||
// Xor blocks
|
||||
let y00 = prev[pi++] ^ input[ii++], y01 = prev[pi++] ^ input[ii++];
|
||||
let y02 = prev[pi++] ^ input[ii++], y03 = prev[pi++] ^ input[ii++];
|
||||
let y04 = prev[pi++] ^ input[ii++], y05 = prev[pi++] ^ input[ii++];
|
||||
let y06 = prev[pi++] ^ input[ii++], y07 = prev[pi++] ^ input[ii++];
|
||||
let y08 = prev[pi++] ^ input[ii++], y09 = prev[pi++] ^ input[ii++];
|
||||
let y10 = prev[pi++] ^ input[ii++], y11 = prev[pi++] ^ input[ii++];
|
||||
let y12 = prev[pi++] ^ input[ii++], y13 = prev[pi++] ^ input[ii++];
|
||||
let y14 = prev[pi++] ^ input[ii++], y15 = prev[pi++] ^ input[ii++];
|
||||
// Save state to temporary variables (salsa)
|
||||
let x00 = y00, x01 = y01, x02 = y02, x03 = y03,
|
||||
x04 = y04, x05 = y05, x06 = y06, x07 = y07,
|
||||
x08 = y08, x09 = y09, x10 = y10, x11 = y11,
|
||||
x12 = y12, x13 = y13, x14 = y14, x15 = y15;
|
||||
// Main loop (salsa)
|
||||
for (let i = 0; i < 8; i += 2) {
|
||||
x04 ^= rotl(x00 + x12 | 0, 7); x08 ^= rotl(x04 + x00 | 0, 9);
|
||||
x12 ^= rotl(x08 + x04 | 0, 13); x00 ^= rotl(x12 + x08 | 0, 18);
|
||||
x09 ^= rotl(x05 + x01 | 0, 7); x13 ^= rotl(x09 + x05 | 0, 9);
|
||||
x01 ^= rotl(x13 + x09 | 0, 13); x05 ^= rotl(x01 + x13 | 0, 18);
|
||||
x14 ^= rotl(x10 + x06 | 0, 7); x02 ^= rotl(x14 + x10 | 0, 9);
|
||||
x06 ^= rotl(x02 + x14 | 0, 13); x10 ^= rotl(x06 + x02 | 0, 18);
|
||||
x03 ^= rotl(x15 + x11 | 0, 7); x07 ^= rotl(x03 + x15 | 0, 9);
|
||||
x11 ^= rotl(x07 + x03 | 0, 13); x15 ^= rotl(x11 + x07 | 0, 18);
|
||||
x01 ^= rotl(x00 + x03 | 0, 7); x02 ^= rotl(x01 + x00 | 0, 9);
|
||||
x03 ^= rotl(x02 + x01 | 0, 13); x00 ^= rotl(x03 + x02 | 0, 18);
|
||||
x06 ^= rotl(x05 + x04 | 0, 7); x07 ^= rotl(x06 + x05 | 0, 9);
|
||||
x04 ^= rotl(x07 + x06 | 0, 13); x05 ^= rotl(x04 + x07 | 0, 18);
|
||||
x11 ^= rotl(x10 + x09 | 0, 7); x08 ^= rotl(x11 + x10 | 0, 9);
|
||||
x09 ^= rotl(x08 + x11 | 0, 13); x10 ^= rotl(x09 + x08 | 0, 18);
|
||||
x12 ^= rotl(x15 + x14 | 0, 7); x13 ^= rotl(x12 + x15 | 0, 9);
|
||||
x14 ^= rotl(x13 + x12 | 0, 13); x15 ^= rotl(x14 + x13 | 0, 18);
|
||||
}
|
||||
// Write output (salsa)
|
||||
out[oi++] = (y00 + x00) | 0; out[oi++] = (y01 + x01) | 0;
|
||||
out[oi++] = (y02 + x02) | 0; out[oi++] = (y03 + x03) | 0;
|
||||
out[oi++] = (y04 + x04) | 0; out[oi++] = (y05 + x05) | 0;
|
||||
out[oi++] = (y06 + x06) | 0; out[oi++] = (y07 + x07) | 0;
|
||||
out[oi++] = (y08 + x08) | 0; out[oi++] = (y09 + x09) | 0;
|
||||
out[oi++] = (y10 + x10) | 0; out[oi++] = (y11 + x11) | 0;
|
||||
out[oi++] = (y12 + x12) | 0; out[oi++] = (y13 + x13) | 0;
|
||||
out[oi++] = (y14 + x14) | 0; out[oi++] = (y15 + x15) | 0;
|
||||
}
|
||||
|
||||
function BlockMix(input: Uint32Array, ii: number, out: Uint32Array, oi: number, r: number) {
|
||||
// The block B is r 128-byte chunks (which is equivalent of 2r 64-byte chunks)
|
||||
let head = oi + 0;
|
||||
let tail = oi + 16 * r;
|
||||
for (let i = 0; i < 16; i++) out[tail + i] = input[ii + (2 * r - 1) * 16 + i]; // X ← B[2r−1]
|
||||
for (let i = 0; i < r; i++, head += 16, ii += 16) {
|
||||
// We write odd & even Yi at same time. Even: 0bXXXXX0 Odd: 0bXXXXX1
|
||||
XorAndSalsa(out, tail, input, ii, out, head); // head[i] = Salsa(blockIn[2*i] ^ tail[i-1])
|
||||
if (i > 0) tail += 16; // First iteration overwrites tmp value in tail
|
||||
XorAndSalsa(out, head, input, (ii += 16), out, tail); // tail[i] = Salsa(blockIn[2*i+1] ^ head[i])
|
||||
}
|
||||
}
|
||||
|
||||
export type ScryptOpts = {
|
||||
N: number; // cost factor
|
||||
r: number; // block size
|
||||
p: number; // parallelization
|
||||
dkLen?: number; // key length
|
||||
asyncTick?: number; // block execution max time
|
||||
maxmem?: number;
|
||||
onProgress?: (progress: number) => void;
|
||||
};
|
||||
|
||||
// Common prologue and epilogue for sync/async functions
|
||||
function scryptInit(password: KDFInput, salt: KDFInput, _opts?: ScryptOpts) {
|
||||
// Maxmem - 1GB+1KB by default
|
||||
const opts = checkOpts(
|
||||
{
|
||||
dkLen: 32,
|
||||
asyncTick: 10,
|
||||
maxmem: 1024 ** 3 + 1024,
|
||||
},
|
||||
_opts
|
||||
);
|
||||
const { N, r, p, dkLen, asyncTick, maxmem, onProgress } = opts;
|
||||
anumber(N);
|
||||
anumber(r);
|
||||
anumber(p);
|
||||
anumber(dkLen);
|
||||
anumber(asyncTick);
|
||||
anumber(maxmem);
|
||||
if (onProgress !== undefined && typeof onProgress !== 'function')
|
||||
throw new Error('progressCb should be function');
|
||||
const blockSize = 128 * r;
|
||||
const blockSize32 = blockSize / 4;
|
||||
|
||||
// Max N is 2^32 (Integrify is 32-bit). Real limit is 2^22: JS engines Uint8Array limit is 4GB in 2024.
|
||||
// Spec check `N >= 2^(blockSize / 8)` is not done for compat with popular libs,
|
||||
// which used incorrect r: 1, p: 8. Also, the check seems to be a spec error:
|
||||
// https://www.rfc-editor.org/errata_search.php?rfc=7914
|
||||
const pow32 = Math.pow(2, 32);
|
||||
if (N <= 1 || (N & (N - 1)) !== 0 || N > pow32) {
|
||||
throw new Error('Scrypt: N must be larger than 1, a power of 2, and less than 2^32');
|
||||
}
|
||||
if (p < 0 || p > ((pow32 - 1) * 32) / blockSize) {
|
||||
throw new Error(
|
||||
'Scrypt: p must be a positive integer less than or equal to ((2^32 - 1) * 32) / (128 * r)'
|
||||
);
|
||||
}
|
||||
if (dkLen < 0 || dkLen > (pow32 - 1) * 32) {
|
||||
throw new Error(
|
||||
'Scrypt: dkLen should be positive integer less than or equal to (2^32 - 1) * 32'
|
||||
);
|
||||
}
|
||||
const memUsed = blockSize * (N + p);
|
||||
if (memUsed > maxmem) {
|
||||
throw new Error(
|
||||
'Scrypt: memused is bigger than maxMem. Expected 128 * r * (N + p) > maxmem of ' + maxmem
|
||||
);
|
||||
}
|
||||
// [B0...Bp−1] ← PBKDF2HMAC-SHA256(Passphrase, Salt, 1, blockSize*ParallelizationFactor)
|
||||
// Since it has only one iteration there is no reason to use async variant
|
||||
const B = pbkdf2(sha256, password, salt, { c: 1, dkLen: blockSize * p });
|
||||
const B32 = u32(B);
|
||||
// Re-used between parallel iterations. Array(iterations) of B
|
||||
const V = u32(new Uint8Array(blockSize * N));
|
||||
const tmp = u32(new Uint8Array(blockSize));
|
||||
let blockMixCb = () => {};
|
||||
if (onProgress) {
|
||||
const totalBlockMix = 2 * N * p;
|
||||
// Invoke callback if progress changes from 10.01 to 10.02
|
||||
// Allows to draw smooth progress bar on up to 8K screen
|
||||
const callbackPer = Math.max(Math.floor(totalBlockMix / 10000), 1);
|
||||
let blockMixCnt = 0;
|
||||
blockMixCb = () => {
|
||||
blockMixCnt++;
|
||||
if (onProgress && (!(blockMixCnt % callbackPer) || blockMixCnt === totalBlockMix))
|
||||
onProgress(blockMixCnt / totalBlockMix);
|
||||
};
|
||||
}
|
||||
return { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick };
|
||||
}
|
||||
|
||||
function scryptOutput(
|
||||
password: KDFInput,
|
||||
dkLen: number,
|
||||
B: Uint8Array,
|
||||
V: Uint32Array,
|
||||
tmp: Uint32Array
|
||||
) {
|
||||
const res = pbkdf2(sha256, password, B, { c: 1, dkLen });
|
||||
clean(B, V, tmp);
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrypt KDF from RFC 7914.
|
||||
* @param password - pass
|
||||
* @param salt - salt
|
||||
* @param opts - parameters
|
||||
* - `N` is cpu/mem work factor (power of 2 e.g. 2**18)
|
||||
* - `r` is block size (8 is common), fine-tunes sequential memory read size and performance
|
||||
* - `p` is parallelization factor (1 is common)
|
||||
* - `dkLen` is output key length in bytes e.g. 32.
|
||||
* - `asyncTick` - (default: 10) max time in ms for which async function can block execution
|
||||
* - `maxmem` - (default: `1024 ** 3 + 1024` aka 1GB+1KB). A limit that the app could use for scrypt
|
||||
* - `onProgress` - callback function that would be executed for progress report
|
||||
* @returns Derived key
|
||||
* @example
|
||||
* scrypt('password', 'salt', { N: 2**18, r: 8, p: 1, dkLen: 32 });
|
||||
*/
|
||||
export function scrypt(password: KDFInput, salt: KDFInput, opts: ScryptOpts): Uint8Array {
|
||||
const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb } = scryptInit(
|
||||
password,
|
||||
salt,
|
||||
opts
|
||||
);
|
||||
swap32IfBE(B32);
|
||||
for (let pi = 0; pi < p; pi++) {
|
||||
const Pi = blockSize32 * pi;
|
||||
for (let i = 0; i < blockSize32; i++) V[i] = B32[Pi + i]; // V[0] = B[i]
|
||||
for (let i = 0, pos = 0; i < N - 1; i++) {
|
||||
BlockMix(V, pos, V, (pos += blockSize32), r); // V[i] = BlockMix(V[i-1]);
|
||||
blockMixCb();
|
||||
}
|
||||
BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); // Process last element
|
||||
blockMixCb();
|
||||
for (let i = 0; i < N; i++) {
|
||||
// First u32 of the last 64-byte block (u32 is LE)
|
||||
const j = B32[Pi + blockSize32 - 16] % N; // j = Integrify(X) % iterations
|
||||
for (let k = 0; k < blockSize32; k++) tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; // tmp = B ^ V[j]
|
||||
BlockMix(tmp, 0, B32, Pi, r); // B = BlockMix(B ^ V[j])
|
||||
blockMixCb();
|
||||
}
|
||||
}
|
||||
swap32IfBE(B32);
|
||||
return scryptOutput(password, dkLen, B, V, tmp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrypt KDF from RFC 7914. Async version.
|
||||
* @example
|
||||
* await scryptAsync('password', 'salt', { N: 2**18, r: 8, p: 1, dkLen: 32 });
|
||||
*/
|
||||
export async function scryptAsync(
|
||||
password: KDFInput,
|
||||
salt: KDFInput,
|
||||
opts: ScryptOpts
|
||||
): Promise<Uint8Array> {
|
||||
const { N, r, p, dkLen, blockSize32, V, B32, B, tmp, blockMixCb, asyncTick } = scryptInit(
|
||||
password,
|
||||
salt,
|
||||
opts
|
||||
);
|
||||
swap32IfBE(B32);
|
||||
for (let pi = 0; pi < p; pi++) {
|
||||
const Pi = blockSize32 * pi;
|
||||
for (let i = 0; i < blockSize32; i++) V[i] = B32[Pi + i]; // V[0] = B[i]
|
||||
let pos = 0;
|
||||
await asyncLoop(N - 1, asyncTick, () => {
|
||||
BlockMix(V, pos, V, (pos += blockSize32), r); // V[i] = BlockMix(V[i-1]);
|
||||
blockMixCb();
|
||||
});
|
||||
BlockMix(V, (N - 1) * blockSize32, B32, Pi, r); // Process last element
|
||||
blockMixCb();
|
||||
await asyncLoop(N, asyncTick, () => {
|
||||
// First u32 of the last 64-byte block (u32 is LE)
|
||||
const j = B32[Pi + blockSize32 - 16] % N; // j = Integrify(X) % iterations
|
||||
for (let k = 0; k < blockSize32; k++) tmp[k] = B32[Pi + k] ^ V[j * blockSize32 + k]; // tmp = B ^ V[j]
|
||||
BlockMix(tmp, 0, B32, Pi, r); // B = BlockMix(B ^ V[j])
|
||||
blockMixCb();
|
||||
});
|
||||
}
|
||||
swap32IfBE(B32);
|
||||
return scryptOutput(password, dkLen, B, V, tmp);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @fileoverview Types for this package.
|
||||
*/
|
||||
|
||||
import type { ConfigObject } from "@eslint/core";
|
||||
|
||||
/** @deprecated Use `ConfigObject` instead. */
|
||||
export type Config = ConfigObject;
|
||||
|
||||
/**
|
||||
* Infinite array type.
|
||||
*/
|
||||
export type InfiniteArray<T> = T | InfiniteArray<T>[];
|
||||
|
||||
/**
|
||||
* A config object that may appear inside of `extends`.
|
||||
* `basePath` and nested `extends` are not allowed on extension config objects.
|
||||
*/
|
||||
export type ExtensionConfigObject = Omit<ConfigObject, "basePath"> & {
|
||||
extends?: never;
|
||||
};
|
||||
|
||||
/**
|
||||
* The type of array element in the `extends` property after flattening.
|
||||
*/
|
||||
export type SimpleExtendsElement = string | ExtensionConfigObject;
|
||||
|
||||
/**
|
||||
* The type of array element in the `extends` property before flattening.
|
||||
*/
|
||||
export type ExtendsElement =
|
||||
SimpleExtendsElement | InfiniteArray<ExtensionConfigObject>;
|
||||
|
||||
/**
|
||||
* Config with extends. Valid only inside of `defineConfig()`.
|
||||
*/
|
||||
export interface ConfigWithExtends extends ConfigObject {
|
||||
extends?: ExtendsElement[];
|
||||
}
|
||||
|
||||
export type ConfigWithExtendsArray = InfiniteArray<ConfigWithExtends>[];
|
||||
@@ -0,0 +1,8 @@
|
||||
function _array_like_to_array(arr, len) {
|
||||
if (len == null || len > arr.length) len = arr.length;
|
||||
|
||||
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
|
||||
|
||||
return arr2;
|
||||
}
|
||||
export { _array_like_to_array as _ };
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"reg": {
|
||||
"name": "reg",
|
||||
"browser": "Edge 14.14393.0 (Windows 10 0.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 456455.66360715276,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.01632374357524679,
|
||||
"rhz": 0.6291712254945833,
|
||||
"sampleSize": 169
|
||||
},
|
||||
"fn if": {
|
||||
"name": "fn if",
|
||||
"browser": "Edge 14.14393.0 (Windows 10 0.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 193679.9495017831,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.01950064206644373,
|
||||
"rhz": 0.2669653613645212,
|
||||
"sampleSize": 169
|
||||
},
|
||||
"fn if reverse": {
|
||||
"name": "fn if reverse",
|
||||
"browser": "Edge 14.14393.0 (Windows 10 0.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 103885.45242442277,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.02131717275903938,
|
||||
"rhz": 0.14319405502915764,
|
||||
"sampleSize": 165
|
||||
},
|
||||
"escape31": {
|
||||
"name": "escape31",
|
||||
"browser": "Edge 14.14393.0 (Windows 10 0.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 203638.06134905503,
|
||||
"success": true,
|
||||
"fastest": false,
|
||||
"rme": 0.020628729439989432,
|
||||
"rhz": 0.28069146432279773,
|
||||
"sampleSize": 171
|
||||
},
|
||||
"native": {
|
||||
"name": "native",
|
||||
"browser": "Edge 14.14393.0 (Windows 10 0.0.0)",
|
||||
"suite": "escape-long",
|
||||
"hz": 725487.1887193171,
|
||||
"success": true,
|
||||
"fastest": true,
|
||||
"rme": 0.020436075036992615,
|
||||
"rhz": 1,
|
||||
"sampleSize": 168
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
# p-locate [](https://travis-ci.com/github/sindresorhus/p-locate)
|
||||
|
||||
> Get the first fulfilled promise that satisfies the provided testing function
|
||||
|
||||
Think of it like an async version of [`Array#find`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/find).
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
$ npm install p-locate
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Here we find the first file that exists on disk, in array order.
|
||||
|
||||
```js
|
||||
const pathExists = require('path-exists');
|
||||
const pLocate = require('p-locate');
|
||||
|
||||
const files = [
|
||||
'unicorn.png',
|
||||
'rainbow.png', // Only this one actually exists on disk
|
||||
'pony.png'
|
||||
];
|
||||
|
||||
(async () => {
|
||||
const foundPath = await pLocate(files, file => pathExists(file));
|
||||
|
||||
console.log(foundPath);
|
||||
//=> 'rainbow'
|
||||
})();
|
||||
```
|
||||
|
||||
*The above is just an example. Use [`locate-path`](https://github.com/sindresorhus/locate-path) if you need this.*
|
||||
|
||||
## API
|
||||
|
||||
### pLocate(input, tester, options?)
|
||||
|
||||
Returns a `Promise` that is fulfilled when `tester` resolves to `true` or the iterable is done, or rejects if any of the promises reject. The fulfilled value is the current iterable value or `undefined` if `tester` never resolved to `true`.
|
||||
|
||||
#### input
|
||||
|
||||
Type: `Iterable<Promise | unknown>`
|
||||
|
||||
An iterable of promises/values to test.
|
||||
|
||||
#### tester(element)
|
||||
|
||||
Type: `Function`
|
||||
|
||||
This function will receive resolved values from `input` and is expected to return a `Promise<boolean>` or `boolean`.
|
||||
|
||||
#### options
|
||||
|
||||
Type: `object`
|
||||
|
||||
##### concurrency
|
||||
|
||||
Type: `number`\
|
||||
Default: `Infinity`\
|
||||
Minimum: `1`
|
||||
|
||||
Number of concurrently pending promises returned by `tester`.
|
||||
|
||||
##### preserveOrder
|
||||
|
||||
Type: `boolean`\
|
||||
Default: `true`
|
||||
|
||||
Preserve `input` order when searching.
|
||||
|
||||
Disable this to improve performance if you don't care about the order.
|
||||
|
||||
## Related
|
||||
|
||||
- [p-map](https://github.com/sindresorhus/p-map) - Map over promises concurrently
|
||||
- [p-filter](https://github.com/sindresorhus/p-filter) - Filter promises concurrently
|
||||
- [p-any](https://github.com/sindresorhus/p-any) - Wait for any promise to be fulfilled
|
||||
- [More…](https://github.com/sindresorhus/promise-fun)
|
||||
|
||||
---
|
||||
|
||||
<div align="center">
|
||||
<b>
|
||||
<a href="https://tidelift.com/subscription/pkg/npm-p-locate?utm_source=npm-p-locate&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
|
||||
</b>
|
||||
<br>
|
||||
<sub>
|
||||
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
|
||||
</sub>
|
||||
</div>
|
||||
@@ -0,0 +1 @@
|
||||
export { _ as default } from "../esm/_object_spread_props.js";
|
||||
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* @fileoverview Worker thread for multithread linting.
|
||||
* @author Francesco Trotta
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const hrtimeBigint = process.hrtime.bigint;
|
||||
|
||||
const startTime = hrtimeBigint();
|
||||
|
||||
// eslint-disable-next-line n/no-unsupported-features/node-builtins -- enable V8's code cache if supported
|
||||
require("node:module").enableCompileCache?.();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const { parentPort, threadId, workerData } = require("node:worker_threads");
|
||||
const {
|
||||
createConfigLoader,
|
||||
createDebug,
|
||||
createDefaultConfigs,
|
||||
createLinter,
|
||||
createLintResultCache,
|
||||
getCacheFile,
|
||||
lintFile,
|
||||
loadOptionsFromModule,
|
||||
processOptions,
|
||||
} = require("./eslint-helpers");
|
||||
const { WarningService } = require("../services/warning-service");
|
||||
const timing = require("../linter/timing");
|
||||
|
||||
const depsLoadedTime = hrtimeBigint();
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Typedefs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @typedef {import("../types").ESLint.LintResult} LintResult */
|
||||
/** @typedef {import("../types").ESLint.Options} ESLintOptions */
|
||||
/** @typedef {LintResult & { index?: number; }} IndexedLintResult */
|
||||
/** @typedef {IndexedLintResult[] & { netLintingDuration: bigint; timings?: Record<string, number>; }} WorkerLintResults */
|
||||
/**
|
||||
* @typedef {Object} WorkerData - Data passed to the worker thread.
|
||||
* @property {ESLintOptions | string} eslintOptionsOrURL - The unprocessed ESLint options or the URL of the options module.
|
||||
* @property {Uint32Array<SharedArrayBuffer>} filePathIndexArray - Shared counter used to track the next file to lint.
|
||||
* @property {string[]} filePaths - File paths to lint.
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const debug = createDebug(`eslint:worker:thread-${threadId}`);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Main
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Prevent timing module from printing profiling output from worker threads.
|
||||
* The main thread is responsible for displaying any aggregated timings.
|
||||
*/
|
||||
timing.disableDisplay();
|
||||
|
||||
debug("Dependencies loaded in %t", depsLoadedTime - startTime);
|
||||
|
||||
(async () => {
|
||||
/** @type {WorkerData} */
|
||||
const { eslintOptionsOrURL, filePathIndexArray, filePaths } = workerData;
|
||||
const eslintOptions =
|
||||
typeof eslintOptionsOrURL === "object"
|
||||
? eslintOptionsOrURL
|
||||
: await loadOptionsFromModule(eslintOptionsOrURL);
|
||||
const processedESLintOptions = processOptions(eslintOptions);
|
||||
|
||||
const warningService = new WarningService();
|
||||
|
||||
// These warnings are always emitted by the controlling thread.
|
||||
warningService.emitEmptyConfigWarning =
|
||||
warningService.emitInactiveFlagWarning = () => {};
|
||||
|
||||
const linter = createLinter(processedESLintOptions, warningService);
|
||||
|
||||
const cacheFilePath = getCacheFile(
|
||||
processedESLintOptions.cacheLocation,
|
||||
processedESLintOptions.cwd,
|
||||
);
|
||||
|
||||
const lintResultCache = createLintResultCache(
|
||||
processedESLintOptions,
|
||||
cacheFilePath,
|
||||
);
|
||||
const defaultConfigs = createDefaultConfigs(eslintOptions.plugins);
|
||||
|
||||
const configLoader = createConfigLoader(
|
||||
processedESLintOptions,
|
||||
defaultConfigs,
|
||||
linter,
|
||||
warningService,
|
||||
);
|
||||
|
||||
/** @type {WorkerLintResults} */
|
||||
const indexedResults = [];
|
||||
let loadConfigTotalDuration = 0n;
|
||||
const readFileCounter = { duration: 0n };
|
||||
|
||||
const lintingStartTime = hrtimeBigint();
|
||||
debug(
|
||||
"Linting started %t after dependencies loaded",
|
||||
lintingStartTime - depsLoadedTime,
|
||||
);
|
||||
|
||||
for (;;) {
|
||||
const fileLintingStartTime = hrtimeBigint();
|
||||
|
||||
// It seems hard to produce an arithmetic overflow under realistic conditions here.
|
||||
const index = Atomics.add(filePathIndexArray, 0, 1);
|
||||
|
||||
const filePath = filePaths[index];
|
||||
if (!filePath) {
|
||||
break;
|
||||
}
|
||||
|
||||
const loadConfigEnterTime = hrtimeBigint();
|
||||
const configs = await configLoader.loadConfigArrayForFile(filePath);
|
||||
const loadConfigExitTime = hrtimeBigint();
|
||||
const loadConfigDuration = loadConfigExitTime - loadConfigEnterTime;
|
||||
debug(
|
||||
'Config array for file "%s" loaded in %t',
|
||||
filePath,
|
||||
loadConfigDuration,
|
||||
);
|
||||
loadConfigTotalDuration += loadConfigDuration;
|
||||
|
||||
/** @type {IndexedLintResult} */
|
||||
const result = await lintFile(
|
||||
filePath,
|
||||
configs,
|
||||
processedESLintOptions,
|
||||
linter,
|
||||
lintResultCache,
|
||||
readFileCounter,
|
||||
);
|
||||
if (result) {
|
||||
result.index = index;
|
||||
indexedResults.push(result);
|
||||
}
|
||||
|
||||
const fileLintingEndTime = hrtimeBigint();
|
||||
debug(
|
||||
'File "%s" processed in %t',
|
||||
filePath,
|
||||
fileLintingEndTime - fileLintingStartTime,
|
||||
);
|
||||
}
|
||||
|
||||
const lintingDuration = hrtimeBigint() - lintingStartTime;
|
||||
|
||||
/*
|
||||
* The net linting duration is the total linting time minus the time spent loading configs and reading files.
|
||||
* It captures the processing time dedicated to computation-intensive tasks that are highly parallelizable and not repeated across threads.
|
||||
*/
|
||||
indexedResults.netLintingDuration =
|
||||
lintingDuration - loadConfigTotalDuration - readFileCounter.duration;
|
||||
|
||||
if (timing.enabled) {
|
||||
indexedResults.timings = timing.getData();
|
||||
}
|
||||
|
||||
parentPort.postMessage(indexedResults);
|
||||
})();
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { TSESLint } from '@typescript-eslint/utils';
|
||||
export type DirectiveConfig = boolean | 'allow-with-description' | {
|
||||
descriptionFormat: string;
|
||||
};
|
||||
export interface OptionsShape {
|
||||
minimumDescriptionLength?: number;
|
||||
'ts-check'?: DirectiveConfig;
|
||||
'ts-expect-error'?: DirectiveConfig;
|
||||
'ts-ignore'?: DirectiveConfig;
|
||||
'ts-nocheck'?: DirectiveConfig;
|
||||
}
|
||||
export type Options = [OptionsShape];
|
||||
export type MessageIds = 'replaceTsIgnoreWithTsExpectError' | 'tsDirectiveComment' | 'tsDirectiveCommentDescriptionNotMatchPattern' | 'tsDirectiveCommentRequiresDescription' | 'tsIgnoreInsteadOfExpectError';
|
||||
declare const _default: TSESLint.RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
|
||||
name: string;
|
||||
};
|
||||
export default _default;
|
||||
Reference in New Issue
Block a user