import { readFile, writeFile } from "node:fs/promises"; import { relative, resolve } from "node:path"; import { confirm, intro, log, outro, spinner } from "@clack/prompts"; import { ansi256, link, underline } from "kolorist"; import { addDevDependency } from "nypm"; import { resolveCommand } from "package-manager-detector/commands"; import { x } from "tinyexec"; import { existsSync } from "node:fs"; import { createResolver } from "exsolve"; import { getPackageInfoSync, isPackageExists } from "local-pkg"; import { detect } from "package-manager-detector"; import { FlatCompat } from "@eslint/eslintrc"; //#region src/constants/cli.ts const ESLINT = "eslint"; const ESLINT_CONFIG = "eslint-config-vuetify"; const VUETIFY = "vuetify"; const LINKS = { [ESLINT]: link(ESLINT, "https://npmjs.org/package/eslint"), [ESLINT_CONFIG]: link(ESLINT_CONFIG, "https://npmjs.org/package/eslint-config-vuetify"), [VUETIFY]: link("Vuetify", "https://vuetifyjs.com/") }; //#endregion //#region src/constants/config.ts const configData = `import vuetify from 'eslint-config-vuetify' export default vuetify() `; new FlatCompat({}); const { resolveModulePath: resolveModulePath$1 } = createResolver({ extensions: [".json"] }); hasPackage("eslint-config-vuetify"); function hasPackage(pkg, scope) { return isPackageExists(pkg, { paths: scope ? [scope] : [] }); } function getPackageVersion(pkg) { return getPackageInfoSync(pkg, { paths: [currentScope] })?.version; } const currentScope = new URL(".", import.meta.url).pathname; process.cwd(); function hasFile(file) { return existsSync(resolve(process.cwd(), file)); } async function getPackageManager() { return detect({ cwd: process.cwd() }); } const { resolveModulePath } = createResolver({ extensions: [ ".js", ".mjs", ".cjs", ".ts", ".mts", ".cts" ] }); const configUrl = resolveModulePath("./eslint.config", { try: true }); function isVersionAtLeast(version, targetVersion) { const [vMajor, vMinor, vPatch] = version.split(".").map(Number); const [major, minor, patch] = targetVersion.split(".").map(Number); return vMajor > major || vMajor === major && vMinor > minor || vMajor === major && vMinor === minor && vPatch >= patch; } //#endregion //#region src/cli.ts const blue = ansi256(33); const description = `Welcome to ${blue(ESLINT_CONFIG)} — an opinionated ESLint config by the ${blue(LINKS[VUETIFY])} team.`; const eslintVersion = getPackageVersion("eslint") ?? "0.0.0"; const configVersion = getPackageVersion("eslint-config-vuetify") ?? "0.0.0"; const hasEslint = hasPackage(ESLINT); const hasEslintConfig = hasPackage(ESLINT_CONFIG); const isEslintVersionValid = isVersionAtLeast(eslintVersion, "9.5.0"); const isConfigVersionValid = isVersionAtLeast(configVersion, "4.0.0"); const packagesToInstall = [...hasEslint ? [] : [ESLINT], ...hasEslintConfig ? [] : [ESLINT_CONFIG]]; const packagesToUpgrade = [...isEslintVersionValid ? [] : [ESLINT], ...isConfigVersionValid ? [] : [ESLINT_CONFIG]]; function getActionMessage() { const actions = []; if (packagesToInstall.length > 0) actions.push(`install ${packagesToInstall.map((pkg) => LINKS[pkg]).join(", ")}`); if (packagesToUpgrade.length > 0) { const upgradeAction = `upgrade ${packagesToUpgrade.map((pkg) => LINKS[pkg]).join(", ")}`; if (packagesToInstall.length > 0) actions.push(`and ${upgradeAction}`); else actions.push(upgradeAction); } if (hasEslint || hasEslintConfig) { actions.push("(Currently:"); if (hasEslint) actions.push(` ${ESLINT}: ${eslintVersion}`); if (hasEslintConfig) actions.push(` ${ESLINT_CONFIG}: ${configVersion}`); actions.push(")"); } return `We need to ${actions.join(" ")}.`; } async function main() { intro(description); if (packagesToInstall.length > 0 || packagesToUpgrade.length > 0) { log.info(getActionMessage()); if (await confirm({ message: "Do you want to proceed?" }) === true) { const s = spinner(); s.start("Installing dependencies..."); if (packagesToInstall.length > 0) await addDevDependency(packagesToInstall); if (packagesToUpgrade.length > 0) { const upgradeCommand = resolveCommand((await getPackageManager()).agent, "upgrade", packagesToUpgrade); await x(upgradeCommand.command, upgradeCommand.args); } s.stop("Dependencies installed!"); } } else log.info("All required dependencies are already installed."); let overwriteConfig = false; overwriteConfig = await (configUrl ? confirm({ message: `Found ${underline(relative(process.cwd(), configUrl))}. Do you want to overwrite it?` }) : confirm({ message: "No ESLint config found. Do you want to create one?" })); if (overwriteConfig === true) { const s = spinner(); s.start("Setting up ESLint config..."); await writeFile(configUrl ?? "eslint.config.mjs", configData); s.stop("ESLint config setup complete!"); } if (hasFile("package.json")) { const packageJson = JSON.parse(await readFile("package.json", "utf8")); if (!packageJson.scripts) packageJson.scripts = {}; if ((packageJson.scripts.lint && packageJson.scripts["lint:fix"] ? false : await confirm({ message: "Do you want to add lint scripts to package.json?" })) === true) { if (!packageJson.scripts.lint) packageJson.scripts.lint = "eslint"; if (!packageJson.scripts["lint:fix"]) packageJson.scripts["lint:fix"] = "eslint --fix"; await writeFile("package.json", JSON.stringify(packageJson, null, 2)); } } outro("All done! Happy hacking!"); } //#endregion export { main };