From 89e41078001a907672035a65c388cf70596a8df9 Mon Sep 17 00:00:00 2001 From: xion Date: Fri, 15 Nov 2024 22:03:13 +0800 Subject: [PATCH] feat: add config set and npm config --- package.json | 2 +- src/command/config.ts | 118 +++++++++++++++++++++-- src/command/npm.ts | 214 ++++++++++++++++++++++++++++++++++++++++++ src/index.ts | 1 + src/module/chalk.ts | 2 + src/uitls/file.ts | 9 ++ 6 files changed, 337 insertions(+), 9 deletions(-) create mode 100644 src/command/npm.ts create mode 100644 src/module/chalk.ts create mode 100644 src/uitls/file.ts diff --git a/package.json b/package.json index db89551..816a7be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kevisual/envision-cli", - "version": "0.0.4", + "version": "0.0.5", "description": "envision command tools", "main": "dist/index.js", "type": "module", diff --git a/src/command/config.ts b/src/command/config.ts index da667ae..bcdb15b 100644 --- a/src/command/config.ts +++ b/src/command/config.ts @@ -2,16 +2,22 @@ import { program as app, Command } from '@/program.ts'; import { checkFileExists, getConfig, writeConfig } from '@/module/index.ts'; import path from 'path'; import fs from 'fs'; +import { chalk } from '@/module/chalk.ts'; +import inquirer from 'inquirer'; const command = new Command('config') .description('') .option('-d, --dev ', 'Specify dev') - .option('-l --list', 'list config') + .option('-s --set ', 'set config') + .option('-g --get ', 'get config') + .option('-r --remove ', 'remove config') + .option('-v --value ', 'value') .option('-w --workdir ', 'web config') .action(async (options) => { const { dev, list, workdir } = options || {}; let config = getConfig(); let flag = false; + const execPath = process.cwd(); if (dev === 'true' || dev === 'false') { flag = true; const config = getConfig(); @@ -21,9 +27,8 @@ const command = new Command('config') config.dev = false; } } - if (options.workdir) { + if (workdir) { let finalPath: string; - flag = true; const workdir = options.workdir; if (workdir.startsWith('/')) { @@ -31,21 +36,118 @@ const command = new Command('config') finalPath = workdir; } else { // 否则,处理为相对路径 - finalPath = path.resolve(workdir); + finalPath = path.join(execPath, workdir); } if (!checkFileExists(finalPath)) { console.log('路径不存在'); fs.mkdirSync(finalPath, { recursive: true }); } - config.workdir = finalPath; + const answers = await inquirer.prompt([ + { + type: 'confirm', + name: 'confirm', + message: `Are you sure you want to set the workdir to: ${finalPath}?`, + default: false, + }, + ]); + if (answers.confirm) { + flag = true; + config.workdir = finalPath; + console.log(chalk.green(`set workdir success:`, finalPath)); + } else { + console.log('Cancel set workdir'); + } } - if (list) { - const config = getConfig(); - console.log('config', config); + if (options.set) { + const key = options.set; + let value = options.value; + const answer = await inquirer.prompt([ + { + type: 'input', + name: 'value', + message: `Enter your ${key}:(current: ${config[key]})`, + when: () => !value, + }, + ]); + value = answer.value || value; + if (key && value) { + flag = true; + config[key] = value; + } + } + if (options.remove) { + const key = options.remove; + if (key) { + flag = true; + delete config[key]; + } + } + + if (flag) { + writeConfig(config); + } + }); + +const setCommand = new Command('set') + .argument('') + .argument('[value]', 'value', 'not_input') + .description('set config') + .action(async (key, value) => { + const config = getConfig(); + if (!key) { + console.log('key is empty'); + return; + } + let flag = false; + const answer = await inquirer.prompt([ + { + type: 'input', + name: 'value', + message: `Enter your ${key}:(current: ${config[key]})`, + when: () => value === 'not_input', + }, + ]); + value = answer.value || value; + if (key && value) { + flag = true; + console.log(chalk.green(`set ${key} success:`, value)); + config[key] = value; } if (flag) { writeConfig(config); } }); +command.addCommand(setCommand); +const getCommand = new Command('get') + .argument('[key]', 'key') + .description('get config') + .action(async (key) => { + const config = getConfig(); + const keys = Object.keys(config); + const answer = await inquirer.prompt([ + { + type: 'input', + name: 'key', + message: `Enter your key:(keys: ${JSON.stringify(keys)})`, + when: () => !key, + }, + ]); + key = answer.key || key; + + if (config[key]) { + console.log(chalk.green(`get ${key}:`)); + console.log(config[key]); + } else { + console.log(chalk.red(`not found ${key}`)); + } + }); +command.addCommand(getCommand); + +const list = new Command('list').action(async () => { + const config = getConfig(); + console.log(chalk.green('config', JSON.stringify(config, null, 2))); +}); +command.addCommand(list); + app.addCommand(command); diff --git a/src/command/npm.ts b/src/command/npm.ts new file mode 100644 index 0000000..21fe2c1 --- /dev/null +++ b/src/command/npm.ts @@ -0,0 +1,214 @@ +import { program, Command } from '@/program.ts'; +import { chalk } from '../module/chalk.ts'; +import path from 'path'; +import { spawn } from 'child_process'; +import { fileIsExist } from '@/uitls/file.ts'; +import { getConfig } from '@/module/get-config.ts'; +import fs from 'fs'; +import inquirer from 'inquirer'; + +const command = new Command('npm') + .description('npm command show publish and set .npmrc') + .option('-p --publish ', 'publish') + .action(async (options) => { + const { publish } = options || {}; + const config = getConfig(); + let cmd = ''; + const execPath = process.cwd(); + if (publish) { + const packageJson = path.resolve(execPath, 'package.json'); + switch (publish) { + case 'me': + cmd = 'npm publish --registry https://npm.xiongxiao.me'; + console.log(chalk.green(cmd)); + break; + case 'npm': + cmd = 'npm publish --registry https://registry.npmjs.org'; + console.log(chalk.green(cmd)); + break; + default: + cmd = 'npm publish --registry https://npm.xiongxiao.me'; + console.log(chalk.green(cmd)); + break; + } + if (fileIsExist(packageJson)) { + const keys = Object.keys(config).filter((key) => key.includes('NPM_TOKEN')); + const tokenEnv = keys.reduce((prev, key) => { + return { + ...prev, + [key]: config[key], + }; + }, {}); + const child = spawn(cmd, { + shell: true, + cwd: execPath, + env: { + ...process.env, // 保留当前环境变量 + ...tokenEnv, + }, + }); + child.stdout.on('data', (data) => { + console.log(chalk.green(`${data}`)); + }); + child.stderr.on('data', (data) => { + // 过滤掉 'npm notice' 或者其他信息 + if (data.toString().includes('npm notice')) { + console.log(chalk.yellow(`notice: ${data}`)); + } else { + console.error(`stderr: ${data}`); + } + }); + child.on('close', (code) => { + // console.log(`child process exited with code ${code}`); + }); + } else { + console.error(chalk.red('package.json not found')); + } + } + }); +const publish = new Command('publish') + .argument('[registry]') + .description('publish npm') + .action(async (registry) => { + const answer = await inquirer.prompt([ + { + type: 'list', + name: 'publish', + message: 'Select the registry to publish', + choices: [ + { + name: 'me', + value: 'me', + }, + { + name: 'npm', + value: 'npm', + }, + ], + when: !registry, + }, + ]); + registry = registry || answer.publish; + const config = getConfig(); + let cmd = ''; + const execPath = process.cwd(); + if (registry) { + const packageJson = path.resolve(execPath, 'package.json'); + switch (registry) { + case 'me': + cmd = 'npm publish --registry https://npm.xiongxiao.me'; + console.log(chalk.green(cmd)); + break; + case 'npm': + cmd = 'npm publish --registry https://registry.npmjs.org'; + console.log(chalk.green(cmd)); + break; + default: + cmd = 'npm publish --registry https://npm.xiongxiao.me'; + console.log(chalk.green(cmd)); + break; + } + if (fileIsExist(packageJson)) { + const keys = Object.keys(config).filter((key) => key.includes('NPM_TOKEN')); + const tokenEnv = keys.reduce((prev, key) => { + return { + ...prev, + [key]: config[key], + }; + }, {}); + const child = spawn(cmd, { + shell: true, + cwd: execPath, + env: { + ...process.env, // 保留当前环境变量 + ...tokenEnv, + }, + }); + child.stdout.on('data', (data) => { + console.log(chalk.green(`${data}`)); + }); + child.stderr.on('data', (data) => { + // 过滤掉 'npm notice' 或者其他信息 + if (data.toString().includes('npm notice')) { + console.log(chalk.yellow(`notice: ${data}`)); + } else { + console.error(`stderr: ${data}`); + } + }); + child.on('close', (code) => { + // console.log(`child process exited with code ${code}`); + }); + } else { + console.error(chalk.red('package.json not found')); + } + } + }); + +command.addCommand(publish); + +const getnpmrc = new Command('get').action(async () => { + const execPath = process.cwd(); + const npmrcPath = path.resolve(execPath, '.npmrc'); + if (fileIsExist(npmrcPath)) { + const npmrcContent = fs.readFileSync(npmrcPath, 'utf-8'); + // console.log(chalk.green('get .npmrc success')); + console.log(npmrcContent); + } +}); +command.addCommand(getnpmrc); + +const npmrc = new Command('set') + .description('set .npmrc') + .option('-f ') + .action(async (options) => { + const config = getConfig(); + const npmrcContent = + config?.npmrc || + `//npm.xiongxiao.me/:_authToken=\${ME_NPM_TOKEN} +@abearxiong:registry=https://npm.pkg.github.com +//registry.npmjs.org/:_authToken=\${NPM_TOKEN} +@kevisual:registry=https://npm.xiongxiao.me`; + const execPath = process.cwd(); + const npmrcPath = path.resolve(execPath, '.npmrc'); + let writeFlag = false; + if (fileIsExist(npmrcPath)) { + if (options.force) { + writeFlag = true; + } else { + const answer = await inquirer.prompt([ + { + type: 'confirm', + name: 'confirm', + message: `Are you sure you want to overwrite the .npmrc file?`, + default: false, + }, + ]); + if (answer.confirm) { + writeFlag = true; + } + } + return; + } else { + writeFlag = true; + } + if (writeFlag) { + fs.writeFileSync(npmrcPath, npmrcContent); + console.log(chalk.green('write .npmrc success')); + } + }); +command.addCommand(npmrc); + +const remove = new Command('remove').description('remove .npmrc').action(async () => { + const execPath = process.cwd(); + const npmrcPath = path.resolve(execPath, '.npmrc'); + if (fileIsExist(npmrcPath)) { + fs.unlinkSync(npmrcPath); + console.log(chalk.green('remove .npmrc success')); + } else { + console.log(chalk.green('.npmrc success')); + } +}); +command.addCommand(remove); + +// +program.addCommand(command); diff --git a/src/index.ts b/src/index.ts index 80ec394..b4b48b2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,7 @@ import './command/serve.ts'; import './command/config.ts'; import './command/web.ts'; import './command/router.ts'; +import './command/npm.ts'; // program.parse(process.argv); diff --git a/src/module/chalk.ts b/src/module/chalk.ts new file mode 100644 index 0000000..ebd384e --- /dev/null +++ b/src/module/chalk.ts @@ -0,0 +1,2 @@ +import { Chalk } from 'chalk'; +export const chalk = new Chalk({ level: 3 }); diff --git a/src/uitls/file.ts b/src/uitls/file.ts new file mode 100644 index 0000000..171158f --- /dev/null +++ b/src/uitls/file.ts @@ -0,0 +1,9 @@ +import fs from 'fs'; +export const fileIsExist = (filePath: string) => { + try { + fs.accessSync(filePath, fs.constants.F_OK); + return true; + } catch (error) { + return false; + } +};