Skip to content

Commit

Permalink
feat: added plugin command and support for add githook or prettier pl…
Browse files Browse the repository at this point in the history
…ugin
  • Loading branch information
Aiden-FE committed Mar 22, 2024
1 parent 7019c6d commit adea3df
Show file tree
Hide file tree
Showing 9 changed files with 337 additions and 4 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@

> Command line interfaces for Compass CLI
## Getting Started

`npm install -g @compass-aiden/cli` 全局安装cli

`compass --help` 获取帮助信息

`compass update` Cli更新检查

`compass create` 创建项目, `compass create --help` 可以获得更多可选项说明, 支持创建的项目如下:

| Name | Description |
| :------: | :----------------: |
| Vue | Vue项目 |
| React | React项目 |
| Angular | Angular项目 |
| Next | Next SSR项目 |
| Turbo | Turbo monorepo项目 |
| Uniapp | Uniapp 跨端项目 |
| Electron | Electron桌面端项目 |
| Nest | Nest后端项目 |
| Utils | 实用程序工具库 |

`compass plugin` 向项目添加或删除插件, `compass plugin --help` 可以获得更多可选项说明

## Contributes

### Install
Expand Down
6 changes: 3 additions & 3 deletions src/commands/create.cmd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default (program: Command) => {
.description('快速创建项目')
.option(
'-T, --project-type [projectType]',
'需要创建的项目类型, turboMonorepo,uniapp,vue,react,electron,nest,next,utils,angular',
'需要创建的项目类型\n\t\t\t\t\t- vue\tVue项目\n\t\t\t\t\t- react\tReact项目\n\t\t\t\t\t- angular\tAngular项目\n\t\t\t\t\t- next\tNext SSR项目\n\t\t\t\t\t- turboMonorepo\tTurbo monorepo项目\n\t\t\t\t\t- uniapp\tUniapp跨端项目\n\t\t\t\t\t- electron\tElectron桌面端项目\n\t\t\t\t\t- nest\tNest后端项目\n\t\t\t\t\t- utils\t实用程序工具库',
)
.option('-M, --pkg-manager [pkgManager]', '指定npm管理器. npm,yarn,pnpm')
.action(async (options: CommandOptions) => {
Expand All @@ -67,11 +67,11 @@ export default (program: Command) => {
value: 'angular',
},
{
name: 'Next SSR及SPA项目',
name: 'Next SSR项目',
value: 'next',
},
{
name: 'Turbo monorepo',
name: 'Turbo monorepo项目',
value: 'turboMonorepo',
},
{
Expand Down
1 change: 1 addition & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as updateCommand } from './update.cmd';
export { default as createCommand } from './create.cmd';
export { default as pluginCommand } from './plugin.cmd';
112 changes: 112 additions & 0 deletions src/commands/plugin.cmd.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { join } from 'path';
import { Command } from 'commander';
import chalk from 'chalk';
import inquirer from 'inquirer';
import { scanDependencyManager } from '@compass-aiden/helpers/cjs';
import { addGithooksPlugin, addPrettierPlugin, removeGithooksPlugin, removePrettierPlugin } from '@/utils';
import { PkgManager } from '@/interfaces';

/**
* @description Compass 项目插件管理
* @example
* ```bash
* compass plugin [options] # 添加或删除插件
* compass plugin --help # 获取更多帮助信息
* ```
*/
export default (program: Command) => {
program
.command('plugin')
.description('项目插件管理')
.option('-T, --type [type]', '操作类型\n\t\t\t- add\t为项目添加插件\n\t\t\t- remove\t为项目移除插件')
.option(
'-N, --name [name]',
'插件名称\n\t\t\t- githooks\t使用SimpleGitHooks基于githooks对项目添加自动化任务\n\t\t\t- prettier\tPrettier 代码格式化',
)
.option('-P, --path [path]', '项目路径,默认为当前路径')
.action(async ({ name: inputName, type: inputType, path: inputPath }) => {
// 确认操作的类型
let type: 'add' | 'remove' = inputType;
let basePath = inputPath || undefined;
if (basePath) {
basePath = basePath.startsWith('/') ? basePath : join(process.cwd(), basePath);
}
if (!['add', 'remove'].includes(type)) {
const { type: selectedType } = await inquirer.prompt([
{
type: 'list',
name: 'type',
message: `请选择您的操作类型`,
choices: [
{
name: '为项目添加插件',
value: 'add',
},
{
name: '为项目移除插件',
value: 'remove',
},
],
},
]);
type = selectedType;
}

// 确认要操作的插件
const { name } = inputName
? { name: inputName }
: await inquirer.prompt([
{
type: 'list',
name: 'name',
message: `请选择您要${type === 'add' ? '添加' : '删除'}的插件`,
choices: [
{
name: '使用SimpleGitHooks基于githooks对项目添加自动化任务',
value: 'githooks',
},
{
name: 'Eslint 基于Airbnb规范对代码进行检查',
value: 'eslint',
},
{
name: 'Prettier 代码格式化',
value: 'prettier',
},
{
name: 'Commitlint 提交信息格式校验,该插件依赖于githooks插件',
value: 'commitlint',
},
{
name: 'PrettyQuick 在Commit前仅对变更文件进行快速格式化,该插件依赖于githooks及prettier插件',
value: 'prettyquick',
},
],
},
]);

// 处理选择的插件
if (name === 'githooks') {
const action = {
add: addGithooksPlugin,
remove: removeGithooksPlugin,
};
const pkgManager: PkgManager = scanDependencyManager({ cwd: basePath });
await action[type]({ pkgManager, cwd: basePath });
return;
}

if (name === 'prettier') {
const action = {
add: addPrettierPlugin,
remove: removePrettierPlugin,
};
const pkgManager: PkgManager = scanDependencyManager({ cwd: basePath });
await action[type]({ pkgManager, cwd: basePath });
return;
}

// eslint-disable-next-line no-console
console.log(chalk.red(`❌ ${name}不是可用的插件名称, 请通过 'compass plugin --help' 获取更多帮助信息`));
});
};
11 changes: 11 additions & 0 deletions src/utils/delete-files-sync.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { unlinkSync, existsSync } from 'fs';

// eslint-disable-next-line import/prefer-default-export
export function deleteFilesSync(filesPath: string | string[]) {
const files = Array.isArray(filesPath) ? filesPath : [filesPath];
files.forEach((file) => {
if (existsSync(file)) {
unlinkSync(file);
}
});
}
39 changes: 39 additions & 0 deletions src/utils/githooks.plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { execSync } from 'child_process';
import chalk from 'chalk';
import { PkgManager } from '@/interfaces';
import Logger from './logger';

export async function addGithooksPlugin(options?: { pkgManager?: PkgManager; cwd?: string }) {
const { pkgManager, cwd } = {
pkgManager: 'npm' as PkgManager,
...options,
};
const loading = Logger.createLoading();
loading.start(chalk.cyan('开始安装SimpleGitHooks插件'));
execSync(`${pkgManager} add -D simple-git-hooks`, { stdio: 'inherit', cwd });
execSync('npm pkg set simple-git-hooks={} --json', { stdio: 'inherit', cwd });
execSync('npm pkg set scripts.prepare="npx simple-git-hooks"', { stdio: 'inherit', cwd });
Logger.success(`Installed simple-git-hooks at ${cwd || process.cwd()}`);
Logger.success(`Set 'simple-git-hooks' fields at ${cwd || process.cwd()}/package.json`);
Logger.success(`Set 'scripts.prepare' fields at ${cwd || process.cwd()}/package.json`);

loading.succeed(
chalk.green('SimpleGitHooks 插件安装完成\n使用文档参考: https://github.com/toplenboren/simple-git-hooks'),
);
}

export async function removeGithooksPlugin(options?: { pkgManager?: PkgManager; cwd?: string }) {
const { pkgManager, cwd } = {
pkgManager: 'npm' as PkgManager,
...options,
};
const loading = Logger.createLoading();
loading.start(chalk.cyan('开始移除SimpleGitHooks插件'));
execSync(`${pkgManager} remove -D simple-git-hooks`, { stdio: 'inherit', cwd });
execSync('npm pkg delete simple-git-hooks', { stdio: 'inherit', cwd });
execSync('npm pkg delete scripts.prepare', { stdio: 'inherit', cwd });
Logger.success(`Uninstalled simple-git-hooks at ${cwd || process.cwd()}`);
Logger.success(`Delete 'simple-git-hooks' fields at ${cwd || process.cwd()}/package.json`);
Logger.success(`Delete 'scripts.prepare' fields at ${cwd || process.cwd()}/package.json`);
loading.succeed(chalk.green('SimpleGitHooks 插件移除完成'));
}
11 changes: 10 additions & 1 deletion src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// create utils
export { default as createTurbo } from './create-turbo';
export { default as selectPkgManager } from './select-pkg-manager';
export { default as createUniapp } from './create-uniapp';
Expand All @@ -7,5 +8,13 @@ export { default as createElectron } from './create-electron';
export { default as createNest } from './create-nest';
export { default as createNext } from './create-next';
export { default as createUtils } from './create-utils';
export { default as batchCompileTemplates } from './batch-compile-templates';
export { default as createAngular } from './create-angular';

// tools
export { default as batchCompileTemplates } from './batch-compile-templates';
export { default as Logger } from './logger';

// plugin utils
export * from './githooks.plugin';
export * from './prettier.plugin';
export * from './delete-files-sync';
33 changes: 33 additions & 0 deletions src/utils/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import chalk from 'chalk';
import ora from 'ora';

export default class Logger {
static log(...args: unknown[]): void {
// eslint-disable-next-line no-console
console.log(...args);
}

static info(...args: unknown[]): void {
// eslint-disable-next-line no-console
console.info(...args.map((arg) => chalk.cyan(arg)));
}

static success(...args: unknown[]): void {
// eslint-disable-next-line no-console
console.log(...args.map((arg) => chalk.green(arg)));
}

static warn(...args: unknown[]): void {
// eslint-disable-next-line no-console
console.warn(...args.map((arg) => chalk.yellow(arg)));
}

static error(...args: unknown[]): void {
// eslint-disable-next-line no-console
console.error(...args.map((arg) => chalk.red(arg)));
}

static createLoading() {
return ora();
}
}
104 changes: 104 additions & 0 deletions src/utils/prettier.plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { execSync } from 'child_process';
import { join } from 'path';
import chalk from 'chalk';
import { createFileSync } from '@compass-aiden/helpers/cjs';
import { PkgManager } from '@/interfaces';
import Logger from './logger';
import { deleteFilesSync } from './delete-files-sync';

const PRETTIERRC_DATA = `{
"printWidth": 120,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"quoteProps": "as-needed",
"jsxSingleQuote": false,
"trailingComma": "all",
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"endOfLine": "lf"
}
`;

const PRETTIERIGNORE_DATA = `# TypeScript v1 declaration files
typings/
types/
# Output
dist
coverage
*.tgz
.next
.nuxt
tmp
out-tsc
stats.html
# lockfile
pnpm-lock.yaml
yarn.lock
package-lock.json
# Cache
.npm
.eslintcache
temp
node_modules
`;

export async function addPrettierPlugin(options?: { pkgManager?: PkgManager; cwd?: string }) {
const { pkgManager, cwd } = {
pkgManager: 'npm' as PkgManager,
...options,
};
const execOption = { stdio: 'inherit' as const, cwd };
const loading = Logger.createLoading();
loading.start(chalk.cyan('开始安装 Prettier 插件'));

const hasEslint = execSync('npm pkg get devDependencies.eslint', { cwd }).toString().trim();
const isHasEslint = !(hasEslint === '{}' || hasEslint === '');
execSync(
`${pkgManager} add -D prettier${isHasEslint ? ' eslint-config-prettier eslint-plugin-prettier' : ''}`,
execOption,
);
execSync('npm pkg set scripts.format="prettier --write src"', execOption);
createFileSync('.prettierrc.json', PRETTIERRC_DATA, { cwd });
createFileSync('.prettierignore', PRETTIERIGNORE_DATA, { cwd });

Logger.success(
`Installed prettier${isHasEslint ? ' eslint-config-prettier eslint-plugin-prettier' : ''} at ${cwd || process.cwd()}`,
);
Logger.success(`Set 'scripts.format' fields at ${cwd || process.cwd()}/package.json`);
Logger.success(`Created file at ${cwd || process.cwd()}/.prettierrc.json`);
Logger.success(`Created file at ${cwd || process.cwd()}/.prettierignore`);
loading.succeed(chalk.green('成功安装 Prettier 插件'));
}

export async function removePrettierPlugin(options?: { pkgManager?: PkgManager; cwd?: string }) {
const { pkgManager, cwd } = {
pkgManager: 'npm' as PkgManager,
...options,
};
const execOption = { stdio: 'inherit' as const, cwd };
const loading = Logger.createLoading();
loading.start(chalk.cyan('开始移除 Prettier 插件'));

const hasEslint = execSync('npm pkg get devDependencies.eslint', { cwd }).toString().trim();
const isHasEslint = !(hasEslint === '{}' || hasEslint === '');
execSync(
`${pkgManager} remove prettier${isHasEslint ? ' eslint-config-prettier eslint-plugin-prettier' : ''}`,
execOption,
);
execSync('npm pkg delete scripts.format', execOption);
deleteFilesSync([join(cwd || './', '.prettierrc.json'), join(cwd || './', '.prettierignore')]);

Logger.success(
`Uninstalled prettier${isHasEslint ? ' eslint-config-prettier eslint-plugin-prettier' : ''} at ${cwd || process.cwd()}`,
);
Logger.success(`Delete 'scripts.format' fields at ${cwd || process.cwd()}/package.json`);
Logger.success(`Delete file at ${cwd || process.cwd()}/.prettierrc.json`);
Logger.success(`Delete file at ${cwd || process.cwd()}/.prettierignore`);
loading.succeed(chalk.green('成功移除 Prettier 插件'));
}

0 comments on commit adea3df

Please sign in to comment.