diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 020f45c34..000000000 --- a/.eslintignore +++ /dev/null @@ -1,13 +0,0 @@ -packages/prettier-config/.prettierrc.js -packages/textlint-config/.textlintrc -packages/babel-preset/babel.config.js -packages/babel-preset/fixture/test.js -packages/babel-preset/fixture/test.ts -packages/stylelint-config/.stylelintrc.js -packages/lint-staged-config/.lintstagedrc.js -packages/eslint-config/src/global.d.ts -packages/eslint-config/src/types.d.ts -packages/eslint-config/__fixtures__/** - -tsup.config.ts -pnpm-lock.yaml diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index ccf436ff4..000000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,35 +0,0 @@ -const config = require("./packages/eslint-config/dist"); -const globals = require("./packages/eslint-config/dist/globals"); - -module.exports = { - ...config, - extends: [...config.extends, "./packages/eslint-config/dist/typescript-type-checking"], - globals: { - ...config?.globals, - ...globals.es2021, - }, - overrides: [ - ...config.overrides, - { - files: ["*.ts", "*.mts", "*.cts", "*.tsx", ".mdx"], - parserOptions: { - project: true, - tsconfigRootDir: __dirname, - }, - }, - { - files: ["packages/eslint-config/src/config/**/*.ts", "packages/eslint-config/src/typescript-type-checking.ts"], - rules: { - "perfectionist/sort-objects": "off", - }, - }, - ], - root: true, - rules: { - ...config.rules, - // Customize your rules - "no-console": "off", - "no-secrets/no-secrets": "off", - "unicorn/text-encoding-identifier-case": "off", - }, -}; diff --git a/.lintstagedrc.js b/.lintstagedrc.js index 4f437b3b4..9cc5dee3c 100644 --- a/.lintstagedrc.js +++ b/.lintstagedrc.js @@ -1,3 +1,7 @@ import { defineConfig } from "./packages/lint-staged-config/dist/index.mjs"; -export default defineConfig(); +export default defineConfig({ + eslint: { + config: "./eslint.config.js", + } +}); diff --git a/.prettierrc.cjs b/.prettierrc.cjs new file mode 100644 index 000000000..1bb4069fb --- /dev/null +++ b/.prettierrc.cjs @@ -0,0 +1 @@ +exports.modules = require("./packages/prettier-config"); diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index 439521962..000000000 --- a/.prettierrc.js +++ /dev/null @@ -1,3 +0,0 @@ -import config from "./packages/prettier-config"; - -export default config; diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 000000000..85a9aff00 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,9 @@ +import { createConfig } from "./packages/eslint-config/dist/index.mjs"; + +export default createConfig({ + zod: true, + unocss: true, + ignores: [ + "eslint.config.js" + ] +}); diff --git a/nx.json b/nx.json index 993b27458..2e16347c6 100644 --- a/nx.json +++ b/nx.json @@ -13,12 +13,20 @@ }, "lint:eslint": { "dependsOn": ["default"], - "inputs": ["default", "{workspaceRoot}/.eslintrc.cjs", "{workspaceRoot}/.eslintrc.js"], + "inputs": [ + "default", + "{workspaceRoot}/.eslintrc.cjs", + "{workspaceRoot}/.eslintrc.js" + ], "cache": true }, "lint:eslint:fix": { "dependsOn": ["default"], - "inputs": ["default", "{workspaceRoot}/.eslintrc.cjs", "{workspaceRoot}/.eslintrc.js"], + "inputs": [ + "default", + "{workspaceRoot}/.eslintrc.cjs", + "{workspaceRoot}/.eslintrc.js" + ], "cache": true }, "lint:package-json": { @@ -38,11 +46,19 @@ "cache": true }, "test": { - "dependsOn": ["default", "^default", "{projectRoot}/vitest.config.ts"], + "dependsOn": [ + "default", + "^default", + "{projectRoot}/vitest.config.ts" + ], "cache": true }, "test:coverage": { - "dependsOn": ["default", "^default", "{projectRoot}/vitest.config.ts"], + "dependsOn": [ + "default", + "^default", + "{projectRoot}/vitest.config.ts" + ], "cache": true } }, @@ -52,7 +68,11 @@ } }, "namedInputs": { - "default": ["sharedGlobals", "{projectRoot}/**/*", "!{projectRoot}/**/*.md"], + "default": [ + "sharedGlobals", + "{projectRoot}/**/*", + "!{projectRoot}/**/*.md" + ], "public": [ "default", "{workspaceRoot}/dist", diff --git a/package.json b/package.json index b0569cbc9..bc8993961 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "private": true, "description": "This project is a code style guide of all basic back- and front end project used at Anolilab.", "keywords": [ - "babel", "es2015", "es2018", "es6", @@ -61,18 +60,18 @@ "clean": "nx run-many --target=clean && rimraf node_modules", "preinstall": "node verify-node-version.cjs", "postinstall": "is-ci || husky || exit 0", - "lint:eslint": "eslint -c .eslintrc.js --ext js,cjs,mjs,ts,tsx,json,yaml,yml,md,mdx ./packages", - "lint:eslint:fix": "eslint -c .eslintrc.js --ext js,cjs,mjs,ts,tsx,json,yaml,yml,md,mdx ./packages --fix", - "lint:prettier:root": "prettier --config=.prettierrc.js --check '*.{json,yml,yaml,js,ts}'", - "lint:prettier:root:fix": "prettier --config=.prettierrc.js --write '*.{json,yml,yaml,js,ts}'", + "lint": "pnpm run lint:prettier && pnpm run lint:eslint", + "lint:eslint": "nx run-many --target=lint:eslint --all --parallel", + "lint:eslint:fix": "nx run-many --target=lint:eslint:fix --all --parallel", + "lint:fix": "pnpm run lint:prettier:fix && pnpm run lint:eslint:fix", + "lint:prettier": "nx run-many --target=lint:prettier --all --parallel", + "lint:prettier:fix": "nx run-many --target=lint:prettier:fix --all --parallel", "lint:secrets": "secretlint **/*", "lint:staged": "lint-staged --verbose --concurrent false --debug", "lint:styles": "stylelint", "lint:text": "textlint ./.github/ ./packages/** ./README.md ./UPGRADE.md --parallel --experimental --cache --dry-run", "lint:text:fix": "textlint ./.github/ ./packages/** ./README.md ./UPGRADE.md --parallel --experimental --fix", - "prettier": "prettier --config=.prettierrc.js --write '**/*.{js,jsx,cjs,tsx,ts,less,md,json}'", - "sort-package-json": "sort-package-json ./packages/**/package.json ./package.json", - "test:all": "nx run-many --target=test:coverage --projects=browserslist-config-anolilab,stylelint-config,eslint-config && pnpm test:stylelint && pnpm test:babel", + "test:all": "nx run-many --target=test:coverage --projects=browserslist-config-anolilab,stylelint-config,eslint-config && pnpm test:stylelint", "test:browserslist-config-anolilab": "pnpm --filter \"browserslist-config-anolilab\" run test", "test:coverage:browserslist-config-anolilab": "pnpm --filter \"browserslist-config-anolilab\" run test:coverage", "test:coverage:lint-staged-config": "pnpm --filter \"lint-staged-config\" run test:coverage", @@ -85,9 +84,6 @@ }, "dependencies": { "@anolilab/multi-semantic-release": "^1.1.6", - "@babel/cli": "^7.26.4", - "@babel/core": "^7.26.0", - "@babel/preset-env": "^7.26.0", "@commitlint/cli": "^19.6.1", "@commitlint/config-conventional": "^19.6.0", "@commitlint/core": "^19.6.1", @@ -97,17 +93,11 @@ "@types/node": "18.19.70", "@vitest/coverage-v8": "^2.1.8", "audit-ci": "^7.1.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2", "commitizen": "^4.3.1", "conventional-changelog-conventionalcommits": "8.0.0", "cross-env": "^7.0.3", "cz-conventional-changelog": "^3.3.0", - "eslint": "^9.17.0", - "eslint-plugin-deprecation": "^3.0.0", - "eslint-plugin-editorconfig": "^4.0.3", - "eslint-plugin-mdx": "^3.1.5", - "eslint-plugin-vitest": "^0.5.4", - "eslint-plugin-vitest-globals": "^1.5.0", + "eslint": "^9.18.0", "husky": "^9.1.7", "is-ci": "^4.1.0", "lint-staged": "^15.3.0", @@ -119,8 +109,7 @@ "rimraf": "^6.0.1", "secretlint": "9.0.0", "semantic-release": "^24.2.1", - "sort-package-json": "^2.12.0", - "stylelint": "^16.12.0", + "stylelint": "^16.13.0", "taze": "^18.1.0", "textlint": "^14.4.2", "typescript": "5.7.3", @@ -136,23 +125,5 @@ "nanoid@<3.3.8": ">=3.3.8", "chrono-node@<2.2.4": ">=2.2.4" } - }, - "anolilab": { - "lint-staged-config": { - "eslint": { - "config": "./.eslintrc.js" - } - }, - "eslint-config": { - "plugin": { - "tsdoc": false, - "etc": false - }, - "warn_on_unsupported_typescript_version": false, - "info_on_disabling_jsx_react_rule": false, - "info_on_disabling_prettier_conflict_rule": false, - "info_on_disabling_jsonc_sort_keys_rule": false, - "info_on_disabling_etc_no_deprecated": false - } } } diff --git a/packages/eslint-config/.prettierignore b/packages/eslint-config/.prettierignore new file mode 100644 index 000000000..ebf52909d --- /dev/null +++ b/packages/eslint-config/.prettierignore @@ -0,0 +1,9 @@ +.gitkeep +.env* +*.ico +*.lock +dist +CHANGELOG.md +coverage +node_modules +.eslintcache diff --git a/packages/eslint-config/.prettierrc.js b/packages/eslint-config/.prettierrc.js new file mode 100644 index 000000000..de1375efd --- /dev/null +++ b/packages/eslint-config/.prettierrc.js @@ -0,0 +1,6 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import config from "@anolilab/prettier-config"; + +export default { + ...config, +}; diff --git a/packages/eslint-config/README.md b/packages/eslint-config/README.md index 48f1f6440..b93db704e 100644 --- a/packages/eslint-config/README.md +++ b/packages/eslint-config/README.md @@ -22,28 +22,28 @@ Our package serves as a valuable resource for JavaScript/Typescript-based projects, offering composable [ESLint](https://eslint.org/) configurations. It encompasses a range of features, including performance optimization and the flexibility to extend pre-defined base configurations. -- Tailored Configuration for Workspaces: With this package, each workspace within your monorepo gains the ability to have its own customized ESLint configuration. This ensures that individual projects can maintain their specific requirements while still adhering to the overall guidelines. +- Tailored Configuration for Workspaces: With this package, each workspace within your monorepo gains the ability to have its own customized ESLint configuration. This ensures that individual projects can maintain their specific requirements while still adhering to the overall guidelines. -- Configurability at Your Fingertips: Crafting your workspace's ESLint configuration is a breeze, thanks to the seamless composition of pre-defined base configurations. This empowers you to tailor the settings to suit your project's unique needs, without starting from scratch. +- Configurability at Your Fingertips: Crafting your workspace's ESLint configuration is a breeze, thanks to the seamless composition of pre-defined base configurations. This empowers you to tailor the settings to suit your project's unique needs, without starting from scratch. -- Streamlined Convenience: Say goodbye to the hassle of installing plugins for each workspace. Our package integrates [@rushstack/eslint-patch](https://www.npmjs.com/package/@rushstack/eslint-patch), eliminating the need for repetitive plugin installations. Enjoy peace of mind as you focus on your work, knowing that the necessary plugins are automatically included. +- Streamlined Convenience: Say goodbye to the hassle of installing plugins for each workspace. Our package integrates [@rushstack/eslint-patch](https://www.npmjs.com/package/@rushstack/eslint-patch), eliminating the need for repetitive plugin installations. Enjoy peace of mind as you focus on your work, knowing that the necessary plugins are automatically included. -- Enhanced Efficiency: We've optimized the package's performance by intelligently enabling plugins based on file naming conventions. This streamlined approach ensures that your ESLint checks run efficiently, targeting the relevant files and maximizing productivity. +- Enhanced Efficiency: We've optimized the package's performance by intelligently enabling plugins based on file naming conventions. This streamlined approach ensures that your ESLint checks run efficiently, targeting the relevant files and maximizing productivity. In summary, our package provides comprehensive and adaptable ESLint configurations for JavaScript and Typescript projects. It empowers you to achieve code quality while minimizing overhead and maximizing productivity throughout your workspaces. ## Highlights -- Zero-config, but configurable when needed. -- Enforces readable code, because you read more code than you write. -- No need to specify file paths to lint as it lints all JS/TS files except for commonly ignored paths. -- Config overrides per files/globs. -- TypeScript supported by default, if `typescript` was installed. -- Includes many useful ESLint plugins, like [unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn), [import](https://github.com/benmosher/eslint-plugin-import) and [more](#plugins). -- Automatically enables rules based on the [engines](https://docs.npmjs.com/files/package.json#engines) field in your package.json. -- Specify indent and semicolon preferences easily without messing with the rule config. -- Disables rules that conflict with [Prettier](#let-prettier-handle-style-related-rules). -- Typesafe, because it's written in TypeScript and uses [eslint-define-config](https://github.com/Shinigami92/eslint-define-config) to define the config. +- Zero-config, but configurable when needed. +- Enforces readable code, because you read more code than you write. +- No need to specify file paths to lint as it lints all JS/TS files except for commonly ignored paths. +- Config overrides per files/globs. +- TypeScript supported by default, if `typescript` was installed. +- Includes many useful ESLint plugins, like [unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn), [import](https://github.com/benmosher/eslint-plugin-import) and [more](#plugins). +- Automatically enables rules based on the [engines](https://docs.npmjs.com/files/package.json#engines) field in your package.json. +- Specify indent and semicolon preferences easily without messing with the rule config. +- Disables rules that conflict with [Prettier](#let-prettier-handle-style-related-rules). +- Typesafe, because it's written in TypeScript and uses [eslint-define-config](https://github.com/Shinigami92/eslint-define-config) to define the config. ## Install @@ -65,402 +65,29 @@ yarn add -D eslint @anolilab/eslint-config eslint-plugin-import@npm:eslint-plugi ## Usage -If you don’t have a `.eslintrc.js`, we will create the file for you after installing `@anolilab/eslint-config`. - -If you already have a `.eslintrc.js`, then you can extend the `.eslintrc.js`, with `@anolilab/eslint-config`. - -> Note: If the script detects an existing `.eslintrc.js` file, it will not overwrite it. - -> Note: It can happen that the postinstall script don't run, then you have to add the `.eslintrc.js` manually, or you will use bin command `./node_modules/bin/anolilab-eslint-config` to generate it. - > Note: Our default export contains all of our ESLint rules, including ECMAScript 6+. `@anolilab/eslint-config` use the `ecmaVersion`:`2021` as default. > > To change this configuration, change `env: { es2021: false, then active you needed env }` same for, `parserOptions: { "ecmaVersion": 2021 change the version }` -```js -/** @ts-check */ -const { defineConfig } = require('@anolilab/eslint-config/define-config'); - -/// -/// -/// -/// -/// - -module.exports = defineConfig({ - env: { - // Your environments (which contains several predefined global variables) - // - // browser: true, - // node: true, - // mocha: true, - // jest: true, - // jquery: true - }, - extends: ["@anolilab/eslint-config"], - globals: { - // Your global variables (setting to false means it's not allowed to be reassigned) - // - // myGlobal: false - }, - root: true, - rules: { - // Customize your rules - }, -}); -``` - -For more advanced use cases see the example configurations for Node, TypeScript, React or Prettier. - -> Note: `@anolilab/eslint-config` will handle the configuration for almost all eslint-plugins / eslint-configs automatically. -> With this you only need to install the needed plugins/configs for TypeScript or React and you done. - -### TypeScript - -```bash -npm install --save-dev typescript -``` - -Please extend the `.eslintrc.js` file with the correct `tsconfig.js` path if you have a custom path. - -```js -module.exports = { - parserOptions: { - project: "./tsconfig.eslint.json", - }, -}; -``` - -For projects that use TypeScript and want additional rules that require type information (rules using type information take longer to run). - -Extend the `.eslintrc.js` file: - -```js -/** @ts-check */ -const { defineConfig } = require('@anolilab/eslint-config/define-config'); - -/// -/// -/// -/// -/// - -module.exports = defineConfig({ - env: { - // Your environments (which contains several predefined global variables) - // - // browser: true, - // node: true, - // mocha: true, - // jest: true, - // jquery: true - }, - extends: ["@anolilab/eslint-config", "@anolilab/eslint-config/typescript-type-checking"], - globals: { - // Your global variables (setting to false means it's not allowed to be reassigned) - // - // myGlobal: false - }, - root: true, - rules: { - // Customize your rules - }, -}); -``` - -> Tip: Run eslint with the TIMING=1 to identify slow rules. -> -> `TIMING=1 eslint . --ext .ts,.tsx` -> -> This is useful to identify rules that are slow because they require type information. - -### React - -You need to have "react" and "react-dom" installed. - -```bash -npm install --save-dev eslint-plugin-react eslint-plugin-react-hooks - -yarn add -D eslint-plugin-react eslint-plugin-react-hooks - -pnpm add -D eslint-plugin-react eslint-plugin-react-hooks -``` - -Or for the use of `TypeScript` in react install "typescript" as a dev dependency. - -Please extend the `.eslintrc.js` file with the correct `tsconfig.js` path if you have a custom path. - -```js -module.exports = { - parserOptions: { - project: "./tsconfig.eslint.json", - }, -}; -``` - -Or for the use of `.jsx` files install "@babel/plugin-syntax-jsx" as a dev dependency. - -```bash -npm install --save-dev babel @babel/plugin-syntax-jsx - -yarn add -D babel @babel/plugin-syntax-jsx - -pnpm add -D babel @babel/plugin-syntax-jsx -``` - -In your `babel.config.js` file add the plugin. - -```js -const babelPluginSyntaxJSX = require("@babel/plugin-syntax-jsx"); - -module.exports = { - plugins: [ - [ - babelPluginSyntaxJSX, - { - pragma: "React.createElement", - pragmaFrag: "React.Fragment", - }, - ], - ], -}; -``` - -### MDX - -```bash -npm install --save-dev eslint eslint-plugin-mdx -``` - -For more information about `missing` or `optional` to install rules see the `eslint` console output. - -### Config - -You can configure `@anolilab/eslint-config` options with your `package.json` file. - -Add this property to your package.json: - -```json5 -{ - anolilab: { - "eslint-config": { - // options - }, - }, -} -``` - -#### indent - -Type: `number` - -Default: `4` - -It will throw an error if the value is not numeric. - -#### plugin - -Type: `object` -> key: `string` value: `boolean` - -Disable a plugin in your package.json config to turn it off globally in your project. - -Example using package.json: - -```json -{ - "anolilab": { - "eslint-config": { - "plugin": { - "unicorn": false - } - } - } -} -``` - -#### warn_on_unsupported_typescript_version - -Type: `boolean` - -Default: `undefined` - -To disable the warning, set the value to `false`. - -```json -{ - "anolilab": { - "eslint-config": { - "warn_on_unsupported_typescript_version": false - } - } -} -``` - -#### info_on_disabling_jsx_react_rule - -Type: `boolean` - -Default: `undefined` - -To disable the info, set the value to `false`. - -```json -{ - "anolilab": { - "eslint-config": { - "info_on_disabling_jsx_react_rule": false - } - } -} -``` - -#### info_on_disabling_prettier_conflict_rule - -Type: `boolean` - -Default: `undefined` - -To disable the info, set the value to `false`. - -```json -{ - "anolilab": { - "eslint-config": { - "info_on_disabling_prettier_conflict_rule": false - } - } -} -``` - -#### info_on_disabling_jsonc_sort_keys_rule - -Type: `boolean` - -Default: `undefined` - -To disable the info, set the value to `false`. - -```json -{ - "anolilab": { - "eslint-config": { - "info_on_disabling_jsonc_sort_keys_rule": false - } - } -} -``` - -#### info_on_disabling_etc_no_deprecated - -Type: `boolean` - -Default: `undefined` - -To disable the info, set the value to `false`. - -```json -{ - "anolilab": { - "eslint-config": { - "info_on_disabling_etc_no_deprecated": false - } - } -} -``` - -#### info_on_testing_library_framework - -Type: `boolean` - -Default: `undefined` - -To disable the info, set the value to `false`. - -```json -{ - "anolilab": { - "eslint-config": { - "info_on_testing_library_framework": false - } - } -} -``` - -#### info_on_found_react_version - -Type: `boolean` - -Default: `undefined` - -To disable the info, set the value to `false`. - -```json -{ - "anolilab": { - "eslint-config": { - "info_on_found_react_version": false - } - } -} -``` - -#### import_ignore_exports - -Type: `string[]` - -Default: `[]` - -An array with files/paths for which unused exports will not be reported (e.g module entry points in a published package). - -```json -{ - "anolilab": { - "eslint-config": { - "import_ignore_exports": [] - } - } -} -``` - -### Let [Prettier](https://prettier.io/) handle style-related rules - -Prettier is a code formatting tool that offers fewer options but is more professional than the style-related rules in ESLint. - -Now that Prettier has become a necessary tool in front end projects, `@anolilab/eslint-config` does not need to maintain the style-related rules in ESLint anymore, -so we completely removed all Prettier related rules, if `prettier` is found in your `package.json` and use ESLint to check logical errors which it’s good at. - -As for whether two spaces or four spaces are used for indentation and whether there is a semicolon at the end, you can configure it in the project’s `.prettierrc.js`. -Of course, we also provide a recommended Prettier [configuration](../prettier-config/README.md) for your reference. - -`@anolilab/eslint-config` does disable all included style-related rules, so there is no need to install [`eslint-config-prettier`](https://github.com/prettier/eslint-config-prettier). - -## Using experimental features with JavaScript - -If you are using experimental features such as class fields with JavaScript files you should install `@babel/eslint-parser`. - -```bash -npm install --save-dev @babel/core -``` - ## Plugins ### Code Quality This plugin provide a range of code quality rules: -- [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) -- [eslint-plugin-antfu](https://github.com/antfu/eslint-config) +- [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) +- [eslint-plugin-antfu](https://github.com/antfu/eslint-config) ### Languages The following plugins expand esLint to work with json files, and lint JavaScript contained in HTML, and MarkDown: -- [eslint-plugin-html](https://github.com/BenoitZugmeyer/eslint-plugin-html) -- [eslint-plugin-jsonc](https://github.com/ota-meshi/eslint-plugin-jsonc) -- [eslint-plugin-markdown](https://github.com/eslint/eslint-plugin-markdown) -- [eslint-plugin-mdx](https://github.com/mdx-js/eslint-mdx) -- [eslint-plugin-toml](https://github.com/ota-meshi/eslint-plugin-toml) -- [eslint-plugin-yml](https://github.com/ota-meshi/eslint-plugin-yml) +- [eslint-plugin-html](https://github.com/BenoitZugmeyer/eslint-plugin-html) +- [eslint-plugin-jsonc](https://github.com/ota-meshi/eslint-plugin-jsonc) +- [eslint-plugin-markdown](https://github.com/eslint/eslint-plugin-markdown) +- [eslint-plugin-mdx](https://github.com/mdx-js/eslint-mdx) +- [eslint-plugin-toml](https://github.com/ota-meshi/eslint-plugin-toml) +- [eslint-plugin-yml](https://github.com/ota-meshi/eslint-plugin-yml) When linting code snippets in Markdown files, a few [rules](src/config/plugins/markdown.ts#L3) relating to globals and unused vars are disabled. @@ -468,76 +95,64 @@ When linting code snippets in Markdown files, a few [rules](src/config/plugins/m If a supported library is part of your project then it’s related esLint plugins will be loaded. The following plugins are supported: -- [eslint-plugin-fsa](https://github.com/joseph-galindo/eslint-plugin-fsa) -- [eslint-plugin-lodash](https://github.com/wix/eslint-plugin-lodash) - - You need to install `eslint-plugin-lodash` and `lodash` to use this plugin. -- [eslint-plugin-lodash-fp](https://github.com/jfmengels/eslint-plugin-lodash-fp) - - You need to install `eslint-plugin-lodash-fp` and `lodash` to use this plugin. -- [eslint-plugin-react-redux](https://github.com/DianaSuvorova/eslint-plugin-react-redux#readme) - - You need to install `eslint-plugin-react-redux` and `react-redux` to use this plugin. -- [eslint-plugin-redux-saga](https://github.com/pke/eslint-plugin-redux-saga) - - You need to install `eslint-plugin-redux-saga` and `redux-saga` to use this plugin. +- [eslint-plugin-fsa](https://github.com/joseph-galindo/eslint-plugin-fsa) +- [eslint-plugin-lodash](https://github.com/wix/eslint-plugin-lodash) + - You need to install `eslint-plugin-lodash` and `lodash` to use this plugin. +- [eslint-plugin-lodash-fp](https://github.com/jfmengels/eslint-plugin-lodash-fp) + - You need to install `eslint-plugin-lodash-fp` and `lodash` to use this plugin. +- [eslint-plugin-react-redux](https://github.com/DianaSuvorova/eslint-plugin-react-redux#readme) + - You need to install `eslint-plugin-react-redux` and `react-redux` to use this plugin. +- [eslint-plugin-redux-saga](https://github.com/pke/eslint-plugin-redux-saga) + - You need to install `eslint-plugin-redux-saga` and `redux-saga` to use this plugin. ### Practices The following esLint plugins enforce good coding practices: -- [eslint-plugin-array-func](https://github.com/freaktechnik/eslint-plugin-array-func) -- [eslint-plugin-eslint-comments](https://github.com/mysticatea/eslint-plugin-eslint-comments) -- [eslint-plugin-promise](https://github.com/xjamundx/eslint-plugin-promise) -- [eslint-plugin-no-loops](https://github.com/buildo/eslint-plugin-no-loops) -- [eslint-plugin-simple-import-sort](https://github.com/lydell/eslint-plugin-simple-import-sort) -- [eslint-plugin-es-x](https://github.com/eslint-community/eslint-plugin-es-x) +- [eslint-plugin-array-func](https://github.com/freaktechnik/eslint-plugin-array-func) +- [eslint-plugin-eslint-comments](https://github.com/mysticatea/eslint-plugin-eslint-comments) +- [eslint-plugin-promise](https://github.com/xjamundx/eslint-plugin-promise) +- [eslint-plugin-simple-import-sort](https://github.com/lydell/eslint-plugin-simple-import-sort) +- [eslint-plugin-es-x](https://github.com/eslint-community/eslint-plugin-es-x) ### Security These plugins add code security rules to esLint: -- [eslint-plugin-no-secrets](https://github.com/nickdeis/eslint-plugin-no-secrets) -- [eslint-plugin-no-unsanitized](https://github.com/mozilla/eslint-plugin-no-unsanitized) -- [eslint-plugin-sonarjs](https://github.com/SonarSource/eslint-plugin-sonarjs) -- [eslint-plugin-security](https://github.com/eslint-community/eslint-plugin-security) -- [rushstack/eslint-plugin-security](https://www.npmjs.com/package/@rushstack/eslint-plugin-security) +- [eslint-plugin-no-secrets](https://github.com/nickdeis/eslint-plugin-no-secrets) +- [eslint-plugin-no-unsanitized](https://github.com/mozilla/eslint-plugin-no-unsanitized) +- [eslint-plugin-sonarjs](https://github.com/SonarSource/eslint-plugin-sonarjs) +- [eslint-plugin-security](https://github.com/eslint-community/eslint-plugin-security) +- [rushstack/eslint-plugin-security](https://www.npmjs.com/package/@rushstack/eslint-plugin-security) ### Test Libraries The following test plugins are supported: -- [eslint-plugin-ava](https://github.com/avajs/eslint-plugin-ava) - - You need to install `eslint-plugin-ava` and `ava` to use this plugin. -- [eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest) - - You need to install `eslint-plugin-jest` and `jest` to use this plugin. -- [eslint-plugin-jest-async](https://www.npmjs.com/package/eslint-plugin-jest-async) - - You need to install `eslint-plugin-jest-async` and `jest` to use this plugin. -- [eslint-plugin-cypress](https://github.com/cypress-io/eslint-plugin-cypress) - - You need to install `eslint-plugin-cypress` and `cypress` to use this plugin. - +- [eslint-plugin-ava](https://github.com/avajs/eslint-plugin-ava) + - You need to install `@vitest/eslint-plugin` and `vitest` to use this plugin. ### List of used plugins -- eslint-plugin-security -- @rushstack/eslint-plugin-security -- @typescript-eslint/eslint-plugin -- eslint-plugin-antfu -- eslint-plugin-compat -- eslint-plugin-es-x -- eslint-plugin-eslint-comments -- eslint-plugin-html -- eslint-plugin-i -- eslint-plugin-jsonc -- eslint-plugin-markdown -- eslint-plugin-mdx -- eslint-plugin-no-loops -- eslint-plugin-no-only-tests -- eslint-plugin-no-secrets -- eslint-plugin-no-use-extend-native -- eslint-plugin-promise -- eslint-plugin-regexp -- eslint-plugin-simple-import-sort -- eslint-plugin-sonarjs -- eslint-plugin-toml -- eslint-plugin-typescript-sort-keys -- eslint-plugin-unicorn -- eslint-plugin-yml +- eslint-plugin-security +- @typescript-eslint/eslint-plugin +- eslint-plugin-antfu +- eslint-plugin-compat +- eslint-plugin-es-x +- eslint-plugin-eslint-comments +- eslint-plugin-html +- eslint-plugin-i +- eslint-plugin-jsonc +- eslint-plugin-markdown +- eslint-plugin-no-only-tests +- eslint-plugin-no-secrets +- eslint-plugin-promise +- eslint-plugin-regexp +- eslint-plugin-simple-import-sort +- eslint-plugin-sonarjs +- eslint-plugin-toml +- eslint-plugin-typescript-sort-keys +- eslint-plugin-unicorn +- eslint-plugin-yml ## Troubleshooting @@ -632,11 +247,10 @@ If you would like to help take a look at the [list of issues](https://github.com ## Credits -- [Daniel Bannert](https://github.com/prisis) -- [All Contributors](https://github.com/anolilab/javascript-style-guide/graphs/contributors) -- [eslint-config-airbnb](https://www.npmjs.com/package/eslint-config-airbnb) -- [eslint-config-alloy](https://github.com/AlloyTeam/eslint-config-alloy) -- [eslint-config-canonical](https://github.com/gajus/eslint-config-canonical) +- [Daniel Bannert](https://github.com/prisis) +- [All Contributors](https://github.com/anolilab/javascript-style-guide/graphs/contributors) +- [eslint-config-airbnb](https://www.npmjs.com/package/eslint-config-airbnb) +- [eslint-config-canonical](https://github.com/gajus/eslint-config-canonical) ## License diff --git a/packages/eslint-config/__fixtures__/input/astro.astro b/packages/eslint-config/__fixtures__/input/astro.astro new file mode 100644 index 000000000..df4e8e5ef --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/astro.astro @@ -0,0 +1,21 @@ +--- +const isJsx = true +const content = "hi!"; +--- + +
+
{content}
+
+ {isJsx && ( +

{content}

+ )} +
+
+ + + diff --git a/packages/eslint-config/__fixtures__/input/css.css b/packages/eslint-config/__fixtures__/input/css.css new file mode 100644 index 000000000..12a4724d6 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/css.css @@ -0,0 +1,10 @@ +@media (max-width: 480px) { + .bd-examples {margin-right: -.75rem;margin-left: -.75rem + } + + .bd-examples>[class^="col-"] { + padding-right: .75rem; + padding-left: .75rem; + + } +} diff --git a/packages/eslint-config/__fixtures__/input/html.html b/packages/eslint-config/__fixtures__/input/html.html new file mode 100644 index 000000000..1516dca6a --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/html.html @@ -0,0 +1,17 @@ + + + + + My tITlE + + + +

Hello world!
This is HTML5 Boilerplate.

+ + + + diff --git a/packages/eslint-config/__fixtures__/input/javascript.js b/packages/eslint-config/__fixtures__/input/javascript.js new file mode 100644 index 000000000..2baab92d7 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/javascript.js @@ -0,0 +1,76 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +var log = console.log; + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name; + this.age = age; + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); + } +} + +// Create an array of objects +const people = [ + new Person("Alice", 30), + new Person("Bob", 25), + new Person("Charlie", 35), +]; + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello(); +}); + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +`; + +// Use destructuring assignment to extract values from an object +const { age, name } = people[0]; + +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString); + +// Use the spread operator to create a new array +const numbers = [1, 2, 3]; +const newNumbers = [...numbers, 4, 5]; + +log(newNumbers); + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse("invalid JSON"); +} catch (error) { + console.error("Error parsing JSON:", error.message); +} + +// Use a ternary conditional operator +const isEven = number_ => number_ % 2 === 0; +const number = 7; + +log(`${number} is ${isEven(number) ? "even" : "odd"}.`); + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log("This code runs after a delay of 2 seconds."); +}, 2000); + +let a; let b; let c; let d; let + foo; + +if (a + || b + || c || d + || (d && b) +) { + foo(); +} diff --git a/packages/eslint-config/__fixtures__/input/jsx.jsx b/packages/eslint-config/__fixtures__/input/jsx.jsx new file mode 100644 index 000000000..1b26251cc --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/jsx.jsx @@ -0,0 +1,28 @@ +export function HelloWorld({ + greeted = "\"World\"", + greeting = "hello", + onMouseOver, + silent = false + , +}) { + if (!greeting) { + return null; + } + + // TODO: Don't use random in render + let number_ = Math + .floor(Math.random() * 1E+7) + .toString() + .replaceAll(/\.\d+/g, ""); + + return
+ { greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(",") + ? " " + : ", " } + + { greeted } + + { silent ? "." : "!"} +
; +} diff --git a/packages/eslint-config/__fixtures__/input/markdown.md b/packages/eslint-config/__fixtures__/input/markdown.md new file mode 100644 index 000000000..7dfed2f97 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/markdown.md @@ -0,0 +1,38 @@ +Header +====== + +_Look,_ code blocks are formatted *too!* + +```js +// This should be handled by ESLint instead of Prettier +/** + * + * @param x + */ +function identity(x) { + if (foo) { + console.log("bar"); + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { color:red;} +``` + +Pilot|Airport|Hours +--|:--:|--: +John Doe|SKG|1338 +Jane Roe|JFK|314 + +- - - - - - - - - - - - - - - + ++ List + + with a [link] (/to/somewhere) ++ and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/packages/eslint-config/__fixtures__/input/svelte.svelte b/packages/eslint-config/__fixtures__/input/svelte.svelte new file mode 100644 index 000000000..bf114b923 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/svelte.svelte @@ -0,0 +1,8 @@ + + +
+ +
{@html content}
+
\ No newline at end of file diff --git a/packages/eslint-config/__fixtures__/input/svg.svg b/packages/eslint-config/__fixtures__/input/svg.svg new file mode 100644 index 000000000..f3e336599 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/svg.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/eslint-config/__fixtures__/input/toml.toml b/packages/eslint-config/__fixtures__/input/toml.toml new file mode 100644 index 000000000..1f73d046b --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] +b = 1 +c = "hello" +a = { answer = 42 } +indent = [ + 1, + 2 +] + +[a-table] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/input/tsconfig.json b/packages/eslint-config/__fixtures__/input/tsconfig.json new file mode 100644 index 000000000..c429e6172 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true + } +} diff --git a/packages/eslint-config/__fixtures__/input/tsx.tsx b/packages/eslint-config/__fixtures__/input/tsx.tsx new file mode 100644 index 000000000..cd29195e1 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/tsx.tsx @@ -0,0 +1,25 @@ +export function Component1() { + return
; +} + +export function jsx2() { + const properties = { + a: 1, + b: 2, + }; + + return < a bar={`foo` } foo= 'bar' > +
Inline Text
+ + Block Text + +
+ Mixed +
Foo
+ Text Bar +
+

+ foobarbaz +

+ ; +} diff --git a/packages/eslint-config/__fixtures__/input/typescript.ts b/packages/eslint-config/__fixtures__/input/typescript.ts new file mode 100644 index 000000000..6d9bf6b81 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/typescript.ts @@ -0,0 +1,91 @@ +// Define a TypeScript interface +interface Person { + age: number; + name: string; +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { age: 30, name: "Alice" }, + { age: 25, name: "Bob" }, + { + age: 35, + name: "Charlie", + }, +]; + +// eslint-disable-next-line no-console +const log = console.log; + +// Use a for...of loop to iterate over the array +for (const person of people) { + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`); +} + +// Define a generic function +function identity< T >(argument: T): T { + return argument; +} + +// Use the generic function with type inference +const result = identity( + "TypeScript is awesome", +); + +log(result); + +// Use optional properties in an interface +interface Car { + make: string; + model?: string; +} + +// Create objects using the interface +const car1: Car = { make: "Toyota" }; +const car2: Car = { + make: "Ford", + model: "Focus", + +}; + +// Use union types +type Fruit = "apple" | "banana" | "orange"; +const favoriteFruit: Fruit = "apple"; + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = "42"; +const numericValue = inputValue as number; + +// Define a class with access modifiers +class Animal { + private name: string; + + constructor(name: string) { + this.name = name; + } + + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`); + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias); + } + + bark() { + this.makeSound("Woof!"); + } +} + +const dog = new Dog("Buddy"); + +dog.bark(); + +const function_ = (): string => { + return "hello" + 1; +}; + +log(car1, car2, favoriteFruit, numericValue, function_()); diff --git a/packages/eslint-config/__fixtures__/input/vue-ts.vue b/packages/eslint-config/__fixtures__/input/vue-ts.vue new file mode 100644 index 000000000..61ed8c6c8 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/vue-ts.vue @@ -0,0 +1,34 @@ + + + + + + + diff --git a/packages/eslint-config/__fixtures__/input/vue.vue b/packages/eslint-config/__fixtures__/input/vue.vue new file mode 100644 index 000000000..b540d06e6 --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/vue.vue @@ -0,0 +1,24 @@ + + + diff --git a/packages/eslint-config/__fixtures__/input/xml.xml b/packages/eslint-config/__fixtures__/input/xml.xml new file mode 100644 index 000000000..8fbc57b9b --- /dev/null +++ b/packages/eslint-config/__fixtures__/input/xml.xml @@ -0,0 +1,9 @@ + +Effective Java45.00 + Bluetooth Speaker120.00 + Clean Code + 33.50 + + + + diff --git a/packages/eslint-config/__fixtures__/old-config/.eslintignore b/packages/eslint-config/__fixtures__/old-config/.eslintignore deleted file mode 100644 index 4f21ac90b..000000000 --- a/packages/eslint-config/__fixtures__/old-config/.eslintignore +++ /dev/null @@ -1,13 +0,0 @@ -packages/semantic-release-preset/commitlint.config.js -packages/semantic-release-preset/.czrc -packages/prettier-config/.prettierrc.js -packages/textlint-config/.textlintrc -packages/babel-preset/babel.config.js -packages/babel-preset/fixture/test.js -packages/babel-preset/fixture/test.ts -packages/stylelint-config/.stylelintrc.js -packages/lint-staged-config/.lintstagedrc.js -packages/eslint-config/src/global.d.ts -packages/eslint-config/src/types.d.ts - -tsup.config.ts diff --git a/packages/eslint-config/__fixtures__/old-config/.eslintrc.js b/packages/eslint-config/__fixtures__/old-config/.eslintrc.js deleted file mode 100644 index cd7f61bd7..000000000 --- a/packages/eslint-config/__fixtures__/old-config/.eslintrc.js +++ /dev/null @@ -1,22 +0,0 @@ -const config = require("@anolilab/eslint-config"); -const globals = require("@anolilab/eslint-config/globals"); - -module.exports = { - ...config, - extends: [...config.extends, "@anolilab/eslint-config/typescript-type-checking"], - globals: { - ...config?.globals, - ...globals.es2021, - }, - overrides: [ - ...config.overrides, - { - files: ["*.ts", "*.mts", "*.cts", "*.tsx", ".mdx"], - parserOptions: { - project: true, - tsconfigRootDir: __dirname, - }, - }, - ], - root: true, -}; diff --git a/packages/eslint-config/__fixtures__/old-config/index.js b/packages/eslint-config/__fixtures__/old-config/index.js deleted file mode 100644 index c36e70fbb..000000000 --- a/packages/eslint-config/__fixtures__/old-config/index.js +++ /dev/null @@ -1,2 +0,0 @@ - -console.log("hello world"); diff --git a/packages/eslint-config/__fixtures__/old-config/package.json b/packages/eslint-config/__fixtures__/old-config/package.json deleted file mode 100644 index 96df50e77..000000000 --- a/packages/eslint-config/__fixtures__/old-config/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "test-package", - "devDependencies": { - "@anolilab/eslint-config": "file:../../dist", - "eslint": "latest", - "eslint-plugin-import": "npm:eslint-plugin-i@2.28.1" - } -} diff --git a/packages/eslint-config/__fixtures__/old-config/pnpm-lock.yaml b/packages/eslint-config/__fixtures__/old-config/pnpm-lock.yaml deleted file mode 100644 index 54fe3d890..000000000 --- a/packages/eslint-config/__fixtures__/old-config/pnpm-lock.yaml +++ /dev/null @@ -1,813 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -devDependencies: - '@anolilab/eslint-config': - specifier: file:../../dist - version: file:../../dist - eslint: - specifier: latest - version: 8.50.0 - eslint-plugin-import: - specifier: npm:eslint-plugin-i@2.28.1 - version: /eslint-plugin-i@2.28.1(eslint@8.50.0) - -packages: - - /@aashutoshrathi/word-wrap@1.2.6: - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} - dev: true - - /@eslint-community/eslint-utils@4.4.0(eslint@8.50.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.50.0 - eslint-visitor-keys: 3.4.3 - dev: true - - /@eslint-community/regexpp@4.8.2: - resolution: {integrity: sha512-0MGxAVt1m/ZK+LTJp/j0qF7Hz97D9O/FH9Ms3ltnyIdDD57cbb1ACIQTkbHvNXtWDv5TPq7w5Kq56+cNukbo7g==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true - - /@eslint/eslintrc@2.1.2: - resolution: {integrity: sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==} - 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.22.0 - ignore: 5.2.4 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - - /@eslint/js@8.50.0: - resolution: {integrity: sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - - /@humanwhocodes/config-array@0.11.11: - resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} - engines: {node: '>=10.10.0'} - dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - dev: true - - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - dev: true - - /@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: true - - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true - - /@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: true - - /acorn-jsx@5.3.2(acorn@8.10.0): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.10.0 - dev: true - - /acorn@8.10.0: - resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - - /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: true - - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true - - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /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: true - - /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: true - - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - - /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: true - - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - - /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: true - - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - - /doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true - - /eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - dependencies: - debug: 3.2.7 - is-core-module: 2.13.0 - resolve: 1.22.6 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-module-utils@2.8.0(eslint-import-resolver-node@0.3.9)(eslint@8.50.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - debug: 3.2.7 - eslint: 8.50.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-plugin-i@2.28.1(eslint@8.50.0): - resolution: {integrity: sha512-a4oVt0j3ixNhGhvV4XF6NS7OWRFK2rrJ0Q5C4S2dSRb8FxZi31J0uUd5WJLL58wnVJ/OiQ1BxiXnFA4dWQO1Cg==} - engines: {node: '>=12'} - peerDependencies: - eslint: ^7.2.0 || ^8 - dependencies: - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.50.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(eslint-import-resolver-node@0.3.9)(eslint@8.50.0) - get-tsconfig: 4.7.2 - is-glob: 4.0.3 - minimatch: 3.1.2 - resolve: 1.22.6 - semver: 7.5.4 - transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - - /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: true - - /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: true - - /eslint@8.50.0: - resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.50.0) - '@eslint-community/regexpp': 4.8.2 - '@eslint/eslintrc': 2.1.2 - '@eslint/js': 8.50.0 - '@humanwhocodes/config-array': 0.11.11 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - 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.22.0 - graphemer: 1.4.0 - ignore: 5.2.4 - 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: true - - /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.10.0 - acorn-jsx: 5.3.2(acorn@8.10.0) - eslint-visitor-keys: 3.4.3 - dev: true - - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true - - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true - - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - - /fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} - dependencies: - reusify: 1.0.4 - dev: true - - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flat-cache: 3.1.0 - dev: true - - /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: true - - /flat-cache@3.1.0: - resolution: {integrity: sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==} - engines: {node: '>=12.0.0'} - dependencies: - flatted: 3.2.9 - keyv: 4.5.3 - rimraf: 3.0.2 - dev: true - - /flatted@3.2.9: - resolution: {integrity: sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==} - dev: true - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true - - /get-tsconfig@4.7.2: - resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} - dependencies: - resolve-pkg-maps: 1.0.0 - dev: true - - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - dev: true - - /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: true - - /globals@13.22.0: - resolution: {integrity: sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 - dev: true - - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true - - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true - - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} - dependencies: - function-bind: 1.1.1 - dev: true - - /ignore@5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} - engines: {node: '>= 4'} - dev: true - - /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: true - - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /is-core-module@2.13.0: - resolution: {integrity: sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==} - dependencies: - has: 1.0.3 - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - dev: true - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - dependencies: - argparse: 2.0.1 - dev: true - - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true - - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true - - /keyv@4.5.3: - resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==} - dependencies: - json-buffer: 3.0.1 - dev: true - - /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: true - - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - dev: true - - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true - - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - dev: true - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true - - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true - - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - - /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: true - - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - dev: true - - /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: true - - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - dev: true - - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true - - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true - - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true - - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true - - /punycode@2.3.0: - resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} - engines: {node: '>=6'} - dev: true - - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true - - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true - - /resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - dev: true - - /resolve@1.22.6: - resolution: {integrity: sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==} - hasBin: true - dependencies: - is-core-module: 2.13.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true - - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true - dependencies: - glob: 7.2.3 - dev: true - - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: true - - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - dev: true - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true - - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - dev: true - - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true - - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - dev: true - - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true - - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true - - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - dev: true - - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true - - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.0 - dev: true - - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true - - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true - - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true - - file:../../dist: - resolution: {directory: ../../dist, type: directory} - name: dist - dev: true diff --git a/packages/eslint-config/__fixtures__/output/all/astro.astro b/packages/eslint-config/__fixtures__/output/all/astro.astro new file mode 100644 index 000000000..b67c6784e --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/astro.astro @@ -0,0 +1,21 @@ +--- +const isJsx = true +const content = 'hi!'; +--- + +
+
{content}
+
+ {isJsx && ( +

{content}

+ )} +
+
+ + + diff --git a/packages/eslint-config/__fixtures__/output/all/javascript.js b/packages/eslint-config/__fixtures__/output/all/javascript.js new file mode 100644 index 000000000..e0702598c --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/javascript.js @@ -0,0 +1,73 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name + this.age = age + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`) + } +} + +// Create an array of objects +const people = [ + new Person('Alice', 30), + new Person('Bob', 25), + new Person('Charlie', 35), +] + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello() +}) + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +` + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0] +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString) + +// Use the spread operator to create a new array +const numbers = [1, 2, 3] +const newNumbers = [...numbers, 4, 5] +log(newNumbers) + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse('invalid JSON') +} +catch (error) { + console.error('Error parsing JSON:', error.message) +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0 +const number = 7 +log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`) + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log('This code runs after a delay of 2 seconds.') +}, 2000) + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) +) { + foo() +} diff --git a/packages/eslint-config/__fixtures__/output/all/jsx.jsx b/packages/eslint-config/__fixtures__/output/all/jsx.jsx new file mode 100644 index 000000000..523af3782 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/jsx.jsx @@ -0,0 +1,29 @@ +export function HelloWorld({ + greeting = 'hello', + greeted = '"World"', + silent = false, + onMouseOver, +}) { + if (!greeting) { + return null + }; + + // TODO: Don't use random in render + const num = Math + .floor (Math.random() * 1e+7) + .toString() + .replace(/\.\d+/g, '') + + return ( +
+ { greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(',') + ? ' ' + : ", " } + + { greeted } + + { (silent) ? '.' : '!'} +
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/all/markdown.md b/packages/eslint-config/__fixtures__/output/all/markdown.md new file mode 100644 index 000000000..a66c94c89 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/markdown.md @@ -0,0 +1,34 @@ +Header +====== + +_Look,_ code blocks are formatted *too!* + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log('bar') + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { color:red;} +``` + +Pilot|Airport|Hours +--|:--:|--: +John Doe|SKG|1338 +Jane Roe|JFK|314 + +- - - - - - - - - - - - - - - + ++ List + + with a [link] (/to/somewhere) ++ and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/packages/eslint-config/__fixtures__/output/all/svelte.svelte b/packages/eslint-config/__fixtures__/output/all/svelte.svelte new file mode 100644 index 000000000..7cc629a47 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/svelte.svelte @@ -0,0 +1,8 @@ + + +
+ +
{@html content}
+
diff --git a/packages/eslint-config/__fixtures__/output/all/toml.toml b/packages/eslint-config/__fixtures__/output/all/toml.toml new file mode 100644 index 000000000..1f73d046b --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] +b = 1 +c = "hello" +a = { answer = 42 } +indent = [ + 1, + 2 +] + +[a-table] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/output/all/tsx.tsx b/packages/eslint-config/__fixtures__/output/all/tsx.tsx new file mode 100644 index 000000000..ab640af67 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/tsx.tsx @@ -0,0 +1,32 @@ +export function Component1() { + return
+} + +export function jsx2() { + const props = { a: 1, b: 2 } + return ( + +
+ Inline Text +
+ + Block Text + +
+ Mixed +
Foo
+ Text + Bar +
+

+ foo + bar + baz +

+
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/all/typescript.ts b/packages/eslint-config/__fixtures__/output/all/typescript.ts new file mode 100644 index 000000000..29016e385 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/typescript.ts @@ -0,0 +1,84 @@ +// Define a TypeScript interface +interface Person { + name: string + age: number +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + { name: 'Charlie', age: 35 }, +] + +// eslint-disable-next-line no-console +const log = console.log + +// Use a for...of loop to iterate over the array +for (const person of people) { + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`) +} + +// Define a generic function +function identity< T >(arg: T): T { + return arg +} + +// Use the generic function with type inference +const result = identity( + 'TypeScript is awesome', +) +log(result) + +// Use optional properties in an interface +interface Car { + make: string + model?: string +} + +// Create objects using the interface +const car1: Car = { make: 'Toyota' } +const car2: Car = { + make: 'Ford', + model: 'Focus', +} + +// Use union types +type Fruit = 'apple' | 'banana' | 'orange' +const favoriteFruit: Fruit = 'apple' + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = '42' +const numericValue = inputValue as number + +// Define a class with access modifiers +class Animal { + private name: string + constructor(name: string) { + this.name = name + } + + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`) + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias) + } + + bark() { + this.makeSound('Woof!') + } +} + +const dog = new Dog('Buddy') +dog.bark() + +function fn(): string { + return `hello${1}` +} + +log(car1, car2, favoriteFruit, numericValue, fn()) diff --git a/packages/eslint-config/__fixtures__/output/all/vue-ts.vue b/packages/eslint-config/__fixtures__/output/all/vue-ts.vue new file mode 100644 index 000000000..ce35e66b0 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/vue-ts.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/packages/eslint-config/__fixtures__/output/all/vue.vue b/packages/eslint-config/__fixtures__/output/all/vue.vue new file mode 100644 index 000000000..944cc4e56 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/all/vue.vue @@ -0,0 +1,27 @@ + + + diff --git a/packages/eslint-config/__fixtures__/output/js/javascript.js b/packages/eslint-config/__fixtures__/output/js/javascript.js new file mode 100644 index 000000000..e0702598c --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/js/javascript.js @@ -0,0 +1,73 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name + this.age = age + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`) + } +} + +// Create an array of objects +const people = [ + new Person('Alice', 30), + new Person('Bob', 25), + new Person('Charlie', 35), +] + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello() +}) + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +` + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0] +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString) + +// Use the spread operator to create a new array +const numbers = [1, 2, 3] +const newNumbers = [...numbers, 4, 5] +log(newNumbers) + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse('invalid JSON') +} +catch (error) { + console.error('Error parsing JSON:', error.message) +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0 +const number = 7 +log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`) + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log('This code runs after a delay of 2 seconds.') +}, 2000) + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) +) { + foo() +} diff --git a/packages/eslint-config/__fixtures__/output/js/jsx.jsx b/packages/eslint-config/__fixtures__/output/js/jsx.jsx new file mode 100644 index 000000000..523af3782 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/js/jsx.jsx @@ -0,0 +1,29 @@ +export function HelloWorld({ + greeting = 'hello', + greeted = '"World"', + silent = false, + onMouseOver, +}) { + if (!greeting) { + return null + }; + + // TODO: Don't use random in render + const num = Math + .floor (Math.random() * 1e+7) + .toString() + .replace(/\.\d+/g, '') + + return ( +
+ { greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(',') + ? ' ' + : ", " } + + { greeted } + + { (silent) ? '.' : '!'} +
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/js/markdown.md b/packages/eslint-config/__fixtures__/output/js/markdown.md new file mode 100644 index 000000000..a66c94c89 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/js/markdown.md @@ -0,0 +1,34 @@ +Header +====== + +_Look,_ code blocks are formatted *too!* + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log('bar') + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { color:red;} +``` + +Pilot|Airport|Hours +--|:--:|--: +John Doe|SKG|1338 +Jane Roe|JFK|314 + +- - - - - - - - - - - - - - - + ++ List + + with a [link] (/to/somewhere) ++ and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/packages/eslint-config/__fixtures__/output/js/toml.toml b/packages/eslint-config/__fixtures__/output/js/toml.toml new file mode 100644 index 000000000..1f73d046b --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/js/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] +b = 1 +c = "hello" +a = { answer = 42 } +indent = [ + 1, + 2 +] + +[a-table] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/output/js/tsx.tsx b/packages/eslint-config/__fixtures__/output/js/tsx.tsx new file mode 100644 index 000000000..ab640af67 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/js/tsx.tsx @@ -0,0 +1,32 @@ +export function Component1() { + return
+} + +export function jsx2() { + const props = { a: 1, b: 2 } + return ( + +
+ Inline Text +
+ + Block Text + +
+ Mixed +
Foo
+ Text + Bar +
+

+ foo + bar + baz +

+
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/javascript.js b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/javascript.js new file mode 100644 index 000000000..e0702598c --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/javascript.js @@ -0,0 +1,73 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name + this.age = age + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`) + } +} + +// Create an array of objects +const people = [ + new Person('Alice', 30), + new Person('Bob', 25), + new Person('Charlie', 35), +] + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello() +}) + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +` + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0] +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString) + +// Use the spread operator to create a new array +const numbers = [1, 2, 3] +const newNumbers = [...numbers, 4, 5] +log(newNumbers) + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse('invalid JSON') +} +catch (error) { + console.error('Error parsing JSON:', error.message) +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0 +const number = 7 +log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`) + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log('This code runs after a delay of 2 seconds.') +}, 2000) + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) +) { + foo() +} diff --git a/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/markdown.md b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/markdown.md new file mode 100644 index 000000000..b049fd926 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/markdown.md @@ -0,0 +1,33 @@ +# Header + +_Look,_ code blocks are formatted _too!_ + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log('bar'); + } + } +``` + +```css +/* This should be handled by Prettier */ +.foo { color:red;} +``` + +| Pilot | Airport | Hours | +| -------- | :-----: | ----: | +| John Doe | SKG | 1338 | +| Jane Roe | JFK | 314 | + +--- + +- List +- with a [link] (/to/somewhere) +- and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/toml.toml b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/toml.toml new file mode 100644 index 000000000..1f73d046b --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] +b = 1 +c = "hello" +a = { answer = 42 } +indent = [ + 1, + 2 +] + +[a-table] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/tsx.tsx b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/tsx.tsx new file mode 100644 index 000000000..efc80b97c --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/tsx.tsx @@ -0,0 +1,21 @@ +export function Component1() { + return
+} + +export function jsx2() { + const props = { a: 1, b: 2 } + return < a foo= 'bar' bar={`foo` } > +
Inline Text
+ + Block Text + +
+ Mixed +
Foo
+ Text Bar +
+

+ foobarbaz +

+ +} diff --git a/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/typescript.ts b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/typescript.ts new file mode 100644 index 000000000..29016e385 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/typescript.ts @@ -0,0 +1,84 @@ +// Define a TypeScript interface +interface Person { + name: string + age: number +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + { name: 'Charlie', age: 35 }, +] + +// eslint-disable-next-line no-console +const log = console.log + +// Use a for...of loop to iterate over the array +for (const person of people) { + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`) +} + +// Define a generic function +function identity< T >(arg: T): T { + return arg +} + +// Use the generic function with type inference +const result = identity( + 'TypeScript is awesome', +) +log(result) + +// Use optional properties in an interface +interface Car { + make: string + model?: string +} + +// Create objects using the interface +const car1: Car = { make: 'Toyota' } +const car2: Car = { + make: 'Ford', + model: 'Focus', +} + +// Use union types +type Fruit = 'apple' | 'banana' | 'orange' +const favoriteFruit: Fruit = 'apple' + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = '42' +const numericValue = inputValue as number + +// Define a class with access modifiers +class Animal { + private name: string + constructor(name: string) { + this.name = name + } + + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`) + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias) + } + + bark() { + this.makeSound('Woof!') + } +} + +const dog = new Dog('Buddy') +dog.bark() + +function fn(): string { + return `hello${1}` +} + +log(car1, car2, favoriteFruit, numericValue, fn()) diff --git a/packages/eslint-config/__fixtures__/output/no-style/javascript.js b/packages/eslint-config/__fixtures__/output/no-style/javascript.js new file mode 100644 index 000000000..9ee4a7ca3 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-style/javascript.js @@ -0,0 +1,72 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name; + this.age = age; + } + +// Define a method within the class +sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`); +} +} + +// Create an array of objects +const people = [ + new Person('Alice', 30), + new Person('Bob', 25), + new Person('Charlie', 35) +]; + +// Use the forEach method to iterate over the array +people.forEach(person => { + person.sayHello(); +}); + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +`; + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0]; +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString); + +// Use the spread operator to create a new array +const numbers = [1, 2, 3]; +const newNumbers = [...numbers, 4, 5]; +log(newNumbers); + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse('invalid JSON'); +} catch (error) { + console.error('Error parsing JSON:', error.message); +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0; +const number = 7; +log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`); + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log('This code runs after a delay of 2 seconds.'); +}, 2000); + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) + ) { + foo() + } diff --git a/packages/eslint-config/__fixtures__/output/no-style/jsx.jsx b/packages/eslint-config/__fixtures__/output/no-style/jsx.jsx new file mode 100644 index 000000000..762fec4f0 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-style/jsx.jsx @@ -0,0 +1,22 @@ +export function HelloWorld({ + greeting = "hello", greeted = '"World"', silent = false, onMouseOver,}) { + + if(!greeting){ + return null}; + + // TODO: Don't use random in render + const num = Math + .floor (Math.random() * 1e+7).toString() + .replace(/\.\d+/g, "") + + return
+ { greeting.slice( 0, 1 ).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(",") + ? " " : ", " } + + { greeted } + + { (silent)? ".": "!"} +
; + +} diff --git a/packages/eslint-config/__fixtures__/output/no-style/toml.toml b/packages/eslint-config/__fixtures__/output/no-style/toml.toml new file mode 100644 index 000000000..a28003c42 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-style/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] + b = 1 + c = "hello" + a = {answer = 42} + +"indent" = [ +1, + 2 +] + +['a-table'] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/output/no-style/typescript.ts b/packages/eslint-config/__fixtures__/output/no-style/typescript.ts new file mode 100644 index 000000000..1cf34cafb --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-style/typescript.ts @@ -0,0 +1,80 @@ +// Define a TypeScript interface +interface Person { + name: string; age: number; +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + { name: 'Charlie', + age: 35 } +]; + +// eslint-disable-next-line no-console +const log = console.log + +// Use a for...of loop to iterate over the array +for (const person of people) { + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`); +} + +// Define a generic function +function identity< T >(arg: T): T { + return arg; +} + +// Use the generic function with type inference +const result = identity( + 'TypeScript is awesome'); +log(result); + +// Use optional properties in an interface +interface Car { + make: string; + model?: string; +} + +// Create objects using the interface +const car1: Car = { make: 'Toyota' }; +const car2: Car = { + make: 'Ford', model: 'Focus' }; + +// Use union types +type Fruit = 'apple' | 'banana' | 'orange'; +const favoriteFruit: Fruit = 'apple'; + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = '42'; +const numericValue = inputValue as number; + +// Define a class with access modifiers +class Animal { + private name: string; + constructor(name: string) { + this.name = name; + } + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`); + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias); + } + bark() { + this.makeSound('Woof!'); + } +} + +const dog = new Dog('Buddy'); +dog.bark(); + +const fn = (): string => { + return `hello${ 1}` +} + +log(car1, car2, favoriteFruit, numericValue, fn()) + diff --git a/packages/eslint-config/__fixtures__/output/no-style/vue-ts.vue b/packages/eslint-config/__fixtures__/output/no-style/vue-ts.vue new file mode 100644 index 000000000..944abcf50 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-style/vue-ts.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/packages/eslint-config/__fixtures__/output/no-style/vue.vue b/packages/eslint-config/__fixtures__/output/no-style/vue.vue new file mode 100644 index 000000000..36b2ff6d8 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/no-style/vue.vue @@ -0,0 +1,27 @@ + + + diff --git a/packages/eslint-config/__fixtures__/output/tab-double-quotes/javascript.js b/packages/eslint-config/__fixtures__/output/tab-double-quotes/javascript.js new file mode 100644 index 000000000..3918d1388 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/javascript.js @@ -0,0 +1,73 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name + this.age = age + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`) + } +} + +// Create an array of objects +const people = [ + new Person("Alice", 30), + new Person("Bob", 25), + new Person("Charlie", 35), +] + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello() +}) + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +` + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0] +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString) + +// Use the spread operator to create a new array +const numbers = [1, 2, 3] +const newNumbers = [...numbers, 4, 5] +log(newNumbers) + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse("invalid JSON") +} +catch (error) { + console.error("Error parsing JSON:", error.message) +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0 +const number = 7 +log(`${number} is ${isEven(number) ? "even" : "odd"}.`) + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log("This code runs after a delay of 2 seconds.") +}, 2000) + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) +) { + foo() +} diff --git a/packages/eslint-config/__fixtures__/output/tab-double-quotes/jsx.jsx b/packages/eslint-config/__fixtures__/output/tab-double-quotes/jsx.jsx new file mode 100644 index 000000000..08744a513 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/jsx.jsx @@ -0,0 +1,29 @@ +export function HelloWorld({ + greeting = "hello", + greeted = "\"World\"", + silent = false, + onMouseOver, +}) { + if (!greeting) { + return null + }; + + // TODO: Don't use random in render + const num = Math + .floor (Math.random() * 1e+7) + .toString() + .replace(/\.\d+/g, "") + + return ( +
+ { greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(",") + ? " " + : ", " } + + { greeted } + + { (silent) ? "." : "!"} +
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/tab-double-quotes/markdown.md b/packages/eslint-config/__fixtures__/output/tab-double-quotes/markdown.md new file mode 100644 index 000000000..c9616151a --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/markdown.md @@ -0,0 +1,34 @@ +Header +====== + +_Look,_ code blocks are formatted *too!* + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log("bar") + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { color:red;} +``` + +Pilot|Airport|Hours +--|:--:|--: +John Doe|SKG|1338 +Jane Roe|JFK|314 + +- - - - - - - - - - - - - - - + ++ List + + with a [link] (/to/somewhere) ++ and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/packages/eslint-config/__fixtures__/output/tab-double-quotes/toml.toml b/packages/eslint-config/__fixtures__/output/tab-double-quotes/toml.toml new file mode 100644 index 000000000..1f73d046b --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] +b = 1 +c = "hello" +a = { answer = 42 } +indent = [ + 1, + 2 +] + +[a-table] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/output/tab-double-quotes/tsconfig.json b/packages/eslint-config/__fixtures__/output/tab-double-quotes/tsconfig.json new file mode 100644 index 000000000..75dd2b29a --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true + } +} diff --git a/packages/eslint-config/__fixtures__/output/tab-double-quotes/tsx.tsx b/packages/eslint-config/__fixtures__/output/tab-double-quotes/tsx.tsx new file mode 100644 index 000000000..2f56c5c4a --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/tsx.tsx @@ -0,0 +1,32 @@ +export function Component1() { + return
+} + +export function jsx2() { + const props = { a: 1, b: 2 } + return ( + +
+ Inline Text +
+ + Block Text + +
+ Mixed +
Foo
+ Text + Bar +
+

+ foo + bar + baz +

+
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/tab-double-quotes/typescript.ts b/packages/eslint-config/__fixtures__/output/tab-double-quotes/typescript.ts new file mode 100644 index 000000000..d0bcb65ba --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/typescript.ts @@ -0,0 +1,84 @@ +// Define a TypeScript interface +interface Person { + name: string + age: number +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { name: "Alice", age: 30 }, + { name: "Bob", age: 25 }, + { name: "Charlie", age: 35 }, +] + +// eslint-disable-next-line no-console +const log = console.log + +// Use a for...of loop to iterate over the array +for (const person of people) { + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`) +} + +// Define a generic function +function identity< T >(arg: T): T { + return arg +} + +// Use the generic function with type inference +const result = identity( + "TypeScript is awesome", +) +log(result) + +// Use optional properties in an interface +interface Car { + make: string + model?: string +} + +// Create objects using the interface +const car1: Car = { make: "Toyota" } +const car2: Car = { + make: "Ford", + model: "Focus", +} + +// Use union types +type Fruit = "apple" | "banana" | "orange" +const favoriteFruit: Fruit = "apple" + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = "42" +const numericValue = inputValue as number + +// Define a class with access modifiers +class Animal { + private name: string + constructor(name: string) { + this.name = name + } + + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`) + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias) + } + + bark() { + this.makeSound("Woof!") + } +} + +const dog = new Dog("Buddy") +dog.bark() + +function fn(): string { + return `hello${1}` +} + +log(car1, car2, favoriteFruit, numericValue, fn()) diff --git a/packages/eslint-config/__fixtures__/output/tab-double-quotes/vue-ts.vue b/packages/eslint-config/__fixtures__/output/tab-double-quotes/vue-ts.vue new file mode 100644 index 000000000..00e3aaeae --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/vue-ts.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/packages/eslint-config/__fixtures__/output/tab-double-quotes/vue.vue b/packages/eslint-config/__fixtures__/output/tab-double-quotes/vue.vue new file mode 100644 index 000000000..1356a70c6 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/vue.vue @@ -0,0 +1,27 @@ + + + diff --git a/packages/eslint-config/__fixtures__/output/ts-override/javascript.js b/packages/eslint-config/__fixtures__/output/ts-override/javascript.js new file mode 100644 index 000000000..e0702598c --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-override/javascript.js @@ -0,0 +1,73 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name + this.age = age + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`) + } +} + +// Create an array of objects +const people = [ + new Person('Alice', 30), + new Person('Bob', 25), + new Person('Charlie', 35), +] + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello() +}) + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +` + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0] +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString) + +// Use the spread operator to create a new array +const numbers = [1, 2, 3] +const newNumbers = [...numbers, 4, 5] +log(newNumbers) + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse('invalid JSON') +} +catch (error) { + console.error('Error parsing JSON:', error.message) +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0 +const number = 7 +log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`) + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log('This code runs after a delay of 2 seconds.') +}, 2000) + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) +) { + foo() +} diff --git a/packages/eslint-config/__fixtures__/output/ts-override/jsx.jsx b/packages/eslint-config/__fixtures__/output/ts-override/jsx.jsx new file mode 100644 index 000000000..523af3782 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-override/jsx.jsx @@ -0,0 +1,29 @@ +export function HelloWorld({ + greeting = 'hello', + greeted = '"World"', + silent = false, + onMouseOver, +}) { + if (!greeting) { + return null + }; + + // TODO: Don't use random in render + const num = Math + .floor (Math.random() * 1e+7) + .toString() + .replace(/\.\d+/g, '') + + return ( +
+ { greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(',') + ? ' ' + : ", " } + + { greeted } + + { (silent) ? '.' : '!'} +
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/ts-override/markdown.md b/packages/eslint-config/__fixtures__/output/ts-override/markdown.md new file mode 100644 index 000000000..a66c94c89 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-override/markdown.md @@ -0,0 +1,34 @@ +Header +====== + +_Look,_ code blocks are formatted *too!* + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log('bar') + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { color:red;} +``` + +Pilot|Airport|Hours +--|:--:|--: +John Doe|SKG|1338 +Jane Roe|JFK|314 + +- - - - - - - - - - - - - - - + ++ List + + with a [link] (/to/somewhere) ++ and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/packages/eslint-config/__fixtures__/output/ts-override/toml.toml b/packages/eslint-config/__fixtures__/output/ts-override/toml.toml new file mode 100644 index 000000000..1f73d046b --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-override/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] +b = 1 +c = "hello" +a = { answer = 42 } +indent = [ + 1, + 2 +] + +[a-table] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/output/ts-override/tsx.tsx b/packages/eslint-config/__fixtures__/output/ts-override/tsx.tsx new file mode 100644 index 000000000..ab640af67 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-override/tsx.tsx @@ -0,0 +1,32 @@ +export function Component1() { + return
+} + +export function jsx2() { + const props = { a: 1, b: 2 } + return ( + +
+ Inline Text +
+ + Block Text + +
+ Mixed +
Foo
+ Text + Bar +
+

+ foo + bar + baz +

+
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/ts-override/typescript.ts b/packages/eslint-config/__fixtures__/output/ts-override/typescript.ts new file mode 100644 index 000000000..ed4c4b607 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-override/typescript.ts @@ -0,0 +1,84 @@ +// Define a TypeScript interface +type Person = { + name: string + age: number +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + { name: 'Charlie', age: 35 }, +] + +// eslint-disable-next-line no-console +const log = console.log + +// Use a for...of loop to iterate over the array +for (const person of people) { + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`) +} + +// Define a generic function +function identity< T >(arg: T): T { + return arg +} + +// Use the generic function with type inference +const result = identity( + 'TypeScript is awesome', +) +log(result) + +// Use optional properties in an interface +type Car = { + make: string + model?: string +} + +// Create objects using the interface +const car1: Car = { make: 'Toyota' } +const car2: Car = { + make: 'Ford', + model: 'Focus', +} + +// Use union types +type Fruit = 'apple' | 'banana' | 'orange' +const favoriteFruit: Fruit = 'apple' + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = '42' +const numericValue = inputValue as number + +// Define a class with access modifiers +class Animal { + private name: string + constructor(name: string) { + this.name = name + } + + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`) + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias) + } + + bark() { + this.makeSound('Woof!') + } +} + +const dog = new Dog('Buddy') +dog.bark() + +function fn(): string { + return `hello${1}` +} + +log(car1, car2, favoriteFruit, numericValue, fn()) diff --git a/packages/eslint-config/__fixtures__/output/ts-override/vue-ts.vue b/packages/eslint-config/__fixtures__/output/ts-override/vue-ts.vue new file mode 100644 index 000000000..ce35e66b0 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-override/vue-ts.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/packages/eslint-config/__fixtures__/output/ts-override/vue.vue b/packages/eslint-config/__fixtures__/output/ts-override/vue.vue new file mode 100644 index 000000000..944cc4e56 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-override/vue.vue @@ -0,0 +1,27 @@ + + + diff --git a/packages/eslint-config/__fixtures__/output/ts-strict-with-react/javascript.js b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/javascript.js new file mode 100644 index 000000000..e0702598c --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/javascript.js @@ -0,0 +1,73 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name + this.age = age + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`) + } +} + +// Create an array of objects +const people = [ + new Person('Alice', 30), + new Person('Bob', 25), + new Person('Charlie', 35), +] + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello() +}) + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +` + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0] +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString) + +// Use the spread operator to create a new array +const numbers = [1, 2, 3] +const newNumbers = [...numbers, 4, 5] +log(newNumbers) + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse('invalid JSON') +} +catch (error) { + console.error('Error parsing JSON:', error.message) +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0 +const number = 7 +log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`) + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log('This code runs after a delay of 2 seconds.') +}, 2000) + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) +) { + foo() +} diff --git a/packages/eslint-config/__fixtures__/output/ts-strict-with-react/jsx.jsx b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/jsx.jsx new file mode 100644 index 000000000..523af3782 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/jsx.jsx @@ -0,0 +1,29 @@ +export function HelloWorld({ + greeting = 'hello', + greeted = '"World"', + silent = false, + onMouseOver, +}) { + if (!greeting) { + return null + }; + + // TODO: Don't use random in render + const num = Math + .floor (Math.random() * 1e+7) + .toString() + .replace(/\.\d+/g, '') + + return ( +
+ { greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(',') + ? ' ' + : ", " } + + { greeted } + + { (silent) ? '.' : '!'} +
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/ts-strict-with-react/markdown.md b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/markdown.md new file mode 100644 index 000000000..a66c94c89 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/markdown.md @@ -0,0 +1,34 @@ +Header +====== + +_Look,_ code blocks are formatted *too!* + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log('bar') + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { color:red;} +``` + +Pilot|Airport|Hours +--|:--:|--: +John Doe|SKG|1338 +Jane Roe|JFK|314 + +- - - - - - - - - - - - - - - + ++ List + + with a [link] (/to/somewhere) ++ and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/packages/eslint-config/__fixtures__/output/ts-strict-with-react/toml.toml b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/toml.toml new file mode 100644 index 000000000..1f73d046b --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] +b = 1 +c = "hello" +a = { answer = 42 } +indent = [ + 1, + 2 +] + +[a-table] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/output/ts-strict-with-react/tsx.tsx b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/tsx.tsx new file mode 100644 index 000000000..ab640af67 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/tsx.tsx @@ -0,0 +1,32 @@ +export function Component1() { + return
+} + +export function jsx2() { + const props = { a: 1, b: 2 } + return ( + +
+ Inline Text +
+ + Block Text + +
+ Mixed +
Foo
+ Text + Bar +
+

+ foo + bar + baz +

+
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/ts-strict-with-react/typescript.ts b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/typescript.ts new file mode 100644 index 000000000..29016e385 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/typescript.ts @@ -0,0 +1,84 @@ +// Define a TypeScript interface +interface Person { + name: string + age: number +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + { name: 'Charlie', age: 35 }, +] + +// eslint-disable-next-line no-console +const log = console.log + +// Use a for...of loop to iterate over the array +for (const person of people) { + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`) +} + +// Define a generic function +function identity< T >(arg: T): T { + return arg +} + +// Use the generic function with type inference +const result = identity( + 'TypeScript is awesome', +) +log(result) + +// Use optional properties in an interface +interface Car { + make: string + model?: string +} + +// Create objects using the interface +const car1: Car = { make: 'Toyota' } +const car2: Car = { + make: 'Ford', + model: 'Focus', +} + +// Use union types +type Fruit = 'apple' | 'banana' | 'orange' +const favoriteFruit: Fruit = 'apple' + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = '42' +const numericValue = inputValue as number + +// Define a class with access modifiers +class Animal { + private name: string + constructor(name: string) { + this.name = name + } + + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`) + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias) + } + + bark() { + this.makeSound('Woof!') + } +} + +const dog = new Dog('Buddy') +dog.bark() + +function fn(): string { + return `hello${1}` +} + +log(car1, car2, favoriteFruit, numericValue, fn()) diff --git a/packages/eslint-config/__fixtures__/output/ts-strict-with-react/vue-ts.vue b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/vue-ts.vue new file mode 100644 index 000000000..ce35e66b0 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/vue-ts.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/packages/eslint-config/__fixtures__/output/ts-strict-with-react/vue.vue b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/vue.vue new file mode 100644 index 000000000..944cc4e56 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/vue.vue @@ -0,0 +1,27 @@ + + + diff --git a/packages/eslint-config/__fixtures__/output/ts-strict/javascript.js b/packages/eslint-config/__fixtures__/output/ts-strict/javascript.js new file mode 100644 index 000000000..e0702598c --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict/javascript.js @@ -0,0 +1,73 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name + this.age = age + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`) + } +} + +// Create an array of objects +const people = [ + new Person('Alice', 30), + new Person('Bob', 25), + new Person('Charlie', 35), +] + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello() +}) + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +` + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0] +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString) + +// Use the spread operator to create a new array +const numbers = [1, 2, 3] +const newNumbers = [...numbers, 4, 5] +log(newNumbers) + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse('invalid JSON') +} +catch (error) { + console.error('Error parsing JSON:', error.message) +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0 +const number = 7 +log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`) + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log('This code runs after a delay of 2 seconds.') +}, 2000) + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) +) { + foo() +} diff --git a/packages/eslint-config/__fixtures__/output/ts-strict/jsx.jsx b/packages/eslint-config/__fixtures__/output/ts-strict/jsx.jsx new file mode 100644 index 000000000..523af3782 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict/jsx.jsx @@ -0,0 +1,29 @@ +export function HelloWorld({ + greeting = 'hello', + greeted = '"World"', + silent = false, + onMouseOver, +}) { + if (!greeting) { + return null + }; + + // TODO: Don't use random in render + const num = Math + .floor (Math.random() * 1e+7) + .toString() + .replace(/\.\d+/g, '') + + return ( +
+ { greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(',') + ? ' ' + : ", " } + + { greeted } + + { (silent) ? '.' : '!'} +
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/ts-strict/markdown.md b/packages/eslint-config/__fixtures__/output/ts-strict/markdown.md new file mode 100644 index 000000000..a66c94c89 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict/markdown.md @@ -0,0 +1,34 @@ +Header +====== + +_Look,_ code blocks are formatted *too!* + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log('bar') + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { color:red;} +``` + +Pilot|Airport|Hours +--|:--:|--: +John Doe|SKG|1338 +Jane Roe|JFK|314 + +- - - - - - - - - - - - - - - + ++ List + + with a [link] (/to/somewhere) ++ and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/packages/eslint-config/__fixtures__/output/ts-strict/toml.toml b/packages/eslint-config/__fixtures__/output/ts-strict/toml.toml new file mode 100644 index 000000000..1f73d046b --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] +b = 1 +c = "hello" +a = { answer = 42 } +indent = [ + 1, + 2 +] + +[a-table] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/output/ts-strict/tsx.tsx b/packages/eslint-config/__fixtures__/output/ts-strict/tsx.tsx new file mode 100644 index 000000000..ab640af67 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict/tsx.tsx @@ -0,0 +1,32 @@ +export function Component1() { + return
+} + +export function jsx2() { + const props = { a: 1, b: 2 } + return ( + +
+ Inline Text +
+ + Block Text + +
+ Mixed +
Foo
+ Text + Bar +
+

+ foo + bar + baz +

+
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/ts-strict/typescript.ts b/packages/eslint-config/__fixtures__/output/ts-strict/typescript.ts new file mode 100644 index 000000000..29016e385 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict/typescript.ts @@ -0,0 +1,84 @@ +// Define a TypeScript interface +interface Person { + name: string + age: number +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + { name: 'Charlie', age: 35 }, +] + +// eslint-disable-next-line no-console +const log = console.log + +// Use a for...of loop to iterate over the array +for (const person of people) { + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`) +} + +// Define a generic function +function identity< T >(arg: T): T { + return arg +} + +// Use the generic function with type inference +const result = identity( + 'TypeScript is awesome', +) +log(result) + +// Use optional properties in an interface +interface Car { + make: string + model?: string +} + +// Create objects using the interface +const car1: Car = { make: 'Toyota' } +const car2: Car = { + make: 'Ford', + model: 'Focus', +} + +// Use union types +type Fruit = 'apple' | 'banana' | 'orange' +const favoriteFruit: Fruit = 'apple' + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = '42' +const numericValue = inputValue as number + +// Define a class with access modifiers +class Animal { + private name: string + constructor(name: string) { + this.name = name + } + + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`) + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias) + } + + bark() { + this.makeSound('Woof!') + } +} + +const dog = new Dog('Buddy') +dog.bark() + +function fn(): string { + return `hello${1}` +} + +log(car1, car2, favoriteFruit, numericValue, fn()) diff --git a/packages/eslint-config/__fixtures__/output/ts-strict/vue-ts.vue b/packages/eslint-config/__fixtures__/output/ts-strict/vue-ts.vue new file mode 100644 index 000000000..ce35e66b0 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict/vue-ts.vue @@ -0,0 +1,35 @@ + + + + + + + diff --git a/packages/eslint-config/__fixtures__/output/ts-strict/vue.vue b/packages/eslint-config/__fixtures__/output/ts-strict/vue.vue new file mode 100644 index 000000000..944cc4e56 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/ts-strict/vue.vue @@ -0,0 +1,27 @@ + + + diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/astro.astro b/packages/eslint-config/__fixtures__/output/with-formatters/astro.astro new file mode 100644 index 000000000..47e8620b5 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/astro.astro @@ -0,0 +1,18 @@ +--- +const isJsx = true +const content = 'hi!' +--- + +
+
{content}
+
+ {isJsx &&

{content}

} +
+
+ + diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/css.css b/packages/eslint-config/__fixtures__/output/with-formatters/css.css new file mode 100644 index 000000000..ad88dbcfb --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/css.css @@ -0,0 +1,11 @@ +@media (max-width: 480px) { + .bd-examples { + margin-right: -0.75rem; + margin-left: -0.75rem; + } + + .bd-examples > [class^='col-'] { + padding-right: 0.75rem; + padding-left: 0.75rem; + } +} diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/html.html b/packages/eslint-config/__fixtures__/output/with-formatters/html.html new file mode 100644 index 000000000..f4aec70fe --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/html.html @@ -0,0 +1,24 @@ + + + + + My tITlE + + + +

+ Hello world!
+ This is HTML5 Boilerplate. +

+ + + + diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/javascript.js b/packages/eslint-config/__fixtures__/output/with-formatters/javascript.js new file mode 100644 index 000000000..e0702598c --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/javascript.js @@ -0,0 +1,73 @@ +// This file is generated by ChatGPT + +// eslint-disable-next-line no-console +const log = console.log + +// Define a class using ES6 class syntax +class Person { + constructor(name, age) { + this.name = name + this.age = age + } + + // Define a method within the class + sayHello() { + log(`Hello, my name is ${this.name} and I am ${this.age} years old.`) + } +} + +// Create an array of objects +const people = [ + new Person('Alice', 30), + new Person('Bob', 25), + new Person('Charlie', 35), +] + +// Use the forEach method to iterate over the array +people.forEach((person) => { + person.sayHello() +}) + +// Use a template literal to create a multiline string +const multilineString = ` + This is a multiline string + that spans multiple lines. +` + +// Use destructuring assignment to extract values from an object +const { name, age } = people[0] +log(`First person in the array is ${name} and they are ${age} years old.`, multilineString) + +// Use the spread operator to create a new array +const numbers = [1, 2, 3] +const newNumbers = [...numbers, 4, 5] +log(newNumbers) + +// Use a try-catch block for error handling +try { + // Attempt to parse an invalid JSON string + JSON.parse('invalid JSON') +} +catch (error) { + console.error('Error parsing JSON:', error.message) +} + +// Use a ternary conditional operator +const isEven = num => num % 2 === 0 +const number = 7 +log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`) + +// Use a callback function with setTimeout for asynchronous code +setTimeout(() => { + log('This code runs after a delay of 2 seconds.') +}, 2000) + +let a, b, c, d, foo + +if (a + || b + || c || d + || (d && b) +) { + foo() +} diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/jsx.jsx b/packages/eslint-config/__fixtures__/output/with-formatters/jsx.jsx new file mode 100644 index 000000000..523af3782 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/jsx.jsx @@ -0,0 +1,29 @@ +export function HelloWorld({ + greeting = 'hello', + greeted = '"World"', + silent = false, + onMouseOver, +}) { + if (!greeting) { + return null + }; + + // TODO: Don't use random in render + const num = Math + .floor (Math.random() * 1e+7) + .toString() + .replace(/\.\d+/g, '') + + return ( +
+ { greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase() } + {greeting.endsWith(',') + ? ' ' + : ", " } + + { greeted } + + { (silent) ? '.' : '!'} +
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/markdown.md b/packages/eslint-config/__fixtures__/output/with-formatters/markdown.md new file mode 100644 index 000000000..337663bd9 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/markdown.md @@ -0,0 +1,35 @@ +# Header + +_Look,_ code blocks are formatted _too!_ + +```js +// This should be handled by ESLint instead of Prettier +function identity(x) { + if (foo) { + console.log('bar') + } +} +``` + +```css +/* This should be handled by Prettier */ +.foo { + color: red; +} +``` + +| Pilot | Airport | Hours | +| -------- | :-----: | ----: | +| John Doe | SKG | 1338 | +| Jane Roe | JFK | 314 | + +--- + +- List +- with a [link] (/to/somewhere) +- and [another one] + + [another one]: http://example.com 'Example title' + +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +Curabitur consectetur maximus risus, sed maximus tellus tincidunt et. diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/svg.svg b/packages/eslint-config/__fixtures__/output/with-formatters/svg.svg new file mode 100644 index 000000000..493e162e7 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/svg.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/toml.toml b/packages/eslint-config/__fixtures__/output/with-formatters/toml.toml new file mode 100644 index 000000000..1f73d046b --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/toml.toml @@ -0,0 +1,23 @@ +comma = [ + 1, + 2, + 3, +] + +[foo] +b = 1 +c = "hello" +a = { answer = 42 } +indent = [ + 1, + 2 +] + +[a-table] +apple.type = "fruit" +apple.skin = "thin" +apple.color = "red" + +orange.type = "fruit" +orange.skin = "thick" +orange.color = "orange" diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/tsx.tsx b/packages/eslint-config/__fixtures__/output/with-formatters/tsx.tsx new file mode 100644 index 000000000..ab640af67 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/tsx.tsx @@ -0,0 +1,32 @@ +export function Component1() { + return
+} + +export function jsx2() { + const props = { a: 1, b: 2 } + return ( + +
+ Inline Text +
+ + Block Text + +
+ Mixed +
Foo
+ Text + Bar +
+

+ foo + bar + baz +

+
+ ) +} diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/typescript.ts b/packages/eslint-config/__fixtures__/output/with-formatters/typescript.ts new file mode 100644 index 000000000..29016e385 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/typescript.ts @@ -0,0 +1,84 @@ +// Define a TypeScript interface +interface Person { + name: string + age: number +} + +// Create an array of objects with the defined interface +const people: Person[] = [ + { name: 'Alice', age: 30 }, + { name: 'Bob', age: 25 }, + { name: 'Charlie', age: 35 }, +] + +// eslint-disable-next-line no-console +const log = console.log + +// Use a for...of loop to iterate over the array +for (const person of people) { + log(`Hello, my name is ${person.name} and I am ${person.age} years old.`) +} + +// Define a generic function +function identity< T >(arg: T): T { + return arg +} + +// Use the generic function with type inference +const result = identity( + 'TypeScript is awesome', +) +log(result) + +// Use optional properties in an interface +interface Car { + make: string + model?: string +} + +// Create objects using the interface +const car1: Car = { make: 'Toyota' } +const car2: Car = { + make: 'Ford', + model: 'Focus', +} + +// Use union types +type Fruit = 'apple' | 'banana' | 'orange' +const favoriteFruit: Fruit = 'apple' + +// Use a type assertion to tell TypeScript about the type +const inputValue: any = '42' +const numericValue = inputValue as number + +// Define a class with access modifiers +class Animal { + private name: string + constructor(name: string) { + this.name = name + } + + protected makeSound(sound: string) { + log(`${this.name} says ${sound}`) + } +} + +// Extend a class +class Dog extends Animal { + constructor(private alias: string) { + super(alias) + } + + bark() { + this.makeSound('Woof!') + } +} + +const dog = new Dog('Buddy') +dog.bark() + +function fn(): string { + return `hello${1}` +} + +log(car1, car2, favoriteFruit, numericValue, fn()) diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/vue-ts.vue b/packages/eslint-config/__fixtures__/output/with-formatters/vue-ts.vue new file mode 100644 index 000000000..ea5c75ae9 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/vue-ts.vue @@ -0,0 +1,38 @@ + + + + + + + diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/vue.vue b/packages/eslint-config/__fixtures__/output/with-formatters/vue.vue new file mode 100644 index 000000000..944cc4e56 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/vue.vue @@ -0,0 +1,27 @@ + + + diff --git a/packages/eslint-config/__fixtures__/output/with-formatters/xml.xml b/packages/eslint-config/__fixtures__/output/with-formatters/xml.xml new file mode 100644 index 000000000..88571e3d8 --- /dev/null +++ b/packages/eslint-config/__fixtures__/output/with-formatters/xml.xml @@ -0,0 +1,20 @@ + + + Effective Java + 45.00 + + + Bluetooth Speaker + 120.00 + + + Clean Code + 33.50 + + + + + + + + diff --git a/packages/eslint-config/__tests__/old-config-loading.test.ts b/packages/eslint-config/__tests__/old-config-loading.test.ts deleted file mode 100644 index 5c94e765f..000000000 --- a/packages/eslint-config/__tests__/old-config-loading.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { exec } from "node:child_process"; -import { rm } from "node:fs/promises"; -import { join } from "node:path"; -import { promisify } from "node:util"; - -import { afterEach, beforeEach, describe, expect, it } from "vitest"; - -const ONE_SECOND_IN_MS = 1000; - -const TEST_DIR = join(__dirname, "../__fixtures__", "old-config"); -const NODE_MODULES = join(TEST_DIR, "node_modules"); - -const execAsync = promisify(exec); - -describe("integration - old config", () => { - beforeEach(async () => { - await rm(NODE_MODULES, { force: true, recursive: true }); - }); - - afterEach(async () => { - await rm(NODE_MODULES, { recursive: true }); - }); - - it( - "installs & works", - async () => { - expect.assertions(2); - await execAsync("pnpm --ignore-workspace i", { cwd: TEST_DIR }); - - const { stderr, stdout } = await execAsync("pnpm exec eslint -c ./.eslintrc.js . || true", { - cwd: TEST_DIR, - env: { ...process.env, FORCE_COLOR: "0" }, - }); - - expect(stderr.replace(TEST_DIR, "mocked-root-dir")).toContain(""); - expect(stdout.replace(TEST_DIR, "mocked-root-dir")).toContain("4 problems (3 errors, 1 warning)"); - }, - 240 * ONE_SECOND_IN_MS, - ); -}); diff --git a/packages/eslint-config/__tests__/rules.test.ts b/packages/eslint-config/__tests__/rules.test.ts new file mode 100644 index 000000000..5f02b7879 --- /dev/null +++ b/packages/eslint-config/__tests__/rules.test.ts @@ -0,0 +1,199 @@ +import { existsSync } from "node:fs"; +import { + copyFile, + lstat, + mkdir, + readdir, + readFile, + rm, + writeFile, +} from "node:fs/promises"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +import { execa } from "execa"; +import { glob } from "tinyglobby"; +import { afterAll, beforeAll, it } from "vitest"; + +import type { OptionsConfig, TypedFlatConfigItem } from "../src/types"; + +const rootPath = dirname(fileURLToPath(import.meta.url)); +const fixturesPath = join(rootPath, "..", "__fixtures__"); + +const copyFolderRecursive = async (from: string, to: string) => { + await mkdir(to, { + recursive: true, + }); + + const files = await readdir(from, { + recursive: true, + }); + + // eslint-disable-next-line no-restricted-syntax + for (const element of files) { + // eslint-disable-next-line unicorn/no-await-expression-member,no-await-in-loop + await ((await lstat(join(from, element))).isFile() + ? copyFile(join(from, element), join(to, element)) + : copyFolderRecursive(join(from, element), join(to, element))); + } +}; + +// eslint-disable-next-line vitest/require-top-level-describe +beforeAll(async () => { + await rm(join(rootPath, "_fixtures"), { force: true, recursive: true }); +}); + +// eslint-disable-next-line vitest/require-top-level-describe +afterAll(async () => { + await rm(join(rootPath, "_fixtures"), { force: true, recursive: true }); +}); + +const runWithConfig = (name: string, configs: OptionsConfig, ...items: TypedFlatConfigItem[]) => { + // eslint-disable-next-line vitest/prefer-expect-assertions,vitest/require-top-level-describe + it.concurrent( + // eslint-disable-next-line vitest/valid-title + name, + async ({ expect }) => { + const from = join(fixturesPath, "input"); + const output = join(fixturesPath, "output", name); + + const target = join(rootPath, "_fixtures", name); + + await copyFolderRecursive(from, target); + await writeFile( + join(target, "eslint.config.js"), + ` +// @eslint-disable +import { createConfig } from "@anolilab/eslint-config"; + +export default createConfig( + ${JSON.stringify(configs)}, + ...(${JSON.stringify(items) ?? []}), +); + `, + ); + + await execa("npx", ["eslint", target, "--fix"], { + cwd: target, + stdio: "pipe", + }); + + const files = await glob("**/*", { + cwd: target, + ignore: ["node_modules", "eslint.config.js"], + }); + + await Promise.all( + files.map(async (file: string) => { + const content = await readFile(join(target, file), "utf8"); + const source = await readFile(join(from, file), "utf8"); + const outputPath = join(output, file); + + if (content === source) { + if (existsSync(outputPath)) { + await rm(outputPath); + } + + return; + } + + await expect.soft(content).toMatchFileSnapshot(join(output, file)); + }), + ); + }, + 30_000, + ); +}; + +// eslint-disable-next-line vitest/require-hook +runWithConfig("js", { + typescript: false, + // vue: false, +}); +// runWithConfig("all", { +// astro: true, +// // svelte: true, +// typescript: true, +// // vue: true, +// }); +// runWithConfig("no-style", { +// stylistic: false, +// typescript: true, +// vue: true, +// }); +// runWithConfig( +// "tab-double-quotes", +// { +// stylistic: { +// indent: "tab", +// quotes: "double", +// }, +// typescript: true, +// vue: true, +// }, +// { +// rules: { +// "style/no-mixed-spaces-and-tabs": "off", +// }, +// }, +// ); +// +// // https://github.com/antfu/eslint-config/issues/255 +// runWithConfig( +// "ts-override", +// { +// typescript: true, +// }, +// { +// rules: { +// "ts/consistent-type-definitions": ["error", "type"], +// }, +// }, +// ); +// +// // https://github.com/antfu/eslint-config/issues/255 +// runWithConfig( +// "ts-strict", +// { +// typescript: { +// tsconfigPath: "./tsconfig.json", +// }, +// }, +// { +// rules: { +// "ts/no-unsafe-return": ["off"], +// }, +// }, +// ); +// +// // https://github.com/antfu/eslint-config/issues/618 +// runWithConfig( +// "ts-strict-with-react", +// { +// react: true, +// typescript: { +// tsconfigPath: "./tsconfig.json", +// }, +// }, +// { +// rules: { +// "ts/no-unsafe-return": ["off"], +// }, +// }, +// ); +// +// runWithConfig("with-formatters", { +// astro: true, +// formatters: true, +// typescript: true, +// vue: true, +// }); +// +// runWithConfig("no-markdown-with-formatters", { +// formatters: { +// markdown: true, +// }, +// jsx: false, +// markdown: false, +// vue: false, +// }); diff --git a/packages/eslint-config/bin/generate-eslint-cofig.js b/packages/eslint-config/bin/generate-eslint-cofig.js deleted file mode 100755 index c08dbd81c..000000000 --- a/packages/eslint-config/bin/generate-eslint-cofig.js +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env node - -require("../dist/postinstall"); diff --git a/packages/eslint-config/debug-eslint.config.mjs b/packages/eslint-config/debug-eslint.config.mjs new file mode 100644 index 000000000..f312ddf6d --- /dev/null +++ b/packages/eslint-config/debug-eslint.config.mjs @@ -0,0 +1,4 @@ +// eslint-disable-next-line import/extensions +import { createConfig } from "./dist"; + +export default createConfig({}); diff --git a/packages/eslint-config/eslint.config.js b/packages/eslint-config/eslint.config.js new file mode 100644 index 000000000..327e8770f --- /dev/null +++ b/packages/eslint-config/eslint.config.js @@ -0,0 +1,41 @@ +import { createConfig } from "./dist/index.mjs"; + +export default createConfig( + { + ignores: ["eslint.config.js", "src/typegen.d.ts", "__fixtures__/**/*"], + react: false, + playwright: false, + storybook: false, + tailwindcss: false, + tanstackQuery: false, + tanstackRouter: false, + testingLibrary: false, + tsdoc: false, + unocss: false, + zod: false, + lodash: false, + jsx: false, + html: false, + astro: false, + }, + { + files: ["**/*.ts"], + rules: { + "no-secrets/no-secrets": "off", + }, + }, + { + files: ["debug-eslint.config.mjs"], + rules: { + "antfu/no-import-dist": "off", + }, + }, + { + files: ["README.md"], + rules: { + "import/no-commonjs": "off", + "unicorn/prefer-module": "off", + "jsdoc/check-tag-names": "off", + }, + }, +); diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index 212f9f946..e3c83c53b 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -22,46 +22,34 @@ "eslint-plugin-antfu", "eslint-plugin-compat", "eslint-plugin-es", + "eslint-plugin-es-x", "eslint-plugin-eslint-comments", "eslint-plugin-html", "eslint-plugin-i", + "@tanstack/eslint-plugin-router", "eslint-plugin-jsonc", - "eslint-plugin-markdown", - "eslint-plugin-mdx", - "eslint-plugin-no-loops", + "eslint-markdown", "eslint-plugin-no-secrets", "eslint-plugin-no-use-extend-native", "eslint-plugin-promise", "eslint-plugin-regexp", - "eslint-plugin-simple-import-sort", "eslint-plugin-sonarjs", "eslint-plugin-toml", "eslint-plugin-unicorn", "eslint-plugin-yml", - "eslint-plugin-array-func", - "eslint-plugin-ava", - "eslint-plugin-babel", - "eslint-plugin-cypress", - "eslint-plugin-jest", - "eslint-plugin-jest-async", - "eslint-plugin-jest-dom", - "eslint-plugin-jest-formatting", "eslint-plugin-playwright", "eslint-plugin-jsdoc", "eslint-plugin-jsx-a11y", "eslint-plugin-n", "eslint-plugin-no-unsanitized", - "eslint-plugin-prefer-object-spread", "eslint-plugin-react", "eslint-plugin-react-hooks", - "eslint-plugin-react-redux", "eslint-plugin-storybook", "eslint-plugin-tailwindcss", "eslint-plugin-testing-library", "eslint-plugin-tsdoc", - "eslint-plugin-etc", - "eslint-plugin-you-dont-need-lodash-underscore", - "eslint-plugin-you-dont-need-momentjs" + "eslint-plugin-no-for-of-array", + "eslint-plugin-you-dont-need-lodash-underscore" ], "homepage": "https://anolilab.com/nodejs/packages/eslint-config", "repository": { @@ -84,206 +72,185 @@ "name": "Daniel Bannert", "email": "d.bannert@anolilab.de" }, - "type": "commonjs", + "sideEffects": false, + "type": "module", "exports": { ".": { - "types": "./dist/index.d.ts", - "require": "./dist/index.js" - }, - "./typescript-type-checking": { - "types": "./dist/typescript-type-checking.d.ts", - "require": "./dist/typescript-type-checking.js" - }, - "./globals": { - "types": "./dist/globals.d.ts", - "require": "./dist/globals.js" - }, - "./define-config": { - "types": "./dist/define-config.d.ts", - "require": "./dist/define-config.js" + "import": { + "types": "./dist/index.d.tjs", + "default": "./dist/index.mjs" + }, + "require": { + "types": "./dist/index.d.cts", + "default": "./dist/index.cjs" + } }, "./package.json": "./package.json" }, - "main": "dist/index.js", + "main": "dist/index.cjs", + "module": "dist/index.mjs", "types": "dist/index.d.ts", - "bin": { - "anolilab-eslint-config": "./bin/generate-eslint-cofig.js" + "typesVersions": { + ">=5.0": { + ".": [ + "./dist/index.d.ts" + ] + } }, "files": [ - "bin/generate-eslint-cofig.js", - "dist", - "skip.js", - "globals.js", - "typescript-type-checking.js", - "README.md", "CHANGELOG.md", - "LICENSE.md" + "LICENSE.md", + "README.md", + "dist" ], "scripts": { - "build": "cross-env NODE_ENV=development tsup", - "build:prod": "cross-env NODE_ENV=production tsup", + "build": "pnpm run build:typegen && pnpm run build:global-vitest && packem build --development", + "build:global-vitest": "tsx ./scripts/global-vitest.ts", + "build:prod": "pnpm run build:typegen && pnpm run build:global-vitest && packem build --production", + "build:typegen": "tsx ./scripts/typegen.ts", "clean": "rimraf node_modules dist", - "postinstall": "node ./skip.js || node ./dist/postinstall.js", - "test": "vitest --config ./vitest.config.ts", - "test:coverage": "vitest --config ./vitest.config.ts --run --coverage" + "debug:rules": "pnpm exec eslint-config-inspector --config ./debug-eslint.config.mjs", + "lint:attw": "attw --pack", + "lint:eslint": "eslint .", + "lint:eslint:fix": "eslint . --fix", + "lint:prettier": "prettier --config=.prettierrc.cjs --check .", + "lint:prettier:fix": "prettier --config=.prettierrc.cjs --write .", + "test": "vitest run", + "test:coverage": "vitest run --coverage", + "test:ui": "vitest --ui --coverage.enabled=true", + "test:watch": "vitest" }, "dependencies": { - "@anolilab/package-json-utils": "3.0.9", - "@babel/eslint-parser": "^7.22.15", - "@babel/plugin-syntax-import-assertions": "^7.22.5", - "@eslint/js": "^8.52.0", - "@html-eslint/eslint-plugin": "^0.20.0", - "@html-eslint/parser": "^0.20.0", - "@jsenv/eslint-import-resolver": ">=8.0.4", - "@rushstack/eslint-patch": "^1.5.1", - "@rushstack/eslint-plugin-security": "^0.7.1", - "@typescript-eslint/eslint-plugin": ">=6.9.1", - "@typescript-eslint/parser": "^6.9.1", + "@antfu/install-pkg": "^1.0.0", + "@eslint-community/eslint-plugin-eslint-comments": "^4.4.1", + "@eslint/compat": "^1.2.5", + "@eslint/js": "^9.18.0", + "@eslint/markdown": "^6.2.1", + "@html-eslint/eslint-plugin": "^0.32.0", + "@html-eslint/parser": "^0.32.0", + "@stylistic/eslint-plugin": "^2.12.1", + "@stylistic/eslint-plugin-ts": "^2.12.1", + "@typescript-eslint/eslint-plugin": "^8.19.1", + "@typescript-eslint/parser": "^8.19.1", + "@visulima/package": "^3.4.2", + "@visulima/tsconfig": "^1.1.6", + "@vitest/eslint-plugin": "^1.1.25", "confusing-browser-globals": "^1.0.11", - "eslint-define-config": "^1.24.1", + "eslint-config-flat-gitignore": "^1.0.0", + "eslint-flat-config-utils": "^1.0.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-antfu": "^1.0.1", - "eslint-plugin-compat": "^4.2.0", - "eslint-plugin-es-x": "^7.2.0", - "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-html": "^7.1.0", - "eslint-plugin-i": "^2.29.0", - "eslint-plugin-jsonc": "^2.10.0", - "eslint-plugin-markdown": "^3.0.1", - "eslint-plugin-mdx": "^2.2.0", - "eslint-plugin-n": "^16.2.0", - "eslint-plugin-no-loops": "^0.3.0", - "eslint-plugin-no-only-tests": "^3.1.0", - "eslint-plugin-no-secrets": "^0.8.9", - "eslint-plugin-no-use-extend-native": "^0.5.0", - "eslint-plugin-perfectionist": "^2.2.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-regexp": "^2.1.1", - "eslint-plugin-security": "^1.7.1", - "eslint-plugin-simple-import-sort": "^10.0.0", - "eslint-plugin-sonarjs": "^0.22.0", - "eslint-plugin-toml": "^0.6.0", - "eslint-plugin-unicorn": "^49.0.0", - "eslint-plugin-yml": "^1.10.0", - "find-up": "5.0.0", - "globals": "^13.23.0", + "eslint-import-resolver-typescript": "^3.7.0", + "eslint-merge-processors": "^1.0.0", + "eslint-plugin-antfu": "^2.7.0", + "eslint-plugin-compat": "^6.0.2", + "eslint-plugin-es-x": "^8.4.1", + "eslint-plugin-html": "^8.1.2", + "eslint-plugin-import-x": "^4.6.1", + "eslint-plugin-jsdoc": "^50.6.1", + "eslint-plugin-jsonc": "^2.18.2", + "eslint-plugin-n": "^17.15.1", + "eslint-plugin-no-for-of-array": "^0.1.0", + "eslint-plugin-no-only-tests": "^3.3.0", + "eslint-plugin-no-secrets": "^2.1.1", + "eslint-plugin-no-unsanitized": "^4.1.2", + "eslint-plugin-perfectionist": "^4.6.0", + "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-regexp": "^2.7.0", + "eslint-plugin-security": "^3.0.1", + "eslint-plugin-simple-import-sort": "^12.1.1", + "eslint-plugin-sonarjs": "^3.0.1", + "eslint-plugin-toml": "^0.12.0", + "eslint-plugin-unicorn": "^56.0.1", + "eslint-plugin-unused-imports": "^4.1.4", + "eslint-plugin-yml": "^1.16.0", + "globals": "^15.14.0", "jsonc-eslint-parser": "^2.4.0", - "read-pkg-up": "^7.0.1", - "semver": "^7.5.4", - "toml-eslint-parser": "^0.6.0", - "yaml-eslint-parser": "^1.2.2" + "parse-gitignore": "^2.0.0", + "semver": "^7.6.3", + "toml-eslint-parser": "^0.10.0", + "typescript-eslint": "^8.19.1", + "yaml-eslint-parser": "^1.2.3" }, "devDependencies": { - "@anolilab/semantic-release-preset": "8.0.3", - "@arthurgeron/eslint-plugin-react-usememo": "^2.2.1", - "@testing-library/dom": "^9.3.3", - "@total-typescript/ts-reset": "^0.5.1", + "@anolilab/prettier-config": "^5.0.14", + "@anolilab/semantic-release-preset": "9.0.3", + "@eslint-react/eslint-plugin": "^1.23.2", + "@eslint/config-inspector": "^0.7.1", + "@stylistic/eslint-plugin-migrate": "^2.12.1", + "@tanstack/eslint-plugin-query": "^5.62.16", + "@tanstack/eslint-plugin-router": "^1.92.7", + "@testing-library/dom": "^10.4.0", + "@total-typescript/ts-reset": "^0.6.1", "@types/confusing-browser-globals": "^1.0.3", - "@types/eslint": "^8.56.0", - "@types/semver": "^7.5.6", - "eslint": "^8.56.0", - "eslint-find-rules": "^4.1.0", - "eslint-plugin-babel": "^5.3.1", - "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-deprecation": "^2.0.0", - "eslint-plugin-editorconfig": "^4.0.3", - "eslint-plugin-etc": "^2.0.3", - "eslint-plugin-jest": "^27.6.0", - "eslint-plugin-jest-async": "^1.0.3", - "eslint-plugin-jest-dom": "^5.1.0", - "eslint-plugin-jest-formatting": "^3.1.0", - "eslint-plugin-jsdoc": "^46.9.1", - "eslint-plugin-jsx-a11y": "^6.8.0", - "eslint-plugin-no-unsanitized": "^4.0.2", - "eslint-plugin-prefer-object-spread": "^1.2.1", - "eslint-plugin-react": "^7.33.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-redux": "^4.1.0", - "eslint-plugin-ssr-friendly": "^1.3.0", - "eslint-plugin-storybook": "^0.6.15", - "eslint-plugin-tailwindcss": "^3.13.0", - "eslint-plugin-testing-library": "^6.2.0", + "@types/eslint": "^9.6.1", + "@types/eslint-plugin-jsx-a11y": "^6.10.0", + "@types/eslint-plugin-tailwindcss": "^3.17.0", + "@types/semver": "^7.5.8", + "@unocss/eslint-plugin": "^65.4.0", + "@visulima/packem": "^1.10.7", + "astro-eslint-parser": "^1.1.0", + "esbuild": "^0.24.2", + "eslint": "^9.18.0", + "eslint-plugin-astro": "^1.3.1", + "eslint-plugin-format": "^1.0.1", + "eslint-plugin-jsx-a11y": "^6.10.2", + "eslint-plugin-react": "^7.37.3", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.18", + "eslint-plugin-storybook": "^0.11.2", + "eslint-plugin-tailwindcss": "^3.17.5", + "eslint-plugin-testing-library": "^7.1.1", + "eslint-plugin-tsdoc": "^0.4.0", "eslint-plugin-validate-jsx-nesting": "^0.1.1", - "eslint-plugin-vitest": "^0.3.18", - "eslint-plugin-you-dont-need-lodash-underscore": "^6.13.0", - "eslint-plugin-you-dont-need-momentjs": "^1.6.0", + "eslint-plugin-vitest": "^0.5.4", + "eslint-plugin-you-dont-need-lodash-underscore": "^6.14.0", "eslint-plugin-zod": "^1.4.0", - "jest": "^29.7.0", - "react": "^18.2.0", - "rimraf": "^5.0.5", - "semantic-release": "^22.0.12", - "tsup": "^8.0.1", - "type-fest": "^4.8.3", - "typescript": "^5.3.3", - "vitest": "^1.1.0" + "eslint-typegen": "^1.0.0", + "execa": "^9.5.2", + "prettier": "^3.4.2", + "react": "^19.0.0", + "rimraf": "^6.0.1", + "semantic-release": "^24.2.1", + "tinyglobby": "^0.2.10", + "tsx": "^4.19.2", + "type-fest": "^4.32.0", + "typescript": "^5.7.3", + "vitest": "^2.1.8" }, "peerDependencies": { - "@arthurgeron/eslint-plugin-react-usememo": "^2.0.1", "@babel/core": "^7.22.20", - "@tanstack/eslint-plugin-query": "^4.34.1 || ^5.0.0", - "eslint": "^8.15.0", - "eslint-plugin-array-func": "^4.0.0", - "eslint-plugin-ava": "^14.0.0", - "eslint-plugin-babel": "^5.3.1", - "eslint-plugin-cypress": "^2.15.1", - "eslint-plugin-editorconfig": "^4.0.3", - "eslint-plugin-jest": "^27.4.0", - "eslint-plugin-jest-async": "^1.0.3", - "eslint-plugin-jest-dom": "^5.1.0", - "eslint-plugin-jest-formatting": "^3.1.0", - "eslint-plugin-jsdoc": "^46.8.2", + "@eslint-react/eslint-plugin": "^1.22.1", + "@tanstack/eslint-plugin-query": "^5.0.0", + "@tanstack/eslint-plugin-router": "^1.92.7", + "@unocss/eslint-plugin": "^0.65.3", + "astro-eslint-parser": "^1.1.0", + "eslint": "^9.10.0", + "eslint-plugin-astro": "^1.3.1", + "eslint-plugin-format": ">=0.1.0", "eslint-plugin-jsx-a11y": "^6.7.1", - "eslint-plugin-no-unsanitized": "^4.0.2", "eslint-plugin-playwright": "^0.16.0 || ^0.18.0", - "eslint-plugin-prefer-object-spread": "^1.2.1", - "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react": "^7.37.3", "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-react-redux": "^4.0.0", - "eslint-plugin-ssr-friendly": "^1.2.0", + "eslint-plugin-react-refresh": "^0.4.16", "eslint-plugin-storybook": "^0.6.14", "eslint-plugin-tailwindcss": "^3.13.0", "eslint-plugin-testing-library": "^6.0.1", "eslint-plugin-tsdoc": "^0.2.17", "eslint-plugin-validate-jsx-nesting": "^0.1.1", "eslint-plugin-you-dont-need-lodash-underscore": "^6.13.0", - "eslint-plugin-you-dont-need-momentjs": "^1.6.0" + "eslint-plugin-zod": "^1.4.0" }, "peerDependenciesMeta": { - "@arthurgeron/eslint-plugin-react-usememo": { + "@eslint-react/eslint-plugin": { "optional": true }, "@tanstack/eslint-plugin-query": { "optional": true }, - "eslint-plugin-array-func": { - "optional": true - }, - "eslint-plugin-ava": { - "optional": true - }, - "eslint-plugin-babel": { - "optional": true - }, - "eslint-plugin-cypress": { - "optional": true - }, - "eslint-plugin-editorconfig": { + "@tanstack/eslint-plugin-router": { "optional": true }, - "eslint-plugin-jest": { - "optional": true - }, - "eslint-plugin-jest-async": { - "optional": true - }, - "eslint-plugin-jest-dom": { - "optional": true - }, - "eslint-plugin-jest-formatting": { - "optional": true - }, - "eslint-plugin-jsdoc": { + "@unocss/eslint-plugin": { "optional": true }, "eslint-plugin-jsx-a11y": { @@ -292,27 +259,15 @@ "eslint-plugin-n": { "optional": true }, - "eslint-plugin-no-unsanitized": { - "optional": true - }, "eslint-plugin-playwright": { "optional": true }, - "eslint-plugin-prefer-object-spread": { - "optional": true - }, "eslint-plugin-react": { "optional": true }, "eslint-plugin-react-hooks": { "optional": true }, - "eslint-plugin-react-redux": { - "optional": true - }, - "eslint-plugin-ssr-friendly": { - "optional": true - }, "eslint-plugin-storybook": { "optional": true }, @@ -331,7 +286,7 @@ "eslint-plugin-you-dont-need-lodash-underscore": { "optional": true }, - "eslint-plugin-you-dont-need-momentjs": { + "eslint-plugin-zod": { "optional": true }, "typescript": { @@ -339,77 +294,10 @@ } }, "engines": { - "node": ">=18.* <=21.*" + "node": ">=18.* <=23.*" }, "publishConfig": { "access": "public", "provenance": true - }, - "sources": [ - "src/config/best-practices.ts", - "src/config/errors.ts", - "src/config/es6.ts", - "src/config/plugins/antfu.ts", - "src/config/plugins/array-func.ts", - "src/config/plugins/ava.ts", - "src/config/plugins/babel.ts", - "src/config/plugins/compat.ts", - "src/config/plugins/cypress.ts", - "src/config/plugins/deprecation.ts", - "src/config/plugins/es.ts", - "src/config/plugins/eslint-comments.ts", - "src/config/plugins/etc.ts", - "src/config/plugins/editorconfig.ts", - "src/config/plugins/html.ts", - "src/config/plugins/import.ts", - "src/config/plugins/jest-async.ts", - "src/config/plugins/jest-dom.ts", - "src/config/plugins/jest-formatting.ts", - "src/config/plugins/jest.ts", - "src/config/plugins/jsdoc.ts", - "src/config/plugins/jsonc.ts", - "src/config/plugins/jsx-a11y.ts", - "src/config/plugins/markdown.ts", - "src/config/plugins/mdx.ts", - "src/config/plugins/no-extend-native.ts", - "src/config/plugins/no-loops.ts", - "src/config/plugins/no-only-tests.ts", - "src/config/plugins/no-secrets.ts", - "src/config/plugins/no-unsanitized.ts", - "src/config/plugins/node.ts", - "src/config/plugins/perfectionist.ts", - "src/config/plugins/playwright.ts", - "src/config/plugins/promise.ts", - "src/config/plugins/regexp.ts", - "src/config/plugins/react.ts", - "src/config/plugins/react-hooks.ts", - "src/config/plugins/react-redux.ts", - "src/config/plugins/react-usememo.ts", - "src/config/plugins/security.ts", - "src/config/plugins/simple-import-sort.ts", - "src/config/plugins/sonarjs.ts", - "src/config/plugins/ssr-friendly.ts", - "src/config/plugins/storybook.ts", - "src/config/plugins/tailwindcss.ts", - "src/config/plugins/tanstack-query.ts", - "src/config/plugins/testing-library-dom.ts", - "src/config/plugins/testing-library-react.ts", - "src/config/plugins/toml.ts", - "src/config/plugins/tsdoc.ts", - "src/config/plugins/typescript.ts", - "src/config/plugins/unicorn.ts", - "src/config/plugins/validate-jsx-nesting.ts", - "src/config/plugins/vitest.ts", - "src/config/plugins/yml.ts", - "src/config/plugins/you-dont-need-lodash-underscore.ts", - "src/config/plugins/you-dont-need-momentjs.ts", - "src/config/plugins/zod.ts", - "src/config/style.ts", - "src/config/variables.ts", - "src/globals.ts", - "src/index.ts", - "src/postinstall.ts", - "src/typescript-type-checking.ts", - "src/define-config.ts" - ] + } } diff --git a/packages/eslint-config/packem.config.ts b/packages/eslint-config/packem.config.ts new file mode 100644 index 000000000..04577878b --- /dev/null +++ b/packages/eslint-config/packem.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from "@visulima/packem/config"; +import transformer from "@visulima/packem/transformer/esbuild"; + +export default defineConfig({ + declaration: false, + rollup: { + license: { + path: "./LICENSE.md", + }, + node10Compatibility: { + typeScriptVersion: ">=5.0", + writeToPackageJson: true, + }, + }, + transformer, + validation: { + packageJson: { + exports: false, + }, + }, +}); diff --git a/packages/eslint-config/scripts/global-vitest.ts b/packages/eslint-config/scripts/global-vitest.ts new file mode 100644 index 000000000..d601f3021 --- /dev/null +++ b/packages/eslint-config/scripts/global-vitest.ts @@ -0,0 +1,93 @@ +/** + * This script is used to generate the globals used by vitest. + * + * A modified version of the original script from https://github.com/FRSOURCE/toolkit/blob/ac470422ba97837556c8a281e6ed4f73bcd0ba90/packages/globals-vitest + * + * MIT License + * Copyright (c) 2024 FRSOURCE - Let's shape your web + */ +import { writeFileSync } from "node:fs"; +import { createRequire } from "node:module"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +import type { ModuleBody, SourceFile } from "typescript"; +// eslint-disable-next-line import/no-extraneous-dependencies +import ts from "typescript"; + +const rootPath = dirname(fileURLToPath(import.meta.url)); + +const showMessageAndExit = (message: string, fail = true) => { + // eslint-disable-next-line no-console + console.log(message); + + // eslint-disable-next-line unicorn/no-process-exit + process.exit(fail ? 1 : 0); +}; + +const extract = (file: string) => { + const program = ts.createProgram([file], {}); + const sourceFile = program.getSourceFile(file) as SourceFile; + const globals: string[] = []; + + ts.forEachChild(sourceFile, (node) => { + if (ts.isModuleDeclaration(node)) { + ts.forEachChild(node.body as ModuleBody, (mNode) => { + if (ts.isVariableStatement(mNode)) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ts.forEachChild(mNode, (vNode: any) => { + if (ts.isVariableDeclarationList(vNode)) { + // eslint-disable-next-line no-restricted-syntax + for (const declaration of vNode.declarations) { + const name = ts.getNameOfDeclaration(declaration); + + if (name && "escapedText" in name) { + globals.push(name.escapedText as string); + } + } + } + }); + } + }); + } + }); + + return globals; +}; + +const require = createRequire(import.meta.url); +const packagePath = require.resolve("vitest/package.json"); + +const { + default: { version: vitestVersion }, +} = await import(packagePath, { + with: { type: "json" }, +}); + +if (!vitestVersion) { + showMessageAndExit("Vitest version cannot be read."); +} + +const globalsPath = require.resolve("vitest/globals.d.ts"); + +const globalsArray = extract(globalsPath); +const globals: Record = {}; + +if (globalsArray.length === 0) { + showMessageAndExit("No globals! Check extractor implementation."); +} + +globalsArray.forEach((globalName) => { + globals[globalName] = true; +}); + +const moduleContent = `/** + * vitest version ${vitestVersion} + */ +export default /** @type {const} */ (${JSON.stringify(globals, undefined, 4)}); +`; + +writeFileSync(join(rootPath, "..", "src", "utils", "vitest-globals.ts"), moduleContent); + +// eslint-disable-next-line no-console +console.log("Finished generation with result:\n", moduleContent); diff --git a/packages/eslint-config/scripts/typegen.ts b/packages/eslint-config/scripts/typegen.ts new file mode 100644 index 000000000..c98602bc8 --- /dev/null +++ b/packages/eslint-config/scripts/typegen.ts @@ -0,0 +1,137 @@ +import fs from "node:fs/promises"; + +import type { NormalizedPackageJson } from "@visulima/package"; +import { builtinRules } from "eslint/use-at-your-own-risk"; +import { flatConfigsToRulesDTS } from "eslint-typegen/core"; + +import bestPractices from "../src/config/best-practices"; +import errors from "../src/config/errors"; +import antfu from "../src/config/plugins/antfu"; +import astro from "../src/config/plugins/astro"; +import comments from "../src/config/plugins/comments"; +import compat from "../src/config/plugins/compat"; +import formatters from "../src/config/plugins/formatters"; +import html from "../src/config/plugins/html"; +import imports from "../src/config/plugins/imports"; +import javascript from "../src/config/plugins/javascript"; +import jsdoc from "../src/config/plugins/jsdoc"; +import jsonc from "../src/config/plugins/jsonc"; +import jsxA11y from "../src/config/plugins/jsx-a11y"; +import markdown from "../src/config/plugins/markdown"; +import noSecrets from "../src/config/plugins/no-secrets"; +import noUnsanitized from "../src/config/plugins/no-unsanitized"; +import node from "../src/config/plugins/node"; +import perfectionist from "../src/config/plugins/perfectionist"; +import playwright from "../src/config/plugins/playwright"; +import promise from "../src/config/plugins/promise"; +import react from "../src/config/plugins/react"; +import regexp from "../src/config/plugins/regexp"; +import simpleImportSort from "../src/config/plugins/simple-import-sort"; +import sonarjs from "../src/config/plugins/sonarjs"; +import storybook from "../src/config/plugins/storybook"; +import stylistic from "../src/config/plugins/stylistic"; +import tailwindcss from "../src/config/plugins/tailwindcss"; +import tanstackQuery from "../src/config/plugins/tanstack-query"; +import tanstackRouter from "../src/config/plugins/tanstack-router"; +import testingLibrary from "../src/config/plugins/testing-library"; +import toml from "../src/config/plugins/toml"; +import tsdoc from "../src/config/plugins/tsdoc"; +import typescript from "../src/config/plugins/typescript"; +import unicorn from "../src/config/plugins/unicorn"; +import unocss from "../src/config/plugins/unocss"; +import validateJsxNesting from "../src/config/plugins/validate-jsx-nesting"; +import vitest from "../src/config/plugins/vitest"; +import yaml from "../src/config/plugins/yml"; +import youDontNeedLodashUnderscore from "../src/config/plugins/you-dont-need-lodash-underscore"; +import zod from "../src/config/plugins/zod"; +import style from "../src/config/style"; +import variables from "../src/config/variables"; +import combine from "../src/utils/combine"; + +const fakePackageJson = {} as NormalizedPackageJson; + +const configs = await combine( + { + plugins: { + "": { + rules: Object.fromEntries(builtinRules.entries()), + }, + }, + }, + antfu({ + packageJson: fakePackageJson, + }), + astro({}), + bestPractices({}), + compat({}), + errors({}), + html({}), + noSecrets({}), + noUnsanitized({}), + playwright({}), + promise({}), + simpleImportSort({}), + sonarjs({}), + storybook({}), + tailwindcss({}), + tanstackQuery({}), + tanstackRouter({}), + tsdoc({}), + validateJsxNesting({}), + variables({}), + style({}), + comments({}), + formatters({}, {}), + imports({ + cwd: "", + packageJson: fakePackageJson, + }), + javascript({ + packageJson: fakePackageJson, + }), + jsxA11y({}), + jsdoc({ + packageJson: fakePackageJson, + }), + jsonc({ + packageJson: fakePackageJson, + }), + markdown({}), + perfectionist({ + packageJson: fakePackageJson, + }), + react({ + packageJson: fakePackageJson, + }), + node({ + packageJson: fakePackageJson, + }), + youDontNeedLodashUnderscore({}), + stylistic({}), + vitest({}), + toml({}), + regexp({}), + typescript({}), + unicorn({ + packageJson: fakePackageJson, + }), + testingLibrary({ + packageJson: fakePackageJson, + }), + unocss({}), + yaml({}), + zod({}), +); + +const configNames = configs.map(index => index.name).filter(Boolean) as string[]; + +let dts = await flatConfigsToRulesDTS(configs, { + includeAugmentation: false, +}); + +dts += ` +// Names of all the configs +export type ConfigNames = ${configNames.map(index => `'${index}'`).join(" | ")} +`; + +await fs.writeFile("src/typegen.d.ts", dts); diff --git a/packages/eslint-config/skip.js b/packages/eslint-config/skip.js deleted file mode 100644 index d64d9b3c9..000000000 --- a/packages/eslint-config/skip.js +++ /dev/null @@ -1,7 +0,0 @@ -if (process.env.SKIP_BUILD) { - // eslint-disable-next-line unicorn/no-process-exit - process.exit(0); -} else { - // eslint-disable-next-line unicorn/no-process-exit - process.exit(1); -} diff --git a/packages/eslint-config/src/config.ts b/packages/eslint-config/src/config.ts deleted file mode 100644 index 0687d2cf4..000000000 --- a/packages/eslint-config/src/config.ts +++ /dev/null @@ -1,574 +0,0 @@ -import { hasDependency, hasDevDependency, hasFile, resolvePackage } from "@anolilab/package-json-utils"; - -import type { PackageRules } from "./types"; -import anolilabEslintConfig from "./utils/eslint-config"; - -const baseConfig = ["best-practices", "errors", "style", "es6", "variables"]; - -// eslint-disable-next-line import/exports-last -export const internalPluginConfig = [ - "compat", - "eslint-comments", - "import", - "promise", - "simple-import-sort", - "no-extend-native", - "node", - // Security Rules - "no-secrets", - "sonarjs", - "security", - "regexp", - // file rules - "jsonc", - "markdown", - "toml", - "yml", - "html", - "no-loops", - - // custom rules - "antfu", - "unicorn", - "es", - "perfectionist", -]; - -const pluginConfig: PackageRules = [ - { - configName: "array-func", - dependencies: ["eslint-plugin-array-func"], - }, - { - configName: "jsdoc", - dependencies: ["eslint-plugin-jsdoc"], - }, - { - configName: "tsdoc", - dependencies: ["eslint-plugin-tsdoc", "typescript"], - }, - { - configName: "you-dont-need-lodash-underscore", - dependencies: ["eslint-plugin-you-dont-need-lodash-underscore"], - oneOfDependency: [ - "lodash", - "underscore", - "lodash-es", - "@types/lodash", - - "lodash.chunk", - "lodash.compact", - "lodash.concat", - "lodash.difference", - "lodash.differenceby", - "lodash.differencewith", - "lodash.drop", - "lodash.dropright", - "lodash.droprightwhile", - "lodash.dropwhile", - "lodash.fill", - "lodash.findindex", - "lodash.findlastindex", - "lodash.flatten", - "lodash.flattendeep", - "lodash.flattendepth", - "lodash.frompairs", - "lodash.head", - "lodash.indexof", - "lodash.initial", - "lodash.intersection", - "lodash.intersectionby", - "lodash.intersectionwith", - "lodash.join", - "lodash.last", - "lodash.lastindexof", - "lodash.nth", - "lodash.pull", - "lodash.pullall", - "lodash.pullallby", - "lodash.pullallwith", - "lodash.pullat", - "lodash.remove", - "lodash.reverse", - "lodash.slice", - "lodash.sortedindex", - "lodash.sortedindexby", - "lodash.sortedindexof", - "lodash.sortedlastindex", - "lodash.sortedlastindexby", - "lodash.sortedlastindexof", - "lodash.sorteduniq", - "lodash.sorteduniqby", - "lodash.tail", - "lodash.take", - "lodash.takeright", - "lodash.takerightwhile", - "lodash.takewhile", - "lodash.union", - "lodash.unionby", - "lodash.unionwith", - "lodash.uniq", - "lodash.uniqby", - "lodash.uniqwith", - "lodash.unzip", - "lodash.unzipwith", - "lodash.without", - "lodash.xor", - "lodash.xorby", - "lodash.xorwith", - "lodash.zip", - "lodash.zipobject", - "lodash.zipobjectdeep", - "lodash.zipwith", - "lodash.countby", - "lodash.every", - "lodash.filter", - "lodash.find", - "lodash.findlast", - "lodash.flatmap", - "lodash.flatmapdeep", - "lodash.flatmapdepth", - "lodash.foreach", - "lodash.foreachright", - "lodash.groupby", - "lodash.includes", - "lodash.invokemap", - "lodash.keyby", - "lodash.map", - "lodash.orderby", - "lodash.partition", - "lodash.reduce", - "lodash.reduceright", - "lodash.reject", - "lodash.sample", - "lodash.samplesize", - "lodash.shuffle", - "lodash.size", - "lodash.some", - "lodash.sortby", - "lodash.now", - "lodash.after", - "lodash.ary", - "lodash.before", - "lodash.bind", - "lodash.bindkey", - "lodash.curry", - "lodash.curryright", - "lodash.debounce", - "lodash.defer", - "lodash.delay", - "lodash.flip", - "lodash.memoize", - "lodash.negate", - "lodash.once", - "lodash.overargs", - "lodash.partial", - "lodash.partialright", - "lodash.rearg", - "lodash.rest", - "lodash.spread", - "lodash.throttle", - "lodash.unary", - "lodash.wrap", - "lodash.castarray", - "lodash.clone", - "lodash.clonedeep", - "lodash.clonedeepwith", - "lodash.clonewith", - "lodash.conformsto", - "lodash.eq", - "lodash.gt", - "lodash.gte", - "lodash.isarguments", - "lodash.isarray", - "lodash.isarraybuffer", - "lodash.isarraylike", - "lodash.isarraylikeobject", - "lodash.isboolean", - "lodash.isbuffer", - "lodash.isdate", - "lodash.iselement", - "lodash.isempty", - "lodash.isequal", - "lodash.isequalwith", - "lodash.iserror", - "lodash.isfinite", - "lodash.isfunction", - "lodash.isinteger", - "lodash.islength", - "lodash.ismap", - "lodash.ismatch", - "lodash.ismatchwith", - "lodash.isnan", - "lodash.isnative", - "lodash.isnil", - "lodash.isnull", - "lodash.isnumber", - "lodash.isobject", - "lodash.isobjectlike", - "lodash.isplainobject", - "lodash.isregexp", - "lodash.issafeinteger", - "lodash.isset", - "lodash.isstring", - "lodash.issymbol", - "lodash.istypedarray", - "lodash.isundefined", - "lodash.isweakmap", - "lodash.isweakset", - "lodash.lt", - "lodash.lte", - "lodash.toarray", - "lodash.tofinite", - "lodash.tointeger", - "lodash.tolength", - "lodash.tonumber", - "lodash.toplainobject", - "lodash.tosafeinteger", - "lodash.tostring", - "lodash.add", - "lodash.ceil", - "lodash.divide", - "lodash.floor", - "lodash.max", - "lodash.maxby", - "lodash.mean", - "lodash.meanby", - "lodash.min", - "lodash.minby", - "lodash.multiply", - "lodash.round", - "lodash.subtract", - "lodash.sum", - "lodash.sumby", - "lodash.clamp", - "lodash.inrange", - "lodash.random", - "lodash.assign", - "lodash.assignin", - "lodash.assigninwith", - "lodash.assignwith", - "lodash.at", - "lodash.create", - "lodash.defaults", - "lodash.defaultsdeep", - "lodash.findkey", - "lodash.findlastkey", - "lodash.forin", - "lodash.forinright", - "lodash.forown", - "lodash.forownright", - "lodash.functions", - "lodash.functionsin", - "lodash.get", - "lodash.has", - "lodash.hasin", - "lodash.invert", - "lodash.invertby", - "lodash.invoke", - "lodash.keys", - "lodash.keysin", - "lodash.mapkeys", - "lodash.mapvalues", - "lodash.merge", - "lodash.mergewith", - "lodash.omit", - "lodash.omitby", - "lodash.pick", - "lodash.pickby", - "lodash.result", - "lodash.set", - "lodash.setwith", - "lodash.topairs", - "lodash.topairsin", - "lodash.transform", - "lodash.unset", - "lodash.update", - "lodash.updatewith", - "lodash.values", - "lodash.valuesin", - "lodash.chain", - "lodash.tap", - "lodash.thru", - "lodash.camelcase", - "lodash.capitalize", - "lodash.deburr", - "lodash.endswith", - "lodash.escape", - "lodash.escaperegexp", - "lodash.kebabcase", - "lodash.lowercase", - "lodash.lowerfirst", - "lodash.pad", - "lodash.padend", - "lodash.padstart", - "lodash.parseint", - "lodash.repeat", - "lodash.replace", - "lodash.snakecase", - "lodash.split", - "lodash.startcase", - "lodash.startswith", - "lodash.template", - "lodash.tolower", - "lodash.toupper", - "lodash.trim", - "lodash.trimend", - "lodash.trimstart", - "lodash.truncate", - "lodash.unescape", - "lodash.uppercase", - "lodash.upperfirst", - "lodash.words", - "lodash.attempt", - "lodash.bindall", - "lodash.cond", - "lodash.conforms", - "lodash.constant", - "lodash.defaultto", - "lodash.flow", - "lodash.flowright", - "lodash.identity", - "lodash.iteratee", - "lodash.matches", - "lodash.matchesproperty", - "lodash.method", - "lodash.methodof", - "lodash.mixin", - "lodash.noconflict", - "lodash.noop", - "lodash.ntharg", - "lodash.over", - "lodash.overevery", - "lodash.oversome", - "lodash.property", - "lodash.propertyof", - "lodash.range", - "lodash.rangeright", - "lodash.runincontext", - "lodash.stubarray", - "lodash.stubfalse", - "lodash.stubobject", - "lodash.stubstring", - "lodash.stubtrue", - "lodash.times", - "lodash.topath", - "lodash.uniqueid", - ], - }, - { - configName: "mdx", - dependencies: ["eslint-plugin-mdx"], - oneOfDependency: ["nextra", "docz", "@docusaurus/core", "gatsby-plugin-mdx"], - resolve: ["@mdx-js/mdx", "remark-mdx", "@mdx-js/loader", "@mdx-js/rollup", "@mdx-js/react"], - }, - { - configName: "no-unsanitized", - dependencies: ["eslint-plugin-no-unsanitized"], - }, - { - configName: "react", - dependencies: ["react", "react-dom", "eslint-plugin-react"], - }, - { - configName: "validate-jsx-nesting", - dependencies: ["eslint-plugin-validate-jsx-nesting"], - oneOfDependency: ["react", "react-dom", "preact", "preact/compat"], - }, - { - configName: "ssr-friendly", - dependencies: ["eslint-plugin-ssr-friendly"], - oneOfDependency: ["react", "react-dom", "preact", "preact/compat"], - }, - { - configName: "react-redux", - dependencies: ["eslint-plugin-react-redux"], - oneOfDependency: ["@reduxjs/toolkit", "redux"], - }, - { - configName: "jsx-a11y", - dependencies: ["eslint-plugin-jsx-a11y"], - oneOfDependency: ["react", "react-dom", "preact", "preact/compat"], - }, - { - configName: "react-hooks", - dependencies: ["eslint-plugin-react-hooks"], - oneOfDependency: ["react", "react-dom", "preact", "preact/compat"], - }, - { - configName: "react-usememo", - dependencies: ["@arthurgeron/eslint-plugin-react-usememo"], - oneOfDependency: ["react", "react-dom", "preact", "preact/compat"], - }, - { - configName: "you-dont-need-momentjs", - dependencies: ["moment", "eslint-plugin-you-dont-need-momentjs"], - }, - { - configName: "you-dont-need-momentjs", - dependencies: ["moment-timezone", "eslint-plugin-you-dont-need-momentjs"], - }, - { - configName: "tailwindcss", - dependencies: ["eslint-plugin-tailwindcss"], - oneOfDependency: ["tailwindcss", "@tailwindcss/typography", "@tailwindcss/forms", "@tailwindcss/aspect-ratio", "@tailwindcss/line-clamp"], - }, - { - configName: "cypress", - dependencies: ["cypress", "eslint-plugin-cypress"], - }, - { - configName: "jest", - dependencies: ["jest", "eslint-plugin-jest"], - }, - { - configName: "jest-dom", - dependencies: ["jest", "@testing-library/jest-dom", "eslint-plugin-jest-dom"], - }, - { - configName: "jest-async", - dependencies: ["jest", "eslint-plugin-jest-async"], - }, - { - configName: "jest-formatting", - dependencies: ["jest", "eslint-plugin-jest-formatting"], - }, - { - configName: "tailwindcss", - dependencies: ["tailwindcss"], - }, - { - configName: "testing-library-dom", - dependencies: ["@testing-library/dom", "eslint-plugin-testing-library"], - }, - { - configName: "testing-library-react", - dependencies: ["react", "@testing-library/react", "eslint-plugin-testing-library"], - }, - { - configName: "typescript", - dependencies: ["typescript"], - files: ["tsconfig.json", "tsconfig.eslint.json"], - }, - { - configName: "deprecation", - dependencies: ["eslint-plugin-deprecation", "typescript"], - files: ["tsconfig.json", "tsconfig.eslint.json"], - }, - { - configName: "no-only-tests", - dependencies: [], - oneOfDependency: ["jest", "mocha", "jasmine", "tape", "ava", "qunit", "cypress"], - }, - { - configName: "etc", - dependencies: ["typescript", "eslint-plugin-etc"], - }, - { - configName: "vitest", - dependencies: ["vitest", "eslint-plugin-vitest"], - }, - { - configName: "vitest", - dependencies: ["vitest", "eslint-plugin-vitest", "eslint-plugin-vitest-globals"], - }, - { - configName: "zod", - dependencies: ["zod", "eslint-plugin-zod"], - }, - { - configName: "ava", - dependencies: ["ava", "eslint-plugin-ava"], - }, - { - configName: "editorconfig", - dependencies: ["eslint-plugin-editorconfig"], - files: [".editorconfig"], - }, - { - configName: "storybook", - dependencies: ["storybook", "eslint-plugin-storybook"], - }, - { - configName: "playwright", - dependencies: ["playwright", "eslint-plugin-playwright"], - }, - { - configName: "tanstack-query", - dependencies: ["@tanstack/react-query", "@tanstack/eslint-plugin-query"], - }, -]; - -const loadedPlugins: string[] = [...internalPluginConfig]; -const possiblePlugins: Record> = {}; - -if (loadedPlugins.length === internalPluginConfig.length) { - // eslint-disable-next-line sonarjs/cognitive-complexity - pluginConfig.forEach((plugin) => { - const { configName, dependencies } = plugin; - - // eslint-disable-next-line security/detect-object-injection - if ((anolilabEslintConfig as unknown as Record>)["plugin"]?.[configName] !== false) { - const foundDependencies = []; - - dependencies.forEach((dependency) => { - if (hasDependency(dependency) || hasDevDependency(dependency)) { - foundDependencies.push(dependency); - } - }); - - // eslint-disable-next-line security/detect-object-injection - possiblePlugins[configName] = {}; - - if (foundDependencies.length === 0) { - if (plugin.oneOfDependency !== undefined) { - let foundOneOfDependency = false; - - plugin.oneOfDependency.forEach((dependency) => { - if (!foundOneOfDependency && (hasDependency(dependency) || hasDevDependency(dependency))) { - foundOneOfDependency = true; - - // eslint-disable-next-line security/detect-object-injection - (possiblePlugins[configName] as Record)[dependency] = true; - } - }); - } - - if (plugin.resolve !== undefined) { - plugin.resolve.forEach((rdependency) => { - if (resolvePackage(rdependency) !== undefined) { - // eslint-disable-next-line security/detect-object-injection - (possiblePlugins[configName] as Record)[rdependency] = true; - } - }); - } - - if (plugin.files !== undefined) { - plugin.files.forEach((file) => { - if (hasFile(file)) { - // eslint-disable-next-line security/detect-object-injection - (possiblePlugins[configName] as Record)[file] = true; - } - }); - } - } - - if (foundDependencies.length === dependencies.length) { - // eslint-disable-next-line security/detect-object-injection,@typescript-eslint/no-dynamic-delete - delete possiblePlugins[configName]; - - loadedPlugins.push(configName); - } else { - dependencies.forEach((dependency) => { - // eslint-disable-next-line security/detect-object-injection - (possiblePlugins[configName] as Record)[dependency] = hasDependency(dependency) || hasDevDependency(dependency); - }); - } - } - }); -} - -export const rules = baseConfig; -export const pluginRules = loadedPlugins; - -export const possiblePluginRules = possiblePlugins; diff --git a/packages/eslint-config/src/config/best-practices.ts b/packages/eslint-config/src/config/best-practices.ts index 6a5691c95..baa907abf 100644 --- a/packages/eslint-config/src/config/best-practices.ts +++ b/packages/eslint-config/src/config/best-practices.ts @@ -1,10 +1,57 @@ import type { Linter } from "eslint"; -import { createConfigs } from "../utils/create-config"; - -const config: Linter.Config = createConfigs([ - { - config: { +import type { OptionsFiles } from "../types"; +import { createConfig, getFilesGlobs } from "../utils/create-config"; + +export const bestPracticesRules: Partial = { + // Disable the "dot-notation" rule, as it can report incorrect errors on TypeScript code + "dot-notation": "off", + + // Require explicit return and argument types on exported functions' and classes' public class methods. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-empty-function.md + "no-empty-function": "off", + + // Disallow using to delete operator on computed key expressions. + // Disable the "no-implied-eval" and "no-new-func" rule, as it can report incorrect errors on TypeScript code + "no-implied-eval": "off", + + // Disallow extra non-null assertions. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-loop-func.md + "no-loop-func": "off", + + // Disallow void type outside of generic or return types. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-magic-numbers.md + "no-magic-numbers": "off", + + "no-new-func": "off", + + // Disallow non-null assertions after an optional chain expression. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-redeclare.md + "no-redeclare": "off", + // Disallow non-null assertions using the ! postfix operator. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/return-await.md + "no-return-await": "off", + + // Disallow type assertions that do not change the type of expression. + // Disable the "no-throw-literal" rule, as it can report incorrect errors on TypeScript code + "no-throw-literal": "off", + + // Disallow calling a value with type any. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-expressions.md + "no-unused-expressions": "off", + + // Disallow empty exports that don't change anything in a module file. + // Breaks @typescript-eslint/parser + strict: "off", +}; + +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles } = config; + + return [ + { + files, + name: "anolilab/best-practices/rules", rules: { // enforces getter/setter pairs in objects "accessor-pairs": "off", @@ -323,7 +370,7 @@ const config: Linter.Config = createConfigs([ property: "parseInt", }, { - message: "Use `Object.getPrototypeOf` instead.", + message: "Use `Object.getPrototypeOf` or `Object.setPrototypeOf` instead.", property: "__proto__", }, { @@ -404,7 +451,7 @@ const config: Linter.Config = createConfigs([ // https://eslint.org/docs/rules/no-void "no-void": "error", - // disallow usage of configurable warning terms in comments: e.g. todo + // disallow usage of configurable warning terms in comments: e.g. "todo" "no-warning-comments": [ "off", { @@ -450,56 +497,10 @@ const config: Linter.Config = createConfigs([ yoda: "error", }, }, - type: "all", - }, - // The following rules are enabled in config, but are already checked (more thoroughly) by the TypeScript compiler - // Some rules also fail in TypeScript files, for example: https://github.com/typescript-eslint/typescript-eslint/issues/662#issuecomment-507081586 - { - config: { - rules: { - // Disallow non-null assertions using the ! postfix operator. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/return-await.md - "no-return-await": "off", - - // Disallow calling a value with type any. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-expressions.md - "no-unused-expressions": "off", - - // Disallow type assertions that do not change the type of expression. - // Disable the "no-throw-literal" rule, as it can report incorrect errors on TypeScript code - "no-throw-literal": "off", - - // Disallow empty exports that don't change anything in a module file. - // Breaks @typescript-eslint/parser - strict: "off", - - // Disable the "dot-notation" rule, as it can report incorrect errors on TypeScript code - "dot-notation": "off", - - // Require explicit return and argument types on exported functions' and classes' public class methods. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-empty-function.md - "no-empty-function": "off", - - // Disallow using to delete operator on computed key expressions. - // Disable the "no-implied-eval" and "no-new-func" rule, as it can report incorrect errors on TypeScript code - "no-implied-eval": "off", - "no-new-func": "off", - - // Disallow extra non-null assertions. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-loop-func.md - "no-loop-func": "off", - - // Disallow void type outside of generic or return types. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-magic-numbers.md - "no-magic-numbers": "off", - - // Disallow non-null assertions after an optional chain expression. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-redeclare.md - "no-redeclare": "off", - }, + { + files: getFilesGlobs("ts"), + name: "anolilab/best-practices/ts-rules", + rules: bestPracticesRules, }, - type: "typescript", - }, -]); - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/errors.ts b/packages/eslint-config/src/config/errors.ts index a7e8dc28e..620e30195 100644 --- a/packages/eslint-config/src/config/errors.ts +++ b/packages/eslint-config/src/config/errors.ts @@ -1,199 +1,186 @@ import type { Linter } from "eslint"; -import { createConfigs } from "../utils/create-config"; +import type { OptionsFiles } from "../types"; +import { createConfig, getFilesGlobs } from "../utils/create-config"; -const config: Linter.Config = createConfigs([ - { - config: { - rules: { - // Enforce “for” loop update clause moving the counter in the right direction - // https://eslint.org/docs/rules/for-direction - "for-direction": "error", +export const errorsRules: Partial = { + // Enforce “for” loop update clause moving the counter in the right direction + // https://eslint.org/docs/rules/for-direction + "for-direction": "error", - // Enforces that a return statement is present in property getters - // https://eslint.org/docs/rules/getter-return - "getter-return": ["error", { allowImplicit: true }], + // Enforces that a return statement is present in property getters + // https://eslint.org/docs/rules/getter-return + "getter-return": ["error", { allowImplicit: true }], - // disallow using an async function as a Promise executor - // https://eslint.org/docs/rules/no-async-promise-executor - "no-async-promise-executor": "error", + // disallow using an async function as a Promise executor + // https://eslint.org/docs/rules/no-async-promise-executor + "no-async-promise-executor": "error", - // Disallow await inside of loops - // https://eslint.org/docs/rules/no-await-in-loop - "no-await-in-loop": "error", + // Disallow await inside of loops + // https://eslint.org/docs/rules/no-await-in-loop + "no-await-in-loop": "error", - // Disallow comparisons to negative zero - // https://eslint.org/docs/rules/no-compare-neg-zero - "no-compare-neg-zero": "error", + // Disallow comparisons to negative zero + // https://eslint.org/docs/rules/no-compare-neg-zero + "no-compare-neg-zero": "error", - // disallow assignment in conditional expressions - "no-cond-assign": ["error", "always"], + // disallow assignment in conditional expressions + "no-cond-assign": ["error", "always"], - // disallow use of console - "no-console": "warn", + // disallow use of console + "no-console": "warn", - // disallow use of constant expressions in conditions - "no-constant-condition": "warn", + // disallow use of constant expressions in conditions + "no-constant-condition": "warn", - // Disabled because of eslint-plugin-regexp - // disallow control characters in regular expressions - "no-control-regex": "off", + // Disabled because of eslint-plugin-regexp + // disallow control characters in regular expressions + "no-control-regex": "off", - // disallow use of debugger - "no-debugger": "error", + // disallow use of debugger + "no-debugger": "error", - // disallow duplicate arguments in functions - "no-dupe-args": "error", + // disallow duplicate arguments in functions + "no-dupe-args": "error", - // Disallow duplicate conditions in if-else-if chains - // https://eslint.org/docs/rules/no-dupe-else-if - "no-dupe-else-if": "error", + // Disallow duplicate conditions in if-else-if chains + // https://eslint.org/docs/rules/no-dupe-else-if + "no-dupe-else-if": "error", - // disallow duplicate keys when creating object literals - "no-dupe-keys": "error", + // disallow duplicate keys when creating object literals + "no-dupe-keys": "error", - // disallow a duplicate case label. - "no-duplicate-case": "error", + // disallow a duplicate case label. + "no-duplicate-case": "error", - // disallow empty statements - "no-empty": "error", + // disallow empty statements + "no-empty": "error", - // disallow the use of empty character classes in regular expressions - "no-empty-character-class": "error", + // disallow the use of empty character classes in regular expressions + "no-empty-character-class": "error", - // disallow assigning to the exception in a catch block - "no-ex-assign": "error", + // disallow assigning to the exception in a catch block + "no-ex-assign": "error", - // disallow double-negation boolean casts in a boolean context - // https://eslint.org/docs/rules/no-extra-boolean-cast - "no-extra-boolean-cast": "error", + // disallow double-negation boolean casts in a boolean context + // https://eslint.org/docs/rules/no-extra-boolean-cast + "no-extra-boolean-cast": "error", - // disallow unnecessary parentheses - // https://eslint.org/docs/rules/no-extra-parens - "no-extra-parens": [ - "error", - "all", - { - conditionalAssign: true, - enforceForArrowConditionals: false, - ignoreJSX: "all", // delegate to eslint-plugin-react - nestedBinaryExpressions: false, - returnAssign: false, - }, - ], + // disallow overwriting functions written as function declarations + "no-func-assign": "error", - // Disallow non-null assertion in locations that may be confusing. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-extra-semi.md - "no-extra-semi": "error", + // https://eslint.org/docs/rules/no-import-assign + "no-import-assign": "error", - // disallow overwriting functions written as function declarations - "no-func-assign": "error", + // disallow function or variable declarations in nested blocks + "no-inner-declarations": "error", - // https://eslint.org/docs/rules/no-import-assign - "no-import-assign": "error", + // Disabled because of eslint-plugin-regexp + // disallow invalid regular expression strings in the RegExp constructor + "no-invalid-regexp": "off", - // disallow function or variable declarations in nested blocks - "no-inner-declarations": "error", + // disallow irregular whitespace outside of strings and comments + "no-irregular-whitespace": "error", - // Disabled because of eslint-plugin-regexp - // disallow invalid regular expression strings in the RegExp constructor - "no-invalid-regexp": "off", + // Disallow Number Literals That Lose Precision + // https://eslint.org/docs/rules/no-loss-of-precision + "no-loss-of-precision": "error", - // disallow irregular whitespace outside of strings and comments - "no-irregular-whitespace": "error", + // Disallow characters which are made with multiple code points in character class syntax + // https://eslint.org/docs/rules/no-misleading-character-class + "no-misleading-character-class": "error", - // Disallow Number Literals That Lose Precision - // https://eslint.org/docs/rules/no-loss-of-precision - "no-loss-of-precision": "error", + // deprecated in favor of no-unsafe-negation + "no-negated-in-lhs": "off", - // Disallow characters which are made with multiple code points in character class syntax - // https://eslint.org/docs/rules/no-misleading-character-class - "no-misleading-character-class": "error", + // Disallow new operators with global non-constructor functions + // https://eslint.org/docs/latest/rules/no-new-native-nonconstructor + "no-new-native-nonconstructor": "error", - // deprecated in favor of no-unsafe-negation - "no-negated-in-lhs": "off", + // Disallow returning values from Promise executor functions + // disallow the use of object properties of the global object (Math and JSON) as functions + "no-obj-calls": "error", - // Disallow returning values from Promise executor functions - // disallow the use of object properties of the global object (Math and JSON) as functions - "no-obj-calls": "error", + // disallow use of Object.prototypes builtins directly + // https://eslint.org/docs/rules/no-promise-executor-return + "no-promise-executor-return": "error", - // Disallow new operators with global non-constructor functions - // https://eslint.org/docs/latest/rules/no-new-native-nonconstructor - // TODO: semver-major, enable - "no-new-native-nonconstructor": "off", + // https://eslint.org/docs/rules/no-prototype-builtins + "no-prototype-builtins": "error", - // disallow use of Object.prototypes builtins directly - // https://eslint.org/docs/rules/no-promise-executor-return - "no-promise-executor-return": "error", + // Disabled because of eslint-plugin-regexp + // disallow multiple spaces in a regular expression literal + "no-regex-spaces": "off", - // https://eslint.org/docs/rules/no-prototype-builtins - "no-prototype-builtins": "error", + // https://eslint.org/docs/rules/no-setter-return + "no-setter-return": "error", - // Disabled because of eslint-plugin-regexp - // disallow multiple spaces in a regular expression literal - "no-regex-spaces": "off", + // Disallow template literal placeholder syntax in regular strings + // disallow sparse arrays + "no-sparse-arrays": "error", - // https://eslint.org/docs/rules/no-setter-return - "no-setter-return": "error", + // Avoid code that looks like two expressions but is actually one + // https://eslint.org/docs/rules/no-template-curly-in-string + "no-template-curly-in-string": "error", - // Disallow template literal placeholder syntax in regular strings - // disallow sparse arrays - "no-sparse-arrays": "error", + // https://eslint.org/docs/rules/no-unexpected-multiline + "no-unexpected-multiline": "error", - // Avoid code that looks like two expressions but is actually one - // https://eslint.org/docs/rules/no-template-curly-in-string - "no-template-curly-in-string": "error", + // Disallow loops with a body that allows only one iteration + // disallow unreachable statements after a return, throw, continue, or break statement + "no-unreachable": "error", - // https://eslint.org/docs/rules/no-unexpected-multiline - "no-unexpected-multiline": "error", + // disallow return/throw/break/continue inside finally blocks + // https://eslint.org/docs/rules/no-unreachable-loop + "no-unreachable-loop": "off", // error with typescript - // Disallow loops with a body that allows only one iteration - // disallow unreachable statements after a return, throw, continue, or break statement - "no-unreachable": "error", + // disallow negating the left operand of relational operators + // https://eslint.org/docs/rules/no-unsafe-finally + "no-unsafe-finally": "error", - // disallow return/throw/break/continue inside finally blocks - // https://eslint.org/docs/rules/no-unreachable-loop - "no-unreachable-loop": "off", // error with typescript + // disallow use of optional chaining in contexts where the undefined value is not allowed + // https://eslint.org/docs/rules/no-unsafe-negation + "no-unsafe-negation": "error", - // disallow negating the left operand of relational operators - // https://eslint.org/docs/rules/no-unsafe-finally - "no-unsafe-finally": "error", - - // disallow use of optional chaining in contexts where the undefined value is not allowed - // https://eslint.org/docs/rules/no-unsafe-negation - "no-unsafe-negation": "error", - - // Disallow useless backreferences in regular expressions - // https://eslint.org/docs/rules/no-unsafe-optional-chaining - "no-unsafe-optional-chaining": ["error", { disallowArithmeticOperators: true }], - - // disallow negation of the left operand of an in expression - // https://eslint.org/docs/rules/no-useless-backreference - "no-useless-backreference": "error", - - // Disallow assignments that can lead to race conditions due to usage of await or yield - // https://eslint.org/docs/rules/require-atomic-updates - // note: not enabled because it is very buggy - "require-atomic-updates": "off", + // Disallow useless backreferences in regular expressions + // https://eslint.org/docs/rules/no-unsafe-optional-chaining + "no-unsafe-optional-chaining": ["error", { disallowArithmeticOperators: true }], - // disallow comparisons with the value NaN - "use-isnan": "error", + // disallow negation of the left operand of an in expression + // https://eslint.org/docs/rules/no-useless-backreference + "no-useless-backreference": "error", - // ensure JSDoc comments are valid - // https://eslint.org/docs/rules/valid-jsdoc - "valid-jsdoc": "off", + // Disallow assignments that can lead to race conditions due to usage of await or yield + // https://eslint.org/docs/rules/require-atomic-updates + // note: not enabled because it is very buggy + "require-atomic-updates": "off", - // ensure that the results of typeof are compared against a valid string - // https://eslint.org/docs/rules/valid-typeof - "valid-typeof": ["error", { requireStringLiterals: true }], - }, + // disallow comparisons with the value NaN + "use-isnan": "error", + + // ensure JSDoc comments are valid + // https://eslint.org/docs/rules/valid-jsdoc + "valid-jsdoc": "off", + + // ensure that the results of typeof are compared against a valid string + // https://eslint.org/docs/rules/valid-typeof + "valid-typeof": ["error", { requireStringLiterals: true }], +}; + +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles } = config; + + return [ + { + files, + name: "anolilab/errors/rules", + rules: errorsRules, }, - type: "all", - }, - // The following rules are enabled in config, but are already checked (more thoroughly) by the TypeScript compiler - // Some rules also fail in TypeScript files, for example: https://github.com/typescript-eslint/typescript-eslint/issues/662#issuecomment-507081586 - { - config: { + // The following rules are enabled in config, but are already checked (more thoroughly) by the TypeScript compiler + // Some rules also fail in TypeScript files, for example: https://github.com/typescript-eslint/typescript-eslint/issues/662#issuecomment-507081586 + { + files: getFilesGlobs("ts"), + name: "anolilab/errors/ts-rules", rules: { "getter-return": "off", @@ -207,6 +194,8 @@ const config: Linter.Config = createConfigs([ // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-extra-parens.md "no-extra-parens": "off", + "no-extra-semi": "off", + // Disallow duplicate enum member values. "no-func-assign": "off", @@ -224,12 +213,7 @@ const config: Linter.Config = createConfigs([ "space-infix-ops": "off", "valid-typeof": "off", - - "no-extra-semi": "off", }, }, - type: "typescript", - }, -]); - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/es6.ts b/packages/eslint-config/src/config/es6.ts index fffbb2896..608e990c2 100644 --- a/packages/eslint-config/src/config/es6.ts +++ b/packages/eslint-config/src/config/es6.ts @@ -1,388 +1,386 @@ import type { Linter } from "eslint"; -import { createConfigs } from "../utils/create-config"; - -const config: Linter.Config = createConfigs([ - { - config: { - env: { - es6: true, - }, - parserOptions: { - ecmaFeatures: { - generators: false, - objectLiteralDuplicateProperties: false, - }, - ecmaVersion: 6, - sourceType: "module", - }, - rules: { - // enforces no braces where they can be omitted - // https://eslint.org/docs/rules/arrow-body-style - "arrow-body-style": [ - "error", - "as-needed", - { - requireReturnForObjectLiteral: true, - }, - ], +import type { OptionsFiles } from "../types"; +import { createConfig, getFilesGlobs } from "../utils/create-config"; + +export const es6Rules: Partial = { + // enforces no braces where they can be omitted + // https://eslint.org/docs/rules/arrow-body-style + "arrow-body-style": [ + "error", + "as-needed", + { + requireReturnForObjectLiteral: true, + }, + ], - // require parens in arrow function arguments - // https://eslint.org/docs/rules/arrow-parens - "arrow-parens": ["error", "always"], + // require parens in arrow function arguments + // https://eslint.org/docs/rules/arrow-parens + "arrow-parens": ["error", "always"], - // require space before/after arrow function's arrow - // https://eslint.org/docs/rules/arrow-spacing - "arrow-spacing": ["error", { after: true, before: true }], + // require space before/after arrow function's arrow + // https://eslint.org/docs/rules/arrow-spacing + "arrow-spacing": ["error", { after: true, before: true }], - // verify super() callings in constructors - "constructor-super": "error", + // verify super() callings in constructors + "constructor-super": "error", - // enforce the spacing around the * in generator functions - // https://eslint.org/docs/rules/generator-star-spacing - "generator-star-spacing": ["error", { after: true, before: false }], + // enforce the spacing around the * in generator functions + // https://eslint.org/docs/rules/generator-star-spacing + "generator-star-spacing": ["error", { after: true, before: false }], - // disallow modifying variables of class declarations - // https://eslint.org/docs/rules/no-class-assign - "no-class-assign": "error", + // disallow modifying variables of class declarations + // https://eslint.org/docs/rules/no-class-assign + "no-class-assign": "error", - // disallow arrow functions where they could be confused with comparisons - // https://eslint.org/docs/rules/no-confusing-arrow - "no-confusing-arrow": [ - "error", - { - allowParens: true, - }, - ], - - // disallow modifying variables that are declared using const - "no-const-assign": "error", - - // disallow duplicate class members - // https://eslint.org/docs/rules/no-dupe-class-members - "no-dupe-class-members": "error", - - // disallow importing from the same path more than once - // https://eslint.org/docs/rules/no-duplicate-imports - // replaced by https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-duplicates.md - "no-duplicate-imports": "off", - - // disallow symbol constructor - // https://eslint.org/docs/rules/no-new-symbol - "no-new-symbol": "error", - - // Disallow specified names in exports - // https://eslint.org/docs/rules/no-restricted-exports - "no-restricted-exports": [ - "error", - { - // default export while still blocking other "default" exports. - // The 'default' entry in restrictedNamedExports must also be removed. - // See https://github.com/airbnb/javascript/issues/2500 and https://github.com/eslint/eslint/pull/16785 - restrictDefaultExports: { - defaultFrom: false, // permits `export { default } from 'foo';` declarations - direct: false, // permits `export default` declarations - named: true, // restricts `export { foo as default };` declarations - namedFrom: false, // permits `export { foo as default } from 'foo';` declarations - namespaceFrom: true, // restricts `export * as default from 'foo';` declarations - }, - // this will cause tons of confusion when your module is dynamically `import()`ed - restrictedNamedExports: ["then"], - }, - ], - - // disallow specific imports - // https://eslint.org/docs/rules/no-restricted-imports - "no-restricted-imports": [ - "error", - { - paths: [ - { - message: - "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead", - name: "lodash.isequal", - }, - { - message: - "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead", - name: "lodash.uniqueId", - }, - { - message: - "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead", - name: "lodash.mergewith", - }, - { - message: - "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead", - name: "lodash.pick", - }, - { - name: "error", - }, - { - name: "domain", - }, - { - name: "freelist", - }, - { - name: "smalloc", - }, - { - name: "punycode", - }, - { - name: "sys", - }, - { - message: 'Is legacy, npm version got deprecated, migrate to URLSearchParams as recommended or try "qs" as a package', - name: "querystring", - }, - { - message: "Please use one of the following instead: chalk, kleur, ansi-colors, @colors/colors", - name: "colors", - }, - { - message: "node v10.12 mkdir supports recursive option", - name: "mkdirp", - }, - { - message: 'Please use "@faker-js/faker" as a replacement', - name: "faker", - }, - { - message: "Please use Object.assign or spread { ...obj }", - name: "xtend", - }, - { - message: "Please use Object.assign or spread { ...obj }", - name: "object-assign", - }, - { - message: "Please use Object.assign or spread { ...obj }", - name: "extend-shallow", - }, - { - message: "node supports recursive option now", - name: "rimraf", - }, - { - message: 'just use "".padStart() and "".padEnd()', - name: "pad-left", - }, - { - message: 'just use "".padStart() and "".padEnd()', - name: "pad-right", - }, - { - message: 'just use "".padStart() and "".padEnd()', - name: "left-pad", - }, - { - message: 'just use "".padStart() and "".padEnd()', - name: "right-pad", - }, - { - message: 'just use "".padStart() and "".padEnd()', - name: "pad", - }, - { - name: "safe-buffer", - }, - { - name: "safer-buffer", - }, - { - message: "just use [].flat() or some other polyfill", - name: "array-flatten", - }, - { - message: "Been deprecated", - name: "request", - }, - { - message: "use async/await instead", - name: "co", - }, - { - message: "Please use TextDecoder instead", - name: "windows-1252", - }, - { - message: "Please use TextDecoder instead", - name: "string_decoder", - }, - { - message: "Please use array.prototype.flatMap instead", - name: "concat-map", - }, - { - name: "buffer-alloc", - }, - ], - // catch-all for any lodash modularized. - // The CVE is listed against the entire family for lodash < 4.17.11 - patterns: ["lodash.*"], - }, - ], - - // disallow to use this/super before super() calling in constructors. - // https://eslint.org/docs/rules/no-this-before-super - "no-this-before-super": "error", - - // disallow useless computed property keys - // https://eslint.org/docs/rules/no-useless-computed-key - "no-useless-computed-key": "error", - - // disallow unnecessary constructor - // https://eslint.org/docs/rules/no-useless-constructor - "no-useless-constructor": "error", - - // disallow renaming import, export, and destructured assignments to the same name - // https://eslint.org/docs/rules/no-useless-rename - "no-useless-rename": [ - "error", - { - ignoreDestructuring: false, - ignoreExport: false, - ignoreImport: false, - }, - ], - - // require let or const instead of var - "no-var": "error", - - // require method and property shorthand syntax for object literals - // https://eslint.org/docs/rules/object-shorthand - "object-shorthand": [ - "error", - "always", - { - avoidQuotes: true, - ignoreConstructors: false, - }, - ], - - // suggest using arrow functions as callbacks - "prefer-arrow-callback": [ - "error", - { - allowNamedFunctions: false, - allowUnboundThis: true, - }, - ], - - // suggest using of const declaration for variables that are never modified after declared - "prefer-const": [ - "error", - { - destructuring: "any", - ignoreReadBeforeAssign: true, - }, - ], - - // Prefer destructuring from arrays and objects - // https://eslint.org/docs/rules/prefer-destructuring - "prefer-destructuring": [ - "error", - { - AssignmentExpression: { - array: true, - object: false, - }, - VariableDeclarator: { - array: false, - object: true, - }, - }, - { - enforceForRenamedProperties: false, - }, - ], - - // disallow parseInt() in favor of binary, octal, and hexadecimal literals - // https://eslint.org/docs/rules/prefer-numeric-literals - "prefer-numeric-literals": "error", - - // suggest using Reflect methods where applicable - // https://eslint.org/docs/rules/prefer-reflect - "prefer-reflect": "off", - - // use rest parameters instead of arguments - // https://eslint.org/docs/rules/prefer-rest-params - "prefer-rest-params": "error", - - // suggest using the spread operator instead of .apply() - // https://eslint.org/docs/rules/prefer-spread - "prefer-spread": "error", - - // suggest using template literals instead of string concatenation - // https://eslint.org/docs/rules/prefer-template - "prefer-template": "error", - - // disallow generator functions that do not have yield - // https://eslint.org/docs/rules/require-yield - "require-yield": "error", - - // enforce spacing between object rest-spread - // https://eslint.org/docs/rules/rest-spread-spacing - "rest-spread-spacing": ["error", "never"], - - // import sorting - // https://eslint.org/docs/rules/sort-imports - "sort-imports": [ - "off", - { - ignoreCase: false, - ignoreDeclarationSort: false, - ignoreMemberSort: false, - memberSyntaxSortOrder: ["none", "all", "multiple", "single"], + // disallow arrow functions where they could be confused with comparisons + // https://eslint.org/docs/rules/no-confusing-arrow + "no-confusing-arrow": [ + "error", + { + allowParens: true, + }, + ], + + // disallow modifying variables that are declared using const + "no-const-assign": "error", + + // disallow duplicate class members + // https://eslint.org/docs/rules/no-dupe-class-members + "no-dupe-class-members": "error", + + // disallow importing from the same path more than once + // https://eslint.org/docs/rules/no-duplicate-imports + // replaced by https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-duplicates.md + "no-duplicate-imports": "off", + + // disallow symbol constructor + // https://eslint.org/docs/rules/no-new-symbol + "no-new-symbol": "error", + + // Disallow specified names in exports + // https://eslint.org/docs/rules/no-restricted-exports + "no-restricted-exports": [ + "error", + { + // default export while still blocking other "default" exports. + // The 'default' entry in restrictedNamedExports must also be removed. + // See https://github.com/airbnb/javascript/issues/2500 and https://github.com/eslint/eslint/pull/16785 + restrictDefaultExports: { + defaultFrom: false, // permits `export { default } from 'foo';` declarations + direct: false, // permits `export default` declarations + named: true, // restricts `export { foo as default };` declarations + namedFrom: false, // permits `export { foo as default } from 'foo';` declarations + namespaceFrom: true, // restricts `export * as default from 'foo';` declarations + }, + // this will cause tons of confusion when your module is dynamically `import()`ed + restrictedNamedExports: ["then"], + }, + ], + + // disallow specific imports + // https://eslint.org/docs/rules/no-restricted-imports + "no-restricted-imports": [ + "error", + { + paths: [ + { + message: "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead", + name: "lodash.isequal", + }, + { + message: "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead", + name: "lodash.uniqueId", + }, + { + message: "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead", + name: "lodash.mergewith", + }, + { + message: "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead", + name: "lodash.pick", + }, + { + name: "error", + }, + { + name: "domain", + }, + { + name: "freelist", + }, + { + name: "smalloc", + }, + { + name: "punycode", + }, + { + name: "sys", + }, + { + message: "Is legacy, npm version got deprecated, migrate to URLSearchParams as recommended or try \"qs\" as a package", + name: "querystring", + }, + { + message: "Please use one of the following instead: chalk, kleur, ansi-colors, @colors/colors", + name: "colors", + }, + { + message: "node v10.12 mkdir supports recursive option", + name: "mkdirp", + }, + { + message: "Please use \"@faker-js/faker\" as a replacement", + name: "faker", + }, + { + message: "Please use Object.assign or spread { ...obj }", + name: "xtend", + }, + { + message: "Please use Object.assign or spread { ...obj }", + name: "object-assign", + }, + { + message: "Please use Object.assign or spread { ...obj }", + name: "extend-shallow", + }, + { + message: "node supports recursive option now", + name: "rimraf", + }, + { + message: "just use \"\".padStart() and \"\".padEnd()", + name: "pad-left", + }, + { + message: "just use \"\".padStart() and \"\".padEnd()", + name: "pad-right", + }, + { + message: "just use \"\".padStart() and \"\".padEnd()", + name: "left-pad", + }, + { + message: "just use \"\".padStart() and \"\".padEnd()", + name: "right-pad", + }, + { + message: "just use \"\".padStart() and \"\".padEnd()", + name: "pad", + }, + { + name: "safe-buffer", + }, + { + name: "safer-buffer", + }, + { + message: "just use [].flat() or some other polyfill", + name: "array-flatten", + }, + { + message: "Been deprecated", + name: "request", + }, + { + message: "use async/await instead", + name: "co", + }, + { + message: "Please use TextDecoder instead", + name: "windows-1252", + }, + { + message: "Please use TextDecoder instead", + name: "string_decoder", + }, + { + message: "Please use array.prototype.flatMap instead", + name: "concat-map", + }, + { + name: "buffer-alloc", + }, + ], + // catch-all for any lodash modularized. + // The CVE is listed against the entire family for lodash < 4.17.11 + patterns: ["lodash.*"], + }, + ], + + // disallow to use this/super before super() calling in constructors. + // https://eslint.org/docs/rules/no-this-before-super + "no-this-before-super": "error", + + // disallow useless computed property keys + // https://eslint.org/docs/rules/no-useless-computed-key + "no-useless-computed-key": "error", + + // disallow unnecessary constructor + // https://eslint.org/docs/rules/no-useless-constructor + "no-useless-constructor": "error", + + // disallow renaming import, export, and destructured assignments to the same name + // https://eslint.org/docs/rules/no-useless-rename + "no-useless-rename": [ + "error", + { + ignoreDestructuring: false, + ignoreExport: false, + ignoreImport: false, + }, + ], + + // require let or const instead of var + "no-var": "error", + + // require method and property shorthand syntax for object literals + // https://eslint.org/docs/rules/object-shorthand + "object-shorthand": [ + "error", + "always", + { + avoidQuotes: true, + ignoreConstructors: false, + }, + ], + + // suggest using arrow functions as callbacks + "prefer-arrow-callback": [ + "error", + { + allowNamedFunctions: false, + allowUnboundThis: true, + }, + ], + + // suggest using of const declaration for variables that are never modified after declared + "prefer-const": [ + "error", + { + destructuring: "any", + ignoreReadBeforeAssign: true, + }, + ], + + // Prefer destructuring from arrays and objects + // https://eslint.org/docs/rules/prefer-destructuring + "prefer-destructuring": [ + "error", + { + AssignmentExpression: { + array: true, + object: false, + }, + VariableDeclarator: { + array: false, + object: true, + }, + }, + { + enforceForRenamedProperties: false, + }, + ], + + // disallow parseInt() in favor of binary, octal, and hexadecimal literals + // https://eslint.org/docs/rules/prefer-numeric-literals + "prefer-numeric-literals": "error", + + // suggest using Reflect methods where applicable + // https://eslint.org/docs/rules/prefer-reflect + "prefer-reflect": "off", + + // use rest parameters instead of arguments + // https://eslint.org/docs/rules/prefer-rest-params + "prefer-rest-params": "error", + + // suggest using the spread operator instead of .apply() + // https://eslint.org/docs/rules/prefer-spread + "prefer-spread": "error", + + // suggest using template literals instead of string concatenation + // https://eslint.org/docs/rules/prefer-template + "prefer-template": "error", + + // disallow generator functions that do not have yield + // https://eslint.org/docs/rules/require-yield + "require-yield": "error", + + // enforce spacing between object rest-spread + // https://eslint.org/docs/rules/rest-spread-spacing + "rest-spread-spacing": ["error", "never"], + + // import sorting + // https://eslint.org/docs/rules/sort-imports + "sort-imports": [ + "off", + { + ignoreCase: false, + ignoreDeclarationSort: false, + ignoreMemberSort: false, + memberSyntaxSortOrder: ["none", "all", "multiple", "single"], + }, + ], + + // require a Symbol description + // https://eslint.org/docs/rules/symbol-description + "symbol-description": "error", + + // enforce usage of spacing in template strings + // https://eslint.org/docs/rules/template-curly-spacing + "template-curly-spacing": "error", + + // enforce spacing around the * in yield* expressions + // https://eslint.org/docs/rules/yield-star-spacing + "yield-star-spacing": ["error", "after"], +}; + +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles } = config; + + return [ + { + files, + languageOptions: { + parserOptions: { + ecmaFeatures: { + generators: false, + objectLiteralDuplicateProperties: false, }, - ], - - // require a Symbol description - // https://eslint.org/docs/rules/symbol-description - "symbol-description": "error", - - // enforce usage of spacing in template strings - // https://eslint.org/docs/rules/template-curly-spacing - "template-curly-spacing": "error", - - // enforce spacing around the * in yield* expressions - // https://eslint.org/docs/rules/yield-star-spacing - "yield-star-spacing": ["error", "after"], + ecmaVersion: 6, + sourceType: "module", + }, }, + name: "anolilab/es6/rules", + rules: es6Rules, }, - type: "all", - }, - // The following rules are enabled in config, but are already checked (more thoroughly) by the TypeScript compiler - // Some rules also fail in TypeScript files, for example: https://github.com/typescript-eslint/typescript-eslint/issues/662#issuecomment-507081586 - { - config: { + // The following rules are enabled in config, but are already checked (more thoroughly) by the TypeScript compiler + // Some rules also fail in TypeScript files, for example: https://github.com/typescript-eslint/typescript-eslint/issues/662#issuecomment-507081586 + { + files: getFilesGlobs("ts"), + name: "anolilab/es6/ts-rules", rules: { "constructor-super": "off", - // Disallow returning a value with type any from a function. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-useless-constructor.md - "no-useless-constructor": "off", + // Enforce constituents of a type union/intersection to be sorted alphabetically. + "no-const-assign": "off", // Enforce specifying generic type arguments on constructor name of a constructor call. // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-dupe-class-members.md "no-dupe-class-members": "off", - // Enforce constituents of a type union/intersection to be sorted alphabetically. - "no-const-assign": "off", - // Disallow TypeScript namespaces. "no-new-symbol": "off", // Disallow aliasing this. "no-this-before-super": "off", + + // Disallow returning a value with type any from a function. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-useless-constructor.md + "no-useless-constructor": "off", }, }, - type: "typescript", - }, -]); - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/ignores.ts b/packages/eslint-config/src/config/ignores.ts new file mode 100644 index 000000000..7109d19da --- /dev/null +++ b/packages/eslint-config/src/config/ignores.ts @@ -0,0 +1,48 @@ +import type { TypedFlatConfigItem } from "../types"; + +const ignores = async (userIgnores: string[] = []): Promise => { + return [ + { + ignores: [ + "**/node_modules", + "**/dist", + "**/package-lock.json", + "**/yarn.lock", + "**/pnpm-lock.yaml", + "**/bun.lockb", + + "**/output", + "**/coverage", + "**/temp", + "**/.temp", + "**/tmp", + "**/.tmp", + "**/.history", + "**/.vitepress/cache", + "**/.nuxt", + "**/.next", + "**/.svelte-kit", + "**/.vercel", + "**/.changeset", + "**/.idea", + "**/.cache", + "**/.output", + "**/.vite-inspect", + "**/.yarn", + "**/vite.config.*.timestamp-*", + + "**/CHANGELOG*.md", + "**/*.min.*", + "**/LICENSE*", + "**/__snapshots__", + "**/auto-import?(s).d.ts", + "**/components.d.ts", + + ...userIgnores, + ], + name: "anolilab/ignores", + }, + ]; +}; + +export default ignores; diff --git a/packages/eslint-config/src/config/plugins/antfu.ts b/packages/eslint-config/src/config/plugins/antfu.ts index 486f15194..b66ed2a90 100644 --- a/packages/eslint-config/src/config/plugins/antfu.ts +++ b/packages/eslint-config/src/config/plugins/antfu.ts @@ -1,19 +1,57 @@ -import { hasTypescript, packageIsTypeModule } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; +import { hasPackageJsonAnyDependency } from "@visulima/package"; +import type { OptionsFiles, OptionsOverrides, OptionsPackageJson } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -const config: Linter.Config = createConfig("all", { - plugins: ["antfu"], - rules: { - "antfu/generic-spacing": "error", - "antfu/if-newline": "error", - "antfu/import-dedupe": "error", - "antfu/no-cjs-exports": packageIsTypeModule ? "error" : "off", - "antfu/no-ts-export-equal": hasTypescript ? "error" : "off", - "antfu/prefer-inline-type-import": "off", - "antfu/top-level-function": "off", - }, -}); +export default createConfig< + OptionsFiles & + OptionsOverrides & + OptionsPackageJson & { + lessOpinionated?: boolean; + } +>("all", async (config, oFiles) => { + const { + files = oFiles, + lessOpinionated = false, + overrides, + packageJson, + } = config; + + const antfuPlugin = await interopDefault(import("eslint-plugin-antfu")); + + return [ + { + files, + name: "anolilab/antfu", + plugins: { + antfu: antfuPlugin, + }, + rules: { + "antfu/consistent-chaining": "error", + "antfu/consistent-list-newline": "error", + "antfu/if-newline": "error", + + "antfu/import-dedupe": "error", -export default config; + "antfu/no-import-dist": "error", + "antfu/no-import-node-modules-by-path": "error", + "antfu/no-ts-export-equal": hasPackageJsonAnyDependency(packageJson, ["typescript"]) ? "error" : "off", + + "antfu/prefer-inline-type-import": "off", + "antfu/top-level-function": "off", + + ...lessOpinionated + ? { + curly: ["error", "all"], + } + : { + "antfu/curly": "error", + "antfu/if-newline": "error", + }, + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/array-func.ts b/packages/eslint-config/src/config/plugins/array-func.ts deleted file mode 100644 index 0f86c31f4..000000000 --- a/packages/eslint-config/src/config/plugins/array-func.ts +++ /dev/null @@ -1,19 +0,0 @@ -// eslint-disable-next-line unicorn/prevent-abbreviations -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -const config: Linter.Config = createConfig("all", { - extends: ["plugin:array-func/recommended"], - plugins: ["array-func"], - rules: { - // Rule disabled due to clash with Unicorn - "array-func/prefer-array-from": "off", - - // Rules not in recommended config - "array-func/prefer-flat": 0, - "array-func/prefer-flat-map": 0, - }, -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/astro.ts b/packages/eslint-config/src/config/plugins/astro.ts new file mode 100644 index 000000000..6836382ec --- /dev/null +++ b/packages/eslint-config/src/config/plugins/astro.ts @@ -0,0 +1,69 @@ +import type { + OptionsFiles, + OptionsOverrides, + OptionsStylistic, + TypedFlatConfigItem, +} from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig("astro", async (config, oFiles): Promise => { + const { files = oFiles, overrides = {}, stylistic = true } = config; + + const [pluginAstro, parserAstro, parserTs] = await Promise.all([ + interopDefault(import("eslint-plugin-astro")), + interopDefault(import("astro-eslint-parser")), + interopDefault(import("@typescript-eslint/parser")), + ] as const); + + return [ + { + name: "anolilab/astro/setup", + plugins: { + astro: pluginAstro, + }, + }, + { + files, + languageOptions: { + globals: pluginAstro.environments.astro.globals, + parser: parserAstro, + parserOptions: { + extraFileExtensions: [".astro"], + parser: parserTs, + }, + sourceType: "module", + }, + name: "anolilab/astro/rules", + processor: "astro/client-side-ts", + rules: { + // Astro uses top level await for e.g. data fetching + // https://docs.astro.build/en/guides/data-fetching/#fetch-in-astro + "antfu/no-top-level-await": "off", + + // use recommended rules + "astro/missing-client-only-directive-value": "error", + "astro/no-conflict-set-directives": "error", + "astro/no-deprecated-astro-canonicalurl": "error", + "astro/no-deprecated-astro-fetchcontent": "error", + "astro/no-deprecated-astro-resolve": "error", + "astro/no-deprecated-getentrybyslug": "error", + "astro/no-set-html-directive": "off", + "astro/no-unused-define-vars-in-style": "error", + "astro/semi": "off", + "astro/valid-compile": "error", + + ...stylistic + ? { + "@stylistic/indent": "off", + "@stylistic/jsx-closing-tag-location": "off", + "@stylistic/jsx-one-expression-per-line": "off", + "@stylistic/no-multiple-empty-lines": "off", + } + : {}, + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/ava.ts b/packages/eslint-config/src/config/plugins/ava.ts deleted file mode 100644 index c2357c775..000000000 --- a/packages/eslint-config/src/config/plugins/ava.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Linter } from "eslint"; - -const config: Linter.Config = { - overrides: [ - { - env: { - es6: true, - }, - extends: "plugin:ava/recommended", - // Default ava test search patterns - files: [ - "test.js", - "src/test.js", - "source/test.js", - "**/test-*.js", - "**/*.spec.js", - "**/*.test.js", - "**/test/**/*.js", - "**/tests/**/*.js", - "**/__tests__/**/*.js", - ], - parserOptions: { - ecmaVersion: "latest", - sourceType: "module", - }, - plugins: ["ava"], - }, - ], -}; - -export default config; diff --git a/packages/eslint-config/src/config/plugins/babel.ts b/packages/eslint-config/src/config/plugins/babel.ts deleted file mode 100644 index 0dabc8d74..000000000 --- a/packages/eslint-config/src/config/plugins/babel.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; -import bestPracticesConfig from "../best-practices"; -import errorsConfig from "../errors"; -import styleConfig from "../style"; - -// @ts-expect-error TODO: find the correct type -const bestPracticesRules = bestPracticesConfig.overrides[0].rules as Linter.RulesRecord; -// @ts-expect-error TODO: find the correct type -const errorsRules = errorsConfig.overrides[0].rules as Linter.RulesRecord; -// @ts-expect-error TODO: find the correct type -const styleRules = styleConfig.overrides[0].rules as Linter.RulesRecord; - -if (global.anolilabEslintConfigBabelPrettierRules === undefined && (hasDependency("prettier") || hasDevDependency("prettier"))) { - global.anolilabEslintConfigBabelPrettierRules = { - "@babel/object-curly-spacing": "off", - - "@babel/semi": "off", - "babel/quotes": 0, - }; -} - -const config: Linter.Config = createConfig("all", { - plugins: ["babel"], - rules: { - // Deep clone to avoid object mutation weirdness - "babel/camelcase": [...(styleRules["camelcase"] as unknown[])] as Linter.RuleEntry, - "babel/new-cap": styleRules["new-cap"], - - "babel/no-invalid-this": bestPracticesRules["no-invalid-this"], - "babel/no-unused-expressions": bestPracticesRules["no-unused-expressions"], - - "babel/object-curly-spacing": styleRules["object-curly-spacing"], - "babel/quotes": styleRules["quotes"], - - "babel/semi": styleRules["semi"], - "babel/valid-typeof": errorsRules["valid-typeof"], - - camelcase: "off", - "new-cap": "off", - - "no-invalid-this": "off", - "no-unused-expressions": "off", - - "object-curly-spacing": "off", - quotes: "off", - - semi: "off", - "valid-typeof": "off", - - ...global.anolilabEslintConfigBabelPrettierRules, - }, -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/comments.ts b/packages/eslint-config/src/config/plugins/comments.ts new file mode 100644 index 000000000..84d4066b1 --- /dev/null +++ b/packages/eslint-config/src/config/plugins/comments.ts @@ -0,0 +1,36 @@ +import type { OptionsFiles, OptionsOverrides } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const pluginComments = await interopDefault(import("@eslint-community/eslint-plugin-eslint-comments")); + + return [ + { + files, + name: "anolilab/eslint-comments/rules", + plugins: { + "eslint-comments": pluginComments, + }, + rules: { + "eslint-comments/no-aggregating-enable": "error", + + "eslint-comments/no-duplicate-disable": "error", + // Rules are not in recommended config + "eslint-comments/no-restricted-disable": "off", + // Disabled as it's already covered by the `unicorn/no-abusive-eslint-disable` rule. + "eslint-comments/no-unlimited-disable": "off", + + "eslint-comments/no-unused-disable": "error", + "eslint-comments/no-unused-enable": "error", + + "eslint-comments/no-use": "off", + "eslint-comments/require-description": "off", + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/compat.ts b/packages/eslint-config/src/config/plugins/compat.ts index b563d0d69..cee0c69ae 100644 --- a/packages/eslint-config/src/config/plugins/compat.ts +++ b/packages/eslint-config/src/config/plugins/compat.ts @@ -1,7 +1,15 @@ -import type { Linter } from "eslint"; +import type { OptionsFiles } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -const config: Linter.Config = { - extends: ["plugin:compat/recommended"], -}; +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles } = config; -export default config; + const compatPlugin = await interopDefault(import("eslint-plugin-compat")); + + const fConfig = compatPlugin.configs["flat/recommended"]; + + fConfig.files = files; + + return [fConfig]; +}); diff --git a/packages/eslint-config/src/config/plugins/cypress.ts b/packages/eslint-config/src/config/plugins/cypress.ts deleted file mode 100644 index 335e93703..000000000 --- a/packages/eslint-config/src/config/plugins/cypress.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Linter } from "eslint"; - -const config: Linter.Config = { - env: { - "cypress/globals": true, - }, - extends: ["plugin:cypress/recommended"], - plugins: ["cypress"], - rules: { - // Rules not in recommend config - "cypress/assertion-before-screenshot": 0, - "cypress/no-force": 0, - "cypress/require-data-selectors": 0, - }, -}; - -export default config; diff --git a/packages/eslint-config/src/config/plugins/deprecation.ts b/packages/eslint-config/src/config/plugins/deprecation.ts deleted file mode 100644 index 233c76c2d..000000000 --- a/packages/eslint-config/src/config/plugins/deprecation.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -// @see https://github.com/francoismassart/eslint-plugin-tailwindcss, -const config: Linter.Config = createConfig("typescript", { - plugins: ["deprecation"], - extends: ["plugin:deprecation/recommended"], -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/editorconfig.ts b/packages/eslint-config/src/config/plugins/editorconfig.ts deleted file mode 100644 index a76065e4f..000000000 --- a/packages/eslint-config/src/config/plugins/editorconfig.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -const config: Linter.Config = createConfig("all", { - extends: ["plugin:editorconfig/all"], - plugins: ["editorconfig"], -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/es.ts b/packages/eslint-config/src/config/plugins/es.ts index f817a9ec1..c0abf9066 100644 --- a/packages/eslint-config/src/config/plugins/es.ts +++ b/packages/eslint-config/src/config/plugins/es.ts @@ -1,12 +1,19 @@ -import type { Linter } from "eslint"; - +import type { OptionsFiles } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -const config: Linter.Config = createConfig("all", { - plugins: ["es-x"], - settings: { - es: { aggressive: true }, - }, -}); +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles } = config; -export default config; + const pluginES = await interopDefault(import("eslint-plugin-es-x")); + + return [ + { + files, + name: "anolilab/es/setup", + plugins: { + "es-x": pluginES, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/eslint-comments.ts b/packages/eslint-config/src/config/plugins/eslint-comments.ts deleted file mode 100644 index 71d4b7d46..000000000 --- a/packages/eslint-config/src/config/plugins/eslint-comments.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -const config: Linter.Config = createConfig("all", { - extends: ["plugin:eslint-comments/recommended"], - plugins: ["eslint-comments"], - rules: { - // Rules are not in recommended config - "eslint-comments/no-restricted-disable": "off", - - // Disabled as it's already covered by the `unicorn/no-abusive-eslint-disable` rule. - "eslint-comments/no-unlimited-disable": "off", - "eslint-comments/no-unused-disable": "error", - "eslint-comments/no-unused-enable": "error", - - "eslint-comments/no-use": "off", - "eslint-comments/require-description": "off", - }, -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/etc.ts b/packages/eslint-config/src/config/plugins/etc.ts deleted file mode 100644 index cd858dcdd..000000000 --- a/packages/eslint-config/src/config/plugins/etc.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { env } from "node:process"; - -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; -import anolilabEslintConfig from "../../utils/eslint-config"; -import { consoleLog } from "../../utils/loggers"; - -if (!global.hasAnolilabEsLintConfigDeprecation && (hasDependency("eslint-plugin-deprecation") || hasDevDependency("eslint-plugin-deprecation"))) { - global.hasAnolilabEsLintConfigDeprecation = true; - let showLog: boolean = env["DISABLE_INFO_ON_DISABLING_ETC_NO_DEPRECATED"] !== "true"; - - if (showLog && anolilabEslintConfig["info_on_disabling_etc_no_deprecated"] !== undefined) { - showLog = anolilabEslintConfig["info_on_disabling_etc_no_deprecated"] as boolean; - } - - if (showLog) { - consoleLog(`\n@anolilab/eslint-config found "eslint-plugin-deprecation" package. \n - Following rules are disabled: etc/no-deprecated. \n`); - } -} - -const config: Linter.Config = createConfig("typescript", { - extends: ["plugin:etc/recommended"], - plugins: ["etc"], - rules: { - "etc/no-deprecated": global.hasAnolilabEsLintConfigDeprecation ? "off" : "error", - }, -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/formatters.ts b/packages/eslint-config/src/config/plugins/formatters.ts new file mode 100644 index 000000000..9d53e1edd --- /dev/null +++ b/packages/eslint-config/src/config/plugins/formatters.ts @@ -0,0 +1,287 @@ +import type { OptionsFormatters, StylisticConfig, TypedFlatConfigItem } from "../../types"; +import { getFilesGlobs } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; +import parserPlain from "../../utils/parser-plain"; +import type { VendoredPrettierOptions, VendoredPrettierRuleOptions } from "../../vender/prettier-types"; +import { StylisticConfigDefaults } from "./stylistic"; + +const mergePrettierOptions = (options: VendoredPrettierOptions, overrides: VendoredPrettierRuleOptions = {}): VendoredPrettierRuleOptions => { + return { + ...options, + ...overrides, + plugins: [...overrides.plugins || [], ...options.plugins || []], + }; +}; + +// eslint-disable-next-line sonarjs/cognitive-complexity +const formatters = async (options: OptionsFormatters, stylistic: StylisticConfig): Promise => { + if (options.slidev && options.markdown !== true && options.markdown !== "prettier") { + throw new Error("`slidev` option only works when `markdown` is enabled with `prettier`"); + } + + const { indent, quotes, semi } = { + ...StylisticConfigDefaults, + ...stylistic, + }; + + const prettierOptions: VendoredPrettierOptions = Object.assign( + { + endOfLine: "auto", + printWidth: 120, + semi, + singleQuote: quotes === "single", + tabWidth: typeof indent === "number" ? indent : 2, + trailingComma: "all", + useTabs: indent === "tab", + } satisfies VendoredPrettierOptions, + options.prettierOptions || {}, + ); + + const prettierXmlOptions: VendoredPrettierOptions = { + xmlQuoteAttributes: "double", + xmlSelfClosingSpace: true, + xmlSortAttributesByKey: false, + xmlWhitespaceSensitivity: "ignore", + }; + + const dprintOptions = { + indentWidth: typeof indent === "number" ? indent : 2, + quoteStyle: quotes === "single" ? "preferSingle" : "preferDouble", + useTabs: indent === "tab", + ...options.dprintOptions, + }; + + const pluginFormat = await interopDefault(import("eslint-plugin-format")); + + const configs: TypedFlatConfigItem[] = [ + { + name: "anolilab/formatter/setup", + plugins: { + format: pluginFormat, + }, + }, + ]; + + if (options.css) { + configs.push( + { + files: [...getFilesGlobs("css"), ...getFilesGlobs("postcss")], + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/css", + rules: { + "format/prettier": [ + "error", + mergePrettierOptions(prettierOptions, { + parser: "css", + }), + ], + }, + }, + { + files: getFilesGlobs("scss"), + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/scss", + rules: { + "format/prettier": [ + "error", + mergePrettierOptions(prettierOptions, { + parser: "scss", + }), + ], + }, + }, + { + files: getFilesGlobs("less"), + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/less", + rules: { + "format/prettier": [ + "error", + mergePrettierOptions(prettierOptions, { + parser: "less", + }), + ], + }, + }, + ); + } + + if (options.html) { + configs.push({ + files: getFilesGlobs("html"), + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/html", + rules: { + "format/prettier": [ + "error", + mergePrettierOptions(prettierOptions, { + parser: "html", + }), + ], + }, + }); + } + + if (options.xml) { + configs.push({ + files: getFilesGlobs("xml"), + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/xml", + rules: { + "format/prettier": [ + "error", + mergePrettierOptions( + { ...prettierXmlOptions, ...prettierOptions }, + { + parser: "xml", + plugins: ["@prettier/plugin-xml"], + }, + ), + ], + }, + }); + } + + if (options.svg) { + configs.push({ + files: getFilesGlobs("svg"), + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/svg", + rules: { + "format/prettier": [ + "error", + mergePrettierOptions( + { ...prettierXmlOptions, ...prettierOptions }, + { + parser: "xml", + plugins: ["@prettier/plugin-xml"], + }, + ), + ], + }, + }); + } + + if (options.markdown) { + const formater = options.markdown === true ? "prettier" : options.markdown; + + let GLOB_SLIDEV: string[] = []; + + if (typeof options.slidev === "boolean" && options.slidev === true) { + GLOB_SLIDEV = ["**/slides.md"]; + } else if (typeof options.slidev === "object" && options.slidev.files) { + GLOB_SLIDEV = options.slidev.files; + } + + configs.push({ + files: getFilesGlobs("markdown"), + ignores: GLOB_SLIDEV, + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/markdown", + rules: { + [`format/${formater}`]: [ + "error", + formater === "prettier" + ? mergePrettierOptions(prettierOptions, { + embeddedLanguageFormatting: "off", + parser: "markdown", + }) + : { + ...dprintOptions, + language: "markdown", + }, + ], + }, + }); + + if (options.slidev) { + configs.push({ + files: GLOB_SLIDEV, + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/slidev", + rules: { + "format/prettier": [ + "error", + mergePrettierOptions(prettierOptions, { + embeddedLanguageFormatting: "off", + parser: "slidev", + plugins: ["prettier-plugin-slidev"], + }), + ], + }, + }); + } + } + + if (options.astro) { + configs.push( + { + files: getFilesGlobs("astro"), + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/astro", + rules: { + "format/prettier": [ + "error", + mergePrettierOptions(prettierOptions, { + parser: "astro", + plugins: ["prettier-plugin-astro"], + }), + ], + }, + }, + { + files: [...getFilesGlobs("astro"), ...getFilesGlobs("astro_ts")], + name: "anolilab/formatter/astro/disables", + rules: { + "@stylistic/arrow-parens": "off", + "@stylistic/block-spacing": "off", + "@stylistic/comma-dangle": "off", + "@stylistic/indent": "off", + "@stylistic/no-multi-spaces": "off", + "@stylistic/quotes": "off", + "@stylistic/semi": "off", + }, + }, + ); + } + + if (options.graphql) { + configs.push({ + files: getFilesGlobs("graphql"), + languageOptions: { + parser: parserPlain, + }, + name: "anolilab/formatter/graphql", + rules: { + "format/prettier": [ + "error", + mergePrettierOptions(prettierOptions, { + parser: "graphql", + }), + ], + }, + }); + } + + return configs; +}; + +export default formatters; diff --git a/packages/eslint-config/src/config/plugins/html.ts b/packages/eslint-config/src/config/plugins/html.ts index 04d2bfe4f..2c122b7ac 100644 --- a/packages/eslint-config/src/config/plugins/html.ts +++ b/packages/eslint-config/src/config/plugins/html.ts @@ -1,74 +1,54 @@ -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; - -import indent from "../../utils/indent"; - -if (!global.hasAnolilabEsLintConfigPrettier && (hasDependency("prettier") || hasDevDependency("prettier"))) { - global.hasAnolilabEsLintConfigPrettier = true; -} - -if (global.hasAnolilabEsLintConfigPrettier) { - global.anolilabEslintConfigHtmlPrettierRules = { - "@html-eslint/element-newline": "off", - "@html-eslint/indent": "off", - "@html-eslint/no-extra-spacing-attrs": "off", - "@html-eslint/quotes": "off", - }; - - global.anolilabEslintConfigHtmlPrettierSettings = { - "html/report-bad-indent": "off", - }; -} - -let settings: Linter.Config["settings"] = {}; - -if (!global.hasAnolilabEsLintConfigPrettier) { - settings = { - "html/indent": `+${indent}`, - }; -} - -const config: Linter.Config = { - overrides: [ +import type { + OptionsFiles, + OptionsHasPrettier, + OptionsOverrides, + OptionsStylistic, +} from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig("html", async (config, oFiles) => { + const { + files = oFiles, + overrides, + prettier, + stylistic = true, + } = config; + + const { indent = 4 } = typeof stylistic === "boolean" ? {} : stylistic; + + const htmlPlugin = await interopDefault(import("eslint-plugin-html")); + + return [ { - extends: ["plugin:@html-eslint/recommended"], - files: [ - "**/*.erb", - "**/*.handlebars", - "**/*.hbs", - "**/*.htm", - "**/*.html", - "**/*.mustache", - "**/*.nunjucks", - "**/*.php", - "**/*.tag", - "**/*.twig", - "**/*.we", - ], - globals: { - sourceCode: true, - }, - env: { - browser: true, - node: false, + files, + name: "anolilab/html/setup", + plugins: { + html: htmlPlugin, }, - parser: "@html-eslint/parser", - plugins: ["html", "@html-eslint"], rules: { "@html-eslint/indent": ["error", indent], "capitalized-comments": "off", // @see https://github.com/yeonjuan/html-eslint/issues/67 bug in html-eslint "spaced-comment": "off", - ...global.anolilabEslintConfigHtmlPrettierRules, + ...prettier + ? { + "@html-eslint/element-newline": "off", + "@html-eslint/indent": "off", + "@html-eslint/no-extra-spacing-attrs": "off", + "@html-eslint/quotes": "off", + } + : {}, + + ...overrides, }, + settings: { + "html/indent": `+${indent}`, "html/report-bad-indent": "error", - ...settings, - ...global.anolilabEslintConfigHtmlPrettierSettings, + ...prettier ? { "html/report-bad-indent": "off" } : {}, }, }, - ], -}; - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/import.ts b/packages/eslint-config/src/config/plugins/import.ts deleted file mode 100644 index 819df56c8..000000000 --- a/packages/eslint-config/src/config/plugins/import.ts +++ /dev/null @@ -1,403 +0,0 @@ -import { fromRoot, packageIsTypeModule, projectPath } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; - -import { createConfigs } from "../../utils/create-config"; -import anolilabEslintConfig from "../../utils/eslint-config"; - -if (global.anolilabEslintImportNoUnusedModulesConfig === undefined && anolilabEslintConfig["import_ignore_exports"]) { - if (!Array.isArray(anolilabEslintConfig["import_ignore_exports"])) { - throw new TypeError("import.ignore_exports must be a array"); - } - - global.anolilabEslintImportNoUnusedModulesConfig = anolilabEslintConfig["import_ignore_exports"] as string[]; -} - -const config: Linter.Config = createConfigs([ - { - config: { - env: { - es6: true, - }, - - parserOptions: { - ecmaVersion: 6, - sourceType: "module", - }, - plugins: ["import"], - rules: { - // enforce a consistent style for type specifiers (inline or top-level) - // https://github.com/un-es/eslint-plugin-i/blob/d5fc8b670dc8e6903dbb7b0894452f60c03089f5/docs/rules/consistent-type-specifier-style.md - "import/consistent-type-specifier-style": ["error", "prefer-top-level"], - - // ensure named imports coupled with named exports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/default.md#when-not-to-use-it - "import/default": "off", - - // dynamic imports require a leading comment with a webpackChunkName - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/dynamic-import-chunkname.md - "import/dynamic-import-chunkname": [ - "off", - { - importFunctions: [], - webpackChunknameFormat: "[0-9a-zA-Z-_/.]+", - }, - ], - - // disallow invalid exports, e.g. multiple defaults - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/export.md - "import/export": "error", - - // This rule enforces that all exports are declared at the bottom of the file. - // https://github.com/import-js/eslint-plugin-import/blob/98acd6afd04dcb6920b81330114e146dc8532ea4/docs/rules/exports-last.md - "import/exports-last": "error", - - // Ensure consistent use of file extension within the import path - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/extensions.md - "import/extensions": [ - "error", - "ignorePackages", - packageIsTypeModule - ? { - cjs: "always", - js: "always", - jsx: "always", - mjs: "always", - json: "always", - } - : { - cjs: "never", - js: "never", - jsx: "never", - mjs: "never", - json: "always", - }, - ], - - // disallow non-import statements appearing before import statements - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/first.md - "import/first": "error", - - // Reports when named exports are not grouped together in a single export declaration - // or when multiple assignments to CommonJS module.exports or exports object are present - // in a single file. - // https://github.com/import-js/eslint-plugin-import/blob/44a038c06487964394b1e15b64f3bd34e5d40cde/docs/rules/group-exports.md - "import/group-exports": "off", - - // disallow non-import statements appearing before import statements - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/imports-first.md - // deprecated: use `import/first` - "import/imports-first": "off", - - // "import/max-dependencies" is not super useful - // Either you will disable the eslint rule because it's "normal" - // to have a lot of dependencies or feel compelled to reduce the number of imports. - // It's already visible that a file has many imports and that ideally they should be - // less imports, no need for ESLint, let's keep ESLint for more valuable things. - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/max-dependencies.md - "import/max-dependencies": ["off", { max: 10 }], - - // disallow require() - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/named.md#when-not-to-use-it - "import/named": "error", - - // disallow AMD require/define - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/namespace.md - "import/namespace": "off", - - // Require a newline after the last import/require in a group - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/newline-after-import.md - "import/newline-after-import": "error", - - // Forbid import of modules using absolute paths - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-absolute-path.md - "import/no-absolute-path": "error", - - // disallow AMD require/define - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-amd.md - "import/no-amd": "error", - - // Reports if a module's default export is unnamed - // https://github.com/import-js/eslint-plugin-import/blob/d9b712ac7fd1fddc391f7b234827925c160d956f/docs/rules/no-anonymous-default-export.md - "import/no-anonymous-default-export": [ - "off", - { - allowAnonymousClass: false, - allowAnonymousFunction: false, - allowArray: false, - allowArrowFunction: false, - allowLiteral: false, - allowObject: false, - }, - ], - - // disallow require() - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md - "import/no-commonjs": packageIsTypeModule ? ["error", { allowPrimitiveModules: true }] : "off", - - // Forbid cyclical dependencies between modules - // https://medium.com/@steven-lemon182/are-typescript-barrel-files-an-anti-pattern-72a713004250 - "import/no-cycle": ["error", { maxDepth: "∞" }], - - // forbid default exports. this is a terrible rule, do not use it. - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-default-export.md - "import/no-default-export": "off", - - // disallow use of jsdoc-marked-deprecated imports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-deprecated.md - "import/no-deprecated": "off", - - // disallow duplicate imports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-duplicates.md - "import/no-duplicates": "error", - - // Forbid require() calls with expressions - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-dynamic-require.md - "import/no-dynamic-require": "error", - - // Reports the use of empty named import blocks. - // https://github.com/un-es/eslint-plugin-i/blob/d5fc8b670dc8e6903dbb7b0894452f60c03089f5/docs/rules/no-empty-named-blocks.md - "import/no-empty-named-blocks": "error", - - // Forbid the use of extraneous packages - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md - // paths are treated both as absolute paths, and relative to process.cwd() - "import/no-extraneous-dependencies": [ - "error", - { - devDependencies: [ - "test/**", // tape, common npm pattern - "tests/**", // also common npm pattern - "spec/**", // mocha, rspec-like pattern - "**/fixture/**", // jest pattern - "**/__mocks__/**", // jest pattern - "test.{js,jsx}", // repos with a single test file - "test-*.{js,jsx}", // repos with multiple top-level test files - "**/*{.,_}{test,spec}.{js,jsx}", // tests where the extension or filename suffix denotes that it is a test - "**/jest.config.cjs", // jest config - "**/jest.setup.js", // jest setup - "**/vue.config.cjs", // vue-cli config - "**/webpack.config.cjs", // webpack config - "**/webpack.config.*.js", // webpack config - "**/rollup.config.cjs", // rollup config - "**/rollup.config.*.js", // rollup config - "**/gulpfile.js", // gulp config - "**/gulpfile.*.js", // gulp config - "**/Gruntfile{,.js}", // grunt config - "**/protractor.conf.js", // protractor config - "**/protractor.conf.*.js", // protractor config - "**/karma.conf.js", // karma config - "**/.eslintrc.js", // eslint config - "**/.eslintrc.cjs", // eslint config - "**/.eslintrc.mjs", // eslint config - "**/eslint.config.js", // eslint flat config - "**/eslint.config.mjs", // eslint flat config - "**/eslint.config.cjs", // eslint flat config - "**/vite.config.js", // vite config - "**/vite.config.ts", // vite config - "**/vitest.config.js", // vitest config - "**/vitest.config.ts", // vitest config - "**/__tests__/**/*.?(c|m)[jt]s?(x)", // vitest config test include - "**/?(*.){test,spec}.?(c|m)[jt]s?(x)", // vitest config test include - ], - optionalDependencies: false, - }, - ], - - // prevent importing the submodules of other modules - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-internal-modules.md - "import/no-internal-modules": [ - "off", - { - allow: [], - }, - ], - - // Forbid mutable exports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-mutable-exports.md - "import/no-mutable-exports": "error", - - // Warn if a module could be mistakenly parsed as a script by a consumer - // leveraging Unambiguous JavaScript Grammar - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/unambiguous.md - // this should not be enabled until this proposal has at least been *presented* to TC39. - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-as-default.md - "import/no-named-as-default": "error", - - // warn on accessing default export property names that are also named exports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-as-default-member.md - "import/no-named-as-default-member": "error", - - // Prevent importing the default as if it were named - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-default.md - "import/no-named-default": "error", - - // Prohibit named exports. this is a terrible rule, do not use it. - // https://github.com/import-js/eslint-plugin-import/blob/1ec80fa35fa1819e2d35a70e68fb6a149fb57c5e/docs/rules/no-named-export.md - "import/no-named-export": "off", - - // disallow namespace imports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-namespace.md - "import/no-namespace": "error", - - // No Node.js builtin modules - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-nodejs-modules.md - // TODO: enable? - "import/no-nodejs-modules": "off", - - // Use this rule to prevent imports to folders in relative parent paths. - // https://github.com/import-js/eslint-plugin-import/blob/c34f14f67f077acd5a61b3da9c0b0de298d20059/docs/rules/no-relative-parent-imports.md - "import/no-relative-parent-imports": "off", - - // Restrict which files can be imported in a given folder - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-restricted-paths.md - "import/no-restricted-paths": "off", - - // Forbid a module from importing itself - // https://github.com/import-js/eslint-plugin-import/blob/44a038c06487964394b1e15b64f3bd34e5d40cde/docs/rules/no-self-import.md - "import/no-self-import": "error", - - // Forbid a module from importing itself - // importing for side effects is perfectly acceptable, if you need side effects. - "import/no-unassigned-import": "off", - - // ensure imports point to files/modules that can be resolved - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md - "import/no-unresolved": ["error", { caseSensitive: true, commonjs: true }], - - // Reports modules without any exports, or with unused exports - // https://github.com/import-js/eslint-plugin-import/blob/f63dd261809de6883b13b6b5b960e6d7f42a7813/docs/rules/no-unused-modules.md - "import/no-unused-modules": [ - packageIsTypeModule ? "error" : "off", - { - ignoreExports: global.anolilabEslintImportNoUnusedModulesConfig ?? [], - missingExports: true, - unusedExports: true, - }, - ], - - // Reports the use of import declarations with CommonJS exports in any module except for the main module. - // https://github.com/import-js/eslint-plugin-import/blob/1012eb951767279ce3b540a4ec4f29236104bb5b/docs/rules/no-import-module-exports.md - "import/no-import-module-exports": [ - packageIsTypeModule ? "off" : "error", - { - exceptions: [], - }, - ], - - // Use this rule to prevent importing packages through relative paths. - // https://github.com/import-js/eslint-plugin-import/blob/1012eb951767279ce3b540a4ec4f29236104bb5b/docs/rules/no-relative-packages.md - "import/no-relative-packages": "error", - - // Ensures that there are no useless path segments - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-useless-path-segments.md - "import/no-useless-path-segments": ["error", { commonjs: true, noUselessIndex: true }], - - // Forbid Webpack loader syntax in imports - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-webpack-loader-syntax.md - "import/no-webpack-loader-syntax": "error", - - // ensure absolute imports are above relative imports and that unassigned imports are ignored - // https://github.com/import-js/eslint-plugin-import/blob/f63dd261809de6883b13b6b5b960e6d7f42a7813/docs/rules/no-unused-modules.md - // simple-import-sort does this better - "import/order": "off", - - // Require modules with a single export to use a default export - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/prefer-default-export.md - "import/prefer-default-export": "error", - - // Warn if a module could be mistakenly parsed as a script by a consumer - // leveraging Unambiguous JavaScript Grammar - // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/unambiguous.md - // this should not be enabled until this proposal has at least been *presented* to TC39. - // At the moment, it's not a thing. - "import/unambiguous": "off", - }, - settings: { - "import/core-modules": [], - // https://github.com/un-es/eslint-plugin-i/blob/main/docs/rules/extensions.md - "import/extensions": [".js", ".cjs", ".mjs", ".jsx"], - // Ensure consistent use of file extension within the import path - "import/ignore": ["\\.(coffee|scss|css|less|hbs|svg|json)$"], - }, - }, - type: "all", - }, - { - config: { - settings: { - "import/resolver": { - "@jsenv/eslint-import-resolver": { - rootDirectoryUrl: projectPath, - packageConditions: ["node", "import"], - }, - }, - }, - }, - type: "javascript", - }, - { - config: { - extends: ["plugin:import/typescript"], - rules: { - // Does not work when the TS definition exports a default const. - "import/default": "off", - - // Disabled because of https://github.com/import-js/eslint-plugin-import/issues/1590 - "import/export": "off", - - // Disabled as it doesn't work with TypeScript. - "import/extensions": [ - "error", - "ignorePackages", - { - js: "never", - jsx: "never", - mjs: "never", - cjs: "never", - ts: "never", - tsx: "never", - json: "always", - svg: "always", - }, - ], - - // This issue and some others: https://github.com/import-js/eslint-plugin-import/issues/1341 - "import/named": "off", - - // ensure imports point to files/modules that can be resolved - "import/no-unresolved": "off", - }, - settings: { - // Append 'ts' extensions to 'import/extensions' setting - "import/extensions": [".js", ".mjs", ".jsx", ".ts", ".tsx", ".d.ts", ".cjs", ".cts", ".mts"], - - // Resolve type definition packages - "import/external-module-folders": ["node_modules", "node_modules/@types"], - - // Apply special parsing for TypeScript files - "import/parsers": { - "@typescript-eslint/parser": [".ts", ".cts", ".mts", ".tsx", ".d.ts"], - }, - - // Append 'ts' extensions to 'import/resolver' setting - "import/resolver": { - typescript: { - alwaysTryTypes: true, // always try to resolve types under `@types` directory even it doesn't contain any source code, like `@types/unist` - project: fromRoot("tsconfig.json"), - }, - }, - }, - }, - type: "typescript", - }, - { - config: { - rules: { - "import/no-duplicates": "off", - }, - }, - type: "d.ts", - }, -]); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/imports.ts b/packages/eslint-config/src/config/plugins/imports.ts new file mode 100644 index 000000000..a0619ee0b --- /dev/null +++ b/packages/eslint-config/src/config/plugins/imports.ts @@ -0,0 +1,418 @@ +import tsParser from "@typescript-eslint/parser"; +import { hasPackageJsonAnyDependency } from "@visulima/package"; + +import type { + OptionsCwd, + OptionsFiles, + OptionsOverrides, + OptionsPackageJson, + OptionsStylistic, + OptionsTypeScriptWithTypes, + TypedFlatConfigItem, +} from "../../types"; +import { createConfig, getFilesGlobs } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig( + "all", + async (config, oFiles) => { + const { + files = oFiles, + overrides, + packageJson, + stylistic, + tsconfigPath, + } = config; + + const importPlugin = await interopDefault(import("eslint-plugin-import-x")); + + const rules: TypedFlatConfigItem[] = [ + { + name: "anolilab/imports/setup", + plugins: { + import: importPlugin, + }, + }, + { + files, + name: "anolilab/imports/rules", + rules: { + // enforce a consistent style for type specifiers (inline or top-level) + // https://github.com/un-es/eslint-plugin-i/blob/d5fc8b670dc8e6903dbb7b0894452f60c03089f5/docs/rules/consistent-type-specifier-style.md + "import/consistent-type-specifier-style": ["error", "prefer-top-level"], + + // ensure named imports coupled with named exports + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/default.md#when-not-to-use-it + "import/default": "off", + + // dynamic imports require a leading comment with a webpackChunkName + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/dynamic-import-chunkname.md + "import/dynamic-import-chunkname": [ + "off", + { + importFunctions: [], + webpackChunknameFormat: "[0-9a-zA-Z-_/.]+", + }, + ], + + // disallow invalid exports, e.g. multiple defaults + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/export.md + "import/export": "error", + + // This rule enforces that all exports are declared at the bottom of the file. + // https://github.com/import-js/eslint-plugin-import/blob/98acd6afd04dcb6920b81330114e146dc8532ea4/docs/rules/exports-last.md + "import/exports-last": "error", + + // Ensure consistent use of file extension within the import path + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/extensions.md + "import/extensions": [ + "error", + "ignorePackages", + { + checkTypeImports: tsconfigPath !== undefined, + ignorePackages: true, + pattern: { + ...packageJson.type === "module" + ? { + cjs: "always", + js: "always", + json: "always", + jsx: "always", + mjs: "always", + } + : { + cjs: "never", + js: "never", + json: "always", + jsx: "never", + mjs: "never", + }, + }, + }, + ], + + // disallow non-import statements appearing before import statements + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/first.md + "import/first": "error", + + // Reports when named exports are not grouped together in a single export declaration + // or when multiple assignments to CommonJS module.exports or exports object are present + // in a single file. + // https://github.com/import-js/eslint-plugin-import/blob/44a038c06487964394b1e15b64f3bd34e5d40cde/docs/rules/group-exports.md + "import/group-exports": "off", + + // disallow non-import statements appearing before import statements + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/imports-first.md + // deprecated: use `import/first` + "import/imports-first": "off", + + // "import/max-dependencies" is not super useful + // Either you will disable the eslint rule because it's "normal" + // to have a lot of dependencies or feel compelled to reduce the number of imports. + // It's already visible that a file has many imports and that ideally they should be + // less imports, no need for ESLint, let's keep ESLint for more valuable things. + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/max-dependencies.md + "import/max-dependencies": ["off", { max: 10 }], + + // disallow require() + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/named.md#when-not-to-use-it + "import/named": "error", + + // disallow AMD require/define + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/namespace.md + "import/namespace": "off", + + // Require a newline after the last import/require in a group + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/newline-after-import.md + ...stylistic + ? { + "import/newline-after-import": ["error", { count: 1 }], + } + : {}, + + // Forbid import of modules using absolute paths + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-absolute-path.md + "import/no-absolute-path": "error", + + // disallow AMD require/define + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-amd.md + "import/no-amd": "error", + + // Reports if a module's default export is unnamed + + // https://github.com/import-js/eslint-plugin-import/blob/d9b712ac7fd1fddc391f7b234827925c160d956f/docs/rules/no-anonymous-default-export.md + "import/no-anonymous-default-export": [ + "off", + { + allowAnonymousClass: false, + allowAnonymousFunction: false, + allowArray: false, + allowArrowFunction: false, + allowLiteral: false, + allowObject: false, + }, + ], + + // disallow require() + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-commonjs.md + "import/no-commonjs": packageJson.type === "module" ? ["error", { allowPrimitiveModules: true }] : "off", + + // Forbid cyclical dependencies between modules + // https://medium.com/@steven-lemon182/are-typescript-barrel-files-an-anti-pattern-72a713004250 + "import/no-cycle": ["error", { maxDepth: "∞" }], + + // forbid default exports. this is a terrible rule, do not use it. + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-default-export.md + "import/no-default-export": "off", + + // disallow use of jsdoc-marked-deprecated imports + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-deprecated.md + "import/no-deprecated": "off", + + // disallow duplicate imports + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-duplicates.md + "import/no-duplicates": "error", + + // Forbid require() calls with expressions + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-dynamic-require.md + "import/no-dynamic-require": "error", + + // Reports the use of empty named import blocks. + + // https://github.com/un-es/eslint-plugin-i/blob/d5fc8b670dc8e6903dbb7b0894452f60c03089f5/docs/rules/no-empty-named-blocks.md + "import/no-empty-named-blocks": "error", + + // Forbid the use of extraneous packages + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-extraneous-dependencies.md + // paths are treated both as absolute paths, and relative to process.cwd() + "import/no-extraneous-dependencies": [ + "error", + { + devDependencies: [ + "test/**", // tape, common npm pattern + "tests/**", // also common npm pattern + "spec/**", // mocha, rspec-like pattern + "**/fixture/**", // jest pattern + "**/__mocks__/**", // jest pattern + "test.{js,jsx}", // repos with a single test file + "test-*.{js,jsx}", // repos with multiple top-level test files + "**/*{.,_}{test,spec}.{js,jsx}", // tests where the extension or filename suffix denotes that it is a test + "**/jest.config.cjs", // jest config + "**/jest.setup.js", // jest setup + "**/vue.config.cjs", // vue-cli config + "**/webpack.config.cjs", // webpack config + "**/webpack.config.*.js", // webpack config + "**/rollup.config.cjs", // rollup config + "**/rollup.config.*.js", // rollup config + "**/gulpfile.js", // gulp config + "**/gulpfile.*.js", // gulp config + "**/Gruntfile{,.js}", // grunt config + "**/protractor.conf.js", // protractor config + "**/protractor.conf.*.js", // protractor config + "**/karma.conf.js", // karma config + "**/.eslintrc.js", // eslint config + "**/.eslintrc.cjs", // eslint config + "**/.eslintrc.mjs", // eslint config + "**/eslint.config.js", // eslint flat config + "**/eslint.config.mjs", // eslint flat config + "**/eslint.config.cjs", // eslint flat config + "**/vite.config.js", // vite config + "**/vite.config.ts", // vite config + "**/vitest.config.js", // vitest config + "**/vitest.config.ts", // vitest config + "**/__tests__/**/*.?(c|m)[jt]s?(x)", // vitest config test include + "**/?(*.){test,spec}.?(c|m)[jt]s?(x)", // vitest config test include + ], + optionalDependencies: false, + }, + ], + + // Reports the use of import declarations with CommonJS exports in any module except for the main module. + // https://github.com/import-js/eslint-plugin-import/blob/1012eb951767279ce3b540a4ec4f29236104bb5b/docs/rules/no-import-module-exports.md + "import/no-import-module-exports": [ + packageJson.type === "module" ? "off" : "error", + { + exceptions: [], + }, + ], + + // prevent importing the submodules of other modules + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-internal-modules.md + "import/no-internal-modules": [ + "off", + { + allow: [], + }, + ], + + // Forbid mutable exports + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-mutable-exports.md + "import/no-mutable-exports": "error", + + // Warn if a module could be mistakenly parsed as a script by a consumer + // leveraging Unambiguous JavaScript Grammar + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/unambiguous.md + // this should not be enabled until this proposal has at least been *presented* to TC39. + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-as-default.md + "import/no-named-as-default": "error", + + // warn on accessing default export property names that are also named exports + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-as-default-member.md + "import/no-named-as-default-member": "error", + + // Prevent importing the default as if it were named + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-named-default.md + "import/no-named-default": "error", + + // Prohibit named exports. this is a terrible rule, do not use it. + // https://github.com/import-js/eslint-plugin-import/blob/1ec80fa35fa1819e2d35a70e68fb6a149fb57c5e/docs/rules/no-named-export.md + "import/no-named-export": "off", + + // disallow namespace imports + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-namespace.md + "import/no-namespace": "error", + + // No Node.js builtin modules + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-nodejs-modules.md + "import/no-nodejs-modules": "off", + + // Use this rule to prevent importing packages through relative paths. + // https://github.com/import-js/eslint-plugin-import/blob/1012eb951767279ce3b540a4ec4f29236104bb5b/docs/rules/no-relative-packages.md + "import/no-relative-packages": "error", + + // Use this rule to prevent imports to folders in relative parent paths. + // https://github.com/import-js/eslint-plugin-import/blob/c34f14f67f077acd5a61b3da9c0b0de298d20059/docs/rules/no-relative-parent-imports.md + "import/no-relative-parent-imports": "off", + + // Restrict which files can be imported in a given folder + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-restricted-paths.md + "import/no-restricted-paths": "off", + + // Forbid a module from importing itself + // https://github.com/import-js/eslint-plugin-import/blob/44a038c06487964394b1e15b64f3bd34e5d40cde/docs/rules/no-self-import.md + "import/no-self-import": "error", + + // @TODO: Enable this rule when it's fixed https://github.com/import-js/eslint-plugin-import/issues/2678 + // Reports modules without any exports, or with unused exports + // https://github.com/import-js/eslint-plugin-import/blob/f63dd261809de6883b13b6b5b960e6d7f42a7813/docs/rules/no-unused-modules.md + // "import/no-unused-modules": [ + // packageJson.type === "module" ? "error" : "off", + // { + // ignoreExports: importNoUnusedModules ?? [], + // missingExports: true, + // unusedExports: true, + // }, + // ], + + // Forbid a module from importing itself + // importing for side effects is perfectly acceptable, if you need side effects. + "import/no-unassigned-import": "off", + + // ensure imports point to files/modules that can be resolved + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md + "import/no-unresolved": ["error", { caseSensitive: true, commonjs: true }], + + // Ensures that there are no useless path segments + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-useless-path-segments.md + "import/no-useless-path-segments": ["error", { commonjs: true, noUselessIndex: true }], + + // Forbid Webpack loader syntax in imports + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-webpack-loader-syntax.md + "import/no-webpack-loader-syntax": "error", + + // ensure absolute imports are above relative imports and that unassigned imports are ignored + // https://github.com/import-js/eslint-plugin-import/blob/f63dd261809de6883b13b6b5b960e6d7f42a7813/docs/rules/no-unused-modules.md + // simple-import-sort does this better + "import/order": "off", + + // Require modules with a single export to use a default export + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/prefer-default-export.md + "import/prefer-default-export": "error", + + // Warn if a module could be mistakenly parsed as a script by a consumer + // leveraging Unambiguous JavaScript Grammar + // https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/unambiguous.md + // this should not be enabled until this proposal has at least been *presented* to TC39. + // At the moment, it's not a thing. + "import/unambiguous": "off", + + ...overrides, + }, + }, + { + files: getFilesGlobs("d.ts"), + name: "anolilab/imports/d.ts-rules", + rules: { + "import/no-duplicates": "off", + }, + }, + ]; + + if (hasPackageJsonAnyDependency(packageJson, ["react", "react-dom"])) { + rules.push(importPlugin.flatConfigs.react); + } + + if (hasPackageJsonAnyDependency(packageJson, ["typescript"])) { + rules.push({ + files: getFilesGlobs("ts"), + languageOptions: { + ecmaVersion: "latest", + parser: tsParser, + sourceType: "module", + }, + name: "anolilab/import/ts-rules", + rules: { + // Does not work when the TS definition exports a default const. + "import/default": "off", + + // Disabled because of https://github.com/import-js/eslint-plugin-import/issues/1590 + "import/export": "off", + + // Disabled as it doesn't work with TypeScript. + "import/extensions": "off", + + // This issue and some others: https://github.com/import-js/eslint-plugin-import/issues/1341 + "import/named": "off", + + // ensure imports point to files/modules that can be resolved + "import/no-unresolved": "off", + }, + settings: { + // Append 'ts' extensions to 'import/extensions' setting + "import/extensions": [...getFilesGlobs("js_and_ts"), ...getFilesGlobs("jsx_and_tsx")].map(extension => extension.replace("**/*", "")), + + // Resolve type definition packages + "import/external-module-folders": ["node_modules", "node_modules/@types"], + + // Apply special parsing for TypeScript files + "import/parsers": { + "@typescript-eslint/parser": getFilesGlobs("ts").map(extension => extension.replace("**/*", "")), + }, + + ...tsconfigPath + ? { + // Append 'ts' extensions to 'import/resolver' setting + "import/resolver": { + node: true, + typescript: { + // always try to resolve types under `@types` directory even it doesn't contain any source code, like `@types/unist` + alwaysTryTypes: true, + project: tsconfigPath, + }, + }, + } + : { + "import/resolver": { + node: true, + // You will also need to install and configure the TypeScript resolver + // See also https://github.com/import-js/eslint-import-resolver-typescript#configuration + typescript: true, + }, + }, + }, + }); + } + + return rules; + }, +); diff --git a/packages/eslint-config/src/config/plugins/javascript.ts b/packages/eslint-config/src/config/plugins/javascript.ts new file mode 100644 index 000000000..e75d995d8 --- /dev/null +++ b/packages/eslint-config/src/config/plugins/javascript.ts @@ -0,0 +1,76 @@ +import globals from "globals"; + +import type { OptionsPackageJson } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig("js", async (config) => { + const { packageJson } = config; + + const eslintJs = await interopDefault(import("@eslint/js")); + + return [ + { + languageOptions: { + ecmaVersion: 2022, + globals: { + ...globals.browser, + ...globals.es2021, + ...globals.node, + document: "readonly", + navigator: "readonly", + window: "readonly", + ...packageJson.type === "module" + ? { + __dirname: "off", + __filename: "off", + exports: "off", + require: "off", + } + : { + __dirname: true, + __filename: true, + exports: true, + require: true, + }, + }, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 2022, + sourceType: "module", + }, + sourceType: "module", + }, + linterOptions: { + reportUnusedDisableDirectives: true, + }, + name: "anolilab/javascript/setup", + }, + eslintJs.configs.recommended, + { + files: ["**/*.cjs"], + languageOptions: { + // inside *.cjs files. restore commonJS "globals" + globals: { + __dirname: true, + __filename: true, + exports: true, + require: true, + }, + }, + }, + { + files: ["**/*.mjs"], + languageOptions: { + globals: { + __dirname: "off", + __filename: "off", + exports: "off", + require: "off", + }, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/jest-async.ts b/packages/eslint-config/src/config/plugins/jest-async.ts deleted file mode 100644 index 2bbb4e6f7..000000000 --- a/packages/eslint-config/src/config/plugins/jest-async.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { Linter } from "eslint"; - -const config: Linter.Config = { - plugins: ["jest-async"], - rules: { - "jest-async/expect-return": "error", - }, -}; - -export default config; diff --git a/packages/eslint-config/src/config/plugins/jest-dom.ts b/packages/eslint-config/src/config/plugins/jest-dom.ts deleted file mode 100644 index e6fcb91c0..000000000 --- a/packages/eslint-config/src/config/plugins/jest-dom.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Linter } from "eslint"; - -const config: Linter.Config = { - extends: ["plugin:jest-dom/recommended"], -}; - -export default config; diff --git a/packages/eslint-config/src/config/plugins/jest-formatting.ts b/packages/eslint-config/src/config/plugins/jest-formatting.ts deleted file mode 100644 index a0e44d73c..000000000 --- a/packages/eslint-config/src/config/plugins/jest-formatting.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Linter } from "eslint"; - -const config: Linter.Config = { - extends: ["plugin:jest-formatting/recommended"], -}; - -export default config; diff --git a/packages/eslint-config/src/config/plugins/jest.ts b/packages/eslint-config/src/config/plugins/jest.ts deleted file mode 100644 index 2ac47f2ba..000000000 --- a/packages/eslint-config/src/config/plugins/jest.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { Linter } from "eslint"; -import globals from "globals"; - -const config: Linter.Config = { - overrides: [ - { - files: ["setupJest.js"], - rules: { - "import/no-extraneous-dependencies": "off", - }, - }, - { - env: { - es6: true, - jest: true, - node: true, - }, - extends: ["plugin:jest/recommended", "plugin:jest/style"], - files: [ - // Test files - "**/*.spec.{js,ts,tsx}", - "**/*.test.{js,ts,tsx}", - "**/test/*.{js,ts,tsx}", - - // Facebook convention - "**/__mocks__/*.{js,ts,tsx}", - "**/__tests__/*.{js,ts,tsx}", - ], - globals: { - ...globals.jest, - }, - plugins: ["jest"], - rules: { - "@typescript-eslint/ban-ts-comment": "off", - - "@typescript-eslint/no-empty-function": "off", - - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-object-literal-type-assertion": "off", - // you should turn the original rule off *only* for test files - "@typescript-eslint/unbound-method": "off", - "import/default": "off", - // Relax rules that are known to be slow and less useful in a test context - "import/namespace": "off", - "import/no-duplicates": "off", - - // Relax rules that makes writing tests easier - "import/no-named-as-default-member": "off", - "jest/consistent-test-it": ["error", { fn: "it" }], - "jest/no-disabled-tests": "off", - "jest/no-duplicate-hooks": "error", - - "jest/no-test-return-statement": "error", - "jest/prefer-hooks-in-order": "error", - "jest/prefer-hooks-on-top": "error", - "jest/prefer-strict-equal": "error", - "jest/prefer-to-have-length": "error", - - // Disabled this rule because jest doc blocks clash with jsdoc/check-tag-names - "jsdoc/check-tag-names": "off", - }, - }, - ], -}; - -export default config; diff --git a/packages/eslint-config/src/config/plugins/jsdoc.ts b/packages/eslint-config/src/config/plugins/jsdoc.ts index 682aaa18f..281c769ed 100644 --- a/packages/eslint-config/src/config/plugins/jsdoc.ts +++ b/packages/eslint-config/src/config/plugins/jsdoc.ts @@ -1,31 +1,74 @@ -import { hasDependency, hasDevDependency, hasTypescript } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; - -import { consoleLog } from "../../utils/loggers"; - -if (global.anolilabEslintConfigJsDocRules === undefined && hasTypescript) { - if (hasDependency("eslint-plugin-tsdoc") || hasDevDependency("eslint-plugin-tsdoc")) { - consoleLog("\nFound eslint-plugin-tsdoc as dependency, disabling the jsdoc rules for *.ts and *.tsx files."); - } else { - global.anolilabEslintConfigJsDocRules = [ - { - extends: ["plugin:jsdoc/recommended-typescript-error"], - files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], - plugins: ["jsdoc"], - }, - ]; +import { hasPackageJsonAnyDependency } from "@visulima/package"; + +import type { + OptionsFiles, + OptionsPackageJson, + OptionsSilentConsoleLogs, + OptionsStylistic, + TypedFlatConfigItem, +} from "../../types"; +import { createConfig, getFilesGlobs } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig("js", async (config, oFiles) => { + const { + files = oFiles, + packageJson, + silent, + stylistic = true, + } = config; + + const jsdocPlugin = await interopDefault(import("eslint-plugin-jsdoc")); + + const hasTypescript = hasPackageJsonAnyDependency(packageJson, ["typescript"]); + const hasTsDocumentPlugin = hasPackageJsonAnyDependency(packageJson, ["eslint-plugin-tsdoc"]); + + if (hasTsDocumentPlugin && !silent) { + // eslint-disable-next-line no-console + console.info("\nFound eslint-plugin-tsdoc as dependency, disabling the jsdoc rules for *.ts and *.tsx files."); } -} -const config: Linter.Config = { - overrides: [ + const rules: TypedFlatConfigItem[] = [ { - extends: ["plugin:jsdoc/recommended-error"], - files: ["**/*.js", "**/*.jsx", "**/*.mjs", "**/*.cjs"], - plugins: ["jsdoc"], + name: "anolilab/jsdoc/setup", + plugins: { + jsdoc: jsdocPlugin, + }, }, - ...(global.anolilabEslintConfigJsDocRules ?? []), - ], -}; + { + files, + name: "anolilab/jsdoc/js-rules", + rules: { + ...jsdocPlugin.configs["flat/recommended-error"].rules, + + ...stylistic + ? { + "jsdoc/check-alignment": "warn", + "jsdoc/multiline-blocks": "warn", + } + : {}, + }, + }, + ]; + + if (hasTypescript && !hasTsDocumentPlugin) { + rules.push({ + files: getFilesGlobs("ts"), + name: "anolilab/jsdoc/ts-rules", + rules: { + ...jsdocPlugin.configs["flat/contents-typescript-error"].rules, + ...jsdocPlugin.configs["flat/logical-typescript-error"].rules, + ...jsdocPlugin.configs["flat/stylistic-typescript-error"].rules, + + ...stylistic + ? { + "jsdoc/check-alignment": "warn", + "jsdoc/multiline-blocks": "warn", + } + : {}, + }, + }); + } -export default config; + return rules; +}); diff --git a/packages/eslint-config/src/config/plugins/jsonc.ts b/packages/eslint-config/src/config/plugins/jsonc.ts index f17f7e755..c1ad1c5e1 100644 --- a/packages/eslint-config/src/config/plugins/jsonc.ts +++ b/packages/eslint-config/src/config/plugins/jsonc.ts @@ -1,120 +1,366 @@ -import { env } from "node:process"; - -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; +import { hasPackageJsonAnyDependency } from "@visulima/package"; import type { Linter } from "eslint"; -import anolilabEslintConfig from "../../utils/eslint-config"; -import { consoleLog } from "../../utils/loggers"; - -const extendedPlugins: string[] = []; +import type { + OptionsHasPrettier, + OptionsOverrides, + OptionsPackageJson, + OptionsSilentConsoleLogs, + OptionsStylistic, + TypedFlatConfigItem, +} from "../../types"; +import interopDefault from "../../utils/interop-default"; -if (hasDependency("prettier") || hasDevDependency("prettier")) { - extendedPlugins.push("plugin:jsonc/prettier"); -} +const jsonc = async ( + config: OptionsHasPrettier & OptionsOverrides & OptionsPackageJson & OptionsSilentConsoleLogs & OptionsStylistic, +): Promise => { + const { + overrides, + packageJson, + prettier, + silent, + stylistic = true, + } = config; + const { indent = 4 } = typeof stylistic === "boolean" ? {} : stylistic; -if (!global.hasAnolilabEsLintConfigJsoncPackageJsonSort && (hasDependency("sort-package-json") || hasDevDependency("sort-package-json"))) { - global.hasAnolilabEsLintConfigJsoncPackageJsonSort = true; + const jsoncPlugin = await interopDefault(import("eslint-plugin-jsonc")); - let showLog: boolean = env["DISABLE_INFO_ON_DISABLING_JSONC_SORT_KEYS_RULE"] !== "true"; + const hasSortPackageJson = hasPackageJsonAnyDependency(packageJson, ["sort-package-json"]); - if (showLog && anolilabEslintConfig["info_on_disabling_jsonc_sort_keys_rule"] !== undefined) { - showLog = anolilabEslintConfig["info_on_disabling_jsonc_sort_keys_rule"] as boolean; - } - - if (showLog) { - consoleLog(`\n@anolilab/eslint-config found "sort-package-json" package. \n + if (hasSortPackageJson && !silent) { + // eslint-disable-next-line no-console + console.info(`\n@anolilab/eslint-config found "sort-package-json" package. \n Following rules are disabled: jsonc/sort-keys for all package.json files. \n`); } -} -const config: Linter.Config = { - overrides: [ - { - extends: extendedPlugins, - files: ["**/*.json", "**/*.json5", "**/*.jsonc"], - parser: "jsonc-eslint-parser", - }, + return [ + ...jsoncPlugin.configs["flat/base"], { - extends: ["plugin:jsonc/recommended-with-json5"], files: ["**/*.json5"], + name: "anolilab/jsonc/json5-rules", + rules: (jsoncPlugin.configs["recommended-with-json5"] as Linter.Config).rules, }, { - extends: ["plugin:jsonc/recommended-with-jsonc"], files: ["**/*.jsonc"], + name: "anolilab/jsonc/jsonc-rules", + rules: (jsoncPlugin.configs["recommended-with-jsonc"] as Linter.Config).rules, }, { - extends: ["plugin:jsonc/recommended-with-json"], files: ["**/*.json"], + name: "anolilab/jsonc/json-rules", + rules: (jsoncPlugin.configs["recommended-with-json"] as Linter.Config).rules, }, { - extends: ["plugin:jsonc/recommended-with-json"], - files: ["package.json"], + files: ["package.json", "**/package.json"], + name: "anolilab/jsonc/package.json-rules", rules: { + "jsonc/sort-array-values": hasSortPackageJson + ? "off" + : [ + "error", + { + order: { type: "asc" }, + pathPattern: "^files$", + }, + ], + + // eslint-disable-next-line max-len // When the package "sort-package-json" is installed, we disable the rule "jsonc/sort-keys" because, the package "sort-package-json" is responsible for sorting the keys. - "jsonc/sort-keys": global.hasAnolilabEsLintConfigJsoncPackageJsonSort + "jsonc/sort-keys": hasSortPackageJson ? "off" : [ "error", { order: [ - "publisher", + "$schema", "name", "displayName", - "type", "version", "private", - "packageManager", "description", - "author", - "license", - "funding", + "categories", + "keywords", "homepage", - "repository", "bugs", - "keywords", - "categories", + "repository", + "funding", + "license", + "qna", + "author", + "maintainers", + "contributors", + "publisher", "sideEffects", + "type", + "imports", "exports", "main", - "module", - "unpkg", + "svelte", + "umd:main", "jsdelivr", + "unpkg", + "module", + "source", + "jsnext:main", + "browser", + "react-native", "types", "typesVersions", + "typings", + "style", + "example", + "examplestyle", + "assets", "bin", - "icon", + "man", + "directories", "files", - "engines", - "activationEvents", - "contributes", + "workspaces", + "binary", "scripts", - "peerDependencies", - "peerDependenciesMeta", - "dependencies", - "optionalDependencies", - "devDependencies", - "pnpm", - "overrides", - "resolutions", + "betterScripts", + "contributes", + "activationEvents", "husky", "simple-git-hooks", + "pre-commit", + "commitlint", "lint-staged", + "nano-staged", + "config", + "nodemonConfig", + "browserify", + "babel", + "browserslist", + "xo", + "prettier", "eslintConfig", + "eslintIgnore", + "npmpackagejsonlint", + "release", + "remarkConfig", + "stylelint", + "ava", + "jest", + "mocha", + "nyc", + "tap", + "oclif", + "resolutions", + "dependencies", + "devDependencies", + "dependenciesMeta", + "peerDependencies", + "peerDependenciesMeta", + "optionalDependencies", + "bundledDependencies", + "bundleDependencies", + "extensionPack", + "extensionDependencies", + "flat", + "packageManager", + "engines", + "engineStrict", + "volta", + "languageName", + "os", + "cpu", + "preferGlobal", + "publishConfig", + "icon", + "badges", + "galleryBanner", + "preview", + "markdown", + "pnpm", ], pathPattern: "^$", }, { order: { type: "asc" }, - pathPattern: "^(?:dev|peer|optional|bundled)?[Dd]ependencies$", + pathPattern: "^(?:dev|peer|optional|bundled)?[Dd]ependencies(Meta)?$", }, { - order: ["types", "require", "import"], + order: { type: "asc" }, + pathPattern: "^(?:resolutions|overrides|pnpm.overrides)$", + }, + { + order: ["types", "import", "require", "default"], pathPattern: "^exports.*$", }, + { + order: [ + "applypatch-msg", + "pre-applypatch", + "post-applypatch", + "pre-commit", + "pre-merge-commit", + "prepare-commit-msg", + "commit-msg", + "post-commit", + "pre-rebase", + "post-checkout", + "post-merge", + "pre-push", + "pre-receive", + "update", + "post-receive", + "post-update", + "push-to-checkout", + "pre-auto-gc", + "post-rewrite", + "sendemail-validate", + "fsmonitor-watchman", + "p4-pre-submit", + "post-index-chang", + ], + pathPattern: "^(?:gitHooks|husky|simple-git-hooks)$", + }, + { + order: ["build", "preinstall", "install", "postinstall", "lint", { order: { type: "asc" } }], + pathPattern: "^scripts$", + }, ], }, }, - ], + { + files: ["**/tsconfig.json", "**/tsconfig.*.json"], + name: "anolilab/jsonc/tsconfig-json", + rules: { + "jsonc/sort-keys": [ + "error", + { + order: ["extends", "compilerOptions", "references", "files", "include", "exclude"], + pathPattern: "^$", + }, + { + order: [ + /* Projects */ + "incremental", + "composite", + "tsBuildInfoFile", + "disableSourceOfProjectReferenceRedirect", + "disableSolutionSearching", + "disableReferencedProjectLoad", + /* Language and Environment */ + "target", + "jsx", + "jsxFactory", + "jsxFragmentFactory", + "jsxImportSource", + "lib", + "moduleDetection", + "noLib", + "reactNamespace", + "useDefineForClassFields", + "emitDecoratorMetadata", + "experimentalDecorators", + /* Modules */ + "baseUrl", + "rootDir", + "rootDirs", + "customConditions", + "module", + "moduleResolution", + "moduleSuffixes", + "noResolve", + "paths", + "resolveJsonModule", + "resolvePackageJsonExports", + "resolvePackageJsonImports", + "typeRoots", + "types", + "allowArbitraryExtensions", + "allowImportingTsExtensions", + "allowUmdGlobalAccess", + /* JavaScript Support */ + "allowJs", + "checkJs", + "maxNodeModuleJsDepth", + /* Type Checking */ + "strict", + "strictBindCallApply", + "strictFunctionTypes", + "strictNullChecks", + "strictPropertyInitialization", + "allowUnreachableCode", + "allowUnusedLabels", + "alwaysStrict", + "exactOptionalPropertyTypes", + "noFallthroughCasesInSwitch", + "noImplicitAny", + "noImplicitOverride", + "noImplicitReturns", + "noImplicitThis", + "noPropertyAccessFromIndexSignature", + "noUncheckedIndexedAccess", + "noUnusedLocals", + "noUnusedParameters", + "useUnknownInCatchVariables", + /* Emit */ + "declaration", + "declarationDir", + "declarationMap", + "downlevelIteration", + "emitBOM", + "emitDeclarationOnly", + "importHelpers", + "importsNotUsedAsValues", + "inlineSourceMap", + "inlineSources", + "mapRoot", + "newLine", + "noEmit", + "noEmitHelpers", + "noEmitOnError", + "outDir", + "outFile", + "preserveConstEnums", + "preserveValueImports", + "removeComments", + "sourceMap", + "sourceRoot", + "stripInternal", + /* Interop Constraints */ + "allowSyntheticDefaultImports", + "esModuleInterop", + "forceConsistentCasingInFileNames", + "isolatedDeclarations", + "isolatedModules", + "preserveSymlinks", + "verbatimModuleSyntax", + /* Completeness */ + "skipDefaultLibCheck", + "skipLibCheck", + ], + pathPattern: "^compilerOptions$", + }, + ], + }, + }, + ...prettier ? jsoncPlugin.configs["flat/prettier"] : [], + { + files: ["**/*.json", "**/*.jsonc", "**/*.json5"], + rules: { + ...stylistic + ? { + "jsonc/array-bracket-spacing": ["error", "never"], + "jsonc/comma-dangle": ["error", "never"], + "jsonc/comma-style": ["error", "last"], + "jsonc/indent": ["error", indent], + "jsonc/key-spacing": ["error", { afterColon: true, beforeColon: false }], + "jsonc/object-curly-newline": ["error", { consistent: true, multiline: true }], + "jsonc/object-curly-spacing": ["error", "always"], + "jsonc/object-property-newline": ["error", { allowMultiplePropertiesPerLine: true }], + "jsonc/quote-props": "error", + "jsonc/quotes": "error", + } + : {}, + + ...overrides, + }, + }, + ]; }; -export default config; +export default jsonc; diff --git a/packages/eslint-config/src/config/plugins/jsx-a11y.ts b/packages/eslint-config/src/config/plugins/jsx-a11y.ts index 4d5589b7e..00455dfb7 100644 --- a/packages/eslint-config/src/config/plugins/jsx-a11y.ts +++ b/packages/eslint-config/src/config/plugins/jsx-a11y.ts @@ -1,256 +1,268 @@ -import type { Linter } from "eslint"; - +import type { OptionsFiles, OptionsOverrides } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -const config: Linter.Config = createConfig("jsx_and_tsx", { - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - }, - - plugins: ["jsx-a11y"], - - rules: { - // Enforce that anchors have content - // disabled; rule is deprecated - "jsx-a11y/accessible-emoji": "off", - - // Require ARIA roles to be valid and non-abstract - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/alt-text.md - "jsx-a11y/alt-text": [ - "error", - { - area: [], - elements: ["img", "object", "area", 'input[type="image"]'], - img: [], - 'input[type="image"]': [], - object: [], - }, - ], - - // Enforce all aria-* props are valid. - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/anchor-has-content.md - "jsx-a11y/anchor-has-content": ["error", { components: [] }], - - // Enforce ARIA state and property values are valid. - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/anchor-is-valid.md - "jsx-a11y/anchor-is-valid": [ - "error", - { - aspects: ["noHref", "invalidHref", "preferButton"], - components: ["A", "LinkTo", "Link"], - specialLink: ["to"], - }, - ], - - // Enforce that elements that do not support ARIA roles, states, and - // properties do not have those attributes. - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-activedescendant-has-tabindex.md - "jsx-a11y/aria-activedescendant-has-tabindex": "error", - - // Enforce that all elements that require alternative text have meaningful information - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-props.md - "jsx-a11y/aria-props": "error", - - // Prevent img alt text from containing redundant words like "image", "picture", or "photo" - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-proptypes.md - "jsx-a11y/aria-proptypes": "error", - - // require that JSX labels use "htmlFor" - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-for.md - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-role.md - "jsx-a11y/aria-role": ["error", { ignoreNonDOM: false }], - - // Enforce that a label tag has a text label and an associated control. - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-unsupported-elements.md - "jsx-a11y/aria-unsupported-elements": "error", - - // Enforce that a control (an interactive element) has a text label. - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/29c68596b15c4ff0a40daae6d4a2670e36e37d35/docs/rules/autocomplete-valid.md - "jsx-a11y/autocomplete-valid": [ - "off", - { - inputComponents: [], - }, - ], - - // require that mouseover/out come with focus/blur, for keyboard-only users - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/click-events-have-key-events.md - "jsx-a11y/click-events-have-key-events": "error", - - // Prevent use of `accessKey` - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/control-has-associated-label.md - "jsx-a11y/control-has-associated-label": [ - "error", - { - controlComponents: [], - depth: 5, - ignoreElements: ["audio", "canvas", "embed", "input", "textarea", "tr", "video"], - ignoreRoles: ["grid", "listbox", "menu", "menubar", "radiogroup", "row", "tablist", "toolbar", "tree", "treegrid"], - labelAttributes: ["label"], - }, - ], - - // require onBlur instead of onChange - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/heading-has-content.md - "jsx-a11y/heading-has-content": ["error", { components: [""] }], - - // Elements with an interactive role and interaction handlers must be focusable - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/html-has-lang.md - "jsx-a11y/html-has-lang": "error", - - // Enforce that elements with ARIA roles must have all required attributes - // for that role. - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/iframe-has-title.md - "jsx-a11y/iframe-has-title": "error", - - // Enforce that elements with explicit or implicit roles defined contain - // only aria-* properties supported by that role. - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/img-redundant-alt.md - "jsx-a11y/img-redundant-alt": "error", - - // Enforce tabIndex value is not greater than zero. - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/interactive-supports-focus.md - "jsx-a11y/interactive-supports-focus": "error", - - // ensure tags have content and are not aria-hidden - // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/b800f40a2a69ad48015ae9226fbe879f946757ed/docs/rules/label-has-associated-control.md - "jsx-a11y/label-has-associated-control": [ - "error", - { - assert: "both", - controlComponents: [], - depth: 25, - labelAttributes: [], - labelComponents: [], - }, - ], - - // require HTML elements to have a "lang" prop - // deprecated: replaced by `label-has-associated-control` rule - "jsx-a11y/label-has-for": [ - "off", - { - allowChildren: false, - components: [], - required: { - every: ["nesting", "id"], +export default createConfig("jsx_and_tsx", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const jsxA11yPlugin = await interopDefault(import("eslint-plugin-jsx-a11y")); + + return [ + { + files, + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, }, }, - ], - - // require HTML element's lang prop to be valid - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/lang.md - "jsx-a11y/lang": "error", - - // prevent distracting elements, like and - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/media-has-caption.md - "jsx-a11y/media-has-caption": [ - "error", - { - audio: [], - track: [], - video: [], - }, - ], - - // only allow to have the "scope" attr - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/mouse-events-have-key-events.md - "jsx-a11y/mouse-events-have-key-events": "error", - - // require onClick be accompanied by onKeyUp/onKeyDown/onKeyPress - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-access-key.md - "jsx-a11y/no-access-key": "error", - - // Enforce that DOM elements without semantic behavior not have interaction handlers - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-autofocus.md - "jsx-a11y/no-autofocus": ["error", { ignoreNonDOM: true }], - - // A non-interactive element does not support event handlers (mouse and key handlers) - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-distracting-elements.md - "jsx-a11y/no-distracting-elements": [ - "error", - { - elements: ["marquee", "blink"], + name: "anolilab/jsx-a11y/setup", + plugins: { + "jsx-a11y": jsxA11yPlugin, }, - ], - - // ensure emoji are accessible - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/accessible-emoji.md - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-interactive-element-to-noninteractive-role.md - "jsx-a11y/no-interactive-element-to-noninteractive-role": [ - "error", - { - tr: ["none", "presentation"], + rules: { + // Enforce that anchors have content + // disabled; rule is deprecated + "jsx-a11y/accessible-emoji": "off", + + // Require ARIA roles to be valid and non-abstract + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/alt-text.md + "jsx-a11y/alt-text": [ + "error", + { + area: [], + elements: ["img", "object", "area", "input[type=\"image\"]"], + img: [], + "input[type=\"image\"]": [], + object: [], + }, + ], + + // Enforce all aria-* props are valid. + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/anchor-has-content.md + "jsx-a11y/anchor-has-content": ["error", { components: [] }], + + // Enforce ARIA state and property values are valid. + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/anchor-is-valid.md + "jsx-a11y/anchor-is-valid": [ + "error", + { + aspects: ["noHref", "invalidHref", "preferButton"], + components: ["A", "LinkTo", "Link"], + specialLink: ["to"], + }, + ], + + // Enforce that elements that do not support ARIA roles, states, and + // properties do not have those attributes. + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-activedescendant-has-tabindex.md + "jsx-a11y/aria-activedescendant-has-tabindex": "error", + + // Enforce that all elements that require alternative text have meaningful information + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-props.md + "jsx-a11y/aria-props": "error", + + // Prevent img alt text from containing redundant words like "image", "picture", or "photo" + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-proptypes.md + "jsx-a11y/aria-proptypes": "error", + + // require that JSX labels use "htmlFor" + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-for.md + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-role.md + "jsx-a11y/aria-role": ["error", { ignoreNonDOM: false }], + + // Enforce that a label tag has a text label and an associated control. + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-unsupported-elements.md + "jsx-a11y/aria-unsupported-elements": "error", + + // Enforce that a control (an interactive element) has a text label. + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/29c68596b15c4ff0a40daae6d4a2670e36e37d35/docs/rules/autocomplete-valid.md + "jsx-a11y/autocomplete-valid": [ + "off", + { + inputComponents: [], + }, + ], + + // require that mouseover/out come with focus/blur, for keyboard-only users + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/click-events-have-key-events.md + "jsx-a11y/click-events-have-key-events": "error", + + // Prevent use of `accessKey` + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/control-has-associated-label.md + "jsx-a11y/control-has-associated-label": [ + "error", + { + controlComponents: [], + depth: 5, + ignoreElements: ["audio", "canvas", "embed", "input", "textarea", "tr", "video"], + ignoreRoles: ["grid", "listbox", "menu", "menubar", "radiogroup", "row", "tablist", "toolbar", "tree", "treegrid"], + labelAttributes: ["label"], + }, + ], + + // require onBlur instead of onChange + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/heading-has-content.md + "jsx-a11y/heading-has-content": ["error", { components: [""] }], + + // Elements with an interactive role and interaction handlers must be focusable + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/html-has-lang.md + "jsx-a11y/html-has-lang": "error", + + // Enforce that elements with ARIA roles must have all required attributes + // for that role. + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/iframe-has-title.md + "jsx-a11y/iframe-has-title": "error", + + // Enforce that elements with explicit or implicit roles defined contain + // only aria-* properties supported by that role. + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/img-redundant-alt.md + "jsx-a11y/img-redundant-alt": "error", + + // Enforce tabIndex value is not greater than zero. + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/interactive-supports-focus.md + "jsx-a11y/interactive-supports-focus": "error", + + // ensure tags have content and are not aria-hidden + // https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/b800f40a2a69ad48015ae9226fbe879f946757ed/docs/rules/label-has-associated-control.md + "jsx-a11y/label-has-associated-control": [ + "error", + { + assert: "both", + controlComponents: [], + depth: 25, + labelAttributes: [], + labelComponents: [], + }, + ], + + // require HTML elements to have a "lang" prop + // deprecated: replaced by `label-has-associated-control` rule + "jsx-a11y/label-has-for": [ + "off", + { + allowChildren: false, + components: [], + required: { + every: ["nesting", "id"], + }, + }, + ], + + // require HTML element's lang prop to be valid + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/lang.md + "jsx-a11y/lang": "error", + + // prevent distracting elements, like and + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/media-has-caption.md + "jsx-a11y/media-has-caption": [ + "error", + { + audio: [], + track: [], + video: [], + }, + ], + + // only allow to have the "scope" attr + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/mouse-events-have-key-events.md + "jsx-a11y/mouse-events-have-key-events": "error", + + // require onClick be accompanied by onKeyUp/onKeyDown/onKeyPress + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-access-key.md + "jsx-a11y/no-access-key": "error", + + // Enforce that DOM elements without semantic behavior not have interaction handlers + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-autofocus.md + "jsx-a11y/no-autofocus": ["error", { ignoreNonDOM: true }], + + // A non-interactive element does not support event handlers (mouse and key handlers) + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-distracting-elements.md + "jsx-a11y/no-distracting-elements": [ + "error", + { + elements: ["marquee", "blink"], + }, + ], + + // ensure emoji are accessible + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/accessible-emoji.md + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-interactive-element-to-noninteractive-role.md + "jsx-a11y/no-interactive-element-to-noninteractive-role": [ + "error", + { + tr: ["none", "presentation"], + }, + ], + + // elements with aria-activedescendant must be tabbable + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-noninteractive-element-interactions.md + "jsx-a11y/no-noninteractive-element-interactions": [ + "error", + { + handlers: ["onClick", "onMouseDown", "onMouseUp", "onKeyPress", "onKeyDown", "onKeyUp"], + }, + ], + + // ensure iframe elements have a unique title + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-noninteractive-element-to-interactive-role.md + "jsx-a11y/no-noninteractive-element-to-interactive-role": [ + "error", + { + li: ["menuitem", "option", "row", "tab", "treeitem"], + ol: ["listbox", "menu", "menubar", "radiogroup", "tablist", "tree", "treegrid"], + table: ["grid"], + td: ["gridcell"], + ul: ["listbox", "menu", "menubar", "radiogroup", "tablist", "tree", "treegrid"], + }, + ], + + // prohibit autoFocus prop + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-noninteractive-tabindex.md + "jsx-a11y/no-noninteractive-tabindex": [ + "error", + { + roles: ["tabpanel"], + tags: [], + }, + ], + + // ensure HTML elements do not specify redundant ARIA roles + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-onchange.md + "jsx-a11y/no-onchange": "off", + + // media elements must have captions + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-redundant-roles.md + "jsx-a11y/no-redundant-roles": "error", + + // WAI-ARIA roles should not be used to convert an interactive element to non-interactive + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-static-element-interactions.md + "jsx-a11y/no-static-element-interactions": [ + "error", + { + handlers: ["onClick", "onMouseDown", "onMouseUp", "onKeyPress", "onKeyDown", "onKeyUp"], + }, + ], + + // WAI-ARIA roles should not be used to convert a non-interactive element to interactive + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/role-has-required-aria-props.md + "jsx-a11y/role-has-required-aria-props": "error", + + // Tab key navigation should be limited to elements on the page that can be interacted with. + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/role-supports-aria-props.md + "jsx-a11y/role-supports-aria-props": "error", + + // ensure tags are valid + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/scope.md + "jsx-a11y/scope": "error", + + // Ensure the autocomplete attribute is correct and suitable for the form field it is used with + // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/tabindex-no-positive.md + "jsx-a11y/tabindex-no-positive": "error", + + ...overrides, }, - ], - - // elements with aria-activedescendant must be tabbable - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-noninteractive-element-interactions.md - "jsx-a11y/no-noninteractive-element-interactions": [ - "error", - { - handlers: ["onClick", "onMouseDown", "onMouseUp", "onKeyPress", "onKeyDown", "onKeyUp"], - }, - ], - - // ensure iframe elements have a unique title - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-noninteractive-element-to-interactive-role.md - "jsx-a11y/no-noninteractive-element-to-interactive-role": [ - "error", - { - li: ["menuitem", "option", "row", "tab", "treeitem"], - ol: ["listbox", "menu", "menubar", "radiogroup", "tablist", "tree", "treegrid"], - table: ["grid"], - td: ["gridcell"], - ul: ["listbox", "menu", "menubar", "radiogroup", "tablist", "tree", "treegrid"], - }, - ], - - // prohibit autoFocus prop - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-noninteractive-tabindex.md - "jsx-a11y/no-noninteractive-tabindex": [ - "error", - { - roles: ["tabpanel"], - tags: [], - }, - ], - - // ensure HTML elements do not specify redundant ARIA roles - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-onchange.md - "jsx-a11y/no-onchange": "off", - - // media elements must have captions - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-redundant-roles.md - "jsx-a11y/no-redundant-roles": "error", - - // WAI-ARIA roles should not be used to convert an interactive element to non-interactive - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/no-static-element-interactions.md - "jsx-a11y/no-static-element-interactions": [ - "error", - { - handlers: ["onClick", "onMouseDown", "onMouseUp", "onKeyPress", "onKeyDown", "onKeyUp"], - }, - ], - - // WAI-ARIA roles should not be used to convert a non-interactive element to interactive - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/role-has-required-aria-props.md - "jsx-a11y/role-has-required-aria-props": "error", - - // Tab key navigation should be limited to elements on the page that can be interacted with. - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/role-supports-aria-props.md - "jsx-a11y/role-supports-aria-props": "error", - - // ensure tags are valid - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/scope.md - "jsx-a11y/scope": "error", - - // Ensure the autocomplete attribute is correct and suitable for the form field it is used with - // https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/tabindex-no-positive.md - "jsx-a11y/tabindex-no-positive": "error", - }, + }, + ]; }); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/markdown.ts b/packages/eslint-config/src/config/plugins/markdown.ts index 478df014b..a37243781 100644 --- a/packages/eslint-config/src/config/plugins/markdown.ts +++ b/packages/eslint-config/src/config/plugins/markdown.ts @@ -1,56 +1,85 @@ -import type { Linter } from "eslint"; +import { mergeProcessors, processorPassThrough } from "eslint-merge-processors"; -import { createConfigs } from "../../utils/create-config"; +import type { OptionsComponentExtensions, OptionsFiles, OptionsOverrides } from "../../types"; +import { createConfig, getFilesGlobs } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; +import parserPlain from "../../utils/parser-plain"; -const config: Linter.Config = createConfigs([ - { - config: { - extends: "plugin:markdown/recommended", - plugins: ["markdown"], - processor: "markdown/markdown", - rules: { - "no-cond-assign": "off", +export default createConfig("markdown", async (config, oFiles) => { + const { componentExts: componentExtensions = [], files = oFiles, overrides } = config; + + const markdown = await interopDefault(import("@eslint/markdown")); + + return [ + { + name: "anolilab/markdown/setup", + plugins: { + markdown, + }, + }, + { + files, + ignores: getFilesGlobs("markdown_in_markdown"), + name: "anolilab/markdown/processor", + // `eslint-plugin-markdown` only creates virtual files for code blocks, + // but not the markdown file itself. We use `eslint-merge-processors` to + // add a pass-through processor for the markdown file itself. + processor: mergeProcessors([markdown.processors?.markdown, processorPassThrough]), + }, + { + files, + languageOptions: { + parser: parserPlain, }, + name: "anolilab/markdown/parser", + rules: markdown.configs.recommended[0].rules, }, - type: "markdown", - }, - { - config: { - extends: "plugin:markdown/recommended", - parserOptions: { - ecmacFeatures: { - impliedStrict: true, + { + files: ["**/*.md/**/*.?([cm])[jt]s?(x)", ...componentExtensions.map(extension => `**/*.md/**/*.${extension}`)], + languageOptions: { + parserOptions: { + ecmaFeatures: { + impliedStrict: true, + }, }, }, - plugins: ["markdown"], - processor: "markdown/markdown", + name: "anolilab/markdown/disables", rules: { - "@typescript-eslint/comma-dangle": "off", + "@stylistic/comma-dangle": "off", + "@stylistic/eol-last": "off", + "@stylistic/prefer-global/process": "off", + + "@typescript-eslint/consistent-type-imports": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-namespace": "off", "@typescript-eslint/no-redeclare": "off", + "@typescript-eslint/no-require-imports": "off", + "@typescript-eslint/no-unused-expressions": "off", "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/no-var-requires": "off", - "global-require": "off", + "antfu/no-top-level-await": "off", - "import/no-unresolved": "off", - "import/order": "off", + "import/newline-after-import": "off", "no-alert": "off", "no-console": "off", - "no-restricted-imports": "off", + "no-labels": "off", + "no-lone-blocks": "off", + "no-restricted-syntax": "off", "no-undef": "off", + "no-unused-expressions": "off", + + "no-unused-labels": "off", "no-unused-vars": "off", - "prefer-reflect": "off", - "sonar/no-dead-store": "off", + "unicode-bom": "off", + "unused-imports/no-unused-imports": "off", + "unused-imports/no-unused-vars": "off", - strict: "off", + ...overrides, }, }, - type: "markdown_inline_js_jsx", - }, -]); - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/mdx.ts b/packages/eslint-config/src/config/plugins/mdx.ts deleted file mode 100644 index a2f2f426c..000000000 --- a/packages/eslint-config/src/config/plugins/mdx.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -// @see https://github.com/mdx-js/eslint-mdx/tree/master/packages/eslint-plugin-mdx -const config: Linter.Config = createConfig("mdx", { - extends: ["plugin:mdx/recommended"], - parser: "eslint-mdx", - parserOptions: { - ecmaVersion: "latest", - }, - processor: "mdx/remark", - rules: { - "@typescript-eslint/comma-dangle": "off", - "@typescript-eslint/no-redeclare": "off", - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/no-var-requires": "off", - - "global-require": "off", - - "import/namespace": "off", - - "import/no-extraneous-dependencies": "off", - "import/no-unresolved": "off", - "import/order": "off", - "no-alert": "off", - - "no-console": "off", - "no-restricted-imports": "off", - "no-undef": "off", - "no-unused-expressions": "off", - "no-unused-vars": "off", - "prefer-reflect": "off", - - "react/jsx-no-undef": "off", - "react-hooks/rules-of-hooks": "off", - - "sonar/no-dead-store": "off", - }, - settings: { - "mdx/code-blocks": true, - }, -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/no-extend-native.ts b/packages/eslint-config/src/config/plugins/no-extend-native.ts deleted file mode 100644 index fa905eb68..000000000 --- a/packages/eslint-config/src/config/plugins/no-extend-native.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Linter } from "eslint"; - -// @see https://github.com/dustinspecker/eslint-plugin-no-use-extend-native -const config: Linter.Config = { - plugins: ["no-use-extend-native"], - rules: { - "no-use-extend-native/no-use-extend-native": "error", - }, -}; - -export default config; diff --git a/packages/eslint-config/src/config/plugins/no-loops.ts b/packages/eslint-config/src/config/plugins/no-loops.ts deleted file mode 100644 index a9f9e8834..000000000 --- a/packages/eslint-config/src/config/plugins/no-loops.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Linter } from "eslint"; - -// @see https://github.com/buildo/eslint-plugin-no-loops -const config: Linter.Config = { - plugins: ["no-loops"], - rules: { - "no-loops/no-loops": 2, - }, -}; - -export default config; diff --git a/packages/eslint-config/src/config/plugins/no-only-tests.ts b/packages/eslint-config/src/config/plugins/no-only-tests.ts deleted file mode 100644 index 277eab500..000000000 --- a/packages/eslint-config/src/config/plugins/no-only-tests.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; -import isInEditor from "../../utils/is-in-editor"; - -// @see https://github.com/francoismassart/eslint-plugin-tailwindcss, -const config: Linter.Config = createConfig("tests", { - plugins: ["no-only-tests"], - rules: { - "no-only-tests/no-only-tests": isInEditor ? "off" : "error", - }, -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/no-secrets.ts b/packages/eslint-config/src/config/plugins/no-secrets.ts index d2df0f010..bf9389512 100644 --- a/packages/eslint-config/src/config/plugins/no-secrets.ts +++ b/packages/eslint-config/src/config/plugins/no-secrets.ts @@ -1,17 +1,28 @@ -import type { Linter } from "eslint"; +import type { OptionsOverrides, TypedFlatConfigItem } from "../../types"; +import interopDefault from "../../utils/interop-default"; // @see https://github.com/nickdeis/eslint-plugin-no-secrets -const config: Linter.Config = { - overrides: [ +const noSecrets = async (config: OptionsOverrides): Promise => { + const noSecretsPlugin = await interopDefault(import("eslint-plugin-no-secrets")); + + return [ { - excludedFiles: ["package.json", "**/package.json", "package-lock.json", "**/package-lock.json", "tsconfig.json", "**/tsconfig.json"], files: ["*", "*/**"], - plugins: ["no-secrets"], + ignores: ["package.json", "**/package.json", "package-lock.json", "**/package-lock.json", "tsconfig.json", "**/tsconfig.json"], + languageOptions: { + ecmaVersion: 6, + }, + name: "anolilab/no-secrets", + plugins: { + "no-secrets": noSecretsPlugin, + }, rules: { "no-secrets/no-secrets": "error", + + ...config.overrides, }, }, - ], + ]; }; -export default config; +export default noSecrets; diff --git a/packages/eslint-config/src/config/plugins/no-unsanitized.ts b/packages/eslint-config/src/config/plugins/no-unsanitized.ts index f91adc869..bb278663d 100644 --- a/packages/eslint-config/src/config/plugins/no-unsanitized.ts +++ b/packages/eslint-config/src/config/plugins/no-unsanitized.ts @@ -1,12 +1,26 @@ -import type { Linter } from "eslint"; +import type { OptionsFiles, OptionsOverrides } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; // @see https://github.com/mozilla/eslint-plugin-no-unsanitized -const config: Linter.Config = { - plugins: ["no-unsanitized"], - rules: { - "no-unsanitized/method": "error", - "no-unsanitized/property": "error", - }, -}; - -export default config; +export default createConfig("js", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const noUnsanitizedPlugin = await interopDefault(import("eslint-plugin-no-unsanitized")); + + return [ + { + files, + name: "anolilab/no-unsanitized/setup", + plugins: { + "no-unsanitized": noUnsanitizedPlugin, + }, + rules: { + "no-unsanitized/method": "error", + "no-unsanitized/property": "error", + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/node.ts b/packages/eslint-config/src/config/plugins/node.ts index 8d73a38c6..497803111 100644 --- a/packages/eslint-config/src/config/plugins/node.ts +++ b/packages/eslint-config/src/config/plugins/node.ts @@ -1,93 +1,103 @@ -import { pkg } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; +import type { OptionsFiles, OptionsOverrides, OptionsPackageJson } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -if (global.anolilabEslintConfigNodeRules === undefined && pkg?.engines?.["node"]) { - const version: string = pkg.engines["node"]; +// @see https://github.com/eslint-community/eslint-plugin-n +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides, packageJson } = config; - global.anolilabEslintConfigNodeRules = { - "n/no-unsupported-features/es-builtins": ["error", { version }], - "n/no-unsupported-features/es-syntax": ["error", { ignores: ["modules"], version }], - "n/no-unsupported-features/node-builtins": ["error", { version }], - }; -} + const pluginNode = await interopDefault(import("eslint-plugin-n")); -// @see https://github.com/eslint-community/eslint-plugin-n -const config: Linter.Config = { - env: { - node: true, - }, - extends: ["plugin:n/recommended"], - parserOptions: { - ecmaVersion: 2021, - }, - plugins: ["n"], - rules: { - // https://eslint.org/docs/rules/global-require - "global-require": "error", - // enforce return after a callback - "n/callback-return": "off", - - // enforce the style of file extensions in import declarations - // This rule is buggy @see https://github.com/eslint-community/eslint-plugin-n/issues/21 - "n/file-extension-in-import": "off", - - // enforces error handling in callbacks (node environment) - "n/handle-callback-err": "off", - - // Redundant with `import/no-extraneous-dependencies`. - "n/no-extraneous-import": "off", - - // disallow require() expressions which import extraneous modules - "n/no-extraneous-require": "off", - - // require all requires be top-level - // Redundant with `import/no-unresolved`. - "n/no-missing-import": "off", // This rule is also buggy and doesn't support `node:`. - - // disallow require() expressions which import non-existence modules - "n/no-missing-require": "off", - - // disallow use of the Buffer() constructor - // disallow mixing regular variable and require declarations - "n/no-mixed-requires": [ - "error", - { - allowCall: true, - grouping: true, + const nodeVersion = packageJson?.engines?.["node"]; + + return [ + { + name: "anolilab/node/setup", + plugins: { + n: pluginNode, }, - ], + }, + { + files, + name: "anolilab/node/rules", + rules: { + ...pluginNode.configs.recommended.rules, + + // https://eslint.org/docs/rules/global-require + "global-require": "error", + + // enforce return after a callback + "n/callback-return": "off", + + // enforce the style of file extensions in import declarations + // This rule is buggy @see https://github.com/eslint-community/eslint-plugin-n/issues/21 + "n/file-extension-in-import": "off", + + // enforces error handling in callbacks (node environment) + "n/handle-callback-err": "off", - // disallow use of new operator with the require function - "n/no-new-require": "error", + // Redundant with `import/no-extraneous-dependencies`. + "n/no-extraneous-import": "off", - // disallow use of process.env - "n/no-process-env": "off", + // disallow require() expressions which import extraneous modules + "n/no-extraneous-require": "off", - // disallow string concatenation with __dirname and __filename - // unicorn/no-process-exit is enabled instead. - "n/no-process-exit": "off", + // require all requires be top-level + // Redundant with `import/no-unresolved`. + "n/no-missing-import": "off", // This rule is also buggy and doesn't support `node:`. - // restrict usage of specified node modules - "n/no-restricted-modules": "off", + // disallow require() expressions which import non-existence modules + "n/no-missing-require": "off", - // disallow process.exit() - // disallow use of synchronous methods (off by default) - "n/no-sync": "off", + // disallow use of the Buffer() constructor + // disallow mixing regular variable and require declarations + "n/no-mixed-requires": [ + "error", + { + allowCall: true, + grouping: true, + }, + ], - // disallow bin files that npm ignores - "n/no-unpublished-bin": "error", + // disallow use of new operator with the require function + "n/no-new-require": "error", - // require that process.exit() expressions use the same code path as throw - "n/process-exit-as-throw": "error", + // disallow use of process.env + "n/no-process-env": "off", - // https://eslint.org/docs/rules/no-buffer-constructor - "no-buffer-constructor": "error", + // disallow string concatenation with __dirname and __filename + // unicorn/no-process-exit is enabled instead. + "n/no-process-exit": "off", - // https://eslint.org/docs/rules/no-path-concat - "no-path-concat": "error", + // restrict usage of specified node modules + "n/no-restricted-modules": "off", - ...global.anolilabEslintConfigNodeRules, - }, -}; + // disallow process.exit() + // disallow use of synchronous methods (off by default) + "n/no-sync": "off", -export default config; + // disallow bin files that npm ignores + "n/no-unpublished-bin": "error", + + // require that process.exit() expressions use the same code path as throw + "n/process-exit-as-throw": "error", + + // https://eslint.org/docs/rules/no-buffer-constructor + "no-buffer-constructor": "error", + + // https://eslint.org/docs/rules/no-path-concat + "no-path-concat": "error", + + ...nodeVersion + ? { + "n/no-unsupported-features/es-builtins": ["error", { version: nodeVersion }], + "n/no-unsupported-features/es-syntax": ["error", { ignores: ["modules"], version: nodeVersion }], + "n/no-unsupported-features/node-builtins": ["error", { version: nodeVersion }], + } + : {}, + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/perfectionist.ts b/packages/eslint-config/src/config/plugins/perfectionist.ts index 4a6b28631..df7407751 100644 --- a/packages/eslint-config/src/config/plugins/perfectionist.ts +++ b/packages/eslint-config/src/config/plugins/perfectionist.ts @@ -1,55 +1,60 @@ -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; +import { hasPackageJsonAnyDependency } from "@visulima/package"; -import { createConfigs } from "../../utils/create-config"; -import { consoleLog } from "../../utils/loggers"; +import type { OptionsFiles, OptionsOverrides, OptionsPackageJson } from "../../types"; +import { createConfig, getFilesGlobs } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -if ( - !global.hasAnolilabEsLintConfigPerfectionistTypescriptSortKeys && - (hasDependency("eslint-plugin-typescript-sort-keys") || hasDevDependency("eslint-plugin-typescript-sort-keys")) -) { - global.hasAnolilabEsLintConfigPerfectionistTypescriptSortKeys = true; +// @see https://github.com/azat-io/eslint-plugin-perfectionist +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides, packageJson } = config; - consoleLog('\nPlease remove "eslint-plugin-typescript-sort-keys" from your package.json, it conflicts with "eslint-plugin-perfectionist".\n'); -} + const pluginPerfectionist = await interopDefault(import("eslint-plugin-perfectionist")); -// @see https://github.com/azat-io/eslint-plugin-perfectionist -const config: Linter.Config = createConfigs([ - { - config: { - extends: ["plugin:perfectionist/recommended-natural"], - plugins: ["perfectionist"], + if (hasPackageJsonAnyDependency(packageJson, ["eslint-plugin-typescript-sort-keys"])) { + // eslint-disable-next-line no-console + console.warn("\nPlease remove \"eslint-plugin-typescript-sort-keys\" from your package.json, it conflicts with \"eslint-plugin-perfectionist\".\n"); + } + + return [ + { + name: "anolilab/perfectionist/setup", + plugins: { + perfectionist: pluginPerfectionist, + }, + }, + { + files, + name: "anolilab/perfectionist/rules", rules: { + ...pluginPerfectionist.configs["recommended-natural"].rules, + // Disabled because of sort-imports "perfectionist/sort-imports": "off", - // Disabled because of @typescript-eslint/sort-type-constituents - "perfectionist/sort-union-types": "off", + // Disabled because of simple-import-sort/exports + "perfectionist/sort-named-exports": "off", // Disabled because of simple-import-sort/imports "perfectionist/sort-named-imports": "off", - // Disabled because of simple-import-sort/exports - "perfectionist/sort-named-exports": "off", + // Disabled because of @typescript-eslint/sort-type-constituents + "perfectionist/sort-union-types": "off", + + ...overrides, }, }, - type: "all", - }, - { - config: { + { + files: getFilesGlobs("ts"), + name: "anolilab/perfectionist/typescript", rules: { // Disabled because of @typescript-eslint/member-ordering "perfectionist/sort-classes": "off", }, }, - type: "typescript", - }, - { - config: { + { + files: getFilesGlobs("postcss"), + name: "anolilab/perfectionist/postcss", rules: { "perfectionist/sort-objects": "off", }, }, - type: "postcss", - }, -]); - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/playwright.ts b/packages/eslint-config/src/config/plugins/playwright.ts index ebc042dd2..b118ea3a4 100644 --- a/packages/eslint-config/src/config/plugins/playwright.ts +++ b/packages/eslint-config/src/config/plugins/playwright.ts @@ -1,37 +1,22 @@ -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; +import type { OptionsFiles, OptionsOverrides } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -if ( - !global.hasAnolilabEsLintConfigPlaywrightJest && - (hasDependency("jest") || - hasDevDependency("jest") || - hasDevDependency("eslint-plugin-jest") || - hasDevDependency("eslint-plugin-jest") || - hasDevDependency("@types/jest") || - hasDevDependency("@types/jest")) -) { - global.hasAnolilabEsLintConfigPlaywrightJest = true; -} +export default createConfig("e2e", async (config, oFiles) => { + const { files = oFiles, overrides } = config; -// @see https://github.com/playwright-community/eslint-plugin-playwright -const config: Linter.Config = { - env: { - browser: true, - es6: true, - node: true, - }, - overrides: [ + const pluginPlaywright = await interopDefault(import("eslint-plugin-playwright")); + + return [ { - extends: [global.hasAnolilabEsLintConfigPlaywrightJest ? "plugin:playwright/jest-playwright" : "plugin:playwright/recommended"], - // To ensure best performance enable only on e2e test files - files: ["**/e2e/**/*.test.{js,ts}"], + files, + plugins: { + playwright: pluginPlaywright, + }, rules: { - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-object-literal-type-assertion": "off", + ...pluginPlaywright.configs["recommended"].rules, + ...overrides, }, }, - ], -}; - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/promise.ts b/packages/eslint-config/src/config/plugins/promise.ts index 146d6eb72..77c5dd0da 100644 --- a/packages/eslint-config/src/config/plugins/promise.ts +++ b/packages/eslint-config/src/config/plugins/promise.ts @@ -1,13 +1,29 @@ -import type { Linter } from "eslint"; +import { fixupPluginRules } from "@eslint/compat"; + +import type { OptionsFiles, OptionsOverrides } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; // @see https://github.com/xjamundx/eslint-plugin-promise#readme -const config: Linter.Config = { - extends: ["plugin:promise/recommended"], - plugins: ["promise"], - rules: { - "promise/prefer-await-to-callbacks": "off", - "promise/prefer-await-to-then": "off", - }, -}; - -export default config; +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const promisesPlugin = await interopDefault(import("eslint-plugin-promise")); + + return [ + { + files, + name: "anolilab/promise/rules", + plugins: { + promise: promisesPlugin, + }, + rules: { + ...fixupPluginRules(promisesPlugin.configs["flat/recommended"].rules), + + "promise/prefer-await-to-callbacks": "off", + "promise/prefer-await-to-then": "off", + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/react-hooks.ts b/packages/eslint-config/src/config/plugins/react-hooks.ts deleted file mode 100644 index eceda5867..000000000 --- a/packages/eslint-config/src/config/plugins/react-hooks.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -// @see https://github.com/yannickcr/eslint-plugin-react -const config: Linter.Config = createConfig("jsx_and_tsx", { - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - }, - plugins: ["react-hooks"], - rules: { - // Enforce Rules of Hooks - // https://github.com/facebook/react/blob/1204c789776cb01fbaf3e9f032e7e2ba85a44137/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js - "react-hooks/exhaustive-deps": "error", - - // Verify the list of the dependencies for Hooks like useEffect and similar - // https://github.com/facebook/react/blob/c11015ff4f610ac2924d1fc6d569a17657a404fd/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js - "react-hooks/rules-of-hooks": "error", - }, -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/react-redux.ts b/packages/eslint-config/src/config/plugins/react-redux.ts deleted file mode 100644 index 311167c6b..000000000 --- a/packages/eslint-config/src/config/plugins/react-redux.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -// @see https://github.com/DianaSuvorova/eslint-plugin-react-redux#readme -const config: Linter.Config = createConfig("jsx_and_tsx", { - extends: ["plugin:react-redux/recommended"], - plugins: ["react-redux"], - rules: { - "react-redux/mapStateToProps-prefer-selectors": "off", - "react-redux/prefer-separate-component-file": "off", - }, -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/react-usememo.ts b/packages/eslint-config/src/config/plugins/react-usememo.ts deleted file mode 100644 index 4bcf587fc..000000000 --- a/packages/eslint-config/src/config/plugins/react-usememo.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -// @see https://www.npmjs.com/package/@arthurgeron/eslint-plugin-react-usememo -const config: Linter.Config = createConfig("jsx_and_tsx", { - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - }, - plugins: ["@arthurgeron/react-usememo"], - rules: { - "@arthurgeron/react-usememo/require-usememo": "error", - }, -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/react.ts b/packages/eslint-config/src/config/plugins/react.ts index ac50026f1..e10f8f64e 100644 --- a/packages/eslint-config/src/config/plugins/react.ts +++ b/packages/eslint-config/src/config/plugins/react.ts @@ -1,108 +1,132 @@ -// @see https://github.com/yannickcr/eslint-plugin-react -import { env } from "node:process"; - -import { getPackageSubProperty, hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; -import findUp from "find-up"; +import { hasPackageJsonAnyDependency } from "@visulima/package"; +import { readTsConfig } from "@visulima/tsconfig"; import { parse } from "semver"; -import anolilabEslintConfig from "../../utils/eslint-config"; -import indent from "../../utils/indent"; -import { consoleLog } from "../../utils/loggers"; -import styleConfig from "../style"; - -// @ts-expect-error TODO: find the correct type -const styleRules = styleConfig.overrides[0].rules as Linter.RulesRecord; -const dangleRules = styleRules["no-underscore-dangle"] as Linter.RuleEntry; - -if (!global.hasAnolilabEsLintConfigPrettier && (hasDependency("prettier") || hasDevDependency("prettier"))) { - global.hasAnolilabEsLintConfigPrettier = true; -} - -if (global.anolilabEslintConfigReactPrettierRules === undefined && global.hasAnolilabEsLintConfigPrettier) { - global.anolilabEslintConfigReactPrettierRules = { - "react/jsx-child-element-spacing": "off", - "react/jsx-closing-bracket-location": "off", - "react/jsx-closing-tag-location": "off", - "react/jsx-curly-newline": "off", - "react/jsx-curly-spacing": "off", - "react/jsx-equals-spacing": "off", - "react/jsx-first-prop-new-line": "off", - "react/jsx-indent": "off", - "react/jsx-indent-props": "off", - "react/jsx-max-props-per-line": "off", - "react/jsx-newline": "off", - "react/jsx-one-expression-per-line": "off", - "react/jsx-props-no-multi-spaces": "off", - "react/jsx-tag-spacing": "off", - "react/jsx-wrap-multilines": "off", +import type { + OptionsFiles, + OptionsHasPrettier, + OptionsOverrides, + OptionsPackageJson, + OptionsSilentConsoleLogs, + OptionsStylistic, + OptionsTypeScriptParserOptions, + OptionsTypeScriptWithTypes, + TypedFlatConfigItem, +} from "../../types"; +import { createConfig, getFilesGlobs } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; +import { noUnderscoreDangle } from "../style"; + +// react refresh +const ReactRefreshAllowConstantExportPackages = ["vite"]; +const RemixPackages = ["@remix-run/node", "@remix-run/react", "@remix-run/serve", "@remix-run/dev"]; +const NextJsPackages = ["next"]; +const ReactRouterPackages = ["@react-router/node", "@react-router/react", "@react-router/serve", "@react-router/dev"]; + +// @see https://github.com/jsx-eslint/eslint-plugin-react +export default createConfig< + OptionsFiles & + OptionsHasPrettier & + OptionsOverrides & + OptionsPackageJson & + OptionsSilentConsoleLogs & + OptionsStylistic & + OptionsTypeScriptParserOptions & + OptionsTypeScriptWithTypes + // eslint-disable-next-line sonarjs/cognitive-complexity +>("jsx_and_tsx", async (config, oFiles) => { + const { + files = oFiles, + filesTypeAware = getFilesGlobs("ts"), + ignoresTypeAware = [`**/*.md/**`, ...getFilesGlobs("astro")], + overrides, + packageJson, + prettier, + silent, + stylistic = true, + tsconfigPath, + } = config; + + const isTypeAware = tsconfigPath !== undefined; + + const { indent = 4 } = typeof stylistic === "boolean" ? {} : stylistic; + + const typeAwareRules: TypedFlatConfigItem["rules"] = { + "react/no-leaked-conditional-rendering": "warn", }; -} - -const hasJsxRuntime = (() => { - // Workaround VS Code trying to run this file twice! - if (!global.hasAnolilabEsLintConfigReactRuntimePath) { - const reactPath = findUp.sync("node_modules/react/jsx-runtime.js"); - const isFile = typeof reactPath === "string"; - - let showLog: boolean = env["DISABLE_INFO_ON_DISABLING_JSX_REACT_RULE"] !== "true"; - - if (showLog && anolilabEslintConfig["info_on_disabling_jsx_react_rule"] !== undefined) { - showLog = anolilabEslintConfig["info_on_disabling_jsx_react_rule"] as boolean; - } - - if (showLog && isFile) { - consoleLog(`\n@anolilab/eslint-config found react jsx-runtime. \n - Following rules are disabled: "react/jsx-uses-react" and "react/react-in-jsx-scope". - If you dont use the new react jsx-runtime in you project, please enable it manually.\n`); - } - global.hasAnolilabEsLintConfigReactRuntimePath = isFile; - } + const [pluginReactX, pluginReact, pluginReactHooks, pluginReactRefresh] = await Promise.all([ + interopDefault(import("@eslint-react/eslint-plugin")), + interopDefault(import("eslint-plugin-react")), + interopDefault(import("eslint-plugin-react-hooks")), + interopDefault(import("eslint-plugin-react-refresh")), + ] as const); - return global.hasAnolilabEsLintConfigReactRuntimePath; -})(); + const isAllowConstantExport = hasPackageJsonAnyDependency(packageJson, ReactRefreshAllowConstantExportPackages); + const isUsingRemix = hasPackageJsonAnyDependency(packageJson, RemixPackages); + const isUsingNext = hasPackageJsonAnyDependency(packageJson, NextJsPackages); + const isUsingReactRouter = hasPackageJsonAnyDependency(packageJson, ReactRouterPackages); -if (!global.anolilabEslintConfigReactVersion) { - let reactVersion = getPackageSubProperty("dependencies")("react"); + const plugins = pluginReactX.configs.all.plugins; - if (reactVersion === undefined) { - reactVersion = getPackageSubProperty("devDependencies")("react"); - } + let reactVersion = packageJson?.["dependencies"]?.["react"] || packageJson?.["devDependencies"]?.["react"]; if (reactVersion !== undefined) { const parsedVersion = parse(reactVersion); if (parsedVersion !== null) { - global.anolilabEslintConfigReactVersion = `${parsedVersion.major}.${parsedVersion.minor}`; + reactVersion = `${parsedVersion.major}.${parsedVersion.minor}`; + + if (!silent) { + // eslint-disable-next-line no-console + console.info( + `\n@anolilab/eslint-config found the version ${reactVersion} of react in your dependencies, this version ${reactVersion} will be used to setup the "eslint-plugin-react"\n`, + ); + } } } -} -if (global.anolilabEslintConfigReactVersion !== undefined && anolilabEslintConfig["info_on_found_react_version"] !== false) { - consoleLog( - `\n@anolilab/eslint-config found the version ${global.anolilabEslintConfigReactVersion} of react in your dependencies, this version ${global.anolilabEslintConfigReactVersion} will be used to setup the "eslint-plugin-react"\n`, - ); -} + let hasJsxRuntime = false; -const config: Linter.Config = { - overrides: [ - { - env: { - browser: true, - }, + if (tsconfigPath !== undefined) { + const tsConfig = readTsConfig(tsconfigPath); + + if (tsConfig?.compilerOptions !== undefined && (tsConfig?.compilerOptions.jsx === "react-jsx" || tsConfig?.compilerOptions.jsx === "react-jsxdev")) { + hasJsxRuntime = true; - files: ["**/*.jsx", "**/*.tsx"], + if (!silent) { + // eslint-disable-next-line no-console + console.info(`\n@anolilab/eslint-config found react jsx-runtime. \n + Following rules are disabled: "react/jsx-uses-react" and "react/react-in-jsx-scope". + If you dont use the new react jsx-runtime in you project, please enable it manually.\n`); + } + } + } - parserOptions: { - ecmaFeatures: { - jsx: true, + return [ + { + name: "anolilab/react/setup", + plugins: { + react: pluginReact, + "react-dom": plugins["@eslint-react/dom"], + "react-hooks": pluginReactHooks, + "react-hooks-extra": plugins["@eslint-react/hooks-extra"], + "react-naming-convention": plugins["@eslint-react/naming-convention"], + "react-refresh": pluginReactRefresh, + "react-x": plugins["@eslint-react"], + }, + }, + { + files, + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, }, }, - - plugins: ["react"], - - // https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules + name: "anolilab/react/rules", + // https://github.com/jsx-eslint/eslint-plugin-react#list-of-supported-rules rules: { "class-methods-use-this": [ "error", @@ -133,16 +157,52 @@ const config: Linter.Config = { "jsx-quotes": ["error", "prefer-double"], "no-underscore-dangle": [ - (dangleRules as unknown[])[0] as Linter.RuleLevel, + "error", { - ...((dangleRules as unknown[])[1] as Linter.RuleLevelAndOptions[]), - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any - allow: [...(dangleRules as any)[1].allow, "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"], + ...noUnderscoreDangle, + + allow: [...noUnderscoreDangle.allow, "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"], + }, + ], + + // Enforce Rules of Hooks + // https://github.com/facebook/react/blob/1204c789776cb01fbaf3e9f032e7e2ba85a44137/packages/eslint-plugin-react-hooks/src/ExhaustiveDeps.js + "react-hooks/exhaustive-deps": "error", + + // Verify the list of the dependencies for Hooks like useEffect and similar + // https://github.com/facebook/react/blob/c11015ff4f610ac2924d1fc6d569a17657a404fd/packages/eslint-plugin-react-hooks/src/RulesOfHooks.js + "react-hooks/rules-of-hooks": "error", + + // react refresh + "react-refresh/only-export-components": [ + "warn", + { + allowConstantExport: isAllowConstantExport, + allowExportNames: [ + ...isUsingNext + ? [ + "dynamic", + "dynamicParams", + "revalidate", + "fetchCache", + "runtime", + "preferredRegion", + "maxDuration", + "config", + "generateStaticParams", + "metadata", + "generateMetadata", + "viewport", + "generateViewport", + ] + : [], + ...isUsingRemix || isUsingReactRouter ? ["meta", "links", "headers", "loader", "action"] : [], + ], }, ], // Prevent missing displayName in a React component definition - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/boolean-prop-naming.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/boolean-prop-naming.md "react/boolean-prop-naming": [ "off", { @@ -153,7 +213,7 @@ const config: Linter.Config = { ], // Forbid certain propTypes (any, array, object) - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/button-has-type.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/button-has-type.md "react/button-has-type": [ "error", { @@ -164,27 +224,27 @@ const config: Linter.Config = { ], // Forbid certain props on DOM Nodes - // https://github.com/yannickcr/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/default-props-match-prop-types.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/default-props-match-prop-types.md "react/default-props-match-prop-types": ["error", { allowRequiredDefaults: false }], // Enforce boolean attributes notation in JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/destructuring-assignment.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/destructuring-assignment.md "react/destructuring-assignment": ["error", "always"], // Validate closing bracket location in JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/display-name.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/display-name.md "react/display-name": ["off", { ignoreTranspilerName: false }], // Enforce or disallow spaces inside curly braces in JSX attributes - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-component-props.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/forbid-component-props.md "react/forbid-component-props": ["off", { forbid: [] }], // Enforce event handler naming conventions in JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/forbid-dom-props.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/forbid-dom-props.md "react/forbid-dom-props": ["off", { forbid: [] }], // Validate props indentation in JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-elements.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/forbid-elements.md "react/forbid-elements": ["off", { forbid: [] }], // Validate JSX has key prop when in array or iterator @@ -192,7 +252,7 @@ const config: Linter.Config = { "react/forbid-foreign-prop-types": ["warn", { allowInPropTypes: true }], // Limit maximum of props on a single line in JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/forbid-prop-types.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/forbid-prop-types.md "react/forbid-prop-types": [ "error", { @@ -203,7 +263,7 @@ const config: Linter.Config = { ], // Prevent usage of .bind() in JSX props - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/function-component-definition.md "react/function-component-definition": [ "error", { @@ -213,7 +273,7 @@ const config: Linter.Config = { ], // Prevent duplicate props in JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md "react/jsx-boolean-value": ["error", "never", { always: [] }], // Prevent usage of unwrapped JSX strings @@ -221,15 +281,15 @@ const config: Linter.Config = { "react/jsx-child-element-spacing": "off", // Disallow undeclared variables in JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md "react/jsx-closing-bracket-location": ["error", "line-aligned"], // Enforce PascalCase for user-defined JSX components - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-brace-presence.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-curly-brace-presence.md "react/jsx-curly-brace-presence": ["error", { children: "never", props: "never" }], // Enforce propTypes declarations alphabetical sorting - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-newline.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-curly-newline.md "react/jsx-curly-newline": [ "error", { @@ -239,23 +299,23 @@ const config: Linter.Config = { ], // Enforce props alphabetical sorting - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md "react/jsx-curly-spacing": ["error", "never", { allowMultiline: true }], // Prevent React to be incorrectly marked as unused - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-equals-spacing.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-equals-spacing.md "react/jsx-equals-spacing": ["error", "never"], // Prevent variables used in JSX to be incorrectly marked as unused - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-first-prop-new-line.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-first-prop-new-line.md "react/jsx-first-prop-new-line": ["error", "multiline-multiprop"], // Prevent usage of dangerous JSX properties - // https://github.com/yannickcr/eslint-plugin-react/blob/bc976b837abeab1dffd90ac6168b746a83fc83cc/docs/rules/jsx-fragments.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/bc976b837abeab1dffd90ac6168b746a83fc83cc/docs/rules/jsx-fragments.md "react/jsx-fragments": ["error", "syntax"], // Prevent usage of deprecated methods - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-handler-names.md "react/jsx-handler-names": [ "off", { @@ -265,31 +325,31 @@ const config: Linter.Config = { ], // Prevent usage of setState in componentWillUpdate - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-indent.md "react/jsx-indent": ["error", indent, { checkAttributes: true, indentLogicalExpressions: true }], // Prevent direct mutation of this.state - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-indent-props.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-indent-props.md "react/jsx-indent-props": ["error", indent], // Prevent usage of isMounted - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-key.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-key.md "react/jsx-key": "off", // Prevent multiple component definition per file - // https://github.com/yannickcr/eslint-plugin-react/blob/abe8381c0d6748047224c430ce47f02e40160ed0/docs/rules/jsx-max-depth.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/abe8381c0d6748047224c430ce47f02e40160ed0/docs/rules/jsx-max-depth.md "react/jsx-max-depth": "off", // Prevent usage of setState - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-max-props-per-line.md "react/jsx-max-props-per-line": ["error", { maximum: 1, when: "multiline" }], // Prevent using string references - // https://github.com/yannickcr/eslint-plugin-react/blob/e2eaadae316f9506d163812a09424eb42698470a/docs/rules/jsx-newline.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/e2eaadae316f9506d163812a09424eb42698470a/docs/rules/jsx-newline.md "react/jsx-newline": "off", // Prevent usage of unknown DOM property - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md "react/jsx-no-bind": [ "error", { @@ -302,23 +362,23 @@ const config: Linter.Config = { ], // Require ES6 class declarations over React.createClass - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-comment-textnodes.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-comment-textnodes.md "react/jsx-no-comment-textnodes": "error", // Require stateless functions when not using lifecycle methods, setState or ref - // https://github.com/yannickcr/eslint-plugin-react/blob/e2eaadae316f9506d163812a09424eb42698470a/docs/rules/jsx-no-constructed-context-values.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/e2eaadae316f9506d163812a09424eb42698470a/docs/rules/jsx-no-constructed-context-values.md "react/jsx-no-constructed-context-values": "error", // Prevent missing props validation in a React component definition - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md "react/jsx-no-duplicate-props": ["error", { ignoreCase: true }], // Prevent missing React when using JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-literals.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-literals.md "react/jsx-no-literals": ["off", { noStrings: true }], // Require render() methods to return something - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-script-url.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-script-url.md "react/jsx-no-script-url": [ "error", [ @@ -330,23 +390,23 @@ const config: Linter.Config = { ], // Prevent extra closing tags for components without children - // https://github.com/yannickcr/eslint-plugin-react/blob/ac102885765be5ff37847a871f239c6703e1c7cc/docs/rules/jsx-no-target-blank.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/ac102885765be5ff37847a871f239c6703e1c7cc/docs/rules/jsx-no-target-blank.md "react/jsx-no-target-blank": ["error", { enforceDynamicLinks: "always" }], // Enforce defaultProps declarations alphabetical sorting - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md "react/jsx-no-undef": "error", // Enforce component methods order - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-useless-fragment.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-useless-fragment.md "react/jsx-no-useless-fragment": "error", // Require that the first prop in a JSX element be on a new line when the element is multiline - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/jsx-one-expression-per-line.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-one-expression-per-line.md "react/jsx-one-expression-per-line": ["error", { allow: "single-child" }], // Enforce spacing around jsx equals signs - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md "react/jsx-pascal-case": [ "error", { @@ -356,12 +416,12 @@ const config: Linter.Config = { ], // Enforce JSX indentation - // https://github.com/yannickcr/eslint-plugin-react/blob/ac102885765be5ff37847a871f239c6703e1c7cc/docs/rules/jsx-props-no-multi-spaces.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/ac102885765be5ff37847a871f239c6703e1c7cc/docs/rules/jsx-props-no-multi-spaces.md "react/jsx-props-no-multi-spaces": "error", // Prevent usage of setState in componentDidMount - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-props-no-spreading.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-props-no-spreading.md "react/jsx-props-no-spreading": [ "error", { @@ -373,7 +433,7 @@ const config: Linter.Config = { ], // Prevent usage of setState in componentDidUpdate - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-sort-props.md "react/jsx-sort-props": "off", // Disallow target="_blank" on links @@ -381,7 +441,7 @@ const config: Linter.Config = { "react/jsx-space-before-closing": ["off", "always"], // prevent accidental JS comments from being injected into JSX as text - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/jsx-tag-spacing.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-tag-spacing.md "react/jsx-tag-spacing": [ "error", { @@ -393,39 +453,39 @@ const config: Linter.Config = { ], // disallow using React.render/ReactDOM.render's return value - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md "react/jsx-uses-react": [hasJsxRuntime ? "off" : "error"], // require a shouldComponentUpdate method, or PureRenderMixin - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md "react/jsx-uses-vars": "error", // warn against using findDOMNode() - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/no-access-state-in-setstate.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-access-state-in-setstate.md "react/no-access-state-in-setstate": "error", // Forbid certain props on Components - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-adjacent-inline-elements.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-adjacent-inline-elements.md "react/no-adjacent-inline-elements": "error", // Forbid certain elements - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md "react/no-array-index-key": "error", // Prevent problem with children and props.dangerouslySetInnerHTML - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md "react/no-children-prop": "error", // Prevent unused propType definitions - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-danger.md "react/no-danger": "warn", // Require style prop value be an object or var - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger-with-children.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-danger-with-children.md "react/no-danger-with-children": "error", // Prevent invalid characters from appearing in markup - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-deprecated.md "react/no-deprecated": ["error"], // Prevent passing of children as props @@ -433,62 +493,62 @@ const config: Linter.Config = { "react/no-did-mount-set-state": "off", // Validate whitespace in and around the JSX opening and closing brackets - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-did-update-set-state.md "react/no-did-update-set-state": "error", // Enforce spaces before the closing bracket of self-closing JSX elements - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-space-before-closing.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-direct-mutation-state.md "react/no-direct-mutation-state": "error", // Prevent usage of Array index in keys - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-find-dom-node.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-find-dom-node.md "react/no-find-dom-node": "error", // Enforce a defaultProps definition for every prop that is not a required prop - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-is-mounted.md "react/no-is-mounted": "error", // Forbids using non-exported propTypes - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/forbid-foreign-prop-types.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/forbid-foreign-prop-types.md // this is intentionally set to "warn". it would be "error", - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md "react/no-multi-comp": "off", // Prevent void DOM elements from receiving children - // https://github.com/yannickcr/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/no-redundant-should-component-update.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/no-redundant-should-component-update.md "react/no-redundant-should-component-update": "error", // Enforce all defaultProps have a corresponding non-required PropType - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-render-return-value.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-render-return-value.md "react/no-render-return-value": "error", // Prevent usage of shouldComponentUpdate when extending React.PureComponent - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-set-state.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-set-state.md "react/no-set-state": "off", // Prevent unused state values - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md "react/no-string-refs": "error", // Enforces consistent naming for boolean props - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/no-this-in-sfc.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-this-in-sfc.md "react/no-this-in-sfc": "error", // Enforce curly braces or disallow unnecessary curly braces in JSX props and/or children - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unescaped-entities.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unescaped-entities.md "react/no-unescaped-entities": "error", // One JSX Element Per Line - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unknown-property.md "react/no-unknown-property": "error", // Enforce consistent usage of destructuring assignment of props, state, and context - // https://github.com/yannickcr/eslint-plugin-react/blob/157cc932be2cfaa56b3f5b45df6f6d4322a2f660/docs/rules/no-unsafe.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/157cc932be2cfaa56b3f5b45df6f6d4322a2f660/docs/rules/no-unsafe.md "react/no-unsafe": "off", // Prevent using this.state within a this.setState - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-unused-prop-types.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-unused-prop-types.md "react/no-unused-prop-types": [ "error", { @@ -498,26 +558,26 @@ const config: Linter.Config = { ], // Prevent usage of button elements without an explicit type attribute - // https://github.com/yannickcr/eslint-plugin-react/pull/1103/ + // https://github.com/jsx-eslint/eslint-plugin-react/pull/1103/ "react/no-unused-state": "error", - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-will-update-set-state.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-will-update-set-state.md "react/no-will-update-set-state": "error", // Prevent this from being used in stateless functional components - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prefer-es6-class.md "react/prefer-es6-class": ["error", "always"], // Validate JSX maximum depth - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-read-only-props.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prefer-read-only-props.md "react/prefer-read-only-props": "off", // Disallow multiple spaces between inline JSX props - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prefer-stateless-function.md "react/prefer-stateless-function": ["error", { ignorePureComponents: true }], // Prevent usage of UNSAFE_ methods - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/prop-types.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prop-types.md "react/prop-types": [ "error", { @@ -528,35 +588,35 @@ const config: Linter.Config = { ], // Enforce shorthand or standard form for React fragments - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/react-in-jsx-scope.md "react/react-in-jsx-scope": hasJsxRuntime ? "off" : "error", // Enforce a defaultProps definition for every prop that is not a required prop - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/require-default-props.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/require-default-props.md "react/require-default-props": [ "error", { forbidDefaultForRequired: true, - functions: hasDependency("typescript") || hasDevDependency("typescript") ? "defaultArguments" : "defaultProps", + functions: hasPackageJsonAnyDependency(packageJson, ["typescript"]) ? "defaultArguments" : "defaultProps", }, ], // Enforce state initialization style - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/state-in-constructor.md - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-optimization.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/state-in-constructor.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/require-optimization.md "react/require-optimization": ["off", { allowDecorators: [] }], // Enforces where React component static properties should be positioned - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/static-property-placement.md - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/require-render-return.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/static-property-placement.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/require-render-return.md "react/require-render-return": "error", // Disallow JSX props spreading - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md "react/self-closing-comp": "error", // Enforce that props are read-only - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/sort-comp.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/sort-comp.md "react/sort-comp": [ "error", { @@ -608,7 +668,7 @@ const config: Linter.Config = { ], // Prevent usage of `javascript:` URLs - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/sort-default-props.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/sort-default-props.md "react/sort-default-props": [ "error", { @@ -617,7 +677,7 @@ const config: Linter.Config = { ], // Disallow unnecessary fragments - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/sort-prop-types.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/sort-prop-types.md "react/sort-prop-types": [ "off", { @@ -629,24 +689,42 @@ const config: Linter.Config = { ], // Prevent adjacent inline elements not separated by whitespace - // TODO: set to "never" once @anolilab/babel-preset supports public class fields - "react/state-in-constructor": ["error", "always"], + "react/state-in-constructor": ["error", "never"], // Enforce a specific function type for function components - // TODO: set to "static public field" once @anolilab/babel-preset supports public class fields - "react/static-property-placement": ["error", "property assignment"], + "react/static-property-placement": ["error", "static public field"], // Enforce a new line after jsx elements and expressions - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/style-prop-object.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/style-prop-object.md "react/style-prop-object": "error", // Prevent react contexts from taking non-stable values - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/void-dom-elements-no-children.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/void-dom-elements-no-children.md "react/void-dom-elements-no-children": "error", - ...global.anolilabEslintConfigReactPrettierRules, + ...prettier + ? { + "react/jsx-child-element-spacing": "off", + "react/jsx-closing-bracket-location": "off", + "react/jsx-closing-tag-location": "off", + "react/jsx-curly-newline": "off", + "react/jsx-curly-spacing": "off", + "react/jsx-equals-spacing": "off", + "react/jsx-first-prop-new-line": "off", + "react/jsx-indent": "off", + "react/jsx-indent-props": "off", + "react/jsx-max-props-per-line": "off", + "react/jsx-newline": "off", + "react/jsx-one-expression-per-line": "off", + "react/jsx-props-no-multi-spaces": "off", + "react/jsx-tag-spacing": "off", + "react/jsx-wrap-multilines": "off", + } + : {}, + + // overrides + ...overrides, }, - // View link below for react rules documentation settings: { propWrapperFunctions: [ @@ -658,32 +736,31 @@ const config: Linter.Config = { // The default value is "detect". Automatic detection works by loading the entire React library // into the linter's process, which is inefficient. It is recommended to specify the version // explicity. - version: global.anolilabEslintConfigReactVersion ?? "detect", + version: reactVersion ?? "detect", }, }, }, { files: ["**/*.jsx"], - parser: "@babel/eslint-parser", - parserOptions: { - ecmaFeatures: { - jsx: true, + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, }, }, - settings: { - extensions: [".jsx"], - }, + name: "anolilab/react/jsx", rules: { // only .jsx files may have JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-tag-location.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-closing-tag-location.md "react/jsx-closing-tag-location": "error", // Prevents common casing typos - // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md "react/jsx-filename-extension": "error", // Validate closing tag location in JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/jsx-wrap-multilines.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-wrap-multilines.md "react/jsx-wrap-multilines": [ "error", { @@ -698,12 +775,16 @@ const config: Linter.Config = { ], // Prevent missing parentheses around multilines JSX - // https://github.com/yannickcr/eslint-plugin-react/blob/73abadb697034b5ccb514d79fb4689836fe61f91/docs/rules/no-typos.md + // https://github.com/jsx-eslint/eslint-plugin-react/blob/73abadb697034b5ccb514d79fb4689836fe61f91/docs/rules/no-typos.md "react/no-typos": "error", }, + settings: { + extensions: [".jsx"], + }, }, { files: ["**/*.tsx"], + name: "anolilab/react/tsx", rules: { "react/default-props-match-prop-types": "off", // Disable JS specific rules @@ -714,12 +795,23 @@ const config: Linter.Config = { }, { // For performance run storybook/recommended on test files, not regular code - files: ["**/*.stories.{ts,tsx,mdx}"], + files: getFilesGlobs("storybook"), + name: "anolilab/react/storybook", rules: { "react/jsx-props-no-spreading": "off", }, }, - ], -}; - -export default config; + ...isTypeAware + ? [ + { + files: filesTypeAware, + ignores: ignoresTypeAware, + name: "anolilab/react/type-aware-rules", + rules: { + ...typeAwareRules, + }, + }, + ] + : [], + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/regexp.ts b/packages/eslint-config/src/config/plugins/regexp.ts index 5b2c7e8fb..81aaeeffb 100644 --- a/packages/eslint-config/src/config/plugins/regexp.ts +++ b/packages/eslint-config/src/config/plugins/regexp.ts @@ -1,14 +1,39 @@ -import type { Linter } from "eslint"; +import { configs } from "eslint-plugin-regexp"; +import type { + OptionsFiles, + OptionsOverrides, + OptionsRegExp, + TypedFlatConfigItem, +} from "../../types"; import { createConfig } from "../../utils/create-config"; -const config: Linter.Config = createConfig("all", { - extends: ["plugin:regexp/recommended"], - plugins: ["regexp"], - rules: { - // disallow control characters - "regexp/no-control-character": "error", - }, -}); +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, level, overrides } = config; + const recommended = configs["flat/recommended"] as TypedFlatConfigItem; + + const rules = { + ...recommended.rules, + }; -export default config; + if (level === "warn") { + // eslint-disable-next-line no-restricted-syntax + for (const key in rules) { + if (rules[key] === "error") { + rules[key] = "warn"; + } + } + } + + return [ + { + ...recommended, + files, + name: "anolilab/regexp/rules", + rules: { + ...rules, + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/security.ts b/packages/eslint-config/src/config/plugins/security.ts deleted file mode 100644 index 8c33f61a4..000000000 --- a/packages/eslint-config/src/config/plugins/security.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { Linter } from "eslint"; - -const config: Linter.Config = { - // @see https://github.com/eslint-community/eslint-plugin-security - extends: ["plugin:security/recommended"], - // @see https://www.npmjs.com/package/@rushstack/eslint-plugin-security - plugins: ["@rushstack/eslint-plugin-security"], - rules: { - // This is disabled for tools because, for example, it is a common and safe practice for a tool - // to read a RegExp from a config file and use it to filter files paths. - - "@rushstack/security/no-unsafe-regexp": process.env["TRUSTED_TOOL"] ? "off" : "warn", - }, -}; - -export default config; diff --git a/packages/eslint-config/src/config/plugins/simple-import-sort.ts b/packages/eslint-config/src/config/plugins/simple-import-sort.ts index 828349c4f..9dcd463cb 100644 --- a/packages/eslint-config/src/config/plugins/simple-import-sort.ts +++ b/packages/eslint-config/src/config/plugins/simple-import-sort.ts @@ -1,17 +1,25 @@ -import type { Linter } from "eslint"; - +import type { OptionsFiles, OptionsOverrides } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -const config: Linter.Config = createConfig("all", { - env: { es6: true }, - parserOptions: { - sourceType: "module", - }, - plugins: ["simple-import-sort"], - rules: { - "simple-import-sort/exports": "error", - "simple-import-sort/imports": "error", - }, -}); +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const pluginSimpleImportSort = await interopDefault(import("eslint-plugin-simple-import-sort")); -export default config; + return [ + { + files, + name: "anolilab/simple-import-sort", + plugins: { + "simple-import-sort": pluginSimpleImportSort, + }, + rules: { + "simple-import-sort/exports": "error", + "simple-import-sort/imports": "error", + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/sonarjs.ts b/packages/eslint-config/src/config/plugins/sonarjs.ts index 2b045ceb0..4fd2dea9e 100644 --- a/packages/eslint-config/src/config/plugins/sonarjs.ts +++ b/packages/eslint-config/src/config/plugins/sonarjs.ts @@ -1,21 +1,39 @@ -import type { Linter } from "eslint"; - -import { createConfigs } from "../../utils/create-config"; +import type { OptionsFiles, OptionsOverrides } from "../../types"; +import { createConfig, getFilesGlobs } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; // @see https://github.com/SonarSource/eslint-plugin-sonarjs -const config: Linter.Config = createConfigs([ - { - config: { - excludedFiles: ["**/?(*.)+(test).{js,jsx,ts,tsx}", "**/*.stories.{js,ts,jsx,tsx}"], - extends: ["plugin:sonarjs/recommended"], +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const sonarJsPlugin = await interopDefault(import("eslint-plugin-sonarjs")); + + return [ + { + name: "anolilab/sonarjs/plugin", + plugins: { + sonarjs: sonarJsPlugin, + }, + }, + { + files, + name: "anolilab/sonarjs/rules", rules: { + ...sonarJsPlugin.configs["recommended"].rules, + "sonarjs/file-name-differ-from-class": "error", + "sonarjs/no-collapsible-if": "error", "sonarjs/no-nested-template-literals": "off", + "sonarjs/no-tab": "error", + + // This rule does not work will with disable next line + "sonarjs/todo-tag": "off", + + ...overrides, }, }, - type: "all", - }, - { - config: { + { + files: getFilesGlobs("js_and_ts"), + name: "anolilab/sonarjs/js-and-ts-rules", rules: { // relax complexity for react code "sonarjs/cognitive-complexity": ["error", 15], @@ -23,21 +41,16 @@ const config: Linter.Config = createConfigs([ "sonarjs/no-duplicate-string": "off", }, }, - type: "js_and_ts", - }, - { - config: { - parser: "espree", - parserOptions: { + { + files: getFilesGlobs("js"), + languageOptions: { ecmaVersion: 2020, }, + name: "anolilab/sonarjs/js-rules", rules: { "sonarjs/no-all-duplicated-branches": "off", "sonarjs/no-duplicate-string": "off", }, }, - type: "javascript", - }, -]); - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/ssr-friendly.ts b/packages/eslint-config/src/config/plugins/ssr-friendly.ts deleted file mode 100644 index 548fe095b..000000000 --- a/packages/eslint-config/src/config/plugins/ssr-friendly.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -// @see https://github.com/francoismassart/eslint-plugin-tailwindcss, -const config: Linter.Config = createConfig("jsx_and_tsx", { - plugins: ["ssr-friendly"], - extends: ["plugin:ssr-friendly/recommended"], -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/storybook.ts b/packages/eslint-config/src/config/plugins/storybook.ts index 844be5bff..3f49dca82 100644 --- a/packages/eslint-config/src/config/plugins/storybook.ts +++ b/packages/eslint-config/src/config/plugins/storybook.ts @@ -1,19 +1,18 @@ -import type { Linter } from "eslint"; +import type { OptionsOverrides } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -// @see https://github.com/storybookjs/eslint-plugin-storybook -const config: Linter.Config = { - env: { - browser: true, - es6: true, - node: true, - }, - overrides: [ - { - extends: ["plugin:storybook/recommended"], - // For performance run storybook/recommended on test files, not regular code - files: ["**/*.stories.{ts,tsx,mdx}", ".storybook/**/*"], - }, - ], -}; +export default createConfig("storybook", async (config) => { + const { overrides } = config; -export default config; + const storybookPlugin = await interopDefault(import("eslint-plugin-storybook")); + + const options = [...storybookPlugin.configs["flat/recommended"]]; + + options[0].rules = { + ...options[0].rules, + ...overrides, + }; + + return options; +}); diff --git a/packages/eslint-config/src/config/plugins/stylistic.ts b/packages/eslint-config/src/config/plugins/stylistic.ts new file mode 100644 index 000000000..3dcaae604 --- /dev/null +++ b/packages/eslint-config/src/config/plugins/stylistic.ts @@ -0,0 +1,431 @@ +import type { + OptionsHasPrettier, + OptionsOverrides, + StylisticConfig, + TypedFlatConfigItem, +} from "../../types"; +import interopDefault from "../../utils/interop-default"; + +const specialRule = 0; + +const stylistic = async (options: OptionsHasPrettier & OptionsOverrides & StylisticConfig): Promise => { + const { + indent, + jsx, + overrides = {}, + prettier, + quotes, + semi, + } = { + // eslint-disable-next-line @typescript-eslint/no-use-before-define + ...StylisticConfigDefaults, + ...options, + }; + + const pluginStylistic = await interopDefault(import("@stylistic/eslint-plugin")); + + const config = pluginStylistic.configs.customize({ + flat: true, + indent, + jsx, + pluginName: "@stylistic", + quotes: prettier ? undefined : quotes, + semi: prettier ? false : semi, + }); + + return [ + { + name: "anolilab/stylistic/rules", + plugins: { + "@stylistic": pluginStylistic, + }, + rules: { + ...config.rules, + + // enforce spacing inside single-line blocks + "@stylistic/block-spacing": ["error", "always"], + + // Replace 'brace-style' rule with '@stylistic' version + // enforce one true brace style + "@stylistic/brace-style": ["error", "1tbs", { allowSingleLine: true }], + + // Replace 'comma-dangle' rule with '@stylistic' version + // The TypeScript version also adds 3 new options, all of which should be set to the same value as the base config + "@stylistic/comma-dangle": [ + "error", + { + arrays: "always-multiline", + enums: "always-multiline", + exports: "always-multiline", + functions: "always-multiline", + generics: "always-multiline", + imports: "always-multiline", + objects: "always-multiline", + tuples: "always-multiline", + }, + ], + + // Replace 'comma-spacing' rule with '@stylistic' version + // enforce spacing before and after comma + "@stylistic/comma-spacing": ["error", { after: true, before: false }], + + // Replace 'func-call-spacing' rule with '@stylistic' version + "@stylistic/func-call-spacing": ["error", "never"], + + "@stylistic/indent": [ + "error", + indent, + { + ArrayExpression: 1, + CallExpression: { + arguments: 1, + }, + flatTernaryExpressions: false, + // MemberExpression: null, + FunctionDeclaration: { + body: 1, + parameters: 1, + }, + FunctionExpression: { + body: 1, + parameters: 1, + }, + ignoreComments: false, + // list derived from https://github.com/benjamn/ast-types/blob/HEAD/def/jsx.js + ignoredNodes: [ + "JSXElement", + "JSXElement > *", + "JSXAttribute", + "JSXIdentifier", + "JSXNamespacedName", + "JSXMemberExpression", + "JSXSpreadAttribute", + "JSXExpressionContainer", + "JSXOpeningElement", + "JSXClosingElement", + "JSXFragment", + "JSXOpeningFragment", + "JSXClosingFragment", + "JSXText", + "JSXEmptyExpression", + "JSXSpreadChild", + ], + ImportDeclaration: 1, + ObjectExpression: 1, + outerIIFEBody: 1, + SwitchCase: 1, + VariableDeclarator: 1, + }, + ], + + // enforces spacing between keys and values in object literal properties + "@stylistic/key-spacing": ["error", { afterColon: true, beforeColon: false }], + + // require a space before & after certain keywords + "@stylistic/keyword-spacing": [ + "error", + { + after: true, + before: true, + overrides: { + case: { after: true }, + return: { after: true }, + throw: { after: true }, + }, + }, + ], + + // require or disallow an empty line between class members + // enforces empty lines around comments + "@stylistic/lines-around-comment": "off", + + // require or disallow newlines around directives + // https://eslint.org/docs/rules/lines-between-class-members + "@stylistic/lines-between-class-members": ["error", "always", { exceptAfterSingleLine: false }], + + "@stylistic/member-delimiter-style": "error", + + // disallow unnecessary parentheses + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-extra-parens.md + "@stylistic/no-extra-parens": [ + "error", + "all", + { + conditionalAssign: true, + enforceForArrowConditionals: false, + ignoreJSX: "all", // delegate to eslint-plugin-react + nestedBinaryExpressions: false, + returnAssign: false, + }, + ], + + // Disallow non-null assertion in locations that may be confusing. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-extra-semi.md + "@stylistic/no-extra-semi": "error", + + "@stylistic/padding-line-between-statements": [ + "error", + // Require blank lines after all directive prologues (e.g. 'use strict') + { + blankLine: "always", + next: "*", + prev: "directive", + }, + // Disallow blank lines between all directive prologues (e.g. 'use strict') + { + blankLine: "never", + next: "directive", + prev: "directive", + }, + // Require blank lines after every sequence of variable declarations + { + blankLine: "always", + next: "*", + prev: ["const", "let", "var"], + }, + // Blank lines could be between variable declarations + { + blankLine: "any", + next: ["const", "let", "var"], + prev: ["const", "let", "var"], + }, + // Require blank lines before all return statements + { + blankLine: "always", + next: "return", + prev: "*", + }, + // Require blank lines before and after all following statements + { + blankLine: "always", + next: ["for", "function", "if", "switch", "try"], + prev: "*", + }, + { + blankLine: "always", + next: "*", + prev: ["for", "function", "if", "switch", "try"], + }, + ], + + // require quotes around object literal property names + // https://eslint.org/docs/rules/quote-props.html + "@stylistic/quote-props": ["error", "as-needed", { keywords: false, numbers: false, unnecessary: true }], + + // require or disallow space before blocks + "@stylistic/space-before-blocks": "error", + + // require or disallow space before function opening parenthesis + "@stylistic/space-before-function-paren": [ + "error", + { + anonymous: "always", + asyncArrow: "always", + named: "never", + }, + ], + + // require spaces around operators + "@stylistic/space-infix-ops": "error", + + "@stylistic/type-annotation-spacing": "error", + + ...overrides, + + ...prettier + ? { + "@stylistic/array-bracket-newline": "off", + "@stylistic/array-bracket-spacing": "off", + "@stylistic/array-element-newline": "off", + "@stylistic/arrow-parens": "off", + "@stylistic/arrow-spacing": "off", + "@stylistic/block-spacing": "off", + "@stylistic/brace-style": "off", + "@stylistic/comma-dangle": "off", + "@stylistic/comma-spacing": "off", + "@stylistic/comma-style": "off", + "@stylistic/computed-property-spacing": "off", + "@stylistic/dot-location": "off", + "@stylistic/eol-last": "off", + "@stylistic/func-call-spacing": "off", + "@stylistic/function-call-argument-newline": "off", + "@stylistic/function-call-spacing": "off", + "@stylistic/function-paren-newline": "off", + "@stylistic/generator-star-spacing": "off", + "@stylistic/implicit-arrow-linebreak": "off", + "@stylistic/indent": "off", + "@stylistic/indent-binary-ops": "off", + "@stylistic/js/array-bracket-newline": "off", + "@stylistic/js/array-bracket-spacing": "off", + "@stylistic/js/array-element-newline": "off", + "@stylistic/js/arrow-parens": "off", + "@stylistic/js/arrow-spacing": "off", + "@stylistic/js/block-spacing": "off", + "@stylistic/js/brace-style": "off", + "@stylistic/js/comma-dangle": "off", + "@stylistic/js/comma-spacing": "off", + "@stylistic/js/comma-style": "off", + "@stylistic/js/computed-property-spacing": "off", + "@stylistic/js/dot-location": "off", + "@stylistic/js/eol-last": "off", + "@stylistic/js/func-call-spacing": "off", + "@stylistic/js/function-call-argument-newline": "off", + "@stylistic/js/function-call-spacing": "off", + "@stylistic/js/function-paren-newline": "off", + "@stylistic/js/generator-star-spacing": "off", + "@stylistic/js/implicit-arrow-linebreak": "off", + "@stylistic/js/indent": "off", + "@stylistic/js/jsx-quotes": "off", + "@stylistic/js/key-spacing": "off", + "@stylistic/js/keyword-spacing": "off", + "@stylistic/js/linebreak-style": "off", + "@stylistic/js/lines-around-comment": specialRule, + "@stylistic/js/max-len": specialRule, + "@stylistic/js/max-statements-per-line": "off", + "@stylistic/js/multiline-ternary": "off", + "@stylistic/js/new-parens": "off", + "@stylistic/js/newline-per-chained-call": "off", + "@stylistic/js/no-confusing-arrow": specialRule, + "@stylistic/js/no-extra-parens": "off", + "@stylistic/js/no-extra-semi": "off", + "@stylistic/js/no-floating-decimal": "off", + "@stylistic/js/no-mixed-operators": specialRule, + "@stylistic/js/no-mixed-spaces-and-tabs": "off", + "@stylistic/js/no-multi-spaces": "off", + "@stylistic/js/no-multiple-empty-lines": "off", + "@stylistic/js/no-tabs": specialRule, + "@stylistic/js/no-trailing-spaces": "off", + "@stylistic/js/no-whitespace-before-property": "off", + "@stylistic/js/nonblock-statement-body-position": "off", + "@stylistic/js/object-curly-newline": "off", + "@stylistic/js/object-curly-spacing": "off", + "@stylistic/js/object-property-newline": "off", + "@stylistic/js/one-var-declaration-per-line": "off", + "@stylistic/js/operator-linebreak": "off", + "@stylistic/js/padded-blocks": "off", + "@stylistic/js/quote-props": "off", + "@stylistic/js/quotes": specialRule, + "@stylistic/js/rest-spread-spacing": "off", + "@stylistic/js/semi": "off", + "@stylistic/js/semi-spacing": "off", + "@stylistic/js/semi-style": "off", + "@stylistic/js/space-before-blocks": "off", + "@stylistic/js/space-before-function-paren": "off", + "@stylistic/js/space-in-parens": "off", + "@stylistic/js/space-infix-ops": "off", + "@stylistic/js/space-unary-ops": "off", + "@stylistic/js/switch-colon-spacing": "off", + "@stylistic/js/template-curly-spacing": "off", + "@stylistic/js/template-tag-spacing": "off", + "@stylistic/js/wrap-iife": "off", + "@stylistic/js/wrap-regex": "off", + "@stylistic/js/yield-star-spacing": "off", + "@stylistic/jsx-child-element-spacing": "off", + "@stylistic/jsx-closing-bracket-location": "off", + "@stylistic/jsx-closing-tag-location": "off", + "@stylistic/jsx-curly-newline": "off", + "@stylistic/jsx-curly-spacing": "off", + "@stylistic/jsx-equals-spacing": "off", + "@stylistic/jsx-first-prop-new-line": "off", + "@stylistic/jsx-indent": "off", + "@stylistic/jsx-indent-props": "off", + "@stylistic/jsx-max-props-per-line": "off", + "@stylistic/jsx-newline": "off", + "@stylistic/jsx-one-expression-per-line": "off", + "@stylistic/jsx-props-no-multi-spaces": "off", + "@stylistic/jsx-quotes": "off", + "@stylistic/jsx-tag-spacing": "off", + "@stylistic/jsx-wrap-multilines": "off", + "@stylistic/jsx/jsx-child-element-spacing": "off", + "@stylistic/jsx/jsx-closing-bracket-location": "off", + "@stylistic/jsx/jsx-closing-tag-location": "off", + "@stylistic/jsx/jsx-curly-newline": "off", + "@stylistic/jsx/jsx-curly-spacing": "off", + "@stylistic/jsx/jsx-equals-spacing": "off", + "@stylistic/jsx/jsx-first-prop-new-line": "off", + "@stylistic/jsx/jsx-indent": "off", + "@stylistic/jsx/jsx-indent-props": "off", + "@stylistic/jsx/jsx-max-props-per-line": "off", + "@stylistic/key-spacing": "off", + "@stylistic/keyword-spacing": "off", + "@stylistic/linebreak-style": "off", + "@stylistic/lines-around-comment": specialRule, + "@stylistic/max-len": specialRule, + "@stylistic/max-statements-per-line": "off", + "@stylistic/member-delimiter-style": "off", + "@stylistic/multiline-ternary": "off", + "@stylistic/new-parens": "off", + "@stylistic/newline-per-chained-call": "off", + "@stylistic/no-confusing-arrow": specialRule, + "@stylistic/no-extra-parens": "off", + "@stylistic/no-extra-semi": "off", + "@stylistic/no-floating-decimal": "off", + "@stylistic/no-mixed-operators": specialRule, + "@stylistic/no-mixed-spaces-and-tabs": "off", + "@stylistic/no-multi-spaces": "off", + "@stylistic/no-multiple-empty-lines": "off", + "@stylistic/no-tabs": specialRule, + "@stylistic/no-trailing-spaces": "off", + "@stylistic/no-whitespace-before-property": "off", + "@stylistic/nonblock-statement-body-position": "off", + "@stylistic/object-curly-newline": "off", + "@stylistic/object-curly-spacing": "off", + "@stylistic/object-property-newline": "off", + "@stylistic/one-var-declaration-per-line": "off", + "@stylistic/operator-linebreak": "off", + "@stylistic/padded-blocks": "off", + "@stylistic/quote-props": "off", + "@stylistic/quotes": specialRule, + "@stylistic/rest-spread-spacing": "off", + "@stylistic/semi": "off", + "@stylistic/semi-spacing": "off", + "@stylistic/semi-style": "off", + "@stylistic/space-before-blocks": "off", + "@stylistic/space-before-function-paren": "off", + "@stylistic/space-in-parens": "off", + "@stylistic/space-infix-ops": "off", + "@stylistic/space-unary-ops": "off", + "@stylistic/switch-colon-spacing": "off", + "@stylistic/template-curly-spacing": "off", + "@stylistic/template-tag-spacing": "off", + "@stylistic/ts/block-spacing": "off", + "@stylistic/ts/brace-style": "off", + "@stylistic/ts/comma-dangle": "off", + "@stylistic/ts/comma-spacing": "off", + "@stylistic/ts/func-call-spacing": "off", + "@stylistic/ts/function-call-spacing": "off", + "@stylistic/ts/indent": "off", + "@stylistic/ts/key-spacing": "off", + "@stylistic/ts/keyword-spacing": "off", + "@stylistic/ts/lines-around-comment": specialRule, + "@stylistic/ts/member-delimiter-style": "off", + "@stylistic/ts/no-extra-parens": "off", + "@stylistic/ts/no-extra-semi": "off", + "@stylistic/ts/object-curly-spacing": "off", + "@stylistic/ts/quotes": specialRule, + "@stylistic/ts/semi": "off", + "@stylistic/ts/space-before-blocks": "off", + "@stylistic/ts/space-before-function-paren": "off", + "@stylistic/ts/space-infix-ops": "off", + "@stylistic/ts/type-annotation-spacing": "off", + "@stylistic/type-annotation-spacing": "off", + "@stylistic/type-generic-spacing": "off", + "@stylistic/type-named-tuple-spacing": "off", + "@stylistic/wrap-iife": "off", + "@stylistic/wrap-regex": "off", + "@stylistic/yield-star-spacing": "off", + } + : {}, + }, + }, + ]; +}; + +export default stylistic; + +export const StylisticConfigDefaults: StylisticConfig = { + indent: 4, + jsx: true, + quotes: "double", + semi: true, +}; diff --git a/packages/eslint-config/src/config/plugins/tailwindcss.ts b/packages/eslint-config/src/config/plugins/tailwindcss.ts index aadbc9771..b7a5ba890 100644 --- a/packages/eslint-config/src/config/plugins/tailwindcss.ts +++ b/packages/eslint-config/src/config/plugins/tailwindcss.ts @@ -1,19 +1,20 @@ -import type { Linter } from "eslint"; - +import type { OptionsFiles, OptionsOverrides } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; // @see https://github.com/francoismassart/eslint-plugin-tailwindcss, -const config: Linter.Config = createConfig( - "jsx_and_tsx", - { - extends: ["plugin:tailwindcss/recommended"], - plugins: ["tailwindcss"], - }, - { - browser: true, - es6: true, - node: true, - }, -); +export default createConfig("jsx_and_tsx", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const validateJsxNestingPlugin = await interopDefault(import("eslint-plugin-tailwindcss")); + + const options = [...validateJsxNestingPlugin.configs["flat/recommended"]]; + + options[1].files = files; + options[1].rules = { + ...options[1].rules, + ...overrides, + }; -export default config; + return options; +}); diff --git a/packages/eslint-config/src/config/plugins/tanstack-query.ts b/packages/eslint-config/src/config/plugins/tanstack-query.ts index b6d7fb25e..209c2408c 100644 --- a/packages/eslint-config/src/config/plugins/tanstack-query.ts +++ b/packages/eslint-config/src/config/plugins/tanstack-query.ts @@ -1,10 +1,23 @@ -import type { Linter } from "eslint"; - +import type { OptionsFiles, OptionsOverrides } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; // @see https://tanstack.com/query/v4/docs/react/eslint/eslint-plugin-query -const config: Linter.Config = createConfig("all", { - extends: ["plugin:@tanstack/eslint-plugin-query/recommended"], -}); +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides } = config; -export default config; + const pluginTanstackQuery = await interopDefault(import("@tanstack/eslint-plugin-query")); + + return [ + { + files, + plugins: { + "@tanstack/query": pluginTanstackQuery, + }, + rules: { + ...pluginTanstackQuery.configs["recommended"].rules, + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/tanstack-router.ts b/packages/eslint-config/src/config/plugins/tanstack-router.ts new file mode 100644 index 000000000..0a9c6d20f --- /dev/null +++ b/packages/eslint-config/src/config/plugins/tanstack-router.ts @@ -0,0 +1,22 @@ +import type { OptionsFiles, OptionsOverrides } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const pluginTanstackRouter = await interopDefault(import("@tanstack/eslint-plugin-router")); + + return [ + { + files, + plugins: { + "@tanstack/router": pluginTanstackRouter, + }, + rules: { + ...pluginTanstackRouter.configs["recommended"].rules, + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/testing-library-dom.ts b/packages/eslint-config/src/config/plugins/testing-library-dom.ts deleted file mode 100644 index 43c43fa54..000000000 --- a/packages/eslint-config/src/config/plugins/testing-library-dom.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; -import anolilabEslintConfig from "../../utils/eslint-config"; -import { consolePlugin } from "../../utils/loggers"; - -// Workaround VS Code trying to run this file twice! -if (!global.hasAnolilabEsLintTestConfigLoaded) { - if (anolilabEslintConfig["info_on_testing_library_framework"] !== false) { - consolePlugin(`testing-library: loading "dom" ruleset`); - } - - global.hasAnolilabEsLintTestConfigLoaded = true; -} - -// For performance enable react-testing-library only on test files -const config: Linter.Config = createConfig( - "tests", - { - extends: [`plugin:testing-library/dom`], - }, - { - browser: true, - es6: true, - node: true, - }, -); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/testing-library-react.ts b/packages/eslint-config/src/config/plugins/testing-library-react.ts deleted file mode 100644 index 0e15a8540..000000000 --- a/packages/eslint-config/src/config/plugins/testing-library-react.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; -import anolilabEslintConfig from "../../utils/eslint-config"; -import { consolePlugin } from "../../utils/loggers"; - -// Workaround VS Code trying to run this file twice! -if (!global.hasAnolilabEsLintTestConfigLoaded) { - if (anolilabEslintConfig["info_on_testing_library_framework"] !== false) { - consolePlugin(`testing-library: loading "react" ruleset`); - } - - global.hasAnolilabEsLintTestConfigLoaded = true; -} - -// For performance enable react-testing-library only on test files -const config: Linter.Config = createConfig( - "tests", - { - extends: [`plugin:testing-library/react`], - }, - { - browser: true, - es6: true, - node: true, - }, -); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/testing-library.ts b/packages/eslint-config/src/config/plugins/testing-library.ts new file mode 100644 index 000000000..cdb80c49b --- /dev/null +++ b/packages/eslint-config/src/config/plugins/testing-library.ts @@ -0,0 +1,28 @@ +import { hasPackageJsonAnyDependency } from "@visulima/package"; + +import type { OptionsFiles, OptionsOverrides, OptionsPackageJson } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig("vitest", async (config, oFiles) => { + const { files = oFiles, overrides, packageJson } = config; + + const testingLibraryPlugin = await interopDefault(import("eslint-plugin-testing-library")); + + const hasReact = hasPackageJsonAnyDependency(packageJson, ["react", "react-dom", "eslint-plugin-react"]); + + return [ + { + files, + plugins: { + "testing-library": testingLibraryPlugin, + }, + rules: { + ...testingLibraryPlugin.configs["flat/dom"].rules, + ...hasReact ? testingLibraryPlugin.configs["flat/react"].rules : {}, + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/toml.ts b/packages/eslint-config/src/config/plugins/toml.ts index 7997348be..88e4bac60 100644 --- a/packages/eslint-config/src/config/plugins/toml.ts +++ b/packages/eslint-config/src/config/plugins/toml.ts @@ -1,13 +1,55 @@ -import type { Linter } from "eslint"; +import type { OptionsFiles, OptionsOverrides, OptionsStylistic } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -const config: Linter.Config = { - overrides: [ +export default createConfig("toml", async (config, oFiles) => { + const { files = oFiles, overrides = {}, stylistic = true } = config; + + const { indent = 2 } = typeof stylistic === "boolean" ? {} : stylistic; + + const [pluginToml, parserToml] = await Promise.all([interopDefault(import("eslint-plugin-toml")), interopDefault(import("toml-eslint-parser"))] as const); + + return [ { - extends: ["plugin:toml/standard"], - files: ["**/*.toml"], - parser: "toml-eslint-parser", - }, - ], -}; + files, + languageOptions: { + parser: parserToml, + }, + name: "anolilab/toml", + plugins: { + toml: pluginToml, + }, + rules: { + ...stylistic ? { "@stylistic/spaced-comment": "off" } : {}, -export default config; + "toml/comma-style": "error", + "toml/keys-order": "error", + "toml/no-space-dots": "error", + "toml/no-unreadable-number-separator": "error", + "toml/precision-of-fractional-seconds": "error", + "toml/precision-of-integer": "error", + "toml/tables-order": "error", + + "toml/vue-custom-block/no-parsing-error": "error", + + ...stylistic + ? { + "toml/array-bracket-newline": "error", + "toml/array-bracket-spacing": "error", + "toml/array-element-newline": "error", + "toml/indent": ["error", indent === "tab" ? 2 : indent], + "toml/inline-table-curly-spacing": "error", + "toml/key-spacing": "error", + "toml/padding-line-between-pairs": "error", + "toml/padding-line-between-tables": "error", + "toml/quoted-keys": "error", + "toml/spaced-comment": "error", + "toml/table-bracket-spacing": "error", + } + : {}, + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/tsdoc.ts b/packages/eslint-config/src/config/plugins/tsdoc.ts index 75a2ac226..689d48adf 100644 --- a/packages/eslint-config/src/config/plugins/tsdoc.ts +++ b/packages/eslint-config/src/config/plugins/tsdoc.ts @@ -1,12 +1,23 @@ -import type { Linter } from "eslint"; - +import type { OptionsFiles, OptionsOverrides } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -const config: Linter.Config = createConfig("typescript", { - plugins: ["eslint-plugin-tsdoc"], - rules: { - "tsdoc/syntax": "error", - }, -}); +export default createConfig("ts", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const eslintPluginTsdoc = await interopDefault(import("eslint-plugin-tsdoc")); -export default config; + return [ + { + files, + plugins: { + tsdoc: eslintPluginTsdoc, + }, + rules: { + "tsdoc/syntax": "error", + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/typescript.ts b/packages/eslint-config/src/config/plugins/typescript.ts index 5865fcec9..67411a6fa 100644 --- a/packages/eslint-config/src/config/plugins/typescript.ts +++ b/packages/eslint-config/src/config/plugins/typescript.ts @@ -1,403 +1,423 @@ -import { env } from "node:process"; - -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; - -import { createConfigs } from "../../utils/create-config"; -import anolilabEslintConfig from "../../utils/eslint-config"; -import bestPracticesConfig from "../best-practices"; -import errorsConfig from "../errors"; -// eslint-disable-next-line unicorn/prevent-abbreviations -import eS6Config from "../es6"; -import styleConfig from "../style"; -import variablesConfig from "../variables"; - -// @ts-expect-error TODO: find the correct type -const bestPracticesRules = bestPracticesConfig.overrides[0].rules as Linter.RulesRecord; -// @ts-expect-error TODO: find the correct type -const errorsRules = errorsConfig.overrides[0].rules as Linter.RulesRecord; -// @ts-expect-error TODO: find the correct type -const styleRules = styleConfig.overrides[0].rules as Linter.RulesRecord; -// @ts-expect-error TODO: find the correct type -// eslint-disable-next-line unicorn/prevent-abbreviations -const eS6Rules = eS6Config.overrides[0].rules as Linter.RulesRecord; -// @ts-expect-error TODO: find the correct type -const variablesRules = variablesConfig.overrides[0].rules as Linter.RulesRecord; - -const { indent, quotes, semi } = styleRules; - -if (global.anolilabEslintConfigTypescriptPrettierRules === undefined && (hasDependency("prettier") || hasDevDependency("prettier"))) { - global.anolilabEslintConfigTypescriptPrettierRules = { - "@typescript-eslint/block-spacing": "off", - "@typescript-eslint/brace-style": "off", - "@typescript-eslint/comma-dangle": "off", - "@typescript-eslint/comma-spacing": "off", - "@typescript-eslint/func-call-spacing": "off", - "@typescript-eslint/indent": "off", - "@typescript-eslint/key-spacing": "off", - "@typescript-eslint/keyword-spacing": "off", - "@typescript-eslint/lines-around-comment": 0, - "@typescript-eslint/member-delimiter-style": "off", - "@typescript-eslint/no-extra-parens": "off", - "@typescript-eslint/no-extra-semi": "off", - "@typescript-eslint/object-curly-spacing": "off", - "@typescript-eslint/quotes": 0, - "@typescript-eslint/semi": "off", - "@typescript-eslint/space-before-blocks": "off", - "@typescript-eslint/space-before-function-paren": "off", - "@typescript-eslint/space-infix-ops": "off", - "@typescript-eslint/type-annotation-spacing": "off", +import type { + OptionsComponentExtensions, + OptionsFiles, + OptionsHasPrettier, + OptionsOverrides, + OptionsStylistic, + OptionsTypeScriptParserOptions, + OptionsTypeScriptWithTypes, + TypedFlatConfigItem, +} from "../../types"; +import { createConfig, getFilesGlobs } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; +import { bestPracticesRules } from "../best-practices"; +import { es6Rules } from "../es6"; +import { styleRules } from "../style"; +import { variablesRules } from "../variables"; + +export default createConfig< + OptionsComponentExtensions & + OptionsFiles & + OptionsHasPrettier & + OptionsOverrides & + OptionsStylistic & + OptionsTypeScriptParserOptions & + OptionsTypeScriptWithTypes +>("ts", async (config, oFiles) => { + const { + componentExts: componentExtensions = [], + files = oFiles, + overrides, + overridesTypeAware, + parserOptions, + prettier, + stylistic = true, + } = config; + + const [pluginTs, parserTs, tseslint, noForOfArrayPlugin] = await Promise.all([ + interopDefault(import("@typescript-eslint/eslint-plugin")), + interopDefault(import("@typescript-eslint/parser")), + interopDefault(import("typescript-eslint")), + interopDefault(import("eslint-plugin-no-for-of-array")), + ] as const); + + const filesTypeAware = config.filesTypeAware ?? getFilesGlobs("ts"); + const ignoresTypeAware = config.ignoresTypeAware ?? [`**/*.md/**`, ...getFilesGlobs("astro")]; + const tsconfigPath = config?.tsconfigPath ?? undefined; + const isTypeAware = tsconfigPath !== undefined; + + const makeParser = (typeAware: boolean, pFiles: string[], ignores?: string[]): TypedFlatConfigItem => { + return { + files: [...pFiles, ...componentExtensions.map(extension => `**/*.${extension}`)], + ...ignores ? { ignores } : {}, + languageOptions: { + parser: parserTs, + parserOptions: { + extraFileExtensions: componentExtensions.map(extension => `.${extension}`), + sourceType: "module", + ...typeAware + ? { + projectService: { + allowDefaultProject: ["./*.js"], + defaultProject: tsconfigPath, + }, + tsconfigRootDir: process.cwd(), + } + : {}, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...(parserOptions as any), + }, + }, + name: `anolilab/typescript/${typeAware ? "type-aware-parser" : "parser"}`, + }; }; -} -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const commaDangle = styleRules["comma-dangle"] as any[]; + const rules: TypedFlatConfigItem[] = [ + { + // Install the plugins without globs, so they can be configured separately. + name: "anolilab/typescript/setup", + plugins: { + "@typescript-eslint": pluginTs, + "no-for-of-array": noForOfArrayPlugin, + }, + }, + // assign type-aware parser for type-aware files and type-unaware parser for the rest + ...isTypeAware ? [makeParser(false, files), makeParser(true, filesTypeAware, ignoresTypeAware)] : [makeParser(false, files)], + ...(tseslint.configs.strict as TypedFlatConfigItem[]), + ]; + + if (isTypeAware) { + rules.push( + ...(tseslint.configs.strictTypeCheckedOnly as TypedFlatConfigItem[]), + { + files: [...filesTypeAware, ...componentExtensions.map(extension => `**/*.${extension}`)], + name: "anolilab/typescript/rules-type-aware", + rules: { + // Disallow type assertions that do not change the type of expression. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unnecessary-type-assertion.md + "@typescript-eslint/no-unnecessary-type-assertion": "error", + + // Disallow calling a function with a value with type any. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-argument.md + "@typescript-eslint/no-unsafe-argument": "error", + + // Disallow assigning a value with type any to variables and properties. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-assignment.md + "@typescript-eslint/no-unsafe-assignment": "error", + + // Disallow calling a value with type any. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-call.md + "@typescript-eslint/no-unsafe-call": "error", + + // Disallow member access on a value with type any. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-member-access.md + "@typescript-eslint/no-unsafe-member-access": "error", + + // Disallow returning a value with type any from a function. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-return.md + "@typescript-eslint/no-unsafe-return": "error", + + // Enforce using the nullish coalescing operator instead of logical chaining. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md + "@typescript-eslint/prefer-nullish-coalescing": "error", + + // Enforce using concise optional chain expressions instead of chained logical ands, negated logical ors, or empty objects. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-optional-chain.md + "@typescript-eslint/prefer-optional-chain": "error", + + ...overridesTypeAware, + }, + }, + { + files: getFilesGlobs("all"), + name: "anolilab/typescript/no-for-of-array/rules", + rules: { + "no-for-of-array/no-for-of-array": "error", + }, + }, + ); + } + + if (stylistic) { + rules.push(...(tseslint.configs.stylistic as TypedFlatConfigItem[])); + + if (isTypeAware) { + rules.push(...(tseslint.configs.stylisticTypeCheckedOnly as TypedFlatConfigItem[])); + } + } + + rules.push({ + files, + name: "anolilab/typescript/rules", + rules: { + // Require that function overload signatures be consecutive. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/adjacent-overload-signatures.md + "@typescript-eslint/adjacent-overload-signatures": "error", + + // Requires using either T[] for arrays (array-type) + "@typescript-eslint/array-type": [ + "error", + { + default: "array", + readonly: "generic", + }, + ], + + // Enforce specifying generic type arguments on constructor name of a constructor call. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/consistent-generic-constructors.md + "@typescript-eslint/consistent-generic-constructors": "error", + + // @TODO: Fix this rule + // Some built-in types have aliases, while some types are considered dangerous or harmful. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/ban-types.md + // Enforces that types will not to be used + // "@typescript-eslint/ban-types": [ + // "error", + // { + // types: { + // String: { message: "Use string instead", fixWith: "string" }, + // Boolean: { message: "Use boolean instead", fixWith: "boolean" }, + // Number: { message: "Use number instead", fixWith: "number" }, + // Object: { message: "Use object instead", fixWith: "object" }, + // Array: { message: "Provide a more specific type" }, + // }, + // }, + // ], + + // Enforce consistent usage of type imports. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/consistent-type-imports.md + "@typescript-eslint/consistent-type-imports": "error", + + // Require explicit accessibility modifiers on class properties and methods. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/explicit-member-accessibility.md + "@typescript-eslint/explicit-member-accessibility": "error", + + // Require explicit return and argument types on exported functions' and classes' public class methods. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md + "@typescript-eslint/explicit-module-boundary-types": "error", + + // Enforce a standard member declaration order. (member-ordering from TSLint) + "@typescript-eslint/member-ordering": [ + "error", + { + default: [ + "public-static-field", + "protected-static-field", + "private-static-field", + "public-static-method", + "protected-static-method", + "private-static-method", + "public-instance-field", + "protected-instance-field", + "private-instance-field", + "constructor", + "public-instance-method", + "protected-instance-method", + "private-instance-method", + ], + }, + ], + + // Enforce using a particular method signature syntax. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/method-signature-style.md + "@typescript-eslint/method-signature-style": "error", + + // The `@typescript-eslint/naming-convention` rule allows `leadingUnderscore` and `trailingUnderscore` settings. + // However, the existing `no-underscore-dangle` rule already takes care of this. + "@typescript-eslint/naming-convention": [ + "error", + // Allow camelCase variables (23.2), PascalCase variables (23.8), and UPPER_CASE variables (23.10) + { + format: ["camelCase", "PascalCase", "UPPER_CASE"], + selector: "variable", + }, + // Allow camelCase functions (23.2), and PascalCase functions (23.8) + { + format: ["camelCase", "PascalCase"], + selector: "function", + }, + // recommends PascalCase for classes (23.3), and although it does not make TypeScript recommendations, + // we are assuming this rule would similarly apply to anything "type like", including interfaces, type aliases, and enums + { + format: ["PascalCase"], + selector: "typeLike", + }, + ], + + // Replace 'no-array-constructor' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-array-constructor.md + "@typescript-eslint/no-array-constructor": styleRules["no-array-constructor"], -let showUnsupportedTypeScriptVersionWarning: boolean = env["DISABLE_ESLINT_WARN_UNSUPPORTED_TYPESCRIPT_VERSION"] !== "true"; + // Disallow non-null assertion in locations that may be confusing. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-confusing-non-null-assertion.md + "@typescript-eslint/no-confusing-non-null-assertion": "error", -if (anolilabEslintConfig["warn_on_unsupported_typescript_version"] !== undefined) { - showUnsupportedTypeScriptVersionWarning = anolilabEslintConfig["warn_on_unsupported_typescript_version"] as boolean; -} + // Replace 'no-dupe-class-members' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-dupe-class-members.md + "@typescript-eslint/no-dupe-class-members": es6Rules["no-dupe-class-members"], -const config: Linter.Config = createConfigs([ - { - config: { - extends: ["plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/stylistic", "plugin:@typescript-eslint/strict"], - parser: "@typescript-eslint/parser", - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - sourceType: "module", - warnOnUnsupportedTypeScriptVersion: showUnsupportedTypeScriptVersionWarning, - }, - plugins: ["@typescript-eslint"], - rules: { - // Replace 'brace-style' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/brace-style.md - "@typescript-eslint/brace-style": styleRules["brace-style"], - - // The `@typescript-eslint/naming-convention` rule allows `leadingUnderscore` and `trailingUnderscore` settings. However, the existing `no-underscore-dangle` rule already takes care of this. - "@typescript-eslint/naming-convention": [ - "error", - // Allow camelCase variables (23.2), PascalCase variables (23.8), and UPPER_CASE variables (23.10) - { - selector: "variable", - format: ["camelCase", "PascalCase", "UPPER_CASE"], - }, - // Allow camelCase functions (23.2), and PascalCase functions (23.8) - { - selector: "function", - format: ["camelCase", "PascalCase"], - }, - // recommends PascalCase for classes (23.3), and although it does not make TypeScript recommendations, - // we are assuming this rule would similarly apply to anything "type like", including interfaces, type aliases, and enums - { - selector: "typeLike", - format: ["PascalCase"], - }, - ], - - // Replace 'comma-dangle' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/comma-dangle.md - // The TypeScript version also adds 3 new options, all of which should be set to the same value as the base config - "@typescript-eslint/comma-dangle": [ - commaDangle[0], - { - ...commaDangle[1], - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access - enums: commaDangle[1].arrays, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access - generics: commaDangle[1].arrays, - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access - tuples: commaDangle[1].arrays, - }, - ], - - // Replace 'comma-spacing' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/comma-spacing.md - "@typescript-eslint/comma-spacing": styleRules["comma-spacing"], - - // Replace 'func-call-spacing' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/func-call-spacing.md - "@typescript-eslint/func-call-spacing": styleRules["func-call-spacing"], - - // Replace 'indent' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/indent.md - "@typescript-eslint/indent": indent, - - // Replace 'keyword-spacing' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/keyword-spacing.md - "@typescript-eslint/keyword-spacing": styleRules["keyword-spacing"], - - // Replace 'lines-between-class-members' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/lines-between-class-members.md - "@typescript-eslint/lines-between-class-members": ["error", "always", { exceptAfterSingleLine: false }], - - // Replace 'no-array-constructor' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-array-constructor.md - "@typescript-eslint/no-array-constructor": styleRules["no-array-constructor"], - - // Replace 'no-dupe-class-members' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-dupe-class-members.md - "@typescript-eslint/no-dupe-class-members": eS6Rules["no-dupe-class-members"], - - // Replace 'no-empty-function' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-empty-function.md - "@typescript-eslint/no-empty-function": bestPracticesRules["no-empty-function"], - - // Replace 'no-extra-parens' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-extra-parens.md - "@typescript-eslint/no-extra-parens": errorsRules["no-extra-parens"], - - // Replace 'no-extra-semi' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-extra-semi.md - "@typescript-eslint/no-extra-semi": errorsRules["no-extra-semi"], - - // Replace 'no-loop-func' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-loop-func.md - "@typescript-eslint/no-loop-func": bestPracticesRules["no-loop-func"], - - // Replace 'no-magic-numbers' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-magic-numbers.md - "@typescript-eslint/no-magic-numbers": bestPracticesRules["no-magic-numbers"], - - // Replace 'no-redeclare' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-redeclare.md - "@typescript-eslint/no-redeclare": bestPracticesRules["no-redeclare"], - - // Replace 'no-shadow' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-shadow.md - "@typescript-eslint/no-shadow": variablesRules["no-shadow"], - - // Replace 'no-unused-expressions' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-expressions.md - "@typescript-eslint/no-unused-expressions": bestPracticesRules["no-unused-expressions"], - - // Replace 'no-unused-vars' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md - "@typescript-eslint/no-unused-vars": variablesRules["no-unused-vars"], - - // Replace 'no-use-before-define' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md - "@typescript-eslint/no-use-before-define": variablesRules["no-use-before-define"], - - // Replace 'no-useless-constructor' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-useless-constructor.md - "@typescript-eslint/no-useless-constructor": eS6Rules["no-useless-constructor"], - - // Replace 'quotes' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/quotes.md - "@typescript-eslint/quotes": quotes, - - // Replace 'semi' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/semi.md - "@typescript-eslint/semi": semi, - - // Replace 'space-before-function-paren' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/space-before-function-paren.md - "@typescript-eslint/space-before-function-paren": styleRules["space-before-function-paren"], - - // Replace 'no-return-await' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/return-await.md - "@typescript-eslint/return-await": bestPracticesRules["no-return-await"], - - // Replace 'space-infix-ops' rule with '@typescript-eslint' version - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/space-infix-ops.md - "@typescript-eslint/space-infix-ops": styleRules["space-infix-ops"], - - // Enforce consistent usage of type imports. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/consistent-type-imports.md - "@typescript-eslint/consistent-type-imports": "error", - - // Require that function overload signatures be consecutive. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/adjacent-overload-signatures.md - "@typescript-eslint/adjacent-overload-signatures": "error", - - // Enforce a standard member declaration order. (member-ordering from TSLint) - "@typescript-eslint/member-ordering": [ - "error", - { - default: [ - "public-static-field", - "protected-static-field", - "private-static-field", - "public-static-method", - "protected-static-method", - "private-static-method", - "public-instance-field", - "protected-instance-field", - "private-instance-field", - "constructor", - "public-instance-method", - "protected-instance-method", - "private-instance-method", - ], - }, - ], - - // Requires using either T[] for arrays (array-type) - "@typescript-eslint/array-type": [ - "error", - { - default: "array", - readonly: "generic", - }, - ], - - // Some built-in types have aliases, while some types are considered dangerous or harmful. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/ban-types.md - // Enforces that types will not to be used - "@typescript-eslint/ban-types": [ - "error", - { - types: { - String: { message: "Use string instead", fixWith: "string" }, - Boolean: { message: "Use boolean instead", fixWith: "boolean" }, - Number: { message: "Use number instead", fixWith: "number" }, - Object: { message: "Use object instead", fixWith: "object" }, - Array: { message: "Provide a more specific type" }, - }, - }, - ], - - // Enforce constituents of a type union/intersection to be sorted alphabetically. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/sort-type-constituents.md - "@typescript-eslint/sort-type-constituents": "error", - - // Enforce using @ts-expect-error over @ts-ignore. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-ts-expect-error.md - "@typescript-eslint/prefer-ts-expect-error": "error", - - // Enforce specifying generic type arguments on constructor name of a constructor call. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/consistent-generic-constructors.md - "@typescript-eslint/consistent-generic-constructors": "error", - - // Require explicit accessibility modifiers on class properties and methods. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/explicit-member-accessibility.md - "@typescript-eslint/explicit-member-accessibility": "error", - - // Require explicit return and argument types on exported functions' and classes' public class methods. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/explicit-module-boundary-types.md - "@typescript-eslint/explicit-module-boundary-types": "error", - - // Enforce using a particular method signature syntax. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/method-signature-style.md - "@typescript-eslint/method-signature-style": "error", - - // Disallow non-null assertion in locations that may be confusing. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-confusing-non-null-assertion.md - "@typescript-eslint/no-confusing-non-null-assertion": "error", - - // Disallow duplicate enum member values. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-duplicate-enum-values.md - "@typescript-eslint/no-duplicate-enum-values": "error", - - // Disallow using to delete operator on computed key expressions. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-dynamic-delete.md - "@typescript-eslint/no-dynamic-delete": "warn", - - // Disallow extra non-null assertions. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-extra-non-null-assertion.md - "@typescript-eslint/no-extra-non-null-assertion": "error", - - // Disallow void type outside of generic or return types. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-invalid-void-type.md - "@typescript-eslint/no-invalid-void-type": "warn", - - // Enforce valid definition of new and constructor. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-misused-new.md - "@typescript-eslint/no-misused-new": "error", - - // Disallow TypeScript namespaces. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-namespace.md - "@typescript-eslint/no-namespace": "error", - - // Disallow non-null assertions in the left operand of a nullish coalescing operator. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-non-null-asserted-nullish-coalescing.md - "@typescript-eslint/no-non-null-asserted-nullish-coalescing": "warn", - - // Disallow non-null assertions after an optional chain expression. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-non-null-asserted-optional-chain.md - "@typescript-eslint/no-non-null-asserted-optional-chain": "error", - - // Disallow non-null assertions using the ! postfix operator. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-non-null-assertion.md - "@typescript-eslint/no-non-null-assertion": "error", - - // Disallow invocation of require(). - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-require-imports.md - "@typescript-eslint/no-require-imports": "error", - - // Disallow aliasing this. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-this-alias.md - "@typescript-eslint/no-this-alias": "error", - - // Disallow type assertions that do not change the type of expression. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unnecessary-type-assertion.md - "@typescript-eslint/no-unnecessary-type-assertion": "error", - - // Disallow unnecessary constraints on generic types. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unnecessary-type-constraint.md - "@typescript-eslint/no-unnecessary-type-constraint": "error", - - // Disallow calling a function with a value with type any. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-argument.md - "@typescript-eslint/no-unsafe-argument": "error", - - // Disallow assigning a value with type any to variables and properties. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-assignment.md - "@typescript-eslint/no-unsafe-assignment": "error", - - // Disallow calling a value with type any. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-call.md - "@typescript-eslint/no-unsafe-call": "error", - - // Disallow unsafe declaration merging. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-declaration-merging.md - "@typescript-eslint/no-unsafe-declaration-merging": "error", + // Disallow duplicate enum member values. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-duplicate-enum-values.md + "@typescript-eslint/no-duplicate-enum-values": "error", - // Disallow member access on a value with type any. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-member-access.md - "@typescript-eslint/no-unsafe-member-access": "error", + // Disallow using to delete operator on computed key expressions. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-dynamic-delete.md + "@typescript-eslint/no-dynamic-delete": "warn", - // Disallow returning a value with type any from a function. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-return.md - "@typescript-eslint/no-unsafe-return": "error", + // Replace 'no-empty-function' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-empty-function.md + "@typescript-eslint/no-empty-function": bestPracticesRules["no-empty-function"], - // Disallow empty exports that don't change anything in a module file. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-useless-empty-export.md - "@typescript-eslint/no-useless-empty-export": "error", + // Disallow extra non-null assertions. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-extra-non-null-assertion.md + "@typescript-eslint/no-extra-non-null-assertion": "error", - // Enforce non-null assertions over explicit type casts. This rule is disabled by @typescript-eslint/no-non-null-assertion. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/non-nullable-type-assertion-style.md - "@typescript-eslint/non-nullable-type-assertion-style": "off", + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-import-type-side-effects.md + "@typescript-eslint/no-import-type-side-effects": "error", - // Require each enum member value to be explicitly initialized. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-enum-initializers.md - "@typescript-eslint/prefer-enum-initializers": "error", + // Disallow void type outside of generic or return types. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-invalid-void-type.md + "@typescript-eslint/no-invalid-void-type": "warn", - // Enforce using function types instead of interfaces with call signatures. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-function-type.md - "@typescript-eslint/prefer-function-type": "error", + // Replace 'no-loop-func' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-loop-func.md + "@typescript-eslint/no-loop-func": bestPracticesRules["no-loop-func"], - // Enforce using the nullish coalescing operator instead of logical chaining. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md - "@typescript-eslint/prefer-nullish-coalescing": "error", + // Replace 'no-magic-numbers' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-magic-numbers.md + "@typescript-eslint/no-magic-numbers": bestPracticesRules["no-magic-numbers"], - // Enforce using concise optional chain expressions instead of chained logical ands, negated logical ors, or empty objects. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-optional-chain.md - "@typescript-eslint/prefer-optional-chain": "error", + // Enforce valid definition of new and constructor. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-misused-new.md + "@typescript-eslint/no-misused-new": "error", - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-import-type-side-effects.md - "@typescript-eslint/no-import-type-side-effects": "error", + // Disallow TypeScript namespaces. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-namespace.md + "@typescript-eslint/no-namespace": "error", - // Disable rules that are handled by prettier - ...global.anolilabEslintConfigTypescriptPrettierRules, - }, + // Disallow non-null assertions in the left operand of a nullish coalescing operator. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-non-null-asserted-nullish-coalescing.md + "@typescript-eslint/no-non-null-asserted-nullish-coalescing": "warn", + + // Disallow non-null assertions after an optional chain expression. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-non-null-asserted-optional-chain.md + "@typescript-eslint/no-non-null-asserted-optional-chain": "error", + + // Disallow non-null assertions using the ! postfix operator. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-non-null-assertion.md + "@typescript-eslint/no-non-null-assertion": "error", + + // Replace 'no-redeclare' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-redeclare.md + "@typescript-eslint/no-redeclare": bestPracticesRules["no-redeclare"], + + // Disallow invocation of require(). + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-require-imports.md + "@typescript-eslint/no-require-imports": "error", + + // Replace 'no-shadow' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-shadow.md + "@typescript-eslint/no-shadow": variablesRules["no-shadow"], + + // Disallow aliasing this. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-this-alias.md + "@typescript-eslint/no-this-alias": "error", + + // Disallow unnecessary constraints on generic types. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unnecessary-type-constraint.md + "@typescript-eslint/no-unnecessary-type-constraint": "error", + + // Disallow unsafe declaration merging. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unsafe-declaration-merging.md + "@typescript-eslint/no-unsafe-declaration-merging": "error", + + // Replace 'no-unused-expressions' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-expressions.md + "@typescript-eslint/no-unused-expressions": bestPracticesRules["no-unused-expressions"], + + // Replace 'no-unused-vars' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md + "@typescript-eslint/no-unused-vars": variablesRules["no-unused-vars"], + + // Replace 'no-use-before-define' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md + "@typescript-eslint/no-use-before-define": variablesRules["no-use-before-define"], + + // Replace 'no-useless-constructor' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-useless-constructor.md + "@typescript-eslint/no-useless-constructor": es6Rules["no-useless-constructor"], + + // Disallow empty exports that don't change anything in a module file. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-useless-empty-export.md + "@typescript-eslint/no-useless-empty-export": "error", + + // Enforce non-null assertions over explicit type casts. This rule is disabled by @typescript-eslint/no-non-null-assertion. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/non-nullable-type-assertion-style.md + "@typescript-eslint/non-nullable-type-assertion-style": "off", + + // Require each enum member value to be explicitly initialized. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-enum-initializers.md + "@typescript-eslint/prefer-enum-initializers": "error", + + // Enforce using function types instead of interfaces with call signatures. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-function-type.md + "@typescript-eslint/prefer-function-type": "error", + + // Disabled to use faster alternatives. + "@typescript-eslint/prefer-string-starts-ends-with": "off", + + // Enforce using @ts-expect-error over @ts-ignore. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-ts-expect-error.md + "@typescript-eslint/prefer-ts-expect-error": "error", + + // Replace 'no-return-await' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/return-await.md + "@typescript-eslint/return-await": bestPracticesRules["no-return-await"], + + // Replace 'semi' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/semi.md + "@typescript-eslint/semi": styleRules["semi"], + + // Enforce constituents of a type union/intersection to be sorted alphabetically. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/sort-type-constituents.md + "@typescript-eslint/sort-type-constituents": "error", + + // Replace 'space-before-function-paren' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/space-before-function-paren.md + "@typescript-eslint/space-before-function-paren": styleRules["space-before-function-paren"], + + // Replace 'space-infix-ops' rule with '@typescript-eslint' version + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/space-infix-ops.md + "@typescript-eslint/space-infix-ops": styleRules["space-infix-ops"], + + ...overrides, + + // Disable rules that are handled by prettier + ...prettier + ? { + "@typescript-eslint/block-spacing": "off", + "@typescript-eslint/brace-style": "off", + "@typescript-eslint/comma-dangle": "off", + "@typescript-eslint/comma-spacing": "off", + "@typescript-eslint/func-call-spacing": "off", + "@typescript-eslint/indent": "off", + "@typescript-eslint/key-spacing": "off", + "@typescript-eslint/keyword-spacing": "off", + "@typescript-eslint/lines-around-comment": 0, + "@typescript-eslint/member-delimiter-style": "off", + "@typescript-eslint/no-extra-parens": "off", + "@typescript-eslint/no-extra-semi": "off", + "@typescript-eslint/object-curly-spacing": "off", + "@typescript-eslint/quotes": 0, + "@typescript-eslint/semi": "off", + "@typescript-eslint/space-before-blocks": "off", + "@typescript-eslint/space-before-function-paren": "off", + "@typescript-eslint/space-infix-ops": "off", + "@typescript-eslint/type-annotation-spacing": "off", + } + : {}, }, - type: "typescript", - }, -]); + }); -export default config; + return rules; +}); diff --git a/packages/eslint-config/src/config/plugins/unicorn.ts b/packages/eslint-config/src/config/plugins/unicorn.ts index 85fd1e348..2900fe39b 100644 --- a/packages/eslint-config/src/config/plugins/unicorn.ts +++ b/packages/eslint-config/src/config/plugins/unicorn.ts @@ -1,75 +1,104 @@ -import { hasDependency, hasDevDependency, packageIsTypeModule } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; - -import indent from "../../utils/indent"; - -if (global.anolilabEslintConfigUnicornPrettierRules === undefined && (hasDependency("prettier") || hasDevDependency("prettier"))) { - global.anolilabEslintConfigUnicornPrettierRules = { - "unicorn/empty-brace-spaces": "off", - "unicorn/no-nested-ternary": "off", - "unicorn/number-literal-case": "off", - "unicorn/template-indent": "off", - }; -} - -// @see https://github.com/sindresorhus/eslint-plugin-unicorn -const config: Linter.Config = { - extends: ["plugin:unicorn/recommended"], - overrides: [ +import globals from "globals"; + +import type { + OptionsFiles, + OptionsHasPrettier, + OptionsOverrides, + OptionsPackageJson, + OptionsStylistic, +} from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig("all", async (config, oFiles) => { + const { + files = oFiles, + overrides, + packageJson, + prettier, + stylistic = true, + } = config; + + const { indent = 4 } = typeof stylistic === "boolean" ? {} : stylistic; + + const pluginUnicorn = await interopDefault(import("eslint-plugin-unicorn")); + + return [ { - files: ["tsconfig.dev.json", "tsconfig.prod.json"], - rules: { - "unicorn/prevent-abbreviations": "off", + languageOptions: { + globals: globals.builtin, + }, + name: "anolilab/unicorn/plugin", + plugins: { + unicorn: pluginUnicorn, }, }, { - files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], + files, + name: "anolilab/unicorn/rules", rules: { - "unicorn/import-style": "off", - }, - }, - ], - plugins: ["unicorn"], - rules: { - // TODO: Temporarily disabled as the rule is buggy. - "function-call-argument-newline": "off", - // Disabled because of eslint-plugin-regexp - "unicorn/better-regex": "off", - // TODO: Disabled for now until it becomes more stable: https://github.com/sindresorhus/eslint-plugin-unicorn/search?q=consistent-destructuring+is:issue&state=open&type=issues - "unicorn/consistent-destructuring": "off", - // TODO: Remove this override when the rule is more stable. - "unicorn/consistent-function-scoping": "off", - - "unicorn/filename-case": [ - "error", - { - case: "kebabCase", - ignore: [/(FUNDING\.yml|README\.md|CHANGELOG\.md|CONTRIBUTING\.md|CODE_OF_CONDUCT\.md|SECURITY\.md|LICENSE)/u], - }, - ], + ...pluginUnicorn.configs["flat/recommended"].rules, + + // Disabled because of eslint-plugin-regexp + "unicorn/better-regex": "off", + // TODO: Disabled for now until it becomes more stable: https://github.com/sindresorhus/eslint-plugin-unicorn/search?q=consistent-destructuring+is:issue&state=open&type=issues + "unicorn/consistent-destructuring": "off", + // TODO: Remove this override when the rule is more stable. + "unicorn/consistent-function-scoping": "off", - "unicorn/no-array-for-each": "off", + "unicorn/filename-case": [ + "error", + { + case: "kebabCase", + ignore: [/(FUNDING\.yml|README\.md|CHANGELOG\.md|CONTRIBUTING\.md|CODE_OF_CONDUCT\.md|SECURITY\.md|LICENSE)/u], + }, + ], - // TODO: Disabled for now as I don't have time to deal with the backslash that might come from this. Try to enable this rule in 2024. - "unicorn/no-null": "off", + "unicorn/no-array-for-each": "off", - // TODO: Temporarily disabled until it becomes more mature. - "unicorn/no-useless-undefined": "off", + // TODO: Temporarily disabled until it becomes more mature. + "unicorn/no-useless-undefined": "off", - // It will be disabled in the next version of eslint-plugin-unicorn. - "unicorn/prefer-json-parse-buffer": "off", + // Disabled to use faster alternatives. + "unicorn/prefer-at": "off", - "unicorn/prefer-module": packageIsTypeModule ? "error" : "off", + // It will be disabled in the next version of eslint-plugin-unicorn. + "unicorn/prefer-json-parse-buffer": "off", - "unicorn/prefer-node-protocol": "error", + "unicorn/prefer-module": packageJson.type === "module" ? "error" : "off", - // We only enforce it for single-line statements to not be too opinionated. - "unicorn/prefer-ternary": ["error", "only-single-line"], + "unicorn/prefer-node-protocol": "error", - "unicorn/template-indent": ["error", { indent }], + // We only enforce it for single-line statements to not be too opinionated. + "unicorn/prefer-ternary": ["error", "only-single-line"], - ...global.anolilabEslintConfigUnicornPrettierRules, - }, -}; + ...prettier + ? { + "unicorn/empty-brace-spaces": "off", + "unicorn/no-nested-ternary": "off", + "unicorn/number-literal-case": "off", + "unicorn/template-indent": "off", + } + : { + "unicorn/template-indent": ["error", { indent }], + }, -export default config; + ...overrides, + }, + }, + { + files: ["tsconfig.dev.json", "tsconfig.prod.json"], + name: "anolilab/unicorn/tsconfig-overrides", + rules: { + "unicorn/prevent-abbreviations": "off", + }, + }, + { + files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], + name: "anolilab/unicorn/ts-overrides", + rules: { + "unicorn/import-style": "off", + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/unocss.ts b/packages/eslint-config/src/config/plugins/unocss.ts new file mode 100644 index 000000000..d64d21d03 --- /dev/null +++ b/packages/eslint-config/src/config/plugins/unocss.ts @@ -0,0 +1,32 @@ +import type { OptionsUnoCSS, TypedFlatConfigItem } from "../../types"; +import interopDefault from "../../utils/interop-default"; + +const unocss = async (options: OptionsUnoCSS): Promise => { + const { attributify = true, strict = false } = options; + + const pluginUnoCSS = await interopDefault(import("@unocss/eslint-plugin")); + + return [ + { + name: "anolilab/unocss", + plugins: { + unocss: pluginUnoCSS, + }, + rules: { + "unocss/order": "warn", + ...attributify + ? { + "unocss/order-attributify": "warn", + } + : {}, + ...strict + ? { + "unocss/blocklist": "error", + } + : {}, + }, + }, + ]; +}; + +export default unocss; diff --git a/packages/eslint-config/src/config/plugins/unused-imports.ts b/packages/eslint-config/src/config/plugins/unused-imports.ts new file mode 100644 index 000000000..3b4d1a3fb --- /dev/null +++ b/packages/eslint-config/src/config/plugins/unused-imports.ts @@ -0,0 +1,32 @@ +import type { OptionsFiles, OptionsIsInEditor } from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; + +export default createConfig("js", async (config, oFiles) => { + const { files = oFiles, isInEditor } = config; + + const pluginUnusedImports = await interopDefault(import("eslint-plugin-unused-imports")); + + return [ + { + files, + name: "anolilab/unused-imports/rules", + plugins: { + "unused-imports": pluginUnusedImports, + }, + rules: { + "unused-imports/no-unused-imports": isInEditor ? "off" : "error", + "unused-imports/no-unused-vars": [ + "error", + { + args: "after-used", + argsIgnorePattern: "^_", + ignoreRestSiblings: true, + vars: "all", + varsIgnorePattern: "^_", + }, + ], + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/validate-jsx-nesting.ts b/packages/eslint-config/src/config/plugins/validate-jsx-nesting.ts index 9d037be12..8913816e1 100644 --- a/packages/eslint-config/src/config/plugins/validate-jsx-nesting.ts +++ b/packages/eslint-config/src/config/plugins/validate-jsx-nesting.ts @@ -1,13 +1,25 @@ -import type { Linter } from "eslint"; - +import type { OptionsFiles, OptionsOverrides } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; // @see https://github.com/francoismassart/eslint-plugin-tailwindcss, -const config: Linter.Config = createConfig("jsx_and_tsx", { - plugins: ["validate-jsx-nesting"], - rules: { - "validate-jsx-nesting/no-invalid-jsx-nesting": "error", - }, -}); +export default createConfig("jsx_and_tsx", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const validateJsxNestingPlugin = await interopDefault(import("eslint-plugin-validate-jsx-nesting")); -export default config; + return [ + { + files, + name: "anolilab/validate-jsx-nesting/setup", + plugins: { + "validate-jsx-nesting": validateJsxNestingPlugin, + }, + rules: { + "validate-jsx-nesting/no-invalid-jsx-nesting": "error", + + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/vitest.ts b/packages/eslint-config/src/config/plugins/vitest.ts index 371c38077..3c883791b 100644 --- a/packages/eslint-config/src/config/plugins/vitest.ts +++ b/packages/eslint-config/src/config/plugins/vitest.ts @@ -1,51 +1,127 @@ -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; - -if (!global.hasAnolilabEsLintVitestGlobalsPlugin) { - global.hasAnolilabEsLintVitestGlobalsPlugin = hasDependency("eslint-plugin-vitest-globals") || hasDevDependency("eslint-plugin-vitest-globals"); -} - -const plugins = ["plugin:vitest/recommended", "plugin:vitest/all"]; - -if (global.hasAnolilabEsLintVitestGlobalsPlugin) { - plugins.push("plugin:vitest-globals/recommended"); -} - -const config: Linter.Config = { - overrides: [ - { - extends: plugins, - files: ["**/__tests__/**/*.?(c|m)[jt]s?(x)", "**/?(*.){test,spec}.?(c|m)[jt]s?(x)"], - plugins: ["vitest"], - // TODO: transform all rules to error +import type { + OptionsFiles, + OptionsHasPrettier, + OptionsIsInEditor, + OptionsOverrides, + OptionsTypeScriptWithTypes, +} from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; +import vitestGlobals from "../../utils/vitest-globals"; + +// Hold the reference so we don't redeclare the plugin on each call +// eslint-disable-next-line @typescript-eslint/no-explicit-any +let pluginTest: any; + +export default createConfig( + "vitest", + async (config, oFiles) => { + const { + files = oFiles, + isInEditor = false, + overrides, + prettier, + tsconfigPath, + } = config; + + const [vitestPlugin, noOnlyTestsPlugin] = await Promise.all([ + interopDefault(import("@vitest/eslint-plugin")), + // @ts-expect-error missing types + interopDefault(import("eslint-plugin-no-only-tests")), + ] as const); + + pluginTest = pluginTest || { + ...vitestPlugin, rules: { - // Enforce a maximum number of expect per test - // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/max-expects.md - // This rule should be set on the root config - "vitest/max-expects": "off", - - // Enforce valid expect() usage - // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-hooks.md - "vitest/no-hooks": "off", - - // Disallow setup and teardown hooks - // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-mocks-import.md - "vitest/no-mocks-import": "off", - - // Disallow importing from mocks directory - // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-restricted-vi-methods.md - "vitest/no-restricted-vi-methods": "off", - - // Disallow specific vi. methods - // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-standalone-expect.md - "vitest/no-standalone-expect": "error", - - // Disallow using expect outside of it or test blocks - // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/valid-expect.md - "vitest/valid-expect": ["error", { alwaysAwait: true, maxArgs: 2, minArgs: 1 }], + ...vitestPlugin.rules, + // extend `test/no-only-tests` rule + ...noOnlyTestsPlugin.rules, + }, + }; + + return [ + { + name: "anolilab/vitest/setup", + plugins: { + vitest: pluginTest, + }, }, - }, - ], -}; + { + files, + ...tsconfigPath + ? { + ...vitestPlugin.configs.env, + settings: { + vitest: { + typecheck: true, + }, + }, + } + : {}, + languageOptions: { + globals: { + ...vitestGlobals, + }, + }, + name: "anolilab/vitest/rules", + rules: { + ...vitestPlugin.configs.all.rules, + ...vitestPlugin.configs.recommended.rules, + + "@typescript-eslint/explicit-function-return-type": "off", + + // Disables + "antfu/no-top-level-await": "off", + + "n/prefer-global/process": "off", + + "no-unused-expressions": "off", -export default config; + "vitest/consistent-test-it": ["error", { fn: "it", withinDescribe: "it" }], + + // Enforce a maximum number of expect per test + // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/max-expects.md + // This rule should be set on the root config + "vitest/max-expects": "off", + + // Enforce valid expect() usage + // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-hooks.md + "vitest/no-hooks": "off", + + // Disallow setup and teardown hooks + // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-mocks-import.md + "vitest/no-mocks-import": "off", + + "vitest/no-only-tests": isInEditor ? "off" : "error", + + // Disallow importing from mocks directory + // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-restricted-vi-methods.md + "vitest/no-restricted-vi-methods": "off", + + // Disallow specific vi. methods + // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/no-standalone-expect.md + "vitest/no-standalone-expect": "error", + + // Disallow using expect outside of it or test blocks + // https://github.com/veritem/eslint-plugin-vitest/blob/main/docs/rules/valid-expect.md + "vitest/valid-expect": ["error", { alwaysAwait: true, maxArgs: 2, minArgs: 1 }], + + ...overrides, + + ...prettier + ? { + "vitest/padding-around-after-all-blocks": "off", + "vitest/padding-around-after-each-blocks": "off", + "vitest/padding-around-all": "off", + "vitest/padding-around-before-all-blocks": "off", + "vitest/padding-around-before-each-blocks": "off", + "vitest/padding-around-describe-blocks": "off", + "vitest/padding-around-expect-blocks": "off", + "vitest/padding-around-test-blocks": "off", + } + : {}, + }, + }, + ]; + }, +); diff --git a/packages/eslint-config/src/config/plugins/yml.ts b/packages/eslint-config/src/config/plugins/yml.ts index 220b9ee76..b9ef1f8df 100644 --- a/packages/eslint-config/src/config/plugins/yml.ts +++ b/packages/eslint-config/src/config/plugins/yml.ts @@ -1,24 +1,66 @@ -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; -import type { Linter } from "eslint"; +import type { + OptionsFiles, + OptionsHasPrettier, + OptionsOverrides, + OptionsStylistic, +} from "../../types"; +import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -import indent from "../../utils/indent"; +export default createConfig("yaml", async (options, oFiles) => { + const { + files = oFiles, + overrides = {}, + prettier, + stylistic = true, + } = options; -if (!global.hasAnolilabEsLintConfigPrettier && (hasDependency("prettier") || hasDevDependency("prettier"))) { - global.hasAnolilabEsLintConfigPrettier = true; -} + const { indent = 4, quotes = "double" } = typeof stylistic === "boolean" ? {} : stylistic; -const config: Linter.Config = { - overrides: [ + const [pluginYaml, parserYaml] = await Promise.all([interopDefault(import("eslint-plugin-yml")), interopDefault(import("yaml-eslint-parser"))] as const); + + return [ { - extends: ["plugin:yml/recommended", ...(global.hasAnolilabEsLintConfigPrettier ? ["plugin:yml/prettier"] : [])], - files: ["**/*.yaml", "**/*.yml"], - parser: "yaml-eslint-parser", + files, + languageOptions: { + parser: parserYaml, + }, + name: "anolilab/yaml", + plugins: { + yaml: pluginYaml, + }, rules: { - indent: [global.hasAnolilabEsLintConfigPrettier ? "off" : "error", indent], - "spaced-comment": "off", + "@stylistic/spaced-comment": "off", + + "yaml/block-mapping": "error", + "yaml/block-sequence": "error", + "yaml/no-empty-key": "error", + "yaml/no-empty-sequence-entry": "error", + "yaml/no-irregular-whitespace": "error", + "yaml/plain-scalar": "error", + + "yaml/vue-custom-block/no-parsing-error": "error", + + ...stylistic + ? { + "yaml/block-mapping-question-indicator-newline": "error", + "yaml/block-sequence-hyphen-indicator-newline": "error", + "yaml/flow-mapping-curly-newline": "error", + "yaml/flow-mapping-curly-spacing": "error", + "yaml/flow-sequence-bracket-newline": "error", + "yaml/flow-sequence-bracket-spacing": "error", + "yaml/indent": [prettier ? "off" : "error", indent === "tab" ? 2 : indent], + "yaml/key-spacing": "error", + "yaml/no-tab-indent": "error", + "yaml/quotes": ["error", { avoidEscape: true, prefer: quotes === "backtick" ? "single" : quotes }], + "yaml/spaced-comment": "error", + } + : {}, + + ...prettier ? pluginYaml.configs.prettier.rules : {}, + + ...overrides, }, }, - ], -}; - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/you-dont-need-lodash-underscore.ts b/packages/eslint-config/src/config/plugins/you-dont-need-lodash-underscore.ts index 7c90a6cc1..f5ec38558 100644 --- a/packages/eslint-config/src/config/plugins/you-dont-need-lodash-underscore.ts +++ b/packages/eslint-config/src/config/plugins/you-dont-need-lodash-underscore.ts @@ -1,9 +1,24 @@ -import type { Linter } from "eslint"; +import { fixupPluginRules } from "@eslint/compat"; +import type { OptionsFiles, OptionsOverrides } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -const config: Linter.Config = createConfig("all", { - extends: ["plugin:you-dont-need-lodash-underscore/compatible"], -}); +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides } = config; + + const pluginYouDontNeedLodashUnderscore = await interopDefault(import("eslint-plugin-you-dont-need-lodash-underscore")); -export default config; + return [ + { + files, + plugins: { + "you-dont-need-lodash-underscore": fixupPluginRules(pluginYouDontNeedLodashUnderscore), + }, + rules: { + ...pluginYouDontNeedLodashUnderscore.configs["all"].rules, + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/plugins/you-dont-need-momentjs.ts b/packages/eslint-config/src/config/plugins/you-dont-need-momentjs.ts deleted file mode 100644 index fdccbf70b..000000000 --- a/packages/eslint-config/src/config/plugins/you-dont-need-momentjs.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { Linter } from "eslint"; - -import { createConfig } from "../../utils/create-config"; - -const config: Linter.Config = createConfig("all", { - extends: ["plugin:you-dont-need-momentjs/recommended"], -}); - -export default config; diff --git a/packages/eslint-config/src/config/plugins/zod.ts b/packages/eslint-config/src/config/plugins/zod.ts index c9f91efcc..c57b824e9 100644 --- a/packages/eslint-config/src/config/plugins/zod.ts +++ b/packages/eslint-config/src/config/plugins/zod.ts @@ -1,13 +1,23 @@ -import type { Linter } from "eslint"; - +import type { OptionsFiles, OptionsOverrides } from "../../types"; import { createConfig } from "../../utils/create-config"; +import interopDefault from "../../utils/interop-default"; -const config: Linter.Config = createConfig("all", { - plugins: ["zod"], - rules: { - "zod/prefer-enum": "error", - "zod/require-strict": "error", - }, -}); +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, overrides } = config; -export default config; + const zodPlugin = await interopDefault(import("eslint-plugin-zod")); + + return [ + { + files, + plugins: { + zod: zodPlugin, + }, + rules: { + "zod/prefer-enum": "error", + "zod/require-strict": "error", + ...overrides, + }, + }, + ]; +}); diff --git a/packages/eslint-config/src/config/style.ts b/packages/eslint-config/src/config/style.ts index c9fd7a456..8ea3eef41 100644 --- a/packages/eslint-config/src/config/style.ts +++ b/packages/eslint-config/src/config/style.ts @@ -1,724 +1,598 @@ -import { hasDependency, hasDevDependency } from "@anolilab/package-json-utils"; import type { Linter } from "eslint"; -import { createConfigs } from "../utils/create-config"; -import indent from "../utils/indent"; - -if (!global.hasAnolilabEsLintConfigPrettier && (hasDependency("prettier") || hasDevDependency("prettier"))) { - global.hasAnolilabEsLintConfigPrettier = true; -} - -let prettierRules: Linter.Config["rules"] = {}; - -if (global.hasAnolilabEsLintConfigPrettier) { - prettierRules = { - // The rest are rules that you never need to enable when using Prettier. - "array-bracket-newline": "off", - "array-bracket-spacing": "off", - "array-element-newline": "off", - "arrow-parens": "off", - "arrow-spacing": "off", - "block-spacing": "off", - "brace-style": "off", - "comma-dangle": "off", - - "comma-spacing": "off", - "comma-style": "off", - "computed-property-spacing": "off", - // script can distinguish them.) - curly: 0, - "dot-location": "off", - "eol-last": "off", - "func-call-spacing": "off", - "function-call-argument-newline": "off", - "function-paren-newline": "off", - "generator-star-spacing": "off", - "implicit-arrow-linebreak": "off", - indent: "off", - "jsx-quotes": "off", - "key-spacing": "off", - "keyword-spacing": "off", - "linebreak-style": "off", - "lines-around-comment": 0, - "max-len": 0, - "max-statements-per-line": "off", - "multiline-ternary": "off", - "new-parens": "off", - "newline-per-chained-call": "off", - "no-confusing-arrow": 0, - "no-extra-parens": "off", - "no-extra-semi": "off", - "no-floating-decimal": "off", - "no-mixed-operators": 0, - "no-mixed-spaces-and-tabs": "off", - "no-multi-spaces": "off", - "no-multiple-empty-lines": "off", - "no-tabs": 0, - "no-trailing-spaces": "off", - "no-unexpected-multiline": 0, - "no-whitespace-before-property": "off", - "nonblock-statement-body-position": "off", - "object-curly-newline": "off", - "object-curly-spacing": "off", - "object-property-newline": "off", - "one-var-declaration-per-line": "off", - "operator-linebreak": "off", - "padded-blocks": "off", - "quote-props": "off", - quotes: 0, - "rest-spread-spacing": "off", - semi: "off", - "semi-spacing": "off", - "semi-style": "off", - "space-before-blocks": "off", - "space-before-function-paren": "off", - "space-in-parens": "off", - "space-unary-ops": "off", - "switch-colon-spacing": "off", - "template-curly-spacing": "off", - "template-tag-spacing": "off", - "wrap-iife": "off", - "wrap-regex": "off", - "yield-star-spacing": "off", - }; -} - -const config: Linter.Config = createConfigs([ - { - config: { - rules: { - // enforce line breaks after opening and before closing array brackets - // https://eslint.org/docs/rules/array-bracket-newline - "array-bracket-newline": "off", - - // enforce line breaks between array elements - // enforce spacing inside array brackets - "array-bracket-spacing": ["error", "never"], - - // https://eslint.org/docs/rules/array-element-newline - "array-element-newline": "off", - - // enforce spacing inside single-line blocks - // https://eslint.org/docs/rules/block-spacing - "block-spacing": ["error", "always"], - - // enforce one true brace style - "brace-style": ["error", "1tbs", { allowSingleLine: true }], - - // require camel case names - camelcase: ["error", { ignoreDestructuring: false, properties: "never" }], - - // enforce or disallow capitalization of the first letter of a comment - // https://eslint.org/docs/rules/capitalized-comments - "capitalized-comments": [ - "off", - "never", - { - block: { - ignoreConsecutiveComments: true, - ignoreInlineComments: true, - ignorePattern: ".*", - }, - line: { - ignoreConsecutiveComments: true, - ignoreInlineComments: true, - ignorePattern: ".*", - }, - }, - ], - - // require trailing commas in multiline object literals - "comma-dangle": [ - "error", - { - arrays: "always-multiline", - exports: "always-multiline", - functions: "always-multiline", - imports: "always-multiline", - objects: "always-multiline", - }, - ], - - // enforce spacing before and after comma - "comma-spacing": ["error", { after: true, before: false }], - - // enforce one true comma style - "comma-style": [ - "error", - "last", - { - exceptions: { - ArrayExpression: false, - ArrayPattern: false, - ArrowFunctionExpression: false, - CallExpression: false, - FunctionDeclaration: false, - FunctionExpression: false, - ImportDeclaration: false, - NewExpression: false, - ObjectExpression: false, - ObjectPattern: false, - VariableDeclaration: false, - }, - }, - ], - - // disallow padding inside computed properties - "computed-property-spacing": ["error", "never"], - - // enforces consistent naming when capturing the current execution context - "consistent-this": "off", - - // enforce that default parameters should come last - "default-param-last": ["error"], - - // enforce newline at the end of file, with no multiple empty lines - "eol-last": ["error", "always"], - - // https://eslint.org/docs/rules/func-call-spacing - "func-call-spacing": ["error", "never"], - - // enforce spacing between functions and their invocations - // https://eslint.org/docs/rules/func-name-matching - "func-name-matching": [ - "off", - "always", - { - considerPropertyDescriptor: true, - includeCommonJSModuleExports: false, - }, - ], - - // requires function names to match the name of the variable or property to which they are - // assigned - // https://eslint.org/docs/rules/func-names - "func-names": ["error", "as-needed"], - - // require function expressions to have a name - // https://eslint.org/docs/rules/func-style - "func-style": ["error", "expression"], - - // enforces use of function declarations or expressions - // https://eslint.org/docs/rules/function-call-argument-newline - "function-call-argument-newline": ["error", "consistent"], - - // enforce consistent line breaks inside function parentheses - // https://eslint.org/docs/rules/function-paren-newline - "function-paren-newline": ["error", "consistent"], - - // Blacklist certain identifiers to prevent them being used - // https://eslint.org/docs/rules/id-blacklist - "id-blacklist": "error", - - // disallow specified identifiers - // https://eslint.org/docs/rules/id-denylist - "id-denylist": "off", - - // this option enforces minimum and maximum identifier lengths - // (variable names, property names etc.) - "id-length": "off", - - // require identifiers to match the provided regular expression - "id-match": "off", - - // Enforce the location of arrow function bodies with implicit returns - // https://eslint.org/docs/rules/implicit-arrow-linebreak - "implicit-arrow-linebreak": ["error", "beside"], - - // this option sets a specific tab width for your code - // https://eslint.org/docs/rules/indent - indent: [ - "error", - indent, - { - ArrayExpression: 1, - CallExpression: { - arguments: 1, - }, - // MemberExpression: null, - FunctionDeclaration: { - body: 1, - parameters: 1, - }, - FunctionExpression: { - body: 1, - parameters: 1, - }, - ImportDeclaration: 1, - ObjectExpression: 1, - SwitchCase: 1, - VariableDeclarator: 1, - flatTernaryExpressions: false, - ignoreComments: false, - // list derived from https://github.com/benjamn/ast-types/blob/HEAD/def/jsx.js - ignoredNodes: [ - "JSXElement", - "JSXElement > *", - "JSXAttribute", - "JSXIdentifier", - "JSXNamespacedName", - "JSXMemberExpression", - "JSXSpreadAttribute", - "JSXExpressionContainer", - "JSXOpeningElement", - "JSXClosingElement", - "JSXFragment", - "JSXOpeningFragment", - "JSXClosingFragment", - "JSXText", - "JSXEmptyExpression", - "JSXSpreadChild", - ], - outerIIFEBody: 1, - }, - ], - - // specify whether double or single quotes should be used in JSX attributes - // https://eslint.org/docs/rules/jsx-quotes - "jsx-quotes": ["off", "prefer-double"], - - // enforces spacing between keys and values in object literal properties - "key-spacing": ["error", { afterColon: true, beforeColon: false }], - - // require a space before & after certain keywords - "keyword-spacing": [ - "error", - { - after: true, - before: true, - overrides: { - case: { after: true }, - return: { after: true }, - throw: { after: true }, - }, - }, - ], - - // enforce position of line comments - // https://eslint.org/docs/rules/line-comment-position - "line-comment-position": "off", - - // disallow mixed 'LF' and 'CRLF' as linebreaks - // https://eslint.org/docs/rules/linebreak-style - "linebreak-style": ["error", "unix"], - - // require or disallow an empty line between class members - // enforces empty lines around comments - "lines-around-comment": "off", - - // https://eslint.org/docs/rules/lines-around-directive - "lines-around-directive": [ - "error", - { - after: "always", - before: "always", - }, - ], - - // specify the maximum depth that blocks can be nested - "max-depth": ["off", 4], - - // specify the maximum length of a line in your program - // https://eslint.org/docs/rules/max-len - "max-len": [ - "error", - 160, - 2, - { - ignoreComments: false, - ignoreRegExpLiterals: true, - ignoreStrings: true, - ignoreTemplateLiterals: true, - ignoreUrls: true, - }, - ], - - // specify the max number of lines in a file - // https://eslint.org/docs/rules/max-lines - "max-lines": [ - "off", - { - max: 300, - skipBlankLines: true, - skipComments: true, - }, - ], - - // enforce a maximum function length - // https://eslint.org/docs/rules/max-lines-per-function - "max-lines-per-function": [ - "off", - { - IIFEs: true, - max: 50, - skipBlankLines: true, - skipComments: true, - }, - ], - - // specify the maximum depth callbacks can be nested - "max-nested-callbacks": "off", - - // limits the number of parameters that can be used in the function declaration. - "max-params": ["off", 3], - - // specify the maximum number of statement allowed in a function - "max-statements": ["off", 10], - - // restrict the number of statements per line - // https://eslint.org/docs/rules/max-statements-per-line - "max-statements-per-line": ["off", { max: 1 }], - - // enforce a particular style for multiline comments - // https://eslint.org/docs/rules/multiline-comment-style - "multiline-comment-style": ["off", "starred-block"], - - // require multiline ternary - // https://eslint.org/docs/rules/multiline-ternary - // TODO: enable? - "multiline-ternary": ["off", "never"], - - // require a capital letter for constructors - "new-cap": [ - "error", - { - capIsNew: false, - capIsNewExceptions: ["Immutable.Map", "Immutable.Set", "Immutable.List"], - newIsCap: true, - newIsCapExceptions: [], - }, - ], - - // disallow the omission of parentheses when invoking a constructor with no arguments - // https://eslint.org/docs/rules/new-parens - "new-parens": "error", - - // allow/disallow an empty newline after var statement - "newline-after-var": "off", - - // https://eslint.org/docs/rules/newline-before-return - "newline-before-return": "off", - - // enforces new line after each method call in the chain to make it - // more readable and easy to maintain - // https://eslint.org/docs/rules/newline-per-chained-call - "newline-per-chained-call": ["error", { ignoreChainWithDepth: 4 }], - - // disallow use of the Array constructor - "no-array-constructor": "error", - - // disallow use of bitwise operators - // https://eslint.org/docs/rules/no-bitwise - "no-bitwise": "error", - - // disallow use of the continue statement - // https://eslint.org/docs/rules/no-continue - "no-continue": "error", - - // disallow comments inline after code - "no-inline-comments": "off", - - // disallow if as the only statement in an else block - // https://eslint.org/docs/rules/no-lonely-if - "no-lonely-if": "error", - - // disallow un-paren'd mixes of different operators - // https://eslint.org/docs/rules/no-mixed-operators - "no-mixed-operators": [ - "error", - { - // the list of arithmetic groups disallows mixing `%` and `**` - allowSamePrecedence: false, - // with other arithmetic operators. - groups: [ - ["%", "**"], - ["%", "+"], - ["%", "-"], - ["%", "*"], - ["%", "/"], - ["/", "*"], - ["&", "|", "<<", ">>", ">>>"], - ["==", "!=", "===", "!=="], - ["&&", "||"], - ["in", "instanceof"], - ], - }, - ], - - // disallow mixed spaces and tabs for indentation - "no-mixed-spaces-and-tabs": "error", - - // disallow use of chained assignment expressions - // https://eslint.org/docs/rules/no-multi-assign - "no-multi-assign": ["error"], - - // disallow multiple empty lines, only one newline at the end, and no new lines at the beginning - // https://eslint.org/docs/rules/no-multiple-empty-lines - "no-multiple-empty-lines": ["error", { max: 1, maxBOF: 0, maxEOF: 0 }], - - // disallow negated conditions - // https://eslint.org/docs/rules/no-negated-condition - "no-negated-condition": "off", - - // disallow nested ternary expressions - "no-nested-ternary": "error", - - // disallow use of the Object constructor - "no-new-object": "error", - - // disallow use of unary operators, ++ and -- - // https://eslint.org/docs/rules/no-plusplus - "no-plusplus": "error", - - // disallow certain syntax forms - // https://eslint.org/docs/rules/no-restricted-syntax - "no-restricted-syntax": [ - "error", - { - message: - "for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.", - selector: "ForInStatement", - }, - { - message: - "iterators/generators require regenerator-runtime, which is too heavyweight for this guide to allow them. Separately, loops should be avoided in favor of array iterations.", - selector: "ForOfStatement", - }, - { - message: "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.", - selector: "LabeledStatement", - }, - { - message: "`with` is disallowed in strict mode because it makes code impossible to predict and optimize.", - selector: "WithStatement", - }, - { - message: "`useMemo` with an empty dependency array can't provide a stable reference, use `useRef` instead.", - selector: "CallExpression[callee.name=useMemo][arguments.1.type=ArrayExpression][arguments.1.elements.length=0]", - }, - { - message: "Use `.key` instead of `.keyCode`", - selector: "MemberExpression > .property[type=Identifier][name=keyCode]", - }, - ], - - // disallow space between function identifier and application - // deprecated in favor of func-call-spacing - "no-spaced-func": "off", - - // disallow tab characters entirely - "no-tabs": "error", - - // disallow the use of ternary operators - "no-ternary": "off", - - // disallow trailing whitespace at the end of lines - "no-trailing-spaces": [ - "error", - { - ignoreComments: false, - skipBlankLines: false, - }, - ], - - // disallow dangling underscores in identifiers - // https://eslint.org/docs/rules/no-underscore-dangle - "no-underscore-dangle": [ - "error", - { - allow: ["__DEV__", "__STORYBOOK_CLIENT_API__", "__STORYBOOK_ADDONS_CHANNEL__", "__STORYBOOK_STORY_STORE__"], - allowAfterSuper: false, - allowAfterThis: false, - enforceInMethodNames: true, - }, - ], - - // disallow the use of Boolean literals in conditional expressions - // also, prefer `a || b` over `a ? a : b` - // https://eslint.org/docs/rules/no-unneeded-ternary - "no-unneeded-ternary": ["error", { defaultAssignment: false }], - - // disallow whitespace before properties - // https://eslint.org/docs/rules/no-whitespace-before-property - "no-whitespace-before-property": "error", - - // enforce the location of single-line statements - // https://eslint.org/docs/rules/nonblock-statement-body-position - "nonblock-statement-body-position": ["error", "beside", { overrides: {} }], - - // https://eslint.org/docs/rules/object-curly-newline - "object-curly-newline": [ - "error", - { - ExportDeclaration: { consistent: true, minProperties: 4, multiline: true }, - ImportDeclaration: { consistent: true, minProperties: 4, multiline: true }, - ObjectExpression: { consistent: true, minProperties: 4, multiline: true }, - ObjectPattern: { consistent: true, minProperties: 4, multiline: true }, - }, - ], - - // enforce line breaks between braces - // require padding inside curly braces - "object-curly-spacing": ["error", "always"], - - // enforce "same line" or "multiple line" on object properties. - // https://eslint.org/docs/rules/object-property-newline - "object-property-newline": [ - "error", - { - allowAllPropertiesOnSameLine: true, - }, - ], - - // allow just one var statement per function - "one-var": ["error", "never"], - - // require a newline around variable declaration - // https://eslint.org/docs/rules/one-var-declaration-per-line - "one-var-declaration-per-line": ["error", "always"], - - // require assignment operator shorthand where possible or prohibit it entirely - // https://eslint.org/docs/rules/operator-assignment - "operator-assignment": ["error", "always"], - - // Requires operator at the beginning of the line in multiline statements - // https://eslint.org/docs/rules/operator-linebreak - "operator-linebreak": ["error", "before", { overrides: { "=": "none" } }], - - // disallow padding within blocks - "padded-blocks": [ - "error", - { - blocks: "never", - classes: "never", - switches: "never", - }, - { - allowSingleLineBlocks: true, - }, - ], - - // Require or disallow padding lines between statements - // https://eslint.org/docs/rules/padding-line-between-statements - "padding-line-between-statements": "off", - - // Disallow the use of Math.pow in favor of the ** operator - // https://eslint.org/docs/rules/prefer-exponentiation-operator - "prefer-exponentiation-operator": "error", - - // Prefer use of an object spread over Object.assign - // https://eslint.org/docs/rules/prefer-object-spread - "prefer-object-spread": "error", - - // require quotes around object literal property names - // https://eslint.org/docs/rules/quote-props.html - "quote-props": ["error", "as-needed", { keywords: false, numbers: false, unnecessary: true }], - - // specify whether double or single quotes should be used - quotes: ["error", "double", { avoidEscape: true }], - - // do not require jsdoc - // https://eslint.org/docs/rules/require-jsdoc - "require-jsdoc": "off", - - // require or disallow use of semicolons instead of ASI - semi: ["error", "always"], - - // enforce spacing before and after semicolons - "semi-spacing": ["error", { after: true, before: false }], - - // Enforce location of semicolons - // https://eslint.org/docs/rules/semi-style - "semi-style": ["error", "last"], - - // requires object keys to be sorted - // Disabled because of perfectionist/sort-objects - "sort-keys": "off", - - // sort variables within the same declaration block - "sort-vars": "off", - - // require or disallow space before blocks - "space-before-blocks": "error", - - // require or disallow space before function opening parenthesis - // https://eslint.org/docs/rules/space-before-function-paren - "space-before-function-paren": [ - "error", - { - anonymous: "always", - asyncArrow: "always", - named: "never", - }, - ], - - // require or disallow spaces inside parentheses - "space-in-parens": ["error", "never"], - - // require spaces around operators - "space-infix-ops": "error", - - // Require or disallow spaces before/after unary operators - // https://eslint.org/docs/rules/space-unary-ops - "space-unary-ops": [ - "error", - { - nonwords: false, - overrides: {}, - words: true, - }, - ], - - // require or disallow a space immediately following the // or /* in a comment - // https://eslint.org/docs/rules/spaced-comment - "spaced-comment": [ - "error", - "always", - { - block: { - balanced: true, - exceptions: ["-", "+"], - markers: ["=", "!", ":", "::"], // space here to support sprockets directives and flow comment types - }, - line: { - exceptions: ["-", "+", "*"], - markers: ["=", "!", "/"], // space here to support sprockets directives, slash for TS /// comments - }, - }, - ], - - // Enforce spacing around colons of switch statements - // https://eslint.org/docs/rules/switch-colon-spacing - "switch-colon-spacing": ["error", { after: true, before: false }], - - // Require or disallow spacing between template tags and their literals - // https://eslint.org/docs/rules/template-tag-spacing - "template-tag-spacing": ["error", "never"], - - // require or disallow the Unicode Byte Order Mark - // https://eslint.org/docs/rules/unicode-bom - "unicode-bom": ["error", "never"], - - // require regex literals to be wrapped in parentheses - "wrap-regex": "off", - - ...prettierRules, +import type { OptionsFiles, OptionsHasPrettier } from "../types"; +import { createConfig, getFilesGlobs } from "../utils/create-config"; + +export const noUnderscoreDangle = { + allow: ["__DEV__", "__STORYBOOK_CLIENT_API__", "__STORYBOOK_ADDONS_CHANNEL__", "__STORYBOOK_STORY_STORE__"], + allowAfterSuper: false, + allowAfterThis: false, + enforceInMethodNames: true, +}; + +export const styleRules: Partial = { + // enforce line breaks after opening and before closing array brackets + // https://eslint.org/docs/rules/array-bracket-newline + "array-bracket-newline": "off", + + // enforce line breaks between array elements + // enforce spacing inside array brackets + "array-bracket-spacing": ["error", "never"], + + // https://eslint.org/docs/rules/array-element-newline + "array-element-newline": "off", + + // require camel case names + camelcase: ["error", { ignoreDestructuring: false, properties: "never" }], + + // enforce or disallow capitalization of the first letter of a comment + // https://eslint.org/docs/rules/capitalized-comments + "capitalized-comments": [ + "off", + "never", + { + block: { + ignoreConsecutiveComments: true, + ignoreInlineComments: true, + ignorePattern: ".*", + }, + line: { + ignoreConsecutiveComments: true, + ignoreInlineComments: true, + ignorePattern: ".*", }, }, - type: "all", - }, - { - config: { + ], + + // enforce one true comma style + "comma-style": [ + "error", + "last", + { + exceptions: { + ArrayExpression: false, + ArrayPattern: false, + ArrowFunctionExpression: false, + CallExpression: false, + FunctionDeclaration: false, + FunctionExpression: false, + ImportDeclaration: false, + NewExpression: false, + ObjectExpression: false, + ObjectPattern: false, + VariableDeclaration: false, + }, + }, + ], + + // disallow padding inside computed properties + "computed-property-spacing": ["error", "never"], + + // enforces consistent naming when capturing the current execution context + "consistent-this": "off", + + // enforce that default parameters should come last + "default-param-last": ["error"], + + // enforce newline at the end of file, with no multiple empty lines + "eol-last": ["error", "always"], + + // enforce spacing between functions and their invocations + // https://eslint.org/docs/rules/func-name-matching + "func-name-matching": [ + "off", + "always", + { + considerPropertyDescriptor: true, + includeCommonJSModuleExports: false, + }, + ], + + // requires function names to match the name of the variable or property to which they are + // assigned + // https://eslint.org/docs/rules/func-names + "func-names": ["error", "as-needed"], + + // require function expressions to have a name + // https://eslint.org/docs/rules/func-style + "func-style": ["error", "expression"], + + // enforces use of function declarations or expressions + // https://eslint.org/docs/rules/function-call-argument-newline + "function-call-argument-newline": ["error", "consistent"], + + // enforce consistent line breaks inside function parentheses + // https://eslint.org/docs/rules/function-paren-newline + "function-paren-newline": ["error", "consistent"], + + // Blacklist certain identifiers to prevent them being used + // https://eslint.org/docs/rules/id-blacklist + "id-blacklist": "error", + + // disallow specified identifiers + // https://eslint.org/docs/rules/id-denylist + "id-denylist": "off", + + // this option enforces minimum and maximum identifier lengths + // (variable names, property names etc.) + "id-length": "off", + + // require identifiers to match the provided regular expression + "id-match": "off", + + // Enforce the location of arrow function bodies with implicit returns + // https://eslint.org/docs/rules/implicit-arrow-linebreak + "implicit-arrow-linebreak": ["error", "beside"], + + // specify whether double or single quotes should be used in JSX attributes + // https://eslint.org/docs/rules/jsx-quotes + "jsx-quotes": ["off", "prefer-double"], + + // enforce position of line comments + // https://eslint.org/docs/rules/line-comment-position + "line-comment-position": "off", + + // disallow mixed 'LF' and 'CRLF' as linebreaks + // https://eslint.org/docs/rules/linebreak-style + "linebreak-style": ["error", "unix"], + + // https://eslint.org/docs/rules/lines-around-directive + "lines-around-directive": [ + "error", + { + after: "always", + before: "always", + }, + ], + + // specify the maximum depth that blocks can be nested + "max-depth": ["off", 4], + + // specify the maximum length of a line in your program + // https://eslint.org/docs/rules/max-len + "max-len": [ + "error", + 160, + 2, + { + ignoreComments: false, + ignoreRegExpLiterals: true, + ignoreStrings: true, + ignoreTemplateLiterals: true, + ignoreUrls: true, + }, + ], + + // specify the max number of lines in a file + // https://eslint.org/docs/rules/max-lines + "max-lines": [ + "off", + { + max: 300, + skipBlankLines: true, + skipComments: true, + }, + ], + + // enforce a maximum function length + // https://eslint.org/docs/rules/max-lines-per-function + "max-lines-per-function": [ + "off", + { + IIFEs: true, + max: 50, + skipBlankLines: true, + skipComments: true, + }, + ], + + // specify the maximum depth callbacks can be nested + "max-nested-callbacks": "off", + + // limits the number of parameters that can be used in the function declaration. + "max-params": ["off", 3], + + // specify the maximum number of statement allowed in a function + "max-statements": ["off", 10], + + // restrict the number of statements per line + // https://eslint.org/docs/rules/max-statements-per-line + "max-statements-per-line": ["off", { max: 1 }], + + // enforce a particular style for multiline comments + // https://eslint.org/docs/rules/multiline-comment-style + "multiline-comment-style": ["off", "starred-block"], + + // require multiline ternary + // https://eslint.org/docs/rules/multiline-ternary + "multiline-ternary": ["off", "never"], + + // require a capital letter for constructors + "new-cap": [ + "error", + { + capIsNew: false, + capIsNewExceptions: ["Immutable.Map", "Immutable.Set", "Immutable.List"], + newIsCap: true, + newIsCapExceptions: [], + }, + ], + + // disallow the omission of parentheses when invoking a constructor with no arguments + // https://eslint.org/docs/rules/new-parens + "new-parens": "error", + + // allow/disallow an empty newline after var statement + "newline-after-var": "off", + + // https://eslint.org/docs/rules/newline-before-return + "newline-before-return": "off", + + // enforces new line after each method call in the chain to make it + // more readable and easy to maintain + // https://eslint.org/docs/rules/newline-per-chained-call + "newline-per-chained-call": ["error", { ignoreChainWithDepth: 4 }], + + // disallow use of the Array constructor + "no-array-constructor": "error", + + // disallow use of bitwise operators + // https://eslint.org/docs/rules/no-bitwise + "no-bitwise": "error", + + // disallow use of the continue statement + // https://eslint.org/docs/rules/no-continue + "no-continue": "error", + + // disallow comments inline after code + "no-inline-comments": "off", + + // disallow if as the only statement in an else block + // https://eslint.org/docs/rules/no-lonely-if + "no-lonely-if": "error", + + // disallow un-paren'd mixes of different operators + // https://eslint.org/docs/rules/no-mixed-operators + "no-mixed-operators": [ + "error", + { + // the list of arithmetic groups disallows mixing `%` and `**` + allowSamePrecedence: false, + // with other arithmetic operators. + groups: [ + ["%", "**"], + ["%", "+"], + ["%", "-"], + ["%", "*"], + ["%", "/"], + ["/", "*"], + ["&", "|", "<<", ">>", ">>>"], + ["==", "!=", "===", "!=="], + ["&&", "||"], + ["in", "instanceof"], + ], + }, + ], + + // disallow mixed spaces and tabs for indentation + "no-mixed-spaces-and-tabs": "error", + + // disallow use of chained assignment expressions + // https://eslint.org/docs/rules/no-multi-assign + "no-multi-assign": ["error"], + + // disallow multiple empty lines, only one newline at the end, and no new lines at the beginning + // https://eslint.org/docs/rules/no-multiple-empty-lines + "no-multiple-empty-lines": ["error", { max: 1, maxBOF: 0, maxEOF: 0 }], + + // disallow negated conditions + // https://eslint.org/docs/rules/no-negated-condition + "no-negated-condition": "off", + + // disallow nested ternary expressions + "no-nested-ternary": "error", + + // disallow use of the Object constructor + "no-new-object": "error", + + // disallow use of unary operators, ++ and -- + // https://eslint.org/docs/rules/no-plusplus + "no-plusplus": "error", + + // disallow certain syntax forms + // https://eslint.org/docs/rules/no-restricted-syntax + "no-restricted-syntax": [ + "error", + { + message: + "for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.", + selector: "ForInStatement", + }, + { + message: + "iterators/generators require regenerator-runtime, which is too heavyweight for this guide to allow them. Separately, loops should be avoided in favor of array iterations.", + selector: "ForOfStatement", + }, + { + message: "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand.", + selector: "LabeledStatement", + }, + { + message: "`with` is disallowed in strict mode because it makes code impossible to predict and optimize.", + selector: "WithStatement", + }, + { + message: "`useMemo` with an empty dependency array can't provide a stable reference, use `useRef` instead.", + selector: "CallExpression[callee.name=useMemo][arguments.1.type=ArrayExpression][arguments.1.elements.length=0]", + }, + { + message: "Use `.key` instead of `.keyCode`", + selector: "MemberExpression > .property[type=Identifier][name=keyCode]", + }, + { + message: "Do not use full-width tilde. Use wave dash instead.", + // eslint-disable-next-line no-restricted-syntax + selector: ":matches(Literal[value=/~/],TemplateElement[value.raw=/~/])", + }, + { + message: "Use `.toString()` instead of template literal if you want to convert a value to string.", + selector: "TemplateLiteral[quasis.0.value.raw=\"\"][quasis.1.tail=true][quasis.1.value.raw=\"\"]", + }, + ], + + // disallow space between function identifier and application + // deprecated in favor of func-call-spacing + "no-spaced-func": "off", + + // disallow tab characters entirely + "no-tabs": "error", + + // disallow the use of ternary operators + "no-ternary": "off", + + // disallow trailing whitespace at the end of lines + "no-trailing-spaces": [ + "error", + { + ignoreComments: false, + skipBlankLines: false, + }, + ], + + // disallow dangling underscores in identifiers + // https://eslint.org/docs/rules/no-underscore-dangle + "no-underscore-dangle": ["error", noUnderscoreDangle], + + // disallow the use of Boolean literals in conditional expressions + // also, prefer `a || b` over `a ? a : b` + // https://eslint.org/docs/rules/no-unneeded-ternary + "no-unneeded-ternary": ["error", { defaultAssignment: false }], + + // disallow whitespace before properties + // https://eslint.org/docs/rules/no-whitespace-before-property + "no-whitespace-before-property": "error", + + // enforce the location of single-line statements + // https://eslint.org/docs/rules/nonblock-statement-body-position + "nonblock-statement-body-position": ["error", "beside", { overrides: {} }], + + // https://eslint.org/docs/rules/object-curly-newline + "object-curly-newline": [ + "error", + { + ExportDeclaration: { consistent: true, minProperties: 4, multiline: true }, + ImportDeclaration: { consistent: true, minProperties: 4, multiline: true }, + ObjectExpression: { consistent: true, minProperties: 4, multiline: true }, + ObjectPattern: { consistent: true, minProperties: 4, multiline: true }, + }, + ], + + // enforce line breaks between braces + // require padding inside curly braces + "object-curly-spacing": ["error", "always"], + + // enforce "same line" or "multiple line" on object properties. + // https://eslint.org/docs/rules/object-property-newline + "object-property-newline": [ + "error", + { + allowAllPropertiesOnSameLine: true, + }, + ], + + // allow just one var statement per function + "one-var": ["error", "never"], + + // require a newline around variable declaration + // https://eslint.org/docs/rules/one-var-declaration-per-line + "one-var-declaration-per-line": ["error", "always"], + + // require assignment operator shorthand where possible or prohibit it entirely + // https://eslint.org/docs/rules/operator-assignment + "operator-assignment": ["error", "always"], + + // Requires operator at the beginning of the line in multiline statements + // https://eslint.org/docs/rules/operator-linebreak + "operator-linebreak": ["error", "before", { overrides: { "=": "none" } }], + + // disallow padding within blocks + "padded-blocks": [ + "error", + { + blocks: "never", + classes: "never", + switches: "never", + }, + { + allowSingleLineBlocks: true, + }, + ], + + // Require or disallow padding lines between statements + // https://eslint.org/docs/rules/padding-line-between-statements + "padding-line-between-statements": "off", + + // Disallow the use of Math.pow in favor of the ** operator + // https://eslint.org/docs/rules/prefer-exponentiation-operator + "prefer-exponentiation-operator": "error", + + // Prefer use of an object spread over Object.assign + // https://eslint.org/docs/rules/prefer-object-spread + "prefer-object-spread": "error", + + // do not require jsdoc + // https://eslint.org/docs/rules/require-jsdoc + "require-jsdoc": "off", + + // enforce spacing before and after semicolons + "semi-spacing": ["error", { after: true, before: false }], + + // Enforce location of semicolons + // https://eslint.org/docs/rules/semi-style + "semi-style": ["error", "last"], + + // requires object keys to be sorted + // Disabled because of perfectionist/sort-objects + "sort-keys": "off", + + // sort variables within the same declaration block + "sort-vars": "off", + + // require or disallow spaces inside parentheses + "space-in-parens": ["error", "never"], + + // Require or disallow spaces before/after unary operators + // https://eslint.org/docs/rules/space-unary-ops + "space-unary-ops": [ + "error", + { + nonwords: false, + overrides: {}, + words: true, + }, + ], + + // require or disallow a space immediately following the // or /* in a comment + // https://eslint.org/docs/rules/spaced-comment + "spaced-comment": [ + "error", + "always", + { + block: { + balanced: true, + exceptions: ["-", "+"], + markers: ["=", "!", ":", "::"], // space here to support sprockets directives and flow comment types + }, + line: { + exceptions: ["-", "+", "*"], + markers: ["=", "!", "/"], // space here to support sprockets directives, slash for TS /// comments + }, + }, + ], + + // Enforce spacing around colons of switch statements + // https://eslint.org/docs/rules/switch-colon-spacing + "switch-colon-spacing": ["error", { after: true, before: false }], + + // Require or disallow spacing between template tags and their literals + // https://eslint.org/docs/rules/template-tag-spacing + "template-tag-spacing": ["error", "never"], + + // require or disallow the Unicode Byte Order Mark + // https://eslint.org/docs/rules/unicode-bom + "unicode-bom": ["error", "never"], + + // require regex literals to be wrapped in parentheses + "wrap-regex": "off", +}; + +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles, prettier } = config; + + return [ + { + files, + name: "anolilab/style/rules", rules: { - // require or disallow newlines around directives - // https://eslint.org/docs/rules/lines-between-class-members - "lines-between-class-members": ["error", "always", { exceptAfterSingleLine: false }], + ...styleRules, + "quote-props": "off", + + ...prettier + ? { + // The rest are rules that you never need to enable when using Prettier. + "array-bracket-newline": "off", + "array-bracket-spacing": "off", + "array-element-newline": "off", + "arrow-parens": "off", + "arrow-spacing": "off", + "block-spacing": "off", + "brace-style": "off", + "comma-dangle": "off", + + "comma-spacing": "off", + "comma-style": "off", + "computed-property-spacing": "off", + // script can distinguish them. + curly: 0, + "dot-location": "off", + "eol-last": "off", + "func-call-spacing": "off", + "function-call-argument-newline": "off", + "function-paren-newline": "off", + "generator-star-spacing": "off", + "implicit-arrow-linebreak": "off", + indent: "off", + "jsx-quotes": "off", + "key-spacing": "off", + "keyword-spacing": "off", + "linebreak-style": "off", + "lines-around-comment": 0, + "max-len": 0, + "max-statements-per-line": "off", + "multiline-ternary": "off", + "new-parens": "off", + "newline-per-chained-call": "off", + "no-confusing-arrow": 0, + "no-extra-parens": "off", + "no-extra-semi": "off", + "no-floating-decimal": "off", + "no-mixed-operators": 0, + "no-mixed-spaces-and-tabs": "off", + "no-multi-spaces": "off", + "no-multiple-empty-lines": "off", + "no-tabs": 0, + "no-trailing-spaces": "off", + "no-unexpected-multiline": 0, + "no-whitespace-before-property": "off", + "nonblock-statement-body-position": "off", + "object-curly-newline": "off", + "object-curly-spacing": "off", + "object-property-newline": "off", + "one-var-declaration-per-line": "off", + "operator-linebreak": "off", + "padded-blocks": "off", + quotes: 0, + "rest-spread-spacing": "off", + semi: "off", + "semi-spacing": "off", + "semi-style": "off", + "space-before-blocks": "off", + "space-before-function-paren": "off", + "space-in-parens": "off", + "space-unary-ops": "off", + "switch-colon-spacing": "off", + "template-curly-spacing": "off", + "template-tag-spacing": "off", + "wrap-iife": "off", + "wrap-regex": "off", + "yield-star-spacing": "off", + } + : {}, }, }, - type: "javascript", - }, - { - config: { + { + files: getFilesGlobs("ts"), + name: "anolilab/style/ts-rules", rules: { // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/brace-style.md "brace-style": "off", @@ -743,6 +617,11 @@ const config: Linter.Config = createConfigs([ // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/lines-between-class-members.md "lines-between-class-members": "off", + // Some built-in types have aliases, while some types are considered dangerous or harmful. + // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/ban-types.md + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-array-constructor.md + "no-array-constructor": "off", + // Enforce using concise optional chain expressions instead of chained logical ands, negated logical ors, or empty objects. // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/quotes.md quotes: "off", @@ -754,15 +633,7 @@ const config: Linter.Config = createConfigs([ // Enforce using function types instead of interfaces with call signatures. // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/space-before-function-paren.md "space-before-function-paren": "off", - - // Some built-in types have aliases, while some types are considered dangerous or harmful. - // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/ban-types.md - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-array-constructor.md - "no-array-constructor": "off", }, }, - type: "typescript", - }, -]); - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/config/variables.ts b/packages/eslint-config/src/config/variables.ts index 47d4518f1..7854b2d87 100644 --- a/packages/eslint-config/src/config/variables.ts +++ b/packages/eslint-config/src/config/variables.ts @@ -1,90 +1,95 @@ import confusingBrowserGlobals from "confusing-browser-globals"; import type { Linter } from "eslint"; -import { createConfigs } from "../utils/create-config"; +import type { OptionsFiles } from "../types"; +import { createConfig, getFilesGlobs } from "../utils/create-config"; -const config: Linter.Config = createConfigs([ - { - config: { - rules: { - // enforce or disallow variable initializations at definition - "init-declarations": "off", - - // disallow the catch clause parameter name being the same as a variable in the outer scope - "no-catch-shadow": "off", - - // disallow deletion of variables - "no-delete-var": "error", - - // disallow labels that share a name with a variable - // https://eslint.org/docs/rules/no-label-var - "no-label-var": "error", - - // disallow specific globals - "no-restricted-globals": [ - "error", - { - message: "Use Number.isFinite instead https://github.com/airbnb/javascript#standard-library--isfinite", - name: "isFinite", - }, - { - message: "Use Number.isNaN instead https://github.com/airbnb/javascript#standard-library--isnan", - name: "isNaN", - }, - ...confusingBrowserGlobals.map((g) => { - return { - name: g, - message: `Use window.${g} instead. https://github.com/facebook/create-react-app/blob/HEAD/packages/confusing-browser-globals/README.md`, - }; - }), - ], - - // disallow declaration of variables already declared in the outer scope - "no-shadow": "error", - - // disallow shadowing of names such as arguments - "no-shadow-restricted-names": "error", - - // disallow use of undeclared variables unless mentioned in a /*global */ block - "no-undef": "error", - - // disallow use of undefined when initializing variables - "no-undef-init": "error", - - // allow use of undefined variable - // https://eslint.org/docs/rules/no-undefined - "no-undefined": "off", - - // disallow declaration of variables that are not used in the code - "no-unused-vars": ["error", { args: "after-used", ignoreRestSiblings: true, vars: "all" }], - - // disallow use of variables before they are defined - "no-use-before-define": ["error", { classes: true, functions: true, variables: true }], - }, - }, - type: "all", - }, - { - config: { - rules: { - // Disallow member access on a value with type any. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md - "no-use-before-define": "off", +export const variablesRules: Partial = { + // enforce or disallow variable initializations at definition + "init-declarations": "off", - // Disallow unsafe declaration merging. - // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md - "no-unused-vars": "off", + // disallow the catch clause parameter name being the same as a variable in the outer scope + "no-catch-shadow": "off", + // disallow deletion of variables + "no-delete-var": "error", + + // disallow labels that share a name with a variable + // https://eslint.org/docs/rules/no-label-var + "no-label-var": "error", + + // disallow specific globals + "no-restricted-globals": [ + "error", + { + message: "Use Number.isFinite instead https://github.com/airbnb/javascript#standard-library--isfinite", + name: "isFinite", + }, + { + message: "Use Number.isNaN instead https://github.com/airbnb/javascript#standard-library--isnan", + name: "isNaN", + }, + ...confusingBrowserGlobals.map((g) => { + return { + message: `Use window.${g} instead. https://github.com/facebook/create-react-app/blob/HEAD/packages/confusing-browser-globals/README.md`, + name: g, + }; + }), + { message: "Use `globalThis` instead.", name: "global" }, + { message: "Use `globalThis` instead.", name: "self" }, + ], + + // disallow declaration of variables already declared in the outer scope + "no-shadow": "error", + + // disallow shadowing of names such as arguments + "no-shadow-restricted-names": "error", + + // disallow use of undeclared variables unless mentioned in a /*global */ block + "no-undef": "error", + + // disallow use of undefined when initializing variables + "no-undef-init": "error", + + // allow use of undefined variable + // https://eslint.org/docs/rules/no-undefined + "no-undefined": "off", + + // disallow declaration of variables that are not used in the code + "no-unused-vars": ["error", { args: "after-used", ignoreRestSiblings: true, vars: "all" }], + + // disallow use of variables before they are defined + "no-use-before-define": ["error", { classes: true, functions: true, variables: true }], +}; + +export default createConfig("all", async (config, oFiles) => { + const { files = oFiles } = config; + + return [ + { + files, + name: "anolilab/variables/rules", + rules: variablesRules, + }, + { + files: getFilesGlobs("ts"), + name: "anolilab/variables/ts-rules", + rules: { // Disallow invocation of require(). // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-shadow.md "no-shadow": "off", // Disallow unnecessary constraints on generic types. "no-undef": "off", + + // Disallow unsafe declaration merging. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md + "no-unused-vars": "off", + + // Disallow member access on a value with type any. + // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md + "no-use-before-define": "off", }, }, - type: "typescript", - }, -]); - -export default config; + ]; +}); diff --git a/packages/eslint-config/src/define-config.ts b/packages/eslint-config/src/define-config.ts deleted file mode 100644 index c1a4b1bbc..000000000 --- a/packages/eslint-config/src/define-config.ts +++ /dev/null @@ -1 +0,0 @@ -export { defineConfig, defineFlatConfig } from "eslint-define-config"; diff --git a/packages/eslint-config/src/engine-node-overwrite.ts b/packages/eslint-config/src/engine-node-overwrite.ts deleted file mode 100644 index 35831a672..000000000 --- a/packages/eslint-config/src/engine-node-overwrite.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** -Define the rules config that are overwritten only for specific version of Node.js based on `engines.node` in package.json or the `nodeVersion` option. - -The keys are rule names and the values are an Object with a valid semver (`4.0.0` is valid `4` is not) as keys and the rule configuration as values. - -Each entry define the rule config and the maximum Node.js version for which to set it. -The entry with the lowest version that is compliant with the `engines.node`/`nodeVersion` range will be used. - -@type {Object} - -@example -``` -{ - 'plugin/rule': { - '6.0.0': ['error', {prop: 'node-6-conf'}], - '8.0.0': ['error', {prop: 'node-8-conf'}] - } -} -``` - -With `engines.node` set to `>=4` the rule `plugin/rule` will not be used. -With `engines.node` set to `>=6` the rule `plugin/rule` will be used with the config `{prop: 'node-6-conf'}`. -With `engines.node` set to `>=8` the rule `plugin/rule` will be used with the config `{prop: 'node-8-conf'}`. -*/ -const engineRules = { - "n/prefer-global/text-decoder": { - "11.0.0": "off", - }, - "n/prefer-global/text-encoder": { - "11.0.0": "off", - }, - "n/prefer-global/url": { - "10.0.0": "off", - }, - "n/prefer-global/url-search-params": { - "10.0.0": "off", - }, - "n/prefer-promises/dns": { - "11.14.0": "off", - }, - "n/prefer-promises/fs": { - "11.14.0": "off", - }, - "no-useless-catch": { - "10.0.0": "off", - }, - "prefer-destructuring": { - "6.0.0": "off", - }, - "prefer-named-capture-group": { - "10.0.0": "off", - }, - "prefer-object-spread": { - "8.3.0": "off", - }, - "prefer-rest-params": { - "6.0.0": "off", - }, - "promise/prefer-await-to-then": { - "7.6.0": "off", - }, - "unicorn/no-new-buffer": { - "5.10.0": "off", - }, - "unicorn/prefer-flat-map": { - "11.0.0": "off", - }, - "unicorn/prefer-spread": { - "5.0.0": "off", - }, -}; - -export default engineRules; diff --git a/packages/eslint-config/src/global.d.ts b/packages/eslint-config/src/global.d.ts deleted file mode 100644 index e12d466fa..000000000 --- a/packages/eslint-config/src/global.d.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { Linter } from "eslint"; - -export {}; - -declare global { - var hasAnolilabEsLintConfigLoaded: undefined | boolean; - - var hasAnolilabEsLintConfigReactRuntimePath: undefined | boolean; - - var hasAnolilabEsLintTestConfigLoaded: undefined | boolean; - - var hasAnolilabEsLintConfigPrettier: undefined | boolean; - - var hasAnolilabEsLintVitestGlobalsPlugin: undefined | boolean; - - var hasAnolilabEsLintConfigJsyA11yStorybook: undefined | boolean; - - var hasAnolilabEsLintConfigPerfectionistTypescriptSortKeys: undefined | boolean; - - var hasAnolilabEsLintConfigPlaywrightJest: undefined | boolean; - - var hasAnolilabEsLintConfigJsoncPackageJsonSort: undefined | boolean; - - var hasAnolilabEsLintConfigDeprecation: undefined | boolean; - - var anolilabEslintIndent: undefined | number; - - var anolilabEslintPackageJsonConfig: undefined | { [key: string]: boolean | undefined }; - - var anolilabEslintConfigTypescriptPrettierRules: undefined | Linter.RulesRecord; - - var anolilabEslintConfigBabelPrettierRules: undefined | Linter.RulesRecord; - - var anolilabEslintConfigJsDocRules: undefined | Linter.Config["overrides"]; - - var anolilabEslintConfigNodeRules: undefined | Linter.RulesRecord; - - var anolilabEslintConfigReactPrettierRules: undefined | Linter.RulesRecord; - - var anolilabEslintConfigHtmlPrettierRules: undefined | Linter.RulesRecord; - var anolilabEslintConfigHtmlPrettierSettings: undefined | Linter.Config["settings"]; - - var anolilabEslintConfigReactVersion: undefined | string; - - var anolilabEslintConfigTestingLibraryRuleSet: undefined | string; - - var anolilabEslintConfigUnicornPrettierRules: undefined | Linter.RulesRecord; - - var anolilabEslintImportNoUnusedModulesConfig: undefined | string[]; -} diff --git a/packages/eslint-config/src/globals.ts b/packages/eslint-config/src/globals.ts deleted file mode 100644 index a34c5d98b..000000000 --- a/packages/eslint-config/src/globals.ts +++ /dev/null @@ -1,13 +0,0 @@ -import globals from "globals"; - -// eslint-disable-next-line prefer-destructuring -export const es2015: typeof globals.es2015 = globals.es2015; - -// eslint-disable-next-line prefer-destructuring -export const es2017: typeof globals.es2017 = globals.es2017; - -// eslint-disable-next-line prefer-destructuring -export const es2020: typeof globals.es2020 = globals.es2020; - -// eslint-disable-next-line prefer-destructuring -export const es2021: typeof globals.es2021 = globals.es2021; diff --git a/packages/eslint-config/src/index.ts b/packages/eslint-config/src/index.ts index 65d789ebd..f4cec85ff 100644 --- a/packages/eslint-config/src/index.ts +++ b/packages/eslint-config/src/index.ts @@ -1,228 +1,944 @@ -/** - * rushstack eslint-patch is used to include plugins as dev - * dependencies instead of imposing them as peer dependencies - * - * {@link https://www.npmjs.com/package/@rushstack/eslint-patch} - * {@link https://stackoverflow.com/a/74478635/1392749} - * {@link https://github.com/eslint/eslint/issues/3458} - * {@link https://eslint.org/blog/2022/08/new-config-system-part-1/} - * {@link https://eslint.org/blog/2022/08/new-config-system-part-2/} - * {@link https://eslint.org/blog/2022/08/new-config-system-part-3/} - * {@link https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new} - */ -import "@rushstack/eslint-patch/modern-module-resolution"; - +import { readFileSync } from "node:fs"; import { join } from "node:path"; -import { hasDependency, hasDevDependency, packageIsTypeModule, pkg } from "@anolilab/package-json-utils"; +import { ensurePackages, hasPackageJsonAnyDependency, parsePackageJson } from "@visulima/package"; import type { Linter } from "eslint"; -import globals from "globals"; -import { intersects, rcompare } from "semver"; +import { FlatConfigComposer } from "eslint-flat-config-utils"; + +import bestPractices from "./config/best-practices"; +import errors from "./config/errors"; +import ignores from "./config/ignores"; +import antfu from "./config/plugins/antfu"; +import astro from "./config/plugins/astro"; +import comments from "./config/plugins/comments"; +import compat from "./config/plugins/compat"; +import formatters from "./config/plugins/formatters"; +import html from "./config/plugins/html"; +import imports from "./config/plugins/imports"; +import javascript from "./config/plugins/javascript"; +import jsdoc from "./config/plugins/jsdoc"; +import jsonc from "./config/plugins/jsonc"; +import jsxA11y from "./config/plugins/jsx-a11y"; +import markdown from "./config/plugins/markdown"; +import noSecrets from "./config/plugins/no-secrets"; +import noUnsanitized from "./config/plugins/no-unsanitized"; +import node from "./config/plugins/node"; +import perfectionist from "./config/plugins/perfectionist"; +import playwright from "./config/plugins/playwright"; +import promise from "./config/plugins/promise"; +import react from "./config/plugins/react"; +import regexp from "./config/plugins/regexp"; +import simpleImportSort from "./config/plugins/simple-import-sort"; +import sonarjs from "./config/plugins/sonarjs"; +import storybook from "./config/plugins/storybook"; +import stylistic from "./config/plugins/stylistic"; +import tailwindcss from "./config/plugins/tailwindcss"; +import tanstackQuery from "./config/plugins/tanstack-query"; +import tanstackRouter from "./config/plugins/tanstack-router"; +import testingLibrary from "./config/plugins/testing-library"; +import toml from "./config/plugins/toml"; +import tsdoc from "./config/plugins/tsdoc"; +import typescript from "./config/plugins/typescript"; +import unicorn from "./config/plugins/unicorn"; +import unocss from "./config/plugins/unocss"; +import validateJsxNesting from "./config/plugins/validate-jsx-nesting"; +import vitest from "./config/plugins/vitest"; +import yaml from "./config/plugins/yml"; +import youDontNeedLodashUnderscore from "./config/plugins/you-dont-need-lodash-underscore"; +import zod from "./config/plugins/zod"; +import style from "./config/style"; +import variables from "./config/variables"; +import type { RuleOptions } from "./typegen"; +import type { + Awaitable, + ConfigNames, + OptionsConfig, + OptionsFiles, + OptionsOverrides, + StylisticConfig, + TypedFlatConfigItem, +} from "./types"; +import { getFilesGlobs } from "./utils/create-config"; +import interopDefault from "./utils/interop-default"; +import isInEditorEnvironment from "./utils/is-in-editor-environment"; + +const flatConfigProperties = ["name", "languageOptions", "linterOptions", "processor", "plugins", "rules", "settings"] satisfies (keyof TypedFlatConfigItem)[]; + +export type ResolvedOptions = T extends boolean ? never : NonNullable; + +export const resolveSubOptions = (options: OptionsConfig, key: K): ResolvedOptions => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return typeof options[key] === "boolean" ? ({} as any) : options[key] || {}; +}; -import { internalPluginConfig, pluginRules, possiblePluginRules, rules } from "./config"; -import engineRules from "./engine-node-overwrite"; -import anolilabEslintConfig from "./utils/eslint-config"; -import { consoleLog, consolePlugin } from "./utils/loggers"; +export const getOverrides = (options: OptionsConfig, key: K): Partial => { + const sub = resolveSubOptions(options, key); -// Workaround VS Code trying to run this file twice! -if (!global.hasAnolilabEsLintConfigLoaded) { - if (process.env["DEBUG"]) { - consoleLog("\n@anolilab/eslint-config loaded the following plugins:\n"); + return { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...(options.overrides as any)?.[key], + ..."overrides" in sub ? sub.overrides : {}, + }; +}; - consoleLog(" @rushstack/eslint-plugin-security"); - internalPluginConfig - .map((name: string) => { - if (name === "import") { - return "i"; - } +export const getFiles = (options: OptionsConfig, key: K): string[] | undefined => { + const sub = resolveSubOptions(options, key); - if (name === "node") { - return "n"; - } + if ("files" in sub) { + if (typeof sub.files === "string") { + return [sub.files]; + } - return name; - }) - .forEach((plugin) => consolePlugin(plugin)); + return sub.files; } - let hasLogged = false; + return undefined; +}; - Object.entries(possiblePluginRules).forEach(([plugin, dependencies]) => { - const hasOneDependency = Object.values(dependencies).some(Boolean); +/** + * Construct an array of ESLint flat config items. + * @param {OptionsConfig & TypedFlatConfigItem} options + * The options for generating the ESLint configurations. + * @param {Awaitable[]} userConfigs + * The user configurations to be merged with the generated configurations. + * @returns {Promise} + * The merged ESLint configurations. + */ +export const createConfig = async ( + options: Omit & OptionsConfig = {}, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...userConfigs: Awaitable | Linter.Config[] | TypedFlatConfigItem | TypedFlatConfigItem[]>[] + // eslint-disable-next-line sonarjs/cognitive-complexity +): Promise> => { + if ("files" in options) { + throw new Error( + "[@anolilab/eslint-config] The first argument should not contain the \"files\" property as the options are supposed to be global. Place it in the second or later config instead.", + ); + } - if (hasOneDependency) { - hasLogged = true; + const cwd = options.cwd ?? process.cwd(); + const packageJson = parsePackageJson(readFileSync(join(cwd, "package.json"), "utf8")); + + const enablePrettier = hasPackageJsonAnyDependency(packageJson, ["prettier"]); + + const isCwdInScope = hasPackageJsonAnyDependency(packageJson, ["@anolilab/eslint-config"]); + + const { + astro: enableAstro = false, + componentExts: componentExtensions = [], + gitignore: enableGitignore = true, + html: enableHtml = false, + jsx: enableJsx = true, + lodash: enableLodash = hasPackageJsonAnyDependency(packageJson, [ + "lodash", + "underscore", + "lodash-es", + "@types/lodash", + + "lodash.chunk", + "lodash.compact", + "lodash.concat", + "lodash.difference", + "lodash.differenceby", + "lodash.differencewith", + "lodash.drop", + "lodash.dropright", + "lodash.droprightwhile", + "lodash.dropwhile", + "lodash.fill", + "lodash.findindex", + "lodash.findlastindex", + "lodash.flatten", + "lodash.flattendeep", + "lodash.flattendepth", + "lodash.frompairs", + "lodash.head", + "lodash.indexof", + "lodash.initial", + "lodash.intersection", + "lodash.intersectionby", + "lodash.intersectionwith", + "lodash.join", + "lodash.last", + "lodash.lastindexof", + "lodash.nth", + "lodash.pull", + "lodash.pullall", + "lodash.pullallby", + "lodash.pullallwith", + "lodash.pullat", + "lodash.remove", + "lodash.reverse", + "lodash.slice", + "lodash.sortedindex", + "lodash.sortedindexby", + "lodash.sortedindexof", + "lodash.sortedlastindex", + "lodash.sortedlastindexby", + "lodash.sortedlastindexof", + "lodash.sorteduniq", + "lodash.sorteduniqby", + "lodash.tail", + "lodash.take", + "lodash.takeright", + "lodash.takerightwhile", + "lodash.takewhile", + "lodash.union", + "lodash.unionby", + "lodash.unionwith", + "lodash.uniq", + "lodash.uniqby", + "lodash.uniqwith", + "lodash.unzip", + "lodash.unzipwith", + "lodash.without", + "lodash.xor", + "lodash.xorby", + "lodash.xorwith", + "lodash.zip", + "lodash.zipobject", + "lodash.zipobjectdeep", + "lodash.zipwith", + "lodash.countby", + "lodash.every", + "lodash.filter", + "lodash.find", + "lodash.findlast", + "lodash.flatmap", + "lodash.flatmapdeep", + "lodash.flatmapdepth", + "lodash.foreach", + "lodash.foreachright", + "lodash.groupby", + "lodash.includes", + "lodash.invokemap", + "lodash.keyby", + "lodash.map", + "lodash.orderby", + "lodash.partition", + "lodash.reduce", + "lodash.reduceright", + "lodash.reject", + "lodash.sample", + "lodash.samplesize", + "lodash.shuffle", + "lodash.size", + "lodash.some", + "lodash.sortby", + "lodash.now", + "lodash.after", + "lodash.ary", + "lodash.before", + "lodash.bind", + "lodash.bindkey", + "lodash.curry", + "lodash.curryright", + "lodash.debounce", + "lodash.defer", + "lodash.delay", + "lodash.flip", + "lodash.memoize", + "lodash.negate", + "lodash.once", + "lodash.overargs", + "lodash.partial", + "lodash.partialright", + "lodash.rearg", + "lodash.rest", + "lodash.spread", + "lodash.throttle", + "lodash.unary", + "lodash.wrap", + "lodash.castarray", + "lodash.clone", + "lodash.clonedeep", + "lodash.clonedeepwith", + "lodash.clonewith", + "lodash.conformsto", + "lodash.eq", + "lodash.gt", + "lodash.gte", + "lodash.isarguments", + "lodash.isarray", + "lodash.isarraybuffer", + "lodash.isarraylike", + "lodash.isarraylikeobject", + "lodash.isboolean", + "lodash.isbuffer", + "lodash.isdate", + "lodash.iselement", + "lodash.isempty", + "lodash.isequal", + "lodash.isequalwith", + "lodash.iserror", + "lodash.isfinite", + "lodash.isfunction", + "lodash.isinteger", + "lodash.islength", + "lodash.ismap", + "lodash.ismatch", + "lodash.ismatchwith", + "lodash.isnan", + "lodash.isnative", + "lodash.isnil", + "lodash.isnull", + "lodash.isnumber", + "lodash.isobject", + "lodash.isobjectlike", + "lodash.isplainobject", + "lodash.isregexp", + "lodash.issafeinteger", + "lodash.isset", + "lodash.isstring", + "lodash.issymbol", + "lodash.istypedarray", + "lodash.isundefined", + "lodash.isweakmap", + "lodash.isweakset", + "lodash.lt", + "lodash.lte", + "lodash.toarray", + "lodash.tofinite", + "lodash.tointeger", + "lodash.tolength", + "lodash.tonumber", + "lodash.toplainobject", + "lodash.tosafeinteger", + "lodash.tostring", + "lodash.add", + "lodash.ceil", + "lodash.divide", + "lodash.floor", + "lodash.max", + "lodash.maxby", + "lodash.mean", + "lodash.meanby", + "lodash.min", + "lodash.minby", + "lodash.multiply", + "lodash.round", + "lodash.subtract", + "lodash.sum", + "lodash.sumby", + "lodash.clamp", + "lodash.inrange", + "lodash.random", + "lodash.assign", + "lodash.assignin", + "lodash.assigninwith", + "lodash.assignwith", + "lodash.at", + "lodash.create", + "lodash.defaults", + "lodash.defaultsdeep", + "lodash.findkey", + "lodash.findlastkey", + "lodash.forin", + "lodash.forinright", + "lodash.forown", + "lodash.forownright", + "lodash.functions", + "lodash.functionsin", + "lodash.get", + "lodash.has", + "lodash.hasin", + "lodash.invert", + "lodash.invertby", + "lodash.invoke", + "lodash.keys", + "lodash.keysin", + "lodash.mapkeys", + "lodash.mapvalues", + "lodash.merge", + "lodash.mergewith", + "lodash.omit", + "lodash.omitby", + "lodash.pick", + "lodash.pickby", + "lodash.result", + "lodash.set", + "lodash.setwith", + "lodash.topairs", + "lodash.topairsin", + "lodash.transform", + "lodash.unset", + "lodash.update", + "lodash.updatewith", + "lodash.values", + "lodash.valuesin", + "lodash.chain", + "lodash.tap", + "lodash.thru", + "lodash.camelcase", + "lodash.capitalize", + "lodash.deburr", + "lodash.endswith", + "lodash.escape", + "lodash.escaperegexp", + "lodash.kebabcase", + "lodash.lowercase", + "lodash.lowerfirst", + "lodash.pad", + "lodash.padend", + "lodash.padstart", + "lodash.parseint", + "lodash.repeat", + "lodash.replace", + "lodash.snakecase", + "lodash.split", + "lodash.startcase", + "lodash.startswith", + "lodash.template", + "lodash.tolower", + "lodash.toupper", + "lodash.trim", + "lodash.trimend", + "lodash.trimstart", + "lodash.truncate", + "lodash.unescape", + "lodash.uppercase", + "lodash.upperfirst", + "lodash.words", + "lodash.attempt", + "lodash.bindall", + "lodash.cond", + "lodash.conforms", + "lodash.constant", + "lodash.defaultto", + "lodash.flow", + "lodash.flowright", + "lodash.identity", + "lodash.iteratee", + "lodash.matches", + "lodash.matchesproperty", + "lodash.method", + "lodash.methodof", + "lodash.mixin", + "lodash.noconflict", + "lodash.noop", + "lodash.ntharg", + "lodash.over", + "lodash.overevery", + "lodash.oversome", + "lodash.property", + "lodash.propertyof", + "lodash.range", + "lodash.rangeright", + "lodash.runincontext", + "lodash.stubarray", + "lodash.stubfalse", + "lodash.stubobject", + "lodash.stubstring", + "lodash.stubtrue", + "lodash.times", + "lodash.topath", + "lodash.uniqueid", + ]), + playwright: enablePlaywright = hasPackageJsonAnyDependency(packageJson, ["playwright", "eslint-plugin-playwright"]), + react: enableReact = hasPackageJsonAnyDependency(packageJson, [ + "react", + "react-dom", + "eslint-plugin-react", + "eslint-plugin-react-hooks", + "eslint-plugin-react-refresh", + "@eslint-react/eslint-plugin", + ]), + regexp: enableRegexp = true, + silent = false, + storybook: enableStorybook = hasPackageJsonAnyDependency(packageJson, ["storybook", "eslint-plugin-storybook"]), + tailwindcss: enableTailwindCss = false, + tanstackQuery: enableTanstackQuery = hasPackageJsonAnyDependency(packageJson, ["@tanstack/react-query"]), + tanstackRouter: enableTanstackRouter = hasPackageJsonAnyDependency(packageJson, ["@tanstack/react-router"]), + testingLibrary: enableTestingLibrary = hasPackageJsonAnyDependency(packageJson, ["@testing-library/dom", "@testing-library/react"]), + tsdoc: enableTsdoc = false, + typescript: enableTypeScript = hasPackageJsonAnyDependency(packageJson, ["typescript"]), + unicorn: enableUnicorn = true, + unocss: enableUnoCSS = false, + vitest: enableVitest = hasPackageJsonAnyDependency(packageJson, ["vitest"]), + zod: enableZod = hasPackageJsonAnyDependency(packageJson, ["zod"]), + } = options; + + if (isCwdInScope) { + const packages = []; + + if (enableZod) { + packages.push("eslint-plugin-zod"); + } - consoleLog( - `\nYour package.json container dependencies for the "${plugin}" eslint-plugin, please add the following dependencies with your chosen package manager to enable this plugin:`, - ); + if (enableUnoCSS) { + packages.push("@unocss/eslint-plugin"); + } - Object.entries(dependencies).forEach(([dependency, installed]) => { - if (!installed) { - consoleLog(` ${dependency}`); - } - }); + if (enableTanstackQuery) { + packages.push("@tanstack/eslint-plugin-query"); } - }); - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (hasLogged) { - consoleLog("\nTo disable this message, add the following to your package.json:"); - consoleLog(' "anolilab": { "eslint-config": { plugin: { "plugin-name": false } } }\n'); - } + if (enableTanstackRouter) { + packages.push("@tanstack/eslint-plugin-router"); + } - consoleLog('To disable all logging, add the following to your eslint command call "NO_LOGS=true eslint ..."'); + if (enableTailwindCss) { + packages.push("eslint-plugin-tailwindcss"); + } + + if (enableStorybook) { + packages.push("eslint-plugin-storybook"); + } - global.hasAnolilabEsLintConfigLoaded = true; -} + if (enableReact) { + packages.push("eslint-plugin-react", "@eslint-react/eslint-plugin", "eslint-plugin-react-hooks"); + } -const configRules: Linter.RulesRecord = {}; + if (enableTestingLibrary) { + packages.push("eslint-plugin-testing-library"); + } -let nodeVersion: string | undefined; + if (enableJsx) { + packages.push("eslint-plugin-jsx-a11y", "eslint-plugin-validate-jsx-nesting"); + } -if (pkg?.engines?.["node"]) { - nodeVersion = pkg.engines["node"]; -} + if (enableLodash) { + packages.push("eslint-plugin-you-dont-need-lodash-underscore"); + } -Object.entries(engineRules).forEach(([rule, ruleConfig]) => { - Object.keys(ruleConfig) - .sort(rcompare) - .forEach((minVersion) => { - if (nodeVersion && intersects(nodeVersion, `<${minVersion}`)) { - // eslint-disable-next-line security/detect-object-injection - configRules[rule] = ruleConfig[minVersion as keyof typeof ruleConfig] as Linter.RuleEntry; + if (enableTsdoc) { + packages.push("eslint-plugin-tsdoc"); + } + + if (options.formatters) { + packages.push("eslint-plugin-format"); + } + + if (enableAstro) { + packages.push("eslint-plugin-astro", "astro-eslint-parser", "@typescript-eslint/parser"); + + if (typeof options.formatters === "object" && options.formatters.astro) { + packages.push("prettier-plugin-astro"); } - }); -}); - -// Workaround VS Code trying to run this file twice! -if (!global.hasAnolilabEsLintConfigPrettier && (hasDependency("prettier") || hasDevDependency("prettier"))) { - global.hasAnolilabEsLintConfigPrettier = true; - - if (anolilabEslintConfig["info_on_disabling_prettier_conflict_rule"] !== false) { - consoleLog("\nFound prettier as dependency, disabling some rules to fix wrong behavior of the rule with eslint and prettier"); - } -} - -const config: Linter.Config = { - // After an .eslintrc.js file is loaded, ESLint will normally continue visiting all parent folders - // to look for other .eslintrc.js files, and also consult a personal file ~/.eslintrc.js. If any files - // are found, their options will be merged. This is difficult for humans to understand, and it will cause - // nondeterministic behavior if files are loaded from outside the Git working folder. - // - // Setting root=true causes ESLint to stop looking for other config files after the first .eslintrc.js - extends: [ - ...rules.map((plugin) => join(__dirname, `./config/${plugin}.js`)), - - ...pluginRules.map((plugin) => join(__dirname, `./config/plugins/${plugin}.js`)), - ], - globals: { - ...globals.browser, - ...globals.nodeBuiltin, - ...(packageIsTypeModule - ? { - __dirname: "off", - __filename: "off", - exports: "off", - require: "off", + } + + if (typeof options.formatters === "object") { + if (options.formatters?.markdown && options.formatters?.slidev) { + packages.push("prettier-plugin-slidev"); } - : { __dirname: true, __filename: true, exports: true, require: true }), - }, - ignorePatterns: [ - "!.*", - - ".git/", - "node_modules/", - "bower_components/", - "jspm_packages/", - ".npm/", - - "lib-cov/", - "coverage/", - ".nyc_output/", - ".cache/", - - "build/", - "dist/", - "tmp/", - - "**/*.min.*", - - // Manually authored .d.ts files are generally used to describe external APIs that are not expected - // to follow our coding conventions. Linting those files tends to produce a lot of spurious suppressions, - // so we simply ignore them. - "*.d.ts", - - "pnpm-lock.yaml", - ], - overrides: [ - { - files: ["**/migrations/*.{js,ts}"], - rules: { - "filenames/match-regex": "off", + + if (options.formatters?.xml || options.formatters?.svg) { + packages.push("@prettier/plugin-xml"); + } + } + + await ensurePackages(packageJson, packages, "devDependencies", { + confirm: { + message: (list: string[]) => `@anolilab/eslint-config requires the following ${list.length === 1 ? "package" : "packages"} to be installed: \n\n"${list.join("\"\n\"")}"\n\nfor the ESLint configurations to work correctly. Do you want to install ${packages.length === 1 ? "it" : "them"} now?`, }, - }, - { - files: [ - // Test files - "**/*.spec.{js,ts,tsx}", - "**/*.test.{js,ts,tsx}", - - // Facebook convention - "**/__mocks__/*.{js,ts,tsx}", - "**/__tests__/*.{js,ts,tsx}", - - // Microsoft convention - "**/test/*.{js,ts,tsx}", + }); + } + + let isInEditor = options.isInEditor; + + if (isInEditor === undefined || isInEditor === false) { + isInEditor = isInEditorEnvironment(); + + if (isInEditor) { + // eslint-disable-next-line no-console + console.log("[@anolilab/eslint-config] Detected running in editor, some rules are disabled."); + } + } + + let stylisticOptions: boolean | (OptionsFiles & OptionsOverrides & StylisticConfig) = {}; + + if (options.stylistic === false) { + stylisticOptions = false; + } else if (typeof options.stylistic === "object") { + stylisticOptions = options.stylistic; + } + + if (stylisticOptions && !("jsx" in stylisticOptions)) { + stylisticOptions.jsx = enableJsx; + } + + const configs: Awaitable[] = []; + + if (enableGitignore) { + if (typeof enableGitignore === "boolean") { + configs.push( + interopDefault(import("eslint-config-flat-gitignore")).then(r => [ + r({ + name: "anolilab/gitignore", + strict: false, + }), + ]), + ); + } else { + configs.push( + interopDefault(import("eslint-config-flat-gitignore")).then(r => [ + r({ + name: "anolilab/gitignore", + ...enableGitignore, + }), + ]), + ); + } + } + + const typescriptOptions = resolveSubOptions(options, "typescript"); + const tsconfigPath = "tsconfigPath" in typescriptOptions ? typescriptOptions.tsconfigPath : undefined; + + // Base configs + configs.push( + ignores(options.ignores), + javascript({ + packageJson, + }), + bestPractices({}), + errors({}), + style({}), + variables({}), + comments({ + files: getFiles(options, "comments"), + overrides: getOverrides(options, "comments"), + }), + node({ + files: getFiles(options, "node"), + overrides: getOverrides(options, "node"), + packageJson, + }), + jsdoc({ + files: getFiles(options, "jsdoc"), + // overrides: getFiles(options, "jsdoc"), + packageJson, + silent, + stylistic: stylisticOptions, + }), + imports({ + cwd, + files: getFiles(options, "imports"), + overrides: getOverrides(options, "imports"), + packageJson, + stylistic: stylisticOptions, + tsconfigPath, + }), + simpleImportSort({ + files: getFiles(options, "simpleImportSort"), + overrides: getOverrides(options, "simpleImportSort"), + }), + antfu({ + files: getFiles(options, "antfu"), + lessOpinionated: options.lessOpinionated, + overrides: getOverrides(options, "antfu"), + packageJson, + }), + noSecrets({ + overrides: getOverrides(options, "noSecrets"), + }), + noUnsanitized({ + overrides: getOverrides(options, "noUnsanitized"), + }), + promise({ + files: getFiles(options, "promise"), + overrides: getOverrides(options, "promise"), + }), + sonarjs({ + files: getFiles(options, "sonarjs"), + overrides: getOverrides(options, "sonarjs"), + }), + perfectionist({ + files: getFiles(options, "perfectionist"), + overrides: getOverrides(options, "perfectionist"), + packageJson, + }), + ); + + if (packageJson["browserlist"] !== undefined) { + configs.push( + compat({ + files: getFiles(options, "compat"), + }), + ); + } + + if (enableUnicorn) { + configs.push( + unicorn({ + files: getFiles(options, "unicorn"), + overrides: getOverrides(options, "unicorn"), + packageJson, + prettier: enablePrettier, + stylistic: stylisticOptions, + }), + ); + } + + if (enableLodash) { + configs.push( + youDontNeedLodashUnderscore({ + files: getFiles(options, "lodash"), + overrides: getOverrides(options, "lodash"), + }), + ); + } + + if (enableJsx) { + configs.push( + [ + { + files: getFilesGlobs("jsx_and_tsx"), + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + name: "anolilab/jsx/setup", + }, ], - rules: { - "no-magic-numbers": "off", - "sonarjs/no-duplicate-string": "off", - }, - }, - // Fixes https://github.com/eslint/eslint/discussions/15305 - { - files: packageIsTypeModule ? ["**/*.js", "**/*.mjs"] : ["**/*.mjs"], - parser: "@babel/eslint-parser", - parserOptions: { - babelOptions: { - plugins: ["@babel/plugin-syntax-import-assertions"], + jsxA11y({ + files: getFiles(options, "jsx-a11y"), + overrides: getOverrides(options, "jsx-a11y"), + }), + validateJsxNesting({ + files: getFiles(options, "validateJsxNesting"), + overrides: getOverrides(options, "validateJsxNesting"), + }), + ); + } + + if (enableTypeScript) { + configs.push( + typescript({ + ...typescriptOptions, + componentExts: componentExtensions, + overrides: getOverrides(options, "typescript"), + prettier: enablePrettier, + stylistic: stylisticOptions, + }), + ); + } + + if (stylisticOptions) { + configs.push( + stylistic({ + ...stylisticOptions, + overrides: getOverrides(options, "stylistic"), + }), + ); + } + + if (enableRegexp) { + configs.push(regexp(typeof enableRegexp === "boolean" ? {} : enableRegexp)); + } + + if (enableVitest) { + configs.push( + vitest({ + files: getFiles(options, "vitest"), + isInEditor, + overrides: getOverrides(options, "vitest"), + prettier: enablePrettier, + tsconfigPath, + }), + ); + } + + if (enableTestingLibrary) { + configs.push( + testingLibrary({ + files: getFiles(options, "testingLibrary"), + overrides: getOverrides(options, "testingLibrary"), + packageJson, + }), + ); + } + + if (enablePlaywright) { + configs.push( + playwright({ + files: getFiles(options, "playwright"), + overrides: getOverrides(options, "playwright"), + }), + ); + } + + if (enableStorybook) { + configs.push( + storybook({ + overrides: getOverrides(options, "storybook"), + }), + ); + } + + if (enableTailwindCss) { + configs.push( + tailwindcss({ + overrides: getOverrides(options, "tailwindcss"), + }), + ); + } + + if (enableTanstackQuery) { + configs.push( + tanstackQuery({ + files: getFiles(options, "tanstackQuery"), + overrides: getOverrides(options, "tanstackQuery"), + }), + ); + } + + if (enableTanstackRouter) { + configs.push( + tanstackRouter({ + files: getFiles(options, "tanstackRouter"), + overrides: getOverrides(options, "tanstackRouter"), + }), + ); + } + + if (enableHtml) { + configs.push( + html({ + files: getFiles(options, "html"), + overrides: getOverrides(options, "html"), + prettier: enablePrettier, + stylistic: stylisticOptions, + }), + ); + } + + if (enableZod) { + configs.push( + zod({ + files: getFiles(options, "zod"), + overrides: getOverrides(options, "zod"), + }), + ); + } + + if (enableTsdoc) { + configs.push( + tsdoc({ + files: getFiles(options, "tsdoc"), + overrides: getOverrides(options, "tsdoc"), + }), + ); + } + + if (enableReact) { + configs.push( + react({ + ...typescriptOptions, + overrides: getOverrides(options, "react"), + packageJson, + silent, + tsconfigPath, + }), + ); + } + + if (enableUnoCSS) { + configs.push( + unocss({ + ...resolveSubOptions(options, "unocss"), + overrides: getOverrides(options, "unocss"), + }), + ); + } + + if (enableAstro) { + configs.push( + astro({ + files: getFiles(options, "astro"), + overrides: getOverrides(options, "astro"), + stylistic: stylisticOptions, + }), + ); + } + + if (options.jsonc ?? true) { + configs.push( + jsonc({ + overrides: getOverrides(options, "jsonc"), + packageJson, + prettier: enablePrettier, + silent, + stylistic: stylisticOptions, + }), + ); + } + + if (options.toml ?? true) { + configs.push( + toml({ + files: getFiles(options, "toml"), + overrides: getOverrides(options, "toml"), + stylistic: stylisticOptions, + }), + ); + } + + if (options.markdown ?? true) { + configs.push( + markdown({ + componentExts: componentExtensions, + files: getFiles(options, "markdown"), + overrides: getOverrides(options, "markdown"), + }), + ); + } + + if (options.yaml ?? true) { + configs.push( + yaml({ + files: getFiles(options, "yaml"), + overrides: getOverrides(options, "yaml"), + prettier: enablePrettier, + stylistic: stylisticOptions, + }), + ); + } + + if (options.formatters) { + const isPrettierPluginXmlInScope = hasPackageJsonAnyDependency(packageJson, ["@prettier/plugin-xml"]); + + configs.push( + formatters( + { + astro: hasPackageJsonAnyDependency(packageJson, ["prettier-plugin-astro"]), + css: true, + graphql: true, + html: true, + markdown: true, + slidev: hasPackageJsonAnyDependency(packageJson, ["@slidev/cli"]), + svg: isPrettierPluginXmlInScope, + xml: isPrettierPluginXmlInScope, + + ...typeof options.formatters === "object" ? options.formatters : {}, }, - requireConfigFile: false, - }, - }, - { - env: { - commonjs: true, - }, - files: ["**/*.cjs"], - // inside *.cjs files. restore commonJS "globals" - globals: { - __dirname: true, - __filename: true, - exports: true, - require: true, - }, - }, - { - env: { - commonjs: false, - }, - files: ["**/*.mjs"], - globals: { - __dirname: "off", - __filename: "off", - exports: "off", - require: "off", - }, - }, - ], - // Disable the parser by default - parser: "", - // is loaded. - rules: { - ...configRules, - }, -}; + typeof stylisticOptions === "object" ? stylisticOptions : {}, + ), + ); + } + + // User can optionally pass a flat config item to the first argument + // We pick the known keys as ESLint would do schema validation + // eslint-disable-next-line unicorn/no-array-reduce + const fusedConfig = flatConfigProperties.reduce((accumulator, key) => { + if (key in options) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + accumulator[key] = options[key] as any; + } + + return accumulator; + }, {} as TypedFlatConfigItem); + + if (Object.keys(fusedConfig).length > 0) { + configs.push([fusedConfig]); + } -export default config; + let composer = new FlatConfigComposer(); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + composer = composer.append(...configs, ...(userConfigs as any)); + + return composer; +}; diff --git a/packages/eslint-config/src/postinstall.ts b/packages/eslint-config/src/postinstall.ts deleted file mode 100644 index 6f8387eed..000000000 --- a/packages/eslint-config/src/postinstall.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { env, exit } from "node:process"; - -import { projectPath } from "@anolilab/package-json-utils"; - -import writeEslintIgnore from "./postinstall/write-eslint-ignore"; -import writeEslintRc from "./postinstall/write-eslint-rc"; - -if (env["CI"]) { - exit(0); -} - -console.log("Configuring @anolilab/eslint-config", projectPath, "\n"); - -// eslint-disable-next-line unicorn/prefer-top-level-await -(async () => { - try { - // eslint-disable-next-line compat/compat - await Promise.all([writeEslintRc(), writeEslintIgnore()]); - - console.log("😎 Everything went well, have fun!"); - - exit(0); - } catch (error) { - console.log("😬 something went wrong:"); - console.error(error); - - exit(1); - } -})(); diff --git a/packages/eslint-config/src/postinstall/write-eslint-ignore.ts b/packages/eslint-config/src/postinstall/write-eslint-ignore.ts deleted file mode 100644 index b51642ebc..000000000 --- a/packages/eslint-config/src/postinstall/write-eslint-ignore.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { existsSync, writeFile } from "node:fs"; -import { join } from "node:path"; -import { promisify } from "node:util"; - -import { projectPath } from "@anolilab/package-json-utils"; - -const writeFileAsync = promisify(writeFile); - -const writeEslintIgnore = async (): Promise => { - const eslintIgnorePath = join(projectPath, ".eslintignore"); - - // eslint-disable-next-line security/detect-non-literal-fs-filename - if (existsSync(eslintIgnorePath)) { - console.warn("⚠️ .eslintignore already exists"); - - return; - } - - await writeFileAsync(eslintIgnorePath, "", "utf8"); -}; - -export default writeEslintIgnore; diff --git a/packages/eslint-config/src/postinstall/write-eslint-rc.ts b/packages/eslint-config/src/postinstall/write-eslint-rc.ts deleted file mode 100644 index f19870f2a..000000000 --- a/packages/eslint-config/src/postinstall/write-eslint-rc.ts +++ /dev/null @@ -1,125 +0,0 @@ -import { existsSync, readFileSync, writeFile } from "node:fs"; -import { join } from "node:path"; -import { promisify } from "node:util"; - -import { packageIsTypeModule, projectPath } from "@anolilab/package-json-utils"; -import type { TsConfigJson } from "type-fest"; - -const writeFileAsync = promisify(writeFile); - -console.log("Configuring @anolilab/eslint-config", projectPath, "\n"); - -const configFile = ".eslintrc"; - -// eslint-disable-next-line sonarjs/cognitive-complexity -const writeEslintRc = async (): Promise => { - // eslint-disable-next-line no-restricted-syntax,no-loops/no-loops - for (const filename of [configFile, `${configFile}.js`, `${configFile}.cjs`, `${configFile}.json`, `${configFile}.yaml`, `${configFile}.yml`]) { - // eslint-disable-next-line security/detect-non-literal-fs-filename - if (existsSync(join(projectPath, filename))) { - console.warn(`⚠️ ${filename} already exists; -Make sure that it includes the following for @anolilab/eslint-config' -to work as it should: { extends: ["@anolilab/eslint-config"] }.`); - - return; - } - } - - const eslintPath = join(projectPath, `.eslintrc.${packageIsTypeModule ? "c" : ""}js`); - - let pluginExtends = ""; - let parserOptions = ` - parserOptions: { - ecmaVersion: "latest", - sourceType: ${packageIsTypeModule ? '"module"' : '"commonjs"'}, - },`; - - const tsconfigPath = join(projectPath, "tsconfig.json"); - - let ecmaVersion = "latest"; - - // eslint-disable-next-line security/detect-non-literal-fs-filename - if (existsSync(tsconfigPath)) { - // eslint-disable-next-line security/detect-non-literal-fs-filename - const tsConfig = JSON.parse(readFileSync(tsconfigPath, "utf8")) as TsConfigJson; - - if (tsConfig.compilerOptions?.target) { - ecmaVersion = tsConfig.compilerOptions.target; - - ecmaVersion = - ecmaVersion.toLowerCase() === "es2022" || ecmaVersion.toLowerCase() === "esnext" ? "latest" : ecmaVersion.toLowerCase().replace("es", ""); - - if (ecmaVersion !== "latest" && ecmaVersion !== "2022" && ecmaVersion !== "2021" && ecmaVersion !== "6") { - pluginExtends = `, "plugin:es-x/restrict-to-es${ecmaVersion}"`; - } - } - - parserOptions = ` - parserOptions: { - project: true, - ecmaVersion: ${ecmaVersion === "latest" ? `"${ecmaVersion}"` : ecmaVersion}, - sourceType: ${packageIsTypeModule ? '"module"' : '"commonjs"'}, - },`; - } - - const content = `/** @ts-check */ -const { defineConfig } = require('@anolilab/eslint-config/define-config'); -${["es2015", "es2017", "es2020", "es2021", "latest"].includes(ecmaVersion) ? 'const { globals } = require("@anolilab/eslint-config/globals");' : ""} - -/// -/// -/// -/// -/// - -module.exports = defineConfig({ - root: true, - extends: ["@anolilab/eslint-config"${pluginExtends}], - ignorePatterns: ["!**/*"], - env: { - // Your environments (which contains several predefined global variables) - // Most environments are loaded automatically if our rules are added - },${parserOptions} - globals: {${ - ["es2015", "es2017", "es2020", "es2021", "latest"].includes(ecmaVersion) - ? `\n ...globals.${ecmaVersion === "latest" ? "es2021" : ecmaVersion},` - : "" -} - // Your global variables (setting to false means it's not allowed to be reassigned) - // myGlobal: false - }, - rules: { - // Customize your rules - }, - overrides: [ - { - files: [ - "**/*.ts", - "**/*.tsx", - "**/*.mts", - "**/*.cts", - "**/*.js", - "**/*.jsx", - ], - // Set parserOptions.project for the project to allow TypeScript to create the type-checker behind the scenes when we run linting - parserOptions: {}, - rules: {}, - }, - { - files: ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"], - // Set parserOptions.project for the project to allow TypeScript to create the type-checker behind the scenes when we run linting - parserOptions: {}, - rules: {}, - }, - { - files: ["**/*.js", "**/*.jsx"], - rules: {}, - }, - ], -}); -`; - - await writeFileAsync(eslintPath, content, "utf8"); -}; - -export default writeEslintRc; diff --git a/packages/eslint-config/src/reset.d.ts b/packages/eslint-config/src/reset.d.ts index e4d600ccb..c0dc8dfa5 100644 --- a/packages/eslint-config/src/reset.d.ts +++ b/packages/eslint-config/src/reset.d.ts @@ -1,2 +1,3 @@ // Do not add any other lines of code to this file! +// eslint-disable-next-line import/no-extraneous-dependencies import "@total-typescript/ts-reset"; diff --git a/packages/eslint-config/src/stub.d.ts b/packages/eslint-config/src/stub.d.ts new file mode 100644 index 000000000..49e0555be --- /dev/null +++ b/packages/eslint-config/src/stub.d.ts @@ -0,0 +1,4 @@ +declare module "eslint-plugin-react-hooks"; +declare module "eslint-plugin-react-refresh"; +declare module "eslint-plugin-you-dont-need-lodash-underscore"; +declare module "eslint-plugin-validate-jsx-nesting"; diff --git a/packages/eslint-config/src/typegen.d.ts b/packages/eslint-config/src/typegen.d.ts new file mode 100644 index 000000000..f667a8a7c --- /dev/null +++ b/packages/eslint-config/src/typegen.d.ts @@ -0,0 +1,16950 @@ +/* eslint-disable */ +/* prettier-ignore */ +import type { Linter } from 'eslint' + +export interface RuleOptions { + /** + * Enforce linebreaks after opening and before closing array brackets + * @see https://eslint.style/rules/js/array-bracket-newline + */ + '@stylistic/array-bracket-newline'?: Linter.RuleEntry + /** + * Enforce consistent spacing inside array brackets + * @see https://eslint.style/rules/js/array-bracket-spacing + */ + '@stylistic/array-bracket-spacing'?: Linter.RuleEntry + /** + * Enforce line breaks after each array element + * @see https://eslint.style/rules/js/array-element-newline + */ + '@stylistic/array-element-newline'?: Linter.RuleEntry + /** + * Require parentheses around arrow function arguments + * @see https://eslint.style/rules/js/arrow-parens + */ + '@stylistic/arrow-parens'?: Linter.RuleEntry + /** + * Enforce consistent spacing before and after the arrow in arrow functions + * @see https://eslint.style/rules/js/arrow-spacing + */ + '@stylistic/arrow-spacing'?: Linter.RuleEntry + /** + * Disallow or enforce spaces inside of blocks after opening block and before closing block + * @see https://eslint.style/rules/ts/block-spacing + */ + '@stylistic/block-spacing'?: Linter.RuleEntry + /** + * Enforce consistent brace style for blocks + * @see https://eslint.style/rules/ts/brace-style + */ + '@stylistic/brace-style'?: Linter.RuleEntry + /** + * Require or disallow trailing commas + * @see https://eslint.style/rules/ts/comma-dangle + */ + '@stylistic/comma-dangle'?: Linter.RuleEntry + /** + * Enforce consistent spacing before and after commas + * @see https://eslint.style/rules/ts/comma-spacing + */ + '@stylistic/comma-spacing'?: Linter.RuleEntry + /** + * Enforce consistent comma style + * @see https://eslint.style/rules/js/comma-style + */ + '@stylistic/comma-style'?: Linter.RuleEntry + /** + * Enforce consistent spacing inside computed property brackets + * @see https://eslint.style/rules/js/computed-property-spacing + */ + '@stylistic/computed-property-spacing'?: Linter.RuleEntry + /** + * Enforce consistent line breaks after opening and before closing braces + * @see https://eslint.style/rules/plus/curly-newline + */ + '@stylistic/curly-newline'?: Linter.RuleEntry + /** + * Enforce consistent newlines before and after dots + * @see https://eslint.style/rules/js/dot-location + */ + '@stylistic/dot-location'?: Linter.RuleEntry + /** + * Require or disallow newline at the end of files + * @see https://eslint.style/rules/js/eol-last + */ + '@stylistic/eol-last'?: Linter.RuleEntry + /** + * Require or disallow spacing between function identifiers and their invocations + * @see https://eslint.style/rules/ts/function-call-spacing + */ + '@stylistic/func-call-spacing'?: Linter.RuleEntry + /** + * Enforce line breaks between arguments of a function call + * @see https://eslint.style/rules/js/function-call-argument-newline + */ + '@stylistic/function-call-argument-newline'?: Linter.RuleEntry + /** + * Require or disallow spacing between function identifiers and their invocations + * @see https://eslint.style/rules/ts/function-call-spacing + */ + '@stylistic/function-call-spacing'?: Linter.RuleEntry + /** + * Enforce consistent line breaks inside function parentheses + * @see https://eslint.style/rules/js/function-paren-newline + */ + '@stylistic/function-paren-newline'?: Linter.RuleEntry + /** + * Enforce consistent spacing around `*` operators in generator functions + * @see https://eslint.style/rules/js/generator-star-spacing + */ + '@stylistic/generator-star-spacing'?: Linter.RuleEntry + /** + * Enforce the location of arrow function bodies + * @see https://eslint.style/rules/js/implicit-arrow-linebreak + */ + '@stylistic/implicit-arrow-linebreak'?: Linter.RuleEntry + /** + * Enforce consistent indentation + * @see https://eslint.style/rules/ts/indent + */ + '@stylistic/indent'?: Linter.RuleEntry + /** + * Indentation for binary operators + * @see https://eslint.style/rules/plus/indent-binary-ops + */ + '@stylistic/indent-binary-ops'?: Linter.RuleEntry + /** + * Enforce or disallow spaces inside of curly braces in JSX attributes and expressions + * @see https://eslint.style/rules/jsx/jsx-child-element-spacing + */ + '@stylistic/jsx-child-element-spacing'?: Linter.RuleEntry<[]> + /** + * Enforce closing bracket location in JSX + * @see https://eslint.style/rules/jsx/jsx-closing-bracket-location + */ + '@stylistic/jsx-closing-bracket-location'?: Linter.RuleEntry + /** + * Enforce closing tag location for multiline JSX + * @see https://eslint.style/rules/jsx/jsx-closing-tag-location + */ + '@stylistic/jsx-closing-tag-location'?: Linter.RuleEntry + /** + * Disallow unnecessary JSX expressions when literals alone are sufficient or enforce JSX expressions on literals in JSX children or attributes + * @see https://eslint.style/rules/jsx/jsx-curly-brace-presence + */ + '@stylistic/jsx-curly-brace-presence'?: Linter.RuleEntry + /** + * Enforce consistent linebreaks in curly braces in JSX attributes and expressions + * @see https://eslint.style/rules/jsx/jsx-curly-newline + */ + '@stylistic/jsx-curly-newline'?: Linter.RuleEntry + /** + * Enforce or disallow spaces inside of curly braces in JSX attributes and expressions + * @see https://eslint.style/rules/jsx/jsx-curly-spacing + */ + '@stylistic/jsx-curly-spacing'?: Linter.RuleEntry + /** + * Enforce or disallow spaces around equal signs in JSX attributes + * @see https://eslint.style/rules/jsx/jsx-equals-spacing + */ + '@stylistic/jsx-equals-spacing'?: Linter.RuleEntry + /** + * Enforce proper position of the first property in JSX + * @see https://eslint.style/rules/jsx/jsx-first-prop-new-line + */ + '@stylistic/jsx-first-prop-new-line'?: Linter.RuleEntry + /** + * Enforce line breaks before and after JSX elements when they are used as arguments to a function. + * @see https://eslint.style/rules/jsx/jsx-function-call-newline + */ + '@stylistic/jsx-function-call-newline'?: Linter.RuleEntry + /** + * Enforce JSX indentation. Deprecated, use `indent` rule instead. + * @see https://eslint.style/rules/jsx/jsx-indent + * @deprecated + */ + '@stylistic/jsx-indent'?: Linter.RuleEntry + /** + * Enforce props indentation in JSX + * @see https://eslint.style/rules/jsx/jsx-indent-props + */ + '@stylistic/jsx-indent-props'?: Linter.RuleEntry + /** + * Enforce maximum of props on a single line in JSX + * @see https://eslint.style/rules/jsx/jsx-max-props-per-line + */ + '@stylistic/jsx-max-props-per-line'?: Linter.RuleEntry + /** + * Require or prevent a new line after jsx elements and expressions. + * @see https://eslint.style/rules/jsx/jsx-newline + */ + '@stylistic/jsx-newline'?: Linter.RuleEntry + /** + * Require one JSX element per line + * @see https://eslint.style/rules/jsx/jsx-one-expression-per-line + */ + '@stylistic/jsx-one-expression-per-line'?: Linter.RuleEntry + /** + * Enforce PascalCase for user-defined JSX components + * @see https://eslint.style/rules/jsx/jsx-pascal-case + */ + '@stylistic/jsx-pascal-case'?: Linter.RuleEntry + /** + * Disallow multiple spaces between inline JSX props + * @see https://eslint.style/rules/jsx/jsx-props-no-multi-spaces + */ + '@stylistic/jsx-props-no-multi-spaces'?: Linter.RuleEntry<[]> + /** + * Enforce the consistent use of either double or single quotes in JSX attributes + * @see https://eslint.style/rules/js/jsx-quotes + */ + '@stylistic/jsx-quotes'?: Linter.RuleEntry + /** + * Disallow extra closing tags for components without children + * @see https://eslint.style/rules/jsx/jsx-self-closing-comp + */ + '@stylistic/jsx-self-closing-comp'?: Linter.RuleEntry + /** + * Enforce props alphabetical sorting + * @see https://eslint.style/rules/jsx/jsx-sort-props + */ + '@stylistic/jsx-sort-props'?: Linter.RuleEntry + /** + * Enforce whitespace in and around the JSX opening and closing brackets + * @see https://eslint.style/rules/jsx/jsx-tag-spacing + */ + '@stylistic/jsx-tag-spacing'?: Linter.RuleEntry + /** + * Disallow missing parentheses around multiline JSX + * @see https://eslint.style/rules/jsx/jsx-wrap-multilines + */ + '@stylistic/jsx-wrap-multilines'?: Linter.RuleEntry + /** + * Enforce consistent spacing between property names and type annotations in types and interfaces + * @see https://eslint.style/rules/ts/key-spacing + */ + '@stylistic/key-spacing'?: Linter.RuleEntry + /** + * Enforce consistent spacing before and after keywords + * @see https://eslint.style/rules/ts/keyword-spacing + */ + '@stylistic/keyword-spacing'?: Linter.RuleEntry + /** + * Enforce position of line comments + * @see https://eslint.style/rules/js/line-comment-position + */ + '@stylistic/line-comment-position'?: Linter.RuleEntry + /** + * Enforce consistent linebreak style + * @see https://eslint.style/rules/js/linebreak-style + */ + '@stylistic/linebreak-style'?: Linter.RuleEntry + /** + * Require empty lines around comments + * @see https://eslint.style/rules/ts/lines-around-comment + */ + '@stylistic/lines-around-comment'?: Linter.RuleEntry + /** + * Require or disallow an empty line between class members + * @see https://eslint.style/rules/ts/lines-between-class-members + */ + '@stylistic/lines-between-class-members'?: Linter.RuleEntry + /** + * Enforce a maximum line length + * @see https://eslint.style/rules/js/max-len + */ + '@stylistic/max-len'?: Linter.RuleEntry + /** + * Enforce a maximum number of statements allowed per line + * @see https://eslint.style/rules/js/max-statements-per-line + */ + '@stylistic/max-statements-per-line'?: Linter.RuleEntry + /** + * Require a specific member delimiter style for interfaces and type literals + * @see https://eslint.style/rules/ts/member-delimiter-style + */ + '@stylistic/member-delimiter-style'?: Linter.RuleEntry + /** + * Enforce a particular style for multiline comments + * @see https://eslint.style/rules/js/multiline-comment-style + */ + '@stylistic/multiline-comment-style'?: Linter.RuleEntry + /** + * Enforce newlines between operands of ternary expressions + * @see https://eslint.style/rules/js/multiline-ternary + */ + '@stylistic/multiline-ternary'?: Linter.RuleEntry + /** + * Enforce or disallow parentheses when invoking a constructor with no arguments + * @see https://eslint.style/rules/js/new-parens + */ + '@stylistic/new-parens'?: Linter.RuleEntry + /** + * Require a newline after each call in a method chain + * @see https://eslint.style/rules/js/newline-per-chained-call + */ + '@stylistic/newline-per-chained-call'?: Linter.RuleEntry + /** + * Disallow arrow functions where they could be confused with comparisons + * @see https://eslint.style/rules/js/no-confusing-arrow + */ + '@stylistic/no-confusing-arrow'?: Linter.RuleEntry + /** + * Disallow unnecessary parentheses + * @see https://eslint.style/rules/ts/no-extra-parens + */ + '@stylistic/no-extra-parens'?: Linter.RuleEntry + /** + * Disallow unnecessary semicolons + * @see https://eslint.style/rules/ts/no-extra-semi + */ + '@stylistic/no-extra-semi'?: Linter.RuleEntry<[]> + /** + * Disallow leading or trailing decimal points in numeric literals + * @see https://eslint.style/rules/js/no-floating-decimal + */ + '@stylistic/no-floating-decimal'?: Linter.RuleEntry<[]> + /** + * Disallow mixed binary operators + * @see https://eslint.style/rules/js/no-mixed-operators + */ + '@stylistic/no-mixed-operators'?: Linter.RuleEntry + /** + * Disallow mixed spaces and tabs for indentation + * @see https://eslint.style/rules/js/no-mixed-spaces-and-tabs + */ + '@stylistic/no-mixed-spaces-and-tabs'?: Linter.RuleEntry + /** + * Disallow multiple spaces + * @see https://eslint.style/rules/js/no-multi-spaces + */ + '@stylistic/no-multi-spaces'?: Linter.RuleEntry + /** + * Disallow multiple empty lines + * @see https://eslint.style/rules/js/no-multiple-empty-lines + */ + '@stylistic/no-multiple-empty-lines'?: Linter.RuleEntry + /** + * Disallow all tabs + * @see https://eslint.style/rules/js/no-tabs + */ + '@stylistic/no-tabs'?: Linter.RuleEntry + /** + * Disallow trailing whitespace at the end of lines + * @see https://eslint.style/rules/js/no-trailing-spaces + */ + '@stylistic/no-trailing-spaces'?: Linter.RuleEntry + /** + * Disallow whitespace before properties + * @see https://eslint.style/rules/js/no-whitespace-before-property + */ + '@stylistic/no-whitespace-before-property'?: Linter.RuleEntry<[]> + /** + * Enforce the location of single-line statements + * @see https://eslint.style/rules/js/nonblock-statement-body-position + */ + '@stylistic/nonblock-statement-body-position'?: Linter.RuleEntry + /** + * Enforce consistent line breaks after opening and before closing braces + * @see https://eslint.style/rules/ts/object-curly-newline + */ + '@stylistic/object-curly-newline'?: Linter.RuleEntry + /** + * Enforce consistent spacing inside braces + * @see https://eslint.style/rules/ts/object-curly-spacing + */ + '@stylistic/object-curly-spacing'?: Linter.RuleEntry + /** + * Enforce placing object properties on separate lines + * @see https://eslint.style/rules/ts/object-property-newline + */ + '@stylistic/object-property-newline'?: Linter.RuleEntry + /** + * Require or disallow newlines around variable declarations + * @see https://eslint.style/rules/js/one-var-declaration-per-line + */ + '@stylistic/one-var-declaration-per-line'?: Linter.RuleEntry + /** + * Enforce consistent linebreak style for operators + * @see https://eslint.style/rules/js/operator-linebreak + */ + '@stylistic/operator-linebreak'?: Linter.RuleEntry + /** + * Require or disallow padding within blocks + * @see https://eslint.style/rules/js/padded-blocks + */ + '@stylistic/padded-blocks'?: Linter.RuleEntry + /** + * Require or disallow padding lines between statements + * @see https://eslint.style/rules/ts/padding-line-between-statements + */ + '@stylistic/padding-line-between-statements'?: Linter.RuleEntry + /** + * Require quotes around object literal, type literal, interfaces and enums property names + * @see https://eslint.style/rules/ts/quote-props + */ + '@stylistic/quote-props'?: Linter.RuleEntry + /** + * Enforce the consistent use of either backticks, double, or single quotes + * @see https://eslint.style/rules/ts/quotes + */ + '@stylistic/quotes'?: Linter.RuleEntry + /** + * Enforce spacing between rest and spread operators and their expressions + * @see https://eslint.style/rules/js/rest-spread-spacing + */ + '@stylistic/rest-spread-spacing'?: Linter.RuleEntry + /** + * Require or disallow semicolons instead of ASI + * @see https://eslint.style/rules/ts/semi + */ + '@stylistic/semi'?: Linter.RuleEntry + /** + * Enforce consistent spacing before and after semicolons + * @see https://eslint.style/rules/js/semi-spacing + */ + '@stylistic/semi-spacing'?: Linter.RuleEntry + /** + * Enforce location of semicolons + * @see https://eslint.style/rules/js/semi-style + */ + '@stylistic/semi-style'?: Linter.RuleEntry + /** + * Enforce consistent spacing before blocks + * @see https://eslint.style/rules/ts/space-before-blocks + */ + '@stylistic/space-before-blocks'?: Linter.RuleEntry + /** + * Enforce consistent spacing before function parenthesis + * @see https://eslint.style/rules/ts/space-before-function-paren + */ + '@stylistic/space-before-function-paren'?: Linter.RuleEntry + /** + * Enforce consistent spacing inside parentheses + * @see https://eslint.style/rules/js/space-in-parens + */ + '@stylistic/space-in-parens'?: Linter.RuleEntry + /** + * Require spacing around infix operators + * @see https://eslint.style/rules/ts/space-infix-ops + */ + '@stylistic/space-infix-ops'?: Linter.RuleEntry + /** + * Enforce consistent spacing before or after unary operators + * @see https://eslint.style/rules/js/space-unary-ops + */ + '@stylistic/space-unary-ops'?: Linter.RuleEntry + /** + * Enforce consistent spacing after the `//` or `/*` in a comment + * @see https://eslint.style/rules/js/spaced-comment + */ + '@stylistic/spaced-comment'?: Linter.RuleEntry + /** + * Enforce spacing around colons of switch statements + * @see https://eslint.style/rules/js/switch-colon-spacing + */ + '@stylistic/switch-colon-spacing'?: Linter.RuleEntry + /** + * Require or disallow spacing around embedded expressions of template strings + * @see https://eslint.style/rules/js/template-curly-spacing + */ + '@stylistic/template-curly-spacing'?: Linter.RuleEntry + /** + * Require or disallow spacing between template tags and their literals + * @see https://eslint.style/rules/js/template-tag-spacing + */ + '@stylistic/template-tag-spacing'?: Linter.RuleEntry + /** + * Require consistent spacing around type annotations + * @see https://eslint.style/rules/ts/type-annotation-spacing + */ + '@stylistic/type-annotation-spacing'?: Linter.RuleEntry + /** + * Enforces consistent spacing inside TypeScript type generics + * @see https://eslint.style/rules/plus/type-generic-spacing + */ + '@stylistic/type-generic-spacing'?: Linter.RuleEntry<[]> + /** + * Expect space before the type declaration in the named tuple + * @see https://eslint.style/rules/plus/type-named-tuple-spacing + */ + '@stylistic/type-named-tuple-spacing'?: Linter.RuleEntry<[]> + /** + * Require parentheses around immediate `function` invocations + * @see https://eslint.style/rules/js/wrap-iife + */ + '@stylistic/wrap-iife'?: Linter.RuleEntry + /** + * Require parenthesis around regex literals + * @see https://eslint.style/rules/js/wrap-regex + */ + '@stylistic/wrap-regex'?: Linter.RuleEntry<[]> + /** + * Require or disallow spacing around the `*` in `yield*` expressions + * @see https://eslint.style/rules/js/yield-star-spacing + */ + '@stylistic/yield-star-spacing'?: Linter.RuleEntry + /** + * Exhaustive deps rule for useQuery + * @see https://tanstack.com/query/latest/docs/eslint/exhaustive-deps + */ + '@tanstack/query/exhaustive-deps'?: Linter.RuleEntry<[]> + /** + * Ensure correct order of inference sensitive properties for infinite queries + * @see https://tanstack.com/query/latest/docs/eslint/infinite-query-property-order + */ + '@tanstack/query/infinite-query-property-order'?: Linter.RuleEntry<[]> + /** + * Disallows rest destructuring in queries + * @see https://tanstack.com/query/latest/docs/eslint/no-rest-destructuring + */ + '@tanstack/query/no-rest-destructuring'?: Linter.RuleEntry<[]> + /** + * Disallow putting the result of query hooks directly in a React hook dependency array + * @see https://tanstack.com/query/latest/docs/eslint/no-unstable-deps + */ + '@tanstack/query/no-unstable-deps'?: Linter.RuleEntry<[]> + /** + * Makes sure that QueryClient is stable + * @see https://tanstack.com/query/latest/docs/eslint/stable-query-client + */ + '@tanstack/query/stable-query-client'?: Linter.RuleEntry<[]> + /** + * Ensure correct order of inference sensitive properties for createRoute functions + * @see https://tanstack.com/router/latest/docs/eslint/create-route-property-order + */ + '@tanstack/router/create-route-property-order'?: Linter.RuleEntry<[]> + /** + * Require that function overload signatures be consecutive + * @see https://typescript-eslint.io/rules/adjacent-overload-signatures + */ + '@typescript-eslint/adjacent-overload-signatures'?: Linter.RuleEntry<[]> + /** + * Require consistently using either `T[]` or `Array` for arrays + * @see https://typescript-eslint.io/rules/array-type + */ + '@typescript-eslint/array-type'?: Linter.RuleEntry + /** + * Disallow awaiting a value that is not a Thenable + * @see https://typescript-eslint.io/rules/await-thenable + */ + '@typescript-eslint/await-thenable'?: Linter.RuleEntry<[]> + /** + * Disallow `@ts-` comments or require descriptions after directives + * @see https://typescript-eslint.io/rules/ban-ts-comment + */ + '@typescript-eslint/ban-ts-comment'?: Linter.RuleEntry + /** + * Disallow `// tslint:` comments + * @see https://typescript-eslint.io/rules/ban-tslint-comment + */ + '@typescript-eslint/ban-tslint-comment'?: Linter.RuleEntry<[]> + /** + * Enforce that literals on classes are exposed in a consistent style + * @see https://typescript-eslint.io/rules/class-literal-property-style + */ + '@typescript-eslint/class-literal-property-style'?: Linter.RuleEntry + /** + * Enforce that class methods utilize `this` + * @see https://typescript-eslint.io/rules/class-methods-use-this + */ + '@typescript-eslint/class-methods-use-this'?: Linter.RuleEntry + /** + * Enforce specifying generic type arguments on type annotation or constructor name of a constructor call + * @see https://typescript-eslint.io/rules/consistent-generic-constructors + */ + '@typescript-eslint/consistent-generic-constructors'?: Linter.RuleEntry + /** + * Require or disallow the `Record` type + * @see https://typescript-eslint.io/rules/consistent-indexed-object-style + */ + '@typescript-eslint/consistent-indexed-object-style'?: Linter.RuleEntry + /** + * Require `return` statements to either always or never specify values + * @see https://typescript-eslint.io/rules/consistent-return + */ + '@typescript-eslint/consistent-return'?: Linter.RuleEntry + /** + * Enforce consistent usage of type assertions + * @see https://typescript-eslint.io/rules/consistent-type-assertions + */ + '@typescript-eslint/consistent-type-assertions'?: Linter.RuleEntry + /** + * Enforce type definitions to consistently use either `interface` or `type` + * @see https://typescript-eslint.io/rules/consistent-type-definitions + */ + '@typescript-eslint/consistent-type-definitions'?: Linter.RuleEntry + /** + * Enforce consistent usage of type exports + * @see https://typescript-eslint.io/rules/consistent-type-exports + */ + '@typescript-eslint/consistent-type-exports'?: Linter.RuleEntry + /** + * Enforce consistent usage of type imports + * @see https://typescript-eslint.io/rules/consistent-type-imports + */ + '@typescript-eslint/consistent-type-imports'?: Linter.RuleEntry + /** + * Enforce default parameters to be last + * @see https://typescript-eslint.io/rules/default-param-last + */ + '@typescript-eslint/default-param-last'?: Linter.RuleEntry<[]> + /** + * Enforce dot notation whenever possible + * @see https://typescript-eslint.io/rules/dot-notation + */ + '@typescript-eslint/dot-notation'?: Linter.RuleEntry + /** + * Require explicit return types on functions and class methods + * @see https://typescript-eslint.io/rules/explicit-function-return-type + */ + '@typescript-eslint/explicit-function-return-type'?: Linter.RuleEntry + /** + * Require explicit accessibility modifiers on class properties and methods + * @see https://typescript-eslint.io/rules/explicit-member-accessibility + */ + '@typescript-eslint/explicit-member-accessibility'?: Linter.RuleEntry + /** + * Require explicit return and argument types on exported functions' and classes' public class methods + * @see https://typescript-eslint.io/rules/explicit-module-boundary-types + */ + '@typescript-eslint/explicit-module-boundary-types'?: Linter.RuleEntry + /** + * Require or disallow initialization in variable declarations + * @see https://typescript-eslint.io/rules/init-declarations + */ + '@typescript-eslint/init-declarations'?: Linter.RuleEntry + /** + * Enforce a maximum number of parameters in function definitions + * @see https://typescript-eslint.io/rules/max-params + */ + '@typescript-eslint/max-params'?: Linter.RuleEntry + /** + * Require a consistent member declaration order + * @see https://typescript-eslint.io/rules/member-ordering + */ + '@typescript-eslint/member-ordering'?: Linter.RuleEntry + /** + * Enforce using a particular method signature syntax + * @see https://typescript-eslint.io/rules/method-signature-style + */ + '@typescript-eslint/method-signature-style'?: Linter.RuleEntry + /** + * Enforce naming conventions for everything across a codebase + * @see https://typescript-eslint.io/rules/naming-convention + */ + '@typescript-eslint/naming-convention'?: Linter.RuleEntry + /** + * Disallow generic `Array` constructors + * @see https://typescript-eslint.io/rules/no-array-constructor + */ + '@typescript-eslint/no-array-constructor'?: Linter.RuleEntry<[]> + /** + * Disallow using the `delete` operator on array values + * @see https://typescript-eslint.io/rules/no-array-delete + */ + '@typescript-eslint/no-array-delete'?: Linter.RuleEntry<[]> + /** + * Require `.toString()` and `.toLocaleString()` to only be called on objects which provide useful information when stringified + * @see https://typescript-eslint.io/rules/no-base-to-string + */ + '@typescript-eslint/no-base-to-string'?: Linter.RuleEntry + /** + * Disallow non-null assertion in locations that may be confusing + * @see https://typescript-eslint.io/rules/no-confusing-non-null-assertion + */ + '@typescript-eslint/no-confusing-non-null-assertion'?: Linter.RuleEntry<[]> + /** + * Require expressions of type void to appear in statement position + * @see https://typescript-eslint.io/rules/no-confusing-void-expression + */ + '@typescript-eslint/no-confusing-void-expression'?: Linter.RuleEntry + /** + * Disallow using code marked as `@deprecated` + * @see https://typescript-eslint.io/rules/no-deprecated + */ + '@typescript-eslint/no-deprecated'?: Linter.RuleEntry<[]> + /** + * Disallow duplicate class members + * @see https://typescript-eslint.io/rules/no-dupe-class-members + */ + '@typescript-eslint/no-dupe-class-members'?: Linter.RuleEntry<[]> + /** + * Disallow duplicate enum member values + * @see https://typescript-eslint.io/rules/no-duplicate-enum-values + */ + '@typescript-eslint/no-duplicate-enum-values'?: Linter.RuleEntry<[]> + /** + * Disallow duplicate constituents of union or intersection types + * @see https://typescript-eslint.io/rules/no-duplicate-type-constituents + */ + '@typescript-eslint/no-duplicate-type-constituents'?: Linter.RuleEntry + /** + * Disallow using the `delete` operator on computed key expressions + * @see https://typescript-eslint.io/rules/no-dynamic-delete + */ + '@typescript-eslint/no-dynamic-delete'?: Linter.RuleEntry<[]> + /** + * Disallow empty functions + * @see https://typescript-eslint.io/rules/no-empty-function + */ + '@typescript-eslint/no-empty-function'?: Linter.RuleEntry + /** + * Disallow the declaration of empty interfaces + * @see https://typescript-eslint.io/rules/no-empty-interface + * @deprecated + */ + '@typescript-eslint/no-empty-interface'?: Linter.RuleEntry + /** + * Disallow accidentally using the "empty object" type + * @see https://typescript-eslint.io/rules/no-empty-object-type + */ + '@typescript-eslint/no-empty-object-type'?: Linter.RuleEntry + /** + * Disallow the `any` type + * @see https://typescript-eslint.io/rules/no-explicit-any + */ + '@typescript-eslint/no-explicit-any'?: Linter.RuleEntry + /** + * Disallow extra non-null assertions + * @see https://typescript-eslint.io/rules/no-extra-non-null-assertion + */ + '@typescript-eslint/no-extra-non-null-assertion'?: Linter.RuleEntry<[]> + /** + * Disallow classes used as namespaces + * @see https://typescript-eslint.io/rules/no-extraneous-class + */ + '@typescript-eslint/no-extraneous-class'?: Linter.RuleEntry + /** + * Require Promise-like statements to be handled appropriately + * @see https://typescript-eslint.io/rules/no-floating-promises + */ + '@typescript-eslint/no-floating-promises'?: Linter.RuleEntry + /** + * Disallow iterating over an array with a for-in loop + * @see https://typescript-eslint.io/rules/no-for-in-array + */ + '@typescript-eslint/no-for-in-array'?: Linter.RuleEntry<[]> + /** + * Disallow the use of `eval()`-like methods + * @see https://typescript-eslint.io/rules/no-implied-eval + */ + '@typescript-eslint/no-implied-eval'?: Linter.RuleEntry<[]> + /** + * Enforce the use of top-level import type qualifier when an import only has specifiers with inline type qualifiers + * @see https://typescript-eslint.io/rules/no-import-type-side-effects + */ + '@typescript-eslint/no-import-type-side-effects'?: Linter.RuleEntry<[]> + /** + * Disallow explicit type declarations for variables or parameters initialized to a number, string, or boolean + * @see https://typescript-eslint.io/rules/no-inferrable-types + */ + '@typescript-eslint/no-inferrable-types'?: Linter.RuleEntry + /** + * Disallow `this` keywords outside of classes or class-like objects + * @see https://typescript-eslint.io/rules/no-invalid-this + */ + '@typescript-eslint/no-invalid-this'?: Linter.RuleEntry + /** + * Disallow `void` type outside of generic or return types + * @see https://typescript-eslint.io/rules/no-invalid-void-type + */ + '@typescript-eslint/no-invalid-void-type'?: Linter.RuleEntry + /** + * Disallow function declarations that contain unsafe references inside loop statements + * @see https://typescript-eslint.io/rules/no-loop-func + */ + '@typescript-eslint/no-loop-func'?: Linter.RuleEntry<[]> + /** + * Disallow literal numbers that lose precision + * @see https://typescript-eslint.io/rules/no-loss-of-precision + * @deprecated + */ + '@typescript-eslint/no-loss-of-precision'?: Linter.RuleEntry<[]> + /** + * Disallow magic numbers + * @see https://typescript-eslint.io/rules/no-magic-numbers + */ + '@typescript-eslint/no-magic-numbers'?: Linter.RuleEntry + /** + * Disallow the `void` operator except when used to discard a value + * @see https://typescript-eslint.io/rules/no-meaningless-void-operator + */ + '@typescript-eslint/no-meaningless-void-operator'?: Linter.RuleEntry + /** + * Enforce valid definition of `new` and `constructor` + * @see https://typescript-eslint.io/rules/no-misused-new + */ + '@typescript-eslint/no-misused-new'?: Linter.RuleEntry<[]> + /** + * Disallow Promises in places not designed to handle them + * @see https://typescript-eslint.io/rules/no-misused-promises + */ + '@typescript-eslint/no-misused-promises'?: Linter.RuleEntry + /** + * Disallow enums from having both number and string members + * @see https://typescript-eslint.io/rules/no-mixed-enums + */ + '@typescript-eslint/no-mixed-enums'?: Linter.RuleEntry<[]> + /** + * Disallow TypeScript namespaces + * @see https://typescript-eslint.io/rules/no-namespace + */ + '@typescript-eslint/no-namespace'?: Linter.RuleEntry + /** + * Disallow non-null assertions in the left operand of a nullish coalescing operator + * @see https://typescript-eslint.io/rules/no-non-null-asserted-nullish-coalescing + */ + '@typescript-eslint/no-non-null-asserted-nullish-coalescing'?: Linter.RuleEntry<[]> + /** + * Disallow non-null assertions after an optional chain expression + * @see https://typescript-eslint.io/rules/no-non-null-asserted-optional-chain + */ + '@typescript-eslint/no-non-null-asserted-optional-chain'?: Linter.RuleEntry<[]> + /** + * Disallow non-null assertions using the `!` postfix operator + * @see https://typescript-eslint.io/rules/no-non-null-assertion + */ + '@typescript-eslint/no-non-null-assertion'?: Linter.RuleEntry<[]> + /** + * Disallow variable redeclaration + * @see https://typescript-eslint.io/rules/no-redeclare + */ + '@typescript-eslint/no-redeclare'?: Linter.RuleEntry + /** + * Disallow members of unions and intersections that do nothing or override type information + * @see https://typescript-eslint.io/rules/no-redundant-type-constituents + */ + '@typescript-eslint/no-redundant-type-constituents'?: Linter.RuleEntry<[]> + /** + * Disallow invocation of `require()` + * @see https://typescript-eslint.io/rules/no-require-imports + */ + '@typescript-eslint/no-require-imports'?: Linter.RuleEntry + /** + * Disallow specified modules when loaded by `import` + * @see https://typescript-eslint.io/rules/no-restricted-imports + */ + '@typescript-eslint/no-restricted-imports'?: Linter.RuleEntry + /** + * Disallow certain types + * @see https://typescript-eslint.io/rules/no-restricted-types + */ + '@typescript-eslint/no-restricted-types'?: Linter.RuleEntry + /** + * Disallow variable declarations from shadowing variables declared in the outer scope + * @see https://typescript-eslint.io/rules/no-shadow + */ + '@typescript-eslint/no-shadow'?: Linter.RuleEntry + /** + * Disallow aliasing `this` + * @see https://typescript-eslint.io/rules/no-this-alias + */ + '@typescript-eslint/no-this-alias'?: Linter.RuleEntry + /** + * Disallow type aliases + * @see https://typescript-eslint.io/rules/no-type-alias + * @deprecated + */ + '@typescript-eslint/no-type-alias'?: Linter.RuleEntry + /** + * Disallow unnecessary equality comparisons against boolean literals + * @see https://typescript-eslint.io/rules/no-unnecessary-boolean-literal-compare + */ + '@typescript-eslint/no-unnecessary-boolean-literal-compare'?: Linter.RuleEntry + /** + * Disallow conditionals where the type is always truthy or always falsy + * @see https://typescript-eslint.io/rules/no-unnecessary-condition + */ + '@typescript-eslint/no-unnecessary-condition'?: Linter.RuleEntry + /** + * Disallow unnecessary assignment of constructor property parameter + * @see https://typescript-eslint.io/rules/no-unnecessary-parameter-property-assignment + */ + '@typescript-eslint/no-unnecessary-parameter-property-assignment'?: Linter.RuleEntry<[]> + /** + * Disallow unnecessary namespace qualifiers + * @see https://typescript-eslint.io/rules/no-unnecessary-qualifier + */ + '@typescript-eslint/no-unnecessary-qualifier'?: Linter.RuleEntry<[]> + /** + * Disallow unnecessary template expressions + * @see https://typescript-eslint.io/rules/no-unnecessary-template-expression + */ + '@typescript-eslint/no-unnecessary-template-expression'?: Linter.RuleEntry<[]> + /** + * Disallow type arguments that are equal to the default + * @see https://typescript-eslint.io/rules/no-unnecessary-type-arguments + */ + '@typescript-eslint/no-unnecessary-type-arguments'?: Linter.RuleEntry<[]> + /** + * Disallow type assertions that do not change the type of an expression + * @see https://typescript-eslint.io/rules/no-unnecessary-type-assertion + */ + '@typescript-eslint/no-unnecessary-type-assertion'?: Linter.RuleEntry + /** + * Disallow unnecessary constraints on generic types + * @see https://typescript-eslint.io/rules/no-unnecessary-type-constraint + */ + '@typescript-eslint/no-unnecessary-type-constraint'?: Linter.RuleEntry<[]> + /** + * Disallow type parameters that aren't used multiple times + * @see https://typescript-eslint.io/rules/no-unnecessary-type-parameters + */ + '@typescript-eslint/no-unnecessary-type-parameters'?: Linter.RuleEntry<[]> + /** + * Disallow calling a function with a value with type `any` + * @see https://typescript-eslint.io/rules/no-unsafe-argument + */ + '@typescript-eslint/no-unsafe-argument'?: Linter.RuleEntry<[]> + /** + * Disallow assigning a value with type `any` to variables and properties + * @see https://typescript-eslint.io/rules/no-unsafe-assignment + */ + '@typescript-eslint/no-unsafe-assignment'?: Linter.RuleEntry<[]> + /** + * Disallow calling a value with type `any` + * @see https://typescript-eslint.io/rules/no-unsafe-call + */ + '@typescript-eslint/no-unsafe-call'?: Linter.RuleEntry<[]> + /** + * Disallow unsafe declaration merging + * @see https://typescript-eslint.io/rules/no-unsafe-declaration-merging + */ + '@typescript-eslint/no-unsafe-declaration-merging'?: Linter.RuleEntry<[]> + /** + * Disallow comparing an enum value with a non-enum value + * @see https://typescript-eslint.io/rules/no-unsafe-enum-comparison + */ + '@typescript-eslint/no-unsafe-enum-comparison'?: Linter.RuleEntry<[]> + /** + * Disallow using the unsafe built-in Function type + * @see https://typescript-eslint.io/rules/no-unsafe-function-type + */ + '@typescript-eslint/no-unsafe-function-type'?: Linter.RuleEntry<[]> + /** + * Disallow member access on a value with type `any` + * @see https://typescript-eslint.io/rules/no-unsafe-member-access + */ + '@typescript-eslint/no-unsafe-member-access'?: Linter.RuleEntry<[]> + /** + * Disallow returning a value with type `any` from a function + * @see https://typescript-eslint.io/rules/no-unsafe-return + */ + '@typescript-eslint/no-unsafe-return'?: Linter.RuleEntry<[]> + /** + * Disallow type assertions that narrow a type + * @see https://typescript-eslint.io/rules/no-unsafe-type-assertion + */ + '@typescript-eslint/no-unsafe-type-assertion'?: Linter.RuleEntry<[]> + /** + * Require unary negation to take a number + * @see https://typescript-eslint.io/rules/no-unsafe-unary-minus + */ + '@typescript-eslint/no-unsafe-unary-minus'?: Linter.RuleEntry<[]> + /** + * Disallow unused expressions + * @see https://typescript-eslint.io/rules/no-unused-expressions + */ + '@typescript-eslint/no-unused-expressions'?: Linter.RuleEntry + /** + * Disallow unused variables + * @see https://typescript-eslint.io/rules/no-unused-vars + */ + '@typescript-eslint/no-unused-vars'?: Linter.RuleEntry + /** + * Disallow the use of variables before they are defined + * @see https://typescript-eslint.io/rules/no-use-before-define + */ + '@typescript-eslint/no-use-before-define'?: Linter.RuleEntry + /** + * Disallow unnecessary constructors + * @see https://typescript-eslint.io/rules/no-useless-constructor + */ + '@typescript-eslint/no-useless-constructor'?: Linter.RuleEntry<[]> + /** + * Disallow empty exports that don't change anything in a module file + * @see https://typescript-eslint.io/rules/no-useless-empty-export + */ + '@typescript-eslint/no-useless-empty-export'?: Linter.RuleEntry<[]> + /** + * Disallow `require` statements except in import statements + * @see https://typescript-eslint.io/rules/no-var-requires + * @deprecated + */ + '@typescript-eslint/no-var-requires'?: Linter.RuleEntry + /** + * Disallow using confusing built-in primitive class wrappers + * @see https://typescript-eslint.io/rules/no-wrapper-object-types + */ + '@typescript-eslint/no-wrapper-object-types'?: Linter.RuleEntry<[]> + /** + * Enforce non-null assertions over explicit type assertions + * @see https://typescript-eslint.io/rules/non-nullable-type-assertion-style + */ + '@typescript-eslint/non-nullable-type-assertion-style'?: Linter.RuleEntry<[]> + /** + * Disallow throwing non-`Error` values as exceptions + * @see https://typescript-eslint.io/rules/only-throw-error + */ + '@typescript-eslint/only-throw-error'?: Linter.RuleEntry + /** + * Require or disallow parameter properties in class constructors + * @see https://typescript-eslint.io/rules/parameter-properties + */ + '@typescript-eslint/parameter-properties'?: Linter.RuleEntry + /** + * Enforce the use of `as const` over literal type + * @see https://typescript-eslint.io/rules/prefer-as-const + */ + '@typescript-eslint/prefer-as-const'?: Linter.RuleEntry<[]> + /** + * Require destructuring from arrays and/or objects + * @see https://typescript-eslint.io/rules/prefer-destructuring + */ + '@typescript-eslint/prefer-destructuring'?: Linter.RuleEntry + /** + * Require each enum member value to be explicitly initialized + * @see https://typescript-eslint.io/rules/prefer-enum-initializers + */ + '@typescript-eslint/prefer-enum-initializers'?: Linter.RuleEntry<[]> + /** + * Enforce the use of Array.prototype.find() over Array.prototype.filter() followed by [0] when looking for a single result + * @see https://typescript-eslint.io/rules/prefer-find + */ + '@typescript-eslint/prefer-find'?: Linter.RuleEntry<[]> + /** + * Enforce the use of `for-of` loop over the standard `for` loop where possible + * @see https://typescript-eslint.io/rules/prefer-for-of + */ + '@typescript-eslint/prefer-for-of'?: Linter.RuleEntry<[]> + /** + * Enforce using function types instead of interfaces with call signatures + * @see https://typescript-eslint.io/rules/prefer-function-type + */ + '@typescript-eslint/prefer-function-type'?: Linter.RuleEntry<[]> + /** + * Enforce `includes` method over `indexOf` method + * @see https://typescript-eslint.io/rules/prefer-includes + */ + '@typescript-eslint/prefer-includes'?: Linter.RuleEntry<[]> + /** + * Require all enum members to be literal values + * @see https://typescript-eslint.io/rules/prefer-literal-enum-member + */ + '@typescript-eslint/prefer-literal-enum-member'?: Linter.RuleEntry + /** + * Require using `namespace` keyword over `module` keyword to declare custom TypeScript modules + * @see https://typescript-eslint.io/rules/prefer-namespace-keyword + */ + '@typescript-eslint/prefer-namespace-keyword'?: Linter.RuleEntry<[]> + /** + * Enforce using the nullish coalescing operator instead of logical assignments or chaining + * @see https://typescript-eslint.io/rules/prefer-nullish-coalescing + */ + '@typescript-eslint/prefer-nullish-coalescing'?: Linter.RuleEntry + /** + * Enforce using concise optional chain expressions instead of chained logical ands, negated logical ors, or empty objects + * @see https://typescript-eslint.io/rules/prefer-optional-chain + */ + '@typescript-eslint/prefer-optional-chain'?: Linter.RuleEntry + /** + * Require using Error objects as Promise rejection reasons + * @see https://typescript-eslint.io/rules/prefer-promise-reject-errors + */ + '@typescript-eslint/prefer-promise-reject-errors'?: Linter.RuleEntry + /** + * Require private members to be marked as `readonly` if they're never modified outside of the constructor + * @see https://typescript-eslint.io/rules/prefer-readonly + */ + '@typescript-eslint/prefer-readonly'?: Linter.RuleEntry + /** + * Require function parameters to be typed as `readonly` to prevent accidental mutation of inputs + * @see https://typescript-eslint.io/rules/prefer-readonly-parameter-types + */ + '@typescript-eslint/prefer-readonly-parameter-types'?: Linter.RuleEntry + /** + * Enforce using type parameter when calling `Array#reduce` instead of using a type assertion + * @see https://typescript-eslint.io/rules/prefer-reduce-type-parameter + */ + '@typescript-eslint/prefer-reduce-type-parameter'?: Linter.RuleEntry<[]> + /** + * Enforce `RegExp#exec` over `String#match` if no global flag is provided + * @see https://typescript-eslint.io/rules/prefer-regexp-exec + */ + '@typescript-eslint/prefer-regexp-exec'?: Linter.RuleEntry<[]> + /** + * Enforce that `this` is used when only `this` type is returned + * @see https://typescript-eslint.io/rules/prefer-return-this-type + */ + '@typescript-eslint/prefer-return-this-type'?: Linter.RuleEntry<[]> + /** + * Enforce using `String#startsWith` and `String#endsWith` over other equivalent methods of checking substrings + * @see https://typescript-eslint.io/rules/prefer-string-starts-ends-with + */ + '@typescript-eslint/prefer-string-starts-ends-with'?: Linter.RuleEntry + /** + * Enforce using `@ts-expect-error` over `@ts-ignore` + * @see https://typescript-eslint.io/rules/prefer-ts-expect-error + * @deprecated + */ + '@typescript-eslint/prefer-ts-expect-error'?: Linter.RuleEntry<[]> + /** + * Require any function or method that returns a Promise to be marked async + * @see https://typescript-eslint.io/rules/promise-function-async + */ + '@typescript-eslint/promise-function-async'?: Linter.RuleEntry + /** + * Enforce that `get()` types should be assignable to their equivalent `set()` type + * @see https://typescript-eslint.io/rules/related-getter-setter-pairs + */ + '@typescript-eslint/related-getter-setter-pairs'?: Linter.RuleEntry<[]> + /** + * Require `Array#sort` and `Array#toSorted` calls to always provide a `compareFunction` + * @see https://typescript-eslint.io/rules/require-array-sort-compare + */ + '@typescript-eslint/require-array-sort-compare'?: Linter.RuleEntry + /** + * Disallow async functions which do not return promises and have no `await` expression + * @see https://typescript-eslint.io/rules/require-await + */ + '@typescript-eslint/require-await'?: Linter.RuleEntry<[]> + /** + * Require both operands of addition to be the same type and be `bigint`, `number`, or `string` + * @see https://typescript-eslint.io/rules/restrict-plus-operands + */ + '@typescript-eslint/restrict-plus-operands'?: Linter.RuleEntry + /** + * Enforce template literal expressions to be of `string` type + * @see https://typescript-eslint.io/rules/restrict-template-expressions + */ + '@typescript-eslint/restrict-template-expressions'?: Linter.RuleEntry + /** + * Enforce consistent awaiting of returned promises + * @see https://typescript-eslint.io/rules/return-await + */ + '@typescript-eslint/return-await'?: Linter.RuleEntry + /** + * Enforce constituents of a type union/intersection to be sorted alphabetically + * @see https://typescript-eslint.io/rules/sort-type-constituents + * @deprecated + */ + '@typescript-eslint/sort-type-constituents'?: Linter.RuleEntry + /** + * Disallow certain types in boolean expressions + * @see https://typescript-eslint.io/rules/strict-boolean-expressions + */ + '@typescript-eslint/strict-boolean-expressions'?: Linter.RuleEntry + /** + * Require switch-case statements to be exhaustive + * @see https://typescript-eslint.io/rules/switch-exhaustiveness-check + */ + '@typescript-eslint/switch-exhaustiveness-check'?: Linter.RuleEntry + /** + * Disallow certain triple slash directives in favor of ES6-style import declarations + * @see https://typescript-eslint.io/rules/triple-slash-reference + */ + '@typescript-eslint/triple-slash-reference'?: Linter.RuleEntry + /** + * Require type annotations in certain places + * @see https://typescript-eslint.io/rules/typedef + */ + '@typescript-eslint/typedef'?: Linter.RuleEntry + /** + * Enforce unbound methods are called with their expected scope + * @see https://typescript-eslint.io/rules/unbound-method + */ + '@typescript-eslint/unbound-method'?: Linter.RuleEntry + /** + * Disallow two overloads that could be unified into one with a union or an optional/rest parameter + * @see https://typescript-eslint.io/rules/unified-signatures + */ + '@typescript-eslint/unified-signatures'?: Linter.RuleEntry + /** + * Enforce typing arguments in Promise rejection callbacks as `unknown` + * @see https://typescript-eslint.io/rules/use-unknown-in-catch-callback-variable + */ + '@typescript-eslint/use-unknown-in-catch-callback-variable'?: Linter.RuleEntry<[]> + /** + * Enforce getter and setter pairs in objects and classes + * @see https://eslint.org/docs/latest/rules/accessor-pairs + */ + 'accessor-pairs'?: Linter.RuleEntry + /** + * Having line breaks styles to object, array and named imports + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/consistent-chaining.md + */ + 'antfu/consistent-chaining'?: Linter.RuleEntry + /** + * Having line breaks styles to object, array and named imports + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/consistent-list-newline.md + */ + 'antfu/consistent-list-newline'?: Linter.RuleEntry + /** + * Enforce Anthony's style of curly bracket + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/curly.md + */ + 'antfu/curly'?: Linter.RuleEntry<[]> + /** + * Newline after if + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/if-newline.md + */ + 'antfu/if-newline'?: Linter.RuleEntry<[]> + /** + * Fix duplication in imports + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/import-dedupe.md + */ + 'antfu/import-dedupe'?: Linter.RuleEntry<[]> + /** + * Enforce consistent indentation in `unindent` template tag + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/indent-unindent.md + */ + 'antfu/indent-unindent'?: Linter.RuleEntry + /** + * Prevent importing modules in `dist` folder + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/no-import-dist.test.ts + */ + 'antfu/no-import-dist'?: Linter.RuleEntry<[]> + /** + * Prevent importing modules in `node_modules` folder by relative or absolute path + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/no-import-node-modules-by-path.test.ts + */ + 'antfu/no-import-node-modules-by-path'?: Linter.RuleEntry<[]> + /** + * Prevent using top-level await + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/no-top-level-await.test.ts + */ + 'antfu/no-top-level-await'?: Linter.RuleEntry<[]> + /** + * Do not use `exports =` + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/no-ts-export-equal.test.ts + */ + 'antfu/no-ts-export-equal'?: Linter.RuleEntry<[]> + /** + * Enforce top-level functions to be declared with function keyword + * @see https://github.com/antfu/eslint-plugin-antfu/blob/main/src/rules/top-level-function.md + */ + 'antfu/top-level-function'?: Linter.RuleEntry<[]> + /** + * Enforce linebreaks after opening and before closing array brackets + * @see https://eslint.org/docs/latest/rules/array-bracket-newline + * @deprecated + */ + 'array-bracket-newline'?: Linter.RuleEntry + /** + * Enforce consistent spacing inside array brackets + * @see https://eslint.org/docs/latest/rules/array-bracket-spacing + * @deprecated + */ + 'array-bracket-spacing'?: Linter.RuleEntry + /** + * Enforce `return` statements in callbacks of array methods + * @see https://eslint.org/docs/latest/rules/array-callback-return + */ + 'array-callback-return'?: Linter.RuleEntry + /** + * Enforce line breaks after each array element + * @see https://eslint.org/docs/latest/rules/array-element-newline + * @deprecated + */ + 'array-element-newline'?: Linter.RuleEntry + /** + * Require braces around arrow function bodies + * @see https://eslint.org/docs/latest/rules/arrow-body-style + */ + 'arrow-body-style'?: Linter.RuleEntry + /** + * Require parentheses around arrow function arguments + * @see https://eslint.org/docs/latest/rules/arrow-parens + * @deprecated + */ + 'arrow-parens'?: Linter.RuleEntry + /** + * Enforce consistent spacing before and after the arrow in arrow functions + * @see https://eslint.org/docs/latest/rules/arrow-spacing + * @deprecated + */ + 'arrow-spacing'?: Linter.RuleEntry + /** + * apply `jsx-a11y/alt-text` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/alt-text/ + */ + 'astro/jsx-a11y/alt-text'?: Linter.RuleEntry + /** + * apply `jsx-a11y/anchor-ambiguous-text` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-ambiguous-text/ + */ + 'astro/jsx-a11y/anchor-ambiguous-text'?: Linter.RuleEntry + /** + * apply `jsx-a11y/anchor-has-content` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-has-content/ + */ + 'astro/jsx-a11y/anchor-has-content'?: Linter.RuleEntry + /** + * apply `jsx-a11y/anchor-is-valid` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-is-valid/ + */ + 'astro/jsx-a11y/anchor-is-valid'?: Linter.RuleEntry + /** + * apply `jsx-a11y/aria-activedescendant-has-tabindex` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-activedescendant-has-tabindex/ + */ + 'astro/jsx-a11y/aria-activedescendant-has-tabindex'?: Linter.RuleEntry + /** + * apply `jsx-a11y/aria-props` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-props/ + */ + 'astro/jsx-a11y/aria-props'?: Linter.RuleEntry + /** + * apply `jsx-a11y/aria-proptypes` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-proptypes/ + */ + 'astro/jsx-a11y/aria-proptypes'?: Linter.RuleEntry + /** + * apply `jsx-a11y/aria-role` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-role/ + */ + 'astro/jsx-a11y/aria-role'?: Linter.RuleEntry + /** + * apply `jsx-a11y/aria-unsupported-elements` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-unsupported-elements/ + */ + 'astro/jsx-a11y/aria-unsupported-elements'?: Linter.RuleEntry + /** + * apply `jsx-a11y/autocomplete-valid` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/autocomplete-valid/ + */ + 'astro/jsx-a11y/autocomplete-valid'?: Linter.RuleEntry + /** + * apply `jsx-a11y/click-events-have-key-events` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/click-events-have-key-events/ + */ + 'astro/jsx-a11y/click-events-have-key-events'?: Linter.RuleEntry + /** + * apply `jsx-a11y/control-has-associated-label` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/control-has-associated-label/ + */ + 'astro/jsx-a11y/control-has-associated-label'?: Linter.RuleEntry + /** + * apply `jsx-a11y/heading-has-content` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/heading-has-content/ + */ + 'astro/jsx-a11y/heading-has-content'?: Linter.RuleEntry + /** + * apply `jsx-a11y/html-has-lang` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/html-has-lang/ + */ + 'astro/jsx-a11y/html-has-lang'?: Linter.RuleEntry + /** + * apply `jsx-a11y/iframe-has-title` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/iframe-has-title/ + */ + 'astro/jsx-a11y/iframe-has-title'?: Linter.RuleEntry + /** + * apply `jsx-a11y/img-redundant-alt` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/img-redundant-alt/ + */ + 'astro/jsx-a11y/img-redundant-alt'?: Linter.RuleEntry + /** + * apply `jsx-a11y/interactive-supports-focus` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/interactive-supports-focus/ + */ + 'astro/jsx-a11y/interactive-supports-focus'?: Linter.RuleEntry + /** + * apply `jsx-a11y/label-has-associated-control` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/label-has-associated-control/ + */ + 'astro/jsx-a11y/label-has-associated-control'?: Linter.RuleEntry + /** + * apply `jsx-a11y/lang` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/lang/ + */ + 'astro/jsx-a11y/lang'?: Linter.RuleEntry + /** + * apply `jsx-a11y/media-has-caption` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/media-has-caption/ + */ + 'astro/jsx-a11y/media-has-caption'?: Linter.RuleEntry + /** + * apply `jsx-a11y/mouse-events-have-key-events` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/mouse-events-have-key-events/ + */ + 'astro/jsx-a11y/mouse-events-have-key-events'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-access-key` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-access-key/ + */ + 'astro/jsx-a11y/no-access-key'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-aria-hidden-on-focusable` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-aria-hidden-on-focusable/ + */ + 'astro/jsx-a11y/no-aria-hidden-on-focusable'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-autofocus` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-autofocus/ + */ + 'astro/jsx-a11y/no-autofocus'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-distracting-elements` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-distracting-elements/ + */ + 'astro/jsx-a11y/no-distracting-elements'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-interactive-element-to-noninteractive-role` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-interactive-element-to-noninteractive-role/ + */ + 'astro/jsx-a11y/no-interactive-element-to-noninteractive-role'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-noninteractive-element-interactions` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-element-interactions/ + */ + 'astro/jsx-a11y/no-noninteractive-element-interactions'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-noninteractive-element-to-interactive-role` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-element-to-interactive-role/ + */ + 'astro/jsx-a11y/no-noninteractive-element-to-interactive-role'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-noninteractive-tabindex` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-tabindex/ + */ + 'astro/jsx-a11y/no-noninteractive-tabindex'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-redundant-roles` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-redundant-roles/ + */ + 'astro/jsx-a11y/no-redundant-roles'?: Linter.RuleEntry + /** + * apply `jsx-a11y/no-static-element-interactions` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-static-element-interactions/ + */ + 'astro/jsx-a11y/no-static-element-interactions'?: Linter.RuleEntry + /** + * apply `jsx-a11y/prefer-tag-over-role` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/prefer-tag-over-role/ + */ + 'astro/jsx-a11y/prefer-tag-over-role'?: Linter.RuleEntry + /** + * apply `jsx-a11y/role-has-required-aria-props` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/role-has-required-aria-props/ + */ + 'astro/jsx-a11y/role-has-required-aria-props'?: Linter.RuleEntry + /** + * apply `jsx-a11y/role-supports-aria-props` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/role-supports-aria-props/ + */ + 'astro/jsx-a11y/role-supports-aria-props'?: Linter.RuleEntry + /** + * apply `jsx-a11y/scope` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/scope/ + */ + 'astro/jsx-a11y/scope'?: Linter.RuleEntry + /** + * apply `jsx-a11y/tabindex-no-positive` rule to Astro components + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/tabindex-no-positive/ + */ + 'astro/jsx-a11y/tabindex-no-positive'?: Linter.RuleEntry + /** + * the client:only directive is missing the correct component's framework value + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/missing-client-only-directive-value/ + */ + 'astro/missing-client-only-directive-value'?: Linter.RuleEntry<[]> + /** + * disallow conflicting set directives and child contents + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-conflict-set-directives/ + */ + 'astro/no-conflict-set-directives'?: Linter.RuleEntry<[]> + /** + * disallow using deprecated `Astro.canonicalURL` + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-astro-canonicalurl/ + */ + 'astro/no-deprecated-astro-canonicalurl'?: Linter.RuleEntry<[]> + /** + * disallow using deprecated `Astro.fetchContent()` + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-astro-fetchcontent/ + */ + 'astro/no-deprecated-astro-fetchcontent'?: Linter.RuleEntry<[]> + /** + * disallow using deprecated `Astro.resolve()` + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-astro-resolve/ + */ + 'astro/no-deprecated-astro-resolve'?: Linter.RuleEntry<[]> + /** + * disallow using deprecated `getEntryBySlug()` + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-getentrybyslug/ + */ + 'astro/no-deprecated-getentrybyslug'?: Linter.RuleEntry<[]> + /** + * disallow value export + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-exports-from-components/ + */ + 'astro/no-exports-from-components'?: Linter.RuleEntry<[]> + /** + * disallow use of `set:html` to prevent XSS attack + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-set-html-directive/ + */ + 'astro/no-set-html-directive'?: Linter.RuleEntry<[]> + /** + * disallow use of `set:text` + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-set-text-directive/ + */ + 'astro/no-set-text-directive'?: Linter.RuleEntry<[]> + /** + * disallow selectors defined in `style` tag that don't use in HTML + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-unused-css-selector/ + */ + 'astro/no-unused-css-selector'?: Linter.RuleEntry<[]> + /** + * disallow unused `define:vars={...}` in `style` tag + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/no-unused-define-vars-in-style/ + */ + 'astro/no-unused-define-vars-in-style'?: Linter.RuleEntry<[]> + /** + * require `class:list` directives instead of `class` with expressions + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-class-list-directive/ + */ + 'astro/prefer-class-list-directive'?: Linter.RuleEntry<[]> + /** + * require use object instead of ternary expression in `class:list` + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-object-class-list/ + */ + 'astro/prefer-object-class-list'?: Linter.RuleEntry<[]> + /** + * require use split array elements in `class:list` + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-split-class-list/ + */ + 'astro/prefer-split-class-list'?: Linter.RuleEntry + /** + * Require or disallow semicolons instead of ASI + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/semi/ + */ + 'astro/semi'?: Linter.RuleEntry + /** + * enforce sorting of attributes + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/sort-attributes/ + */ + 'astro/sort-attributes'?: Linter.RuleEntry + /** + * disallow warnings when compiling. + * @see https://ota-meshi.github.io/eslint-plugin-astro/rules/valid-compile/ + */ + 'astro/valid-compile'?: Linter.RuleEntry<[]> + /** + * Enforce the use of variables within the scope they are defined + * @see https://eslint.org/docs/latest/rules/block-scoped-var + */ + 'block-scoped-var'?: Linter.RuleEntry<[]> + /** + * Disallow or enforce spaces inside of blocks after opening block and before closing block + * @see https://eslint.org/docs/latest/rules/block-spacing + * @deprecated + */ + 'block-spacing'?: Linter.RuleEntry + /** + * Enforce consistent brace style for blocks + * @see https://eslint.org/docs/latest/rules/brace-style + * @deprecated + */ + 'brace-style'?: Linter.RuleEntry + /** + * Require `return` statements after callbacks + * @see https://eslint.org/docs/latest/rules/callback-return + * @deprecated + */ + 'callback-return'?: Linter.RuleEntry + /** + * Enforce camelcase naming convention + * @see https://eslint.org/docs/latest/rules/camelcase + */ + 'camelcase'?: Linter.RuleEntry + /** + * Enforce or disallow capitalization of the first letter of a comment + * @see https://eslint.org/docs/latest/rules/capitalized-comments + */ + 'capitalized-comments'?: Linter.RuleEntry + /** + * Enforce that class methods utilize `this` + * @see https://eslint.org/docs/latest/rules/class-methods-use-this + */ + 'class-methods-use-this'?: Linter.RuleEntry + /** + * Require or disallow trailing commas + * @see https://eslint.org/docs/latest/rules/comma-dangle + * @deprecated + */ + 'comma-dangle'?: Linter.RuleEntry + /** + * Enforce consistent spacing before and after commas + * @see https://eslint.org/docs/latest/rules/comma-spacing + * @deprecated + */ + 'comma-spacing'?: Linter.RuleEntry + /** + * Enforce consistent comma style + * @see https://eslint.org/docs/latest/rules/comma-style + * @deprecated + */ + 'comma-style'?: Linter.RuleEntry + /** + * Ensure cross-browser API compatibility + * @see https://github.com/amilajack/eslint-plugin-compat/blob/master/docs/rules/compat.md + */ + 'compat/compat'?: Linter.RuleEntry + /** + * Enforce a maximum cyclomatic complexity allowed in a program + * @see https://eslint.org/docs/latest/rules/complexity + */ + 'complexity'?: Linter.RuleEntry + /** + * Enforce consistent spacing inside computed property brackets + * @see https://eslint.org/docs/latest/rules/computed-property-spacing + * @deprecated + */ + 'computed-property-spacing'?: Linter.RuleEntry + /** + * Require `return` statements to either always or never specify values + * @see https://eslint.org/docs/latest/rules/consistent-return + */ + 'consistent-return'?: Linter.RuleEntry + /** + * Enforce consistent naming when capturing the current execution context + * @see https://eslint.org/docs/latest/rules/consistent-this + */ + 'consistent-this'?: Linter.RuleEntry + /** + * Require `super()` calls in constructors + * @see https://eslint.org/docs/latest/rules/constructor-super + */ + 'constructor-super'?: Linter.RuleEntry<[]> + /** + * Enforce consistent brace style for all control statements + * @see https://eslint.org/docs/latest/rules/curly + */ + 'curly'?: Linter.RuleEntry + /** + * Require `default` cases in `switch` statements + * @see https://eslint.org/docs/latest/rules/default-case + */ + 'default-case'?: Linter.RuleEntry + /** + * Enforce `default` clauses in switch statements to be last + * @see https://eslint.org/docs/latest/rules/default-case-last + */ + 'default-case-last'?: Linter.RuleEntry<[]> + /** + * Enforce default parameters to be last + * @see https://eslint.org/docs/latest/rules/default-param-last + */ + 'default-param-last'?: Linter.RuleEntry<[]> + /** + * Enforce consistent newlines before and after dots + * @see https://eslint.org/docs/latest/rules/dot-location + * @deprecated + */ + 'dot-location'?: Linter.RuleEntry + /** + * Enforce dot notation whenever possible + * @see https://eslint.org/docs/latest/rules/dot-notation + */ + 'dot-notation'?: Linter.RuleEntry + /** + * Require or disallow newline at the end of files + * @see https://eslint.org/docs/latest/rules/eol-last + * @deprecated + */ + 'eol-last'?: Linter.RuleEntry + /** + * Require the use of `===` and `!==` + * @see https://eslint.org/docs/latest/rules/eqeqeq + */ + 'eqeqeq'?: Linter.RuleEntry + /** + * require a `eslint-enable` comment for every `eslint-disable` comment + * @see https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/disable-enable-pair.html + */ + 'eslint-comments/disable-enable-pair'?: Linter.RuleEntry + /** + * disallow a `eslint-enable` comment for multiple `eslint-disable` comments + * @see https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/no-aggregating-enable.html + */ + 'eslint-comments/no-aggregating-enable'?: Linter.RuleEntry<[]> + /** + * disallow duplicate `eslint-disable` comments + * @see https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/no-duplicate-disable.html + */ + 'eslint-comments/no-duplicate-disable'?: Linter.RuleEntry<[]> + /** + * disallow `eslint-disable` comments about specific rules + * @see https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/no-restricted-disable.html + */ + 'eslint-comments/no-restricted-disable'?: Linter.RuleEntry + /** + * disallow `eslint-disable` comments without rule names + * @see https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/no-unlimited-disable.html + */ + 'eslint-comments/no-unlimited-disable'?: Linter.RuleEntry<[]> + /** + * disallow unused `eslint-disable` comments + * @see https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/no-unused-disable.html + */ + 'eslint-comments/no-unused-disable'?: Linter.RuleEntry<[]> + /** + * disallow unused `eslint-enable` comments + * @see https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/no-unused-enable.html + */ + 'eslint-comments/no-unused-enable'?: Linter.RuleEntry<[]> + /** + * disallow ESLint directive-comments + * @see https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/no-use.html + */ + 'eslint-comments/no-use'?: Linter.RuleEntry + /** + * require include descriptions in ESLint directive-comments + * @see https://eslint-community.github.io/eslint-plugin-eslint-comments/rules/require-description.html + */ + 'eslint-comments/require-description'?: Linter.RuleEntry + /** + * Enforce `for` loop update clause moving the counter in the right direction + * @see https://eslint.org/docs/latest/rules/for-direction + */ + 'for-direction'?: Linter.RuleEntry<[]> + /** + * Use dprint to format code + */ + 'format/dprint'?: Linter.RuleEntry + /** + * Use Prettier to format code + */ + 'format/prettier'?: Linter.RuleEntry + /** + * Require or disallow spacing between function identifiers and their invocations + * @see https://eslint.org/docs/latest/rules/func-call-spacing + * @deprecated + */ + 'func-call-spacing'?: Linter.RuleEntry + /** + * Require function names to match the name of the variable or property to which they are assigned + * @see https://eslint.org/docs/latest/rules/func-name-matching + */ + 'func-name-matching'?: Linter.RuleEntry + /** + * Require or disallow named `function` expressions + * @see https://eslint.org/docs/latest/rules/func-names + */ + 'func-names'?: Linter.RuleEntry + /** + * Enforce the consistent use of either `function` declarations or expressions assigned to variables + * @see https://eslint.org/docs/latest/rules/func-style + */ + 'func-style'?: Linter.RuleEntry + /** + * Enforce line breaks between arguments of a function call + * @see https://eslint.org/docs/latest/rules/function-call-argument-newline + * @deprecated + */ + 'function-call-argument-newline'?: Linter.RuleEntry + /** + * Enforce consistent line breaks inside function parentheses + * @see https://eslint.org/docs/latest/rules/function-paren-newline + * @deprecated + */ + 'function-paren-newline'?: Linter.RuleEntry + /** + * Enforce consistent spacing around `*` operators in generator functions + * @see https://eslint.org/docs/latest/rules/generator-star-spacing + * @deprecated + */ + 'generator-star-spacing'?: Linter.RuleEntry + /** + * Enforce `return` statements in getters + * @see https://eslint.org/docs/latest/rules/getter-return + */ + 'getter-return'?: Linter.RuleEntry + /** + * Require `require()` calls to be placed at top-level module scope + * @see https://eslint.org/docs/latest/rules/global-require + * @deprecated + */ + 'global-require'?: Linter.RuleEntry<[]> + /** + * Require grouped accessor pairs in object literals and classes + * @see https://eslint.org/docs/latest/rules/grouped-accessor-pairs + */ + 'grouped-accessor-pairs'?: Linter.RuleEntry + /** + * Require `for-in` loops to include an `if` statement + * @see https://eslint.org/docs/latest/rules/guard-for-in + */ + 'guard-for-in'?: Linter.RuleEntry<[]> + /** + * Require error handling in callbacks + * @see https://eslint.org/docs/latest/rules/handle-callback-err + * @deprecated + */ + 'handle-callback-err'?: Linter.RuleEntry + /** + * Disallow specified identifiers + * @see https://eslint.org/docs/latest/rules/id-blacklist + * @deprecated + */ + 'id-blacklist'?: Linter.RuleEntry + /** + * Disallow specified identifiers + * @see https://eslint.org/docs/latest/rules/id-denylist + */ + 'id-denylist'?: Linter.RuleEntry + /** + * Enforce minimum and maximum identifier lengths + * @see https://eslint.org/docs/latest/rules/id-length + */ + 'id-length'?: Linter.RuleEntry + /** + * Require identifiers to match a specified regular expression + * @see https://eslint.org/docs/latest/rules/id-match + */ + 'id-match'?: Linter.RuleEntry + /** + * Enforce the location of arrow function bodies + * @see https://eslint.org/docs/latest/rules/implicit-arrow-linebreak + * @deprecated + */ + 'implicit-arrow-linebreak'?: Linter.RuleEntry + /** + * Enforce or ban the use of inline type-only markers for named imports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/consistent-type-specifier-style.md + */ + 'import/consistent-type-specifier-style'?: Linter.RuleEntry + /** + * Ensure a default export is present, given a default import. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/default.md + */ + 'import/default'?: Linter.RuleEntry<[]> + /** + * Enforce a leading comment with the webpackChunkName for dynamic imports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/dynamic-import-chunkname.md + */ + 'import/dynamic-import-chunkname'?: Linter.RuleEntry + /** + * Forbid any invalid exports, i.e. re-export of the same name. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/export.md + */ + 'import/export'?: Linter.RuleEntry<[]> + /** + * Ensure all exports appear after other statements. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/exports-last.md + */ + 'import/exports-last'?: Linter.RuleEntry<[]> + /** + * Ensure consistent use of file extension within the import path. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/extensions.md + */ + 'import/extensions'?: Linter.RuleEntry + /** + * Ensure all imports appear before other statements. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/first.md + */ + 'import/first'?: Linter.RuleEntry + /** + * Prefer named exports to be grouped together in a single export declaration. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/group-exports.md + */ + 'import/group-exports'?: Linter.RuleEntry<[]> + /** + * Replaced by `import-x/first`. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/imports-first.md + * @deprecated + */ + 'import/imports-first'?: Linter.RuleEntry + /** + * Enforce the maximum number of dependencies a module can have. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/max-dependencies.md + */ + 'import/max-dependencies'?: Linter.RuleEntry + /** + * Ensure named imports correspond to a named export in the remote file. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/named.md + */ + 'import/named'?: Linter.RuleEntry + /** + * Ensure imported namespaces contain dereferenced properties as they are dereferenced. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/namespace.md + */ + 'import/namespace'?: Linter.RuleEntry + /** + * Enforce a newline after import statements. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/newline-after-import.md + */ + 'import/newline-after-import'?: Linter.RuleEntry + /** + * Forbid import of modules using absolute paths. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-absolute-path.md + */ + 'import/no-absolute-path'?: Linter.RuleEntry + /** + * Forbid AMD `require` and `define` calls. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-amd.md + */ + 'import/no-amd'?: Linter.RuleEntry<[]> + /** + * Forbid anonymous values as default exports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-anonymous-default-export.md + */ + 'import/no-anonymous-default-export'?: Linter.RuleEntry + /** + * Forbid CommonJS `require` calls and `module.exports` or `exports.*`. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-commonjs.md + */ + 'import/no-commonjs'?: Linter.RuleEntry + /** + * Forbid a module from importing a module with a dependency path back to itself. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-cycle.md + */ + 'import/no-cycle'?: Linter.RuleEntry + /** + * Forbid default exports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-default-export.md + */ + 'import/no-default-export'?: Linter.RuleEntry<[]> + /** + * Forbid imported names marked with `@deprecated` documentation tag. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-deprecated.md + */ + 'import/no-deprecated'?: Linter.RuleEntry<[]> + /** + * Forbid repeated import of the same module in multiple places. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-duplicates.md + */ + 'import/no-duplicates'?: Linter.RuleEntry + /** + * Forbid `require()` calls with expressions. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-dynamic-require.md + */ + 'import/no-dynamic-require'?: Linter.RuleEntry + /** + * Forbid empty named import blocks. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-empty-named-blocks.md + */ + 'import/no-empty-named-blocks'?: Linter.RuleEntry<[]> + /** + * Forbid the use of extraneous packages. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-extraneous-dependencies.md + */ + 'import/no-extraneous-dependencies'?: Linter.RuleEntry + /** + * Forbid import statements with CommonJS module.exports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-import-module-exports.md + */ + 'import/no-import-module-exports'?: Linter.RuleEntry + /** + * Forbid importing the submodules of other modules. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-internal-modules.md + */ + 'import/no-internal-modules'?: Linter.RuleEntry + /** + * Forbid the use of mutable exports with `var` or `let`. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-mutable-exports.md + */ + 'import/no-mutable-exports'?: Linter.RuleEntry<[]> + /** + * Forbid use of exported name as identifier of default export. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-named-as-default.md + */ + 'import/no-named-as-default'?: Linter.RuleEntry<[]> + /** + * Forbid use of exported name as property of default export. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-named-as-default-member.md + */ + 'import/no-named-as-default-member'?: Linter.RuleEntry<[]> + /** + * Forbid named default exports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-named-default.md + */ + 'import/no-named-default'?: Linter.RuleEntry<[]> + /** + * Forbid named exports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-named-export.md + */ + 'import/no-named-export'?: Linter.RuleEntry<[]> + /** + * Forbid namespace (a.k.a. "wildcard" `*`) imports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-namespace.md + */ + 'import/no-namespace'?: Linter.RuleEntry + /** + * Forbid Node.js builtin modules. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-nodejs-modules.md + */ + 'import/no-nodejs-modules'?: Linter.RuleEntry + /** + * Forbid importing packages through relative paths. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-relative-packages.md + */ + 'import/no-relative-packages'?: Linter.RuleEntry + /** + * Forbid importing modules from parent directories. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-relative-parent-imports.md + */ + 'import/no-relative-parent-imports'?: Linter.RuleEntry + /** + * Forbid importing a default export by a different name. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-rename-default.md + */ + 'import/no-rename-default'?: Linter.RuleEntry + /** + * Enforce which files can be imported in a given folder. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-restricted-paths.md + */ + 'import/no-restricted-paths'?: Linter.RuleEntry + /** + * Forbid a module from importing itself. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-self-import.md + */ + 'import/no-self-import'?: Linter.RuleEntry<[]> + /** + * Forbid unassigned imports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-unassigned-import.md + */ + 'import/no-unassigned-import'?: Linter.RuleEntry + /** + * Ensure imports point to a file/module that can be resolved. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-unresolved.md + */ + 'import/no-unresolved'?: Linter.RuleEntry + /** + * Forbid modules without exports, or exports without matching import in another module. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-unused-modules.md + */ + 'import/no-unused-modules'?: Linter.RuleEntry + /** + * Forbid unnecessary path segments in import and require statements. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-useless-path-segments.md + */ + 'import/no-useless-path-segments'?: Linter.RuleEntry + /** + * Forbid webpack loader syntax in imports. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/no-webpack-loader-syntax.md + */ + 'import/no-webpack-loader-syntax'?: Linter.RuleEntry<[]> + /** + * Enforce a convention in module import order. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/order.md + */ + 'import/order'?: Linter.RuleEntry + /** + * Prefer a default export if module exports a single name or multiple names. + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/prefer-default-export.md + */ + 'import/prefer-default-export'?: Linter.RuleEntry + /** + * Forbid potentially ambiguous parse goal (`script` vs. `module`). + * @see https://github.com/un-ts/eslint-plugin-import-x/blob/v4.6.1/docs/rules/unambiguous.md + */ + 'import/unambiguous'?: Linter.RuleEntry<[]> + /** + * Enforce consistent indentation + * @see https://eslint.org/docs/latest/rules/indent + * @deprecated + */ + 'indent'?: Linter.RuleEntry + /** + * Enforce consistent indentation + * @see https://eslint.org/docs/latest/rules/indent-legacy + * @deprecated + */ + 'indent-legacy'?: Linter.RuleEntry + /** + * Require or disallow initialization in variable declarations + * @see https://eslint.org/docs/latest/rules/init-declarations + */ + 'init-declarations'?: Linter.RuleEntry + /** + * Checks that `@access` tags have a valid value. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-access.md#repos-sticky-header + */ + 'jsdoc/check-access'?: Linter.RuleEntry<[]> + /** + * Reports invalid alignment of JSDoc block asterisks. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-alignment.md#repos-sticky-header + */ + 'jsdoc/check-alignment'?: Linter.RuleEntry<[]> + /** + * Ensures that (JavaScript) examples within JSDoc adhere to ESLint rules. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-examples.md#repos-sticky-header + */ + 'jsdoc/check-examples'?: Linter.RuleEntry + /** + * Reports invalid padding inside JSDoc blocks. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-indentation.md#repos-sticky-header + */ + 'jsdoc/check-indentation'?: Linter.RuleEntry + /** + * Reports invalid alignment of JSDoc block lines. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-line-alignment.md#repos-sticky-header + */ + 'jsdoc/check-line-alignment'?: Linter.RuleEntry + /** + * Ensures that parameter names in JSDoc match those in the function declaration. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-param-names.md#repos-sticky-header + */ + 'jsdoc/check-param-names'?: Linter.RuleEntry + /** + * Ensures that property names in JSDoc are not duplicated on the same block and that nested properties have defined roots. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-property-names.md#repos-sticky-header + */ + 'jsdoc/check-property-names'?: Linter.RuleEntry + /** + * Reports against syntax not valid for the mode (e.g., Google Closure Compiler in non-Closure mode). + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-syntax.md#repos-sticky-header + */ + 'jsdoc/check-syntax'?: Linter.RuleEntry<[]> + /** + * Reports invalid block tag names. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-tag-names.md#repos-sticky-header + */ + 'jsdoc/check-tag-names'?: Linter.RuleEntry + /** + * Checks that any `@template` names are actually used in the connected `@typedef` or type alias. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-template-names.md#repos-sticky-header + */ + 'jsdoc/check-template-names'?: Linter.RuleEntry<[]> + /** + * Reports invalid types. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-types.md#repos-sticky-header + */ + 'jsdoc/check-types'?: Linter.RuleEntry + /** + * This rule checks the values for a handful of tags: `@version`, `@since`, `@license` and `@author`. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-values.md#repos-sticky-header + */ + 'jsdoc/check-values'?: Linter.RuleEntry + /** + * Converts non-JSDoc comments preceding or following nodes into JSDoc ones + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/convert-to-jsdoc-comments.md#repos-sticky-header + */ + 'jsdoc/convert-to-jsdoc-comments'?: Linter.RuleEntry + /** + * Expects specific tags to be empty of any content. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/empty-tags.md#repos-sticky-header + */ + 'jsdoc/empty-tags'?: Linter.RuleEntry + /** + * Reports an issue with any non-constructor function using `@implements`. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/implements-on-classes.md#repos-sticky-header + */ + 'jsdoc/implements-on-classes'?: Linter.RuleEntry + /** + * Reports if JSDoc `import()` statements point to a package which is not listed in `dependencies` or `devDependencies` + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/imports-as-dependencies.md#repos-sticky-header + */ + 'jsdoc/imports-as-dependencies'?: Linter.RuleEntry<[]> + /** + * This rule reports doc comments that only restate their attached name. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/informative-docs.md#repos-sticky-header + */ + 'jsdoc/informative-docs'?: Linter.RuleEntry + /** + * Enforces minimum number of newlines before JSDoc comment blocks + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/lines-before-block.md#repos-sticky-header + */ + 'jsdoc/lines-before-block'?: Linter.RuleEntry + /** + * Enforces a regular expression pattern on descriptions. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/match-description.md#repos-sticky-header + */ + 'jsdoc/match-description'?: Linter.RuleEntry + /** + * Reports the name portion of a JSDoc tag if matching or not matching a given regular expression. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/match-name.md#repos-sticky-header + */ + 'jsdoc/match-name'?: Linter.RuleEntry + /** + * Controls how and whether jsdoc blocks can be expressed as single or multiple line blocks. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/multiline-blocks.md#repos-sticky-header + */ + 'jsdoc/multiline-blocks'?: Linter.RuleEntry + /** + * This rule checks for multi-line-style comments which fail to meet the criteria of a jsdoc block. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-bad-blocks.md#repos-sticky-header + */ + 'jsdoc/no-bad-blocks'?: Linter.RuleEntry + /** + * Detects and removes extra lines of a blank block description + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-blank-block-descriptions.md#repos-sticky-header + */ + 'jsdoc/no-blank-block-descriptions'?: Linter.RuleEntry<[]> + /** + * Removes empty blocks with nothing but possibly line breaks + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-blank-blocks.md#repos-sticky-header + */ + 'jsdoc/no-blank-blocks'?: Linter.RuleEntry + /** + * This rule reports defaults being used on the relevant portion of `@param` or `@default`. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-defaults.md#repos-sticky-header + */ + 'jsdoc/no-defaults'?: Linter.RuleEntry + /** + * Reports when certain comment structures are always expected. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-missing-syntax.md#repos-sticky-header + */ + 'jsdoc/no-missing-syntax'?: Linter.RuleEntry + /** + * Prevents use of multiple asterisks at the beginning of lines. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-multi-asterisks.md#repos-sticky-header + */ + 'jsdoc/no-multi-asterisks'?: Linter.RuleEntry + /** + * Reports when certain comment structures are present. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-restricted-syntax.md#repos-sticky-header + */ + 'jsdoc/no-restricted-syntax'?: Linter.RuleEntry + /** + * This rule reports types being used on `@param` or `@returns`. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-types.md#repos-sticky-header + */ + 'jsdoc/no-types'?: Linter.RuleEntry + /** + * Checks that types in jsdoc comments are defined. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/no-undefined-types.md#repos-sticky-header + */ + 'jsdoc/no-undefined-types'?: Linter.RuleEntry + /** + * Requires that each JSDoc line starts with an `*`. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-asterisk-prefix.md#repos-sticky-header + */ + 'jsdoc/require-asterisk-prefix'?: Linter.RuleEntry + /** + * Requires that all functions have a description. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-description.md#repos-sticky-header + */ + 'jsdoc/require-description'?: Linter.RuleEntry + /** + * Requires that block description, explicit `@description`, and `@param`/`@returns` tag descriptions are written in complete sentences. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-description-complete-sentence.md#repos-sticky-header + */ + 'jsdoc/require-description-complete-sentence'?: Linter.RuleEntry + /** + * Requires that all functions have examples. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-example.md#repos-sticky-header + */ + 'jsdoc/require-example'?: Linter.RuleEntry + /** + * Checks that all files have one `@file`, `@fileoverview`, or `@overview` tag at the beginning of the file. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-file-overview.md#repos-sticky-header + */ + 'jsdoc/require-file-overview'?: Linter.RuleEntry + /** + * Requires a hyphen before the `@param` description. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-hyphen-before-param-description.md#repos-sticky-header + */ + 'jsdoc/require-hyphen-before-param-description'?: Linter.RuleEntry + /** + * Require JSDoc comments + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-jsdoc.md#repos-sticky-header + */ + 'jsdoc/require-jsdoc'?: Linter.RuleEntry + /** + * Requires that all function parameters are documented. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param.md#repos-sticky-header + */ + 'jsdoc/require-param'?: Linter.RuleEntry + /** + * Requires that each `@param` tag has a `description` value. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param-description.md#repos-sticky-header + */ + 'jsdoc/require-param-description'?: Linter.RuleEntry + /** + * Requires that all function parameters have names. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param-name.md#repos-sticky-header + */ + 'jsdoc/require-param-name'?: Linter.RuleEntry + /** + * Requires that each `@param` tag has a `type` value. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-param-type.md#repos-sticky-header + */ + 'jsdoc/require-param-type'?: Linter.RuleEntry + /** + * Requires that all `@typedef` and `@namespace` tags have `@property` when their type is a plain `object`, `Object`, or `PlainObject`. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-property.md#repos-sticky-header + */ + 'jsdoc/require-property'?: Linter.RuleEntry<[]> + /** + * Requires that each `@property` tag has a `description` value. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-property-description.md#repos-sticky-header + */ + 'jsdoc/require-property-description'?: Linter.RuleEntry<[]> + /** + * Requires that all function `@property` tags have names. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-property-name.md#repos-sticky-header + */ + 'jsdoc/require-property-name'?: Linter.RuleEntry<[]> + /** + * Requires that each `@property` tag has a `type` value. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-property-type.md#repos-sticky-header + */ + 'jsdoc/require-property-type'?: Linter.RuleEntry<[]> + /** + * Requires that returns are documented. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns.md#repos-sticky-header + */ + 'jsdoc/require-returns'?: Linter.RuleEntry + /** + * Requires a return statement in function body if a `@returns` tag is specified in jsdoc comment. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns-check.md#repos-sticky-header + */ + 'jsdoc/require-returns-check'?: Linter.RuleEntry + /** + * Requires that the `@returns` tag has a `description` value. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns-description.md#repos-sticky-header + */ + 'jsdoc/require-returns-description'?: Linter.RuleEntry + /** + * Requires that `@returns` tag has `type` value. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns-type.md#repos-sticky-header + */ + 'jsdoc/require-returns-type'?: Linter.RuleEntry + /** + * Requires template tags for each generic type parameter + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-template.md#repos-sticky-header + */ + 'jsdoc/require-template'?: Linter.RuleEntry + /** + * Requires that throw statements are documented. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-throws.md#repos-sticky-header + */ + 'jsdoc/require-throws'?: Linter.RuleEntry + /** + * Requires yields are documented. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-yields.md#repos-sticky-header + */ + 'jsdoc/require-yields'?: Linter.RuleEntry + /** + * Requires a yield statement in function body if a `@yields` tag is specified in jsdoc comment. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-yields-check.md#repos-sticky-header + */ + 'jsdoc/require-yields-check'?: Linter.RuleEntry + /** + * Sorts tags by a specified sequence according to tag name. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/sort-tags.md#repos-sticky-header + */ + 'jsdoc/sort-tags'?: Linter.RuleEntry + /** + * Enforces lines (or no lines) between tags. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/tag-lines.md#repos-sticky-header + */ + 'jsdoc/tag-lines'?: Linter.RuleEntry + /** + * Auto-escape certain characters that are input within block and tag descriptions. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/text-escaping.md#repos-sticky-header + */ + 'jsdoc/text-escaping'?: Linter.RuleEntry + /** + * Requires all types to be valid JSDoc or Closure compiler types without syntax errors. + * @see https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/valid-types.md#repos-sticky-header + */ + 'jsdoc/valid-types'?: Linter.RuleEntry + /** + * enforce line breaks after opening and before closing array brackets + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/array-bracket-newline.html + */ + 'jsonc/array-bracket-newline'?: Linter.RuleEntry + /** + * disallow or enforce spaces inside of brackets + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/array-bracket-spacing.html + */ + 'jsonc/array-bracket-spacing'?: Linter.RuleEntry + /** + * enforce line breaks between array elements + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/array-element-newline.html + */ + 'jsonc/array-element-newline'?: Linter.RuleEntry + /** + * apply jsonc rules similar to your configured ESLint core rules + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/auto.html + */ + 'jsonc/auto'?: Linter.RuleEntry<[]> + /** + * require or disallow trailing commas + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/comma-dangle.html + */ + 'jsonc/comma-dangle'?: Linter.RuleEntry + /** + * enforce consistent comma style + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/comma-style.html + */ + 'jsonc/comma-style'?: Linter.RuleEntry + /** + * enforce consistent indentation + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/indent.html + */ + 'jsonc/indent'?: Linter.RuleEntry + /** + * enforce naming convention to property key names + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/key-name-casing.html + */ + 'jsonc/key-name-casing'?: Linter.RuleEntry + /** + * enforce consistent spacing between keys and values in object literal properties + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/key-spacing.html + */ + 'jsonc/key-spacing'?: Linter.RuleEntry + /** + * disallow BigInt literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-bigint-literals.html + */ + 'jsonc/no-bigint-literals'?: Linter.RuleEntry<[]> + /** + * disallow binary expression + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-binary-expression.html + */ + 'jsonc/no-binary-expression'?: Linter.RuleEntry<[]> + /** + * disallow binary numeric literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-binary-numeric-literals.html + */ + 'jsonc/no-binary-numeric-literals'?: Linter.RuleEntry<[]> + /** + * disallow comments + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-comments.html + */ + 'jsonc/no-comments'?: Linter.RuleEntry<[]> + /** + * disallow duplicate keys in object literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-dupe-keys.html + */ + 'jsonc/no-dupe-keys'?: Linter.RuleEntry<[]> + /** + * disallow escape sequences in identifiers. + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-escape-sequence-in-identifier.html + */ + 'jsonc/no-escape-sequence-in-identifier'?: Linter.RuleEntry<[]> + /** + * disallow leading or trailing decimal points in numeric literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-floating-decimal.html + */ + 'jsonc/no-floating-decimal'?: Linter.RuleEntry<[]> + /** + * disallow hexadecimal numeric literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-hexadecimal-numeric-literals.html + */ + 'jsonc/no-hexadecimal-numeric-literals'?: Linter.RuleEntry<[]> + /** + * disallow Infinity + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-infinity.html + */ + 'jsonc/no-infinity'?: Linter.RuleEntry<[]> + /** + * disallow irregular whitespace + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-irregular-whitespace.html + */ + 'jsonc/no-irregular-whitespace'?: Linter.RuleEntry + /** + * disallow multiline strings + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-multi-str.html + */ + 'jsonc/no-multi-str'?: Linter.RuleEntry<[]> + /** + * disallow NaN + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-nan.html + */ + 'jsonc/no-nan'?: Linter.RuleEntry<[]> + /** + * disallow number property keys + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-number-props.html + */ + 'jsonc/no-number-props'?: Linter.RuleEntry<[]> + /** + * disallow numeric separators + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-numeric-separators.html + */ + 'jsonc/no-numeric-separators'?: Linter.RuleEntry<[]> + /** + * disallow legacy octal literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-octal.html + */ + 'jsonc/no-octal'?: Linter.RuleEntry<[]> + /** + * disallow octal escape sequences in string literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-octal-escape.html + */ + 'jsonc/no-octal-escape'?: Linter.RuleEntry<[]> + /** + * disallow octal numeric literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-octal-numeric-literals.html + */ + 'jsonc/no-octal-numeric-literals'?: Linter.RuleEntry<[]> + /** + * disallow parentheses around the expression + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-parenthesized.html + */ + 'jsonc/no-parenthesized'?: Linter.RuleEntry<[]> + /** + * disallow plus sign + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-plus-sign.html + */ + 'jsonc/no-plus-sign'?: Linter.RuleEntry<[]> + /** + * disallow RegExp literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-regexp-literals.html + */ + 'jsonc/no-regexp-literals'?: Linter.RuleEntry<[]> + /** + * disallow sparse arrays + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-sparse-arrays.html + */ + 'jsonc/no-sparse-arrays'?: Linter.RuleEntry<[]> + /** + * disallow template literals + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-template-literals.html + */ + 'jsonc/no-template-literals'?: Linter.RuleEntry<[]> + /** + * disallow `undefined` + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-undefined-value.html + */ + 'jsonc/no-undefined-value'?: Linter.RuleEntry<[]> + /** + * disallow Unicode code point escape sequences. + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-unicode-codepoint-escapes.html + */ + 'jsonc/no-unicode-codepoint-escapes'?: Linter.RuleEntry<[]> + /** + * disallow unnecessary escape usage + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/no-useless-escape.html + */ + 'jsonc/no-useless-escape'?: Linter.RuleEntry<[]> + /** + * enforce consistent line breaks inside braces + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/object-curly-newline.html + */ + 'jsonc/object-curly-newline'?: Linter.RuleEntry + /** + * enforce consistent spacing inside braces + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/object-curly-spacing.html + */ + 'jsonc/object-curly-spacing'?: Linter.RuleEntry + /** + * enforce placing object properties on separate lines + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/object-property-newline.html + */ + 'jsonc/object-property-newline'?: Linter.RuleEntry + /** + * require quotes around object literal property names + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/quote-props.html + */ + 'jsonc/quote-props'?: Linter.RuleEntry + /** + * enforce use of double or single quotes + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/quotes.html + */ + 'jsonc/quotes'?: Linter.RuleEntry + /** + * require array values to be sorted + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/sort-array-values.html + */ + 'jsonc/sort-array-values'?: Linter.RuleEntry + /** + * require object keys to be sorted + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/sort-keys.html + */ + 'jsonc/sort-keys'?: Linter.RuleEntry + /** + * disallow spaces after unary operators + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/space-unary-ops.html + */ + 'jsonc/space-unary-ops'?: Linter.RuleEntry + /** + * disallow invalid number for JSON + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/valid-json-number.html + */ + 'jsonc/valid-json-number'?: Linter.RuleEntry<[]> + /** + * disallow parsing errors in Vue custom blocks + * @see https://ota-meshi.github.io/eslint-plugin-jsonc/rules/vue-custom-block/no-parsing-error.html + */ + 'jsonc/vue-custom-block/no-parsing-error'?: Linter.RuleEntry<[]> + /** + * Enforce emojis are wrapped in `` and provide screen reader access. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/accessible-emoji.md + * @deprecated + */ + 'jsx-a11y/accessible-emoji'?: Linter.RuleEntry + /** + * Enforce all elements that require alternative text have meaningful information to relay back to end user. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/alt-text.md + */ + 'jsx-a11y/alt-text'?: Linter.RuleEntry + /** + * Enforce `` text to not exactly match "click here", "here", "link", or "a link". + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-ambiguous-text.md + */ + 'jsx-a11y/anchor-ambiguous-text'?: Linter.RuleEntry + /** + * Enforce all anchors to contain accessible content. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-has-content.md + */ + 'jsx-a11y/anchor-has-content'?: Linter.RuleEntry + /** + * Enforce all anchors are valid, navigable elements. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/anchor-is-valid.md + */ + 'jsx-a11y/anchor-is-valid'?: Linter.RuleEntry + /** + * Enforce elements with aria-activedescendant are tabbable. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-activedescendant-has-tabindex.md + */ + 'jsx-a11y/aria-activedescendant-has-tabindex'?: Linter.RuleEntry + /** + * Enforce all `aria-*` props are valid. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-props.md + */ + 'jsx-a11y/aria-props'?: Linter.RuleEntry + /** + * Enforce ARIA state and property values are valid. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-proptypes.md + */ + 'jsx-a11y/aria-proptypes'?: Linter.RuleEntry + /** + * Enforce that elements with ARIA roles must use a valid, non-abstract ARIA role. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-role.md + */ + 'jsx-a11y/aria-role'?: Linter.RuleEntry + /** + * Enforce that elements that do not support ARIA roles, states, and properties do not have those attributes. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/aria-unsupported-elements.md + */ + 'jsx-a11y/aria-unsupported-elements'?: Linter.RuleEntry + /** + * Enforce that autocomplete attributes are used correctly. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/autocomplete-valid.md + */ + 'jsx-a11y/autocomplete-valid'?: Linter.RuleEntry + /** + * Enforce a clickable non-interactive element has at least one keyboard event listener. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/click-events-have-key-events.md + */ + 'jsx-a11y/click-events-have-key-events'?: Linter.RuleEntry + /** + * Enforce that a control (an interactive element) has a text label. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/control-has-associated-label.md + */ + 'jsx-a11y/control-has-associated-label'?: Linter.RuleEntry + /** + * Enforce heading (`h1`, `h2`, etc) elements contain accessible content. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/heading-has-content.md + */ + 'jsx-a11y/heading-has-content'?: Linter.RuleEntry + /** + * Enforce `` element has `lang` prop. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/html-has-lang.md + */ + 'jsx-a11y/html-has-lang'?: Linter.RuleEntry + /** + * Enforce iframe elements have a title attribute. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/iframe-has-title.md + */ + 'jsx-a11y/iframe-has-title'?: Linter.RuleEntry + /** + * Enforce `` alt prop does not contain the word "image", "picture", or "photo". + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/img-redundant-alt.md + */ + 'jsx-a11y/img-redundant-alt'?: Linter.RuleEntry + /** + * Enforce that elements with interactive handlers like `onClick` must be focusable. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/tree/HEAD/docs/rules/interactive-supports-focus.md + */ + 'jsx-a11y/interactive-supports-focus'?: Linter.RuleEntry + /** + * Enforce that a `label` tag has a text label and an associated control. + * @see https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/label-has-associated-control.md + */ + 'jsx-a11y/label-has-associated-control'?: Linter.RuleEntry + /** + * Enforce that `