WIP: bootstrap and partial real Solana watcher implementation

This commit is contained in:
2026-08-16 09:17:45 +00:00
commit dc23412c3f
7232 changed files with 1687637 additions and 0 deletions

View File

@@ -0,0 +1,238 @@
/**
* @fileoverview Rule to flag when IIFE is not wrapped in parens
* @author Ilya Volodin
* @deprecated in ESLint v8.53.0
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
const eslintUtils = require("@eslint-community/eslint-utils");
//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------
/**
* Check if the given node is callee of a `NewExpression` node
* @param {ASTNode} node node to check
* @returns {boolean} True if the node is callee of a `NewExpression` node
* @private
*/
function isCalleeOfNewExpression(node) {
const maybeCallee =
node.parent.type === "ChainExpression" ? node.parent : node;
return (
maybeCallee.parent.type === "NewExpression" &&
maybeCallee.parent.callee === maybeCallee
);
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
deprecated: {
message: "Formatting rules are being moved out of ESLint core.",
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
deprecatedSince: "8.53.0",
availableUntil: "11.0.0",
replacedBy: [
{
message:
"ESLint Stylistic now maintains deprecated stylistic core rules.",
url: "https://eslint.style/guide/migration",
plugin: {
name: "@stylistic/eslint-plugin",
url: "https://eslint.style",
},
rule: {
name: "wrap-iife",
url: "https://eslint.style/rules/wrap-iife",
},
},
],
},
type: "layout",
docs: {
description:
"Require parentheses around immediate `function` invocations",
recommended: false,
url: "https://eslint.org/docs/latest/rules/wrap-iife",
},
schema: [
{
enum: ["outside", "inside", "any"],
},
{
type: "object",
properties: {
functionPrototypeMethods: {
type: "boolean",
default: false,
},
},
additionalProperties: false,
},
],
fixable: "code",
messages: {
wrapInvocation:
"Wrap an immediate function invocation in parentheses.",
wrapExpression: "Wrap only the function expression in parens.",
moveInvocation:
"Move the invocation into the parens that contain the function.",
},
},
create(context) {
const style = context.options[0] || "outside";
const includeFunctionPrototypeMethods =
context.options[1] && context.options[1].functionPrototypeMethods;
const sourceCode = context.sourceCode;
/**
* Check if the node is wrapped in any (). All parens count: grouping parens and parens for constructs such as if()
* @param {ASTNode} node node to evaluate
* @returns {boolean} True if it is wrapped in any parens
* @private
*/
function isWrappedInAnyParens(node) {
return astUtils.isParenthesised(sourceCode, node);
}
/**
* Check if the node is wrapped in grouping (). Parens for constructs such as if() don't count
* @param {ASTNode} node node to evaluate
* @returns {boolean} True if it is wrapped in grouping parens
* @private
*/
function isWrappedInGroupingParens(node) {
return eslintUtils.isParenthesized(1, node, sourceCode);
}
/**
* Get the function node from an IIFE
* @param {ASTNode} node node to evaluate
* @returns {ASTNode} node that is the function expression of the given IIFE, or null if none exist
*/
function getFunctionNodeFromIIFE(node) {
const callee = astUtils.skipChainExpression(node.callee);
if (callee.type === "FunctionExpression") {
return callee;
}
if (
includeFunctionPrototypeMethods &&
callee.type === "MemberExpression" &&
callee.object.type === "FunctionExpression" &&
(astUtils.getStaticPropertyName(callee) === "call" ||
astUtils.getStaticPropertyName(callee) === "apply")
) {
return callee.object;
}
return null;
}
return {
CallExpression(node) {
const innerNode = getFunctionNodeFromIIFE(node);
if (!innerNode) {
return;
}
const isCallExpressionWrapped = isWrappedInAnyParens(node),
isFunctionExpressionWrapped =
isWrappedInAnyParens(innerNode);
if (!isCallExpressionWrapped && !isFunctionExpressionWrapped) {
context.report({
node,
messageId: "wrapInvocation",
fix(fixer) {
const nodeToSurround =
style === "inside" ? innerNode : node;
return fixer.replaceText(
nodeToSurround,
`(${sourceCode.getText(nodeToSurround)})`,
);
},
});
} else if (style === "inside" && !isFunctionExpressionWrapped) {
context.report({
node,
messageId: "wrapExpression",
fix(fixer) {
// The outer call expression will always be wrapped at this point.
if (
isWrappedInGroupingParens(node) &&
!isCalleeOfNewExpression(node)
) {
/*
* Parenthesize the function expression and remove unnecessary grouping parens around the call expression.
* Replace the range between the end of the function expression and the end of the call expression.
* for example, in `(function(foo) {}(bar))`, the range `(bar))` should get replaced with `)(bar)`.
*/
const parenAfter =
sourceCode.getTokenAfter(node);
return fixer.replaceTextRange(
[innerNode.range[1], parenAfter.range[1]],
`)${sourceCode.getText().slice(innerNode.range[1], parenAfter.range[0])}`,
);
}
/*
* Call expression is wrapped in mandatory parens such as if(), or in necessary grouping parens.
* These parens cannot be removed, so just parenthesize the function expression.
*/
return fixer.replaceText(
innerNode,
`(${sourceCode.getText(innerNode)})`,
);
},
});
} else if (style === "outside" && !isCallExpressionWrapped) {
context.report({
node,
messageId: "moveInvocation",
fix(fixer) {
/*
* The inner function expression will always be wrapped at this point.
* It's only necessary to replace the range between the end of the function expression
* and the call expression. For example, in `(function(foo) {})(bar)`, the range `)(bar)`
* should get replaced with `(bar))`.
*/
const parenAfter =
sourceCode.getTokenAfter(innerNode);
return fixer.replaceTextRange(
[parenAfter.range[0], node.range[1]],
`${sourceCode.getText().slice(parenAfter.range[1], node.range[1])})`,
);
},
});
}
},
};
},
};

View File

@@ -0,0 +1,464 @@
(function (global, factory) {
if (typeof exports === 'object' && typeof module !== 'undefined') {
factory(module);
module.exports = def(module);
} else if (typeof define === 'function' && define.amd) {
define(['module'], function(mod) {
factory.apply(this, arguments);
mod.exports = def(mod);
});
} else {
const mod = { exports: {} };
factory(mod);
global = typeof globalThis !== 'undefined' ? globalThis : global || self;
global.sourcemapCodec = def(mod);
}
function def(m) { return 'default' in m.exports ? m.exports.default : m.exports; }
})(this, (function (module) {
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/sourcemap-codec.ts
var sourcemap_codec_exports = {};
__export(sourcemap_codec_exports, {
decode: () => decode,
decodeGeneratedRanges: () => decodeGeneratedRanges,
decodeOriginalScopes: () => decodeOriginalScopes,
encode: () => encode,
encodeGeneratedRanges: () => encodeGeneratedRanges,
encodeOriginalScopes: () => encodeOriginalScopes
});
module.exports = __toCommonJS(sourcemap_codec_exports);
// src/vlq.ts
var comma = ",".charCodeAt(0);
var semicolon = ";".charCodeAt(0);
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var intToChar = new Uint8Array(64);
var charToInt = new Uint8Array(128);
for (let i = 0; i < chars.length; i++) {
const c = chars.charCodeAt(i);
intToChar[i] = c;
charToInt[c] = i;
}
function decodeInteger(reader, relative) {
let value = 0;
let shift = 0;
let integer = 0;
do {
const c = reader.next();
integer = charToInt[c];
value |= (integer & 31) << shift;
shift += 5;
} while (integer & 32);
const shouldNegate = value & 1;
value >>>= 1;
if (shouldNegate) {
value = -2147483648 | -value;
}
return relative + value;
}
function encodeInteger(builder, num, relative) {
let delta = num - relative;
delta = delta < 0 ? -delta << 1 | 1 : delta << 1;
do {
let clamped = delta & 31;
delta >>>= 5;
if (delta > 0) clamped |= 32;
builder.write(intToChar[clamped]);
} while (delta > 0);
return num;
}
function hasMoreVlq(reader, max) {
if (reader.pos >= max) return false;
return reader.peek() !== comma;
}
// src/strings.ts
var bufLength = 1024 * 16;
var td = typeof TextDecoder !== "undefined" ? /* @__PURE__ */ new TextDecoder() : typeof Buffer !== "undefined" ? {
decode(buf) {
const out = Buffer.from(buf.buffer, buf.byteOffset, buf.byteLength);
return out.toString();
}
} : {
decode(buf) {
let out = "";
for (let i = 0; i < buf.length; i++) {
out += String.fromCharCode(buf[i]);
}
return out;
}
};
var StringWriter = class {
constructor() {
this.pos = 0;
this.out = "";
this.buffer = new Uint8Array(bufLength);
}
write(v) {
const { buffer } = this;
buffer[this.pos++] = v;
if (this.pos === bufLength) {
this.out += td.decode(buffer);
this.pos = 0;
}
}
flush() {
const { buffer, out, pos } = this;
return pos > 0 ? out + td.decode(buffer.subarray(0, pos)) : out;
}
};
var StringReader = class {
constructor(buffer) {
this.pos = 0;
this.buffer = buffer;
}
next() {
return this.buffer.charCodeAt(this.pos++);
}
peek() {
return this.buffer.charCodeAt(this.pos);
}
indexOf(char) {
const { buffer, pos } = this;
const idx = buffer.indexOf(char, pos);
return idx === -1 ? buffer.length : idx;
}
};
// src/scopes.ts
var EMPTY = [];
function decodeOriginalScopes(input) {
const { length } = input;
const reader = new StringReader(input);
const scopes = [];
const stack = [];
let line = 0;
for (; reader.pos < length; reader.pos++) {
line = decodeInteger(reader, line);
const column = decodeInteger(reader, 0);
if (!hasMoreVlq(reader, length)) {
const last = stack.pop();
last[2] = line;
last[3] = column;
continue;
}
const kind = decodeInteger(reader, 0);
const fields = decodeInteger(reader, 0);
const hasName = fields & 1;
const scope = hasName ? [line, column, 0, 0, kind, decodeInteger(reader, 0)] : [line, column, 0, 0, kind];
let vars = EMPTY;
if (hasMoreVlq(reader, length)) {
vars = [];
do {
const varsIndex = decodeInteger(reader, 0);
vars.push(varsIndex);
} while (hasMoreVlq(reader, length));
}
scope.vars = vars;
scopes.push(scope);
stack.push(scope);
}
return scopes;
}
function encodeOriginalScopes(scopes) {
const writer = new StringWriter();
for (let i = 0; i < scopes.length; ) {
i = _encodeOriginalScopes(scopes, i, writer, [0]);
}
return writer.flush();
}
function _encodeOriginalScopes(scopes, index, writer, state) {
const scope = scopes[index];
const { 0: startLine, 1: startColumn, 2: endLine, 3: endColumn, 4: kind, vars } = scope;
if (index > 0) writer.write(comma);
state[0] = encodeInteger(writer, startLine, state[0]);
encodeInteger(writer, startColumn, 0);
encodeInteger(writer, kind, 0);
const fields = scope.length === 6 ? 1 : 0;
encodeInteger(writer, fields, 0);
if (scope.length === 6) encodeInteger(writer, scope[5], 0);
for (const v of vars) {
encodeInteger(writer, v, 0);
}
for (index++; index < scopes.length; ) {
const next = scopes[index];
const { 0: l, 1: c } = next;
if (l > endLine || l === endLine && c >= endColumn) {
break;
}
index = _encodeOriginalScopes(scopes, index, writer, state);
}
writer.write(comma);
state[0] = encodeInteger(writer, endLine, state[0]);
encodeInteger(writer, endColumn, 0);
return index;
}
function decodeGeneratedRanges(input) {
const { length } = input;
const reader = new StringReader(input);
const ranges = [];
const stack = [];
let genLine = 0;
let definitionSourcesIndex = 0;
let definitionScopeIndex = 0;
let callsiteSourcesIndex = 0;
let callsiteLine = 0;
let callsiteColumn = 0;
let bindingLine = 0;
let bindingColumn = 0;
do {
const semi = reader.indexOf(";");
let genColumn = 0;
for (; reader.pos < semi; reader.pos++) {
genColumn = decodeInteger(reader, genColumn);
if (!hasMoreVlq(reader, semi)) {
const last = stack.pop();
last[2] = genLine;
last[3] = genColumn;
continue;
}
const fields = decodeInteger(reader, 0);
const hasDefinition = fields & 1;
const hasCallsite = fields & 2;
const hasScope = fields & 4;
let callsite = null;
let bindings = EMPTY;
let range;
if (hasDefinition) {
const defSourcesIndex = decodeInteger(reader, definitionSourcesIndex);
definitionScopeIndex = decodeInteger(
reader,
definitionSourcesIndex === defSourcesIndex ? definitionScopeIndex : 0
);
definitionSourcesIndex = defSourcesIndex;
range = [genLine, genColumn, 0, 0, defSourcesIndex, definitionScopeIndex];
} else {
range = [genLine, genColumn, 0, 0];
}
range.isScope = !!hasScope;
if (hasCallsite) {
const prevCsi = callsiteSourcesIndex;
const prevLine = callsiteLine;
callsiteSourcesIndex = decodeInteger(reader, callsiteSourcesIndex);
const sameSource = prevCsi === callsiteSourcesIndex;
callsiteLine = decodeInteger(reader, sameSource ? callsiteLine : 0);
callsiteColumn = decodeInteger(
reader,
sameSource && prevLine === callsiteLine ? callsiteColumn : 0
);
callsite = [callsiteSourcesIndex, callsiteLine, callsiteColumn];
}
range.callsite = callsite;
if (hasMoreVlq(reader, semi)) {
bindings = [];
do {
bindingLine = genLine;
bindingColumn = genColumn;
const expressionsCount = decodeInteger(reader, 0);
let expressionRanges;
if (expressionsCount < -1) {
expressionRanges = [[decodeInteger(reader, 0)]];
for (let i = -1; i > expressionsCount; i--) {
const prevBl = bindingLine;
bindingLine = decodeInteger(reader, bindingLine);
bindingColumn = decodeInteger(reader, bindingLine === prevBl ? bindingColumn : 0);
const expression = decodeInteger(reader, 0);
expressionRanges.push([expression, bindingLine, bindingColumn]);
}
} else {
expressionRanges = [[expressionsCount]];
}
bindings.push(expressionRanges);
} while (hasMoreVlq(reader, semi));
}
range.bindings = bindings;
ranges.push(range);
stack.push(range);
}
genLine++;
reader.pos = semi + 1;
} while (reader.pos < length);
return ranges;
}
function encodeGeneratedRanges(ranges) {
if (ranges.length === 0) return "";
const writer = new StringWriter();
for (let i = 0; i < ranges.length; ) {
i = _encodeGeneratedRanges(ranges, i, writer, [0, 0, 0, 0, 0, 0, 0]);
}
return writer.flush();
}
function _encodeGeneratedRanges(ranges, index, writer, state) {
const range = ranges[index];
const {
0: startLine,
1: startColumn,
2: endLine,
3: endColumn,
isScope,
callsite,
bindings
} = range;
if (state[0] < startLine) {
catchupLine(writer, state[0], startLine);
state[0] = startLine;
state[1] = 0;
} else if (index > 0) {
writer.write(comma);
}
state[1] = encodeInteger(writer, range[1], state[1]);
const fields = (range.length === 6 ? 1 : 0) | (callsite ? 2 : 0) | (isScope ? 4 : 0);
encodeInteger(writer, fields, 0);
if (range.length === 6) {
const { 4: sourcesIndex, 5: scopesIndex } = range;
if (sourcesIndex !== state[2]) {
state[3] = 0;
}
state[2] = encodeInteger(writer, sourcesIndex, state[2]);
state[3] = encodeInteger(writer, scopesIndex, state[3]);
}
if (callsite) {
const { 0: sourcesIndex, 1: callLine, 2: callColumn } = range.callsite;
if (sourcesIndex !== state[4]) {
state[5] = 0;
state[6] = 0;
} else if (callLine !== state[5]) {
state[6] = 0;
}
state[4] = encodeInteger(writer, sourcesIndex, state[4]);
state[5] = encodeInteger(writer, callLine, state[5]);
state[6] = encodeInteger(writer, callColumn, state[6]);
}
if (bindings) {
for (const binding of bindings) {
if (binding.length > 1) encodeInteger(writer, -binding.length, 0);
const expression = binding[0][0];
encodeInteger(writer, expression, 0);
let bindingStartLine = startLine;
let bindingStartColumn = startColumn;
for (let i = 1; i < binding.length; i++) {
const expRange = binding[i];
bindingStartLine = encodeInteger(writer, expRange[1], bindingStartLine);
bindingStartColumn = encodeInteger(writer, expRange[2], bindingStartColumn);
encodeInteger(writer, expRange[0], 0);
}
}
}
for (index++; index < ranges.length; ) {
const next = ranges[index];
const { 0: l, 1: c } = next;
if (l > endLine || l === endLine && c >= endColumn) {
break;
}
index = _encodeGeneratedRanges(ranges, index, writer, state);
}
if (state[0] < endLine) {
catchupLine(writer, state[0], endLine);
state[0] = endLine;
state[1] = 0;
} else {
writer.write(comma);
}
state[1] = encodeInteger(writer, endColumn, state[1]);
return index;
}
function catchupLine(writer, lastLine, line) {
do {
writer.write(semicolon);
} while (++lastLine < line);
}
// src/sourcemap-codec.ts
function decode(mappings) {
const { length } = mappings;
const reader = new StringReader(mappings);
const decoded = [];
let genColumn = 0;
let sourcesIndex = 0;
let sourceLine = 0;
let sourceColumn = 0;
let namesIndex = 0;
do {
const semi = reader.indexOf(";");
const line = [];
let sorted = true;
let lastCol = 0;
genColumn = 0;
while (reader.pos < semi) {
let seg;
genColumn = decodeInteger(reader, genColumn);
if (genColumn < lastCol) sorted = false;
lastCol = genColumn;
if (hasMoreVlq(reader, semi)) {
sourcesIndex = decodeInteger(reader, sourcesIndex);
sourceLine = decodeInteger(reader, sourceLine);
sourceColumn = decodeInteger(reader, sourceColumn);
if (hasMoreVlq(reader, semi)) {
namesIndex = decodeInteger(reader, namesIndex);
seg = [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex];
} else {
seg = [genColumn, sourcesIndex, sourceLine, sourceColumn];
}
} else {
seg = [genColumn];
}
line.push(seg);
reader.pos++;
}
if (!sorted) sort(line);
decoded.push(line);
reader.pos = semi + 1;
} while (reader.pos <= length);
return decoded;
}
function sort(line) {
line.sort(sortComparator);
}
function sortComparator(a, b) {
return a[0] - b[0];
}
function encode(decoded) {
const writer = new StringWriter();
let sourcesIndex = 0;
let sourceLine = 0;
let sourceColumn = 0;
let namesIndex = 0;
for (let i = 0; i < decoded.length; i++) {
const line = decoded[i];
if (i > 0) writer.write(semicolon);
if (line.length === 0) continue;
let genColumn = 0;
for (let j = 0; j < line.length; j++) {
const segment = line[j];
if (j > 0) writer.write(comma);
genColumn = encodeInteger(writer, segment[0], genColumn);
if (segment.length === 1) continue;
sourcesIndex = encodeInteger(writer, segment[1], sourcesIndex);
sourceLine = encodeInteger(writer, segment[2], sourceLine);
sourceColumn = encodeInteger(writer, segment[3], sourceColumn);
if (segment.length === 4) continue;
namesIndex = encodeInteger(writer, segment[4], namesIndex);
}
}
return writer.flush();
}
}));
//# sourceMappingURL=sourcemap-codec.umd.js.map

View File

@@ -0,0 +1,12 @@
import type { TSESLint } from '@typescript-eslint/utils';
type AllowedSingleElementEquality = 'always' | 'never';
export type Options = [
{
allowSingleElementEquality?: AllowedSingleElementEquality;
}
];
export type MessageIds = 'preferEndsWith' | 'preferStartsWith';
declare const _default: TSESLint.RuleModule<MessageIds, Options, import("../../rules").ESLintPluginDocs, TSESLint.RuleListener> & {
name: string;
};
export default _default;

View File

@@ -0,0 +1,11 @@
const pino = require("../../../../");
module.exports = function() {
const logger = pino(
pino.transport({
target: 'pino/file'
})
)
logger.info('done!')
}

View File

@@ -0,0 +1,7 @@
var stringify = require('../');
var obj = { d: 6, c: 5, b: [{z:3,y:2,x:1},9], a: 10 };
var s = stringify(obj, function (a, b) {
return a.value < b.value ? 1 : -1;
});
console.log(s);

View File

@@ -0,0 +1,19 @@
name: Lock Threads
on:
schedule:
- cron: '0 0 1 * *'
workflow_dispatch:
concurrency:
group: lock
permissions:
contents: read
jobs:
lock-threads:
permissions:
issues: write
pull-requests: write
uses: fastify/workflows/.github/workflows/lock-threads.yml@2073dc8e1f9e172bf42daa3843c9dbd31af1e8cb # v6.0.0

View File

@@ -0,0 +1,13 @@
import type { TSESTree } from '@typescript-eslint/types';
import type { Referencer } from './Referencer';
import { Visitor } from './Visitor';
export type ExportNode = TSESTree.ExportAllDeclaration | TSESTree.ExportDefaultDeclaration | TSESTree.ExportNamedDeclaration;
export declare class ExportVisitor extends Visitor {
#private;
constructor(node: ExportNode, referencer: Referencer);
static visit(referencer: Referencer, node: ExportNode): void;
protected ExportDefaultDeclaration(node: TSESTree.ExportDefaultDeclaration): void;
protected ExportNamedDeclaration(node: TSESTree.ExportNamedDeclaration): void;
protected ExportSpecifier(node: TSESTree.ExportSpecifier): void;
protected Identifier(node: TSESTree.Identifier): void;
}

View File

@@ -0,0 +1,91 @@
/**
* @fileoverview Rule to flag references to the undefined variable.
* @author Michael Ficarra
*/
"use strict";
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
/** @typedef {import("eslint-scope").Scope} Scope */
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "Disallow the use of `undefined` as an identifier",
recommended: false,
frozen: true,
url: "https://eslint.org/docs/latest/rules/no-undefined",
},
schema: [],
messages: {
unexpectedUndefined: "Unexpected use of undefined.",
},
},
create(context) {
const sourceCode = context.sourceCode;
/**
* Report an invalid "undefined" identifier node.
* @param {ASTNode} node The node to report.
* @returns {void}
*/
function report(node) {
context.report({
node,
messageId: "unexpectedUndefined",
});
}
/**
* Checks the given scope for references to `undefined` and reports
* all references found.
* @param {Scope} scope The scope to check.
* @returns {void}
*/
function checkScope(scope) {
const undefinedVar = scope.set.get("undefined");
if (!undefinedVar) {
return;
}
const references = undefinedVar.references;
const defs = undefinedVar.defs;
// Report non-initializing references (those are covered in defs below)
references
.filter(ref => !ref.init)
.forEach(ref => report(ref.identifier));
defs.forEach(def => report(def.name));
}
return {
"Program:exit"(node) {
const globalScope = sourceCode.getScope(node);
const stack = [globalScope];
while (stack.length) {
const scope = stack.pop();
stack.push(...scope.childScopes);
checkScope(scope);
}
},
};
},
};

View File

@@ -0,0 +1,841 @@
// parse a single path portion
var _a;
import { parseClass } from './brace-expressions.js';
import { unescape } from './unescape.js';
const types = new Set(['!', '?', '+', '*', '@']);
const isExtglobType = (c) => types.has(c);
const isExtglobAST = (c) => isExtglobType(c.type);
// Map of which extglob types can adopt the children of a nested extglob
//
// anything but ! can adopt a matching type:
// +(a|+(b|c)|d) => +(a|b|c|d)
// *(a|*(b|c)|d) => *(a|b|c|d)
// @(a|@(b|c)|d) => @(a|b|c|d)
// ?(a|?(b|c)|d) => ?(a|b|c|d)
//
// * can adopt anything, because 0 or repetition is allowed
// *(a|?(b|c)|d) => *(a|b|c|d)
// *(a|+(b|c)|d) => *(a|b|c|d)
// *(a|@(b|c)|d) => *(a|b|c|d)
//
// + can adopt @, because 1 or repetition is allowed
// +(a|@(b|c)|d) => +(a|b|c|d)
//
// + and @ CANNOT adopt *, because 0 would be allowed
// +(a|*(b|c)|d) => would match "", on *(b|c)
// @(a|*(b|c)|d) => would match "", on *(b|c)
//
// + and @ CANNOT adopt ?, because 0 would be allowed
// +(a|?(b|c)|d) => would match "", on ?(b|c)
// @(a|?(b|c)|d) => would match "", on ?(b|c)
//
// ? can adopt @, because 0 or 1 is allowed
// ?(a|@(b|c)|d) => ?(a|b|c|d)
//
// ? and @ CANNOT adopt * or +, because >1 would be allowed
// ?(a|*(b|c)|d) => would match bbb on *(b|c)
// @(a|*(b|c)|d) => would match bbb on *(b|c)
// ?(a|+(b|c)|d) => would match bbb on +(b|c)
// @(a|+(b|c)|d) => would match bbb on +(b|c)
//
// ! CANNOT adopt ! (nothing else can either)
// !(a|!(b|c)|d) => !(a|b|c|d) would fail to match on b (not not b|c)
//
// ! can adopt @
// !(a|@(b|c)|d) => !(a|b|c|d)
//
// ! CANNOT adopt *
// !(a|*(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
//
// ! CANNOT adopt +
// !(a|+(b|c)|d) => !(a|b|c|d) would match on bbb, not allowed
//
// ! CANNOT adopt ?
// x!(a|?(b|c)|d) => x!(a|b|c|d) would fail to match "x"
const adoptionMap = new Map([
['!', ['@']],
['?', ['?', '@']],
['@', ['@']],
['*', ['*', '+', '?', '@']],
['+', ['+', '@']],
]);
// nested extglobs that can be adopted in, but with the addition of
// a blank '' element.
const adoptionWithSpaceMap = new Map([
['!', ['?']],
['@', ['?']],
['+', ['?', '*']],
]);
// union of the previous two maps
const adoptionAnyMap = new Map([
['!', ['?', '@']],
['?', ['?', '@']],
['@', ['?', '@']],
['*', ['*', '+', '?', '@']],
['+', ['+', '@', '?', '*']],
]);
// Extglobs that can take over their parent if they are the only child
// the key is parent, value maps child to resulting extglob parent type
// '@' is omitted because it's a special case. An `@` extglob with a single
// member can always be usurped by that subpattern.
const usurpMap = new Map([
['!', new Map([['!', '@']])],
[
'?',
new Map([
['*', '*'],
['+', '*'],
]),
],
[
'@',
new Map([
['!', '!'],
['?', '?'],
['@', '@'],
['*', '*'],
['+', '+'],
]),
],
[
'+',
new Map([
['?', '*'],
['*', '*'],
]),
],
]);
// Patterns that get prepended to bind to the start of either the
// entire string, or just a single path portion, to prevent dots
// and/or traversal patterns, when needed.
// Exts don't need the ^ or / bit, because the root binds that already.
const startNoTraversal = '(?!(?:^|/)\\.\\.?(?:$|/))';
const startNoDot = '(?!\\.)';
// characters that indicate a start of pattern needs the "no dots" bit,
// because a dot *might* be matched. ( is not in the list, because in
// the case of a child extglob, it will handle the prevention itself.
const addPatternStart = new Set(['[', '.']);
// cases where traversal is A-OK, no dot prevention needed
const justDots = new Set(['..', '.']);
const reSpecials = new Set('().*{}+?[]^$\\!');
const regExpEscape = (s) => s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
// any single thing other than /
const qmark = '[^/]';
// * => any number of characters
const star = qmark + '*?';
// use + when we need to ensure that *something* matches, because the * is
// the only thing in the path portion.
const starNoEmpty = qmark + '+?';
// remove the \ chars that we added if we end up doing a nonmagic compare
// const deslash = (s: string) => s.replace(/\\(.)/g, '$1')
let ID = 0;
export class AST {
type;
#root;
#hasMagic;
#uflag = false;
#parts = [];
#parent;
#parentIndex;
#negs;
#filledNegs = false;
#options;
#toString;
// set to true if it's an extglob with no children
// (which really means one child of '')
#emptyExt = false;
id = ++ID;
get depth() {
return (this.#parent?.depth ?? -1) + 1;
}
[Symbol.for('nodejs.util.inspect.custom')]() {
return {
'@@type': 'AST',
id: this.id,
type: this.type,
root: this.#root.id,
parent: this.#parent?.id,
depth: this.depth,
partsLength: this.#parts.length,
parts: this.#parts,
};
}
constructor(type, parent, options = {}) {
this.type = type;
// extglobs are inherently magical
if (type)
this.#hasMagic = true;
this.#parent = parent;
this.#root = this.#parent ? this.#parent.#root : this;
this.#options = this.#root === this ? options : this.#root.#options;
this.#negs = this.#root === this ? [] : this.#root.#negs;
if (type === '!' && !this.#root.#filledNegs)
this.#negs.push(this);
this.#parentIndex = this.#parent ? this.#parent.#parts.length : 0;
}
get hasMagic() {
/* c8 ignore start */
if (this.#hasMagic !== undefined)
return this.#hasMagic;
/* c8 ignore stop */
for (const p of this.#parts) {
if (typeof p === 'string')
continue;
if (p.type || p.hasMagic)
return (this.#hasMagic = true);
}
// note: will be undefined until we generate the regexp src and find out
return this.#hasMagic;
}
// reconstructs the pattern
toString() {
return (this.#toString !== undefined ? this.#toString
: !this.type ?
(this.#toString = this.#parts.map(p => String(p)).join(''))
: (this.#toString =
this.type +
'(' +
this.#parts.map(p => String(p)).join('|') +
')'));
}
#fillNegs() {
/* c8 ignore start */
if (this !== this.#root)
throw new Error('should only call on root');
if (this.#filledNegs)
return this;
/* c8 ignore stop */
// call toString() once to fill this out
this.toString();
this.#filledNegs = true;
let n;
while ((n = this.#negs.pop())) {
if (n.type !== '!')
continue;
// walk up the tree, appending everthing that comes AFTER parentIndex
let p = n;
let pp = p.#parent;
while (pp) {
for (let i = p.#parentIndex + 1; !pp.type && i < pp.#parts.length; i++) {
for (const part of n.#parts) {
/* c8 ignore start */
if (typeof part === 'string') {
throw new Error('string part in extglob AST??');
}
/* c8 ignore stop */
part.copyIn(pp.#parts[i]);
}
}
p = pp;
pp = p.#parent;
}
}
return this;
}
push(...parts) {
for (const p of parts) {
if (p === '')
continue;
/* c8 ignore start */
if (typeof p !== 'string' &&
!(p instanceof _a && p.#parent === this)) {
throw new Error('invalid part: ' + p);
}
/* c8 ignore stop */
this.#parts.push(p);
}
}
toJSON() {
const ret = this.type === null ?
this.#parts
.slice()
.map(p => (typeof p === 'string' ? p : p.toJSON()))
: [this.type, ...this.#parts.map(p => p.toJSON())];
if (this.isStart() && !this.type)
ret.unshift([]);
if (this.isEnd() &&
(this === this.#root ||
(this.#root.#filledNegs && this.#parent?.type === '!'))) {
ret.push({});
}
return ret;
}
isStart() {
if (this.#root === this)
return true;
// if (this.type) return !!this.#parent?.isStart()
if (!this.#parent?.isStart())
return false;
if (this.#parentIndex === 0)
return true;
// if everything AHEAD of this is a negation, then it's still the "start"
const p = this.#parent;
for (let i = 0; i < this.#parentIndex; i++) {
const pp = p.#parts[i];
if (!(pp instanceof _a && pp.type === '!')) {
return false;
}
}
return true;
}
isEnd() {
if (this.#root === this)
return true;
if (this.#parent?.type === '!')
return true;
if (!this.#parent?.isEnd())
return false;
if (!this.type)
return this.#parent?.isEnd();
// if not root, it'll always have a parent
/* c8 ignore start */
const pl = this.#parent ? this.#parent.#parts.length : 0;
/* c8 ignore stop */
return this.#parentIndex === pl - 1;
}
copyIn(part) {
if (typeof part === 'string')
this.push(part);
else
this.push(part.clone(this));
}
clone(parent) {
const c = new _a(this.type, parent);
for (const p of this.#parts) {
c.copyIn(p);
}
return c;
}
static #parseAST(str, ast, pos, opt, extDepth) {
const maxDepth = opt.maxExtglobRecursion ?? 2;
let escaping = false;
let inBrace = false;
let braceStart = -1;
let braceNeg = false;
if (ast.type === null) {
// outside of a extglob, append until we find a start
let i = pos;
let acc = '';
while (i < str.length) {
const c = str.charAt(i++);
// still accumulate escapes at this point, but we do ignore
// starts that are escaped
if (escaping || c === '\\') {
escaping = !escaping;
acc += c;
continue;
}
if (inBrace) {
if (i === braceStart + 1) {
if (c === '^' || c === '!') {
braceNeg = true;
}
}
else if (c === ']' && !(i === braceStart + 2 && braceNeg)) {
inBrace = false;
}
acc += c;
continue;
}
else if (c === '[') {
inBrace = true;
braceStart = i;
braceNeg = false;
acc += c;
continue;
}
// we don't have to check for adoption here, because that's
// done at the other recursion point.
const doRecurse = !opt.noext &&
isExtglobType(c) &&
str.charAt(i) === '(' &&
extDepth <= maxDepth;
if (doRecurse) {
ast.push(acc);
acc = '';
const ext = new _a(c, ast);
i = _a.#parseAST(str, ext, i, opt, extDepth + 1);
ast.push(ext);
continue;
}
acc += c;
}
ast.push(acc);
return i;
}
// some kind of extglob, pos is at the (
// find the next | or )
let i = pos + 1;
let part = new _a(null, ast);
const parts = [];
let acc = '';
while (i < str.length) {
const c = str.charAt(i++);
// still accumulate escapes at this point, but we do ignore
// starts that are escaped
if (escaping || c === '\\') {
escaping = !escaping;
acc += c;
continue;
}
if (inBrace) {
if (i === braceStart + 1) {
if (c === '^' || c === '!') {
braceNeg = true;
}
}
else if (c === ']' && !(i === braceStart + 2 && braceNeg)) {
inBrace = false;
}
acc += c;
continue;
}
else if (c === '[') {
inBrace = true;
braceStart = i;
braceNeg = false;
acc += c;
continue;
}
const doRecurse = !opt.noext &&
isExtglobType(c) &&
str.charAt(i) === '(' &&
/* c8 ignore start - the maxDepth is sufficient here */
(extDepth <= maxDepth || (ast && ast.#canAdoptType(c)));
/* c8 ignore stop */
if (doRecurse) {
const depthAdd = ast && ast.#canAdoptType(c) ? 0 : 1;
part.push(acc);
acc = '';
const ext = new _a(c, part);
part.push(ext);
i = _a.#parseAST(str, ext, i, opt, extDepth + depthAdd);
continue;
}
if (c === '|') {
part.push(acc);
acc = '';
parts.push(part);
part = new _a(null, ast);
continue;
}
if (c === ')') {
if (acc === '' && ast.#parts.length === 0) {
ast.#emptyExt = true;
}
part.push(acc);
acc = '';
ast.push(...parts, part);
return i;
}
acc += c;
}
// unfinished extglob
// if we got here, it was a malformed extglob! not an extglob, but
// maybe something else in there.
ast.type = null;
ast.#hasMagic = undefined;
ast.#parts = [str.substring(pos - 1)];
return i;
}
#canAdoptWithSpace(child) {
return this.#canAdopt(child, adoptionWithSpaceMap);
}
#canAdopt(child, map = adoptionMap) {
if (!child ||
typeof child !== 'object' ||
child.type !== null ||
child.#parts.length !== 1 ||
this.type === null) {
return false;
}
const gc = child.#parts[0];
if (!gc || typeof gc !== 'object' || gc.type === null) {
return false;
}
return this.#canAdoptType(gc.type, map);
}
#canAdoptType(c, map = adoptionAnyMap) {
return !!map.get(this.type)?.includes(c);
}
#adoptWithSpace(child, index) {
const gc = child.#parts[0];
const blank = new _a(null, gc, this.options);
blank.#parts.push('');
gc.push(blank);
this.#adopt(child, index);
}
#adopt(child, index) {
const gc = child.#parts[0];
this.#parts.splice(index, 1, ...gc.#parts);
for (const p of gc.#parts) {
if (typeof p === 'object')
p.#parent = this;
}
this.#toString = undefined;
}
#canUsurpType(c) {
const m = usurpMap.get(this.type);
return !!m?.has(c);
}
#canUsurp(child) {
if (!child ||
typeof child !== 'object' ||
child.type !== null ||
child.#parts.length !== 1 ||
this.type === null ||
this.#parts.length !== 1) {
return false;
}
const gc = child.#parts[0];
if (!gc || typeof gc !== 'object' || gc.type === null) {
return false;
}
return this.#canUsurpType(gc.type);
}
#usurp(child) {
const m = usurpMap.get(this.type);
const gc = child.#parts[0];
const nt = m?.get(gc.type);
/* c8 ignore start - impossible */
if (!nt)
return false;
/* c8 ignore stop */
this.#parts = gc.#parts;
for (const p of this.#parts) {
if (typeof p === 'object') {
p.#parent = this;
}
}
this.type = nt;
this.#toString = undefined;
this.#emptyExt = false;
}
static fromGlob(pattern, options = {}) {
const ast = new _a(null, undefined, options);
_a.#parseAST(pattern, ast, 0, options, 0);
return ast;
}
// returns the regular expression if there's magic, or the unescaped
// string if not.
toMMPattern() {
// should only be called on root
/* c8 ignore start */
if (this !== this.#root)
return this.#root.toMMPattern();
/* c8 ignore stop */
const glob = this.toString();
const [re, body, hasMagic, uflag] = this.toRegExpSource();
// if we're in nocase mode, and not nocaseMagicOnly, then we do
// still need a regular expression if we have to case-insensitively
// match capital/lowercase characters.
const anyMagic = hasMagic ||
this.#hasMagic ||
(this.#options.nocase &&
!this.#options.nocaseMagicOnly &&
glob.toUpperCase() !== glob.toLowerCase());
if (!anyMagic) {
return body;
}
const flags = (this.#options.nocase ? 'i' : '') + (uflag ? 'u' : '');
return Object.assign(new RegExp(`^${re}$`, flags), {
_src: re,
_glob: glob,
});
}
get options() {
return this.#options;
}
// returns the string match, the regexp source, whether there's magic
// in the regexp (so a regular expression is required) and whether or
// not the uflag is needed for the regular expression (for posix classes)
// TODO: instead of injecting the start/end at this point, just return
// the BODY of the regexp, along with the start/end portions suitable
// for binding the start/end in either a joined full-path makeRe context
// (where we bind to (^|/), or a standalone matchPart context (where
// we bind to ^, and not /). Otherwise slashes get duped!
//
// In part-matching mode, the start is:
// - if not isStart: nothing
// - if traversal possible, but not allowed: ^(?!\.\.?$)
// - if dots allowed or not possible: ^
// - if dots possible and not allowed: ^(?!\.)
// end is:
// - if not isEnd(): nothing
// - else: $
//
// In full-path matching mode, we put the slash at the START of the
// pattern, so start is:
// - if first pattern: same as part-matching mode
// - if not isStart(): nothing
// - if traversal possible, but not allowed: /(?!\.\.?(?:$|/))
// - if dots allowed or not possible: /
// - if dots possible and not allowed: /(?!\.)
// end is:
// - if last pattern, same as part-matching mode
// - else nothing
//
// Always put the (?:$|/) on negated tails, though, because that has to be
// there to bind the end of the negated pattern portion, and it's easier to
// just stick it in now rather than try to inject it later in the middle of
// the pattern.
//
// We can just always return the same end, and leave it up to the caller
// to know whether it's going to be used joined or in parts.
// And, if the start is adjusted slightly, can do the same there:
// - if not isStart: nothing
// - if traversal possible, but not allowed: (?:/|^)(?!\.\.?$)
// - if dots allowed or not possible: (?:/|^)
// - if dots possible and not allowed: (?:/|^)(?!\.)
//
// But it's better to have a simpler binding without a conditional, for
// performance, so probably better to return both start options.
//
// Then the caller just ignores the end if it's not the first pattern,
// and the start always gets applied.
//
// But that's always going to be $ if it's the ending pattern, or nothing,
// so the caller can just attach $ at the end of the pattern when building.
//
// So the todo is:
// - better detect what kind of start is needed
// - return both flavors of starting pattern
// - attach $ at the end of the pattern when creating the actual RegExp
//
// Ah, but wait, no, that all only applies to the root when the first pattern
// is not an extglob. If the first pattern IS an extglob, then we need all
// that dot prevention biz to live in the extglob portions, because eg
// +(*|.x*) can match .xy but not .yx.
//
// So, return the two flavors if it's #root and the first child is not an
// AST, otherwise leave it to the child AST to handle it, and there,
// use the (?:^|/) style of start binding.
//
// Even simplified further:
// - Since the start for a join is eg /(?!\.) and the start for a part
// is ^(?!\.), we can just prepend (?!\.) to the pattern (either root
// or start or whatever) and prepend ^ or / at the Regexp construction.
toRegExpSource(allowDot) {
const dot = allowDot ?? !!this.#options.dot;
if (this.#root === this) {
this.#flatten();
this.#fillNegs();
}
if (!isExtglobAST(this)) {
const noEmpty = this.isStart() &&
this.isEnd() &&
!this.#parts.some(s => typeof s !== 'string');
const src = this.#parts
.map(p => {
const [re, _, hasMagic, uflag] = typeof p === 'string' ?
_a.#parseGlob(p, this.#hasMagic, noEmpty)
: p.toRegExpSource(allowDot);
this.#hasMagic = this.#hasMagic || hasMagic;
this.#uflag = this.#uflag || uflag;
return re;
})
.join('');
let start = '';
if (this.isStart()) {
if (typeof this.#parts[0] === 'string') {
// this is the string that will match the start of the pattern,
// so we need to protect against dots and such.
// '.' and '..' cannot match unless the pattern is that exactly,
// even if it starts with . or dot:true is set.
const dotTravAllowed = this.#parts.length === 1 && justDots.has(this.#parts[0]);
if (!dotTravAllowed) {
const aps = addPatternStart;
// check if we have a possibility of matching . or ..,
// and prevent that.
const needNoTrav =
// dots are allowed, and the pattern starts with [ or .
(dot && aps.has(src.charAt(0))) ||
// the pattern starts with \., and then [ or .
(src.startsWith('\\.') && aps.has(src.charAt(2))) ||
// the pattern starts with \.\., and then [ or .
(src.startsWith('\\.\\.') && aps.has(src.charAt(4)));
// no need to prevent dots if it can't match a dot, or if a
// sub-pattern will be preventing it anyway.
const needNoDot = !dot && !allowDot && aps.has(src.charAt(0));
start =
needNoTrav ? startNoTraversal
: needNoDot ? startNoDot
: '';
}
}
}
// append the "end of path portion" pattern to negation tails
let end = '';
if (this.isEnd() &&
this.#root.#filledNegs &&
this.#parent?.type === '!') {
end = '(?:$|\\/)';
}
const final = start + src + end;
return [
final,
unescape(src),
(this.#hasMagic = !!this.#hasMagic),
this.#uflag,
];
}
// We need to calculate the body *twice* if it's a repeat pattern
// at the start, once in nodot mode, then again in dot mode, so a
// pattern like *(?) can match 'x.y'
const repeated = this.type === '*' || this.type === '+';
// some kind of extglob
const start = this.type === '!' ? '(?:(?!(?:' : '(?:';
let body = this.#partsToRegExp(dot);
if (this.isStart() && this.isEnd() && !body && this.type !== '!') {
// invalid extglob, has to at least be *something* present, if it's
// the entire path portion.
const s = this.toString();
const me = this;
me.#parts = [s];
me.type = null;
me.#hasMagic = undefined;
return [s, unescape(this.toString()), false, false];
}
let bodyDotAllowed = !repeated || allowDot || dot || !startNoDot ?
''
: this.#partsToRegExp(true);
if (bodyDotAllowed === body) {
bodyDotAllowed = '';
}
if (bodyDotAllowed) {
body = `(?:${body})(?:${bodyDotAllowed})*?`;
}
// an empty !() is exactly equivalent to a starNoEmpty
let final = '';
if (this.type === '!' && this.#emptyExt) {
final = (this.isStart() && !dot ? startNoDot : '') + starNoEmpty;
}
else {
const close = this.type === '!' ?
// !() must match something,but !(x) can match ''
'))' +
(this.isStart() && !dot && !allowDot ? startNoDot : '') +
star +
')'
: this.type === '@' ? ')'
: this.type === '?' ? ')?'
: this.type === '+' && bodyDotAllowed ? ')'
: this.type === '*' && bodyDotAllowed ? `)?`
: `)${this.type}`;
final = start + body + close;
}
return [
final,
unescape(body),
(this.#hasMagic = !!this.#hasMagic),
this.#uflag,
];
}
#flatten() {
if (!isExtglobAST(this)) {
for (const p of this.#parts) {
if (typeof p === 'object') {
p.#flatten();
}
}
}
else {
// do up to 10 passes to flatten as much as possible
let iterations = 0;
let done = false;
do {
done = true;
for (let i = 0; i < this.#parts.length; i++) {
const c = this.#parts[i];
if (typeof c === 'object') {
c.#flatten();
if (this.#canAdopt(c)) {
done = false;
this.#adopt(c, i);
}
else if (this.#canAdoptWithSpace(c)) {
done = false;
this.#adoptWithSpace(c, i);
}
else if (this.#canUsurp(c)) {
done = false;
this.#usurp(c);
}
}
}
} while (!done && ++iterations < 10);
}
this.#toString = undefined;
}
#partsToRegExp(dot) {
return this.#parts
.map(p => {
// extglob ASTs should only contain parent ASTs
/* c8 ignore start */
if (typeof p === 'string') {
throw new Error('string type in extglob ast??');
}
/* c8 ignore stop */
// can ignore hasMagic, because extglobs are already always magic
const [re, _, _hasMagic, uflag] = p.toRegExpSource(dot);
this.#uflag = this.#uflag || uflag;
return re;
})
.filter(p => !(this.isStart() && this.isEnd()) || !!p)
.join('|');
}
static #parseGlob(glob, hasMagic, noEmpty = false) {
let escaping = false;
let re = '';
let uflag = false;
// multiple stars that aren't globstars coalesce into one *
let inStar = false;
for (let i = 0; i < glob.length; i++) {
const c = glob.charAt(i);
if (escaping) {
escaping = false;
re += (reSpecials.has(c) ? '\\' : '') + c;
continue;
}
if (c === '*') {
if (inStar)
continue;
inStar = true;
re += noEmpty && /^[*]+$/.test(glob) ? starNoEmpty : star;
hasMagic = true;
continue;
}
else {
inStar = false;
}
if (c === '\\') {
if (i === glob.length - 1) {
re += '\\\\';
}
else {
escaping = true;
}
continue;
}
if (c === '[') {
const [src, needUflag, consumed, magic] = parseClass(glob, i);
if (consumed) {
re += src;
uflag = uflag || needUflag;
i += consumed - 1;
hasMagic = hasMagic || magic;
continue;
}
}
if (c === '?') {
re += qmark;
hasMagic = true;
continue;
}
re += regExpEscape(c);
}
return [re, unescape(glob), !!hasMagic, uflag];
}
}
_a = AST;
//# sourceMappingURL=ast.js.map

View File

@@ -0,0 +1,73 @@
'use strict';
module.exports = function generate_anyOf(it, $keyword, $ruleType) {
var out = ' ';
var $lvl = it.level;
var $dataLvl = it.dataLevel;
var $schema = it.schema[$keyword];
var $schemaPath = it.schemaPath + it.util.getProperty($keyword);
var $errSchemaPath = it.errSchemaPath + '/' + $keyword;
var $breakOnError = !it.opts.allErrors;
var $data = 'data' + ($dataLvl || '');
var $valid = 'valid' + $lvl;
var $errs = 'errs__' + $lvl;
var $it = it.util.copy(it);
var $closingBraces = '';
$it.level++;
var $nextValid = 'valid' + $it.level;
var $noEmptySchema = $schema.every(function($sch) {
return (it.opts.strictKeywords ? (typeof $sch == 'object' && Object.keys($sch).length > 0) || $sch === false : it.util.schemaHasRules($sch, it.RULES.all));
});
if ($noEmptySchema) {
var $currentBaseId = $it.baseId;
out += ' var ' + ($errs) + ' = errors; var ' + ($valid) + ' = false; ';
var $wasComposite = it.compositeRule;
it.compositeRule = $it.compositeRule = true;
var arr1 = $schema;
if (arr1) {
var $sch, $i = -1,
l1 = arr1.length - 1;
while ($i < l1) {
$sch = arr1[$i += 1];
$it.schema = $sch;
$it.schemaPath = $schemaPath + '[' + $i + ']';
$it.errSchemaPath = $errSchemaPath + '/' + $i;
out += ' ' + (it.validate($it)) + ' ';
$it.baseId = $currentBaseId;
out += ' ' + ($valid) + ' = ' + ($valid) + ' || ' + ($nextValid) + '; if (!' + ($valid) + ') { ';
$closingBraces += '}';
}
}
it.compositeRule = $it.compositeRule = $wasComposite;
out += ' ' + ($closingBraces) + ' if (!' + ($valid) + ') { var err = '; /* istanbul ignore else */
if (it.createErrors !== false) {
out += ' { keyword: \'' + ('anyOf') + '\' , dataPath: (dataPath || \'\') + ' + (it.errorPath) + ' , schemaPath: ' + (it.util.toQuotedString($errSchemaPath)) + ' , params: {} ';
if (it.opts.messages !== false) {
out += ' , message: \'should match some schema in anyOf\' ';
}
if (it.opts.verbose) {
out += ' , schema: validate.schema' + ($schemaPath) + ' , parentSchema: validate.schema' + (it.schemaPath) + ' , data: ' + ($data) + ' ';
}
out += ' } ';
} else {
out += ' {} ';
}
out += '; if (vErrors === null) vErrors = [err]; else vErrors.push(err); errors++; ';
if (!it.compositeRule && $breakOnError) {
/* istanbul ignore if */
if (it.async) {
out += ' throw new ValidationError(vErrors); ';
} else {
out += ' validate.errors = vErrors; return false; ';
}
}
out += ' } else { errors = ' + ($errs) + '; if (vErrors !== null) { if (' + ($errs) + ') vErrors.length = ' + ($errs) + '; else vErrors = null; } ';
if (it.opts.allErrors) {
out += ' } ';
}
} else {
if ($breakOnError) {
out += ' if (true) { ';
}
}
return out;
}

View File

@@ -0,0 +1,125 @@
import Dispatcher from './dispatcher'
export default RetryHandler
declare class RetryHandler implements Dispatcher.DispatchHandler {
constructor (
options: Dispatcher.DispatchOptions & {
retryOptions?: RetryHandler.RetryOptions;
},
retryHandlers: RetryHandler.RetryHandlers
)
}
declare namespace RetryHandler {
export type RetryState = { counter: number; }
export type RetryContext = {
state: RetryState;
opts: Dispatcher.DispatchOptions & {
retryOptions?: RetryHandler.RetryOptions;
};
}
export type OnRetryCallback = (result?: Error | null) => void
export type RetryCallback = (
err: Error,
context: {
state: RetryState;
opts: Dispatcher.DispatchOptions & {
retryOptions?: RetryHandler.RetryOptions;
};
},
callback: OnRetryCallback
) => void
export interface RetryOptions {
/**
* If true, the retry handler will throw an error if the request fails,
* this will prevent the folling handlers from being called, and will destroy the socket.
*
* @type {boolean}
* @memberof RetryOptions
* @default true
*/
throwOnError?: boolean;
/**
* Callback to be invoked on every retry iteration.
* It receives the error, current state of the retry object and the options object
* passed when instantiating the retry handler.
*
* @type {RetryCallback}
* @memberof RetryOptions
*/
retry?: RetryCallback;
/**
* Maximum number of retries to allow.
*
* @type {number}
* @memberof RetryOptions
* @default 5
*/
maxRetries?: number;
/**
* Max number of milliseconds allow between retries
*
* @type {number}
* @memberof RetryOptions
* @default 30000
*/
maxTimeout?: number;
/**
* Initial number of milliseconds to wait before retrying for the first time.
*
* @type {number}
* @memberof RetryOptions
* @default 500
*/
minTimeout?: number;
/**
* Factior to multiply the timeout factor between retries.
*
* @type {number}
* @memberof RetryOptions
* @default 2
*/
timeoutFactor?: number;
/**
* It enables to automatically infer timeout between retries based on the `Retry-After` header.
*
* @type {boolean}
* @memberof RetryOptions
* @default true
*/
retryAfter?: boolean;
/**
* HTTP methods to retry.
*
* @type {Dispatcher.HttpMethod[]}
* @memberof RetryOptions
* @default ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE'],
*/
methods?: Dispatcher.HttpMethod[];
/**
* Error codes to be retried. e.g. `ECONNRESET`, `ENOTFOUND`, `ETIMEDOUT`, `ECONNREFUSED`, etc.
*
* @type {string[]}
* @default ['ECONNRESET','ECONNREFUSED','ENOTFOUND','ENETDOWN','ENETUNREACH','EHOSTDOWN','EHOSTUNREACH','EPIPE']
*/
errorCodes?: string[];
/**
* HTTP status codes to be retried.
*
* @type {number[]}
* @memberof RetryOptions
* @default [500, 502, 503, 504, 429],
*/
statusCodes?: number[];
}
export interface RetryHandlers {
dispatch: Dispatcher['dispatch'];
handler: Dispatcher.DispatchHandler;
}
}

View File

@@ -0,0 +1,73 @@
//compile doT templates to js functions
'use strict';
var glob = require('glob')
, fs = require('fs')
, path = require('path')
, doT = require('dot')
, beautify = require('js-beautify').js_beautify;
var defsRootPath = process.argv[2] || path.join(__dirname, '../lib');
var defs = {};
var defFiles = glob.sync('./dot/**/*.def', { cwd: defsRootPath });
defFiles.forEach(function (f) {
var name = path.basename(f, '.def');
defs[name] = fs.readFileSync(path.join(defsRootPath, f));
});
var filesRootPath = process.argv[3] || path.join(__dirname, '../lib');
var files = glob.sync('./dot/**/*.jst', { cwd: filesRootPath });
var dotjsPath = path.join(filesRootPath, './dotjs');
try { fs.mkdirSync(dotjsPath); } catch(e) {}
console.log('\n\nCompiling:');
var FUNCTION_NAME = /function\s+anonymous\s*\(it[^)]*\)\s*{/;
var OUT_EMPTY_STRING = /out\s*\+=\s*'\s*';/g;
var ISTANBUL = /'(istanbul[^']+)';/g;
var ERROR_KEYWORD = /\$errorKeyword/g;
var ERROR_KEYWORD_OR = /\$errorKeyword\s+\|\|/g;
var VARS = [
'$errs', '$valid', '$lvl', '$data', '$dataLvl',
'$errorKeyword', '$closingBraces', '$schemaPath',
'$validate'
];
files.forEach(function (f) {
var keyword = path.basename(f, '.jst');
var targetPath = path.join(dotjsPath, keyword + '.js');
var template = fs.readFileSync(path.join(filesRootPath, f));
var code = doT.compile(template, defs);
code = code.toString()
.replace(OUT_EMPTY_STRING, '')
.replace(FUNCTION_NAME, 'function generate_' + keyword + '(it, $keyword, $ruleType) {')
.replace(ISTANBUL, '/* $1 */');
removeAlwaysFalsyInOr();
VARS.forEach(removeUnusedVar);
code = "'use strict';\nmodule.exports = " + code;
code = beautify(code, { indent_size: 2 }) + '\n';
fs.writeFileSync(targetPath, code);
console.log('compiled', keyword);
function removeUnusedVar(v) {
v = v.replace(/\$/g, '\\$$');
var regexp = new RegExp(v + '[^A-Za-z0-9_$]', 'g');
var count = occurrences(regexp);
if (count == 1) {
regexp = new RegExp('var\\s+' + v + '\\s*=[^;]+;|var\\s+' + v + ';');
code = code.replace(regexp, '');
}
}
function removeAlwaysFalsyInOr() {
var countUsed = occurrences(ERROR_KEYWORD);
var countOr = occurrences(ERROR_KEYWORD_OR);
if (countUsed == countOr + 1) code = code.replace(ERROR_KEYWORD_OR, '');
}
function occurrences(regexp) {
return (code.match(regexp) || []).length;
}
});

View File

@@ -0,0 +1,130 @@
export var CharacterCodes;
(function (CharacterCodes) {
CharacterCodes[CharacterCodes["EOF"] = -1] = "EOF";
CharacterCodes[CharacterCodes["nullCharacter"] = 0] = "nullCharacter";
CharacterCodes[CharacterCodes["maxAsciiCharacter"] = 127] = "maxAsciiCharacter";
CharacterCodes[CharacterCodes["lineFeed"] = 10] = "lineFeed";
CharacterCodes[CharacterCodes["carriageReturn"] = 13] = "carriageReturn";
CharacterCodes[CharacterCodes["lineSeparator"] = 8232] = "lineSeparator";
CharacterCodes[CharacterCodes["paragraphSeparator"] = 8233] = "paragraphSeparator";
CharacterCodes[CharacterCodes["nextLine"] = 133] = "nextLine";
CharacterCodes[CharacterCodes["space"] = 32] = "space";
CharacterCodes[CharacterCodes["nonBreakingSpace"] = 160] = "nonBreakingSpace";
CharacterCodes[CharacterCodes["enQuad"] = 8192] = "enQuad";
CharacterCodes[CharacterCodes["emQuad"] = 8193] = "emQuad";
CharacterCodes[CharacterCodes["enSpace"] = 8194] = "enSpace";
CharacterCodes[CharacterCodes["emSpace"] = 8195] = "emSpace";
CharacterCodes[CharacterCodes["threePerEmSpace"] = 8196] = "threePerEmSpace";
CharacterCodes[CharacterCodes["fourPerEmSpace"] = 8197] = "fourPerEmSpace";
CharacterCodes[CharacterCodes["sixPerEmSpace"] = 8198] = "sixPerEmSpace";
CharacterCodes[CharacterCodes["figureSpace"] = 8199] = "figureSpace";
CharacterCodes[CharacterCodes["punctuationSpace"] = 8200] = "punctuationSpace";
CharacterCodes[CharacterCodes["thinSpace"] = 8201] = "thinSpace";
CharacterCodes[CharacterCodes["hairSpace"] = 8202] = "hairSpace";
CharacterCodes[CharacterCodes["zeroWidthSpace"] = 8203] = "zeroWidthSpace";
CharacterCodes[CharacterCodes["narrowNoBreakSpace"] = 8239] = "narrowNoBreakSpace";
CharacterCodes[CharacterCodes["ideographicSpace"] = 12288] = "ideographicSpace";
CharacterCodes[CharacterCodes["mathematicalSpace"] = 8287] = "mathematicalSpace";
CharacterCodes[CharacterCodes["ogham"] = 5765] = "ogham";
CharacterCodes[CharacterCodes["replacementCharacter"] = 65533] = "replacementCharacter";
CharacterCodes[CharacterCodes["_"] = 95] = "_";
CharacterCodes[CharacterCodes["$"] = 36] = "$";
CharacterCodes[CharacterCodes["_0"] = 48] = "_0";
CharacterCodes[CharacterCodes["_1"] = 49] = "_1";
CharacterCodes[CharacterCodes["_2"] = 50] = "_2";
CharacterCodes[CharacterCodes["_3"] = 51] = "_3";
CharacterCodes[CharacterCodes["_4"] = 52] = "_4";
CharacterCodes[CharacterCodes["_5"] = 53] = "_5";
CharacterCodes[CharacterCodes["_6"] = 54] = "_6";
CharacterCodes[CharacterCodes["_7"] = 55] = "_7";
CharacterCodes[CharacterCodes["_8"] = 56] = "_8";
CharacterCodes[CharacterCodes["_9"] = 57] = "_9";
CharacterCodes[CharacterCodes["a"] = 97] = "a";
CharacterCodes[CharacterCodes["b"] = 98] = "b";
CharacterCodes[CharacterCodes["c"] = 99] = "c";
CharacterCodes[CharacterCodes["d"] = 100] = "d";
CharacterCodes[CharacterCodes["e"] = 101] = "e";
CharacterCodes[CharacterCodes["f"] = 102] = "f";
CharacterCodes[CharacterCodes["g"] = 103] = "g";
CharacterCodes[CharacterCodes["h"] = 104] = "h";
CharacterCodes[CharacterCodes["i"] = 105] = "i";
CharacterCodes[CharacterCodes["j"] = 106] = "j";
CharacterCodes[CharacterCodes["k"] = 107] = "k";
CharacterCodes[CharacterCodes["l"] = 108] = "l";
CharacterCodes[CharacterCodes["m"] = 109] = "m";
CharacterCodes[CharacterCodes["n"] = 110] = "n";
CharacterCodes[CharacterCodes["o"] = 111] = "o";
CharacterCodes[CharacterCodes["p"] = 112] = "p";
CharacterCodes[CharacterCodes["q"] = 113] = "q";
CharacterCodes[CharacterCodes["r"] = 114] = "r";
CharacterCodes[CharacterCodes["s"] = 115] = "s";
CharacterCodes[CharacterCodes["t"] = 116] = "t";
CharacterCodes[CharacterCodes["u"] = 117] = "u";
CharacterCodes[CharacterCodes["v"] = 118] = "v";
CharacterCodes[CharacterCodes["w"] = 119] = "w";
CharacterCodes[CharacterCodes["x"] = 120] = "x";
CharacterCodes[CharacterCodes["y"] = 121] = "y";
CharacterCodes[CharacterCodes["z"] = 122] = "z";
CharacterCodes[CharacterCodes["A"] = 65] = "A";
CharacterCodes[CharacterCodes["B"] = 66] = "B";
CharacterCodes[CharacterCodes["C"] = 67] = "C";
CharacterCodes[CharacterCodes["D"] = 68] = "D";
CharacterCodes[CharacterCodes["E"] = 69] = "E";
CharacterCodes[CharacterCodes["F"] = 70] = "F";
CharacterCodes[CharacterCodes["G"] = 71] = "G";
CharacterCodes[CharacterCodes["H"] = 72] = "H";
CharacterCodes[CharacterCodes["I"] = 73] = "I";
CharacterCodes[CharacterCodes["J"] = 74] = "J";
CharacterCodes[CharacterCodes["K"] = 75] = "K";
CharacterCodes[CharacterCodes["L"] = 76] = "L";
CharacterCodes[CharacterCodes["M"] = 77] = "M";
CharacterCodes[CharacterCodes["N"] = 78] = "N";
CharacterCodes[CharacterCodes["O"] = 79] = "O";
CharacterCodes[CharacterCodes["P"] = 80] = "P";
CharacterCodes[CharacterCodes["Q"] = 81] = "Q";
CharacterCodes[CharacterCodes["R"] = 82] = "R";
CharacterCodes[CharacterCodes["S"] = 83] = "S";
CharacterCodes[CharacterCodes["T"] = 84] = "T";
CharacterCodes[CharacterCodes["U"] = 85] = "U";
CharacterCodes[CharacterCodes["V"] = 86] = "V";
CharacterCodes[CharacterCodes["W"] = 87] = "W";
CharacterCodes[CharacterCodes["X"] = 88] = "X";
CharacterCodes[CharacterCodes["Y"] = 89] = "Y";
CharacterCodes[CharacterCodes["Z"] = 90] = "Z";
CharacterCodes[CharacterCodes["ampersand"] = 38] = "ampersand";
CharacterCodes[CharacterCodes["asterisk"] = 42] = "asterisk";
CharacterCodes[CharacterCodes["at"] = 64] = "at";
CharacterCodes[CharacterCodes["backslash"] = 92] = "backslash";
CharacterCodes[CharacterCodes["backtick"] = 96] = "backtick";
CharacterCodes[CharacterCodes["bar"] = 124] = "bar";
CharacterCodes[CharacterCodes["caret"] = 94] = "caret";
CharacterCodes[CharacterCodes["closeBrace"] = 125] = "closeBrace";
CharacterCodes[CharacterCodes["closeBracket"] = 93] = "closeBracket";
CharacterCodes[CharacterCodes["closeParen"] = 41] = "closeParen";
CharacterCodes[CharacterCodes["colon"] = 58] = "colon";
CharacterCodes[CharacterCodes["comma"] = 44] = "comma";
CharacterCodes[CharacterCodes["dot"] = 46] = "dot";
CharacterCodes[CharacterCodes["doubleQuote"] = 34] = "doubleQuote";
CharacterCodes[CharacterCodes["equals"] = 61] = "equals";
CharacterCodes[CharacterCodes["exclamation"] = 33] = "exclamation";
CharacterCodes[CharacterCodes["greaterThan"] = 62] = "greaterThan";
CharacterCodes[CharacterCodes["hash"] = 35] = "hash";
CharacterCodes[CharacterCodes["lessThan"] = 60] = "lessThan";
CharacterCodes[CharacterCodes["minus"] = 45] = "minus";
CharacterCodes[CharacterCodes["openBrace"] = 123] = "openBrace";
CharacterCodes[CharacterCodes["openBracket"] = 91] = "openBracket";
CharacterCodes[CharacterCodes["openParen"] = 40] = "openParen";
CharacterCodes[CharacterCodes["percent"] = 37] = "percent";
CharacterCodes[CharacterCodes["plus"] = 43] = "plus";
CharacterCodes[CharacterCodes["question"] = 63] = "question";
CharacterCodes[CharacterCodes["semicolon"] = 59] = "semicolon";
CharacterCodes[CharacterCodes["singleQuote"] = 39] = "singleQuote";
CharacterCodes[CharacterCodes["slash"] = 47] = "slash";
CharacterCodes[CharacterCodes["tilde"] = 126] = "tilde";
CharacterCodes[CharacterCodes["backspace"] = 8] = "backspace";
CharacterCodes[CharacterCodes["formFeed"] = 12] = "formFeed";
CharacterCodes[CharacterCodes["byteOrderMark"] = 65279] = "byteOrderMark";
CharacterCodes[CharacterCodes["tab"] = 9] = "tab";
CharacterCodes[CharacterCodes["verticalTab"] = 11] = "verticalTab";
})(CharacterCodes || (CharacterCodes = {}));
//# sourceMappingURL=characterCodes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"blake2b.js","sourceRoot":"","sources":["../src/blake2b.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,aAAa,CAAC;AAC7D,+DAA+D;AAC/D,MAAM,CAAC,MAAM,OAAO,GAAe,GAAG,CAAC;AACvC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,OAAO,GAAe,GAAG,CAAC"}

View File

@@ -0,0 +1,40 @@
"use strict";
// THIS CODE WAS AUTOMATICALLY GENERATED
// DO NOT EDIT THIS CODE BY HAND
// SEE https://typescript-eslint.io/users/configs
//
// For developers working in the typescript-eslint monorepo:
// You can regenerate it using `pnpm run generate-configs`
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const base_1 = __importDefault(require("./base"));
const eslint_recommended_1 = __importDefault(require("./eslint-recommended"));
/**
* Rules considered to be best practice for modern TypeScript codebases, but that do not impact program logic.
* @see {@link https://typescript-eslint.io/users/configs#stylistic}
*/
exports.default = (plugin, parser) => [
(0, base_1.default)(plugin, parser),
(0, eslint_recommended_1.default)(plugin, parser),
{
name: 'typescript-eslint/stylistic',
rules: {
'@typescript-eslint/adjacent-overload-signatures': 'error',
'@typescript-eslint/array-type': 'error',
'@typescript-eslint/ban-tslint-comment': 'error',
'@typescript-eslint/class-literal-property-style': 'error',
'@typescript-eslint/consistent-generic-constructors': 'error',
'@typescript-eslint/consistent-indexed-object-style': 'error',
'@typescript-eslint/consistent-type-assertions': 'error',
'@typescript-eslint/consistent-type-definitions': 'error',
'@typescript-eslint/no-confusing-non-null-assertion': 'error',
'no-empty-function': 'off',
'@typescript-eslint/no-empty-function': 'error',
'@typescript-eslint/no-inferrable-types': 'error',
'@typescript-eslint/prefer-for-of': 'error',
'@typescript-eslint/prefer-function-type': 'error',
},
},
];

View File

@@ -0,0 +1,24 @@
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/// <reference no-default-lib="true"/>
/// <reference lib="es2018" />
/// <reference lib="es2019.array" />
/// <reference lib="es2019.object" />
/// <reference lib="es2019.string" />
/// <reference lib="es2019.symbol" />
/// <reference lib="es2019.intl" />

View File

@@ -0,0 +1,52 @@
'use strict'
const bench = require('fastbench')
const pino = require('../')
const bunyan = require('bunyan')
const fs = require('node:fs')
const dest = fs.createWriteStream('/dev/null')
const plogNodeStream = pino(dest).child({ a: 'property' }).child({ sub: 'child' })
delete require.cache[require.resolve('../')]
const plogDest = require('../')(pino.destination('/dev/null')).child({ a: 'property' }).child({ sub: 'child' })
delete require.cache[require.resolve('../')]
const plogMinLength = require('../')(pino.destination({ dest: '/dev/null', sync: false, minLength: 4096 }))
.child({ a: 'property' })
.child({ sub: 'child' })
const max = 10
const blog = bunyan.createLogger({
name: 'myapp',
streams: [{
level: 'trace',
stream: dest
}]
}).child({ a: 'property' }).child({ sub: 'child' })
const run = bench([
function benchBunyanChildChild (cb) {
for (var i = 0; i < max; i++) {
blog.info({ hello: 'world' })
}
setImmediate(cb)
},
function benchPinoChildChild (cb) {
for (var i = 0; i < max; i++) {
plogDest.info({ hello: 'world' })
}
setImmediate(cb)
},
function benchPinoMinLengthChildChild (cb) {
for (var i = 0; i < max; i++) {
plogMinLength.info({ hello: 'world' })
}
setImmediate(cb)
},
function benchPinoNodeStreamChildChild (cb) {
for (var i = 0; i < max; i++) {
plogNodeStream.info({ hello: 'world' })
}
setImmediate(cb)
}
], 10000)
run(run)

View File

@@ -0,0 +1,4 @@
function _objectDestructuringEmpty(t) {
if (null == t) throw new TypeError("Cannot destructure " + t);
}
module.exports = _objectDestructuringEmpty, module.exports.__esModule = true, module.exports["default"] = module.exports;

View File

@@ -0,0 +1,22 @@
declare global {
let suite: typeof import('vitest')['suite']
let test: typeof import('vitest')['test']
let chai: typeof import("vitest")["chai"]
let describe: typeof import('vitest')['describe']
let it: typeof import('vitest')['it']
let expectTypeOf: typeof import('vitest')['expectTypeOf']
let assertType: typeof import('vitest')['assertType']
let expect: typeof import('vitest')['expect']
let assert: typeof import('vitest')['assert']
let vitest: typeof import('vitest')['vitest']
let vi: typeof import('vitest')['vitest']
let beforeAll: typeof import('vitest')['beforeAll']
let afterAll: typeof import('vitest')['afterAll']
let beforeEach: typeof import('vitest')['beforeEach']
let afterEach: typeof import('vitest')['afterEach']
let aroundEach: typeof import('vitest')['aroundEach']
let aroundAll: typeof import('vitest')['aroundAll']
let onTestFailed: typeof import('vitest')['onTestFailed']
let onTestFinished: typeof import('vitest')['onTestFinished']
}
export {}

View File

@@ -0,0 +1,126 @@
import { allProcessors } from "./json-schema-processors.js";
import type * as JSONSchema from "./json-schema.js";
import type { $ZodRegistry } from "./registries.js";
import type * as schemas from "./schemas.js";
import {
type JSONSchemaGeneratorParams,
type ProcessParams,
type Seen,
type ToJSONSchemaContext,
extractDefs,
finalize,
initializeContext,
process,
} from "./to-json-schema.js";
/**
* Parameters for the emit method of JSONSchemaGenerator.
* @deprecated Use toJSONSchema function instead
*/
export type EmitParams = Pick<JSONSchemaGeneratorParams, "cycles" | "reused" | "external">;
/**
* Parameters for JSONSchemaGenerator constructor.
* @deprecated Use toJSONSchema function instead
*/
type JSONSchemaGeneratorConstructorParams = Pick<
JSONSchemaGeneratorParams,
"metadata" | "target" | "unrepresentable" | "override" | "io"
>;
/**
* Legacy class-based interface for JSON Schema generation.
* This class wraps the new functional implementation to provide backward compatibility.
*
* @deprecated Use the `toJSONSchema` function instead for new code.
*
* @example
* ```typescript
* // Legacy usage (still supported)
* const gen = new JSONSchemaGenerator({ target: "draft-07" });
* gen.process(schema);
* const result = gen.emit(schema);
*
* // Preferred modern usage
* const result = toJSONSchema(schema, { target: "draft-07" });
* ```
*/
export class JSONSchemaGenerator {
private ctx: ToJSONSchemaContext;
/** @deprecated Access via ctx instead */
get metadataRegistry(): $ZodRegistry<Record<string, any>> {
return this.ctx.metadataRegistry;
}
/** @deprecated Access via ctx instead */
get target() {
return this.ctx.target;
}
/** @deprecated Access via ctx instead */
get unrepresentable() {
return this.ctx.unrepresentable;
}
/** @deprecated Access via ctx instead */
get override() {
return this.ctx.override;
}
/** @deprecated Access via ctx instead */
get io() {
return this.ctx.io;
}
/** @deprecated Access via ctx instead */
get counter() {
return this.ctx.counter;
}
set counter(value: number) {
this.ctx.counter = value;
}
/** @deprecated Access via ctx instead */
get seen(): Map<schemas.$ZodType, Seen> {
return this.ctx.seen;
}
constructor(params?: JSONSchemaGeneratorConstructorParams) {
// Normalize target for internal context
let normalizedTarget: ToJSONSchemaContext["target"] = params?.target ?? "draft-2020-12";
if (normalizedTarget === "draft-4") normalizedTarget = "draft-04";
if (normalizedTarget === "draft-7") normalizedTarget = "draft-07";
this.ctx = initializeContext({
processors: allProcessors,
target: normalizedTarget,
...(params?.metadata && { metadata: params.metadata }),
...(params?.unrepresentable && { unrepresentable: params.unrepresentable }),
...(params?.override && { override: params.override as any }),
...(params?.io && { io: params.io }),
});
}
/**
* Process a schema to prepare it for JSON Schema generation.
* This must be called before emit().
*/
process(schema: schemas.$ZodType, _params: ProcessParams = { path: [], schemaPath: [] }): JSONSchema.BaseSchema {
return process(schema, this.ctx, _params);
}
/**
* Emit the final JSON Schema after processing.
* Must call process() first.
*/
emit(schema: schemas.$ZodType, _params?: EmitParams): JSONSchema.BaseSchema {
// Apply emit params to the context
if (_params) {
if (_params.cycles) this.ctx.cycles = _params.cycles;
if (_params.reused) this.ctx.reused = _params.reused;
if (_params.external) this.ctx.external = _params.external;
}
extractDefs(this.ctx, schema);
const result = finalize(this.ctx, schema);
// Strip ~standard property to match old implementation's return type
const { "~standard": _, ...plainResult } = result as any;
return plainResult as JSONSchema.BaseSchema;
}
}

View File

@@ -0,0 +1,513 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const regexpp_1 = require("@eslint-community/regexpp");
const utils_1 = require("@typescript-eslint/utils");
const util_1 = require("../util");
const EQ_OPERATORS = /^[=!]=/;
const regexpp = new regexpp_1.RegExpParser();
exports.default = (0, util_1.createRule)({
name: 'prefer-string-starts-ends-with',
meta: {
type: 'suggestion',
docs: {
description: 'Enforce using `String#startsWith` and `String#endsWith` over other equivalent methods of checking substrings',
recommended: 'stylistic',
requiresTypeChecking: true,
},
fixable: 'code',
messages: {
preferEndsWith: "Use the 'String#endsWith' method instead.",
preferStartsWith: "Use 'String#startsWith' method instead.",
},
schema: [
{
type: 'object',
additionalProperties: false,
properties: {
allowSingleElementEquality: {
type: 'string',
description: 'Whether to allow equality checks against the first or last element of a string.',
enum: ['always', 'never'],
},
},
},
],
},
defaultOptions: [{ allowSingleElementEquality: 'never' }],
create(context, [{ allowSingleElementEquality }]) {
const globalScope = context.sourceCode.getScope(context.sourceCode.ast);
const services = (0, util_1.getParserServices)(context);
const checker = services.program.getTypeChecker();
/**
* Check if a given node is a string.
* @param node The node to check.
*/
function isStringType(node) {
const objectType = services.getTypeAtLocation(node);
return (0, util_1.getTypeName)(checker, objectType) === 'string';
}
/**
* Check if a given node is a `Literal` node that is null.
* @param node The node to check.
*/
function isNull(node) {
const evaluated = (0, util_1.getStaticValue)(node, globalScope);
return evaluated != null && evaluated.value == null;
}
/**
* Check if a given node is a `Literal` node that is a given value.
* @param node The node to check.
* @param value The expected value of the `Literal` node.
*/
function isNumber(node, value) {
const evaluated = (0, util_1.getStaticValue)(node, globalScope);
return evaluated?.value === value;
}
/**
* Check if a given node is a `Literal` node that is a character.
* @param node The node to check.
*/
function isCharacter(node) {
const evaluated = (0, util_1.getStaticValue)(node, globalScope);
return (evaluated != null &&
typeof evaluated.value === 'string' &&
// checks if the string is a character long
evaluated.value[0] === evaluated.value);
}
/**
* Check if a given node is `==`, `===`, `!=`, or `!==`.
* @param node The node to check.
*/
function isEqualityComparison(node) {
return (node.type === utils_1.AST_NODE_TYPES.BinaryExpression &&
EQ_OPERATORS.test(node.operator));
}
/**
* Check if two given nodes are the same meaning.
* @param node1 A node to compare.
* @param node2 Another node to compare.
*/
function isSameTokens(node1, node2) {
const tokens1 = context.sourceCode.getTokens(node1);
const tokens2 = context.sourceCode.getTokens(node2);
if (tokens1.length !== tokens2.length) {
return false;
}
for (let i = 0; i < tokens1.length; ++i) {
const token1 = tokens1[i];
const token2 = tokens2[i];
if (token1.type !== token2.type || token1.value !== token2.value) {
return false;
}
}
return true;
}
/**
* Check if a given node is the expression of the length of a string.
*
* - If `length` property access of `expectedObjectNode`, it's `true`.
* E.g., `foo` → `foo.length` / `"foo"` → `"foo".length`
* - If `expectedObjectNode` is a string literal, `node` can be a number.
* E.g., `"foo"` → `3`
*
* @param node The node to check.
* @param expectedObjectNode The node which is expected as the receiver of `length` property.
*/
function isLengthExpression(node, expectedObjectNode) {
if (node.type === utils_1.AST_NODE_TYPES.MemberExpression) {
return ((0, util_1.getPropertyName)(node, globalScope) === 'length' &&
isSameTokens(node.object, expectedObjectNode));
}
const evaluatedLength = (0, util_1.getStaticValue)(node, globalScope);
const evaluatedString = (0, util_1.getStaticValue)(expectedObjectNode, globalScope);
return (evaluatedLength != null &&
evaluatedString != null &&
typeof evaluatedLength.value === 'number' &&
typeof evaluatedString.value === 'string' &&
evaluatedLength.value === evaluatedString.value.length);
}
/**
* Returns true if `node` is `-substring.length` or
* `parentString.length - substring.length`
*/
function isLengthAheadOfEnd(node, substring, parentString) {
return ((node.type === utils_1.AST_NODE_TYPES.UnaryExpression &&
node.operator === '-' &&
isLengthExpression(node.argument, substring)) ||
(node.type === utils_1.AST_NODE_TYPES.BinaryExpression &&
node.operator === '-' &&
isLengthExpression(node.left, parentString) &&
isLengthExpression(node.right, substring)));
}
/**
* Check if a given node is the expression of the last index.
*
* E.g. `foo.length - 1`
*
* @param node The node to check.
* @param expectedObjectNode The node which is expected as the receiver of `length` property.
*/
function isLastIndexExpression(node, expectedObjectNode) {
return (node.type === utils_1.AST_NODE_TYPES.BinaryExpression &&
node.operator === '-' &&
isLengthExpression(node.left, expectedObjectNode) &&
isNumber(node.right, 1));
}
/**
* Get the range of the property of a given `MemberExpression` node.
*
* - `obj[foo]` → the range of `[foo]`
* - `obf.foo` → the range of `.foo`
* - `(obj).foo` → the range of `.foo`
*
* @param node The member expression node to get.
*/
function getPropertyRange(node) {
const dotOrOpenBracket = (0, util_1.nullThrows)(context.sourceCode.getTokenAfter(node.object, util_1.isNotClosingParenToken), util_1.NullThrowsReasons.MissingToken('closing parenthesis', 'member'));
return [dotOrOpenBracket.range[0], node.range[1]];
}
/**
* Parse a given `RegExp` pattern to that string if it's a static string.
* @param pattern The RegExp pattern text to parse.
* @param unicode Whether the RegExp is unicode.
*/
function parseRegExpText(pattern, unicode) {
// Parse it.
const ast = regexpp.parsePattern(pattern, undefined, undefined, {
unicode,
});
if (ast.alternatives.length !== 1) {
return null;
}
// Drop `^`/`$` assertion.
const chars = ast.alternatives[0].elements;
const first = chars[0];
if (first.type === 'Assertion' && first.kind === 'start') {
chars.shift();
}
else {
chars.pop();
}
// Check if it can determine a unique string.
if (!chars.every(c => c.type === 'Character')) {
return null;
}
// To string.
return String.fromCodePoint(...chars.map(c => c.value));
}
/**
* Parse a given node if it's a `RegExp` instance.
* @param node The node to parse.
*/
function parseRegExp(node) {
const evaluated = (0, util_1.getStaticValue)(node, globalScope);
if (evaluated == null || !(evaluated.value instanceof RegExp)) {
return null;
}
const { flags, source } = evaluated.value;
const isStartsWith = source.startsWith('^');
// ends with a $ preceded by an even number of backslashes (or zero)
const isEndsWith = /[^\\](\\\\)*\$$/.test(source);
if (isStartsWith === isEndsWith ||
flags.includes('i') ||
flags.includes('m')) {
return null;
}
const text = parseRegExpText(source, flags.includes('u'));
if (text == null) {
return null;
}
return { isEndsWith, isStartsWith, text };
}
function getLeftNode(init) {
const node = (0, util_1.skipChainExpression)(init);
const leftNode = node.type === utils_1.AST_NODE_TYPES.CallExpression ? node.callee : node;
if (leftNode.type !== utils_1.AST_NODE_TYPES.MemberExpression) {
throw new Error(`Expected a MemberExpression, got ${leftNode.type}`);
}
return leftNode;
}
/**
* Fix code with using the right operand as the search string.
* For example: `foo.slice(0, 3) === 'bar'` → `foo.startsWith('bar')`
* @param fixer The rule fixer.
* @param node The node which was reported.
* @param kind The kind of the report.
* @param isNegative The flag to fix to negative condition.
*/
function* fixWithRightOperand(fixer, node, kind, isNegative, isOptional) {
// left is CallExpression or MemberExpression.
const leftNode = getLeftNode(node.left);
const propertyRange = getPropertyRange(leftNode);
if (isNegative) {
yield fixer.insertTextBefore(node, '!');
}
yield fixer.replaceTextRange([propertyRange[0], node.right.range[0]], `${isOptional ? '?.' : '.'}${kind}sWith(`);
yield fixer.replaceTextRange([node.right.range[1], node.range[1]], ')');
}
/**
* Fix code with using the first argument as the search string.
* For example: `foo.indexOf('bar') === 0` → `foo.startsWith('bar')`
* @param fixer The rule fixer.
* @param node The node which was reported.
* @param kind The kind of the report.
* @param negative The flag to fix to negative condition.
*/
function* fixWithArgument(fixer, node, callNode, calleeNode, kind, negative, isOptional) {
if (negative) {
yield fixer.insertTextBefore(node, '!');
}
yield fixer.replaceTextRange(getPropertyRange(calleeNode), `${isOptional ? '?.' : '.'}${kind}sWith`);
yield fixer.removeRange([callNode.range[1], node.range[1]]);
}
function getParent(node) {
return node.parent.type === utils_1.AST_NODE_TYPES.ChainExpression
? node.parent.parent
: node.parent;
}
return {
// foo[0] === "a"
// foo.charAt(0) === "a"
// foo[foo.length - 1] === "a"
// foo.charAt(foo.length - 1) === "a"
[[
'BinaryExpression > MemberExpression.left[computed=true]',
'BinaryExpression > CallExpression.left > MemberExpression.callee[property.name="charAt"][computed=false]',
'BinaryExpression > ChainExpression.left > MemberExpression[computed=true]',
'BinaryExpression > ChainExpression.left > CallExpression > MemberExpression.callee[property.name="charAt"][computed=false]',
].join(', ')](node) {
let parentNode = getParent(node);
let indexNode = null;
if (parentNode.type === utils_1.AST_NODE_TYPES.CallExpression) {
if (parentNode.arguments.length === 1) {
indexNode = parentNode.arguments[0];
}
parentNode = getParent(parentNode);
}
else {
indexNode = node.property;
}
if (indexNode == null ||
!isEqualityComparison(parentNode) ||
!isStringType(node.object)) {
return;
}
const isEndsWith = isLastIndexExpression(indexNode, node.object);
if (allowSingleElementEquality === 'always' && isEndsWith) {
return;
}
const isStartsWith = !isEndsWith && isNumber(indexNode, 0);
if ((allowSingleElementEquality === 'always' && isStartsWith) ||
(!isStartsWith && !isEndsWith)) {
return;
}
const eqNode = parentNode;
context.report({
node: parentNode,
messageId: isStartsWith ? 'preferStartsWith' : 'preferEndsWith',
fix(fixer) {
// Don't fix if it can change the behavior.
if (!isCharacter(eqNode.right)) {
return null;
}
return fixWithRightOperand(fixer, eqNode, isStartsWith ? 'start' : 'end', eqNode.operator.startsWith('!'), node.optional);
},
});
},
// foo.indexOf('bar') === 0
[[
'BinaryExpression > CallExpression.left > MemberExpression.callee[property.name="indexOf"][computed=false]',
'BinaryExpression > ChainExpression.left > CallExpression > MemberExpression.callee[property.name="indexOf"][computed=false]',
].join(', ')](node) {
const callNode = getParent(node);
const parentNode = getParent(callNode);
if (callNode.arguments.length !== 1 ||
!isEqualityComparison(parentNode) ||
!isNumber(parentNode.right, 0) ||
!isStringType(node.object)) {
return;
}
context.report({
node: parentNode,
messageId: 'preferStartsWith',
fix(fixer) {
return fixWithArgument(fixer, parentNode, callNode, node, 'start', parentNode.operator.startsWith('!'), node.optional);
},
});
},
// foo.lastIndexOf('bar') === foo.length - 3
// foo.lastIndexOf(bar) === foo.length - bar.length
[[
'BinaryExpression > CallExpression.left > MemberExpression.callee[property.name="lastIndexOf"][computed=false]',
'BinaryExpression > ChainExpression.left > CallExpression > MemberExpression.callee[property.name="lastIndexOf"][computed=false]',
].join(', ')](node) {
const callNode = getParent(node);
const parentNode = getParent(callNode);
if (callNode.arguments.length !== 1 ||
!isEqualityComparison(parentNode) ||
parentNode.right.type !== utils_1.AST_NODE_TYPES.BinaryExpression ||
parentNode.right.operator !== '-' ||
!isLengthExpression(parentNode.right.left, node.object) ||
!isLengthExpression(parentNode.right.right, callNode.arguments[0]) ||
!isStringType(node.object)) {
return;
}
context.report({
node: parentNode,
messageId: 'preferEndsWith',
fix(fixer) {
return fixWithArgument(fixer, parentNode, callNode, node, 'end', parentNode.operator.startsWith('!'), node.optional);
},
});
},
// foo.match(/^bar/) === null
// foo.match(/bar$/) === null
[[
'BinaryExpression > CallExpression.left > MemberExpression.callee[property.name="match"][computed=false]',
'BinaryExpression > ChainExpression.left > CallExpression > MemberExpression.callee[property.name="match"][computed=false]',
].join(', ')](node) {
const callNode = getParent(node);
const parentNode = getParent(callNode);
if (!isNull(parentNode.right) || !isStringType(node.object)) {
return;
}
const parsed = callNode.arguments.length === 1
? parseRegExp(callNode.arguments[0])
: null;
if (parsed == null) {
return;
}
const { isStartsWith, text } = parsed;
context.report({
node: callNode,
messageId: isStartsWith ? 'preferStartsWith' : 'preferEndsWith',
*fix(fixer) {
if (!parentNode.operator.startsWith('!')) {
yield fixer.insertTextBefore(parentNode, '!');
}
yield fixer.replaceTextRange(getPropertyRange(node), `${node.optional ? '?.' : '.'}${isStartsWith ? 'start' : 'end'}sWith`);
yield fixer.replaceText(callNode.arguments[0], JSON.stringify(text));
yield fixer.removeRange([callNode.range[1], parentNode.range[1]]);
},
});
},
// foo.slice(0, 3) === 'bar'
// foo.slice(-3) === 'bar'
// foo.slice(-3, foo.length) === 'bar'
// foo.substring(0, 3) === 'bar'
// foo.substring(foo.length - 3) === 'bar'
// foo.substring(foo.length - 3, foo.length) === 'bar'
[[
'BinaryExpression > CallExpression.left > MemberExpression',
'BinaryExpression > ChainExpression.left > CallExpression > MemberExpression',
].join(', ')](node) {
if (!(0, util_1.isStaticMemberAccessOfValue)(node, context, 'slice', 'substring')) {
return;
}
const callNode = getParent(node);
const parentNode = getParent(callNode);
if (!isEqualityComparison(parentNode) || !isStringType(node.object)) {
return;
}
let isEndsWith = false;
let isStartsWith = false;
if (callNode.arguments.length === 1) {
if (
// foo.slice(-bar.length) === bar
// foo.slice(foo.length - bar.length) === bar
isLengthAheadOfEnd(callNode.arguments[0], parentNode.right, node.object)) {
isEndsWith = true;
}
}
else if (callNode.arguments.length === 2) {
if (
// foo.slice(0, bar.length) === bar
isNumber(callNode.arguments[0], 0) &&
isLengthExpression(callNode.arguments[1], parentNode.right)) {
isStartsWith = true;
}
else if (
// foo.slice(foo.length - bar.length, foo.length) === bar
// foo.slice(foo.length - bar.length, 0) === bar
// foo.slice(-bar.length, foo.length) === bar
// foo.slice(-bar.length, 0) === bar
(isLengthExpression(callNode.arguments[1], node.object) ||
isNumber(callNode.arguments[1], 0)) &&
isLengthAheadOfEnd(callNode.arguments[0], parentNode.right, node.object)) {
isEndsWith = true;
}
}
if (!isStartsWith && !isEndsWith) {
return;
}
const eqNode = parentNode;
const negativeIndexSupported = node.property.name === 'slice';
context.report({
node: parentNode,
messageId: isStartsWith ? 'preferStartsWith' : 'preferEndsWith',
fix(fixer) {
// Don't fix if it can change the behavior.
if (eqNode.operator.length === 2 &&
(eqNode.right.type !== utils_1.AST_NODE_TYPES.Literal ||
typeof eqNode.right.value !== 'string')) {
return null;
}
// code being checked is likely mistake:
// unequal length of strings being checked for equality
// or reliant on behavior of substring (negative indices interpreted as 0)
if (isStartsWith) {
if (!isLengthExpression(callNode.arguments[1], eqNode.right)) {
return null;
}
}
else {
const posNode = callNode.arguments[0];
const posNodeIsAbsolutelyValid = (posNode.type === utils_1.AST_NODE_TYPES.BinaryExpression &&
posNode.operator === '-' &&
isLengthExpression(posNode.left, node.object) &&
isLengthExpression(posNode.right, eqNode.right)) ||
(negativeIndexSupported &&
posNode.type === utils_1.AST_NODE_TYPES.UnaryExpression &&
posNode.operator === '-' &&
isLengthExpression(posNode.argument, eqNode.right));
if (!posNodeIsAbsolutelyValid) {
return null;
}
}
return fixWithRightOperand(fixer, parentNode, isStartsWith ? 'start' : 'end', parentNode.operator.startsWith('!'), node.optional);
},
});
},
// /^bar/.test(foo)
// /bar$/.test(foo)
'CallExpression > MemberExpression.callee[property.name="test"][computed=false]'(node) {
const callNode = getParent(node);
const parsed = callNode.arguments.length === 1 ? parseRegExp(node.object) : null;
if (parsed == null) {
return;
}
const { isStartsWith, text } = parsed;
const messageId = isStartsWith ? 'preferStartsWith' : 'preferEndsWith';
const methodName = isStartsWith ? 'startsWith' : 'endsWith';
context.report({
node: callNode,
messageId,
*fix(fixer) {
const argNode = callNode.arguments[0];
const needsParen = argNode.type !== utils_1.AST_NODE_TYPES.Literal &&
argNode.type !== utils_1.AST_NODE_TYPES.TemplateLiteral &&
argNode.type !== utils_1.AST_NODE_TYPES.Identifier &&
argNode.type !== utils_1.AST_NODE_TYPES.MemberExpression &&
argNode.type !== utils_1.AST_NODE_TYPES.CallExpression;
yield fixer.removeRange([callNode.range[0], argNode.range[0]]);
if (needsParen) {
yield fixer.insertTextBefore(argNode, '(');
yield fixer.insertTextAfter(argNode, ')');
}
yield fixer.insertTextAfter(argNode, `${node.optional ? '?.' : '.'}${methodName}(${JSON.stringify(text)}`);
},
});
},
};
},
});

View File

@@ -0,0 +1,93 @@
'use strict'
// just pre-load all the stuff that index.js lazily exports
const internalRe = require('./internal/re')
const constants = require('./internal/constants')
const SemVer = require('./classes/semver')
const identifiers = require('./internal/identifiers')
const parse = require('./functions/parse')
const valid = require('./functions/valid')
const clean = require('./functions/clean')
const inc = require('./functions/inc')
const diff = require('./functions/diff')
const major = require('./functions/major')
const minor = require('./functions/minor')
const patch = require('./functions/patch')
const prerelease = require('./functions/prerelease')
const compare = require('./functions/compare')
const rcompare = require('./functions/rcompare')
const compareLoose = require('./functions/compare-loose')
const compareBuild = require('./functions/compare-build')
const sort = require('./functions/sort')
const rsort = require('./functions/rsort')
const gt = require('./functions/gt')
const lt = require('./functions/lt')
const eq = require('./functions/eq')
const neq = require('./functions/neq')
const gte = require('./functions/gte')
const lte = require('./functions/lte')
const cmp = require('./functions/cmp')
const coerce = require('./functions/coerce')
const truncate = require('./functions/truncate')
const Comparator = require('./classes/comparator')
const Range = require('./classes/range')
const satisfies = require('./functions/satisfies')
const toComparators = require('./ranges/to-comparators')
const maxSatisfying = require('./ranges/max-satisfying')
const minSatisfying = require('./ranges/min-satisfying')
const minVersion = require('./ranges/min-version')
const validRange = require('./ranges/valid')
const outside = require('./ranges/outside')
const gtr = require('./ranges/gtr')
const ltr = require('./ranges/ltr')
const intersects = require('./ranges/intersects')
const simplifyRange = require('./ranges/simplify')
const subset = require('./ranges/subset')
module.exports = {
parse,
valid,
clean,
inc,
diff,
major,
minor,
patch,
prerelease,
compare,
rcompare,
compareLoose,
compareBuild,
sort,
rsort,
gt,
lt,
eq,
neq,
gte,
lte,
cmp,
coerce,
truncate,
Comparator,
Range,
satisfies,
toComparators,
maxSatisfying,
minSatisfying,
minVersion,
validRange,
outside,
gtr,
ltr,
intersects,
simplifyRange,
subset,
SemVer,
re: internalRe.re,
src: internalRe.src,
tokens: internalRe.t,
SEMVER_SPEC_VERSION: constants.SEMVER_SPEC_VERSION,
RELEASE_TYPES: constants.RELEASE_TYPES,
compareIdentifiers: identifiers.compareIdentifiers,
rcompareIdentifiers: identifiers.rcompareIdentifiers,
}

View File

@@ -0,0 +1,267 @@
import {Buffer} from 'buffer';
import * as BufferLayout from '@solana/buffer-layout';
import {PublicKey} from './publickey';
import {Transaction, PACKET_DATA_SIZE} from './transaction';
import {MS_PER_SLOT} from './timing';
import {SYSVAR_RENT_PUBKEY} from './sysvar';
import {sendAndConfirmTransaction} from './utils/send-and-confirm-transaction';
import {sleep} from './utils/sleep';
import type {Connection} from './connection';
import type {Signer} from './keypair';
import {SystemProgram} from './programs/system';
import {IInstructionInputData} from './instruction';
// Keep program chunks under PACKET_DATA_SIZE, leaving enough room for the
// rest of the Transaction fields
//
// TODO: replace 300 with a proper constant for the size of the other
// Transaction fields
const CHUNK_SIZE = PACKET_DATA_SIZE - 300;
/**
* Program loader interface
*/
export class Loader {
/**
* @internal
*/
constructor() {}
/**
* Amount of program data placed in each load Transaction
*/
static chunkSize: number = CHUNK_SIZE;
/**
* Minimum number of signatures required to load a program not including
* retries
*
* Can be used to calculate transaction fees
*/
static getMinNumSignatures(dataLength: number): number {
return (
2 * // Every transaction requires two signatures (payer + program)
(Math.ceil(dataLength / Loader.chunkSize) +
1 + // Add one for Create transaction
1) // Add one for Finalize transaction
);
}
/**
* Loads a generic program
*
* @param connection The connection to use
* @param payer System account that pays to load the program
* @param program Account to load the program into
* @param programId Public key that identifies the loader
* @param data Program octets
* @return true if program was loaded successfully, false if program was already loaded
*/
static async load(
connection: Connection,
payer: Signer,
program: Signer,
programId: PublicKey,
data: Buffer | Uint8Array | Array<number>,
): Promise<boolean> {
{
const balanceNeeded = await connection.getMinimumBalanceForRentExemption(
data.length,
);
// Fetch program account info to check if it has already been created
const programInfo = await connection.getAccountInfo(
program.publicKey,
'confirmed',
);
let transaction: Transaction | null = null;
if (programInfo !== null) {
if (programInfo.executable) {
console.error('Program load failed, account is already executable');
return false;
}
if (programInfo.data.length !== data.length) {
transaction = transaction || new Transaction();
transaction.add(
SystemProgram.allocate({
accountPubkey: program.publicKey,
space: data.length,
}),
);
}
if (!programInfo.owner.equals(programId)) {
transaction = transaction || new Transaction();
transaction.add(
SystemProgram.assign({
accountPubkey: program.publicKey,
programId,
}),
);
}
if (programInfo.lamports < balanceNeeded) {
transaction = transaction || new Transaction();
transaction.add(
SystemProgram.transfer({
fromPubkey: payer.publicKey,
toPubkey: program.publicKey,
lamports: balanceNeeded - programInfo.lamports,
}),
);
}
} else {
transaction = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: program.publicKey,
lamports: balanceNeeded > 0 ? balanceNeeded : 1,
space: data.length,
programId,
}),
);
}
// If the account is already created correctly, skip this step
// and proceed directly to loading instructions
if (transaction !== null) {
await sendAndConfirmTransaction(
connection,
transaction,
[payer, program],
{
commitment: 'confirmed',
},
);
}
}
const dataLayout = BufferLayout.struct<
Readonly<{
bytes: number[];
bytesLength: number;
bytesLengthPadding: number;
instruction: number;
offset: number;
}>
>([
BufferLayout.u32('instruction'),
BufferLayout.u32('offset'),
BufferLayout.u32('bytesLength'),
BufferLayout.u32('bytesLengthPadding'),
BufferLayout.seq(
BufferLayout.u8('byte'),
BufferLayout.offset(BufferLayout.u32(), -8),
'bytes',
),
]);
const chunkSize = Loader.chunkSize;
let offset = 0;
let array = data;
let transactions = [];
while (array.length > 0) {
const bytes = array.slice(0, chunkSize);
const data = Buffer.alloc(chunkSize + 16);
dataLayout.encode(
{
instruction: 0, // Load instruction
offset,
bytes: bytes as number[],
bytesLength: 0,
bytesLengthPadding: 0,
},
data,
);
const transaction = new Transaction().add({
keys: [{pubkey: program.publicKey, isSigner: true, isWritable: true}],
programId,
data,
});
transactions.push(
sendAndConfirmTransaction(connection, transaction, [payer, program], {
commitment: 'confirmed',
}),
);
// Delay between sends in an attempt to reduce rate limit errors
if (connection._rpcEndpoint.includes('solana.com')) {
const REQUESTS_PER_SECOND = 4;
await sleep(1000 / REQUESTS_PER_SECOND);
}
offset += chunkSize;
array = array.slice(chunkSize);
}
await Promise.all(transactions);
// Finalize the account loaded with program data for execution
{
const dataLayout = BufferLayout.struct<IInstructionInputData>([
BufferLayout.u32('instruction'),
]);
const data = Buffer.alloc(dataLayout.span);
dataLayout.encode(
{
instruction: 1, // Finalize instruction
},
data,
);
const transaction = new Transaction().add({
keys: [
{pubkey: program.publicKey, isSigner: true, isWritable: true},
{pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false},
],
programId,
data,
});
const deployCommitment = 'processed';
const finalizeSignature = await connection.sendTransaction(
transaction,
[payer, program],
{preflightCommitment: deployCommitment},
);
const {context, value} = await connection.confirmTransaction(
{
signature: finalizeSignature,
lastValidBlockHeight: transaction.lastValidBlockHeight!,
blockhash: transaction.recentBlockhash!,
},
deployCommitment,
);
if (value.err) {
throw new Error(
`Transaction ${finalizeSignature} failed (${JSON.stringify(value)})`,
);
}
// We prevent programs from being usable until the slot after their deployment.
// See https://github.com/solana-labs/solana/pull/29654
while (
true // eslint-disable-line no-constant-condition
) {
try {
const currentSlot = await connection.getSlot({
commitment: deployCommitment,
});
if (currentSlot > context.slot) {
break;
}
} catch {
/* empty */
}
await new Promise(resolve =>
setTimeout(resolve, Math.round(MS_PER_SLOT / 2)),
);
}
}
// success
return true;
}
}

View File

@@ -0,0 +1,80 @@
"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;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getScriptKind = getScriptKind;
exports.getLanguageVariant = getLanguageVariant;
const node_path_1 = __importDefault(require("node:path"));
const ts = __importStar(require("typescript"));
function getScriptKind(filePath, jsx) {
const extension = node_path_1.default.extname(filePath).toLowerCase();
// note - we only respect the user's jsx setting for unknown extensions
// this is so that we always match TS's internal script kind logic, preventing
// weird errors due to a mismatch.
// https://github.com/microsoft/TypeScript/blob/da00ba67ed1182ad334f7c713b8254fba174aeba/src/compiler/utilities.ts#L6948-L6968
switch (extension) {
case ts.Extension.Cjs:
case ts.Extension.Js:
case ts.Extension.Mjs:
return ts.ScriptKind.JS;
case ts.Extension.Cts:
case ts.Extension.Mts:
case ts.Extension.Ts:
return ts.ScriptKind.TS;
case ts.Extension.Json:
return ts.ScriptKind.JSON;
case ts.Extension.Jsx:
return ts.ScriptKind.JSX;
case ts.Extension.Tsx:
return ts.ScriptKind.TSX;
default:
// unknown extension, force typescript to ignore the file extension, and respect the user's setting
return jsx ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
}
}
function getLanguageVariant(scriptKind) {
// https://github.com/microsoft/TypeScript/blob/d6e483b8dabd8fd37c00954c3f2184bb7f1eb90c/src/compiler/utilities.ts#L6281-L6285
switch (scriptKind) {
case ts.ScriptKind.JS:
case ts.ScriptKind.JSON:
case ts.ScriptKind.JSX:
case ts.ScriptKind.TSX:
return ts.LanguageVariant.JSX;
default:
return ts.LanguageVariant.Standard;
}
}

View File

@@ -0,0 +1,130 @@
/**
* @fileoverview Rule to spot scenarios where a newline looks like it is ending a statement, but is not.
* @author Glen Mailer
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
docs: {
description: "Disallow confusing multiline expressions",
recommended: true,
url: "https://eslint.org/docs/latest/rules/no-unexpected-multiline",
},
schema: [],
messages: {
function:
"Unexpected newline between function and ( of function call.",
property:
"Unexpected newline between object and [ of property access.",
taggedTemplate:
"Unexpected newline between template tag and template literal.",
division:
"Unexpected newline between numerator and division operator.",
},
},
create(context) {
const REGEX_FLAG_MATCHER = /^[gimsuy]+$/u;
const sourceCode = context.sourceCode;
/**
* Check to see if there is a newline between the node and the following open bracket
* line's expression
* @param {ASTNode} node The node to check.
* @param {string} messageId The error messageId to use.
* @returns {void}
* @private
*/
function checkForBreakAfter(node, messageId) {
const openParen = sourceCode.getTokenAfter(
node,
astUtils.isNotClosingParenToken,
);
const nodeExpressionEnd = sourceCode.getTokenBefore(openParen);
if (openParen.loc.start.line !== nodeExpressionEnd.loc.end.line) {
context.report({
node,
loc: openParen.loc,
messageId,
});
}
}
//--------------------------------------------------------------------------
// Public API
//--------------------------------------------------------------------------
return {
MemberExpression(node) {
if (!node.computed || node.optional) {
return;
}
checkForBreakAfter(node.object, "property");
},
TaggedTemplateExpression(node) {
const { quasi } = node;
// handles common tags, parenthesized tags, and typescript's generic type arguments
const tokenBefore = sourceCode.getTokenBefore(quasi);
if (tokenBefore.loc.end.line !== quasi.loc.start.line) {
context.report({
node,
loc: {
start: quasi.loc.start,
end: {
line: quasi.loc.start.line,
column: quasi.loc.start.column + 1,
},
},
messageId: "taggedTemplate",
});
}
},
CallExpression(node) {
if (node.arguments.length === 0 || node.optional) {
return;
}
checkForBreakAfter(node.callee, "function");
},
"BinaryExpression[operator='/'] > BinaryExpression[operator='/'].left"(
node,
) {
const secondSlash = sourceCode.getTokenAfter(
node,
token => token.value === "/",
);
const tokenAfterOperator =
sourceCode.getTokenAfter(secondSlash);
if (
tokenAfterOperator.type === "Identifier" &&
REGEX_FLAG_MATCHER.test(tokenAfterOperator.value) &&
secondSlash.range[1] === tokenAfterOperator.range[0]
) {
checkForBreakAfter(node.left, "division");
}
},
};
},
};

View File

@@ -0,0 +1,70 @@
/*
Copyright (C) 2014 Yusuke Suzuki <utatane.tea@gmail.com>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS'
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
'use strict';
var gulp = require('gulp'),
git = require('gulp-git'),
bump = require('gulp-bump'),
filter = require('gulp-filter'),
tagVersion = require('gulp-tag-version');
var TEST = [ 'test/*.js' ];
var POWERED = [ 'powered-test/*.js' ];
var SOURCE = [ 'src/**/*.js' ];
/**
* Bumping version number and tagging the repository with it.
* Please read http://semver.org/
*
* You can use the commands
*
* gulp patch # makes v0.1.0 -> v0.1.1
* gulp feature # makes v0.1.1 -> v0.2.0
* gulp release # makes v0.2.1 -> v1.0.0
*
* To bump the version numbers accordingly after you did a patch,
* introduced a feature or made a backwards-incompatible release.
*/
function inc(importance) {
// get all the files to bump version in
return gulp.src(['./package.json'])
// bump the version number in those files
.pipe(bump({type: importance}))
// save it back to filesystem
.pipe(gulp.dest('./'))
// commit the changed version number
.pipe(git.commit('Bumps package version'))
// read only one file to get the version number
.pipe(filter('package.json'))
// **tag it in the repository**
.pipe(tagVersion({
prefix: ''
}));
}
gulp.task('patch', [ ], function () { return inc('patch'); })
gulp.task('minor', [ ], function () { return inc('minor'); })
gulp.task('major', [ ], function () { return inc('major'); })

View File

@@ -0,0 +1,7 @@
'use strict'
module.exports = isObject
function isObject (input) {
return Object.prototype.toString.apply(input) === '[object Object]'
}

View File

@@ -0,0 +1,57 @@
/**
* @fileoverview Reports useless `catch` clauses that just rethrow their error.
* @author Teddy Katz
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "Disallow unnecessary `catch` clauses",
recommended: true,
url: "https://eslint.org/docs/latest/rules/no-useless-catch",
},
schema: [],
messages: {
unnecessaryCatchClause: "Unnecessary catch clause.",
unnecessaryCatch: "Unnecessary try/catch wrapper.",
},
},
create(context) {
return {
CatchClause(node) {
if (
node.param &&
node.param.type === "Identifier" &&
node.body.body.length &&
node.body.body[0].type === "ThrowStatement" &&
node.body.body[0].argument.type === "Identifier" &&
node.body.body[0].argument.name === node.param.name
) {
if (node.parent.finalizer) {
context.report({
node,
messageId: "unnecessaryCatchClause",
});
} else {
context.report({
node: node.parent,
messageId: "unnecessaryCatch",
});
}
}
},
};
},
};

View File

@@ -0,0 +1,36 @@
export {}; // Make this a module
declare global {
namespace NodeJS {
type TypedArray =
| Uint8Array
| Uint8ClampedArray
| Uint16Array
| Uint32Array
| Int8Array
| Int16Array
| Int32Array
| BigUint64Array
| BigInt64Array
| Float16Array
| Float32Array
| Float64Array;
type ArrayBufferView = TypedArray | DataView;
type NonSharedUint8Array = Uint8Array;
type NonSharedUint8ClampedArray = Uint8ClampedArray;
type NonSharedUint16Array = Uint16Array;
type NonSharedUint32Array = Uint32Array;
type NonSharedInt8Array = Int8Array;
type NonSharedInt16Array = Int16Array;
type NonSharedInt32Array = Int32Array;
type NonSharedBigUint64Array = BigUint64Array;
type NonSharedBigInt64Array = BigInt64Array;
type NonSharedFloat16Array = Float16Array;
type NonSharedFloat32Array = Float32Array;
type NonSharedFloat64Array = Float64Array;
type NonSharedDataView = DataView;
type NonSharedTypedArray = TypedArray;
type NonSharedArrayBufferView = ArrayBufferView;
}
}

View File

@@ -0,0 +1,9 @@
function _isNativeReflectConstruct() {
try {
var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
} catch (t) {}
return (_isNativeReflectConstruct = function _isNativeReflectConstruct() {
return !!t;
})();
}
export { _isNativeReflectConstruct as default };

View File

@@ -0,0 +1,554 @@
/**
* @fileoverview A rule to suggest using of const declaration for variables that are never reassigned after declared.
* @author Toru Nagashima
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const FixTracker = require("./utils/fix-tracker");
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
/** @typedef {import("eslint-scope").Scope} Scope */
/** @typedef {import("eslint-scope").Variable} Variable */
/** @typedef {import("eslint-scope").Reference} Reference */
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const PATTERN_TYPE =
/^(?:.+?Pattern|RestElement|SpreadProperty|ExperimentalRestProperty|Property)$/u;
const DECLARATION_HOST_TYPE =
/^(?:Program|BlockStatement|StaticBlock|SwitchCase)$/u;
const DESTRUCTURING_HOST_TYPE =
/^(?:VariableDeclarator|AssignmentExpression)$/u;
/**
* Checks whether a given node is located at `ForStatement.init` or not.
* @param {ASTNode} node A node to check.
* @returns {boolean} `true` if the node is located at `ForStatement.init`.
*/
function isInitOfForStatement(node) {
return node.parent.type === "ForStatement" && node.parent.init === node;
}
/**
* Checks whether a given Identifier node becomes a VariableDeclaration or not.
* @param {ASTNode} identifier An Identifier node to check.
* @returns {boolean} `true` if the node can become a VariableDeclaration.
*/
function canBecomeVariableDeclaration(identifier) {
let node = identifier.parent;
while (PATTERN_TYPE.test(node.type)) {
node = node.parent;
}
return (
node.type === "VariableDeclarator" ||
(node.type === "AssignmentExpression" &&
node.parent.type === "ExpressionStatement" &&
DECLARATION_HOST_TYPE.test(node.parent.parent.type))
);
}
/**
* Checks if an property or element is from outer scope or function parameters
* in destructing pattern.
* @param {string} name A variable name to be checked.
* @param {Scope} initScope A scope to start find.
* @returns {boolean} Indicates if the variable is from outer scope or function parameters.
*/
function isOuterVariableInDestructing(name, initScope) {
if (
initScope.through.some(
ref => ref.resolved && ref.resolved.name === name,
)
) {
return true;
}
const variable = astUtils.getVariableByName(initScope, name);
if (variable !== null) {
return variable.defs.some(def => def.type === "Parameter");
}
return false;
}
/**
* Gets the VariableDeclarator/AssignmentExpression node that a given reference
* belongs to.
* This is used to detect a mix of reassigned and never reassigned in a
* destructuring.
* @param {Reference} reference A reference to get.
* @returns {ASTNode|null} A VariableDeclarator/AssignmentExpression node or
* null.
*/
function getDestructuringHost(reference) {
if (!reference.isWrite()) {
return null;
}
let node = reference.identifier.parent;
while (PATTERN_TYPE.test(node.type)) {
node = node.parent;
}
if (!DESTRUCTURING_HOST_TYPE.test(node.type)) {
return null;
}
return node;
}
/**
* Determines if a destructuring assignment node contains
* any MemberExpression nodes. This is used to determine if a
* variable that is only written once using destructuring can be
* safely converted into a const declaration.
* @param {ASTNode} node The ObjectPattern or ArrayPattern node to check.
* @returns {boolean} True if the destructuring pattern contains
* a MemberExpression, false if not.
*/
function hasMemberExpressionAssignment(node) {
switch (node.type) {
case "ObjectPattern":
return node.properties.some(prop => {
if (prop) {
/*
* Spread elements have an argument property while
* others have a value property. Because different
* parsers use different node types for spread elements,
* we just check if there is an argument property.
*/
return hasMemberExpressionAssignment(
prop.argument || prop.value,
);
}
return false;
});
case "ArrayPattern":
return node.elements.some(element => {
if (element) {
return hasMemberExpressionAssignment(element);
}
return false;
});
case "AssignmentPattern":
return hasMemberExpressionAssignment(node.left);
case "MemberExpression":
return true;
// no default
}
return false;
}
/**
* Gets an identifier node of a given variable.
*
* If the initialization exists or one or more reading references exist before
* the first assignment, the identifier node is the node of the declaration.
* Otherwise, the identifier node is the node of the first assignment.
*
* If the variable should not change to const, this function returns null.
* - If the variable is reassigned.
* - If the variable is never initialized nor assigned.
* - If the variable is initialized in a different scope from the declaration.
* - If the unique assignment of the variable cannot change to a declaration.
* e.g. `if (a) b = 1` / `return (b = 1)`
* - If the variable is declared in the global scope and `eslintUsed` is `true`.
* `/*exported foo` directive comment makes such variables. This rule does not
* warn such variables because this rule cannot distinguish whether the
* exported variables are reassigned or not.
* @param {Variable} variable A variable to get.
* @param {boolean} ignoreReadBeforeAssign
* The value of `ignoreReadBeforeAssign` option.
* @returns {ASTNode|null}
* An Identifier node if the variable should change to const.
* Otherwise, null.
*/
function getIdentifierIfShouldBeConst(variable, ignoreReadBeforeAssign) {
if (variable.eslintUsed && variable.scope.type === "global") {
return null;
}
// Finds the unique WriteReference.
let writer = null;
let isReadBeforeInit = false;
const references = variable.references;
for (let i = 0; i < references.length; ++i) {
const reference = references[i];
if (reference.isWrite()) {
const isReassigned =
writer !== null && writer.identifier !== reference.identifier;
if (isReassigned) {
return null;
}
const destructuringHost = getDestructuringHost(reference);
if (
destructuringHost !== null &&
destructuringHost.left !== void 0
) {
const leftNode = destructuringHost.left;
let hasOuterVariables = false,
hasNonIdentifiers = false;
if (leftNode.type === "ObjectPattern") {
const properties = leftNode.properties;
hasOuterVariables = properties
.filter(prop => prop.value)
.map(prop => prop.value.name)
.some(name =>
isOuterVariableInDestructing(name, variable.scope),
);
hasNonIdentifiers = hasMemberExpressionAssignment(leftNode);
} else if (leftNode.type === "ArrayPattern") {
const elements = leftNode.elements;
hasOuterVariables = elements
.map(element => element && element.name)
.some(name =>
isOuterVariableInDestructing(name, variable.scope),
);
hasNonIdentifiers = hasMemberExpressionAssignment(leftNode);
}
if (hasOuterVariables || hasNonIdentifiers) {
return null;
}
}
writer = reference;
} else if (reference.isRead() && writer === null) {
if (ignoreReadBeforeAssign) {
return null;
}
isReadBeforeInit = true;
}
}
/*
* If the assignment is from a different scope, ignore it.
* If the assignment cannot change to a declaration, ignore it.
*/
const shouldBeConst =
writer !== null &&
writer.from === variable.scope &&
canBecomeVariableDeclaration(writer.identifier);
if (!shouldBeConst) {
return null;
}
if (isReadBeforeInit) {
return variable.defs[0].name;
}
return writer.identifier;
}
/**
* Groups by the VariableDeclarator/AssignmentExpression node that each
* reference of given variables belongs to.
* This is used to detect a mix of reassigned and never reassigned in a
* destructuring.
* @param {Variable[]} variables Variables to group by destructuring.
* @param {boolean} ignoreReadBeforeAssign
* The value of `ignoreReadBeforeAssign` option.
* @returns {Map<ASTNode, ASTNode[]>} Grouped identifier nodes.
*/
function groupByDestructuring(variables, ignoreReadBeforeAssign) {
const identifierMap = new Map();
for (let i = 0; i < variables.length; ++i) {
const variable = variables[i];
const references = variable.references;
const identifier = getIdentifierIfShouldBeConst(
variable,
ignoreReadBeforeAssign,
);
let prevId = null;
for (let j = 0; j < references.length; ++j) {
const reference = references[j];
const id = reference.identifier;
/*
* Avoid counting a reference twice or more for default values of
* destructuring.
*/
if (id === prevId) {
continue;
}
prevId = id;
// Add the identifier node into the destructuring group.
const group = getDestructuringHost(reference);
if (group) {
if (identifierMap.has(group)) {
identifierMap.get(group).push(identifier);
} else {
identifierMap.set(group, [identifier]);
}
}
}
}
return identifierMap;
}
/**
* Finds the nearest parent of node with a given type.
* @param {ASTNode} node The node to search from.
* @param {string} type The type field of the parent node.
* @param {Function} shouldStop A predicate that returns true if the traversal should stop, and false otherwise.
* @returns {ASTNode} The closest ancestor with the specified type; null if no such ancestor exists.
*/
function findUp(node, type, shouldStop) {
if (!node || shouldStop(node)) {
return null;
}
if (node.type === type) {
return node;
}
return findUp(node.parent, type, shouldStop);
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "suggestion",
defaultOptions: [
{
destructuring: "any",
ignoreReadBeforeAssign: false,
},
],
docs: {
description:
"Require `const` declarations for variables that are never reassigned after declared",
recommended: false,
url: "https://eslint.org/docs/latest/rules/prefer-const",
},
fixable: "code",
schema: [
{
type: "object",
properties: {
destructuring: { enum: ["any", "all"] },
ignoreReadBeforeAssign: { type: "boolean" },
},
additionalProperties: false,
},
],
messages: {
useConst: "'{{name}}' is never reassigned. Use 'const' instead.",
},
},
create(context) {
const [{ destructuring, ignoreReadBeforeAssign }] = context.options;
const shouldMatchAnyDestructuredVariable = destructuring !== "all";
const sourceCode = context.sourceCode;
const variables = [];
let reportCount = 0;
let checkedId = null;
let checkedName = "";
/**
* Reports given identifier nodes if all of the nodes should be declared
* as const.
*
* The argument 'nodes' is an array of Identifier nodes.
* This node is the result of 'getIdentifierIfShouldBeConst()', so it's
* nullable. In simple declaration or assignment cases, the length of
* the array is 1. In destructuring cases, the length of the array can
* be 2 or more.
* @param {(Reference|null)[]} nodes
* References which are grouped by destructuring to report.
* @returns {void}
*/
function checkGroup(nodes) {
const nodesToReport = nodes.filter(Boolean);
if (
nodes.length &&
(shouldMatchAnyDestructuredVariable ||
nodesToReport.length === nodes.length)
) {
const varDeclParent = findUp(
nodes[0],
"VariableDeclaration",
parentNode => parentNode.type.endsWith("Statement"),
);
const isVarDecParentNull = varDeclParent === null;
if (
!isVarDecParentNull &&
varDeclParent.declarations.length > 0
) {
const firstDeclaration = varDeclParent.declarations[0];
if (firstDeclaration.init) {
const firstDecParent = firstDeclaration.init.parent;
/*
* First we check the declaration type and then depending on
* if the type is a "VariableDeclarator" or its an "ObjectPattern"
* we compare the name and id from the first identifier, if the names are different
* we assign the new name, id and reset the count of reportCount and nodeCount in
* order to check each block for the number of reported errors and base our fix
* based on comparing nodes.length and nodesToReport.length.
*/
if (firstDecParent.type === "VariableDeclarator") {
if (firstDecParent.id.name !== checkedName) {
checkedName = firstDecParent.id.name;
reportCount = 0;
}
if (firstDecParent.id.type === "ObjectPattern") {
if (firstDecParent.init.name !== checkedName) {
checkedName = firstDecParent.init.name;
reportCount = 0;
}
}
if (firstDecParent.id !== checkedId) {
checkedId = firstDecParent.id;
reportCount = 0;
}
}
}
}
let shouldFix =
varDeclParent &&
// Don't do a fix unless all variables in the declarations are initialized (or it's in a for-in or for-of loop)
(varDeclParent.parent.type === "ForInStatement" ||
varDeclParent.parent.type === "ForOfStatement" ||
varDeclParent.declarations.every(
declaration => declaration.init,
)) &&
/*
* If options.destructuring is "all", then this warning will not occur unless
* every assignment in the destructuring should be const. In that case, it's safe
* to apply the fix.
*/
nodesToReport.length === nodes.length;
if (
!isVarDecParentNull &&
varDeclParent.declarations &&
varDeclParent.declarations.length !== 1
) {
if (
varDeclParent &&
varDeclParent.declarations &&
varDeclParent.declarations.length >= 1
) {
/*
* Add nodesToReport.length to a count, then comparing the count to the length
* of the declarations in the current block.
*/
reportCount += nodesToReport.length;
let totalDeclarationsCount = 0;
varDeclParent.declarations.forEach(declaration => {
if (declaration.id.type === "ObjectPattern") {
totalDeclarationsCount +=
declaration.id.properties.length;
} else if (declaration.id.type === "ArrayPattern") {
totalDeclarationsCount +=
declaration.id.elements.length;
} else {
totalDeclarationsCount += 1;
}
});
shouldFix =
shouldFix && reportCount === totalDeclarationsCount;
}
}
nodesToReport.forEach(node => {
context.report({
node,
messageId: "useConst",
data: node,
fix: shouldFix
? fixer => {
const letKeywordToken =
sourceCode.getFirstToken(
varDeclParent,
t => t.value === varDeclParent.kind,
);
/**
* Extend the replacement range to the whole declaration,
* in order to prevent other fixes in the same pass
* https://github.com/eslint/eslint/issues/13899
*/
return new FixTracker(fixer, sourceCode)
.retainRange(varDeclParent.range)
.replaceTextRange(
letKeywordToken.range,
"const",
);
}
: null,
});
});
}
}
return {
"Program:exit"() {
groupByDestructuring(variables, ignoreReadBeforeAssign).forEach(
checkGroup,
);
},
VariableDeclaration(node) {
if (node.kind === "let" && !isInitOfForStatement(node)) {
variables.push(...sourceCode.getDeclaredVariables(node));
}
},
};
},
};

View File

@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _crypto = _interopRequireDefault(require("crypto"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function sha1(bytes) {
if (Array.isArray(bytes)) {
bytes = Buffer.from(bytes);
} else if (typeof bytes === 'string') {
bytes = Buffer.from(bytes, 'utf8');
}
return _crypto.default.createHash('sha1').update(bytes).digest();
}
var _default = sha1;
exports.default = _default;

View File

@@ -0,0 +1,102 @@
export type IncludeIgnoreFileOptionsObject = {
/**
* Whether to interpret the contents of an ignore file relative to the config file or the ignore file.
* - gitignoreResolution: false (default): Interprets ignore patterns relative to the config file
* - gitignoreResolution: true: Interprets the ignore patterns in a file relative to the ignore file
*/
gitignoreResolution?: boolean;
/**
* The name to give the output config object(s).
*/
name?: string;
};
/**
* Options for `includeIgnoreFile()`. May be provided as an object or, for
* legacy compatibility with `@eslint/compat`, as a string which is treated as
* the `name` option.
*/
export type IncludeIgnoreFileOptions = IncludeIgnoreFileOptionsObject | string;
export type ConfigObject = $eslintcore.ConfigObject;
export type LegacyConfig = $eslintcore.LegacyConfigObject;
export type Plugin = $eslintcore.Plugin;
export type RuleConfig = $eslintcore.RuleConfig;
export type Config = $typests.Config;
export type ExtendsElement = $typests.ExtendsElement;
export type ExtensionConfigObject = $typests.ExtensionConfigObject;
export type SimpleExtendsElement = $typests.SimpleExtendsElement;
export type ConfigWithExtends = $typests.ConfigWithExtends;
export type InfiniteConfigArray = $typests.InfiniteArray<ConfigObject>;
export type ConfigWithExtendsArray = $typests.ConfigWithExtendsArray;
/**
* @fileoverview Ignore file utilities for the config-helpers package.
* This file was forked from the source code for the compat package.
*
* @author Nicholas C. Zakas
* @author Kirk Waiblinger
*/
/**
* @typedef {object} IncludeIgnoreFileOptionsObject
* @property {boolean} [gitignoreResolution] Whether to interpret the contents of an ignore file relative to the config file or the ignore file.
* - gitignoreResolution: false (default): Interprets ignore patterns relative to the config file
* - gitignoreResolution: true: Interprets the ignore patterns in a file relative to the ignore file
* @property {string} [name] The name to give the output config object(s).
*/
/**
* Options for `includeIgnoreFile()`. May be provided as an object or, for
* legacy compatibility with `@eslint/compat`, as a string which is treated as
* the `name` option.
* @typedef {IncludeIgnoreFileOptionsObject | string} IncludeIgnoreFileOptions
*/
/**
* Converts an ESLint ignore pattern to a minimatch pattern.
* @param {string} pattern The .eslintignore or .gitignore pattern to convert.
* @returns {string} The converted pattern.
*/
export function convertIgnorePatternToMinimatch(pattern: string): string;
/**
* Helper function to define a config array.
* @param {ConfigWithExtendsArray} args The arguments to the function.
* @returns {ConfigObject[]} The config array.
* @throws {TypeError} If no arguments are provided or if an argument is not an object.
*/
export function defineConfig(...args: ConfigWithExtendsArray): ConfigObject[];
/**
* Creates a global ignores config with the given patterns.
* @param {string[]} ignorePatterns The ignore patterns.
* @param {string} [name] The name of the global ignores config.
* @returns {ConfigObject} The global ignores config.
* @throws {TypeError} If ignorePatterns is not an array or if it is empty.
*/
export function globalIgnores(ignorePatterns: string[], name?: string): ConfigObject;
/**
* @overload
*
* Reads ignore files and returns objects with the ignore patterns.
*
* @param {string[]} ignoreFilePathArg The paths of ignore files to include.
* @param {IncludeIgnoreFileOptions} [options]
* @returns {ConfigObject[]}
*/
export function includeIgnoreFile(ignoreFilePathArg: string[], options?: IncludeIgnoreFileOptions): ConfigObject[];
/**
* @overload
*
* Reads an ignore file and returns an object with the ignore patterns.
*
* @param {string} ignoreFilePathArg The path of the ignore file to include.
* @param {IncludeIgnoreFileOptions} [options]
* @returns {ConfigObject}
*/
export function includeIgnoreFile(ignoreFilePathArg: string, options?: IncludeIgnoreFileOptions): ConfigObject;
/**
* @overload
*
* Reads an ignore file(s) and returns an object(s) with the ignore patterns.
*
* @param {string[] | string} ignoreFilePathArg The path(s) of the ignore file(s) to include.
* @param {IncludeIgnoreFileOptions} [options]
* @returns {ConfigObject[] | ConfigObject}
*/
export function includeIgnoreFile(ignoreFilePathArg: string[] | string, options?: IncludeIgnoreFileOptions): ConfigObject[] | ConfigObject;
import type * as $eslintcore from "@eslint/core";
import type * as $typests from "./types.cts";