diff --git a/bin/create-config.js b/bin/create-config.js old mode 100644 new mode 100755 index b29d8e8e..285f706c --- a/bin/create-config.js +++ b/bin/create-config.js @@ -9,6 +9,6 @@ import { ConfigGenerator } from "../lib/config-generator.js"; const generator = new ConfigGenerator(); -generator.prompt(); +await generator.prompt(); generator.calc(); -generator.output(); +await generator.output(); diff --git a/eslint.config.js b/eslint.config.js index a8293635..b1544b43 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,5 +1,4 @@ import eslintConfigESLint from "eslint-config-eslint"; -import globals from "globals"; export default [ { @@ -8,13 +7,5 @@ export default [ "tests/fixtures/" ] }, - ...eslintConfigESLint, - { - files: ["tests/**"], - languageOptions: { - globals: { - ...globals.mocha - } - } - } + ...eslintConfigESLint ]; diff --git a/lib/config-generator.js b/lib/config-generator.js index df2ca2ec..cec35c11 100644 --- a/lib/config-generator.js +++ b/lib/config-generator.js @@ -7,7 +7,7 @@ import path from "path"; import { spawnSync } from "child_process"; import { writeFile } from "fs/promises"; import enquirer from "enquirer"; -import { isPackageTypeModule, installSyncSaveDev } from "./utils/npm-utils.js"; +import { isPackageTypeModule, installSyncSaveDev, checkPackageJson } from "./utils/npm-utils.js"; import * as log from "./utils/logging.js"; /** @@ -36,16 +36,94 @@ export class ConfigGenerator { * Prompt the user for input. * @returns {void} */ - prompt() { - - // TODO: ask users to input - this.answers = { - purpose: "syntax", - module: "esm", - framework: "vue", - lang: "js", - env: ["browser", "node"] - }; + async prompt() { + const packageJsonExists = checkPackageJson(this.cwd); + + if (!packageJsonExists) { + throw new Error("A package.json file is necessary to initialize ESLint. Run `npm init` to create a package.json file and try again."); + } + + const questions = [ + { + type: "select", + name: "purpose", + message: "How would you like to use ESLint?", + initial: 1, + choices: [ + { message: "To check syntax only", name: "syntax" }, + { message: "To check syntax and find problems", name: "problems" }, + { message: "To check syntax, find problems, and enforce code style", name: "style" } + ] + }, + { + type: "select", + name: "moduleType", + message: "What type of modules does your project use?", + initial: 0, + choices: [ + { message: "JavaScript modules (import/export)", name: "esm" }, + { message: "CommonJS (require/exports)", name: "commonjs" }, + { message: "None of these", name: "none" } + ] + }, + { + type: "select", + name: "framework", + message: "Which framework does your project use?", + initial: 0, + choices: [ + { message: "React", name: "react" }, + { message: "Vue.js", name: "vue" }, + { message: "None of these", name: "none" } + ] + }, + { + type: "select", + name: "language", + message: "Does your project use TypeScript?", + choices: [ + { message: "No", name: "javascript" }, + { message: "Yes", name: "typescript" } + ], + initial: 0 + }, + { + type: "multiselect", + name: "env", + message: "Where does your code run?", + hint: "(Press to select, to toggle all, to invert selection)", + initial: 0, + choices: [ + { message: "Browser", name: "browser" }, + { message: "Node", name: "node" } + ] + } + ]; + + const answers = await enquirer.prompt(questions); + + Object.assign(this.answers, answers); + + if (this.answers.purpose === "style") { + + const jsStyleGuides = [ + { message: "Airbnb: https://github.com/airbnb/javascript", name: "eslint-config-airbnb" }, + { message: "Standard: https://github.com/standard/standard", name: "staeslint-config-standard" }, + { message: "XO: https://github.com/xojs/eslint-config-xo", name: "eslint-config-xo" } + ]; + const tsStyleGuides = [ + { message: "Standard: https://github.com/standard/eslint-config-standard-with-typescript", name: "eslint-config-standard-with-typescript" }, + { message: "XO: https://github.com/xojs/eslint-config-xo-typescript", name: "eslint-config-xo-typescript" } + ]; + const styleguideAnswer = await enquirer.prompt({ + type: "select", + name: "styleguide", + message: "Which style guide do you want to follow?", + choices: this.answers.language === "javascript" ? jsStyleGuides : tsStyleGuides + }); + + Object.assign(this.answers, styleguideAnswer); + } } // eslint-disable-next-line jsdoc/require-throws -- ts is not supported yet @@ -59,6 +137,7 @@ export class ConfigGenerator { this.result.configFilename = isModule ? "eslint.config.js" : "eslint.config.mjs"; let importContent = ""; + let helperContent = ""; let exportContent = ""; let languageOptionsContent = ""; @@ -70,8 +149,17 @@ export class ConfigGenerator { importContent += "import pluginJs from \"@eslint/js\";\n"; exportContent += " pluginJs.configs.recommended,\n"; } else if (this.answers.purpose === "style") { + this.result.devDependencies.push(this.answers.styleguide, "@eslint/js"); + importContent += "import pluginJs from \"@eslint/js\";\n"; + + // importContent += `import styleguide from "${this.answers.styleguide}";\n`; + importContent += "import path from \"path\";\nimport { fileURLToPath } from \"url\"\n;import { FlatCompat } from \"@eslint/eslintrc\";\n"; + helperContent += "// mimic CommonJS variables -- not needed if using CommonJS\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n"; + helperContent += "const compat = new FlatCompat({baseDirectory: __dirname, recommendedConfig: pluginJs.configs.recommended});\n"; + + const extendedName = this.answers.styleguide.replace("eslint-config-", ""); - // TODO: style + exportContent += ` compat.extends("${extendedName}"),\n`; } if (this.answers.module === "commonjs") { @@ -112,7 +200,7 @@ export class ConfigGenerator { exportContent += " pluginReactConfig,\n"; } - this.result.configContent = `${importContent}export default [\n { ${languageOptionsContent}},\n${exportContent}];`; + this.result.configContent = `${importContent}\n${helperContent}\nexport default [].concat(\n { ${languageOptionsContent}},\n${exportContent});`; } /** diff --git a/package.json b/package.json index c2ffac4e..fa079edb 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,6 @@ "test:snapshots": "vitest run snapshots", "test:snapshots:update": "vitest -u run snapshots" }, - "mocha": { - "loader": "esmock", - "ui": "bdd", - "timeout": 10000 - }, "dependencies": { "@eslint/eslintrc": "^1.0.3", "cross-spawn": "^7.0.2", @@ -58,7 +53,7 @@ "c8": "^7.10.0", "chai": "^4.3.4", "cross-env": "^7.0.3", - "eslint": "^8.48.0", + "eslint": "^8.56.0", "eslint-config-eslint": "^9.0.0", "eslint-release": "^3.2.0", "esmock": "^2.5.8",