From c6fe80f1d66306326182b1ae8c71b0eb7e6f4c89 Mon Sep 17 00:00:00 2001 From: Adham Farrag Date: Fri, 3 May 2024 10:05:28 +0800 Subject: [PATCH] feat: @nuxt/eslint integration workflow --- src/commands/CSS.ts | 10 +-- src/commands/Linters.ts | 123 ++++++++++++++++++------------------ src/commands/Store.ts | 4 +- src/sideBar/index.ts | 4 +- src/templates/index.ts | 3 +- src/templates/linters.ts | 18 +++--- src/utils/index.ts | 11 ++-- src/utils/nuxt.ts | 132 ++++++++++++++++++++++----------------- src/utils/pkgJSON.ts | 17 +++++ 9 files changed, 178 insertions(+), 144 deletions(-) create mode 100644 src/utils/pkgJSON.ts diff --git a/src/commands/CSS.ts b/src/commands/CSS.ts index 0b47628..cc10592 100644 --- a/src/commands/CSS.ts +++ b/src/commands/CSS.ts @@ -1,6 +1,6 @@ import { window } from 'vscode' import { unoCSSConfig, windiCSSConfig, tailwindCSSFile, tailwindCSSJSConfig, tailwindCSSTSConfig, vuetifyConfigFile } from '../templates' -import { isNuxtTwo, createFile, projectSrcDirectory, runCommand, openExternalLink, addNuxtModule, getInstallationCommand, projectRootDirectory } from '../utils' +import { isNuxtTwo, createFile, projectSrcDirectory, runCommand, openExternalLink, updateNuxtConfig, getInstallationCommand, projectRootDirectory } from '../utils' const frameworks = ['TailwindCSS', 'WindiCSS', 'UnoCSS', 'Vuetify'] @@ -76,7 +76,7 @@ const configureTailwind = () => { successMessage: 'TailwindCSS Module installed successfully', errorMessage: 'TailwindCSS Module installation failed', }) - await addNuxtModule(moduleName) + await updateNuxtConfig('add-module', moduleName) } if (selections.includes(TailwindOptions.createTailwindCSSFile)) { @@ -136,7 +136,7 @@ const configureWindi = async () => { errorMessage: 'WindiCSS installation failed', }) - await addNuxtModule(moduleName) + await updateNuxtConfig('add-module', moduleName) } if (selections.includes(WindiOptions.createConfigFile)) { @@ -184,7 +184,7 @@ const configureUno = async () => { errorMessage: 'UnoCSS installation failed', }) - await addNuxtModule(moduleName) + await updateNuxtConfig('add-module', moduleName) } if (selections.includes(UnoCSSOptions.createConfigFile)) { @@ -232,7 +232,7 @@ const configureVuetify = async () => { errorMessage: 'Vuetify installation failed', }) - await addNuxtModule(moduleName) + await updateNuxtConfig('add-module', moduleName) } if (selections.includes(VuetifyOptions.createConfigFile)) { diff --git a/src/commands/Linters.ts b/src/commands/Linters.ts index 9617145..5664a2e 100644 --- a/src/commands/Linters.ts +++ b/src/commands/Linters.ts @@ -1,15 +1,9 @@ -import { window } from 'vscode' +import { window, workspace, ConfigurationTarget } from 'vscode' import { writeFileSync } from 'node:fs' -import { createFile, projectRootDirectory, runCommand, getInstallationCommand } from '../utils' -import { eslintConfig, eslintIgnore, stylelintConfig, stylelintIgnore } from '../templates' +import { createFile, projectRootDirectory, runCommand, getInstallationCommand, injectPkgJSONScript, openExternalLink, updateNuxtConfig} from '../utils' +import { eslintConfig, stylelintConfig, stylelintIgnore } from '../templates' const frameworks = ['Eslint', 'Stylelint'] -enum EslintOptions { - installModule = 'Install Eslint module', - addScriptToPackageJSON = 'Add lint script to package.json', - createESLintAndIgnoreFiles = 'Create .eslintrc & .eslintignore files', -} - enum StylelintOptions { installModule = 'Install Stylelint & Stylelint module', addScriptToPackageJSON = 'Add lint script to package.json', @@ -33,59 +27,66 @@ function configureLinters() { }) } -const configureEslint = () => { - try { - const eslintOptions = Object.values(EslintOptions) - - window - .showQuickPick(eslintOptions, { - canPickMany: true, - placeHolder: 'Select files to create', - }) - .then(async (selections) => { - if (selections !== undefined && selections.length > 0) { - if (selections.includes(EslintOptions.installModule)) { - const moduleName = '@nuxtjs/eslint-config-typescript eslint' - const command = await getInstallationCommand(moduleName, true) - - await runCommand({ - command, - message: 'Installing Eslint module', - successMessage: 'Eslint installed successfully', - errorMessage: 'Eslint installation failed', - }) - } - - if (selections.includes(EslintOptions.addScriptToPackageJSON)) { - const packageJsonPath = `${projectRootDirectory()}/package.json` - const packageJson = require(packageJsonPath) - - packageJson.scripts.lint = 'eslint --ext .js,.vue,.ts,.tsx --ignore-path .gitignore .' - - writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2), 'utf-8') - } - - if (selections.includes(EslintOptions.createESLintAndIgnoreFiles)) { - const eslintPath = `${projectRootDirectory()}/.eslintrc` - const eslintIgnorePath = `${projectRootDirectory()}/.eslintignore` - - await createFile({ - fileName: `.eslintignore`, - content: eslintIgnore, - fullPath: eslintIgnorePath, - }) - - await createFile({ - fileName: `.eslintrc`, - content: eslintConfig, - fullPath: eslintPath, - }) - } - } - }) - } catch (error) { - console.error(error) +const configureEslint = async () => { + const packages = { eslint: 'eslint', module: '@nuxt/eslint', } + const eslintCommand = await getInstallationCommand(packages.eslint, true) + const moduleCommand = await getInstallationCommand(packages.module, true) + const devServerCheckerCommand = await getInstallationCommand('vite-plugin-eslint2', true) + + await runCommand({ + command: eslintCommand, + message: `Installing Eslint`, + successMessage: 'Eslint installed successfully', + errorMessage: 'Eslint installation failed', + }) + + await runCommand({ + command: moduleCommand, + message: `Installing ${packages.module} module`, + successMessage: `${packages.module} installed successfully`, + errorMessage: `${packages.module} installation failed`, + docsURL: 'https://eslint.nuxt.com' + }) + + await updateNuxtConfig('add-module', '@nuxt/eslint') + + + const scriptName = 'lint' + const script = 'eslint .' + await injectPkgJSONScript(scriptName, script) + + await createFile({ + fileName: `eslint.config.mjs`, + content: eslintConfig, + fullPath: `${projectRootDirectory()}/eslint.config.mjs` + }) + + const config = workspace.getConfiguration('eslint') + config.update('experimental.useFlatConfig', true, ConfigurationTarget.Workspace) + window.showInformationMessage('Eslint useFlagConfig enabled successfully') + + + const devServerChecker = await window.showInformationMessage( + 'Eslint configured successfully, do you want to configure Dev Server Checker?', + 'Yes', + 'Learn More' + ) + + if (devServerChecker === 'Yes') { + await runCommand({ + command: devServerCheckerCommand, + message: `Installing vite-plugin-eslint2 module`, + successMessage: `vite-plugin-eslint2 installed successfully`, + errorMessage: `vite-plugin-eslint2 installation failed`, + }) + + await updateNuxtConfig('inject-eslint-devChcker') + } + + if (devServerChecker === 'Learn More') { + openExternalLink('https://eslint.nuxt.com/packages/module#dev-server-checker') } + } const configureStylelint = () => { diff --git a/src/commands/Store.ts b/src/commands/Store.ts index 96571cb..52832ae 100644 --- a/src/commands/Store.ts +++ b/src/commands/Store.ts @@ -8,7 +8,7 @@ import { isModuleConfigured, getInstallationCommand, runCommand, - addNuxtModule, + updateNuxtConfig, isDependencyInstalled } from '../utils' import { vuexContent } from '../templates' @@ -31,7 +31,7 @@ async function detectPiniaModule() { } if (!isConfigured) { - await addNuxtModule(moduleName) + await updateNuxtConfig('add-module', moduleName) } } diff --git a/src/sideBar/index.ts b/src/sideBar/index.ts index ccddedd..37f1ed1 100644 --- a/src/sideBar/index.ts +++ b/src/sideBar/index.ts @@ -13,7 +13,7 @@ import { getProjectScripts, newTerminal, detectPackageManagerByName, - addNuxtModule, + updateNuxtConfig, removeNuxtModule, getInstallationCommand, getOutdatedPackages, @@ -269,7 +269,7 @@ export class ModulesView implements vscode.WebviewViewProvider { } private async addNuxtModule(module: any) { - await addNuxtModule(module) + await updateNuxtConfig('add-module', module) .then(async () => { this.postMessage({ command: 'moduleInstalled', diff --git a/src/templates/index.ts b/src/templates/index.ts index 4675eb5..af47dc7 100644 --- a/src/templates/index.ts +++ b/src/templates/index.ts @@ -1,4 +1,4 @@ -import { eslintConfig, stylelintConfig, stylelintIgnore, eslintIgnore } from './linters' +import { eslintConfig, stylelintConfig, stylelintIgnore } from './linters' import { unoCSSConfig, windiCSSConfig, tailwindCSSJSConfig, tailwindCSSTSConfig, tailwindCSSFile, vuetifyConfigFile } from './css' import { nitroDefaultTemplate, @@ -24,7 +24,6 @@ export { eslintConfig, stylelintConfig, stylelintIgnore, - eslintIgnore, nitroDefaultTemplate, nuxtMiddlewareTemplate, composableTemplate, diff --git a/src/templates/linters.ts b/src/templates/linters.ts index c06c8e3..e130f46 100644 --- a/src/templates/linters.ts +++ b/src/templates/linters.ts @@ -1,6 +1,9 @@ -const eslintConfig = `{ - "extends": ["@nuxtjs/eslint-config-typescript"] -} +const eslintConfig = `// @ts-check +import withNuxt from './.nuxt/eslint.config.mjs' + +export default withNuxt( + // Your custom configs here +) ` const stylelintConfig = `{ @@ -10,12 +13,5 @@ const stylelintConfig = `{ const stylelintIgnore = `node_modules` -const eslintIgnore = `dist -node_modules -schema -**/*.tmpl.* -sw.js -` - -export { eslintConfig, stylelintConfig, stylelintIgnore, eslintIgnore } \ No newline at end of file +export { eslintConfig, stylelintConfig, stylelintIgnore } \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts index 6dc1c2d..f469743 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -12,14 +12,14 @@ import { } from './global' import { - addNuxtModule, removeNuxtModule, getNuxtVersion, isNuxtTwo, hasServerDir, findNuxtConfig, isNuxtProject, - isModuleConfigured + isModuleConfigured, + updateNuxtConfig, } from './nuxt' import { @@ -45,6 +45,8 @@ import { removePackage, managePackageVersion } from './dependency' import { createConfigWatcher } from './watchers' +import { injectPkgJSONScript } from './pkgJSON' + export { openExternalLink, getProjectDependencies, @@ -72,7 +74,6 @@ export { newTerminal, getNonce, getUri, - addNuxtModule, removeNuxtModule, runCommand, logger, @@ -90,5 +91,7 @@ export { openFolder, quickOpenButtons, isModuleConfigured, - isDependencyInstalled + isDependencyInstalled, + injectPkgJSONScript, + updateNuxtConfig, } diff --git a/src/utils/nuxt.ts b/src/utils/nuxt.ts index 19a53f3..ec8b480 100644 --- a/src/utils/nuxt.ts +++ b/src/utils/nuxt.ts @@ -51,40 +51,6 @@ export const isModuleConfigured = async (module: string) => { } -export const addNuxtModule = async (module: string) => { - try { - const nuxtConfigPath = findNuxtConfig(); - const nuxtConfig = readFileSync(`${nuxtConfigPath}`, 'utf-8'); - - const mod = parseModule(nuxtConfig, { sourceFileName: nuxtConfigPath }); - const config = - mod.exports.default.$type === 'function-call' - ? mod.exports.default.$args[0] - : mod.exports.default; - - let layer = await isLayer(module); - - if (layer) { - config.extends ||= []; - if (!config.extends.includes(module)) { - config.extends.push(module); - } - } else { - config.modules ||= []; - if (!config.modules.includes(module)) { - config.modules.push(module); - } - } - - const generated = mod.generate().code; - writeFileSync(`${nuxtConfigPath}`, `${trimEnd(generated)}\n`, 'utf-8'); - } catch (error) { - window.showErrorMessage( - `${module} failed to install, please install it manually, ${error}` - ); - } -}; - export const removeNuxtModule = async (module: any) => { try { const nuxtConfigPath = findNuxtConfig(); @@ -219,28 +185,6 @@ export const isNuxtTwo = (): boolean | undefined => { } }; -const updateNuxtConfig = (update: (config: any) => void) => { - try { - const nuxtConfigPath = findNuxtConfig(); - const nuxtConfig = readFileSync(`${nuxtConfigPath}`, 'utf-8'); - - const mod = parseModule(nuxtConfig, { sourceFileName: nuxtConfigPath }); - const config = - mod.exports.default.$type === 'function-call' - ? mod.exports.default.$args[0] - : mod.exports.default; - - update(config); - - const generated = mod.generate().code; - writeFileSync(`${nuxtConfigPath}`, `${trimEnd(generated)}\n`, 'utf-8'); - } catch (error) { - window.showErrorMessage( - `Failed to update nuxt config, please update it manually, ${error}` - ); - } -}; - const scanNuxtDirectories = async () => { let projectSrcDir = `${await projectSrcDirectory()}`; @@ -318,4 +262,78 @@ function parseTsconfigPaths(tsconfigPaths: TsconfigPaths): {} { } return parsedTsconfigPaths; -} \ No newline at end of file +} + + +export const getNuxtConfig = async (action: 'inject-eslint-devChcker', input?: string) => { + try { + const nuxtConfigPath = findNuxtConfig(); + const nuxtConfig = readFileSync(`${nuxtConfigPath}`, 'utf-8'); + + const mod = parseModule(nuxtConfig, { sourceFileName: nuxtConfigPath }); + const config = + mod.exports.default.$type === 'function-call' + ? mod.exports.default.$args[0] + : mod.exports.default; + + if (action === 'inject-eslint-devChcker') { + config.eslint ||= {}; + config.eslint.checker = true; + } + + + const generated = mod.generate().code; + writeFileSync(`${nuxtConfigPath}`, `${trimEnd(generated)}\n`, 'utf-8'); + + + } catch (error) { + window.showErrorMessage( + `Failed to update nuxt config.` + ); + } +}; + + +export const updateNuxtConfig = async (action: 'inject-eslint-devChcker' | 'add-module', input?: string) => { + try { + const nuxtConfigPath = findNuxtConfig(); + const nuxtConfig = readFileSync(`${nuxtConfigPath}`, 'utf-8'); + + const mod = parseModule(nuxtConfig, { sourceFileName: nuxtConfigPath }); + const config = + mod.exports.default.$type === 'function-call' + ? mod.exports.default.$args[0] + : mod.exports.default; + + if (action === 'inject-eslint-devChcker') { + config.eslint ||= {}; + config.eslint.checker = true; + } + + if (action === 'add-module') { + let layer = await isLayer(input); + + if (layer) { + config.extends ||= []; + if (!config.extends.includes(input)) { + config.extends.push(input); + } + } else { + config.modules ||= []; + if (!config.modules.includes(input)) { + config.modules.push(input); + } + } + } + + + const generated = mod.generate().code; + writeFileSync(`${nuxtConfigPath}`, `${trimEnd(generated)}\n`, 'utf-8'); + + + } catch (error) { + window.showErrorMessage( + `Failed to update nuxt config.` + ); + } +}; diff --git a/src/utils/pkgJSON.ts b/src/utils/pkgJSON.ts new file mode 100644 index 0000000..f17eff2 --- /dev/null +++ b/src/utils/pkgJSON.ts @@ -0,0 +1,17 @@ + +import { projectRootDirectory } from './' +import { readPackageJSON, writePackageJSON } from 'pkg-types' + +export const injectPkgJSONScript = async (scriptName: string, script: string) => { + const packageJsonPath = `${projectRootDirectory()}/package.json` + const packageJson = await readPackageJSON(packageJsonPath) + if (packageJson) { + if (packageJson.scripts) { + if (!packageJson.scripts[scriptName]) { + packageJson.scripts[scriptName] = script + await writePackageJSON(packageJsonPath, packageJson) + } + + } + } +}