diff --git a/.eslintrc.js b/.eslintrc.js
index e131f7cb8f2f..7d9386a11ea0 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -301,6 +301,7 @@ module.exports = {
{
files: ['rollup.config.ts'],
rules: {
+ // rollup config must be default exported
'import/no-default-export': 'off',
},
},
@@ -311,5 +312,42 @@ module.exports = {
'no-console': 'off',
},
},
+ {
+ files: ['*.{js,jsx}'],
+ rules: {
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ },
+ },
+ // CLI lint configs
+ {
+ files: [
+ 'packages/cli/bin/**/*.{ts,js}',
+ 'packages/cli/src/reporters/Reporter.ts',
+ ],
+ rules: {
+ 'no-console': 'off',
+ },
+ },
+ {
+ files: ['packages/cli/bin/**/*.js'],
+ rules: {
+ '@typescript-eslint/no-unsafe-assignment': 'off',
+ '@typescript-eslint/ban-ts-comment': 'off',
+ },
+ },
+ {
+ files: ['packages/cli/**/*.{ts,tsx,js}'],
+ rules: {
+ '@typescript-eslint/consistent-type-imports': [
+ 'error',
+ { prefer: 'type-imports', disallowTypeAnnotations: true },
+ ],
+ '@typescript-eslint/consistent-type-exports': 'error',
+ 'import/first': 'error',
+ 'import/newline-after-import': 'error',
+ 'import/no-duplicates': 'error',
+ 'simple-import-sort/imports': 'error',
+ },
+ },
],
};
diff --git a/package.json b/package.json
index d2df363bc502..083629d0f555 100644
--- a/package.json
+++ b/package.json
@@ -37,8 +37,8 @@
"lint-fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"lint-markdown-fix": "yarn lint-markdown --fix",
"lint-markdown": "markdownlint \"**/*.md\" --config=.markdownlint.json --ignore-path=.markdownlintignore",
- "lint": "cross-env NODE_OPTIONS=\"--max-old-space-size=16384\" eslint . --ext .js,.jsx,.ts,.tsx",
- "postinstall": "yarn husky install && yarn build",
+ "lint": "ts-eslint -p ./tsconfig.eslint.json -p \"packages/*/tsconfig.json\"",
+ "postinstall": "yarn patch-package && yarn husky install && yarn build",
"pre-commit": "yarn lint-staged",
"pre-push": "yarn check-format",
"start": "nx run website:start",
@@ -75,10 +75,12 @@
"@types/marked": "^3.0.2",
"@types/ncp": "^2.0.5",
"@types/node": "^16.11.4",
+ "@types/node-fetch": "^3.0.3",
"@types/prettier": "^2.4.2",
"@types/rimraf": "^3.0.2",
"@types/semver": "^7.3.9",
"@types/tmp": "^0.2.2",
+ "@types/yargs": "^17.0.8",
"all-contributors-cli": "^6.20.0",
"cross-env": "^7.0.3",
"cspell": "^5.12.3",
@@ -101,6 +103,7 @@
"markdownlint-cli": "^0.29.0",
"ncp": "^2.0.0",
"node-fetch": "^3.0.0",
+ "patch-package": "^6.4.7",
"prettier": "^2.5.0",
"pretty-format": "^27.3.1",
"rimraf": "^3.0.2",
diff --git a/packages/cli/LICENSE b/packages/cli/LICENSE
new file mode 100644
index 000000000000..7e7370143b26
--- /dev/null
+++ b/packages/cli/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 TypeScript ESLint and other contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/cli/README.md b/packages/cli/README.md
new file mode 100644
index 000000000000..505fa3225b3b
--- /dev/null
+++ b/packages/cli/README.md
@@ -0,0 +1,15 @@
+
typescript-eslint CLI
+
+
+
+
+
+
+
+CLI for coordinating lint runs that use typescript-eslint.
+
+TODO: docs on CLI args
+
+## Contributing
+
+[See the contributing guide here](../../CONTRIBUTING.md)
diff --git a/packages/cli/bin/ts-eslint.js b/packages/cli/bin/ts-eslint.js
new file mode 100755
index 000000000000..9b643b460a1c
--- /dev/null
+++ b/packages/cli/bin/ts-eslint.js
@@ -0,0 +1,76 @@
+#!/usr/bin/env node
+
+// @ts-check
+
+if (process.env.USE_TS_ESLINT_SRC == null) {
+ // to use V8's code cache to speed up instantiation time
+ require('v8-compile-cache');
+}
+
+/**
+ * @param {unknown} thing
+ * @returns {thing is Record}
+ */
+function isObject(thing) {
+ return typeof thing === 'object' && thing != null;
+}
+
+/**
+ * Get the error message of a given value.
+ * @param {unknown} error The value to get.
+ * @returns {string} The error message.
+ */
+function getErrorMessage(error) {
+ // Lazy loading because this is used only if an error happened.
+ const util = require('util');
+
+ if (!isObject(error)) {
+ return String(error);
+ }
+
+ // Use the stacktrace if it's an error object.
+ if (typeof error.stack === 'string') {
+ return error.stack;
+ }
+
+ // Otherwise, dump the object.
+ return util.format('%o', error);
+}
+
+/**
+ * Catch and report unexpected error.
+ * @param {unknown} error The thrown error object.
+ * @returns {void}
+ */
+function onFatalError(error) {
+ process.exitCode = 2;
+ const message = getErrorMessage(error);
+ console.error(`
+An unhandled exception occurred!
+${message}`);
+}
+
+(async function main() {
+ process.on('uncaughtException', onFatalError);
+ process.on('unhandledRejection', onFatalError);
+
+ /** @type {import('../src/index')} */
+ const cli = (() => {
+ if (process.env.USE_TS_ESLINT_SRC == null) {
+ // using an ignore because after a build a ts-expect-error will no longer error because TS will follow the
+ // build maps to the source files...
+ // @ts-ignore - have to reference the built file, not the src file
+ return require('../dist/index');
+ }
+
+ // ensure ts-node is registered correctly
+ // eslint-disable-next-line import/no-extraneous-dependencies
+ require('ts-node').register({
+ transpileOnly: true,
+ project: require('path').resolve(__dirname, '..', 'tsconfig.json'),
+ });
+ return require('../src/index');
+ })();
+
+ await cli.execute();
+})().catch(onFatalError);
diff --git a/packages/cli/jest.config.js b/packages/cli/jest.config.js
new file mode 100644
index 000000000000..c23ca67fbc68
--- /dev/null
+++ b/packages/cli/jest.config.js
@@ -0,0 +1,20 @@
+'use strict';
+
+// @ts-check
+/** @type {import('@jest/types').Config.InitialOptions} */
+module.exports = {
+ globals: {
+ 'ts-jest': {
+ isolatedModules: true,
+ },
+ },
+ testEnvironment: 'node',
+ transform: {
+ ['^.+\\.tsx?$']: 'ts-jest',
+ },
+ testRegex: ['./tests/.+\\.test\\.ts$'],
+ collectCoverage: false,
+ collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}'],
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
+ coverageReporters: ['text-summary', 'lcov'],
+};
diff --git a/packages/cli/package.json b/packages/cli/package.json
new file mode 100644
index 000000000000..2dfb77e67250
--- /dev/null
+++ b/packages/cli/package.json
@@ -0,0 +1,77 @@
+{
+ "name": "@typescript-eslint/cli",
+ "version": "5.9.0",
+ "description": "TypeScript-ESLint CLI",
+ "keywords": [
+ "eslint",
+ "typescript",
+ "estree",
+ "cli"
+ ],
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "files": [
+ "dist",
+ "package.json",
+ "README.md",
+ "LICENSE"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/typescript-eslint/typescript-eslint.git",
+ "directory": "packages/cli"
+ },
+ "bugs": {
+ "url": "https://github.com/typescript-eslint/typescript-eslint/issues"
+ },
+ "license": "MIT",
+ "main": "dist/index.js",
+ "bin": {
+ "ts-eslint": "./bin/ts-eslint.js"
+ },
+ "types": "dist/index.d.ts",
+ "scripts": {
+ "build": "tsc -b tsconfig.build.json",
+ "postbuild": "downlevel-dts dist _ts3.4/dist",
+ "clean": "tsc -b tsconfig.build.json --clean",
+ "postclean": "rimraf dist && rimraf _ts3.4 && rimraf coverage",
+ "format": "prettier --write \"./**/*.{ts,js,json,md}\" --ignore-path ../../.prettierignore",
+ "lint": "eslint . --ext .js,.ts --ignore-path='../../.eslintignore'",
+ "typecheck": "tsc -p tsconfig.json --noEmit",
+ "ts-eslint": "USE_TS_ESLINT_SRC=1 ts-node --transpile-only ./bin/ts-eslint.js"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "typesVersions": {
+ "<3.8": {
+ "*": [
+ "_ts3.4/*"
+ ]
+ }
+ },
+ "dependencies": {
+ "@typescript-eslint/experimental-utils": "5.9.0",
+ "debug": "^4.3.2",
+ "globby": "^11.0.4",
+ "ink": "^3.2.0",
+ "ink-use-stdout-dimensions": "^1.0.5",
+ "is-glob": "^4.0.3",
+ "jest-worker": "^27.4.5",
+ "react": "^17.0.2",
+ "semver": "^7.3.5",
+ "v8-compile-cache": "^2.3.0",
+ "yargs": "^17.3.1"
+ },
+ "peerDependencies": {
+ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0",
+ "typescript": "*"
+ },
+ "devDependencies": {
+ "@types/is-glob": "*",
+ "@types/semver": "*",
+ "@types/yargs": "*"
+ }
+}
diff --git a/packages/cli/project.json b/packages/cli/project.json
new file mode 100644
index 000000000000..4b2535e26f5b
--- /dev/null
+++ b/packages/cli/project.json
@@ -0,0 +1,5 @@
+{
+ "root": "packages/cli",
+ "type": "library",
+ "implicitDependencies": []
+}
diff --git a/packages/cli/src/FileEnumerator.ts b/packages/cli/src/FileEnumerator.ts
new file mode 100644
index 000000000000..46be3f7e62ba
--- /dev/null
+++ b/packages/cli/src/FileEnumerator.ts
@@ -0,0 +1,31 @@
+import { version } from 'eslint/package.json';
+import * as semver from 'semver';
+
+const isESLintV8 = semver.major(version) >= 8;
+
+declare class _FileEnumerator {
+ constructor(options?: {
+ readonly cwd?: string;
+ readonly extensions?: string | null;
+ readonly globInputPaths?: boolean;
+ readonly errorOnUnmatchedPattern?: boolean;
+ readonly ignore?: boolean;
+ });
+
+ iterateFiles(
+ patternOrPatterns: string | readonly string[],
+ ): IterableIterator<{
+ readonly filePath: string;
+ readonly config: unknown;
+ readonly ignored: boolean;
+ }>;
+}
+
+const FileEnumerator = (
+ isESLintV8
+ ? // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
+ require('eslint/use-at-your-own-risk').FileEnumerator
+ : require('eslint/lib/cli-engine/file-enumerator')
+) as typeof _FileEnumerator;
+
+export { FileEnumerator };
diff --git a/packages/cli/src/commands/Command.ts b/packages/cli/src/commands/Command.ts
new file mode 100644
index 000000000000..a05b466031a9
--- /dev/null
+++ b/packages/cli/src/commands/Command.ts
@@ -0,0 +1,54 @@
+import type { ArgumentsCamelCase, CommandBuilder, CommandModule } from 'yargs';
+
+import type { Reporter } from '../reporters/Reporter';
+
+// eslint-disable-next-line @typescript-eslint/ban-types
+export interface Command
+ extends CommandModule<
+ TRawOpts & GlobalOptions,
+ TProcessedOpts & GlobalOptions
+ > {
+ /** object declaring the options the command accepts, or a function accepting and returning a yargs instance */
+ builder: CommandBuilder<
+ TRawOpts & GlobalOptions,
+ TProcessedOpts & GlobalOptions
+ >;
+ /** string used as the description for the command in help text, use `false` for a hidden command */
+ describe: string;
+ /** a function which will be passed the parsed argv. */
+ handler: (
+ args: ArgumentsCamelCase,
+ ) => Promise;
+}
+
+export interface CommandNoOpts extends CommandModule {
+ /** string (or array of strings) that executes this command when given on the command line, first string may contain positional args */
+ command: ReadonlyArray | string;
+ /** string used as the description for the command in help text, use `false` for a hidden command */
+ describe: string;
+ /** a function which will be passed the parsed argv. */
+ handler: () => void | Promise;
+}
+
+export enum ReporterConfig {
+ ink = 'ink',
+ plain = 'plain',
+}
+
+// numbering is important as each level includes the prior levels
+// eg level >= LogLevel.error should include both info and debug
+export enum LogLevel {
+ error = 0,
+ info = 1,
+ debug = 2,
+}
+
+export interface GlobalOptionsRaw {
+ logLevel: keyof typeof LogLevel;
+ reporter: ReporterConfig;
+}
+
+export interface GlobalOptions {
+ logLevel: LogLevel;
+ reporter: Reporter;
+}
diff --git a/packages/cli/src/commands/env.ts b/packages/cli/src/commands/env.ts
new file mode 100644
index 000000000000..8c4ae4655aae
--- /dev/null
+++ b/packages/cli/src/commands/env.ts
@@ -0,0 +1,66 @@
+/* eslint-disable no-console -- no need to use a reporter for this command as it's intended to dump straight to console */
+
+import Module from 'module';
+
+import type { CommandNoOpts } from './Command';
+
+const packagesToResolve = [
+ '@typescript-eslint/cli',
+ '@typescript-eslint/eslint-plugin',
+ '@typescript-eslint/experimental-utils',
+ '@typescript-eslint/parser',
+ '@typescript-eslint/scope-manager',
+ '@typescript-eslint/typescript-estree',
+ 'typescript',
+];
+
+const command: CommandNoOpts = {
+ aliases: ['environment', 'env-info', 'support-info'],
+ command: 'env',
+ describe:
+ 'Prints information about your environment to provide when reporting an issue.',
+ handler: () => {
+ const nodeVersion = process.version.replace(/^v/, '');
+ const versions: Record = {
+ node: nodeVersion,
+ };
+
+ const require = Module.createRequire(process.cwd());
+
+ let maxPackageLength = 0;
+ let maxVersionLength = Math.max(nodeVersion.length, 'version'.length);
+ for (const pkg of packagesToResolve) {
+ const packageJson = require(`${pkg}/package.json`) as { version: string };
+ versions[pkg] = packageJson.version;
+
+ maxPackageLength = Math.max(maxPackageLength, pkg.length);
+ maxVersionLength = Math.max(maxVersionLength, packageJson.version.length);
+ }
+
+ console.log(
+ '|',
+ 'package'.padEnd(maxPackageLength, ' '),
+ '|',
+ 'version'.padEnd(maxVersionLength, ' '),
+ '|',
+ );
+ console.log(
+ '|',
+ '-'.padEnd(maxPackageLength, '-'),
+ '|',
+ '-'.padEnd(maxVersionLength, '-'),
+ '|',
+ );
+ for (const [pkg, version] of Object.entries(versions)) {
+ console.log(
+ '|',
+ pkg.padEnd(maxPackageLength, ' '),
+ '|',
+ version.padEnd(maxVersionLength, ' '),
+ '|',
+ );
+ }
+ },
+};
+
+export { command };
diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts
new file mode 100644
index 000000000000..4aec7a66da90
--- /dev/null
+++ b/packages/cli/src/commands/lint.ts
@@ -0,0 +1,77 @@
+import { sync as globSync } from 'globby';
+import isGlob from 'is-glob';
+
+import type { AbsolutePath } from '../path';
+import { getAbsolutePath } from '../path';
+import { lintProjects } from '../workers/lintProjects';
+import type { Command } from './Command';
+
+export interface OptionsRaw {
+ cwd: string;
+ project: readonly string[];
+}
+export interface Options {
+ cwd: AbsolutePath;
+ project: readonly string[];
+}
+
+const command: Command = {
+ builder: yargs => {
+ return yargs.options({
+ project: {
+ alias: ['p', 'projects'],
+ array: true,
+ demandOption: 'Must pass at least one project.',
+ describe:
+ 'Path to a tsconfig, relative to the CWD. Can also specify a glob pattern - ensure you wrap in quotes to prevent CLI expansion of the glob.',
+ normalize: true,
+ requiresArg: true,
+ type: 'string',
+ },
+ cwd: {
+ coerce: (cwd: OptionsRaw['cwd']) => getAbsolutePath(cwd),
+ default: process.cwd(),
+ describe:
+ 'The path to the current working directory to use for the run.',
+ type: 'string',
+ },
+ });
+ },
+ command: 'lint',
+ describe: 'Lint your project.',
+ handler: async args => {
+ const projects = new Set();
+ const globProjects: string[] = [];
+ for (const project of args.project) {
+ if (isGlob(project)) {
+ globProjects.push(project);
+ } else {
+ projects.add(getAbsolutePath(project, args.cwd));
+ }
+ }
+ for (const globProject of globSync(
+ ['!**/node_modules/**', ...globProjects],
+ { cwd: args.cwd },
+ )) {
+ projects.add(getAbsolutePath(globProject, args.cwd));
+ }
+
+ args.reporter.debug('found the following projects', Array.from(projects));
+ args.reporter.log('Linting', projects.size, 'projects');
+
+ const lintReturnState = await lintProjects(
+ {
+ cwd: args.cwd,
+ logLevel: args.logLevel,
+ projects: Array.from(projects),
+ },
+ args.reporter,
+ );
+
+ args.reporter.debug('linting finished');
+
+ process.exitCode = lintReturnState;
+ },
+};
+
+export { command };
diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts
new file mode 100644
index 000000000000..862b4d02faff
--- /dev/null
+++ b/packages/cli/src/index.ts
@@ -0,0 +1,75 @@
+import path from 'path';
+import type { CommandModule } from 'yargs';
+import * as yargs from 'yargs';
+
+import type { GlobalOptions, GlobalOptionsRaw } from './commands/Command';
+import { LogLevel, ReporterConfig } from './commands/Command';
+import * as lintCommand from './commands/lint';
+import { InkReporter } from './reporters/InkReporter';
+import { PlainReporter } from './reporters/PlainReporter';
+
+function prepareReporter(argvRaw: GlobalOptionsRaw): void {
+ /* yargs and dynamic js - the middleware overwrites the options object
+ @ts-expect-error */
+ const argvResult = argvRaw as GlobalOptions;
+
+ const logLevel = LogLevel[argvRaw.logLevel];
+ argvResult.logLevel = logLevel;
+
+ switch (argvRaw.reporter) {
+ default:
+ case ReporterConfig.ink:
+ argvResult.reporter = new InkReporter(logLevel);
+ return;
+
+ case ReporterConfig.plain:
+ argvResult.reporter = new PlainReporter(logLevel);
+ return;
+ }
+}
+
+async function execute(): Promise {
+ // @ts-expect-error - yargs and dynamic js
+ const argv: GlobalOptions = await yargs
+ .usage('Usage: $0 -p ./tsconfig.json')
+ .scriptName('ts-eslint')
+ .strict(true)
+ .commandDir(path.resolve(__dirname, 'commands'), {
+ extensions: ['js', 'ts'],
+ exclude: /\.d\.ts$/,
+ visit: (mod: { readonly command: CommandModule }) => {
+ return mod.command;
+ },
+ })
+ // specify the `lint` command as the default command
+ .command('$0', false, lintCommand.command as CommandModule)
+ // global options
+ .options({
+ logLevel: {
+ describe: 'Control the log level',
+ default: 'error' as const,
+ enum: Object.keys(LogLevel) as (keyof typeof LogLevel)[],
+ global: true,
+ type: 'string',
+ },
+ reporter: {
+ describe: 'Control how the console output is rendered',
+ default: process.env.CI ? ReporterConfig.plain : ReporterConfig.ink,
+ enum: Object.values(ReporterConfig) as ReporterConfig[],
+ global: true,
+ type: 'string',
+ },
+ })
+ .middleware(prepareReporter)
+ .help()
+ .wrap(yargs.terminalWidth()).argv;
+
+ argv.reporter.cleanup();
+}
+
+if (require.main === module) {
+ // for easy testing - execute directly if we are the main node script
+ void execute();
+}
+
+export { execute };
diff --git a/packages/cli/src/path.ts b/packages/cli/src/path.ts
new file mode 100644
index 000000000000..6fbe44ad3cd3
--- /dev/null
+++ b/packages/cli/src/path.ts
@@ -0,0 +1,15 @@
+import path from 'path';
+
+type AbsolutePath = string & { __AbsolutePathBrand: unknown };
+function getAbsolutePath(
+ p: string,
+ base: string = process.cwd(),
+): AbsolutePath {
+ if (path.isAbsolute(p)) {
+ return p as AbsolutePath;
+ }
+ return path.resolve(base, p) as AbsolutePath;
+}
+
+export type { AbsolutePath };
+export { getAbsolutePath };
diff --git a/packages/cli/src/reporters/InkReporter/Divider.tsx b/packages/cli/src/reporters/InkReporter/Divider.tsx
new file mode 100644
index 000000000000..25787633673e
--- /dev/null
+++ b/packages/cli/src/reporters/InkReporter/Divider.tsx
@@ -0,0 +1,18 @@
+import * as ink from 'ink';
+import React from 'react';
+
+interface Props {
+ readonly stdoutWidth: number;
+}
+const Divider = React.memo(({ stdoutWidth }: Props): JSX.Element => {
+ const bar = ''.padEnd(stdoutWidth, '-');
+
+ return (
+
+ {bar}
+
+ );
+});
+
+export type { Props as DividerProps };
+export { Divider };
diff --git a/packages/cli/src/reporters/InkReporter/InkCLUI.tsx b/packages/cli/src/reporters/InkReporter/InkCLUI.tsx
new file mode 100644
index 000000000000..1db17b8779f3
--- /dev/null
+++ b/packages/cli/src/reporters/InkReporter/InkCLUI.tsx
@@ -0,0 +1,95 @@
+import * as ink from 'ink';
+import useStdoutDimensions from 'ink-use-stdout-dimensions';
+import React, { useMemo } from 'react';
+
+import type { LogLevel } from '../../commands/Command';
+import { Divider } from './Divider';
+import type { Progress } from './ProgressBar';
+import { ProgressBar } from './ProgressBar';
+
+function sortEntriesByKey(obj: Record): [string, T][] {
+ return Object.entries(obj).sort(([a], [b]) => (a < b ? -1 : 1));
+}
+
+interface Props {
+ hideProgress?: boolean;
+ logLevel: LogLevel;
+ lintResult: { [id: string]: string };
+ logLines: { type: 'log' | 'debug' | 'error'; line: string }[];
+ progress: {
+ [id: string]: Progress;
+ };
+}
+
+function InkCLUI(props: Readonly): JSX.Element {
+ const [stdoutWidth] = useStdoutDimensions();
+ const lintResult = useMemo(
+ () => sortEntriesByKey(props.lintResult),
+ [props.lintResult],
+ );
+ const progress = useMemo(
+ () => sortEntriesByKey(props.progress),
+ [props.progress],
+ );
+ return (
+
+
+ {(line, idx): JSX.Element => (
+
+ {
+ switch (line.type) {
+ case 'debug':
+ return {
+ color: 'gray',
+ };
+
+ case 'error':
+ return {
+ color: 'red',
+ };
+
+ case 'log':
+ return {
+ color: 'white',
+ };
+ }
+ })()}
+ >
+ {line.line}
+
+
+ )}
+
+
+ {lintResult.length > 0 && (
+
+ {lintResult.map(([id, result]) => (
+
+ {id}
+ {result}
+
+ ))}
+
+ )}
+
+ {props.hideProgress !== true && (
+ <>
+
+
+
+ {progress.map(([id, progress]) => (
+
+ {id}
+
+
+ ))}
+
+ >
+ )}
+
+ );
+}
+
+export type { Props as InkCLUIProps };
+export { InkCLUI };
diff --git a/packages/cli/src/reporters/InkReporter/ProgressBar.tsx b/packages/cli/src/reporters/InkReporter/ProgressBar.tsx
new file mode 100644
index 000000000000..6b85b899a396
--- /dev/null
+++ b/packages/cli/src/reporters/InkReporter/ProgressBar.tsx
@@ -0,0 +1,36 @@
+import * as ink from 'ink';
+import React, { useMemo } from 'react';
+
+interface Progress {
+ readonly current: number;
+ readonly max: number;
+}
+interface Props extends Progress {
+ readonly stdoutWidth: number;
+}
+const ProgressBar = React.memo(
+ ({ current, max, stdoutWidth }: Props): JSX.Element => {
+ const progress = current / max;
+ const text = `[${current}/${max} (${(progress * 100).toFixed(1)}%)]`;
+ // calculate the "max length" of the text so the progress bar remains a constant width
+ const textMaxLength = useMemo(
+ () => `[${max}/${max} (100.0%)]`.length,
+ [max],
+ );
+ const bar = ''.padEnd(
+ Math.round(progress * stdoutWidth) - textMaxLength,
+ '█',
+ );
+
+ return (
+
+ {bar}
+
+ {text}
+
+ );
+ },
+);
+
+export type { Progress, Props as ProgressBarProps };
+export { ProgressBar };
diff --git a/packages/cli/src/reporters/InkReporter/index.tsx b/packages/cli/src/reporters/InkReporter/index.tsx
new file mode 100644
index 000000000000..6bf4c3b1caeb
--- /dev/null
+++ b/packages/cli/src/reporters/InkReporter/index.tsx
@@ -0,0 +1,120 @@
+import { TSESLint } from '@typescript-eslint/experimental-utils';
+import * as ink from 'ink';
+import React from 'react';
+
+import { LogLevel } from '../../commands/Command';
+import { throttle } from '../../throttle';
+import type { Reporter } from '../Reporter';
+import { ReporterBase } from '../Reporter';
+import type { InkCLUIProps } from './InkCLUI';
+import { InkCLUI } from './InkCLUI';
+
+class InkReporter extends ReporterBase implements Reporter {
+ #state: InkCLUIProps = {
+ logLevel: LogLevel.error,
+ logLines: [],
+ progress: {},
+ lintResult: {},
+ };
+
+ readonly #inkInstance: ink.Instance;
+
+ constructor(logLevel: LogLevel) {
+ super(logLevel);
+ this.#state.logLevel = logLevel;
+
+ this.#inkInstance = ink.render(Initializing...);
+ }
+
+ #prepareLog(
+ type: InkCLUIProps['logLines'][number]['type'],
+ args: readonly unknown[],
+ ): InkCLUIProps['logLines'][number][] {
+ return args
+ .map(arg => {
+ if (typeof arg === 'object') {
+ return JSON.stringify(arg, null, 2);
+ }
+ return String(arg);
+ })
+ .join(' ')
+ .split('\n')
+ .map(line => ({
+ type,
+ line,
+ }));
+ }
+
+ log(...args: readonly unknown[]): void {
+ if (!this.isLogLevel(LogLevel.info)) {
+ return;
+ }
+ this.#state.logLines = this.#state.logLines.concat(
+ this.#prepareLog('log', args),
+ );
+ this.#render();
+ }
+
+ error(...args: readonly unknown[]): void {
+ if (!this.isLogLevel(LogLevel.error)) {
+ return;
+ }
+ this.#state.logLines = this.#state.logLines.concat(
+ this.#prepareLog('error', args),
+ );
+ this.#render();
+ }
+
+ debug(...args: readonly unknown[]): void {
+ if (!this.isLogLevel(LogLevel.debug)) {
+ return;
+ }
+ this.#state.logLines = this.#state.logLines.concat(
+ this.#prepareLog('debug', args),
+ );
+ this.#render();
+ }
+
+ updateProgress(id: string, current: number, max: number): void {
+ this.#state.progress = {
+ ...this.#state.progress,
+ [id]: { current, max },
+ };
+ this.#render();
+ }
+
+ async logLintResult(
+ id: string,
+ results: TSESLint.ESLint.LintResult[],
+ ): Promise {
+ const eslint = new TSESLint.ESLint();
+ const formatter = await eslint.loadFormatter();
+ const result = formatter.format(results);
+ this.#state.lintResult = {
+ ...this.#state.lintResult,
+ [id]: result === '' ? '\n\u2714 No Lint Reports\n' : result,
+ };
+ this.#render();
+ }
+
+ #render = throttle(
+ (): void => {
+ this.#inkInstance.rerender();
+ },
+ // at most 30 times a second
+ 1000 / 30,
+ );
+
+ cleanup(): void {
+ // ensure no more throttled renders occur
+ this.#render.cleanup();
+
+ // do one final render without the progress bar before cleaning up ink
+ this.#inkInstance.rerender(
+ ,
+ );
+ this.#inkInstance.cleanup();
+ }
+}
+
+export { InkReporter };
diff --git a/packages/cli/src/reporters/PlainReporter.ts b/packages/cli/src/reporters/PlainReporter.ts
new file mode 100644
index 000000000000..b6231b5a7949
--- /dev/null
+++ b/packages/cli/src/reporters/PlainReporter.ts
@@ -0,0 +1,50 @@
+import { TSESLint } from '@typescript-eslint/experimental-utils';
+
+import { LogLevel } from '../commands/Command';
+import type { Reporter } from './Reporter';
+import { ReporterBase } from './Reporter';
+
+class PlainReporter extends ReporterBase implements Reporter {
+ log(...args: readonly unknown[]): void {
+ if (!this.isLogLevel(LogLevel.info)) {
+ return;
+ }
+ this.console.log(...args);
+ }
+
+ error(...args: readonly unknown[]): void {
+ if (!this.isLogLevel(LogLevel.error)) {
+ return;
+ }
+ this.console.error(...args);
+ }
+
+ debug(...args: readonly unknown[]): void {
+ if (!this.isLogLevel(LogLevel.debug)) {
+ return;
+ }
+ this.console.log(...args);
+ }
+
+ updateProgress(): void {
+ // plain reporter intentionally hides progress reports
+ }
+
+ async logLintResult(
+ _id: string,
+ results: TSESLint.ESLint.LintResult[],
+ ): Promise {
+ const eslint = new TSESLint.ESLint();
+ const formatter = await eslint.loadFormatter();
+ const result = formatter.format(results);
+ if (result !== '') {
+ this.log();
+ }
+ }
+
+ cleanup(): void {
+ // nothing to cleanup
+ }
+}
+
+export { PlainReporter };
diff --git a/packages/cli/src/reporters/Reporter.ts b/packages/cli/src/reporters/Reporter.ts
new file mode 100644
index 000000000000..73992ff64919
--- /dev/null
+++ b/packages/cli/src/reporters/Reporter.ts
@@ -0,0 +1,59 @@
+import type { TSESLint } from '@typescript-eslint/experimental-utils';
+
+import type { LogLevel } from '../commands/Command';
+
+interface ReporterLogs {
+ log(...args: readonly unknown[]): void;
+ error(...args: readonly unknown[]): void;
+ debug(...args: readonly unknown[]): void;
+}
+
+interface Reporter extends ReporterLogs {
+ // called when a worker updates its status
+ updateProgress(id: string, current: number, max: number): void;
+ // called when lint results are ready
+ logLintResult(
+ id: string,
+ results: TSESLint.ESLint.LintResult[],
+ ): Promise;
+ // called at the end of the program
+ cleanup(): void;
+}
+
+type OldConsole = Readonly;
+const oldConsole: OldConsole = {
+ ...console,
+};
+
+abstract class ReporterBase implements ReporterLogs {
+ protected readonly console: OldConsole = oldConsole;
+ protected readonly logLevel: LogLevel;
+
+ constructor(logLevel: LogLevel) {
+ this.logLevel = logLevel;
+
+ console.log = (...args): void => {
+ this.log(...args);
+ };
+ console.info = (...args): void => {
+ this.log(...args);
+ };
+ console.warn = (...args): void => {
+ this.log('[WARN]', ...args);
+ };
+ console.error = (...args): void => {
+ this.error(...args);
+ };
+ }
+
+ abstract log(...args: readonly unknown[]): void;
+ abstract error(...args: readonly unknown[]): void;
+ abstract debug(...args: readonly unknown[]): void;
+
+ protected isLogLevel(level: LogLevel): boolean {
+ return this.logLevel >= level;
+ }
+}
+
+export type { Reporter, ReporterLogs };
+export { ReporterBase };
diff --git a/packages/cli/src/reporters/WorkerReporter.ts b/packages/cli/src/reporters/WorkerReporter.ts
new file mode 100644
index 000000000000..c9680b09b904
--- /dev/null
+++ b/packages/cli/src/reporters/WorkerReporter.ts
@@ -0,0 +1,135 @@
+/**
+ * This reporter is used by workers to ensure they log in a consistent, parsable format that can be sent
+ * across the thread boundary.
+ */
+
+import { LogLevel } from '../commands/Command';
+import type { ThrottledFunction } from '../throttle';
+import { throttle } from '../throttle';
+import type { Reporter } from './Reporter';
+import { ReporterBase } from './Reporter';
+
+interface WorkerMessageBase {
+ readonly id: string;
+}
+
+interface WorkerMessageLog extends WorkerMessageBase {
+ readonly type: 'log';
+ readonly messages: readonly unknown[];
+}
+interface WorkerMessageDebug extends WorkerMessageBase {
+ readonly type: 'debug';
+ readonly messages: readonly unknown[];
+}
+interface WorkerMessageUpdateProgress extends WorkerMessageBase {
+ readonly type: 'update-progress';
+ readonly current: number;
+ readonly max: number;
+}
+interface WorkerMessageError extends WorkerMessageBase {
+ readonly type: 'error';
+ readonly error: {
+ readonly message: string;
+ readonly stack: string;
+ };
+}
+type WorkerMessage =
+ | WorkerMessageLog
+ | WorkerMessageDebug
+ | WorkerMessageUpdateProgress
+ | WorkerMessageError;
+
+class WorkerReporter extends ReporterBase {
+ readonly #id: string;
+
+ constructor(id: string, logLevel: LogLevel) {
+ super(logLevel);
+ this.#id = id;
+ }
+
+ static handleMessage(raw: Buffer, reporter: Reporter): void {
+ const messages = raw.toString('utf8').trim();
+ for (const rawMessage of messages.split('\n')) {
+ try {
+ const message = JSON.parse(rawMessage) as WorkerMessage;
+ switch (message.type) {
+ case 'log':
+ reporter.log(`[${message.id}]`, ...message.messages);
+ break;
+
+ case 'debug':
+ reporter.debug(`[${message.id}]`, ...message.messages);
+ break;
+
+ case 'error':
+ reporter.error(`[${message.id}]`, message.error);
+ break;
+
+ case 'update-progress':
+ reporter.updateProgress(message.id, message.current, message.max);
+ break;
+ }
+ } catch (ex) {
+ reporter.error(rawMessage, '\n', ex);
+ }
+ }
+ }
+
+ log(...args: readonly unknown[]): void {
+ if (!this.isLogLevel(LogLevel.info)) {
+ return;
+ }
+
+ const message: WorkerMessageLog = {
+ id: this.#id,
+ type: 'log',
+ messages: args,
+ };
+ this.console.log(JSON.stringify(message));
+ }
+
+ error(error: Error): void {
+ if (!this.isLogLevel(LogLevel.error)) {
+ return;
+ }
+
+ const message: WorkerMessageError = {
+ id: this.#id,
+ type: 'error',
+ error: {
+ message: error.message,
+ stack: error.stack!,
+ },
+ };
+ this.console.log(JSON.stringify(message));
+ }
+
+ debug(...args: readonly unknown[]): void {
+ if (!this.isLogLevel(LogLevel.debug)) {
+ return;
+ }
+
+ const message: WorkerMessageDebug = {
+ id: this.#id,
+ type: 'debug',
+ messages: args,
+ };
+ this.console.log(JSON.stringify(message));
+ }
+
+ // throttle so that we don't overflow the log buffer if the main thread can't keep up
+ updateProgress: ThrottledFunction<[number, number]> = throttle(
+ (current: number, max: number): void => {
+ const message: WorkerMessageUpdateProgress = {
+ id: this.#id,
+ type: 'update-progress',
+ current,
+ max,
+ };
+ this.console.log(JSON.stringify(message));
+ },
+ 0,
+ );
+}
+
+export { WorkerReporter };
diff --git a/packages/cli/src/throttle.ts b/packages/cli/src/throttle.ts
new file mode 100644
index 000000000000..5f7c50086d4b
--- /dev/null
+++ b/packages/cli/src/throttle.ts
@@ -0,0 +1,49 @@
+interface ThrottledFunction {
+ (...args: T): void;
+ cleanup: () => void;
+ flush: () => void;
+ immediate: (...args: T) => void;
+}
+
+function throttle(
+ fn: (...args: T) => void,
+ waitMs: number,
+): ThrottledFunction {
+ let timeout: NodeJS.Timeout | null = null;
+ let lastArgs: T;
+ const retVal = ((...args) => {
+ lastArgs = args;
+
+ if (timeout) {
+ return;
+ }
+
+ timeout = setTimeout(() => {
+ timeout = null;
+
+ fn(...lastArgs);
+ }, waitMs);
+ }) as ThrottledFunction;
+
+ retVal.cleanup = (): void => {
+ if (timeout) {
+ clearTimeout(timeout);
+ timeout = null;
+ }
+ };
+ retVal.immediate = (...args): void => {
+ retVal.cleanup();
+ fn(...args);
+ };
+ retVal.flush = (): void => {
+ if (timeout) {
+ fn(...lastArgs);
+ }
+ retVal.cleanup;
+ };
+
+ return retVal;
+}
+
+export type { ThrottledFunction };
+export { throttle };
diff --git a/packages/cli/src/workers/lintProjects/index.ts b/packages/cli/src/workers/lintProjects/index.ts
new file mode 100644
index 000000000000..ec6bcff14e40
--- /dev/null
+++ b/packages/cli/src/workers/lintProjects/index.ts
@@ -0,0 +1,96 @@
+import { Worker as JestWorker } from 'jest-worker';
+import path from 'path';
+
+import type { LogLevel } from '../../commands/Command';
+import type { AbsolutePath } from '../../path';
+import type { Reporter } from '../../reporters/Reporter';
+import { WorkerReporter } from '../../reporters/WorkerReporter';
+import type * as lintProjectWorker from './lintProjectWorker';
+
+// the value is also reported as the exit code
+const enum LintReturnState {
+ Success = 0,
+ Warning = 1,
+ Error = 2,
+ Fatal = 3,
+}
+
+async function lintProjects(
+ {
+ cwd,
+ logLevel,
+ projects,
+ }: {
+ readonly cwd: string;
+ readonly logLevel: LogLevel;
+ readonly projects: readonly AbsolutePath[];
+ },
+ reporter: Reporter,
+): Promise {
+ const worker = new JestWorker(require.resolve('./lintProjectWorker'), {
+ enableWorkerThreads: false,
+ forkOptions:
+ process.env.USE_TS_ESLINT_SRC == null
+ ? {}
+ : { execArgv: ['-r', 'ts-node/register/transpile-only'] },
+ exposedMethods: ['processProject'],
+ maxRetries: 0,
+ numWorkers: projects.length,
+ }) as JestWorker & {
+ processProject: typeof lintProjectWorker.processProject;
+ };
+
+ worker.getStdout().on('data', (data: Buffer) => {
+ WorkerReporter.handleMessage(data, reporter);
+ });
+ worker.getStderr().on('data', (data: Buffer) => {
+ reporter.error(data.toString('utf8'));
+ });
+
+ const promises: Promise[] = [];
+ for (const project of projects) {
+ promises.push(
+ (async (): Promise => {
+ try {
+ const id = path.relative(cwd, project);
+ const results = await worker.processProject({
+ cwd,
+ id,
+ logLevel,
+ project,
+ });
+ await reporter.logLintResult(id, results);
+
+ if (results.find(r => r.messages.find(m => m.fatal === true))) {
+ return LintReturnState.Fatal;
+ }
+ if (results.find(r => r.errorCount > 0)) {
+ return LintReturnState.Error;
+ }
+ // TODO - implement "max-warnings" option from ESLint
+ if (results.find(r => r.warningCount > 0)) {
+ return LintReturnState.Warning;
+ }
+ return LintReturnState.Success;
+ } catch (ex: unknown) {
+ reporter.error(
+ `An error occurred when linting project ${project}:`,
+ (ex as object).toString(),
+ );
+ return LintReturnState.Fatal;
+ }
+ })(),
+ );
+ }
+
+ let maxReturnState = LintReturnState.Success;
+ for (const report of await Promise.all(promises)) {
+ maxReturnState = Math.max(report, maxReturnState);
+ }
+ // as per jest-worker docs - intentionally not awaiting the end
+ void worker.end();
+
+ return maxReturnState;
+}
+
+export { lintProjects };
diff --git a/packages/cli/src/workers/lintProjects/lintProjectWorker.ts b/packages/cli/src/workers/lintProjects/lintProjectWorker.ts
new file mode 100644
index 000000000000..fc73e3be86cc
--- /dev/null
+++ b/packages/cli/src/workers/lintProjects/lintProjectWorker.ts
@@ -0,0 +1,113 @@
+import { TSESLint } from '@typescript-eslint/experimental-utils';
+import debugLogger from 'debug';
+import * as ts from 'typescript';
+
+import type { LogLevel } from '../../commands/Command';
+import { FileEnumerator } from '../../FileEnumerator';
+import type { AbsolutePath } from '../../path';
+import { getAbsolutePath } from '../../path';
+import { WorkerReporter } from '../../reporters/WorkerReporter';
+
+async function processProject({
+ cwd,
+ id,
+ logLevel,
+ project,
+}: {
+ cwd: string;
+ id: string;
+ logLevel: LogLevel;
+ project: AbsolutePath;
+}): Promise {
+ const reporter = new WorkerReporter(id, logLevel);
+ // ensure the debug package logs to our debug channel
+ debugLogger.log = reporter.debug.bind(reporter);
+
+ const tsconfig = ts.getParsedCommandLineOfConfigFile(
+ project,
+ {},
+ {
+ fileExists: ts.sys.fileExists,
+ getCurrentDirectory: ts.sys.getCurrentDirectory,
+ readDirectory: ts.sys.readDirectory,
+ readFile: ts.sys.readFile,
+ useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
+ onUnRecoverableConfigFileDiagnostic: diagnostic => {
+ throw new Error(
+ ts.flattenDiagnosticMessageText(
+ diagnostic.messageText,
+ ts.sys.newLine,
+ ),
+ );
+ },
+ },
+ );
+
+ if (tsconfig == null) {
+ throw new Error(`Unable to parse the project "${project}"`);
+ }
+
+ reporter.debug(tsconfig.fileNames.length, 'files included in the tsconfig');
+
+ // TODO - handling for --fix
+
+ // force single-run inference
+ process.env.TSESTREE_SINGLE_RUN = 'true';
+ const eslint = new TSESLint.ESLint({
+ cwd,
+ overrideConfig: {
+ parserOptions: {
+ allowAutomaticSingleRunInference: true,
+ project: [project],
+ EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
+ },
+ },
+ });
+
+ let count = 0;
+ reporter.updateProgress.immediate(0, tsconfig.fileNames.length);
+
+ const absFilenames = tsconfig.fileNames.map(f => getAbsolutePath(f));
+ const enumerator = new FileEnumerator({
+ cwd,
+ });
+
+ const results: Promise[] = [];
+ for (const { filePath, ignored } of enumerator.iterateFiles(absFilenames)) {
+ if (ignored) {
+ reporter.updateProgress(++count, tsconfig.fileNames.length);
+ continue;
+ }
+ results.push(
+ (async (): Promise => {
+ try {
+ const result = await eslint.lintFiles(filePath);
+ reporter.updateProgress(++count, tsconfig.fileNames.length);
+ return result;
+ } catch (ex: unknown) {
+ // eslint will sometimes report exceptions with the current AST node
+ // if that happens it'll crash the IPC because the AST contains circular references
+ if (isObject(ex) && isObject(ex.currentNode)) {
+ const { parent: _, ...currentNode } = ex.currentNode;
+ ex.currentNode = currentNode;
+ throw ex;
+ }
+
+ throw ex;
+ }
+ })(),
+ );
+ }
+ const flattenedResults = (await Promise.all(results)).flat();
+
+ // ensure the updates are fully flushed
+ reporter.updateProgress.flush();
+
+ return flattenedResults;
+}
+
+function isObject(thing: unknown): thing is Record {
+ return typeof thing === 'object' && thing != null;
+}
+
+export { processProject };
diff --git a/packages/cli/tsconfig.build.json b/packages/cli/tsconfig.build.json
new file mode 100644
index 000000000000..cce9185120a9
--- /dev/null
+++ b/packages/cli/tsconfig.build.json
@@ -0,0 +1,12 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "composite": true,
+ "outDir": "./dist",
+ "jsx": "react",
+ "rootDir": "./src",
+ "resolveJsonModule": true
+ },
+ "include": ["src", "typings"],
+ "references": [{ "path": "../experimental-utils/tsconfig.build.json" }]
+}
diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json
new file mode 100644
index 000000000000..f564a295a18d
--- /dev/null
+++ b/packages/cli/tsconfig.json
@@ -0,0 +1,11 @@
+{
+ "extends": "./tsconfig.build.json",
+ "compilerOptions": {
+ "composite": false,
+ "checkJs": true,
+ "jsx": "react",
+ "rootDir": "."
+ },
+ "include": ["src", "bin", "typings", "tests", "tools"],
+ "references": [{ "path": "../experimental-utils/tsconfig.build.json" }]
+}
diff --git a/packages/cli/typings/v8-compile-cache.d.ts b/packages/cli/typings/v8-compile-cache.d.ts
new file mode 100644
index 000000000000..ae4f4ea1b3dc
--- /dev/null
+++ b/packages/cli/typings/v8-compile-cache.d.ts
@@ -0,0 +1,3 @@
+declare module 'v8-compile-cache' {
+ export {};
+}
diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json
index 874aae4be62e..d0cc2a07627b 100644
--- a/packages/eslint-plugin/package.json
+++ b/packages/eslint-plugin/package.json
@@ -58,6 +58,7 @@
"@types/debug": "*",
"@types/marked": "*",
"@types/prettier": "*",
+ "@types/semver": "*",
"chalk": "^4.1.2",
"marked": "^3.0.7",
"prettier": "*",
diff --git a/packages/experimental-utils/src/ts-eslint/Linter.ts b/packages/experimental-utils/src/ts-eslint/Linter.ts
index 77c338f5a753..8ac49e466448 100644
--- a/packages/experimental-utils/src/ts-eslint/Linter.ts
+++ b/packages/experimental-utils/src/ts-eslint/Linter.ts
@@ -176,7 +176,7 @@ namespace Linter {
export interface ConfigOverride extends BaseConfig {
excludedFiles?: string | string[];
- files: string | string[];
+ files?: string | string[];
}
export interface Config extends BaseConfig {
diff --git a/packages/types/src/parser-options.ts b/packages/types/src/parser-options.ts
index 18ecbee7943f..72c132dbbf2e 100644
--- a/packages/types/src/parser-options.ts
+++ b/packages/types/src/parser-options.ts
@@ -38,6 +38,7 @@ interface ParserOptions {
lib?: Lib[];
// typescript-estree specific
+ allowAutomaticSingleRunInference?: boolean;
comment?: boolean;
debugLevel?: DebugLevel;
errorOnTypeScriptSyntacticAndSemanticIssues?: boolean;
diff --git a/packages/typescript-estree/tsconfig.json b/packages/typescript-estree/tsconfig.json
index bc1141dd051a..e2e1b75ba330 100644
--- a/packages/typescript-estree/tsconfig.json
+++ b/packages/typescript-estree/tsconfig.json
@@ -4,7 +4,7 @@
"composite": false,
"rootDir": "."
},
- "include": ["src", "typings", "tests", "tools"],
+ "include": ["bin", "src", "typings", "tests", "tools"],
"exclude": ["tests/fixtures/**/*"],
"references": [
{ "path": "../types/tsconfig.build.json" },
diff --git a/patches/@types+yargs+17.0.8.patch b/patches/@types+yargs+17.0.8.patch
new file mode 100644
index 000000000000..4f52788ff63a
--- /dev/null
+++ b/patches/@types+yargs+17.0.8.patch
@@ -0,0 +1,13 @@
+diff --git a/node_modules/@types/yargs/index.d.ts b/node_modules/@types/yargs/index.d.ts
+index 842b4a4..9c9eef4 100755
+--- a/node_modules/@types/yargs/index.d.ts
++++ b/node_modules/@types/yargs/index.d.ts
+@@ -846,7 +846,7 @@ declare namespace yargs {
+
+ // prettier-ignore
+ type InferredOptionTypeInner =
+- O extends { default: any, coerce: (arg: any) => infer T } ? T :
++ O extends { coerce: (arg: any) => infer T } ? T :
+ O extends { default: infer D } ? D :
+ O extends { type: "count" } ? number :
+ O extends { count: true } ? number :
diff --git a/workspace.json b/workspace.json
index 6fbf76fb0786..e88c9d227970 100644
--- a/workspace.json
+++ b/workspace.json
@@ -2,6 +2,7 @@
"version": 2,
"projects": {
"@typescript-eslint/ast-spec": "packages/ast-spec",
+ "@typescript-eslint/cli": "packages/cli",
"@typescript-eslint/eslint-plugin": "packages/eslint-plugin",
"@typescript-eslint/eslint-plugin-internal": "packages/eslint-plugin-internal",
"@typescript-eslint/eslint-plugin-tslint": "packages/eslint-plugin-tslint",
diff --git a/yarn.lock b/yarn.lock
index 3c305e231a21..b54344d0487b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3751,6 +3751,13 @@
dependencies:
"@types/node" "*"
+"@types/node-fetch@^3.0.3":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-3.0.3.tgz#9d969c9a748e841554a40ee435d26e53fa3ee899"
+ integrity sha512-HhggYPH5N+AQe/OmN6fmhKmRRt2XuNJow+R3pQwJxOOF9GuwM7O2mheyGeIrs5MOIeNjDEdgdoyHBOrFeJBR3g==
+ dependencies:
+ node-fetch "*"
+
"@types/node@*", "@types/node@12.20.24", "@types/node@^16.11.4":
version "16.11.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.4.tgz#90771124822d6663814f7c1c9b45a6654d8fd964"
@@ -3873,6 +3880,13 @@
resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129"
integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==
+"@types/yargs@*", "@types/yargs@^17.0.8":
+ version "17.0.8"
+ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.8.tgz#d23a3476fd3da8a0ea44b5494ca7fa677b9dad4c"
+ integrity sha512-wDeUwiUmem9FzsyysEwRukaEdDNcwbROvQ9QGRKaLI6t+IltNzbn4/i4asmB10auvZGQCzSQ6t0GSczEThlUXw==
+ dependencies:
+ "@types/yargs-parser" "*"
+
"@types/yargs@^16.0.0":
version "16.0.4"
resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977"
@@ -3880,6 +3894,11 @@
dependencies:
"@types/yargs-parser" "*"
+"@types/yoga-layout@1.9.2":
+ version "1.9.2"
+ resolved "https://registry.yarnpkg.com/@types/yoga-layout/-/yoga-layout-1.9.2.tgz#efaf9e991a7390dc081a0b679185979a83a9639a"
+ integrity sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==
+
"@webassemblyjs/ast@1.11.1":
version "1.11.1"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.1.tgz#2bfd767eae1a6996f432ff7e8d7fc75679c0b6a7"
@@ -4011,6 +4030,11 @@
resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+"@yarnpkg/lockfile@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
+ integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
+
JSONStream@^1.0.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
@@ -4458,6 +4482,11 @@ at-least-node@^1.0.0:
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
+auto-bind@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb"
+ integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==
+
autoprefixer@^10.3.5, autoprefixer@^10.3.7:
version "10.4.0"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.0.tgz#c3577eb32a1079a440ec253e404eaf1eb21388c8"
@@ -5067,7 +5096,7 @@ clear-module@^4.1.1:
parent-module "^2.0.0"
resolve-from "^5.0.0"
-cli-boxes@^2.2.1:
+cli-boxes@^2.2.0, cli-boxes@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
@@ -5168,6 +5197,13 @@ co@^4.6.0:
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
+code-excerpt@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/code-excerpt/-/code-excerpt-3.0.0.tgz#fcfb6748c03dba8431c19f5474747fad3f250f10"
+ integrity sha512-VHNTVhd7KsLGOqfX3SyeO8RyYPMp1GJOg194VITk04WMYCv4plV68YWe6TJZxd9MhobjtpMRnVky01gqZsalaw==
+ dependencies:
+ convert-to-spaces "^1.0.1"
+
code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
@@ -5506,6 +5542,11 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
dependencies:
safe-buffer "~5.1.1"
+convert-to-spaces@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/convert-to-spaces/-/convert-to-spaces-1.0.2.tgz#7e3e48bbe6d997b1417ddca2868204b4d3d85715"
+ integrity sha1-fj5Iu+bZl7FBfdyihoIEtNPYVxU=
+
cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
@@ -7222,6 +7263,13 @@ find-up@^5.0.0:
locate-path "^6.0.0"
path-exists "^4.0.0"
+find-yarn-workspace-root@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd"
+ integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==
+ dependencies:
+ micromatch "^4.0.2"
+
findup-sync@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-4.0.0.tgz#956c9cdde804052b881b428512905c4a5f2cdef0"
@@ -7345,6 +7393,15 @@ fs-extra@^10.0.0:
jsonfile "^6.0.1"
universalify "^2.0.0"
+fs-extra@^7.0.1, fs-extra@~7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
+ integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
fs-extra@^9.0.0, fs-extra@^9.1.0:
version "9.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
@@ -7355,15 +7412,6 @@ fs-extra@^9.0.0, fs-extra@^9.1.0:
jsonfile "^6.0.1"
universalify "^2.0.0"
-fs-extra@~7.0.1:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
- integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
- dependencies:
- graceful-fs "^4.1.2"
- jsonfile "^4.0.0"
- universalify "^0.1.0"
-
fs-minipass@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7"
@@ -8277,6 +8325,40 @@ init-package-json@^2.0.2:
validate-npm-package-license "^3.0.4"
validate-npm-package-name "^3.0.0"
+ink-use-stdout-dimensions@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/ink-use-stdout-dimensions/-/ink-use-stdout-dimensions-1.0.5.tgz#7739876c00284840601c4150aa84eb7adc143de2"
+ integrity sha512-rVsqnw4tQEAJUoknU09+zHdDf30GJdkumkHr0iz/TOYMYEZJkYqziQSGJAM+Z+M603EDfO89+Nxyn/Ko2Zknfw==
+
+ink@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/ink/-/ink-3.2.0.tgz#434793630dc57d611c8fe8fffa1db6b56f1a16bb"
+ integrity sha512-firNp1q3xxTzoItj/eOOSZQnYSlyrWks5llCTVX37nJ59K3eXbQ8PtzCguqo8YI19EELo5QxaKnJd4VxzhU8tg==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ auto-bind "4.0.0"
+ chalk "^4.1.0"
+ cli-boxes "^2.2.0"
+ cli-cursor "^3.1.0"
+ cli-truncate "^2.1.0"
+ code-excerpt "^3.0.0"
+ indent-string "^4.0.0"
+ is-ci "^2.0.0"
+ lodash "^4.17.20"
+ patch-console "^1.0.0"
+ react-devtools-core "^4.19.1"
+ react-reconciler "^0.26.2"
+ scheduler "^0.20.2"
+ signal-exit "^3.0.2"
+ slice-ansi "^3.0.0"
+ stack-utils "^2.0.2"
+ string-width "^4.2.2"
+ type-fest "^0.12.0"
+ widest-line "^3.1.0"
+ wrap-ansi "^6.2.0"
+ ws "^7.5.5"
+ yoga-layout-prebuilt "^1.9.6"
+
inline-style-parser@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
@@ -9471,6 +9553,13 @@ kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+klaw-sync@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c"
+ integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==
+ dependencies:
+ graceful-fs "^4.1.11"
+
kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
@@ -10454,6 +10543,15 @@ node-emoji@^1.10.0:
dependencies:
lodash "^4.17.21"
+node-fetch@*, node-fetch@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.1.0.tgz#714f4922dc270239487654eaeeab86b8206cb52e"
+ integrity sha512-QU0WbIfMUjd5+MUzQOYhenAazakV7Irh1SGkWCsRzBwvm4fAhzEUaHMJ6QLP7gWT6WO9/oH2zhKMMGMuIrDyKw==
+ dependencies:
+ data-uri-to-buffer "^4.0.0"
+ fetch-blob "^3.1.2"
+ formdata-polyfill "^4.0.10"
+
node-fetch@2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
@@ -10466,15 +10564,6 @@ node-fetch@^2.6.0, node-fetch@^2.6.1:
dependencies:
whatwg-url "^5.0.0"
-node-fetch@^3.0.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-3.1.0.tgz#714f4922dc270239487654eaeeab86b8206cb52e"
- integrity sha512-QU0WbIfMUjd5+MUzQOYhenAazakV7Irh1SGkWCsRzBwvm4fAhzEUaHMJ6QLP7gWT6WO9/oH2zhKMMGMuIrDyKw==
- dependencies:
- data-uri-to-buffer "^4.0.0"
- fetch-blob "^3.1.2"
- formdata-polyfill "^4.0.10"
-
node-forge@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
@@ -11199,6 +11288,30 @@ pascal-case@^3.1.2:
no-case "^3.0.4"
tslib "^2.0.3"
+patch-console@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/patch-console/-/patch-console-1.0.0.tgz#19b9f028713feb8a3c023702a8cc8cb9f7466f9d"
+ integrity sha512-nxl9nrnLQmh64iTzMfyylSlRozL7kAXIaxw1fVcLYdyhNkJCRUzirRZTikXGJsg+hc4fqpneTK6iU2H1Q8THSA==
+
+patch-package@^6.4.7:
+ version "6.4.7"
+ resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.4.7.tgz#2282d53c397909a0d9ef92dae3fdeb558382b148"
+ integrity sha512-S0vh/ZEafZ17hbhgqdnpunKDfzHQibQizx9g8yEf5dcVk3KOflOfdufRXQX8CSEkyOQwuM/bNz1GwKvFj54kaQ==
+ dependencies:
+ "@yarnpkg/lockfile" "^1.1.0"
+ chalk "^2.4.2"
+ cross-spawn "^6.0.5"
+ find-yarn-workspace-root "^2.0.0"
+ fs-extra "^7.0.1"
+ is-ci "^2.0.0"
+ klaw-sync "^6.0.0"
+ minimist "^1.2.0"
+ open "^7.4.2"
+ rimraf "^2.6.3"
+ semver "^5.6.0"
+ slash "^2.0.0"
+ tmp "^0.0.33"
+
path-exists@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
@@ -11942,6 +12055,14 @@ react-dev-utils@12.0.0-next.47:
strip-ansi "^6.0.0"
text-table "^0.2.0"
+react-devtools-core@^4.19.1:
+ version "4.22.1"
+ resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.22.1.tgz#b276d42f860bedc373c9b3c0f5f96734318dd453"
+ integrity sha512-pvpNDHE7p0FtcCmIWGazoY8LLVfBI9sw0Kf10kdHhPI9Tzt3OG/qEt16GrAbE0keuna5WzX3r1qPKVjqOqsuUg==
+ dependencies:
+ shell-quote "^1.6.1"
+ ws "^7"
+
react-dom@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
@@ -12008,6 +12129,15 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1:
dependencies:
"@babel/runtime" "^7.10.3"
+react-reconciler@^0.26.2:
+ version "0.26.2"
+ resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.26.2.tgz#bbad0e2d1309423f76cf3c3309ac6c96e05e9d91"
+ integrity sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==
+ dependencies:
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+ scheduler "^0.20.2"
+
react-router-config@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-5.1.1.tgz#0f4263d1a80c6b2dc7b9c1902c9526478194a988"
@@ -12955,6 +13085,11 @@ sisteransi@^1.0.5:
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
+slash@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
+ integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
+
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@@ -13193,7 +13328,7 @@ stable@^0.1.8:
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
-stack-utils@^2.0.3:
+stack-utils@^2.0.2, stack-utils@^2.0.3:
version "2.0.5"
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5"
integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==
@@ -13893,6 +14028,11 @@ type-detect@4.0.8:
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+type-fest@^0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.12.0.tgz#f57a27ab81c68d136a51fd71467eff94157fa1ee"
+ integrity sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==
+
type-fest@^0.18.0:
version "0.18.1"
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
@@ -14255,7 +14395,7 @@ uuid@^3.3.2, uuid@^3.4.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
-v8-compile-cache@2.3.0, v8-compile-cache@^2.0.3:
+v8-compile-cache@2.3.0, v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
@@ -14719,6 +14859,11 @@ write-pkg@^4.0.0:
type-fest "^0.4.1"
write-json-file "^3.2.0"
+ws@^7, ws@^7.5.5:
+ version "7.5.6"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b"
+ integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==
+
ws@^7.3.1, ws@^7.4.6:
version "7.5.5"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881"
@@ -14804,6 +14949,11 @@ yargs-parser@^18.1.2:
camelcase "^5.0.0"
decamelize "^1.2.0"
+yargs-parser@^21.0.0:
+ version "21.0.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55"
+ integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==
+
yargs@15.4.1, yargs@^15.0.1:
version "15.4.1"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
@@ -14847,6 +14997,19 @@ yargs@^17.0.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"
+yargs@^17.3.1:
+ version "17.3.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9"
+ integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA==
+ dependencies:
+ cliui "^7.0.2"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.0.0"
+
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
@@ -14857,6 +15020,13 @@ yocto-queue@^0.1.0:
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+yoga-layout-prebuilt@^1.9.6:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/yoga-layout-prebuilt/-/yoga-layout-prebuilt-1.10.0.tgz#2936fbaf4b3628ee0b3e3b1df44936d6c146faa6"
+ integrity sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g==
+ dependencies:
+ "@types/yoga-layout" "1.9.2"
+
z-schema@~5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-5.0.2.tgz#f410394b2c9fcb9edaf6a7511491c0bb4e89a504"
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy