generated from nhcarrigan/template
Compare commits
No commits in common. "6cc2b478a100c74f4cd723796743a8639485bb2d" and "1faaed08153e354815a1c46fcdc7cf1d8c4d4aea" have entirely different histories.
6cc2b478a1
...
1faaed0815
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/node_modules/
|
||||
/prod/
|
||||
|
||||
# Ignore packed files so that npm pack can be run locally
|
||||
*.tgz
|
||||
|
||||
# Sonarcloud
|
||||
.scannerwork
|
7
.npmignore
Normal file
7
.npmignore
Normal file
@ -0,0 +1,7 @@
|
||||
/.forgejo/
|
||||
.prettierrc.json
|
||||
.gitattributes
|
||||
/src/
|
||||
|
||||
# Ignore packed files so that npm pack can be run locally
|
||||
*.tgz
|
12
.vscode/settings.json
vendored
Normal file
12
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"eslint.validate": [
|
||||
"typescript"
|
||||
],
|
||||
"sonarlint.connectedMode.project": {
|
||||
"connectionId": "nhcarrigan",
|
||||
"projectKey": "nhcarrigan_eslint-config"
|
||||
}
|
||||
}
|
105
README.md
105
README.md
@ -1,20 +1,95 @@
|
||||
# New Repository Template
|
||||
# Naomi's ESLint Config
|
||||
|
||||
This template contains all of our basic files for a new GitHub repository. There is also a handy workflow that will create an issue on a new repository made from this template, with a checklist for the steps we usually take in setting up a new repository.
|
||||
|
||||
If you're starting a Node.JS project with TypeScript, we have a [specific template](https://github.com/naomi-lgbt/nodejs-typescript-template) for that purpose.
|
||||
|
||||
## Readme
|
||||
|
||||
Delete all of the above text (including this line), and uncomment the below text to use our standard readme template.
|
||||
|
||||
<!-- # Project Name
|
||||
|
||||
Project Description
|
||||
This package holds my ESLint configuration for easy installation and syncing changes across projects.
|
||||
|
||||
## Live Version
|
||||
|
||||
This page is currently deployed. [View the live website.]
|
||||
This package is currently published. [View the `npm` page](https://www.npmjs.com/package/@nhcarrigan/eslint-config).
|
||||
|
||||
## Installation
|
||||
|
||||
To install this package, run the following command:
|
||||
|
||||
```bash
|
||||
npm i @nhcarrigan/eslint-config eslint
|
||||
```
|
||||
|
||||
## Compatibility
|
||||
|
||||
This package is compatible with ESLint 9.
|
||||
|
||||
## Usage
|
||||
|
||||
To use this package, add the following to your `eslint.config.js` file:
|
||||
|
||||
```js
|
||||
import NaomisConfig from "@nhcarrigan/eslint-config";
|
||||
|
||||
export default [
|
||||
...NaomisConfig,
|
||||
// Any overrides you need, such as:
|
||||
{
|
||||
rules: {
|
||||
complexity: "off",
|
||||
"max-lines-per-function": "off",
|
||||
"max-statements": "off",
|
||||
"jsdoc/require-file-overview": "off"
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["test/__mocks__/Database.mock.ts"],
|
||||
rules: {
|
||||
"require-await": "off"
|
||||
}
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
Then set up these two scripts in your `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"format": "eslint src test --max-warnings 0 --fix",
|
||||
"lint": "eslint src test --max-warnings 0",
|
||||
}
|
||||
```
|
||||
|
||||
### Formatting
|
||||
|
||||
Our rulesets include the `stylistic` package, which enforces quite a bit of specific formatting. With this being the case, projects should NOT use Prettier in tandem with this config.
|
||||
|
||||
Instead, set your editor to run the ESLint formatter on save. For example, in VSCodium, you can add a `.vscode/settings.json` file to your project:
|
||||
|
||||
```json
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"eslint.validate": ["typescript"]
|
||||
}
|
||||
```
|
||||
|
||||
## Stylistic Standards
|
||||
|
||||
This configuration does not extend or incorporate any external rulesets. Every rule this config sets has been added deliberately and with reason.
|
||||
|
||||
### Warnings and Errors
|
||||
|
||||
A rule is set to be a warning when it is something that is okay during development (e.g. using a `console.log`, or not having a JSDoc definition yet) but should not make it to production code.
|
||||
|
||||
A rule is set to an error when it is something that should not occur in development or production (e.g. missing semi-colons, using loose equality).
|
||||
|
||||
### No Deactivated Rules
|
||||
|
||||
Because this config is built from scratch, there is no need to explicitly deactivate any rules. Everything is "off" by default, and turned on as desired by this package.
|
||||
|
||||
The tests will not allow you to explicitly disable rules.
|
||||
|
||||
The only exception is the `disabledEslintRules` object, which explicitly turns off built-in ESLint rules to avoid conflicts with external packages like `@typescript-eslint`.
|
||||
|
||||
### Proposing Style Changes
|
||||
|
||||
All style changes should be proposed in our [chat server](https://chat.nhcarrigan.com).
|
||||
|
||||
## Feedback and Bugs
|
||||
|
||||
@ -30,10 +105,10 @@ Before interacting with our community, please read our [Code of Conduct](CODE_OF
|
||||
|
||||
## License
|
||||
|
||||
This software is licensed under our [global software license](https://docs.nhcarrigan.com/#/license).
|
||||
This software is licensed under our [global software license](https://docs.nhcarrigan.com/legal/license/).
|
||||
|
||||
Copyright held by Naomi Carrigan.
|
||||
|
||||
## Contact
|
||||
|
||||
We may be contacted through our [Chat Server](http://chat.nhcarrigan.com) or via email at `contact@nhcarrigan.com`. -->
|
||||
We may be contacted through our [Chat Server](http://chat.nhcarrigan.com) or via email at `contact@nhcarrigan.com`.
|
||||
|
17
eslint.config.js
Normal file
17
eslint.config.js
Normal file
@ -0,0 +1,17 @@
|
||||
import naomisRules from "./prod/index.js";
|
||||
|
||||
export default [
|
||||
...naomisRules,
|
||||
{
|
||||
rules: {
|
||||
"@typescript-eslint/naming-convention": "off",
|
||||
"import/no-default-export": "off",
|
||||
"import/namespace": "off",
|
||||
"import/no-deprecated": "off",
|
||||
"@typescript-eslint/consistent-type-assertions": "off",
|
||||
"max-lines-per-function": "off",
|
||||
"complexity": "off",
|
||||
"max-nested-callbacks": "off"
|
||||
},
|
||||
},
|
||||
];
|
64
package.json
Normal file
64
package.json
Normal file
@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "@nhcarrigan/eslint-config",
|
||||
"version": "5.1.0",
|
||||
"description": "Global config for ESLint",
|
||||
"main": "prod/index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"prepublish": "pnpm format && pnpm test",
|
||||
"build": "tsc",
|
||||
"format": "pnpm build && eslint src test --max-warnings 0 --fix",
|
||||
"lint": "pnpm build && eslint src test --max-warnings 0",
|
||||
"test": "vitest run",
|
||||
"scan": "SONAR_TOKEN='op://Environment Variables - Development/SonarCloud/eslint-config' op run -- sonar-scanner -Dsonar.organization=nhcarrigan -Dsonar.projectKey=nhcarrigan_eslint-config -Dsonar.sources=. -Dsonar.host.url=https://sonarcloud.io"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@codeberg.org:naomi-lgbt/eslint-config.git"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22",
|
||||
"pnpm": ">=9"
|
||||
},
|
||||
"keywords": [
|
||||
"eslint"
|
||||
],
|
||||
"author": "Naomi Carrigan",
|
||||
"license": "SEE LICENSE IN https://docs.nhcarrigan.com/#/license",
|
||||
"bugs": {
|
||||
"url": "https://codeberg.org/naomi-lgbt/eslint-config/issues"
|
||||
},
|
||||
"homepage": "https://codeberg.org/naomi-lgbt/eslint-config",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-plugin-eslint-comments": "4.4.1",
|
||||
"@eslint/compat": "1.2.4",
|
||||
"@eslint/eslintrc": "3.2.0",
|
||||
"@eslint/js": "9.17.0",
|
||||
"@stylistic/eslint-plugin": "2.12.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.19.0",
|
||||
"@typescript-eslint/parser": "8.19.0",
|
||||
"@vitest/eslint-plugin": "1.1.24",
|
||||
"eslint-plugin-deprecation": "3.0.0",
|
||||
"eslint-plugin-import": "2.31.0",
|
||||
"eslint-plugin-jsdoc": "50.6.1",
|
||||
"eslint-plugin-playwright": "2.1.0",
|
||||
"eslint-plugin-react": "7.37.3",
|
||||
"eslint-plugin-sort-keys-fix": "1.1.2",
|
||||
"eslint-plugin-unicorn": "56.0.1",
|
||||
"globals": "15.14.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">=9",
|
||||
"playwright": ">=1",
|
||||
"react": ">=18",
|
||||
"typescript": ">=5",
|
||||
"vitest": ">=2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nhcarrigan/typescript-config": "4.0.0",
|
||||
"@types/eslint": "9.6.1",
|
||||
"@types/node": "22.10.5",
|
||||
"typescript": "5.7.2",
|
||||
"vitest": "2.1.8"
|
||||
}
|
||||
}
|
4594
pnpm-lock.yaml
generated
Normal file
4594
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
214
src/index.ts
Normal file
214
src/index.ts
Normal file
@ -0,0 +1,214 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { fixupPluginRules } from "@eslint/compat";
|
||||
import comments from "@eslint-community/eslint-plugin-eslint-comments";
|
||||
import stylistic from "@stylistic/eslint-plugin";
|
||||
import tslint from "@typescript-eslint/eslint-plugin";
|
||||
import parser from "@typescript-eslint/parser";
|
||||
import vitest from "@vitest/eslint-plugin";
|
||||
import deprecation from "eslint-plugin-deprecation";
|
||||
import importPlugin from "eslint-plugin-import";
|
||||
import jsdoc from "eslint-plugin-jsdoc";
|
||||
import playwright from "eslint-plugin-playwright";
|
||||
import react from "eslint-plugin-react";
|
||||
import sortKeysFix from "eslint-plugin-sort-keys-fix";
|
||||
import unicorn from "eslint-plugin-unicorn";
|
||||
import globals from "globals";
|
||||
import { commentsRules } from "./rules/comments.js";
|
||||
import { deprecationRules } from "./rules/deprecation.js";
|
||||
import { disabledEslintRules, eslintRules } from "./rules/eslint.js";
|
||||
import { importRules } from "./rules/import.js";
|
||||
import { jsdocRules } from "./rules/jsdoc.js";
|
||||
import { playwrightRules } from "./rules/playwright.js";
|
||||
import { reactRules } from "./rules/react.js";
|
||||
import { sortKeysFixRules } from "./rules/sortKeysFix.js";
|
||||
import { stylisticRules } from "./rules/stylistic.js";
|
||||
import { typescriptEslintRules, typescriptEslintRulesWithTypes }
|
||||
from "./rules/typescriptEslint.js";
|
||||
import { unicornRules } from "./rules/unicorn.js";
|
||||
import { vitestRules } from "./rules/vitest.js";
|
||||
import type { ESLint, Linter } from "eslint";
|
||||
|
||||
const config: Array<Linter.Config> = [
|
||||
// #region Typescript Config
|
||||
{
|
||||
files: [ "src/**/*.ts" ],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
parser: parser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 11,
|
||||
project: true,
|
||||
sourceType: "module",
|
||||
tsconfigRootDir: process.cwd(),
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
// @ts-expect-error It's a config. It's just not the narrow config. SMH.
|
||||
"@typescript-eslint": tslint,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Not unsafe, just not typed.
|
||||
"comments": comments,
|
||||
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||
"deprecation": fixupPluginRules(deprecation),
|
||||
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
|
||||
"jsdoc": jsdoc,
|
||||
"sort-keys-fix": sortKeysFix as ESLint.Plugin,
|
||||
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||
"stylistic": fixupPluginRules(stylistic),
|
||||
"unicorn": unicorn,
|
||||
},
|
||||
rules: {
|
||||
...eslintRules,
|
||||
...disabledEslintRules,
|
||||
...typescriptEslintRules,
|
||||
...typescriptEslintRulesWithTypes,
|
||||
...importRules,
|
||||
...jsdocRules,
|
||||
...deprecationRules,
|
||||
...stylisticRules,
|
||||
...unicornRules,
|
||||
...sortKeysFixRules,
|
||||
...commentsRules,
|
||||
},
|
||||
},
|
||||
// #endregion
|
||||
|
||||
// #region Vitest Config
|
||||
{
|
||||
files: [ "test/**/*.spec.ts" ],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
parser: parser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 11,
|
||||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
// @ts-expect-error It's a config. It's just not the narrow config. SMH.
|
||||
"@typescript-eslint": tslint,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Not unsafe, just not typed.
|
||||
"comments": comments,
|
||||
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
|
||||
"jsdoc": jsdoc,
|
||||
"sort-keys-fix": sortKeysFix as ESLint.Plugin,
|
||||
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||
"stylistic": fixupPluginRules(stylistic),
|
||||
"unicorn": unicorn,
|
||||
"vitest": vitest,
|
||||
},
|
||||
rules: {
|
||||
...eslintRules,
|
||||
...disabledEslintRules,
|
||||
...typescriptEslintRules,
|
||||
...vitestRules,
|
||||
...importRules,
|
||||
...jsdocRules,
|
||||
...stylisticRules,
|
||||
...unicornRules,
|
||||
...sortKeysFixRules,
|
||||
...commentsRules,
|
||||
},
|
||||
},
|
||||
// #endregion
|
||||
|
||||
// #region Playwright Config
|
||||
{
|
||||
files: [ "e2e/**/*.spec.ts" ],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
parser: parser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 11,
|
||||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
// @ts-expect-error It's a config. It's just not the narrow config. SMH.
|
||||
"@typescript-eslint": tslint,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Not unsafe, just not typed.
|
||||
"comments": comments,
|
||||
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
|
||||
"jsdoc": jsdoc,
|
||||
"playwright": playwright,
|
||||
"sort-keys-fix": sortKeysFix as ESLint.Plugin,
|
||||
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||
"stylistic": fixupPluginRules(stylistic),
|
||||
"unicorn": unicorn,
|
||||
},
|
||||
rules: {
|
||||
...eslintRules,
|
||||
...disabledEslintRules,
|
||||
...typescriptEslintRules,
|
||||
...playwrightRules,
|
||||
...importRules,
|
||||
...jsdocRules,
|
||||
...stylisticRules,
|
||||
...unicornRules,
|
||||
...sortKeysFixRules,
|
||||
...commentsRules,
|
||||
},
|
||||
},
|
||||
// #endregion
|
||||
|
||||
// #region React Config
|
||||
{
|
||||
files: [ "src/**/*.tsx" ],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
},
|
||||
parser: parser,
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
},
|
||||
ecmaVersion: 11,
|
||||
project: true,
|
||||
sourceType: "module",
|
||||
tsconfigRootDir: process.cwd(),
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
// @ts-expect-error It's a config. It's just not the narrow config. SMH.
|
||||
"@typescript-eslint": tslint,
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Not unsafe, just not typed.
|
||||
"comments": comments,
|
||||
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||
"deprecation": fixupPluginRules(deprecation),
|
||||
"import": fixupPluginRules(importPlugin as ESLint.Plugin),
|
||||
"jsdoc": jsdoc,
|
||||
"react": react as ESLint.Plugin,
|
||||
"sort-keys-fix": sortKeysFix as ESLint.Plugin,
|
||||
// @ts-expect-error They haven't typedef this yet because it technically doesn't support eslint9
|
||||
"stylistic": fixupPluginRules(stylistic),
|
||||
"unicorn": unicorn,
|
||||
},
|
||||
rules: {
|
||||
...eslintRules,
|
||||
...disabledEslintRules,
|
||||
...typescriptEslintRules,
|
||||
...typescriptEslintRulesWithTypes,
|
||||
...importRules,
|
||||
...jsdocRules,
|
||||
...deprecationRules,
|
||||
...stylisticRules,
|
||||
...unicornRules,
|
||||
...sortKeysFixRules,
|
||||
...reactRules,
|
||||
...commentsRules,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default config;
|
12
src/rules/comments.ts
Normal file
12
src/rules/comments.ts
Normal file
@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
export const commentsRules: Linter.RulesRecord = {
|
||||
"comments/no-unlimited-disable": "warn",
|
||||
"comments/require-description": "warn",
|
||||
};
|
11
src/rules/deprecation.ts
Normal file
11
src/rules/deprecation.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
export const deprecationRules: Linter.RulesRecord = {
|
||||
"deprecation/deprecation": "error",
|
||||
};
|
202
src/rules/eslint.ts
Normal file
202
src/rules/eslint.ts
Normal file
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
const maxComplexity = 10;
|
||||
const maxClasses = 1;
|
||||
const maxDepth = 5;
|
||||
const maxCallbacks = 2;
|
||||
const maxStatements = 20;
|
||||
|
||||
/**
|
||||
* Rules explicitly disabled to be overridden
|
||||
* by external packages.
|
||||
*/
|
||||
const disabledEslintRules: Linter.RulesRecord = {
|
||||
"class-methods-use-this": "off",
|
||||
"default-param-last": "off",
|
||||
"dot-notation": "off",
|
||||
"init-declarations": "off",
|
||||
"max-params": "off",
|
||||
"no-array-constructor": "off",
|
||||
"no-empty-function": "off",
|
||||
"no-implied-eval": "off",
|
||||
"no-loop-func": "off",
|
||||
"no-loss-of-precision": "off",
|
||||
"no-return-await": "off",
|
||||
"no-shadow": "off",
|
||||
"no-throw-literal": "off",
|
||||
"no-unused-expressions": "off",
|
||||
"no-unused-vars": "off",
|
||||
"no-use-before-define": "off",
|
||||
"no-useless-constructor": "off",
|
||||
"prefer-destructuring": "off",
|
||||
"prefer-promise-reject-errors": "off",
|
||||
"require-await": "off",
|
||||
};
|
||||
|
||||
/**
|
||||
* Rules for the base eslint.
|
||||
*/
|
||||
const eslintRules: Linter.RulesRecord = {
|
||||
"accessor-pairs": "error",
|
||||
"array-callback-return": [ "error", { allowImplicit: true } ],
|
||||
"arrow-body-style": [ "warn", "always" ],
|
||||
"block-scoped-var": "error",
|
||||
"capitalized-comments": "warn",
|
||||
"complexity": [ "error", maxComplexity ],
|
||||
"consistent-return": "error",
|
||||
"curly": "error",
|
||||
"default-case": "error",
|
||||
"default-case-last": "warn",
|
||||
"eqeqeq": "error",
|
||||
"for-direction": "error",
|
||||
"func-name-matching": "error",
|
||||
"func-names": [ "warn", "always" ],
|
||||
"func-style":
|
||||
[ "warn", "declaration", { allowArrowFunctions: true } ],
|
||||
"getter-return": [ "error", { allowImplicit: false } ],
|
||||
"grouped-accessor-pairs": "warn",
|
||||
"logical-assignment-operators": [ "error", "never" ],
|
||||
"max-classes-per-file": [ "error", maxClasses ],
|
||||
"max-depth": [ "warn", maxDepth ],
|
||||
"max-lines":
|
||||
[ "warn", { max: 300, skipBlankLines: true, skipComments: true } ],
|
||||
"max-lines-per-function": [
|
||||
"warn",
|
||||
{ IIFEs: true, max: 50, skipBlankLines: true, skipComments: false },
|
||||
],
|
||||
"max-nested-callbacks": [ "warn", maxCallbacks ],
|
||||
"max-statements": [ "warn", maxStatements ],
|
||||
"new-cap": "warn",
|
||||
"no-alert": "warn",
|
||||
"no-async-promise-executor": "error",
|
||||
"no-await-in-loop": "warn",
|
||||
"no-bitwise": "error",
|
||||
"no-caller": "error",
|
||||
"no-case-declarations": "warn",
|
||||
"no-class-assign": "error",
|
||||
"no-compare-neg-zero": "error",
|
||||
"no-cond-assign": "error",
|
||||
"no-console": "warn",
|
||||
// Technically covered by ts
|
||||
"no-const-assign": "error",
|
||||
"no-constant-binary-expression": "error",
|
||||
"no-constant-condition": "error",
|
||||
"no-constructor-return": "error",
|
||||
"no-control-regex": "error",
|
||||
"no-debugger": "warn",
|
||||
"no-delete-var": "error",
|
||||
"no-div-regex": "warn",
|
||||
"no-dupe-args": "error",
|
||||
"no-dupe-class-members": "error",
|
||||
"no-dupe-else-if": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-duplicate-imports": "warn",
|
||||
"no-else-return": "warn",
|
||||
"no-empty": "warn",
|
||||
"no-empty-character-class": "warn",
|
||||
"no-empty-pattern": "warn",
|
||||
"no-empty-static-block": "warn",
|
||||
"no-eq-null": "error",
|
||||
"no-eval": "error",
|
||||
"no-ex-assign": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-extra-bind": "warn",
|
||||
"no-extra-boolean-cast": "warn",
|
||||
"no-extra-label": "warn",
|
||||
"no-fallthrough": "error",
|
||||
"no-func-assign": "error",
|
||||
"no-global-assign": "error",
|
||||
"no-implicit-coercion": "warn",
|
||||
"no-implicit-globals": "error",
|
||||
"no-import-assign": "error",
|
||||
"no-inner-declarations": "warn",
|
||||
"no-invalid-regexp": "warn",
|
||||
"no-invalid-this": "error",
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-iterator": "error",
|
||||
"no-label-var": "error",
|
||||
"no-labels": "warn",
|
||||
"no-lone-blocks": "warn",
|
||||
"no-lonely-if": "warn",
|
||||
"no-misleading-character-class": "warn",
|
||||
"no-multi-assign": "warn",
|
||||
"no-multi-str": "warn",
|
||||
"no-negated-condition": "warn",
|
||||
"no-nested-ternary": "warn",
|
||||
"no-new": "warn",
|
||||
"no-new-native-nonconstructor": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-nonoctal-decimal-escape": "warn",
|
||||
"no-obj-calls": "warn",
|
||||
"no-object-constructor": "error",
|
||||
"no-octal": "warn",
|
||||
"no-octal-escape": "warn",
|
||||
"no-param-reassign": "error",
|
||||
"no-plusplus": "warn",
|
||||
"no-promise-executor-return": "warn",
|
||||
"no-proto": "warn",
|
||||
"no-prototype-builtins": "error",
|
||||
"no-regex-spaces": "warn",
|
||||
"no-return-assign": "error",
|
||||
"no-script-url": "warn",
|
||||
"no-self-assign": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "warn",
|
||||
"no-setter-return": "error",
|
||||
"no-sparse-arrays": "error",
|
||||
"no-template-curly-in-string": "warn",
|
||||
"no-this-before-super": "error",
|
||||
"no-undef": "error",
|
||||
"no-undef-init": "warn",
|
||||
"no-underscore-dangle": "warn",
|
||||
"no-unexpected-multiline": "warn",
|
||||
"no-unmodified-loop-condition": "warn",
|
||||
"no-unneeded-ternary": "warn",
|
||||
"no-unreachable": "warn",
|
||||
"no-unreachable-loop": "warn",
|
||||
"no-unsafe-finally": "error",
|
||||
"no-unsafe-negation": "error",
|
||||
"no-unsafe-optional-chaining": "error",
|
||||
"no-unused-private-class-members": "warn",
|
||||
"no-useless-assignment": "warn",
|
||||
"no-useless-backreference": "warn",
|
||||
"no-useless-call": "warn",
|
||||
"no-useless-catch": "warn",
|
||||
"no-useless-computed-key": "warn",
|
||||
"no-useless-concat": "warn",
|
||||
"no-useless-escape": "warn",
|
||||
"no-useless-rename": "warn",
|
||||
"no-useless-return": "warn",
|
||||
"no-var": "error",
|
||||
"no-warning-comments": "warn",
|
||||
"no-with": "error",
|
||||
"object-shorthand": [ "warn", "consistent-as-needed" ],
|
||||
"operator-assignment": [ "warn", "never" ],
|
||||
"prefer-arrow-callback": "warn",
|
||||
"prefer-const": "error",
|
||||
"prefer-named-capture-group": "warn",
|
||||
"prefer-object-has-own": "warn",
|
||||
"prefer-object-spread": "warn",
|
||||
"prefer-regex-literals": "warn",
|
||||
"prefer-rest-params": "warn",
|
||||
"prefer-spread": "warn",
|
||||
"prefer-template": "warn",
|
||||
"radix": "error",
|
||||
"require-atomic-updates": "error",
|
||||
"require-yield": "warn",
|
||||
"sort-keys": "warn",
|
||||
"sort-vars": "warn",
|
||||
"symbol-description": "warn",
|
||||
"use-isnan": "warn",
|
||||
"valid-typeof": "error",
|
||||
"yoda": [ "warn", "never" ],
|
||||
};
|
||||
|
||||
export { disabledEslintRules, eslintRules };
|
62
src/rules/import.ts
Normal file
62
src/rules/import.ts
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
export const importRules: Linter.RulesRecord = {
|
||||
"import/default": "error",
|
||||
"import/export": "error",
|
||||
"import/exports-last": "warn",
|
||||
"import/extensions": [ "warn", "ignorePackages" ],
|
||||
"import/first": "warn",
|
||||
"import/group-exports": "warn",
|
||||
"import/newline-after-import": [ "warn", { count: 1 } ],
|
||||
"import/no-absolute-path": [ "error" ],
|
||||
"import/no-amd": "error",
|
||||
"import/no-anonymous-default-export": [ "warn" ],
|
||||
"import/no-commonjs": [ "error" ],
|
||||
"import/no-cycle": [ "error" ],
|
||||
"import/no-default-export": "warn",
|
||||
"import/no-duplicates": [ "error" ],
|
||||
"import/no-dynamic-require": "error",
|
||||
"import/no-empty-named-blocks": "error",
|
||||
"import/no-extraneous-dependencies": [
|
||||
"error",
|
||||
{ devDependencies: [ "**/*.spec.ts" ] },
|
||||
],
|
||||
"import/no-import-module-exports": [ "error" ],
|
||||
"import/no-mutable-exports": "error",
|
||||
"import/no-named-as-default": "warn",
|
||||
"import/no-named-as-default-member": "warn",
|
||||
"import/no-namespace": [ "warn" ],
|
||||
"import/no-relative-packages": "warn",
|
||||
"import/no-self-import": "error",
|
||||
"import/no-unassigned-import": [ "error" ],
|
||||
"import/no-unused-modules": [ "warn" ],
|
||||
"import/no-useless-path-segments": [ "warn" ],
|
||||
"import/no-webpack-loader-syntax": "error",
|
||||
"import/order": [
|
||||
"warn",
|
||||
{
|
||||
"alphabetize": {
|
||||
caseInsensitive: true,
|
||||
order: "asc",
|
||||
},
|
||||
"groups": [
|
||||
"builtin",
|
||||
"external",
|
||||
"internal",
|
||||
"parent",
|
||||
"sibling",
|
||||
"index",
|
||||
"object",
|
||||
"type",
|
||||
"unknown",
|
||||
],
|
||||
"newlines-between": "never",
|
||||
},
|
||||
],
|
||||
};
|
102
src/rules/jsdoc.ts
Normal file
102
src/rules/jsdoc.ts
Normal file
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
export const jsdocRules: Linter.RulesRecord = {
|
||||
"jsdoc/check-access": "warn",
|
||||
"jsdoc/check-alignment": "warn",
|
||||
"jsdoc/check-indentation": "warn",
|
||||
"jsdoc/check-param-names": "warn",
|
||||
"jsdoc/check-property-names": "warn",
|
||||
"jsdoc/check-syntax": "warn",
|
||||
"jsdoc/check-tag-names": "warn",
|
||||
"jsdoc/check-template-names": "warn",
|
||||
"jsdoc/check-values": [
|
||||
"warn",
|
||||
{
|
||||
allowedLicenses: [ "Naomi's Public License" ],
|
||||
},
|
||||
],
|
||||
"jsdoc/convert-to-jsdoc-comments": [
|
||||
"warn",
|
||||
{
|
||||
enableFixer: true,
|
||||
enforceJsdocLineStyle: "multi",
|
||||
lineOrBlockStyle: "both",
|
||||
},
|
||||
],
|
||||
"jsdoc/empty-tags": "warn",
|
||||
"jsdoc/implements-on-classes": "warn",
|
||||
"jsdoc/imports-as-dependencies": "warn",
|
||||
"jsdoc/informative-docs": "warn",
|
||||
"jsdoc/match-description": "warn",
|
||||
"jsdoc/multiline-blocks":
|
||||
[ "warn", { noSingleLineBlocks: true } ],
|
||||
"jsdoc/no-bad-blocks": "warn",
|
||||
"jsdoc/no-blank-block-descriptions": "warn",
|
||||
"jsdoc/no-blank-blocks": "warn",
|
||||
"jsdoc/no-defaults": "warn",
|
||||
"jsdoc/no-types": "warn",
|
||||
"jsdoc/require-asterisk-prefix": "warn",
|
||||
"jsdoc/require-description": "warn",
|
||||
"jsdoc/require-description-complete-sentence": "warn",
|
||||
"jsdoc/require-file-overview": [
|
||||
"warn",
|
||||
{
|
||||
tags: {
|
||||
author: {
|
||||
mustExist: true,
|
||||
preventDuplicates: true,
|
||||
},
|
||||
copyright: {
|
||||
mustExist: true,
|
||||
preventDuplicates: true,
|
||||
},
|
||||
license: {
|
||||
mustExist: true,
|
||||
preventDuplicates: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"jsdoc/require-hyphen-before-param-description": "warn",
|
||||
"jsdoc/require-jsdoc": [
|
||||
"warn",
|
||||
{
|
||||
publicOnly: true,
|
||||
require: {
|
||||
ArrowFunctionExpression: true,
|
||||
ClassDeclaration: true,
|
||||
ClassExpression: true,
|
||||
FunctionDeclaration: true,
|
||||
FunctionExpression: true,
|
||||
MethodDefinition: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
"jsdoc/require-param": "warn",
|
||||
"jsdoc/require-param-description": "warn",
|
||||
"jsdoc/require-param-name": "warn",
|
||||
"jsdoc/require-property": "warn",
|
||||
"jsdoc/require-property-description": "warn",
|
||||
"jsdoc/require-property-name": "warn",
|
||||
"jsdoc/require-returns": "warn",
|
||||
"jsdoc/require-returns-check": "warn",
|
||||
"jsdoc/require-returns-description": "warn",
|
||||
"jsdoc/require-template": "warn",
|
||||
"jsdoc/require-throws": "warn",
|
||||
"jsdoc/require-yields": "warn",
|
||||
"jsdoc/require-yields-check": "warn",
|
||||
"jsdoc/sort-tags": [
|
||||
"warn",
|
||||
{
|
||||
linesBetween: 0,
|
||||
},
|
||||
],
|
||||
"jsdoc/tag-lines": [ "warn", "never" ],
|
||||
"jsdoc/valid-types": "warn",
|
||||
};
|
53
src/rules/playwright.ts
Normal file
53
src/rules/playwright.ts
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
export const playwrightRules: Linter.RulesRecord = {
|
||||
"playwright/expect-expect": "warn",
|
||||
"playwright/max-nested-describe": [ "warn", { max: 2 } ],
|
||||
"playwright/missing-playwright-await": "warn",
|
||||
"playwright/no-commented-out-tests": "warn",
|
||||
"playwright/no-conditional-expect": "warn",
|
||||
"playwright/no-conditional-in-test": "warn",
|
||||
"playwright/no-duplicate-hooks": "warn",
|
||||
"playwright/no-element-handle": "warn",
|
||||
"playwright/no-eval": "warn",
|
||||
"playwright/no-focused-test": "warn",
|
||||
"playwright/no-force-option": "warn",
|
||||
"playwright/no-get-by-title": "warn",
|
||||
"playwright/no-nested-step": "warn",
|
||||
"playwright/no-networkidle": "warn",
|
||||
"playwright/no-nth-methods": "warn",
|
||||
"playwright/no-page-pause": "warn",
|
||||
"playwright/no-raw-locators": "warn",
|
||||
"playwright/no-skipped-test": "warn",
|
||||
"playwright/no-standalone-expect": "warn",
|
||||
"playwright/no-unsafe-references": "warn",
|
||||
"playwright/no-useless-await": "warn",
|
||||
"playwright/no-useless-not": "warn",
|
||||
"playwright/no-wait-for-selector": "warn",
|
||||
"playwright/no-wait-for-timeout": "warn",
|
||||
"playwright/prefer-comparison-matcher": "warn",
|
||||
"playwright/prefer-equality-matcher": "warn",
|
||||
"playwright/prefer-hooks-in-order": "warn",
|
||||
"playwright/prefer-hooks-on-top": "warn",
|
||||
"playwright/prefer-lowercase-title": "warn",
|
||||
"playwright/prefer-strict-equal": "warn",
|
||||
"playwright/prefer-to-be": "warn",
|
||||
"playwright/prefer-to-contain": "warn",
|
||||
"playwright/prefer-to-have-count": "warn",
|
||||
"playwright/prefer-to-have-length": "warn",
|
||||
"playwright/prefer-web-first-assertions": "warn",
|
||||
"playwright/require-hook": "warn",
|
||||
"playwright/require-to-throw-message": "warn",
|
||||
"playwright/require-top-level-describe": "warn",
|
||||
"playwright/valid-describe-callback": "warn",
|
||||
"playwright/valid-expect":
|
||||
[ "warn", { maxArgs: 2, minArgs: 2 } ],
|
||||
"playwright/valid-expect-in-promise": "warn",
|
||||
"playwright/valid-title": "warn",
|
||||
};
|
87
src/rules/react.ts
Normal file
87
src/rules/react.ts
Normal file
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
export const reactRules: Linter.RulesRecord = {
|
||||
"react/boolean-prop-naming": "warn",
|
||||
"react/button-has-type": "error",
|
||||
"react/checked-requires-onchange-or-readonly": "error",
|
||||
"react/default-props-match-prop-types": "warn",
|
||||
"react/destructuring-assignment": "warn",
|
||||
"react/display-name": "warn",
|
||||
"react/forbid-foreign-prop-types": "warn",
|
||||
"react/forbid-prop-types": "warn",
|
||||
"react/forward-ref-uses-ref": "warn",
|
||||
"react/function-component-definition":
|
||||
[ "warn",
|
||||
{
|
||||
namedComponents: "arrow-function",
|
||||
unnamedComponents: "arrow-function",
|
||||
} ],
|
||||
"react/hook-use-state": "warn",
|
||||
"react/iframe-missing-sandbox": "error",
|
||||
"react/jsx-boolean-value": [ "warn", "always" ],
|
||||
"react/jsx-child-element-spacing": "warn",
|
||||
"react/jsx-filename-extension":
|
||||
[ "warn", { allow: "as-needed", extensions: [ ".jsx", ".tsx" ] } ],
|
||||
"react/jsx-fragments": [ "warn", "syntax" ],
|
||||
"react/jsx-handler-names": "warn",
|
||||
"react/jsx-key": "error",
|
||||
"react/jsx-no-bind": "error",
|
||||
"react/jsx-no-comment-textnodes": "error",
|
||||
"react/jsx-no-constructed-context-values": "error",
|
||||
"react/jsx-no-duplicate-props": "error",
|
||||
"react/jsx-no-leaked-render": "error",
|
||||
"react/jsx-no-literals": "warn",
|
||||
"react/jsx-no-script-url": "error",
|
||||
"react/jsx-no-target-blank": "error",
|
||||
"react/jsx-no-undef": "error",
|
||||
"react/jsx-no-useless-fragment": "warn",
|
||||
"react/jsx-pascal-case": "warn",
|
||||
"react/jsx-props-no-spread-multi": "warn",
|
||||
"react/jsx-sort-props": "warn",
|
||||
"react/jsx-uses-vars": "warn",
|
||||
"react/no-access-state-in-setstate": "error",
|
||||
"react/no-array-index-key": "error",
|
||||
"react/no-arrow-function-lifecycle": "warn",
|
||||
"react/no-children-prop": "error",
|
||||
"react/no-danger": "error",
|
||||
"react/no-danger-with-children": "error",
|
||||
"react/no-deprecated": "warn",
|
||||
"react/no-did-mount-set-state": "error",
|
||||
"react/no-did-update-set-state": "error",
|
||||
"react/no-direct-mutation-state": "error",
|
||||
"react/no-find-dom-node": "error",
|
||||
"react/no-is-mounted": "error",
|
||||
"react/no-multi-comp": "warn",
|
||||
"react/no-object-type-as-default-prop": "error",
|
||||
"react/no-redundant-should-component-update": "warn",
|
||||
"react/no-render-return-value": "error",
|
||||
"react/no-string-refs": "error",
|
||||
"react/no-this-in-sfc": "error",
|
||||
"react/no-typos": "warn",
|
||||
"react/no-unescaped-entities": "error",
|
||||
"react/no-unknown-property": "error",
|
||||
"react/no-unsafe": "warn",
|
||||
"react/no-unstable-nested-components": "warn",
|
||||
"react/no-unused-class-component-methods": "warn",
|
||||
"react/no-unused-prop-types": "warn",
|
||||
"react/no-unused-state": "warn",
|
||||
"react/no-will-update-set-state": "error",
|
||||
"react/prefer-es6-class": "warn",
|
||||
"react/prefer-read-only-props": "error",
|
||||
"react/prefer-stateless-function": "warn",
|
||||
"react/prop-types": "warn",
|
||||
"react/require-default-props": "warn",
|
||||
"react/require-render-return": "error",
|
||||
"react/self-closing-comp":
|
||||
[ "warn", { component: false, html: false } ],
|
||||
"react/state-in-constructor": "warn",
|
||||
"react/static-property-placement": "warn",
|
||||
"react/style-prop-object": "warn",
|
||||
"react/void-dom-elements-no-children": "error",
|
||||
};
|
11
src/rules/sortKeysFix.ts
Normal file
11
src/rules/sortKeysFix.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
export const sortKeysFixRules: Linter.RulesRecord = {
|
||||
"sort-keys-fix/sort-keys-fix": "warn",
|
||||
};
|
105
src/rules/stylistic.ts
Normal file
105
src/rules/stylistic.ts
Normal file
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
const spacesPerIndent = 2;
|
||||
|
||||
export const stylisticRules: Linter.RulesRecord = {
|
||||
"stylistic/array-bracket-newline": [ "warn", "consistent" ],
|
||||
"stylistic/array-bracket-spacing": [ "warn", "always" ],
|
||||
"stylistic/array-element-newline": [ "warn", "consistent" ],
|
||||
"stylistic/arrow-parens": [ "warn", "always" ],
|
||||
"stylistic/arrow-spacing":
|
||||
[ "warn", { after: true, before: true } ],
|
||||
"stylistic/block-spacing": [ "warn", "always" ],
|
||||
"stylistic/brace-style": [ "warn", "1tbs" ],
|
||||
"stylistic/comma-dangle": [ "warn", "always-multiline" ],
|
||||
"stylistic/comma-spacing": [ "warn" ],
|
||||
"stylistic/comma-style": [ "warn", "last" ],
|
||||
"stylistic/computed-property-spacing": [ "warn", "never" ],
|
||||
"stylistic/dot-location": [ "warn", "object" ],
|
||||
"stylistic/eol-last": [ "warn", "always" ],
|
||||
"stylistic/function-call-argument-newline": [ "warn", "consistent" ],
|
||||
"stylistic/function-call-spacing": [ "warn", "never" ],
|
||||
"stylistic/function-paren-newline": [ "warn", "consistent" ],
|
||||
"stylistic/generator-star-spacing": [ "warn", "after" ],
|
||||
"stylistic/indent": [ "warn", spacesPerIndent ],
|
||||
"stylistic/key-spacing": [
|
||||
"warn",
|
||||
{ afterColon: true,
|
||||
align: "value",
|
||||
beforeColon: false,
|
||||
mode: "strict" },
|
||||
],
|
||||
"stylistic/keyword-spacing":
|
||||
[ "warn", { after: true, before: true } ],
|
||||
"stylistic/line-comment-position": [ "warn", "above" ],
|
||||
"stylistic/linebreak-style": [ "warn", "unix" ],
|
||||
"stylistic/lines-around-comment": [
|
||||
"warn",
|
||||
{ afterBlockComment: false, beforeBlockComment: true },
|
||||
],
|
||||
"stylistic/max-len": [
|
||||
"warn",
|
||||
{ code: 80,
|
||||
ignoreComments: true,
|
||||
ignoreTemplateLiterals: true,
|
||||
tabWidth: 2 },
|
||||
],
|
||||
"stylistic/max-statements-per-line": [ "warn", { max: 1 } ],
|
||||
"stylistic/member-delimiter-style": "warn",
|
||||
"stylistic/multiline-comment-style": [ "warn", "starred-block" ],
|
||||
"stylistic/multiline-ternary": [ "warn", "always" ],
|
||||
"stylistic/new-parens": [ "warn", "always" ],
|
||||
"stylistic/newline-per-chained-call":
|
||||
[ "warn", { ignoreChainWithDepth: 2 } ],
|
||||
"stylistic/no-confusing-arrow": [
|
||||
"warn",
|
||||
{ allowParens: false, onlyOneSimpleParam: false },
|
||||
],
|
||||
"stylistic/no-extra-parens": [ "warn", "all" ],
|
||||
"stylistic/no-extra-semi": "warn",
|
||||
"stylistic/no-floating-decimal": "warn",
|
||||
"stylistic/no-mixed-operators":
|
||||
[ "warn", { allowSamePrecedence: false } ],
|
||||
"stylistic/no-mixed-spaces-and-tabs": [ "warn" ],
|
||||
"stylistic/no-multi-spaces":
|
||||
[ "warn", { exceptions: { Property: true, TSTypeAnnotation: true } } ],
|
||||
"stylistic/no-multiple-empty-lines": [ "warn", { max: 1 } ],
|
||||
"stylistic/no-tabs": "warn",
|
||||
"stylistic/no-trailing-spaces": "warn",
|
||||
"stylistic/no-whitespace-before-property": "warn",
|
||||
"stylistic/object-curly-newline":
|
||||
[ "warn", { consistent: true } ],
|
||||
"stylistic/object-curly-spacing": [ "warn", "always" ],
|
||||
"stylistic/one-var-declaration-per-line": [ "warn", "always" ],
|
||||
"stylistic/operator-linebreak": [ "warn", "before" ],
|
||||
"stylistic/padded-blocks": [ "warn", "never" ],
|
||||
"stylistic/quote-props": [ "warn", "consistent-as-needed" ],
|
||||
"stylistic/quotes":
|
||||
[ "warn", "double", { allowTemplateLiterals: true } ],
|
||||
"stylistic/rest-spread-spacing": [ "warn", "never" ],
|
||||
"stylistic/semi": [ "warn", "always" ],
|
||||
"stylistic/semi-spacing":
|
||||
[ "warn", { after: true, before: false } ],
|
||||
"stylistic/semi-style": [ "warn", "last" ],
|
||||
"stylistic/space-before-blocks": [ "warn", "always" ],
|
||||
"stylistic/space-before-function-paren": [ "warn", "never" ],
|
||||
"stylistic/space-in-parens": [ "warn", "never" ],
|
||||
"stylistic/space-infix-ops": [ "warn" ],
|
||||
"stylistic/spaced-comment": [ "warn", "always" ],
|
||||
"stylistic/switch-colon-spacing":
|
||||
[ "warn", { after: true, before: false } ],
|
||||
"stylistic/template-curly-spacing": [ "warn", "never" ],
|
||||
"stylistic/template-tag-spacing": [ "warn", "never" ],
|
||||
"stylistic/type-annotation-spacing":
|
||||
[ "warn", { after: true, before: false } ],
|
||||
"stylistic/type-generic-spacing": "warn",
|
||||
"stylistic/type-named-tuple-spacing": "warn",
|
||||
"stylistic/wrap-iife": [ "warn", "inside" ],
|
||||
"stylistic/yield-star-spacing": [ "warn", "after" ],
|
||||
};
|
231
src/rules/typescriptEslint.ts
Normal file
231
src/rules/typescriptEslint.ts
Normal file
@ -0,0 +1,231 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
/**
|
||||
* Rules that require type definitions.
|
||||
* These CANNOT run on the test directory as our typescript
|
||||
* configuration excludes tests from compliation.
|
||||
*/
|
||||
const typescriptEslintRulesWithTypes: Linter.RulesRecord = {
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"@typescript-eslint/consistent-type-exports": [
|
||||
"warn",
|
||||
{ fixMixedExportsWithInlineTypeSpecifier: true },
|
||||
],
|
||||
"@typescript-eslint/dot-notation": [ "error" ],
|
||||
"@typescript-eslint/no-array-delete": "error",
|
||||
"@typescript-eslint/no-base-to-string": [ "error" ],
|
||||
"@typescript-eslint/no-confusing-void-expression": [ "error" ],
|
||||
"@typescript-eslint/no-duplicate-type-constituents": [ "error" ],
|
||||
"@typescript-eslint/no-floating-promises": [ "error" ],
|
||||
"@typescript-eslint/no-implied-eval": [ "error" ],
|
||||
"@typescript-eslint/no-meaningless-void-operator": [ "warn" ],
|
||||
"@typescript-eslint/no-misused-promises":
|
||||
[ "error" ],
|
||||
"@typescript-eslint/no-mixed-enums": "error",
|
||||
"@typescript-eslint/no-redundant-type-constituents": "warn",
|
||||
"@typescript-eslint/no-unnecessary-boolean-literal-compare": [ "warn" ],
|
||||
"@typescript-eslint/no-unnecessary-condition": [ "warn" ],
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "warn",
|
||||
"@typescript-eslint/no-unnecessary-template-expression": "warn",
|
||||
"@typescript-eslint/no-unnecessary-type-arguments": "warn",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": [ "warn" ],
|
||||
"@typescript-eslint/no-unnecessary-type-parameters": "warn",
|
||||
"@typescript-eslint/no-unsafe-argument": "error",
|
||||
"@typescript-eslint/no-unsafe-assignment": "error",
|
||||
"@typescript-eslint/no-unsafe-call": "error",
|
||||
"@typescript-eslint/no-unsafe-declaration-merging": "error",
|
||||
"@typescript-eslint/no-unsafe-enum-comparison": "error",
|
||||
"@typescript-eslint/no-unsafe-function-type": "error",
|
||||
"@typescript-eslint/no-unsafe-member-access": "error",
|
||||
"@typescript-eslint/no-unsafe-return": "error",
|
||||
"@typescript-eslint/no-unsafe-unary-minus": "error",
|
||||
"@typescript-eslint/only-throw-error": [ "error" ],
|
||||
"@typescript-eslint/prefer-destructuring": [ "warn" ],
|
||||
"@typescript-eslint/prefer-find": "error",
|
||||
"@typescript-eslint/prefer-includes": "warn",
|
||||
"@typescript-eslint/prefer-nullish-coalescing": "error",
|
||||
"@typescript-eslint/prefer-optional-chain": [ "warn" ],
|
||||
"@typescript-eslint/prefer-promise-reject-errors": [ "error" ],
|
||||
"@typescript-eslint/prefer-readonly": "warn",
|
||||
"@typescript-eslint/prefer-reduce-type-parameter": "warn",
|
||||
"@typescript-eslint/prefer-regexp-exec": "error",
|
||||
"@typescript-eslint/prefer-return-this-type": "warn",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||
"@typescript-eslint/promise-function-async":
|
||||
[ "error", { allowAny: false } ],
|
||||
"@typescript-eslint/require-array-sort-compare": [
|
||||
"error",
|
||||
{ ignoreStringArrays: false },
|
||||
],
|
||||
"@typescript-eslint/require-await": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": [
|
||||
"error",
|
||||
{
|
||||
allowAny: false,
|
||||
allowBoolean: false,
|
||||
allowNullish: false,
|
||||
allowNumberAndString: false,
|
||||
allowRegExp: false,
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/restrict-template-expressions": [
|
||||
"error",
|
||||
{
|
||||
allowAny: false,
|
||||
allowBoolean: false,
|
||||
allowNever: false,
|
||||
allowNullish: false,
|
||||
allowNumber: false,
|
||||
allowRegExp: false,
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/return-await": [ "error", "always" ],
|
||||
"@typescript-eslint/strict-boolean-expressions": [
|
||||
"error",
|
||||
{
|
||||
allowNullableObject: true,
|
||||
allowNumber: false,
|
||||
allowString: false,
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/switch-exhaustiveness-check": [
|
||||
"error",
|
||||
{ requireDefaultForNonUnion: true },
|
||||
],
|
||||
"@typescript-eslint/unbound-method": "error",
|
||||
"@typescript-eslint/use-unknown-in-catch-callback-variable": "error",
|
||||
};
|
||||
|
||||
/**
|
||||
* Rules that do not require type definitions.
|
||||
* These can run on both the src and test directories.
|
||||
*/
|
||||
const typescriptEslintRules: Linter.RulesRecord = {
|
||||
"@typescript-eslint/adjacent-overload-signatures": "warn",
|
||||
"@typescript-eslint/array-type":
|
||||
[ "warn", { default: "generic" } ],
|
||||
"@typescript-eslint/ban-ts-comment": [
|
||||
"error",
|
||||
{ "ts-expect-error": "allow-with-description" },
|
||||
],
|
||||
"@typescript-eslint/class-literal-property-style": [ "error", "getters" ],
|
||||
"@typescript-eslint/class-methods-use-this": [ "error" ],
|
||||
"@typescript-eslint/consistent-generic-constructors": [
|
||||
"error",
|
||||
"constructor",
|
||||
],
|
||||
"@typescript-eslint/consistent-indexed-object-style": [ "warn", "record" ],
|
||||
"@typescript-eslint/consistent-type-assertions": [
|
||||
"warn",
|
||||
{ assertionStyle: "never" },
|
||||
],
|
||||
"@typescript-eslint/consistent-type-definitions": [ "warn", "interface" ],
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"warn",
|
||||
{ fixStyle: "inline-type-imports", prefer: "type-imports" },
|
||||
],
|
||||
"@typescript-eslint/default-param-last": "error",
|
||||
"@typescript-eslint/explicit-function-return-type": [ "warn" ],
|
||||
"@typescript-eslint/explicit-member-accessibility": [
|
||||
"warn",
|
||||
{ accessibility: "explicit" },
|
||||
],
|
||||
"@typescript-eslint/explicit-module-boundary-types": [ "warn" ],
|
||||
"@typescript-eslint/init-declarations": [ "error", "always" ],
|
||||
// Anything more than 3 and we should be using a params object
|
||||
"@typescript-eslint/max-params":
|
||||
[ "error", { max: 3 } ],
|
||||
"@typescript-eslint/member-ordering": [ "warn" ],
|
||||
"@typescript-eslint/method-signature-style": [ "warn", "property" ],
|
||||
"@typescript-eslint/naming-convention": [
|
||||
"warn",
|
||||
{
|
||||
format: [ "camelCase" ],
|
||||
leadingUnderscore: "allow",
|
||||
selector: "default",
|
||||
trailingUnderscore: "forbid",
|
||||
},
|
||||
{
|
||||
format: [ "PascalCase" ],
|
||||
leadingUnderscore: "forbid",
|
||||
selector: "typeLike",
|
||||
trailingUnderscore: "forbid",
|
||||
},
|
||||
{
|
||||
format: [ "PascalCase" ],
|
||||
leadingUnderscore: "forbid",
|
||||
selector: "class",
|
||||
trailingUnderscore: "forbid",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-array-constructor": [ "error" ],
|
||||
"@typescript-eslint/no-confusing-non-null-assertion": "warn",
|
||||
"@typescript-eslint/no-duplicate-enum-values": "error",
|
||||
"@typescript-eslint/no-dynamic-delete": "error",
|
||||
"@typescript-eslint/no-empty-function": [ "error" ],
|
||||
"@typescript-eslint/no-empty-interface": [ "warn" ],
|
||||
"@typescript-eslint/no-empty-object-type": [ "warn" ],
|
||||
"@typescript-eslint/no-explicit-any":
|
||||
[ "error", { fixToUnknown: true } ],
|
||||
"@typescript-eslint/no-extraneous-class": [ "error" ],
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-import-type-side-effects": "error",
|
||||
"@typescript-eslint/no-inferrable-types": [ "warn" ],
|
||||
"@typescript-eslint/no-invalid-void-type":
|
||||
[ "error" ],
|
||||
"@typescript-eslint/no-loop-func": "error",
|
||||
"@typescript-eslint/no-loss-of-precision": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-asserted-nullish-coalescing": "error",
|
||||
"@typescript-eslint/no-non-null-asserted-optional-chain": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "error",
|
||||
"@typescript-eslint/no-require-imports":
|
||||
[ "error" ],
|
||||
"@typescript-eslint/no-shadow":
|
||||
[ "error" ],
|
||||
"@typescript-eslint/no-this-alias": [ "warn" ],
|
||||
"@typescript-eslint/no-unnecessary-parameter-property-assignment": "warn",
|
||||
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
|
||||
"@typescript-eslint/no-unused-expressions": [ "warn" ],
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
args: "all",
|
||||
argsIgnorePattern: "^_",
|
||||
caughtErrors: "all",
|
||||
vars: "all",
|
||||
varsIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-use-before-define": [ "error" ],
|
||||
"@typescript-eslint/no-useless-constructor": "warn",
|
||||
"@typescript-eslint/no-useless-empty-export": "warn",
|
||||
"@typescript-eslint/no-var-requires": [ "error" ],
|
||||
"@typescript-eslint/no-wrapper-object-types": "warn",
|
||||
"@typescript-eslint/parameter-properties": [
|
||||
"warn",
|
||||
{ prefer: "parameter-property" },
|
||||
],
|
||||
"@typescript-eslint/prefer-as-const": "warn",
|
||||
"@typescript-eslint/prefer-enum-initializers": "error",
|
||||
"@typescript-eslint/prefer-for-of": "warn",
|
||||
"@typescript-eslint/prefer-function-type": "warn",
|
||||
"@typescript-eslint/prefer-literal-enum-member": [ "error" ],
|
||||
"@typescript-eslint/triple-slash-reference": [
|
||||
"warn",
|
||||
{ lib: "never", path: "never", types: "prefer-import" },
|
||||
],
|
||||
"@typescript-eslint/unified-signatures": [ "warn" ],
|
||||
};
|
||||
|
||||
export {
|
||||
typescriptEslintRules,
|
||||
typescriptEslintRulesWithTypes,
|
||||
};
|
85
src/rules/unicorn.ts
Normal file
85
src/rules/unicorn.ts
Normal file
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
export const unicornRules: Linter.RulesRecord = {
|
||||
"unicorn/better-regex": "warn",
|
||||
"unicorn/catch-error-name":
|
||||
[ "warn", { name: "error" } ],
|
||||
"unicorn/consistent-destructuring": "warn",
|
||||
"unicorn/consistent-empty-array-spread": "error",
|
||||
"unicorn/consistent-function-scoping": "error",
|
||||
"unicorn/error-message": "error",
|
||||
"unicorn/escape-case": "warn",
|
||||
"unicorn/filename-case":
|
||||
[ "warn", { case: "camelCase" } ],
|
||||
"unicorn/no-array-callback-reference": "error",
|
||||
"unicorn/no-array-for-each": "warn",
|
||||
"unicorn/no-array-method-this-argument": "error",
|
||||
"unicorn/no-array-push-push": "warn",
|
||||
"unicorn/no-array-reduce": "warn",
|
||||
"unicorn/no-await-expression-member": "warn",
|
||||
"unicorn/no-await-in-promise-methods": "error",
|
||||
"unicorn/no-empty-file": "error",
|
||||
"unicorn/no-for-loop": "warn",
|
||||
"unicorn/no-hex-escape": "error",
|
||||
"unicorn/no-instanceof-array": "error",
|
||||
"unicorn/no-invalid-fetch-options": "warn",
|
||||
"unicorn/no-keyword-prefix": "warn",
|
||||
"unicorn/no-length-as-slice-end": "warn",
|
||||
"unicorn/no-lonely-if": "warn",
|
||||
"unicorn/no-negation-in-equality-check": "error",
|
||||
"unicorn/no-new-buffer": "error",
|
||||
"unicorn/no-object-as-default-parameter": "warn",
|
||||
"unicorn/no-single-promise-in-promise-methods": "warn",
|
||||
"unicorn/no-static-only-class": "warn",
|
||||
"unicorn/no-thenable": "warn",
|
||||
"unicorn/no-this-assignment": "warn",
|
||||
"unicorn/no-typeof-undefined": "error",
|
||||
"unicorn/no-unnecessary-await": "warn",
|
||||
"unicorn/no-unreadable-array-destructuring": "warn",
|
||||
"unicorn/no-unreadable-iife": "warn",
|
||||
"unicorn/no-useless-promise-resolve-reject": "warn",
|
||||
"unicorn/no-useless-spread": "warn",
|
||||
"unicorn/no-useless-switch-case": "warn",
|
||||
"unicorn/no-zero-fractions": "warn",
|
||||
"unicorn/number-literal-case": "warn",
|
||||
"unicorn/numeric-separators-style": "warn",
|
||||
"unicorn/prefer-array-flat": "warn",
|
||||
"unicorn/prefer-array-flat-map": "warn",
|
||||
"unicorn/prefer-array-index-of": "warn",
|
||||
"unicorn/prefer-array-some": "warn",
|
||||
"unicorn/prefer-at": "warn",
|
||||
"unicorn/prefer-code-point": "error",
|
||||
"unicorn/prefer-date-now": "warn",
|
||||
"unicorn/prefer-default-parameters": "warn",
|
||||
"unicorn/prefer-includes": "warn",
|
||||
"unicorn/prefer-math-trunc": "warn",
|
||||
"unicorn/prefer-modern-math-apis": "warn",
|
||||
"unicorn/prefer-module": "error",
|
||||
"unicorn/prefer-native-coercion-functions": "error",
|
||||
"unicorn/prefer-negative-index": "warn",
|
||||
"unicorn/prefer-node-protocol": "warn",
|
||||
"unicorn/prefer-number-properties": "error",
|
||||
"unicorn/prefer-object-from-entries": "warn",
|
||||
"unicorn/prefer-optional-catch-binding": "warn",
|
||||
"unicorn/prefer-prototype-methods": "warn",
|
||||
"unicorn/prefer-regexp-test": "warn",
|
||||
"unicorn/prefer-set-has": "warn",
|
||||
"unicorn/prefer-set-size": "warn",
|
||||
"unicorn/prefer-spread": "warn",
|
||||
"unicorn/prefer-string-replace-all": "warn",
|
||||
"unicorn/prefer-string-slice": "warn",
|
||||
"unicorn/prefer-string-starts-ends-with": "warn",
|
||||
"unicorn/prefer-string-trim-start-end": "warn",
|
||||
"unicorn/prefer-structured-clone": "warn",
|
||||
"unicorn/prefer-top-level-await": "warn",
|
||||
"unicorn/prefer-type-error": "warn",
|
||||
"unicorn/prevent-abbreviations": "warn",
|
||||
"unicorn/require-array-join-separator": "error",
|
||||
"unicorn/require-number-to-fixed-digits-argument": "error",
|
||||
};
|
57
src/rules/vitest.ts
Normal file
57
src/rules/vitest.ts
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
export const vitestRules: Linter.RulesRecord = {
|
||||
"vitest/consistent-test-filename":
|
||||
[ "warn", { pattern: /^[\da-z-]+\.spec\.ts$/i } ],
|
||||
"vitest/consistent-test-it": "warn",
|
||||
"vitest/expect-expect": "warn",
|
||||
"vitest/max-nested-describe": [ "warn", { max: 2 } ],
|
||||
"vitest/no-alias-methods": "warn",
|
||||
"vitest/no-commented-out-tests": "warn",
|
||||
"vitest/no-conditional-expect": "warn",
|
||||
"vitest/no-conditional-in-test": "warn",
|
||||
"vitest/no-conditional-tests": "warn",
|
||||
"vitest/no-disabled-tests": "warn",
|
||||
"vitest/no-done-callback": "warn",
|
||||
"vitest/no-duplicate-hooks": "warn",
|
||||
"vitest/no-focused-tests": "warn",
|
||||
"vitest/no-identical-title": "warn",
|
||||
"vitest/no-import-node-test": "warn",
|
||||
"vitest/no-interpolation-in-snapshots": "warn",
|
||||
"vitest/no-restricted-vi-methods": "warn",
|
||||
"vitest/no-standalone-expect": "warn",
|
||||
"vitest/no-test-prefixes": "warn",
|
||||
"vitest/no-test-return-statement": "warn",
|
||||
"vitest/prefer-called-with": "warn",
|
||||
"vitest/prefer-comparison-matcher": "warn",
|
||||
"vitest/prefer-each": "warn",
|
||||
"vitest/prefer-equality-matcher": "warn",
|
||||
"vitest/prefer-expect-assertions": "warn",
|
||||
"vitest/prefer-expect-resolves": "warn",
|
||||
"vitest/prefer-hooks-in-order": "warn",
|
||||
"vitest/prefer-hooks-on-top": "warn",
|
||||
"vitest/prefer-lowercase-title": "warn",
|
||||
"vitest/prefer-mock-promise-shorthand": "warn",
|
||||
"vitest/prefer-spy-on": "warn",
|
||||
"vitest/prefer-strict-equal": "warn",
|
||||
"vitest/prefer-to-be": "warn",
|
||||
"vitest/prefer-to-be-falsy": "warn",
|
||||
"vitest/prefer-to-be-object": "warn",
|
||||
"vitest/prefer-to-be-truthy": "warn",
|
||||
"vitest/prefer-to-contain": "warn",
|
||||
"vitest/prefer-to-have-length": "warn",
|
||||
"vitest/prefer-todo": "warn",
|
||||
"vitest/require-hook": "warn",
|
||||
"vitest/require-to-throw-message": "warn",
|
||||
"vitest/require-top-level-describe": "warn",
|
||||
"vitest/valid-describe-callback": "warn",
|
||||
"vitest/valid-expect":
|
||||
[ "warn", { maxArgs: 2, minArgs: 2 } ],
|
||||
"vitest/valid-title": "warn",
|
||||
};
|
10
src/types.d.ts
vendored
Normal file
10
src/types.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
declare module "eslint-plugin-no-only-tests";
|
||||
declare module "eslint-plugin-import";
|
||||
declare module "eslint-plugin-sort-keys-fix";
|
||||
declare module "@eslint-community/eslint-plugin-eslint-comments";
|
270
test/config.spec.ts
Normal file
270
test/config.spec.ts
Normal file
@ -0,0 +1,270 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import config from "../src/index.ts";
|
||||
import { commentsRules } from "../src/rules/comments.ts";
|
||||
import { deprecationRules } from "../src/rules/deprecation.ts";
|
||||
import { eslintRules } from "../src/rules/eslint.ts";
|
||||
import { importRules } from "../src/rules/import.ts";
|
||||
import { jsdocRules } from "../src/rules/jsdoc.ts";
|
||||
import { playwrightRules } from "../src/rules/playwright.ts";
|
||||
import { reactRules } from "../src/rules/react.ts";
|
||||
import { sortKeysFixRules } from "../src/rules/sortKeysFix.ts";
|
||||
import { stylisticRules } from "../src/rules/stylistic.ts";
|
||||
import {
|
||||
typescriptEslintRules,
|
||||
typescriptEslintRulesWithTypes,
|
||||
} from "../src/rules/typescriptEslint.ts";
|
||||
import { unicornRules } from "../src/rules/unicorn.ts";
|
||||
import { vitestRules } from "../src/rules/vitest.ts";
|
||||
import type { Linter } from "eslint";
|
||||
|
||||
// #region Custom matcher
|
||||
expect.extend({
|
||||
toContainRules(received, expected) {
|
||||
const missingRules: Array<string> = [];
|
||||
const mismatchedRules: Array<string> = [];
|
||||
|
||||
for (const [ key, value ] of Object.entries(expected)) {
|
||||
if (!(key in received)) {
|
||||
missingRules.push(key);
|
||||
} else if (!this.equals(received[key], value)) {
|
||||
mismatchedRules.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
const pass = missingRules.length === 0 && mismatchedRules.length === 0;
|
||||
|
||||
let message = "";
|
||||
// eslint-disable-next-line no-negated-condition -- This is a test.
|
||||
if (!pass) {
|
||||
message = `${message}Expected rules to contain all specified rules.\n`;
|
||||
if (missingRules.length > 0) {
|
||||
message = `${message}Missing rules: ${missingRules.join(", ")}\n`;
|
||||
}
|
||||
if (mismatchedRules.length > 0) {
|
||||
message = `${message}Mismatched rules: ${mismatchedRules.join(", ")}\n`;
|
||||
}
|
||||
} else {
|
||||
message = "Expected rules not to contain all specified rules";
|
||||
}
|
||||
|
||||
return {
|
||||
message: (): string => {
|
||||
return message;
|
||||
},
|
||||
pass: pass,
|
||||
};
|
||||
},
|
||||
});
|
||||
// #endregion
|
||||
|
||||
// #region Helper function
|
||||
|
||||
const baseProperties = (
|
||||
ruleset: Linter.Config<Linter.RulesRecord>,
|
||||
isNoTypes: boolean,
|
||||
): void => {
|
||||
expect(ruleset?.plugins, "missing @typescript-eslint plugin").toHaveProperty(
|
||||
"@typescript-eslint",
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- This is a test.
|
||||
isNoTypes
|
||||
? expect(
|
||||
ruleset?.plugins,
|
||||
"should not have deprecation plugin",
|
||||
).not.toHaveProperty("deprecation")
|
||||
: expect(ruleset?.plugins, "missing deprecation plugin").toHaveProperty(
|
||||
"deprecation",
|
||||
);
|
||||
expect(ruleset?.plugins, "missing import plugin").toHaveProperty("import");
|
||||
expect(ruleset?.plugins, "missing jsdoc plugin").toHaveProperty("jsdoc");
|
||||
expect(ruleset?.plugins, "missing sort-keys-fix plugin").toHaveProperty(
|
||||
"sort-keys-fix",
|
||||
);
|
||||
expect(ruleset?.plugins, "missing stylistic plugin").toHaveProperty(
|
||||
"stylistic",
|
||||
);
|
||||
expect(ruleset?.plugins, "missing unicorn plugin").toHaveProperty("unicorn");
|
||||
expect(ruleset?.rules, "missing eslint rules").toContainRules(eslintRules);
|
||||
expect(ruleset?.rules, "missing typescript-eslint rules").toContainRules(
|
||||
typescriptEslintRules,
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- This is a test.
|
||||
isNoTypes
|
||||
? expect(
|
||||
ruleset?.rules,
|
||||
"should not have deprecation rules",
|
||||
).not.toContainRules(deprecationRules)
|
||||
: expect(ruleset?.rules, "missing deprecation rules").toContainRules(
|
||||
deprecationRules,
|
||||
);
|
||||
expect(ruleset?.rules, "missing import rules").toContainRules(importRules);
|
||||
expect(ruleset?.rules, "missing jsdoc rules").toContainRules(jsdocRules);
|
||||
expect(ruleset?.rules, "missing sort-keys-fix rules").toContainRules(
|
||||
sortKeysFixRules,
|
||||
);
|
||||
expect(ruleset?.rules, "missing stylistic rules").toContainRules(
|
||||
stylisticRules,
|
||||
);
|
||||
expect(ruleset?.rules, "missing unicorn rules").toContainRules(unicornRules);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- This is a test.
|
||||
isNoTypes
|
||||
? expect(
|
||||
ruleset?.rules,
|
||||
"should not have typescript-eslint rules with types",
|
||||
).not.toContainRules(typescriptEslintRulesWithTypes)
|
||||
: expect(
|
||||
ruleset?.rules,
|
||||
"missing typescript-eslint rules with types",
|
||||
).toContainRules(typescriptEslintRulesWithTypes);
|
||||
expect(ruleset?.rules, "missing comment rules").toContainRules(commentsRules);
|
||||
};
|
||||
// #endregion
|
||||
|
||||
describe("global config", () => {
|
||||
// #region Typescript
|
||||
it("should apply the expected plugins for typescript", () => {
|
||||
expect.assertions(27);
|
||||
const ruleset = config.find((rule) => {
|
||||
return rule?.files?.includes("src/**/*.ts");
|
||||
});
|
||||
expect(ruleset, "ruleset is not defined").toBeDefined();
|
||||
expect(ruleset?.plugins, "ruleset does not have plugins").toBeDefined();
|
||||
expect(
|
||||
ruleset?.plugins,
|
||||
"should not have vitest plugin",
|
||||
).not.toHaveProperty("vitest");
|
||||
expect(
|
||||
ruleset?.plugins,
|
||||
"should not have playwright plugin",
|
||||
).not.toHaveProperty("playwright");
|
||||
expect(ruleset?.plugins, "should not have react plugin").not.toHaveProperty(
|
||||
"react",
|
||||
);
|
||||
expect(ruleset?.rules, "ruleset does not have rules").toBeDefined();
|
||||
expect(ruleset?.rules, "should not have vitest rules").not.toContainRules(
|
||||
vitestRules,
|
||||
);
|
||||
expect(
|
||||
ruleset?.rules,
|
||||
"should not have playwright rules",
|
||||
).not.toContainRules(playwrightRules);
|
||||
expect(ruleset?.rules, "should not have react rules").not.toContainRules(
|
||||
reactRules,
|
||||
);
|
||||
baseProperties(ruleset as Linter.Config<Linter.RulesRecord>, false);
|
||||
expect(
|
||||
Object.keys(ruleset?.plugins ?? {}),
|
||||
"should not have extraneous plugins",
|
||||
).toHaveLength(8);
|
||||
});
|
||||
// #endregion
|
||||
|
||||
// #region Vitest
|
||||
it("should apply the expected plugins for vitest files", () => {
|
||||
expect.assertions(27);
|
||||
const ruleset = config.find((rule) => {
|
||||
return rule?.files?.includes("test/**/*.spec.ts");
|
||||
});
|
||||
expect(ruleset, "ruleset is not defined").toBeDefined();
|
||||
expect(ruleset?.plugins, "ruleset does not have plugins").toBeDefined();
|
||||
expect(ruleset?.plugins, "missing vitest plugin").toHaveProperty("vitest");
|
||||
expect(
|
||||
ruleset?.plugins,
|
||||
"should not have playwright plugin",
|
||||
).not.toHaveProperty("playwright");
|
||||
expect(ruleset?.plugins, "should not have react plugin").not.toHaveProperty(
|
||||
"react",
|
||||
);
|
||||
expect(ruleset?.rules, "ruleset does not have rules").toBeDefined();
|
||||
expect(ruleset?.rules, "missing vitest rules").toContainRules(vitestRules);
|
||||
expect(
|
||||
ruleset?.rules,
|
||||
"should not have playwright rules",
|
||||
).not.toContainRules(playwrightRules);
|
||||
expect(ruleset?.rules, "should not have react rules").not.toContainRules(
|
||||
reactRules,
|
||||
);
|
||||
baseProperties(ruleset as Linter.Config<Linter.RulesRecord>, true);
|
||||
expect(
|
||||
Object.keys(ruleset?.plugins ?? {}),
|
||||
"should not have extraneous plugins",
|
||||
).toHaveLength(8);
|
||||
});
|
||||
// #endregion
|
||||
|
||||
// #region Playwright
|
||||
it("should apply the expected plugins for playwright", () => {
|
||||
expect.assertions(27);
|
||||
const ruleset = config.find((rule) => {
|
||||
return rule?.files?.includes("e2e/**/*.spec.ts");
|
||||
});
|
||||
expect(ruleset, "ruleset is not defined").toBeDefined();
|
||||
expect(ruleset?.plugins, "ruleset does not have plugins").toBeDefined();
|
||||
expect(
|
||||
ruleset?.plugins,
|
||||
"should not have vitest plugin",
|
||||
).not.toHaveProperty("vitest");
|
||||
expect(ruleset?.plugins, "missing playwright plugin").toHaveProperty(
|
||||
"playwright",
|
||||
);
|
||||
expect(ruleset?.plugins, "should not have react plugin").not.toHaveProperty(
|
||||
"react",
|
||||
);
|
||||
expect(ruleset?.rules, "ruleset does not have rules").toBeDefined();
|
||||
expect(ruleset?.rules, "should not have vitest rules").not.toContainRules(
|
||||
vitestRules,
|
||||
);
|
||||
expect(ruleset?.rules, "missing playwright rules").toContainRules(
|
||||
playwrightRules,
|
||||
);
|
||||
expect(ruleset?.rules, "should not have react rules").not.toContainRules(
|
||||
reactRules,
|
||||
);
|
||||
baseProperties(ruleset as Linter.Config<Linter.RulesRecord>, true);
|
||||
expect(
|
||||
Object.keys(ruleset?.plugins ?? {}),
|
||||
"should not have extraneous plugins",
|
||||
).toHaveLength(8);
|
||||
});
|
||||
// #endregion
|
||||
|
||||
// #region React
|
||||
it("should apply the expected plugins for react", () => {
|
||||
expect.assertions(27);
|
||||
const ruleset = config.find((rule) => {
|
||||
return rule?.files?.includes("src/**/*.tsx");
|
||||
});
|
||||
expect(ruleset, "ruleset is not defined").toBeDefined();
|
||||
expect(ruleset?.plugins, "ruleset does not have plugins").toBeDefined();
|
||||
expect(
|
||||
ruleset?.plugins,
|
||||
"should not have vitest plugin",
|
||||
).not.toHaveProperty("vitest");
|
||||
expect(
|
||||
ruleset?.plugins,
|
||||
"should not have playwright plugin",
|
||||
).not.toHaveProperty("playwright");
|
||||
expect(ruleset?.plugins, "missing react plugin").toHaveProperty("react");
|
||||
expect(ruleset?.rules, "ruleset does not have rules").toBeDefined();
|
||||
expect(ruleset?.rules, "should not have vitest rules").not.toContainRules(
|
||||
vitestRules,
|
||||
);
|
||||
expect(
|
||||
ruleset?.rules,
|
||||
"should not have playwright rules",
|
||||
).not.toContainRules(playwrightRules);
|
||||
expect(ruleset?.rules, "missing react rules").toContainRules(reactRules);
|
||||
baseProperties(ruleset as Linter.Config<Linter.RulesRecord>, false);
|
||||
expect(
|
||||
Object.keys(ruleset?.plugins ?? {}),
|
||||
"should not have extraneous plugins",
|
||||
).toHaveLength(9);
|
||||
});
|
||||
// #endregion
|
||||
});
|
31
test/eslint.spec.ts
Normal file
31
test/eslint.spec.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { disabledEslintRules, eslintRules } from "../src/rules/eslint.ts";
|
||||
|
||||
describe("eslint configs", () => {
|
||||
it("should not enable disabled rules", () => {
|
||||
expect.assertions(20);
|
||||
const disabled = Object.keys(disabledEslintRules);
|
||||
const enabled = Object.keys(eslintRules);
|
||||
for (const key of disabled) {
|
||||
expect(enabled, `Disabled rule ${key} has been re-enabled!`).not.toContain(key);
|
||||
}
|
||||
});
|
||||
|
||||
it("all disabled rules should be off", () => {
|
||||
expect.assertions(20);
|
||||
const rules = Object.entries(disabledEslintRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned on - disabled rules should be explicitly turned off.`).toBe("off");
|
||||
continue;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
108
test/off.spec.ts
Normal file
108
test/off.spec.ts
Normal file
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { eslintRules } from "../src/rules/eslint.ts";
|
||||
import { importRules } from "../src/rules/import.js";
|
||||
import { jsdocRules } from "../src/rules/jsdoc.js";
|
||||
import { playwrightRules } from "../src/rules/playwright.ts";
|
||||
import { reactRules } from "../src/rules/react.js";
|
||||
import { stylisticRules } from "../src/rules/stylistic.ts";
|
||||
import { typescriptEslintRules } from "../src/rules/typescriptEslint.js";
|
||||
import { unicornRules } from "../src/rules/unicorn.js";
|
||||
import { vitestRules } from "../src/rules/vitest.js";
|
||||
|
||||
describe("no rules should be turned off in", () => {
|
||||
it("eslint rules", () => {
|
||||
expect.assertions(148);
|
||||
const rules = Object.entries(eslintRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
|
||||
}
|
||||
});
|
||||
|
||||
it("import rules", () => {
|
||||
expect.assertions(29);
|
||||
const rules = Object.entries(importRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
|
||||
}
|
||||
});
|
||||
|
||||
it("jsdoc rules", () => {
|
||||
expect.assertions(43);
|
||||
const rules = Object.entries(jsdocRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
|
||||
}
|
||||
});
|
||||
|
||||
it("playwright rules", () => {
|
||||
expect.assertions(42);
|
||||
const rules = Object.entries(playwrightRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
|
||||
}
|
||||
});
|
||||
|
||||
it("react rules", () => {
|
||||
expect.assertions(70);
|
||||
const rules = Object.entries(reactRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
|
||||
}
|
||||
});
|
||||
|
||||
it("stylistic rules", () => {
|
||||
expect.assertions(65);
|
||||
const rules = Object.entries(stylisticRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
|
||||
}
|
||||
});
|
||||
|
||||
it("typescript-eslint rules", () => {
|
||||
expect.assertions(59);
|
||||
const rules = Object.entries(typescriptEslintRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
|
||||
}
|
||||
});
|
||||
|
||||
it("unicorn rules", () => {
|
||||
expect.assertions(73);
|
||||
const rules = Object.entries(unicornRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
|
||||
}
|
||||
});
|
||||
|
||||
it("vitest rules", () => {
|
||||
expect.assertions(45);
|
||||
const rules = Object.entries(vitestRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be turned off - this project does not use any external configs, so all rules should be off by default.`).not.toBe("off");
|
||||
}
|
||||
});
|
||||
});
|
21
test/playwright.spec.ts
Normal file
21
test/playwright.spec.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { playwrightRules } from "../src/rules/playwright.ts";
|
||||
|
||||
describe("playwright configs", () => {
|
||||
it("should never be an error", () => {
|
||||
expect.assertions(42);
|
||||
const rules = Object.entries(playwrightRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be set to an error!`).not.toBe("error");
|
||||
continue;
|
||||
}
|
||||
});
|
||||
});
|
21
test/stylistic.spec.ts
Normal file
21
test/stylistic.spec.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { stylisticRules } from "../src/rules/stylistic.ts";
|
||||
|
||||
describe("stylistic configs", () => {
|
||||
it("should never be an error", () => {
|
||||
expect.assertions(65);
|
||||
const rules = Object.entries(stylisticRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be set to an error!`).not.toBe("error");
|
||||
continue;
|
||||
}
|
||||
});
|
||||
});
|
19
test/vitest.d.ts
vendored
Normal file
19
test/vitest.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/// <reference types="vitest" />
|
||||
|
||||
import type { Assertion, AsymmetricMatchersContaining } from 'vitest';
|
||||
|
||||
interface CustomMatchers<R = unknown> {
|
||||
toContainRules(expected: Record<string, unknown>): R;
|
||||
}
|
||||
|
||||
declare module 'vitest' {
|
||||
interface Assertion<T = any> extends CustomMatchers<T> {}
|
||||
interface AsymmetricMatchersContaining extends CustomMatchers {}
|
||||
}
|
||||
|
||||
declare module 'vitest' {
|
||||
// @ts-expect-error We need to extend the TestAPI interface
|
||||
export interface TestAPI {
|
||||
extend: <T>(matchers: Record<string, (this: T, ...args: any[]) => any>) => void;
|
||||
}
|
||||
}
|
21
test/vitest.spec.ts
Normal file
21
test/vitest.spec.ts
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { vitestRules } from "../src/rules/vitest.ts";
|
||||
|
||||
describe("vitest configs", () => {
|
||||
it("should never be an error", () => {
|
||||
expect.assertions(45);
|
||||
const rules = Object.entries(vitestRules);
|
||||
for (const [ name, rule ] of rules) {
|
||||
expect(Array.isArray(rule)
|
||||
? rule.at(0)
|
||||
: rule, `${name} appears to be set to an error!`).not.toBe("error");
|
||||
continue;
|
||||
}
|
||||
});
|
||||
});
|
23
tsconfig.json
Normal file
23
tsconfig.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "Node16",
|
||||
"moduleResolution": "Node16",
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"exactOptionalPropertyTypes": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "prod"
|
||||
},
|
||||
"exclude": ["./test", "vitest.config.ts"]
|
||||
}
|
3
vitest.config.ts
Normal file
3
vitest.config.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({});
|
Loading…
x
Reference in New Issue
Block a user