@coderwyd/eslint-config
Version:
Donny's ESLint config
185 lines (176 loc) • 6.59 kB
JavaScript
import process from "node:process";
import c from "picocolors";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import fs from "node:fs";
import fsp from "node:fs/promises";
import path from "node:path";
import parse from "parse-gitignore";
import prompts from "prompts";
import { execSync } from "node:child_process";
//#region package.json
var version = "4.4.0";
var devDependencies = {
"@antfu/ni": "^25.0.0",
"@eslint-react/eslint-plugin": "^1.52.2",
"@eslint/config-inspector": "^1.1.0",
"@types/eslint-config-prettier": "^6.11.3",
"@types/node": "^24.0.3",
"@types/prompts": "^2.4.9",
"@types/yargs": "^17.0.33",
"@unocss/eslint-plugin": "^66.2.3",
"bumpp": "^10.2.0",
"eslint": "^9.29.0",
"eslint-plugin-import-lite": "^0.3.0",
"eslint-plugin-react-hooks": "6.0.0-rc.1",
"eslint-plugin-react-refresh": "^0.4.20",
"eslint-plugin-svelte": "^3.9.2",
"eslint-plugin-tailwindcss": "^3.18.0",
"jiti": "^2.4.2",
"nano-staged": "^0.8.0",
"simple-git-hooks": "^2.13.0",
"svelte": "^5.34.6",
"svelte-eslint-parser": "^1.2.0",
"tsdown": "^0.12.8",
"typescript": "^5.8.3"
};
//#endregion
//#region src/cli/constants.ts
const ARROW = c.cyan("→");
const CHECK = c.green("✔");
const CROSS = c.red("✘");
const WARN = c.yellow("ℹ");
const eslintVersion = devDependencies.eslint;
const vscodeSettingsString = `
"editor.formatOnSave": true,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "never"
},
`;
//#endregion
//#region src/cli/utils.ts
function isGitClean() {
try {
execSync("git diff-index --quiet HEAD --");
return true;
} catch {
return false;
}
}
//#endregion
//#region 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(c.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(c.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(c.green(`${CHECK} changes wrote to package.json`));
const eslintIgnores = [];
if (fs.existsSync(pathESLintIngore)) {
console.log(c.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({\n${coderwydConfig}\n})
`.trimStart();
else eslintConfigContent = `
const { defineConfig } = require('@coderwyd/eslint-config')
module.exports = defineConfig({\n${coderwydConfig}\n})
`.trimStart();
await fsp.writeFile(pathFlatConfig, eslintConfigContent);
console.log(c.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(` ${c.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}}\n`, "utf-8");
console.log(c.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}}\n`;
await fsp.writeFile(settingsPath, settingsContent, "utf-8");
console.log(c.green(`${CHECK} updated .vscode/settings.json`));
}
}
console.log(c.green(`${CHECK} migration completed`));
console.log(`Now you can update the dependencies and run ${c.blue("eslint . --fix")}\n`);
}
//#endregion
//#region src/cli/index.ts
function header() {
console.log(`\n${c.green(`@coderwyd/eslint-config `)}${c.dim(`v${version}`)}`);
}
const instance = yargs(hideBin(process.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(c.inverse(c.red(" Failed to migrate ")));
console.error(c.red(`${CROSS} ${String(error)}`));
process.exit(1);
}
}).showHelpOnFail(false).alias("h", "help").version("version", version).alias("v", "version");
instance.help().argv;
//#endregion