Skip to content

Commit ecee627

Browse files
committed
feat(eslint-config)!: make nest and next configs executable to dynamically accept apps
1 parent 57b264f commit ecee627

File tree

3 files changed

+85
-85
lines changed

3 files changed

+85
-85
lines changed

packages/eslint-config/README.md

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,16 @@ Use one of the following configurations in your repository's root `eslint.config
2222

2323
### Base
2424

25+
Suitable for general TypeScript projects.
26+
2527
```javascript
2628
export { base as default } from '@apitree.cz/eslint-config';
2729
```
2830

2931
### React
3032

33+
Necessary for React (JSX/MDX) projects.
34+
3135
```javascript
3236
import { base, react } from '@apitree.cz/eslint-config';
3337

@@ -41,30 +45,29 @@ Next.js configuration requires to specify the path to the app(s).
4145
```javascript
4246
import { base, react, nextjs } from '@apitree.cz/eslint-config';
4347

44-
export default [
45-
...base,
46-
...react,
47-
{
48-
files: ['apps/*/<next-js-app-name>/**/*'],
49-
// or `files: ['**/*.{ts,tsx}']` in single-app repo
50-
...nextjs,
51-
},
52-
];
48+
export default [...base, ...react, ...nextjs(['apps/<nextjs-app>'])];
5349
```
5450

51+
> Omit the apps array if you have a single Next.js app repository (no monorepo).
52+
5553
### Nest.js
5654

5755
Nest.js configuration requires to specify the path to the app(s).
5856

5957
```javascript
6058
import { base, nestjs } from '@apitree.cz/eslint-config';
6159

62-
export default [
63-
...base,
64-
{
65-
files: ['apps/*/<nest-js-app-name>/**/*'],
66-
// or `files: ['**/*.ts']` in single-app repo
67-
...nestjs,
68-
},
69-
];
60+
export default [...base, ...nestjs(['apps/<nestjs-app>'])];
61+
```
62+
63+
> Omit the apps array if you have a single Nest.js app repository (no monorepo).
64+
65+
### Storybook
66+
67+
Necessary for projects containing Storybook instance.
68+
69+
```javascript
70+
import { base, react, storybook } from '@apitree.cz/eslint-config';
71+
72+
export default [...base, ...react, ...storybook];
7073
```
Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,23 @@
1-
import { FlatCompat } from '@eslint/eslintrc';
1+
import type { Linter } from 'eslint';
22

3-
const compat = new FlatCompat({
4-
baseDirectory: import.meta.dirname,
5-
});
6-
7-
export const [config] = compat.config({
8-
overrides: [
9-
{
10-
files: ['src/**/models/**/*.ts'],
11-
rules: {
12-
'import/no-cycle': 'off', // Allow circular dependencies in models as they might reference each other
13-
},
3+
export const config = (apps = ['.']): Linter.Config[] => [
4+
{
5+
files: apps.map((app) => `${app}/src/**/models/**/*.ts`),
6+
rules: {
7+
'import/no-cycle': 'off', // Allow circular dependencies in models as they might reference each other
148
},
15-
{
16-
files: ['src/**/*.ts'],
17-
rules: {
18-
'class-methods-use-this': 'off', // Allow class methods that don't use `this` keyword
19-
'no-empty-function': ['error', { allow: ['constructors'] }], // Allow empty constructors for Nest classes
20-
'@typescript-eslint/consistent-type-imports': 'off', // Allow types being imported without `type` keyword as Nest.js services and models are ambiguous
21-
'@typescript-eslint/no-extraneous-class': [
22-
// Allow classes that are used as Nest decorators
23-
'error',
24-
{ allowWithDecorator: true },
25-
],
26-
},
9+
},
10+
{
11+
files: apps.map((app) => `${app}/src/**/*.ts`),
12+
rules: {
13+
'class-methods-use-this': 'off', // Allow class methods that don't use `this` keyword
14+
'no-empty-function': ['error', { allow: ['constructors'] }], // Allow empty constructors for Nest classes
15+
'@typescript-eslint/consistent-type-imports': 'off', // Allow types being imported without `type` keyword as Nest.js services and models are ambiguous
16+
'@typescript-eslint/no-extraneous-class': [
17+
// Allow classes that are used as Nest decorators
18+
'error',
19+
{ allowWithDecorator: true },
20+
],
2721
},
28-
],
29-
});
22+
},
23+
];
Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,57 @@
11
import { FlatCompat } from '@eslint/eslintrc';
2+
import type { Linter } from 'eslint';
23

34
const compat = new FlatCompat({
45
baseDirectory: import.meta.dirname,
56
});
67

7-
export const [config] = compat.config({
8-
extends: ['plugin:@next/next/recommended'],
9-
plugins: ['@next/next'],
10-
settings: {
11-
next: {
12-
rootDir: process.cwd(),
13-
},
14-
},
15-
overrides: [
16-
{
17-
files: ['next-env.d.ts'],
18-
rules: {
19-
'unicorn/prevent-abbreviations': 'off', // next-env.d.ts is a Next.js convention
8+
export const config = (apps = ['.']): Linter.Config[] => [
9+
...compat.config({
10+
extends: ['plugin:@next/next/recommended'],
11+
plugins: ['@next/next'],
12+
settings: {
13+
next: {
14+
rootDir: process.cwd(),
2015
},
2116
},
22-
{
23-
files: ['src/app/**/*.ts', 'src/app/**/*.tsx', 'src/pages/**/*.ts', 'src/pages/**/*.tsx'],
24-
rules: {
25-
'react/function-component-definition': [
26-
// Allow components as function declarations in Next.js App and Page components for shorthand default exports
27-
'error',
28-
{
29-
namedComponents: ['arrow-function', 'function-declaration'],
30-
unnamedComponents: 'function-expression',
31-
},
32-
],
33-
},
17+
}),
18+
{
19+
files: apps.map((app) => `${app}/next-env.d.ts`),
20+
rules: {
21+
'unicorn/prevent-abbreviations': 'off', // next-env.d.ts is a Next.js convention
3422
},
35-
{
36-
files: ['app/**/layout.tsx', 'src/**/layouts/**/*.tsx'],
37-
rules: {
38-
'@next/next/no-head-element': 'off', // Allow <head/> element in Next.js App layouts
39-
},
23+
},
24+
{
25+
files: apps.map((app) => [`${app}/src/app/**/*.{ts,tsx}`, `${app}/src/pages/**/*.{ts,tsx}`]).flat(),
26+
rules: {
27+
'react/function-component-definition': [
28+
// Allow components as function declarations in Next.js App and Page components for shorthand default exports
29+
'error',
30+
{
31+
namedComponents: ['arrow-function', 'function-declaration'],
32+
unnamedComponents: 'function-expression',
33+
},
34+
],
4035
},
41-
{
42-
files: ['src/**/layouts/**/*.tsx', 'rc/pages/_app.tsx', 'src/pages/_document.tsx'],
43-
rules: {
44-
'react/jsx-props-no-spreading': 'off', // Allow spreading props in Next.js App layouts, _app.tsx and _document.tsx
45-
},
36+
},
37+
{
38+
files: apps.map((app) => [`${app}/app/**/layout.tsx`, `${app}/src/**/layouts/**/*.tsx`]).flat(),
39+
rules: {
40+
'@next/next/no-head-element': 'off', // Allow <head/> element in Next.js App layouts
4641
},
47-
{
48-
files: ['src/**/actions.ts'],
49-
rules: {
50-
'@typescript-eslint/require-await': 'off', // Next.js Server Actions must be async but don't need to await
51-
},
42+
},
43+
{
44+
files: apps
45+
.map((app) => [`${app}/src/**/layouts/**/*.tsx`, `${app}/src/pages/_app.tsx`, `${app}/src/pages/_document.tsx`])
46+
.flat(),
47+
rules: {
48+
'react/jsx-props-no-spreading': 'off', // Allow spreading props in Next.js App layouts, _app.tsx and _document.tsx
5249
},
53-
],
54-
});
50+
},
51+
{
52+
files: apps.map((app) => `${app}/src/**/actions.ts`),
53+
rules: {
54+
'@typescript-eslint/require-await': 'off', // Next.js Server Actions must be async but don't need to await
55+
},
56+
},
57+
];

0 commit comments

Comments
 (0)