Skip to content

Commit 92fcd27

Browse files
committed
feat: add options to generate a flat config
1 parent 9df38b7 commit 92fcd27

File tree

3 files changed

+136
-13
lines changed

3 files changed

+136
-13
lines changed

index.js

+73-13
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,12 @@ export function deepMerge (target, obj) {
5252
// This is also used in `create-vue`
5353
export default function createConfig ({
5454
vueVersion = '3.x', // '2.x' | '3.x' (TODO: 2.7 / vue-demi)
55+
configFormat = 'eslintrc', // eslintrc | flat
5556

56-
styleGuide = 'default', // default | airbnb | typescript
57-
hasTypeScript = false, // js | ts
57+
filePatterns = [], // flat format only - e.g. '**/*.vue', '**/*.js', etc.
58+
59+
styleGuide = 'default', // default | airbnb | standard
60+
hasTypeScript = false, // true | false
5861
needsPrettier = false, // true | false
5962

6063
additionalConfig = {}, // e.g. Cypress, createAliasSetting for Airbnb, etc.
@@ -69,13 +72,18 @@ export default function createConfig ({
6972
addDependency('eslint')
7073
addDependency('eslint-plugin-vue')
7174

72-
if (styleGuide !== 'default' || hasTypeScript || needsPrettier) {
75+
if (configFormat === 'flat') {
76+
addDependency('@eslint/eslintrc')
77+
addDependency('@eslint/js')
78+
} else if (styleGuide !== 'default' || hasTypeScript || needsPrettier) {
7379
addDependency('@rushstack/eslint-patch')
7480
}
7581

7682
const language = hasTypeScript ? 'typescript' : 'javascript'
7783

78-
const eslintConfig = {
84+
const flatConfigExtends = []
85+
const flatConfigImports = []
86+
const eslintrcConfig = {
7987
root: true,
8088
extends: [
8189
vueVersion.startsWith('2')
@@ -85,49 +93,75 @@ export default function createConfig ({
8593
}
8694
const addDependencyAndExtend = (name) => {
8795
addDependency(name)
88-
eslintConfig.extends.push(name)
96+
eslintrcConfig.extends.push(name)
8997
}
9098

9199
switch (`${styleGuide}-${language}`) {
92100
case 'default-javascript':
93-
eslintConfig.extends.push('eslint:recommended')
101+
eslintrcConfig.extends.push('eslint:recommended')
102+
flatConfigImports.push(`import js from '@eslint/js'`)
103+
flatConfigExtends.push('js.configs.recommended')
94104
break
95105
case 'default-typescript':
96-
eslintConfig.extends.push('eslint:recommended')
106+
eslintrcConfig.extends.push('eslint:recommended')
107+
flatConfigImports.push(`import js from '@eslint/js'`)
108+
flatConfigExtends.push('js.configs.recommended')
97109
addDependencyAndExtend('@vue/eslint-config-typescript')
110+
flatConfigExtends.push(`...compat.extends('@vue/eslint-config-typescript')`)
98111
break
99112
case 'airbnb-javascript':
100113
case 'standard-javascript':
101114
addDependencyAndExtend(`@vue/eslint-config-${styleGuide}`)
115+
flatConfigExtends.push(`...compat.extends('@vue/eslint-config-${styleGuide}')`)
102116
break
103117
case 'airbnb-typescript':
104118
case 'standard-typescript':
105119
addDependencyAndExtend(`@vue/eslint-config-${styleGuide}-with-typescript`)
120+
flatConfigExtends.push(`...compat.extends('@vue/eslint-config-${styleGuide}-with-typescript')`)
106121
break
107122
default:
108123
throw new Error(`unexpected combination of styleGuide and language: ${styleGuide}-${language}`)
109124
}
110125

126+
flatConfigImports.push(`import pluginVue from 'eslint-plugin-vue'`)
127+
flatConfigExtends.push(
128+
vueVersion.startsWith('2')
129+
? `...pluginVue.configs['flat/vue2-essential']`
130+
: `...pluginVue.configs['flat/essential']`
131+
)
132+
111133
deepMerge(pkg.devDependencies, additionalDependencies)
112-
deepMerge(eslintConfig, additionalConfig)
134+
deepMerge(eslintrcConfig, additionalConfig)
135+
136+
const flatConfigEntry = {
137+
files: filePatterns
138+
}
139+
deepMerge(flatConfigEntry, additionalConfig)
113140

114141
if (needsPrettier) {
115142
addDependency('prettier')
116143
addDependency('@vue/eslint-config-prettier')
117-
eslintConfig.extends.push('@vue/eslint-config-prettier/skip-formatting')
144+
eslintrcConfig.extends.push('@vue/eslint-config-prettier/skip-formatting')
145+
flatConfigExtends.push(`...compat.extends('@vue/eslint-config-prettier/skip-formatting')`)
118146
}
119147

148+
const configFilename = configFormat === 'flat'
149+
? 'eslint.config.js'
150+
: '.eslintrc.cjs'
120151
const files = {
121-
'.eslintrc.cjs': ''
152+
[configFilename]: ''
122153
}
123154

124155
if (styleGuide === 'default') {
125156
// Both Airbnb & Standard have already set `env: node`
126-
files['.eslintrc.cjs'] += '/* eslint-env node */\n'
157+
files[configFilename] += '/* eslint-env node */\n'
127158

128159
// Both Airbnb & Standard have already set `ecmaVersion`
129160
// The default in eslint-plugin-vue is 2020, which doesn't support top-level await
130-
eslintConfig.parserOptions = {
161+
eslintrcConfig.parserOptions = {
162+
ecmaVersion: 'latest'
163+
}
164+
flatConfigEntry.languageOptions = {
131165
ecmaVersion: 'latest'
132166
}
133167
}
@@ -136,7 +170,33 @@ export default function createConfig ({
136170
files['.eslintrc.cjs'] += "require('@rushstack/eslint-patch/modern-module-resolution')\n\n"
137171
}
138172

139-
files['.eslintrc.cjs'] += `module.exports = ${stringifyJS(eslintConfig, styleGuide)}\n`
173+
// eslint.config.js | .eslintrc.cjs
174+
if (configFormat === 'flat') {
175+
files['eslint.config.js'] += "import path from 'node:path'\n"
176+
files['eslint.config.js'] += "import { fileURLToPath } from 'node:url'\n\n"
177+
178+
flatConfigImports.forEach((pkgImport) => {
179+
files['eslint.config.js'] += `${pkgImport}\n`
180+
})
181+
files['eslint.config.js'] += '\n'
182+
183+
// neccesary for compatibility until all packages support flat config
184+
files['eslint.config.js'] += 'const __filename = fileURLToPath(import.meta.url)\n'
185+
files['eslint.config.js'] += 'const __dirname = path.dirname(__filename)\n'
186+
files['eslint.config.js'] += 'const compat = new FlatCompat({\n'
187+
files['eslint.config.js'] += ' baseDirectory: __dirname\n'
188+
files['eslint.config.js'] += '})\n\n'
189+
190+
files['eslint.config.js'] += 'export default [\n'
191+
flatConfigExtends.forEach((usage) => {
192+
files['eslint.config.js'] += ` ${usage},\n`
193+
})
194+
195+
const [, ...keep] = stringifyJS([flatConfigEntry], styleGuide).split('{')
196+
files['eslint.config.js'] += ` {${keep.join('{')}\n`
197+
} else {
198+
files['.eslintrc.cjs'] += `module.exports = ${stringifyJS(eslintrcConfig, styleGuide)}\n`
199+
}
140200

141201
// .editorconfig & .prettierrc.json
142202
if (editorconfigs[styleGuide]) {

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
"kolorist": "^1.8.0"
3838
},
3939
"devDependencies": {
40+
"@eslint/eslintrc": "^3.0.2",
41+
"@eslint/js": "^9.0.0",
4042
"@rushstack/eslint-patch": "^1.10.1",
4143
"@vue/eslint-config-airbnb": "^8.0.0",
4244
"@vue/eslint-config-airbnb-with-typescript": "^8.0.0",

pnpm-lock.yaml

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

0 commit comments

Comments
 (0)