WIP: bootstrap and partial real Solana watcher implementation
This commit is contained in:
@@ -0,0 +1,476 @@
|
||||
/**
|
||||
* @fileoverview A utility for retrying failed async method calls.
|
||||
*/
|
||||
|
||||
/* global setTimeout, clearTimeout */
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constants
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const MAX_TASK_TIMEOUT = 60000;
|
||||
const MAX_TASK_DELAY = 100;
|
||||
const MAX_CONCURRENCY = 1000;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Logs a message to the console if the DEBUG environment variable is set.
|
||||
* @param {string} message The message to log.
|
||||
* @returns {void}
|
||||
*/
|
||||
function debug(message) {
|
||||
if (globalThis?.process?.env.DEBUG === "@hwc/retry") {
|
||||
console.debug(message);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following logic has been extracted from graceful-fs.
|
||||
*
|
||||
* The ISC License
|
||||
*
|
||||
* Copyright (c) 2011-2023 Isaac Z. Schlueter, Ben Noordhuis, and Contributors
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
||||
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks if it is time to retry a task based on the timestamp and last attempt time.
|
||||
* @param {RetryTask} task The task to check.
|
||||
* @param {number} maxDelay The maximum delay for the queue.
|
||||
* @returns {boolean} true if it is time to retry, false otherwise.
|
||||
*/
|
||||
function isTimeToRetry(task, maxDelay) {
|
||||
const timeSinceLastAttempt = Date.now() - task.lastAttempt;
|
||||
const timeSinceStart = Math.max(task.lastAttempt - task.timestamp, 1);
|
||||
const desiredDelay = Math.min(timeSinceStart * 1.2, maxDelay);
|
||||
|
||||
return timeSinceLastAttempt >= desiredDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if it is time to bail out based on the given timestamp.
|
||||
* @param {RetryTask} task The task to check.
|
||||
* @param {number} timeout The timeout for the queue.
|
||||
* @returns {boolean} true if it is time to bail, false otherwise.
|
||||
*/
|
||||
function isTimeToBail(task, timeout) {
|
||||
return task.age > timeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new promise with resolve and reject functions.
|
||||
* @returns {{promise:Promise<any>, resolve:(value:any) => any, reject: (value:any) => any}} A new promise.
|
||||
*/
|
||||
function createPromise() {
|
||||
if (Promise.withResolvers) {
|
||||
return Promise.withResolvers();
|
||||
}
|
||||
|
||||
let resolve, reject;
|
||||
|
||||
const promise = new Promise((res, rej) => {
|
||||
resolve = res;
|
||||
reject = rej;
|
||||
});
|
||||
|
||||
if (resolve === undefined || reject === undefined) {
|
||||
throw new Error("Promise executor did not initialize resolve or reject.");
|
||||
}
|
||||
|
||||
return { promise, resolve, reject };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A class to represent a task in the retry queue.
|
||||
*/
|
||||
class RetryTask {
|
||||
|
||||
/**
|
||||
* The unique ID for the task.
|
||||
* @type {string}
|
||||
*/
|
||||
id = Math.random().toString(36).slice(2);
|
||||
|
||||
/**
|
||||
* The function to call.
|
||||
* @type {Function}
|
||||
*/
|
||||
fn;
|
||||
|
||||
/**
|
||||
* The error that was thrown.
|
||||
* @type {Error}
|
||||
*/
|
||||
error;
|
||||
|
||||
/**
|
||||
* The timestamp of the task.
|
||||
* @type {number}
|
||||
*/
|
||||
timestamp = Date.now();
|
||||
|
||||
/**
|
||||
* The timestamp of the last attempt.
|
||||
* @type {number}
|
||||
*/
|
||||
lastAttempt = this.timestamp;
|
||||
|
||||
/**
|
||||
* The resolve function for the promise.
|
||||
* @type {Function}
|
||||
*/
|
||||
resolve;
|
||||
|
||||
/**
|
||||
* The reject function for the promise.
|
||||
* @type {Function}
|
||||
*/
|
||||
reject;
|
||||
|
||||
/**
|
||||
* The AbortSignal to monitor for cancellation.
|
||||
* @type {AbortSignal|undefined}
|
||||
*/
|
||||
signal;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Function} fn The function to call.
|
||||
* @param {Error} error The error that was thrown.
|
||||
* @param {Function} resolve The resolve function for the promise.
|
||||
* @param {Function} reject The reject function for the promise.
|
||||
* @param {AbortSignal|undefined} signal The AbortSignal to monitor for cancellation.
|
||||
*/
|
||||
constructor(fn, error, resolve, reject, signal) {
|
||||
this.fn = fn;
|
||||
this.error = error;
|
||||
this.timestamp = Date.now();
|
||||
this.lastAttempt = Date.now();
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
this.signal = signal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the age of the task.
|
||||
* @returns {number} The age of the task in milliseconds.
|
||||
* @readonly
|
||||
*/
|
||||
get age() {
|
||||
return Date.now() - this.timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A class that manages a queue of retry jobs.
|
||||
*/
|
||||
class Retrier {
|
||||
|
||||
/**
|
||||
* Represents the queue for processing tasks.
|
||||
* @type {Array<RetryTask>}
|
||||
*/
|
||||
#retrying = [];
|
||||
|
||||
/**
|
||||
* Represents the queue for pending tasks.
|
||||
* @type {Array<Function>}
|
||||
*/
|
||||
#pending = [];
|
||||
|
||||
/**
|
||||
* The number of tasks currently being processed.
|
||||
* @type {number}
|
||||
*/
|
||||
#working = 0;
|
||||
|
||||
/**
|
||||
* The timeout for the queue.
|
||||
* @type {number}
|
||||
*/
|
||||
#timeout;
|
||||
|
||||
/**
|
||||
* The maximum delay for the queue.
|
||||
* @type {number}
|
||||
*/
|
||||
#maxDelay;
|
||||
|
||||
/**
|
||||
* The setTimeout() timer ID.
|
||||
* @type {NodeJS.Timeout|undefined}
|
||||
*/
|
||||
#timerId;
|
||||
|
||||
/**
|
||||
* The function to call.
|
||||
* @type {Function}
|
||||
*/
|
||||
#check;
|
||||
|
||||
/**
|
||||
* The maximum number of concurrent tasks.
|
||||
* @type {number}
|
||||
*/
|
||||
#concurrency;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param {Function} check The function to call.
|
||||
* @param {object} [options] The options for the instance.
|
||||
* @param {number} [options.timeout] The timeout for the queue.
|
||||
* @param {number} [options.maxDelay] The maximum delay for the queue.
|
||||
* @param {number} [options.concurrency] The maximum number of concurrent tasks.
|
||||
*/
|
||||
constructor(check, { timeout = MAX_TASK_TIMEOUT, maxDelay = MAX_TASK_DELAY, concurrency = MAX_CONCURRENCY } = {}) {
|
||||
|
||||
if (typeof check !== "function") {
|
||||
throw new Error("Missing function to check errors");
|
||||
}
|
||||
|
||||
this.#check = check;
|
||||
this.#timeout = timeout;
|
||||
this.#maxDelay = maxDelay;
|
||||
this.#concurrency = concurrency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of tasks waiting to be retried.
|
||||
* @returns {number} The number of tasks in the retry queue.
|
||||
*/
|
||||
get retrying() {
|
||||
return this.#retrying.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of tasks waiting to be processed in the pending queue.
|
||||
* @returns {number} The number of tasks in the pending queue.
|
||||
*/
|
||||
get pending() {
|
||||
return this.#pending.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of tasks currently being processed.
|
||||
* @returns {number} The number of tasks currently being processed.
|
||||
*/
|
||||
get working() {
|
||||
return this.#working;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the function and retries if it fails.
|
||||
* @param {Function} fn The function to call.
|
||||
* @param {Object} options The options for the job.
|
||||
* @param {AbortSignal} [options.signal] The AbortSignal to monitor for cancellation.
|
||||
* @param {Promise<any>} options.promise The promise to return when the function settles.
|
||||
* @param {Function} options.resolve The resolve function for the promise.
|
||||
* @param {Function} options.reject The reject function for the promise.
|
||||
* @returns {Promise<any>} A promise that resolves when the function is
|
||||
* called successfully.
|
||||
*/
|
||||
#call(fn, { signal, promise, resolve, reject }) {
|
||||
|
||||
let result;
|
||||
|
||||
try {
|
||||
result = fn();
|
||||
} catch (/** @type {any} */ error) {
|
||||
reject(new Error(`Synchronous error: ${error.message}`, { cause: error }));
|
||||
return promise;
|
||||
}
|
||||
|
||||
// if the result is not a promise then reject an error
|
||||
if (!result || typeof result.then !== "function") {
|
||||
reject(new Error("Result is not a promise."));
|
||||
return promise;
|
||||
}
|
||||
|
||||
this.#working++;
|
||||
promise.finally(() => {
|
||||
this.#working--;
|
||||
this.#processPending();
|
||||
})
|
||||
// `promise.finally` creates a new promise that may be rejected, so it must be handled.
|
||||
.catch(() => { });
|
||||
|
||||
// call the original function and catch any ENFILE or EMFILE errors
|
||||
Promise.resolve(result)
|
||||
.then(value => {
|
||||
debug("Function called successfully without retry.");
|
||||
resolve(value);
|
||||
})
|
||||
.catch(error => {
|
||||
if (!this.#check(error)) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
const task = new RetryTask(fn, error, resolve, reject, signal);
|
||||
|
||||
debug(`Function failed, queuing for retry with task ${task.id}.`);
|
||||
this.#retrying.push(task);
|
||||
|
||||
signal?.addEventListener("abort", () => {
|
||||
debug(`Task ${task.id} was aborted due to AbortSignal.`);
|
||||
reject(signal.reason);
|
||||
});
|
||||
|
||||
this.#processQueue();
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new retry job to the queue.
|
||||
* @template {(...args: unknown[]) => Promise<unknown>} Func
|
||||
* @template {Awaited<ReturnType<Func>>} RetVal
|
||||
* @param {Func} fn The function to call.
|
||||
* @param {object} [options] The options for the job.
|
||||
* @param {AbortSignal} [options.signal] The AbortSignal to monitor for cancellation.
|
||||
* @returns {Promise<RetVal>} A promise that resolves when the queue is processed.
|
||||
*/
|
||||
retry(fn, { signal } = {}) {
|
||||
|
||||
signal?.throwIfAborted();
|
||||
|
||||
const { promise, resolve, reject } = createPromise();
|
||||
|
||||
this.#pending.push(() => this.#call(fn, { signal, promise, resolve, reject }));
|
||||
this.#processPending();
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Processes the pending queue and the retry queue.
|
||||
* @returns {void}
|
||||
*/
|
||||
#processAll() {
|
||||
if (this.pending) {
|
||||
this.#processPending();
|
||||
}
|
||||
|
||||
if (this.retrying) {
|
||||
this.#processQueue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the pending queue to see which tasks can be started.
|
||||
* @returns {void}
|
||||
*/
|
||||
#processPending() {
|
||||
|
||||
debug(`Processing pending tasks: ${this.pending} pending, ${this.working} working.`);
|
||||
|
||||
const available = this.#concurrency - this.working;
|
||||
|
||||
if (available <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const count = Math.min(this.pending, available);
|
||||
|
||||
for (let i = 0; i < count; i++) {
|
||||
const task = this.#pending.shift();
|
||||
task?.();
|
||||
}
|
||||
|
||||
debug(`Processed pending tasks: ${this.pending} pending, ${this.working} working.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the queue.
|
||||
* @returns {void}
|
||||
*/
|
||||
#processQueue() {
|
||||
// clear any timer because we're going to check right now
|
||||
clearTimeout(this.#timerId);
|
||||
this.#timerId = undefined;
|
||||
|
||||
debug(`Processing retry queue: ${this.retrying} retrying, ${this.working} working.`);
|
||||
|
||||
const processAgain = () => {
|
||||
this.#timerId = setTimeout(() => this.#processAll(), 0);
|
||||
};
|
||||
|
||||
// if there's nothing in the queue, we're done
|
||||
const task = this.#retrying.shift();
|
||||
if (!task) {
|
||||
debug("Queue is empty, exiting.");
|
||||
|
||||
if (this.pending) {
|
||||
processAgain();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// if it's time to bail, then bail
|
||||
if (isTimeToBail(task, this.#timeout)) {
|
||||
debug(`Task ${task.id} was abandoned due to timeout.`);
|
||||
task.reject(task.error);
|
||||
processAgain();
|
||||
return;
|
||||
}
|
||||
|
||||
// if it's not time to retry, then wait and try again
|
||||
if (!isTimeToRetry(task, this.#maxDelay)) {
|
||||
debug(`Task ${task.id} is not ready to retry, skipping.`);
|
||||
this.#retrying.push(task);
|
||||
processAgain();
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise, try again
|
||||
task.lastAttempt = Date.now();
|
||||
|
||||
// Promise.resolve needed in case it's a thenable but not a Promise
|
||||
Promise.resolve(task.fn())
|
||||
// @ts-ignore because we know it's any
|
||||
.then(result => {
|
||||
debug(`Task ${task.id} succeeded after ${task.age}ms.`);
|
||||
task.resolve(result);
|
||||
})
|
||||
|
||||
// @ts-ignore because we know it's any
|
||||
.catch(error => {
|
||||
if (!this.#check(error)) {
|
||||
debug(`Task ${task.id} failed with non-retryable error: ${error.message}.`);
|
||||
task.reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
// update the task timestamp and push to back of queue to try again
|
||||
task.lastAttempt = Date.now();
|
||||
this.#retrying.push(task);
|
||||
debug(`Task ${task.id} failed, requeueing to try again.`);
|
||||
})
|
||||
.finally(() => {
|
||||
this.#processAll();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { Retrier };
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @fileoverview disallow using an async function as a Promise executor
|
||||
* @author Teddy Katz
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Disallow using an async function as a Promise executor",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-async-promise-executor",
|
||||
},
|
||||
|
||||
fixable: null,
|
||||
schema: [],
|
||||
messages: {
|
||||
async: "Promise executor functions should not be async.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
return {
|
||||
"NewExpression[callee.name='Promise'][arguments.0.async=true]"(
|
||||
node,
|
||||
) {
|
||||
if (!sourceCode.isGlobalReference(node.callee)) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.report({
|
||||
node: sourceCode.getFirstToken(
|
||||
node.arguments[0],
|
||||
token => token.value === "async",
|
||||
),
|
||||
messageId: "async",
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* @fileoverview Rule to disallow unused labels.
|
||||
* @author Toru Nagashima
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description: "Disallow unused labels",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-unused-labels",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
|
||||
fixable: "code",
|
||||
|
||||
messages: {
|
||||
unused: "'{{name}}:' is defined but never used.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
let scopeInfo = null;
|
||||
|
||||
/**
|
||||
* Adds a scope info to the stack.
|
||||
* @param {ASTNode} node A node to add. This is a LabeledStatement.
|
||||
* @returns {void}
|
||||
*/
|
||||
function enterLabeledScope(node) {
|
||||
scopeInfo = {
|
||||
label: node.label.name,
|
||||
used: false,
|
||||
upper: scopeInfo,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a `LabeledStatement` node is fixable.
|
||||
* For a node to be fixable, there must be no comments between the label and the body.
|
||||
* Furthermore, is must be possible to remove the label without turning the body statement into a
|
||||
* directive after other fixes are applied.
|
||||
* @param {ASTNode} node The node to evaluate.
|
||||
* @returns {boolean} Whether or not the node is fixable.
|
||||
*/
|
||||
function isFixable(node) {
|
||||
/*
|
||||
* Only perform a fix if there are no comments between the label and the body. This will be the case
|
||||
* when there is exactly one token/comment (the ":") between the label and the body.
|
||||
*/
|
||||
if (
|
||||
sourceCode.getTokenAfter(node.label, {
|
||||
includeComments: true,
|
||||
}) !==
|
||||
sourceCode.getTokenBefore(node.body, { includeComments: true })
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Looking for the node's deepest ancestor which is not a `LabeledStatement`.
|
||||
let ancestor = node.parent;
|
||||
|
||||
while (ancestor.type === "LabeledStatement") {
|
||||
ancestor = ancestor.parent;
|
||||
}
|
||||
|
||||
if (
|
||||
ancestor.type === "Program" ||
|
||||
(ancestor.type === "BlockStatement" &&
|
||||
astUtils.isFunction(ancestor.parent))
|
||||
) {
|
||||
const { body } = node;
|
||||
|
||||
if (
|
||||
body.type === "ExpressionStatement" &&
|
||||
((body.expression.type === "Literal" &&
|
||||
typeof body.expression.value === "string") ||
|
||||
astUtils.isStaticTemplateLiteral(body.expression))
|
||||
) {
|
||||
return false; // potential directive
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do not fix if removing the label would create an ASI hazard.
|
||||
* e.g. `foo()\nLABEL: [1].forEach(x => x)` → `foo()\n[1].forEach(x => x)`
|
||||
* would be parsed as `foo()[1].forEach(x => x)`.
|
||||
*/
|
||||
const SAFE_TOKENS_BEFORE = /^[:;{]$/u;
|
||||
const UNSAFE_FIRST_CHARS = /^[([\-+/`]/u;
|
||||
const tokenBefore = sourceCode.getTokenBefore(node);
|
||||
const firstBodyToken = sourceCode.getFirstToken(node.body);
|
||||
|
||||
if (
|
||||
tokenBefore &&
|
||||
!SAFE_TOKENS_BEFORE.test(tokenBefore.value) &&
|
||||
UNSAFE_FIRST_CHARS.test(firstBodyToken.value)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the top of the stack.
|
||||
* At the same time, this reports the label if it's never used.
|
||||
* @param {ASTNode} node A node to report. This is a LabeledStatement.
|
||||
* @returns {void}
|
||||
*/
|
||||
function exitLabeledScope(node) {
|
||||
if (!scopeInfo.used) {
|
||||
context.report({
|
||||
node: node.label,
|
||||
messageId: "unused",
|
||||
data: node.label,
|
||||
fix: isFixable(node)
|
||||
? fixer =>
|
||||
fixer.removeRange([
|
||||
node.range[0],
|
||||
node.body.range[0],
|
||||
])
|
||||
: null,
|
||||
});
|
||||
}
|
||||
|
||||
scopeInfo = scopeInfo.upper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the label of a given node as used.
|
||||
* @param {ASTNode} node A node to mark. This is a BreakStatement or
|
||||
* ContinueStatement.
|
||||
* @returns {void}
|
||||
*/
|
||||
function markAsUsed(node) {
|
||||
if (!node.label) {
|
||||
return;
|
||||
}
|
||||
|
||||
const label = node.label.name;
|
||||
let info = scopeInfo;
|
||||
|
||||
while (info) {
|
||||
if (info.label === label) {
|
||||
info.used = true;
|
||||
break;
|
||||
}
|
||||
info = info.upper;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
LabeledStatement: enterLabeledScope,
|
||||
"LabeledStatement:exit": exitLabeledScope,
|
||||
BreakStatement: markAsUsed,
|
||||
ContinueStatement: markAsUsed,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
'use strict'
|
||||
|
||||
const { register, unregister } = require('../..')
|
||||
const assert = require('assert')
|
||||
|
||||
function setup () {
|
||||
const obj = { foo: 'bar' }
|
||||
register(obj, shutdown)
|
||||
setImmediate(function () {
|
||||
unregister(obj)
|
||||
unregister(obj) // twice, this should not throw
|
||||
})
|
||||
}
|
||||
|
||||
let shutdownCalled = false
|
||||
function shutdown (obj) {
|
||||
shutdownCalled = true
|
||||
}
|
||||
|
||||
setup()
|
||||
|
||||
process.on('exit', function () {
|
||||
assert.strictEqual(shutdownCalled, false)
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
var regenerator = require("./regenerator.js");
|
||||
var regeneratorAsyncIterator = require("./regeneratorAsyncIterator.js");
|
||||
function _regeneratorAsyncGen(r, e, t, o, n) {
|
||||
return new regeneratorAsyncIterator(regenerator().w(r, e, t, o), n || Promise);
|
||||
}
|
||||
module.exports = _regeneratorAsyncGen, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @fileoverview Rule to flag when regex literals are not wrapped in parens
|
||||
* @author Matt DuVall <http://www.mattduvall.com>
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// 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-regex",
|
||||
url: "https://eslint.style/rules/wrap-regex",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description: "Require parenthesis around regex literals",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/wrap-regex",
|
||||
},
|
||||
|
||||
schema: [],
|
||||
fixable: "code",
|
||||
|
||||
messages: {
|
||||
requireParens:
|
||||
"Wrap the regexp literal in parens to disambiguate the slash.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.sourceCode;
|
||||
|
||||
return {
|
||||
Literal(node) {
|
||||
const token = sourceCode.getFirstToken(node),
|
||||
nodeType = token.type;
|
||||
|
||||
if (nodeType === "RegularExpression") {
|
||||
const beforeToken = sourceCode.getTokenBefore(node);
|
||||
const afterToken = sourceCode.getTokenAfter(node);
|
||||
const { parent } = node;
|
||||
|
||||
if (
|
||||
parent.type === "MemberExpression" &&
|
||||
parent.object === node &&
|
||||
!(
|
||||
beforeToken &&
|
||||
beforeToken.value === "(" &&
|
||||
afterToken &&
|
||||
afterToken.value === ")"
|
||||
)
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: "requireParens",
|
||||
fix: fixer =>
|
||||
fixer.replaceText(
|
||||
node,
|
||||
`(${sourceCode.getText(node)})`,
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,807 @@
|
||||
import { expect, expectTypeOf, test } from "vitest";
|
||||
import * as z from "zod/v4";
|
||||
|
||||
declare const iss: z.core.$ZodIssueCode;
|
||||
|
||||
const Test = z.object({
|
||||
f1: z.number(),
|
||||
f2: z.string().optional(),
|
||||
f3: z.string().nullable(),
|
||||
f4: z.array(z.object({ t: z.union([z.string(), z.boolean()]) })),
|
||||
});
|
||||
// type TestFlattenedErrors = core.inferFlattenedErrors<typeof Test, { message: string; code: number }>;
|
||||
// type TestFormErrors = core.inferFlattenedErrors<typeof Test>;
|
||||
const parsed = Test.safeParse({});
|
||||
|
||||
test("regular error", () => {
|
||||
expect(parsed).toMatchInlineSnapshot(`
|
||||
{
|
||||
"error": [ZodError: [
|
||||
{
|
||||
"expected": "number",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"f1"
|
||||
],
|
||||
"message": "Invalid input: expected number, received undefined"
|
||||
},
|
||||
{
|
||||
"expected": "string",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"f3"
|
||||
],
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
},
|
||||
{
|
||||
"expected": "array",
|
||||
"code": "invalid_type",
|
||||
"path": [
|
||||
"f4"
|
||||
],
|
||||
"message": "Invalid input: expected array, received undefined"
|
||||
}
|
||||
]],
|
||||
"success": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test(".flatten()", () => {
|
||||
const flattened = parsed.error!.flatten();
|
||||
// flattened.
|
||||
expectTypeOf(flattened).toMatchTypeOf<{
|
||||
formErrors: string[];
|
||||
fieldErrors: {
|
||||
f2?: string[];
|
||||
f1?: string[];
|
||||
f3?: string[];
|
||||
f4?: string[];
|
||||
};
|
||||
}>();
|
||||
|
||||
expect(flattened).toMatchInlineSnapshot(`
|
||||
{
|
||||
"fieldErrors": {
|
||||
"f1": [
|
||||
"Invalid input: expected number, received undefined",
|
||||
],
|
||||
"f3": [
|
||||
"Invalid input: expected string, received undefined",
|
||||
],
|
||||
"f4": [
|
||||
"Invalid input: expected array, received undefined",
|
||||
],
|
||||
},
|
||||
"formErrors": [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("custom .flatten()", () => {
|
||||
type ErrorType = { message: string; code: number };
|
||||
const flattened = parsed.error!.flatten((iss) => ({
|
||||
message: iss.message,
|
||||
code: 1234,
|
||||
}));
|
||||
expectTypeOf(flattened).toMatchTypeOf<{
|
||||
formErrors: ErrorType[];
|
||||
fieldErrors: {
|
||||
f2?: ErrorType[];
|
||||
f1?: ErrorType[];
|
||||
f3?: ErrorType[];
|
||||
f4?: ErrorType[];
|
||||
};
|
||||
}>();
|
||||
|
||||
expect(flattened).toMatchInlineSnapshot(`
|
||||
{
|
||||
"fieldErrors": {
|
||||
"f1": [
|
||||
{
|
||||
"code": 1234,
|
||||
"message": "Invalid input: expected number, received undefined",
|
||||
},
|
||||
],
|
||||
"f3": [
|
||||
{
|
||||
"code": 1234,
|
||||
"message": "Invalid input: expected string, received undefined",
|
||||
},
|
||||
],
|
||||
"f4": [
|
||||
{
|
||||
"code": 1234,
|
||||
"message": "Invalid input: expected array, received undefined",
|
||||
},
|
||||
],
|
||||
},
|
||||
"formErrors": [],
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test(".format()", () => {
|
||||
const formatted = parsed.error!.format();
|
||||
expectTypeOf(formatted).toMatchTypeOf<{
|
||||
_errors: string[];
|
||||
f2?: { _errors: string[] };
|
||||
f1?: { _errors: string[] };
|
||||
f3?: { _errors: string[] };
|
||||
f4?: {
|
||||
[x: number]: {
|
||||
_errors: string[];
|
||||
t?: {
|
||||
_errors: string[];
|
||||
};
|
||||
};
|
||||
_errors: string[];
|
||||
};
|
||||
}>();
|
||||
|
||||
expect(formatted).toMatchInlineSnapshot(`
|
||||
{
|
||||
"_errors": [],
|
||||
"f1": {
|
||||
"_errors": [
|
||||
"Invalid input: expected number, received undefined",
|
||||
],
|
||||
},
|
||||
"f3": {
|
||||
"_errors": [
|
||||
"Invalid input: expected string, received undefined",
|
||||
],
|
||||
},
|
||||
"f4": {
|
||||
"_errors": [
|
||||
"Invalid input: expected array, received undefined",
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("custom .format()", () => {
|
||||
type ErrorType = { message: string; code: number };
|
||||
const formatted = parsed.error!.format((iss) => ({
|
||||
message: iss.message,
|
||||
code: 1234,
|
||||
}));
|
||||
expectTypeOf(formatted).toMatchTypeOf<{
|
||||
_errors: ErrorType[];
|
||||
f2?: { _errors: ErrorType[] };
|
||||
f1?: { _errors: ErrorType[] };
|
||||
f3?: { _errors: ErrorType[] };
|
||||
f4?: {
|
||||
[x: number]: {
|
||||
_errors: ErrorType[];
|
||||
t?: {
|
||||
_errors: ErrorType[];
|
||||
};
|
||||
};
|
||||
_errors: ErrorType[];
|
||||
};
|
||||
}>();
|
||||
|
||||
expect(formatted).toMatchInlineSnapshot(`
|
||||
{
|
||||
"_errors": [],
|
||||
"f1": {
|
||||
"_errors": [
|
||||
{
|
||||
"code": 1234,
|
||||
"message": "Invalid input: expected number, received undefined",
|
||||
},
|
||||
],
|
||||
},
|
||||
"f3": {
|
||||
"_errors": [
|
||||
{
|
||||
"code": 1234,
|
||||
"message": "Invalid input: expected string, received undefined",
|
||||
},
|
||||
],
|
||||
},
|
||||
"f4": {
|
||||
"_errors": [
|
||||
{
|
||||
"code": 1234,
|
||||
"message": "Invalid input: expected array, received undefined",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("all errors", () => {
|
||||
const propertySchema = z.string();
|
||||
const schema = z
|
||||
.object({
|
||||
a: propertySchema,
|
||||
b: propertySchema,
|
||||
})
|
||||
.refine(
|
||||
(val) => {
|
||||
return val.a === val.b;
|
||||
},
|
||||
{ message: "Must be equal" }
|
||||
);
|
||||
|
||||
const r1 = schema.safeParse({
|
||||
a: "asdf",
|
||||
b: "qwer",
|
||||
});
|
||||
|
||||
expect(z.core.flattenError(r1.error!)).toEqual({
|
||||
formErrors: ["Must be equal"],
|
||||
fieldErrors: {},
|
||||
});
|
||||
|
||||
const r2 = schema.safeParse({
|
||||
a: null,
|
||||
b: null,
|
||||
});
|
||||
|
||||
// const error = _error as z.ZodError;
|
||||
expect(z.core.flattenError(r2.error!)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"fieldErrors": {
|
||||
"a": [
|
||||
"Invalid input: expected string, received null",
|
||||
],
|
||||
"b": [
|
||||
"Invalid input: expected string, received null",
|
||||
],
|
||||
},
|
||||
"formErrors": [],
|
||||
}
|
||||
`);
|
||||
|
||||
expect(z.core.flattenError(r2.error!, (iss) => iss.message.toUpperCase())).toMatchInlineSnapshot(`
|
||||
{
|
||||
"fieldErrors": {
|
||||
"a": [
|
||||
"INVALID INPUT: EXPECTED STRING, RECEIVED NULL",
|
||||
],
|
||||
"b": [
|
||||
"INVALID INPUT: EXPECTED STRING, RECEIVED NULL",
|
||||
],
|
||||
},
|
||||
"formErrors": [],
|
||||
}
|
||||
`);
|
||||
// Test identity
|
||||
|
||||
expect(z.core.flattenError(r2.error!, (i: z.ZodIssue) => i)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"fieldErrors": {
|
||||
"a": [
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"message": "Invalid input: expected string, received null",
|
||||
"path": [
|
||||
"a",
|
||||
],
|
||||
},
|
||||
],
|
||||
"b": [
|
||||
{
|
||||
"code": "invalid_type",
|
||||
"expected": "string",
|
||||
"message": "Invalid input: expected string, received null",
|
||||
"path": [
|
||||
"b",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"formErrors": [],
|
||||
}
|
||||
`);
|
||||
|
||||
// Test mapping
|
||||
const f1 = z.core.flattenError(r2.error!, (i: z.ZodIssue) => i.message.length);
|
||||
expect(f1).toMatchInlineSnapshot(`
|
||||
{
|
||||
"fieldErrors": {
|
||||
"a": [
|
||||
45,
|
||||
],
|
||||
"b": [
|
||||
45,
|
||||
],
|
||||
},
|
||||
"formErrors": [],
|
||||
}
|
||||
`);
|
||||
// expect(f1.fieldErrors.a![0]).toEqual("Invalid input: expected string".length);
|
||||
// expect(f1).toMatchObject({
|
||||
// formErrors: [],
|
||||
// fieldErrors: {
|
||||
// a: ["Invalid input: expected string".length],
|
||||
// b: ["Invalid input: expected string".length],
|
||||
// },
|
||||
// });
|
||||
});
|
||||
|
||||
const schema = z.strictObject({
|
||||
username: z.string().brand<"username">(),
|
||||
favoriteNumbers: z.array(z.number()),
|
||||
nesting: z.object({
|
||||
a: z.string(),
|
||||
}),
|
||||
});
|
||||
const result = schema.safeParse({
|
||||
username: 1234,
|
||||
favoriteNumbers: [1234, "4567"],
|
||||
nesting: {
|
||||
a: 123,
|
||||
},
|
||||
extra: 1234,
|
||||
});
|
||||
|
||||
const tree = z.treeifyError(result.error!);
|
||||
|
||||
expectTypeOf(tree).toEqualTypeOf<{
|
||||
errors: string[];
|
||||
properties?: {
|
||||
username?: {
|
||||
errors: string[];
|
||||
};
|
||||
favoriteNumbers?: {
|
||||
errors: string[];
|
||||
items?: {
|
||||
errors: string[];
|
||||
}[];
|
||||
};
|
||||
nesting?: {
|
||||
errors: string[];
|
||||
properties?: {
|
||||
a?: {
|
||||
errors: string[];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}>();
|
||||
|
||||
test("z.treeifyError", () => {
|
||||
expect(tree).toMatchInlineSnapshot(`
|
||||
{
|
||||
"errors": [
|
||||
"Unrecognized key: "extra"",
|
||||
],
|
||||
"properties": {
|
||||
"favoriteNumbers": {
|
||||
"errors": [],
|
||||
"items": [
|
||||
,
|
||||
{
|
||||
"errors": [
|
||||
"Invalid input: expected number, received string",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"nesting": {
|
||||
"errors": [],
|
||||
"properties": {
|
||||
"a": {
|
||||
"errors": [
|
||||
"Invalid input: expected string, received number",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"username": {
|
||||
"errors": [
|
||||
"Invalid input: expected string, received number",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("z.treeifyError 2", () => {
|
||||
const schema = z.strictObject({
|
||||
name: z.string(),
|
||||
logLevel: z.union([z.string(), z.number()]),
|
||||
env: z.literal(["production", "development"]),
|
||||
});
|
||||
|
||||
const data = {
|
||||
name: 1000,
|
||||
logLevel: false,
|
||||
extra: 1000,
|
||||
};
|
||||
|
||||
const result = schema.safeParse(data);
|
||||
const err = z.treeifyError(result.error!);
|
||||
expect(err).toMatchInlineSnapshot(`
|
||||
{
|
||||
"errors": [
|
||||
"Unrecognized key: "extra"",
|
||||
],
|
||||
"properties": {
|
||||
"env": {
|
||||
"errors": [
|
||||
"Invalid option: expected one of "production"|"development"",
|
||||
],
|
||||
},
|
||||
"logLevel": {
|
||||
"errors": [
|
||||
"Invalid input: expected string, received boolean",
|
||||
"Invalid input: expected number, received boolean",
|
||||
],
|
||||
},
|
||||
"name": {
|
||||
"errors": [
|
||||
"Invalid input: expected string, received number",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("z.prettifyError", () => {
|
||||
expect(z.prettifyError(result.error!)).toMatchInlineSnapshot(`
|
||||
"✖ Unrecognized key: "extra"
|
||||
✖ Invalid input: expected string, received number
|
||||
→ at username
|
||||
✖ Invalid input: expected number, received string
|
||||
→ at favoriteNumbers[1]
|
||||
✖ Invalid input: expected string, received number
|
||||
→ at nesting.a"
|
||||
`);
|
||||
});
|
||||
|
||||
test("z.toDotPath", () => {
|
||||
expect(z.core.toDotPath(["a", "b", 0, "c"])).toMatchInlineSnapshot(`"a.b[0].c"`);
|
||||
|
||||
expect(z.core.toDotPath(["a", Symbol("b"), 0, "c"])).toMatchInlineSnapshot(`"a["Symbol(b)"][0].c"`);
|
||||
|
||||
// Test with periods in keys
|
||||
expect(z.core.toDotPath(["user.name", "first.last"])).toMatchInlineSnapshot(`"["user.name"]["first.last"]"`);
|
||||
|
||||
// Test with special characters
|
||||
expect(z.core.toDotPath(["user", "$special", Symbol("#symbol")])).toMatchInlineSnapshot(
|
||||
`"user.$special["Symbol(#symbol)"]"`
|
||||
);
|
||||
|
||||
// Test with dots and quotes
|
||||
expect(z.core.toDotPath(["search", `query("foo.bar"="abc")`])).toMatchInlineSnapshot(
|
||||
`"search["query(\\"foo.bar\\"=\\"abc\\")"]"`
|
||||
);
|
||||
|
||||
// Test with newlines
|
||||
expect(z.core.toDotPath(["search", `foo\nbar`])).toMatchInlineSnapshot(`"search["foo\\nbar"]"`);
|
||||
|
||||
// Test with empty strings
|
||||
expect(z.core.toDotPath(["", "empty"])).toMatchInlineSnapshot(`".empty"`);
|
||||
|
||||
// Test with array indices
|
||||
expect(z.core.toDotPath(["items", 0, 1, 2])).toMatchInlineSnapshot(`"items[0][1][2]"`);
|
||||
|
||||
// Test with mixed path elements
|
||||
expect(z.core.toDotPath(["users", "user.config", 0, "settings.theme"])).toMatchInlineSnapshot(
|
||||
`"users["user.config"][0]["settings.theme"]"`
|
||||
);
|
||||
|
||||
// Test with square brackets in keys
|
||||
expect(z.core.toDotPath(["data[0]", "value"])).toMatchInlineSnapshot(`"["data[0]"].value"`);
|
||||
|
||||
// Test with empty path
|
||||
expect(z.core.toDotPath([])).toMatchInlineSnapshot(`""`);
|
||||
});
|
||||
|
||||
test("inheritance", () => {
|
||||
const e1 = new z.ZodError([]);
|
||||
expect(e1).toBeInstanceOf(z.core.$ZodError);
|
||||
expect(e1).toBeInstanceOf(z.ZodError);
|
||||
// expect(e1).not.toBeInstanceOf(Error);
|
||||
|
||||
const e2 = new z.ZodRealError([]);
|
||||
expect(e2).toBeInstanceOf(z.ZodError);
|
||||
expect(e2).toBeInstanceOf(z.ZodRealError);
|
||||
expect(e2).toBeInstanceOf(Error);
|
||||
});
|
||||
|
||||
test("disc union treeify/format", () => {
|
||||
const schema = z.discriminatedUnion(
|
||||
"foo",
|
||||
[
|
||||
z.object({
|
||||
foo: z.literal("x"),
|
||||
x: z.string(),
|
||||
}),
|
||||
z.object({
|
||||
foo: z.literal("y"),
|
||||
y: z.string(),
|
||||
}),
|
||||
],
|
||||
{
|
||||
error: "Invalid discriminator",
|
||||
}
|
||||
);
|
||||
|
||||
const error = schema.safeParse({ foo: "invalid" }).error;
|
||||
expect(z.treeifyError(error!)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"errors": [],
|
||||
"properties": {
|
||||
"foo": {
|
||||
"errors": [
|
||||
"Invalid discriminator",
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
expect(z.prettifyError(error!)).toMatchInlineSnapshot(`
|
||||
"✖ Invalid discriminator
|
||||
→ at foo"
|
||||
`);
|
||||
expect(z.formatError(error!)).toMatchInlineSnapshot(`
|
||||
{
|
||||
"_errors": [],
|
||||
"foo": {
|
||||
"_errors": [
|
||||
"Invalid discriminator",
|
||||
],
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
test("update message after adding issues", () => {
|
||||
const e = new z.ZodError([]);
|
||||
e.addIssue({
|
||||
code: "custom",
|
||||
message: "message",
|
||||
input: "asdf",
|
||||
path: [],
|
||||
});
|
||||
expect(e.message).toMatchInlineSnapshot(`
|
||||
"[
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "message",
|
||||
"input": "asdf",
|
||||
"path": []
|
||||
}
|
||||
]"
|
||||
`);
|
||||
|
||||
e.addIssue({
|
||||
code: "custom",
|
||||
message: "message",
|
||||
input: "asdf",
|
||||
path: [],
|
||||
});
|
||||
expect(e.message).toMatchInlineSnapshot(`
|
||||
"[
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "message",
|
||||
"input": "asdf",
|
||||
"path": []
|
||||
},
|
||||
{
|
||||
"code": "custom",
|
||||
"message": "message",
|
||||
"input": "asdf",
|
||||
"path": []
|
||||
}
|
||||
]"
|
||||
`);
|
||||
});
|
||||
|
||||
test("z.formatError nested union preserves parent path", () => {
|
||||
const syntheticError = new z.ZodError([
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["parent"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: [],
|
||||
message: "Expected string",
|
||||
input: {},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["child"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: [],
|
||||
message: "Expected string",
|
||||
input: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "number",
|
||||
path: [],
|
||||
message: "Expected number",
|
||||
input: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
] as any);
|
||||
|
||||
const formatted: any = z.formatError(syntheticError);
|
||||
|
||||
// "child" must be nested under "parent", not at root
|
||||
expect(formatted).not.toHaveProperty("child");
|
||||
expect(formatted).toHaveProperty("parent");
|
||||
expect(formatted.parent).toHaveProperty("child");
|
||||
expect(formatted.parent.child._errors).toContain("Expected string");
|
||||
expect(formatted.parent.child._errors).toContain("Expected number");
|
||||
expect(formatted.parent._errors).toContain("Expected string");
|
||||
});
|
||||
test("z.treeifyError nested union preserves parent path", () => {
|
||||
// When a nested invalid_union appears inside another invalid_union,
|
||||
// the inner errors must stay nested under their parent path, not flatten to root.
|
||||
const syntheticError = new z.ZodError([
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["parent"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: [],
|
||||
message: "Expected string",
|
||||
input: {},
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["child"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: [],
|
||||
message: "Expected string",
|
||||
input: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "number",
|
||||
path: [],
|
||||
message: "Expected number",
|
||||
input: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
] as any);
|
||||
|
||||
const tree: any = z.treeifyError(syntheticError);
|
||||
|
||||
// "child" must be nested under "parent", not at root
|
||||
expect(tree.properties).not.toHaveProperty("child");
|
||||
expect(tree.properties).toHaveProperty("parent");
|
||||
expect(tree.properties.parent.properties).toHaveProperty("child");
|
||||
expect(tree.properties.parent.properties.child.errors).toContain("Expected string");
|
||||
expect(tree.properties.parent.properties.child.errors).toContain("Expected number");
|
||||
expect(tree.properties.parent.errors).toContain("Expected string");
|
||||
});
|
||||
|
||||
test("z.treeifyError deeply nested union (4 levels) preserves full path", () => {
|
||||
// a > b > c > d — each level wrapped in an invalid_union
|
||||
const syntheticError = new z.ZodError([
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["a"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["b"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_union",
|
||||
path: ["c"],
|
||||
message: "Invalid input",
|
||||
errors: [
|
||||
[
|
||||
{
|
||||
code: "invalid_type",
|
||||
expected: "string",
|
||||
path: ["d"],
|
||||
message: "Expected string",
|
||||
input: 123,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
] as any);
|
||||
|
||||
const tree: any = z.treeifyError(syntheticError);
|
||||
|
||||
// The full path must be preserved: a.b.c.d
|
||||
expect(tree.properties).toHaveProperty("a");
|
||||
expect(tree.properties).not.toHaveProperty("b");
|
||||
expect(tree.properties).not.toHaveProperty("c");
|
||||
|
||||
const lvlA = tree.properties.a;
|
||||
expect(lvlA.properties).toHaveProperty("b");
|
||||
|
||||
const lvlB = lvlA.properties.b;
|
||||
expect(lvlB.properties).toHaveProperty("c");
|
||||
|
||||
const lvlC = lvlB.properties.c;
|
||||
expect(lvlC.properties).toHaveProperty("d");
|
||||
expect(lvlC.properties.d.errors).toContain("Expected string");
|
||||
});
|
||||
|
||||
test("z.treeifyError nested union with real schema", () => {
|
||||
const innerUnion = z.union([
|
||||
z.object({ type: z.literal("a"), value: z.string() }),
|
||||
z.object({ type: z.literal("b"), value: z.number() }),
|
||||
]);
|
||||
|
||||
const schema = z.string().or(
|
||||
z.object({
|
||||
settings: z.object({ name: z.string() }).and(innerUnion),
|
||||
})
|
||||
);
|
||||
|
||||
const result = schema.safeParse({
|
||||
settings: { name: 123, type: "x", value: true },
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
if (!result.success) {
|
||||
const tree: any = z.treeifyError(result.error);
|
||||
|
||||
// All settings-related errors should be under "settings", not at root
|
||||
expect(tree.properties).toHaveProperty("settings");
|
||||
const settingsProperties = tree.properties.settings.properties ?? {};
|
||||
for (const key of Object.keys(settingsProperties)) {
|
||||
// Every sub-property under settings should NOT also appear at root
|
||||
if (key !== "settings") {
|
||||
expect(tree.properties).not.toHaveProperty(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,239 @@
|
||||
{
|
||||
"name": "vitest",
|
||||
"type": "module",
|
||||
"version": "4.1.10",
|
||||
"description": "Next generation testing framework powered by Vite",
|
||||
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
|
||||
"license": "MIT",
|
||||
"funding": "https://opencollective.com/vitest",
|
||||
"homepage": "https://vitest.dev",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vitest-dev/vitest.git",
|
||||
"directory": "packages/vitest"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vitest-dev/vitest/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"vite",
|
||||
"vitest",
|
||||
"test",
|
||||
"jest"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"imports": {
|
||||
"#module-evaluator": {
|
||||
"types": "./dist/module-evaluator.d.ts",
|
||||
"default": "./dist/module-evaluator.js"
|
||||
},
|
||||
"#nodejs-worker-loader": "./dist/nodejs-worker-loader.js"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"import": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"require": {
|
||||
"types": "./index.d.cts",
|
||||
"default": "./index.cjs"
|
||||
}
|
||||
},
|
||||
"./browser": {
|
||||
"types": "./browser/context.d.ts",
|
||||
"default": "./browser/context.js"
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
"./optional-types.js": {
|
||||
"types": "./optional-types.d.ts"
|
||||
},
|
||||
"./optional-runtime-types.js": {
|
||||
"types": "./optional-runtime-types.d.ts"
|
||||
},
|
||||
"./src/*": "./src/*",
|
||||
"./globals": {
|
||||
"types": "./globals.d.ts"
|
||||
},
|
||||
"./jsdom": {
|
||||
"types": "./jsdom.d.ts"
|
||||
},
|
||||
"./importMeta": {
|
||||
"types": "./importMeta.d.ts"
|
||||
},
|
||||
"./import-meta": {
|
||||
"types": "./import-meta.d.ts"
|
||||
},
|
||||
"./node": {
|
||||
"types": "./dist/node.d.ts",
|
||||
"default": "./dist/node.js"
|
||||
},
|
||||
"./internal/browser": {
|
||||
"types": "./dist/browser.d.ts",
|
||||
"default": "./dist/browser.js"
|
||||
},
|
||||
"./runners": {
|
||||
"types": "./dist/runners.d.ts",
|
||||
"default": "./dist/runners.js"
|
||||
},
|
||||
"./suite": {
|
||||
"types": "./dist/suite.d.ts",
|
||||
"default": "./dist/suite.js"
|
||||
},
|
||||
"./environments": {
|
||||
"types": "./dist/environments.d.ts",
|
||||
"default": "./dist/environments.js"
|
||||
},
|
||||
"./config": {
|
||||
"types": "./config.d.ts",
|
||||
"require": "./dist/config.cjs",
|
||||
"default": "./dist/config.js"
|
||||
},
|
||||
"./coverage": {
|
||||
"types": "./coverage.d.ts",
|
||||
"default": "./dist/coverage.js"
|
||||
},
|
||||
"./reporters": {
|
||||
"types": "./dist/reporters.d.ts",
|
||||
"default": "./dist/reporters.js"
|
||||
},
|
||||
"./snapshot": {
|
||||
"types": "./dist/snapshot.d.ts",
|
||||
"default": "./dist/snapshot.js"
|
||||
},
|
||||
"./runtime": {
|
||||
"types": "./dist/runtime.d.ts",
|
||||
"default": "./dist/runtime.js"
|
||||
},
|
||||
"./worker": {
|
||||
"types": "./worker.d.ts",
|
||||
"default": "./dist/worker.js"
|
||||
}
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"bin": {
|
||||
"vitest": "./vitest.mjs"
|
||||
},
|
||||
"files": [
|
||||
"*.cjs",
|
||||
"*.d.cts",
|
||||
"*.d.ts",
|
||||
"*.mjs",
|
||||
"bin",
|
||||
"browser",
|
||||
"dist"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.0.0 || ^22.0.0 || >=24.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
|
||||
"@vitest/browser-preview": "4.1.10",
|
||||
"@vitest/coverage-istanbul": "4.1.10",
|
||||
"@vitest/browser-playwright": "4.1.10",
|
||||
"@vitest/browser-webdriverio": "4.1.10",
|
||||
"@vitest/coverage-v8": "4.1.10",
|
||||
"@vitest/ui": "4.1.10"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@edge-runtime/vm": {
|
||||
"optional": true
|
||||
},
|
||||
"@opentelemetry/api": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/browser-playwright": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/browser-preview": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/browser-webdriverio": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/coverage-istanbul": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/coverage-v8": {
|
||||
"optional": true
|
||||
},
|
||||
"@vitest/ui": {
|
||||
"optional": true
|
||||
},
|
||||
"happy-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"jsdom": {
|
||||
"optional": true
|
||||
},
|
||||
"vite": {
|
||||
"optional": false
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"magic-string": "^0.30.21",
|
||||
"obug": "^2.1.1",
|
||||
"pathe": "^2.0.3",
|
||||
"picomatch": "^4.0.3",
|
||||
"std-env": "^4.0.0-rc.1",
|
||||
"tinybench": "^2.9.0",
|
||||
"tinyexec": "^1.0.2",
|
||||
"tinyglobby": "^0.2.15",
|
||||
"tinyrainbow": "^3.1.0",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0",
|
||||
"why-is-node-running": "^2.3.0",
|
||||
"@vitest/expect": "4.1.10",
|
||||
"@vitest/mocker": "4.1.10",
|
||||
"@vitest/pretty-format": "4.1.10",
|
||||
"@vitest/runner": "4.1.10",
|
||||
"@vitest/spy": "4.1.10",
|
||||
"@vitest/snapshot": "4.1.10",
|
||||
"@vitest/utils": "4.1.10"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/install-pkg": "^1.1.0",
|
||||
"@bomb.sh/tab": "^0.0.14",
|
||||
"@edge-runtime/vm": "^5.0.0",
|
||||
"@jridgewell/trace-mapping": "0.3.31",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@sinonjs/fake-timers": "15.0.0",
|
||||
"@types/estree": "^1.0.8",
|
||||
"@types/istanbul-lib-coverage": "^2.0.6",
|
||||
"@types/istanbul-reports": "^3.0.4",
|
||||
"@types/jsdom": "^27.0.0",
|
||||
"@types/node": "^24.12.0",
|
||||
"@types/picomatch": "^4.0.2",
|
||||
"@types/prompts": "^2.4.9",
|
||||
"@types/sinonjs__fake-timers": "^15.0.1",
|
||||
"acorn": "8.11.3",
|
||||
"acorn-walk": "^8.3.5",
|
||||
"birpc": "^4.0.0",
|
||||
"cac": "^6.7.14",
|
||||
"empathic": "^2.0.0",
|
||||
"flatted": "^3.4.2",
|
||||
"happy-dom": "^20.8.3",
|
||||
"jsdom": "^27.4.0",
|
||||
"local-pkg": "^1.1.2",
|
||||
"mime": "^4.1.0",
|
||||
"prompts": "^2.4.2",
|
||||
"strip-literal": "^3.1.0",
|
||||
"tinyhighlight": "^0.3.2",
|
||||
"ws": "^8.19.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "premove dist && rollup -c",
|
||||
"dev": "NODE_OPTIONS=\"--max-old-space-size=8192\" rollup -c --watch -m inline"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
"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"));
|
||||
/**
|
||||
* Enables each the rules provided as a part of typescript-eslint. Note that many rules are not applicable in all codebases, or are meant to be configured.
|
||||
* @see {@link https://typescript-eslint.io/users/configs#all}
|
||||
*/
|
||||
exports.default = (plugin, parser) => [
|
||||
(0, base_1.default)(plugin, parser),
|
||||
(0, eslint_recommended_1.default)(plugin, parser),
|
||||
{
|
||||
name: 'typescript-eslint/all',
|
||||
rules: {
|
||||
'@typescript-eslint/adjacent-overload-signatures': 'error',
|
||||
'@typescript-eslint/array-type': 'error',
|
||||
'@typescript-eslint/await-thenable': 'error',
|
||||
'@typescript-eslint/ban-ts-comment': 'error',
|
||||
'@typescript-eslint/ban-tslint-comment': 'error',
|
||||
'@typescript-eslint/class-literal-property-style': 'error',
|
||||
'class-methods-use-this': 'off',
|
||||
'@typescript-eslint/class-methods-use-this': 'error',
|
||||
'@typescript-eslint/consistent-generic-constructors': 'error',
|
||||
'@typescript-eslint/consistent-indexed-object-style': 'error',
|
||||
'consistent-return': 'off',
|
||||
'@typescript-eslint/consistent-return': 'error',
|
||||
'@typescript-eslint/consistent-type-assertions': 'error',
|
||||
'@typescript-eslint/consistent-type-definitions': 'error',
|
||||
'@typescript-eslint/consistent-type-exports': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'default-param-last': 'off',
|
||||
'@typescript-eslint/default-param-last': 'error',
|
||||
'dot-notation': 'off',
|
||||
'@typescript-eslint/dot-notation': 'error',
|
||||
'@typescript-eslint/explicit-function-return-type': 'error',
|
||||
'@typescript-eslint/explicit-member-accessibility': 'error',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'error',
|
||||
'init-declarations': 'off',
|
||||
'@typescript-eslint/init-declarations': 'error',
|
||||
'max-params': 'off',
|
||||
'@typescript-eslint/max-params': 'error',
|
||||
'@typescript-eslint/member-ordering': 'error',
|
||||
'@typescript-eslint/method-signature-style': 'error',
|
||||
'@typescript-eslint/naming-convention': 'error',
|
||||
'no-array-constructor': 'off',
|
||||
'@typescript-eslint/no-array-constructor': 'error',
|
||||
'@typescript-eslint/no-array-delete': 'error',
|
||||
'@typescript-eslint/no-base-to-string': 'error',
|
||||
'@typescript-eslint/no-confusing-non-null-assertion': 'error',
|
||||
'@typescript-eslint/no-confusing-void-expression': 'error',
|
||||
'@typescript-eslint/no-deprecated': 'error',
|
||||
'no-dupe-class-members': 'off',
|
||||
'@typescript-eslint/no-dupe-class-members': 'error',
|
||||
'@typescript-eslint/no-duplicate-enum-values': 'error',
|
||||
'@typescript-eslint/no-duplicate-type-constituents': 'error',
|
||||
'@typescript-eslint/no-dynamic-delete': 'error',
|
||||
'no-empty-function': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'error',
|
||||
'@typescript-eslint/no-empty-object-type': 'error',
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'@typescript-eslint/no-extra-non-null-assertion': 'error',
|
||||
'@typescript-eslint/no-extraneous-class': 'error',
|
||||
'@typescript-eslint/no-floating-promises': 'error',
|
||||
'@typescript-eslint/no-for-in-array': 'error',
|
||||
'no-implied-eval': 'off',
|
||||
'@typescript-eslint/no-implied-eval': 'error',
|
||||
'@typescript-eslint/no-import-type-side-effects': 'error',
|
||||
'@typescript-eslint/no-inferrable-types': 'error',
|
||||
'no-invalid-this': 'off',
|
||||
'@typescript-eslint/no-invalid-this': 'error',
|
||||
'@typescript-eslint/no-invalid-void-type': 'error',
|
||||
'no-magic-numbers': 'off',
|
||||
'@typescript-eslint/no-magic-numbers': 'error',
|
||||
'@typescript-eslint/no-meaningless-void-operator': 'error',
|
||||
'@typescript-eslint/no-misused-new': 'error',
|
||||
'@typescript-eslint/no-misused-promises': 'error',
|
||||
'@typescript-eslint/no-misused-spread': 'error',
|
||||
'@typescript-eslint/no-mixed-enums': 'error',
|
||||
'@typescript-eslint/no-namespace': 'error',
|
||||
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error',
|
||||
'@typescript-eslint/no-non-null-asserted-optional-chain': 'error',
|
||||
'@typescript-eslint/no-non-null-assertion': 'error',
|
||||
'no-redeclare': 'off',
|
||||
'@typescript-eslint/no-redeclare': 'error',
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'error',
|
||||
'@typescript-eslint/no-require-imports': 'error',
|
||||
'@typescript-eslint/no-restricted-types': 'error',
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
'@typescript-eslint/no-this-alias': 'error',
|
||||
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
|
||||
'@typescript-eslint/no-unnecessary-condition': 'error',
|
||||
'@typescript-eslint/no-unnecessary-parameter-property-assignment': 'error',
|
||||
'@typescript-eslint/no-unnecessary-qualifier': 'error',
|
||||
'@typescript-eslint/no-unnecessary-template-expression': 'error',
|
||||
'@typescript-eslint/no-unnecessary-type-arguments': 'error',
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
|
||||
'@typescript-eslint/no-unnecessary-type-constraint': 'error',
|
||||
'@typescript-eslint/no-unnecessary-type-conversion': 'error',
|
||||
'@typescript-eslint/no-unnecessary-type-parameters': 'error',
|
||||
'@typescript-eslint/no-unsafe-argument': 'error',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'error',
|
||||
'@typescript-eslint/no-unsafe-call': 'error',
|
||||
'@typescript-eslint/no-unsafe-declaration-merging': 'error',
|
||||
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'error',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'error',
|
||||
'@typescript-eslint/no-unsafe-return': 'error',
|
||||
'@typescript-eslint/no-unsafe-type-assertion': 'error',
|
||||
'@typescript-eslint/no-unsafe-unary-minus': 'error',
|
||||
'no-unused-expressions': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'error',
|
||||
'no-unused-private-class-members': 'off',
|
||||
'@typescript-eslint/no-unused-private-class-members': 'error',
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'error',
|
||||
'no-useless-constructor': 'off',
|
||||
'@typescript-eslint/no-useless-constructor': 'error',
|
||||
'@typescript-eslint/no-useless-default-assignment': 'error',
|
||||
'@typescript-eslint/no-useless-empty-export': 'error',
|
||||
'@typescript-eslint/no-wrapper-object-types': 'error',
|
||||
'@typescript-eslint/non-nullable-type-assertion-style': 'error',
|
||||
'no-throw-literal': 'off',
|
||||
'@typescript-eslint/only-throw-error': 'error',
|
||||
'@typescript-eslint/parameter-properties': 'error',
|
||||
'@typescript-eslint/prefer-as-const': 'error',
|
||||
'prefer-destructuring': 'off',
|
||||
'@typescript-eslint/prefer-destructuring': 'error',
|
||||
'@typescript-eslint/prefer-enum-initializers': 'error',
|
||||
'@typescript-eslint/prefer-find': 'error',
|
||||
'@typescript-eslint/prefer-for-of': 'error',
|
||||
'@typescript-eslint/prefer-function-type': 'error',
|
||||
'@typescript-eslint/prefer-includes': 'error',
|
||||
'@typescript-eslint/prefer-literal-enum-member': 'error',
|
||||
'@typescript-eslint/prefer-namespace-keyword': 'error',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'error',
|
||||
'@typescript-eslint/prefer-optional-chain': 'error',
|
||||
'prefer-promise-reject-errors': 'off',
|
||||
'@typescript-eslint/prefer-promise-reject-errors': 'error',
|
||||
'@typescript-eslint/prefer-readonly': 'error',
|
||||
'@typescript-eslint/prefer-readonly-parameter-types': 'error',
|
||||
'@typescript-eslint/prefer-reduce-type-parameter': 'error',
|
||||
'@typescript-eslint/prefer-regexp-exec': 'error',
|
||||
'@typescript-eslint/prefer-return-this-type': 'error',
|
||||
'@typescript-eslint/prefer-string-starts-ends-with': 'error',
|
||||
'@typescript-eslint/promise-function-async': 'error',
|
||||
'@typescript-eslint/related-getter-setter-pairs': 'error',
|
||||
'@typescript-eslint/require-array-sort-compare': 'error',
|
||||
'require-await': 'off',
|
||||
'@typescript-eslint/require-await': 'error',
|
||||
'@typescript-eslint/restrict-plus-operands': 'error',
|
||||
'@typescript-eslint/restrict-template-expressions': 'error',
|
||||
'no-return-await': 'off',
|
||||
'@typescript-eslint/return-await': 'error',
|
||||
'@typescript-eslint/strict-boolean-expressions': 'error',
|
||||
'@typescript-eslint/strict-void-return': 'error',
|
||||
'@typescript-eslint/switch-exhaustiveness-check': 'error',
|
||||
'@typescript-eslint/triple-slash-reference': 'error',
|
||||
'@typescript-eslint/unbound-method': 'error',
|
||||
'@typescript-eslint/unified-signatures': 'error',
|
||||
'@typescript-eslint/use-unknown-in-catch-callback-variable': 'error',
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* @fileoverview Rule to require function names to match the name of the variable or property to which they are assigned.
|
||||
* @author Annie Zhang, Pavel Strashkin
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Requirements
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
const astUtils = require("./utils/ast-utils");
|
||||
const esutils = require("esutils");
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Determines if a pattern is `module.exports` or `module["exports"]`
|
||||
* @param {ASTNode} pattern The left side of the AssignmentExpression
|
||||
* @returns {boolean} True if the pattern is `module.exports` or `module["exports"]`
|
||||
*/
|
||||
function isModuleExports(pattern) {
|
||||
if (
|
||||
pattern.type === "MemberExpression" &&
|
||||
pattern.object.type === "Identifier" &&
|
||||
pattern.object.name === "module"
|
||||
) {
|
||||
// module.exports
|
||||
if (
|
||||
pattern.property.type === "Identifier" &&
|
||||
pattern.property.name === "exports"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// module["exports"]
|
||||
if (
|
||||
pattern.property.type === "Literal" &&
|
||||
pattern.property.value === "exports"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a string name is a valid identifier
|
||||
* @param {string} name The string to be checked
|
||||
* @param {number} ecmaVersion The ECMAScript version if specified in the parserOptions config
|
||||
* @returns {boolean} True if the string is a valid identifier
|
||||
*/
|
||||
function isIdentifier(name, ecmaVersion) {
|
||||
if (ecmaVersion >= 2015) {
|
||||
return esutils.keyword.isIdentifierES6(name);
|
||||
}
|
||||
return esutils.keyword.isIdentifierES5(name);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const alwaysOrNever = { enum: ["always", "never"] };
|
||||
const optionsObject = {
|
||||
type: "object",
|
||||
properties: {
|
||||
considerPropertyDescriptor: {
|
||||
type: "boolean",
|
||||
},
|
||||
includeCommonJSModuleExports: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
};
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "suggestion",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Require function names to match the name of the variable or property to which they are assigned",
|
||||
recommended: false,
|
||||
frozen: true,
|
||||
url: "https://eslint.org/docs/latest/rules/func-name-matching",
|
||||
},
|
||||
|
||||
schema: {
|
||||
anyOf: [
|
||||
{
|
||||
type: "array",
|
||||
additionalItems: false,
|
||||
items: [alwaysOrNever, optionsObject],
|
||||
},
|
||||
{
|
||||
type: "array",
|
||||
additionalItems: false,
|
||||
items: [optionsObject],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
defaultOptions: ["always"],
|
||||
|
||||
messages: {
|
||||
matchProperty:
|
||||
"Function name `{{funcName}}` should match property name `{{name}}`.",
|
||||
matchVariable:
|
||||
"Function name `{{funcName}}` should match variable name `{{name}}`.",
|
||||
notMatchProperty:
|
||||
"Function name `{{funcName}}` should not match property name `{{name}}`.",
|
||||
notMatchVariable:
|
||||
"Function name `{{funcName}}` should not match variable name `{{name}}`.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const options =
|
||||
(typeof context.options[0] === "object"
|
||||
? context.options[0]
|
||||
: context.options[1]) || {};
|
||||
const nameMatches =
|
||||
typeof context.options[0] === "string"
|
||||
? context.options[0]
|
||||
: "always";
|
||||
const considerPropertyDescriptor = options.considerPropertyDescriptor;
|
||||
const includeModuleExports = options.includeCommonJSModuleExports;
|
||||
const ecmaVersion = context.languageOptions.ecmaVersion;
|
||||
|
||||
/**
|
||||
* Check whether node is a certain CallExpression.
|
||||
* @param {string} objName object name
|
||||
* @param {string} funcName function name
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} `true` if node matches CallExpression
|
||||
*/
|
||||
function isPropertyCall(objName, funcName, node) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
node.type === "CallExpression" &&
|
||||
astUtils.isSpecificMemberAccess(node.callee, objName, funcName)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares identifiers based on the nameMatches option
|
||||
* @param {string} x the first identifier
|
||||
* @param {string} y the second identifier
|
||||
* @returns {boolean} whether the two identifiers should warn.
|
||||
*/
|
||||
function shouldWarn(x, y) {
|
||||
return (
|
||||
(nameMatches === "always" && x !== y) ||
|
||||
(nameMatches === "never" && x === y)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports
|
||||
* @param {ASTNode} node The node to report
|
||||
* @param {string} name The variable or property name
|
||||
* @param {string} funcName The function name
|
||||
* @param {boolean} isProp True if the reported node is a property assignment
|
||||
* @returns {void}
|
||||
*/
|
||||
function report(node, name, funcName, isProp) {
|
||||
let messageId;
|
||||
|
||||
if (nameMatches === "always" && isProp) {
|
||||
messageId = "matchProperty";
|
||||
} else if (nameMatches === "always") {
|
||||
messageId = "matchVariable";
|
||||
} else if (isProp) {
|
||||
messageId = "notMatchProperty";
|
||||
} else {
|
||||
messageId = "notMatchVariable";
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
messageId,
|
||||
data: {
|
||||
name,
|
||||
funcName,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a given node is a string literal
|
||||
* @param {ASTNode} node The node to check
|
||||
* @returns {boolean} `true` if the node is a string literal
|
||||
*/
|
||||
function isStringLiteral(node) {
|
||||
return node.type === "Literal" && typeof node.value === "string";
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Public
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
return {
|
||||
VariableDeclarator(node) {
|
||||
if (
|
||||
!node.init ||
|
||||
node.init.type !== "FunctionExpression" ||
|
||||
node.id.type !== "Identifier"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
node.init.id &&
|
||||
shouldWarn(node.id.name, node.init.id.name)
|
||||
) {
|
||||
report(node, node.id.name, node.init.id.name, false);
|
||||
}
|
||||
},
|
||||
|
||||
AssignmentExpression(node) {
|
||||
if (
|
||||
node.right.type !== "FunctionExpression" ||
|
||||
(node.left.computed &&
|
||||
node.left.property.type !== "Literal") ||
|
||||
(!includeModuleExports && isModuleExports(node.left)) ||
|
||||
(node.left.type !== "Identifier" &&
|
||||
node.left.type !== "MemberExpression")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isProp = node.left.type === "MemberExpression";
|
||||
const name = isProp
|
||||
? astUtils.getStaticPropertyName(node.left)
|
||||
: node.left.name;
|
||||
|
||||
if (
|
||||
node.right.id &&
|
||||
name &&
|
||||
isIdentifier(name) &&
|
||||
shouldWarn(name, node.right.id.name)
|
||||
) {
|
||||
report(node, name, node.right.id.name, isProp);
|
||||
}
|
||||
},
|
||||
|
||||
"Property, PropertyDefinition[value]"(node) {
|
||||
if (!(
|
||||
node.value.type === "FunctionExpression" && node.value.id
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.key.type === "Identifier" && !node.computed) {
|
||||
const functionName = node.value.id.name;
|
||||
let propertyName = node.key.name;
|
||||
|
||||
if (
|
||||
considerPropertyDescriptor &&
|
||||
propertyName === "value" &&
|
||||
node.parent.type === "ObjectExpression"
|
||||
) {
|
||||
if (
|
||||
isPropertyCall(
|
||||
"Object",
|
||||
"defineProperty",
|
||||
node.parent.parent,
|
||||
) ||
|
||||
isPropertyCall(
|
||||
"Reflect",
|
||||
"defineProperty",
|
||||
node.parent.parent,
|
||||
)
|
||||
) {
|
||||
const property = node.parent.parent.arguments[1];
|
||||
|
||||
if (
|
||||
isStringLiteral(property) &&
|
||||
shouldWarn(property.value, functionName)
|
||||
) {
|
||||
report(
|
||||
node,
|
||||
property.value,
|
||||
functionName,
|
||||
true,
|
||||
);
|
||||
}
|
||||
} else if (
|
||||
isPropertyCall(
|
||||
"Object",
|
||||
"defineProperties",
|
||||
node.parent.parent.parent.parent,
|
||||
)
|
||||
) {
|
||||
propertyName = node.parent.parent.key.name;
|
||||
if (
|
||||
!node.parent.parent.computed &&
|
||||
shouldWarn(propertyName, functionName)
|
||||
) {
|
||||
report(node, propertyName, functionName, true);
|
||||
}
|
||||
} else if (
|
||||
isPropertyCall(
|
||||
"Object",
|
||||
"create",
|
||||
node.parent.parent.parent.parent,
|
||||
)
|
||||
) {
|
||||
propertyName = node.parent.parent.key.name;
|
||||
if (
|
||||
!node.parent.parent.computed &&
|
||||
shouldWarn(propertyName, functionName)
|
||||
) {
|
||||
report(node, propertyName, functionName, true);
|
||||
}
|
||||
} else if (shouldWarn(propertyName, functionName)) {
|
||||
report(node, propertyName, functionName, true);
|
||||
}
|
||||
} else if (shouldWarn(propertyName, functionName)) {
|
||||
report(node, propertyName, functionName, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
isStringLiteral(node.key) &&
|
||||
isIdentifier(node.key.value, ecmaVersion) &&
|
||||
shouldWarn(node.key.value, node.value.id.name)
|
||||
) {
|
||||
report(node, node.key.value, node.value.id.name, true);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* HMAC: RFC2104 message authentication code.
|
||||
* @module
|
||||
*/
|
||||
import { abytes, aexists, ahash, clean, Hash, toBytes } from "./utils.js";
|
||||
export class HMAC extends Hash {
|
||||
constructor(hash, _key) {
|
||||
super();
|
||||
this.finished = false;
|
||||
this.destroyed = false;
|
||||
ahash(hash);
|
||||
const key = toBytes(_key);
|
||||
this.iHash = hash.create();
|
||||
if (typeof this.iHash.update !== 'function')
|
||||
throw new Error('Expected instance of class which extends utils.Hash');
|
||||
this.blockLen = this.iHash.blockLen;
|
||||
this.outputLen = this.iHash.outputLen;
|
||||
const blockLen = this.blockLen;
|
||||
const pad = new Uint8Array(blockLen);
|
||||
// blockLen can be bigger than outputLen
|
||||
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
||||
for (let i = 0; i < pad.length; i++)
|
||||
pad[i] ^= 0x36;
|
||||
this.iHash.update(pad);
|
||||
// By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
|
||||
this.oHash = hash.create();
|
||||
// Undo internal XOR && apply outer XOR
|
||||
for (let i = 0; i < pad.length; i++)
|
||||
pad[i] ^= 0x36 ^ 0x5c;
|
||||
this.oHash.update(pad);
|
||||
clean(pad);
|
||||
}
|
||||
update(buf) {
|
||||
aexists(this);
|
||||
this.iHash.update(buf);
|
||||
return this;
|
||||
}
|
||||
digestInto(out) {
|
||||
aexists(this);
|
||||
abytes(out, this.outputLen);
|
||||
this.finished = true;
|
||||
this.iHash.digestInto(out);
|
||||
this.oHash.update(out);
|
||||
this.oHash.digestInto(out);
|
||||
this.destroy();
|
||||
}
|
||||
digest() {
|
||||
const out = new Uint8Array(this.oHash.outputLen);
|
||||
this.digestInto(out);
|
||||
return out;
|
||||
}
|
||||
_cloneInto(to) {
|
||||
// Create new instance without calling constructor since key already in state and we don't know it.
|
||||
to || (to = Object.create(Object.getPrototypeOf(this), {}));
|
||||
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
||||
to = to;
|
||||
to.finished = finished;
|
||||
to.destroyed = destroyed;
|
||||
to.blockLen = blockLen;
|
||||
to.outputLen = outputLen;
|
||||
to.oHash = oHash._cloneInto(to.oHash);
|
||||
to.iHash = iHash._cloneInto(to.iHash);
|
||||
return to;
|
||||
}
|
||||
clone() {
|
||||
return this._cloneInto();
|
||||
}
|
||||
destroy() {
|
||||
this.destroyed = true;
|
||||
this.oHash.destroy();
|
||||
this.iHash.destroy();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* HMAC: RFC2104 message authentication code.
|
||||
* @param hash - function that would be used e.g. sha256
|
||||
* @param key - message key
|
||||
* @param message - message data
|
||||
* @example
|
||||
* import { hmac } from '@noble/hashes/hmac';
|
||||
* import { sha256 } from '@noble/hashes/sha2';
|
||||
* const mac1 = hmac(sha256, 'key', 'message');
|
||||
*/
|
||||
export const hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
|
||||
hmac.create = (hash, key) => new HMAC(hash, key);
|
||||
//# sourceMappingURL=hmac.js.map
|
||||
@@ -0,0 +1,7 @@
|
||||
import type { FlatConfig } from '@typescript-eslint/utils/ts-eslint';
|
||||
export default _default;
|
||||
/**
|
||||
* A version of `strict` that only contains type-checked rules and disables of any corresponding core ESLint rules.
|
||||
* @see {@link https://typescript-eslint.io/users/configs#strict-type-checked-only}
|
||||
*/
|
||||
declare function _default(plugin: FlatConfig.Plugin, parser: FlatConfig.Parser): FlatConfig.ConfigArray;
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "../../cjs/_ts_param.cjs",
|
||||
"module": "../../esm/_ts_param.js"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Generated by LiveScript 1.6.0
|
||||
(function(){
|
||||
var parseString, cast, parseType, VERSION, parsedTypeParse, parse;
|
||||
parseString = require('./parse-string');
|
||||
cast = require('./cast');
|
||||
parseType = require('type-check').parseType;
|
||||
VERSION = '0.4.1';
|
||||
parsedTypeParse = function(parsedType, string, options){
|
||||
options == null && (options = {});
|
||||
options.explicit == null && (options.explicit = false);
|
||||
options.customTypes == null && (options.customTypes = {});
|
||||
return cast(parseString(parsedType, string, options), parsedType, options);
|
||||
};
|
||||
parse = function(type, string, options){
|
||||
return parsedTypeParse(parseType(type), string, options);
|
||||
};
|
||||
module.exports = {
|
||||
VERSION: VERSION,
|
||||
parse: parse,
|
||||
parsedTypeParse: parsedTypeParse
|
||||
};
|
||||
}).call(this);
|
||||
@@ -0,0 +1,222 @@
|
||||
import _typeof from "./typeof.js";
|
||||
import checkInRHS from "./checkInRHS.js";
|
||||
import setFunctionName from "./setFunctionName.js";
|
||||
import toPropertyKey from "./toPropertyKey.js";
|
||||
function applyDecs2301Factory() {
|
||||
function createAddInitializerMethod(e, t) {
|
||||
return function (r) {
|
||||
!function (e) {
|
||||
if (e.v) throw Error("attempted to call addInitializer after decoration was finished");
|
||||
}(t), assertCallable(r, "An initializer"), e.push(r);
|
||||
};
|
||||
}
|
||||
function assertInstanceIfPrivate(e, t) {
|
||||
if (!e(t)) throw new TypeError("Attempted to access private element on non-instance");
|
||||
}
|
||||
function memberDec(e, t, r, n, a, i, s, o, c) {
|
||||
var u;
|
||||
switch (a) {
|
||||
case 1:
|
||||
u = "accessor";
|
||||
break;
|
||||
case 2:
|
||||
u = "method";
|
||||
break;
|
||||
case 3:
|
||||
u = "getter";
|
||||
break;
|
||||
case 4:
|
||||
u = "setter";
|
||||
break;
|
||||
default:
|
||||
u = "field";
|
||||
}
|
||||
var l,
|
||||
f,
|
||||
p = {
|
||||
kind: u,
|
||||
name: s ? "#" + t : toPropertyKey(t),
|
||||
"static": i,
|
||||
"private": s
|
||||
},
|
||||
d = {
|
||||
v: !1
|
||||
};
|
||||
if (0 !== a && (p.addInitializer = createAddInitializerMethod(n, d)), s || 0 !== a && 2 !== a) {
|
||||
if (2 === a) l = function l(e) {
|
||||
return assertInstanceIfPrivate(c, e), r.value;
|
||||
};else {
|
||||
var h = 0 === a || 1 === a;
|
||||
(h || 3 === a) && (l = s ? function (e) {
|
||||
return assertInstanceIfPrivate(c, e), r.get.call(e);
|
||||
} : function (e) {
|
||||
return r.get.call(e);
|
||||
}), (h || 4 === a) && (f = s ? function (e, t) {
|
||||
assertInstanceIfPrivate(c, e), r.set.call(e, t);
|
||||
} : function (e, t) {
|
||||
r.set.call(e, t);
|
||||
});
|
||||
}
|
||||
} else l = function l(e) {
|
||||
return e[t];
|
||||
}, 0 === a && (f = function f(e, r) {
|
||||
e[t] = r;
|
||||
});
|
||||
var v = s ? c.bind() : function (e) {
|
||||
return t in e;
|
||||
};
|
||||
p.access = l && f ? {
|
||||
get: l,
|
||||
set: f,
|
||||
has: v
|
||||
} : l ? {
|
||||
get: l,
|
||||
has: v
|
||||
} : {
|
||||
set: f,
|
||||
has: v
|
||||
};
|
||||
try {
|
||||
return e(o, p);
|
||||
} finally {
|
||||
d.v = !0;
|
||||
}
|
||||
}
|
||||
function assertCallable(e, t) {
|
||||
if ("function" != typeof e) throw new TypeError(t + " must be a function");
|
||||
}
|
||||
function assertValidReturnValue(e, t) {
|
||||
var r = _typeof(t);
|
||||
if (1 === e) {
|
||||
if ("object" !== r || null === t) throw new TypeError("accessor decorators must return an object with get, set, or init properties or void 0");
|
||||
void 0 !== t.get && assertCallable(t.get, "accessor.get"), void 0 !== t.set && assertCallable(t.set, "accessor.set"), void 0 !== t.init && assertCallable(t.init, "accessor.init");
|
||||
} else if ("function" !== r) throw new TypeError((0 === e ? "field" : 10 === e ? "class" : "method") + " decorators must return a function or void 0");
|
||||
}
|
||||
function curryThis2(e) {
|
||||
return function (t) {
|
||||
e(this, t);
|
||||
};
|
||||
}
|
||||
function applyMemberDec(e, t, r, n, a, i, s, o, c) {
|
||||
var u,
|
||||
l,
|
||||
f,
|
||||
p,
|
||||
d,
|
||||
h,
|
||||
v,
|
||||
y,
|
||||
g = r[0];
|
||||
if (s ? (0 === a || 1 === a ? (u = {
|
||||
get: (d = r[3], function () {
|
||||
return d(this);
|
||||
}),
|
||||
set: curryThis2(r[4])
|
||||
}, f = "get") : 3 === a ? (u = {
|
||||
get: r[3]
|
||||
}, f = "get") : 4 === a ? (u = {
|
||||
set: r[3]
|
||||
}, f = "set") : u = {
|
||||
value: r[3]
|
||||
}, 0 !== a && (1 === a && setFunctionName(u.set, "#" + n, "set"), setFunctionName(u[f || "value"], "#" + n, f))) : 0 !== a && (u = Object.getOwnPropertyDescriptor(t, n)), 1 === a ? p = {
|
||||
get: u.get,
|
||||
set: u.set
|
||||
} : 2 === a ? p = u.value : 3 === a ? p = u.get : 4 === a && (p = u.set), "function" == typeof g) void 0 !== (h = memberDec(g, n, u, o, a, i, s, p, c)) && (assertValidReturnValue(a, h), 0 === a ? l = h : 1 === a ? (l = h.init, v = h.get || p.get, y = h.set || p.set, p = {
|
||||
get: v,
|
||||
set: y
|
||||
}) : p = h);else for (var m = g.length - 1; m >= 0; m--) {
|
||||
var b;
|
||||
void 0 !== (h = memberDec(g[m], n, u, o, a, i, s, p, c)) && (assertValidReturnValue(a, h), 0 === a ? b = h : 1 === a ? (b = h.init, v = h.get || p.get, y = h.set || p.set, p = {
|
||||
get: v,
|
||||
set: y
|
||||
}) : p = h, void 0 !== b && (void 0 === l ? l = b : "function" == typeof l ? l = [l, b] : l.push(b)));
|
||||
}
|
||||
if (0 === a || 1 === a) {
|
||||
if (void 0 === l) l = function l(e, t) {
|
||||
return t;
|
||||
};else if ("function" != typeof l) {
|
||||
var I = l;
|
||||
l = function l(e, t) {
|
||||
for (var r = t, n = 0; n < I.length; n++) r = I[n].call(e, r);
|
||||
return r;
|
||||
};
|
||||
} else {
|
||||
var w = l;
|
||||
l = function l(e, t) {
|
||||
return w.call(e, t);
|
||||
};
|
||||
}
|
||||
e.push(l);
|
||||
}
|
||||
0 !== a && (1 === a ? (u.get = p.get, u.set = p.set) : 2 === a ? u.value = p : 3 === a ? u.get = p : 4 === a && (u.set = p), s ? 1 === a ? (e.push(function (e, t) {
|
||||
return p.get.call(e, t);
|
||||
}), e.push(function (e, t) {
|
||||
return p.set.call(e, t);
|
||||
})) : 2 === a ? e.push(p) : e.push(function (e, t) {
|
||||
return p.call(e, t);
|
||||
}) : Object.defineProperty(t, n, u));
|
||||
}
|
||||
function applyMemberDecs(e, t, r) {
|
||||
for (var n, a, i, s = [], o = new Map(), c = new Map(), u = 0; u < t.length; u++) {
|
||||
var l = t[u];
|
||||
if (Array.isArray(l)) {
|
||||
var f,
|
||||
p,
|
||||
d = l[1],
|
||||
h = l[2],
|
||||
v = l.length > 3,
|
||||
y = d >= 5,
|
||||
g = r;
|
||||
if (y ? (f = e, 0 != (d -= 5) && (p = a = a || []), v && !i && (i = function i(t) {
|
||||
return checkInRHS(t) === e;
|
||||
}), g = i) : (f = e.prototype, 0 !== d && (p = n = n || [])), 0 !== d && !v) {
|
||||
var m = y ? c : o,
|
||||
b = m.get(h) || 0;
|
||||
if (!0 === b || 3 === b && 4 !== d || 4 === b && 3 !== d) throw Error("Attempted to decorate a public method/accessor that has the same name as a previously decorated public method/accessor. This is not currently supported by the decorators plugin. Property name was: " + h);
|
||||
!b && d > 2 ? m.set(h, d) : m.set(h, !0);
|
||||
}
|
||||
applyMemberDec(s, f, l, h, d, y, v, p, g);
|
||||
}
|
||||
}
|
||||
return pushInitializers(s, n), pushInitializers(s, a), s;
|
||||
}
|
||||
function pushInitializers(e, t) {
|
||||
t && e.push(function (e) {
|
||||
for (var r = 0; r < t.length; r++) t[r].call(e);
|
||||
return e;
|
||||
});
|
||||
}
|
||||
return function (e, t, r, n) {
|
||||
return {
|
||||
e: applyMemberDecs(e, t, n),
|
||||
get c() {
|
||||
return function (e, t) {
|
||||
if (t.length > 0) {
|
||||
for (var r = [], n = e, a = e.name, i = t.length - 1; i >= 0; i--) {
|
||||
var s = {
|
||||
v: !1
|
||||
};
|
||||
try {
|
||||
var o = t[i](n, {
|
||||
kind: "class",
|
||||
name: a,
|
||||
addInitializer: createAddInitializerMethod(r, s)
|
||||
});
|
||||
} finally {
|
||||
s.v = !0;
|
||||
}
|
||||
void 0 !== o && (assertValidReturnValue(10, o), n = o);
|
||||
}
|
||||
return [n, function () {
|
||||
for (var e = 0; e < r.length; e++) r[e].call(n);
|
||||
}];
|
||||
}
|
||||
}(e, r);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
function applyDecs2301(e, t, r, n) {
|
||||
return (applyDecs2301 = applyDecs2301Factory())(e, t, r, n);
|
||||
}
|
||||
export { applyDecs2301 as default };
|
||||
@@ -0,0 +1,16 @@
|
||||
'use strict'
|
||||
|
||||
const { join } = require('path')
|
||||
const ThreadStream = require('..')
|
||||
|
||||
const stream = new ThreadStream({
|
||||
filename: join(__dirname, 'to-file.js'),
|
||||
workerData: { dest: process.argv[2] },
|
||||
sync: true
|
||||
})
|
||||
|
||||
stream.write('hello')
|
||||
stream.write(' ')
|
||||
stream.write('world\n')
|
||||
stream.flushSync()
|
||||
stream.unref()
|
||||
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "@vitest/pretty-format",
|
||||
"type": "module",
|
||||
"version": "4.1.10",
|
||||
"description": "Fork of pretty-format with support for ESM",
|
||||
"license": "MIT",
|
||||
"funding": "https://opencollective.com/vitest",
|
||||
"homepage": "https://github.com/vitest-dev/vitest/tree/main/packages/pretty-format",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/vitest-dev/vitest.git",
|
||||
"directory": "packages/pretty-format"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/vitest-dev/vitest/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"vitest",
|
||||
"test",
|
||||
"pretty",
|
||||
"pretty-format"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./*": "./*"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"*.d.ts",
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-is": "^19.2.0",
|
||||
"react-is": "^19.2.4",
|
||||
"react-is-18": "npm:react-is@18.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "premove dist && rollup -c",
|
||||
"dev": "rollup -c --watch"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
import type { JSDOM } from 'jsdom'
|
||||
|
||||
declare global {
|
||||
const jsdom: JSDOM
|
||||
}
|
||||
export {}
|
||||
@@ -0,0 +1,595 @@
|
||||
/**
|
||||
* @author Toru Nagashima <https://github.com/mysticatea>
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
CALL,
|
||||
CONSTRUCT,
|
||||
ReferenceTracker,
|
||||
getStaticValue,
|
||||
getStringIfConstant,
|
||||
} = require("@eslint-community/eslint-utils");
|
||||
const { RegExpParser, visitRegExpAST } = require("@eslint-community/regexpp");
|
||||
const {
|
||||
isCombiningCharacter,
|
||||
isEmojiModifier,
|
||||
isRegionalIndicatorSymbol,
|
||||
isSurrogatePair,
|
||||
} = require("./utils/unicode");
|
||||
const astUtils = require("./utils/ast-utils.js");
|
||||
const { isValidWithUnicodeFlag } = require("./utils/regular-expressions");
|
||||
const {
|
||||
parseStringLiteral,
|
||||
parseTemplateToken,
|
||||
} = require("./utils/char-source");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @typedef {import('@eslint-community/regexpp').AST.Character} Character
|
||||
* @typedef {import('@eslint-community/regexpp').AST.CharacterClassElement} CharacterClassElement
|
||||
*/
|
||||
|
||||
/**
|
||||
* Iterate character sequences of a given nodes.
|
||||
*
|
||||
* CharacterClassRange syntax can steal a part of character sequence,
|
||||
* so this function reverts CharacterClassRange syntax and restore the sequence.
|
||||
* @param {CharacterClassElement[]} nodes The node list to iterate character sequences.
|
||||
* @returns {IterableIterator<Character[]>} The list of character sequences.
|
||||
*/
|
||||
function* iterateCharacterSequence(nodes) {
|
||||
/** @type {Character[]} */
|
||||
let seq = [];
|
||||
|
||||
for (const node of nodes) {
|
||||
switch (node.type) {
|
||||
case "Character":
|
||||
seq.push(node);
|
||||
break;
|
||||
|
||||
case "CharacterClassRange":
|
||||
seq.push(node.min);
|
||||
yield seq;
|
||||
seq = [node.max];
|
||||
break;
|
||||
|
||||
case "CharacterSet":
|
||||
case "CharacterClass": // [[]] nesting character class
|
||||
case "ClassStringDisjunction": // \q{...}
|
||||
case "ExpressionCharacterClass": // [A--B]
|
||||
if (seq.length > 0) {
|
||||
yield seq;
|
||||
seq = [];
|
||||
}
|
||||
break;
|
||||
|
||||
// no default
|
||||
}
|
||||
}
|
||||
|
||||
if (seq.length > 0) {
|
||||
yield seq;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given character node is a Unicode code point escape or not.
|
||||
* @param {Character} char the character node to check.
|
||||
* @returns {boolean} `true` if the character node is a Unicode code point escape.
|
||||
*/
|
||||
function isUnicodeCodePointEscape(char) {
|
||||
return /^\\u\{[\da-f]+\}$/iu.test(char.raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* Each function returns matched characters if it detects that kind of problem.
|
||||
* @type {Record<string, (chars: Character[]) => IterableIterator<Character[]>>}
|
||||
*/
|
||||
const findCharacterSequences = {
|
||||
*surrogatePairWithoutUFlag(chars) {
|
||||
for (const [index, char] of chars.entries()) {
|
||||
const previous = chars[index - 1];
|
||||
|
||||
if (
|
||||
previous &&
|
||||
char &&
|
||||
isSurrogatePair(previous.value, char.value) &&
|
||||
!isUnicodeCodePointEscape(previous) &&
|
||||
!isUnicodeCodePointEscape(char)
|
||||
) {
|
||||
yield [previous, char];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
*surrogatePair(chars) {
|
||||
for (const [index, char] of chars.entries()) {
|
||||
const previous = chars[index - 1];
|
||||
|
||||
if (
|
||||
previous &&
|
||||
char &&
|
||||
isSurrogatePair(previous.value, char.value) &&
|
||||
(isUnicodeCodePointEscape(previous) ||
|
||||
isUnicodeCodePointEscape(char))
|
||||
) {
|
||||
yield [previous, char];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
*combiningClass(chars, unfilteredChars) {
|
||||
/*
|
||||
* When `allowEscape` is `true`, a combined character should only be allowed if the combining mark appears as an escape sequence.
|
||||
* This means that the base character should be considered even if it's escaped.
|
||||
*/
|
||||
for (const [index, char] of chars.entries()) {
|
||||
const previous = unfilteredChars[index - 1];
|
||||
|
||||
if (
|
||||
previous &&
|
||||
char &&
|
||||
isCombiningCharacter(char.value) &&
|
||||
!isCombiningCharacter(previous.value)
|
||||
) {
|
||||
yield [previous, char];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
*emojiModifier(chars) {
|
||||
for (const [index, char] of chars.entries()) {
|
||||
const previous = chars[index - 1];
|
||||
|
||||
if (
|
||||
previous &&
|
||||
char &&
|
||||
isEmojiModifier(char.value) &&
|
||||
!isEmojiModifier(previous.value)
|
||||
) {
|
||||
yield [previous, char];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
*regionalIndicatorSymbol(chars) {
|
||||
for (const [index, char] of chars.entries()) {
|
||||
const previous = chars[index - 1];
|
||||
|
||||
if (
|
||||
previous &&
|
||||
char &&
|
||||
isRegionalIndicatorSymbol(char.value) &&
|
||||
isRegionalIndicatorSymbol(previous.value)
|
||||
) {
|
||||
yield [previous, char];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
*zwj(chars) {
|
||||
let sequence = null;
|
||||
|
||||
for (const [index, char] of chars.entries()) {
|
||||
const previous = chars[index - 1];
|
||||
const next = chars[index + 1];
|
||||
|
||||
if (
|
||||
previous &&
|
||||
char &&
|
||||
next &&
|
||||
char.value === 0x200d &&
|
||||
previous.value !== 0x200d &&
|
||||
next.value !== 0x200d
|
||||
) {
|
||||
if (sequence) {
|
||||
if (sequence.at(-1) === previous) {
|
||||
sequence.push(char, next); // append to the sequence
|
||||
} else {
|
||||
yield sequence;
|
||||
sequence = chars.slice(index - 1, index + 2);
|
||||
}
|
||||
} else {
|
||||
sequence = chars.slice(index - 1, index + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sequence) {
|
||||
yield sequence;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const kinds = Object.keys(findCharacterSequences);
|
||||
|
||||
/**
|
||||
* Gets the value of the given node if it's a static value other than a regular expression object,
|
||||
* or the node's `regex` property.
|
||||
* The purpose of this method is to provide a replacement for `getStaticValue` in environments where certain regular expressions cannot be evaluated.
|
||||
* A known example is Node.js 18 which does not support the `v` flag.
|
||||
* Calling `getStaticValue` on a regular expression node with the `v` flag on Node.js 18 always returns `null`.
|
||||
* A limitation of this method is that it can only detect a regular expression if the specified node is itself a regular expression literal node.
|
||||
* @param {ASTNode | undefined} node The node to be inspected.
|
||||
* @param {Scope} initialScope Scope to start finding variables. This function tries to resolve identifier references which are in the given scope.
|
||||
* @returns {{ value: any } | { regex: { pattern: string, flags: string } } | null} The static value of the node, or `null`.
|
||||
*/
|
||||
function getStaticValueOrRegex(node, initialScope) {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
if (node.type === "Literal" && node.regex) {
|
||||
return { regex: node.regex };
|
||||
}
|
||||
|
||||
const staticValue = getStaticValue(node, initialScope);
|
||||
|
||||
if (staticValue?.value instanceof RegExp) {
|
||||
return null;
|
||||
}
|
||||
return staticValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a specified regexpp character is represented as an acceptable escape sequence.
|
||||
* This function requires the source text of the character to be known.
|
||||
* @param {Character} char Character to check.
|
||||
* @param {string} charSource Source text of the character to check.
|
||||
* @returns {boolean} Whether the specified regexpp character is represented as an acceptable escape sequence.
|
||||
*/
|
||||
function checkForAcceptableEscape(char, charSource) {
|
||||
if (!charSource.startsWith("\\")) {
|
||||
return false;
|
||||
}
|
||||
const match = /(?<=^\\+).$/su.exec(charSource);
|
||||
|
||||
return match?.[0] !== String.fromCodePoint(char.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a specified regexpp character is represented as an acceptable escape sequence.
|
||||
* This function works with characters that are produced by a string or template literal.
|
||||
* It requires the source text and the CodeUnit list of the literal to be known.
|
||||
* @param {Character} char Character to check.
|
||||
* @param {string} nodeSource Source text of the string or template literal that produces the character.
|
||||
* @param {CodeUnit[]} codeUnits List of CodeUnit objects of the literal that produces the character.
|
||||
* @returns {boolean} Whether the specified regexpp character is represented as an acceptable escape sequence.
|
||||
*/
|
||||
function checkForAcceptableEscapeInString(char, nodeSource, codeUnits) {
|
||||
const firstIndex = char.start;
|
||||
const lastIndex = char.end - 1;
|
||||
const start = codeUnits[firstIndex].start;
|
||||
const end = codeUnits[lastIndex].end;
|
||||
const charSource = nodeSource.slice(start, end);
|
||||
|
||||
return checkForAcceptableEscape(char, charSource);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
type: "problem",
|
||||
|
||||
defaultOptions: [
|
||||
{
|
||||
allowEscape: false,
|
||||
},
|
||||
],
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Disallow characters which are made with multiple code points in character class syntax",
|
||||
recommended: true,
|
||||
url: "https://eslint.org/docs/latest/rules/no-misleading-character-class",
|
||||
},
|
||||
|
||||
hasSuggestions: true,
|
||||
|
||||
schema: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
allowEscape: {
|
||||
type: "boolean",
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
|
||||
messages: {
|
||||
surrogatePairWithoutUFlag:
|
||||
"Unexpected surrogate pair in character class. Use 'u' flag.",
|
||||
surrogatePair: "Unexpected surrogate pair in character class.",
|
||||
combiningClass: "Unexpected combined character in character class.",
|
||||
emojiModifier: "Unexpected modified Emoji in character class.",
|
||||
regionalIndicatorSymbol:
|
||||
"Unexpected national flag in character class.",
|
||||
zwj: "Unexpected joined character sequence in character class.",
|
||||
suggestUnicodeFlag: "Add unicode 'u' flag to regex.",
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
const [{ allowEscape }] = context.options;
|
||||
const sourceCode = context.sourceCode;
|
||||
const parser = new RegExpParser();
|
||||
const checkedPatternNodes = new Set();
|
||||
|
||||
/**
|
||||
* Verify a given regular expression.
|
||||
* @param {Node} node The node to report.
|
||||
* @param {string} pattern The regular expression pattern to verify.
|
||||
* @param {string} flags The flags of the regular expression.
|
||||
* @param {Function} unicodeFixer Fixer for missing "u" flag.
|
||||
* @returns {void}
|
||||
*/
|
||||
function verify(node, pattern, flags, unicodeFixer) {
|
||||
let patternNode;
|
||||
|
||||
try {
|
||||
patternNode = parser.parsePattern(pattern, 0, pattern.length, {
|
||||
unicode: flags.includes("u"),
|
||||
unicodeSets: flags.includes("v"),
|
||||
});
|
||||
} catch {
|
||||
// Ignore regular expressions with syntax errors
|
||||
return;
|
||||
}
|
||||
|
||||
let codeUnits = null;
|
||||
|
||||
/**
|
||||
* Checks whether a specified regexpp character is represented as an acceptable escape sequence.
|
||||
* For the purposes of this rule, an escape sequence is considered acceptable if it consists of one or more backslashes followed by the character being escaped.
|
||||
* @param {Character} char Character to check.
|
||||
* @returns {boolean} Whether the specified regexpp character is represented as an acceptable escape sequence.
|
||||
*/
|
||||
function isAcceptableEscapeSequence(char) {
|
||||
if (node.type === "Literal" && node.regex) {
|
||||
return checkForAcceptableEscape(char, char.raw);
|
||||
}
|
||||
if (node.type === "Literal" && typeof node.value === "string") {
|
||||
const nodeSource = node.raw;
|
||||
|
||||
codeUnits ??= parseStringLiteral(nodeSource);
|
||||
|
||||
return checkForAcceptableEscapeInString(
|
||||
char,
|
||||
nodeSource,
|
||||
codeUnits,
|
||||
);
|
||||
}
|
||||
if (astUtils.isStaticTemplateLiteral(node)) {
|
||||
const nodeSource = sourceCode.getText(node);
|
||||
|
||||
codeUnits ??= parseTemplateToken(nodeSource);
|
||||
|
||||
return checkForAcceptableEscapeInString(
|
||||
char,
|
||||
nodeSource,
|
||||
codeUnits,
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const foundKindMatches = new Map();
|
||||
|
||||
visitRegExpAST(patternNode, {
|
||||
onCharacterClassEnter(ccNode) {
|
||||
for (const unfilteredChars of iterateCharacterSequence(
|
||||
ccNode.elements,
|
||||
)) {
|
||||
let chars;
|
||||
|
||||
if (allowEscape) {
|
||||
// Replace escape sequences with null to avoid having them flagged.
|
||||
chars = unfilteredChars.map(char =>
|
||||
isAcceptableEscapeSequence(char) ? null : char,
|
||||
);
|
||||
} else {
|
||||
chars = unfilteredChars;
|
||||
}
|
||||
for (const kind of kinds) {
|
||||
const matches = findCharacterSequences[kind](
|
||||
chars,
|
||||
unfilteredChars,
|
||||
);
|
||||
|
||||
if (foundKindMatches.has(kind)) {
|
||||
foundKindMatches.get(kind).push(...matches);
|
||||
} else {
|
||||
foundKindMatches.set(kind, [...matches]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Finds the report loc(s) for a range of matches.
|
||||
* Only literals and expression-less templates generate granular errors.
|
||||
* @param {Character[][]} matches Lists of individual characters being reported on.
|
||||
* @returns {Location[]} locs for context.report.
|
||||
* @see https://github.com/eslint/eslint/pull/17515
|
||||
*/
|
||||
function getNodeReportLocations(matches) {
|
||||
if (
|
||||
!astUtils.isStaticTemplateLiteral(node) &&
|
||||
node.type !== "Literal"
|
||||
) {
|
||||
return matches.length ? [node.loc] : [];
|
||||
}
|
||||
return matches.map(chars => {
|
||||
const firstIndex = chars[0].start;
|
||||
const lastIndex = chars.at(-1).end - 1;
|
||||
let start;
|
||||
let end;
|
||||
|
||||
if (node.type === "TemplateLiteral") {
|
||||
const source = sourceCode.getText(node);
|
||||
const offset = node.range[0];
|
||||
|
||||
codeUnits ??= parseTemplateToken(source);
|
||||
start = offset + codeUnits[firstIndex].start;
|
||||
end = offset + codeUnits[lastIndex].end;
|
||||
} else if (typeof node.value === "string") {
|
||||
// String Literal
|
||||
const source = node.raw;
|
||||
const offset = node.range[0];
|
||||
|
||||
codeUnits ??= parseStringLiteral(source);
|
||||
start = offset + codeUnits[firstIndex].start;
|
||||
end = offset + codeUnits[lastIndex].end;
|
||||
} else {
|
||||
// RegExp Literal
|
||||
const offset = node.range[0] + 1; // Add 1 to skip the leading slash.
|
||||
|
||||
start = offset + firstIndex;
|
||||
end = offset + lastIndex + 1;
|
||||
}
|
||||
|
||||
return {
|
||||
start: sourceCode.getLocFromIndex(start),
|
||||
end: sourceCode.getLocFromIndex(end),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
for (const [kind, matches] of foundKindMatches) {
|
||||
let suggest;
|
||||
|
||||
if (kind === "surrogatePairWithoutUFlag") {
|
||||
suggest = [
|
||||
{
|
||||
messageId: "suggestUnicodeFlag",
|
||||
fix: unicodeFixer,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const locs = getNodeReportLocations(matches);
|
||||
|
||||
for (const loc of locs) {
|
||||
context.report({
|
||||
node,
|
||||
loc,
|
||||
messageId: kind,
|
||||
suggest,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
"Literal[regex]"(node) {
|
||||
if (checkedPatternNodes.has(node)) {
|
||||
return;
|
||||
}
|
||||
verify(node, node.regex.pattern, node.regex.flags, fixer => {
|
||||
if (
|
||||
!isValidWithUnicodeFlag(
|
||||
context.languageOptions.ecmaVersion,
|
||||
node.regex.pattern,
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fixer.insertTextAfter(node, "u");
|
||||
});
|
||||
},
|
||||
Program(node) {
|
||||
const scope = sourceCode.getScope(node);
|
||||
const tracker = new ReferenceTracker(scope);
|
||||
|
||||
/*
|
||||
* Iterate calls of RegExp.
|
||||
* E.g., `new RegExp()`, `RegExp()`, `new window.RegExp()`,
|
||||
* `const {RegExp: a} = window; new a()`, etc...
|
||||
*/
|
||||
for (const { node: refNode } of tracker.iterateGlobalReferences(
|
||||
{
|
||||
RegExp: { [CALL]: true, [CONSTRUCT]: true },
|
||||
},
|
||||
)) {
|
||||
let pattern, flags;
|
||||
const [patternNode, flagsNode] = refNode.arguments;
|
||||
const evaluatedPattern = getStaticValueOrRegex(
|
||||
patternNode,
|
||||
scope,
|
||||
);
|
||||
|
||||
if (!evaluatedPattern) {
|
||||
continue;
|
||||
}
|
||||
if (flagsNode) {
|
||||
if (evaluatedPattern.regex) {
|
||||
pattern = evaluatedPattern.regex.pattern;
|
||||
checkedPatternNodes.add(patternNode);
|
||||
} else {
|
||||
pattern = String(evaluatedPattern.value);
|
||||
}
|
||||
flags = getStringIfConstant(flagsNode, scope);
|
||||
} else {
|
||||
if (evaluatedPattern.regex) {
|
||||
continue;
|
||||
}
|
||||
pattern = String(evaluatedPattern.value);
|
||||
flags = "";
|
||||
}
|
||||
|
||||
if (typeof flags === "string") {
|
||||
verify(patternNode, pattern, flags, fixer => {
|
||||
if (
|
||||
!isValidWithUnicodeFlag(
|
||||
context.languageOptions.ecmaVersion,
|
||||
pattern,
|
||||
)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (refNode.arguments.length === 1) {
|
||||
const penultimateToken =
|
||||
sourceCode.getLastToken(refNode, {
|
||||
skip: 1,
|
||||
}); // skip closing parenthesis
|
||||
|
||||
return fixer.insertTextAfter(
|
||||
penultimateToken,
|
||||
astUtils.isCommaToken(penultimateToken)
|
||||
? ' "u",'
|
||||
: ', "u"',
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
(flagsNode.type === "Literal" &&
|
||||
typeof flagsNode.value === "string") ||
|
||||
flagsNode.type === "TemplateLiteral"
|
||||
) {
|
||||
const range = [
|
||||
flagsNode.range[0],
|
||||
flagsNode.range[1] - 1,
|
||||
];
|
||||
|
||||
return fixer.insertTextAfterRange(range, "u");
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,255 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const utils_1 = require("@typescript-eslint/utils");
|
||||
const ignore_1 = __importDefault(require("ignore"));
|
||||
const util_1 = require("../util");
|
||||
const getESLintCoreRule_1 = require("../util/getESLintCoreRule");
|
||||
const baseRule = (0, getESLintCoreRule_1.getESLintCoreRule)('no-restricted-imports');
|
||||
// In some versions of eslint, the base rule has a completely incompatible schema
|
||||
// This helper function is to safely try to get parts of the schema. If it's not
|
||||
// possible, we'll fallback to less strict checks.
|
||||
const tryAccess = (getter, fallback) => {
|
||||
try {
|
||||
return getter();
|
||||
}
|
||||
catch {
|
||||
return fallback;
|
||||
}
|
||||
};
|
||||
const baseSchema = baseRule.meta.schema;
|
||||
const allowTypeImportsOptionSchema = {
|
||||
allowTypeImports: {
|
||||
type: 'boolean',
|
||||
description: 'Whether to allow type-only imports for a path.',
|
||||
},
|
||||
};
|
||||
const arrayOfStringsOrObjects = {
|
||||
type: 'array',
|
||||
items: {
|
||||
anyOf: [
|
||||
{ type: 'string' },
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
...tryAccess(() => baseSchema.anyOf[1].items[0].properties.paths.items.anyOf[1]
|
||||
.properties, undefined),
|
||||
...allowTypeImportsOptionSchema,
|
||||
},
|
||||
required: tryAccess(() => baseSchema.anyOf[1].items[0].properties.paths.items.anyOf[1]
|
||||
.required, undefined),
|
||||
},
|
||||
],
|
||||
},
|
||||
uniqueItems: true,
|
||||
};
|
||||
const arrayOfStringsOrObjectPatterns = {
|
||||
anyOf: [
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
uniqueItems: true,
|
||||
},
|
||||
{
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
...tryAccess(() => baseSchema.anyOf[1].items[0].properties.patterns.anyOf[1].items
|
||||
.properties, undefined),
|
||||
...allowTypeImportsOptionSchema,
|
||||
},
|
||||
required: tryAccess(() => baseSchema.anyOf[1].items[0].properties.patterns.anyOf[1].items
|
||||
.required, []),
|
||||
},
|
||||
uniqueItems: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
const schema = {
|
||||
anyOf: [
|
||||
arrayOfStringsOrObjects,
|
||||
{
|
||||
type: 'array',
|
||||
additionalItems: false,
|
||||
items: [
|
||||
{
|
||||
type: 'object',
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
paths: arrayOfStringsOrObjects,
|
||||
patterns: arrayOfStringsOrObjectPatterns,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
function isObjectOfPaths(obj) {
|
||||
return !!obj && Object.hasOwn(obj, 'paths');
|
||||
}
|
||||
function isObjectOfPatterns(obj) {
|
||||
return !!obj && Object.hasOwn(obj, 'patterns');
|
||||
}
|
||||
function isOptionsArrayOfStringOrObject(options) {
|
||||
if (isObjectOfPaths(options[0])) {
|
||||
return false;
|
||||
}
|
||||
if (isObjectOfPatterns(options[0])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function getRestrictedPaths(options) {
|
||||
if (isOptionsArrayOfStringOrObject(options)) {
|
||||
return options;
|
||||
}
|
||||
if (isObjectOfPaths(options[0])) {
|
||||
return options[0].paths;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
function getRestrictedPatterns(options) {
|
||||
if (isObjectOfPatterns(options[0])) {
|
||||
return options[0].patterns;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
function shouldCreateRule(baseRules, options) {
|
||||
if (Object.keys(baseRules).length === 0 || options.length === 0) {
|
||||
return false;
|
||||
}
|
||||
if (!isOptionsArrayOfStringOrObject(options)) {
|
||||
return !!(options[0].paths?.length || options[0].patterns?.length);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
exports.default = (0, util_1.createRule)({
|
||||
name: 'no-restricted-imports',
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
// defaultOptions, -- base rule does not use defaultOptions
|
||||
deprecated: {
|
||||
deprecatedSince: '8.64.0',
|
||||
replacedBy: [
|
||||
{
|
||||
rule: {
|
||||
name: 'no-restricted-imports',
|
||||
url: 'https://eslint.org/docs/latest/rules/no-restricted-imports',
|
||||
},
|
||||
},
|
||||
],
|
||||
url: 'https://github.com/typescript-eslint/typescript-eslint/pull/12527',
|
||||
},
|
||||
docs: {
|
||||
description: 'Disallow specified modules when loaded by `import`',
|
||||
extendsBaseRule: true,
|
||||
},
|
||||
fixable: baseRule.meta.fixable,
|
||||
messages: baseRule.meta.messages,
|
||||
schema,
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
const rules = baseRule.create(context);
|
||||
const { options } = context;
|
||||
if (!shouldCreateRule(rules, options)) {
|
||||
return {};
|
||||
}
|
||||
const restrictedPaths = getRestrictedPaths(options);
|
||||
const allowedTypeImportPathNameSet = new Set();
|
||||
for (const restrictedPath of restrictedPaths) {
|
||||
if (typeof restrictedPath === 'object' &&
|
||||
restrictedPath.allowTypeImports) {
|
||||
allowedTypeImportPathNameSet.add(restrictedPath.name);
|
||||
}
|
||||
}
|
||||
function isAllowedTypeImportPath(importSource) {
|
||||
return allowedTypeImportPathNameSet.has(importSource);
|
||||
}
|
||||
const restrictedPatterns = getRestrictedPatterns(options);
|
||||
const allowedImportTypeMatchers = [];
|
||||
const allowedImportTypeRegexMatchers = [];
|
||||
for (const restrictedPattern of restrictedPatterns) {
|
||||
if (typeof restrictedPattern === 'object' &&
|
||||
restrictedPattern.allowTypeImports) {
|
||||
// Following how ignore is configured in the base rule
|
||||
if (restrictedPattern.group) {
|
||||
allowedImportTypeMatchers.push((0, ignore_1.default)({
|
||||
allowRelativePaths: true,
|
||||
ignoreCase: !restrictedPattern.caseSensitive,
|
||||
}).add(restrictedPattern.group));
|
||||
}
|
||||
if (restrictedPattern.regex) {
|
||||
allowedImportTypeRegexMatchers.push(new RegExp(restrictedPattern.regex, restrictedPattern.caseSensitive ? 'u' : 'iu'));
|
||||
}
|
||||
}
|
||||
}
|
||||
function isAllowedTypeImportPattern(importSource) {
|
||||
return (
|
||||
// As long as there's one matching pattern that allows type import
|
||||
allowedImportTypeMatchers.some(matcher => matcher.ignores(importSource)) ||
|
||||
allowedImportTypeRegexMatchers.some(regex => regex.test(importSource)));
|
||||
}
|
||||
function checkImportNode(node) {
|
||||
if (node.importKind === 'type' ||
|
||||
(node.specifiers.length > 0 &&
|
||||
node.specifiers.every(specifier => specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
|
||||
specifier.importKind === 'type'))) {
|
||||
const importSource = node.source.value.trim();
|
||||
if (!isAllowedTypeImportPath(importSource) &&
|
||||
!isAllowedTypeImportPattern(importSource)) {
|
||||
return rules.ImportDeclaration(node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return rules.ImportDeclaration(node);
|
||||
}
|
||||
}
|
||||
return {
|
||||
ExportAllDeclaration: rules.ExportAllDeclaration,
|
||||
'ExportNamedDeclaration[source]'(node) {
|
||||
if (node.exportKind === 'type' ||
|
||||
(node.specifiers.length > 0 &&
|
||||
node.specifiers.every(specifier => specifier.exportKind === 'type'))) {
|
||||
const importSource = node.source.value.trim();
|
||||
if (!isAllowedTypeImportPath(importSource) &&
|
||||
!isAllowedTypeImportPattern(importSource)) {
|
||||
return rules.ExportNamedDeclaration(node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return rules.ExportNamedDeclaration(node);
|
||||
}
|
||||
},
|
||||
ImportDeclaration: checkImportNode,
|
||||
TSImportEqualsDeclaration(node) {
|
||||
if (node.moduleReference.type === utils_1.AST_NODE_TYPES.TSExternalModuleReference) {
|
||||
const synthesizedImport = {
|
||||
...node,
|
||||
type: utils_1.AST_NODE_TYPES.ImportDeclaration,
|
||||
assertions: [],
|
||||
attributes: [],
|
||||
source: node.moduleReference.expression,
|
||||
specifiers: [
|
||||
{
|
||||
...node.id,
|
||||
type: utils_1.AST_NODE_TYPES.ImportDefaultSpecifier,
|
||||
local: node.id,
|
||||
// @ts-expect-error -- parent types are incompatible but it's fine for the purposes of this extension
|
||||
parent: node.id.parent,
|
||||
},
|
||||
],
|
||||
};
|
||||
return checkImportNode(synthesizedImport);
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
function _usingCtx() {
|
||||
var r = "function" == typeof SuppressedError ? SuppressedError : function (r, e) {
|
||||
var n = Error();
|
||||
return n.name = "SuppressedError", n.error = r, n.suppressed = e, n;
|
||||
},
|
||||
e = {},
|
||||
n = [];
|
||||
function using(r, e) {
|
||||
if (null != e) {
|
||||
if (Object(e) !== e) throw new TypeError("using declarations can only be used with objects, functions, null, or undefined.");
|
||||
if (r) var o = e[Symbol.asyncDispose || Symbol["for"]("Symbol.asyncDispose")];
|
||||
if (void 0 === o && (o = e[Symbol.dispose || Symbol["for"]("Symbol.dispose")], r)) var t = o;
|
||||
if ("function" != typeof o) throw new TypeError("Object is not disposable.");
|
||||
t && (o = function o() {
|
||||
try {
|
||||
t.call(e);
|
||||
} catch (r) {
|
||||
return Promise.reject(r);
|
||||
}
|
||||
}), n.push({
|
||||
v: e,
|
||||
d: o,
|
||||
a: r
|
||||
});
|
||||
} else r && n.push({
|
||||
d: e,
|
||||
a: r
|
||||
});
|
||||
return e;
|
||||
}
|
||||
return {
|
||||
e: e,
|
||||
u: using.bind(null, !1),
|
||||
a: using.bind(null, !0),
|
||||
d: function d() {
|
||||
var o,
|
||||
t = this.e,
|
||||
s = 0;
|
||||
function next() {
|
||||
for (; o = n.pop();) try {
|
||||
if (!o.a && 1 === s) return s = 0, n.push(o), Promise.resolve().then(next);
|
||||
if (o.d) {
|
||||
var r = o.d.call(o.v);
|
||||
if (o.a) return s |= 2, Promise.resolve(r).then(next, err);
|
||||
} else s |= 1;
|
||||
} catch (r) {
|
||||
return err(r);
|
||||
}
|
||||
if (1 === s) return t !== e ? Promise.reject(t) : Promise.resolve();
|
||||
if (t !== e) throw t;
|
||||
}
|
||||
function err(n) {
|
||||
return t = t !== e ? new r(n, t) : n, next();
|
||||
}
|
||||
return next();
|
||||
}
|
||||
};
|
||||
}
|
||||
export { _usingCtx as default };
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @preserve
|
||||
* JS Implementation of incremental MurmurHash3 (r150) (as of May 10, 2013)
|
||||
*
|
||||
* @author <a href="mailto:jensyt@gmail.com">Jens Taylor</a>
|
||||
* @see http://github.com/homebrewing/brauhaus-diff
|
||||
* @author <a href="mailto:gary.court@gmail.com">Gary Court</a>
|
||||
* @see http://github.com/garycourt/murmurhash-js
|
||||
* @author <a href="mailto:aappleby@gmail.com">Austin Appleby</a>
|
||||
* @see http://sites.google.com/site/murmurhash/
|
||||
*/
|
||||
!function(){function t(h,r){var s=this instanceof t?this:e;return s.reset(r),"string"==typeof h&&h.length>0&&s.hash(h),s!==this?s:void 0}var e;t.prototype.hash=function(t){var e,h,r,s,i;switch(i=t.length,this.len+=i,h=this.k1,r=0,this.rem){case 0:h^=i>r?65535&t.charCodeAt(r++):0;case 1:h^=i>r?(65535&t.charCodeAt(r++))<<8:0;case 2:h^=i>r?(65535&t.charCodeAt(r++))<<16:0;case 3:h^=i>r?(255&t.charCodeAt(r))<<24:0,h^=i>r?(65280&t.charCodeAt(r++))>>8:0}if(this.rem=3&i+this.rem,i-=this.rem,i>0){for(e=this.h1;;){if(h=4294967295&11601*h+3432906752*(65535&h),h=h<<15|h>>>17,h=4294967295&13715*h+461832192*(65535&h),e^=h,e=e<<13|e>>>19,e=4294967295&5*e+3864292196,r>=i)break;h=65535&t.charCodeAt(r++)^(65535&t.charCodeAt(r++))<<8^(65535&t.charCodeAt(r++))<<16,s=t.charCodeAt(r++),h^=(255&s)<<24^(65280&s)>>8}switch(h=0,this.rem){case 3:h^=(65535&t.charCodeAt(r+2))<<16;case 2:h^=(65535&t.charCodeAt(r+1))<<8;case 1:h^=65535&t.charCodeAt(r)}this.h1=e}return this.k1=h,this},t.prototype.result=function(){var t,e;return t=this.k1,e=this.h1,t>0&&(t=4294967295&11601*t+3432906752*(65535&t),t=t<<15|t>>>17,t=4294967295&13715*t+461832192*(65535&t),e^=t),e^=this.len,e^=e>>>16,e=4294967295&51819*e+2246770688*(65535&e),e^=e>>>13,e=4294967295&44597*e+3266445312*(65535&e),e^=e>>>16,e>>>0},t.prototype.reset=function(t){return this.h1="number"==typeof t?t:0,this.rem=this.k1=this.len=0,this},e=new t,"undefined"!=typeof module?module.exports=t:this.MurmurHash3=t}();
|
||||
@@ -0,0 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
const pathKey = (options = {}) => {
|
||||
const environment = options.env || process.env;
|
||||
const platform = options.platform || process.platform;
|
||||
|
||||
if (platform !== 'win32') {
|
||||
return 'PATH';
|
||||
}
|
||||
|
||||
return Object.keys(environment).reverse().find(key => key.toUpperCase() === 'PATH') || 'Path';
|
||||
};
|
||||
|
||||
module.exports = pathKey;
|
||||
// TODO: Remove this for the next major release
|
||||
module.exports.default = pathKey;
|
||||
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @fileoverview A rule to disallow or enforce spaces inside of single line blocks.
|
||||
* @author Toru Nagashima
|
||||
* @deprecated in ESLint v8.53.0
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const util = require("./utils/ast-utils");
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Rule Definition
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** @type {import('../types').Rule.RuleModule} */
|
||||
module.exports = {
|
||||
meta: {
|
||||
deprecated: {
|
||||
message: "Formatting rules are being moved out of ESLint core.",
|
||||
url: "https://eslint.org/blog/2023/10/deprecating-formatting-rules/",
|
||||
deprecatedSince: "8.53.0",
|
||||
availableUntil: "11.0.0",
|
||||
replacedBy: [
|
||||
{
|
||||
message:
|
||||
"ESLint Stylistic now maintains deprecated stylistic core rules.",
|
||||
url: "https://eslint.style/guide/migration",
|
||||
plugin: {
|
||||
name: "@stylistic/eslint-plugin",
|
||||
url: "https://eslint.style",
|
||||
},
|
||||
rule: {
|
||||
name: "block-spacing",
|
||||
url: "https://eslint.style/rules/block-spacing",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
type: "layout",
|
||||
|
||||
docs: {
|
||||
description:
|
||||
"Disallow or enforce spaces inside of blocks after opening block and before closing block",
|
||||
recommended: false,
|
||||
url: "https://eslint.org/docs/latest/rules/block-spacing",
|
||||
},
|
||||
|
||||
fixable: "whitespace",
|
||||
|
||||
schema: [{ enum: ["always", "never"] }],
|
||||
|
||||
messages: {
|
||||
missing: "Requires a space {{location}} '{{token}}'.",
|
||||
extra: "Unexpected space(s) {{location}} '{{token}}'.",
|
||||
},
|
||||
},
|
||||
|
||||
create(context) {
|
||||
const always = context.options[0] !== "never",
|
||||
messageId = always ? "missing" : "extra",
|
||||
sourceCode = context.sourceCode;
|
||||
|
||||
/**
|
||||
* Gets the open brace token from a given node.
|
||||
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to get.
|
||||
* @returns {Token} The token of the open brace.
|
||||
*/
|
||||
function getOpenBrace(node) {
|
||||
if (node.type === "SwitchStatement") {
|
||||
if (node.cases.length > 0) {
|
||||
return sourceCode.getTokenBefore(node.cases[0]);
|
||||
}
|
||||
return sourceCode.getLastToken(node, 1);
|
||||
}
|
||||
|
||||
if (node.type === "StaticBlock") {
|
||||
return sourceCode.getFirstToken(node, { skip: 1 }); // skip the `static` token
|
||||
}
|
||||
|
||||
// "BlockStatement"
|
||||
return sourceCode.getFirstToken(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not:
|
||||
* - given tokens are on same line.
|
||||
* - there is/isn't a space between given tokens.
|
||||
* @param {Token} left A token to check.
|
||||
* @param {Token} right The token which is next to `left`.
|
||||
* @returns {boolean}
|
||||
* When the option is `"always"`, `true` if there are one or more spaces between given tokens.
|
||||
* When the option is `"never"`, `true` if there are not any spaces between given tokens.
|
||||
* If given tokens are not on same line, it's always `true`.
|
||||
*/
|
||||
function isValid(left, right) {
|
||||
return (
|
||||
!util.isTokenOnSameLine(left, right) ||
|
||||
sourceCode.isSpaceBetween(left, right) === always
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks and reports invalid spacing style inside braces.
|
||||
* @param {ASTNode} node A BlockStatement/StaticBlock/SwitchStatement node to check.
|
||||
* @returns {void}
|
||||
*/
|
||||
function checkSpacingInsideBraces(node) {
|
||||
// Gets braces and the first/last token of content.
|
||||
const openBrace = getOpenBrace(node);
|
||||
const closeBrace = sourceCode.getLastToken(node);
|
||||
const firstToken = sourceCode.getTokenAfter(openBrace, {
|
||||
includeComments: true,
|
||||
});
|
||||
const lastToken = sourceCode.getTokenBefore(closeBrace, {
|
||||
includeComments: true,
|
||||
});
|
||||
|
||||
// Skip if the node is invalid or empty.
|
||||
if (
|
||||
openBrace.type !== "Punctuator" ||
|
||||
openBrace.value !== "{" ||
|
||||
closeBrace.type !== "Punctuator" ||
|
||||
closeBrace.value !== "}" ||
|
||||
firstToken === closeBrace
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip line comments for option never
|
||||
if (!always && firstToken.type === "Line") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check.
|
||||
if (!isValid(openBrace, firstToken)) {
|
||||
let loc = openBrace.loc;
|
||||
|
||||
if (messageId === "extra") {
|
||||
loc = {
|
||||
start: openBrace.loc.end,
|
||||
end: firstToken.loc.start,
|
||||
};
|
||||
}
|
||||
|
||||
context.report({
|
||||
node,
|
||||
loc,
|
||||
messageId,
|
||||
data: {
|
||||
location: "after",
|
||||
token: openBrace.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
if (always) {
|
||||
return fixer.insertTextBefore(firstToken, " ");
|
||||
}
|
||||
|
||||
return fixer.removeRange([
|
||||
openBrace.range[1],
|
||||
firstToken.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
if (!isValid(lastToken, closeBrace)) {
|
||||
let loc = closeBrace.loc;
|
||||
|
||||
if (messageId === "extra") {
|
||||
loc = {
|
||||
start: lastToken.loc.end,
|
||||
end: closeBrace.loc.start,
|
||||
};
|
||||
}
|
||||
context.report({
|
||||
node,
|
||||
loc,
|
||||
messageId,
|
||||
data: {
|
||||
location: "before",
|
||||
token: closeBrace.value,
|
||||
},
|
||||
fix(fixer) {
|
||||
if (always) {
|
||||
return fixer.insertTextAfter(lastToken, " ");
|
||||
}
|
||||
|
||||
return fixer.removeRange([
|
||||
lastToken.range[1],
|
||||
closeBrace.range[0],
|
||||
]);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
BlockStatement: checkSpacingInsideBraces,
|
||||
StaticBlock: checkSpacingInsideBraces,
|
||||
SwitchStatement: checkSpacingInsideBraces,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
Copyright 2013 Thorsten Lorenz.
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Deprecated module: moved from curves/abstract/utils.js to curves/utils.js
|
||||
* @module
|
||||
*/
|
||||
import * as u from "../utils.js";
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const abytes = u.abytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const anumber = u.anumber;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const bytesToHex = u.bytesToHex;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const bytesToUtf8 = u.bytesToUtf8;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const concatBytes = u.concatBytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const hexToBytes = u.hexToBytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const isBytes = u.isBytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const randomBytes = u.randomBytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const utf8ToBytes = u.utf8ToBytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const abool = u.abool;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const numberToHexUnpadded = u.numberToHexUnpadded;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const hexToNumber = u.hexToNumber;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const bytesToNumberBE = u.bytesToNumberBE;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const bytesToNumberLE = u.bytesToNumberLE;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const numberToBytesBE = u.numberToBytesBE;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const numberToBytesLE = u.numberToBytesLE;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const numberToVarBytesBE = u.numberToVarBytesBE;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const ensureBytes = u.ensureBytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const equalBytes = u.equalBytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const copyBytes = u.copyBytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const asciiToBytes = u.asciiToBytes;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const inRange = u.inRange;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const aInRange = u.aInRange;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const bitLen = u.bitLen;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const bitGet = u.bitGet;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const bitSet = u.bitSet;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const bitMask = u.bitMask;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const createHmacDrbg = u.createHmacDrbg;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const notImplemented = u.notImplemented;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const memoized = u.memoized;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const validateObject = u.validateObject;
|
||||
/** @deprecated moved to `@noble/curves/utils.js` */
|
||||
export const isHash = u.isHash;
|
||||
//# sourceMappingURL=utils.js.map
|
||||
Reference in New Issue
Block a user