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"