+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
\ No newline at end of file
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..ab9c71f97
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/input/javascript.js
@@ -0,0 +1,72 @@
+// 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 { 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__/input/jsx.jsx b/packages/eslint-config/__fixtures__/input/jsx.jsx
new file mode 100644
index 000000000..f2d2a2563
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/input/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
+ let num = Math
+ .floor (Math.random() * 1E+7).toString()
+ .replace(/\.\d+/ig, "")
+
+ 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..a7f61a305
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/input/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__/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..31e10f1eb
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/input/toml.toml
@@ -0,0 +1,24 @@
+comma = [
+ 1
+ ,2
+ ,3,
+]
+
+[foo]
+ b = 1
+ c = "hello"
+ a = {answer = 42}
+
+"indent" = [
+1,
+ 2
+]
+
+['a-table']
+apple.type = "fruit"
+orange.type = "fruit"
+apple.skin = "thin"
+orange.skin = "thick"
+
+apple.color = "red"
+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..66372fb65
--- /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..97ca0890b
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/input/tsx.tsx
@@ -0,0 +1,24 @@
+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
+
+
+ foobar baz
+
+ a >
+}
diff --git a/packages/eslint-config/__fixtures__/input/typescript.ts b/packages/eslint-config/__fixtures__/input/typescript.ts
new file mode 100644
index 000000000..213ff3db2
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/input/typescript.ts
@@ -0,0 +1,90 @@
+// 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
+var 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();
+
+var fn = (): string => {
+ return 'hello' + 1
+}
+
+log(car1, car2, favoriteFruit, numericValue, fn())
+
+// Generator
+export function* generator1() {
+ let id = 0;
+ while (id < 100) {
+ yield id++;
+ }
+}
+export function * generator2() {
+ yield* generator1()
+}
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 @@
+
+
+
{{ greeting }}
+
Click me!
+
+
Counter: {{ counter }}
+
+
+
+
+
+
+
+
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 @@
+
+
+
+ {{ greeting }}
+
Click me!
+
Counter: {{ counter }}
+
+
+
+
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 Java 45.00
+ Bluetooth Speaker 120.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..c1d6575f7
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/output/all/typescript.ts
@@ -0,0 +1,95 @@
+// 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(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())
+
+// Generator
+export function* generator1() {
+ let id = 0
+ while (id < 100) {
+ yield id++
+ }
+}
+export function* generator2() {
+ yield* generator1()
+}
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 @@
+
+
+
+
+
{{ greeting }}
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{ greeting }}
+
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
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
+
+
+ foobar baz
+
+ a >
+}
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..c1d6575f7
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/output/no-markdown-with-formatters/typescript.ts
@@ -0,0 +1,95 @@
+// 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(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())
+
+// Generator
+export function* generator1() {
+ let id = 0
+ while (id < 100) {
+ yield id++
+ }
+}
+export function* generator2() {
+ yield* generator1()
+}
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..52a7e6a92
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/output/no-style/typescript.ts
@@ -0,0 +1,90 @@
+// 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())
+
+// Generator
+export function* generator1() {
+ let id = 0;
+ while (id < 100) {
+ yield id++;
+ }
+}
+export function * generator2() {
+ yield* generator1()
+}
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 @@
+
+
+
+
+
{{ greeting }}
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{ greeting }}
+
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
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..59ba5af14
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/output/tab-double-quotes/typescript.ts
@@ -0,0 +1,95 @@
+// 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(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())
+
+// Generator
+export function* generator1() {
+ let id = 0
+ while (id < 100) {
+ yield id++
+ }
+}
+export function* generator2() {
+ yield* generator1()
+}
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 @@
+
+
+
+
+
{{ greeting }}
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{ greeting }}
+
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
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..5d8e5f8d6
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/output/ts-override/typescript.ts
@@ -0,0 +1,95 @@
+// 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(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())
+
+// Generator
+export function* generator1() {
+ let id = 0
+ while (id < 100) {
+ yield id++
+ }
+}
+export function* generator2() {
+ yield* generator1()
+}
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 @@
+
+
+
+
+
{{ greeting }}
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{ greeting }}
+
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
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..c1d6575f7
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/output/ts-strict-with-react/typescript.ts
@@ -0,0 +1,95 @@
+// 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(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())
+
+// Generator
+export function* generator1() {
+ let id = 0
+ while (id < 100) {
+ yield id++
+ }
+}
+export function* generator2() {
+ yield* generator1()
+}
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 @@
+
+
+
+
+
{{ greeting }}
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{ greeting }}
+
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
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..c1d6575f7
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/output/ts-strict/typescript.ts
@@ -0,0 +1,95 @@
+// 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(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())
+
+// Generator
+export function* generator1() {
+ let id = 0
+ while (id < 100) {
+ yield id++
+ }
+}
+export function* generator2() {
+ yield* generator1()
+}
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 @@
+
+
+
+
+
{{ greeting }}
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{ greeting }}
+
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
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..c1d6575f7
--- /dev/null
+++ b/packages/eslint-config/__fixtures__/output/with-formatters/typescript.ts
@@ -0,0 +1,95 @@
+// 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(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())
+
+// Generator
+export function* generator1() {
+ let id = 0
+ while (id < 100) {
+ yield id++
+ }
+}
+export function* generator2() {
+ yield* generator1()
+}
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 @@
+
+
+
+
+
{{ greeting }}
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
+
+
+
+
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 @@
+
+
+
+
+
+ {{ greeting }}
+
+
+ Click me!
+
+
Counter: {{ counter }}
+
+
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..cc388135c
--- /dev/null
+++ b/packages/eslint-config/__tests__/rules.test.ts
@@ -0,0 +1,228 @@
+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,
+ });
+
+ 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)));
+ }
+};
+
+const temporaryDirectoryPath = join(rootPath, "..", "tmp_fixtures");
+
+// eslint-disable-next-line vitest/require-top-level-describe
+beforeAll(async () => {
+ await rm(temporaryDirectoryPath, { force: true, recursive: true });
+});
+
+// eslint-disable-next-line vitest/require-top-level-describe
+afterAll(async () => {
+ await rm(temporaryDirectoryPath, { 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(temporaryDirectoryPath, name);
+
+ await copyFolderRecursive(from, target);
+ await writeFile(
+ join(target, "eslint.config.js"),
+ `
+// @eslint-disable
+import { createConfig } from "../../dist/index.mjs";
+
+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,
+ );
+};
+
+// runWithConfig("no-config", {
+// astro: false,
+// formatters: false,
+// gitignore: false,
+// html: false,
+// isInEditor: false,
+// jsonc: false,
+// jsx: false,
+// lessOpinionated: false,
+// lodash: false,
+// markdown: false,
+// playwright: false,
+// react: false,
+// regexp: false,
+// storybook: false,
+// stylistic: false,
+// tailwindcss: false,
+// tanstackQuery: false,
+// tanstackRouter: false,
+// testingLibrary: false,
+// toml: false,
+// tsdoc: false,
+// typescript: false,
+// unicorn: false,
+// unocss: false,
+// vitest: false,
+// yaml: false,
+// zod: false,
+// });
+// runWithConfig("js", {
+// typescript: false,
+// vitest: 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..0881003b6
--- /dev/null
+++ b/packages/eslint-config/debug-eslint.config.mjs
@@ -0,0 +1,3 @@
+import { createConfig } from "./dist/index.mjs";
+
+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..00dc60c60
--- /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", "./src/utils/vitest-globals.ts", "./__fixtures__/**/*", "./__tests__/**/*"],
+ 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..f2e5a6834 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,184 @@
"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:global-vitest && pnpm run build:typegen && packem build --development",
+ "build:global-vitest": "tsx ./scripts/global-vitest.ts",
+ "build:prod": "pnpm run build:global-vitest && pnpm run build:typegen && 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.js --check .",
+ "lint:prettier:fix": "prettier --config=.prettierrc.js --write .",
+ "test": "vitest run || exit 0",
+ "test:coverage": "vitest run --coverage || exit 0",
+ "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",
+ "@eslint-community/eslint-plugin-eslint-comments": "^4.5.0",
+ "@eslint/compat": "^1.2.9",
+ "@eslint/js": "^9.27.0",
+ "@eslint/markdown": "^6.4.0",
+ "@html-eslint/eslint-plugin": "^0.40.3",
+ "@html-eslint/parser": "^0.40.0",
+ "@stylistic/eslint-plugin": "^4.2.0",
+ "@stylistic/eslint-plugin-ts": "^4.2.0",
+ "@typescript-eslint/eslint-plugin": "^8.32.1",
+ "@typescript-eslint/parser": "^8.32.1",
+ "@visulima/package": "^3.5.4",
+ "@visulima/tsconfig": "^1.1.16",
+ "@vitest/eslint-plugin": "^1.2.0",
"confusing-browser-globals": "^1.0.11",
- "eslint-define-config": "^1.24.1",
+ "eslint-config-flat-gitignore": "^2.1.0",
+ "eslint-flat-config-utils": "^2.1.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": "^4.3.5",
+ "eslint-merge-processors": "^2.0.0",
+ "eslint-plugin-antfu": "^3.1.1",
+ "eslint-plugin-compat": "^6.0.2",
+ "eslint-plugin-es-x": "^8.6.2",
+ "eslint-plugin-html": "^8.1.3",
+ "eslint-plugin-import-x": "^4.12.2",
+ "eslint-plugin-jsdoc": "^50.6.17",
+ "eslint-plugin-jsonc": "^2.20.1",
+ "eslint-plugin-n": "^17.18.0",
+ "eslint-plugin-no-for-of-array": "^0.1.0",
+ "eslint-plugin-no-only-tests": "^3.3.0",
+ "eslint-plugin-no-secrets": "^2.2.1",
+ "eslint-plugin-no-unsanitized": "^4.1.2",
+ "eslint-plugin-perfectionist": "^4.13.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.2",
+ "eslint-plugin-toml": "^0.12.0",
+ "eslint-plugin-unicorn": "^59.0.1",
+ "eslint-plugin-unused-imports": "^4.1.4",
+ "eslint-plugin-yml": "^1.18.0",
+ "globals": "^16.1.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.7.2",
+ "toml-eslint-parser": "^0.10.0",
+ "typescript-eslint": "^8.32.1",
+ "yaml-eslint-parser": "^1.3.0"
},
"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": "10.0.5",
+ "@eslint-react/eslint-plugin": "^1.49.0",
+ "@eslint/config-inspector": "^1.0.2",
+ "@stylistic/eslint-plugin-migrate": "^4.2.0",
+ "@tanstack/eslint-plugin-query": "^5.74.7",
+ "@tanstack/eslint-plugin-router": "^1.115.0",
+ "@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.7.0",
+ "@unocss/eslint-plugin": "^66.1.2",
+ "@visulima/packem": "^1.19.1",
+ "astro-eslint-parser": "^1.2.2",
+ "esbuild": "^0.25.4",
+ "eslint": "^9.27.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.5",
+ "eslint-plugin-react-hooks": "^5.2.0",
+ "eslint-plugin-react-refresh": "^0.4.20",
+ "eslint-plugin-storybook": "^0.12.0",
+ "eslint-plugin-tailwindcss": "^3.18.0",
+ "eslint-plugin-testing-library": "^7.2.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": "^2.2.0",
+ "execa": "^9.5.3",
+ "prettier": "^3.5.3",
+ "react": "^19.1.0",
+ "rimraf": "^6.0.1",
+ "semantic-release": "^24.2.4",
+ "tinyglobby": "^0.2.13",
+ "tsx": "^4.19.4",
+ "type-fest": "^4.41.0",
+ "typescript": "^5.8.3",
+ "vitest": "^3.1.4"
},
"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 +258,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 +285,7 @@
"eslint-plugin-you-dont-need-lodash-underscore": {
"optional": true
},
- "eslint-plugin-you-dont-need-momentjs": {
+ "eslint-plugin-zod": {
"optional": true
},
"typescript": {
@@ -339,77 +293,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/project.json b/packages/eslint-config/project.json
index 58a39ba7e..5ab52c637 100644
--- a/packages/eslint-config/project.json
+++ b/packages/eslint-config/project.json
@@ -1,4 +1,5 @@
{
+ "name": "eslint-config",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/eslint-config/src",
"projectType": "library",
diff --git a/packages/eslint-config/scripts/global-vitest.ts b/packages/eslint-config/scripts/global-vitest.ts
new file mode 100644
index 000000000..64faafbc6
--- /dev/null
+++ b/packages/eslint-config/scripts/global-vitest.ts
@@ -0,0 +1,92 @@
+/**
+ * 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)) {
+ 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..610bc746d
--- /dev/null
+++ b/packages/eslint-config/scripts/typegen.ts
@@ -0,0 +1,137 @@
+import fs from "node:fs/promises";
+
+import JS from "@eslint/js";
+import type { NormalizedPackageJson } from "@visulima/package";
+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: JS.configs.all,
+ },
+ },
+ },
+ 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..be0fae47a 100644
--- a/packages/eslint-config/src/config/es6.ts
+++ b/packages/eslint-config/src/config/es6.ts
@@ -1,388 +1,390 @@
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",
+import type { OptionsFiles, OptionsIsInEditor } from "../types";
+import { createConfig, getFilesGlobs } from "../utils/create-config";
+
+export const es6Rules: (isInEditor: boolean) => Partial = (isInEditor: boolean) => {
+ return {
+ // enforces no braces where they can be omitted
+ // https://eslint.org/docs/rules/arrow-body-style
+ "arrow-body-style": [
+ "error",
+ "as-needed",
+ {
+ requireReturnForObjectLiteral: true,
},
- 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,
- },
- ],
+ ],
- // 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",
+ // 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: [
{
- allowParens: true,
+ message: "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead",
+ name: "lodash.isequal",
},
- ],
-
- // 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"],
+ {
+ message: "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead",
+ name: "lodash.uniqueId",
},
- ],
-
- // 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.*"],
+ {
+ message: "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead",
+ name: "lodash.mergewith",
},
- ],
-
- // 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,
+ message: "Lodash modularised (and lodash < 4.17.11) have CVE vulnerabilities. Please use tree-shakeable imports like lodash/xxx instead",
+ name: "lodash.pick",
},
- ],
-
- // 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,
+ name: "error",
},
- ],
-
- // suggest using arrow functions as callbacks
- "prefer-arrow-callback": [
- "error",
{
- allowNamedFunctions: false,
- allowUnboundThis: true,
+ name: "domain",
},
- ],
-
- // suggest using of const declaration for variables that are never modified after declared
- "prefer-const": [
- "error",
{
- destructuring: "any",
- ignoreReadBeforeAssign: true,
+ name: "freelist",
},
- ],
-
- // 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,
- },
+ name: "smalloc",
},
{
- enforceForRenamedProperties: false,
+ 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",
},
- ],
-
- // 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"],
+ 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",
},
],
-
- // 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"],
+ // 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": isInEditor
+ ? "off"
+ : [
+ "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, isInEditor = false } = config;
+
+ return [
+ {
+ files,
+ languageOptions: {
+ parserOptions: {
+ ecmaFeatures: {
+ generators: false,
+ objectLiteralDuplicateProperties: false,
+ },
+ ecmaVersion: 6,
+ sourceType: "module",
+ },
},
+ name: "anolilab/es6/rules",
+ rules: es6Rules(isInEditor),
},
- 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..06317a261
--- /dev/null
+++ b/packages/eslint-config/src/config/ignores.ts
@@ -0,0 +1,46 @@
+import type { TypedFlatConfigItem } from "../types";
+
+const ignores = async (userIgnores: string[] = []): Promise => [
+ {
+ 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..4aa2e9993
--- /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: false }],
+
+ // 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..37aead5d7 100644
--- a/packages/eslint-config/src/config/plugins/jsdoc.ts
+++ b/packages/eslint-config/src/config/plugins/jsdoc.ts
@@ -1,31 +1,97 @@
-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,
+ OptionsOverrides,
+ OptionsPackageJson,
+ OptionsSilentConsoleLogs,
+ OptionsStylistic,
+ OptionsTypescript,
+ 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,
+ jsx = false,
+ overrides = {},
+ packageJson,
+ silent,
+ stylistic = true,
+ typescript,
+ } = config;
+
+ const jsdocPlugin = await interopDefault(import("eslint-plugin-jsdoc"));
+
+ 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 definedTags = ["remarks", "openapi"];
+ const excludeTags = ["openapi"];
+
+ const rules: TypedFlatConfigItem[] = [
+ {
+ name: "anolilab/jsdoc/setup",
+ plugins: {
+ jsdoc: jsdocPlugin,
+ },
+ },
{
- extends: ["plugin:jsdoc/recommended-error"],
- files: ["**/*.js", "**/*.jsx", "**/*.mjs", "**/*.cjs"],
- plugins: ["jsdoc"],
+ files,
+ name: "anolilab/jsdoc/js-rules",
+ rules: {
+ ...jsdocPlugin.configs["flat/recommended-error"].rules,
+
+ "jsdoc/check-indentation": ["error", { excludeTags }],
+ "jsdoc/check-tag-names": ["error", {
+ definedTags,
+ jsxTags: jsx,
+ }],
+
+ ...overrides,
+
+ ...stylistic
+ ? {
+ "jsdoc/check-alignment": "warn",
+ "jsdoc/multiline-blocks": "warn",
+ }
+ : {},
+ },
},
- ...(global.anolilabEslintConfigJsDocRules ?? []),
- ],
-};
+ ];
+
+ if (typescript && !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,
+
+ "jsdoc/check-indentation": ["error", { excludeTags }],
+ "jsdoc/check-tag-names": ["error", {
+ definedTags,
+ jsxTags: jsx,
+ }],
+
+ ...overrides,
+
+ ...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..f89c9f5c9 100644
--- a/packages/eslint-config/src/config/plugins/jsonc.ts
+++ b/packages/eslint-config/src/config/plugins/jsonc.ts
@@ -1,120 +1,368 @@
-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: {
- // 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-array-values": hasSortPackageJson
+ ? "off"
+ : [
+ "error",
+ {
+ order: { type: "asc" },
+ pathPattern: "^files$",
+ },
+ ],
+
+ // 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": 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",
+ "libReplacement",
+ /* 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",
+ "erasableSyntaxOnly",
+ /* 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..b6b35bf5f 100644
--- a/packages/eslint-config/src/config/plugins/markdown.ts
+++ b/packages/eslint-config/src/config/plugins/markdown.ts
@@ -1,56 +1,90 @@
-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,
},
},
- type: "markdown",
- },
- {
- config: {
- extends: "plugin:markdown/recommended",
- parserOptions: {
- ecmacFeatures: {
- impliedStrict: true,
+ {
+ 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,
+ },
+ {
+ 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",
+
+ "unicorn/prefer-module": "off",
+ "unicorn/prefer-string-raw": "off",
- strict: "off",
+ "unused-imports/no-unused-imports": "off",
+
+ "unused-imports/no-unused-vars": "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..6fbf6d8cf 100644
--- a/packages/eslint-config/src/config/plugins/react.ts
+++ b/packages/eslint-config/src/config/plugins/react.ts
@@ -1,108 +1,133 @@
-// @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-x/no-leaked-conditional-rendering": "error",
};
-}
-
-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";
+ 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);
- 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 isAllowConstantExport = hasPackageJsonAnyDependency(packageJson, ReactRefreshAllowConstantExportPackages);
+ const isUsingRemix = hasPackageJsonAnyDependency(packageJson, RemixPackages);
+ const isUsingNext = hasPackageJsonAnyDependency(packageJson, NextJsPackages);
+ const isUsingReactRouter = hasPackageJsonAnyDependency(packageJson, ReactRouterPackages);
- return global.hasAnolilabEsLintConfigReactRuntimePath;
-})();
+ const { plugins } = pluginReactX.configs.all;
-if (!global.anolilabEslintConfigReactVersion) {
- let reactVersion = getPackageSubProperty("dependencies")("react");
-
- 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);
- files: ["**/*.jsx", "**/*.tsx"],
+ if (tsConfig?.compilerOptions !== undefined && (tsConfig?.compilerOptions.jsx === "react-jsx" || tsConfig?.compilerOptions.jsx === "react-jsxdev")) {
+ hasJsxRuntime = true;
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
+ 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`);
+ }
+ }
+ }
+
+ 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-web-api": plugins["@eslint-react/web-api"],
+ "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 +158,335 @@ const config: Linter.Config = {
"jsx-quotes": ["error", "prefer-double"],
"no-underscore-dangle": [
- (dangleRules as unknown[])[0] as Linter.RuleLevel,
+ "error",
+ {
+ ...noUnderscoreDangle,
+
+ allow: [...noUnderscoreDangle.allow, "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__"],
+ },
+ ],
+
+ // Disallow direct calls to the set function of useState in useEffect
+ // https://eslint-react.xyz/docs/rules/no-direct-set-state-in-use-effect
+ "react-hooks-extra/no-direct-set-state-in-use-effect": "error",
+
+ // Disallow unnecessary usage of useCallback
+ // https://eslint-react.xyz/docs/rules/hooks-extra-no-unnecessary-use-callback
+ "react-hooks-extra/no-unnecessary-use-callback": "error",
+
+ // Disallow unnecessary usage of useMemo
+ // https://eslint-react.xyz/docs/rules/react-hooks-extra/no-unnecessary-use-memo
+ "react-hooks-extra/no-unnecessary-use-memo": "error",
+
+ // Enforces that a function with the use prefix should use at least one hook inside of it
+ // https://eslint-react.xyz/docs/rules/no-unnecessary-use-prefix
+ "react-hooks-extra/no-unnecessary-use-prefix": "error",
+
+ // Prefer lazy initialization for useState
+ // https://eslint-react.xyz/docs/rules/prefer-use-state-lazy-initialization
+ "react-hooks-extra/prefer-use-state-lazy-initialization": "error",
+
+ // 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",
+
+ // Enforces naming conventions for components
+ // https://eslint-react.xyz/docs/rules/naming-convention-component-name
+ "react-naming-convention/component-name": "error",
+
+ // Enforces context name to be a valid component name with the suffix Context
+ // https://eslint-react.xyz/docs/rules/naming-convention-context-name
+ "react-naming-convention/context-name": "error",
+
+ // Enforces consistent file naming conventions
+ // https://eslint-react.xyz/docs/rules/naming-convention-filename
+ "react-naming-convention/filename": "off",
+
+ // Enforces naming conventions for useState
+ // https://eslint-react.xyz/docs/rules/naming-convention-use-state
+ "react-naming-convention/use-state": "error",
+
+ // react refresh
+ "react-refresh/only-export-components": [
+ "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__"],
+ allowConstantExport: isAllowConstantExport,
+ allowExportNames: [
+ ...isUsingNext
+ ? [
+ "dynamic",
+ "dynamicParams",
+ "revalidate",
+ "fetchCache",
+ "runtime",
+ "preferredRegion",
+ "maxDuration",
+ "config",
+ "generateStaticParams",
+ "metadata",
+ "generateMetadata",
+ "viewport",
+ "generateViewport",
+ ]
+ : [],
+ ...isUsingRemix || isUsingReactRouter ? ["meta", "links", "headers", "loader", "action"] : [],
+ ],
},
],
+ // Prevents leaked addEventListener in a component or custom hook
+ // https://eslint-react.xyz/docs/rules/web-api-no-leaked-event-listener
+ "react-web-api/no-leaked-event-listener": "error",
+
+ // Prevents leaked setInterval in a component or custom hook
+ // https://eslint-react.xyz/docs/rules/web-api-no-leaked-interval
+ "react-web-api/no-leaked-interval": "error",
+
+ // Prevents leaked ResizeObserver in a component or custom hook
+ // https://eslint-react.xyz/docs/rules/web-api-no-leaked-resize-observer
+ "react-web-api/no-leaked-resize-observer": "error",
+
+ // Prevents leaked setTimeout in a component or custom hook
+ // https://eslint-react.xyz/docs/rules/web-api-no-leaked-timeout
+ "react-web-api/no-leaked-timeout": "error",
+
+ // React-X Rules
+ // https://eslint-react.xyz/docs/rules
+
+ // Enforces explicit boolean values for boolean attributes
+ // https://eslint-react.xyz/docs/rules/avoid-shorthand-boolean
+ "react-x/avoid-shorthand-boolean": "off",
+
+ // Enforces explicit components instead of the shorthand <> or > syntax
+ // https://eslint-react.xyz/docs/rules/avoid-shorthand-fragment
+ "react-x/avoid-shorthand-fragment": "off",
+
+ // Enforces that the key attribute is placed before the spread attribute in JSX elements
+ // https://eslint-react.xyz/docs/rules/jsx-key-before-spread
+ "react-x/jsx-key-before-spread": "error",
+
+ // Disallow duplicate props in JSX elements
+ // https://eslint-react.xyz/docs/rules/jsx-no-duplicate-props
+ "react-x/jsx-no-duplicate-props": "error",
+
+ // Disallow undefined variables in JSX elements
+ // https://eslint-react.xyz/docs/rules/jsx-no-undef
+ "react-x/jsx-no-undef": "off",
+
+ // Marks React variables as used when JSX is used
+ // https://eslint-react.xyz/docs/rules/jsx-uses-react
+ "react-x/jsx-uses-react": hasJsxRuntime ? "off" : "error",
+
+ // Marks variables used in JSX elements as used
+ // https://eslint-react.xyz/docs/rules/jsx-uses-vars
+ "react-x/jsx-uses-vars": "error",
+
+ // Disallow accessing this.state inside setState calls
+ // https://eslint-react.xyz/docs/rules/no-access-state-in-setstate
+ "react-x/no-access-state-in-setstate": "error",
+
+ // Disallow an item's index in the array as its key
+ // https://eslint-react.xyz/docs/rules/no-array-index-key
+ "react-x/no-array-index-key": "error",
+
+ // Disallow Children.count
+ // https://eslint-react.xyz/docs/rules/no-children-count
+ "react-x/no-children-count": "error",
+
+ // Disallow Children.forEach
+ // https://eslint-react.xyz/docs/rules/no-children-for-each
+ "react-x/no-children-for-each": "error",
+
+ // Disallow Children.map
+ // https://eslint-react.xyz/docs/rules/no-children-map
+ "react-x/no-children-map": "error",
+
+ // Disallow Children.only
+ // https://eslint-react.xyz/docs/rules/no-children-only
+ "react-x/no-children-only": "error",
+
+ // Disallow passing children as a prop
+ // https://eslint-react.xyz/docs/rules/no-children-prop
+ "react-x/no-children-prop": "off",
+
+ // Disallow Children.toArray
+ // https://eslint-react.xyz/docs/rules/no-children-to-array
+ "react-x/no-children-to-array": "error",
+
+ // Disallow class components except for error boundaries
+ // https://eslint-react.xyz/docs/rules/no-class-component
+ "react-x/no-class-component": "off",
+
+ // Disallow cloneElement
+ // https://eslint-react.xyz/docs/rules/no-clone-element
+ "react-x/no-clone-element": "error",
+
+ // Prevents comments from being inserted as text nodes
+ // https://eslint-react.xyz/docs/rules/no-comment-textnodes
+ "react-x/no-comment-textnodes": "error",
+
+ // Disallow complex conditional rendering in JSX expressions
+ // https://eslint-react.xyz/docs/rules/no-complex-conditional-rendering
+ "react-x/no-complex-conditional-rendering": "off",
+
+ // Replaces usages of componentWillMount with UNSAFE_componentWillMount
+ // https://eslint-react.xyz/docs/rules/no-component-will-mount
+ "react-x/no-component-will-mount": "error",
+
+ // Replaces usages of componentWillReceiveProps with UNSAFE_componentWillReceiveProps
+ // https://eslint-react.xyz/docs/rules/no-component-will-receive-props
+ "react-x/no-component-will-receive-props": "error",
+
+ // Replaces usages of componentWillUpdate with UNSAFE_componentWillUpdate
+ // https://eslint-react.xyz/docs/rules/no-component-will-update
+ "react-x/no-component-will-update": "error",
+
+ // Replaces usages of with
+ // https://eslint-react.xyz/docs/rules/no-context-provider
+ "react-x/no-context-provider": "error",
+
+ // Disallow createRef in function components
+ // https://eslint-react.xyz/docs/rules/no-create-ref
+ "react-x/no-create-ref": "error",
+
+ // Disallow defaultProps property in favor of ES6 default parameters
+ // https://eslint-react.xyz/docs/rules/no-default-props
+ "react-x/no-default-props": "error",
+
+ // Disallow direct mutation of this.state
+ // https://eslint-react.xyz/docs/rules/no-direct-mutation-state
+ "react-x/no-direct-mutation-state": "error",
+
+ // Disallow duplicate key on elements in the same array or a list of children
+ // https://eslint-react.xyz/docs/rules/no-duplicate-key
+ "react-x/no-duplicate-key": "error",
+
+ // Replaces usages of forwardRef with passing ref as a prop
+ // https://eslint-react.xyz/docs/rules/no-forward-ref
+ "react-x/no-forward-ref": "error",
+
+ // Prevents key from not being explicitly specified (e.g. spreading key from objects)
+ // https://eslint-react.xyz/docs/rules/no-implicit-key
+ "react-x/no-implicit-key": "error",
+
+ // Prevents problematic leaked values from being rendered
+ // https://eslint-react.xyz/docs/rules/no-leaked-conditional-rendering
+ "react-x/no-leaked-conditional-rendering": "error",
+
+ // Enforces that all components have a displayName which can be used in devtools
+ // https://eslint-react.xyz/docs/rules/no-missing-component-display-name
+ "react-x/no-missing-component-display-name": "off",
+
+ // Enforces that all contexts have a displayName which can be used in devtools
+ // https://eslint-react.xyz/docs/rules/no-missing-context-display-name
+ "react-x/no-missing-context-display-name": "off",
+
+ // Disallow missing key on items in list rendering
+ // https://eslint-react.xyz/docs/rules/no-missing-key
+ "react-x/no-missing-key": "error",
+
+ // Prevents incorrect usage of captureOwnerStack
+ // https://eslint-react.xyz/docs/rules/no-misused-capture-owner-stack
+ "react-x/no-misused-capture-owner-stack": "off",
+
+ // Disallow nesting component definitions inside other components
+ // https://eslint-react.xyz/docs/rules/no-nested-component-definitions
+ "react-x/no-nested-component-definitions": "error",
+
+ // Disallow nesting lazy component declarations inside other components
+ // https://eslint-react.xyz/docs/rules/no-nested-lazy-component-declarations
+ "react-x/no-nested-lazy-component-declarations": "error",
+
+ // Disallow propTypes in favor of TypeScript or another type-checking solution
+ // https://eslint-react.xyz/docs/rules/no-prop-types
+ "react-x/no-prop-types": "error",
+
+ // Disallow shouldComponentUpdate when extending React.PureComponent
+ // https://eslint-react.xyz/docs/rules/no-redundant-should-component-update
+ "react-x/no-redundant-should-component-update": "error",
+
+ // Disallow calling this.setState in componentDidMount outside of functions, such as callbacks
+ // https://eslint-react.xyz/docs/rules/no-set-state-in-component-did-mount
+ "react-x/no-set-state-in-component-did-mount": "error",
+
+ // Disallow calling this.setState in componentDidUpdate outside of functions, such as callbacks
+ // https://eslint-react.xyz/docs/rules/no-set-state-in-component-did-update
+ "react-x/no-set-state-in-component-did-update": "error",
+
+ // Disallow calling this.setState in componentWillUpdate outside of functions, such as callbacks
+ // https://eslint-react.xyz/docs/rules/no-set-state-in-component-will-update
+ "react-x/no-set-state-in-component-will-update": "error",
+
+ // Replaces string refs with callback refs
+ // https://eslint-react.xyz/docs/rules/no-string-refs
+ "react-x/no-string-refs": "error",
+
+ // Warns the usage of UNSAFE_componentWillMount in class components
+ // https://eslint-react.xyz/docs/rules/no-unsafe-component-will-mount
+ "react-x/no-unsafe-component-will-mount": "error",
+
+ // Warns the usage of UNSAFE_componentWillReceiveProps in class components
+ // https://eslint-react.xyz/docs/rules/no-unsafe-component-will-receive-props
+ "react-x/no-unsafe-component-will-receive-props": "error",
+
+ // Warns the usage of UNSAFE_componentWillUpdate in class components
+ // https://eslint-react.xyz/docs/rules/no-unsafe-component-will-update
+ "react-x/no-unsafe-component-will-update": "error",
+
+ // Prevents non-stable values (i.e. object literals) from being used as a value for Context.Provider
+ // https://eslint-react.xyz/docs/rules/no-unstable-context-value
+ "react-x/no-unstable-context-value": "error",
+
+ // Prevents using referential-type values as default props in object destructuring
+ // https://eslint-react.xyz/docs/rules/no-unstable-default-props
+ "react-x/no-unstable-default-props": "error",
+
+ // Warns unused class component methods and properties
+ // https://eslint-react.xyz/docs/rules/no-unused-class-component-members
+ "react-x/no-unused-class-component-members": "error",
+
+ // Warns unused class component state
+ // https://eslint-react.xyz/docs/rules/no-unused-state
+ "react-x/no-unused-state": "error",
+
+ // Replaces usages of useContext with use
+ // https://eslint-react.xyz/docs/rules/no-use-context
+ "react-x/no-use-context": "error",
+
+ // Disallow useless forwardRef calls on components that don't use refs
+ // https://eslint-react.xyz/docs/rules/no-useless-forward-ref
+ "react-x/no-useless-forward-ref": "error",
+
+ // Disallow useless fragment elements
+ // https://eslint-react.xyz/docs/rules/no-useless-fragment
+ "react-x/no-useless-fragment": "off",
+
+ // Enforces destructuring assignment for component props and context
+ // https://eslint-react.xyz/docs/rules/prefer-destructuring-assignment
+ "react-x/prefer-destructuring-assignment": "off",
+
+ // Enforces React is imported via a namespace import
+ // https://eslint-react.xyz/docs/rules/prefer-react-namespace-import
+ "react-x/prefer-react-namespace-import": "off",
+
+ // Enforces read-only props in components
+ // https://eslint-react.xyz/docs/rules/prefer-read-only-props
+ "react-x/prefer-read-only-props": "off",
+
+ // Enforces shorthand syntax for boolean attributes
+ // https://eslint-react.xyz/docs/rules/prefer-shorthand-boolean
+ "react-x/prefer-shorthand-boolean": "off",
+
+ // Enforces shorthand syntax for fragments
+ // https://eslint-react.xyz/docs/rules/prefer-shorthand-fragment
+ "react-x/prefer-shorthand-fragment": "off",
+
// 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 +497,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,35 +508,35 @@ 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
// but it's only critical if you're stripping propTypes in production.
- "react/forbid-foreign-prop-types": ["warn", { allowInPropTypes: true }],
+ "react/forbid-foreign-prop-types": ["error", { 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 +547,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 +557,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 +565,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 +583,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 +609,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 +646,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
- "react/jsx-no-comment-textnodes": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-comment-textnodes.md
+ "react/jsx-no-comment-textnodes": "off",
// 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
- "react/jsx-no-duplicate-props": ["error", { ignoreCase: true }],
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-duplicate-props.md
+ "react/jsx-no-duplicate-props": "off",
// 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 +674,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
- "react/jsx-no-undef": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-undef.md
+ "react/jsx-no-undef": "off",
// Enforce component methods order
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-useless-fragment.md
- "react/jsx-no-useless-fragment": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-no-useless-fragment.md
+ "react/jsx-no-useless-fragment": "off",
// 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 +700,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 +717,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 +725,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 +737,44 @@ 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
- "react/jsx-uses-react": [hasJsxRuntime ? "off" : "error"],
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-uses-react.md
+ // DISABLED: Handled by react-x/jsx-uses-react
+ "react/jsx-uses-react": "off",
// require a shouldComponentUpdate method, or PureRenderMixin
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md
- "react/jsx-uses-vars": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-uses-vars.md
+ // DISABLED: Handled by react-x/jsx-uses-vars
+ "react/jsx-uses-vars": "off",
// warn against using findDOMNode()
- // https://github.com/yannickcr/eslint-plugin-react/blob/843d71a432baf0f01f598d7cf1eea75ad6896e4b/docs/rules/no-access-state-in-setstate.md
- "react/no-access-state-in-setstate": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-access-state-in-setstate.md
+ // DISABLED: Handled by react-x/no-access-state-in-setstate
+ "react/no-access-state-in-setstate": "off",
// 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
- "react/no-array-index-key": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md
+ // DISABLED: Handled by react-x/no-array-index-key
+ "react/no-array-index-key": "off",
// Prevent problem with children and props.dangerouslySetInnerHTML
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md
- "react/no-children-prop": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-children-prop.md
+ // DISABLED: Handled by react-x/no-children-prop
+ "react/no-children-prop": "off",
// Prevent unused propType definitions
- // https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-danger.md
- "react/no-danger": "warn",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-danger.md
+ "react/no-danger": "error",
// 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 +782,65 @@ 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
- "react/no-direct-mutation-state": "error",
+ // 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
+ // DISABLED: Handled by react-x/no-direct-mutation-state
+ "react/no-direct-mutation-state": "off",
// 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
- // 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/forbid-foreign-prop-types.md
+ // this is intentionally set to "error". it would be "error",
+ // 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
- "react/no-redundant-should-component-update": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/9e13ae2c51e44872b45cc15bf1ac3a72105bdd0e/docs/rules/no-redundant-should-component-update.md
+ // DISABLED: Handled by react-x/no-redundant-should-component-update
+ "react/no-redundant-should-component-update": "off",
// 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
- "react/no-string-refs": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md
+ // DISABLED: Handled by react-x/no-string-refs
+ "react/no-string-refs": "off",
// 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,65 +850,53 @@ const config: Linter.Config = {
],
// Prevent usage of button elements without an explicit type attribute
- // https://github.com/yannickcr/eslint-plugin-react/pull/1103/
- "react/no-unused-state": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/pull/1103/
+ // DISABLED: Handled by react-x/no-unused-state
+ "react/no-unused-state": "off",
- // 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
- "react/prop-types": [
- "error",
- {
- customValidators: [],
- ignore: [],
- skipUndeclared: false,
- },
- ],
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/prop-types.md
+ "react/prop-types": "off",
// 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
- "react/require-default-props": [
- "error",
- {
- forbidDefaultForRequired: true,
- functions: hasDependency("typescript") || hasDevDependency("typescript") ? "defaultArguments" : "defaultProps",
- },
- ],
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/require-default-props.md
+ "react/require-default-props": "off",
// 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 +948,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 +957,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 +969,41 @@ 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 +1015,35 @@ 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: {
+ // Enforces consistent use of the JSX file extension.
+ // https://eslint-react.xyz/docs/rules/naming-convention-filename-extension
+ "react-x/naming-convention/filename-extension": ["error", "as-needed"],
+
// 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
- "react/jsx-filename-extension": "error",
+ // https://github.com/jsx-eslint/eslint-plugin-react/blob/master/docs/rules/jsx-filename-extension.md
+ "react/jsx-filename-extension": "off",
// 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 +1058,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 +1078,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..e4b7a31d4
--- /dev/null
+++ b/packages/eslint-config/src/config/plugins/stylistic.ts
@@ -0,0 +1,438 @@
+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({
+ indent,
+ jsx,
+ pluginName: "@stylistic",
+ quotes: prettier ? undefined : quotes,
+ semi: prettier ? false : semi,
+ });
+
+ return [
+ {
+ name: "anolilab/stylistic/rules",
+ plugins: {
+ "@stylistic": pluginStylistic,
+ },
+ rules: {
+ ...config.rules,
+
+ // Disable arrow parens rule
+ // We are using the arrow-parens
+ "@stylistic/arrow-parens": "off",
+
+ // 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/generator-star-spacing": ["error", { after: true, before: false }],
+
+ "@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",
+
+ "@stylistic/yield-star-spacing": ["error", { after: true, before: false }],
+
+ ...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..dc52efc4c 100644
--- a/packages/eslint-config/src/config/plugins/typescript.ts
+++ b/packages/eslint-config/src/config/plugins/typescript.ts
@@ -1,403 +1,449 @@
-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,
+ OptionsIsInEditor,
+ 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 as es6RulesFunction } from "../es6";
+import { styleRules as styleRulesFunction } from "../style";
+import { variablesRules } from "../variables";
+
+export default createConfig<
+ OptionsComponentExtensions &
+ OptionsFiles &
+ OptionsHasPrettier &
+ OptionsIsInEditor &
+ OptionsOverrides &
+ OptionsStylistic &
+ OptionsTypeScriptParserOptions &
+ OptionsTypeScriptWithTypes
+>("ts", async (config, oFiles) => {
+ const {
+ componentExts: componentExtensions = [],
+ files = oFiles,
+ isInEditor = false,
+ overrides,
+ overridesTypeAware,
+ parserOptions,
+ prettier,
+ stylistic = true,
+ } = config;
+
+ const styleRules = styleRulesFunction(stylistic);
+ const es6Rules = es6RulesFunction(isInEditor);
+
+ 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",
+ },
+ ],
+
+ "@typescript-eslint/ban-ts-comment": [
+ "error",
+ {
+ minimumDescriptionLength: 3,
+ "ts-check": false,
+ "ts-expect-error": "allow-with-description",
+ "ts-ignore": "allow-with-description",
+ "ts-nocheck": true,
+ },
+ ],
+
+ // @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 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",
+
+ // 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",
+ {
+ disallowTypeAnnotations: false,
+ fixStyle: "separate-type-imports",
+ prefer: "type-imports",
+ },
+ ],
+
+ // 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"] as Linter.RuleEntry<[]>,
-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"] as Linter.RuleEntry<[]>,
-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"] as Linter.RuleEntry<[]>,
- // 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"] as Linter.RuleEntry<[]>,
- // 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"] as Linter.RuleEntry<[]>,
- // 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"] as Linter.RuleEntry<[]>,
+
+ // 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"] as Linter.RuleEntry<[]>,
+
+ // 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"] as Linter.RuleEntry<[]>,
+
+ // 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"] as Linter.RuleEntry<[]>,
+
+ // 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"] as Linter.RuleEntry<[]>,
+
+ // 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"] as Linter.RuleEntry<[]>,
+
+ // 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
+ // DEPRECATED: in favor of ban-ts-comment
+ "@typescript-eslint/prefer-ts-expect-error": "off",
+
+ // 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"] as Linter.RuleEntry<[]>,
+
+ // 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"] as Linter.RuleEntry<[]>,
+
+ // 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"] as Linter.RuleEntry<[]>,
+
+ // 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"] as Linter.RuleEntry<[]>,
+
+ ...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..8bae748da 100644
--- a/packages/eslint-config/src/config/plugins/unicorn.ts
+++ b/packages/eslint-config/src/config/plugins/unicorn.ts
@@ -1,75 +1,106 @@
-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.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",
+ "unicorn/no-instanceof-builtins": "error",
- // It will be disabled in the next version of eslint-plugin-unicorn.
- "unicorn/prefer-json-parse-buffer": "off",
+ // TODO: Temporarily disabled until it becomes more mature.
+ "unicorn/no-useless-undefined": "off",
- "unicorn/prefer-module": packageIsTypeModule ? "error" : "off",
+ // Disabled to use faster alternatives.
+ "unicorn/prefer-at": "off",
- "unicorn/prefer-node-protocol": "error",
+ // It will be disabled in the next version of eslint-plugin-unicorn.
+ "unicorn/prefer-json-parse-buffer": "off",
- // We only enforce it for single-line statements to not be too opinionated.
- "unicorn/prefer-ternary": ["error", "only-single-line"],
+ "unicorn/prefer-module": packageJson.type === "module" ? "error" : "off",
- "unicorn/template-indent": ["error", { indent }],
+ "unicorn/prefer-node-protocol": "error",
- ...global.anolilabEslintConfigUnicornPrettierRules,
- },
-};
+ // We only enforce it for single-line statements to not be too opinionated.
+ "unicorn/prefer-ternary": ["error", "only-single-line"],
-export default config;
+ ...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 }],
+ },
+
+ ...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..5c73a27cc 100644
--- a/packages/eslint-config/src/config/plugins/yml.ts
+++ b/packages/eslint-config/src/config/plugins/yml.ts
@@ -1,24 +1,98 @@
-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,
},
},
- ],
-};
+ {
+ files: ["pnpm-workspace.yaml"],
+ name: "anolilab/yaml/pnpm-workspace",
+ rules: {
+ "yaml/sort-keys": [
+ "error",
+ {
+ order: [
+ "packages",
+ "overrides",
+ "patchedDependencies",
+ "hoistPattern",
+ "catalog",
+ "catalogs",
-export default config;
+ "allowedDeprecatedVersions",
+ "allowNonAppliedPatches",
+ "configDependencies",
+ "ignoredBuiltDependencies",
+ "ignoredOptionalDependencies",
+ "neverBuiltDependencies",
+ "onlyBuiltDependencies",
+ "onlyBuiltDependenciesFile",
+ "packageExtensions",
+ "peerDependencyRules",
+ "supportedArchitectures",
+ ],
+ pathPattern: "^$",
+ },
+ ],
+ },
+ },
+ ];
+});
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..24da8b552 100644
--- a/packages/eslint-config/src/config/style.ts
+++ b/packages/eslint-config/src/config/style.ts
@@ -1,724 +1,600 @@
-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.
+import type {
+ OptionsFiles,
+ OptionsHasPrettier,
+ OptionsStylistic,
+ StylisticConfig,
+} 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 = (stylistic?: StylisticConfig | boolean): Partial => {
+ return {
+ // enforce line breaks after opening and before closing array brackets
+ // https://eslint.org/docs/rules/array-bracket-newline
"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,
- },
- },
- ],
+ // enforce line breaks between array elements
+ // enforce spacing inside array brackets
+ "array-bracket-spacing": ["error", "never"],
- // disallow padding inside computed properties
- "computed-property-spacing": ["error", "never"],
+ // https://eslint.org/docs/rules/array-element-newline
+ "array-element-newline": "off",
- // enforces consistent naming when capturing the current execution context
- "consistent-this": "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: ".*",
+ },
+ },
+ ],
+
+ // 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,
+ },
+ },
+ ],
- // enforce that default parameters should come last
- "default-param-last": ["error"],
+ // disallow padding inside computed properties
+ "computed-property-spacing": ["error", "never"],
- // enforce newline at the end of file, with no multiple empty lines
- "eol-last": ["error", "always"],
+ // enforces consistent naming when capturing the current execution context
+ "consistent-this": "off",
- // https://eslint.org/docs/rules/func-call-spacing
- "func-call-spacing": ["error", "never"],
+ // enforce that default parameters should come last
+ "default-param-last": ["error"],
- // enforce spacing between functions and their invocations
- // https://eslint.org/docs/rules/func-name-matching
- "func-name-matching": [
- "off",
- "always",
- {
- considerPropertyDescriptor: true,
- includeCommonJSModuleExports: false,
- },
- ],
+ // enforce newline at the end of file, with no multiple empty lines
+ "eol-last": ["error", "always"],
- // 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,
- },
- ],
+ // 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",
+ 180,
+ 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 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 },
- },
- },
- ],
+ // specify the maximum depth callbacks can be nested
+ "max-nested-callbacks": "off",
- // 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",
- },
- ],
+ // limits the number of parameters that can be used in the function declaration.
+ "max-params": ["off", 3],
- // 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 maximum number of statement allowed in a function
+ "max-statements": ["off", 10],
- // 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,
- },
- ],
+ // 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 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,
- },
- ],
+ // enforce a particular style for multiline comments
+ // https://eslint.org/docs/rules/multiline-comment-style
+ "multiline-comment-style": ["off", "starred-block"],
- // 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: [],
- },
- ],
+ // require multiline ternary
+ // https://eslint.org/docs/rules/multiline-ternary
+ "multiline-ternary": ["off", "never"],
- // 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"],
- ],
- },
+ // 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": "off",
+
+ // 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 mixed spaces and tabs for indentation
+ "no-mixed-spaces-and-tabs": "error",
- // disallow space between function identifier and application
- // deprecated in favor of func-call-spacing
- "no-spaced-func": "off",
+ // disallow use of chained assignment expressions
+ // https://eslint.org/docs/rules/no-multi-assign
+ "no-multi-assign": ["error"],
- // disallow tab characters entirely
- "no-tabs": "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 the use of ternary operators
- "no-ternary": "off",
+ // disallow negated conditions
+ // https://eslint.org/docs/rules/no-negated-condition
+ "no-negated-condition": "off",
- // disallow trailing whitespace at the end of lines
- "no-trailing-spaces": [
- "error",
- {
- ignoreComments: false,
- skipBlankLines: false,
- },
- ],
+ // disallow nested ternary expressions
+ "no-nested-ternary": "error",
- // 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 use of the Object constructor
+ "no-new-object": "error",
- // 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 },
- },
- ],
+ // disallow use of unary operators, ++ and --
+ // https://eslint.org/docs/rules/no-plusplus
+ "no-plusplus": "error",
- // 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,
- },
- ],
+ // 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: "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=\"\"]",
+ },
+ ],
- // Require or disallow padding lines between statements
- // https://eslint.org/docs/rules/padding-line-between-statements
- "padding-line-between-statements": "off",
+ // disallow space between function identifier and application
+ // deprecated in favor of func-call-spacing
+ "no-spaced-func": "off",
- // Disallow the use of Math.pow in favor of the ** operator
- // https://eslint.org/docs/rules/prefer-exponentiation-operator
- "prefer-exponentiation-operator": "error",
+ // disallow tab characters entirelyp
+ "no-tabs": "error",
- // Prefer use of an object spread over Object.assign
- // https://eslint.org/docs/rules/prefer-object-spread
- "prefer-object-spread": "error",
+ // disallow the use of ternary operators
+ "no-ternary": "off",
- // 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 }],
+ // disallow trailing whitespace at the end of lines
+ "no-trailing-spaces": [
+ "error",
+ {
+ ignoreComments: true,
+ 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": stylistic ? "off" : ["error", "before", { overrides: { "=": "none" } }],
+
+ // disallow padding within blocks
+ "padded-blocks": [
+ "error",
+ {
+ blocks: "never",
+ classes: "never",
+ switches: "never",
+ },
+ {
+ allowSingleLineBlocks: true,
+ },
+ ],
- // specify whether double or single quotes should be used
- quotes: ["error", "double", { avoidEscape: true }],
+ // Require or disallow padding lines between statements
+ // https://eslint.org/docs/rules/padding-line-between-statements
+ "padding-line-between-statements": "off",
- // do not require jsdoc
- // https://eslint.org/docs/rules/require-jsdoc
- "require-jsdoc": "off",
+ // Disallow the use of Math.pow in favor of the ** operator
+ // https://eslint.org/docs/rules/prefer-exponentiation-operator
+ "prefer-exponentiation-operator": "error",
- // require or disallow use of semicolons instead of ASI
- semi: ["error", "always"],
+ // Prefer use of an object spread over Object.assign
+ // https://eslint.org/docs/rules/prefer-object-spread
+ "prefer-object-spread": "error",
- // enforce spacing before and after semicolons
- "semi-spacing": ["error", { after: true, before: false }],
+ // do not require jsdoc
+ // https://eslint.org/docs/rules/require-jsdoc
+ "require-jsdoc": "off",
- // Enforce location of semicolons
- // https://eslint.org/docs/rules/semi-style
- "semi-style": ["error", "last"],
+ // enforce spacing before and after semicolons
+ "semi-spacing": ["error", { after: true, before: false }],
- // requires object keys to be sorted
- // Disabled because of perfectionist/sort-objects
- "sort-keys": "off",
+ // Enforce location of semicolons
+ // https://eslint.org/docs/rules/semi-style
+ "semi-style": ["error", "last"],
- // sort variables within the same declaration block
- "sort-vars": "off",
+ // requires object keys to be sorted
+ // Disabled because of perfectionist/sort-objects
+ "sort-keys": "off",
- // require or disallow space before blocks
- "space-before-blocks": "error",
+ // sort variables within the same declaration block
+ "sort-vars": "off",
- // 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 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 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
+ },
+ },
+ ],
- // 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 }],
- // 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 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 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",
+ };
+};
- // require regex literals to be wrapped in parentheses
- "wrap-regex": "off",
+export default createConfig("all", async (config, oFiles) => {
+ const { files = oFiles, prettier, stylistic } = config;
- ...prettierRules,
- },
- },
- type: "all",
- },
- {
- 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(stylistic),
+ "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 +619,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 +635,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..cf07ac734 100644
--- a/packages/eslint-config/src/index.ts
+++ b/packages/eslint-config/src/index.ts
@@ -1,228 +1,949 @@
-/**
- * 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 es6 from "./config/es6";
+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 => (typeof options[key] === "boolean" ? {} : options[key] || {}) as ResolvedOptions;
+export const getOverrides = (options: OptionsConfig, key: K): Partial => {
+ const sub = resolveSubOptions(options, key);
+
+ return {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ...(options.overrides as any)?.[key],
+ ..."overrides" in sub ? sub.overrides : {},
+ };
+};
-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 getFiles = (options: OptionsConfig, key: K): string[] | undefined => {
+ 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");
+ if ("files" in sub) {
+ if (typeof sub.files === "string") {
+ return [sub.files];
+ }
- consoleLog(" @rushstack/eslint-plugin-security");
- internalPluginConfig
- .map((name: string) => {
- if (name === "import") {
- return "i";
- }
+ return sub.files;
+ }
- if (name === "node") {
- return "n";
- }
+ return undefined;
+};
- return name;
- })
- .forEach((plugin) => consolePlugin(plugin));
+/**
+ * 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.",
+ );
}
- let hasLogged = false;
+ 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 hasReact = hasPackageJsonAnyDependency(packageJson, ["react", "react-dom"]);
+
+ const {
+ astro: enableAstro = hasPackageJsonAnyDependency(packageJson, ["astro"]),
+ componentExts: componentExtensions = [],
+ gitignore: enableGitignore = true,
+ html: enableHtml = false,
+ jsx: enableJsx = hasPackageJsonAnyDependency(packageJson, ["eslint-plugin-jsx-a11y", "eslint-plugin-validate-jsx-nesting"]) || hasReact,
+ 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 = hasReact || hasPackageJsonAnyDependency(packageJson, [
+ "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");
+ }
- Object.entries(possiblePluginRules).forEach(([plugin, dependencies]) => {
- const hasOneDependency = Object.values(dependencies).some(Boolean);
+ if (enableUnoCSS) {
+ packages.push("@unocss/eslint-plugin");
+ }
- if (hasOneDependency) {
- hasLogged = true;
+ if (enableTanstackQuery) {
+ packages.push("@tanstack/eslint-plugin-query");
+ }
- 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 (enableTanstackRouter) {
+ packages.push("@tanstack/eslint-plugin-router");
+ }
- Object.entries(dependencies).forEach(([dependency, installed]) => {
- if (!installed) {
- consoleLog(` ${dependency}`);
- }
- });
+ if (enableTailwindCss) {
+ packages.push("eslint-plugin-tailwindcss");
}
- });
- // 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 (enableStorybook) {
+ packages.push("eslint-plugin-storybook");
+ }
+
+ if (enableReact) {
+ packages.push("eslint-plugin-react", "@eslint-react/eslint-plugin", "eslint-plugin-react-hooks");
+ }
+
+ if (enableTestingLibrary) {
+ packages.push("eslint-plugin-testing-library");
+ }
- consoleLog('To disable all logging, add the following to your eslint command call "NO_LOGS=true eslint ..."');
+ if (enableJsx) {
+ packages.push("eslint-plugin-jsx-a11y", "eslint-plugin-validate-jsx-nesting");
+ }
- global.hasAnolilabEsLintConfigLoaded = true;
-}
+ if (enableLodash) {
+ packages.push("eslint-plugin-you-dont-need-lodash-underscore");
+ }
-const configRules: Linter.RulesRecord = {};
+ if (enableTsdoc) {
+ packages.push("eslint-plugin-tsdoc");
+ }
-let nodeVersion: string | undefined;
+ if (options.formatters) {
+ packages.push("eslint-plugin-format");
+ }
-if (pkg?.engines?.["node"]) {
- nodeVersion = pkg.engines["node"];
-}
+ if (enableAstro) {
+ packages.push("eslint-plugin-astro", "astro-eslint-parser", "@typescript-eslint/parser");
-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 (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",
- },
- },
- {
- 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}",
+
+ if (options.formatters?.xml || options.formatters?.svg) {
+ packages.push("@prettier/plugin-xml");
+ }
+ }
+
+ if (packages.length > 0) {
+ 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?`,
+ },
+ });
+ }
+ }
+
+ let { isInEditor } = options;
+
+ 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({
+ stylistic: stylisticOptions,
+ }),
+ es6({
+ isInEditor,
+ }),
+ 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"),
+ jsx: enableJsx,
+ overrides: getOverrides(options, "jsdoc"),
+ packageJson,
+ silent,
+ stylistic: stylisticOptions,
+ typescript: enableTypeScript,
+ }),
+ 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;
+ }
-export default config;
+ return accumulator;
+ }, {} as TypedFlatConfigItem);
+
+ if (Object.keys(fusedConfig).length > 0) {
+ configs.push([fusedConfig]);
+ }
+
+ 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/types.d.ts b/packages/eslint-config/src/types.d.ts
deleted file mode 100644
index 50343ddf9..000000000
--- a/packages/eslint-config/src/types.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export type PackageRules = {
- configName: string;
- dependencies: string[];
- oneOfDependency?: string[];
- resolve?: string[];
- files?: string[];
-}[];
diff --git a/packages/eslint-config/src/types.ts b/packages/eslint-config/src/types.ts
new file mode 100644
index 000000000..bd8ea2aca
--- /dev/null
+++ b/packages/eslint-config/src/types.ts
@@ -0,0 +1,565 @@
+import type { StylisticCustomizeOptions } from "@stylistic/eslint-plugin";
+import type { ParserOptions } from "@typescript-eslint/parser";
+import type { NormalizedPackageJson } from "@visulima/package";
+import type { Linter } from "eslint";
+import type { FlatGitignoreOptions } from "eslint-config-flat-gitignore";
+
+import type { RuleOptions } from "./typegen";
+import type { VendoredPrettierOptions } from "./vender/prettier-types";
+
+export type Awaitable = Promise | T;
+
+export interface OptionsComponentExtensions {
+ /**
+ * Additional extensions for components.
+ * @example ['vue']
+ * @default []
+ */
+ componentExts?: string[];
+}
+
+export type { ConfigNames } from "./typegen";
+
+export interface OptionsConfig extends OptionsComponentExtensions, OptionsSilentConsoleLogs {
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ antfu?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Enable ASTRO support.
+ *
+ * Requires installing:
+ * - `eslint-plugin-astro`
+ *
+ * Requires installing for formatting .astro:
+ * - `prettier-plugin-astro`
+ * @default false
+ */
+ astro?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ comments?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Override the `files` option to provide custom globs.
+ */
+ compat?: OptionsFiles;
+
+ /**
+ * The working directory for the config.
+ * @default process.cwd()
+ */
+ cwd?: string;
+
+ /**
+ * Use external formatters to format files.
+ *
+ * Requires installing:
+ * - `eslint-plugin-format`
+ *
+ * When set to `true`, it will enable all formatters.
+ * @default false
+ */
+ formatters?: OptionsFormatters | boolean;
+
+ /**
+ * Enable gitignore support.
+ *
+ * Passing an object to configure the options.
+ * @see https://github.com/antfu/eslint-config-flat-gitignore
+ * @default true
+ */
+ gitignore?: FlatGitignoreOptions | boolean;
+
+ /**
+ * Enable HTML support.
+ *
+ * Requires installing:
+ * - `eslint-plugin-html`
+ * @default false
+ */
+ html?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ imports?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Control to disable some rules in editors.
+ * @default auto-detect based on the process.env
+ */
+ isInEditor?: boolean;
+
+ /**
+ * Core rules. Can't be disabled.
+ */
+ javascript?: OptionsOverrides;
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ jsdoc?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Enable JSONC support.
+ * @default true
+ */
+ jsonc?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable JSX related rules.
+ *
+ * Currently only stylistic rules are included.
+ * @default true
+ */
+ jsx?: boolean;
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ "jsx-a11y"?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Disable some opinionated rules to Anolilab's preference.
+ *
+ * Including:
+ * - `antfu/top-level-function`
+ * - `antfu/if-newline`
+ * @default false
+ */
+ lessOpinionated?: boolean;
+
+ /**
+ * Enable lodash rules.
+ *
+ * Requires installing:
+ * - `eslint-plugin-lodash`
+ * @default false
+ */
+ lodash?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable linting for **code snippets** in Markdown.
+ *
+ * For formatting Markdown content, enable also `formatters.markdown`.
+ * @default true
+ */
+ markdown?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ node?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Override some rules.
+ */
+ noSecrets?: OptionsOverrides;
+
+ /**
+ * Override some rules.
+ */
+ noUnsanitized?: OptionsOverrides;
+
+ /**
+ * Provide overrides for rules for each integration.
+ * @deprecated use `overrides` option in each integration key instead
+ */
+ overrides?: {
+ html?: TypedFlatConfigItem["rules"];
+ javascript?: TypedFlatConfigItem["rules"];
+ jsonc?: TypedFlatConfigItem["rules"];
+ "jsx-a11y"?: TypedFlatConfigItem["rules"];
+ lodash?: TypedFlatConfigItem["rules"];
+ markdown?: TypedFlatConfigItem["rules"];
+ node?: TypedFlatConfigItem["rules"];
+ noSecrets?: TypedFlatConfigItem["rules"];
+ noUnsanitized?: TypedFlatConfigItem["rules"];
+ perfectionist?: TypedFlatConfigItem["rules"];
+ playwright?: TypedFlatConfigItem["rules"];
+ promise?: TypedFlatConfigItem["rules"];
+ react?: TypedFlatConfigItem["rules"];
+ simpleImportSort?: TypedFlatConfigItem["rules"];
+ sonarjs?: TypedFlatConfigItem["rules"];
+ storybook?: TypedFlatConfigItem["rules"];
+ stylistic?: TypedFlatConfigItem["rules"];
+ svelte?: TypedFlatConfigItem["rules"];
+ test?: TypedFlatConfigItem["rules"];
+ toml?: TypedFlatConfigItem["rules"];
+ typescript?: TypedFlatConfigItem["rules"];
+ unocss?: TypedFlatConfigItem["rules"];
+ validateJsxNesting?: TypedFlatConfigItem["rules"];
+ yaml?: TypedFlatConfigItem["rules"];
+ };
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ perfectionist?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Enable playwright rules.
+ *
+ * Requires installing:
+ * - `eslint-plugin-playwright`
+ * @default false
+ */
+ playwright?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ promise?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Enable react rules.
+ *
+ * Requires installing:
+ * - `@eslint-react/eslint-plugin`
+ * - `eslint-plugin-react-hooks`
+ * - `eslint-plugin-react-refresh`
+ * @default false
+ */
+ react?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable regexp rules.
+ * @see https://ota-meshi.github.io/eslint-plugin-regexp/
+ * @default true
+ */
+ regexp?: boolean | (OptionsFiles & OptionsOverrides & OptionsRegExp);
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ simpleImportSort?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ sonarjs?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Enable Storybook rules.
+ *
+ * Requires installing:
+ * - `eslint-plugin-storybook`
+ * @default false
+ */
+ storybook?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable stylistic rules.
+ * @see https://eslint.style/
+ * @default true
+ */
+ stylistic?: boolean | (OptionsFiles & OptionsOverrides & StylisticConfig);
+
+ /**
+ * Enable tailwindcss support.
+ *
+ * Requires installing:
+ * - `eslint-plugin-tailwindcss`
+ * @default false
+ */
+ tailwindcss?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable tanstack rules.
+ *
+ * Requires installing:
+ * - `@tanstack/eslint-plugin-query`
+ * @default false
+ */
+ tanstackQuery?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable tanstack rules.
+ *
+ * Requires installing:
+ * - `@tanstack/eslint-plugin-router`
+ * @default false
+ */
+ tanstackRouter?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable testing-library rules.
+ *
+ * Requires installing:
+ * - `eslint-plugin-testing-library`
+ * @default false
+ */
+ testingLibrary?: boolean | (OptionsFiles & OptionsOverrides & OptionsPackageJson);
+
+ /**
+ * Enable TOML support.
+ * @default true
+ */
+ toml?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable tsdoc rules.
+ *
+ * Requires installing:
+ * - `eslint-plugin-tsdoc`
+ * @default false
+ */
+ tsdoc?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable TypeScript support.
+ *
+ * Passing an object to enable TypeScript Language Server support.
+ * @default auto-detect based on the dependencies
+ */
+ typescript?: OptionsTypescript | boolean;
+
+ /**
+ * Options for eslint-plugin-unicorn.
+ * @default true
+ */
+ unicorn?: OptionsUnicorn | boolean;
+
+ /**
+ * Enable unocss rules.
+ *
+ * Requires installing:
+ * - `@unocss/eslint-plugin`
+ * @default false
+ */
+ unocss?: OptionsUnoCSS | boolean;
+
+ /**
+ * Override the `files` option to provide custom globs or disable some rules.
+ */
+ validateJsxNesting?: OptionsFiles & OptionsOverrides;
+
+ /**
+ * Enable vitest support.
+ * @default true
+ */
+ vitest?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable YAML support.
+ * @default true
+ */
+ yaml?: boolean | (OptionsFiles & OptionsOverrides);
+
+ /**
+ * Enable Zod rules.
+ *
+ * Requires installing:
+ * - `eslint-plugin-zod`
+ * @default false
+ */
+ zod?: boolean | (OptionsFiles & OptionsOverrides);
+}
+
+export interface OptionsCwd {
+ /**
+ * The working directory for the config.
+ * @default process.cwd()
+ */
+ cwd: string;
+}
+
+export interface OptionsFiles {
+ /**
+ * Override the `files` option to provide custom globs.
+ */
+ files?: string[];
+}
+
+export interface OptionsFormatters {
+ /**
+ * Enable formatting support for Astro.
+ *
+ * Currently only support Prettier.
+ */
+ astro?: boolean | "prettier";
+
+ /**
+ * Enable formatting support for CSS, Less, Sass, and SCSS.
+ *
+ * Currently only support Prettier.
+ */
+ css?: boolean | "prettier";
+
+ /**
+ * Custom options for dprint.
+ *
+ * By default it's controlled by our own config.
+ */
+ dprintOptions?: {
+ indent?: "space" | "tab";
+ indentWidth?: number;
+ quoteStyle?: "preferDouble" | "preferSingle";
+ useTabs?: boolean;
+ };
+
+ /**
+ * Enable formatting support for GraphQL.
+ */
+ graphql?: boolean | "prettier";
+
+ /**
+ * Enable formatting support for HTML.
+ *
+ * Currently only support Prettier.
+ */
+ html?: boolean | "prettier";
+
+ /**
+ * Enable formatting support for Markdown.
+ *
+ * Support both Prettier and dprint.
+ *
+ * When set to `true`, it will use Prettier.
+ */
+ markdown?: boolean | "dprint" | "prettier";
+
+ /**
+ * Custom options for Prettier.
+ *
+ * By default it's controlled by our own config.
+ */
+ prettierOptions?: VendoredPrettierOptions;
+
+ /**
+ * Install the prettier plugin for handle Slidev markdown
+ *
+ * Only works when `markdown` is enabled with `prettier`.
+ */
+ slidev?:
+ | boolean
+ | {
+ files?: string[];
+ };
+
+ /**
+ * Enable formatting support for SVG.
+ *
+ * Currently only support Prettier.
+ */
+ svg?: boolean | "prettier";
+
+ /**
+ * Enable formatting support for XML.
+ *
+ * Currently only support Prettier.
+ */
+ xml?: boolean | "prettier";
+}
+
+export interface OptionsHasPrettier {
+ prettier?: boolean;
+}
+
+export interface OptionsIsInEditor {
+ isInEditor?: boolean;
+}
+
+export interface OptionsOverrides {
+ overrides?: TypedFlatConfigItem["rules"];
+}
+
+export interface OptionsPackageJson {
+ /**
+ * The package.json object
+ */
+ packageJson: NormalizedPackageJson;
+}
+
+export interface OptionsRegExp {
+ /**
+ * Override rulelevels
+ */
+ level?: "error" | "warn";
+}
+
+export interface OptionsSilentConsoleLogs {
+ /**
+ * This option is used to enable or disable to console log information.
+ */
+ silent?: boolean;
+}
+
+export interface OptionsStylistic {
+ stylistic?: StylisticConfig | boolean;
+}
+
+export type OptionsTypescript = (OptionsOverrides & OptionsTypeScriptParserOptions) | (OptionsOverrides & OptionsTypeScriptWithTypes);
+
+export interface OptionsTypeScriptParserOptions {
+ /**
+ * Glob patterns for files that should be type aware.
+ * @default ['**\/*.{ts,tsx}']
+ */
+ filesTypeAware?: string[];
+
+ /**
+ * Glob patterns for files that should not be type aware.
+ * @default ['**\/*.md\/**', '**\/*.astro/*.ts']
+ */
+ ignoresTypeAware?: string[];
+
+ /**
+ * Additional parser options for TypeScript.
+ */
+ parserOptions?: Partial;
+}
+
+export interface OptionsTypeScriptWithTypes {
+ /**
+ * Override type aware rules.
+ */
+ overridesTypeAware?: TypedFlatConfigItem["rules"];
+
+ /**
+ * When this options is provided, type aware rules will be enabled.
+ * @see https://typescript-eslint.io/linting/typed-linting/
+ */
+ tsconfigPath?: string;
+}
+
+export interface OptionsUnicorn {
+ /**
+ * Include all rules recommended by `eslint-plugin-unicorn`, instead of only ones picked by Anthony.
+ * @default false
+ */
+ allRecommended?: boolean;
+}
+
+export interface OptionsUnoCSS extends OptionsOverrides {
+ /**
+ * Enable attributify support.
+ * @default true
+ */
+ attributify?: boolean;
+ /**
+ * Enable strict mode by throwing errors about blocklisted classes.
+ * @default false
+ */
+ strict?: boolean;
+}
+
+// eslint-disable-next-line @typescript-eslint/no-empty-object-type
+export interface Rules extends RuleOptions {}
+
+export type StylisticConfig = Pick;
+
+export type TypedFlatConfigItem = Omit, "plugins"> & {
+ // Relax plugins type limitation, as most of the plugins did not have correct type info yet.
+ /**
+ * An object containing a name-value mapping of plugin names to plugin objects.
+ * When `files` is specified, these plugins are only available to the matching files.
+ * @see [Using plugins in your configuration](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new#using-plugins-in-your-configuration)
+ */
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ plugins?: Record;
+};
diff --git a/packages/eslint-config/src/typescript-type-checking.ts b/packages/eslint-config/src/typescript-type-checking.ts
deleted file mode 100644
index 3a346a6dd..000000000
--- a/packages/eslint-config/src/typescript-type-checking.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-import { env } from "node:process";
-
-import type { Linter } from "eslint";
-
-import bestPracticesConfig from "./config/best-practices";
-import { createConfig } from "./utils/create-config";
-import anolilabEslintConfig from "./utils/eslint-config";
-
-// @ts-expect-error TODO: find the correct type
-const bestPracticesRules = bestPracticesConfig.overrides[0].rules as Linter.RulesRecord;
-
-let showUnsupportedTypeScriptVersionWarning: boolean = env["DISABLE_ESLINT_WARN_UNSUPPORTED_TYPESCRIPT_VERSION"] !== "true";
-
-if (anolilabEslintConfig["warn_on_unsupported_typescript_version"] !== undefined) {
- showUnsupportedTypeScriptVersionWarning = anolilabEslintConfig["warn_on_unsupported_typescript_version"] as boolean;
-}
-
-const config = createConfig("typescript", {
- extends: [
- "plugin:@typescript-eslint/recommended-type-checked",
- "plugin:@typescript-eslint/strict-type-checked",
- "plugin:@typescript-eslint/stylistic-type-checked",
- ],
- parser: "@typescript-eslint/parser",
- parserOptions: {
- ecmaFeatures: {
- jsx: true,
- },
- sourceType: "module",
- warnOnUnsupportedTypeScriptVersion: showUnsupportedTypeScriptVersionWarning,
- },
- plugins: ["@typescript-eslint"],
- rules: {
- // Disallows awaiting a value that is not a Thenable
- "@typescript-eslint/await-thenable": "error",
-
- "@typescript-eslint/consistent-type-exports": [
- "error",
- {
- fixMixedExportsWithInlineTypeSpecifier: true,
- },
- ],
-
- // Replace 'dot-notation' rule with '@typescript-eslint' version
- "@typescript-eslint/dot-notation": ["error", { allowKeywords: true }],
- // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-base-to-string.md
- "@typescript-eslint/no-base-to-string": [
- "error",
- {
- ignoredTypeNames: ["RegExp"],
- },
- ],
-
- // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-confusing-void-expression.md
- "@typescript-eslint/no-confusing-void-expression": [
- "error",
- {
- ignoreArrowShorthand: true,
- ignoreVoidOperator: false,
- },
- ],
-
- // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-floating-promises.md
- "@typescript-eslint/no-floating-promises": [
- "error",
- {
- ignoreIIFE: true,
- ignoreVoid: true,
- },
- ],
-
- // Disallow iterating over an array with a for-in loop
- "@typescript-eslint/no-for-in-array": "error",
-
- "@typescript-eslint/no-implied-eval": bestPracticesRules["no-implied-eval"],
-
- // Replace 'no-throw-literal' rule with '@typescript-eslint' version
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-meaningless-void-operator.md
- "@typescript-eslint/no-meaningless-void-operator": ["error", { checkNever: true }],
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-misused-promises.md
- "@typescript-eslint/no-misused-promises": [
- "error",
- {
- checksConditionals: true,
- checksVoidReturn: {
- arguments: true,
- attributes: false,
- properties: true,
- returns: true,
- variables: true,
- },
- },
- ],
-
- // Replace 'no-implied-eval' and 'no-new-func' rules with '@typescript-eslint' version
- "@typescript-eslint/no-throw-literal": bestPracticesRules["no-throw-literal"],
-
- // Force array predicates to return something that could be either truthy or falsy.
- // See https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md
- // See also https://github.com/typescript-eslint/typescript-eslint/issues/1038
- // See also https://github.com/microsoft/TypeScript/issues/19456
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md
- "@typescript-eslint/no-unnecessary-condition": "error",
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unnecessary-qualifier.md
- "@typescript-eslint/no-unnecessary-qualifier": "error",
-
- // Disallow the void operator except when used to discard a value.
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/no-unnecessary-type-arguments.md
- "@typescript-eslint/no-unnecessary-type-arguments": "error",
-
- // Disabling here because in most cases the explicitness is still valuable
- "@typescript-eslint/no-unnecessary-type-assertion": "off",
-
- // Warns if a type assertion does not change the type of an expression
- // See https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/non-nullable-type-assertion-style.md
- "@typescript-eslint/non-nullable-type-assertion-style": "off",
-
- // See https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/method-signature-style.md
- "@typescript-eslint/method-signature-style": "error",
-
- // Enforce includes method over indexOf method.
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-includes.md
- "@typescript-eslint/prefer-includes": "error",
-
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md
- "@typescript-eslint/prefer-nullish-coalescing": [
- "error",
- {
- ignoreConditionalTests: true,
- ignoreMixedLogicalExpressions: true,
- },
- ],
-
- // Enforce RegExp#exec over String#match if no global flag is provided.
- // Requires that private members are marked as readonly if they're never modified outside of the constructor
- "@typescript-eslint/prefer-readonly": ["error", { onlyInlineLambdas: false }],
-
- // Enforce that this is used when only this type is returned.
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-reduce-type-parameter.md
- "@typescript-eslint/prefer-reduce-type-parameter": "error",
-
- // Enforce using String#startsWith and String#endsWith over other equivalent methods of checking substrings.
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-regexp-exec.md
- "@typescript-eslint/prefer-regexp-exec": "error",
-
- // Replace 'require-await' rule with '@typescript-eslint' version
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-return-this-type.md
- "@typescript-eslint/prefer-return-this-type": "error",
- // https://github.com/typescript-eslint/typescript-eslint/tree/main/packages/eslint-plugin/docs/rules/prefer-string-starts-ends-with.md
- "@typescript-eslint/prefer-string-starts-ends-with": "error",
-
- // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/promise-function-async.md
- "@typescript-eslint/promise-function-async": "error",
-
- // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/require-array-sort-compare.md
- "@typescript-eslint/require-array-sort-compare": [
- "error",
- {
- ignoreStringArrays: false,
- },
- ],
-
- "@typescript-eslint/require-await": bestPracticesRules["require-await"],
-
- // When adding two variables, operands must both be of type number or of type string
- "@typescript-eslint/restrict-plus-operands": "error",
-
- // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/return-await.md
- "@typescript-eslint/return-await": ["error", "always"],
-
- // Disallow unnecessary namespace qualifiers.
- // https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/switch-exhaustiveness-check.md
- "@typescript-eslint/switch-exhaustiveness-check": "error",
-
- // Enforces unbound methods are called with their expected scope
- "@typescript-eslint/unbound-method": ["error", { ignoreStatic: false }],
-
- // TODO: enable this rule when decision is made on
- "@typescript-eslint/consistent-type-assertions": [
- "off",
- {
- assertionStyle: "never",
- },
- ],
-
- // TODO: enable this rule when decision is made on
- "@typescript-eslint/strict-boolean-expressions": [
- "off",
- {
- allowString: false,
- allowNumber: false,
- allowNullableObject: false,
- },
- ],
-
- // Interfaces encourage OO, types encourage FP.
- "@typescript-eslint/consistent-type-definitions": "off",
- },
-});
-
-export default config;
diff --git a/packages/eslint-config/src/utils/combine.ts b/packages/eslint-config/src/utils/combine.ts
new file mode 100644
index 000000000..677e24935
--- /dev/null
+++ b/packages/eslint-config/src/utils/combine.ts
@@ -0,0 +1,14 @@
+import type { Awaitable, TypedFlatConfigItem } from "../types";
+
+/**
+ * Combine array and non-array configs into a single array.
+ * @param {TypedFlatConfigItem | TypedFlatConfigItem[]} configs
+ * @returns {Promise}
+ */
+const combine = async (...configs: Awaitable[]): Promise => {
+ const resolved = await Promise.all(configs);
+
+ return resolved.flat();
+};
+
+export default combine;
diff --git a/packages/eslint-config/src/utils/create-config.ts b/packages/eslint-config/src/utils/create-config.ts
index 57bda539b..39948b2b5 100644
--- a/packages/eslint-config/src/utils/create-config.ts
+++ b/packages/eslint-config/src/utils/create-config.ts
@@ -1,134 +1,129 @@
-import type { Linter } from "eslint";
+import type { TypedFlatConfigItem } from "../types";
type FileType =
| "all"
- | "ava"
+ | "astro_ts"
+ | "astro"
+ | "css"
| "d.ts"
- | "javascript"
- | "jest"
+ | "e2e"
+ | "graphql"
+ | "html"
| "js_and_ts"
+ | "js"
| "jsx_and_tsx"
+ | "less"
+ | "markdown_in_markdown"
| "markdown_inline_js_jsx"
| "markdown"
- | "mdx"
| "postcss"
- | "tests"
- | "typescript"
- | "vitest";
+ | "scss"
+ | "storybook"
+ | "svg"
+ | "toml"
+ | "ts"
+ | "vitest"
+ | "xml"
+ | "yaml";
-const getType = (fileType: FileType) => {
+// @see https://devblogs.microsoft.com/typescript/announcing-typescript-4-5-beta/#new-file-extensions
+const dtsGlobal = ["**/*.d.ts", "**/*.d.cts", "**/*.d.mts"];
+const tsGlobal = ["**/*.ts", "**/*.cts", "**/*.mts"];
+const tsxGlobal = ["**/*.tsx", "**/*.mtsx", "**/*.ctsx"];
+
+const jsGlobal = ["**/*.js", "**/*.mjs", "**/*.cjs"];
+const jsxGlobal = ["**/*.jsx", "**/*.mjsx", "**/*.cjsx"];
+
+export const getFilesGlobs = (fileType: FileType): string[] => {
switch (fileType) {
- case "typescript": {
- // @see https://devblogs.microsoft.com/typescript/announcing-typescript-4-5-beta/#new-file-extensions
- return ["**/*.ts", "**/*.d.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
+ case "all": {
+ return [...jsGlobal, ...dtsGlobal, ...tsGlobal, ...tsxGlobal, ...jsxGlobal];
}
- case "jsx_and_tsx": {
- return ["**/*.jsx", "**/*.tsx"];
+ case "astro": {
+ return ["**/*.astro"];
+ }
+ case "astro_ts": {
+ return ["**/*.astro/*.ts"];
+ }
+ case "css": {
+ return ["**/*.css"];
+ }
+ case "d.ts": {
+ return dtsGlobal;
+ }
+ case "e2e": {
+ return ["**/e2e/**/*.test.{js,ts,jsx,tsx}"];
+ }
+ case "graphql": {
+ return ["**/*.{g,graph}ql"];
+ }
+ case "html": {
+ return [
+ "**/*.erb",
+ "**/*.handlebars",
+ "**/*.hbs",
+ "**/*.htm",
+ "**/*.html",
+ "**/*.mustache",
+ "**/*.nunjucks",
+ "**/*.php",
+ "**/*.tag",
+ "**/*.twig",
+ "**/*.we",
+ ];
+ }
+ case "js": {
+ return jsGlobal;
}
case "js_and_ts": {
- return ["**/*.js", "**/*.mjs", "**/*.cjs", "**/*.ts", "**/*.d.ts", "**/*.mts", "**/*.cts"];
+ return [...jsGlobal, ...tsGlobal];
}
- case "javascript": {
- return ["**/*.js", "**/*.mjs", "**/*.cjs"];
+ case "jsx_and_tsx": {
+ return [...jsxGlobal, ...tsxGlobal];
}
- case "all": {
- return ["**/*.js", "**/*.jsx", "**/*.mjs", "**/*.cjs", "**/*.ts", "**/*.d.ts", "**/*.tsx", "**/*.mts", "**/*.cts"];
+ case "less": {
+ return ["**/*.less"];
}
case "markdown": {
return ["**/*.{md,mkdn,mdown,markdown}"];
}
+ case "markdown_in_markdown": {
+ return ["**/*.{md,mkdn,mdown,markdown}/*.{md,mkdn,mdown,markdown}"];
+ }
case "markdown_inline_js_jsx": {
return ["**/*.{md,mkdn,mdown,markdown}/*.{js,javascript,jsx,node,json}"];
}
- case "mdx": {
- return ["**/*.mdx"];
+ case "postcss": {
+ return ["**/postcss.config.js", "**/postcssrc.js", "**/postcss.config.cjs", "**/postcssrc.cjs"];
+ }
+ case "scss": {
+ return ["**/*.scss"];
}
- case "jest": {
- return [
- // Test files
- "**/*.spec.{js,ts,tsx}",
- "**/*.test.{js,ts,tsx}",
- "**/test/*.{js,ts,tsx}",
-
- // Facebook convention
- "**/__mocks__/*.{js,ts,tsx}",
- "**/__tests__/*.{js,ts,tsx}",
- ];
+ case "storybook": {
+ return ["**/*.stories.@(ts|tsx|js|jsx|mjs|cjs)", "**/*.story.@(ts|tsx|js|jsx|mjs|cjs)"];
}
- case "ava": {
- return [
- "test.js",
- "src/test.js",
- "source/test.js",
- "**/test-*.js",
- "**/*.spec.js",
- "**/*.test.js",
- "**/test/**/*.js",
- "**/tests/**/*.js",
- "**/__tests__/**/*.js",
- ];
+ case "svg": {
+ return ["**/*.svg"];
+ }
+ case "toml": {
+ return ["**/*.toml"];
+ }
+ case "ts": {
+ return [...tsGlobal, ...dtsGlobal, ...tsxGlobal];
}
case "vitest": {
return ["**/__tests__/**/*.?(c|m)[jt]s?(x)", "**/?(*.){test,spec}.?(c|m)[jt]s?(x)"];
}
- case "tests": {
- return [
- // ava
- "test.js",
- "src/test.js",
- "source/test.js",
- "**/test-*.js",
- "**/*.spec.js",
- "**/*.test.js",
- "**/test/**/*.js",
- "**/tests/**/*.js",
- "**/__tests__/**/*.js",
-
- // jest
- "**/*.spec.{js,ts,tsx}",
- "**/*.test.{js,ts,tsx}",
- "**/test/*.{js,ts,tsx}",
- "**/__mocks__/*.{js,ts,tsx}",
- "**/__tests__/*.{js,ts,tsx}",
- "**/__tests__/**/*.?(c|m)[jt]s?(x)",
- "**/?(*.){test,spec}.?(c|m)[jt]s?(x)",
- ];
+ case "xml": {
+ return ["**/*.xml"];
}
- case "d.ts": {
- return ["**/*.d.ts"];
- }
- case "postcss": {
- return ["**/postcss.config.js", "**/postcssrc.js", "**/postcss.config.cjs", "**/postcssrc.cjs"];
+ case "yaml": {
+ return ["**/*.yaml", "**/*.yml"];
}
default: {
- throw new Error("Unknown type");
+ throw new Error(`Unknown file type: ${fileType}`);
}
}
};
-export const createConfig = (type: FileType, config: Omit, environment?: Record): Linter.Config => {
- return {
- env: environment,
- overrides: [
- {
- files: getType(type),
- ...config,
- },
- ],
- };
-};
-export const createConfigs = (
- rules: {
- config: Omit;
- type: FileType;
- }[],
-): Linter.Config => {
- return {
- overrides: rules.map(({ config, type }) => {
- return {
- files: getType(type),
- ...config,
- };
- }),
- };
-};
+export const createConfig = (type: FileType, rules: (options: O, files: string[]) => Promise[]>) => async (options: O): Promise => await rules(options, getFilesGlobs(type));
diff --git a/packages/eslint-config/src/utils/eslint-config.ts b/packages/eslint-config/src/utils/eslint-config.ts
deleted file mode 100644
index e1e6ae8af..000000000
--- a/packages/eslint-config/src/utils/eslint-config.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { pkg } from "@anolilab/package-json-utils";
-
-if (!global.anolilabEslintPackageJsonConfig && pkg) {
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-member-access
- global.anolilabEslintPackageJsonConfig = pkg["anolilab"]?.["eslint-config"];
-}
-
-const config: Record = global.anolilabEslintPackageJsonConfig ?? {};
-
-export default config;
diff --git a/packages/eslint-config/src/utils/indent.ts b/packages/eslint-config/src/utils/indent.ts
deleted file mode 100644
index cf1e48e54..000000000
--- a/packages/eslint-config/src/utils/indent.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import anolilabEslintConfig from "./eslint-config";
-
-if (global.anolilabEslintIndent === undefined && anolilabEslintConfig["indent"]) {
- if (Number.isNaN(anolilabEslintConfig["indent"])) {
- throw new TypeError("Indent must be a number");
- }
-
- global.anolilabEslintIndent = Number(anolilabEslintConfig["indent"]);
-} else {
- global.anolilabEslintIndent = 4;
-}
-
-const indent = global.anolilabEslintIndent;
-
-export default indent;
diff --git a/packages/eslint-config/src/utils/interop-default.ts b/packages/eslint-config/src/utils/interop-default.ts
new file mode 100644
index 000000000..164668f49
--- /dev/null
+++ b/packages/eslint-config/src/utils/interop-default.ts
@@ -0,0 +1,10 @@
+import type { Awaitable } from "../types";
+
+const interopDefault = async (m: Awaitable): Promise => {
+ const resolved = await m;
+
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return (resolved as any).default || resolved;
+};
+
+export default interopDefault;
diff --git a/packages/eslint-config/src/utils/is-in-editor-environment.ts b/packages/eslint-config/src/utils/is-in-editor-environment.ts
new file mode 100644
index 000000000..7c8f80915
--- /dev/null
+++ b/packages/eslint-config/src/utils/is-in-editor-environment.ts
@@ -0,0 +1,15 @@
+import isInGitHooksOrLintStaged from "./is-in-git-hooks-or-lint-staged";
+
+const isInEditorEnvironment = (): boolean => {
+ if (process.env["CI"]) {
+ return false;
+ }
+
+ if (isInGitHooksOrLintStaged()) {
+ return false;
+ }
+
+ return !!(process.env["VSCODE_PID"] ?? process.env["VSCODE_CWD"] ?? process.env["JETBRAINS_IDE"] ?? process.env["VIM"] ?? process.env["NVIM"]);
+};
+
+export default isInEditorEnvironment;
diff --git a/packages/eslint-config/src/utils/is-in-editor.ts b/packages/eslint-config/src/utils/is-in-editor.ts
deleted file mode 100644
index 9d05ddae4..000000000
--- a/packages/eslint-config/src/utils/is-in-editor.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-const isInEditor = (process.env["VSCODE_PID"] || process.env["JETBRAINS_IDE"]) && !process.env["CI"];
-
-export default isInEditor;
diff --git a/packages/eslint-config/src/utils/is-in-git-hooks-or-lint-staged.ts b/packages/eslint-config/src/utils/is-in-git-hooks-or-lint-staged.ts
new file mode 100644
index 000000000..7b00ea42a
--- /dev/null
+++ b/packages/eslint-config/src/utils/is-in-git-hooks-or-lint-staged.ts
@@ -0,0 +1,3 @@
+const isInGitHooksOrLintStaged = (): boolean => !!(process.env["GIT_PARAMS"] || process.env["VSCODE_GIT_COMMAND"] || process.env["npm_lifecycle_script"]?.startsWith("lint-staged"));
+
+export default isInGitHooksOrLintStaged;
diff --git a/packages/eslint-config/src/utils/loggers.ts b/packages/eslint-config/src/utils/loggers.ts
deleted file mode 100644
index ef92d8f26..000000000
--- a/packages/eslint-config/src/utils/loggers.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-const noop = () => undefined;
-
-const consolePrefix = (prefix: string) => (process.env["NO_LOGS"] ? noop : (message: string) => console.log(`${prefix}${message}`));
-
-export const consolePlugin = consolePrefix(" eslint-plugin-");
-export const consoleLog = consolePrefix("");
diff --git a/packages/eslint-config/src/utils/parser-plain.ts b/packages/eslint-config/src/utils/parser-plain.ts
new file mode 100644
index 000000000..c914bcd0a
--- /dev/null
+++ b/packages/eslint-config/src/utils/parser-plain.ts
@@ -0,0 +1,26 @@
+import type { Linter } from "eslint";
+
+const parserPlain: Linter.Parser = {
+ meta: {
+ name: "parser-plain",
+ },
+ parseForESLint: (code: string) => {
+ return {
+ ast: {
+ body: [],
+ comments: [],
+ loc: { end: code.length, start: 0 },
+ range: [0, code.length],
+ tokens: [],
+ type: "Program",
+ },
+ scopeManager: undefined,
+ services: { isPlain: true },
+ visitorKeys: {
+ Program: [],
+ },
+ };
+ },
+};
+
+export default parserPlain;
diff --git a/packages/eslint-config/src/vender/prettier-types.ts b/packages/eslint-config/src/vender/prettier-types.ts
new file mode 100644
index 000000000..9097f707b
--- /dev/null
+++ b/packages/eslint-config/src/vender/prettier-types.ts
@@ -0,0 +1,164 @@
+/**
+ * Vendor types from Prettier so we don't rely on the dependency.
+ */
+
+export type BuiltInParserName =
+ | "acorn"
+ | "angular"
+ | "babel-flow"
+ | "babel-ts"
+ | "babel"
+ | "css"
+ | "espree"
+ | "flow"
+ | "glimmer"
+ | "graphql"
+ | "html"
+ | "json-stringify"
+ | "json"
+ | "json5"
+ | "less"
+ | "lwc"
+ | "markdown"
+ | "mdx"
+ | "meriyah"
+ | "scss"
+ | "typescript"
+ | "vue"
+ | "xml"
+ | "yaml";
+
+export type ExternalParserName = "astro" | "slidev";
+
+// This utility is here to handle the case where you have an explicit union
+// between string literals and the generic string type. It would normally
+// resolve out to just the string type, but this generic LiteralUnion maintains
+// the intellisense of the original union.
+//
+// It comes from this issue: microsoft/TypeScript#29729:
+// https://github.com/microsoft/TypeScript/issues/29729#issuecomment-700527227
+export type LiteralUnion = T | (Pick & { _?: never | undefined });
+
+export type VendoredPrettierOptions = Partial;
+
+export interface VendoredPrettierOptionsRequired {
+ /**
+ * Include parentheses around a sole arrow function parameter.
+ * @default "always"
+ */
+ arrowParens: "always" | "avoid";
+ /**
+ * Put the `>` of a multi-line HTML (HTML, XML, JSX, Vue, Angular) element at the end of the last line instead of being
+ * alone on the next line (does not apply to self closing elements).
+ */
+ bracketSameLine: boolean;
+ /**
+ * Print spaces between brackets in object literals.
+ */
+ bracketSpacing: boolean;
+ /**
+ * Which end of line characters to apply.
+ * @default "lf"
+ */
+ endOfLine: "auto" | "cr" | "crlf" | "lf";
+ /**
+ * How to handle whitespaces in HTML.
+ * @default "css"
+ */
+ htmlWhitespaceSensitivity: "css" | "ignore" | "strict";
+ /**
+ * Put the `>` of a multi-line JSX element at the end of the last line instead of being alone on the next line.
+ * @deprecated use bracketSameLine instead
+ */
+ jsxBracketSameLine: boolean;
+ /**
+ * Use single quotes in JSX.
+ */
+ jsxSingleQuote: boolean;
+ /**
+ * Provide ability to support new languages to prettier.
+ */
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ plugins: (any | string)[];
+ /**
+ * Specify the line length that the printer will wrap on.
+ * @default 120
+ */
+ printWidth: number;
+ /**
+ * By default, Prettier will wrap markdown text as-is since some services use a linebreak-sensitive renderer.
+ * In some cases you may want to rely on editor/viewer soft wrapping instead, so this option allows you to opt out.
+ * @default "preserve"
+ */
+ proseWrap: "always" | "never" | "preserve";
+ /**
+ * Change when properties in objects are quoted.
+ * @default "as-needed"
+ */
+ quoteProps: "as-needed" | "consistent" | "preserve";
+ /**
+ * Format only a segment of a file.
+ * @default Number.POSITIVE_INFINITY
+ */
+ rangeEnd: number;
+ /**
+ * Format only a segment of a file.
+ */
+ rangeStart: number;
+ /**
+ * Print semicolons at the ends of statements.
+ */
+ semi: boolean;
+ /**
+ * Enforce single attribute per line in HTML, XML, Vue and JSX.
+ * @default false
+ */
+ singleAttributePerLine: boolean;
+ /**
+ * Use single quotes instead of double quotes.
+ */
+ singleQuote: boolean;
+ /**
+ * Specify the number of spaces per indentation-level.
+ */
+ tabWidth: number;
+ /**
+ * Print trailing commas wherever possible.
+ */
+ trailingComma: "all" | "es5" | "none";
+ /**
+ * Indent lines with tabs instead of spaces
+ */
+ useTabs?: boolean;
+ /**
+ * Whether or not to indent the code inside