WIP: bootstrap and partial real Solana watcher implementation

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

View File

@@ -0,0 +1,177 @@
/**
* @fileoverview Rule to flag use constant conditions
* @author Christian Schulz <http://rndm.de>
*/
"use strict";
const { isConstant } = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
defaultOptions: [{ checkLoops: "allExceptWhileTrue" }],
docs: {
description: "Disallow constant expressions in conditions",
recommended: true,
url: "https://eslint.org/docs/latest/rules/no-constant-condition",
},
schema: [
{
type: "object",
properties: {
checkLoops: {
enum: [
"all",
"allExceptWhileTrue",
"none",
true,
false,
],
},
},
additionalProperties: false,
},
],
messages: {
unexpected: "Unexpected constant condition.",
},
},
create(context) {
const loopSetStack = [];
const sourceCode = context.sourceCode;
let [{ checkLoops }] = context.options;
if (checkLoops === true) {
checkLoops = "all";
} else if (checkLoops === false) {
checkLoops = "none";
}
let loopsInCurrentScope = new Set();
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
/**
* Tracks when the given node contains a constant condition.
* @param {ASTNode} node The AST node to check.
* @returns {void}
* @private
*/
function trackConstantConditionLoop(node) {
if (
node.test &&
isConstant(sourceCode.getScope(node), node.test, true)
) {
loopsInCurrentScope.add(node);
}
}
/**
* Reports when the set contains the given constant condition node
* @param {ASTNode} node The AST node to check.
* @returns {void}
* @private
*/
function checkConstantConditionLoopInSet(node) {
if (loopsInCurrentScope.has(node)) {
loopsInCurrentScope.delete(node);
context.report({ node: node.test, messageId: "unexpected" });
}
}
/**
* Reports when the given node contains a constant condition.
* @param {ASTNode} node The AST node to check.
* @returns {void}
* @private
*/
function reportIfConstant(node) {
if (
node.test &&
isConstant(sourceCode.getScope(node), node.test, true)
) {
context.report({ node: node.test, messageId: "unexpected" });
}
}
/**
* Stores current set of constant loops in loopSetStack temporarily
* and uses a new set to track constant loops
* @returns {void}
* @private
*/
function enterFunction() {
loopSetStack.push(loopsInCurrentScope);
loopsInCurrentScope = new Set();
}
/**
* Reports when the set still contains stored constant conditions
* @returns {void}
* @private
*/
function exitFunction() {
loopsInCurrentScope = loopSetStack.pop();
}
/**
* Checks node when checkLoops option is enabled
* @param {ASTNode} node The AST node to check.
* @returns {void}
* @private
*/
function checkLoop(node) {
if (checkLoops === "all" || checkLoops === "allExceptWhileTrue") {
trackConstantConditionLoop(node);
}
}
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
return {
ConditionalExpression: reportIfConstant,
IfStatement: reportIfConstant,
WhileStatement(node) {
if (
node.test.type === "Literal" &&
node.test.value === true &&
checkLoops === "allExceptWhileTrue"
) {
return;
}
checkLoop(node);
},
"WhileStatement:exit": checkConstantConditionLoopInSet,
DoWhileStatement: checkLoop,
"DoWhileStatement:exit": checkConstantConditionLoopInSet,
ForStatement: checkLoop,
"ForStatement > .test": node => checkLoop(node.parent),
"ForStatement:exit": checkConstantConditionLoopInSet,
FunctionDeclaration: enterFunction,
"FunctionDeclaration:exit": exitFunction,
FunctionExpression: enterFunction,
"FunctionExpression:exit": exitFunction,
YieldExpression: () => loopsInCurrentScope.clear(),
};
},
};

View File

@@ -0,0 +1,13 @@
function _class_apply_descriptor_set(receiver, descriptor, value) {
if (descriptor.set) descriptor.set.call(receiver, value);
else {
if (!descriptor.writable) {
// This should only throw in strict mode, but class bodies are
// always strict and private fields can only be used inside
// class bodies.
throw new TypeError("attempted to set read only private field");
}
descriptor.value = value;
}
}
export { _class_apply_descriptor_set as _ };

View File

@@ -0,0 +1,380 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearWatchCaches = clearWatchCaches;
exports.getWatchProgramsForProjects = getWatchProgramsForProjects;
const debug_1 = __importDefault(require("debug"));
const node_fs_1 = __importDefault(require("node:fs"));
const ts = __importStar(require("typescript"));
const source_files_1 = require("../source-files");
const shared_1 = require("./shared");
const log = (0, debug_1.default)('typescript-eslint:typescript-estree:create-program:getWatchProgramsForProjects');
/**
* Maps tsconfig paths to their corresponding file contents and resulting watches
*/
const knownWatchProgramMap = new Map();
/**
* Maps file/folder paths to their set of corresponding watch callbacks
* There may be more than one per file/folder if a file/folder is shared between projects
*/
const fileWatchCallbackTrackingMap = new Map();
const folderWatchCallbackTrackingMap = new Map();
/**
* Stores the list of known files for each program
*/
const programFileListCache = new Map();
/**
* Caches the last modified time of the tsconfig files
*/
const tsconfigLastModifiedTimestampCache = new Map();
const parsedFilesSeenHash = new Map();
/**
* Clear all of the parser caches.
* This should only be used in testing to ensure the parser is clean between tests.
*/
function clearWatchCaches() {
knownWatchProgramMap.clear();
fileWatchCallbackTrackingMap.clear();
folderWatchCallbackTrackingMap.clear();
parsedFilesSeenHash.clear();
programFileListCache.clear();
tsconfigLastModifiedTimestampCache.clear();
}
function saveWatchCallback(trackingMap) {
return (fileName, callback) => {
const normalizedFileName = (0, shared_1.getCanonicalFileName)(fileName);
const watchers = (() => {
let watchers = trackingMap.get(normalizedFileName);
if (!watchers) {
watchers = new Set();
trackingMap.set(normalizedFileName, watchers);
}
return watchers;
})();
watchers.add(callback);
return {
close: () => {
watchers.delete(callback);
},
};
};
}
/**
* Holds information about the file currently being linted
*/
const currentLintOperationState = {
code: '',
filePath: '',
};
/**
* Appropriately report issues found when reading a config file
* @param diagnostic The diagnostic raised when creating a program
*/
function diagnosticReporter(diagnostic) {
throw new Error(ts.flattenDiagnosticMessageText(diagnostic.messageText, ts.sys.newLine));
}
function updateCachedFileList(tsconfigPath, program) {
const fileList = new Set(program.getRootFileNames().map(f => (0, shared_1.getCanonicalFileName)(f)));
programFileListCache.set(tsconfigPath, fileList);
return fileList;
}
/**
* Calculate project environments using options provided by consumer and paths from config
* @param parseSettings Internal settings for parsing the file
* @returns The programs corresponding to the supplied tsconfig paths
*/
function getWatchProgramsForProjects(parseSettings) {
const filePath = (0, shared_1.getCanonicalFileName)(parseSettings.filePath);
const results = [];
// preserve reference to code and file being linted
currentLintOperationState.code = parseSettings.code;
currentLintOperationState.filePath = filePath;
// Update file version if necessary
const fileWatchCallbacks = fileWatchCallbackTrackingMap.get(filePath);
const codeHash = (0, shared_1.createHash)((0, source_files_1.getCodeText)(parseSettings.code));
if (parsedFilesSeenHash.get(filePath) !== codeHash &&
fileWatchCallbacks &&
fileWatchCallbacks.size > 0) {
fileWatchCallbacks.forEach(cb => cb(filePath, ts.FileWatcherEventKind.Changed));
}
const currentProjectsFromSettings = new Map(parseSettings.projects);
/*
* before we go into the process of attempting to find and update every program
* see if we know of a program that contains this file
*/
for (const [tsconfigPath, existingWatch] of knownWatchProgramMap.entries()) {
if (!currentProjectsFromSettings.has(tsconfigPath)) {
// the current parser run doesn't specify this tsconfig in parserOptions.project
// so we don't want to consider it for caching purposes.
//
// if we did consider it we might return a program for a project
// that wasn't specified in the current parser run (which is obv bad!).
continue;
}
let fileList = programFileListCache.get(tsconfigPath);
let updatedProgram = null;
if (!fileList) {
updatedProgram = existingWatch.getProgram().getProgram();
fileList = updateCachedFileList(tsconfigPath, updatedProgram);
}
if (fileList.has(filePath)) {
log('Found existing program for file. %s', filePath);
updatedProgram ??= existingWatch.getProgram().getProgram();
// sets parent pointers in source files
updatedProgram.getTypeChecker();
return [updatedProgram];
}
}
log('File did not belong to any existing programs, moving to create/update. %s', filePath);
/*
* We don't know of a program that contains the file, this means that either:
* - the required program hasn't been created yet, or
* - the file is new/renamed, and the program hasn't been updated.
*/
for (const tsconfigPath of parseSettings.projects) {
const existingWatch = knownWatchProgramMap.get(tsconfigPath[0]);
if (existingWatch) {
const updatedProgram = maybeInvalidateProgram(existingWatch, filePath, tsconfigPath[0]);
if (!updatedProgram) {
continue;
}
// sets parent pointers in source files
updatedProgram.getTypeChecker();
// cache and check the file list
const fileList = updateCachedFileList(tsconfigPath[0], updatedProgram);
if (fileList.has(filePath)) {
log('Found updated program for file. %s', filePath);
// we can return early because we know this program contains the file
return [updatedProgram];
}
results.push(updatedProgram);
continue;
}
const programWatch = createWatchProgram(tsconfigPath[1], parseSettings);
knownWatchProgramMap.set(tsconfigPath[0], programWatch);
const program = programWatch.getProgram().getProgram();
// sets parent pointers in source files
program.getTypeChecker();
// cache and check the file list
const fileList = updateCachedFileList(tsconfigPath[0], program);
if (fileList.has(filePath)) {
log('Found program for file. %s', filePath);
// we can return early because we know this program contains the file
return [program];
}
results.push(program);
}
return results;
}
function createWatchProgram(tsconfigPath, parseSettings) {
log('Creating watch program for %s.', tsconfigPath);
// create compiler host
const watchCompilerHost = ts.createWatchCompilerHost(tsconfigPath, (0, shared_1.createDefaultCompilerOptionsFromExtra)(parseSettings), ts.sys, ts.createAbstractBuilder, diagnosticReporter,
// TODO: file issue on TypeScript to suggest making optional?
// eslint-disable-next-line @typescript-eslint/no-empty-function
/*reportWatchStatus*/ () => { });
watchCompilerHost.jsDocParsingMode = parseSettings.jsDocParsingMode;
// ensure readFile reads the code being linted instead of the copy on disk
const oldReadFile = watchCompilerHost.readFile;
watchCompilerHost.readFile = (filePathIn, encoding) => {
const filePath = (0, shared_1.getCanonicalFileName)(filePathIn);
const fileContent = filePath === currentLintOperationState.filePath
? (0, source_files_1.getCodeText)(currentLintOperationState.code)
: oldReadFile(filePath, encoding);
if (fileContent != null) {
parsedFilesSeenHash.set(filePath, (0, shared_1.createHash)(fileContent));
}
return fileContent;
};
// ensure process reports error on failure instead of exiting process immediately
watchCompilerHost.onUnRecoverableConfigFileDiagnostic = diagnosticReporter;
// ensure process doesn't emit programs
watchCompilerHost.afterProgramCreate = (program) => {
// report error if there are any errors in the config file
const configFileDiagnostics = program
.getConfigFileParsingDiagnostics()
.filter(diag => diag.category === ts.DiagnosticCategory.Error && diag.code !== 18003);
if (configFileDiagnostics.length > 0) {
diagnosticReporter(configFileDiagnostics[0]);
}
};
/*
* From the CLI, the file watchers won't matter, as the files will be parsed once and then forgotten.
* When running from an IDE, these watchers will let us tell typescript about changes.
*
* ESLint IDE plugins will send us unfinished file content as the user types (before it's saved to disk).
* We use the file watchers to tell typescript about this latest file content.
*
* When files are created (or renamed), we won't know about them because we have no filesystem watchers attached.
* We use the folder watchers to tell typescript it needs to go and find new files in the project folders.
*/
watchCompilerHost.watchFile = saveWatchCallback(fileWatchCallbackTrackingMap);
watchCompilerHost.watchDirectory = saveWatchCallback(folderWatchCallbackTrackingMap);
// allow files with custom extensions to be included in program (uses internal ts api)
const oldOnDirectoryStructureHostCreate = watchCompilerHost.onCachedDirectoryStructureHostCreate;
watchCompilerHost.onCachedDirectoryStructureHostCreate = (host) => {
const oldReadDirectory = host.readDirectory;
host.readDirectory = (path, extensions, exclude, include, depth) => oldReadDirectory(path, !extensions
? undefined
: [...extensions, ...parseSettings.extraFileExtensions], exclude, include, depth);
oldOnDirectoryStructureHostCreate(host);
};
// This works only on 3.9
watchCompilerHost.extraFileExtensions = parseSettings.extraFileExtensions.map(extension => ({
extension,
isMixedContent: true,
scriptKind: ts.ScriptKind.Deferred,
}));
watchCompilerHost.trace = log;
// Since we don't want to asynchronously update program we want to disable timeout methods
// So any changes in the program will be delayed and updated when getProgram is called on watch
watchCompilerHost.setTimeout = undefined;
watchCompilerHost.clearTimeout = undefined;
return ts.createWatchProgram(watchCompilerHost);
}
function hasTSConfigChanged(tsconfigPath) {
const stat = node_fs_1.default.statSync(tsconfigPath);
const lastModifiedAt = stat.mtimeMs;
const cachedLastModifiedAt = tsconfigLastModifiedTimestampCache.get(tsconfigPath);
tsconfigLastModifiedTimestampCache.set(tsconfigPath, lastModifiedAt);
if (cachedLastModifiedAt == null) {
return false;
}
return Math.abs(cachedLastModifiedAt - lastModifiedAt) > Number.EPSILON;
}
function maybeInvalidateProgram(existingWatch, filePath, tsconfigPath) {
/*
* By calling watchProgram.getProgram(), it will trigger a resync of the program based on
* whatever new file content we've given it from our input.
*/
let updatedProgram = existingWatch.getProgram().getProgram();
// In case this change causes problems in larger real world codebases
// Provide an escape hatch so people don't _have_ to revert to an older version
if (process.env.TSESTREE_NO_INVALIDATION === 'true') {
return updatedProgram;
}
if (hasTSConfigChanged(tsconfigPath)) {
/*
* If the stat of the tsconfig has changed, that could mean the include/exclude/files lists has changed
* We need to make sure typescript knows this so it can update appropriately
*/
log('tsconfig has changed - triggering program update. %s', tsconfigPath);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
fileWatchCallbackTrackingMap
.get(tsconfigPath)
.forEach(cb => cb(tsconfigPath, ts.FileWatcherEventKind.Changed));
// tsconfig change means that the file list more than likely changed, so clear the cache
programFileListCache.delete(tsconfigPath);
}
let sourceFile = updatedProgram.getSourceFile(filePath);
if (sourceFile) {
return updatedProgram;
}
/*
* Missing source file means our program's folder structure might be out of date.
* So we need to tell typescript it needs to update the correct folder.
*/
log('File was not found in program - triggering folder update. %s', filePath);
// Find the correct directory callback by climbing the folder tree
const currentDir = (0, shared_1.canonicalDirname)(filePath);
let current = null;
let next = currentDir;
let hasCallback = false;
while (current !== next) {
current = next;
const folderWatchCallbacks = folderWatchCallbackTrackingMap.get(current);
if (folderWatchCallbacks) {
for (const cb of folderWatchCallbacks) {
if (currentDir !== current) {
cb(currentDir, ts.FileWatcherEventKind.Changed);
}
cb(current, ts.FileWatcherEventKind.Changed);
}
hasCallback = true;
}
next = (0, shared_1.canonicalDirname)(current);
}
if (!hasCallback) {
/*
* No callback means the paths don't matchup - so no point returning any program
* this will signal to the caller to skip this program
*/
log('No callback found for file, not part of this program. %s', filePath);
return null;
}
// directory update means that the file list more than likely changed, so clear the cache
programFileListCache.delete(tsconfigPath);
// force the immediate resync
updatedProgram = existingWatch.getProgram().getProgram();
sourceFile = updatedProgram.getSourceFile(filePath);
if (sourceFile) {
return updatedProgram;
}
/*
* At this point we're in one of two states:
* - The file isn't supposed to be in this program due to exclusions
* - The file is new, and was renamed from an old, included filename
*
* For the latter case, we need to tell typescript that the old filename is now deleted
*/
log('File was still not found in program after directory update - checking file deletions. %s', filePath);
const rootFilenames = updatedProgram.getRootFileNames();
// use find because we only need to "delete" one file to cause typescript to do a full resync
const deletedFile = rootFilenames.find(file => !node_fs_1.default.existsSync(file));
if (!deletedFile) {
// There are no deleted files, so it must be the former case of the file not belonging to this program
return null;
}
const fileWatchCallbacks = fileWatchCallbackTrackingMap.get((0, shared_1.getCanonicalFileName)(deletedFile));
if (!fileWatchCallbacks) {
// shouldn't happen, but just in case
log('Could not find watch callbacks for root file. %s', deletedFile);
return updatedProgram;
}
log('Marking file as deleted. %s', deletedFile);
fileWatchCallbacks.forEach(cb => cb(deletedFile, ts.FileWatcherEventKind.Deleted));
// deleted files means that the file list _has_ changed, so clear the cache
programFileListCache.delete(tsconfigPath);
updatedProgram = existingWatch.getProgram().getProgram();
sourceFile = updatedProgram.getSourceFile(filePath);
if (sourceFile) {
return updatedProgram;
}
log('File was still not found in program after deletion check, assuming it is not part of this program. %s', filePath);
return null;
}

View File

@@ -0,0 +1,30 @@
"use strict";
// THIS CODE WAS AUTOMATICALLY GENERATED
// DO NOT EDIT THIS CODE BY HAND
// RUN THE FOLLOWING COMMAND FROM THE WORKSPACE ROOT TO REGENERATE:
// npx nx generate-lib repo
Object.defineProperty(exports, "__esModule", { value: true });
exports.es2020 = void 0;
const es2019_1 = require("./es2019");
const es2020_bigint_1 = require("./es2020.bigint");
const es2020_date_1 = require("./es2020.date");
const es2020_intl_1 = require("./es2020.intl");
const es2020_number_1 = require("./es2020.number");
const es2020_promise_1 = require("./es2020.promise");
const es2020_sharedmemory_1 = require("./es2020.sharedmemory");
const es2020_string_1 = require("./es2020.string");
const es2020_symbol_wellknown_1 = require("./es2020.symbol.wellknown");
exports.es2020 = {
libs: [
es2019_1.es2019,
es2020_bigint_1.es2020_bigint,
es2020_date_1.es2020_date,
es2020_number_1.es2020_number,
es2020_promise_1.es2020_promise,
es2020_sharedmemory_1.es2020_sharedmemory,
es2020_string_1.es2020_string,
es2020_symbol_wellknown_1.es2020_symbol_wellknown,
es2020_intl_1.es2020_intl,
],
variables: [],
};

View File

@@ -0,0 +1,214 @@
import * as util from "../core/util.js";
const error = () => {
// Hebrew labels + grammatical gender
const TypeNames = {
string: { label: "מחרוזת", gender: "f" },
number: { label: "מספר", gender: "m" },
boolean: { label: "ערך בוליאני", gender: "m" },
bigint: { label: "BigInt", gender: "m" },
date: { label: "תאריך", gender: "m" },
array: { label: "מערך", gender: "m" },
object: { label: "אובייקט", gender: "m" },
null: { label: "ערך ריק (null)", gender: "m" },
undefined: { label: "ערך לא מוגדר (undefined)", gender: "m" },
symbol: { label: "סימבול (Symbol)", gender: "m" },
function: { label: "פונקציה", gender: "f" },
map: { label: "מפה (Map)", gender: "f" },
set: { label: "קבוצה (Set)", gender: "f" },
file: { label: "קובץ", gender: "m" },
promise: { label: "Promise", gender: "m" },
NaN: { label: "NaN", gender: "m" },
unknown: { label: "ערך לא ידוע", gender: "m" },
value: { label: "ערך", gender: "m" },
};
// Sizing units for size-related messages + localized origin labels
const Sizable = {
string: { unit: "תווים", shortLabel: "קצר", longLabel: "ארוך" },
file: { unit: "בייטים", shortLabel: "קטן", longLabel: "גדול" },
array: { unit: "פריטים", shortLabel: "קטן", longLabel: "גדול" },
set: { unit: "פריטים", shortLabel: "קטן", longLabel: "גדול" },
number: { unit: "", shortLabel: "קטן", longLabel: "גדול" }, // no unit
};
// Helpers — labels, articles, and verbs
const typeEntry = (t) => (t ? TypeNames[t] : undefined);
const typeLabel = (t) => {
const e = typeEntry(t);
if (e)
return e.label;
// fallback: show raw string if unknown
return t ?? TypeNames.unknown.label;
};
const withDefinite = (t) => `ה${typeLabel(t)}`;
const verbFor = (t) => {
const e = typeEntry(t);
const gender = e?.gender ?? "m";
return gender === "f" ? "צריכה להיות" : "צריך להיות";
};
const getSizing = (origin) => {
if (!origin)
return null;
return Sizable[origin] ?? null;
};
const FormatDictionary = {
regex: { label: "קלט", gender: "m" },
email: { label: "כתובת אימייל", gender: "f" },
url: { label: "כתובת רשת", gender: "f" },
emoji: { label: "אימוג'י", gender: "m" },
uuid: { label: "UUID", gender: "m" },
nanoid: { label: "nanoid", gender: "m" },
guid: { label: "GUID", gender: "m" },
cuid: { label: "cuid", gender: "m" },
cuid2: { label: "cuid2", gender: "m" },
ulid: { label: "ULID", gender: "m" },
xid: { label: "XID", gender: "m" },
ksuid: { label: "KSUID", gender: "m" },
datetime: { label: "תאריך וזמן ISO", gender: "m" },
date: { label: "תאריך ISO", gender: "m" },
time: { label: "זמן ISO", gender: "m" },
duration: { label: "משך זמן ISO", gender: "m" },
ipv4: { label: "כתובת IPv4", gender: "f" },
ipv6: { label: "כתובת IPv6", gender: "f" },
cidrv4: { label: "טווח IPv4", gender: "m" },
cidrv6: { label: "טווח IPv6", gender: "m" },
base64: { label: "מחרוזת בבסיס 64", gender: "f" },
base64url: { label: "מחרוזת בבסיס 64 לכתובות רשת", gender: "f" },
json_string: { label: "מחרוזת JSON", gender: "f" },
e164: { label: "מספר E.164", gender: "m" },
jwt: { label: "JWT", gender: "m" },
ends_with: { label: "קלט", gender: "m" },
includes: { label: "קלט", gender: "m" },
lowercase: { label: "קלט", gender: "m" },
starts_with: { label: "קלט", gender: "m" },
uppercase: { label: "קלט", gender: "m" },
};
const TypeDictionary = {
nan: "NaN",
};
return (issue) => {
switch (issue.code) {
case "invalid_type": {
// Expected type: show without definite article for clearer Hebrew
const expectedKey = issue.expected;
const expected = TypeDictionary[expectedKey ?? ""] ?? typeLabel(expectedKey);
// Received: show localized label if known, otherwise constructor/raw
const receivedType = util.parsedType(issue.input);
const received = TypeDictionary[receivedType] ?? TypeNames[receivedType]?.label ?? receivedType;
if (/^[A-Z]/.test(issue.expected)) {
return `קלט לא תקין: צריך להיות instanceof ${issue.expected}, התקבל ${received}`;
}
return `קלט לא תקין: צריך להיות ${expected}, התקבל ${received}`;
}
case "invalid_value": {
if (issue.values.length === 1) {
return `ערך לא תקין: הערך חייב להיות ${util.stringifyPrimitive(issue.values[0])}`;
}
// Join values with proper Hebrew formatting
const stringified = issue.values.map((v) => util.stringifyPrimitive(v));
if (issue.values.length === 2) {
return `ערך לא תקין: האפשרויות המתאימות הן ${stringified[0]} או ${stringified[1]}`;
}
// For 3+ values: "a", "b" או "c"
const lastValue = stringified[stringified.length - 1];
const restValues = stringified.slice(0, -1).join(", ");
return `ערך לא תקין: האפשרויות המתאימות הן ${restValues} או ${lastValue}`;
}
case "too_big": {
const sizing = getSizing(issue.origin);
const subject = withDefinite(issue.origin ?? "value");
if (issue.origin === "string") {
// Special handling for strings - more natural Hebrew
return `${sizing?.longLabel ?? "ארוך"} מדי: ${subject} צריכה להכיל ${issue.maximum.toString()} ${sizing?.unit ?? ""} ${issue.inclusive ? "או פחות" : "לכל היותר"}`.trim();
}
if (issue.origin === "number") {
// Natural Hebrew for numbers
const comparison = issue.inclusive ? `קטן או שווה ל-${issue.maximum}` : `קטן מ-${issue.maximum}`;
return `גדול מדי: ${subject} צריך להיות ${comparison}`;
}
if (issue.origin === "array" || issue.origin === "set") {
// Natural Hebrew for arrays and sets
const verb = issue.origin === "set" ? "צריכה" : "צריך";
const comparison = issue.inclusive
? `${issue.maximum} ${sizing?.unit ?? ""} או פחות`
: `פחות מ-${issue.maximum} ${sizing?.unit ?? ""}`;
return `גדול מדי: ${subject} ${verb} להכיל ${comparison}`.trim();
}
const adj = issue.inclusive ? "<=" : "<";
const be = verbFor(issue.origin ?? "value");
if (sizing?.unit) {
return `${sizing.longLabel} מדי: ${subject} ${be} ${adj}${issue.maximum.toString()} ${sizing.unit}`;
}
return `${sizing?.longLabel ?? "גדול"} מדי: ${subject} ${be} ${adj}${issue.maximum.toString()}`;
}
case "too_small": {
const sizing = getSizing(issue.origin);
const subject = withDefinite(issue.origin ?? "value");
if (issue.origin === "string") {
// Special handling for strings - more natural Hebrew
return `${sizing?.shortLabel ?? "קצר"} מדי: ${subject} צריכה להכיל ${issue.minimum.toString()} ${sizing?.unit ?? ""} ${issue.inclusive ? "או יותר" : "לפחות"}`.trim();
}
if (issue.origin === "number") {
// Natural Hebrew for numbers
const comparison = issue.inclusive ? `גדול או שווה ל-${issue.minimum}` : `גדול מ-${issue.minimum}`;
return `קטן מדי: ${subject} צריך להיות ${comparison}`;
}
if (issue.origin === "array" || issue.origin === "set") {
// Natural Hebrew for arrays and sets
const verb = issue.origin === "set" ? "צריכה" : "צריך";
// Special case for singular (minimum === 1)
if (issue.minimum === 1 && issue.inclusive) {
const singularPhrase = issue.origin === "set" ? "לפחות פריט אחד" : "לפחות פריט אחד";
return `קטן מדי: ${subject} ${verb} להכיל ${singularPhrase}`;
}
const comparison = issue.inclusive
? `${issue.minimum} ${sizing?.unit ?? ""} או יותר`
: `יותר מ-${issue.minimum} ${sizing?.unit ?? ""}`;
return `קטן מדי: ${subject} ${verb} להכיל ${comparison}`.trim();
}
const adj = issue.inclusive ? ">=" : ">";
const be = verbFor(issue.origin ?? "value");
if (sizing?.unit) {
return `${sizing.shortLabel} מדי: ${subject} ${be} ${adj}${issue.minimum.toString()} ${sizing.unit}`;
}
return `${sizing?.shortLabel ?? "קטן"} מדי: ${subject} ${be} ${adj}${issue.minimum.toString()}`;
}
case "invalid_format": {
const _issue = issue;
// These apply to strings — use feminine grammar + ה׳ הידיעה
if (_issue.format === "starts_with")
return `המחרוזת חייבת להתחיל ב "${_issue.prefix}"`;
if (_issue.format === "ends_with")
return `המחרוזת חייבת להסתיים ב "${_issue.suffix}"`;
if (_issue.format === "includes")
return `המחרוזת חייבת לכלול "${_issue.includes}"`;
if (_issue.format === "regex")
return `המחרוזת חייבת להתאים לתבנית ${_issue.pattern}`;
// Handle gender agreement for formats
const nounEntry = FormatDictionary[_issue.format];
const noun = nounEntry?.label ?? _issue.format;
const gender = nounEntry?.gender ?? "m";
const adjective = gender === "f" ? "תקינה" : "תקין";
return `${noun} לא ${adjective}`;
}
case "not_multiple_of":
return `מספר לא תקין: חייב להיות מכפלה של ${issue.divisor}`;
case "unrecognized_keys":
return `מפתח${issue.keys.length > 1 ? "ות" : ""} לא מזוה${issue.keys.length > 1 ? "ים" : "ה"}: ${util.joinValues(issue.keys, ", ")}`;
case "invalid_key": {
return `שדה לא תקין באובייקט`;
}
case "invalid_union":
return "קלט לא תקין";
case "invalid_element": {
const place = withDefinite(issue.origin ?? "array");
return `ערך לא תקין ב${place}`;
}
default:
return `קלט לא תקין`;
}
};
};
export default function () {
return {
localeError: error(),
};
}

View File

@@ -0,0 +1,445 @@
import * as core from "../core/index.js";
import * as util from "../core/util.js";
type SomeType = core.SomeType;
export interface ZodMiniType<out Output = unknown, out Input = unknown, out Internals extends core.$ZodTypeInternals<Output, Input> = core.$ZodTypeInternals<Output, Input>> extends core.$ZodType<Output, Input, Internals> {
type: Internals["def"]["type"];
check(...checks: (core.CheckFn<core.output<this>> | core.$ZodCheck<core.output<this>>)[]): this;
with(...checks: (core.CheckFn<core.output<this>> | core.$ZodCheck<core.output<this>>)[]): this;
clone(def?: Internals["def"], params?: {
parent: boolean;
}): this;
register<R extends core.$ZodRegistry>(registry: R, ...meta: this extends R["_schema"] ? undefined extends R["_meta"] ? [core.$replace<R["_meta"], this>?] : [core.$replace<R["_meta"], this>] : ["Incompatible schema"]): this;
brand<T extends PropertyKey = PropertyKey, Dir extends "in" | "out" | "inout" = "out">(value?: T): PropertyKey extends T ? this : core.$ZodBranded<this, T, Dir>;
def: Internals["def"];
parse(data: unknown, params?: core.ParseContext<core.$ZodIssue>): core.output<this>;
safeParse(data: unknown, params?: core.ParseContext<core.$ZodIssue>): util.SafeParseResult<core.output<this>>;
parseAsync(data: unknown, params?: core.ParseContext<core.$ZodIssue>): Promise<core.output<this>>;
safeParseAsync(data: unknown, params?: core.ParseContext<core.$ZodIssue>): Promise<util.SafeParseResult<core.output<this>>>;
apply<T>(fn: (schema: this) => T): T;
}
interface _ZodMiniType<out Internals extends core.$ZodTypeInternals = core.$ZodTypeInternals> extends ZodMiniType<any, any, Internals> {
}
export declare const ZodMiniType: core.$constructor<ZodMiniType>;
export interface _ZodMiniString<T extends core.$ZodStringInternals<unknown> = core.$ZodStringInternals<unknown>> extends _ZodMiniType<T>, core.$ZodString<T["input"]> {
_zod: T;
}
export interface ZodMiniString<Input = unknown> extends _ZodMiniString<core.$ZodStringInternals<Input>>, core.$ZodString<Input> {
}
export declare const ZodMiniString: core.$constructor<ZodMiniString>;
export declare function string(params?: string | core.$ZodStringParams): ZodMiniString<string>;
export interface ZodMiniStringFormat<Format extends string = string> extends _ZodMiniString<core.$ZodStringFormatInternals<Format>>, core.$ZodStringFormat<Format> {
}
export declare const ZodMiniStringFormat: core.$constructor<ZodMiniStringFormat>;
export interface ZodMiniEmail extends _ZodMiniString<core.$ZodEmailInternals> {
}
export declare const ZodMiniEmail: core.$constructor<ZodMiniEmail>;
export declare function email(params?: string | core.$ZodEmailParams): ZodMiniEmail;
export interface ZodMiniGUID extends _ZodMiniString<core.$ZodGUIDInternals> {
}
export declare const ZodMiniGUID: core.$constructor<ZodMiniGUID>;
export declare function guid(params?: string | core.$ZodGUIDParams): ZodMiniGUID;
export interface ZodMiniUUID extends _ZodMiniString<core.$ZodUUIDInternals> {
}
export declare const ZodMiniUUID: core.$constructor<ZodMiniUUID>;
export declare function uuid(params?: string | core.$ZodUUIDParams): ZodMiniUUID;
export declare function uuidv4(params?: string | core.$ZodUUIDv4Params): ZodMiniUUID;
export declare function uuidv6(params?: string | core.$ZodUUIDv6Params): ZodMiniUUID;
export declare function uuidv7(params?: string | core.$ZodUUIDv7Params): ZodMiniUUID;
export interface ZodMiniURL extends _ZodMiniString<core.$ZodURLInternals> {
}
export declare const ZodMiniURL: core.$constructor<ZodMiniURL>;
export declare function url(params?: string | core.$ZodURLParams): ZodMiniURL;
export declare function httpUrl(params?: string | Omit<core.$ZodURLParams, "protocol" | "hostname">): ZodMiniURL;
export interface ZodMiniEmoji extends _ZodMiniString<core.$ZodEmojiInternals> {
}
export declare const ZodMiniEmoji: core.$constructor<ZodMiniEmoji>;
export declare function emoji(params?: string | core.$ZodEmojiParams): ZodMiniEmoji;
export interface ZodMiniNanoID extends _ZodMiniString<core.$ZodNanoIDInternals> {
}
export declare const ZodMiniNanoID: core.$constructor<ZodMiniNanoID>;
export declare function nanoid(params?: string | core.$ZodNanoIDParams): ZodMiniNanoID;
/**
* @deprecated CUID v1 is deprecated by its authors due to information leakage
* (timestamps embedded in the id). Use {@link ZodMiniCUID2} instead.
* See https://github.com/paralleldrive/cuid.
*/
export interface ZodMiniCUID extends _ZodMiniString<core.$ZodCUIDInternals> {
}
/**
* @deprecated CUID v1 is deprecated by its authors due to information leakage
* (timestamps embedded in the id). Use {@link ZodMiniCUID2} instead.
* See https://github.com/paralleldrive/cuid.
*/
export declare const ZodMiniCUID: core.$constructor<ZodMiniCUID>;
/**
* Validates a CUID v1 string.
*
* @deprecated CUID v1 is deprecated by its authors due to information leakage
* (timestamps embedded in the id). Use {@link cuid2 | `z.cuid2()`} instead.
* See https://github.com/paralleldrive/cuid.
*/
export declare function cuid(params?: string | core.$ZodCUIDParams): ZodMiniCUID;
export interface ZodMiniCUID2 extends _ZodMiniString<core.$ZodCUID2Internals> {
}
export declare const ZodMiniCUID2: core.$constructor<ZodMiniCUID2>;
export declare function cuid2(params?: string | core.$ZodCUID2Params): ZodMiniCUID2;
export interface ZodMiniULID extends _ZodMiniString<core.$ZodULIDInternals> {
}
export declare const ZodMiniULID: core.$constructor<ZodMiniULID>;
export declare function ulid(params?: string | core.$ZodULIDParams): ZodMiniULID;
export interface ZodMiniXID extends _ZodMiniString<core.$ZodXIDInternals> {
}
export declare const ZodMiniXID: core.$constructor<ZodMiniXID>;
export declare function xid(params?: string | core.$ZodXIDParams): ZodMiniXID;
export interface ZodMiniKSUID extends _ZodMiniString<core.$ZodKSUIDInternals> {
}
export declare const ZodMiniKSUID: core.$constructor<ZodMiniKSUID>;
export declare function ksuid(params?: string | core.$ZodKSUIDParams): ZodMiniKSUID;
export interface ZodMiniIPv4 extends _ZodMiniString<core.$ZodIPv4Internals> {
}
export declare const ZodMiniIPv4: core.$constructor<ZodMiniIPv4>;
export declare function ipv4(params?: string | core.$ZodIPv4Params): ZodMiniIPv4;
export interface ZodMiniIPv6 extends _ZodMiniString<core.$ZodIPv6Internals> {
}
export declare const ZodMiniIPv6: core.$constructor<ZodMiniIPv6>;
export declare function ipv6(params?: string | core.$ZodIPv6Params): ZodMiniIPv6;
export interface ZodMiniCIDRv4 extends _ZodMiniString<core.$ZodCIDRv4Internals> {
}
export declare const ZodMiniCIDRv4: core.$constructor<ZodMiniCIDRv4>;
export declare function cidrv4(params?: string | core.$ZodCIDRv4Params): ZodMiniCIDRv4;
export interface ZodMiniCIDRv6 extends _ZodMiniString<core.$ZodCIDRv6Internals> {
}
export declare const ZodMiniCIDRv6: core.$constructor<ZodMiniCIDRv6>;
export declare function cidrv6(params?: string | core.$ZodCIDRv6Params): ZodMiniCIDRv6;
export interface ZodMiniMAC extends _ZodMiniString<core.$ZodMACInternals> {
}
export declare const ZodMiniMAC: core.$constructor<ZodMiniMAC>;
export declare function mac(params?: string | core.$ZodMACParams): ZodMiniMAC;
export interface ZodMiniBase64 extends _ZodMiniString<core.$ZodBase64Internals> {
}
export declare const ZodMiniBase64: core.$constructor<ZodMiniBase64>;
export declare function base64(params?: string | core.$ZodBase64Params): ZodMiniBase64;
export interface ZodMiniBase64URL extends _ZodMiniString<core.$ZodBase64URLInternals> {
}
export declare const ZodMiniBase64URL: core.$constructor<ZodMiniBase64URL>;
export declare function base64url(params?: string | core.$ZodBase64URLParams): ZodMiniBase64URL;
export interface ZodMiniE164 extends _ZodMiniString<core.$ZodE164Internals> {
}
export declare const ZodMiniE164: core.$constructor<ZodMiniE164>;
export declare function e164(params?: string | core.$ZodE164Params): ZodMiniE164;
export interface ZodMiniJWT extends _ZodMiniString<core.$ZodJWTInternals> {
}
export declare const ZodMiniJWT: core.$constructor<ZodMiniJWT>;
export declare function jwt(params?: string | core.$ZodJWTParams): ZodMiniJWT;
export interface ZodMiniCustomStringFormat<Format extends string = string> extends ZodMiniStringFormat<Format>, core.$ZodCustomStringFormat<Format> {
_zod: core.$ZodCustomStringFormatInternals<Format>;
}
export declare const ZodMiniCustomStringFormat: core.$constructor<ZodMiniCustomStringFormat>;
export declare function stringFormat<Format extends string>(format: Format, fnOrRegex: ((arg: string) => util.MaybeAsync<unknown>) | RegExp, _params?: string | core.$ZodStringFormatParams): ZodMiniCustomStringFormat<Format>;
export declare function hostname(_params?: string | core.$ZodStringFormatParams): ZodMiniCustomStringFormat<"hostname">;
export declare function hex(_params?: string | core.$ZodStringFormatParams): ZodMiniCustomStringFormat<"hex">;
export declare function hash<Alg extends util.HashAlgorithm, Enc extends util.HashEncoding = "hex">(alg: Alg, params?: {
enc?: Enc;
} & core.$ZodStringFormatParams): ZodMiniCustomStringFormat<`${Alg}_${Enc}`>;
interface _ZodMiniNumber<T extends core.$ZodNumberInternals<unknown> = core.$ZodNumberInternals<unknown>> extends _ZodMiniType<T>, core.$ZodNumber<T["input"]> {
_zod: T;
}
export interface ZodMiniNumber<Input = unknown> extends _ZodMiniNumber<core.$ZodNumberInternals<Input>>, core.$ZodNumber<Input> {
}
export declare const ZodMiniNumber: core.$constructor<ZodMiniNumber>;
export declare function number(params?: string | core.$ZodNumberParams): ZodMiniNumber<number>;
export interface ZodMiniNumberFormat extends _ZodMiniNumber<core.$ZodNumberFormatInternals>, core.$ZodNumberFormat {
}
export declare const ZodMiniNumberFormat: core.$constructor<ZodMiniNumberFormat>;
export declare function int(params?: string | core.$ZodCheckNumberFormatParams): ZodMiniNumberFormat;
export declare function float32(params?: string | core.$ZodCheckNumberFormatParams): ZodMiniNumberFormat;
export declare function float64(params?: string | core.$ZodCheckNumberFormatParams): ZodMiniNumberFormat;
export declare function int32(params?: string | core.$ZodCheckNumberFormatParams): ZodMiniNumberFormat;
export declare function uint32(params?: string | core.$ZodCheckNumberFormatParams): ZodMiniNumberFormat;
export interface ZodMiniBoolean<T = unknown> extends _ZodMiniType<core.$ZodBooleanInternals<T>> {
}
export declare const ZodMiniBoolean: core.$constructor<ZodMiniBoolean>;
export declare function boolean(params?: string | core.$ZodBooleanParams): ZodMiniBoolean<boolean>;
export interface ZodMiniBigInt<T = unknown> extends _ZodMiniType<core.$ZodBigIntInternals<T>>, core.$ZodBigInt<T> {
}
export declare const ZodMiniBigInt: core.$constructor<ZodMiniBigInt>;
export declare function bigint(params?: string | core.$ZodBigIntParams): ZodMiniBigInt<bigint>;
export interface ZodMiniBigIntFormat extends _ZodMiniType<core.$ZodBigIntFormatInternals> {
}
export declare const ZodMiniBigIntFormat: core.$constructor<ZodMiniBigIntFormat>;
export declare function int64(params?: string | core.$ZodBigIntFormatParams): ZodMiniBigIntFormat;
export declare function uint64(params?: string | core.$ZodBigIntFormatParams): ZodMiniBigIntFormat;
export interface ZodMiniSymbol extends _ZodMiniType<core.$ZodSymbolInternals> {
}
export declare const ZodMiniSymbol: core.$constructor<ZodMiniSymbol>;
export declare function symbol(params?: string | core.$ZodSymbolParams): ZodMiniSymbol;
export interface ZodMiniUndefined extends _ZodMiniType<core.$ZodUndefinedInternals> {
}
export declare const ZodMiniUndefined: core.$constructor<ZodMiniUndefined>;
declare function _undefined(params?: string | core.$ZodUndefinedParams): ZodMiniUndefined;
export { _undefined as undefined };
export interface ZodMiniNull extends _ZodMiniType<core.$ZodNullInternals> {
}
export declare const ZodMiniNull: core.$constructor<ZodMiniNull>;
declare function _null(params?: string | core.$ZodNullParams): ZodMiniNull;
export { _null as null };
export interface ZodMiniAny extends _ZodMiniType<core.$ZodAnyInternals> {
}
export declare const ZodMiniAny: core.$constructor<ZodMiniAny>;
export declare function any(): ZodMiniAny;
export interface ZodMiniUnknown extends _ZodMiniType<core.$ZodUnknownInternals> {
}
export declare const ZodMiniUnknown: core.$constructor<ZodMiniUnknown>;
export declare function unknown(): ZodMiniUnknown;
export interface ZodMiniNever extends _ZodMiniType<core.$ZodNeverInternals> {
}
export declare const ZodMiniNever: core.$constructor<ZodMiniNever>;
export declare function never(params?: string | core.$ZodNeverParams): ZodMiniNever;
export interface ZodMiniVoid extends _ZodMiniType<core.$ZodVoidInternals> {
}
export declare const ZodMiniVoid: core.$constructor<ZodMiniVoid>;
declare function _void(params?: string | core.$ZodVoidParams): ZodMiniVoid;
export { _void as void };
export interface ZodMiniDate<T = unknown> extends _ZodMiniType<core.$ZodDateInternals<T>> {
}
export declare const ZodMiniDate: core.$constructor<ZodMiniDate>;
export declare function date(params?: string | core.$ZodDateParams): ZodMiniDate<Date>;
export interface ZodMiniArray<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodArrayInternals<T>>, core.$ZodArray<T> {
}
export declare const ZodMiniArray: core.$constructor<ZodMiniArray>;
export declare function array<T extends SomeType>(element: T, params?: string | core.$ZodArrayParams): ZodMiniArray<T>;
export declare function keyof<T extends ZodMiniObject>(schema: T): ZodMiniEnum<util.KeysEnum<T["shape"]>>;
export interface ZodMiniObject<
/** @ts-ignore Cast variance */
out Shape extends core.$ZodShape = core.$ZodShape, out Config extends core.$ZodObjectConfig = core.$strip> extends ZodMiniType<any, any, core.$ZodObjectInternals<Shape, Config>>, core.$ZodObject<Shape, Config> {
shape: Shape;
}
export declare const ZodMiniObject: core.$constructor<ZodMiniObject>;
export declare function object<T extends core.$ZodLooseShape = Record<never, SomeType>>(shape?: T, params?: string | core.$ZodObjectParams): ZodMiniObject<util.Writeable<T>, core.$strip>;
export declare function strictObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodMiniObject<util.Writeable<T>, core.$strict>;
export declare function looseObject<T extends core.$ZodLooseShape>(shape: T, params?: string | core.$ZodObjectParams): ZodMiniObject<util.Writeable<T>, core.$loose>;
export declare function extend<T extends ZodMiniObject, U extends core.$ZodLooseShape>(schema: T, shape: U): ZodMiniObject<util.Extend<T["shape"], util.Writeable<U>>, T["_zod"]["config"]>;
export type SafeExtendShape<Base extends core.$ZodShape, Ext extends core.$ZodLooseShape> = {
[K in keyof Ext]: K extends keyof Base ? core.output<Ext[K]> extends core.output<Base[K]> ? core.input<Ext[K]> extends core.input<Base[K]> ? Ext[K] : never : never : Ext[K];
};
export declare function safeExtend<T extends ZodMiniObject, U extends core.$ZodLooseShape>(schema: T, shape: SafeExtendShape<T["shape"], U>): ZodMiniObject<util.Extend<T["shape"], util.Writeable<U>>, T["_zod"]["config"]>;
/** @deprecated Identical to `z.extend(A, B)` */
export declare function merge<T extends ZodMiniObject, U extends ZodMiniObject>(a: T, b: U): ZodMiniObject<util.Extend<T["shape"], U["shape"]>, T["_zod"]["config"]>;
export declare function pick<T extends ZodMiniObject, M extends util.Mask<keyof T["shape"]>>(schema: T, mask: M & Record<Exclude<keyof M, keyof T["shape"]>, never>): ZodMiniObject<util.Flatten<Pick<T["shape"], keyof T["shape"] & keyof M>>, T["_zod"]["config"]>;
export declare function omit<T extends ZodMiniObject, M extends util.Mask<keyof T["shape"]>>(schema: T, mask: M & Record<Exclude<keyof M, keyof T["shape"]>, never>): ZodMiniObject<util.Flatten<Omit<T["shape"], keyof M>>, T["_zod"]["config"]>;
export declare function partial<T extends ZodMiniObject>(schema: T): ZodMiniObject<{
-readonly [k in keyof T["shape"]]: ZodMiniOptional<T["shape"][k]>;
}, T["_zod"]["config"]>;
export declare function partial<T extends ZodMiniObject, M extends util.Mask<keyof T["shape"]>>(schema: T, mask: M & Record<Exclude<keyof M, keyof T["shape"]>, never>): ZodMiniObject<{
-readonly [k in keyof T["shape"]]: k extends keyof M ? ZodMiniOptional<T["shape"][k]> : T["shape"][k];
}, T["_zod"]["config"]>;
export type RequiredInterfaceShape<Shape extends core.$ZodLooseShape, Keys extends PropertyKey = keyof Shape> = util.Identity<{
[k in keyof Shape as k extends Keys ? k : never]: ZodMiniNonOptional<Shape[k]>;
} & {
[k in keyof Shape as k extends Keys ? never : k]: Shape[k];
}>;
export declare function required<T extends ZodMiniObject>(schema: T): ZodMiniObject<{
-readonly [k in keyof T["shape"]]: ZodMiniNonOptional<T["shape"][k]>;
}, T["_zod"]["config"]>;
export declare function required<T extends ZodMiniObject, M extends util.Mask<keyof T["shape"]>>(schema: T, mask: M & Record<Exclude<keyof M, keyof T["shape"]>, never>): ZodMiniObject<util.Extend<T["shape"], {
[k in keyof M & keyof T["shape"]]: ZodMiniNonOptional<T["shape"][k]>;
}>, T["_zod"]["config"]>;
export declare function catchall<T extends ZodMiniObject, U extends SomeType>(inst: T, catchall: U): ZodMiniObject<T["shape"], core.$catchall<U>>;
export interface ZodMiniUnion<T extends readonly SomeType[] = readonly core.$ZodType[]> extends _ZodMiniType<core.$ZodUnionInternals<T>> {
}
export declare const ZodMiniUnion: core.$constructor<ZodMiniUnion>;
export declare function union<const T extends readonly SomeType[]>(options: T, params?: string | core.$ZodUnionParams): ZodMiniUnion<T>;
export interface ZodMiniXor<T extends readonly SomeType[] = readonly core.$ZodType[]> extends _ZodMiniType<core.$ZodXorInternals<T>> {
}
export declare const ZodMiniXor: core.$constructor<ZodMiniXor>;
/** Creates an exclusive union (XOR) where exactly one option must match.
* Unlike regular unions that succeed when any option matches, xor fails if
* zero or more than one option matches the input. */
export declare function xor<const T extends readonly SomeType[]>(options: T, params?: string | core.$ZodXorParams): ZodMiniXor<T>;
export interface ZodMiniDiscriminatedUnion<Options extends readonly SomeType[] = readonly core.$ZodType[], Disc extends string = string> extends ZodMiniUnion<Options> {
_zod: core.$ZodDiscriminatedUnionInternals<Options, Disc>;
}
export declare const ZodMiniDiscriminatedUnion: core.$constructor<ZodMiniDiscriminatedUnion>;
export declare function discriminatedUnion<Types extends readonly [core.$ZodTypeDiscriminable<Disc>, ...core.$ZodTypeDiscriminable<Disc>[]], Disc extends string>(discriminator: Disc, options: Types, params?: string | core.$ZodDiscriminatedUnionParams): ZodMiniDiscriminatedUnion<Types, Disc>;
export interface ZodMiniIntersection<A extends SomeType = core.$ZodType, B extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodIntersectionInternals<A, B>> {
}
export declare const ZodMiniIntersection: core.$constructor<ZodMiniIntersection>;
export declare function intersection<T extends SomeType, U extends SomeType>(left: T, right: U): ZodMiniIntersection<T, U>;
export interface ZodMiniTuple<T extends util.TupleItems = readonly core.$ZodType[], Rest extends SomeType | null = core.$ZodType | null> extends _ZodMiniType<core.$ZodTupleInternals<T, Rest>> {
}
export declare const ZodMiniTuple: core.$constructor<ZodMiniTuple>;
export declare function tuple<const T extends readonly [SomeType, ...SomeType[]]>(items: T, params?: string | core.$ZodTupleParams): ZodMiniTuple<T, null>;
export declare function tuple<const T extends readonly [SomeType, ...SomeType[]], Rest extends SomeType>(items: T, rest: Rest, params?: string | core.$ZodTupleParams): ZodMiniTuple<T, Rest>;
export declare function tuple(items: [], params?: string | core.$ZodTupleParams): ZodMiniTuple<[], null>;
export interface ZodMiniRecord<Key extends core.$ZodRecordKey = core.$ZodRecordKey, Value extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodRecordInternals<Key, Value>> {
}
export declare const ZodMiniRecord: core.$constructor<ZodMiniRecord>;
export declare function record<Key extends core.$ZodRecordKey, Value extends SomeType>(keyType: Key, valueType: Value, params?: string | core.$ZodRecordParams): ZodMiniRecord<Key, Value>;
export declare function partialRecord<Key extends core.$ZodRecordKey, Value extends SomeType>(keyType: Key, valueType: Value, params?: string | core.$ZodRecordParams): ZodMiniRecord<Key & core.$partial, Value>;
export declare function looseRecord<Key extends core.$ZodRecordKey, Value extends SomeType>(keyType: Key, valueType: Value, params?: string | core.$ZodRecordParams): ZodMiniRecord<Key, Value>;
export interface ZodMiniMap<Key extends SomeType = core.$ZodType, Value extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodMapInternals<Key, Value>> {
}
export declare const ZodMiniMap: core.$constructor<ZodMiniMap>;
export declare function map<Key extends SomeType, Value extends SomeType>(keyType: Key, valueType: Value, params?: string | core.$ZodMapParams): ZodMiniMap<Key, Value>;
export interface ZodMiniSet<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodSetInternals<T>> {
}
export declare const ZodMiniSet: core.$constructor<ZodMiniSet>;
export declare function set<Value extends SomeType>(valueType: Value, params?: string | core.$ZodSetParams): ZodMiniSet<Value>;
export interface ZodMiniEnum<T extends util.EnumLike = util.EnumLike> extends _ZodMiniType<core.$ZodEnumInternals<T>> {
options: Array<T[keyof T]>;
}
export declare const ZodMiniEnum: core.$constructor<ZodMiniEnum>;
declare function _enum<const T extends readonly string[]>(values: T, params?: string | core.$ZodEnumParams): ZodMiniEnum<util.ToEnum<T[number]>>;
declare function _enum<T extends util.EnumLike>(entries: T, params?: string | core.$ZodEnumParams): ZodMiniEnum<T>;
export { _enum as enum };
/** @deprecated This API has been merged into `z.enum()`. Use `z.enum()` instead.
*
* ```ts
* enum Colors { red, green, blue }
* z.enum(Colors);
* ```
*/
export declare function nativeEnum<T extends util.EnumLike>(entries: T, params?: string | core.$ZodEnumParams): ZodMiniEnum<T>;
export interface ZodMiniLiteral<T extends util.Literal = util.Literal> extends _ZodMiniType<core.$ZodLiteralInternals<T>> {
}
export declare const ZodMiniLiteral: core.$constructor<ZodMiniLiteral>;
export declare function literal<const T extends ReadonlyArray<util.Literal>>(value: T, params?: string | core.$ZodLiteralParams): ZodMiniLiteral<T[number]>;
export declare function literal<const T extends util.Literal>(value: T, params?: string | core.$ZodLiteralParams): ZodMiniLiteral<T>;
export interface ZodMiniFile extends _ZodMiniType<core.$ZodFileInternals> {
}
export declare const ZodMiniFile: core.$constructor<ZodMiniFile>;
export declare function file(params?: string | core.$ZodFileParams): ZodMiniFile;
export interface ZodMiniTransform<O = unknown, I = unknown> extends _ZodMiniType<core.$ZodTransformInternals<O, I>> {
}
export declare const ZodMiniTransform: core.$constructor<ZodMiniTransform>;
export declare function transform<I = unknown, O = I>(fn: (input: I, ctx: core.ParsePayload) => O): ZodMiniTransform<Awaited<O>, I>;
export interface ZodMiniOptional<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodOptionalInternals<T>>, core.$ZodOptional<T> {
}
export declare const ZodMiniOptional: core.$constructor<ZodMiniOptional>;
export declare function optional<T extends SomeType>(innerType: T): ZodMiniOptional<T>;
export interface ZodMiniExactOptional<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodExactOptionalInternals<T>>, core.$ZodExactOptional<T> {
}
export declare const ZodMiniExactOptional: core.$constructor<ZodMiniExactOptional>;
export declare function exactOptional<T extends SomeType>(innerType: T): ZodMiniExactOptional<T>;
export interface ZodMiniNullable<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodNullableInternals<T>> {
}
export declare const ZodMiniNullable: core.$constructor<ZodMiniNullable>;
export declare function nullable<T extends SomeType>(innerType: T): ZodMiniNullable<T>;
export declare function nullish<T extends SomeType>(innerType: T): ZodMiniOptional<ZodMiniNullable<T>>;
export interface ZodMiniDefault<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodDefaultInternals<T>> {
}
export declare const ZodMiniDefault: core.$constructor<ZodMiniDefault>;
export declare function _default<T extends SomeType>(innerType: T, defaultValue: util.NoUndefined<core.output<T>> | (() => util.NoUndefined<core.output<T>>)): ZodMiniDefault<T>;
export interface ZodMiniPrefault<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodPrefaultInternals<T>> {
}
export declare const ZodMiniPrefault: core.$constructor<ZodMiniPrefault>;
export declare function prefault<T extends SomeType>(innerType: T, defaultValue: util.NoUndefined<core.input<T>> | (() => util.NoUndefined<core.input<T>>)): ZodMiniPrefault<T>;
export interface ZodMiniNonOptional<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodNonOptionalInternals<T>> {
}
export declare const ZodMiniNonOptional: core.$constructor<ZodMiniNonOptional>;
export declare function nonoptional<T extends SomeType>(innerType: T, params?: string | core.$ZodNonOptionalParams): ZodMiniNonOptional<T>;
export interface ZodMiniSuccess<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodSuccessInternals<T>> {
}
export declare const ZodMiniSuccess: core.$constructor<ZodMiniSuccess>;
export declare function success<T extends SomeType>(innerType: T): ZodMiniSuccess<T>;
export interface ZodMiniCatch<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodCatchInternals<T>> {
}
export declare const ZodMiniCatch: core.$constructor<ZodMiniCatch>;
declare function _catch<T extends SomeType>(innerType: T, catchValue: core.output<T> | ((ctx: core.$ZodCatchCtx) => core.output<T>)): ZodMiniCatch<T>;
export { _catch as catch };
export interface ZodMiniNaN extends _ZodMiniType<core.$ZodNaNInternals> {
}
export declare const ZodMiniNaN: core.$constructor<ZodMiniNaN>;
export declare function nan(params?: string | core.$ZodNaNParams): ZodMiniNaN;
export interface ZodMiniPipe<A extends SomeType = core.$ZodType, B extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodPipeInternals<A, B>> {
}
export declare const ZodMiniPipe: core.$constructor<ZodMiniPipe>;
export declare function pipe<const A extends SomeType, B extends core.$ZodType<unknown, core.output<A>> = core.$ZodType<unknown, core.output<A>>>(in_: A, out: B | core.$ZodType<unknown, core.output<A>>): ZodMiniPipe<A, B>;
export interface ZodMiniCodec<A extends SomeType = core.$ZodType, B extends SomeType = core.$ZodType> extends ZodMiniPipe<A, B>, core.$ZodCodec<A, B> {
_zod: core.$ZodCodecInternals<A, B>;
def: core.$ZodCodecDef<A, B>;
}
export declare const ZodMiniCodec: core.$constructor<ZodMiniCodec>;
export declare function codec<const A extends SomeType, B extends core.SomeType = core.$ZodType>(in_: A, out: B, params: {
decode: (value: core.output<A>, payload: core.ParsePayload<core.output<A>>) => core.util.MaybeAsync<core.input<B>>;
encode: (value: core.input<B>, payload: core.ParsePayload<core.input<B>>) => core.util.MaybeAsync<core.output<A>>;
}): ZodMiniCodec<A, B>;
export declare function invertCodec<A extends SomeType, B extends SomeType>(codec: ZodMiniCodec<A, B>): ZodMiniCodec<B, A>;
export interface ZodMiniReadonly<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodReadonlyInternals<T>> {
}
export declare const ZodMiniReadonly: core.$constructor<ZodMiniReadonly>;
export declare function readonly<T extends SomeType>(innerType: T): ZodMiniReadonly<T>;
export interface ZodMiniTemplateLiteral<Template extends string = string> extends _ZodMiniType<core.$ZodTemplateLiteralInternals<Template>> {
}
export declare const ZodMiniTemplateLiteral: core.$constructor<ZodMiniTemplateLiteral>;
export declare function templateLiteral<const Parts extends core.$ZodTemplateLiteralPart[]>(parts: Parts, params?: string | core.$ZodTemplateLiteralParams): ZodMiniTemplateLiteral<core.$PartsToTemplateLiteral<Parts>>;
export interface ZodMiniLazy<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodLazyInternals<T>> {
}
export declare const ZodMiniLazy: core.$constructor<ZodMiniLazy>;
declare function _lazy<T extends SomeType>(getter: () => T): ZodMiniLazy<T>;
export { _lazy as lazy };
export interface ZodMiniPromise<T extends SomeType = core.$ZodType> extends _ZodMiniType<core.$ZodPromiseInternals<T>> {
}
export declare const ZodMiniPromise: core.$constructor<ZodMiniPromise>;
export declare function promise<T extends SomeType>(innerType: T): ZodMiniPromise<T>;
export interface ZodMiniCustom<O = unknown, I = unknown> extends _ZodMiniType<core.$ZodCustomInternals<O, I>> {
}
export declare const ZodMiniCustom: core.$constructor<ZodMiniCustom>;
export declare function check<O = unknown>(fn: core.CheckFn<O>, params?: string | core.$ZodCustomParams): core.$ZodCheck<O>;
export declare function custom<O = unknown, I = O>(fn?: (data: O) => unknown, _params?: string | core.$ZodCustomParams | undefined): ZodMiniCustom<O, I>;
export declare function refine<T>(fn: (arg: NoInfer<T>) => util.MaybeAsync<unknown>, _params?: string | core.$ZodCustomParams): core.$ZodCheck<T>;
export declare function superRefine<T>(fn: (arg: T, payload: core.$RefinementCtx<T>) => void | Promise<void>, params?: core.$ZodSuperRefineParams): core.$ZodCheck<T>;
export declare const describe: typeof core.describe;
export declare const meta: typeof core.meta;
declare abstract class Class {
constructor(..._args: any[]);
}
declare function _instanceof<T extends typeof Class>(cls: T, params?: core.$ZodCustomParams): ZodMiniCustom<InstanceType<T>, InstanceType<T>>;
export { _instanceof as instanceof };
export declare const stringbool: (_params?: string | core.$ZodStringBoolParams) => ZodMiniCodec<ZodMiniString, ZodMiniBoolean>;
export type _ZodMiniJSONSchema = ZodMiniUnion<[
ZodMiniString,
ZodMiniNumber,
ZodMiniBoolean,
ZodMiniNull,
ZodMiniArray<ZodMiniJSONSchema>,
ZodMiniRecord<ZodMiniString<string>, ZodMiniJSONSchema>
]>;
export type _ZodMiniJSONSchemaInternals = _ZodMiniJSONSchema["_zod"];
export interface ZodMiniJSONSchemaInternals extends _ZodMiniJSONSchemaInternals {
output: util.JSONType;
input: util.JSONType;
}
export interface ZodMiniJSONSchema extends _ZodMiniJSONSchema {
_zod: ZodMiniJSONSchemaInternals;
}
export declare function json(): ZodMiniJSONSchema;
export interface ZodMiniFunction<Args extends core.$ZodFunctionIn = core.$ZodFunctionIn, Returns extends core.$ZodFunctionOut = core.$ZodFunctionOut> extends _ZodMiniType<core.$ZodFunctionInternals<Args, Returns>>, core.$ZodFunction<Args, Returns> {
_def: core.$ZodFunctionDef<Args, Returns>;
_input: core.$InferInnerFunctionType<Args, Returns>;
_output: core.$InferOuterFunctionType<Args, Returns>;
input<const Items extends util.TupleItems, const Rest extends core.$ZodFunctionOut = core.$ZodFunctionOut>(args: Items, rest?: Rest): ZodMiniFunction<ZodMiniTuple<Items, Rest>, Returns>;
input<NewArgs extends core.$ZodFunctionIn>(args: NewArgs): ZodMiniFunction<NewArgs, Returns>;
input(...args: any[]): ZodMiniFunction<any, Returns>;
output<NewReturns extends core.$ZodFunctionOut>(output: NewReturns): ZodMiniFunction<Args, NewReturns>;
}
export declare const ZodMiniFunction: core.$constructor<ZodMiniFunction>;
export declare function _function(): ZodMiniFunction;
export declare function _function<const In extends Array<SomeType> = Array<SomeType>>(params: {
input: In;
}): ZodMiniFunction<ZodMiniTuple<In, null>, core.$ZodFunctionOut>;
export declare function _function<const In extends Array<SomeType> = Array<SomeType>, const Out extends core.$ZodFunctionOut = core.$ZodFunctionOut>(params: {
input: In;
output: Out;
}): ZodMiniFunction<ZodMiniTuple<In, null>, Out>;
export declare function _function<const In extends core.$ZodFunctionIn = core.$ZodFunctionIn>(params: {
input: In;
}): ZodMiniFunction<In, core.$ZodFunctionOut>;
export declare function _function<const Out extends core.$ZodFunctionOut = core.$ZodFunctionOut>(params: {
output: Out;
}): ZodMiniFunction<core.$ZodFunctionIn, Out>;
export declare function _function<In extends core.$ZodFunctionIn = core.$ZodFunctionIn, Out extends core.$ZodFunctionOut = core.$ZodFunctionOut>(params?: {
input: In;
output: Out;
}): ZodMiniFunction<In, Out>;
export { _function as function };

View File

@@ -0,0 +1,91 @@
'use strict';
const path = require('path');
const resolveCommand = require('./util/resolveCommand');
const escape = require('./util/escape');
const readShebang = require('./util/readShebang');
const isWin = process.platform === 'win32';
const isExecutableRegExp = /\.(?:com|exe)$/i;
const isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
function detectShebang(parsed) {
parsed.file = resolveCommand(parsed);
const shebang = parsed.file && readShebang(parsed.file);
if (shebang) {
parsed.args.unshift(parsed.file);
parsed.command = shebang;
return resolveCommand(parsed);
}
return parsed.file;
}
function parseNonShell(parsed) {
if (!isWin) {
return parsed;
}
// Detect & add support for shebangs
const commandFile = detectShebang(parsed);
// We don't need a shell if the command filename is an executable
const needsShell = !isExecutableRegExp.test(commandFile);
// If a shell is required, use cmd.exe and take care of escaping everything correctly
// Note that `forceShell` is an hidden option used only in tests
if (parsed.options.forceShell || needsShell) {
// Need to double escape meta chars if the command is a cmd-shim located in `node_modules/.bin/`
// The cmd-shim simply calls execute the package bin file with NodeJS, proxying any argument
// Because the escape of metachars with ^ gets interpreted when the cmd.exe is first called,
// we need to double escape them
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
// Normalize posix paths into OS compatible paths (e.g.: foo/bar -> foo\bar)
// This is necessary otherwise it will always fail with ENOENT in those cases
parsed.command = path.normalize(parsed.command);
// Escape command & arguments
parsed.command = escape.command(parsed.command);
parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
const shellCommand = [parsed.command].concat(parsed.args).join(' ');
parsed.args = ['/d', '/s', '/c', `"${shellCommand}"`];
parsed.command = process.env.comspec || 'cmd.exe';
parsed.options.windowsVerbatimArguments = true; // Tell node's spawn that the arguments are already escaped
}
return parsed;
}
function parse(command, args, options) {
// Normalize arguments, similar to nodejs
if (args && !Array.isArray(args)) {
options = args;
args = null;
}
args = args ? args.slice(0) : []; // Clone array to avoid changing the original
options = Object.assign({}, options); // Clone object to avoid changing the original
// Build our parsed object
const parsed = {
command,
args,
options,
file: undefined,
original: {
command,
args,
},
};
// Delegate further parsing to shell or non-shell
return options.shell ? parsed : parseNonShell(parsed);
}
module.exports = parse;

View File

@@ -0,0 +1,77 @@
/**
* @fileoverview Rule to flag comparison where left part is the same as the right
* part.
* @author Ilya Volodin
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
docs: {
description:
"Disallow comparisons where both sides are exactly the same",
recommended: false,
url: "https://eslint.org/docs/latest/rules/no-self-compare",
},
schema: [],
messages: {
comparingToSelf: "Comparing to itself is potentially pointless.",
},
},
create(context) {
const sourceCode = context.sourceCode;
/**
* Determines whether two nodes are composed of the same tokens.
* @param {ASTNode} nodeA The first node
* @param {ASTNode} nodeB The second node
* @returns {boolean} true if the nodes have identical token representations
*/
function hasSameTokens(nodeA, nodeB) {
const tokensA = sourceCode.getTokens(nodeA);
const tokensB = sourceCode.getTokens(nodeB);
return (
tokensA.length === tokensB.length &&
tokensA.every(
(token, index) =>
token.type === tokensB[index].type &&
token.value === tokensB[index].value,
)
);
}
return {
BinaryExpression(node) {
const operators = new Set([
"===",
"==",
"!==",
"!=",
">",
"<",
">=",
"<=",
]);
if (
operators.has(node.operator) &&
hasSameTokens(node.left, node.right)
) {
context.report({ node, messageId: "comparingToSelf" });
}
},
};
},
};

View File

@@ -0,0 +1,66 @@
export {
// Type-only exports
AcceptedPlugin,
AnyNode,
atRule,
AtRule,
AtRuleProps,
Builder,
ChildNode,
ChildProps,
comment,
Comment,
CommentProps,
Container,
ContainerProps,
CssSyntaxError,
decl,
Declaration,
DeclarationProps,
// postcss function / namespace
default,
document,
Document,
DocumentProps,
FilePosition,
fromJSON,
Helpers,
Input,
JSONHydrator,
// This is a class, but its not re-exported. Thats why its exported as type-only here.
type LazyResult,
list,
Message,
Node,
NodeErrorOptions,
NodeProps,
OldPlugin,
parse,
Parser,
// @ts-expect-error This value exists, but its untyped.
plugin,
Plugin,
PluginCreator,
Position,
Postcss,
ProcessOptions,
Processor,
Result,
root,
Root,
RootProps,
rule,
Rule,
RuleProps,
Source,
SourceMap,
SourceMapOptions,
Stringifier,
// Value exports from postcss.mjs
stringify,
Syntax,
TransformCallback,
Transformer,
Warning,
WarningOptions
} from './postcss.js'

View File

@@ -0,0 +1,336 @@
/**
* @fileoverview JavaScript Language Object
* @author Nicholas C. Zakas
*/
"use strict";
//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------
const { SourceCode } = require("./source-code");
const createDebug = require("debug");
const astUtils = require("../../shared/ast-utils");
const espree = require("espree");
const eslintScope = require("eslint-scope");
const evk = require("eslint-visitor-keys");
const { validateLanguageOptions } = require("./validate-language-options");
const { LATEST_ECMA_VERSION } = require("../../../conf/ecma-version");
//-----------------------------------------------------------------------------
// Type Definitions
//-----------------------------------------------------------------------------
/** @typedef {import("@eslint/core").File} File */
/** @typedef {import("@eslint/core").Language} Language */
/** @typedef {import("@eslint/core").OkParseResult} OkParseResult */
/** @typedef {import("../../types").Linter.LanguageOptions} JSLanguageOptions */
//-----------------------------------------------------------------------------
// Helpers
//-----------------------------------------------------------------------------
const debug = createDebug("eslint:languages:js");
const DEFAULT_ECMA_VERSION = 5;
const parserSymbol = Symbol.for("eslint.RuleTester.parser");
/**
* Analyze scope of the given AST.
* @param {ASTNode} ast The `Program` node to analyze.
* @param {JSLanguageOptions} languageOptions The parser options.
* @param {Record<string, string[]>} visitorKeys The visitor keys.
* @returns {ScopeManager} The analysis result.
*/
function analyzeScope(ast, languageOptions, visitorKeys) {
const parserOptions = languageOptions.parserOptions;
const ecmaFeatures = parserOptions.ecmaFeatures || {};
const ecmaVersion = languageOptions.ecmaVersion || DEFAULT_ECMA_VERSION;
return eslintScope.analyze(ast, {
ignoreEval: true,
nodejsScope: ecmaFeatures.globalReturn,
impliedStrict: ecmaFeatures.impliedStrict,
ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
sourceType: languageOptions.sourceType || "script",
childVisitorKeys: visitorKeys || evk.KEYS,
fallback: evk.getKeys,
jsx: ecmaFeatures.jsx,
});
}
/**
* Determines if a given object is Espree.
* @param {Object} parser The parser to check.
* @returns {boolean} `true` if the parser is Espree or `false` if not.
*/
function isEspree(parser) {
return !!(parser === espree || parser[parserSymbol] === espree);
}
/**
* Normalize ECMAScript version from the initial config into languageOptions (year)
* format.
* @param {any} [ecmaVersion] ECMAScript version from the initial config
* @returns {number} normalized ECMAScript version
*/
function normalizeEcmaVersionForLanguageOptions(ecmaVersion) {
switch (ecmaVersion) {
case 3:
return 3;
// void 0 = no ecmaVersion specified so use the default
case 5:
case void 0:
return 5;
default:
if (typeof ecmaVersion === "number") {
return ecmaVersion >= 2015 ? ecmaVersion : ecmaVersion + 2009;
}
}
/*
* We default to the latest supported ecmaVersion for everything else.
* Remember, this is for languageOptions.ecmaVersion, which sets the version
* that is used for a number of processes inside of ESLint. It's normally
* safe to assume people want the latest unless otherwise specified.
*/
return LATEST_ECMA_VERSION;
}
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* @type {Language}
*/
module.exports = {
fileType: "text",
lineStart: 1,
columnStart: 0,
nodeTypeKey: "type",
visitorKeys: evk.KEYS,
defaultLanguageOptions: {
sourceType: "module",
ecmaVersion: "latest",
parser: espree,
parserOptions: {},
},
validateLanguageOptions,
/**
* Normalizes the language options.
* @param {Object} languageOptions The language options to normalize.
* @returns {Object} The normalized language options.
*/
normalizeLanguageOptions(languageOptions) {
languageOptions.ecmaVersion = normalizeEcmaVersionForLanguageOptions(
languageOptions.ecmaVersion,
);
// Espree expects this information to be passed in
if (isEspree(languageOptions.parser)) {
const parserOptions = languageOptions.parserOptions;
if (languageOptions.sourceType) {
parserOptions.sourceType = languageOptions.sourceType;
if (
parserOptions.sourceType === "module" &&
parserOptions.ecmaFeatures &&
parserOptions.ecmaFeatures.globalReturn
) {
parserOptions.ecmaFeatures.globalReturn = false;
}
}
}
return languageOptions;
},
/**
* Determines if a given node matches a given selector class.
* @param {string} className The class name to check.
* @param {ASTNode} node The node to check.
* @param {Array<ASTNode>} ancestry The ancestry of the node.
* @returns {boolean} `true` if there's a match, `false` if not.
* @throws {Error} When an unknown class name is passed.
*/
matchesSelectorClass(className, node, ancestry) {
/*
* Copyright (c) 2013, Joel Feenstra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the ESQuery nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL JOEL FEENSTRA BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
switch (className.toLowerCase()) {
case "statement":
if (node.type.slice(-9) === "Statement") {
return true;
}
// fallthrough: interface Declaration <: Statement { }
case "declaration":
return node.type.slice(-11) === "Declaration";
case "pattern":
if (node.type.slice(-7) === "Pattern") {
return true;
}
// fallthrough: interface Expression <: Node, Pattern { }
case "expression":
return (
node.type.slice(-10) === "Expression" ||
node.type.slice(-7) === "Literal" ||
(node.type === "Identifier" &&
(ancestry.length === 0 ||
ancestry[0].type !== "MetaProperty")) ||
node.type === "MetaProperty"
);
case "function":
return (
node.type === "FunctionDeclaration" ||
node.type === "FunctionExpression" ||
node.type === "ArrowFunctionExpression"
);
default:
throw new Error(`Unknown class name: ${className}`);
}
},
/**
* Parses the given file into an AST.
* @param {File} file The virtual file to parse.
* @param {Object} options Additional options passed from ESLint.
* @param {JSLanguageOptions} options.languageOptions The language options.
* @returns {Object} The result of parsing.
*/
parse(file, { languageOptions }) {
// Note: BOM already removed
const { body: text, path: filePath } = file;
const textToParse = text.replace(
astUtils.shebangPattern,
(match, captured) => `//${captured}`,
);
const { ecmaVersion, sourceType, parser } = languageOptions;
const parserOptions = Object.assign(
{ ecmaVersion, sourceType },
languageOptions.parserOptions,
{
loc: true,
range: true,
tokens: true,
comment: true,
eslintVisitorKeys: true,
eslintScopeManager: true,
filePath,
},
);
/*
* Check for parsing errors first. If there's a parsing error, nothing
* else can happen. However, a parsing error does not throw an error
* from this method - it's just considered a fatal error message, a
* problem that ESLint identified just like any other.
*/
try {
debug("Parsing:", filePath);
const parseResult =
typeof parser.parseForESLint === "function"
? parser.parseForESLint(textToParse, parserOptions)
: { ast: parser.parse(textToParse, parserOptions) };
debug("Parsing successful:", filePath);
const {
ast,
services: parserServices = {},
visitorKeys = evk.KEYS,
scopeManager,
} = parseResult;
return {
ok: true,
ast,
parserServices,
visitorKeys,
scopeManager,
};
} catch (ex) {
// If the message includes a leading line number, strip it:
const message = ex.message.replace(/^line \d+:/iu, "").trim();
debug("%s\n%s", message, ex.stack);
return {
ok: false,
errors: [
{
message,
line: ex.lineNumber,
column: ex.column,
},
],
};
}
},
/**
* Creates a new `SourceCode` object from the given information.
* @param {File} file The virtual file to create a `SourceCode` object from.
* @param {OkParseResult} parseResult The result returned from `parse()`.
* @param {Object} options Additional options passed from ESLint.
* @param {JSLanguageOptions} options.languageOptions The language options.
* @returns {SourceCode} The new `SourceCode` object.
*/
createSourceCode(file, parseResult, { languageOptions }) {
const { body: text, path: filePath, bom: hasBOM } = file;
const { ast, parserServices, visitorKeys } = parseResult;
debug("Scope analysis:", filePath);
const scopeManager =
parseResult.scopeManager ||
analyzeScope(ast, languageOptions, visitorKeys);
debug("Scope analysis successful:", filePath);
return new SourceCode({
text,
ast,
hasBOM,
parserServices,
scopeManager,
visitorKeys,
});
},
};

View File

@@ -0,0 +1,465 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("@typescript-eslint/utils");
const util_1 = require("../util");
exports.default = (0, util_1.createRule)({
name: 'unified-signatures',
meta: {
type: 'suggestion',
docs: {
description: 'Disallow two overloads that could be unified into one with a union or an optional/rest parameter',
// too opinionated to be recommended
recommended: 'strict',
},
messages: {
omittingRestParameter: '{{failureStringStart}} with a rest parameter.',
omittingSingleParameter: '{{failureStringStart}} with an optional parameter.',
singleParameterDifference: '{{failureStringStart}} taking `{{type1}} | {{type2}}`.',
},
schema: [
{
type: 'object',
additionalProperties: false,
properties: {
ignoreDifferentlyNamedParameters: {
type: 'boolean',
description: 'Whether two parameters with different names at the same index should be considered different even if their types are the same.',
},
ignoreOverloadsWithDifferentJSDoc: {
type: 'boolean',
description: 'Whether two overloads with different JSDoc comments should be considered different even if their parameter and return types are the same.',
},
},
},
],
},
defaultOptions: [
{
ignoreDifferentlyNamedParameters: false,
ignoreOverloadsWithDifferentJSDoc: false,
},
],
create(context, [{ ignoreDifferentlyNamedParameters, ignoreOverloadsWithDifferentJSDoc }]) {
//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------
function failureStringStart(otherLine) {
// For only 2 overloads we don't need to specify which is the other one.
const overloads = otherLine == null
? 'These overloads'
: `This overload and the one on line ${otherLine}`;
return `${overloads} can be combined into one signature`;
}
function addFailures(failures) {
for (const failure of failures) {
const { only2, unify } = failure;
switch (unify.kind) {
case 'single-parameter-difference': {
const { p0, p1 } = unify;
const lineOfOtherOverload = only2 ? undefined : p0.loc.start.line;
const typeAnnotation0 = isTSParameterProperty(p0)
? p0.parameter.typeAnnotation
: p0.typeAnnotation;
const typeAnnotation1 = isTSParameterProperty(p1)
? p1.parameter.typeAnnotation
: p1.typeAnnotation;
context.report({
loc: p1.loc,
node: p1,
messageId: 'singleParameterDifference',
data: {
failureStringStart: failureStringStart(lineOfOtherOverload),
type1: context.sourceCode.getText(typeAnnotation0?.typeAnnotation),
type2: context.sourceCode.getText(typeAnnotation1?.typeAnnotation),
},
});
break;
}
case 'extra-parameter': {
const { extraParameter, otherSignature } = unify;
const lineOfOtherOverload = only2
? undefined
: otherSignature.loc.start.line;
context.report({
loc: extraParameter.loc,
node: extraParameter,
messageId: extraParameter.type === utils_1.AST_NODE_TYPES.RestElement
? 'omittingRestParameter'
: 'omittingSingleParameter',
data: {
failureStringStart: failureStringStart(lineOfOtherOverload),
},
});
}
}
}
}
function checkOverloads(signatures, typeParameters) {
const result = [];
const isTypeParameter = getIsTypeParameter(typeParameters);
for (const overloads of signatures) {
forEachPair(overloads, (a, b) => {
const signature0 = a.value ?? a;
const signature1 = b.value ?? b;
const unify = compareSignatures(signature0, signature1, isTypeParameter);
if (unify != null) {
result.push({ only2: overloads.length === 2, unify });
}
});
}
return result;
}
function compareSignatures(a, b, isTypeParameter) {
if (!signaturesCanBeUnified(a, b, isTypeParameter)) {
return undefined;
}
return a.params.length === b.params.length
? signaturesDifferBySingleParameter(a.params, b.params)
: signaturesDifferByOptionalOrRestParameter(a, b);
}
function signaturesCanBeUnified(a, b, isTypeParameter) {
// Must return the same type.
const aTypeParams = a.typeParameters != null ? a.typeParameters.params : undefined;
const bTypeParams = b.typeParameters != null ? b.typeParameters.params : undefined;
if (ignoreDifferentlyNamedParameters) {
const commonParamsLength = Math.min(a.params.length, b.params.length);
for (let i = 0; i < commonParamsLength; i += 1) {
if (a.params[i].type === b.params[i].type &&
getStaticParameterName(a.params[i]) !==
getStaticParameterName(b.params[i])) {
return false;
}
}
}
if (ignoreOverloadsWithDifferentJSDoc) {
const aComment = getBlockCommentForNode(getCommentTargetNode(a));
const bComment = getBlockCommentForNode(getCommentTargetNode(b));
if (aComment?.value !== bComment?.value) {
return false;
}
}
return (typesAreEqual(a.returnType, b.returnType) &&
// Must take the same type parameters.
// If one uses a type parameter (from outside) and the other doesn't, they shouldn't be joined.
(0, util_1.arraysAreEqual)(aTypeParams, bTypeParams, typeParametersAreEqual) &&
signatureUsesTypeParameter(a, isTypeParameter) ===
signatureUsesTypeParameter(b, isTypeParameter));
}
/** Detect `a(x: number, y: number, z: number)` and `a(x: number, y: string, z: number)`. */
function signaturesDifferBySingleParameter(types1, types2) {
const firstParam1 = types1[0];
const firstParam2 = types2[0];
// exempt signatures with `this: void` from the rule
if (isThisVoidParam(firstParam1) || isThisVoidParam(firstParam2)) {
return undefined;
}
const index = getIndexOfFirstDifference(types1, types2, parametersAreEqual);
if (index == null) {
return undefined;
}
// If remaining arrays are equal, the signatures differ by just one parameter type
if (!(0, util_1.arraysAreEqual)(types1.slice(index + 1), types2.slice(index + 1), parametersAreEqual)) {
return undefined;
}
const a = types1[index];
const b = types2[index];
// Can unify `a?: string` and `b?: number`. Can't unify `...args: string[]` and `...args: number[]`.
// See https://github.com/Microsoft/TypeScript/issues/5077
return parametersHaveEqualSigils(a, b) &&
a.type !== utils_1.AST_NODE_TYPES.RestElement
? { kind: 'single-parameter-difference', p0: a, p1: b }
: undefined;
}
function isThisParam(param) {
return param?.type === utils_1.AST_NODE_TYPES.Identifier && param.name === 'this';
}
function isThisVoidParam(param) {
return (isThisParam(param) &&
param.typeAnnotation?.typeAnnotation.type ===
utils_1.AST_NODE_TYPES.TSVoidKeyword);
}
/**
* Detect `a(): void` and `a(x: number): void`.
* Returns the parameter declaration (`x: number` in this example) that should be optional/rest, and overload it's a part of.
*/
function signaturesDifferByOptionalOrRestParameter(a, b) {
const sig1 = a.params;
const sig2 = b.params;
const minLength = Math.min(sig1.length, sig2.length);
const longer = sig1.length < sig2.length ? sig2 : sig1;
const shorter = sig1.length < sig2.length ? sig1 : sig2;
const shorterSig = sig1.length < sig2.length ? a : b;
const firstParam1 = sig1.at(0);
const firstParam2 = sig2.at(0);
// If one signature has explicit this type and another doesn't, they can't
// be unified.
if (isThisParam(firstParam1) !== isThisParam(firstParam2)) {
return undefined;
}
// exempt signatures with `this: void` from the rule
if (isThisVoidParam(firstParam1) || isThisVoidParam(firstParam2)) {
return undefined;
}
// If one is has 2+ parameters more than the other, they must all be optional/rest.
// Differ by optional parameters: f() and f(x), f() and f(x, ?y, ...z)
// Not allowed: f() and f(x, y)
for (let i = minLength + 1; i < longer.length; i++) {
if (!parameterMayBeMissing(longer[i])) {
return undefined;
}
}
for (let i = 0; i < minLength; i++) {
const sig1i = sig1[i];
const sig2i = sig2[i];
const typeAnnotation1 = isTSParameterProperty(sig1i)
? sig1i.parameter.typeAnnotation
: sig1i.typeAnnotation;
const typeAnnotation2 = isTSParameterProperty(sig2i)
? sig2i.parameter.typeAnnotation
: sig2i.typeAnnotation;
if (!typesAreEqual(typeAnnotation1, typeAnnotation2)) {
return undefined;
}
}
if (minLength > 0 &&
shorter[minLength - 1].type === utils_1.AST_NODE_TYPES.RestElement) {
return undefined;
}
return {
extraParameter: longer[longer.length - 1],
kind: 'extra-parameter',
otherSignature: shorterSig,
};
}
/** Given type parameters, returns a function to test whether a type is one of those parameters. */
function getIsTypeParameter(typeParameters) {
if (typeParameters == null) {
return () => false;
}
const set = new Set();
for (const t of typeParameters.params) {
set.add(t.name.name);
}
return typeName => set.has(typeName);
}
/** True if any of the outer type parameters are used in a signature. */
function signatureUsesTypeParameter(sig, isTypeParameter) {
return sig.params.some((p) => typeContainsTypeParameter(isTSParameterProperty(p)
? p.parameter.typeAnnotation
: p.typeAnnotation));
function typeContainsTypeParameter(type) {
if (!type) {
return false;
}
if (type.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
const typeName = type.typeName;
if (isIdentifier(typeName) && isTypeParameter(typeName.name)) {
return true;
}
}
return typeContainsTypeParameter(type.typeAnnotation ??
type.elementType);
}
}
function isTSParameterProperty(node) {
return node.type === utils_1.AST_NODE_TYPES.TSParameterProperty;
}
function parametersAreEqual(a, b) {
const typeAnnotationA = isTSParameterProperty(a)
? a.parameter.typeAnnotation
: a.typeAnnotation;
const typeAnnotationB = isTSParameterProperty(b)
? b.parameter.typeAnnotation
: b.typeAnnotation;
return (parametersHaveEqualSigils(a, b) &&
typesAreEqual(typeAnnotationA, typeAnnotationB));
}
/** True for optional/rest parameters. */
function parameterMayBeMissing(p) {
const optional = isTSParameterProperty(p)
? p.parameter.optional
: p.optional;
return p.type === utils_1.AST_NODE_TYPES.RestElement || optional;
}
/** False if one is optional and the other isn't, or one is a rest parameter and the other isn't. */
function parametersHaveEqualSigils(a, b) {
const optionalA = isTSParameterProperty(a)
? a.parameter.optional
: a.optional;
const optionalB = isTSParameterProperty(b)
? b.parameter.optional
: b.optional;
return ((a.type === utils_1.AST_NODE_TYPES.RestElement) ===
(b.type === utils_1.AST_NODE_TYPES.RestElement) && optionalA === optionalB);
}
function typeParametersAreEqual(a, b) {
return (a.name.name === b.name.name &&
constraintsAreEqual(a.constraint, b.constraint));
}
function typesAreEqual(a, b) {
return (a === b ||
(a != null &&
b != null &&
context.sourceCode.getText(a.typeAnnotation) ===
context.sourceCode.getText(b.typeAnnotation)));
}
function constraintsAreEqual(a, b) {
return a === b || (a != null && a.type === b?.type);
}
/* Returns the first index where `a` and `b` differ. */
function getIndexOfFirstDifference(a, b, equal) {
for (let i = 0; i < a.length && i < b.length; i++) {
if (!equal(a[i], b[i])) {
return i;
}
}
return undefined;
}
/** Calls `action` for every pair of values in `values`. */
function forEachPair(values, action) {
for (let i = 0; i < values.length; i++) {
for (let j = i + 1; j < values.length; j++) {
action(values[i], values[j]);
}
}
}
const scopes = [];
let currentScope = {
overloads: new Map(),
};
function createScope(parent, typeParameters) {
if (currentScope) {
scopes.push(currentScope);
}
currentScope = {
overloads: new Map(),
parent,
typeParameters,
};
}
function checkScope() {
const scope = (0, util_1.nullThrows)(currentScope, 'checkScope() called without a current scope');
const failures = checkOverloads([...scope.overloads.values()], scope.typeParameters);
addFailures(failures);
currentScope = scopes.pop();
}
/**
* @returns the first valid JSDoc comment annotating `node`
*/
function getBlockCommentForNode(node) {
return context.sourceCode
.getCommentsBefore(node)
.reverse()
.find(comment => comment.type === utils_1.AST_TOKEN_TYPES.Block);
}
function addOverload(signature, key, containingNode) {
key ??= getOverloadKey(signature);
if ((containingNode ?? signature).parent === currentScope?.parent) {
const overloads = currentScope.overloads.get(key);
if (overloads != null) {
overloads.push(signature);
}
else {
currentScope.overloads.set(key, [signature]);
}
}
}
//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
return {
ClassDeclaration(node) {
createScope(node.body, node.typeParameters);
},
Program: createScope,
TSInterfaceDeclaration(node) {
createScope(node.body, node.typeParameters);
},
TSModuleBlock: createScope,
TSTypeLiteral: createScope,
// collect overloads
MethodDefinition(node) {
if (!node.value.body && !isGetterOrSetter(node)) {
addOverload(node);
}
},
TSAbstractMethodDefinition(node) {
if (!node.value.body && !isGetterOrSetter(node)) {
addOverload(node);
}
},
TSCallSignatureDeclaration: addOverload,
TSConstructSignatureDeclaration: addOverload,
TSDeclareFunction(node) {
const exportingNode = getExportingNode(node);
addOverload(node, node.id?.name ?? exportingNode?.type, exportingNode);
},
TSMethodSignature(node) {
if (!isGetterOrSetter(node)) {
addOverload(node);
}
},
// validate scopes
'ClassDeclaration:exit': checkScope,
'Program:exit': checkScope,
'TSInterfaceDeclaration:exit': checkScope,
'TSModuleBlock:exit': checkScope,
'TSTypeLiteral:exit': checkScope,
};
},
});
function getCommentTargetNode(node) {
if (node.type === utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression) {
return node.parent;
}
return getExportingNode(node) ?? node;
}
function getExportingNode(node) {
return node.parent.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration ||
node.parent.type === utils_1.AST_NODE_TYPES.ExportDefaultDeclaration
? node.parent
: undefined;
}
function getOverloadKey(node) {
const info = getOverloadInfo(node);
return ((node.computed ? '0' : '1') +
(node.static ? '0' : '1') +
info);
}
function getOverloadInfo(node) {
switch (node.type) {
case utils_1.AST_NODE_TYPES.TSConstructSignatureDeclaration:
return 'constructor';
case utils_1.AST_NODE_TYPES.TSCallSignatureDeclaration:
return '()';
default: {
const { key } = node;
if (isPrivateIdentifier(key)) {
return `private_identifier_${key.name}`;
}
if (isIdentifier(key)) {
return `identifier_${key.name}`;
}
return key.raw;
}
}
}
function getStaticParameterName(param) {
switch (param.type) {
case utils_1.AST_NODE_TYPES.Identifier:
return param.name;
case utils_1.AST_NODE_TYPES.RestElement:
return getStaticParameterName(param.argument);
default:
return undefined;
}
}
function isIdentifier(node) {
return node.type === utils_1.AST_NODE_TYPES.Identifier;
}
function isPrivateIdentifier(node) {
return node.type === utils_1.AST_NODE_TYPES.PrivateIdentifier;
}
function isGetterOrSetter(node) {
return node.kind === 'get' || node.kind === 'set';
}

View File

@@ -0,0 +1,154 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CloudflareSocket = void 0;
const events_1 = require("events");
/**
* Wrapper around the Cloudflare built-in socket that can be used by the `Connection`.
*/
class CloudflareSocket extends events_1.EventEmitter {
constructor(ssl) {
super();
this.ssl = ssl;
this.writable = false;
this.destroyed = false;
this._upgrading = false;
this._upgraded = false;
this._cfSocket = null;
this._cfWriter = null;
this._cfReader = null;
}
setNoDelay() {
return this;
}
setKeepAlive() {
return this;
}
ref() {
return this;
}
unref() {
return this;
}
async connect(port, host, connectListener) {
try {
log('connecting');
if (connectListener)
this.once('connect', connectListener);
const options = this.ssl ? { secureTransport: 'starttls' } : {};
const mod = await import('cloudflare:sockets');
const connect = mod.connect;
this._cfSocket = connect(`${host}:${port}`, options);
this._cfWriter = this._cfSocket.writable.getWriter();
this._addClosedHandler();
this._cfReader = this._cfSocket.readable.getReader();
if (this.ssl) {
this._listenOnce().catch((e) => this.emit('error', e));
}
else {
this._listen().catch((e) => this.emit('error', e));
}
await this._cfWriter.ready;
log('socket ready');
this.writable = true;
this.emit('connect');
return this;
}
catch (e) {
this.emit('error', e);
}
}
async _listen() {
// eslint-disable-next-line no-constant-condition
while (true) {
log('awaiting receive from CF socket');
const { done, value } = await this._cfReader.read();
log('CF socket received:', done, value);
if (done) {
log('done');
break;
}
this.emit('data', Buffer.from(value));
}
}
async _listenOnce() {
log('awaiting first receive from CF socket');
const { done, value } = await this._cfReader.read();
log('First CF socket received:', done, value);
this.emit('data', Buffer.from(value));
}
write(data, encoding = 'utf8', callback = () => { }) {
if (data.length === 0)
return callback();
if (typeof data === 'string')
data = Buffer.from(data, encoding);
log('sending data direct:', data);
this._cfWriter.write(data).then(() => {
log('data sent');
callback();
}, (err) => {
log('send error', err);
callback(err);
});
return true;
}
end(data = Buffer.alloc(0), encoding = 'utf8', callback = () => { }) {
log('ending CF socket');
this.write(data, encoding, (err) => {
this._cfSocket.close();
if (callback)
callback(err);
});
return this;
}
destroy(reason) {
log('destroying CF socket', reason);
this.destroyed = true;
return this.end();
}
startTls(options) {
if (this._upgraded) {
// Don't try to upgrade again.
this.emit('error', 'Cannot call `startTls()` more than once on a socket');
return;
}
this._cfWriter.releaseLock();
this._cfReader.releaseLock();
this._upgrading = true;
this._cfSocket = this._cfSocket.startTls(options);
this._cfWriter = this._cfSocket.writable.getWriter();
this._cfReader = this._cfSocket.readable.getReader();
this._addClosedHandler();
this._listen().catch((e) => this.emit('error', e));
}
_addClosedHandler() {
this._cfSocket.closed.then(() => {
if (!this._upgrading) {
log('CF socket closed');
this._cfSocket = null;
this.emit('close');
}
else {
this._upgrading = false;
this._upgraded = true;
}
}).catch((e) => this.emit('error', e));
}
}
exports.CloudflareSocket = CloudflareSocket;
const debug = false;
function dump(data) {
if (data instanceof Uint8Array || data instanceof ArrayBuffer) {
// workaround https://github.com/microsoft/TypeScript/issues/63447
const buf = data instanceof Uint8Array ? Buffer.from(data) : Buffer.from(data);
const hex = buf.toString('hex');
const str = new TextDecoder().decode(data);
return `\n>>> STR: "${str.replace(/\n/g, '\\n')}"\n>>> HEX: ${hex}\n`;
}
else {
return data;
}
}
function log(...args) {
debug && console.log(...args.map(dump));
}
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1,12 @@
import type { Definition, ImportBindingDefinition } from '@typescript-eslint/scope-manager';
/**
* Determine whether a variable definition is a type import. e.g.:
*
* ```ts
* import type { Foo } from 'foo';
* import { type Bar } from 'bar';
* ```
*
* @param definition - The variable definition to check.
*/
export declare function isTypeImport(definition?: Definition): definition is ImportBindingDefinition;

View File

@@ -0,0 +1,205 @@
import { OptionsReceived, Plugin } from '@vitest/pretty-format';
import { ParsedStack } from '@vitest/utils';
import { S as SnapshotEnvironment } from './environment.d-DOJxxZV9.js';
interface DomainMatchResult {
pass: boolean;
message?: string;
/**
* The captured value viewed through the template's lens.
*
* Where the template uses patterns (e.g. regexes) or omits details,
* the resolved string adopts those patterns. Where the template doesn't
* match, the resolved string uses literal captured values instead.
*
* Used for two purposes:
* - **Diff display** (actual side): compared against `expected`
* so the diff highlights only genuine mismatches, not pattern-vs-literal noise.
* - **Snapshot update** (`--update`): written as the new snapshot content,
* preserving user-edited patterns from matched regions while incorporating
* actual values for mismatched regions.
*
* When omitted, falls back to `render(capture(received))` (the raw rendered value).
*/
resolved?: string;
/**
* The stored template re-rendered as a string, representing what the user
* originally wrote or last saved.
*
* Used as the expected side in diff display.
*
* When omitted, falls back to the raw snapshot string from the snap file
* or inline snapshot.
*/
expected?: string;
}
interface DomainSnapshotAdapter<
Captured = unknown,
Expected = unknown
> {
name: string;
capture: (received: unknown) => Captured;
render: (captured: Captured) => string;
parseExpected: (input: string) => Expected;
match: (captured: Captured, expected: Expected) => DomainMatchResult;
}
/**
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
declare class DefaultMap<
K,
V
> extends Map<K, V> {
private defaultFn;
constructor(defaultFn: (key: K) => V, entries?: Iterable<readonly [K, V]>);
get(key: K): V;
}
declare class CounterMap<K> extends DefaultMap<K, number> {
constructor();
_total: number | undefined;
valueOf(): number;
increment(key: K): void;
total(): number;
}
interface SnapshotReturnOptions {
actual: string;
count: number;
expected?: string;
key: string;
pass: boolean;
}
interface SaveStatus {
deleted: boolean;
saved: boolean;
}
interface ExpectedSnapshot {
key: string;
count: number;
data?: string;
markAsChecked: () => void;
}
declare class SnapshotState {
testFilePath: string;
snapshotPath: string;
private _counters;
private _dirty;
private _updateSnapshot;
private _snapshotData;
private _initialData;
private _inlineSnapshots;
private _inlineSnapshotStacks;
private _testIdToKeys;
private _rawSnapshots;
private _uncheckedKeys;
private _snapshotFormat;
private _environment;
private _fileExists;
expand: boolean;
private _added;
private _matched;
private _unmatched;
private _updated;
get added(): CounterMap<string>;
set added(value: number);
get matched(): CounterMap<string>;
set matched(value: number);
get unmatched(): CounterMap<string>;
set unmatched(value: number);
get updated(): CounterMap<string>;
set updated(value: number);
private constructor();
static create(testFilePath: string, options: SnapshotStateOptions): Promise<SnapshotState>;
get snapshotUpdateState(): SnapshotUpdateState;
get environment(): SnapshotEnvironment;
markSnapshotsAsCheckedForTest(testName: string): void;
clearTest(testId: string): void;
protected _inferInlineSnapshotStack(stacks: ParsedStack[]): ParsedStack | null;
private _addSnapshot;
private _resolveKey;
private _resolveInlineStack;
private _reconcile;
save(): Promise<SaveStatus>;
getUncheckedCount(): number;
getUncheckedKeys(): Array<string>;
removeUncheckedKeys(): void;
probeExpectedSnapshot(options: Pick<SnapshotMatchOptions, "testName" | "testId" | "isInline" | "inlineSnapshot">): ExpectedSnapshot;
match({ testId, testName, received, key, inlineSnapshot, isInline, error, rawSnapshot, assertionName }: SnapshotMatchOptions): SnapshotReturnOptions;
processDomainSnapshot({ testId, received, expectedSnapshot, matchResult, isInline, error, assertionName }: ProcessDomainSnapshotOptions): SnapshotReturnOptions;
pack(): Promise<SnapshotResult>;
}
type SnapshotData = Record<string, string>;
type SnapshotUpdateState = "all" | "new" | "none";
type SnapshotSerializer = Plugin;
interface SnapshotStateOptions {
updateSnapshot: SnapshotUpdateState;
snapshotEnvironment: SnapshotEnvironment;
expand?: boolean;
snapshotFormat?: OptionsReceived;
resolveSnapshotPath?: (path: string, extension: string, context?: any) => string;
}
interface SnapshotMatchOptions {
testId: string;
testName: string;
received: unknown;
key?: string;
inlineSnapshot?: string;
isInline: boolean;
error?: Error;
rawSnapshot?: RawSnapshotInfo;
assertionName?: string;
}
interface ProcessDomainSnapshotOptions {
testId: string;
received: string;
expectedSnapshot: ExpectedSnapshot;
matchResult?: DomainMatchResult;
isInline?: boolean;
assertionName?: string;
error?: Error;
}
interface SnapshotResult {
filepath: string;
added: number;
fileDeleted: boolean;
matched: number;
unchecked: number;
uncheckedKeys: Array<string>;
unmatched: number;
updated: number;
}
interface UncheckedSnapshot {
filePath: string;
keys: Array<string>;
}
interface SnapshotSummary {
added: number;
didUpdate: boolean;
failure: boolean;
filesAdded: number;
filesRemoved: number;
filesRemovedList: Array<string>;
filesUnmatched: number;
filesUpdated: number;
matched: number;
total: number;
unchecked: number;
uncheckedKeysByFile: Array<UncheckedSnapshot>;
unmatched: number;
updated: number;
}
interface RawSnapshotInfo {
file: string;
readonly?: boolean;
content?: string;
}
export { SnapshotState as S };
export type { DomainSnapshotAdapter as D, RawSnapshotInfo as R, UncheckedSnapshot as U, SnapshotStateOptions as a, SnapshotResult as b, DomainMatchResult as c, SnapshotData as d, SnapshotMatchOptions as e, SnapshotSerializer as f, SnapshotSummary as g, SnapshotUpdateState as h };

View File

@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LINEBREAK_MATCHER = void 0;
exports.isTokenOnSameLine = isTokenOnSameLine;
/**
* A regular expression to match line terminators.
* @see https://tc39.es/ecma262/multipage/ecmascript-language-lexical-grammar.html#prod-LineTerminator
*/
exports.LINEBREAK_MATCHER = /\r\n|[\r\n\u2028\u2029]/;
/**
* Determines whether two adjacent tokens are on the same line
*/
function isTokenOnSameLine(left, right) {
return left.loc.end.line === right.loc.start.line;
}

View File

@@ -0,0 +1,29 @@
import { Awaitable } from '@vitest/utils';
interface EnvironmentReturn {
teardown: (global: any) => Awaitable<void>;
}
interface VmEnvironmentReturn {
getVmContext: () => {
[key: string]: any;
};
teardown: () => Awaitable<void>;
}
interface Environment {
name: string;
/**
* @deprecated use `viteEnvironment` instead. Uses `name` by default
*/
transformMode?: "web" | "ssr";
/**
* Environment initiated by the Vite server. It is usually available
* as `vite.server.environments.${name}`.
*
* By default, fallbacks to `name`.
*/
viteEnvironment?: "client" | "ssr" | ({} & string);
setupVM?: (options: Record<string, any>) => Awaitable<VmEnvironmentReturn>;
setup: (global: any, options: Record<string, any>) => Awaitable<EnvironmentReturn>;
}
export type { Environment as E, VmEnvironmentReturn as V, EnvironmentReturn as a };

View File

@@ -0,0 +1,22 @@
var REACT_ELEMENT_TYPE;
function _createRawReactElement(e, r, E, l) {
REACT_ELEMENT_TYPE || (REACT_ELEMENT_TYPE = "function" == typeof Symbol && Symbol["for"] && Symbol["for"]("react.element") || 60103);
var o = e && e.defaultProps,
n = arguments.length - 3;
if (r || 0 === n || (r = {
children: void 0
}), 1 === n) r.children = l;else if (n > 1) {
for (var t = Array(n), f = 0; f < n; f++) t[f] = arguments[f + 3];
r.children = t;
}
if (r && o) for (var i in o) void 0 === r[i] && (r[i] = o[i]);else r || (r = o || {});
return {
$$typeof: REACT_ELEMENT_TYPE,
type: e,
key: void 0 === E ? null : "" + E,
ref: null,
props: r,
_owner: null
};
}
module.exports = _createRawReactElement, module.exports.__esModule = true, module.exports["default"] = module.exports;

View File

@@ -0,0 +1,419 @@
/**
* @fileoverview Rule to flag declared but unused private class members
* @author Tim van der Lippe
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require("./utils/ast-utils");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
/** @type {import('../types').Rule.RuleModule} */
module.exports = {
meta: {
type: "problem",
hasSuggestions: true,
docs: {
description: "Disallow unused private class members",
recommended: true,
url: "https://eslint.org/docs/latest/rules/no-unused-private-class-members",
},
schema: [],
messages: {
unusedPrivateClassMember:
"'{{classMemberName}}' is defined but never used.",
removeUnusedPrivateClassMember:
"Remove unused private class member '{{classMemberName}}'.",
},
},
create(context) {
const sourceCode = context.sourceCode;
const trackedClasses = [];
/**
* Gets the start index of the line that contains a given token or node.
* @param {ASTNode|Token|Comment} nodeOrToken The token or node to check
* @returns {number} The line start index
*/
function getLineStartIndex(nodeOrToken) {
return nodeOrToken.range[0] - nodeOrToken.loc.start.column;
}
/**
* Checks whether a token or node starts on its own line, preceded only by whitespace.
* @param {ASTNode|Token|Comment} nodeOrToken The token or node to check
* @returns {boolean} Whether the token or node starts on its own line
*/
function startsOnOwnLine(nodeOrToken) {
return (
sourceCode.getTokenBefore(nodeOrToken, {
includeComments: true,
}).loc.end.line !== nodeOrToken.loc.start.line
);
}
/**
* Gets leading comments that are directly attached to a class member.
* @param {ASTNode} classMemberNode The class member node
* @returns {Comment[]} Leading comments to remove with the member
*/
function getLeadingComments(classMemberNode) {
const commentsBefore =
sourceCode.getCommentsBefore(classMemberNode);
const lastNonLeadingCommentIndex = commentsBefore.findLastIndex(
(comment, index, self) => {
const next =
index < self.length - 1
? self[index + 1]
: classMemberNode;
return (
!startsOnOwnLine(comment) ||
next.loc.start.line - comment.loc.end.line > 1
);
},
);
return commentsBefore.slice(lastNonLeadingCommentIndex + 1);
}
/**
* Checks whether a class member shares its line with another token.
* @param {ASTNode} classMemberNode The class member node
* @returns {boolean} Whether the member shares its line with another token
*/
function sharesLineWithAnotherToken(classMemberNode) {
const previousToken = sourceCode.getTokenBefore(classMemberNode);
const nextToken = sourceCode.getTokenAfter(classMemberNode);
return (
previousToken.loc.end.line === classMemberNode.loc.start.line ||
nextToken.loc.start.line === classMemberNode.loc.end.line
);
}
/**
* Gets trailing comments that are directly attached to a class member.
* Same-line trailing comments are preserved when another token shares
* the line, because the comment might describe the remaining code rather
* than the unused member alone.
* @param {ASTNode} classMemberNode The class member node
* @returns {Comment[]} Trailing comments to remove with the member
*/
function getTrailingComments(classMemberNode) {
if (sharesLineWithAnotherToken(classMemberNode)) {
return [];
}
return sourceCode
.getCommentsAfter(classMemberNode)
.filter(
comment =>
comment.loc.start.line === classMemberNode.loc.end.line,
);
}
/**
* Gets the token after which a semicolon should be inserted when removing a class member.
* @param {ASTNode} classMemberNode The member that would be removed
* @returns {Token|null} The token after which a semicolon should be inserted, or null if no semicolon is needed
*/
function getSemicolonInsertionToken(classMemberNode) {
const nextToken = sourceCode.getTokenAfter(classMemberNode);
if (
astUtils.canContinueExpressionInClassBody(nextToken) &&
astUtils.needsPrecedingSemicolon(sourceCode, classMemberNode)
) {
return sourceCode.getTokenBefore(classMemberNode);
}
return null;
}
/**
* Gets the replacement range for removing an unused class member.
* @param {ASTNode} classMemberNode The member that would be removed
* @returns {number[]} The text range to remove
*/
function getMemberRemovalRange(classMemberNode) {
const leadingComments = getLeadingComments(classMemberNode);
const trailingComments = getTrailingComments(classMemberNode);
const shouldRemoveLeadingComments =
leadingComments.length > 0 &&
!sharesLineWithAnotherToken(classMemberNode);
const lastItemToRemove =
trailingComments.length > 0
? trailingComments.at(-1)
: classMemberNode;
const previousToken = sourceCode.getTokenBefore(classMemberNode);
const nextToken = sourceCode.getTokenAfter(lastItemToRemove, {
includeComments: true,
});
const nextTokenStartsOnNewLine =
nextToken.loc.start.line > lastItemToRemove.loc.end.line;
const shouldRemoveOwnLine =
!shouldRemoveLeadingComments &&
startsOnOwnLine(classMemberNode) &&
nextTokenStartsOnNewLine;
let start = classMemberNode.range[0];
let end = lastItemToRemove.range[1];
if (shouldRemoveLeadingComments) {
start = nextTokenStartsOnNewLine
? getLineStartIndex(leadingComments[0])
: leadingComments[0].range[0];
end = nextTokenStartsOnNewLine
? getLineStartIndex(nextToken)
: nextToken.range[0];
} else if (shouldRemoveOwnLine) {
start = getLineStartIndex(classMemberNode);
end = getLineStartIndex(nextToken);
} else if (
previousToken.loc.end.line === classMemberNode.loc.start.line
) {
start = previousToken.range[1];
} else if (
nextToken.loc.start.line === lastItemToRemove.loc.end.line
) {
end = nextToken.range[0];
}
return [start, end];
}
/**
* Check whether the current node is in a write only assignment.
* @param {ASTNode} privateIdentifierNode Node referring to a private identifier
* @returns {boolean} Whether the node is in a write only assignment
* @private
*/
function isWriteOnlyAssignment(privateIdentifierNode) {
const parentStatement = privateIdentifierNode.parent.parent;
const isAssignmentExpression =
parentStatement.type === "AssignmentExpression";
if (
!isAssignmentExpression &&
parentStatement.type !== "ForInStatement" &&
parentStatement.type !== "ForOfStatement" &&
parentStatement.type !== "AssignmentPattern"
) {
return false;
}
// It is a write-only usage, since we still allow usages on the right for reads
if (parentStatement.left !== privateIdentifierNode.parent) {
return false;
}
// For any other operator (such as '+=') we still consider it a read operation
if (isAssignmentExpression && parentStatement.operator !== "=") {
/*
* However, if the read operation is "discarded" in an empty statement, then
* we consider it write only.
*/
return parentStatement.parent.type === "ExpressionStatement";
}
return true;
}
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
return {
// Collect all declared members up front and assume they are all unused
ClassBody(classBodyNode) {
const privateMembers = new Map();
trackedClasses.unshift(privateMembers);
for (const bodyMember of classBodyNode.body) {
if (
bodyMember.type === "PropertyDefinition" ||
bodyMember.type === "MethodDefinition"
) {
if (bodyMember.key.type === "PrivateIdentifier") {
privateMembers.set(bodyMember.key.name, {
declaredNode: bodyMember,
hasReference: false,
isAccessor:
bodyMember.type === "MethodDefinition" &&
(bodyMember.kind === "set" ||
bodyMember.kind === "get"),
});
}
}
}
},
/*
* Process all usages of the private identifier and remove a member from
* `declaredAndUnusedPrivateMembers` if we deem it used.
*/
PrivateIdentifier(privateIdentifierNode) {
const classBody = trackedClasses.find(classProperties =>
classProperties.has(privateIdentifierNode.name),
);
// Can't happen, as it is a parser to have a missing class body, but let's code defensively here.
if (!classBody) {
return;
}
// In case any other usage was already detected, we can short circuit the logic here.
const memberDefinition = classBody.get(
privateIdentifierNode.name,
);
if (memberDefinition.isUsed) {
return;
}
// The definition of the class member itself
if (
privateIdentifierNode.parent.type ===
"PropertyDefinition" ||
privateIdentifierNode.parent.type === "MethodDefinition"
) {
return;
}
memberDefinition.hasReference = true;
/*
* Any usage of an accessor is considered a read, as the getter/setter can have
* side-effects in its definition.
*/
if (memberDefinition.isAccessor) {
memberDefinition.isUsed = true;
return;
}
// Any assignments to this member, except for assignments that also read
if (isWriteOnlyAssignment(privateIdentifierNode)) {
return;
}
const wrappingExpressionType =
privateIdentifierNode.parent.parent.type;
const parentOfWrappingExpressionType =
privateIdentifierNode.parent.parent.parent.type;
// A statement which only increments (`this.#x++;`)
if (
wrappingExpressionType === "UpdateExpression" &&
parentOfWrappingExpressionType === "ExpressionStatement"
) {
return;
}
/*
* ({ x: this.#usedInDestructuring } = bar);
*
* But should treat the following as a read:
* ({ [this.#x]: a } = foo);
*/
if (
wrappingExpressionType === "Property" &&
parentOfWrappingExpressionType === "ObjectPattern" &&
privateIdentifierNode.parent.parent.value ===
privateIdentifierNode.parent
) {
return;
}
// [...this.#unusedInRestPattern] = bar;
if (wrappingExpressionType === "RestElement") {
return;
}
// [this.#unusedInAssignmentPattern] = bar;
if (wrappingExpressionType === "ArrayPattern") {
return;
}
/*
* We can't delete the memberDefinition, as we need to keep track of which member we are marking as used.
* In the case of nested classes, we only mark the first member we encounter as used. If you were to delete
* the member, then any subsequent usage could incorrectly mark the member of an encapsulating parent class
* as used, which is incorrect.
*/
memberDefinition.isUsed = true;
},
/*
* Post-process the class members and report any remaining members.
* Since private members can only be accessed in the current class context,
* we can safely assume that all usages are within the current class body.
*/
"ClassBody:exit"() {
const unusedPrivateMembers = trackedClasses.shift();
for (const [
classMemberName,
{ declaredNode, hasReference, isUsed },
] of unusedPrivateMembers.entries()) {
if (isUsed) {
continue;
}
context.report({
node: declaredNode,
loc: declaredNode.key.loc,
messageId: "unusedPrivateClassMember",
data: {
classMemberName: `#${classMemberName}`,
},
suggest: [
{
messageId: "removeUnusedPrivateClassMember",
data: {
classMemberName: `#${classMemberName}`,
},
*fix(fixer) {
if (hasReference) {
return;
}
const removalRange =
getMemberRemovalRange(declaredNode);
const semicolonInsertionToken =
getSemicolonInsertionToken(
declaredNode,
);
const removalFix = fixer.replaceTextRange(
removalRange,
"",
);
yield removalFix;
if (semicolonInsertionToken) {
yield fixer.insertTextAfter(
semicolonInsertionToken,
";",
);
}
},
},
],
});
}
},
};
},
};

View File

@@ -0,0 +1,39 @@
{
"name": "why-is-node-running",
"version": "2.3.0",
"description": "Node is running but you don't know why? why-is-node-running is here to help you.",
"main": "index.js",
"dependencies": {
"siginfo": "^2.0.0",
"stackback": "0.0.2"
},
"bin": {
"why-is-node-running": "cli.js"
},
"engines": {
"node": ">=8"
},
"repository": {
"type": "git",
"url": "https://github.com/mafintosh/why-is-node-running.git"
},
"keywords": [
"debug",
"devops",
"test",
"events",
"handles"
],
"author": "Mathias Buus (@mafintosh)",
"contributors": [
{
"name": "Jon Peck",
"email": "jpeck@fluxsauce.com"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/mafintosh/why-is-node-running/issues"
},
"homepage": "https://github.com/mafintosh/why-is-node-running"
}

View File

@@ -0,0 +1,4 @@
function _classCheckPrivateStaticFieldDescriptor(t, e) {
if (void 0 === t) throw new TypeError("attempted to " + e + " private static field before its declaration");
}
export { _classCheckPrivateStaticFieldDescriptor as default };

View File

@@ -0,0 +1,6 @@
export var CommentDirectiveType;
(function (CommentDirectiveType) {
CommentDirectiveType[CommentDirectiveType["ExpectError"] = 0] = "ExpectError";
CommentDirectiveType[CommentDirectiveType["Ignore"] = 1] = "Ignore";
})(CommentDirectiveType || (CommentDirectiveType = {}));
//# sourceMappingURL=commentDirectiveType.js.map

View File

@@ -0,0 +1,19 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,147 @@
import * as util from "../core/util.js";
function getArmenianPlural(count, one, many) {
return Math.abs(count) === 1 ? one : many;
}
function withDefiniteArticle(word) {
if (!word)
return "";
const vowels = ["ա", "ե", "ը", "ի", "ո", "ու", "օ"];
const lastChar = word[word.length - 1];
return word + (vowels.includes(lastChar) ? "ն" : "ը");
}
const error = () => {
const Sizable = {
string: {
unit: {
one: "նշան",
many: "նշաններ",
},
verb: "ունենալ",
},
file: {
unit: {
one: "բայթ",
many: "բայթեր",
},
verb: "ունենալ",
},
array: {
unit: {
one: "տարր",
many: "տարրեր",
},
verb: "ունենալ",
},
set: {
unit: {
one: "տարր",
many: "տարրեր",
},
verb: "ունենալ",
},
};
function getSizing(origin) {
return Sizable[origin] ?? null;
}
const FormatDictionary = {
regex: "մուտք",
email: "էլ. հասցե",
url: "URL",
emoji: "էմոջի",
uuid: "UUID",
uuidv4: "UUIDv4",
uuidv6: "UUIDv6",
nanoid: "nanoid",
guid: "GUID",
cuid: "cuid",
cuid2: "cuid2",
ulid: "ULID",
xid: "XID",
ksuid: "KSUID",
datetime: "ISO ամսաթիվ և ժամ",
date: "ISO ամսաթիվ",
time: "ISO ժամ",
duration: "ISO տևողություն",
ipv4: "IPv4 հասցե",
ipv6: "IPv6 հասցե",
cidrv4: "IPv4 միջակայք",
cidrv6: "IPv6 միջակայք",
base64: "base64 ձևաչափով տող",
base64url: "base64url ձևաչափով տող",
json_string: "JSON տող",
e164: "E.164 համար",
jwt: "JWT",
template_literal: "մուտք",
};
const TypeDictionary = {
nan: "NaN",
number: "թիվ",
array: "զանգված",
};
return (issue) => {
switch (issue.code) {
case "invalid_type": {
const expected = TypeDictionary[issue.expected] ?? issue.expected;
const receivedType = util.parsedType(issue.input);
const received = TypeDictionary[receivedType] ?? receivedType;
if (/^[A-Z]/.test(issue.expected)) {
return `Սխալ մուտքագրում․ սպասվում էր instanceof ${issue.expected}, ստացվել է ${received}`;
}
return `Սխալ մուտքագրում․ սպասվում էր ${expected}, ստացվել է ${received}`;
}
case "invalid_value":
if (issue.values.length === 1)
return `Սխալ մուտքագրում․ սպասվում էր ${util.stringifyPrimitive(issue.values[1])}`;
return `Սխալ տարբերակ․ սպասվում էր հետևյալներից մեկը՝ ${util.joinValues(issue.values, "|")}`;
case "too_big": {
const adj = issue.inclusive ? "<=" : "<";
const sizing = getSizing(issue.origin);
if (sizing) {
const maxValue = Number(issue.maximum);
const unit = getArmenianPlural(maxValue, sizing.unit.one, sizing.unit.many);
return `Չափազանց մեծ արժեք․ սպասվում է, որ ${withDefiniteArticle(issue.origin ?? "արժեք")} կունենա ${adj}${issue.maximum.toString()} ${unit}`;
}
return `Չափազանց մեծ արժեք․ սպասվում է, որ ${withDefiniteArticle(issue.origin ?? "արժեք")} լինի ${adj}${issue.maximum.toString()}`;
}
case "too_small": {
const adj = issue.inclusive ? ">=" : ">";
const sizing = getSizing(issue.origin);
if (sizing) {
const minValue = Number(issue.minimum);
const unit = getArmenianPlural(minValue, sizing.unit.one, sizing.unit.many);
return `Չափազանց փոքր արժեք․ սպասվում է, որ ${withDefiniteArticle(issue.origin)} կունենա ${adj}${issue.minimum.toString()} ${unit}`;
}
return `Չափազանց փոքր արժեք․ սպասվում է, որ ${withDefiniteArticle(issue.origin)} լինի ${adj}${issue.minimum.toString()}`;
}
case "invalid_format": {
const _issue = issue;
if (_issue.format === "starts_with")
return `Սխալ տող․ պետք է սկսվի "${_issue.prefix}"-ով`;
if (_issue.format === "ends_with")
return `Սխալ տող․ պետք է ավարտվի "${_issue.suffix}"-ով`;
if (_issue.format === "includes")
return `Սխալ տող․ պետք է պարունակի "${_issue.includes}"`;
if (_issue.format === "regex")
return `Սխալ տող․ պետք է համապատասխանի ${_issue.pattern} ձևաչափին`;
return `Սխալ ${FormatDictionary[_issue.format] ?? issue.format}`;
}
case "not_multiple_of":
return `Սխալ թիվ․ պետք է բազմապատիկ լինի ${issue.divisor}-ի`;
case "unrecognized_keys":
return `Չճանաչված բանալի${issue.keys.length > 1 ? "ներ" : ""}. ${util.joinValues(issue.keys, ", ")}`;
case "invalid_key":
return `Սխալ բանալի ${withDefiniteArticle(issue.origin)}-ում`;
case "invalid_union":
return "Սխալ մուտքագրում";
case "invalid_element":
return `Սխալ արժեք ${withDefiniteArticle(issue.origin)}-ում`;
default:
return `Սխալ մուտքագրում`;
}
};
};
export default function () {
return {
localeError: error(),
};
}

View File

@@ -0,0 +1,13 @@
Copyright © 2017, Charmander <~@charmander.me>
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.

View File

@@ -0,0 +1,2 @@
import type { LibDefinition } from '../variable';
export declare const es2024: LibDefinition;