From 449f0e1d2d557b3811a32a74d3e36e6ed419dd3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=94=AF=E7=84=B6?= Date: Wed, 10 Jan 2024 18:10:26 +0800 Subject: [PATCH] --wip-- [skip ci] --- .editorconfig | 8 + lib/config-generator.js | 43 +- lib/init/config-file.js | 134 ---- lib/init/config-initializer.js | 632 ------------------ lib/shared/logging.js | 25 - lib/utils/npm-utils.js | 5 +- package.json | 4 +- tests/__snapshots__/problem-commonjs--js/esm | 12 + tests/__snapshots__/problem-commonjs--ts/esm | 12 + .../problem-commonjs-react-js/esm | 15 + .../problem-commonjs-react-ts/esm | 15 + .../__snapshots__/problem-commonjs-vue-js/esm | 15 + .../__snapshots__/problem-commonjs-vue-ts/esm | 15 + tests/__snapshots__/problem-esm--js/esm | 11 + tests/__snapshots__/problem-esm--ts/esm | 11 + tests/__snapshots__/problem-esm-react-js/esm | 14 + tests/__snapshots__/problem-esm-react-ts/esm | 14 + tests/__snapshots__/problem-esm-vue-js/esm | 14 + tests/__snapshots__/problem-esm-vue-ts/esm | 14 + tests/__snapshots__/problem-script--js/esm | 11 + tests/__snapshots__/problem-script--ts/esm | 11 + .../__snapshots__/problem-script-react-js/esm | 14 + .../__snapshots__/problem-script-react-ts/esm | 14 + tests/__snapshots__/problem-script-vue-js/esm | 14 + tests/__snapshots__/problem-script-vue-ts/esm | 14 + tests/__snapshots__/syntax-commonjs--js/esm | 9 + tests/__snapshots__/syntax-commonjs--ts/esm | 9 + .../syntax-commonjs-react-js/esm | 12 + .../syntax-commonjs-react-ts/esm | 12 + .../__snapshots__/syntax-commonjs-vue-js/esm | 12 + .../__snapshots__/syntax-commonjs-vue-ts/esm | 12 + tests/__snapshots__/syntax-esm--js/esm | 8 + tests/__snapshots__/syntax-esm--ts/esm | 8 + tests/__snapshots__/syntax-esm-react-js/esm | 11 + tests/__snapshots__/syntax-esm-react-ts/esm | 11 + tests/__snapshots__/syntax-esm-vue-js/esm | 11 + tests/__snapshots__/syntax-esm-vue-ts/esm | 11 + tests/__snapshots__/syntax-script--js/esm | 8 + tests/__snapshots__/syntax-script--ts/esm | 8 + .../__snapshots__/syntax-script-react-js/esm | 11 + .../__snapshots__/syntax-script-react-ts/esm | 11 + tests/__snapshots__/syntax-script-vue-js/esm | 11 + tests/__snapshots__/syntax-script-vue-ts/esm | 11 + tests/config-snapshots.spec.js | 57 ++ tests/fixtures/cjs-project/package.json | 6 + tests/fixtures/esm-project/package.json | 6 + tests/init/config-file.js | 145 ---- tests/init/config-initializer.js | 544 --------------- tests/{init => utils}/npm-utils.js | 8 +- 49 files changed, 542 insertions(+), 1501 deletions(-) create mode 100644 .editorconfig delete mode 100644 lib/init/config-file.js delete mode 100644 lib/init/config-initializer.js delete mode 100644 lib/shared/logging.js create mode 100644 tests/__snapshots__/problem-commonjs--js/esm create mode 100644 tests/__snapshots__/problem-commonjs--ts/esm create mode 100644 tests/__snapshots__/problem-commonjs-react-js/esm create mode 100644 tests/__snapshots__/problem-commonjs-react-ts/esm create mode 100644 tests/__snapshots__/problem-commonjs-vue-js/esm create mode 100644 tests/__snapshots__/problem-commonjs-vue-ts/esm create mode 100644 tests/__snapshots__/problem-esm--js/esm create mode 100644 tests/__snapshots__/problem-esm--ts/esm create mode 100644 tests/__snapshots__/problem-esm-react-js/esm create mode 100644 tests/__snapshots__/problem-esm-react-ts/esm create mode 100644 tests/__snapshots__/problem-esm-vue-js/esm create mode 100644 tests/__snapshots__/problem-esm-vue-ts/esm create mode 100644 tests/__snapshots__/problem-script--js/esm create mode 100644 tests/__snapshots__/problem-script--ts/esm create mode 100644 tests/__snapshots__/problem-script-react-js/esm create mode 100644 tests/__snapshots__/problem-script-react-ts/esm create mode 100644 tests/__snapshots__/problem-script-vue-js/esm create mode 100644 tests/__snapshots__/problem-script-vue-ts/esm create mode 100644 tests/__snapshots__/syntax-commonjs--js/esm create mode 100644 tests/__snapshots__/syntax-commonjs--ts/esm create mode 100644 tests/__snapshots__/syntax-commonjs-react-js/esm create mode 100644 tests/__snapshots__/syntax-commonjs-react-ts/esm create mode 100644 tests/__snapshots__/syntax-commonjs-vue-js/esm create mode 100644 tests/__snapshots__/syntax-commonjs-vue-ts/esm create mode 100644 tests/__snapshots__/syntax-esm--js/esm create mode 100644 tests/__snapshots__/syntax-esm--ts/esm create mode 100644 tests/__snapshots__/syntax-esm-react-js/esm create mode 100644 tests/__snapshots__/syntax-esm-react-ts/esm create mode 100644 tests/__snapshots__/syntax-esm-vue-js/esm create mode 100644 tests/__snapshots__/syntax-esm-vue-ts/esm create mode 100644 tests/__snapshots__/syntax-script--js/esm create mode 100644 tests/__snapshots__/syntax-script--ts/esm create mode 100644 tests/__snapshots__/syntax-script-react-js/esm create mode 100644 tests/__snapshots__/syntax-script-react-ts/esm create mode 100644 tests/__snapshots__/syntax-script-vue-js/esm create mode 100644 tests/__snapshots__/syntax-script-vue-ts/esm create mode 100644 tests/config-snapshots.spec.js create mode 100644 tests/fixtures/cjs-project/package.json create mode 100644 tests/fixtures/esm-project/package.json delete mode 100644 tests/init/config-file.js delete mode 100644 tests/init/config-initializer.js rename tests/{init => utils}/npm-utils.js (97%) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..2e62126f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +end_of_line = lf +insert_final_newline = true diff --git a/lib/config-generator.js b/lib/config-generator.js index 413d3d00..9e3929ef 100644 --- a/lib/config-generator.js +++ b/lib/config-generator.js @@ -3,7 +3,6 @@ * @author 唯然 */ import process from "process"; -import path from "path"; import { writeFile } from "fs/promises"; import { isPackageTypeModule } from "./utils/npm-utils.js"; @@ -11,12 +10,12 @@ import { isPackageTypeModule } from "./utils/npm-utils.js"; * */ export class ConfigGenerator { - constructor(options) { + constructor(options = {}) { this.cwd = options.cwd || process.cwd(); this.answers = options.answers || {}; this.result = { - devDependencies: [], - configPath: "", + devDependencies: ["eslint"], + configFilename: "eslint.config.js", configContent: "" }; } @@ -33,37 +32,53 @@ export class ConfigGenerator { } calc() { - const isModule = isPackageTypeModule(); + const isModule = isPackageTypeModule(this.cwd); - this.result.configPath = path.join(this.cwd, isModule ? "eslint.config.js" : "eslint.config.mjs"); + this.result.configFilename = isModule ? "eslint.config.js" : "eslint.config.mjs"; let importContent = ""; let exportContent = ""; + if (this.answers.purpose === "syntax") { + + // ? + } else if (this.answers.purpose === "problem") { + this.result.devDependencies.push("@eslint/js"); + importContent += `import pluginJs from "@eslint/js";\n`; + exportContent += " pluginJs.configs.recommended,\n"; + } else if (this.answers.purpose === "style") { + + // TODO: style + } + + if (this.answers.module === "commonjs") { + exportContent = ` {languageOption:{sourceType: "commonjs"}},\n${exportContent}`; + } + // TODO: we may need to use "@eslint/eslintrc" as these plugins have not support flat configs yet? if (this.answers.typescript) { this.result.devDependencies.push("@typescript-eslint/eslint-plugin"); - importContent += "import PluginTs from '@typescript-eslint/eslint-plugin';\n"; - exportContent += "PluginTs.configs.recommended,"; + importContent += `import pluginTs from "@typescript-eslint/eslint-plugin";\n`; + exportContent += " pluginTs.configs.recommended,\n"; } if (this.answers.framework === "vue") { this.result.devDependencies.push("eslint-plugin-vue"); - importContent += "import PluginVue from 'eslint-plugin-vue';\n"; - exportContent += "PluginVue.configs.recommended,"; + importContent += `import pluginVue from "eslint-plugin-vue";\n`; + exportContent += " pluginVue.configs.recommended,\n"; } if (this.answers.framework === "react") { this.result.devDependencies.push("eslint-plugin-react"); - importContent += "import PluginReact from 'eslint-plugin-react';\n"; - exportContent += "PluginReact.configs.recommended,"; + importContent += `import pluginReact from "eslint-plugin-react";\n`; + exportContent += " pluginReact.configs.recommended,\n"; } - this.result.configContent = `${importContent}export default [${exportContent}];`; + this.result.configContent = `${importContent}export default [\n${exportContent}];`; } async output() { - await writeFile(this.result.configPath, this.result.configContent); + await writeFile(this.result.configFilename, this.result.configContent); // TODO: install this.result.devDependencies // TODO: is peerDependencies still needed? diff --git a/lib/init/config-file.js b/lib/init/config-file.js deleted file mode 100644 index e8ca0399..00000000 --- a/lib/init/config-file.js +++ /dev/null @@ -1,134 +0,0 @@ -/** - * @fileoverview Helper to locate and load configuration files. - * @author Nicholas C. Zakas - */ - - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -import fs from "fs"; -import path from "path"; -import stringify from "json-stable-stringify-without-jsonify"; -import debugEsm from "debug"; -import spawn from "cross-spawn"; -import * as log from "../shared/logging.js"; - -const debug = debugEsm("eslint:config-file"); -const cwd = process.cwd(); - -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -/** - * Determines sort order for object keys for json-stable-stringify - * - * see: https://github.com/samn/json-stable-stringify#cmp - * @param {Object} a The first comparison object ({key: akey, value: avalue}) - * @param {Object} b The second comparison object ({key: bkey, value: bvalue}) - * @returns {number} 1 or -1, used in stringify cmp method - */ -function sortByKey(a, b) { - return a.key > b.key ? 1 : -1; -} - -//------------------------------------------------------------------------------ -// Private -//------------------------------------------------------------------------------ - -/** - * Writes a configuration file in JSON format. - * @param {Object} config The configuration object to write. - * @param {string} filePath The filename to write to. - * @returns {void} - * @private - */ -function writeJSONConfigFile(config, filePath) { - debug(`Writing JSON config file: ${filePath}`); - - const content = `${stringify(config, { cmp: sortByKey, space: 4 })}\n`; - - fs.writeFileSync(filePath, content, "utf8"); -} - -/** - * Writes a configuration file in YAML format. - * @param {Object} config The configuration object to write. - * @param {string} filePath The filename to write to. - * @returns {void} - * @private - */ -async function writeYAMLConfigFile(config, filePath) { - debug(`Writing YAML config file: ${filePath}`); - - // lazy load YAML to improve performance when not used - const yaml = await import("js-yaml"); - - const content = yaml.dump(config, { sortKeys: true }); - - fs.writeFileSync(filePath, content, "utf8"); -} - -/** - * Writes a configuration file in JavaScript format. - * @param {Object} config The configuration object to write. - * @param {string} filePath The filename to write to. - * @throws {Error} If an error occurs linting the config file contents. - * @returns {void} - * @private - */ -async function writeJSConfigFile(config, filePath) { - debug(`Writing JS config file: ${filePath}`); - - const stringifiedContent = `module.exports = ${stringify(config, { cmp: sortByKey, space: 4 })}\n`; - - fs.writeFileSync(filePath, stringifiedContent, "utf8"); - - // import("eslint") won't work in some cases. - // refs: https://github.com/eslint/create-config/issues/8, https://github.com/eslint/create-config/issues/12 - const eslintBin = path.join(cwd, "./node_modules/.bin/eslint"); - const result = spawn.sync(eslintBin, ["--fix", "--quiet", filePath], { encoding: "utf8" }); - - if (result.error || result.status !== 0) { - log.error("A config file was generated, but the config file itself may not follow your linting rules."); - } -} - -/** - * Writes a configuration file. - * @param {Object} config The configuration object to write. - * @param {string} filePath The filename to write to. - * @returns {void} - * @throws {Error} When an unknown file type is specified. - * @private - */ -async function write(config, filePath) { - switch (path.extname(filePath)) { - case ".js": - case ".cjs": - await writeJSConfigFile(config, filePath); - break; - - case ".json": - writeJSONConfigFile(config, filePath); - break; - - case ".yaml": - case ".yml": - await writeYAMLConfigFile(config, filePath); - break; - - default: - throw new Error("Can't write to unknown file type."); - } -} - -//------------------------------------------------------------------------------ -// Public Interface -//------------------------------------------------------------------------------ - -export { - write -}; diff --git a/lib/init/config-initializer.js b/lib/init/config-initializer.js deleted file mode 100644 index fe0dc921..00000000 --- a/lib/init/config-initializer.js +++ /dev/null @@ -1,632 +0,0 @@ -/** - * @fileoverview Config initialization wizard. - * @author Ilya Volodin - */ - - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -import path from "path"; -import fs from "fs"; -import enquirer from "enquirer"; -import semver from "semver"; -import { Legacy } from "@eslint/eslintrc"; -import { info } from "../shared/logging.js"; -import * as ConfigFile from "./config-file.js"; -import * as npmUtils from "./npm-utils.js"; -import mri from "mri"; - -const { ConfigOps, naming, ModuleResolver } = Legacy; - -//------------------------------------------------------------------------------ -// Private -//------------------------------------------------------------------------------ - -/** - * check if the package.type === "module" - * @returns {boolean} return true if the package.type === "module" - */ -function isPackageTypeModule() { - const pkgJSONPath = npmUtils.findPackageJson(); - - if (pkgJSONPath) { - const pkgJSONContents = JSON.parse(fs.readFileSync(pkgJSONPath, "utf8")); - - if (pkgJSONContents.type === "module") { - return true; - } - } - - return false; -} - -/* istanbul ignore next: hard to test fs function */ -/** - * Create .eslintrc file in the current working directory - * @param {Object} config object that contains user's answers - * @param {string} format The file format to write to. - * @returns {void} - */ -async function writeFile(config, format) { - - // default is .js - let extname = ".js"; - - if (format === "YAML") { - extname = ".yml"; - } else if (format === "JSON") { - extname = ".json"; - } else if (format === "JavaScript") { - if (isPackageTypeModule()) { - extname = ".cjs"; - } - } - - delete config.installedESLint; - - await ConfigFile.write(config, `./.eslintrc${extname}`); - info(`Successfully created .eslintrc${extname} file in ${process.cwd()}`); -} - -/** - * Get the peer dependencies of the given module. - * This adds the gotten value to cache at the first time, then reuses it. - * In a process, this function is called twice, but `npmUtils.fetchPeerDependencies` needs to access network which is relatively slow. - * @param {string} moduleName The module name to get. - * @returns {Object} The peer dependencies of the given module. - * This object is the object of `peerDependencies` field of `package.json`. - * Returns null if npm was not found. - */ -function getPeerDependencies(moduleName) { - let result = getPeerDependencies.cache.get(moduleName); - - if (!result) { - info(`Checking peerDependencies of ${moduleName}`); - - result = npmUtils.fetchPeerDependencies(moduleName); - getPeerDependencies.cache.set(moduleName, result); - } - - return result; -} -getPeerDependencies.cache = new Map(); - -/** - * Return necessary plugins, configs, parsers, etc. based on the config - * @param {Object} config config object - * @param {boolean} [installESLint=true] If `false` is given, it does not install eslint. - * @returns {string[]} An array of modules to be installed. - */ -function getModulesList(config, installESLint) { - const modules = {}; - - // Create a list of modules which should be installed based on config - if (config.plugins) { - for (const plugin of config.plugins) { - const moduleName = naming.normalizePackageName(plugin, "eslint-plugin"); - - modules[moduleName] = "latest"; - } - } - - const extendList = []; - const overrides = config.overrides || []; - - for (const item of [config, ...overrides]) { - if (typeof item.extends === "string") { - extendList.push(item.extends); - } else if (Array.isArray(item.extends)) { - extendList.push(...item.extends); - } - } - - for (const extend of extendList) { - if (extend.startsWith("eslint:") || extend.startsWith("plugin:")) { - continue; - } - const moduleName = naming.normalizePackageName(extend, "eslint-config"); - - modules[moduleName] = "latest"; - Object.assign( - modules, - getPeerDependencies(`${moduleName}@latest`) - ); - } - - const parser = config.parser || (config.parserOptions && config.parserOptions.parser); - - if (parser) { - modules[parser] = "latest"; - } - - if (installESLint === false) { - delete modules.eslint; - } else { - const installStatus = npmUtils.checkDevDeps(["eslint"]); - - // Mark to show messages if it's new installation of eslint. - if (installStatus.eslint === false) { - info("Local ESLint installation not found."); - modules.eslint = modules.eslint || "latest"; - config.installedESLint = true; - } - } - - return Object.keys(modules).map(name => `${name}@${modules[name]}`); -} - -/** - * process user's answers and create config object - * @param {Object} answers answers received from enquirer - * @returns {Object} config object - */ -function processAnswers(answers) { - const config = { - rules: {}, - env: {}, - parserOptions: {}, - extends: [], - plugins: [], - overrides: [] - }; - - config.parserOptions.ecmaVersion = "latest"; - config.env.es2021 = true; - - if (answers.format === "JavaScript") { - config.overrides.push({ - files: [".eslintrc.{js,cjs}"], - parserOptions: { sourceType: "script" }, - env: { node: true } - }); - } - - // set the module type - if (answers.moduleType === "esm") { - config.parserOptions.sourceType = "module"; - } else if (answers.moduleType === "commonjs") { - config.env.commonjs = true; - } - - // add in browser and node environments if necessary - answers.env.forEach(env => { - config.env[env] = true; - }); - - // if answers.source == "guide", the ts supports should be in the shared config. - if (answers.typescript && answers.source !== "guide") { - - // .vue files should be parsed by vue-eslint-parser. - // https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser - if (answers.framework === "vue") { - config.parserOptions.parser = "@typescript-eslint/parser"; - } else { - config.parser = "@typescript-eslint/parser"; - } - - config.plugins.push("@typescript-eslint"); - } - - // set config.extends based the selected guide - if (answers.source === "guide") { - if (answers.styleguide === "airbnb" && answers.framework !== "react") { - config.extends.push("airbnb-base"); - } else if (answers.styleguide === "xo-typescript") { - config.extends.push("xo"); - config.overrides.push({ - files: ["*.ts", "*.tsx"], - extends: ["xo-typescript"] - }); - } else { - config.extends.push(answers.styleguide); - } - } - - // setup rules based on problems/style enforcement preferences - if (answers.purpose === "problems") { - config.extends.unshift("eslint:recommended"); - } else if (answers.purpose === "style") { - if (answers.source === "prompt") { - config.extends.unshift("eslint:recommended"); - config.rules.indent = ["error", answers.indent]; - config.rules.quotes = ["error", answers.quotes]; - config.rules["linebreak-style"] = ["error", answers.linebreak]; - config.rules.semi = ["error", answers.semi ? "always" : "never"]; - } - } - if (answers.typescript && config.extends.includes("eslint:recommended")) { - config.extends.push("plugin:@typescript-eslint/recommended"); - } - - // add in library information - // The configuration of the framework plugins should be placed at the end of extends. - if (answers.framework === "react" && answers.styleguide !== "airbnb") { - config.plugins.push("react"); - config.extends.push("plugin:react/recommended"); - } else if (answers.framework === "vue") { - config.plugins.push("vue"); - config.extends.push("plugin:vue/vue3-essential"); - } - - // normalize extends - if (config.extends.length === 0) { - delete config.extends; - } else if (config.extends.length === 1) { - config.extends = config.extends[0]; - } - if (config.overrides.length === 0) { - delete config.overrides; - } - if (config.plugins.length === 0) { - delete config.plugins; - } - - ConfigOps.normalizeToStrings(config); - return config; -} - -/** - * Get the version of the local ESLint. - * @returns {string|null} The version. If the local ESLint was not found, returns null. - */ -function getLocalESLintVersion() { - try { - const eslintPkgPath = path.join(ModuleResolver.resolve("eslint/package.json", path.join(process.cwd(), "__placeholder__.js"))); - const eslintPkg = JSON.parse(fs.readFileSync(eslintPkgPath, "utf8")); - - return eslintPkg.version || null; - } catch { - return null; - } -} - -/** - * Get the shareable config name of the chosen style guide. - * @param {Object} answers The answers object. - * @returns {string} The shareable config name. - */ -function getStyleGuideName(answers) { - if (answers.styleguide === "airbnb" && answers.framework !== "react") { - return "airbnb-base"; - } - return answers.styleguide; -} - -/** - * Check whether the local ESLint version conflicts with the required version of the chosen shareable config. - * @param {Object} answers The answers object. - * @returns {boolean} `true` if the local ESLint is found then it conflicts with the required version of the chosen shareable config. - */ -function hasESLintVersionConflict(answers) { - - // Get the local ESLint version. - const localESLintVersion = getLocalESLintVersion(); - - if (!localESLintVersion) { - return false; - } - - // Get the required range of ESLint version. - const configName = getStyleGuideName(answers); - const moduleName = `eslint-config-${configName}@latest`; - const peerDependencies = getPeerDependencies(moduleName) || {}; - const requiredESLintVersionRange = peerDependencies.eslint; - - if (!requiredESLintVersionRange) { - return false; - } - - answers.localESLintVersion = localESLintVersion; - answers.requiredESLintVersionRange = requiredESLintVersionRange; - - // Check the version. - if (semver.satisfies(localESLintVersion, requiredESLintVersionRange)) { - answers.installESLint = false; - return false; - } - - return true; -} - -/** - * Install modules. - * @param {string[]} modules Modules to be installed. - * @param {string} packageManager Package manager to use for installation. - * @returns {void} - */ -function installModules(modules, packageManager) { - info(`Installing ${modules.join(", ")}`); - npmUtils.installSyncSaveDev(modules, packageManager); -} - -/* istanbul ignore next: no need to test enquirer */ -/** - * Ask user to install modules. - * @param {string[]} modules Array of modules to be installed. - * @returns {Promise} Answer that indicates if user wants to install. - */ -function askInstallModules(modules) { - - // If no modules, do nothing. - if (modules.length === 0) { - return Promise.resolve(); - } - - info("The config that you've selected requires the following dependencies:\n"); - info(modules.join(" ")); - return enquirer.prompt([ - { - type: "toggle", - name: "executeInstallation", - message: "Would you like to install them now?", - enabled: "Yes", - disabled: "No", - initial: 1, - skip() { - return !modules.length; - }, - result(input) { - return this.skipped ? null : input; - } - }, - { - type: "select", - name: "packageManager", - message: "Which package manager do you want to use?", - initial: 0, - choices: ["npm", "yarn", "pnpm", "bun"], - skip() { - return !this.state.answers.executeInstallation; - } - } - ]).then(({ executeInstallation, packageManager }) => { - if (executeInstallation) { - installModules(modules, packageManager); - } - }); -} - -/* istanbul ignore next: no need to test enquirer */ -/** - * Ask use a few questions on command prompt - * @returns {Promise} The promise with the result of the prompt - * @throws {Error} If `package.json` file doesn't exist. - */ -function promptUser() { - const packageJsonExists = npmUtils.checkPackageJson(); - - 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 styleGuides = []; - - return enquirer.prompt([ - { - type: "select", - name: "purpose", - message: "How would you like to use ESLint?", - - // The returned number matches the name value of nth in the choices array. - 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: "toggle", - name: "typescript", - message: "Does your project use TypeScript?", - enabled: "Yes", - disabled: "No", - initial: 0, - result(val) { - if (val) { - - // remove airbnb/google javascript style guide, as they do not support ts - styleGuides.push( - { message: "Standard: https://github.com/standard/eslint-config-standard-with-typescript", name: "standard-with-typescript" }, - { message: "XO: https://github.com/xojs/eslint-config-xo-typescript", name: "xo-typescript" } - ); - } else { - styleGuides.push( - { message: "Airbnb: https://github.com/airbnb/javascript", name: "airbnb" }, - { message: "Standard: https://github.com/standard/standard", name: "standard" }, - { message: "Google: https://github.com/google/eslint-config-google", name: "google" }, - { message: "XO: https://github.com/xojs/eslint-config-xo", name: "xo" } - ); - } - return val; - } - }, - { - 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" } - ] - }, - { - type: "select", - name: "source", - message: "How would you like to define a style for your project?", - choices: [ - { message: "Use a popular style guide", name: "guide" }, - { message: "Answer questions about your style", name: "prompt" } - ], - skip() { - return this.state.answers.purpose !== "style"; - }, - result(input) { - return this.skipped ? null : input; - } - }, - { - type: "select", - name: "styleguide", - message: "Which style guide do you want to follow?", - choices: styleGuides, - skip() { - return this.state.answers.source !== "guide"; - }, - result(input) { - return this.skipped ? null : input; - } - }, - { - type: "select", - name: "format", - message: "What format do you want your config file to be in?", - initial: 0, - choices: ["JavaScript", "YAML", "JSON"] - }, - { - type: "toggle", - name: "installESLint", - message() { - const { answers } = this.state; - const verb = semver.ltr(answers.localESLintVersion, answers.requiredESLintVersionRange) - ? "upgrade" - : "downgrade"; - - return `The style guide "${answers.styleguide}" requires eslint@${answers.requiredESLintVersionRange}. You are currently using eslint@${answers.localESLintVersion}.\n Do you want to ${verb}?`; - }, - enabled: "Yes", - disabled: "No", - initial: 1, - skip() { - return !(this.state.answers.source === "guide" && hasESLintVersionConflict(this.state.answers)); - }, - result(input) { - return this.skipped ? null : input; - } - } - ]).then(earlyAnswers => { - - // early exit if no style guide is necessary - if (earlyAnswers.purpose !== "style") { - const config = processAnswers(earlyAnswers); - const modules = getModulesList(config); - - return askInstallModules(modules) - .then(() => writeFile(config, earlyAnswers.format)); - } - - // early exit if you are using a style guide - if (earlyAnswers.source === "guide") { - if (earlyAnswers.installESLint === false && !semver.satisfies(earlyAnswers.localESLintVersion, earlyAnswers.requiredESLintVersionRange)) { - info(`Note: it might not work since ESLint's version is mismatched with the ${earlyAnswers.styleguide} config.`); - } - - const config = processAnswers(earlyAnswers); - const modules = getModulesList(config); - - return askInstallModules(modules) - .then(() => writeFile(config, earlyAnswers.format)); - - } - - // continue with the style questions otherwise... - return enquirer.prompt([ - { - type: "select", - name: "indent", - message: "What style of indentation do you use?", - initial: 0, - choices: [{ message: "Tabs", name: "tab" }, { message: "Spaces", name: 4 }] - }, - { - type: "select", - name: "quotes", - message: "What quotes do you use for strings?", - initial: 0, - choices: [{ message: "Double", name: "double" }, { message: "Single", name: "single" }] - }, - { - type: "select", - name: "linebreak", - message: "What line endings do you use?", - initial: 0, - choices: [{ message: "Unix", name: "unix" }, { message: "Windows", name: "windows" }] - }, - { - type: "toggle", - name: "semi", - message: "Do you require semicolons?", - enabled: "Yes", - disabled: "No", - initial: 1 - } - ]).then(answers => { - const totalAnswers = Object.assign({}, earlyAnswers, answers); - - const config = processAnswers(totalAnswers); - const modules = getModulesList(config); - - return askInstallModules(modules).then(() => writeFile(config, earlyAnswers.format)); - }); - }); -} - -/* istanbul ignore next */ -/** - * an wrapper for promptUser - * @returns {void} - */ -function initializeConfig() { - const argv = mri(process.argv.slice(2)); - - if (argv.config) { - const config = { - extends: typeof argv.config === "string" ? argv.config.split(",") : argv.config - }; - const modules = getModulesList(config); - - return askInstallModules(modules).then(() => writeFile(config, "JavaScript")); - } - - return promptUser(); -} - -//------------------------------------------------------------------------------ -// Public Interface -//------------------------------------------------------------------------------ - -export { - getModulesList, - hasESLintVersionConflict, - installModules, - processAnswers, - writeFile, - initializeConfig -}; diff --git a/lib/shared/logging.js b/lib/shared/logging.js deleted file mode 100644 index 4cedc861..00000000 --- a/lib/shared/logging.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @fileoverview Handle logging for ESLint - * @author Gyandeep Singh - */ - - -/* eslint no-console: "off" -- Logging util */ - -/** - * Cover for console.log - * @param {...any} args The elements to log. - * @returns {void} - */ -export function info(...args) { - console.log(...args); -} - -/** - * Cover for console.error - * @param {...any} args The elements to log. - * @returns {void} - */ -export function error(...args) { - console.error(...args); -} diff --git a/lib/utils/npm-utils.js b/lib/utils/npm-utils.js index f5d88626..805daae0 100644 --- a/lib/utils/npm-utils.js +++ b/lib/utils/npm-utils.js @@ -157,10 +157,11 @@ function checkPackageJson(startDir) { /** * check if the package.type === "module" + * @param {string} [cwd] The current working directory * @returns {boolean} return true if the package.type === "module" */ -function isPackageTypeModule() { - const pkgJSONPath = findPackageJson(); +function isPackageTypeModule(cwd) { + const pkgJSONPath = findPackageJson(cwd); if (pkgJSONPath) { const pkgJSONContents = JSON.parse(fs.readFileSync(pkgJSONPath, "utf8")); diff --git a/package.json b/package.json index fdccdfae..2a7404d8 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "release:generate:beta": "eslint-generate-prerelease beta", "release:generate:rc": "eslint-generate-prerelease rc", "release:publish": "eslint-publish-release", - "test": "c8 mocha \"tests/init/**/*.js\"" + "test": "c8 mocha \"tests/utils/**/*.js\"", + "debug": "vitest snapshots" }, "mocha": { "loader": "esmock", @@ -68,6 +69,7 @@ "mocha": "^9.1.3", "shelljs": "^0.8.4", "sinon": "^12.0.1", + "vitest": "^1.1.1", "yorkie": "^2.0.0" }, "engines": { diff --git a/tests/__snapshots__/problem-commonjs--js/esm b/tests/__snapshots__/problem-commonjs--js/esm new file mode 100644 index 00000000..9144f840 --- /dev/null +++ b/tests/__snapshots__/problem-commonjs--js/esm @@ -0,0 +1,12 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginJs.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-commonjs--ts/esm b/tests/__snapshots__/problem-commonjs--ts/esm new file mode 100644 index 00000000..9144f840 --- /dev/null +++ b/tests/__snapshots__/problem-commonjs--ts/esm @@ -0,0 +1,12 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginJs.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-commonjs-react-js/esm b/tests/__snapshots__/problem-commonjs-react-js/esm new file mode 100644 index 00000000..40f2fa1a --- /dev/null +++ b/tests/__snapshots__/problem-commonjs-react-js/esm @@ -0,0 +1,15 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginReact from "eslint-plugin-react"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginJs.configs.recommended, + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-commonjs-react-ts/esm b/tests/__snapshots__/problem-commonjs-react-ts/esm new file mode 100644 index 00000000..40f2fa1a --- /dev/null +++ b/tests/__snapshots__/problem-commonjs-react-ts/esm @@ -0,0 +1,15 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginReact from "eslint-plugin-react"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginJs.configs.recommended, + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-commonjs-vue-js/esm b/tests/__snapshots__/problem-commonjs-vue-js/esm new file mode 100644 index 00000000..84e70695 --- /dev/null +++ b/tests/__snapshots__/problem-commonjs-vue-js/esm @@ -0,0 +1,15 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginVue from "eslint-plugin-vue"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginJs.configs.recommended, + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-commonjs-vue-ts/esm b/tests/__snapshots__/problem-commonjs-vue-ts/esm new file mode 100644 index 00000000..84e70695 --- /dev/null +++ b/tests/__snapshots__/problem-commonjs-vue-ts/esm @@ -0,0 +1,15 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginVue from "eslint-plugin-vue"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginJs.configs.recommended, + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-esm--js/esm b/tests/__snapshots__/problem-esm--js/esm new file mode 100644 index 00000000..79da49c2 --- /dev/null +++ b/tests/__snapshots__/problem-esm--js/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +export default [ + pluginJs.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-esm--ts/esm b/tests/__snapshots__/problem-esm--ts/esm new file mode 100644 index 00000000..79da49c2 --- /dev/null +++ b/tests/__snapshots__/problem-esm--ts/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +export default [ + pluginJs.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-esm-react-js/esm b/tests/__snapshots__/problem-esm-react-js/esm new file mode 100644 index 00000000..208cc8c8 --- /dev/null +++ b/tests/__snapshots__/problem-esm-react-js/esm @@ -0,0 +1,14 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginReact from "eslint-plugin-react"; +export default [ + pluginJs.configs.recommended, + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-esm-react-ts/esm b/tests/__snapshots__/problem-esm-react-ts/esm new file mode 100644 index 00000000..208cc8c8 --- /dev/null +++ b/tests/__snapshots__/problem-esm-react-ts/esm @@ -0,0 +1,14 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginReact from "eslint-plugin-react"; +export default [ + pluginJs.configs.recommended, + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-esm-vue-js/esm b/tests/__snapshots__/problem-esm-vue-js/esm new file mode 100644 index 00000000..b675dbf9 --- /dev/null +++ b/tests/__snapshots__/problem-esm-vue-js/esm @@ -0,0 +1,14 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginVue from "eslint-plugin-vue"; +export default [ + pluginJs.configs.recommended, + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-esm-vue-ts/esm b/tests/__snapshots__/problem-esm-vue-ts/esm new file mode 100644 index 00000000..b675dbf9 --- /dev/null +++ b/tests/__snapshots__/problem-esm-vue-ts/esm @@ -0,0 +1,14 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginVue from "eslint-plugin-vue"; +export default [ + pluginJs.configs.recommended, + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-script--js/esm b/tests/__snapshots__/problem-script--js/esm new file mode 100644 index 00000000..79da49c2 --- /dev/null +++ b/tests/__snapshots__/problem-script--js/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +export default [ + pluginJs.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-script--ts/esm b/tests/__snapshots__/problem-script--ts/esm new file mode 100644 index 00000000..79da49c2 --- /dev/null +++ b/tests/__snapshots__/problem-script--ts/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +export default [ + pluginJs.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-script-react-js/esm b/tests/__snapshots__/problem-script-react-js/esm new file mode 100644 index 00000000..208cc8c8 --- /dev/null +++ b/tests/__snapshots__/problem-script-react-js/esm @@ -0,0 +1,14 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginReact from "eslint-plugin-react"; +export default [ + pluginJs.configs.recommended, + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-script-react-ts/esm b/tests/__snapshots__/problem-script-react-ts/esm new file mode 100644 index 00000000..208cc8c8 --- /dev/null +++ b/tests/__snapshots__/problem-script-react-ts/esm @@ -0,0 +1,14 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginReact from "eslint-plugin-react"; +export default [ + pluginJs.configs.recommended, + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-script-vue-js/esm b/tests/__snapshots__/problem-script-vue-js/esm new file mode 100644 index 00000000..b675dbf9 --- /dev/null +++ b/tests/__snapshots__/problem-script-vue-js/esm @@ -0,0 +1,14 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginVue from "eslint-plugin-vue"; +export default [ + pluginJs.configs.recommended, + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/problem-script-vue-ts/esm b/tests/__snapshots__/problem-script-vue-ts/esm new file mode 100644 index 00000000..b675dbf9 --- /dev/null +++ b/tests/__snapshots__/problem-script-vue-ts/esm @@ -0,0 +1,14 @@ +{ + "configContent": "import pluginJs from "@eslint/js"; +import pluginVue from "eslint-plugin-vue"; +export default [ + pluginJs.configs.recommended, + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "@eslint/js", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-commonjs--js/esm b/tests/__snapshots__/syntax-commonjs--js/esm new file mode 100644 index 00000000..8a90106e --- /dev/null +++ b/tests/__snapshots__/syntax-commonjs--js/esm @@ -0,0 +1,9 @@ +{ + "configContent": "export default [ + {languageOption:{sourceType: "commonjs"}}, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-commonjs--ts/esm b/tests/__snapshots__/syntax-commonjs--ts/esm new file mode 100644 index 00000000..8a90106e --- /dev/null +++ b/tests/__snapshots__/syntax-commonjs--ts/esm @@ -0,0 +1,9 @@ +{ + "configContent": "export default [ + {languageOption:{sourceType: "commonjs"}}, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-commonjs-react-js/esm b/tests/__snapshots__/syntax-commonjs-react-js/esm new file mode 100644 index 00000000..61047b0f --- /dev/null +++ b/tests/__snapshots__/syntax-commonjs-react-js/esm @@ -0,0 +1,12 @@ +{ + "configContent": "import pluginReact from "eslint-plugin-react"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-commonjs-react-ts/esm b/tests/__snapshots__/syntax-commonjs-react-ts/esm new file mode 100644 index 00000000..61047b0f --- /dev/null +++ b/tests/__snapshots__/syntax-commonjs-react-ts/esm @@ -0,0 +1,12 @@ +{ + "configContent": "import pluginReact from "eslint-plugin-react"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-commonjs-vue-js/esm b/tests/__snapshots__/syntax-commonjs-vue-js/esm new file mode 100644 index 00000000..cbcde114 --- /dev/null +++ b/tests/__snapshots__/syntax-commonjs-vue-js/esm @@ -0,0 +1,12 @@ +{ + "configContent": "import pluginVue from "eslint-plugin-vue"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-commonjs-vue-ts/esm b/tests/__snapshots__/syntax-commonjs-vue-ts/esm new file mode 100644 index 00000000..cbcde114 --- /dev/null +++ b/tests/__snapshots__/syntax-commonjs-vue-ts/esm @@ -0,0 +1,12 @@ +{ + "configContent": "import pluginVue from "eslint-plugin-vue"; +export default [ + {languageOption:{sourceType: "commonjs"}}, + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-esm--js/esm b/tests/__snapshots__/syntax-esm--js/esm new file mode 100644 index 00000000..7e79bdb3 --- /dev/null +++ b/tests/__snapshots__/syntax-esm--js/esm @@ -0,0 +1,8 @@ +{ + "configContent": "export default [ +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-esm--ts/esm b/tests/__snapshots__/syntax-esm--ts/esm new file mode 100644 index 00000000..7e79bdb3 --- /dev/null +++ b/tests/__snapshots__/syntax-esm--ts/esm @@ -0,0 +1,8 @@ +{ + "configContent": "export default [ +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-esm-react-js/esm b/tests/__snapshots__/syntax-esm-react-js/esm new file mode 100644 index 00000000..7cd465f3 --- /dev/null +++ b/tests/__snapshots__/syntax-esm-react-js/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginReact from "eslint-plugin-react"; +export default [ + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-esm-react-ts/esm b/tests/__snapshots__/syntax-esm-react-ts/esm new file mode 100644 index 00000000..7cd465f3 --- /dev/null +++ b/tests/__snapshots__/syntax-esm-react-ts/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginReact from "eslint-plugin-react"; +export default [ + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-esm-vue-js/esm b/tests/__snapshots__/syntax-esm-vue-js/esm new file mode 100644 index 00000000..bdc6d75a --- /dev/null +++ b/tests/__snapshots__/syntax-esm-vue-js/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginVue from "eslint-plugin-vue"; +export default [ + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-esm-vue-ts/esm b/tests/__snapshots__/syntax-esm-vue-ts/esm new file mode 100644 index 00000000..bdc6d75a --- /dev/null +++ b/tests/__snapshots__/syntax-esm-vue-ts/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginVue from "eslint-plugin-vue"; +export default [ + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-script--js/esm b/tests/__snapshots__/syntax-script--js/esm new file mode 100644 index 00000000..7e79bdb3 --- /dev/null +++ b/tests/__snapshots__/syntax-script--js/esm @@ -0,0 +1,8 @@ +{ + "configContent": "export default [ +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-script--ts/esm b/tests/__snapshots__/syntax-script--ts/esm new file mode 100644 index 00000000..7e79bdb3 --- /dev/null +++ b/tests/__snapshots__/syntax-script--ts/esm @@ -0,0 +1,8 @@ +{ + "configContent": "export default [ +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-script-react-js/esm b/tests/__snapshots__/syntax-script-react-js/esm new file mode 100644 index 00000000..7cd465f3 --- /dev/null +++ b/tests/__snapshots__/syntax-script-react-js/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginReact from "eslint-plugin-react"; +export default [ + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-script-react-ts/esm b/tests/__snapshots__/syntax-script-react-ts/esm new file mode 100644 index 00000000..7cd465f3 --- /dev/null +++ b/tests/__snapshots__/syntax-script-react-ts/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginReact from "eslint-plugin-react"; +export default [ + pluginReact.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-react", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-script-vue-js/esm b/tests/__snapshots__/syntax-script-vue-js/esm new file mode 100644 index 00000000..bdc6d75a --- /dev/null +++ b/tests/__snapshots__/syntax-script-vue-js/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginVue from "eslint-plugin-vue"; +export default [ + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/__snapshots__/syntax-script-vue-ts/esm b/tests/__snapshots__/syntax-script-vue-ts/esm new file mode 100644 index 00000000..bdc6d75a --- /dev/null +++ b/tests/__snapshots__/syntax-script-vue-ts/esm @@ -0,0 +1,11 @@ +{ + "configContent": "import pluginVue from "eslint-plugin-vue"; +export default [ + pluginVue.configs.recommended, +];", + "configFilename": "eslint.config.js", + "devDependencies": [ + "eslint", + "eslint-plugin-vue", + ], +} \ No newline at end of file diff --git a/tests/config-snapshots.spec.js b/tests/config-snapshots.spec.js new file mode 100644 index 00000000..f786fbb2 --- /dev/null +++ b/tests/config-snapshots.spec.js @@ -0,0 +1,57 @@ +/** + * @fileoverview snapshot tests for config-generator.js + * run `npm run test:snapshots` to assert snapshots + * run `npm run test:snapshots:update` to update snapshots - you need + * to check the changes manually (see the diff) and make sure it's correct. + * + * @author 唯然 + */ +import { ConfigGenerator } from "../lib/config-generator.js"; +import { expect, describe, it, test } from "vitest"; +import { fileURLToPath } from "node:url"; +import { join } from "path"; + +const __filename = fileURLToPath(import.meta.url); +const esmProjectDir = join(__filename, "../fixtures/esm-project"); +const cjsProjectDir = join(__filename, "../fixtures/cjs-project"); + +let answers = { + purpose: ['syntax', 'problem'], + module: ['esm', 'commonjs', 'script'], + framework: ['react', 'vue', ''], + lang: ['js', 'ts'], +} + +const inputs = []; + +for (let i = 0; i < answers.purpose.length; i++){ + for (let j = 0; j < answers.module.length; j++){ + for (let k = 0; k < answers.framework.length; k++){ + for (let m = 0; m < answers.lang.length; m++){ + inputs.push({ + name: `${answers.purpose[i]}-${answers.module[j]}-${answers.framework[k]}-${answers.lang[m]}`, + answers: { + purpose: answers.purpose[i], + module: answers.module[j], + framework: answers.framework[k], + lang: answers.lang[m], + } + }) + } + } + } +} + + +describe("generate config for projects", () => { + inputs.forEach(item => { + test(`${item.name} + esm projects`, () => { + const generator = new ConfigGenerator({ cwd: esmProjectDir, answers: item.answers }); + + generator.calc(); + + expect(generator.result.configFilename).toBe("eslint.config.js"); + expect(generator.result).toMatchFileSnapshot(`./__snapshots__/${item.name}/esm`); + }); + }); +}); diff --git a/tests/fixtures/cjs-project/package.json b/tests/fixtures/cjs-project/package.json new file mode 100644 index 00000000..24d28279 --- /dev/null +++ b/tests/fixtures/cjs-project/package.json @@ -0,0 +1,6 @@ +{ + "name": "esm", + "private": true, + "type": "commonjs", + "version": "1.0.0" +} diff --git a/tests/fixtures/esm-project/package.json b/tests/fixtures/esm-project/package.json new file mode 100644 index 00000000..1da57407 --- /dev/null +++ b/tests/fixtures/esm-project/package.json @@ -0,0 +1,6 @@ +{ + "name": "esm", + "private": true, + "type": "module", + "version": "1.0.0" +} diff --git a/tests/init/config-file.js b/tests/init/config-file.js deleted file mode 100644 index 64947291..00000000 --- a/tests/init/config-file.js +++ /dev/null @@ -1,145 +0,0 @@ -/** - * @fileoverview Tests for ConfigFile - * @author Nicholas C. Zakas - */ - - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -import sinon from "sinon"; -import path from "path"; -import yaml from "js-yaml"; -import * as espree from "espree"; -import * as ConfigFile from "../../lib/init/config-file.js"; -import nodeAssert from "assert"; -import esmock from "esmock"; - -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -/** - * Helper function get easily get a path in the fixtures directory. - * @param {string} filepath The path to find in the fixtures directory. - * @returns {string} Full path in the fixtures directory. - * @private - */ -function getFixturePath(filepath) { - const dirname = path.dirname(new URL(import.meta.url).pathname); - - return path.resolve(dirname, "../../fixtures/config-file", filepath); -} - -//------------------------------------------------------------------------------ -// Tests -//------------------------------------------------------------------------------ - -describe("ConfigFile", () => { - describe("write()", () => { - let config; - - beforeEach(() => { - config = { - env: { - browser: true, - node: true - }, - rules: { - quotes: 2, - semi: 1 - } - }; - }); - - afterEach(() => { - sinon.verifyAndRestore(); - }); - - [ - ["JavaScript", "foo.js", espree.parse], - ["JSON", "bar.json", JSON.parse], - ["YAML", "foo.yaml", yaml.load], - ["YML", "foo.yml", yaml.load] - ].forEach(([fileType, filename, validate]) => { - - it(`should write a file through fs when a ${fileType} path is passed`, async () => { - const fakeFS = { - writeFileSync() {} - }; - - sinon.mock(fakeFS).expects("writeFileSync").withExactArgs( - filename, - sinon.match(value => !!validate(value)), - "utf8" - ); - - const StubbedConfigFile = await esmock("../../lib/init/config-file.js", { - fs: fakeFS - }); - - await StubbedConfigFile.write(config, filename); - }); - - it("should include a newline character at EOF", async () => { - const fakeFS = { - writeFileSync() {} - }; - - sinon.mock(fakeFS).expects("writeFileSync").withExactArgs( - filename, - sinon.match(value => value.endsWith("\n")), - "utf8" - ); - - const StubbedConfigFile = await esmock("../../lib/init/config-file.js", { - fs: fakeFS - }); - - await StubbedConfigFile.write(config, filename); - }); - }); - - it("should run 'eslint --fix' to make sure js config files match linting rules", async () => { - const fakeFS = { - writeFileSync() {} - }; - - const singleQuoteConfig = { - rules: { - quotes: [2, "single"] - } - }; - - sinon.mock(fakeFS).expects("writeFileSync").withExactArgs( - "test-config.js", - sinon.match.string, - "utf8" - ); - - const syncStub = sinon.fake(); - const StubbedConfigFile = await esmock("../../lib/init/config-file.js", { - fs: fakeFS, - "cross-spawn": { - default: { - sync: syncStub - } - } - }); - - StubbedConfigFile.write(singleQuoteConfig, "test-config.js"); - nodeAssert(syncStub.called); - nodeAssert(syncStub.calledWith( - sinon.match("eslint"), - sinon.match.array.contains(["--fix"]) - )); - }); - - it("should throw error if file extension is not valid", () => { - nodeAssert.rejects(async () => { - await ConfigFile.write({}, getFixturePath("yaml/.eslintrc.class")); - }, /write to unknown file type/u); - }); - }); -}); diff --git a/tests/init/config-initializer.js b/tests/init/config-initializer.js deleted file mode 100644 index 18261b2d..00000000 --- a/tests/init/config-initializer.js +++ /dev/null @@ -1,544 +0,0 @@ -/** - * @fileoverview Tests for configInitializer. - * @author Ilya Volodin - */ - - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -import chai from "chai"; -import fs from "fs"; -import path from "path"; -import sinon from "sinon"; -import sh from "shelljs"; -import esmock from "esmock"; -import { fileURLToPath } from "url"; -import * as npmUtils from "../../lib/init/npm-utils.js"; -import { defineInMemoryFs } from "../_utils/in-memory-fs.js"; - -const originalDir = process.cwd(); -const { assert } = chai; - -//------------------------------------------------------------------------------ -// Helpers -//------------------------------------------------------------------------------ - -let fixtureDir; -let localInstalledEslintDir; - -/** - * change local installed eslint version in fixtures - * @param {string|null} version installed eslint version, null => not installed - * @returns {void} - */ -function setLocalInstalledEslint(version) { - const eslintPkgPath = path.join(localInstalledEslintDir, "./package.json"); - let pkg = JSON.parse(fs.readFileSync(eslintPkgPath, "utf8")); - - if (version) { - pkg.version = version; - } else { - pkg = {}; - } - - fs.writeFileSync(eslintPkgPath, JSON.stringify(pkg, null, 2), "utf8"); -} - - -//------------------------------------------------------------------------------ -// Tests -//------------------------------------------------------------------------------ - -let answers = {}; -let pkgJSONContents = {}; -let pkgJSONPath = ""; - -describe("configInitializer", () => { - - let npmCheckStub; - let npmInstallStub; - let npmFetchPeerDependenciesStub; - let init; - let log; - - - // copy into clean area so as not to get "infected" by this project's .eslintrc files - before(() => { - const __filename = fileURLToPath(import.meta.url); // eslint-disable-line no-underscore-dangle -- Conventional - - fixtureDir = path.join(__filename, "../../../tmp/eslint/fixtures/config-initializer"); - localInstalledEslintDir = path.join(fixtureDir, "./node_modules/eslint"); - sh.mkdir("-p", localInstalledEslintDir); - sh.cp("-r", "./tests/fixtures/config-initializer/.", fixtureDir); - sh.cp("-r", "./tests/fixtures/eslint/.", localInstalledEslintDir); - fixtureDir = fs.realpathSync(fixtureDir); - }); - - beforeEach(async () => { - log = { - info: sinon.spy(), - error: sinon.spy() - }; - - npmInstallStub = sinon.stub(); - npmCheckStub = sinon.fake(packages => packages.reduce((status, pkg) => { - status[pkg] = false; - return status; - }, {})); - npmFetchPeerDependenciesStub = sinon.fake(() => ({ - eslint: "^3.19.0", - "eslint-plugin-jsx-a11y": "^5.0.1", - "eslint-plugin-import": "^2.2.0", - "eslint-plugin-react": "^7.0.1" - })); - - const requireStubs = { - "../../lib/shared/logging.js": log, - "../../lib/init/npm-utils.js": { - ...npmUtils, - installSyncSaveDev: npmInstallStub, - checkDevDeps: npmCheckStub, - fetchPeerDependencies: npmFetchPeerDependenciesStub - } - }; - - init = await esmock("../../lib/init/config-initializer.js", requireStubs, {}); - }); - - afterEach(() => { - log.info.resetHistory(); - log.error.resetHistory(); - npmInstallStub.resetHistory(); - npmCheckStub.resetHistory(); - npmFetchPeerDependenciesStub.resetHistory(); - }); - - after(() => { - sh.rm("-r", fixtureDir); - }); - - describe("processAnswers()", () => { - - describe("prompt", () => { - - beforeEach(() => { - answers = { - purpose: "style", - source: "prompt", - extendDefault: true, - indent: 2, - quotes: "single", - linebreak: "unix", - semi: true, - moduleType: "esm", - es6Globals: true, - env: ["browser"], - format: "JSON" - }; - }); - it("should throw error with message when no package.json", async () => { - const requireStubs = { - "../../lib/shared/logging.js": log, - "../../lib/init/npm-utils.js": { - ...await esmock("../../lib/init/npm-utils.js", { fs: defineInMemoryFs({}) }) - } - }; - - - init = await esmock("../../lib/init/config-initializer.js", requireStubs, { }); - - assert.throws(() => { - init.initializeConfig(); - }, "A package.json file is necessary to initialize ESLint. Run `npm init` to create a package.json file and try again."); - }); - - it("should create default config", () => { - const config = init.processAnswers(answers); - - assert.deepStrictEqual(config.rules.indent, ["error", 2]); - assert.deepStrictEqual(config.rules.quotes, ["error", "single"]); - assert.deepStrictEqual(config.rules["linebreak-style"], ["error", "unix"]); - assert.deepStrictEqual(config.rules.semi, ["error", "always"]); - assert.strictEqual(config.env.es2021, true); - assert.strictEqual(config.parserOptions.ecmaVersion, "latest"); - assert.strictEqual(config.parserOptions.sourceType, "module"); - assert.strictEqual(config.env.browser, true); - assert.strictEqual(config.extends, "eslint:recommended"); - }); - - it("should disable semi", () => { - answers.semi = false; - const config = init.processAnswers(answers); - - assert.deepStrictEqual(config.rules.semi, ["error", "never"]); - }); - - it("should enable react plugin", () => { - answers.framework = "react"; - const config = init.processAnswers(answers); - - assert.strictEqual(config.parserOptions.ecmaVersion, "latest"); - assert.deepStrictEqual(config.plugins, ["react"]); - assert.include(config.extends, "plugin:react/recommended"); - }); - - it("should enable vue plugin", () => { - answers.framework = "vue"; - const config = init.processAnswers(answers); - - assert.strictEqual(config.parserOptions.ecmaVersion, "latest"); - assert.deepStrictEqual(config.plugins, ["vue"]); - assert.deepStrictEqual(config.extends, ["eslint:recommended", "plugin:vue/vue3-essential"]); - }); - - it("should enable typescript parser and plugin", () => { - answers.typescript = true; - const config = init.processAnswers(answers); - - assert.strictEqual(config.parser, "@typescript-eslint/parser"); - assert.deepStrictEqual(config.plugins, ["@typescript-eslint"]); - assert.deepStrictEqual(config.extends, ["eslint:recommended", "plugin:@typescript-eslint/recommended"]); - }); - - it("should enable typescript parser and plugin with vue", () => { - answers.framework = "vue"; - answers.typescript = true; - const config = init.processAnswers(answers); - - assert.include(config.parserOptions, { parser: "@typescript-eslint/parser" }); - assert.deepStrictEqual(config.extends, ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:vue/vue3-essential"]); - assert.deepStrictEqual(config.plugins, ["@typescript-eslint", "vue"]); - }); - - it("should extend eslint:recommended", () => { - const config = init.processAnswers(answers); - - assert.strictEqual(config.extends, "eslint:recommended"); - }); - - it("should not use commonjs by default", () => { - const config = init.processAnswers(answers); - - assert.isUndefined(config.env.commonjs); - }); - - it("should use commonjs when set", () => { - answers.moduleType = "commonjs"; - const config = init.processAnswers(answers); - - assert.isTrue(config.env.commonjs); - }); - - it("should set commonjs config for `.eslintrc.cjs` in esm projects", () => { - answers.moduleType = "esm"; - answers.format = "JavaScript"; - const config = init.processAnswers(answers); - - assert.isArray(config.overrides, "should have overrides config"); - assert.strictEqual(config.overrides.length, 1); - assert.deepStrictEqual(config.overrides[0].parserOptions, { sourceType: "script" }); - assert.deepStrictEqual(config.overrides[0].env, { node: true }); - }); - - }); - - describe("guide", () => { - it("should support the google style guide", () => { - const config = { extends: "google" }; - const modules = init.getModulesList(config); - - assert.deepStrictEqual(config, { extends: "google", installedESLint: true }); - assert.include(modules, "eslint-config-google@latest"); - }); - - it("should support the airbnb style guide", () => { - const config = { extends: "airbnb" }; - const modules = init.getModulesList(config); - - assert.deepStrictEqual(config, { extends: "airbnb", installedESLint: true }); - assert.include(modules, "eslint-config-airbnb@latest"); - }); - - it("should support the airbnb base style guide", () => { - const config = { extends: "airbnb-base" }; - const modules = init.getModulesList(config); - - assert.deepStrictEqual(config, { extends: "airbnb-base", installedESLint: true }); - assert.include(modules, "eslint-config-airbnb-base@latest"); - }); - - it("should support the standard style guide", () => { - const config = { extends: "standard" }; - const modules = init.getModulesList(config); - - assert.deepStrictEqual(config, { extends: "standard", installedESLint: true }); - assert.include(modules, "eslint-config-standard@latest"); - }); - - it("should support the xo style guide", () => { - const config = { extends: "xo" }; - const modules = init.getModulesList(config); - - assert.deepStrictEqual(config, { extends: "xo", installedESLint: true }); - assert.include(modules, "eslint-config-xo@latest"); - }); - - it("should support the xo-typescript style guide", () => { - const config = { extends: "xo", overrides: [{ files: ["*.ts"], extends: ["xo-typescript"] }] }; - const modules = init.getModulesList(config); - - assert.deepStrictEqual(config.extends, "xo"); - assert.deepStrictEqual(config.overrides[0].extends[0], "xo-typescript"); - assert.strictEqual(config.installedESLint, true); - assert.include(modules, "eslint-config-xo@latest"); - assert.include(modules, "eslint-config-xo-typescript@latest"); - }); - - it("should install required sharable config", () => { - const config = { extends: "google" }; - - init.installModules(init.getModulesList(config)); - assert(npmInstallStub.calledOnce); - assert(npmInstallStub.firstCall.args[0].some(name => name.startsWith("eslint-config-google@"))); - }); - - it("should install ESLint if not installed locally", () => { - const config = { extends: "google" }; - - init.installModules(init.getModulesList(config)); - assert(npmInstallStub.calledOnce); - assert(npmInstallStub.firstCall.args[0].some(name => name.startsWith("eslint@"))); - }); - - it("should install peerDependencies of the sharable config", () => { - const config = { extends: "airbnb" }; - - init.installModules(init.getModulesList(config)); - - assert(npmFetchPeerDependenciesStub.calledOnce); - assert(npmFetchPeerDependenciesStub.firstCall.args[0] === "eslint-config-airbnb@latest"); - assert(npmInstallStub.calledOnce); - assert.deepStrictEqual( - npmInstallStub.firstCall.args[0], - [ - "eslint-config-airbnb@latest", - "eslint@^3.19.0", - "eslint-plugin-jsx-a11y@^5.0.1", - "eslint-plugin-import@^2.2.0", - "eslint-plugin-react@^7.0.1" - ] - ); - }); - - describe('hasESLintVersionConflict (Note: peerDependencies always `eslint: "^3.19.0"` by stubs)', () => { - - before(() => { - - // FIX: not sure why it was changed somewhere??? - process.chdir(fixtureDir); - }); - - describe("if local ESLint is not found,", () => { - before(() => { - setLocalInstalledEslint(null); - }); - - it("should return false.", () => { - const result = init.hasESLintVersionConflict({ styleguide: "airbnb" }); - - assert.strictEqual(result, false); - }); - }); - - describe("if local ESLint is 3.19.0,", () => { - before(() => { - setLocalInstalledEslint("3.19.0"); - }); - - it("should return false.", () => { - const result = init.hasESLintVersionConflict({ styleguide: "airbnb" }); - - assert.strictEqual(result, false); - }); - }); - - describe("if local ESLint is 4.0.0,", () => { - before(() => { - setLocalInstalledEslint("4.0.0"); - }); - - it("should return true.", () => { - const result = init.hasESLintVersionConflict({ styleguide: "airbnb" }); - - assert.strictEqual(result, true); - }); - }); - - describe("if local ESLint is 3.18.0,", () => { - before(() => { - setLocalInstalledEslint("3.18.0"); - }); - - it("should return true.", () => { - const result = init.hasESLintVersionConflict({ styleguide: "airbnb" }); - - assert.strictEqual(result, true); - }); - }); - }); - - it("should support the standard style guide with Vue.js", () => { - const config = { - plugins: ["vue"], - extends: ["plugin:vue/vue3-essential", "standard"] - }; - const modules = init.getModulesList(config); - - assert.include(modules, "eslint-plugin-vue@latest"); - assert.include(modules, "eslint-config-standard@latest"); - }); - - it("should support custom parser", () => { - const config = { - parser: "@typescript-eslint/parser" - }; - const modules = init.getModulesList(config); - - assert.include(modules, "@typescript-eslint/parser@latest"); - }); - - it("should support custom parser with Vue.js", () => { - const config = { - - // We should declare the parser at `parserOptions` when using with `eslint-plugin-vue`. - parserOptions: { - parser: "@typescript-eslint/parser" - } - }; - const modules = init.getModulesList(config); - - assert.include(modules, "@typescript-eslint/parser@latest"); - }); - }); - - }); - - describe("writeFile()", () => { - - beforeEach(() => { - answers = { - purpose: "style", - source: "prompt", - extendDefault: true, - indent: 2, - quotes: "single", - linebreak: "unix", - semi: true, - moduleType: "esm", - es6Globals: true, - env: ["browser"], - format: "JSON" - }; - - pkgJSONContents = { - name: "config-initializer", - version: "1.0.0" - }; - - process.chdir(fixtureDir); - - pkgJSONPath = path.resolve(fixtureDir, "package.json"); - }); - - afterEach(() => { - process.chdir(originalDir); - }); - - it("should create .eslintrc.json", () => { - const config = init.processAnswers(answers); - const filePath = path.resolve(fixtureDir, ".eslintrc.json"); - - fs.writeFileSync(pkgJSONPath, JSON.stringify(pkgJSONContents)); - - init.writeFile(config, answers.format); - - assert.isTrue(fs.existsSync(filePath)); - - fs.unlinkSync(filePath); - fs.unlinkSync(pkgJSONPath); - }); - - it("should create .eslintrc.js", async () => { - answers.format = "JavaScript"; - - const config = init.processAnswers(answers); - const filePath = path.resolve(fixtureDir, ".eslintrc.js"); - - fs.writeFileSync(pkgJSONPath, JSON.stringify(pkgJSONContents)); - - await init.writeFile(config, answers.format); - - assert.isTrue(fs.existsSync(filePath)); - - fs.unlinkSync(filePath); - fs.unlinkSync(pkgJSONPath); - }); - - it("should create .eslintrc.yml", async () => { - answers.format = "YAML"; - - const config = init.processAnswers(answers); - const filePath = path.resolve(fixtureDir, ".eslintrc.yml"); - - fs.writeFileSync(pkgJSONPath, JSON.stringify(pkgJSONContents)); - - await init.writeFile(config, answers.format); - - assert.isTrue(fs.existsSync(filePath)); - - fs.unlinkSync(filePath); - fs.unlinkSync(pkgJSONPath); - }); - - // For https://github.com/eslint/eslint/issues/14137 - it("should create .eslintrc.cjs", async () => { - answers.format = "JavaScript"; - - // create package.json with "type": "module" - pkgJSONContents.type = "module"; - - fs.writeFileSync(pkgJSONPath, JSON.stringify(pkgJSONContents)); - - const config = init.processAnswers(answers); - const filePath = path.resolve(fixtureDir, ".eslintrc.cjs"); - - await init.writeFile(config, answers.format); - - assert.isTrue(fs.existsSync(filePath)); - - fs.unlinkSync(filePath); - fs.unlinkSync(pkgJSONPath); - }); - - it("should create .eslintrc.json even with type: 'module'", async () => { - answers.format = "JSON"; - - // create package.json with "type": "module" - pkgJSONContents.type = "module"; - - fs.writeFileSync(pkgJSONPath, JSON.stringify(pkgJSONContents)); - - const config = init.processAnswers(answers); - const filePath = path.resolve(fixtureDir, ".eslintrc.json"); - - await init.writeFile(config, answers.format); - - assert.isTrue(fs.existsSync(filePath)); - - fs.unlinkSync(filePath); - fs.unlinkSync(pkgJSONPath); - }); - }); -}); diff --git a/tests/init/npm-utils.js b/tests/utils/npm-utils.js similarity index 97% rename from tests/init/npm-utils.js rename to tests/utils/npm-utils.js index d7b72ca1..7dc0eeca 100644 --- a/tests/init/npm-utils.js +++ b/tests/utils/npm-utils.js @@ -16,7 +16,7 @@ import { fetchPeerDependencies, checkDeps, checkDevDeps -} from "../../lib/init/npm-utils.js"; +} from "../../lib/utils/npm-utils.js"; import { defineInMemoryFs } from "../_utils/in-memory-fs.js"; import esmock from "esmock"; @@ -34,7 +34,7 @@ const { assert } = chai; async function requireNpmUtilsWithInMemoryFileSystem(files) { const fs = defineInMemoryFs({ files }); - return await esmock("../../lib/init/npm-utils.js", { fs }); + return await esmock("../../lib/utils/npm-utils.js", { fs }); } //------------------------------------------------------------------------------ @@ -200,8 +200,8 @@ describe("npmUtils", () => { const logErrorStub = sinon.spy(); const npmUtilsStub = sinon.stub(spawn, "sync").returns({ error: { code: "ENOENT" } }); - const { installSyncSaveDev: stubinstallSyncSaveDev } = await esmock("../../lib/init/npm-utils.js", { - "../../lib/shared/logging.js": { + const { installSyncSaveDev: stubinstallSyncSaveDev } = await esmock("../../lib/utils/npm-utils.js", { + "../../lib/utils/logging.js": { error: logErrorStub } });