UNPKG

@coderwyd/eslint-config

Version:
228 lines (217 loc) 7.14 kB
// src/cli/index.ts import process2 from "node:process"; import c3 from "picocolors"; import yargs from "yargs"; import { hideBin } from "yargs/helpers"; // src/cli/constants.ts import c from "picocolors"; // package.json var version = "4.2.1"; var devDependencies = { "@antfu/ni": "^24.3.0", "@eslint-react/eslint-plugin": "^1.38.0", "@eslint/config-inspector": "^1.0.2", "@types/eslint-config-prettier": "^6.11.3", "@types/node": "^22.13.13", "@types/prompts": "^2.4.9", "@types/yargs": "^17.0.33", "@unocss/eslint-plugin": "^66.1.0-beta.6", bumpp: "^10.1.0", eslint: "^9.23.0", "eslint-plugin-react-compiler": "19.0.0-beta-e552027-20250112", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.19", "eslint-plugin-svelte": "^3.3.3", "eslint-plugin-tailwindcss": "^3.18.0", jiti: "^2.4.2", "nano-staged": "^0.8.0", "simple-git-hooks": "^2.12.1", svelte: "^5.25.3", "svelte-eslint-parser": "^1.1.0", tsup: "^8.4.0", typescript: "^5.8.2" }; // src/cli/constants.ts var ARROW = c.cyan("\u2192"); var CHECK = c.green("\u2714"); var CROSS = c.red("\u2718"); var WARN = c.yellow("\u2139"); var eslintVersion = devDependencies.eslint; var vscodeSettingsString = ` "editor.formatOnSave": true, // Auto fix "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit", "source.organizeImports": "never" }, `; // src/cli/run.ts import fs from "node:fs"; import fsp from "node:fs/promises"; import path from "node:path"; import process from "node:process"; import parse from "parse-gitignore"; import c2 from "picocolors"; import prompts from "prompts"; // src/cli/utils.ts import { execSync } from "node:child_process"; function isGitClean() { try { execSync("git diff-index --quiet HEAD --"); return true; } catch { return false; } } // src/cli/run.ts async function run(options = {}) { const SKIP_PROMPT = !!process.env.SKIP_PROMPT || options.yes; const SKIP_GIT_CHECK = !!process.env.SKIP_GIT_CHECK; const cwd = process.cwd(); const pathFlatConfig = path.join(cwd, "eslint.config.js"); const pathPackageJSON = path.join(cwd, "package.json"); const pathESLintIngore = path.join(cwd, ".eslintignore"); if (fs.existsSync(pathFlatConfig)) { console.log( c2.yellow( `${WARN} eslint.config.js already exists, migration wizard exited.` ) ); return process.exit(1); } if (!SKIP_GIT_CHECK && !isGitClean()) { const { confirmed } = await prompts({ initial: false, message: "There are uncommitted changes in the current repository, are you sure to continue?", name: "confirmed", type: "confirm" }); if (!confirmed) return process.exit(1); } console.log(c2.cyan(`${ARROW} bumping @coderwyd/eslint-config to v${version}`)); const pkgContent = await fsp.readFile(pathPackageJSON, "utf-8"); const pkg = JSON.parse(pkgContent); pkg.devDependencies ??= {}; pkg.devDependencies["@coderwyd/eslint-config"] = `^${version}`; if (!pkg.devDependencies.eslint) pkg.devDependencies.eslint = eslintVersion; await fsp.writeFile(pathPackageJSON, JSON.stringify(pkg, null, 2)); console.log(c2.green(`${CHECK} changes wrote to package.json`)); const eslintIgnores = []; if (fs.existsSync(pathESLintIngore)) { console.log(c2.cyan(`${ARROW} migrating existing .eslintignore`)); const content = await fsp.readFile(pathESLintIngore, "utf-8"); const parsed = parse(content); const globs = parsed.globs(); for (const glob of globs) { if (glob.type === "ignore") { eslintIgnores.push(...glob.patterns); } else if (glob.type === "unignore") { eslintIgnores.push( ...glob.patterns.map((pattern) => `!${pattern}`) ); } } } let eslintConfigContent = ""; const coderwydConfig = `${eslintIgnores.length > 0 ? `ignores: ${JSON.stringify(eslintIgnores)}` : ""}`; if (pkg.type === "module") { eslintConfigContent = ` import { defineConfig } from '@coderwyd/eslint-config' export default defineConfig({ ${coderwydConfig} }) `.trimStart(); } else { eslintConfigContent = ` const { defineConfig } = require('@coderwyd/eslint-config') module.exports = defineConfig({ ${coderwydConfig} }) `.trimStart(); } await fsp.writeFile(pathFlatConfig, eslintConfigContent); console.log(c2.green(`${CHECK} created eslint.config.js`)); const files = fs.readdirSync(cwd); const legacyConfig = []; files.forEach((file) => { if (/eslint|prettier/.test(file) && !/eslint.config./.test(file)) legacyConfig.push(file); }); if (legacyConfig.length > 0) { console.log(`${WARN} you can now remove those files manually:`); console.log(` ${c2.dim(legacyConfig.join(", "))}`); } let promptResult = { updateVscodeSettings: true }; if (!SKIP_PROMPT) { try { promptResult = await prompts( { initial: true, message: "Update .vscode/settings.json for better VS Code experience?", name: "updateVscodeSettings", type: "confirm" }, { onCancel: () => { throw new Error(`Cancelled`); } } ); } catch (error) { console.log(error.message); return; } } if (promptResult?.updateVscodeSettings ?? true) { const dotVscodePath = path.join(cwd, ".vscode"); const settingsPath = path.join(dotVscodePath, "settings.json"); if (!fs.existsSync(dotVscodePath)) await fsp.mkdir(dotVscodePath, { recursive: true }); if (!fs.existsSync(settingsPath)) { await fsp.writeFile(settingsPath, `{${vscodeSettingsString}} `, "utf-8"); console.log(c2.green(`${CHECK} created .vscode/settings.json`)); } else { let settingsContent = await fsp.readFile(settingsPath, "utf8"); settingsContent = settingsContent.trim().replace(/\s*\}$/, ""); settingsContent += settingsContent.endsWith(",") || settingsContent.endsWith("{") ? "" : ","; settingsContent += `${vscodeSettingsString}} `; await fsp.writeFile(settingsPath, settingsContent, "utf-8"); console.log(c2.green(`${CHECK} updated .vscode/settings.json`)); } } console.log(c2.green(`${CHECK} migration completed`)); console.log( `Now you can update the dependencies and run ${c2.blue("eslint . --fix")} ` ); } // src/cli/index.ts function header() { console.log(` ${c3.green(`@coderwyd/eslint-config `)}${c3.dim(`v${version}`)}`); } var instance = yargs(hideBin(process2.argv)).scriptName("@coderwyd/eslint-config").usage("").command( "*", "Run the initialization or migration", (args) => args.option("yes", { alias: "y", description: "Skip prompts and use default values", type: "boolean" }).help(), async (args) => { header(); console.log(); try { await run(args); } catch (error) { console.error(c3.inverse(c3.red(" Failed to migrate "))); console.error(c3.red(`${CROSS} ${String(error)}`)); process2.exit(1); } } ).showHelpOnFail(false).alias("h", "help").version("version", version).alias("v", "version"); instance.help().argv;