Compare commits

..

21 Commits

Author SHA1 Message Date
179cf83891 Inline repo 2024-04-19 21:42:48 -04:00
fb50ede688 Update 2024-04-17 00:43:45 -04:00
51455e3c21 Update 2024-04-16 22:29:31 -04:00
1d955d951d Bump ver 2024-04-06 19:15:05 -04:00
8ba9b0725a Update 2024-04-06 19:05:14 -04:00
4d2762de39 Update 2024-03-30 02:06:38 -04:00
19b07691fc bump 2024-03-14 22:31:04 -04:00
4c67de9f72 Update 2024-03-04 03:37:23 -05:00
9ea078f414 Bump 2024-02-26 03:29:42 -05:00
ba2671d760 New patch 2024-02-03 20:22:42 -05:00
d8f224c5cf Update and refactor 2024-01-13 18:20:36 -05:00
690b46fd2b Update 2023-12-30 16:24:54 -05:00
4563047e01 Update 2023-12-21 15:20:12 -05:00
3ec7c342ba Bump 2023-12-20 12:23:05 -05:00
02fe9f4799 Update 2023-11-24 01:35:24 -05:00
4d94af3f70 Update build and housekeeping 2023-11-20 19:13:21 -05:00
a022050ab4 Update 2023-11-13 18:23:25 -05:00
60b1b8fde3 Update 2023-11-10 20:29:53 -05:00
ee3e7e4203 Add sucrase support 2023-11-06 22:36:18 -05:00
d5f4de03d6 Update upstream 2023-11-06 21:34:20 -05:00
9352bf6baf Update versions 2023-11-01 21:14:15 -04:00
117 changed files with 13878 additions and 1262 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
!/packages/eslint-plugin-react-hooks
/react
src/types/rules
dist/**/*.js
dist/**/*.js.map

1
.stignore Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -1,7 +1,9 @@
# eslint-rules
Personal ESLint config. Guaranteed to have no useless polyfills.
## flat config support
- ❌ [import](https://github.com/import-js/eslint-plugin-import/issues/2556)
- ✅ [react](https://github.com/jsx-eslint/eslint-plugin-react/pull/3429)
- 🇵🇷 [a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/pull/891)
- ⏱️ [a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/pull/891)

View File

@ -1,6 +0,0 @@
#!/bin/bash
./src/build-local-rules.ts
npx dts-bundle-generator "./src/index.ts" -o "./dist/index.d.ts" --project "./tsconfig.build.json" --no-check
./esbuild.ts
sed -i '' '/import.*redirect.*;/d' "dist/index.d.ts"

1
dist/.npmrc vendored Normal file
View File

@ -0,0 +1 @@
shamefully-hoist=true

68
dist/index.d.ts vendored
View File

@ -1,10 +1,72 @@
// Generated by dts-bundle-generator v8.0.1
// Generated by dts-bundle-generator v9.4.0
import { ESLintConfig } from 'eslint-define-config';
import { ESLintUtils } from '@typescript-eslint/utils';
import { Rule } from 'eslint';
import { ESLintConfig, Rules } from 'eslint-define-config';
export declare const error = "error";
export declare const warn = "warn";
export declare const off = "off";
export declare function extendConfig({ plugins, settings, rules, extends: _extends, overrides, ...rest }?: ESLintConfig): ESLintConfig;
export type RuleLevel = "error" | "warn" | "off" | 0 | 1 | 2;
export type RuleEntry<Options> = RuleLevel | [
RuleLevel,
Partial<Options>
];
export interface LocalRuleOptions {
/** Bans import from the specifier '.' and '..' and replaces it with '.+/index' */
"rules/no-import-dot": RuleEntry<unknown>;
/**
* Enforce template literal expressions to be of `string` type
* @see [restrict-template-expressions](https://typescript-eslint.io/rules/restrict-template-expressions)
*/
"rules/restrict-template-expressions": RuleEntry<{
allow: string[];
}>;
/** Ban assignment of empty object literals `{}` and replace them with `Object.create(null)` */
"rules/no-empty-object-literal": RuleEntry<unknown>;
}
export type RuleOptions = Rules & Partial<LocalRuleOptions>;
export interface CustomRule {
rule: () => Promise<{
default: Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>;
}>;
options?: RuleLevel;
}
/**
* ESLint Configuration.
* @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/)
*/
export type InputConfig = Omit<ESLintConfig, "rules"> & {
/**
* Rules.
* @see [Rules](https://eslint.org/docs/latest/user-guide/configuring/rules)
*/
rules?: RuleOptions;
/**
* Glob pattern to find paths to custom rule files in JavaScript or TypeScript.
* Note this must be a string literal or an array of string literals since
* this is statically analyzed.
*/
customRuleFiles?: string | string[];
};
/**
* Returns a ESLint config object.
*
* By default, it includes `["@typescript-eslint", "import", "prettier"]` configs.
* Additional bundled plugins include:
*
* 1. [`react`](https://github.com/jsx-eslint/eslint-plugin-react#list-of-supported-rules)
* (automatically enables
* [`react-hooks`](https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks))
* 2. [`react-refresh`](https://github.com/ArnaudBarre/eslint-plugin-react-refresh)
* 3. [`jsx-a11y`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#supported-rules)
* 4. [`unicorn`](https://github.com/sindresorhus/eslint-plugin-unicorn#rules)
* 5. [`n`](https://github.com/eslint-community/eslint-plugin-n#-rules) (Node.js specific)
* 6. [`jsdoc`](https://github.com/gajus/eslint-plugin-jsdoc#rules)
*
* Non bundled:
* 1. [`graphql`](https://the-guild.dev/graphql/eslint/rules)
*/
export declare function extendConfig(of?: InputConfig): ESLintConfig;
export {};

View File

@ -0,0 +1,4 @@
{
"name": "is-core-module",
"version": "2.13.1"
}

View File

@ -0,0 +1,4 @@
{
"name": "supports-preserve-symlinks-flag",
"version": "1.0.0"
}

55
dist/package.json vendored
View File

@ -1,37 +1,60 @@
{
"name": "@aet/eslint-rules",
"version": "0.0.1-beta.42",
"version": "0.0.24-beta.1",
"license": "UNLICENSED",
"peerDependencies": {
"typescript": "^5.2.2"
"eslint": "^8.57.0",
"typescript": "^5.4.4"
},
"dependencies": {
"@types/eslint": "^8.44.4",
"@typescript-eslint/eslint-plugin": "6.7.5",
"@typescript-eslint/parser": "6.7.5",
"@eslint-community/eslint-utils": "^4.4.0",
"@types/eslint": "^8.56.9",
"@typescript-eslint/eslint-plugin": "^7.7.0",
"@typescript-eslint/parser": "^7.7.0",
"@typescript-eslint/type-utils": "^7.7.0",
"@typescript-eslint/utils": "^7.7.0",
"aria-query": "^5.3.0",
"axe-core": "4.8.2",
"axe-core": "^4.9.0",
"axobject-query": "^4.0.0",
"damerau-levenshtein": "1.0.8",
"debug": "^4.3.4",
"doctrine": "^3.0.0",
"emoji-regex": "^10.2.1",
"enhanced-resolve": "^5.15.0",
"eslint-config-prettier": "9.0.0",
"emoji-regex": "^10.3.0",
"enhanced-resolve": "^5.16.0",
"eslint-config-prettier": "^9.1.0",
"eslint-define-config": "^1.24.1",
"eslint-import-resolver-node": "^0.3.9",
"eslint-module-utils": "^2.8.0",
"eslint-module-utils": "^2.8.1",
"eslint-plugin-es-x": "^7.6.0",
"eslint-plugin-jsdoc": "^48.2.3",
"eslint-plugin-unicorn": "^52.0.0",
"esprima": "^4.0.1",
"esquery": "^1.5.0",
"estraverse": "^5.3.0",
"fast-glob": "^3.3.1",
"get-tsconfig": "^4.7.2",
"ignore": "^5.2.4",
"is-core-module": "^2.13.0",
"fast-glob": "^3.3.2",
"get-tsconfig": "^4.7.3",
"ignore": "^5.3.1",
"is-builtin-module": "^3.2.1",
"is-glob": "^4.0.3",
"language-tags": "^1.0.9",
"lodash": "^4.17.21",
"minimatch": "^9.0.3",
"minimatch": "^9.0.4",
"resolve": "^2.0.0-next.5",
"semver": "^7.5.4",
"semver": "^7.6.0",
"tsconfig-paths": "^4.2.0"
},
"overrides": {
"supports-preserve-symlinks-flag": "file:./overrides/supports-preserve-symlinks-flag",
"is-core-module": "file:./overrides/is-core-module"
},
"resolutions": {
"**/supports-preserve-symlinks-flag": "file:./overrides/supports-preserve-symlinks-flag",
"**/is-core-module": "file:./overrides/is-core-module"
},
"pnpm": {
"overrides": {
"supports-preserve-symlinks-flag": "file:./overrides/supports-preserve-symlinks-flag",
"is-core-module": "file:./overrides/is-core-module"
}
}
}

13
dist/prettier.d.ts vendored Normal file
View File

@ -0,0 +1,13 @@
// Generated by dts-bundle-generator v9.4.0
import { Config } from 'prettier';
declare function defineConfig({ tailwind, ...config }: Partial<Config> & {
tailwind?: boolean;
}): Config;
export {
defineConfig as default,
};
export {};

16
dist/types.d.ts vendored Normal file
View File

@ -0,0 +1,16 @@
// Generated by dts-bundle-generator v9.4.0
import { ESLintUtils } from '@typescript-eslint/utils';
import { Rule } from 'eslint';
export declare function defineRules(rules: {
[ruleName: string]: Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>;
}): {
[ruleName: string]: Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[], ESLintUtils.RuleListener>;
};
export declare function defineRule({ name, create, ...meta }: Rule.RuleMetaData & {
name?: string;
create: (context: Rule.RuleContext) => Rule.RuleListener;
}): Rule.RuleModule;
export {};

1130
dist/yarn.lock vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,38 +1,49 @@
{
"name": "@aet/eslint-configs",
"scripts": {
"build": "./build.sh",
"check-import": "./src/check-imports.ts"
"build": "./scripts/build-all.ts",
"build-types": "cd ./packages/eslint-define-config && ./scripts/index.ts",
"check-import": "./scripts/check-imports.ts"
},
"private": true,
"devDependencies": {
"@babel/core": "^7.23.2",
"@babel/plugin-transform-flow-strip-types": "^7.22.5",
"@babel/preset-env": "^7.23.2",
"@types/babel-plugin-macros": "^3.1.1",
"@types/babel__core": "^7.20.2",
"@types/eslint": "^8.44.4",
"@types/estree": "^1.0.2",
"@types/estree-jsx": "^1.0.1",
"@types/lodash": "^4.14.199",
"@types/node": "^20.8.6",
"@typescript-eslint/types": "^6.7.5",
"@babel/core": "^7.24.4",
"@babel/plugin-transform-flow-strip-types": "^7.24.1",
"@babel/preset-env": "^7.24.4",
"@types/babel-plugin-macros": "^3.1.3",
"@types/babel__core": "^7.20.5",
"@types/eslint": "^8.56.10",
"@types/esprima": "^4.0.6",
"@types/esquery": "^1.5.3",
"@types/estree": "^1.0.5",
"@types/estree-jsx": "^1.0.5",
"@types/lodash": "^4.17.0",
"@types/node": "^20.12.7",
"@typescript-eslint/eslint-plugin": "7.7.0",
"@typescript-eslint/type-utils": "^7.7.0",
"@typescript-eslint/types": "^7.7.0",
"@typescript-eslint/typescript-estree": "^7.7.0",
"@typescript-eslint/utils": "^7.7.0",
"babel-plugin-macros": "^3.1.0",
"dts-bundle-generator": "^8.0.1",
"esbin": "0.0.3",
"esbuild": "0.19.4",
"dts-bundle-generator": "^9.5.0",
"esbin": "0.0.4",
"esbuild": "0.20.2",
"esbuild-plugin-alias": "^0.2.1",
"eslint": "8.51.0",
"eslint-config-prettier": "9.0.0",
"eslint-define-config": "^1.24.1",
"fast-glob": "^3.3.1",
"json-schema-to-ts": "^2.9.2",
"eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-define-config": "file:./src/types",
"esprima": "^4.0.1",
"esquery": "^1.5.0",
"fast-glob": "^3.3.2",
"find-cache-dir": "^5.0.0",
"json-schema-to-ts": "^3.0.1",
"lodash": "^4.17.21",
"minimatch": "^9.0.3",
"minimatch": "^9.0.4",
"patch-package": "^8.0.0",
"picocolors": "^1.0.0",
"prettier": "^3.0.3",
"prettier": "^3.2.5",
"prop-types": "^15.8.1",
"typescript": "5.2.2"
"typescript": "^5.4.5"
},
"prettier": {
"arrowParens": "avoid",
@ -41,5 +52,18 @@
"semi": true,
"singleQuote": true,
"trailingComma": "all"
},
"pnpm": {
"overrides": {
"function-bind": "npm:@nolyfill/function-bind@latest",
"has-proto": "npm:@nolyfill/has-proto@latest",
"has-symbols": "npm:@nolyfill/has-symbols@latest",
"hasown": "npm:@nolyfill/hasown@latest",
"isarray": "npm:@nolyfill/isarray@latest",
"jsonify": "npm:@nolyfill/jsonify@latest",
"object-keys": "npm:@nolyfill/object-keys@latest",
"set-function-length": "npm:@nolyfill/set-function-length@latest",
"@babel/types": "7.24.0"
}
}
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-2023 Christopher Quadflieg
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.

View File

@ -0,0 +1,144 @@
<p>
<a href="https://www.npmjs.com/package/eslint-define-config" target="_blank">
<img alt="NPM package" src="https://img.shields.io/npm/v/eslint-define-config.svg">
</a>
<a href="https://www.npmjs.com/package/eslint-define-config" target="_blank">
<img alt="Downloads" src="https://img.shields.io/npm/dt/eslint-define-config.svg">
</a>
<a href="https://github.com/eslint-types/eslint-define-config/actions/workflows/ci.yml">
<img alt="Build Status" src="https://github.com/eslint-types/eslint-define-config/actions/workflows/ci.yml/badge.svg?branch=main">
</a>
<a href="https://github.com/eslint-types/eslint-define-config/blob/main/LICENSE">
<img alt="License: MIT" src="https://img.shields.io/github/license/eslint-types/eslint-define-config.svg">
</a>
<a href="https://prettier.io" target="_blank">
<img alt="Code Style: Prettier" src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg">
</a>
<a href="https://www.paypal.com/donate?hosted_button_id=L7GY729FBKTZY" target="_blank">
<img alt="Donate: PayPal" src="https://img.shields.io/badge/Donate-PayPal-blue.svg">
</a>
</p>
# eslint-define-config
Provide a `defineConfig` function for `.eslintrc.js`, and a `defineFlatConfig` function for `eslint.config.js` files.
> This project is written by a human and only partially automatically generated!
> Some rules are even enhanced by hand!
> Unfortunately, this has the disadvantage that not everything is immediately defined. For example, if a rule is not defined, it falls back to a basic definition.
> However, the advantage is that you get documentation for pretty much everything in the code and usually get a direct link to the respective plugin or eslint rule. The types are also strictly typed.
>
> So if you are missing something like a rule or a plugin that should also be supported or a rule definition is e.g. out of date, feel free to open an issue or PR for it.
# Installation
```bash
# add eslint and eslint-define-config to projects dev dependencies
npm add --save-dev eslint eslint-define-config
# or
yarn add --dev eslint eslint-define-config
# or
pnpm add --save-dev eslint eslint-define-config
```
# Usage
`.eslintrc.js`
```ts
// @ts-check
// To activate auto-suggestions for Rules of specific plugins, you need to add a `/// <reference types="eslint-plugin-PLUGIN_NAME/define-config-support" />` comment.
// ⚠️ This feature is very new and requires the support of the respective plugin owners.
/// <reference types="@typescript-eslint/eslint-plugin/define-config-support" />
const { defineConfig } = require('eslint-define-config');
module.exports = defineConfig({
root: true,
rules: {
// rules...
},
});
```
## Flat Config
`eslint.config.js`
```ts
// @ts-check
const { defineFlatConfig } = require('eslint-define-config');
module.exports = defineFlatConfig([
'eslint:recommended',
{
plugins: {
// plugins...
},
rules: {
// rules...
},
},
]);
```
# Why?
Improve your eslint configuration experience with:
- auto-suggestions
- type checking (Use `// @ts-check` at the first line in your `.eslintrc.js` or `eslint.config.js`)
- documentation
- deprecation warnings
<img src="https://user-images.githubusercontent.com/7195563/112484789-8a416480-8d7a-11eb-9337-d8b5bc16de17.png" alt="Image" width="600px"/>
## Video
_Click on the thumbnail to play the video_
<a href="https://user-images.githubusercontent.com/7195563/112726158-4a19e780-8f1c-11eb-8cc6-4ea6c100137f.mp4" target="_blank">
<img src="https://user-images.githubusercontent.com/7195563/112726343-30c56b00-8f1d-11eb-9b92-260c530caf1b.png" alt="Video" width="600px"/>
</a>
## Want to support your own plugin?
:warning: **This feature is very new and requires the support of the respective plugin owners**
Add a `declare module` to your plugin package like this:
```ts
declare module 'eslint-define-config' {
export interface CustomRuleOptions {
/**
* Require consistently using either `T[]` or `Array<T>` for arrays.
*
* @see [array-type](https://typescript-eslint.io/rules/array-type)
*/
'@typescript-eslint/array-type': [
{
default?: 'array' | 'generic' | 'array-simple';
readonly?: 'array' | 'generic' | 'array-simple';
},
];
// ... more Rules
}
}
```
There are other interfaces that can be extended.
- `CustomExtends`
- `CustomParserOptions`
- `CustomParsers`
- `CustomPlugins`
- `CustomSettings`
# Credits
- [Proposal Idea](https://github.com/eslint/eslint/issues/14249)
- [Vite](https://github.com/vitejs/vite) and [Evan You](https://github.com/yyx990803) for the idea
- [@antfu](https://github.com/antfu) and his [tweet](https://twitter.com/antfu7/status/1365907188338753536)

View File

@ -0,0 +1,120 @@
{
"name": "eslint-define-config",
"version": "1.24.1",
"description": "Provide a defineConfig function for .eslintrc.js files",
"scripts": {
"clean": "rimraf coverage .eslintcache dist pnpm-lock.yaml node_modules",
"format": "prettier --cache --write .",
"lint:run": "eslint --cache --cache-strategy content --report-unused-disable-directives .",
"lint": "run-s build lint:run",
"typecheck": "vitest typecheck",
"ts-check": "tsc",
"test": "vitest",
"coverage": "vitest run --coverage",
"generate:rules": "tsx ./scripts/generate-rule-files/cli.ts",
"prepublishOnly": "pnpm run clean && pnpm install && pnpm run build",
"preflight": "pnpm install && run-s format lint ts-check test typecheck"
},
"type": "module",
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"default": "./dist/index.js"
}
},
"keywords": [
"config",
"configuration",
"define-config",
"eslint-config",
"eslint",
"eslintconfig",
"typed",
"typescript"
],
"author": {
"name": "Christopher Quadflieg",
"email": "chrissi92@hotmail.de",
"url": "https://github.com/Shinigami92"
},
"repository": {
"type": "git",
"url": "https://github.com/eslint-types/eslint-define-config.git"
},
"funding": [
{
"type": "github",
"url": "https://github.com/Shinigami92"
},
{
"type": "paypal",
"url": "https://www.paypal.com/donate/?hosted_button_id=L7GY729FBKTZY"
}
],
"bugs": "https://github.com/eslint-types/eslint-define-config/issues",
"license": "MIT",
"files": [
"dist",
"src",
"tsconfig.json"
],
"devDependencies": {
"@graphql-eslint/eslint-plugin": "~3.20.1",
"@intlify/eslint-plugin-vue-i18n": "~2.0.0",
"@poppinss/cliui": "~6.4.1",
"@types/dedent": "^0.7.2",
"@types/eslint": "~8.44.3",
"@types/json-schema": "~7.0.13",
"@types/node": "~20.8.3",
"@typescript-eslint/eslint-plugin": "~6.7.4",
"@typescript-eslint/parser": "~6.7.4",
"@vitest/coverage-v8": "~0.34.6",
"change-case": "~5.4.4",
"dedent": "^1.5.3",
"eslint-config-prettier": "~9.0.0",
"eslint-gitignore": "~0.1.0",
"eslint-plugin-deprecation": "~2.0.0",
"eslint-plugin-eslint-comments": "~3.2.0",
"eslint-plugin-import": "~2.28.1",
"eslint-plugin-inclusive-language": "~2.2.1",
"eslint-plugin-jsdoc": "~46.8.2",
"eslint-plugin-jsonc": "~2.9.0",
"eslint-plugin-jsx-a11y": "~6.7.1",
"eslint-plugin-mdx": "~3.1.5",
"eslint-plugin-n": "~16.1.0",
"eslint-plugin-node": "~11.1.0",
"eslint-plugin-prettier": "~5.0.0",
"eslint-plugin-promise": "~6.1.1",
"eslint-plugin-react": "~7.33.2",
"eslint-plugin-react-hooks": "~4.6.0",
"eslint-plugin-sonarjs": "~0.21.0",
"eslint-plugin-spellcheck": "~0.0.20",
"eslint-plugin-testing-library": "~6.0.2",
"eslint-plugin-unicorn": "~48.0.1",
"eslint-plugin-vitest": "~0.3.2",
"eslint-plugin-vue": "~9.17.0",
"eslint-plugin-vue-pug": "~0.6.0",
"eslint-plugin-yml": "~1.10.0",
"expect-type": "~0.17.3",
"graphql": "~16.8.1",
"json-schema": "~0.4.0",
"json-schema-to-ts": "~2.9.2",
"json-schema-to-typescript": "~13.1.1",
"npm-run-all": "~4.1.5",
"prettier-plugin-organize-imports": "^3.2.4",
"rimraf": "~5.0.5",
"tsup": "~7.2.0",
"vue-eslint-parser": "~9.3.2"
},
"packageManager": "pnpm@8.8.0",
"engines": {
"node": ">=18.0.0",
"npm": ">=9.0.0",
"pnpm": ">=8.6.0"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
diff --git b/lib/rules/eslint/no-constructor-return.d.ts a/lib/rules/eslint/no-constructor-return.d.ts
index fedeca4..3e1fd03 100644
--- b/lib/rules/eslint/no-constructor-return.d.ts
+++ a/lib/rules/eslint/no-constructor-return.d.ts
@@ -1,16 +1,9 @@
import type { RuleConfig } from '../rule-config';
-/**
- * Option.
- */
-export interface NoConstructorReturnOption {
- [k: string]: any;
-}
-
/**
* Options.
*/
-export type NoConstructorReturnOptions = NoConstructorReturnOption;
+export type NoConstructorReturnOptions = [];
/**
* Disallow returning value from constructor.

View File

@ -0,0 +1,14 @@
diff --git b/lib/rules/graphql-eslint/naming-convention.d.ts a/lib/rules/graphql-eslint/naming-convention.d.ts
index 60b228b..5e01373 100644
--- b/lib/rules/graphql-eslint/naming-convention.d.ts
+++ a/lib/rules/graphql-eslint/naming-convention.d.ts
@@ -78,8 +78,7 @@ export type NamingConventionOption =
VariableDefinition?: AsString | AsObject;
allowLeadingUnderscore?: boolean;
allowTrailingUnderscore?: boolean;
- /**
- */
+ } & {
[k: string]: AsString | AsObject;
},
];

View File

@ -0,0 +1,13 @@
diff --git b/lib/rules/node/file-extension-in-import.d.ts a/lib/rules/node/file-extension-in-import.d.ts
index 652b18d..7261252 100644
--- b/lib/rules/node/file-extension-in-import.d.ts
+++ a/lib/rules/node/file-extension-in-import.d.ts
@@ -5,7 +5,7 @@ import type { RuleConfig } from '../rule-config';
*/
export interface FileExtensionInImportConfig {
tryExtensions?: string[];
- [k: string]: 'always' | 'never';
+ [ext: `.${string}`]: 'always' | 'never';
}
/**

View File

@ -0,0 +1,23 @@
diff --git a/lib/rules/react/jsx-no-constructed-context-values.d.ts b/lib/rules/react/jsx-no-constructed-context-values.d.ts
index 410f060..e356693 100644
--- a/lib/rules/react/jsx-no-constructed-context-values.d.ts
+++ b/lib/rules/react/jsx-no-constructed-context-values.d.ts
@@ -1,17 +1,9 @@
import type { RuleConfig } from '../rule-config';
-/**
- * Option.
- */
-export interface JsxNoConstructedContextValuesOption {
- [k: string]: any;
-}
-
/**
* Options.
*/
-export type JsxNoConstructedContextValuesOptions =
- JsxNoConstructedContextValuesOption;
+export type JsxNoConstructedContextValuesOptions = [];
/**
* Disallows JSX context provider values from taking values that will cause needless rerenders.

View File

@ -0,0 +1,13 @@
diff --git a/lib/rules/react/jsx-props-no-spreading.d.ts b/lib/rules/react/jsx-props-no-spreading.d.ts
index c1e0069..ba1e1bc 100644
--- a/lib/rules/react/jsx-props-no-spreading.d.ts
+++ b/lib/rules/react/jsx-props-no-spreading.d.ts
@@ -8,8 +8,6 @@ export type JsxPropsNoSpreadingOption = {
custom?: 'enforce' | 'ignore';
exceptions?: string[];
[k: string]: any;
-} & {
- [k: string]: any;
};
/**

View File

@ -0,0 +1,21 @@
diff --git a/lib/rules/vitest/valid-title.d.ts b/lib/rules/vitest/valid-title.d.ts
index 160be76..834ac9b 100644
--- a/lib/rules/vitest/valid-title.d.ts
+++ b/lib/rules/vitest/valid-title.d.ts
@@ -7,15 +7,7 @@ export interface ValidTitleOption {
ignoreTypeOfDescribeName?: boolean;
allowArguments?: boolean;
disallowedWords?: string[];
- /**
- */
- [k: string]:
- | string
- | [string]
- | [string, string]
- | {
- [k: string]: string | [string] | [string, string];
- };
+ [k: string]: any;
}
/**

View File

@ -0,0 +1,178 @@
#!/usr/bin/env bun
import { Logger, colors as cliColors } from '@poppinss/cliui';
import { pascalCase } from 'change-case';
import type { Rule } from 'eslint';
import { existsSync, promises as fs } from 'node:fs';
import { join, resolve } from 'node:path';
import { format } from 'prettier';
import { buildJSDoc, prettierConfig, type Plugin } from './utils';
import { PLUGIN_REGISTRY, loadPlugin } from './plugins-map';
import { RuleFile } from './rule-file';
interface FailedRule {
ruleName: string;
err: unknown;
}
const logger = new Logger();
const colors = cliColors.ansi();
const getRuleName = (name: string) =>
name === 'ESLint' ? 'ESLintRule' : `${pascalCase(name)}Rule`;
const index: [string, string][] = [];
/**
* Generate the `index.d.ts` file for the plugin's rules that will re-export all rules.
*/
async function generateRuleIndexFile(
pluginDirectory: string,
{ rules, name, id }: Plugin,
failedRules: FailedRule[],
): Promise<void> {
const generatedRules = Object.keys(rules!).filter(
ruleName => !failedRules.some(failedRule => failedRule.ruleName === ruleName),
);
/**
* Build all the import statements for the rules.
*/
const rulesImports = generatedRules
.map(name => `import type { ${getRuleName(name)} } from './${name}';`)
.join('\n');
/**
* Build the exported type that is an intersection of all the rules.
*/
const rulesFinalIntersection = generatedRules
.map(name => `${getRuleName(name)}`)
.sort()
.join(' & ');
const pluginRulesType = `
${buildJSDoc([`All ${name} rules.`])}
export type ${name}Rules = ${rulesFinalIntersection};
`;
/**
* Write the final `index.d.ts` file.
*/
const fileContent = `
${rulesImports}
${pluginRulesType}
`;
const indexPath = join(pluginDirectory, 'index.d.ts');
await fs.writeFile(indexPath, await format(fileContent, prettierConfig));
index.push([`${name}Rules`, `./${id}/index`]);
}
/**
* Print a report after having generated rules files for a plugin.
*/
function printGenerationReport(
rules: Array<[string, Rule.RuleModule]>,
failedRules: FailedRule[],
): void {
const msg: string = ` ✅ Generated ${rules.length - failedRules.length} rules`;
logger.logUpdate(colors.green(msg));
logger.logUpdatePersist();
if (failedRules.length) {
logger.log(colors.red(` ❌ Failed ${failedRules.length} rules`));
failedRules.forEach(({ ruleName, err }) => {
logger.log(colors.red(` - ${ruleName}: ${String(err)}`));
});
}
logger.log('');
}
/**
* Generate a `.d.ts` file for each rule in the given plugin.
*/
async function generateRulesFiles(
plugin: Plugin,
pluginDirectory: string,
): Promise<{ failedRules: FailedRule[] }> {
const failedRules: FailedRule[] = [];
const pluginRules = plugin.rules;
if (!pluginRules) {
throw new Error(
`Plugin ${plugin.name} doesn't have any rules. Did you forget to load them?`,
);
}
const rules = Object.entries(pluginRules);
for (const [ruleName, rule] of rules) {
logger.logUpdate(colors.yellow(` Generating > ${ruleName}`));
try {
await RuleFile(plugin, pluginDirectory, ruleName, rule);
} catch (err) {
failedRules.push({ ruleName, err });
}
}
printGenerationReport(rules, failedRules);
return { failedRules };
}
const rulesDirectory = resolve(__dirname, '../../../src/types/rules');
/**
* If it doesn't exist, create the directory that will contain the plugin's rule files.
*/
async function createPluginDirectory(pluginName: string): Promise<string> {
const pluginDirectory = join(rulesDirectory, pluginName);
if (existsSync(pluginDirectory)) {
await fs.rm(pluginDirectory, { recursive: true, force: true });
}
await fs.mkdir(pluginDirectory, { mode: 0o755, recursive: true });
return pluginDirectory;
}
export interface RunOptions {
plugins?: string[];
targetDirectory?: string;
}
for (const plugin of PLUGIN_REGISTRY) {
logger.info(`Generating ${plugin.name} rules.`);
logger.logUpdate(colors.yellow(` Loading plugin > ${plugin.name}`));
const loadedPlugin = await loadPlugin(plugin);
const pluginDir = await createPluginDirectory(plugin.id);
const { failedRules } = await generateRulesFiles(loadedPlugin, pluginDir);
await generateRuleIndexFile(pluginDir, loadedPlugin, failedRules);
}
await fs.writeFile(
resolve(rulesDirectory, 'index.d.ts'),
await format(
[
'import type { RuleConfig } from "./rule-config";',
...index.map(([name, path]) => `import { ${name} } from ${JSON.stringify(path)};`),
'',
'/**',
' * Rules.',
' *',
' * @see [Rules](https://eslint.org/docs/user-guide/configuring/rules)',
' */',
'',
'export type Rules = Partial<',
...index.map(([name]) => ` ${name} &`),
' Record<string, RuleConfig>',
'>;',
].join('\n'),
prettierConfig,
),
);

View File

@ -0,0 +1,58 @@
import type { JSONSchema4 } from 'json-schema';
import { compile } from 'json-schema-to-typescript';
/**
* Remove unnecessary comments that are generated by `json-schema-to-typescript`.
*/
function cleanJsDoc(content: string): string {
const patterns = [
/\* This interface was referenced by .+ JSON-Schema definition/,
/\* via the `.+` "/,
];
return content
.split('\n')
.filter(line => !patterns.some(ignoredLine => ignoredLine.test(line)))
.join('\n');
}
/**
* Replace some types that are generated by `json-schema-to-typescript`.
*/
export function patchTypes(content: string): string {
const replacements: [RegExp, string][] = [
[
/\(string & \{\s*\[k: string\]: any\s*\} & \{\s*\[k: string\]: any\s*\}\)\[\]/,
'string[]',
],
];
for (const [pattern, replacement] of replacements) {
content = content.replace(pattern, replacement);
}
return content;
}
/**
* Generate a type from the given JSON schema.
*/
export async function generateTypeFromSchema(
schema: JSONSchema4,
typeName: string,
): Promise<string> {
schema = JSON.parse(
JSON.stringify(schema).replace(/#\/items\/0\/\$defs\//g, '#/$defs/'),
);
const result = await compile(schema, typeName, {
format: false,
bannerComment: '',
style: {
singleQuote: true,
trailingComma: 'all',
},
unknownAny: false,
});
return patchTypes(cleanJsDoc(result));
}

View File

@ -0,0 +1,145 @@
import type { Plugin, PluginRules } from './utils';
/**
* Map of plugins for which the script will generate rule files.
*/
export const PLUGIN_REGISTRY: Plugin[] = [
{
id: 'deprecation',
name: 'Deprecation',
module: () => import('eslint-plugin-deprecation'),
},
{
id: 'eslint',
name: 'ESLint',
module: () => import('eslint'),
},
{
id: 'typescript-eslint',
name: 'TypeScript',
prefix: '@typescript-eslint',
module: () => import('@typescript-eslint/eslint-plugin'),
},
{
id: 'import',
name: 'Import',
module: () => import('eslint-plugin-import'),
},
{
id: 'eslint-comments',
name: 'EslintComments',
module: () => import('eslint-plugin-eslint-comments'),
},
{
id: 'graphql-eslint',
name: 'GraphQL',
prefix: '@graphql-eslint',
module: () => import('@graphql-eslint/eslint-plugin'),
},
{
id: 'jsdoc',
name: 'JSDoc',
prefix: 'jsdoc',
module: () => import('eslint-plugin-jsdoc'),
},
{
id: 'jsonc',
name: 'Jsonc',
module: () => import('eslint-plugin-jsonc'),
},
{
id: 'jsx-a11y',
name: 'JsxA11y',
module: () => import('eslint-plugin-jsx-a11y'),
},
{
id: 'mdx',
name: 'Mdx',
module: () => import('eslint-plugin-mdx'),
},
{
id: 'n',
name: 'N',
module: () => import('eslint-plugin-n'),
},
{
id: 'node',
name: 'Node',
module: () => import('eslint-plugin-node'),
},
{
id: 'promise',
name: 'Promise',
module: () => import('eslint-plugin-promise'),
},
{
id: 'react',
name: 'React',
module: () => import('eslint-plugin-react'),
},
{
id: 'react-hooks',
name: 'ReactHooks',
module: () => import('eslint-plugin-react-hooks'),
},
{
id: 'sonarjs',
name: 'SonarJS',
prefix: 'sonarjs',
module: () => import('eslint-plugin-sonarjs'),
},
{
id: 'spellcheck',
name: 'Spellcheck',
module: () => import('eslint-plugin-spellcheck'),
},
{
id: 'testing-library',
name: 'TestingLibrary',
module: () => import('eslint-plugin-testing-library'),
},
{
id: 'unicorn',
name: 'Unicorn',
module: () => import('eslint-plugin-unicorn'),
},
{
id: 'vitest',
name: 'Vitest',
module: () => import('eslint-plugin-vitest'),
},
{
id: 'vue',
name: 'Vue',
module: () => import('eslint-plugin-vue'),
},
{
id: 'vue-i18n',
name: 'VueI18n',
prefix: '@intlify/vue-i18n',
module: () => import('@intlify/eslint-plugin-vue-i18n'),
},
{
id: 'vue-pug',
name: 'VuePug',
module: () => import('eslint-plugin-vue-pug'),
},
{
id: 'yml',
name: 'Yml',
module: () => import('eslint-plugin-yml'),
},
] as const;
export async function loadPlugin(plugin: Plugin): Promise<Plugin> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const mod: any = await plugin.module();
const rules: PluginRules =
plugin.name === 'ESLint'
? Object.fromEntries(
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
new mod.Linter().getRules().entries(),
)
: mod.rules ?? mod.default.rules;
return { ...plugin, rules };
}

View File

@ -0,0 +1,168 @@
import { Logger, colors as cliColors } from '@poppinss/cliui';
import { pascalCase, kebabCase } from 'change-case';
import type { Rule } from 'eslint';
import type { JSONSchema4 } from 'json-schema';
import { execSync } from 'node:child_process';
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
import { dirname, resolve } from 'node:path';
import { format } from 'prettier';
import { generateTypeFromSchema } from './json-schema-to-ts';
import { buildJSDoc, prettierConfig, type Plugin } from './utils';
const logger = new Logger();
const colors = cliColors.ansi();
/**
* Build the rule description to append to the JSDoc.
*/
function buildDescription(description = ''): string {
description = description.charAt(0).toUpperCase() + description.slice(1);
if (description.length > 0 && !description.endsWith('.')) {
description += '.';
}
return description.replace('*/', '');
}
export async function RuleFile(
plugin: Plugin,
pluginDirectory: string,
ruleName: string,
rule: Rule.RuleModule,
) {
let content = '';
const rulePath = resolve(pluginDirectory, `${ruleName}.d.ts`);
const ruleNamePascalCase = pascalCase(ruleName);
const schema: JSONSchema4 | JSONSchema4[] | undefined = rule.meta?.schema;
const isSchemaArray = Array.isArray(schema);
const mainSchema = isSchemaArray ? schema[0] : schema;
const sideSchema = isSchemaArray && schema.length > 1 ? schema[1] : undefined;
const thirdSchema = isSchemaArray && schema.length > 2 ? schema[2] : undefined;
/**
* Generate a JSDoc with the rule description and `@see` url.
*/
function generateTypeJsDoc(): string {
const { meta } = rule;
const seeDocLink: string = meta?.docs?.url
? `@see [${ruleName}](${meta.docs.url})`
: '';
return buildJSDoc([
buildDescription(rule.meta?.docs?.description),
' ',
rule.meta?.deprecated ? '@deprecated' : '',
rule.meta?.deprecated ? ' ' : '',
seeDocLink,
]);
}
/**
* Generate a type from a JSON schema and append it to the file content.
*/
async function appendJsonSchemaType(
schema: JSONSchema4,
comment: string,
): Promise<void> {
const type = await generateTypeFromSchema(schema, ruleNamePascalCase + comment);
const jsdoc = buildJSDoc([`${comment}.`]);
content += `\n${jsdoc}`;
content += `\n${type}\n`;
}
/**
* Scoped rule name ESLint config uses.
*/
function prefixedRuleName(): string {
const { prefix, name } = plugin;
const rulePrefix = (prefix ?? kebabCase(name)) + '/';
return name === 'ESLint' ? ruleName : `${rulePrefix}${ruleName}`;
}
/**
* Append the `import type { RuleConfig } from '../rule-config'` at the top of the file.
*/
const nestedDepth = ruleName.split('/').length;
content += `import type { RuleConfig } from '${'../'.repeat(nestedDepth)}rule-config'\n\n`;
/**
* Generate and append types for the rule schemas.
*/
if (thirdSchema) {
await appendJsonSchemaType(thirdSchema, 'Setting');
}
if (sideSchema) {
await appendJsonSchemaType(sideSchema, 'Config');
}
if (mainSchema) {
await appendJsonSchemaType(mainSchema, 'Option');
}
if (mainSchema) {
/**
* Append the rule type options to the file content.
*/
let type: string = '';
if (!isSchemaArray) {
type = `${ruleNamePascalCase}Option`;
} else if (thirdSchema) {
type = `[${ruleNamePascalCase}Option?, ${ruleNamePascalCase}Config?, ${ruleNamePascalCase}Setting?]`;
} else if (sideSchema) {
type = `[${ruleNamePascalCase}Option?, ${ruleNamePascalCase}Config?]`;
} else if (mainSchema) {
type = `[${ruleNamePascalCase}Option?]`;
}
content += buildJSDoc(['Options.']) + '\n';
content += `export type ${ruleNamePascalCase}Options = ${type}\n\n`;
}
/**
* Append the rule config type to the file content.
*/
content += generateTypeJsDoc() + '\n';
content += `export type ${ruleNamePascalCase}RuleConfig = RuleConfig<${mainSchema ? `${ruleNamePascalCase}Options` : '[]'}>;\n\n`;
/**
* Append the final rule interface to the file content.
*/
content += generateTypeJsDoc() + '\n';
content += `export interface ${ruleNamePascalCase}Rule {`;
content += `${generateTypeJsDoc()}\n`;
content += `'${prefixedRuleName()}': ${ruleNamePascalCase}RuleConfig;`;
content += '}';
content = await format(content, prettierConfig);
/**
* Create the directory of the rule file if it doesn't exist.
*/
const subPath = dirname(rulePath);
if (!existsSync(subPath)) {
mkdirSync(subPath, { recursive: true });
}
writeFileSync(rulePath, content);
/**
* Apply a patch to the generated content if a diff file exists for it.
*
* Must be called after `generate()`.
*/
const pathParts = rulePath.split('/');
const diffFile = resolve(
__dirname,
'./diffs/rules',
pathParts.at(-2) ?? '',
`${pathParts.at(-1) ?? ''}.diff`,
);
if (existsSync(diffFile)) {
logger.logUpdate(colors.yellow(` 🧹 Adjusting ${prefixedRuleName()}`));
logger.logUpdatePersist();
execSync(`git apply ${diffFile}`);
}
}

View File

@ -0,0 +1,24 @@
import type { Rule } from 'eslint';
import type { Config } from 'prettier';
export function buildJSDoc(content: string[]) {
return ['/**', ...content.filter(Boolean).map(line => ` * ${line}`), ' */'].join('\n');
}
export const prettierConfig: Config = {
plugins: ['prettier-plugin-organize-imports'],
parser: 'typescript',
singleQuote: true,
trailingComma: 'all',
};
export type MaybeArray<T> = T | T[];
export type PluginRules = Record<string, Rule.RuleModule>;
export interface Plugin {
id: string;
name: string;
prefix?: string;
module: () => Promise<any>;
rules?: PluginRules;
}

Submodule packages/eslint-import-resolver-typescript updated: 7b6bfc3947...7a02ac08b5

Submodule packages/eslint-plugin-import updated: 6b95a02193...f77ceb679d

Submodule packages/eslint-plugin-jsx-a11y updated: fffb05b38c...0d5321a545

Submodule packages/eslint-plugin-n updated: 47cd9a6a0e...eb11b5b35a

Submodule packages/eslint-plugin-react updated: ecadb92609...4467db503e

View File

@ -8,20 +8,22 @@
/* eslint-disable no-for-of-loops/no-for-of-loops */
import type { Rule, Scope } from 'eslint';
import type {
FunctionDeclaration,
CallExpression,
Expression,
Super,
Node,
ArrayExpression,
ArrowFunctionExpression,
FunctionExpression,
SpreadElement,
Identifier,
VariableDeclarator,
MemberExpression,
CallExpression,
ChainExpression,
Pattern,
Expression,
FunctionDeclaration,
FunctionExpression,
Identifier,
MemberExpression,
Node,
OptionalMemberExpression,
Pattern,
SpreadElement,
Super,
TSAsExpression,
VariableDeclarator,
} from 'estree';
import type { FromSchema } from 'json-schema-to-ts';
import { __EXPERIMENTAL__ } from './index';
@ -109,7 +111,7 @@ const rule: Rule.RuleModule = {
*/
function visitFunctionWithDependencies(
node: ArrowFunctionExpression | FunctionExpression | FunctionDeclaration,
declaredDependenciesNode: SpreadElement | Expression,
declaredDependenciesNode: SpreadElement | Expression | undefined,
reactiveHook: Super | Expression,
reactiveHookName: string,
isEffect: boolean,
@ -128,7 +130,7 @@ const rule: Rule.RuleModule = {
' }\n' +
' fetchData();\n' +
`}, [someId]); // Or [] if effect doesn't need props or state\n\n` +
'Learn more about data fetching with Hooks: https://reactjs.org/link/hooks-data-fetching',
'Learn more about data fetching with Hooks: https://react.dev/link/hooks-data-fetching',
});
}
@ -194,7 +196,7 @@ const rule: Rule.RuleModule = {
if (init == null) {
return false;
}
while (init.type === 'TSAsExpression') {
while (init.type === 'TSAsExpression' || init.type === 'AsExpression') {
init = init.expression;
}
// Detect primitive constants
@ -620,7 +622,11 @@ const rule: Rule.RuleModule = {
const declaredDependencies: DeclaredDependency[] = [];
const externalDependencies = new Set<string>();
if (declaredDependenciesNode.type !== 'ArrayExpression') {
const isArrayExpression = declaredDependenciesNode.type === 'ArrayExpression';
const isTSAsArrayExpression =
declaredDependenciesNode.type === 'TSAsExpression' &&
declaredDependenciesNode.expression.type === 'ArrayExpression';
if (!isArrayExpression && !isTSAsArrayExpression) {
// If the declared dependencies are not an array expression then we
// can't verify that the user provided the correct dependencies. Tell
// the user this in an error.
@ -633,7 +639,10 @@ const rule: Rule.RuleModule = {
'dependencies.',
});
} else {
declaredDependenciesNode.elements.forEach(declaredDependencyNode => {
const arrayExpression = isTSAsArrayExpression
? ((declaredDependenciesNode as TSAsExpression).expression as ArrayExpression)
: (declaredDependenciesNode as ArrayExpression);
arrayExpression.elements.forEach(declaredDependencyNode => {
// Skip elided elements.
if (declaredDependencyNode === null) {
return;
@ -1158,7 +1167,11 @@ const rule: Rule.RuleModule = {
const reactiveHook = node.callee as Identifier | MemberExpression;
const reactiveHookName = (getNodeWithoutReactNamespace(reactiveHook) as Identifier)
.name;
const declaredDependenciesNode = node.arguments[callbackIndex + 1];
const maybeNode = node.arguments[callbackIndex + 1];
const declaredDependenciesNode =
maybeNode && !(maybeNode.type === 'Identifier' && maybeNode.name === 'undefined')
? maybeNode
: undefined;
const isEffect = /Effect($|[^a-z])/g.test(reactiveHookName);
// Check whether a callback is supplied. If there is no callback supplied
@ -1203,6 +1216,15 @@ const rule: Rule.RuleModule = {
isEffect,
);
return; // Handled
case 'TSAsExpression':
visitFunctionWithDependencies(
callback.expression,
declaredDependenciesNode,
reactiveHook,
reactiveHookName,
isEffect,
);
return; // Handled
case 'Identifier':
if (!declaredDependenciesNode) {
// No deps, no problems.
@ -1545,7 +1567,7 @@ function getConstructionExpressionType(node: Node) {
}
return null;
case 'TypeCastExpression':
return getConstructionExpressionType(node.expression);
case 'AsExpression':
case 'TSAsExpression':
return getConstructionExpressionType(node.expression);
}
@ -1749,7 +1771,7 @@ function analyzePropertyChain(
}
}
function getNodeWithoutReactNamespace(node: Identifier | MemberExpression) {
function getNodeWithoutReactNamespace(node: Expression | Super) {
if (
node.type === 'MemberExpression' &&
node.object.type === 'Identifier' &&

View File

@ -24,10 +24,7 @@ import { __EXPERIMENTAL__ } from './index';
*/
function isHookName(s: string) {
if (__EXPERIMENTAL__) {
return s === 'use' || /^use[A-Z0-9]/.test(s);
}
return /^use[A-Z0-9]/.test(s);
return s === 'use' || /^use[A-Z0-9]/.test(s);
}
/**
@ -59,7 +56,7 @@ function isComponentName(node: Node) {
return node.type === 'Identifier' && /^[A-Z]/.test(node.name);
}
function isReactFunction(node: Expression | Super, functionName: string) {
function isReactFunction(node: Node, functionName: string) {
return (
(node as Identifier).name === functionName ||
(node.type === 'MemberExpression' &&
@ -115,10 +112,7 @@ function isUseEffectEventIdentifier(node: Node) {
}
function isUseIdentifier(node: Node) {
if (__EXPERIMENTAL__) {
return node.type === 'Identifier' && node.name === 'use';
}
return false;
return isReactFunction(node, 'use');
}
const rule: Rule.RuleModule = {

View File

@ -3,8 +3,8 @@
"version": 1,
"sources": {
"main": {
"repository": "git@github.com:facebook/react.git",
"commit": "899cb95f52cc83ab5ca1eb1e268c909d3f0961e7",
"repository": "https://github.com/facebook/react",
"commit": "0e0b69321a6fcfe8a3eaae3b1016beb110437b38",
"branch": "main"
}
}

View File

@ -1,5 +1,5 @@
diff --git a/package.json b/package.json
index 72587ff..74b7051 100644
index 98370b5..da6cd9b 100644
--- a/package.json
+++ b/package.json
@@ -62,8 +62,7 @@
@ -14,13 +14,14 @@ index 72587ff..74b7051 100644
"debug": "^4.3.4",
diff --git a/tsconfig.json b/tsconfig.json
deleted file mode 100644
index 81e4c05..0000000
index a303861..0000000
--- a/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
@@ -1,8 +0,0 @@
-{
- "extends": "@1stg/tsconfig/node16",
- "compilerOptions": {
- "module": "Node16",
- "outDir": "./lib"
- },
- "include": ["./src", "./shim.d.ts"]

View File

@ -26,10 +26,10 @@ index 883c03b7..0111d616 100644
}
diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 3c9c658f..00000000
index 80e1014c..00000000
--- a/.eslintrc
+++ /dev/null
@@ -1,248 +0,0 @@
@@ -1,267 +0,0 @@
-{
- "root": true,
- "plugins": [
@ -128,6 +128,7 @@ index 3c9c658f..00000000
- "no-multiple-empty-lines": [2, { "max": 1, "maxEOF": 1, "maxBOF": 0 }],
- "no-return-assign": [2, "always"],
- "no-trailing-spaces": 2,
- "no-use-before-define": [2, { "functions": true, "classes": true, "variables": true }],
- "no-var": 2,
- "object-curly-spacing": [2, "always"],
- "object-shorthand": ["error", "always", {
@ -241,10 +242,10 @@ index 3c9c658f..00000000
- "exports": "always-multiline",
- "functions": "never"
- }],
- "prefer-destructuring": "warn",
- "prefer-destructuring": "off",
- "prefer-object-spread": "off",
- "prefer-rest-params": "off",
- "prefer-spread": "warn",
- "prefer-spread": "off",
- "prefer-template": "off",
- }
- },
@ -259,6 +260,24 @@ index 3c9c658f..00000000
- },
- {
- "files": [
- "utils/**", // TODO
- ],
- "rules": {
- "no-use-before-define": "off",
- },
- },
- {
- "files": [
- "resolvers/webpack/index.js",
- "resolvers/webpack/test/example.js",
- "utils/parse.js",
- ],
- "rules": {
- "no-console": "off",
- },
- },
- {
- "files": [
- "resolvers/*/test/**/*",
- ],
- "env": {

View File

@ -1,5 +1,5 @@
diff --git a/lib/index.js b/lib/index.js
index def1bbf..6fdff14 100644
index 49fd4c7..a0fdd81 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,9 +1,9 @@
@ -14,111 +14,16 @@ index def1bbf..6fdff14 100644
+import cjsConfig from "./configs/recommended-script"
+import recommendedConfig from "./configs/recommended"
const rules = {
"callback-return": require("./rules/callback-return"),
@@ -51,8 +51,8 @@ const rules = {
const mod = {
/**
* @typedef {{
@@ -20,8 +20,8 @@ const recommendedConfig = require("./configs/recommended")
/** @type {import('eslint').ESLint.Plugin & { configs: Configs }} */
const plugin = {
meta: {
- name: pkg.name,
- version: pkg.version,
+ name,
+ version,
},
rules,
}
diff --git a/tests/fixtures/no-extraneous/dependencies/node_modules/@bbb/aaa.js b/tests/fixtures/no-extraneous/dependencies/node_modules/@bbb/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/dependencies/node_modules/aaa.js b/tests/fixtures/no-extraneous/dependencies/node_modules/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/dependencies/node_modules/bbb/index.js b/tests/fixtures/no-extraneous/dependencies/node_modules/bbb/index.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/dependencies/node_modules/bbb/package.json b/tests/fixtures/no-extraneous/dependencies/node_modules/bbb/package.json
deleted file mode 100644
index b7d25e2..0000000
--- a/tests/fixtures/no-extraneous/dependencies/node_modules/bbb/package.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "bbb",
- "main": "index.js"
-}
\ No newline at end of file
diff --git a/tests/fixtures/no-extraneous/devDependencies/node_modules/@bbb/aaa.js b/tests/fixtures/no-extraneous/devDependencies/node_modules/@bbb/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/devDependencies/node_modules/aaa.js b/tests/fixtures/no-extraneous/devDependencies/node_modules/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/devDependencies/node_modules/bbb/index.js b/tests/fixtures/no-extraneous/devDependencies/node_modules/bbb/index.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/devDependencies/node_modules/bbb/package.json b/tests/fixtures/no-extraneous/devDependencies/node_modules/bbb/package.json
deleted file mode 100644
index b7d25e2..0000000
--- a/tests/fixtures/no-extraneous/devDependencies/node_modules/bbb/package.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "bbb",
- "main": "index.js"
-}
\ No newline at end of file
diff --git a/tests/fixtures/no-extraneous/noDependencies/node_modules/@bbb/aaa.js b/tests/fixtures/no-extraneous/noDependencies/node_modules/@bbb/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/noDependencies/node_modules/aaa.js b/tests/fixtures/no-extraneous/noDependencies/node_modules/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/noDependencies/node_modules/bbb.js b/tests/fixtures/no-extraneous/noDependencies/node_modules/bbb.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/optionalDependencies/node_modules/@bbb/aaa.js b/tests/fixtures/no-extraneous/optionalDependencies/node_modules/@bbb/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/optionalDependencies/node_modules/aaa.js b/tests/fixtures/no-extraneous/optionalDependencies/node_modules/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/optionalDependencies/node_modules/bbb/index.js b/tests/fixtures/no-extraneous/optionalDependencies/node_modules/bbb/index.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/optionalDependencies/node_modules/bbb/package.json b/tests/fixtures/no-extraneous/optionalDependencies/node_modules/bbb/package.json
deleted file mode 100644
index b7d25e2..0000000
--- a/tests/fixtures/no-extraneous/optionalDependencies/node_modules/bbb/package.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "bbb",
- "main": "index.js"
-}
\ No newline at end of file
diff --git a/tests/fixtures/no-extraneous/peerDependencies/node_modules/@bbb/aaa.js b/tests/fixtures/no-extraneous/peerDependencies/node_modules/@bbb/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/peerDependencies/node_modules/aaa.js b/tests/fixtures/no-extraneous/peerDependencies/node_modules/aaa.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/peerDependencies/node_modules/bbb/index.js b/tests/fixtures/no-extraneous/peerDependencies/node_modules/bbb/index.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-extraneous/peerDependencies/node_modules/bbb/package.json b/tests/fixtures/no-extraneous/peerDependencies/node_modules/bbb/package.json
deleted file mode 100644
index b7d25e2..0000000
--- a/tests/fixtures/no-extraneous/peerDependencies/node_modules/bbb/package.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "bbb",
- "main": "index.js"
-}
\ No newline at end of file
diff --git a/tests/fixtures/no-hide-core-modules/indirect-thirdparty/node_modules/util/index.js b/tests/fixtures/no-hide-core-modules/indirect-thirdparty/node_modules/util/index.js
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/fixtures/no-hide-core-modules/thirdparty/node_modules/util/index.js b/tests/fixtures/no-hide-core-modules/thirdparty/node_modules/util/index.js
deleted file mode 100644
index e69de29..0000000
rules: /** @type {Record<string, import('eslint').Rule.RuleModule>} */ ({
"callback-return": require("./rules/callback-return"),

View File

@ -171,7 +171,7 @@ index 38b4dd8b..d0575572 100644
const variableUtil = require('../util/variable');
const testReactVersion = require('../util/version').testReactVersion;
diff --git a/lib/rules/jsx-key.js b/lib/rules/jsx-key.js
index c13a00cf..fb457e63 100644
index 7ea874d0..48df0dba 100644
--- a/lib/rules/jsx-key.js
+++ b/lib/rules/jsx-key.js
@@ -5,8 +5,7 @@
@ -185,7 +185,7 @@ index c13a00cf..fb457e63 100644
const docsUrl = require('../util/docsUrl');
const pragmaUtil = require('../util/pragma');
diff --git a/lib/rules/jsx-no-bind.js b/lib/rules/jsx-no-bind.js
index 0a4c38e6..75a57bd9 100644
index 17e56e2e..cb6dec1a 100644
--- a/lib/rules/jsx-no-bind.js
+++ b/lib/rules/jsx-no-bind.js
@@ -7,7 +7,7 @@
@ -198,7 +198,7 @@ index 0a4c38e6..75a57bd9 100644
const jsxUtil = require('../util/jsx');
const report = require('../util/report');
diff --git a/lib/rules/jsx-pascal-case.js b/lib/rules/jsx-pascal-case.js
index a1bb4811..db051356 100644
index efeef403..33df4653 100644
--- a/lib/rules/jsx-pascal-case.js
+++ b/lib/rules/jsx-pascal-case.js
@@ -5,7 +5,7 @@
@ -211,7 +211,7 @@ index a1bb4811..db051356 100644
const docsUrl = require('../util/docsUrl');
const jsxUtil = require('../util/jsx');
diff --git a/lib/rules/jsx-sort-props.js b/lib/rules/jsx-sort-props.js
index 6d19f201..4b1849cc 100644
index 3ca1724e..faf58f91 100644
--- a/lib/rules/jsx-sort-props.js
+++ b/lib/rules/jsx-sort-props.js
@@ -5,7 +5,7 @@
@ -224,7 +224,7 @@ index 6d19f201..4b1849cc 100644
const toSorted = require('array.prototype.tosorted');
diff --git a/lib/rules/no-namespace.js b/lib/rules/no-namespace.js
index 64bbc8d5..b5e9c803 100644
index d7559f5e..fbfad23a 100644
--- a/lib/rules/no-namespace.js
+++ b/lib/rules/no-namespace.js
@@ -5,7 +5,7 @@
@ -237,24 +237,10 @@ index 64bbc8d5..b5e9c803 100644
const isCreateElement = require('../util/isCreateElement');
const report = require('../util/report');
diff --git a/lib/rules/no-unknown-property.js b/lib/rules/no-unknown-property.js
index fc573366..74bc36f6 100644
index 9491f9c6..44396948 100644
--- a/lib/rules/no-unknown-property.js
+++ b/lib/rules/no-unknown-property.js
@@ -516,6 +516,13 @@ module.exports = {
type: 'string',
},
},
+ extends: {
+ type: 'array',
+ items: {
+ type: 'string',
+ enum: ['next', 'emotion'],
+ },
+ }
},
additionalProperties: false,
}],
@@ -523,14 +530,18 @@ module.exports = {
@@ -543,7 +543,7 @@ module.exports = {
create(context) {
function getIgnoreConfig() {
@ -262,11 +248,8 @@ index fc573366..74bc36f6 100644
+ return context.options[0]?.ignore || DEFAULTS.ignore;
}
+ const extensions = /** @type {string[]} */ (context.options[0]?.extends || []);
+ const hasEmotion = extensions.includes('emotion');
+ const hasNext = extensions.includes('next');
+
return {
function getRequireDataLowercase() {
@@ -556,7 +556,7 @@ module.exports = {
JSXAttribute(node) {
const ignoreNames = getIgnoreConfig();
const actualName = context.getSourceCode().getText(node.name);
@ -275,22 +258,6 @@ index fc573366..74bc36f6 100644
return;
}
const name = normalizeAttributeCase(actualName);
@@ -546,6 +557,15 @@ module.exports = {
const tagName = getTagName(node);
+ if (
+ (actualName === 'css' && hasEmotion) ||
+ (tagName === 'style' &&
+ (actualName === 'global' || actualName === 'jsx') &&
+ hasNext)
+ ) {
+ return;
+ }
+
if (tagName === 'fbt' || tagName === 'fbs') { return; } // fbt/fbs nodes are bonkers, let's not go there
if (!isValidHTMLTagInJSX(node)) { return; }
diff --git a/lib/util/annotations.js b/lib/util/annotations.js
index 60aaef8c..ad8dc0bf 100644
--- a/lib/util/annotations.js
@ -338,34 +305,6 @@ index 55073bfe..efc07af1 100644
const astUtil = require('./ast');
const isCreateElement = require('./isCreateElement');
diff --git a/package.json b/package.json
index 702b9f6f..f34d71d3 100644
--- a/package.json
+++ b/package.json
@@ -25,22 +25,14 @@
"homepage": "https://github.com/jsx-eslint/eslint-plugin-react",
"bugs": "https://github.com/jsx-eslint/eslint-plugin-react/issues",
"dependencies": {
- "array-includes": "^3.1.6",
- "array.prototype.flatmap": "^1.3.1",
- "array.prototype.tosorted": "^1.1.1",
"doctrine": "^2.1.0",
"es-iterator-helpers": "^1.0.13",
"estraverse": "^5.3.0",
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
"minimatch": "^3.1.2",
- "object.entries": "^1.1.6",
- "object.fromentries": "^2.0.6",
- "object.hasown": "^1.1.2",
- "object.values": "^1.1.6",
"prop-types": "^15.8.1",
"resolve": "^2.0.0-next.4",
- "semver": "^6.3.1",
- "string.prototype.matchall": "^4.0.8"
+ "semver": "^6.3.1"
},
"devDependencies": {
"@babel/core": "^7.22.10",
diff --git a/tsconfig.json b/tsconfig.json
deleted file mode 100644
index 39187b7f..00000000

View File

@ -0,0 +1,10 @@
diff --git a/node_modules/@typescript-eslint/utils/dist/ts-eslint/Scope.d.ts b/node_modules/@typescript-eslint/utils/dist/ts-eslint/Scope.d.ts
index 4e57af9..29b7cf7 100644
--- a/node_modules/@typescript-eslint/utils/dist/ts-eslint/Scope.d.ts
+++ b/node_modules/@typescript-eslint/utils/dist/ts-eslint/Scope.d.ts
@@ -1,4 +1,4 @@
-import * as scopeManager from '@typescript-eslint/scope-manager';
+import * as scopeManager from '@typescript-eslint/scope-manager/dist';
declare namespace Scope {
type ScopeManager = scopeManager.ScopeManager;
type Reference = scopeManager.Reference;

3
playground/.eslintrc.js Normal file
View File

@ -0,0 +1,3 @@
const { extendConfig } = require('@aet/eslint-rules');
module.exports = extendConfig({});

17
playground/package.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "playground",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@aet/eslint-rules": "link:/Users/aet/Documents/Git/eslint/dist",
"eslint": "^8.54.0",
"typescript": "^5.3.2"
}
}

672
playground/pnpm-lock.yaml generated Normal file
View File

@ -0,0 +1,672 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
'@aet/eslint-rules':
specifier: link:/Users/aet/Documents/Git/eslint/dist
version: link:../dist
eslint:
specifier: 8.54.0
version: 8.54.0
typescript:
specifier: ^5.3.2
version: 5.3.2
packages:
/@aashutoshrathi/word-wrap@1.2.6:
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
engines: {node: '>=0.10.0'}
dev: false
/@eslint-community/eslint-utils@4.4.0(eslint@8.54.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
dependencies:
eslint: 8.54.0
eslint-visitor-keys: 3.4.3
dev: false
/@eslint-community/regexpp@4.10.0:
resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
dev: false
/@eslint/eslintrc@2.1.3:
resolution: {integrity: sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
ajv: 6.12.6
debug: 4.3.4
espree: 9.6.1
globals: 13.23.0
ignore: 5.3.0
import-fresh: 3.3.0
js-yaml: 4.1.0
minimatch: 3.1.2
strip-json-comments: 3.1.1
transitivePeerDependencies:
- supports-color
dev: false
/@eslint/js@8.54.0:
resolution: {integrity: sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: false
/@humanwhocodes/config-array@0.11.13:
resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==}
engines: {node: '>=10.10.0'}
dependencies:
'@humanwhocodes/object-schema': 2.0.1
debug: 4.3.4
minimatch: 3.1.2
transitivePeerDependencies:
- supports-color
dev: false
/@humanwhocodes/module-importer@1.0.1:
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
engines: {node: '>=12.22'}
dev: false
/@humanwhocodes/object-schema@2.0.1:
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
dev: false
/@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.stat': 2.0.5
run-parallel: 1.2.0
dev: false
/@nodelib/fs.stat@2.0.5:
resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
engines: {node: '>= 8'}
dev: false
/@nodelib/fs.walk@1.2.8:
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
engines: {node: '>= 8'}
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
dev: false
/@ungap/structured-clone@1.2.0:
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
dev: false
/acorn-jsx@5.3.2(acorn@8.11.2):
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
acorn: 8.11.2
dev: false
/acorn@8.11.2:
resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: false
/ajv@6.12.6:
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
dependencies:
fast-deep-equal: 3.1.3
fast-json-stable-stringify: 2.1.0
json-schema-traverse: 0.4.1
uri-js: 4.4.1
dev: false
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: false
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: false
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: false
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: false
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
dev: false
/callsites@3.1.0:
resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
engines: {node: '>=6'}
dev: false
/chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
dev: false
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: false
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: false
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: false
/cross-spawn@7.0.3:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
dev: false
/debug@4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.2
dev: false
/deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: false
/doctrine@3.0.0:
resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
engines: {node: '>=6.0.0'}
dependencies:
esutils: 2.0.3
dev: false
/escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
dev: false
/eslint-scope@7.2.2:
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
dev: false
/eslint-visitor-keys@3.4.3:
resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: false
/eslint@8.54.0:
resolution: {integrity: sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.54.0)
'@eslint-community/regexpp': 4.10.0
'@eslint/eslintrc': 2.1.3
'@eslint/js': 8.54.0
'@humanwhocodes/config-array': 0.11.13
'@humanwhocodes/module-importer': 1.0.1
'@nodelib/fs.walk': 1.2.8
'@ungap/structured-clone': 1.2.0
ajv: 6.12.6
chalk: 4.1.2
cross-spawn: 7.0.3
debug: 4.3.4
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.3
espree: 9.6.1
esquery: 1.5.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
file-entry-cache: 6.0.1
find-up: 5.0.0
glob-parent: 6.0.2
globals: 13.23.0
graphemer: 1.4.0
ignore: 5.3.0
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
js-yaml: 4.1.0
json-stable-stringify-without-jsonify: 1.0.1
levn: 0.4.1
lodash.merge: 4.6.2
minimatch: 3.1.2
natural-compare: 1.4.0
optionator: 0.9.3
strip-ansi: 6.0.1
text-table: 0.2.0
transitivePeerDependencies:
- supports-color
dev: false
/espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
acorn: 8.11.2
acorn-jsx: 5.3.2(acorn@8.11.2)
eslint-visitor-keys: 3.4.3
dev: false
/esquery@1.5.0:
resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==}
engines: {node: '>=0.10'}
dependencies:
estraverse: 5.3.0
dev: false
/esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
engines: {node: '>=4.0'}
dependencies:
estraverse: 5.3.0
dev: false
/estraverse@5.3.0:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
dev: false
/esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
dev: false
/fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: false
/fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: false
/fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
dev: false
/fastq@1.15.0:
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
dependencies:
reusify: 1.0.4
dev: false
/file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
engines: {node: ^10.12.0 || >=12.0.0}
dependencies:
flat-cache: 3.2.0
dev: false
/find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
dependencies:
locate-path: 6.0.0
path-exists: 4.0.0
dev: false
/flat-cache@3.2.0:
resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==}
engines: {node: ^10.12.0 || >=12.0.0}
dependencies:
flatted: 3.2.9
keyv: 4.5.4
rimraf: 3.0.2
dev: false
/flatted@3.2.9:
resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==}
dev: false
/fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: false
/glob-parent@6.0.2:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
dependencies:
is-glob: 4.0.3
dev: false
/glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
dev: false
/globals@13.23.0:
resolution: {integrity: sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==}
engines: {node: '>=8'}
dependencies:
type-fest: 0.20.2
dev: false
/graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
dev: false
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: false
/ignore@5.3.0:
resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==}
engines: {node: '>= 4'}
dev: false
/import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'}
dependencies:
parent-module: 1.0.1
resolve-from: 4.0.0
dev: false
/imurmurhash@0.1.4:
resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
engines: {node: '>=0.8.19'}
dev: false
/inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
dependencies:
once: 1.4.0
wrappy: 1.0.2
dev: false
/inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: false
/is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'}
dev: false
/is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: 2.1.1
dev: false
/is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
dev: false
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: false
/js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
dependencies:
argparse: 2.0.1
dev: false
/json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
dev: false
/json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
dev: false
/json-stable-stringify-without-jsonify@1.0.1:
resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==}
dev: false
/keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
dependencies:
json-buffer: 3.0.1
dev: false
/levn@0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
dependencies:
prelude-ls: 1.2.1
type-check: 0.4.0
dev: false
/locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
dependencies:
p-locate: 5.0.0
dev: false
/lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: false
/minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
brace-expansion: 1.1.11
dev: false
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: false
/natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: false
/once@1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: false
/optionator@0.9.3:
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
engines: {node: '>= 0.8.0'}
dependencies:
'@aashutoshrathi/word-wrap': 1.2.6
deep-is: 0.1.4
fast-levenshtein: 2.0.6
levn: 0.4.1
prelude-ls: 1.2.1
type-check: 0.4.0
dev: false
/p-limit@3.1.0:
resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
engines: {node: '>=10'}
dependencies:
yocto-queue: 0.1.0
dev: false
/p-locate@5.0.0:
resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
engines: {node: '>=10'}
dependencies:
p-limit: 3.1.0
dev: false
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
dependencies:
callsites: 3.1.0
dev: false
/path-exists@4.0.0:
resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
engines: {node: '>=8'}
dev: false
/path-is-absolute@1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
dev: false
/path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
dev: false
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
dev: false
/punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
dev: false
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: false
/resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
dev: false
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: false
/rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
hasBin: true
dependencies:
glob: 7.2.3
dev: false
/run-parallel@1.2.0:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
dev: false
/shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
dependencies:
shebang-regex: 3.0.0
dev: false
/shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
dev: false
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: false
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'}
dev: false
/supports-color@7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
dev: false
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
dev: false
/type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
dependencies:
prelude-ls: 1.2.1
dev: false
/type-fest@0.20.2:
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
engines: {node: '>=10'}
dev: false
/typescript@5.3.2:
resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==}
engines: {node: '>=14.17'}
hasBin: true
dev: false
/uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
dependencies:
punycode: 2.3.1
dev: false
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
dependencies:
isexe: 2.0.0
dev: false
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: false
/yocto-queue@0.1.0:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: false

2176
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

153
scripts/build-all.ts Executable file
View File

@ -0,0 +1,153 @@
#!/usr/bin/env bun
import './build-local-rules';
import { promises as fs } from 'node:fs';
import { resolve, relative } from 'node:path';
import { isBuiltin } from 'node:module';
import esbuild from 'esbuild';
import type { Plugin } from 'esbuild';
import { memoize } from 'lodash';
import { gray, green } from 'picocolors';
import { dependencies } from '../dist/package.json';
import { dts } from './dts';
import { babelPlugin } from './modifier';
const ENV = (process.env.NODE_ENV ??= 'production');
const PROD = ENV === 'production';
declare global {
interface Array<T> {
filter(
predicate: BooleanConstructor,
): Exclude<T, null | undefined | false | '' | 0>[];
}
}
const log = memoize(console.log);
const plugins: Plugin[] = [
babelPlugin,
{
name: 'alias',
setup(build) {
build.onResolve({ filter: /^jsx-ast-utils$/ }, () => ({
path: resolve('./packages/jsx-ast-utils/src/index.js'),
}));
build.onResolve({ filter: /^jsx-ast-utils\/.+$/ }, ({ path }) => ({
path:
resolve('./packages/jsx-ast-utils/', path.slice('jsx-ast-utils/'.length)) +
'.js',
}));
},
},
];
if (process.env.DEBUG) {
plugins.push({
name: 'deps-check',
setup(build) {
const declared = new Set(Object.keys(dependencies));
build.onResolve({ filter: /^.*$/ }, ({ path, importer }) => {
if (
!path.startsWith('./') &&
!path.startsWith('../') &&
!isBuiltin(path) &&
path !== 'eslint' &&
!path.startsWith('eslint/') &&
!path.startsWith('eslint-module-utils/') &&
!declared.has(path)
) {
log(green(path), gray('from'), './' + relative(process.cwd(), importer));
}
return null;
});
},
});
}
function bundle(
entry: string,
outfile = entry
.replace('./packages/', './dist/')
.replace('src/', '')
.replace('.ts', '.js'),
) {
return esbuild.build({
entryPoints: [entry],
outfile,
bundle: true,
minify: PROD,
platform: 'node',
packages: 'external',
sourcemap: 'linked',
plugins,
define: {},
alias: {},
external: ['find-cache-dir'],
banner: {
js: '/* eslint-disable */',
},
});
}
async function editPackageJson() {
const [state, setState] = await useText('./dist/package.json');
const distPackageJson = JSON.parse(state);
const overrideList = await fs.readdir('dist/overrides');
const npmOverrides = Object.fromEntries(
overrideList.map(name => [name, `file:./overrides/${name}`]),
);
Object.assign(distPackageJson, {
overrides: npmOverrides,
resolutions: Object.fromEntries(
overrideList.map(name => [`**/${name}`, `file:./overrides/${name}`]),
),
pnpm: { overrides: npmOverrides },
});
await setState(JSON.stringify(distPackageJson, null, 2) + '\n');
}
async function useText(path: string) {
const state = await fs.readFile(path, 'utf-8');
const setState = (text: string) => fs.writeFile(path, text);
return [state, setState] as const;
}
function bundleType(source: string, output: string) {
return dts({
source,
dist: output,
project: './tsconfig.build.json',
});
}
async function main() {
console.log('Building type definitions...');
bundleType('./src/index.ts', './dist/index.d.ts');
bundleType('./src/prettier.ts', './dist/prettier.d.ts');
bundleType('./src/types.ts', './dist/types.d.ts');
console.log('Building packages...');
await Promise.all([
bundle('./packages/eslint-plugin-react/index.js'),
bundle('./packages/eslint-plugin-import/src/index.js'),
bundle('./packages/eslint-plugin-jsx-a11y/src/index.js'),
bundle('./packages/eslint-plugin-react-hooks/index.ts'),
bundle('./packages/eslint-plugin-n/lib/index.js', './dist/eslint-plugin-n/index.js'),
bundle('./packages/eslint-import-resolver-typescript/src/index.ts'),
bundle('./src/rules/index.ts', './dist/eslint-plugin-rules/index.js'),
bundle('./src/local/index.ts', './dist/eslint-plugin-local/index.js'),
bundle('./src/index.ts', './dist/index.js'),
bundle('./src/types.ts', './dist/types.js'),
bundle('./src/prettier.ts', './dist/prettier.js'),
editPackageJson(),
]);
console.log('Removing redirect...');
const [distIndex, setDistIndex] = await useText('./dist/index.js');
await setDistIndex(distIndex.replace(/import.*redirect.*;/g, ''));
}
void main();

24
scripts/build-local-rules.ts Executable file
View File

@ -0,0 +1,24 @@
import { promises as fs } from 'node:fs';
import { camelCase } from 'lodash';
const files = (await fs.readdir('./src/rules'))
.filter(file => file.endsWith('.ts'))
.filter(file => file !== 'index.ts')
.map(file => file.slice(0, -3));
const entryFile = /* js */ `
import type { Rule } from 'eslint';
import type { ESLintUtils } from '@typescript-eslint/utils';
${files.map(file => `import ${camelCase(file)} from './${file}';`).join('\n')}
export const rules: Record<
string,
Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>
> = {
${files.map(file => `'${file}': ${camelCase(file)},`).join('\n ')}
};
`.trim();
console.log('Building local rules...');
await fs.writeFile('./src/rules/index.ts', entryFile + '\n');

69
scripts/check-imports.ts Executable file
View File

@ -0,0 +1,69 @@
#!/usr/bin/env bun
import glob from 'fast-glob';
import fs from 'fs';
import { builtinModules } from 'module';
import { uniq } from 'lodash';
import { dependencies, peerDependencies, overrides } from '../dist/package.json';
function checkImports() {
const deps = Object.keys({ ...dependencies, ...peerDependencies, ...overrides }).concat(
'eslint',
);
const builtIn = new Set(builtinModules.flatMap(module => [module, `node:${module}`]));
function findRequires(text: string) {
const list = Array.from(text.matchAll(/require\(["']([^"']+)["']\)/g))
.map(m => m[1])
.filter(
module =>
!(
builtIn.has(module) ||
module.startsWith('eslint/') ||
module.startsWith('typescript/')
),
);
return uniq(list);
}
const moduleMap = glob
.sync(['dist/**/*.js', '!dist/node_modules/**'])
.map(path => ({ key: path, value: findRequires(fs.readFileSync(path, 'utf8')) }));
const files = Object.fromEntries(
moduleMap
.map(({ key, value }) => ({
key,
value: value.filter(
module =>
!(deps.includes(module) || deps.some(dep => module.startsWith(`${dep}/`))),
),
}))
.filter(({ value }) => value.length > 0)
.map(({ key, value }) => [key, value]),
);
const uselessDeps = Object.keys(dependencies).filter(
dep => !moduleMap.some(({ value }) => value.includes(dep)),
);
return {
missingImports: files,
unusedDependencies: uselessDeps,
};
}
function checkDeps() {
const pkgJson = glob
.sync(['dist/node_modules/@*/*/package.json', 'dist/node_modules/*/package.json'])
.sort()
.map(path => fs.readFileSync(path, 'utf8'))
.map(content => JSON.parse(content))
.filter(({ author }) => JSON.stringify(author ?? 'null').includes('ljharb'))
.map(({ name }) => name);
return { suspiciousPackages: pkgJson };
}
console.log({
...checkImports(),
...checkDeps(),
});

39
scripts/dts.ts Normal file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env node
import * as ts from 'typescript';
import {
generateDtsBundle,
type EntryPointConfig,
} from 'dts-bundle-generator/dist/bundle-generator';
export function dts({
source,
dist,
project,
}: {
source: string;
dist: string;
project: string;
}): void {
const entry: EntryPointConfig = {
filePath: source,
failOnClass: false,
libraries: {
importedLibraries: ['eslint-define-config'],
},
output: {
inlineDeclareExternals: false,
inlineDeclareGlobals: false,
sortNodes: false,
noBanner: false,
respectPreserveConstEnum: false,
exportReferencedTypes: true,
},
};
const generatedDts = generateDtsBundle([entry], {
preferredConfigPath: project,
followSymlinks: false,
});
ts.sys.writeFile(dist, generatedDts[0]);
}

117
esbuild.ts → scripts/modifier.ts Executable file → Normal file
View File

@ -1,22 +1,16 @@
#!/usr/bin/env tsx
import assert from 'node:assert';
import { readFileSync } from 'node:fs';
import { resolve, extname, relative } from 'node:path';
import { isBuiltin } from 'node:module';
import esbuild from 'esbuild';
import { resolve, extname } from 'node:path';
import type { Loader, Plugin } from 'esbuild';
import * as babel from '@babel/core';
import { memoize } from 'lodash';
import { gray, green } from 'picocolors';
import type { types as t, types } from '@babel/core';
import { dependencies } from './dist/package.json';
import { createMacro, type MacroHandler } from 'babel-plugin-macros';
import * as polyfill from './src/polyfill';
import * as polyfill from '../src/polyfill';
const polyfills = Object.keys(polyfill);
const ENV = process.env.NODE_ENV || 'development';
const PROD = ENV === 'production';
const ENV = (process.env.NODE_ENV ??= 'production');
class HandlerMap {
map = new Map<string, MacroHandler>();
@ -56,6 +50,10 @@ const map = new HandlerMap()
'object.entries',
replace(t => t.memberExpression(t.identifier('Object'), t.identifier('entries'))),
)
.set(
'hasown',
replace(t => t.memberExpression(t.identifier('Object'), t.identifier('hasOwn'))),
)
.set(
'has',
replace(t => t.memberExpression(t.identifier('Object'), t.identifier('hasOwn'))),
@ -80,10 +78,22 @@ const map = new HandlerMap()
'array.prototype.tosorted',
proto(t => t.identifier('toSorted')),
)
.set(
'array.prototype.toreversed',
proto(t => t.identifier('toReversed')),
)
.set(
'array.prototype.findlast',
proto(t => t.identifier('findLast')),
)
.set(
'string.prototype.matchall',
proto(t => t.identifier('matchAll')),
)
.set(
'string.prototype.includes',
proto(t => t.identifier('includes')),
)
.set(
'object.groupby',
replace(t =>
@ -95,7 +105,7 @@ const map = new HandlerMap()
);
// es-iterator-helpers/Iterator.prototype.*
const polyfillPath = resolve(__dirname, './src/polyfill.ts');
const polyfillPath = resolve(__dirname, '../src/polyfill.ts');
const requirePolyfill = (t: typeof types, name: string) =>
t.memberExpression(
t.callExpression(t.identifier('require'), [t.stringLiteral(polyfillPath)]),
@ -112,6 +122,11 @@ for (const name of polyfills) {
);
}
map.set(
'safe-regex-test',
replace(t => requirePolyfill(t, 'safeRegexTest')),
);
function replace(getReplacement: (types: typeof t) => t.Expression): MacroHandler {
return ({ references, babel: { types: t } }) => {
references.default.forEach(referencePath => {
@ -189,85 +204,3 @@ export const babelPlugin: Plugin = {
});
},
};
declare global {
interface Array<T> {
filter(
predicate: BooleanConstructor,
): Exclude<T, null | undefined | false | '' | 0>[];
}
}
const log = memoize(console.log);
const plugins: Plugin[] = [
babelPlugin,
{
name: 'alias',
setup(build) {
build.onResolve({ filter: /^jsx-ast-utils$/ }, () => ({
path: resolve('./packages/jsx-ast-utils/src/index.js'),
}));
build.onResolve({ filter: /^jsx-ast-utils\/.+$/ }, ({ path }) => ({
path:
resolve('./packages/jsx-ast-utils/', path.slice('jsx-ast-utils/'.length)) +
'.js',
}));
},
},
];
if (process.env.DEBUG) {
plugins.push({
name: 'deps-check',
setup(build) {
const declared = new Set(Object.keys(dependencies));
build.onResolve({ filter: /^.*$/ }, ({ path, importer }) => {
if (
!path.startsWith('./') &&
!path.startsWith('../') &&
!isBuiltin(path) &&
path !== 'eslint' &&
!path.startsWith('eslint/') &&
!path.startsWith('eslint-module-utils/') &&
!declared.has(path)
) {
log(green(path), gray('from'), './' + relative(process.cwd(), importer));
}
return null;
});
},
});
}
async function main(
entry: string,
outfile = entry
.replace('./packages/', './dist/')
.replace('src/', '')
.replace('.ts', '.js'),
) {
await esbuild.build({
entryPoints: [entry],
outfile,
bundle: true,
minify: PROD,
platform: 'node',
packages: 'external',
sourcemap: 'linked',
plugins,
define: {},
banner: {
js: '/* eslint-disable */',
},
});
}
main('./packages/eslint-plugin-react/index.js');
main('./packages/eslint-plugin-import/src/index.js');
main('./packages/eslint-plugin-jsx-a11y/src/index.js');
main('./packages/eslint-plugin-react-hooks/index.ts');
main('./packages/eslint-plugin-n/lib/index.js');
main('./packages/eslint-import-resolver-typescript/src/index.ts');
main('./src/rules/index.ts', './dist/rules/index.js');
main('./src/index.ts', './dist/index.js');

View File

@ -1,13 +1,22 @@
#!/bin/bash
set -e
git-pull() {
name=$1
git config pull.rebase true
git config rebase.autoStash true
git pull --quiet
ref=$(git log -1 --pretty='{"hash":"%H","date":"%aI","committer":"%cn","subject":"%s"}')
yq -iP ".$name=$ref" ../../src/commits.json -o json
}
pull() {
echo "🚛 Pulling $2"
if [ ! -d "packages/$2" ]; then
echo "📦 Repository not found, cloning..."
git clone "https://github.com/$1/$2.git" "packages/$2"
fi
(cd "packages/$2" && git config pull.rebase true && git config rebase.autoStash true && git pull)
(cd "packages/$2" && git-pull "$2")
echo
}

View File

@ -1,6 +1,6 @@
#!/bin/bash
sync() (
cd "packages/$1" && git diff > "../../patch/$1.patch"
cd "packages/$1" && git diff HEAD > "../../patch/$1.patch"
)
sync eslint-import-resolver-typescript

View File

@ -1,20 +0,0 @@
#!/usr/bin/env tsx
import { readdirSync, writeFileSync } from 'node:fs';
import { camelCase } from 'lodash';
const files = readdirSync('./src/rules')
.filter(file => file.endsWith('.ts'))
.filter(file => file !== 'index.ts')
.map(file => file.slice(0, -3));
const entryFile = `
import type { Rule } from 'eslint';
${files.map(file => `import ${camelCase(file)} from "./${file}"`).join(';\n')}
export const rules: Record<string, Rule.RuleModule> = {
${files.map(file => `"${file}": ${camelCase(file)}`).join(',\n ')}
};
`.trim();
writeFileSync('./src/rules/index.ts', entryFile);

View File

@ -1,34 +0,0 @@
#!/usr/bin/env bun
import glob from 'fast-glob';
import fs from 'fs';
import { builtinModules } from 'module';
import { uniq } from 'lodash';
import { dependencies, peerDependencies } from '../dist/package.json';
const deps = Object.keys({ ...dependencies, ...peerDependencies }).concat('eslint');
const builtIn = new Set(builtinModules.flatMap(module => [module, `node:${module}`]));
const files = Object.fromEntries(
glob
.sync('dist/**/*.js')
.map(path => [
path,
uniq(
Array.from(fs.readFileSync(path, 'utf8').matchAll(/require\(["']([^"']+)["']\)/g))
.map(m => m[1])
.filter(
module =>
!(
builtIn.has(module) ||
deps.includes(module) ||
deps.some(dep => module.startsWith(`${dep}/`)) ||
module.startsWith('eslint/') ||
module.startsWith('typescript/')
),
),
),
])
.filter(([, modules]) => modules.length > 0),
);
console.log(files);

38
src/commits.json Normal file
View File

@ -0,0 +1,38 @@
{
"eslint-plugin-import": {
"hash": "f77ceb679d59ced5d9a633123385470a9eea10d9",
"date": "2024-04-07T12:55:28+12:00",
"committer": "Jordan Harband",
"subject": "[actions] cancel in-progress runs on PR updates"
},
"eslint-import-resolver-typescript": {
"hash": "7a02ac08b5aaac8c217f0e87142f97eafcc38fbc",
"date": "2024-04-01T01:06:20+00:00",
"committer": "GitHub",
"subject": "chore(deps): update dependency npm-run-all2 to ^5.0.2 (#277)"
},
"eslint-plugin-jsx-a11y": {
"hash": "0d5321a5457c5f0da0ca216053cc5b4f571b53ae",
"date": "2024-01-27T22:18:19-08:00",
"committer": "Jordan Harband",
"subject": "[Deps] update `@babel/runtime`, `safe-regex-test`"
},
"eslint-plugin-n": {
"hash": "eb11b5b35a6a797dc7fba6df53b1c4dada3a2a55",
"date": "2024-04-17T17:40:32+08:00",
"committer": "GitHub",
"subject": "chore: upgrade globals v15 (#241)"
},
"eslint-plugin-react": {
"hash": "4467db503e38b9356517cf6926d11be544ccf4b1",
"date": "2024-03-16T12:54:58+09:00",
"committer": "Jordan Harband",
"subject": "[Fix] `boolean-prop-naming`: avoid a crash with a non-TSTypeReference type"
},
"jsx-ast-utils": {
"hash": "5943318eaf23764eec3ff397ebb969613d728a95",
"date": "2023-07-28T18:34:04-07:00",
"committer": "Jordan Harband",
"subject": "v3.3.5"
}
}

View File

@ -1,62 +1,155 @@
/// <reference path="./modules.d.ts" />
import './redirect';
import type { ESLintConfig } from 'eslint-define-config';
import fs from 'node:fs';
import type { Rule } from 'eslint';
import type { ESLintUtils } from '@typescript-eslint/utils';
import type { ESLintConfig, Rules } from 'eslint-define-config';
import { typescriptRules } from './presets/typescript';
import { unicornRules } from './presets/unicorn';
import { eslintRules } from './presets/eslint';
import { reactRules } from './presets/react';
import { importRules } from './presets/import';
import { jsDocRules } from './presets/jsdoc';
import { graphqlRules } from './presets/graphql';
import { localRules } from './presets/local';
import { error, warn, off } from './constants';
// @ts-expect-error
const { name } = (0, require)('./package.json');
import { tailwindRules } from './presets/tailwind';
export { error, warn, off };
const unique = <T>(arr: T[]): T[] => [...new Set(arr)];
declare global {
interface Array<T> {
filter(
predicate: BooleanConstructor,
): Exclude<T, null | undefined | false | '' | 0>[];
}
}
const unique = (...arr: (false | undefined | string | string[])[]): string[] => [
...new Set(arr.flat(1).filter(Boolean)),
];
const ensureArray = <T>(value?: T | T[]): T[] =>
value == null ? [] : Array.isArray(value) ? value : [value];
declare module 'eslint-define-config/src/rules/react/no-unknown-property.d.ts' {
export interface NoUnknownPropertyOption {
type RuleLevel = 'error' | 'warn' | 'off' | 0 | 1 | 2;
type RuleEntry<Options> = RuleLevel | [RuleLevel, Partial<Options>];
declare module 'eslint-define-config' {
interface NoUnknownPropertyOption {
extends: ('next' | 'emotion')[];
}
}
export function extendConfig({
plugins,
settings,
rules,
extends: _extends,
overrides,
...rest
}: ESLintConfig = {}): ESLintConfig {
const hasReact = plugins?.includes('react');
const hasReactRefresh = plugins?.includes('react-refresh');
const hasUnicorn = plugins?.includes('unicorn');
const hasNext = ensureArray(_extends).some(name => name.includes(':@next/next'));
export interface LocalRuleOptions {
/** Bans import from the specifier '.' and '..' and replaces it with '.+/index' */
'rules/no-import-dot': RuleEntry<unknown>;
/**
* Enforce template literal expressions to be of `string` type
* @see [restrict-template-expressions](https://typescript-eslint.io/rules/restrict-template-expressions)
*/
'rules/restrict-template-expressions': RuleEntry<{ allow: string[] }>;
/** Ban assignment of empty object literals `{}` and replace them with `Object.create(null)` */
'rules/no-empty-object-literal': RuleEntry<unknown>;
}
const result: ESLintConfig = {
export type RuleOptions = Rules & Partial<LocalRuleOptions>;
export interface CustomRule {
rule: () => Promise<{
default: Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>;
}>;
options?: RuleLevel;
}
/**
* ESLint Configuration.
* @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/)
*/
export type InputConfig = Omit<ESLintConfig, 'rules'> & {
/**
* Rules.
* @see [Rules](https://eslint.org/docs/latest/user-guide/configuring/rules)
*/
rules?: RuleOptions;
/**
* Glob pattern to find paths to custom rule files in JavaScript or TypeScript.
* Note this must be a string literal or an array of string literals since
* this is statically analyzed.
*/
customRuleFiles?: string | string[];
};
/**
* Returns a ESLint config object.
*
* By default, it includes `["@typescript-eslint", "import", "prettier"]` configs.
* Additional bundled plugins include:
*
* 1. [`react`](https://github.com/jsx-eslint/eslint-plugin-react#list-of-supported-rules)
* (automatically enables
* [`react-hooks`](https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks))
* 2. [`react-refresh`](https://github.com/ArnaudBarre/eslint-plugin-react-refresh)
* 3. [`jsx-a11y`](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#supported-rules)
* 4. [`unicorn`](https://github.com/sindresorhus/eslint-plugin-unicorn#rules)
* 5. [`n`](https://github.com/eslint-community/eslint-plugin-n#-rules) (Node.js specific)
* 6. [`jsdoc`](https://github.com/gajus/eslint-plugin-jsdoc#rules)
*
* Non bundled:
* 1. [`graphql`](https://the-guild.dev/graphql/eslint/rules)
*/
export function extendConfig(of: InputConfig = {}): ESLintConfig {
const {
plugins = [],
settings,
rules,
extends: _extends,
overrides,
customRuleFiles,
...rest
} = of;
const hasReact = plugins.includes('react');
const hasReactRefresh = plugins.includes('react-refresh');
const hasUnicorn = plugins.includes('unicorn');
const hasJsDoc = plugins.includes('jsdoc');
const hasGraphQL = plugins.includes('@graphql-eslint');
const hasNext = ensureArray(_extends).some(name => name.includes(':@next/next'));
const hasTailwind = ensureArray(_extends).some(name =>
name.includes('plugin:tailwindcss/'),
);
const ruleDir = false; // ?? findCacheDirectory({ name: '_eslint-rules' });
if (ruleDir) {
fs.rmSync(ruleDir, { recursive: true, force: true });
fs.mkdirSync(ruleDir, { recursive: true });
}
const result: InputConfig = {
root: true,
parser: '@typescript-eslint/parser',
plugins: unique(['@typescript-eslint', 'import', ...(plugins ?? [])]),
plugins: unique('@typescript-eslint', 'import', 'rules', plugins),
env: { node: true, browser: true, es2023: true },
reportUnusedDisableDirectives: true,
parserOptions: {
project: true,
},
extends: unique([
extends: unique(
'eslint:recommended',
'prettier',
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:import/errors',
'plugin:import/typescript',
...(hasReact
? [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
]
: []),
...(_extends ?? []),
]),
hasReact && [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:jsx-a11y/recommended',
],
hasJsDoc && 'plugin:jsdoc/recommended-typescript',
hasGraphQL && 'plugin:@graphql-eslint/recommended',
_extends,
),
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx', '.mts', '.cts'],
@ -73,8 +166,11 @@ export function extendConfig({
},
overrides: [
{
files: ['.eslintrc.js', '*.config.js', 'index.js', 'babel.config.js'],
files: ['.eslintrc.js', '.eslintrc.cjs', '*.config.js', 'index.js'],
extends: ['plugin:@typescript-eslint/disable-type-checked'],
rules: {
'rules/restrict-template-expressions': off,
},
},
{
files: ['*.d.ts'],
@ -82,24 +178,33 @@ export function extendConfig({
'@typescript-eslint/consistent-type-imports': off,
},
},
{
files: ['repl.ts', 'scripts/**/*.ts'],
rules: {
'no-console': off,
},
},
...(overrides ?? []),
],
rules: {
...eslintRules,
...typescriptRules,
'import/export': off,
'import/order': [error, { groups: ['builtin', 'external'] }],
...importRules,
...localRules,
...(hasReact && {
...reactRules,
'react/no-unknown-property': [
error,
{ ignore: hasNext ? ['emotion', 'next'] : ['emotion'] },
{ ignore: hasNext ? ['css', 'next'] : ['css'] },
],
}),
...(hasReactRefresh && {
'react-refresh/only-export-components': [warn, { allowConstantExport: true }],
}),
...(hasUnicorn && unicornRules),
...(hasJsDoc && jsDocRules),
...(hasGraphQL && graphqlRules),
...(hasTailwind && tailwindRules),
...rules,
},
...rest,

View File

@ -1,9 +1,24 @@
import type { ESLint } from 'eslint';
import * as fs from 'node:fs';
import { resolve, basename, extname } from 'node:path';
import { glob } from 'fast-glob';
import { parseModule } from 'esprima';
import query from 'esquery';
import type { Node, Property } from 'estree';
function tryRequire(candidates: string[]) {
for (const candidate of candidates) {
// https://github.com/gulpjs/interpret
const transpilers = [
'esbin/register',
'esbuild-register',
'ts-node/register/transpile-only',
'@swc/register',
'sucrase/register',
'@babel/register',
'coffeescript/register',
];
function tryRequire() {
for (const candidate of transpilers) {
try {
require(candidate);
return;
@ -11,27 +26,52 @@ function tryRequire(candidates: string[]) {
}
}
// https://github.com/gulpjs/interpret
tryRequire([
'esbin/register',
'esbuild-register',
'ts-node/register/transpile-only',
'@swc/register',
'@babel/register',
'coffeescript/register',
]);
const folders = resolve(process.cwd(), 'eslint-local-rules');
const files = fs.readdirSync(folders);
const unwrapDefault = <T = any>(module: any): T => module.default ?? module;
const plugin: ESLint.Plugin = {
rules: {},
};
for (const file of files) {
const name = basename(file, extname(file));
const module = require(resolve(folders, file));
plugin.rules![name] = module.default ?? module;
function hydrateESTreeNode(n: Node): any {
switch (n.type) {
case 'Literal':
return n.value;
case 'ArrayExpression':
return n.elements.filter(Boolean).map(hydrateESTreeNode);
default:
throw new Error(`Unsupported node type: ${n.type}`);
}
}
function parseConfigFile(js: string) {
const [node] = query(
parseModule(js),
'CallExpression[callee.name="extendConfig"] > ObjectExpression > Property[key.name="customRuleFiles"]',
);
return hydrateESTreeNode((node as Property).value);
}
function main() {
const rootDir = process.cwd();
const eslintConfigFile = ['.eslintrc.js', '.eslintrc.cjs']
.map(file => resolve(rootDir, file))
.find(file => fs.existsSync(file));
if (!eslintConfigFile) return;
const eslintConfig = fs.readFileSync(eslintConfigFile, 'utf8');
const customRuleFiles = parseConfigFile(eslintConfig);
if (!customRuleFiles?.length) return;
tryRequire();
for (const file of glob.sync(customRuleFiles)) {
const module = unwrapDefault(require(file));
const name = module.name ?? basename(file, extname(file));
plugin.rules![name] = module;
}
}
main();
export = plugin;

36
src/modules.d.ts vendored Normal file
View File

@ -0,0 +1,36 @@
declare module '@typescript-eslint/utils' {
export * from '@typescript-eslint/utils/dist/index';
}
declare module '@typescript-eslint/typescript-estree' {
export * from '@typescript-eslint/typescript-estree/dist/index';
}
declare module '@typescript-eslint/type-utils' {
export * from '@typescript-eslint/type-utils/dist/index';
}
declare module '@typescript-eslint/utils/eslint-utils' {
export * from '@typescript-eslint/utils/dist/eslint-utils';
}
declare module '@typescript-eslint/utils/json-schema' {
export * from '@typescript-eslint/utils/dist/json-schema';
}
declare module '@typescript-eslint/scope-manager' {
export * from '@typescript-eslint/scope-manager/dist/index';
}
declare module '@typescript-eslint/types' {
export * from '@typescript-eslint/types/dist/index';
}
declare module 'module' {
export function _resolveFilename(
request: string,
parent: {
/**
* Can be null if the parent id is 'internal/preload' (e.g. via --require)
* which doesn't have a file path.
*/
filename: string | null;
},
isMain: boolean,
options?: Record<PropertyKey, unknown>,
): string;
}

View File

@ -57,3 +57,8 @@ export function* map<T, U>(
yield callback(value);
}
}
// safe-regex-test/index.js
export function safeRegexTest(regex: RegExp) {
return (text: string) => regex.test(text);
}

View File

@ -1,15 +1,16 @@
import { error, warn, off } from '../constants';
import { EslintRules } from 'eslint-define-config/src/rules/eslint';
import { ESLintRules } from 'eslint-define-config/rules/eslint';
export const eslintRules: Partial<EslintRules> = {
export const eslintRules: Partial<ESLintRules> = {
'arrow-body-style': [error, 'as-needed'],
'class-methods-use-this': off,
'func-style': [error, 'declaration', { allowArrowFunctions: true }],
'no-async-promise-executor': off,
'no-case-declarations': off,
'no-console': warn,
'no-constant-condition': [error, { checkLoops: false }],
'no-debugger': warn,
'no-duplicate-imports': error,
'no-duplicate-imports': off,
'no-empty': [error, { allowEmptyCatch: true }],
'no-inner-declarations': off,
'no-lonely-if': error,

4
src/presets/graphql.ts Normal file
View File

@ -0,0 +1,4 @@
import { GraphQLRules } from 'eslint-define-config/rules/graphql-eslint';
// https://the-guild.dev/graphql/eslint/rules
export const graphqlRules: Partial<GraphQLRules> = {};

8
src/presets/import.ts Normal file
View File

@ -0,0 +1,8 @@
import { error, off } from '../constants';
import { ImportRules } from 'eslint-define-config/rules/import';
export const importRules: Partial<ImportRules> = {
'import/export': off,
'import/no-duplicates': error,
'import/order': [error, { groups: ['builtin', 'external'] }],
};

3
src/presets/jsdoc.ts Normal file
View File

@ -0,0 +1,3 @@
import { JSDocRules } from 'eslint-define-config/rules/jsdoc';
export const jsDocRules: Partial<JSDocRules> = {};

7
src/presets/local.ts Normal file
View File

@ -0,0 +1,7 @@
import type { LocalRuleOptions } from '../index';
import { error } from '../constants';
export const localRules: Partial<LocalRuleOptions> = {
'rules/no-import-dot': error,
'rules/restrict-template-expressions': error,
};

View File

@ -1,5 +1,5 @@
import { error, off } from '../constants';
import { ReactRules } from 'eslint-define-config/src/rules/react';
import { ReactRules } from 'eslint-define-config/rules/react';
export const reactRules: Partial<ReactRules> = {
'react/display-name': off,

5
src/presets/tailwind.ts Normal file
View File

@ -0,0 +1,5 @@
import { off } from '../constants';
export const tailwindRules = {
'tailwindcss/no-custom-classname': off,
} as const;

View File

@ -1,5 +1,5 @@
import { error, off } from '../constants';
import type { TypeScriptRules } from 'eslint-define-config/src/rules/typescript-eslint';
import { error, off, warn } from '../constants';
import type { TypeScriptRules } from 'eslint-define-config/rules/typescript-eslint';
export const typescriptRules: Partial<TypeScriptRules> = {
'@typescript-eslint/ban-ts-comment': [
@ -16,9 +16,12 @@ export const typescriptRules: Partial<TypeScriptRules> = {
error,
{ disallowTypeAnnotations: false, fixStyle: 'inline-type-imports' },
],
'@typescript-eslint/explicit-member-accessibility': [
warn,
{ accessibility: 'no-public' },
],
'@typescript-eslint/no-empty-interface': [error, { allowSingleExtends: true }],
'@typescript-eslint/no-explicit-any': off,
'@typescript-eslint/no-extraneous-class': error,
'@typescript-eslint/no-misused-promises': [error, { checksVoidReturn: false }],
'@typescript-eslint/no-namespace': off,
'@typescript-eslint/no-unnecessary-type-assertion': error,
@ -27,12 +30,10 @@ export const typescriptRules: Partial<TypeScriptRules> = {
'@typescript-eslint/no-unsafe-call': off,
'@typescript-eslint/no-unsafe-member-access': off,
'@typescript-eslint/no-unsafe-return': off,
'@typescript-eslint/no-unused-vars': [
error,
{ ignoreRestSiblings: true, varsIgnorePattern: '^_' },
],
'@typescript-eslint/no-unused-vars': off,
'@typescript-eslint/no-use-before-define': off,
'@typescript-eslint/no-var-requires': off,
'@typescript-eslint/restrict-template-expressions': off,
'@typescript-eslint/triple-slash-reference': off,
'@typescript-eslint/unbound-method': off,
};

View File

@ -1,5 +1,5 @@
import { error, warn } from '../constants';
import { UnicornRules } from 'eslint-define-config/src/rules/unicorn';
import { UnicornRules } from 'eslint-define-config/rules/unicorn';
const suggest = (suggest: string) => ({ suggest, fix: false });

37
src/prettier.ts Normal file
View File

@ -0,0 +1,37 @@
import type { Config } from 'prettier';
const prettier: Config = {
arrowParens: 'avoid',
tabWidth: 2,
printWidth: 90,
semi: true,
singleQuote: true,
trailingComma: 'all',
plugins: [],
};
export default function defineConfig({
tailwind,
...config
}: Partial<Config> & {
tailwind?: boolean;
}) {
const result: Config = {
...prettier,
...config,
};
if (tailwind) {
ensureHas(result.plugins!, 'prettier-plugin-tailwindcss');
result.tailwindAttributes ??= ['css'];
result.tailwindFunctions ??= ['tw'];
}
return result;
}
function ensureHas<T>(list: T[], item: T) {
if (!list.includes(item)) {
list.push(item);
}
}

View File

@ -1,8 +1,7 @@
import Module from 'module';
// @ts-expect-error
const { name } = (0, require)('./package.json');
const { name } = [require][0]('./package.json');
const _resolveFilename = (Module as any)._resolveFilename;
const _resolveFilename = Module._resolveFilename;
const alias = new Set([
'eslint-import-resolver-typescript',
'eslint-plugin-import',
@ -14,9 +13,14 @@ const alias = new Set([
'eslint-plugin-rules',
]);
(Module as any)._resolveFilename = function (module: string, ...args: any[]) {
if (alias.has(module)) {
module = `${name}/${module}`;
type CDR<T> = T extends [any, ...infer R] ? R : [];
Module._resolveFilename = function (
request: string,
...args: CDR<Parameters<typeof _resolveFilename>>
) {
if (alias.has(request)) {
request = `${name}/${request}`;
}
return _resolveFilename(module, ...args);
return _resolveFilename(request, ...args);
};

View File

@ -1,7 +1,15 @@
import type { Rule } from 'eslint';
import type { ESLintUtils } from '@typescript-eslint/utils';
import noImportDot from "./no-import-dot"
import noImportDot from './no-import-dot';
import noEmptyObjectLiteral from './no-empty-object-literal';
import restrictTemplateExpressions from './restrict-template-expressions';
export const rules: Record<string, Rule.RuleModule> = {
"no-import-dot": noImportDot
};
export const rules: Record<
string,
Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>
> = {
'no-import-dot': noImportDot,
'no-empty-object-literal': noEmptyObjectLiteral,
'restrict-template-expressions': restrictTemplateExpressions,
};

View File

@ -0,0 +1,29 @@
import { defineRule } from '../types';
export default defineRule({
type: 'problem',
docs: {
description:
'Ban assignment of empty object literals `{}` and replace them with `Object.create(null)`',
category: 'Best Practices',
recommended: true,
},
fixable: 'code',
create: context => ({
AssignmentExpression(node) {
if (
node.operator === '=' &&
node.right.type === 'ObjectExpression' &&
node.right.properties.length === 0
) {
context.report({
node,
message:
'Assigning empty object literals are not allowed, use `Object.create(null)` instead.',
fix: fixer => fixer.replaceText(node.right, 'Object.create(null)'),
});
}
},
}),
});

View File

@ -1,19 +1,19 @@
import type { Rule } from "eslint";
import type { Rule } from 'eslint';
const rule: Rule.RuleModule = {
meta: {
type: "problem",
type: 'problem',
docs: {
description:
"Bans import from the specifier '.' and '..' and replaces it with '.+/index'",
category: "Best Practices",
category: 'Best Practices',
recommended: true,
},
fixable: "code",
fixable: 'code',
},
create: context => ({
ImportDeclaration(node) {
if (node.source.value === ".") {
if (node.source.value === '.') {
context.report({
node: node.source,
message:
@ -22,7 +22,7 @@ const rule: Rule.RuleModule = {
return fixer.replaceText(node.source, '"./index"');
},
});
} else if (node.source.value === "..") {
} else if (node.source.value === '..') {
context.report({
node: node.source,
message:

View File

@ -0,0 +1,122 @@
// https://github.com/typescript-eslint/typescript-eslint/blob/75c128856b1ce05a4fec799bfa6de03b3dab03d0/packages/eslint-plugin/src/rules/restrict-template-expressions.ts
import * as ts from 'typescript';
import { ESLintUtils, type TSESTree, AST_NODE_TYPES } from '@typescript-eslint/utils';
import {
getTypeName,
isTypeAnyType,
isTypeFlagSet,
isTypeNeverType,
getConstrainedTypeAtLocation,
} from '@typescript-eslint/type-utils';
import { getParserServices } from '@typescript-eslint/utils/eslint-utils';
const createRule = ESLintUtils.RuleCreator(
name => `https://typescript-eslint.io/rules/${name}`,
);
interface Option {
allow: string[];
}
const defaultOption: Option = {
allow: ['any', 'boolean', 'null', 'undefined', 'number', 'RegExp', 'URLSearchParams'],
};
type MessageId = 'invalidType';
export default createRule<Option[], MessageId>({
name: 'restrict-template-expressions',
meta: {
type: 'problem',
docs: {
description: 'Enforce template literal expressions to be of `string` type',
recommended: 'recommended',
requiresTypeChecking: true,
},
messages: {
invalidType: 'Invalid type "{{type}}" of template literal expression.',
},
schema: [
{
type: 'object',
additionalProperties: false,
properties: {
allow: {
type: 'array',
items: {
type: 'string',
},
description: 'Allow specific types',
uniqueItems: true,
},
},
},
],
},
defaultOptions: [defaultOption],
create(context, [options]) {
const services = getParserServices(context);
const checker = services.program!.getTypeChecker();
const allowed = new Set(options.allow);
const { StringLike, NumberLike, BigIntLike, BooleanLike, Null, Undefined } =
ts.TypeFlags;
function isUnderlyingTypePrimitive(type: ts.Type): boolean {
return (
isTypeFlagSet(type, StringLike) ||
(allowed.has('number') && isTypeFlagSet(type, NumberLike | BigIntLike)) ||
(allowed.has('boolean') && isTypeFlagSet(type, BooleanLike)) ||
(allowed.has('any') && isTypeAnyType(type)) ||
allowed.has(getTypeName(checker, type)) ||
(allowed.has('null') && isTypeFlagSet(type, Null)) ||
(allowed.has('undefined') && isTypeFlagSet(type, Undefined)) ||
(allowed.has('never') && isTypeNeverType(type))
);
}
return {
TemplateLiteral(node: TSESTree.TemplateLiteral): void {
// don't check tagged template literals
if (node.parent.type === AST_NODE_TYPES.TaggedTemplateExpression) {
return;
}
for (const expression of node.expressions) {
const expressionType = getConstrainedTypeAtLocation(services, expression);
if (
!isInnerUnionOrIntersectionConformingTo(
expressionType,
isUnderlyingTypePrimitive,
)
) {
context.report({
node: expression,
messageId: 'invalidType',
data: { type: checker.typeToString(expressionType) },
});
}
}
},
};
function isInnerUnionOrIntersectionConformingTo(
type: ts.Type,
predicate: (underlyingType: ts.Type) => boolean,
): boolean {
return rec(type);
function rec(innerType: ts.Type): boolean {
if (innerType.isUnion()) {
return innerType.types.every(rec);
}
if (innerType.isIntersection()) {
return innerType.types.some(rec);
}
return predicate(innerType);
}
}
},
});

26
src/types.ts Normal file
View File

@ -0,0 +1,26 @@
import type { Rule } from 'eslint';
import type { ESLintUtils } from '@typescript-eslint/utils';
export function defineRules(rules: {
[ruleName: string]: Rule.RuleModule | ESLintUtils.RuleModule<string, unknown[]>;
}) {
return rules;
}
export function defineRule({
name,
create,
...meta
}: Rule.RuleMetaData & {
name?: string;
create: (context: Rule.RuleContext) => Rule.RuleListener;
}): Rule.RuleModule {
const module: Rule.RuleModule = {
meta,
create,
};
if (name != null) {
Object.defineProperty(module, 'name', { value: name });
}
return module;
}

171
src/types/config/env.d.ts vendored Normal file
View File

@ -0,0 +1,171 @@
/**
* An environment provides predefined global variables.
*
* @see [Environments](https://eslint.org/docs/user-guide/configuring/language-options#specifying-environments)
*/
export interface Environments extends Partial<Record<string, boolean>> {
/**
* Browser global variables.
*/
browser?: boolean;
/**
* Node.js global variables and Node.js scoping.
*/
node?: boolean;
/**
* CommonJS global variables and CommonJS scoping (use this for browser-only code that uses Browserify/WebPack).
*/
commonjs?: boolean;
/**
* Globals common to both Node.js and Browser.
*/
'shared-node-browser'?: boolean;
/**
* Enable all ECMAScript 6 features except for modules (this automatically sets the `ecmaVersion` parser option to 6).
*/
es6?: boolean;
/**
* Adds all ECMAScript 2016 globals and automatically sets the `ecmaVersion` parser option to 7.
*/
es2016?: boolean;
/**
* Adds all ECMAScript 2017 globals and automatically sets the `ecmaVersion` parser option to 8.
*/
es2017?: boolean;
/**
* Adds all ECMAScript 2018 globals and automatically sets the `ecmaVersion` parser option to 9.
*/
es2018?: boolean;
/**
* Adds all ECMAScript 2019 globals and automatically sets the `ecmaVersion` parser option to 10.
*/
es2019?: boolean;
/**
* Adds all ECMAScript 2020 globals and automatically sets the `ecmaVersion` parser option to 11.
*/
es2020?: boolean;
/**
* Adds all ECMAScript 2021 globals and automatically sets the `ecmaVersion` parser option to 12.
*/
es2021?: boolean;
/**
* Adds all ECMAScript 2022 globals and automatically sets the `ecmaVersion` parser option to 13.
*/
es2022?: boolean;
/**
* Adds all ECMAScript 2023 globals and automatically sets the `ecmaVersion` parser option to 14.
*/
es2023?: boolean;
/**
* Web workers global variables.
*/
worker?: boolean;
/**
* Defines `require()` and `define()` as global variables as per the amd spec.
*/
amd?: boolean;
/**
* Adds all of the Mocha testing global variables.
*/
mocha?: boolean;
/**
* Adds all of the Jasmine testing global variables for version 1.3 and 2.0.
*/
jasmine?: boolean;
/**
* Jest global variables.
*/
jest?: boolean;
/**
* PhantomJS global variables.
*/
phantomjs?: boolean;
/**
* Protractor global variables.
*/
protractor?: boolean;
/**
* QUnit global variables.
*/
qunit?: boolean;
/**
* jQuery global variables.
*/
jquery?: boolean;
/**
* Prototype.js global variables.
*/
prototypejs?: boolean;
/**
* ShellJS global variables.
*/
shelljs?: boolean;
/**
* Meteor global variables.
*/
meteor?: boolean;
/**
* MongoDB global variables.
*/
mongo?: boolean;
/**
* AppleScript global variables.
*/
applescript?: boolean;
/**
* Java 8 Nashorn global variables.
*/
nashorn?: boolean;
/**
* Service Worker global variables.
*/
serviceworker?: boolean;
/**
* Atom test helper globals.
*/
atomtest?: boolean;
/**
* Ember test helper globals.
*/
embertest?: boolean;
/**
* WebExtensions globals.
*/
webextensions?: boolean;
/**
* GreaseMonkey globals.
*/
greasemonkey?: boolean;
}

View File

@ -0,0 +1,6 @@
/**
* Eslint EslintComments extends.
*
* @see [Eslint EslintComments extends](https://mysticatea.github.io/eslint-plugin-eslint-comments/#%F0%9F%93%96-usage)
*/
export type EslintCommentsExtends = 'plugin:eslint-comments/recommended';

View File

@ -0,0 +1,11 @@
/**
* Eslint GraphQL extends.
*
* @see [Eslint GraphQL extends](https://the-guild.dev/graphql/eslint/docs/configs)
*/
export type GraphqlExtends =
| 'plugin:@graphql-eslint/operations-all'
| 'plugin:@graphql-eslint/operations-recommended'
| 'plugin:@graphql-eslint/relay'
| 'plugin:@graphql-eslint/schema-all'
| 'plugin:@graphql-eslint/schema-recommended';

View File

@ -0,0 +1,9 @@
/**
* Eslint import extends.
*
* @see [Eslint import extends](https://github.com/benmosher/eslint-plugin-import#installation)
*/
export type ImportExtends =
| 'plugin:import/errors'
| 'plugin:import/warnings'
| 'plugin:import/typescript';

View File

@ -0,0 +1,6 @@
/**
* Eslint JSDoc extends.
*
* @see [Eslint JSDoc extends](https://github.com/gajus/eslint-plugin-jsdoc#configuration)
*/
export type JsdocExtends = 'plugin:jsdoc/recommended';

View File

@ -0,0 +1,13 @@
/**
* Eslint Jsonc extends.
*
* @see [Eslint Jsonc extends](https://github.com/ota-meshi/eslint-plugin-jsonc#configuration)
*/
export type JsoncExtends =
| 'plugin:jsdoc/base'
| 'plugin:jsdoc/recommended'
| 'plugin:jsonc/recommended-with-json'
| 'plugin:jsonc/recommended-with-jsonc'
| 'plugin:jsonc/recommended-with-json5'
| 'plugin:jsonc/prettier'
| 'plugin:jsonc/all';

View File

@ -0,0 +1,8 @@
/**
* Eslint JSX A11y extends.
*
* @see [Eslint JSX A11y extends](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y)
*/
export type JsxA11yExtends =
| 'plugin:jsx-a11y/strict'
| 'plugin:jsx-a11y/recommended';

View File

@ -0,0 +1,10 @@
/**
* Eslint MDX extends.
*
* @see [Eslint MDX extends](https://github.com/mdx-js/eslint-mdx/tree/master/packages/eslint-plugin-mdx)
*/
export type MdxExtends =
| 'plugin:mdx/base'
| 'plugin:mdx/code-blocks'
| 'plugin:mdx/overrides'
| 'plugin:mdx/recommended';

View File

@ -0,0 +1,9 @@
/**
* Eslint N (Node) extends.
*
* @see [Eslint N extends](https://github.com/eslint-community/eslint-plugin-n#-configs)
*/
export type NExtends =
| 'plugin:n/recommended'
| 'plugin:n/recommended-module'
| 'plugin:n/recommended-script';

View File

@ -0,0 +1,9 @@
/**
* Eslint Node extends.
*
* @see [Eslint Node extends](https://github.com/mysticatea/eslint-plugin-node#-configs)
*/
export type NodeExtends =
| 'plugin:node/recommended'
| 'plugin:node/recommended-module'
| 'plugin:node/recommended-script';

View File

@ -0,0 +1,6 @@
/**
* Eslint Prettier extends.
*
* @see [Eslint Prettier extends](https://github.com/prettier/eslint-plugin-prettier#recommended-configuration)
*/
export type PrettierExtends = 'plugin:prettier/recommended' | 'prettier';

View File

@ -0,0 +1,6 @@
/**
* Eslint promise extends.
*
* @see [Eslint promise extends](https://github.com/eslint-community/eslint-plugin-promise#usage)
*/
export type PromiseExtends = 'plugin:promise/recommended';

View File

@ -0,0 +1,6 @@
/**
* Eslint ReactHooks extends.
*
* @see [Eslint ReactHooks extends](https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks)
*/
export type ReactHooksExtends = 'plugin:react-hooks/recommended';

View File

@ -0,0 +1,9 @@
/**
* Eslint React extends.
*
* @see [Eslint React extends](https://github.com/jsx-eslint/eslint-plugin-react)
*/
export type ReactExtends =
| 'plugin:react/all'
| 'plugin:react/jsx-runtime'
| 'plugin:react/recommended';

View File

@ -0,0 +1,6 @@
/**
* Eslint Sonarjs extends.
*
* @see [Eslint Sonarjs extends](https://github.com/SonarSource/eslint-plugin-sonarjs#available-configurations)
*/
export type SonarjsExtends = 'plugin:sonarjs/recommended';

View File

@ -0,0 +1,11 @@
/**
* Eslint TestingLibrary extends.
*
* @see [Eslint TestingLibrary extends](https://github.com/testing-library/eslint-plugin-testing-library)
*/
export type TestingLibraryExtends =
| 'plugin:testing-library/angular'
| 'plugin:testing-library/dom'
| 'plugin:testing-library/marko'
| 'plugin:testing-library/react'
| 'plugin:testing-library/vue';

View File

@ -0,0 +1,8 @@
/**
* Eslint Unicorn extends.
*
* @see [Eslint Unicorn extends](https://github.com/sindresorhus/eslint-plugin-unicorn)
*/
export type UnicornExtends =
| 'plugin:unicorn/recommended'
| 'plugin:unicorn/all';

View File

@ -0,0 +1,6 @@
/**
* Eslint Vitest extends.
*
* @see [Eslint Vitest extends](https://eslint.vuejs.org/user-guide/#usage)
*/
export type VitestExtends = 'plugin:vitest/all' | 'plugin:vitest/recommended';

View File

@ -0,0 +1,13 @@
/**
* Eslint Vue Pug extends.
*
* @see [Eslint Vue Pug extends](https://github.com/rashfael/eslint-plugin-vue-pug#usage)
*/
export type VuePugExtends =
| 'plugin:vue-pug/base'
| 'plugin:vue-pug/vue3-essential'
| 'plugin:vue-pug/vue3-strongly-recommended'
| 'plugin:vue-pug/vue3-recommended'
| 'plugin:vue-pug/essential'
| 'plugin:vue-pug/strongly-recommended'
| 'plugin:vue-pug/recommended';

View File

@ -0,0 +1,13 @@
/**
* Eslint Vue extends.
*
* @see [Eslint Vue extends](https://eslint.vuejs.org/user-guide/#usage)
*/
export type VueExtends =
| 'plugin:vue/base'
| 'plugin:vue/vue3-essential'
| 'plugin:vue/vue3-strongly-recommended'
| 'plugin:vue/vue3-recommended'
| 'plugin:vue/essential'
| 'plugin:vue/strongly-recommended'
| 'plugin:vue/recommended';

4
src/types/config/extends/eslint.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
/**
* Eslint extends.
*/
export type EslintExtends = 'eslint:recommended' | 'eslint:all';

82
src/types/config/extends/index.d.ts vendored Normal file
View File

@ -0,0 +1,82 @@
import type { LiteralUnion } from '../../utility-types';
import type { EslintExtends } from './eslint';
import type { EslintCommentsExtends } from './eslint-plugin-eslint-comment';
import type { GraphqlExtends } from './eslint-plugin-graphql';
import type { ImportExtends } from './eslint-plugin-import';
import type { JsdocExtends } from './eslint-plugin-jsdoc';
import type { JsoncExtends } from './eslint-plugin-jsonc';
import type { MdxExtends } from './eslint-plugin-mdx';
import type { NExtends } from './eslint-plugin-n';
import type { NodeExtends } from './eslint-plugin-node';
import type { PrettierExtends } from './eslint-plugin-prettier';
import type { PromiseExtends } from './eslint-plugin-promise';
import type { ReactExtends } from './eslint-plugin-react';
import type { ReactHooksExtends } from './eslint-plugin-react-hooks';
import type { SonarjsExtends } from './eslint-plugin-sonarjs';
import type { TestingLibraryExtends } from './eslint-plugin-testing-library';
import type { UnicornExtends } from './eslint-plugin-unicorn';
import type { VitestExtends } from './eslint-plugin-vitest';
import type { VueExtends } from './eslint-plugin-vue';
import type { VuePugExtends } from './eslint-plugin-vue-pug';
import type { IntlifyVueI18nExtends } from './intlify-vue-i18n';
import type { TypescriptEslintExtends } from './typescript-eslint';
/**
* This is a special exported interface for other packages to declare
* additional extensions that should bail out for eslint extensions. For example
* `'@typescript-eslint/eslint-plugin'` can declare it like so in its `d.ts`:
*
* ```ts
* declare module 'eslint-define-config' {
* export interface CustomExtends {
* 'plugin:@typescript-eslint/all': void;
* 'plugin:@typescript-eslint/base': void;
* 'plugin:@typescript-eslint/disable-type-checked': void;
* 'plugin:@typescript-eslint/eslint-recommended': void;
* 'plugin:@typescript-eslint/recommended-type-checked': void;
* 'plugin:@typescript-eslint/recommended': void;
* 'plugin:@typescript-eslint/strict-type-checked': void;
* 'plugin:@typescript-eslint/strict': void;
* 'plugin:@typescript-eslint/stylistic-type-checked': void;
* 'plugin:@typescript-eslint/stylistic': void;
* }
* }
* ```
*/
export interface CustomExtends {}
/**
* All known extends.
*/
export type KnownExtends = LiteralUnion<
| EslintCommentsExtends
| EslintExtends
| GraphqlExtends
| ImportExtends
| IntlifyVueI18nExtends
| JsdocExtends
| JsoncExtends
| MdxExtends
| NExtends
| NodeExtends
| PrettierExtends
| PromiseExtends
| ReactExtends
| ReactHooksExtends
| SonarjsExtends
| TestingLibraryExtends
| TypescriptEslintExtends
| UnicornExtends
| VitestExtends
| VueExtends
| VuePugExtends
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
| keyof CustomExtends
>;
/**
* Extending Configuration Files.
*
* @see [Extends](https://eslint.org/docs/user-guide/configuring/configuration-files#extending-configuration-files)
*/
export type Extends = KnownExtends | KnownExtends[];

View File

@ -0,0 +1,6 @@
/**
* Eslint Intlify VueI18n extends.
*
* @see [Eslint Intlify VueI18n extends](https://eslint-plugin-vue-i18n.intlify.dev/started.html)
*/
export type IntlifyVueI18nExtends = 'plugin:@intlify/vue-i18n/recommended';

View File

@ -0,0 +1,17 @@
/**
* Typescript eslint extends.
*
* @see [Typescript eslint extends](https://typescript-eslint.io/linting/configs#recommended-configurations)
*/
export type TypescriptEslintExtends =
| 'plugin:@typescript-eslint/all'
| 'plugin:@typescript-eslint/base'
| 'plugin:@typescript-eslint/disable-type-checked'
| 'plugin:@typescript-eslint/eslint-recommended'
| 'plugin:@typescript-eslint/recommended-requiring-type-checking' // this requiring-type-checking is deprecated and only for @typescript-eslint/eslint-plugin@v5
| 'plugin:@typescript-eslint/recommended-type-checked'
| 'plugin:@typescript-eslint/recommended'
| 'plugin:@typescript-eslint/strict-type-checked'
| 'plugin:@typescript-eslint/strict'
| 'plugin:@typescript-eslint/stylistic-type-checked'
| 'plugin:@typescript-eslint/stylistic';

121
src/types/config/index.d.ts vendored Normal file
View File

@ -0,0 +1,121 @@
import type { Parser, ParserOptions } from '../parser-options';
import type { Rules } from '../rules';
import type { Environments } from './env';
import type { Extends } from './extends';
import type { Overrides } from './overrides';
import type { Plugin } from './plugin';
import type { Settings } from './settings';
/**
* ESLint Configuration.
*
* @see [ESLint Configuration](https://eslint.org/docs/latest/user-guide/configuring/)
*/
export interface ESLintConfig {
/**
* @see [Using Configuration Files](https://eslint.org/docs/latest/user-guide/configuring/configuration-files#using-configuration-files)
*/
root?: boolean;
/**
* Tell ESLint to ignore specific files and directories.
*
* @see [Ignore Patterns](https://eslint.org/docs/latest/user-guide/configuring/ignoring-code)
*/
ignorePatterns?: string[];
/**
* An environment provides predefined global variables.
*
* @see [Environments](https://eslint.org/docs/latest/user-guide/configuring/language-options#specifying-environments)
*/
env?: Environments;
/**
* Extending Configuration Files.
*
* @see [Extends](https://eslint.org/docs/latest/user-guide/configuring/configuration-files#extending-configuration-files)
*/
extends?: Extends;
/**
* Specifying Globals.
*
* @see [Globals](https://eslint.org/docs/latest/user-guide/configuring/language-options#specifying-globals)
*/
globals?: Record<
string,
'readonly' | 'writable' | false | 'readable' | true | 'writeable' | 'off'
>;
/**
* Parser.
*
* @see [Working with Custom Parsers](https://eslint.org/docs/latest/developer-guide/working-with-custom-parsers)
* @see [Specifying Parser](https://eslint.org/docs/latest/user-guide/configuring/plugins#configure-a-parser)
*/
parser?: Parser;
/**
* Parser Options.
*
* @see [Working with Custom Parsers](https://eslint.org/docs/latest/developer-guide/working-with-custom-parsers)
* @see [Specifying Parser Options](https://eslint.org/docs/latest/user-guide/configuring/language-options#specifying-parser-options)
*/
parserOptions?: ParserOptions;
/**
* Which third-party plugins define additional rules, environments, configs, etc. for ESLint to use.
*
* @see [Configuring Plugins](https://eslint.org/docs/latest/user-guide/configuring/plugins#configure-plugins)
*/
plugins?: Plugin[];
/**
* Specifying Processor.
*
* @see [processor](https://eslint.org/docs/latest/user-guide/configuring/plugins#specify-a-processor)
*/
processor?: string;
/**
* Rules.
*
* @see [Rules](https://eslint.org/docs/latest/user-guide/configuring/rules)
*/
rules?: Partial<Rules>;
/**
* Overrides.
*
* @see [How do overrides work](https://eslint.org/docs/latest/user-guide/configuring/configuration-files#how-do-overrides-work)
*/
overrides?: Overrides;
/**
* Settings.
*
* @see [Settings](https://eslint.org/docs/latest/user-guide/configuring/configuration-files#adding-shared-settings)
*/
settings?: Settings;
/**
* Disabling Inline Comments.
*
* @see [Disabling Inline Comments](https://eslint.org/docs/latest/user-guide/configuring/rules#disabling-inline-comments)
*/
noInlineConfig?: boolean;
/**
* Report unused `ESLint-disable` comments.
*
* @see [Report unused `ESLint-disable` comments](https://eslint.org/docs/latest/user-guide/configuring/rules#report-unused-eslint-disable-comments)
*/
reportUnusedDisableDirectives?: boolean;
}
export * from './env';
export * from './extends';
export * from './overrides';
export * from './plugin';
export * from './settings';

Some files were not shown because too many files have changed in this diff Show More