├── .eslintignore ├── .gitignore ├── typings └── json.d.ts ├── .prettierignore ├── dist ├── assets │ ├── icon.png │ └── git.svg ├── package.json ├── README.md ├── gacm.js └── gnrm.js ├── package ├── assets │ ├── icon.png │ └── git.svg ├── commands │ ├── common │ │ └── useVersion.ts │ ├── gacm │ │ ├── index.ts │ │ ├── useAdd.ts │ │ ├── useDelete.ts │ │ ├── useAlias.ts │ │ ├── useUse.ts │ │ └── useLs.ts │ └── gnrm │ │ ├── index.ts │ │ ├── useAdd.ts │ │ ├── useDelete.ts │ │ ├── useAlias.ts │ │ ├── useUse.ts │ │ ├── useTest.ts │ │ └── useLs.ts ├── config │ ├── path.ts │ └── registry.ts ├── utils │ ├── log.ts │ ├── shell.ts │ ├── tools.ts │ ├── getUserList.ts │ └── helper.ts ├── package.json ├── type │ └── shell.type.ts ├── gacm.ts └── gnrm.ts ├── .husky ├── pre-commit └── commit-msg ├── .prettierrc ├── .lintstagedrc ├── .eslintrc.js ├── changeloger.config.js ├── tsconfig.json ├── script └── release.ts ├── .github ├── workflows │ └── release.yml └── ISSUE_TEMPLATE │ ├── feature-request.yml │ └── bug-report.yml ├── .commitlintrc.js ├── LICENSE ├── package.json ├── README-zh_CN.md ├── README.md └── CHANGELOG.md /.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /typings/json.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.json'; 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | /*.* 4 | .prettierignore -------------------------------------------------------------------------------- /dist/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinfuy/gacm/HEAD/dist/assets/icon.png -------------------------------------------------------------------------------- /package/assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinfuy/gacm/HEAD/package/assets/icon.png -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx commitlint --edit $1 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "singleQuote": true, 4 | "endOfLine": "lf", 5 | "semi": true 6 | } -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "package/**/*.{js,ts,json,css,vue}": [ 3 | "eslint -c ./.eslintrc.js --fix --ext .jsx,.js,.tsx,.ts,.vue" 4 | ] 5 | } -------------------------------------------------------------------------------- /package/commands/common/useVersion.ts: -------------------------------------------------------------------------------- 1 | import pkg from '../../package.json'; 2 | 3 | export const useVersion = () => { 4 | return pkg.version; 5 | }; 6 | -------------------------------------------------------------------------------- /package/commands/gacm/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useLs'; 2 | export * from './useDelete'; 3 | export * from './useAdd'; 4 | export * from './useAlias'; 5 | export * from './useUse'; 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@alqmc/eslint-config-ts'], 3 | rules: { 4 | 'operator-linebreak': ['error', 'before', { overrides: { '?': 'ignore', ':': 'ignore' } }] 5 | } 6 | }; 7 | -------------------------------------------------------------------------------- /package/commands/gnrm/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useLs'; 2 | export * from './useUse'; 3 | export * from './useAdd'; 4 | export * from './useAlias'; 5 | export * from './useDelete'; 6 | export * from './useTest'; 7 | -------------------------------------------------------------------------------- /package/commands/gacm/useAdd.ts: -------------------------------------------------------------------------------- 1 | import { insertUser } from '../../utils/helper'; 2 | 3 | export interface AddCmd { 4 | name: string 5 | email: string 6 | alias: string 7 | } 8 | // 相同的情况直接覆盖更新 9 | export const useAdd = async (cmd: AddCmd) => { 10 | if (cmd.name && cmd.email) 11 | await insertUser(cmd.name, cmd.email, cmd.alias); 12 | }; 13 | -------------------------------------------------------------------------------- /package/config/path.ts: -------------------------------------------------------------------------------- 1 | // 基于打包后的路径 dist 2 | import { join, resolve } from 'path'; 3 | export const rootPath = __dirname; 4 | export const outputPath = __dirname; 5 | export const enterPath = resolve(rootPath, 'package'); 6 | export const HOME 7 | = process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME'] || ''; 8 | export const registriesPath = join(HOME, '.gacmrc'); 9 | -------------------------------------------------------------------------------- /package/commands/gnrm/useAdd.ts: -------------------------------------------------------------------------------- 1 | import { insertRegistry } from '../../utils/helper'; 2 | 3 | export interface AddCmd { 4 | name: string 5 | registry: string 6 | alias: string 7 | } 8 | // 相同的情况直接覆盖更新 9 | export const useAdd = async (cmd: AddCmd) => { 10 | if (cmd.name && cmd.registry) { 11 | const alias = cmd.alias || cmd.name; 12 | await insertRegistry(cmd.name, alias, cmd.registry); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /changeloger.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | theme: 'simple', 3 | types: { 4 | feat: { title: 'Features' }, 5 | perf: { title: 'Performance Improvements' }, 6 | fix: { title: 'Bug Fixes' }, 7 | refactor: { title: 'Code Refactoring' }, 8 | docs: { title: 'ocumentation' } 9 | }, 10 | showContributors: false, 11 | showNotMatchComiit: false, 12 | repository: 'https://github.com/alqmc/gacm' 13 | }; 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "strict": true, 6 | "moduleResolution": "node", 7 | "allowSyntheticDefaultImports": true, 8 | "baseUrl": "dist", 9 | "esModuleInterop": true, 10 | "skipLibCheck": true, 11 | "forceConsistentCasingInFileNames": true 12 | }, 13 | "include": ["package", "typings", "build"], 14 | "exclude": ["node_modules"] 15 | } 16 | -------------------------------------------------------------------------------- /package/utils/log.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import { blue, green, red, yellow } from 'kolorist'; 3 | const success = (msg: string) => console.log(`\n${green(msg)}\n`); 4 | const error = (msg: string) => console.log(`\n${red(msg)}\n`); 5 | const warning = (msg: string) => console.log(`\n${yellow(msg)}\n`); 6 | const info = (msg: string) => console.log(`\n${blue(msg)}\n`); 7 | export const log = { 8 | success, 9 | error, 10 | warning, 11 | info 12 | }; 13 | -------------------------------------------------------------------------------- /package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gacm", 3 | "version": "1.2.11", 4 | "private": false, 5 | "description": "git account manage", 6 | "author": "kinfuy (https://github.com/kinfuy)", 7 | "license": "MIT", 8 | "repository": "https://github.com/kinfuy/gacm", 9 | "keywords": [ 10 | "git", 11 | "account", 12 | "manage" 13 | ], 14 | "bin": { 15 | "gacm": "gacm.js", 16 | "gnrm": "gnrm.js" 17 | }, 18 | "publishConfig": { 19 | "access": "public" 20 | }, 21 | "dependencies": { 22 | "cac": "^6.7.14", 23 | "execa": "5.1.1", 24 | "kolorist": "^1.5.1", 25 | "node-fetch": "2.6.6", 26 | "prompts": "^2.4.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /dist/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gacm", 3 | "version": "1.2.11", 4 | "private": false, 5 | "description": "git account manage", 6 | "author": "kinfuy (https://github.com/kinfuy)", 7 | "license": "MIT", 8 | "repository": "https://github.com/kinfuy/vite-plugin-shortcuts", 9 | "keywords": [ 10 | "git", 11 | "account", 12 | "manage" 13 | ], 14 | "bin": { 15 | "gacm": "gacm.js", 16 | "gnrm": "gnrm.js" 17 | }, 18 | "publishConfig": { 19 | "access": "public" 20 | }, 21 | "dependencies": { 22 | "cac": "^6.7.14", 23 | "execa": "5.1.1", 24 | "kolorist": "^1.5.1", 25 | "node-fetch": "2.6.6", 26 | "prompts": "^2.4.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /package/type/shell.type.ts: -------------------------------------------------------------------------------- 1 | export interface UserInfo { 2 | name: string 3 | email: string 4 | alias: string 5 | } 6 | 7 | export interface RegistryInfo { 8 | name: string 9 | alias: string 10 | home: string 11 | registry: string 12 | } 13 | export interface UserInfoJson { 14 | version: string 15 | users: Array 16 | registry?: Array 17 | } 18 | export interface UserOldInfoJson extends Record { 19 | key: UserInfo 20 | } 21 | 22 | export type PackageManagertype = 'pnpm' | 'npm' | 'cnpm' | 'yarn'; 23 | export interface NrmCmd { 24 | packageManager: PackageManagertype 25 | } 26 | 27 | export interface TestCmd { 28 | registry: string 29 | all: boolean 30 | } 31 | -------------------------------------------------------------------------------- /script/release.ts: -------------------------------------------------------------------------------- 1 | import execa from 'execa'; 2 | import prompts from 'prompts'; 3 | 4 | const run = (bin, args, opts = {}) => 5 | execa(bin, args, { stdio: 'inherit', ...opts }); 6 | 7 | const main = async () => { 8 | const { tag } = await prompts({ 9 | type: 'text', 10 | name: 'tag', 11 | message: '发布的版本' 12 | }); 13 | try { 14 | await run('git', ['tag', `v${tag}`]); 15 | await run('pnpm', ['log']); 16 | await run('git', ['add', '.']); 17 | await run('git', ['commit', '-m', `release: v${tag}`]); 18 | await run('git', ['push', 'github', 'master']); 19 | await run('git', ['push', 'github', `v${tag}`]); 20 | } 21 | catch (error) { 22 | process.exit(0); 23 | } 24 | }; 25 | main(); 26 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: npm-release 2 | on: 3 | push: 4 | tags: 5 | - 'v*' 6 | jobs: 7 | release: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | fetch-depth: 0 13 | - name: Set node 14 | uses: actions/setup-node@v3 15 | with: 16 | node-version: 16.x 17 | 18 | - name: changelog 19 | run: npx changelogithub@0.12 20 | env: 21 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 22 | 23 | - name: publish 24 | run: | 25 | cd dist 26 | npm config set //registry.npmjs.org/:_authToken=$NPM_TOKEN 27 | npm publish --access=public 28 | env: 29 | NPM_TOKEN: ${{secrets.NPM_TOKEN}} 30 | -------------------------------------------------------------------------------- /.commitlintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | rules: { 4 | 'type-enum': [ 5 | 2, 6 | 'always', 7 | [ 8 | 'build', 9 | 'other', 10 | 'docs', 11 | 'feat', 12 | 'fix', 13 | 'perf', 14 | 'refactor', 15 | 'revert', 16 | 'style', 17 | 'test', 18 | "ci", 19 | 'release', 20 | "chore", 21 | 'deps', 22 | ], 23 | ], 24 | 'type-case': [0], 25 | 'type-empty': [0], 26 | 'scope-empty': [0], 27 | 'scope-case': [0], 28 | 'subject-full-stop': [0, 'never'], 29 | 'subject-case': [0, 'never'], 30 | 'header-max-length': [0, 'always', 72], 31 | }, 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.yml: -------------------------------------------------------------------------------- 1 | name: ✨ Feature Request 2 | description: Propose new features to vue-simple-json to improve it. 3 | title: '[Feature]: ' 4 | labels: [feature] 5 | body: 6 | - type: textarea 7 | id: feature-solve 8 | attributes: 9 | label: What problem does this feature solve 10 | description: | 11 | Explain your use case, context, and rationale behind this feature request. More importantly, what is the end user experience you are trying to build that led to the need for this feature? 12 | placeholder: Please Input 13 | - type: textarea 14 | id: feature-api 15 | attributes: 16 | label: What does the proposed API look like 17 | description: | 18 | Describe how you propose to solve the problem and provide code samples of how the API would work once implemented. Note that you can use Markdown to format your code blocks. 19 | placeholder: Please Input 20 | -------------------------------------------------------------------------------- /package/utils/shell.ts: -------------------------------------------------------------------------------- 1 | import { spawn } from 'child_process'; 2 | import { cwd } from 'process'; 3 | import execa from 'execa'; 4 | 5 | export const run = (command: string, dir: string = cwd()) => { 6 | const [cmd, ...args] = command.split(' '); 7 | return new Promise((resolve, reject) => { 8 | const app = spawn(cmd, args, { 9 | cwd: dir, 10 | stdio: 'inherit', 11 | shell: process.platform === 'win32' 12 | }); 13 | const processExit = () => app.kill('SIGHUP'); 14 | 15 | app.on('close', (code) => { 16 | process.removeListener('exit', processExit); 17 | if (code === 0) 18 | resolve(); 19 | else 20 | reject(new Error(`command failed: \n command:${cmd} \n code:${code}`)); 21 | }); 22 | process.on('exit', processExit); 23 | }); 24 | }; 25 | export const execCommand = async (cmd: string, args: string[]) => { 26 | const res = await execa(cmd, args); 27 | return res.stdout.trim(); 28 | }; 29 | -------------------------------------------------------------------------------- /package/commands/gnrm/useDelete.ts: -------------------------------------------------------------------------------- 1 | import { registriesPath } from '../../config/path'; 2 | import { getFileUser, writeFileUser } from '../../utils/getUserList'; 3 | import { log } from '../../utils/log'; 4 | 5 | export const useDelete = async (name: string) => { 6 | const userConfig = await getFileUser(registriesPath); 7 | 8 | if (!userConfig) 9 | return log.error('no registry'); 10 | 11 | if (!userConfig.registry) 12 | return log.error('no registry'); 13 | 14 | const useRegistry = userConfig.registry.find(x => x.alias === name); 15 | 16 | if (!useRegistry) 17 | return log.error(`${name} not found`); 18 | 19 | for (let i = 0; i < userConfig.registry.length; i++) 20 | if (userConfig.registry[i].alias === name) { 21 | log.success( 22 | `[delete]: ${userConfig.registry[i].alias} ${userConfig.registry[i].registry}` 23 | ); 24 | userConfig.registry.splice(i, 1); 25 | } 26 | 27 | await writeFileUser(registriesPath, userConfig); 28 | }; 29 | -------------------------------------------------------------------------------- /package/commands/gacm/useDelete.ts: -------------------------------------------------------------------------------- 1 | import { registriesPath } from '../../config/path'; 2 | import { getFileUser, writeFileUser } from '../../utils/getUserList'; 3 | import { log } from '../../utils/log'; 4 | 5 | export const useDelete = async (name: string) => { 6 | const userList = await getFileUser(registriesPath); 7 | 8 | if (!userList) 9 | return log.error('no user'); 10 | 11 | const useUser = userList.users.find( 12 | x => x.alias === name || (!x.alias && x.name === name) 13 | ); 14 | 15 | if (!useUser) 16 | return log.error(`${name} not found`); 17 | 18 | for (let i = 0; i < userList.users.length; i++) 19 | if ( 20 | (!userList.users[i].alias && userList.users[i].name === name) 21 | || userList.users[i].alias === name 22 | ) { 23 | log.success( 24 | `[delete]: ${userList.users[i].alias}${ 25 | userList.users[i].alias !== userList.users[i].name 26 | ? `(${userList.users[i].name})` 27 | : '' 28 | }` 29 | ); 30 | 31 | userList.users.splice(i, 1); 32 | } 33 | 34 | await writeFileUser(registriesPath, userList); 35 | }; 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 alqmc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package/commands/gacm/useAlias.ts: -------------------------------------------------------------------------------- 1 | import { registriesPath } from '../../config/path'; 2 | import { getFileUser, writeFileUser } from '../../utils/getUserList'; 3 | import { log } from '../../utils/log'; 4 | import { isExistAlias } from '../../utils/helper'; 5 | import type { UserInfoJson } from '../../type/shell.type'; 6 | 7 | export const useAlias = async (origin: string, target: string) => { 8 | if (!origin || !target) 9 | return; 10 | 11 | let userList = await getFileUser(registriesPath); 12 | 13 | if (!userList) 14 | userList = { version: '', users: [] } as UserInfoJson; 15 | 16 | let changed = false; 17 | 18 | userList.users.forEach((x) => { 19 | if (x.alias === origin) { 20 | if (userList && !isExistAlias(userList?.users, target)) { 21 | x.alias = target; 22 | 23 | log.success(`[update]: ${origin}=>${x.alias} (${x.name})`); 24 | } 25 | else { 26 | log.error(`${target} is exist, please enter another one `); 27 | } 28 | 29 | changed = true; 30 | } 31 | }); 32 | 33 | if (!changed) 34 | return log.error(`${origin} not found`); 35 | 36 | await writeFileUser(registriesPath, userList); 37 | }; 38 | -------------------------------------------------------------------------------- /package/gacm.ts: -------------------------------------------------------------------------------- 1 | import cac from 'cac'; 2 | import { useAdd, useAlias, useDelete, useLs, useUse } from './commands/gacm'; 3 | import { useVersion } from './commands/common/useVersion'; 4 | 5 | const program = cac('gacm'); 6 | 7 | program.version(useVersion()); 8 | 9 | program.command('ls', '当前用户列表').action(useLs); 10 | 11 | program 12 | .command('use [name]', '切换用户') 13 | .option('-l, --local', '当前用户') 14 | .option('-g, --global', '全局用户') 15 | .option('-s, --system', '系统用户') 16 | .action(useUse); 17 | 18 | program 19 | .command('add', '添加用户') 20 | .option('-n, --name ', '用户名称') 21 | .option('-e, --email ', '用户邮箱') 22 | .option('-a, --alias ', '用户别名') 23 | .action(useAdd); 24 | 25 | program.command('alias ', '添加别名').action(useAlias); 26 | 27 | program.command('delete ', '删除用户').action(useDelete); 28 | 29 | program.help(); 30 | 31 | const init = async () => { 32 | try { 33 | program.parse(process.argv, { run: false }); 34 | await program.runMatchedCommand(); 35 | } 36 | catch (error: any) { 37 | console.error(error?.message || '未知错误'); 38 | program.outputHelp(); 39 | process.exit(0); 40 | } 41 | }; 42 | 43 | init(); 44 | -------------------------------------------------------------------------------- /package/commands/gnrm/useAlias.ts: -------------------------------------------------------------------------------- 1 | import { registriesPath } from '../../config/path'; 2 | import { getFileUser, writeFileUser } from '../../utils/getUserList'; 3 | import { log } from '../../utils/log'; 4 | import type { UserInfoJson } from '../../type/shell.type'; 5 | 6 | export const useAlias = async (origin: string, target: string) => { 7 | if (!origin || !target) 8 | return; 9 | 10 | let useConfig = await getFileUser(registriesPath); 11 | 12 | if (!useConfig) 13 | useConfig = { version: '', users: [], registry: [] } as UserInfoJson; 14 | if (!useConfig.registry) 15 | useConfig.registry = []; 16 | 17 | let changed = false; 18 | 19 | useConfig.registry?.forEach((x) => { 20 | if (x.alias === origin) { 21 | if (useConfig && useConfig.registry?.every(x => x.alias !== target)) { 22 | x.alias = target; 23 | log.success(`[update]: ${origin}=>${x.alias} (${x.name})`); 24 | } 25 | else { 26 | log.error(`${target} is exist, please enter another one `); 27 | } 28 | 29 | changed = true; 30 | } 31 | }); 32 | 33 | if (!changed) 34 | return log.error(`${origin} not found`); 35 | 36 | await writeFileUser(registriesPath, useConfig); 37 | }; 38 | -------------------------------------------------------------------------------- /package/config/registry.ts: -------------------------------------------------------------------------------- 1 | import type { PackageManagertype, RegistryInfo } from '../type/shell.type'; 2 | 3 | export const defaultPackageManager = ['npm', 'yarn', 'cnpm', 'pnpm'] as PackageManagertype[]; 4 | 5 | export const defaultNpmMirror: RegistryInfo[] = [ 6 | { 7 | name: 'npm', 8 | alias: 'npm', 9 | home: 'https://www.npmjs.org', 10 | registry: 'https://registry.npmjs.org/' 11 | }, 12 | { 13 | name: 'yarn', 14 | alias: 'yarn', 15 | home: 'https://yarnpkg.com', 16 | registry: 'https://registry.yarnpkg.com/' 17 | }, 18 | { 19 | name: 'tencent', 20 | alias: 'tencent', 21 | home: 'https://mirrors.cloud.tencent.com/npm/', 22 | registry: 'https://mirrors.cloud.tencent.com/npm/' 23 | }, 24 | { 25 | name: 'cnpm', 26 | alias: 'cnpm', 27 | home: 'https://cnpmjs.org', 28 | registry: 'https://r.cnpmjs.org/' 29 | }, 30 | { 31 | name: 'taobao', 32 | alias: 'taobao', 33 | home: 'https://npmmirror.com', 34 | registry: 'https://registry.npmmirror.com/' 35 | }, 36 | { 37 | name: 'npmMirror', 38 | alias: 'npmMirror', 39 | home: 'https://skimdb.npmjs.com/', 40 | registry: 'https://skimdb.npmjs.com/registry/' 41 | } 42 | ]; 43 | -------------------------------------------------------------------------------- /dist/assets/git.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package/assets/git.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package/gnrm.ts: -------------------------------------------------------------------------------- 1 | import cac from 'cac'; 2 | import { useVersion } from './commands/common/useVersion'; 3 | import { useAdd, useAlias, useDelete, useLs, useTest, useUse } from './commands/gnrm'; 4 | 5 | const program = cac('gnrm'); 6 | program.version(useVersion()); 7 | 8 | program 9 | .command('ls', '当前用户列表') 10 | .option('-p, --packageManager ', '查看对应包管理器:默认npm') 11 | .action(useLs); 12 | 13 | program 14 | .command('use [name]', '切换镜像源') 15 | .option('-p, --registry ', '设置对应包管理器:默认npm') 16 | .action(useUse); 17 | 18 | program 19 | .command('test', '切换镜像源') 20 | .option('-r, --registry ', '测试源名称或者别名') 21 | .option('-a, --all', '测试存在的镜像源') 22 | .action(useTest); 23 | 24 | program 25 | .command('add', '添加镜像') 26 | .option('-n, --name ', '镜像名称') 27 | .option('-r, --registry ', '镜像地址') 28 | .option('-a, --alias ', '镜像别名') 29 | .action(useAdd); 30 | 31 | program.command('alias ', '镜像添加别名').action(useAlias); 32 | 33 | program.command('delete ', '删除镜像').action(useDelete); 34 | 35 | program.help(); 36 | 37 | const init = async () => { 38 | try { 39 | program.parse(process.argv, { run: false }); 40 | await program.runMatchedCommand(); 41 | } 42 | catch (error: any) { 43 | console.error(error?.message || '未知错误'); 44 | program.outputHelp(); 45 | process.exit(0); 46 | } 47 | }; 48 | 49 | init(); 50 | -------------------------------------------------------------------------------- /package/utils/tools.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import { white } from 'kolorist'; 3 | import type { UserInfoJson, UserOldInfoJson } from '../type/shell.type'; 4 | 5 | export const transformData = (data: UserOldInfoJson): UserInfoJson => { 6 | const userInfo: UserInfoJson = { version: '', users: [] }; 7 | Object.keys(data).forEach((x) => { 8 | userInfo.users.push({ 9 | name: data[x].name, 10 | email: data[x].email, 11 | alias: data[x].name 12 | }); 13 | }); 14 | 15 | return userInfo; 16 | }; 17 | 18 | export const padding = (message = '', before = 1, after = 1) => { 19 | return ( 20 | new Array(before).fill(' ').join(' ') 21 | + message 22 | + new Array(after).fill(' ').join(' ') 23 | ); 24 | }; 25 | 26 | export const geneDashLine = (message: string, length: number) => { 27 | const finalMessage = new Array(Math.max(2, length - message.length + 2)).join( 28 | '-' 29 | ); 30 | return padding(white(finalMessage)); 31 | }; 32 | 33 | export const isLowerCaseEqual = (str1: string, str2: string) => { 34 | if (str1 && str2) 35 | return str1.toLowerCase() === str2.toLowerCase(); 36 | 37 | else 38 | return !str1 && !str2; 39 | }; 40 | 41 | export const printMessages = (messages: string[]) => { 42 | console.log('\n'); 43 | for (const message of messages) 44 | console.log(message); 45 | 46 | console.log('\n'); 47 | }; 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gacm", 3 | "version": "1.2.11", 4 | "description": "gacm", 5 | "author": "alqmc", 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "gulp --require sucrase/register/ts --gulpfile build/gulpfile.ts", 9 | "clear": "rimraf dist", 10 | "link": "cd dist && pnpm link --global", 11 | "push": "git push gitee master && git push github master", 12 | "update:version": "sucrase-node build/utils/version.ts", 13 | "lint": "eslint . --fix", 14 | "log": "changeloger", 15 | "release": "sucrase-node script/release.ts", 16 | "prepare": "husky install" 17 | }, 18 | "dependencies": { 19 | "execa": "5.1.1", 20 | "kolorist": "^1.5.1", 21 | "minimist": "^1.2.6", 22 | "node-fetch": "2.6.6", 23 | "prompts": "^2.4.2" 24 | }, 25 | "devDependencies": { 26 | "@alqmc/build-ts": "^0.0.8", 27 | "@alqmc/build-utils": "^0.0.3", 28 | "@alqmc/eslint-config-ts": "^0.0.9", 29 | "@commitlint/cli": "^8.3.5", 30 | "@commitlint/config-angular": "^8.3.4", 31 | "@commitlint/config-conventional": "^16.2.1", 32 | "@types/fs-extra": "^9.0.13", 33 | "@types/gulp": "^4.0.9", 34 | "@types/node": "^17.0.21", 35 | "@types/node-fetch": "^2.6.2", 36 | "@types/prompts": "^2.0.14", 37 | "cac": "^6.7.14", 38 | "changeloger": "0.1.0", 39 | "commitizen": "^4.1.2", 40 | "eslint": "^8.31.0", 41 | "fs-extra": "^10.1.0", 42 | "gulp": "^4.0.2", 43 | "husky": "^8.0.1", 44 | "lint-staged": "^10.5.4", 45 | "prettier": "^2.6.2", 46 | "prompts": "^2.4.2", 47 | "rimraf": "^3.0.2", 48 | "sucrase": "^3.20.3", 49 | "tslib": "^2.4.0", 50 | "typescript": "^4.6.3" 51 | } 52 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: 🐛 Bug report 2 | description: Create a report to help us improve gacm 3 | title: '[Bug]: ' 4 | labels: [bug] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | Please fill out the following carefully in order to better fix the problem. 10 | - type: input 11 | id: gacm-version 12 | attributes: 13 | label: Version 14 | description: | 15 | ### **Check if the issue is reproducible with the latest stable version.** 16 | You can use the command `pnpm view gacm versions` to view it 17 | placeholder: latest 18 | - type: textarea 19 | id: reproduce 20 | attributes: 21 | label: Step to reproduce 22 | description: | 23 | **After the replay is turned on, what actions do we need to perform to make the bug appear? Simple and clear steps can help us locate the problem more quickly. Please clearly describe the steps of reproducing the issue. Issues without clear reproducing steps will not be repaired. If the issue marked with 'need reproduction' does not provide relevant steps within 7 days, it will be closed directly.** 24 | placeholder: Please Input 25 | - type: textarea 26 | id: expected 27 | attributes: 28 | label: What is expected 29 | placeholder: Please Input 30 | - type: textarea 31 | id: actually 32 | attributes: 33 | label: What is actually happening 34 | placeholder: Please Input 35 | - type: textarea 36 | id: additional-comments 37 | attributes: 38 | label: Any additional comments (optional) 39 | description: | 40 | **Some background / context of how you ran into this bug.** 41 | placeholder: Please Input 42 | -------------------------------------------------------------------------------- /package/utils/getUserList.ts: -------------------------------------------------------------------------------- 1 | import { existsSync, promises } from 'fs'; 2 | import { registriesPath } from '../config/path'; 3 | import { defaultNpmMirror } from '../config/registry'; 4 | import type { UserInfoJson, UserOldInfoJson } from '../type/shell.type'; 5 | import { log } from './log'; 6 | import { transformData } from './tools'; 7 | 8 | const { readFile, writeFile } = promises; 9 | 10 | /** 11 | * 获取用户 12 | * @param path 13 | * @returns 14 | */ 15 | export const getFileUser = async (rootPath: string) => { 16 | if (existsSync(rootPath)) { 17 | const fileBuffer = await readFile(rootPath, 'utf-8'); 18 | let userList = fileBuffer 19 | ? (JSON.parse(fileBuffer.toString()) as UserInfoJson) 20 | : null; 21 | if (userList && !userList.version) 22 | userList = transformData(userList as unknown as UserOldInfoJson); 23 | 24 | return userList; 25 | } 26 | return null; 27 | }; 28 | 29 | /** 30 | * 将shell写入文件 31 | * @param dir 32 | * @param data 33 | */ 34 | export async function writeFileUser(dir: string, data: UserInfoJson) { 35 | writeFile(dir, JSON.stringify(data, null, 4)).catch((error) => { 36 | log.error(error as string); 37 | process.exit(0); 38 | }); 39 | } 40 | 41 | /** 42 | * 检查是否写入过Registry 43 | * @returns Registrys 44 | */ 45 | export const checkRegistry = async () => { 46 | const userConfig = await getFileUser(registriesPath); 47 | let registryList = defaultNpmMirror; 48 | if (userConfig) 49 | if (!userConfig.registry || userConfig.registry.length === 0) { 50 | userConfig.registry = registryList; 51 | writeFileUser(registriesPath, userConfig); 52 | } 53 | else { registryList = userConfig.registry; } 54 | return registryList; 55 | }; 56 | -------------------------------------------------------------------------------- /package/commands/gacm/useUse.ts: -------------------------------------------------------------------------------- 1 | import prompts from 'prompts'; 2 | import { registriesPath } from '../../config/path'; 3 | import { getFileUser } from '../../utils/getUserList'; 4 | import { log } from '../../utils/log'; 5 | import { run } from '../../utils/shell'; 6 | import type { UserInfo } from '../../type/shell.type'; 7 | 8 | export interface UseCmd { 9 | local?: boolean 10 | global?: boolean 11 | system?: boolean 12 | } 13 | 14 | export const useUse = async (name: string, cmd: UseCmd) => { 15 | const userList = await getFileUser(registriesPath); 16 | 17 | if (!userList) 18 | return log.error('no user exists'); 19 | 20 | let useUser: UserInfo | undefined; 21 | if (name) { 22 | useUser = userList.users.find(x => x.alias === name); 23 | } 24 | else { 25 | const { user } = await prompts({ 26 | type: 'select', 27 | name: 'user', 28 | message: 'Pick a account', 29 | choices: userList.users.map((x) => { 30 | return { 31 | title: `${x.alias}${x.alias === x.name ? '' : `(${x.name})`} ${ 32 | x.email 33 | }`, 34 | value: x 35 | }; 36 | }) 37 | }); 38 | if (!user) { 39 | log.error('user cancel operation'); 40 | return; 41 | } 42 | useUser = user; 43 | } 44 | 45 | if (!useUser) 46 | return log.error(`${name} not found`); 47 | 48 | let env = 'local'; 49 | 50 | if (cmd.system) 51 | env = 'system'; 52 | 53 | if (cmd.global) 54 | env = 'global'; 55 | 56 | if (cmd.local) 57 | env = 'local'; 58 | 59 | await run(`git config --${env} user.name ${useUser.name}`); 60 | 61 | await run(`git config --${env} user.email ${useUser.email}`); 62 | 63 | log.success( 64 | `git user changed [${env}]:${useUser.alias}${ 65 | useUser.alias !== useUser.name ? `(${useUser.name})` : '' 66 | }` 67 | ); 68 | }; 69 | -------------------------------------------------------------------------------- /package/commands/gacm/useLs.ts: -------------------------------------------------------------------------------- 1 | import { gray, green } from 'kolorist'; 2 | import { registriesPath } from '../../config/path'; 3 | import { getFileUser } from '../../utils/getUserList'; 4 | import { execCommand } from '../../utils/shell'; 5 | import { log } from '../../utils/log'; 6 | import { geneDashLine, printMessages } from '../../utils/tools'; 7 | import { insertUser } from '../../utils/helper'; 8 | import pkg from '../../package.json'; 9 | import type { UserInfoJson } from '../../type/shell.type'; 10 | 11 | export const useLs = async () => { 12 | const userList = (await getFileUser(registriesPath)) || ({ version: pkg.version, users: [], registry: [] } as UserInfoJson); 13 | 14 | const currectUser = await execCommand('git', ['config', 'user.name']).catch(() => {}); 15 | 16 | const currectEmail = await execCommand('git', ['config', 'user.email']).catch(() => {}); 17 | 18 | if (userList.users.length === 0 && (!currectUser || !currectEmail)) 19 | return log.info('no user'); 20 | 21 | if ( 22 | !userList.users.some(x => x.name === currectUser) 23 | && currectUser 24 | && currectEmail 25 | ) { 26 | // 默认添加本地账户 27 | 28 | await insertUser(currectUser, currectEmail); 29 | 30 | log.info(`[found new user]: ${currectUser}`); 31 | 32 | userList.users.push({ 33 | name: currectUser, 34 | email: currectEmail, 35 | alias: currectUser 36 | }); 37 | } 38 | 39 | const length 40 | = Math.max( 41 | ...userList.users.map( 42 | user => 43 | user.alias.length + (user.alias !== user.name ? user.name.length : 0) 44 | ) 45 | ) + 3; 46 | 47 | const prefix = ' '; 48 | 49 | const messages = userList.users.map((user) => { 50 | const currect 51 | = user.name === currectUser && user.email === currectEmail 52 | ? `${green('■')} ` 53 | : ' '; 54 | 55 | const isSame = user.alias === user.name; 56 | 57 | return `${prefix + currect}${ 58 | isSame ? user.alias : `${user.alias}(${gray(user.name)})` 59 | }${geneDashLine(user.name, length)}${user.email}`; 60 | }); 61 | 62 | printMessages(messages); 63 | }; 64 | -------------------------------------------------------------------------------- /README-zh_CN.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | GitHub stars 16 | 17 | 18 |
19 |

20 | 21 |

极简的git账号与npm registry管理工具( Git Account Management Tools & NPM Registry Manager )

22 | 23 | 简体中文 | [English](./README.md) 24 | 25 | ### Features 26 | 27 | - ✨ git账户与npm registry管理工具(无缝切换) 28 | 29 | - 🚀 极简的操作方式,just like nvm 30 | 31 | - 😊 gacm [gnrm] ls 自动添加本地git账户或者本地npm registry管理工具 32 | 33 | - 👋 gnrm 灵活配置,无污染,区分包管理器 34 | 35 | 36 | ### Getting Started 37 | 38 | ``` 39 | pnpm add gacm -g 40 | 41 | yarn add gacm -g 42 | 43 | npm install gacm -g 44 | 45 | ``` 46 | 47 | ### Usage 48 | 49 | 50 | #### 切换git账户 51 | 52 | ```shell 53 | ## just like nvm 54 | 55 | ## 查看用户列表,会自动添加本地用户 56 | gacm ls 57 | 58 | 59 | ## 切换git账户 60 | gacm use xxx --local 61 | 62 | gacm use xxx --global 63 | 64 | 65 | ## 添加用户,--alias 可选 定义用户别名 66 | gacm add --name xxx --email xxx [--alias xxx] 67 | 68 | ## 定义用户别名 69 | gacm alias xxxx xxxx 70 | 71 | ## 删除用户 72 | gacm delete user 73 | 74 | ``` 75 | 76 | #### 切换NPM Registry 77 | 78 | ```shell 79 | ## just like nvm 80 | 81 | ## 查看NPM Registry 列表,会自动添加本地NPM Registry 82 | gnrm ls [-p xxxx] 83 | 84 | 85 | ## 切换 npm registry default npm 86 | gacm use xxx [-p yarn] 87 | 88 | gacm use xxx [-p cnpm] 89 | 90 | 91 | ## 添加registry --alias 可选 定义 registry 别名 92 | gacm add --name xxx --registry xxx [--alias xxx] 93 | 94 | ## 定义registry别名 95 | gacm alias xxxx xxxx 96 | 97 | ## 删除 registry 98 | gacm delete xxx 99 | 100 | ``` 101 | 102 | ### License 103 | 104 | MIT License © 2022 [阿乐去买菜(kinfuy)](https://github.com/kinfuy) 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /package/commands/gnrm/useUse.ts: -------------------------------------------------------------------------------- 1 | import prompts from 'prompts'; 2 | import { registriesPath } from '../../config/path'; 3 | import { defaultNpmMirror, defaultPackageManager } from '../../config/registry'; 4 | import { getFileUser } from '../../utils/getUserList'; 5 | import { log } from '../../utils/log'; 6 | import { execCommand } from '../../utils/shell'; 7 | import type { NrmCmd, RegistryInfo } from '../../type/shell.type'; 8 | 9 | export const useUse = async (name: string, cmd: NrmCmd) => { 10 | const userConfig = await getFileUser(registriesPath); 11 | let registrylist = defaultNpmMirror; 12 | let packageManager = 'npm'; 13 | if (userConfig && userConfig.registry) 14 | registrylist = userConfig.registry; 15 | 16 | let useRegistry: RegistryInfo | undefined; 17 | if (name) { 18 | useRegistry = registrylist.find(x => x.alias === name); 19 | } 20 | else { 21 | const { registry, pkg } = await prompts([ 22 | { 23 | type: 'select', 24 | name: 'registry', 25 | message: 'Pick a registry', 26 | choices: registrylist.map((x) => { 27 | return { 28 | title: `${x.alias}${x.alias === x.name ? '' : `(${x.name})`} ${ 29 | x.registry 30 | }`, 31 | value: x 32 | }; 33 | }) 34 | }, 35 | { 36 | type: 'select', 37 | name: 'pkg', 38 | message: 'Pick a packageManager,and you will set registry for it', 39 | initial: 0, 40 | choices: defaultPackageManager.map(x => ({ 41 | title: x, 42 | value: x 43 | })) 44 | } 45 | ]); 46 | 47 | if (pkg) 48 | packageManager = pkg; 49 | 50 | if (!registry) { 51 | log.error('user cancel operation'); 52 | return; 53 | } 54 | useRegistry = registry; 55 | } 56 | if (!useRegistry) 57 | return log.error(`${name} not found`); 58 | 59 | if (cmd.packageManager) 60 | packageManager = cmd.packageManager; 61 | 62 | execCommand(packageManager, [ 63 | 'config', 64 | 'set', 65 | 'registry', 66 | useRegistry.registry 67 | ]).then(() => { 68 | log.success( 69 | `${packageManager} registry has been set to: ${useRegistry!.registry}` 70 | ); 71 | }).catch(() => { 72 | log.error(`${packageManager} is not found`); 73 | }); 74 | }; 75 | -------------------------------------------------------------------------------- /package/commands/gnrm/useTest.ts: -------------------------------------------------------------------------------- 1 | import prompts from 'prompts'; 2 | import fetch from 'node-fetch'; 3 | import { gray, green, red } from 'kolorist'; 4 | import type { RegistryInfo, TestCmd } from '../../type/shell.type'; 5 | import { checkRegistry } from '../../utils/getUserList'; 6 | 7 | const testRegistry = async (registry: string) => { 8 | const start = Date.now(); 9 | const options = { 10 | timeout: 5000 11 | }; 12 | let status = false; 13 | let isTimeout = false; 14 | try { 15 | const response = await fetch(registry, { 16 | ...options 17 | }); 18 | status = response.ok; 19 | } 20 | catch (error: any) { 21 | isTimeout = error.type === 'request-timeout'; 22 | } 23 | return { 24 | status, 25 | isTimeout, 26 | start 27 | }; 28 | }; 29 | 30 | export const useTest = async (cmd: TestCmd) => { 31 | const registryList = await checkRegistry(); 32 | 33 | const test = async (registry: RegistryInfo) => { 34 | const { status, start, isTimeout } = await testRegistry(new URL('', registry.registry).href); 35 | if (isTimeout) 36 | // eslint-disable-next-line no-console 37 | console.log((`\n ${red('【Timeout】')} ping ${registry.alias}${registry.alias === registry.name ? '' : `${gray(`(${registry.name})`)}`}:${registry.registry}`)); 38 | 39 | if (status) { 40 | const end = Date.now(); 41 | // eslint-disable-next-line no-console 42 | console.log((`\n ${green(`【${end - start}ms】`)} ping ${registry.alias}${registry.alias === registry.name ? '' : `${gray(`(${registry.name})`)}`}:${registry.registry}`)); 43 | } 44 | }; 45 | 46 | if (cmd.all) { 47 | const list = registryList.map(async (r) => { 48 | return { 49 | handle: await test(r) 50 | }; 51 | }); 52 | for (const iterator of list) 53 | await iterator; 54 | 55 | return; 56 | } 57 | 58 | if (cmd.registry) { 59 | const registry = registryList.find(x => x.alias === cmd.registry || x.name === cmd.registry); 60 | if (registry) 61 | await test(registry); 62 | 63 | return; 64 | } 65 | 66 | const { registry } = await prompts([ 67 | { 68 | type: 'select', 69 | name: 'registry', 70 | message: 'Pick a registry', 71 | choices: registryList.map((x) => { 72 | return { 73 | title: `${x.alias}${x.alias === x.name ? '' : `(${x.name})`} ${ 74 | x.registry 75 | }`, 76 | value: x 77 | }; 78 | }) 79 | } 80 | ]); 81 | 82 | await test(registry); 83 | }; 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | GitHub stars 16 | 17 | 18 |
19 |

20 | 21 |

Git Account Management Tools & NPM Registry Manager

22 | 23 | English | [简体中文](./README-zh_CN.md) 24 | 25 | ### Features 26 | 27 | - ✨ Seamless switching of GIT account and npm registry 28 | 29 | - 🚀Minimalist operation,just like nvm 30 | 31 | - 😊 gacm ls Automatically add local git account or npm registry 32 | 33 | - 👋 gnrm Flexible configuration, pollution-free,distinguish package manager 34 | 35 | 36 | 37 | ### Getting Started 38 | 39 | ``` 40 | pnpm add gacm -g 41 | 42 | yarn add gacm -g 43 | 44 | npm install gacm -g 45 | 46 | ``` 47 | 48 | ### Usage 49 | 50 | #### switch git account 51 | 52 | 53 | ```shell 54 | ## just like nvm 55 | 56 | ## View the user list, and local users will be automatically added 57 | gacm ls 58 | 59 | 60 | ## Switch git account 61 | gacm use xxx --local 62 | 63 | gacm use xxx --global 64 | 65 | 66 | ## Add user,--alias Optional define user alias 67 | gacm add --name xxx --email xxx [--alias xxx] 68 | 69 | ## Define user alias 70 | gacm alias xxxx xxxx 71 | 72 | ## delete user 73 | gacm delete user 74 | 75 | ``` 76 | 77 | #### switch npm registry 78 | 79 | ```shell 80 | ## just like nvm 81 | 82 | ## View the registry list, and local registry will be automatically added 83 | gnrm ls [-p xxxx] 84 | 85 | 86 | ## Switch npm registry default npm 87 | gacm use xxx [-p yarn] 88 | 89 | gacm use xxx [-p cnpm] 90 | 91 | 92 | ## Add registry--alias Optional define registry alias 93 | gacm add --name xxx --registry xxx [--alias xxx] 94 | 95 | ## Define registry alias 96 | gacm alias xxxx xxxx 97 | 98 | ## delete registry 99 | gacm delete xxx 100 | 101 | ``` 102 | ### License 103 | 104 | MIT License © 2022 [阿乐去买菜(kinfuy)](https://github.com/kinfuy) 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 |

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | GitHub stars 16 | 17 | 18 |
19 |

20 | 21 |

Git Account Management Tools & NPM Registry Manager

22 | 23 | English | [简体中文](./README-zh_CN.md) 24 | 25 | ### Features 26 | 27 | - ✨ Seamless switching of GIT account and npm registry 28 | 29 | - 🚀Minimalist operation,just like nvm 30 | 31 | - 😊 gacm ls Automatically add local git account or npm registry 32 | 33 | - 👋 gnrm Flexible configuration, pollution-free,distinguish package manager 34 | 35 | 36 | 37 | ### Getting Started 38 | 39 | ``` 40 | pnpm add gacm -g 41 | 42 | yarn add gacm -g 43 | 44 | npm install gacm -g 45 | 46 | ``` 47 | 48 | ### Usage 49 | 50 | #### switch git account 51 | 52 | 53 | ```shell 54 | ## just like nvm 55 | 56 | ## View the user list, and local users will be automatically added 57 | gacm ls 58 | 59 | 60 | ## Switch git account 61 | gacm use xxx --local 62 | 63 | gacm use xxx --global 64 | 65 | 66 | ## Add user,--alias Optional define user alias 67 | gacm add --name xxx --email xxx [--alias xxx] 68 | 69 | ## Define user alias 70 | gacm alias xxxx xxxx 71 | 72 | ## delete user 73 | gacm delete user 74 | 75 | ``` 76 | 77 | #### switch npm registry 78 | 79 | ```shell 80 | ## just like nvm 81 | 82 | ## View the registry list, and local registry will be automatically added 83 | gnrm ls [-p xxxx] 84 | 85 | 86 | ## Switch npm registry default npm 87 | gacm use xxx [-p yarn] 88 | 89 | gacm use xxx [-p cnpm] 90 | 91 | 92 | ## Add registry--alias Optional define registry alias 93 | gacm add --name xxx --registry xxx [--alias xxx] 94 | 95 | ## Define registry alias 96 | gacm alias xxxx xxxx 97 | 98 | ## delete registry 99 | gacm delete xxx 100 | 101 | ``` 102 | ### License 103 | 104 | MIT License © 2022 [阿乐去买菜(kinfuy)](https://github.com/kinfuy) 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /package/utils/helper.ts: -------------------------------------------------------------------------------- 1 | import { registriesPath } from '../config/path'; 2 | import pkg from '../../package.json'; 3 | import type { 4 | UserInfo, 5 | UserInfoJson, 6 | UserOldInfoJson 7 | } from '../type/shell.type'; 8 | import { getFileUser, writeFileUser } from './getUserList'; 9 | import { log } from './log'; 10 | import { transformData } from './tools'; 11 | 12 | export const isExistAlias = ( 13 | users: UserInfo[], 14 | alias: string, 15 | name?: string, 16 | email?: string 17 | ) => { 18 | return users.some( 19 | x => 20 | x.alias === alias 21 | || (!x.alias && x.name === alias) 22 | || (name && email && x.name === name && x.email === email) 23 | ); 24 | }; 25 | 26 | export const insertRegistry = async ( 27 | name: string, 28 | alias: string, 29 | registry: string, 30 | home?: string 31 | ) => { 32 | let userConfig = await getFileUser(registriesPath); 33 | if (!userConfig) 34 | userConfig = { 35 | version: pkg.version, 36 | users: [], 37 | registry: [] 38 | } as UserInfoJson; 39 | if (!userConfig.registry) 40 | userConfig.registry = []; 41 | const isExist = userConfig.registry?.some(x => x.alias === alias); 42 | if (isExist) { 43 | userConfig.registry?.forEach((x) => { 44 | if (x.alias === alias) { 45 | x.alias = alias; 46 | x.name = name; 47 | x.home = home || ''; 48 | x.registry = registry; 49 | } 50 | }); 51 | log.success( 52 | `[update]:${alias} ${ 53 | alias !== name ? `(${name})` : '' 54 | } registry ${registry}` 55 | ); 56 | } 57 | else { 58 | userConfig.registry?.push({ 59 | alias, 60 | name, 61 | home: home || '', 62 | registry 63 | }); 64 | log.success( 65 | `[add]:${alias} ${alias !== name ? `(${name})` : ''} registry ${registry}` 66 | ); 67 | } 68 | await writeFileUser(registriesPath, userConfig); 69 | }; 70 | /** 71 | * 插入用户 72 | * @param name 73 | * @param email 74 | * @param alias 75 | */ 76 | export const insertUser = async (name: string, email: string, alias = name) => { 77 | let userConfig = await getFileUser(registriesPath); 78 | if (!userConfig) 79 | userConfig = { 80 | version: pkg.version, 81 | users: [], 82 | registry: [] 83 | } as UserInfoJson; 84 | if (!userConfig.version) 85 | userConfig = transformData(userConfig as unknown as UserOldInfoJson); 86 | 87 | if (isExistAlias(userConfig.users, alias, name, email)) { 88 | userConfig.users.forEach((user) => { 89 | if ( 90 | user.alias === alias 91 | || (!user.alias && user.name === alias) 92 | || (name && email && user.name === name && user.email === email) 93 | ) { 94 | user.alias = alias === name ? (user.alias ? user.alias : alias) : alias; 95 | 96 | user.email = email; 97 | 98 | user.name = name; 99 | 100 | log.success( 101 | `[update]:${alias} ${user.alias !== name ? `(${user.name})` : ''}` 102 | ); 103 | } 104 | }); 105 | } 106 | else { 107 | userConfig.users.push({ 108 | name, 109 | email, 110 | alias 111 | }); 112 | 113 | log.success(`[add]: ${alias} ${alias !== name ? `(${name})` : ''}`); 114 | } 115 | 116 | await writeFileUser(registriesPath, userConfig); 117 | }; 118 | -------------------------------------------------------------------------------- /package/commands/gnrm/useLs.ts: -------------------------------------------------------------------------------- 1 | import { blue, gray, green, red, yellow } from 'kolorist'; 2 | import prompts from 'prompts'; 3 | import { checkRegistry } from '../../utils/getUserList'; 4 | import { defaultPackageManager } from '../../config/registry'; 5 | import { execCommand } from '../../utils/shell'; 6 | import { geneDashLine, padding, printMessages } from '../../utils/tools'; 7 | import { log } from '../../utils/log'; 8 | import { insertRegistry } from '../../utils/helper'; 9 | import type { NrmCmd, PackageManagertype } from '../../type/shell.type'; 10 | 11 | const getRegistry = async (pkg: PackageManagertype) => { 12 | return await execCommand(pkg, [ 13 | 'config', 14 | 'get', 15 | 'registry' 16 | ]).catch(() => {}); 17 | }; 18 | 19 | export const getRegistrys = async (pkgs: PackageManagertype[] = defaultPackageManager) => { 20 | const registrys: { 21 | [key in PackageManagertype]: string 22 | } = { 23 | npm: '', 24 | pnpm: '', 25 | cnpm: '', 26 | yarn: '' 27 | }; 28 | const list = pkgs.map(async (pkg) => { 29 | return { 30 | pkg, 31 | handle: await getRegistry(pkg) 32 | }; 33 | }); 34 | for (const iterator of list) { 35 | const itme = await iterator; 36 | registrys[itme.pkg] = itme.handle || ''; 37 | } 38 | 39 | return registrys; 40 | }; 41 | 42 | export const useLs = async (cmd: NrmCmd) => { 43 | const registryList = await checkRegistry(); 44 | 45 | const pkgs: PackageManagertype[] = []; 46 | 47 | if (cmd.packageManager) 48 | pkgs.push(cmd.packageManager); 49 | 50 | else 51 | pkgs.push(...defaultPackageManager); 52 | 53 | const currectRegistry = await getRegistrys(pkgs); 54 | 55 | if (registryList.every(x => Object.values(currectRegistry).includes(x.registry))) 56 | // 默认添加本地源 57 | try { 58 | const newRegistry = Object.keys(currectRegistry).map((x) => { 59 | if (registryList.every(val => currectRegistry[x as PackageManagertype] && val.registry !== currectRegistry[x as PackageManagertype])) 60 | return currectRegistry[x as PackageManagertype]; 61 | return ''; 62 | }); 63 | Array.from(new Set(newRegistry)).filter(x => x).forEach(async (registry) => { 64 | const { name } = await prompts({ 65 | type: 'text', 66 | name: 'name', 67 | message: `find new registry:${currectRegistry}, please give it a name` 68 | }); 69 | await insertRegistry(name, name, registry); 70 | log.info(`[found new registry]: ${currectRegistry}`); 71 | registryList.push({ 72 | name, 73 | registry, 74 | home: '', 75 | alias: name 76 | }); 77 | }); 78 | } 79 | catch (error) {} 80 | 81 | const length 82 | = Math.max( 83 | ...registryList.map((x) => { 84 | return x.alias.length + (x.alias !== x.name ? x.name.length : 0); 85 | }) 86 | ) + 3; 87 | 88 | const prefix = ''; 89 | 90 | const colorMap: Record = { 91 | npm: green, 92 | cnpm: red, 93 | yarn: blue, 94 | pnpm: yellow 95 | }; 96 | 97 | const currentTip = `current: ${Object.keys(currectRegistry).map((key) => { 98 | if (currectRegistry[key as PackageManagertype]) 99 | return `${key}: ${colorMap[key]('■')}`; 100 | return ''; 101 | }).filter(i => i).join(' ')}\n\n`; 102 | 103 | const messages = registryList.map((item) => { 104 | const currect = Object.keys(currectRegistry).map((key) => { 105 | if (currectRegistry[key as PackageManagertype] && item.registry.includes(currectRegistry[key as PackageManagertype])) 106 | return colorMap[key]('■'); 107 | return ''; 108 | }).filter(x => x); 109 | 110 | const isSame = item.alias === item.name; 111 | const str = `${prefix}${ 112 | isSame ? item.alias : `${item.alias}(${gray(item.name)})` 113 | }${geneDashLine(item.name, length)}${item.registry}`; 114 | return `${currect.length > 0 ? padding(`${currect.join(' ')}`, 4 - currect.length, 1) : ''} ${padding(str, currect.length > 0 ? 0 : 4, 0)}`; 115 | }); 116 | 117 | messages.unshift(currentTip); 118 | 119 | printMessages(messages); 120 | }; 121 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # [v1.2.11](https://github.com/alqmc/gacm/compare/v1.2.10...v1.2.11)(2024-09-12) 2 | 3 | 4 | ## What's Changed 5 | - Fix: unknown options output help ([#25](https://github.com/alqmc/gacm/pull/#25)) 6 | # [v1.2.10](https://github.com/alqmc/gacm/compare/v1.2.9...v1.2.10)(2024-08-23) 7 | 8 | 9 | ## What's Changed 10 | - Fix: type & gacm ls current ([b8fa5d5](https://github.com/alqmc/gacm/commit/b8fa5d5)) 11 | - Fix: gacm test timetout output ([a4ad686](https://github.com/alqmc/gacm/commit/a4ad686)) 12 | - Fix: gacm 当前标记样式 ([aea8599](https://github.com/alqmc/gacm/commit/aea8599)) 13 | # [v1.2.9](https://github.com/alqmc/gacm/compare/v1.2.8...v1.2.9)(2023-03-22) 14 | 15 | 16 | ## What's Changed 17 | - Feat: gnrm test registry ([4e4c132](https://github.com/alqmc/gacm/commit/4e4c132)) 18 | - Fix: 当前源标记白色主题不明显 ([b5f6f79](https://github.com/alqmc/gacm/commit/b5f6f79)) 19 | - Fix: gnrm test options -r ([4ddd7df](https://github.com/alqmc/gacm/commit/4ddd7df)) 20 | # [v1.2.8](https://github.com/alqmc/gacm/compare/v1.2.7...v1.2.8)(2023-03-08) 21 | 22 | 23 | ## What's Changed 24 | - Feat: command --help ([5c29a6e](https://github.com/alqmc/gacm/commit/5c29a6e)) 25 | - Perf: 提升gnrm ls 执行效率 ([c2ec9bb](https://github.com/alqmc/gacm/commit/c2ec9bb)) 26 | # [v1.2.7](https://github.com/alqmc/gacm/compare/v1.2.6...v1.2.7)(2023-02-09) 27 | 28 | 29 | ## What's Changed 30 | - Feat: the new ui shows the current registry ([#23](https://github.com/alqmc/gacm/pull/#23)) 31 | - Fix: gnrm use pkg not found error tips ([8b747a1](https://github.com/alqmc/gacm/commit/8b747a1)) 32 | # [v1.2.6](https://github.com/alqmc/gacm/compare/v1.2.5...v1.2.6)(2023-01-30) 33 | 34 | 35 | ## What's Changed 36 | - Fix: gnrm use select options ([a3f6925](https://github.com/alqmc/gacm/commit/a3f6925)) 37 | # [v1.2.5](https://github.com/alqmc/gacm/compare/v1.2.4...v1.2.5)(2022-11-18) 38 | 39 | 40 | ## What's Changed 41 | - Fix: gacm ls nouser error ([#21](https://github.com/alqmc/gacm/pull/#21)) 42 | # [v1.2.4](https://github.com/alqmc/gacm/compare/v1.2.3...v1.2.4)(2022-11-11) 43 | 44 | 45 | ## What's Changed 46 | - Fix: gacm gnrm use no args error ([90a3cb6](https://github.com/alqmc/gacm/commit/90a3cb6)) 47 | # [v1.2.3](https://github.com/alqmc/gacm/compare/v1.2.2...v1.2.3)(2022-11-09) 48 | 49 | 50 | ## What's Changed 51 | - Feat: new logo ([05c20ad](https://github.com/alqmc/gacm/commit/05c20ad)) 52 | - Fix: gacm use not work ([5178486](https://github.com/alqmc/gacm/commit/5178486)) 53 | - Refactor: use cac ([7fda76b](https://github.com/alqmc/gacm/commit/7fda76b)) 54 | # [v1.2.2](https://github.com/alqmc/gacm/compare/v1.2.0...v1.2.2)(2022-10-26) 55 | 56 | 57 | ## What's Changed 58 | - Feat: gnrm use can selete package ([#16](https://github.com/alqmc/gacm/pull/#16)) 59 | - Fix: gnrm add params error ([#14](https://github.com/alqmc/gacm/pull/#14)) 60 | # [v1.2.0](https://github.com/alqmc/gacm/compare/v1.2.1...v1.2.0)(2022-10-24) 61 | 62 | 63 | ## What's Changed 64 | - Fix: gnrm add params error ([#14](https://github.com/alqmc/gacm/pull/#14)) 65 | # [v1.2.1](https://github.com/alqmc/gacm/compare/v1.1.5...v1.2.1)(2022-10-24) 66 | 67 | 68 | ## What's Changed 69 | - Feat: gnrm ls and gnrm use ([20afc0c](https://github.com/alqmc/gacm/commit/20afc0c)) 70 | - Feat: gnrm add、gnrm alias、gnrm delete ([9f28df6](https://github.com/alqmc/gacm/commit/9f28df6)) 71 | - Fix: gnrm add params error ([#14](https://github.com/alqmc/gacm/pull/#14)) 72 | - Docs: readme update ([1f71b1e](https://github.com/alqmc/gacm/commit/1f71b1e)) 73 | # [v1.1.5](https://github.com/alqmc/gacm/compare/v1.1.3...v1.1.5)(2022-10-21) 74 | 75 | 76 | ## What's Changed 77 | - Feat: gacm use user switching can be selected ([607301a](https://github.com/alqmc/gacm/commit/607301a)) 78 | - Fix: gacm use switch cancel ([54c3d2a](https://github.com/alqmc/gacm/commit/54c3d2a)) 79 | - Refactor: commands ([6a67674](https://github.com/alqmc/gacm/commit/6a67674)) 80 | - Docs: delete ([e6f3359](https://github.com/alqmc/gacm/commit/e6f3359)) 81 | # [v1.1.3](https://github.com/alqmc/gacm/compare/v1.1.2...v1.1.3)(2022-09-21) 82 | 83 | 84 | ## What's Changed 85 | - Fix: 修复mac执行异常 ([#8](https://github.com/alqmc/gacm/pull/#8)) 86 | # [v1.1.2](https://github.com/alqmc/gacm/compare/v1.1.0...v1.1.2)(2022-07-28) 87 | 88 | 89 | ## What's Changed 90 | - Feat: 别名与名称统一,所有操作基于别名 ([9108ba7](https://github.com/alqmc/gacm/commit/9108ba7)) 91 | - Feat: 别名与名称统一,所有操作基于别名 ([fe6c196](https://github.com/alqmc/gacm/commit/fe6c196)) 92 | - Fix: log ([5f694ca](https://github.com/alqmc/gacm/commit/5f694ca)) 93 | - Fix: log ([7a1f0e6](https://github.com/alqmc/gacm/commit/7a1f0e6)) 94 | - Fix: detail ([f9c42d2](https://github.com/alqmc/gacm/commit/f9c42d2)) 95 | - Docs: 更新文档 ([a843e67](https://github.com/alqmc/gacm/commit/a843e67)) 96 | - Docs: 更新文档 ([bfe0985](https://github.com/alqmc/gacm/commit/bfe0985)) 97 | - Docs: usage ([de64f7a](https://github.com/alqmc/gacm/commit/de64f7a)) 98 | - Docs: up readme ([cd0e4c4](https://github.com/alqmc/gacm/commit/cd0e4c4)) 99 | - Docs: log ([1baa451](https://github.com/alqmc/gacm/commit/1baa451)) 100 | - Docs: merge ([d6737ef](https://github.com/alqmc/gacm/commit/d6737ef)) 101 | # [v1.1.0](https://github.com/alqmc/gacm/compare/v1.1.1...v1.1.0)(2022-07-17) 102 | 103 | 104 | ## What's Changed 105 | - Feat: 别名与名称统一,所有操作基于别名 ([9108ba7](https://github.com/alqmc/gacm/commit/9108ba7)) 106 | - Fix: log ([5f694ca](https://github.com/alqmc/gacm/commit/5f694ca)) 107 | # [v1.1.1](https://github.com/alqmc/gacm/compare/v1.0.0...v1.1.1)(2022-07-17) 108 | 109 | 110 | ## What's Changed 111 | - Feat: gacm alias ([f6e7335](https://github.com/alqmc/gacm/commit/f6e7335)) 112 | - Feat: 别名与名称统一,所有操作基于别名 ([9108ba7](https://github.com/alqmc/gacm/commit/9108ba7)) 113 | - Fix: update lost users ([2175be2](https://github.com/alqmc/gacm/commit/2175be2)) 114 | - Fix: deatil ([5da265e](https://github.com/alqmc/gacm/commit/5da265e)) 115 | - Fix: add name not in alias ([c28f62c](https://github.com/alqmc/gacm/commit/c28f62c)) 116 | - Fix: log ([5f694ca](https://github.com/alqmc/gacm/commit/5f694ca)) 117 | - Docs: update ([c730345](https://github.com/alqmc/gacm/commit/c730345)) 118 | - Docs: update ([a77df4a](https://github.com/alqmc/gacm/commit/a77df4a)) 119 | # [v1.0.0](https://github.com/alqmc/gacm/compare/v1.0.1...v1.0.0)(2022-07-07) 120 | 121 | 122 | ## What's Changed 123 | - Fix: update lost users ([2175be2](https://github.com/alqmc/gacm/commit/2175be2)) 124 | - Docs: update ([c730345](https://github.com/alqmc/gacm/commit/c730345)) 125 | # [v1.0.1](https://github.com/alqmc/gacm/compare/v0.0.8...v1.0.1)(2022-07-07) 126 | 127 | 128 | ## What's Changed 129 | - Fix: verison shell ([1b9003b](https://github.com/alqmc/gacm/commit/1b9003b)) 130 | - Fix: update lost users ([2175be2](https://github.com/alqmc/gacm/commit/2175be2)) 131 | - Docs: 更新readme ([abaf13e](https://github.com/alqmc/gacm/commit/abaf13e)) 132 | - Docs: 更新readme ([251ab4b](https://github.com/alqmc/gacm/commit/251ab4b)) 133 | # [v0.0.8](https://github.com/alqmc/gacm/compare/v0.0.5...v0.0.8)(2022-06-24) 134 | 135 | 136 | ## What's Changed 137 | - Feat: 自动添加本地账户 ([816e44b](https://github.com/alqmc/gacm/commit/816e44b)) 138 | - Fix: readme ([070c2b7](https://github.com/alqmc/gacm/commit/070c2b7)) 139 | - Fix: detail ([d7a596b](https://github.com/alqmc/gacm/commit/d7a596b)) 140 | - Docs: 更新readme ([abaf13e](https://github.com/alqmc/gacm/commit/abaf13e)) 141 | # [v0.0.5](https://github.com/alqmc/gacm/compare/v0.0.6...v0.0.5)(2022-06-22) 142 | 143 | 144 | ## What's Changed 145 | # [v0.0.6](https://github.com/alqmc/gacm/compare/v0.0.3...v0.0.6)(2022-06-22) 146 | 147 | 148 | ## What's Changed 149 | - Feat: 当前用户查看 ([41adefa](https://github.com/alqmc/gacm/commit/41adefa)) 150 | - Fix: detail ([c6bae2d](https://github.com/alqmc/gacm/commit/c6bae2d)) 151 | - Fix: version ([d77228e](https://github.com/alqmc/gacm/commit/d77228e)) 152 | - Fix: user not found ([e9f9ba6](https://github.com/alqmc/gacm/commit/e9f9ba6)) 153 | # [v0.0.3](https://github.com/alqmc/gacm/compare/v0.0.4...v0.0.3)(2022-04-26) 154 | 155 | 156 | ## What's Changed 157 | - Fix: detail ([c6bae2d](https://github.com/alqmc/gacm/commit/c6bae2d)) 158 | - Fix: version ([d77228e](https://github.com/alqmc/gacm/commit/d77228e)) 159 | - Fix: user not found ([e9f9ba6](https://github.com/alqmc/gacm/commit/e9f9ba6)) 160 | # [v0.0.4](https://github.com/alqmc/gacm/compare/v0.0.4)(2022-04-26) 161 | 162 | 163 | ## What's Changed 164 | - Feat: user add delete ([b2eff8f](https://github.com/alqmc/gacm/commit/b2eff8f)) 165 | - Fix: detail ([a904d0c](https://github.com/alqmc/gacm/commit/a904d0c)) 166 | - Fix: detail ([c6bae2d](https://github.com/alqmc/gacm/commit/c6bae2d)) 167 | - Fix: version ([d77228e](https://github.com/alqmc/gacm/commit/d77228e)) 168 | - Fix: user not found ([e9f9ba6](https://github.com/alqmc/gacm/commit/e9f9ba6)) -------------------------------------------------------------------------------- /dist/gacm.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | var cac = require('cac'); 5 | var kolorist = require('kolorist'); 6 | var path = require('path'); 7 | var fs = require('fs'); 8 | var child_process = require('child_process'); 9 | var process$1 = require('process'); 10 | var execa = require('execa'); 11 | var prompts = require('prompts'); 12 | 13 | function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } 14 | 15 | var cac__default = /*#__PURE__*/_interopDefaultLegacy(cac); 16 | var execa__default = /*#__PURE__*/_interopDefaultLegacy(execa); 17 | var prompts__default = /*#__PURE__*/_interopDefaultLegacy(prompts); 18 | 19 | const rootPath = __dirname; 20 | __dirname; 21 | path.resolve(rootPath, "package"); 22 | const HOME = process.env[process.platform === "win32" ? "USERPROFILE" : "HOME"] || ""; 23 | const registriesPath = path.join(HOME, ".gacmrc"); 24 | 25 | const success = (msg) => console.log(` 26 | ${kolorist.green(msg)} 27 | `); 28 | const error = (msg) => console.log(` 29 | ${kolorist.red(msg)} 30 | `); 31 | const warning = (msg) => console.log(` 32 | ${kolorist.yellow(msg)} 33 | `); 34 | const info = (msg) => console.log(` 35 | ${kolorist.blue(msg)} 36 | `); 37 | const log = { 38 | success, 39 | error, 40 | warning, 41 | info 42 | }; 43 | 44 | const transformData = (data) => { 45 | const userInfo = { version: "", users: [] }; 46 | Object.keys(data).forEach((x) => { 47 | userInfo.users.push({ 48 | name: data[x].name, 49 | email: data[x].email, 50 | alias: data[x].name 51 | }); 52 | }); 53 | return userInfo; 54 | }; 55 | const padding = (message = "", before = 1, after = 1) => { 56 | return new Array(before).fill(" ").join(" ") + message + new Array(after).fill(" ").join(" "); 57 | }; 58 | const geneDashLine = (message, length) => { 59 | const finalMessage = new Array(Math.max(2, length - message.length + 2)).join("-"); 60 | return padding(kolorist.white(finalMessage)); 61 | }; 62 | const printMessages = (messages) => { 63 | console.log("\n"); 64 | for (const message of messages) 65 | console.log(message); 66 | console.log("\n"); 67 | }; 68 | 69 | const { readFile, writeFile } = fs.promises; 70 | const getFileUser = async (rootPath) => { 71 | if (fs.existsSync(rootPath)) { 72 | const fileBuffer = await readFile(rootPath, "utf-8"); 73 | let userList = fileBuffer ? JSON.parse(fileBuffer.toString()) : null; 74 | if (userList && !userList.version) 75 | userList = transformData(userList); 76 | return userList; 77 | } 78 | return null; 79 | }; 80 | async function writeFileUser(dir, data) { 81 | writeFile(dir, JSON.stringify(data, null, 4)).catch((error) => { 82 | log.error(error); 83 | process.exit(0); 84 | }); 85 | } 86 | 87 | const run = (command, dir = process$1.cwd()) => { 88 | const [cmd, ...args] = command.split(" "); 89 | return new Promise((resolve, reject) => { 90 | const app = child_process.spawn(cmd, args, { 91 | cwd: dir, 92 | stdio: "inherit", 93 | shell: process.platform === "win32" 94 | }); 95 | const processExit = () => app.kill("SIGHUP"); 96 | app.on("close", (code) => { 97 | process.removeListener("exit", processExit); 98 | if (code === 0) 99 | resolve(); 100 | else 101 | reject(new Error(`command failed: 102 | command:${cmd} 103 | code:${code}`)); 104 | }); 105 | process.on("exit", processExit); 106 | }); 107 | }; 108 | const execCommand = async (cmd, args) => { 109 | const res = await execa__default["default"](cmd, args); 110 | return res.stdout.trim(); 111 | }; 112 | 113 | var name$1 = "gacm"; 114 | var version$1 = "1.2.11"; 115 | var description$1 = "gacm"; 116 | var author$1 = "alqmc"; 117 | var license$1 = "MIT"; 118 | var scripts = { 119 | build: "gulp --require sucrase/register/ts --gulpfile build/gulpfile.ts", 120 | clear: "rimraf dist", 121 | link: "cd dist && pnpm link --global", 122 | push: "git push gitee master && git push github master", 123 | "update:version": "sucrase-node build/utils/version.ts", 124 | lint: "eslint . --fix", 125 | log: "changeloger", 126 | release: "sucrase-node script/release.ts", 127 | prepare: "husky install" 128 | }; 129 | var dependencies$1 = { 130 | execa: "5.1.1", 131 | kolorist: "^1.5.1", 132 | minimist: "^1.2.6", 133 | "node-fetch": "2.6.6", 134 | prompts: "^2.4.2" 135 | }; 136 | var devDependencies = { 137 | "@alqmc/build-ts": "^0.0.8", 138 | "@alqmc/build-utils": "^0.0.3", 139 | "@alqmc/eslint-config-ts": "^0.0.9", 140 | "@commitlint/cli": "^8.3.5", 141 | "@commitlint/config-angular": "^8.3.4", 142 | "@commitlint/config-conventional": "^16.2.1", 143 | "@types/fs-extra": "^9.0.13", 144 | "@types/gulp": "^4.0.9", 145 | "@types/node": "^17.0.21", 146 | "@types/node-fetch": "^2.6.2", 147 | "@types/prompts": "^2.0.14", 148 | cac: "^6.7.14", 149 | changeloger: "0.1.0", 150 | commitizen: "^4.1.2", 151 | eslint: "^8.31.0", 152 | "fs-extra": "^10.1.0", 153 | gulp: "^4.0.2", 154 | husky: "^8.0.1", 155 | "lint-staged": "^10.5.4", 156 | prettier: "^2.6.2", 157 | prompts: "^2.4.2", 158 | rimraf: "^3.0.2", 159 | sucrase: "^3.20.3", 160 | tslib: "^2.4.0", 161 | typescript: "^4.6.3" 162 | }; 163 | var pkg$1 = { 164 | name: name$1, 165 | version: version$1, 166 | description: description$1, 167 | author: author$1, 168 | license: license$1, 169 | scripts: scripts, 170 | dependencies: dependencies$1, 171 | devDependencies: devDependencies 172 | }; 173 | 174 | const isExistAlias = (users, alias, name, email) => { 175 | return users.some((x) => x.alias === alias || !x.alias && x.name === alias || name && email && x.name === name && x.email === email); 176 | }; 177 | const insertUser = async (name, email, alias = name) => { 178 | let userConfig = await getFileUser(registriesPath); 179 | if (!userConfig) 180 | userConfig = { 181 | version: pkg$1.version, 182 | users: [], 183 | registry: [] 184 | }; 185 | if (!userConfig.version) 186 | userConfig = transformData(userConfig); 187 | if (isExistAlias(userConfig.users, alias, name, email)) { 188 | userConfig.users.forEach((user) => { 189 | if (user.alias === alias || !user.alias && user.name === alias || name && email && user.name === name && user.email === email) { 190 | user.alias = alias === name ? user.alias ? user.alias : alias : alias; 191 | user.email = email; 192 | user.name = name; 193 | log.success(`[update]:${alias} ${user.alias !== name ? `(${user.name})` : ""}`); 194 | } 195 | }); 196 | } else { 197 | userConfig.users.push({ 198 | name, 199 | email, 200 | alias 201 | }); 202 | log.success(`[add]: ${alias} ${alias !== name ? `(${name})` : ""}`); 203 | } 204 | await writeFileUser(registriesPath, userConfig); 205 | }; 206 | 207 | var name = "gacm"; 208 | var version = "1.2.11"; 209 | var description = "git account manage"; 210 | var author = "kinfuy (https://github.com/kinfuy)"; 211 | var license = "MIT"; 212 | var repository = "https://github.com/kinfuy/vite-plugin-shortcuts"; 213 | var keywords = [ 214 | "git", 215 | "account", 216 | "manage" 217 | ]; 218 | var bin = { 219 | gacm: "gacm.js", 220 | gnrm: "gnrm.js" 221 | }; 222 | var publishConfig = { 223 | access: "public" 224 | }; 225 | var dependencies = { 226 | cac: "^6.7.14", 227 | execa: "5.1.1", 228 | kolorist: "^1.5.1", 229 | "node-fetch": "2.6.6", 230 | prompts: "^2.4.2" 231 | }; 232 | var pkg = { 233 | name: name, 234 | version: version, 235 | "private": false, 236 | description: description, 237 | author: author, 238 | license: license, 239 | repository: repository, 240 | keywords: keywords, 241 | bin: bin, 242 | publishConfig: publishConfig, 243 | dependencies: dependencies 244 | }; 245 | 246 | const useLs = async () => { 247 | const userList = await getFileUser(registriesPath) || { version: pkg.version, users: [], registry: [] }; 248 | const currectUser = await execCommand("git", ["config", "user.name"]).catch(() => { 249 | }); 250 | const currectEmail = await execCommand("git", ["config", "user.email"]).catch(() => { 251 | }); 252 | if (userList.users.length === 0 && (!currectUser || !currectEmail)) 253 | return log.info("no user"); 254 | if (!userList.users.some((x) => x.name === currectUser) && currectUser && currectEmail) { 255 | await insertUser(currectUser, currectEmail); 256 | log.info(`[found new user]: ${currectUser}`); 257 | userList.users.push({ 258 | name: currectUser, 259 | email: currectEmail, 260 | alias: currectUser 261 | }); 262 | } 263 | const length = Math.max(...userList.users.map((user) => user.alias.length + (user.alias !== user.name ? user.name.length : 0))) + 3; 264 | const prefix = " "; 265 | const messages = userList.users.map((user) => { 266 | const currect = user.name === currectUser && user.email === currectEmail ? `${kolorist.green("\u25A0")} ` : " "; 267 | const isSame = user.alias === user.name; 268 | return `${prefix + currect}${isSame ? user.alias : `${user.alias}(${kolorist.gray(user.name)})`}${geneDashLine(user.name, length)}${user.email}`; 269 | }); 270 | printMessages(messages); 271 | }; 272 | 273 | const useDelete = async (name) => { 274 | const userList = await getFileUser(registriesPath); 275 | if (!userList) 276 | return log.error("no user"); 277 | const useUser = userList.users.find((x) => x.alias === name || !x.alias && x.name === name); 278 | if (!useUser) 279 | return log.error(`${name} not found`); 280 | for (let i = 0; i < userList.users.length; i++) 281 | if (!userList.users[i].alias && userList.users[i].name === name || userList.users[i].alias === name) { 282 | log.success(`[delete]: ${userList.users[i].alias}${userList.users[i].alias !== userList.users[i].name ? `(${userList.users[i].name})` : ""}`); 283 | userList.users.splice(i, 1); 284 | } 285 | await writeFileUser(registriesPath, userList); 286 | }; 287 | 288 | const useAdd = async (cmd) => { 289 | if (cmd.name && cmd.email) 290 | await insertUser(cmd.name, cmd.email, cmd.alias); 291 | }; 292 | 293 | const useAlias = async (origin, target) => { 294 | if (!origin || !target) 295 | return; 296 | let userList = await getFileUser(registriesPath); 297 | if (!userList) 298 | userList = { version: "", users: [] }; 299 | let changed = false; 300 | userList.users.forEach((x) => { 301 | if (x.alias === origin) { 302 | if (userList && !isExistAlias(userList?.users, target)) { 303 | x.alias = target; 304 | log.success(`[update]: ${origin}=>${x.alias} (${x.name})`); 305 | } else { 306 | log.error(`${target} is exist, please enter another one `); 307 | } 308 | changed = true; 309 | } 310 | }); 311 | if (!changed) 312 | return log.error(`${origin} not found`); 313 | await writeFileUser(registriesPath, userList); 314 | }; 315 | 316 | const useUse = async (name, cmd) => { 317 | const userList = await getFileUser(registriesPath); 318 | if (!userList) 319 | return log.error("no user exists"); 320 | let useUser; 321 | if (name) { 322 | useUser = userList.users.find((x) => x.alias === name); 323 | } else { 324 | const { user } = await prompts__default["default"]({ 325 | type: "select", 326 | name: "user", 327 | message: "Pick a account", 328 | choices: userList.users.map((x) => { 329 | return { 330 | title: `${x.alias}${x.alias === x.name ? "" : `(${x.name})`} ${x.email}`, 331 | value: x 332 | }; 333 | }) 334 | }); 335 | if (!user) { 336 | log.error("user cancel operation"); 337 | return; 338 | } 339 | useUser = user; 340 | } 341 | if (!useUser) 342 | return log.error(`${name} not found`); 343 | let env = "local"; 344 | if (cmd.system) 345 | env = "system"; 346 | if (cmd.global) 347 | env = "global"; 348 | if (cmd.local) 349 | env = "local"; 350 | await run(`git config --${env} user.name ${useUser.name}`); 351 | await run(`git config --${env} user.email ${useUser.email}`); 352 | log.success(`git user changed [${env}]:${useUser.alias}${useUser.alias !== useUser.name ? `(${useUser.name})` : ""}`); 353 | }; 354 | 355 | const useVersion = () => { 356 | return pkg.version; 357 | }; 358 | 359 | const program = cac__default["default"]("gacm"); 360 | program.version(useVersion()); 361 | program.command("ls", "\u5F53\u524D\u7528\u6237\u5217\u8868").action(useLs); 362 | program.command("use [name]", "\u5207\u6362\u7528\u6237").option("-l, --local", "\u5F53\u524D\u7528\u6237").option("-g, --global", "\u5168\u5C40\u7528\u6237").option("-s, --system", "\u7CFB\u7EDF\u7528\u6237").action(useUse); 363 | program.command("add", "\u6DFB\u52A0\u7528\u6237").option("-n, --name ", "\u7528\u6237\u540D\u79F0").option("-e, --email ", "\u7528\u6237\u90AE\u7BB1").option("-a, --alias ", "\u7528\u6237\u522B\u540D").action(useAdd); 364 | program.command("alias ", "\u6DFB\u52A0\u522B\u540D").action(useAlias); 365 | program.command("delete ", "\u5220\u9664\u7528\u6237").action(useDelete); 366 | program.help(); 367 | const init = async () => { 368 | try { 369 | program.parse(process.argv, { run: false }); 370 | await program.runMatchedCommand(); 371 | } catch (error) { 372 | console.error(error?.message || "\u672A\u77E5\u9519\u8BEF"); 373 | program.outputHelp(); 374 | process.exit(0); 375 | } 376 | }; 377 | init(); 378 | -------------------------------------------------------------------------------- /dist/gnrm.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | var cac = require('cac'); 5 | var kolorist = require('kolorist'); 6 | var prompts = require('prompts'); 7 | var fs = require('fs'); 8 | var path = require('path'); 9 | require('child_process'); 10 | require('process'); 11 | var execa = require('execa'); 12 | var fetch = require('node-fetch'); 13 | 14 | function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } 15 | 16 | var cac__default = /*#__PURE__*/_interopDefaultLegacy(cac); 17 | var prompts__default = /*#__PURE__*/_interopDefaultLegacy(prompts); 18 | var execa__default = /*#__PURE__*/_interopDefaultLegacy(execa); 19 | var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch); 20 | 21 | var name$1 = "gacm"; 22 | var version$1 = "1.2.11"; 23 | var description$1 = "git account manage"; 24 | var author$1 = "kinfuy (https://github.com/kinfuy)"; 25 | var license$1 = "MIT"; 26 | var repository = "https://github.com/kinfuy/vite-plugin-shortcuts"; 27 | var keywords = [ 28 | "git", 29 | "account", 30 | "manage" 31 | ]; 32 | var bin = { 33 | gacm: "gacm.js", 34 | gnrm: "gnrm.js" 35 | }; 36 | var publishConfig = { 37 | access: "public" 38 | }; 39 | var dependencies$1 = { 40 | cac: "^6.7.14", 41 | execa: "5.1.1", 42 | kolorist: "^1.5.1", 43 | "node-fetch": "2.6.6", 44 | prompts: "^2.4.2" 45 | }; 46 | var pkg$1 = { 47 | name: name$1, 48 | version: version$1, 49 | "private": false, 50 | description: description$1, 51 | author: author$1, 52 | license: license$1, 53 | repository: repository, 54 | keywords: keywords, 55 | bin: bin, 56 | publishConfig: publishConfig, 57 | dependencies: dependencies$1 58 | }; 59 | 60 | const useVersion = () => { 61 | return pkg$1.version; 62 | }; 63 | 64 | const rootPath = __dirname; 65 | __dirname; 66 | path.resolve(rootPath, "package"); 67 | const HOME = process.env[process.platform === "win32" ? "USERPROFILE" : "HOME"] || ""; 68 | const registriesPath = path.join(HOME, ".gacmrc"); 69 | 70 | const defaultPackageManager = ["npm", "yarn", "cnpm", "pnpm"]; 71 | const defaultNpmMirror = [ 72 | { 73 | name: "npm", 74 | alias: "npm", 75 | home: "https://www.npmjs.org", 76 | registry: "https://registry.npmjs.org/" 77 | }, 78 | { 79 | name: "yarn", 80 | alias: "yarn", 81 | home: "https://yarnpkg.com", 82 | registry: "https://registry.yarnpkg.com/" 83 | }, 84 | { 85 | name: "tencent", 86 | alias: "tencent", 87 | home: "https://mirrors.cloud.tencent.com/npm/", 88 | registry: "https://mirrors.cloud.tencent.com/npm/" 89 | }, 90 | { 91 | name: "cnpm", 92 | alias: "cnpm", 93 | home: "https://cnpmjs.org", 94 | registry: "https://r.cnpmjs.org/" 95 | }, 96 | { 97 | name: "taobao", 98 | alias: "taobao", 99 | home: "https://npmmirror.com", 100 | registry: "https://registry.npmmirror.com/" 101 | }, 102 | { 103 | name: "npmMirror", 104 | alias: "npmMirror", 105 | home: "https://skimdb.npmjs.com/", 106 | registry: "https://skimdb.npmjs.com/registry/" 107 | } 108 | ]; 109 | 110 | const success = (msg) => console.log(` 111 | ${kolorist.green(msg)} 112 | `); 113 | const error = (msg) => console.log(` 114 | ${kolorist.red(msg)} 115 | `); 116 | const warning = (msg) => console.log(` 117 | ${kolorist.yellow(msg)} 118 | `); 119 | const info = (msg) => console.log(` 120 | ${kolorist.blue(msg)} 121 | `); 122 | const log = { 123 | success, 124 | error, 125 | warning, 126 | info 127 | }; 128 | 129 | const transformData = (data) => { 130 | const userInfo = { version: "", users: [] }; 131 | Object.keys(data).forEach((x) => { 132 | userInfo.users.push({ 133 | name: data[x].name, 134 | email: data[x].email, 135 | alias: data[x].name 136 | }); 137 | }); 138 | return userInfo; 139 | }; 140 | const padding = (message = "", before = 1, after = 1) => { 141 | return new Array(before).fill(" ").join(" ") + message + new Array(after).fill(" ").join(" "); 142 | }; 143 | const geneDashLine = (message, length) => { 144 | const finalMessage = new Array(Math.max(2, length - message.length + 2)).join("-"); 145 | return padding(kolorist.white(finalMessage)); 146 | }; 147 | const printMessages = (messages) => { 148 | console.log("\n"); 149 | for (const message of messages) 150 | console.log(message); 151 | console.log("\n"); 152 | }; 153 | 154 | const { readFile, writeFile } = fs.promises; 155 | const getFileUser = async (rootPath) => { 156 | if (fs.existsSync(rootPath)) { 157 | const fileBuffer = await readFile(rootPath, "utf-8"); 158 | let userList = fileBuffer ? JSON.parse(fileBuffer.toString()) : null; 159 | if (userList && !userList.version) 160 | userList = transformData(userList); 161 | return userList; 162 | } 163 | return null; 164 | }; 165 | async function writeFileUser(dir, data) { 166 | writeFile(dir, JSON.stringify(data, null, 4)).catch((error) => { 167 | log.error(error); 168 | process.exit(0); 169 | }); 170 | } 171 | const checkRegistry = async () => { 172 | const userConfig = await getFileUser(registriesPath); 173 | let registryList = defaultNpmMirror; 174 | if (userConfig) 175 | if (!userConfig.registry || userConfig.registry.length === 0) { 176 | userConfig.registry = registryList; 177 | writeFileUser(registriesPath, userConfig); 178 | } else { 179 | registryList = userConfig.registry; 180 | } 181 | return registryList; 182 | }; 183 | 184 | const execCommand = async (cmd, args) => { 185 | const res = await execa__default["default"](cmd, args); 186 | return res.stdout.trim(); 187 | }; 188 | 189 | var name = "gacm"; 190 | var version = "1.2.11"; 191 | var description = "gacm"; 192 | var author = "alqmc"; 193 | var license = "MIT"; 194 | var scripts = { 195 | build: "gulp --require sucrase/register/ts --gulpfile build/gulpfile.ts", 196 | clear: "rimraf dist", 197 | link: "cd dist && pnpm link --global", 198 | push: "git push gitee master && git push github master", 199 | "update:version": "sucrase-node build/utils/version.ts", 200 | lint: "eslint . --fix", 201 | log: "changeloger", 202 | release: "sucrase-node script/release.ts", 203 | prepare: "husky install" 204 | }; 205 | var dependencies = { 206 | execa: "5.1.1", 207 | kolorist: "^1.5.1", 208 | minimist: "^1.2.6", 209 | "node-fetch": "2.6.6", 210 | prompts: "^2.4.2" 211 | }; 212 | var devDependencies = { 213 | "@alqmc/build-ts": "^0.0.8", 214 | "@alqmc/build-utils": "^0.0.3", 215 | "@alqmc/eslint-config-ts": "^0.0.9", 216 | "@commitlint/cli": "^8.3.5", 217 | "@commitlint/config-angular": "^8.3.4", 218 | "@commitlint/config-conventional": "^16.2.1", 219 | "@types/fs-extra": "^9.0.13", 220 | "@types/gulp": "^4.0.9", 221 | "@types/node": "^17.0.21", 222 | "@types/node-fetch": "^2.6.2", 223 | "@types/prompts": "^2.0.14", 224 | cac: "^6.7.14", 225 | changeloger: "0.1.0", 226 | commitizen: "^4.1.2", 227 | eslint: "^8.31.0", 228 | "fs-extra": "^10.1.0", 229 | gulp: "^4.0.2", 230 | husky: "^8.0.1", 231 | "lint-staged": "^10.5.4", 232 | prettier: "^2.6.2", 233 | prompts: "^2.4.2", 234 | rimraf: "^3.0.2", 235 | sucrase: "^3.20.3", 236 | tslib: "^2.4.0", 237 | typescript: "^4.6.3" 238 | }; 239 | var pkg = { 240 | name: name, 241 | version: version, 242 | description: description, 243 | author: author, 244 | license: license, 245 | scripts: scripts, 246 | dependencies: dependencies, 247 | devDependencies: devDependencies 248 | }; 249 | 250 | const insertRegistry = async (name, alias, registry, home) => { 251 | let userConfig = await getFileUser(registriesPath); 252 | if (!userConfig) 253 | userConfig = { 254 | version: pkg.version, 255 | users: [], 256 | registry: [] 257 | }; 258 | if (!userConfig.registry) 259 | userConfig.registry = []; 260 | const isExist = userConfig.registry?.some((x) => x.alias === alias); 261 | if (isExist) { 262 | userConfig.registry?.forEach((x) => { 263 | if (x.alias === alias) { 264 | x.alias = alias; 265 | x.name = name; 266 | x.home = home || ""; 267 | x.registry = registry; 268 | } 269 | }); 270 | log.success(`[update]:${alias} ${alias !== name ? `(${name})` : ""} registry ${registry}`); 271 | } else { 272 | userConfig.registry?.push({ 273 | alias, 274 | name, 275 | home: home || "", 276 | registry 277 | }); 278 | log.success(`[add]:${alias} ${alias !== name ? `(${name})` : ""} registry ${registry}`); 279 | } 280 | await writeFileUser(registriesPath, userConfig); 281 | }; 282 | 283 | const getRegistry = async (pkg) => { 284 | return await execCommand(pkg, [ 285 | "config", 286 | "get", 287 | "registry" 288 | ]).catch(() => { 289 | }); 290 | }; 291 | const getRegistrys = async (pkgs = defaultPackageManager) => { 292 | const registrys = { 293 | npm: "", 294 | pnpm: "", 295 | cnpm: "", 296 | yarn: "" 297 | }; 298 | const list = pkgs.map(async (pkg) => { 299 | return { 300 | pkg, 301 | handle: await getRegistry(pkg) 302 | }; 303 | }); 304 | for (const iterator of list) { 305 | const itme = await iterator; 306 | registrys[itme.pkg] = itme.handle || ""; 307 | } 308 | return registrys; 309 | }; 310 | const useLs = async (cmd) => { 311 | const registryList = await checkRegistry(); 312 | const pkgs = []; 313 | if (cmd.packageManager) 314 | pkgs.push(cmd.packageManager); 315 | else 316 | pkgs.push(...defaultPackageManager); 317 | const currectRegistry = await getRegistrys(pkgs); 318 | if (registryList.every((x) => Object.values(currectRegistry).includes(x.registry))) 319 | try { 320 | const newRegistry = Object.keys(currectRegistry).map((x) => { 321 | if (registryList.every((val) => currectRegistry[x] && val.registry !== currectRegistry[x])) 322 | return currectRegistry[x]; 323 | return ""; 324 | }); 325 | Array.from(new Set(newRegistry)).filter((x) => x).forEach(async (registry) => { 326 | const { name } = await prompts__default["default"]({ 327 | type: "text", 328 | name: "name", 329 | message: `find new registry:${currectRegistry}, please give it a name` 330 | }); 331 | await insertRegistry(name, name, registry); 332 | log.info(`[found new registry]: ${currectRegistry}`); 333 | registryList.push({ 334 | name, 335 | registry, 336 | home: "", 337 | alias: name 338 | }); 339 | }); 340 | } catch (error) { 341 | } 342 | const length = Math.max(...registryList.map((x) => { 343 | return x.alias.length + (x.alias !== x.name ? x.name.length : 0); 344 | })) + 3; 345 | const prefix = ""; 346 | const colorMap = { 347 | npm: kolorist.green, 348 | cnpm: kolorist.red, 349 | yarn: kolorist.blue, 350 | pnpm: kolorist.yellow 351 | }; 352 | const currentTip = `current: ${Object.keys(currectRegistry).map((key) => { 353 | if (currectRegistry[key]) 354 | return `${key}: ${colorMap[key]("\u25A0")}`; 355 | return ""; 356 | }).filter((i) => i).join(" ")} 357 | 358 | `; 359 | const messages = registryList.map((item) => { 360 | const currect = Object.keys(currectRegistry).map((key) => { 361 | if (currectRegistry[key] && item.registry.includes(currectRegistry[key])) 362 | return colorMap[key]("\u25A0"); 363 | return ""; 364 | }).filter((x) => x); 365 | const isSame = item.alias === item.name; 366 | const str = `${prefix}${isSame ? item.alias : `${item.alias}(${kolorist.gray(item.name)})`}${geneDashLine(item.name, length)}${item.registry}`; 367 | return `${currect.length > 0 ? padding(`${currect.join(" ")}`, 4 - currect.length, 1) : ""} ${padding(str, currect.length > 0 ? 0 : 4, 0)}`; 368 | }); 369 | messages.unshift(currentTip); 370 | printMessages(messages); 371 | }; 372 | 373 | const useUse = async (name, cmd) => { 374 | const userConfig = await getFileUser(registriesPath); 375 | let registrylist = defaultNpmMirror; 376 | let packageManager = "npm"; 377 | if (userConfig && userConfig.registry) 378 | registrylist = userConfig.registry; 379 | let useRegistry; 380 | if (name) { 381 | useRegistry = registrylist.find((x) => x.alias === name); 382 | } else { 383 | const { registry, pkg } = await prompts__default["default"]([ 384 | { 385 | type: "select", 386 | name: "registry", 387 | message: "Pick a registry", 388 | choices: registrylist.map((x) => { 389 | return { 390 | title: `${x.alias}${x.alias === x.name ? "" : `(${x.name})`} ${x.registry}`, 391 | value: x 392 | }; 393 | }) 394 | }, 395 | { 396 | type: "select", 397 | name: "pkg", 398 | message: "Pick a packageManager,and you will set registry for it", 399 | initial: 0, 400 | choices: defaultPackageManager.map((x) => ({ 401 | title: x, 402 | value: x 403 | })) 404 | } 405 | ]); 406 | if (pkg) 407 | packageManager = pkg; 408 | if (!registry) { 409 | log.error("user cancel operation"); 410 | return; 411 | } 412 | useRegistry = registry; 413 | } 414 | if (!useRegistry) 415 | return log.error(`${name} not found`); 416 | if (cmd.packageManager) 417 | packageManager = cmd.packageManager; 418 | execCommand(packageManager, [ 419 | "config", 420 | "set", 421 | "registry", 422 | useRegistry.registry 423 | ]).then(() => { 424 | log.success(`${packageManager} registry has been set to: ${useRegistry.registry}`); 425 | }).catch(() => { 426 | log.error(`${packageManager} is not found`); 427 | }); 428 | }; 429 | 430 | const useAdd = async (cmd) => { 431 | if (cmd.name && cmd.registry) { 432 | const alias = cmd.alias || cmd.name; 433 | await insertRegistry(cmd.name, alias, cmd.registry); 434 | } 435 | }; 436 | 437 | const useAlias = async (origin, target) => { 438 | if (!origin || !target) 439 | return; 440 | let useConfig = await getFileUser(registriesPath); 441 | if (!useConfig) 442 | useConfig = { version: "", users: [], registry: [] }; 443 | if (!useConfig.registry) 444 | useConfig.registry = []; 445 | let changed = false; 446 | useConfig.registry?.forEach((x) => { 447 | if (x.alias === origin) { 448 | if (useConfig && useConfig.registry?.every((x2) => x2.alias !== target)) { 449 | x.alias = target; 450 | log.success(`[update]: ${origin}=>${x.alias} (${x.name})`); 451 | } else { 452 | log.error(`${target} is exist, please enter another one `); 453 | } 454 | changed = true; 455 | } 456 | }); 457 | if (!changed) 458 | return log.error(`${origin} not found`); 459 | await writeFileUser(registriesPath, useConfig); 460 | }; 461 | 462 | const useDelete = async (name) => { 463 | const userConfig = await getFileUser(registriesPath); 464 | if (!userConfig) 465 | return log.error("no registry"); 466 | if (!userConfig.registry) 467 | return log.error("no registry"); 468 | const useRegistry = userConfig.registry.find((x) => x.alias === name); 469 | if (!useRegistry) 470 | return log.error(`${name} not found`); 471 | for (let i = 0; i < userConfig.registry.length; i++) 472 | if (userConfig.registry[i].alias === name) { 473 | log.success(`[delete]: ${userConfig.registry[i].alias} ${userConfig.registry[i].registry}`); 474 | userConfig.registry.splice(i, 1); 475 | } 476 | await writeFileUser(registriesPath, userConfig); 477 | }; 478 | 479 | const testRegistry = async (registry) => { 480 | const start = Date.now(); 481 | const options = { 482 | timeout: 5e3 483 | }; 484 | let status = false; 485 | let isTimeout = false; 486 | try { 487 | const response = await fetch__default["default"](registry, { 488 | ...options 489 | }); 490 | status = response.ok; 491 | } catch (error) { 492 | isTimeout = error.type === "request-timeout"; 493 | } 494 | return { 495 | status, 496 | isTimeout, 497 | start 498 | }; 499 | }; 500 | const useTest = async (cmd) => { 501 | const registryList = await checkRegistry(); 502 | const test = async (registry2) => { 503 | const { status, start, isTimeout } = await testRegistry(new URL("", registry2.registry).href); 504 | if (isTimeout) 505 | console.log(` 506 | ${kolorist.red("\u3010Timeout\u3011")} ping ${registry2.alias}${registry2.alias === registry2.name ? "" : `${kolorist.gray(`(${registry2.name})`)}`}\uFF1A${registry2.registry}`); 507 | if (status) { 508 | const end = Date.now(); 509 | console.log(` 510 | ${kolorist.green(`\u3010${end - start}ms\u3011`)} ping ${registry2.alias}${registry2.alias === registry2.name ? "" : `${kolorist.gray(`(${registry2.name})`)}`}\uFF1A${registry2.registry}`); 511 | } 512 | }; 513 | if (cmd.all) { 514 | const list = registryList.map(async (r) => { 515 | return { 516 | handle: await test(r) 517 | }; 518 | }); 519 | for (const iterator of list) 520 | await iterator; 521 | return; 522 | } 523 | if (cmd.registry) { 524 | const registry2 = registryList.find((x) => x.alias === cmd.registry || x.name === cmd.registry); 525 | if (registry2) 526 | await test(registry2); 527 | return; 528 | } 529 | const { registry } = await prompts__default["default"]([ 530 | { 531 | type: "select", 532 | name: "registry", 533 | message: "Pick a registry", 534 | choices: registryList.map((x) => { 535 | return { 536 | title: `${x.alias}${x.alias === x.name ? "" : `(${x.name})`} ${x.registry}`, 537 | value: x 538 | }; 539 | }) 540 | } 541 | ]); 542 | await test(registry); 543 | }; 544 | 545 | const program = cac__default["default"]("gnrm"); 546 | program.version(useVersion()); 547 | program.command("ls", "\u5F53\u524D\u7528\u6237\u5217\u8868").option("-p, --packageManager ", "\u67E5\u770B\u5BF9\u5E94\u5305\u7BA1\u7406\u5668\uFF1A\u9ED8\u8BA4npm").action(useLs); 548 | program.command("use [name]", "\u5207\u6362\u955C\u50CF\u6E90").option("-p, --registry ", "\u8BBE\u7F6E\u5BF9\u5E94\u5305\u7BA1\u7406\u5668\uFF1A\u9ED8\u8BA4npm").action(useUse); 549 | program.command("test", "\u5207\u6362\u955C\u50CF\u6E90").option("-r, --registry ", "\u6D4B\u8BD5\u6E90\u540D\u79F0\u6216\u8005\u522B\u540D").option("-a, --all", "\u6D4B\u8BD5\u5B58\u5728\u7684\u955C\u50CF\u6E90").action(useTest); 550 | program.command("add", "\u6DFB\u52A0\u955C\u50CF").option("-n, --name ", "\u955C\u50CF\u540D\u79F0").option("-r, --registry ", "\u955C\u50CF\u5730\u5740").option("-a, --alias ", "\u955C\u50CF\u522B\u540D").action(useAdd); 551 | program.command("alias ", "\u955C\u50CF\u6DFB\u52A0\u522B\u540D").action(useAlias); 552 | program.command("delete ", "\u5220\u9664\u955C\u50CF").action(useDelete); 553 | program.help(); 554 | const init = async () => { 555 | try { 556 | program.parse(process.argv, { run: false }); 557 | await program.runMatchedCommand(); 558 | } catch (error) { 559 | console.error(error?.message || "\u672A\u77E5\u9519\u8BEF"); 560 | program.outputHelp(); 561 | process.exit(0); 562 | } 563 | }; 564 | init(); 565 | --------------------------------------------------------------------------------