@@ -15,6 +15,7 @@ import enquirer from "enquirer";
1515import { isPackageTypeModule , installSyncSaveDev , fetchPeerDependencies , findPackageJson } from "./utils/npm-utils.js" ;
1616import { getShorthandName } from "./utils/naming.js" ;
1717import * as log from "./utils/logging.js" ;
18+ import { langQuestions , jsQuestions , mdQuestions , installationQuestions } from "./questions.js" ;
1819
1920//-----------------------------------------------------------------------------
2021// Helpers
@@ -47,6 +48,17 @@ function getExtensions(answers) {
4748 return extensions ;
4849}
4950
51+ const helperContent = `import path from "node:path";
52+ import { fileURLToPath } from "node:url";
53+ import { FlatCompat } from "@eslint/eslintrc";
54+ import js from "@eslint/js";
55+
56+ // mimic CommonJS variables -- not needed if using CommonJS
57+ const __filename = fileURLToPath(import.meta.url);
58+ const __dirname = path.dirname(__filename);
59+ const compat = new FlatCompat({baseDirectory: __dirname, recommendedConfig: js.configs.recommended});
60+ ` ;
61+
5062//-----------------------------------------------------------------------------
5163// Exports
5264//-----------------------------------------------------------------------------
@@ -80,65 +92,15 @@ export class ConfigGenerator {
8092 * @returns {void }
8193 */
8294 async prompt ( ) {
83- const questions = [
84- {
85- type : "select" ,
86- name : "purpose" ,
87- message : "How would you like to use ESLint?" ,
88- initial : 1 ,
89- choices : [
90- { message : "To check syntax only" , name : "syntax" } ,
91- { message : "To check syntax and find problems" , name : "problems" }
92- ]
93- } ,
94- {
95- type : "select" ,
96- name : "moduleType" ,
97- message : "What type of modules does your project use?" ,
98- initial : 0 ,
99- choices : [
100- { message : "JavaScript modules (import/export)" , name : "esm" } ,
101- { message : "CommonJS (require/exports)" , name : "commonjs" } ,
102- { message : "None of these" , name : "script" }
103- ]
104- } ,
105- {
106- type : "select" ,
107- name : "framework" ,
108- message : "Which framework does your project use?" ,
109- initial : 0 ,
110- choices : [
111- { message : "React" , name : "react" } ,
112- { message : "Vue.js" , name : "vue" } ,
113- { message : "None of these" , name : "none" }
114- ]
115- } ,
116- {
117- type : "select" ,
118- name : "language" ,
119- message : "Does your project use TypeScript?" ,
120- choices : [
121- { message : "No" , name : "javascript" } ,
122- { message : "Yes" , name : "typescript" }
123- ] ,
124- initial : 0
125- } ,
126- {
127- type : "multiselect" ,
128- name : "env" ,
129- message : "Where does your code run?" ,
130- hint : "(Press <space> to select, <a> to toggle all, <i> to invert selection)" ,
131- initial : 0 ,
132- choices : [
133- { message : "Browser" , name : "browser" } ,
134- { message : "Node" , name : "node" }
135- ]
136- }
137- ] ;
95+ Object . assign ( this . answers , await enquirer . prompt ( langQuestions ) ) ;
13896
139- const answers = await enquirer . prompt ( questions ) ;
97+ if ( this . answers . languages . includes ( "javascript" ) ) {
98+ Object . assign ( this . answers , await enquirer . prompt ( jsQuestions ) ) ;
99+ }
140100
141- Object . assign ( this . answers , answers ) ;
101+ if ( this . answers . languages . includes ( "md" ) ) {
102+ Object . assign ( this . answers , await enquirer . prompt ( mdQuestions ) ) ;
103+ }
142104 }
143105
144106 /**
@@ -155,45 +117,40 @@ export class ConfigGenerator {
155117 const extensions = `**/*.{${ getExtensions ( this . answers ) } }` ;
156118
157119 let importContent = "import { defineConfig } from \"eslint/config\";\n" ;
158- const helperContent = `import path from "node:path";
159- import { fileURLToPath } from "node:url";
160- import { FlatCompat } from "@eslint/eslintrc";
161- import js from "@eslint/js";
162-
163- // mimic CommonJS variables -- not needed if using CommonJS
164- const __filename = fileURLToPath(import.meta.url);
165- const __dirname = path.dirname(__filename);
166- const compat = new FlatCompat({baseDirectory: __dirname, recommendedConfig: js.configs.recommended});
167- ` ;
168120 let exportContent = "" ;
169121 let needCompatHelper = false ;
122+ const languages = this . answers . languages ?? [ "javascript" ] ;
123+ const purpose = this . answers . purpose ;
124+ const useTs = this . answers . useTs ;
170125
171- if ( this . answers . moduleType === "commonjs" || this . answers . moduleType === "script" ) {
172- exportContent += ` { files: ["**/*.js"], languageOptions: { sourceType: "${ this . answers . moduleType } " } },\n` ;
173- }
126+ if ( languages . includes ( "javascript" ) ) {
127+ if ( this . answers . moduleType === "commonjs" || this . answers . moduleType === "script" ) {
128+ exportContent += ` { files: ["**/*.js"], languageOptions: { sourceType: "${ this . answers . moduleType } " } },\n` ;
129+ }
174130
175- if ( this . answers . env ?. length > 0 ) {
176- this . result . devDependencies . push ( "globals" ) ;
177- importContent += "import globals from \"globals\";\n" ;
178- const envContent = {
179- browser : "globals: globals.browser" ,
180- node : "globals: globals.node" ,
181- "browser,node" : "globals: {...globals.browser, ...globals.node}"
182- } ;
131+ if ( this . answers . env ?. length > 0 ) {
132+ this . result . devDependencies . push ( "globals" ) ;
133+ importContent += "import globals from \"globals\";\n" ;
134+ const envContent = {
135+ browser : "globals: globals.browser" ,
136+ node : "globals: globals.node" ,
137+ "browser,node" : "globals: {...globals.browser, ...globals.node}"
138+ } ;
183139
184- exportContent += ` { files: ["${ extensions } "], languageOptions: { ${ envContent [ this . answers . env . join ( "," ) ] } } },\n` ;
140+ exportContent += ` { files: ["${ extensions } "], languageOptions: { ${ envContent [ this . answers . env . join ( "," ) ] } } },\n` ;
141+ }
185142 }
186143
187- if ( this . answers . purpose === "syntax" ) {
144+ if ( purpose === "syntax" ) {
188145
189146 // no need to install any plugin
190- } else if ( this . answers . purpose === "problems" ) {
147+ } else if ( purpose === "problems" ) {
191148 this . result . devDependencies . push ( "@eslint/js" ) ;
192149 importContent += "import js from \"@eslint/js\";\n" ;
193150 exportContent += ` { files: ["${ extensions } "], plugins: { js }, extends: ["js/recommended"] },\n` ;
194151 }
195152
196- if ( this . answers . language === "typescript" ) {
153+ if ( useTs ) {
197154 this . result . devDependencies . push ( "typescript-eslint" ) ;
198155 importContent += "import tseslint from \"typescript-eslint\";\n" ;
199156 exportContent += " tseslint.configs.recommended,\n" ;
@@ -216,6 +173,53 @@ const compat = new FlatCompat({baseDirectory: __dirname, recommendedConfig: js.c
216173 exportContent += " pluginReact.configs.flat.recommended,\n" ;
217174 }
218175
176+ if ( languages . some ( item => item . startsWith ( "json" ) ) ) {
177+ this . result . devDependencies . push ( "@eslint/json" ) ;
178+ importContent += "import json from \"@eslint/json\";\n" ;
179+ }
180+ if ( languages . includes ( "json" ) ) {
181+ const config = purpose === "syntax"
182+ ? " {files: [\"**/*.json\"], plugins: {json}, language: \"json/json\"},\n"
183+ : " {files: [\"**/*.json\"], language: \"json/json\", ...json.configs.recommended},\n" ;
184+
185+ exportContent += config ;
186+ }
187+ if ( languages . includes ( "jsonc" ) ) {
188+ const config = purpose === "syntax"
189+ ? " {files: [\"**/*.jsonc\"], plugins: {json}, language: \"json/jsonc\"},\n"
190+ : " {files: [\"**/*.jsonc\"], language: \"json/jsonc\", ...json.configs.recommended},\n" ;
191+
192+ exportContent += config ;
193+ }
194+ if ( languages . includes ( "json5" ) ) {
195+ const config = purpose === "syntax"
196+ ? " {files: [\"**/*.json5\"], plugins: {json}, language: \"json/json5\"},\n"
197+ : " {files: [\"**/*.json5\"], language: \"json/json5\", ...json.configs.recommended},\n" ;
198+
199+ exportContent += config ;
200+ }
201+
202+ if ( languages . includes ( "md" ) ) {
203+ this . result . devDependencies . push ( "@eslint/markdown" ) ;
204+ importContent += "import markdown from \"@eslint/markdown\";\n" ;
205+
206+ if ( purpose === "syntax" ) {
207+ const config = this . answers . mdType === "commonmark"
208+ ? " {files: [\"**/*.md\"], plugins: {markdown}, language: \"markdown/commonmark\"},\n"
209+ : " {files: [\"**/*.md\"], plugins: {markdown}, language: \"markdown/gfm\"},\n" ;
210+
211+ exportContent += config ;
212+ } else if ( purpose === "problems" ) {
213+ exportContent += " ...markdown.configs.recommended,\n" ;
214+
215+ if ( this . answers . mdType === "gfm" ) {
216+
217+ // the default is commonmark
218+ exportContent += " {files: [\"**/*.md\"], language: \"markdown/gfm\"},\n" ;
219+ }
220+ }
221+ }
222+
219223 if ( this . answers . config ) {
220224 const config = this . answers . config ;
221225
@@ -274,24 +278,8 @@ export default defineConfig([\n${exportContent || " {}\n"}]);`; // defaults to
274278 log . info ( "The config that you've selected requires the following dependencies:\n" ) ;
275279 log . info ( this . result . devDependencies . join ( ", " ) ) ;
276280
277- const questions = [ {
278- type : "toggle" ,
279- name : "executeInstallation" ,
280- message : "Would you like to install them now?" ,
281- enabled : "Yes" ,
282- disabled : "No" ,
283- initial : 1
284- } , {
285- type : "select" ,
286- name : "packageManager" ,
287- message : "Which package manager do you want to use?" ,
288- initial : 0 ,
289- choices : [ "npm" , "yarn" , "pnpm" , "bun" ] ,
290- skip ( ) {
291- return this . state . answers . executeInstallation === false ;
292- }
293- } ] ;
294- const { executeInstallation, packageManager } = ( await enquirer . prompt ( questions ) ) ;
281+
282+ const { executeInstallation, packageManager } = ( await enquirer . prompt ( installationQuestions ) ) ;
295283 const configPath = path . join ( this . cwd , this . result . configFilename ) ;
296284
297285 if ( executeInstallation === true ) {
0 commit comments