neat-admin-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # ndc
2
+
3
+ A CLI tool to scaffold an Ant Design admin project from the [ant-admin-template](https://github.com/leonwgc/ant-admin-template) GitHub template.
4
+
5
+ [中文文档](./README.zh-CN.md)
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g ndc
11
+ ```
12
+
13
+ Or use it directly via `npx`:
14
+
15
+ ```bash
16
+ npx ndc init --dir my-admin-project
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```bash
22
+ ndc init --dir <directory>
23
+ ```
24
+
25
+ ### Options
26
+
27
+ | Option | Description |
28
+ |--------|-------------|
29
+ | `--dir <directory>` | Target directory name or path for the new project (required) |
30
+ | `-V, --version` | Output the version number |
31
+ | `-h, --help` | Display help information |
32
+
33
+ ### Example
34
+
35
+ ```bash
36
+ # Create a project in the current directory
37
+ ndc init --dir my-admin-project
38
+
39
+ # Create a project at an absolute path
40
+ ndc init --dir /path/to/my-admin-project
41
+ ```
42
+
43
+ After initialization, the tool will:
44
+
45
+ 1. Clone the template with `git clone --depth 1`
46
+ 2. Re-initialize a clean git repository
47
+ 3. Install dependencies with `npm install`
48
+
49
+ Then start the development server:
50
+
51
+ ```bash
52
+ cd my-admin-project
53
+ npm run dev
54
+ ```
55
+
56
+ ## Template
57
+
58
+ The project template is based on [ant-admin-template](https://github.com/leonwgc/ant-admin-template), which includes:
59
+
60
+ - React + TypeScript
61
+ - Ant Design component library
62
+ - gdn-pack build tool
63
+ - Routing & layout setup
64
+
65
+ ## License
66
+
67
+ MIT
@@ -0,0 +1,67 @@
1
+ # ndc
2
+
3
+ 一个基于 Node.js 的 CLI 工具,用于从 [ant-admin-template](https://github.com/leonwgc/ant-admin-template) 模板快速初始化 Ant Design 后台管理项目。
4
+
5
+ [English](./README.md)
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ npm install -g ndc
11
+ ```
12
+
13
+ 或通过 `npx` 直接使用(无需全局安装):
14
+
15
+ ```bash
16
+ npx ndc init --dir my-admin-project
17
+ ```
18
+
19
+ ## 使用方法
20
+
21
+ ```bash
22
+ ndc init --dir <目录>
23
+ ```
24
+
25
+ ### 参数说明
26
+
27
+ | 参数 | 说明 |
28
+ |------|------|
29
+ | `--dir <目录>` | 新项目的目标目录名称或路径(必填) |
30
+ | `-V, --version` | 输出版本号 |
31
+ | `-h, --help` | 显示帮助信息 |
32
+
33
+ ### 示例
34
+
35
+ ```bash
36
+ # 在当前目录下创建项目
37
+ ndc init --dir my-admin-project
38
+
39
+ # 指定绝对路径创建项目
40
+ ndc init --dir /path/to/my-admin-project
41
+ ```
42
+
43
+ 初始化完成后,工具会依次执行:
44
+
45
+ 1. 使用 `git clone --depth 1` 克隆模板仓库
46
+ 2. 删除原始 `.git`,重新初始化为全新 git 仓库
47
+ 3. 使用 `npm install` 自动安装依赖
48
+
49
+ 然后启动开发服务器:
50
+
51
+ ```bash
52
+ cd my-admin-project
53
+ npm run dev
54
+ ```
55
+
56
+ ## 模板介绍
57
+
58
+ 项目模板基于 [ant-admin-template](https://github.com/leonwgc/ant-admin-template),包含以下技术栈:
59
+
60
+ - React + TypeScript
61
+ - Ant Design 组件库
62
+ - gdn-pack 构建工具
63
+ - 路由与布局结构
64
+
65
+ ## License
66
+
67
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const commander_1 = require("commander");
41
+ const child_process_1 = require("child_process");
42
+ const path = __importStar(require("path"));
43
+ const fs = __importStar(require("fs"));
44
+ const chalk_1 = __importDefault(require("chalk"));
45
+ const TEMPLATE_URL = 'https://github.com/leonwgc/neat-admin-template.git';
46
+ function run(command, cwd) {
47
+ return new Promise((resolve, reject) => {
48
+ const [cmd, ...args] = command.split(' ');
49
+ const child = (0, child_process_1.spawn)(cmd, args, {
50
+ cwd,
51
+ stdio: 'inherit',
52
+ shell: process.platform === 'win32',
53
+ });
54
+ child.on('close', (code) => {
55
+ if (code === 0) {
56
+ resolve();
57
+ }
58
+ else {
59
+ reject(new Error(chalk_1.default.red(`Command failed: ${command} (exit code: ${code})`)));
60
+ }
61
+ });
62
+ child.on('error', (err) => {
63
+ reject(new Error(chalk_1.default.red(`Failed to start command: ${command}\n${err.message}`)));
64
+ });
65
+ });
66
+ }
67
+ async function init(dir) {
68
+ const targetDir = path.resolve(process.cwd(), dir);
69
+ if (fs.existsSync(targetDir)) {
70
+ console.error(chalk_1.default.red(`Error: Directory already exists: ${targetDir}`));
71
+ process.exit(1);
72
+ }
73
+ const parentDir = path.dirname(targetDir);
74
+ const projectName = path.basename(targetDir);
75
+ if (!fs.existsSync(parentDir)) {
76
+ fs.mkdirSync(parentDir, { recursive: true });
77
+ }
78
+ console.log(chalk_1.default.cyan(`\nCloning codes into ${chalk_1.default.bold(targetDir)} ...\n`));
79
+ try {
80
+ await run(`git clone --depth 1 ${TEMPLATE_URL} ${projectName}`, parentDir);
81
+ }
82
+ catch (err) {
83
+ console.error(chalk_1.default.red('Clone failed:'), err.message);
84
+ process.exit(1);
85
+ }
86
+ // Remove .git and re-initialize
87
+ const gitDir = path.join(targetDir, '.git');
88
+ if (fs.existsSync(gitDir)) {
89
+ fs.rmSync(gitDir, { recursive: true, force: true });
90
+ }
91
+ await run('git init', targetDir);
92
+ // Remove docs directory if present
93
+ const docsDir = path.join(targetDir, 'docs');
94
+ if (fs.existsSync(docsDir)) {
95
+ fs.rmSync(docsDir, { recursive: true, force: true });
96
+ console.log(chalk_1.default.gray('Removed docs directory.'));
97
+ }
98
+ // Update package.json name and description
99
+ const pkgPath = path.join(targetDir, 'package.json');
100
+ if (fs.existsSync(pkgPath)) {
101
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
102
+ pkg.name = projectName;
103
+ pkg.description = projectName;
104
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
105
+ }
106
+ // Replace HashRouter with BrowserRouter in index.tsx
107
+ const indexTsxPath = path.join(targetDir, 'src', 'index.tsx');
108
+ if (fs.existsSync(indexTsxPath)) {
109
+ let content = fs.readFileSync(indexTsxPath, 'utf-8');
110
+ if (content.includes('HashRouter')) {
111
+ content = content.replace(/HashRouter/g, 'BrowserRouter');
112
+ fs.writeFileSync(indexTsxPath, content, 'utf-8');
113
+ }
114
+ }
115
+ const pm = 'npm';
116
+ console.log(chalk_1.default.cyan(`\nInstalling dependencies...\n`));
117
+ try {
118
+ await run(`${pm} install`, targetDir);
119
+ }
120
+ catch (err) {
121
+ console.error(chalk_1.default.red('Install failed:'), err.message);
122
+ process.exit(1);
123
+ }
124
+ console.log(chalk_1.default.green(`\n✅ Project initialized successfully!\n`));
125
+ console.log(chalk_1.default.cyan(`\nStarting development server...\n`));
126
+ try {
127
+ await run(`${pm} start`, targetDir);
128
+ }
129
+ catch (err) {
130
+ console.error(chalk_1.default.red('Start failed:'), err.message);
131
+ process.exit(1);
132
+ }
133
+ }
134
+ const program = new commander_1.Command();
135
+ program
136
+ .name('ndc')
137
+ .description('Scaffold a neat design admin project from template')
138
+ .version('1.0.0');
139
+ program
140
+ .command('init')
141
+ .description('Initialize a new project')
142
+ .requiredOption('--dir <directory>', 'Target directory name or path for the new project')
143
+ .action((options) => {
144
+ init(options.dir).catch((err) => {
145
+ console.error(err.message);
146
+ process.exit(1);
147
+ });
148
+ });
149
+ program.parse(process.argv);
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "neat-admin-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool to initialize ant-admin project from template",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "neat-admin-cli": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "ts-node src/index.ts",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "keywords": [
15
+ "cli",
16
+ "ant-admin",
17
+ "template"
18
+ ],
19
+ "author": "leonwgc",
20
+ "license": "MIT",
21
+ "dependencies": {
22
+ "chalk": "^4.1.2",
23
+ "commander": "^12.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/chalk": "^0.4.31",
27
+ "@types/node": "^20.0.0",
28
+ "ts-node": "^10.9.2",
29
+ "typescript": "^5.4.0"
30
+ }
31
+ }
package/src/index.ts ADDED
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { spawn } from 'child_process';
5
+ import * as path from 'path';
6
+ import * as fs from 'fs';
7
+ import chalk from 'chalk';
8
+
9
+ const TEMPLATE_URL = 'https://github.com/leonwgc/neat-admin-template.git';
10
+
11
+ function run(command: string, cwd: string): Promise<void> {
12
+ return new Promise((resolve, reject) => {
13
+ const [cmd, ...args] = command.split(' ');
14
+ const child = spawn(cmd, args, {
15
+ cwd,
16
+ stdio: 'inherit',
17
+ shell: process.platform === 'win32',
18
+ });
19
+
20
+ child.on('close', (code) => {
21
+ if (code === 0) {
22
+ resolve();
23
+ } else {
24
+ reject(new Error(chalk.red(`Command failed: ${command} (exit code: ${code})`)));
25
+ }
26
+ });
27
+
28
+ child.on('error', (err) => {
29
+ reject(new Error(chalk.red(`Failed to start command: ${command}\n${err.message}`)));
30
+ });
31
+ });
32
+ }
33
+
34
+ async function init(dir: string): Promise<void> {
35
+ const targetDir = path.resolve(process.cwd(), dir);
36
+
37
+ if (fs.existsSync(targetDir)) {
38
+ console.error(chalk.red(`Error: Directory already exists: ${targetDir}`));
39
+ process.exit(1);
40
+ }
41
+
42
+ const parentDir = path.dirname(targetDir);
43
+ const projectName = path.basename(targetDir);
44
+
45
+ if (!fs.existsSync(parentDir)) {
46
+ fs.mkdirSync(parentDir, { recursive: true });
47
+ }
48
+
49
+ console.log(chalk.cyan(`\nCloning codes into ${chalk.bold(targetDir)} ...\n`));
50
+ try {
51
+ await run(
52
+ `git clone --depth 1 ${TEMPLATE_URL} ${projectName}`,
53
+ parentDir
54
+ );
55
+ } catch (err) {
56
+ console.error(chalk.red('Clone failed:'), (err as Error).message);
57
+ process.exit(1);
58
+ }
59
+
60
+ // Remove .git and re-initialize
61
+ const gitDir = path.join(targetDir, '.git');
62
+ if (fs.existsSync(gitDir)) {
63
+ fs.rmSync(gitDir, { recursive: true, force: true });
64
+ }
65
+ await run('git init', targetDir);
66
+
67
+ // Remove docs directory if present
68
+ const docsDir = path.join(targetDir, 'docs');
69
+ if (fs.existsSync(docsDir)) {
70
+ fs.rmSync(docsDir, { recursive: true, force: true });
71
+ console.log(chalk.gray('Removed docs directory.'));
72
+ }
73
+
74
+ // Update package.json name and description
75
+ const pkgPath = path.join(targetDir, 'package.json');
76
+ if (fs.existsSync(pkgPath)) {
77
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
78
+ pkg.name = projectName;
79
+ pkg.description = projectName;
80
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
81
+ }
82
+
83
+ // Replace HashRouter with BrowserRouter in index.tsx
84
+ const indexTsxPath = path.join(targetDir, 'src', 'index.tsx');
85
+ if (fs.existsSync(indexTsxPath)) {
86
+ let content = fs.readFileSync(indexTsxPath, 'utf-8');
87
+ if (content.includes('HashRouter')) {
88
+ content = content.replace(/HashRouter/g, 'BrowserRouter');
89
+ fs.writeFileSync(indexTsxPath, content, 'utf-8');
90
+ }
91
+ }
92
+
93
+ const pm = 'npm';
94
+ console.log(chalk.cyan(`\nInstalling dependencies...\n`));
95
+ try {
96
+ await run(`${pm} install`, targetDir);
97
+ } catch (err) {
98
+ console.error(chalk.red('Install failed:'), (err as Error).message);
99
+ process.exit(1);
100
+ }
101
+
102
+ console.log(chalk.green(`\n✅ Project initialized successfully!\n`));
103
+ console.log(chalk.cyan(`\nStarting development server...\n`));
104
+ try {
105
+ await run(`${pm} start`, targetDir);
106
+ } catch (err) {
107
+ console.error(chalk.red('Start failed:'), (err as Error).message);
108
+ process.exit(1);
109
+ }
110
+ }
111
+
112
+ const program = new Command();
113
+
114
+ program
115
+ .name('ndc')
116
+ .description('Scaffold a neat design admin project from template')
117
+ .version('1.0.0');
118
+
119
+ program
120
+ .command('init')
121
+ .description('Initialize a new project')
122
+ .requiredOption('--dir <directory>', 'Target directory name or path for the new project')
123
+ .action((options) => {
124
+ init(options.dir).catch((err) => {
125
+ console.error(err.message);
126
+ process.exit(1);
127
+ });
128
+ });
129
+
130
+ program.parse(process.argv);
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2018",
4
+ "module": "commonjs",
5
+ "lib": ["ES2018"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "declaration": true,
12
+ "resolveJsonModule": true
13
+ },
14
+ "include": ["src/**/*"],
15
+ "exclude": ["node_modules", "dist"]
16
+ }