UNPKG

@vue/create-eslint-config

Version:

Utility to setup ESLint in Vue.js projects.

199 lines (173 loc) 5.58 kB
#!/usr/bin/env node import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs' import { createRequire } from 'node:module' import path from 'node:path' import process from 'node:process' import { bold, blue, yellow, red, green, dim } from 'kolorist' import createConfig, { deepMerge } from '../index.js' const require = createRequire(import.meta.url) const Enquirer = require('enquirer') const enquirer = new Enquirer() function abort() { console.error(red('✖') + ' Operation cancelled') process.exit(1) } function prompt(questions) { return enquirer.prompt(questions).catch(abort) } const cwd = process.cwd() const requireInCwd = createRequire(path.resolve(cwd, 'index.cjs')) // Only works in directories that has a `package.json` const pkgJsonPath = path.resolve(cwd, 'package.json') if (!existsSync(pkgJsonPath)) { console.error( `${bold(yellow('package.json'))} not found in the current directory.`, ) abort() } const rawPkgJson = readFileSync(pkgJsonPath, 'utf-8') function inferIndent(rawJson) { const lines = rawJson.split('\n') const firstLineWithIndent = lines.find( l => l.startsWith(' ') || l.startsWith('\t'), ) if (!firstLineWithIndent) { return '' } return /^\s+/.exec(firstLineWithIndent)[0] } const indent = inferIndent(rawPkgJson) const pkg = JSON.parse(rawPkgJson) // 1. check for existing config files // `.eslintrc.*`, `eslintConfig` in `package.json` // FIXME: `eslint.config.*` // ask if wanna overwrite? // https://eslint.org/docs/latest/user-guide/configuring/configuration-files#configuration-file-formats // The experimental `eslint.config.js` isn't supported yet const eslintConfigFormats = ['js', 'cjs', 'yaml', 'yml', 'json'] for (const fmt of eslintConfigFormats) { const configFileName = `.eslintrc.${fmt}` const fullConfigPath = path.resolve(cwd, configFileName) if (existsSync(fullConfigPath)) { const { shouldRemove } = await prompt({ type: 'toggle', disabled: 'No', enabled: 'Yes', name: 'shouldRemove', message: `Found existing ESLint config file: ${bold(blue(configFileName))}.\n` + 'Do you want to remove the config file and continue?', initial: false, }) if (shouldRemove) { unlinkSync(fullConfigPath) } else { abort() } } } if (pkg.eslintConfig) { const { shouldRemoveConfigField } = await prompt({ type: 'toggle', disabled: 'No', enabled: 'Yes', name: 'shouldRemoveConfigField', message: `Found existing ${bold(blue('eslintConfig'))} field in ${bold(yellow('package.json'))}.\n` + 'Do you want to remove the config field and continue?', initial: false, }) if (shouldRemoveConfigField) { delete pkg.eslintConfig } } // 2. Check Vue let vueVersion // Not detected? Abort // Vue 2? Abort because this tool only supports Vue 3 try { vueVersion = requireInCwd('vue/package.json').version console.info(dim(`Detected Vue.js version: ${vueVersion}`)) } catch { // Vue.js not found, will prompt later } if (!vueVersion || !vueVersion.startsWith('3.')) { const { continueAnyway } = await prompt({ type: 'toggle', disabled: 'No', enabled: 'Yes', name: 'continueAnyway', message: 'Vue 3.x is required but not detected. Continue anyway?', initial: false, }) if (!continueAnyway) { abort() } } // 4. Check TypeScript // 4.1 Allow JS? // 4.2 Allow JS in Vue? Allow JSX (TSX, if answered no in 4.1) in Vue? let detectedTypeScript = false try { const tsVersion = requireInCwd('typescript/package.json').version console.info(dim(`Detected TypeScript version: ${tsVersion}`)) detectedTypeScript = true } catch { // TypeScript not found, will prompt later } const { hasTypeScript } = await prompt({ type: 'toggle', disabled: 'No', enabled: 'Yes', name: 'hasTypeScript', message: 'Does your project use TypeScript?', initial: detectedTypeScript, }) const supportedScriptLangs = {} // 5. Do you need Prettier to format your codebase? const { needsPrettier } = await prompt({ type: 'toggle', disabled: 'No', enabled: 'Yes', name: 'needsPrettier', message: 'Do you need Prettier to format your code?', }) const { needsOxlint } = await prompt({ type: 'toggle', disabled: 'No', enabled: 'Yes', name: 'needsOxlint', message: 'Would you like to supplement ESLint with Oxlint for faster linting (experimental)?', }) const { pkg: pkgToExtend, files } = createConfig({ hasTypeScript, supportedScriptLangs, needsPrettier, needsOxlint, }) deepMerge(pkg, pkgToExtend) // Write `package.json` back writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, indent) + '\n', 'utf8') // Write files back for (const [name, content] of Object.entries(files)) { const fullPath = path.resolve(cwd, name) writeFileSync(fullPath, content, 'utf8') } // Prompt: Run `npm install` or `yarn` or `pnpm install` const userAgent = process.env.npm_config_user_agent ?? '' const packageManager = /pnpm/.test(userAgent) ? 'pnpm' : /yarn/.test(userAgent) ? 'yarn' : 'npm' const installCommand = packageManager === 'yarn' ? 'yarn' : `${packageManager} install` const lintCommand = packageManager === 'npm' ? 'npm run lint' : `${packageManager} lint` console.info( '\n' + `${bold(yellow('package.json'))} and ${bold(blue(`eslint.config.${hasTypeScript ? 'ts' : 'js'}`))} have been updated.\n` + `Now please run ${bold(green(installCommand))} to re-install the dependencies.\n` + `Then you can run ${bold(green(lintCommand))} to lint your files.`, )