Skip to content

Commit a3625fd

Browse files
authoredMar 29, 2024··
feat(eslint-config): support for multiple src dirs and auto infer directories structure (#370)
1 parent fda2a07 commit a3625fd

File tree

11 files changed

+177
-74
lines changed

11 files changed

+177
-74
lines changed
 

Diff for: ‎eslint.config.js

+16-24
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,22 @@ export default createConfigForNuxt({
66
stylistic: true,
77
},
88
dirs: {
9-
src: 'playground',
10-
pages: [
11-
'playground/pages',
12-
'docs/pages',
13-
],
14-
layouts: [
15-
'playground/layouts',
16-
'docs/layouts',
17-
],
18-
components: [
19-
'playground/components',
20-
'docs/components',
21-
],
22-
},
23-
}).append(
24-
{
25-
ignores: [
26-
'packages-legacy/**',
9+
src: [
10+
'playground',
11+
'docs',
2712
],
2813
},
29-
{
30-
files: ['docs/**/*.vue'],
31-
rules: {
32-
'vue/no-v-html': 'off',
14+
})
15+
.append(
16+
{
17+
ignores: [
18+
'packages-legacy/**',
19+
],
3320
},
34-
},
35-
)
21+
{
22+
files: ['docs/**/*.vue'],
23+
rules: {
24+
'vue/no-v-html': 'off',
25+
},
26+
},
27+
)

Diff for: ‎packages/eslint-config/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"dependencies": {
4040
"@eslint/js": "^8.57.0",
4141
"@nuxt/eslint-plugin": "workspace:*",
42-
"@rushstack/eslint-patch": "^1.9.0",
42+
"@rushstack/eslint-patch": "^1.10.1",
4343
"@stylistic/eslint-plugin": "^1.7.0",
4444
"@typescript-eslint/eslint-plugin": "^7.4.0",
4545
"@typescript-eslint/parser": "^7.4.0",

Diff for: ‎packages/eslint-config/src/flat/configs/disables.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,26 @@ import { join } from 'pathe'
22
import { GLOB_EXTS } from '../constants'
33
import type { NuxtESLintConfigOptions } from '../types'
44
import type { FlatConfigItem } from 'eslint-flat-config-utils'
5+
import { resolveOptions } from '../utils'
56

67
export default function disables(options: NuxtESLintConfigOptions): FlatConfigItem[] {
7-
const dirs = options.dirs ?? {}
8+
const resolved = resolveOptions(options)
9+
const dirs = resolved.dirs
810
const nestedGlobPattern = `**/*.${GLOB_EXTS}`
911

1012
const fileRoutes = [
1113
// These files must have one-word names as they have a special meaning in Nuxt.
12-
...dirs.layers?.flatMap(layersDir => [
14+
...dirs.src.flatMap(layersDir => [
1315
join(layersDir, `app.${GLOB_EXTS}`),
1416
join(layersDir, `error.${GLOB_EXTS}`),
1517
]) || [],
1618

1719
// Layouts and pages are not used directly by users so they can have one-word names.
18-
...(dirs.layouts?.map(layoutsDir => join(layoutsDir, nestedGlobPattern)) || []),
19-
...(dirs.pages?.map(pagesDir => join(pagesDir, nestedGlobPattern)) || []),
20+
...(dirs.layouts.map(layoutsDir => join(layoutsDir, nestedGlobPattern)) || []),
21+
...(dirs.pages.map(pagesDir => join(pagesDir, nestedGlobPattern)) || []),
2022

2123
// These files should have multiple words in their names as they are within subdirectories.
22-
...(dirs.components?.map(componentsDir => join(componentsDir, '*', nestedGlobPattern)) || []),
24+
...(dirs.components.map(componentsDir => join(componentsDir, '*', nestedGlobPattern)) || []),
2325
]
2426

2527
const configs: FlatConfigItem[] = []

Diff for: ‎packages/eslint-config/src/flat/configs/nuxt.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ import type { NuxtESLintConfigOptions } from '../types'
33
import nuxtPlugin from '@nuxt/eslint-plugin'
44
import { GLOB_EXTS } from '../constants'
55
import type { FlatConfigItem } from 'eslint-flat-config-utils'
6+
import { resolveOptions } from '../utils'
67

78
export default function nuxt(options: NuxtESLintConfigOptions): FlatConfigItem[] {
8-
const dirs = options.dirs ?? {}
9+
const resolved = resolveOptions(options)
10+
const dirs = resolved.dirs
911

1012
const fileSingleRoot = [
1113
...(dirs.layouts?.map(layoutsDir => join(layoutsDir, `**/*.${GLOB_EXTS}`)) || []),

Diff for: ‎packages/eslint-config/src/flat/configs/vue.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import * as parserTs from '@typescript-eslint/parser'
44
// @ts-expect-error missing types
55
import pluginVue from 'eslint-plugin-vue'
66
import type { NuxtESLintConfigOptions } from '../types'
7-
import { removeUndefined } from '../utils'
7+
import { removeUndefined, resolveOptions } from '../utils'
88
import type { FlatConfigItem } from 'eslint-flat-config-utils'
99

1010
export default function vue(options: NuxtESLintConfigOptions): FlatConfigItem[] {
11+
const resolved = resolveOptions(options)
12+
1113
return [
1214
{
1315
name: 'nuxt:setup-vue',
@@ -92,7 +94,7 @@ export default function vue(options: NuxtESLintConfigOptions): FlatConfigItem[]
9294
'prefer-spread': 'error', // ts transpiles spread to apply, so no need for manual apply
9395
'valid-typeof': 'off', // ts(2367)
9496

95-
...(options.features?.stylistic
97+
...(resolved.features.stylistic
9698
? {}
9799
: {
98100
// Disable Vue's default stylistic rules when stylistic is not enabled

Diff for: ‎packages/eslint-config/src/flat/index.ts

+9-6
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import stylistic from './configs/stylistic'
99
import type { FlatConfigItem, ResolvableFlatConfig } from 'eslint-flat-config-utils'
1010
import { FlatConfigPipeline } from 'eslint-flat-config-utils'
1111
import { pipe } from 'eslint-flat-config-utils'
12+
import { resolveOptions } from './utils'
1213

1314
export * from './types'
1415

@@ -34,24 +35,26 @@ export function defineFlatConfigs(
3435
export function createConfigForNuxt(options: NuxtESLintConfigOptions = {}): FlatConfigPipeline<FlatConfigItem> {
3536
const pipeline = pipe()
3637

37-
if (options.features?.standalone !== false) {
38+
const resolved = resolveOptions(options)
39+
40+
if (resolved.features.standalone !== false) {
3841
pipeline.append(
3942
base(),
4043
javascript(),
4144
typescript(),
42-
vue(options),
45+
vue(resolved),
4346
)
4447
}
4548

46-
if (options.features?.stylistic) {
49+
if (resolved.features.stylistic) {
4750
pipeline.append(
48-
stylistic(options.features.stylistic === true ? {} : options.features.stylistic),
51+
stylistic(resolved.features.stylistic === true ? {} : resolved.features.stylistic),
4952
)
5053
}
5154

5255
pipeline.append(
53-
nuxt(options),
54-
disables(options),
56+
nuxt(resolved),
57+
disables(resolved),
5558
)
5659

5760
return pipeline

Diff for: ‎packages/eslint-config/src/flat/types.ts

+13-6
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ export interface NuxtESLintConfigOptions {
2626
/**
2727
* Nuxt source directory
2828
*/
29-
src?: string
29+
src?: string[]
30+
31+
/**
32+
* Root directory for nuxt project
33+
*/
34+
root?: string[]
3035

3136
/**
3237
* Directory for pages
@@ -67,12 +72,14 @@ export interface NuxtESLintConfigOptions {
6772
* Directory for server
6873
*/
6974
servers?: string[]
70-
71-
/**
72-
* Directory for layers
73-
*/
74-
layers?: string[]
7575
}
7676
}
7777

78+
type NotNill<T> = T extends null | undefined ? never : T
79+
80+
export interface NuxtESLintConfigOptionsResolved {
81+
features: Required<NotNill<NuxtESLintFeaturesOptions>>
82+
dirs: Required<NotNill<NuxtESLintConfigOptions['dirs']>>
83+
}
84+
7885
export type Awaitable<T> = T | Promise<T>

Diff for: ‎packages/eslint-config/src/flat/utils.ts

+38
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,41 @@
1+
import type { NuxtESLintConfigOptions, NuxtESLintConfigOptionsResolved } from '../flat'
2+
13
export function removeUndefined<T extends object>(obj: T): T {
24
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined)) as T
35
}
6+
7+
export function resolveOptions(
8+
config: NuxtESLintConfigOptions,
9+
): NuxtESLintConfigOptionsResolved {
10+
if ('__resolved' in config) {
11+
return config as NuxtESLintConfigOptionsResolved
12+
}
13+
14+
const dirs = {
15+
...config.dirs,
16+
} as NuxtESLintConfigOptionsResolved['dirs']
17+
18+
dirs.root ||= [process.cwd()]
19+
dirs.src ||= dirs.root
20+
dirs.pages ||= dirs.src.map(src => `${src}/pages`)
21+
dirs.layouts ||= dirs.src.map(src => `${src}/layouts`)
22+
dirs.components ||= dirs.src.map(src => `${src}/components`)
23+
dirs.composables ||= dirs.src.map(src => `${src}/composables`)
24+
dirs.plugins ||= dirs.src.map(src => `${src}/plugins`)
25+
dirs.modules ||= dirs.src.map(src => `${src}/modules`)
26+
dirs.middleware ||= dirs.src.map(src => `${src}/middleware`)
27+
dirs.servers ||= dirs.src.map(src => `${src}/servers`)
28+
29+
const resolved: NuxtESLintConfigOptionsResolved = {
30+
features: {
31+
standalone: true,
32+
stylistic: false,
33+
...config.features,
34+
},
35+
dirs,
36+
}
37+
38+
Object.defineProperty(resolved, '__resolved', { value: true, enumerable: false })
39+
40+
return resolved
41+
}

Diff for: ‎packages/module/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
"@nuxt/kit": "^3.11.1",
5555
"chokidar": "^3.6.0",
5656
"eslint-flat-config-utils": "^0.1.2",
57-
"eslint-flat-config-viewer": "^0.1.14",
58-
"eslint-typegen": "^0.1.5",
57+
"eslint-flat-config-viewer": "^0.1.20",
58+
"eslint-typegen": "^0.1.6",
5959
"get-port-please": "^3.1.2",
6060
"pathe": "^1.1.2",
6161
"unimport": "^3.7.1"

Diff for: ‎packages/module/src/modules/config.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -203,15 +203,15 @@ function getDirs(nuxt: Nuxt): NuxtESLintConfigOptions['dirs'] {
203203
plugins: [],
204204
middleware: [],
205205
modules: [],
206-
layers: [],
207206
servers: [],
208-
src: nuxt.options.srcDir,
207+
root: [nuxt.options.rootDir],
208+
src: [nuxt.options.srcDir],
209209
}
210210

211211
for (const layer of nuxt.options._layers) {
212212
const r = (t: string) => relative(nuxt.options.rootDir, resolve(layer.config.srcDir, t))
213213

214-
dirs.layers.push(r(''))
214+
dirs.src.push(r(''))
215215
dirs.pages.push(r(nuxt.options.dir.pages || 'pages'))
216216
dirs.layouts.push(r(nuxt.options.dir.layouts || 'layouts'))
217217
dirs.plugins.push(r(nuxt.options.dir.plugins || 'plugins'))

Diff for: ‎pnpm-lock.yaml

+81-24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.