create-art-app-pino 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 +213 -0
- package/dist/index.cjs +418 -0
- package/package.json +44 -0
- package/template/auth-art/_env.development +2 -0
- package/template/auth-art/src/api/auth.ts +37 -0
- package/template/auth-art/src/router/guards/beforeEach.ts +64 -0
- package/template/auth-art/src/router/index.ts.ejs +52 -0
- package/template/auth-art/src/store/modules/user.ts +64 -0
- package/template/auth-art/src/utils/http/index.ts +60 -0
- package/template/auth-art/src/views/auth/login/index.vue +172 -0
- package/template/auth-zhihuishu/_env.development +5 -0
- package/template/auth-zhihuishu/_env.local.example +5 -0
- package/template/auth-zhihuishu/src/constants/auth.ts +10 -0
- package/template/auth-zhihuishu/src/router/guards/beforeEach.ts +47 -0
- package/template/auth-zhihuishu/src/router/index.ts.ejs +46 -0
- package/template/auth-zhihuishu/src/services/authService.ts +55 -0
- package/template/auth-zhihuishu/src/store/modules/auth.ts +227 -0
- package/template/auth-zhihuishu/src/types/auth.ts +43 -0
- package/template/auth-zhihuishu/src/utils/auth.ts +161 -0
- package/template/auth-zhihuishu/src/utils/http/index.ts +61 -0
- package/template/base/AGENTS.md.ejs +65 -0
- package/template/base/_gitignore.ejs +6 -0
- package/template/base/_husky/commit-msg +1 -0
- package/template/base/_husky/pre-commit.ejs +3 -0
- package/template/base/_husky/pre-push +1 -0
- package/template/base/_vscode/extensions.json.ejs +6 -0
- package/template/base/_vscode/settings.json.ejs +26 -0
- package/template/base/commitlint.config.mjs +6 -0
- package/template/base/eslint.config.mjs +11 -0
- package/template/base/index.html +13 -0
- package/template/base/lint-staged.config.mjs.ejs +4 -0
- package/template/base/package.json.ejs +58 -0
- package/template/base/src/App.vue +3 -0
- package/template/base/src/assets/styles/index.scss +10 -0
- package/template/base/src/env.d.ts +7 -0
- package/template/base/src/main.ts +19 -0
- package/template/base/src/router/index.ts.ejs +42 -0
- package/template/base/src/store/index.ts +7 -0
- package/template/base/src/store/modules/setting.ts +17 -0
- package/template/base/src/utils/http/index.ts +34 -0
- package/template/base/src/views/dashboard/index.vue +42 -0
- package/template/base/src/views/exception/403.vue +25 -0
- package/template/base/src/views/exception/404.vue +25 -0
- package/template/base/src/views/index/index.vue +122 -0
- package/template/base/tsconfig.app.json +12 -0
- package/template/base/tsconfig.json +19 -0
- package/template/base/tsconfig.node.json +7 -0
- package/template/base/vite.config.ts +34 -0
- package/template/feature-echarts/package.json +5 -0
- package/template/feature-echarts/src/plugins/echarts.ts +22 -0
- package/template/feature-markdown/package.json +5 -0
- package/template/feature-markdown/src/components/MdPreviewWrapper.vue +26 -0
- package/template/feature-sse/package.json +5 -0
- package/template/feature-sse/src/utils/sse.ts +100 -0
- package/template/scaffold-doc-governance/CHANGELOG.md +19 -0
- package/template/scaffold-doc-governance/_github/PULL_REQUEST_TEMPLATE.md +28 -0
- package/template/scaffold-doc-governance/docs/README.md +35 -0
- package/template/scaffold-doc-governance/docs/adr/0001-doc-governance.md +195 -0
- package/template/scaffold-doc-governance/docs/architecture/.gitkeep +0 -0
- package/template/scaffold-doc-governance/docs/archive/.gitkeep +0 -0
- package/template/scaffold-doc-governance/docs/changes/requirements/.gitkeep +0 -0
- package/template/scaffold-doc-governance/docs/getting-started/quick-start.md.ejs +62 -0
- package/template/scaffold-doc-governance/docs/guides/.gitkeep +0 -0
- package/template/scaffold-doc-governance/docs/maintenance/incidents/.gitkeep +0 -0
- package/template/scaffold-doc-governance/docs/maintenance/troubleshooting.md +25 -0
- package/template/scaffold-doc-governance/docs/reference/.gitkeep +0 -0
- package/template/scaffold-doc-governance/docs/reference/cli.md +46 -0
- package/template/scaffold-doc-governance/docs/templates/adr.md +21 -0
- package/template/scaffold-doc-governance/docs/templates/incident.md +25 -0
- package/template/scaffold-doc-governance/docs/templates/requirement.md +29 -0
- package/template/scaffold-doc-governance/package.json +5 -0
- package/template/scaffold-doc-governance/scripts/docs/lint-frontmatter.mjs +85 -0
- package/template/scaffold-doc-governance/scripts/docs/lint-links.sh +13 -0
- package/template/scaffold-doc-governance/scripts/docs/lint-naming.mjs +89 -0
- package/template/scaffold-doc-governance/scripts/docs/lint-no-private-path.sh +19 -0
package/README.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# create-art-app-pino
|
|
2
|
+
|
|
3
|
+
基于 [Art Design Pro](https://github.com/Daymychen/art-design-pro) 的 Vue 3 项目脚手架 CLI。
|
|
4
|
+
|
|
5
|
+
一条命令生成包含认证、路由、工程化、文档治理的完整前端项目,生成后独立演进,CLI 不再介入。
|
|
6
|
+
|
|
7
|
+
## 快速开始
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# 推荐:交互式创建
|
|
11
|
+
pnpm create art-app-pino my-project
|
|
12
|
+
|
|
13
|
+
# 或使用 npx
|
|
14
|
+
npx create-art-app-pino my-project
|
|
15
|
+
|
|
16
|
+
# 全默认(跳过所有问答)
|
|
17
|
+
pnpm create art-app-pino my-project --default
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## CLI 参数
|
|
21
|
+
|
|
22
|
+
| 参数 | 说明 | 默认值 |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| `--default` | 跳过所有交互,使用默认值 | — |
|
|
25
|
+
| `--auth art` | Art 内置登录页 | `art` |
|
|
26
|
+
| `--auth zhs` | 智慧树 CAS 统一认证 | — |
|
|
27
|
+
| `--history` | History 路由模式 | ✅ |
|
|
28
|
+
| `--hash` | Hash 路由模式 | — |
|
|
29
|
+
| `--no-reference` | 不克隆 `.reference/art-design-pro` | — |
|
|
30
|
+
| `--no-vscode` | 不生成 `.vscode/` 配置 | — |
|
|
31
|
+
| `--no-agents` | 不生成 `AGENTS.md` | — |
|
|
32
|
+
| `--no-doc-governance` | 不启用文档治理 | — |
|
|
33
|
+
|
|
34
|
+
### 示例
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# 智慧树认证 + Hash 路由 + 不克隆 reference
|
|
38
|
+
pnpm create art-app-pino my-app --auth zhs --hash --no-reference
|
|
39
|
+
|
|
40
|
+
# 最小化项目
|
|
41
|
+
pnpm create art-app-pino my-app --default --no-reference --no-vscode --no-doc-governance
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 生成项目的技术栈
|
|
45
|
+
|
|
46
|
+
- **框架**:Vue 3 + TypeScript + Vite
|
|
47
|
+
- **UI**:Element Plus + Tailwind CSS v4
|
|
48
|
+
- **状态管理**:Pinia + pinia-plugin-persistedstate
|
|
49
|
+
- **工程化**:ESLint + Husky + lint-staged + commitlint
|
|
50
|
+
- **文档治理**(可选):frontmatter 校验 + 命名规范 + 私人路径检测 + 死链检测
|
|
51
|
+
|
|
52
|
+
## 交互式选项
|
|
53
|
+
|
|
54
|
+
### 认证方式
|
|
55
|
+
|
|
56
|
+
| 选项 | 说明 |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| **Art 内置登录** | 用户名/密码登录页 + 前端 token 管理 |
|
|
59
|
+
| **智慧树 CAS** | 企业 CAS 统一认证 + 开发态 env token 模式 |
|
|
60
|
+
|
|
61
|
+
### 功能模块
|
|
62
|
+
|
|
63
|
+
| 模块 | 包 | 默认 |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| Markdown 渲染 | `md-editor-v3` | ✅ |
|
|
66
|
+
| SSE 流式请求 | `@microsoft/fetch-event-source` | ✅ |
|
|
67
|
+
| ECharts 图表 | `echarts` + `vue-echarts` | ✅ |
|
|
68
|
+
| 拖拽 | `vue-draggable-plus` | ✅ |
|
|
69
|
+
| 日期工具 | `dayjs` | ✅ |
|
|
70
|
+
|
|
71
|
+
### 工程化配置
|
|
72
|
+
|
|
73
|
+
| 配置 | 说明 | 默认 |
|
|
74
|
+
| --- | --- | --- |
|
|
75
|
+
| `.reference` | 克隆 art-design-pro 作为参考代码 | ✅ |
|
|
76
|
+
| `.vscode` | 统一编辑器配置 | ✅ |
|
|
77
|
+
| `AGENTS.md` | AI 开发约束文件 | ✅ |
|
|
78
|
+
| 文档治理 | `docs/` 骨架 + 4 道护栏 + PR 模板 | ✅ |
|
|
79
|
+
|
|
80
|
+
## 版本标记与升级迁移
|
|
81
|
+
|
|
82
|
+
### 版本标记
|
|
83
|
+
|
|
84
|
+
每个生成的项目在 `package.json` 中自动记录创建时使用的 CLI 版本:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"create-art-app-pino": {
|
|
89
|
+
"version": "1.0.0"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 迁移机制
|
|
95
|
+
|
|
96
|
+
**生成后的项目与 CLI 解耦**——CLI 只负责初始创建,不提供 `upgrade` 命令。当脚手架升级时,通过 [MIGRATION.md](./MIGRATION.md) 指导已有项目手动跟进。
|
|
97
|
+
|
|
98
|
+
#### 对于 CLI 维护者
|
|
99
|
+
|
|
100
|
+
每次发版时在 `MIGRATION.md` 中新增版本段落,包含:
|
|
101
|
+
|
|
102
|
+
1. **变更概述** — 本次改了什么
|
|
103
|
+
2. **必须操作** — 已有项目必须执行的步骤
|
|
104
|
+
3. **可选操作** — 按需执行的步骤
|
|
105
|
+
|
|
106
|
+
#### 对于已有项目的开发者
|
|
107
|
+
|
|
108
|
+
1. 查看项目 `package.json` 中的 `create-art-app-pino.version`
|
|
109
|
+
2. 打开 CLI 仓库的 [MIGRATION.md](./MIGRATION.md)
|
|
110
|
+
3. 找到从当前版本到最新版本之间的所有段落
|
|
111
|
+
4. 按顺序执行迁移步骤
|
|
112
|
+
|
|
113
|
+
## 开发
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
pnpm install # 安装依赖
|
|
117
|
+
pnpm dev # 开发模式(watch)
|
|
118
|
+
pnpm build # 构建
|
|
119
|
+
|
|
120
|
+
# 本地测试
|
|
121
|
+
mkdir -p _test-output && cd _test-output
|
|
122
|
+
node ../dist/index.cjs my-test --default --no-reference
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 发布
|
|
126
|
+
|
|
127
|
+
### 前置:npm registry 配置
|
|
128
|
+
|
|
129
|
+
国内开发者通常用 CNPM 镜像加速安装,但 **登录和发布必须走官方 registry**。
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# 查看当前 registry(如果是 npmmirror 则需要额外配置)
|
|
133
|
+
npm config get registry
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**方式 A:命令行指定(推荐,不改全局配置)**
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npm login --registry=https://registry.npmjs.org
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**方式 B:在 package.json 中锁定发布地址(一劳永逸)**
|
|
143
|
+
|
|
144
|
+
项目已配置 `publishConfig`,`pnpm publish` 会自动走官方 registry:
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"publishConfig": {
|
|
149
|
+
"registry": "https://registry.npmjs.org"
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
> 日常 `pnpm install` 仍走 CNPM 镜像,两不耽误。
|
|
155
|
+
|
|
156
|
+
### 首次发布
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# 1. 登录 npm(首次需要,会打开浏览器验证)
|
|
160
|
+
npm login --registry=https://registry.npmjs.org
|
|
161
|
+
|
|
162
|
+
# 2. 确认登录成功
|
|
163
|
+
npm whoami --registry=https://registry.npmjs.org
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 日常发版
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# 1. 更新版本号(自动同步到生成项目的版本标记)
|
|
170
|
+
npm version patch # 或 minor / major
|
|
171
|
+
|
|
172
|
+
# 2. 更新 MIGRATION.md(如有变更需要已有项目跟进)
|
|
173
|
+
|
|
174
|
+
# 3. 发布到 npm(prepublishOnly 自动构建)
|
|
175
|
+
pnpm publish
|
|
176
|
+
|
|
177
|
+
# 4. 推送 tag
|
|
178
|
+
git push --follow-tags
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
发布后用户即可通过 `pnpm create art-app-pino` 使用最新版本。
|
|
182
|
+
## 项目结构
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
create-art-app-pino/
|
|
186
|
+
├── src/ # CLI 源码
|
|
187
|
+
│ ├── index.ts # 入口
|
|
188
|
+
│ ├── prompts.ts # 交互式问答 + 选项定义
|
|
189
|
+
│ ├── generator.ts # 生成编排(模板叠加 + EJS)
|
|
190
|
+
│ ├── postActions.ts # 后置操作(git init + .reference)
|
|
191
|
+
│ ├── featureDeps.ts # 功能模块依赖声明
|
|
192
|
+
│ └── utils/
|
|
193
|
+
│ ├── renderTemplate.ts # 模板渲染引擎
|
|
194
|
+
│ ├── deepMerge.ts # package.json 深度合并
|
|
195
|
+
│ └── banner.ts # CLI 横幅
|
|
196
|
+
├── template/ # 模板层
|
|
197
|
+
│ ├── base/ # 基础模板(所有项目共享)
|
|
198
|
+
│ ├── auth-art/ # Art 内置登录叠加层
|
|
199
|
+
│ ├── auth-zhihuishu/ # 智慧树 CAS 叠加层
|
|
200
|
+
│ ├── scaffold-doc-governance/ # 文档治理叠加层
|
|
201
|
+
│ ├── feature-markdown/ # Markdown 功能模板
|
|
202
|
+
│ ├── feature-sse/ # SSE 功能模板
|
|
203
|
+
│ └── feature-echarts/ # ECharts 功能模板
|
|
204
|
+
├── package.json
|
|
205
|
+
├── tsconfig.json
|
|
206
|
+
├── tsup.config.ts
|
|
207
|
+
├── MIGRATION.md # 版本迁移指南
|
|
208
|
+
└── README.md
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var import_node_fs4 = __toESM(require("fs"), 1);
|
|
28
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
29
|
+
var import_minimist = __toESM(require("minimist"), 1);
|
|
30
|
+
|
|
31
|
+
// src/utils/banner.ts
|
|
32
|
+
var import_kolorist = require("kolorist");
|
|
33
|
+
function showBanner() {
|
|
34
|
+
console.log();
|
|
35
|
+
console.log((0, import_kolorist.bold)((0, import_kolorist.cyan)(" create-art-app-pino")));
|
|
36
|
+
console.log();
|
|
37
|
+
console.log(` ${(0, import_kolorist.green)("\u2714")} Art Design Pro based project scaffold`);
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
40
|
+
function logError(message) {
|
|
41
|
+
console.error((0, import_kolorist.red)(` \u2716 ${message}`));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/prompts.ts
|
|
45
|
+
var import_prompts = __toESM(require("prompts"), 1);
|
|
46
|
+
async function getProjectOptions(argv) {
|
|
47
|
+
const defaultMode = argv.default === true;
|
|
48
|
+
const argProjectName = argv._[0];
|
|
49
|
+
let result;
|
|
50
|
+
try {
|
|
51
|
+
result = await (0, import_prompts.default)(
|
|
52
|
+
[
|
|
53
|
+
{
|
|
54
|
+
type: argProjectName ? null : "text",
|
|
55
|
+
name: "projectName",
|
|
56
|
+
message: "\u9879\u76EE\u540D\u79F0:",
|
|
57
|
+
initial: "my-project",
|
|
58
|
+
validate: (val) => /^[a-z0-9-]+$/.test(val) || "\u9879\u76EE\u540D\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u8FDE\u5B57\u7B26"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: defaultMode || argv.auth ? null : "select",
|
|
62
|
+
name: "auth",
|
|
63
|
+
message: "\u8BA4\u8BC1\u65B9\u5F0F:",
|
|
64
|
+
choices: [
|
|
65
|
+
{ title: "Art \u5185\u7F6E\u767B\u5F55\u9875\uFF08\u7528\u6237\u540D/\u5BC6\u7801 + \u524D\u7AEF token \u7BA1\u7406\uFF09", value: "art" },
|
|
66
|
+
{ title: "\u667A\u6167\u6811 CAS \u767B\u5F55\uFF08\u4F01\u4E1A\u7EDF\u4E00\u8BA4\u8BC1 + \u5F00\u53D1\u6001 env token\uFF09", value: "zhihuishu" }
|
|
67
|
+
],
|
|
68
|
+
initial: 0
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: defaultMode || argv.history || argv.hash ? null : "select",
|
|
72
|
+
name: "routerMode",
|
|
73
|
+
message: "\u8DEF\u7531\u6A21\u5F0F:",
|
|
74
|
+
choices: [
|
|
75
|
+
{ title: "History\uFF08\u63A8\u8350\uFF0C\u9700\u670D\u52A1\u7AEF\u914D\u5408\uFF09", value: "history" },
|
|
76
|
+
{ title: "Hash", value: "hash" }
|
|
77
|
+
],
|
|
78
|
+
initial: 0
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: defaultMode ? null : "multiselect",
|
|
82
|
+
name: "features",
|
|
83
|
+
message: "\u542F\u7528\u529F\u80FD\u6A21\u5757\uFF08\u7A7A\u683C\u5207\u6362\uFF0C\u56DE\u8F66\u786E\u8BA4\uFF09:",
|
|
84
|
+
choices: [
|
|
85
|
+
{ title: "Markdown \u6E32\u67D3\uFF08md-editor-v3\uFF09", value: "markdown", selected: true },
|
|
86
|
+
{ title: "SSE \u6D41\u5F0F\u8BF7\u6C42\uFF08@microsoft/fetch-event-source\uFF09", value: "sse", selected: true },
|
|
87
|
+
{ title: "ECharts \u56FE\u8868", value: "echarts", selected: true },
|
|
88
|
+
{ title: "vue-draggable-plus \u62D6\u62FD", value: "draggable", selected: true },
|
|
89
|
+
{ title: "dayjs \u65E5\u671F\u5DE5\u5177", value: "dayjs", selected: true }
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
type: defaultMode ? null : "multiselect",
|
|
94
|
+
name: "scaffold",
|
|
95
|
+
message: "\u5DE5\u7A0B\u5316\u914D\u7F6E\uFF08\u7A7A\u683C\u5207\u6362\uFF0C\u56DE\u8F66\u786E\u8BA4\uFF09:",
|
|
96
|
+
choices: [
|
|
97
|
+
{ title: ".reference \u53C2\u8003\u9879\u76EE\uFF08\u514B\u9686 art-design-pro \u6700\u65B0\u4EE3\u7801\uFF09", value: "reference", selected: true },
|
|
98
|
+
{ title: ".vscode \u7EDF\u4E00\u7F16\u8F91\u5668\u914D\u7F6E", value: "vscode", selected: true },
|
|
99
|
+
{ title: "AGENTS.md AI \u5F00\u53D1\u7EA6\u675F\u6587\u4EF6", value: "agentsMd", selected: true },
|
|
100
|
+
{ title: "\u6587\u6863\u6CBB\u7406\uFF08docs/ + 4 \u9053\u62A4\u680F + PR \u6A21\u677F\uFF09", value: "docGovernance", selected: true }
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
type: defaultMode ? null : "select",
|
|
105
|
+
name: "packageManager",
|
|
106
|
+
message: "\u5305\u7BA1\u7406\u5668:",
|
|
107
|
+
choices: [
|
|
108
|
+
{ title: "pnpm\uFF08\u63A8\u8350\uFF09", value: "pnpm" },
|
|
109
|
+
{ title: "npm", value: "npm" }
|
|
110
|
+
],
|
|
111
|
+
initial: 0
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
{
|
|
115
|
+
onCancel: () => {
|
|
116
|
+
throw new Error("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const projectName = argProjectName || result.projectName || "my-project";
|
|
124
|
+
const auth = argv.auth === "zhs" ? "zhihuishu" : argv.auth || result.auth || "art";
|
|
125
|
+
const routerMode = argv.hash ? "hash" : argv.history ? "history" : result.routerMode || "history";
|
|
126
|
+
const features = defaultMode ? ["markdown", "sse", "echarts", "draggable", "dayjs"] : result.features || ["markdown", "sse", "echarts", "draggable", "dayjs"];
|
|
127
|
+
const scaffoldChoices = defaultMode ? ["reference", "vscode", "agentsMd", "docGovernance"] : result.scaffold || ["reference", "vscode", "agentsMd", "docGovernance"];
|
|
128
|
+
const scaffold = {
|
|
129
|
+
reference: argv.reference === false ? false : scaffoldChoices.includes("reference"),
|
|
130
|
+
vscode: argv.vscode === false ? false : scaffoldChoices.includes("vscode"),
|
|
131
|
+
agentsMd: argv.agents === false ? false : scaffoldChoices.includes("agentsMd"),
|
|
132
|
+
docGovernance: argv["doc-governance"] === false ? false : scaffoldChoices.includes("docGovernance")
|
|
133
|
+
};
|
|
134
|
+
const packageManager = defaultMode ? "pnpm" : result.packageManager || "pnpm";
|
|
135
|
+
return {
|
|
136
|
+
projectName,
|
|
137
|
+
auth,
|
|
138
|
+
routerMode,
|
|
139
|
+
features,
|
|
140
|
+
scaffold,
|
|
141
|
+
packageManager
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/generator.ts
|
|
146
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
147
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
148
|
+
|
|
149
|
+
// src/featureDeps.ts
|
|
150
|
+
var FEATURE_DEPS = {
|
|
151
|
+
draggable: { deps: { "vue-draggable-plus": "^0.5.6" } },
|
|
152
|
+
dayjs: { deps: { dayjs: "^1.11.13" } }
|
|
153
|
+
};
|
|
154
|
+
var TEMPLATE_FEATURES = ["markdown", "sse", "echarts"];
|
|
155
|
+
function hasTemplateDir(feature) {
|
|
156
|
+
return TEMPLATE_FEATURES.includes(feature);
|
|
157
|
+
}
|
|
158
|
+
function getFeatureDeps(features) {
|
|
159
|
+
const result = { deps: {}, devDeps: {} };
|
|
160
|
+
for (const feature of features) {
|
|
161
|
+
const config = FEATURE_DEPS[feature];
|
|
162
|
+
if (config) {
|
|
163
|
+
Object.assign(result.deps, config.deps || {});
|
|
164
|
+
Object.assign(result.devDeps, config.devDeps || {});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// src/utils/renderTemplate.ts
|
|
171
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
172
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
173
|
+
var import_ejs = __toESM(require("ejs"), 1);
|
|
174
|
+
async function renderTemplate(templateDir, targetDir, options, skipFiles = []) {
|
|
175
|
+
const stats = import_node_fs.default.statSync(templateDir);
|
|
176
|
+
if (!stats.isDirectory()) return;
|
|
177
|
+
const files = import_node_fs.default.readdirSync(templateDir);
|
|
178
|
+
for (const file of files) {
|
|
179
|
+
if (skipFiles.includes(file)) continue;
|
|
180
|
+
const srcPath = import_node_path.default.join(templateDir, file);
|
|
181
|
+
const srcStat = import_node_fs.default.statSync(srcPath);
|
|
182
|
+
if (srcStat.isDirectory()) {
|
|
183
|
+
const destName = file.startsWith("_") ? `.${file.slice(1)}` : file;
|
|
184
|
+
const destDir = import_node_path.default.join(targetDir, destName);
|
|
185
|
+
import_node_fs.default.mkdirSync(destDir, { recursive: true });
|
|
186
|
+
await renderTemplate(srcPath, destDir, options);
|
|
187
|
+
} else {
|
|
188
|
+
await renderFile(srcPath, targetDir, file, options);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async function renderFile(srcPath, targetDir, fileName, options) {
|
|
193
|
+
let destName = fileName;
|
|
194
|
+
let content;
|
|
195
|
+
if (fileName.endsWith(".ejs")) {
|
|
196
|
+
destName = fileName.slice(0, -4);
|
|
197
|
+
const template = import_node_fs.default.readFileSync(srcPath, "utf-8");
|
|
198
|
+
content = import_ejs.default.render(template, { options });
|
|
199
|
+
if (!content.trim()) return;
|
|
200
|
+
} else {
|
|
201
|
+
content = import_node_fs.default.readFileSync(srcPath, "utf-8");
|
|
202
|
+
}
|
|
203
|
+
if (destName.startsWith("_")) {
|
|
204
|
+
destName = `.${destName.slice(1)}`;
|
|
205
|
+
}
|
|
206
|
+
const destPath = import_node_path.default.join(targetDir, destName);
|
|
207
|
+
import_node_fs.default.mkdirSync(import_node_path.default.dirname(destPath), { recursive: true });
|
|
208
|
+
import_node_fs.default.writeFileSync(destPath, content);
|
|
209
|
+
}
|
|
210
|
+
async function renderEjsInPlace(targetDir, options) {
|
|
211
|
+
const files = getAllFiles(targetDir);
|
|
212
|
+
for (const filePath of files) {
|
|
213
|
+
if (filePath.endsWith(".ejs")) {
|
|
214
|
+
const template = import_node_fs.default.readFileSync(filePath, "utf-8");
|
|
215
|
+
const content = import_ejs.default.render(template, { options });
|
|
216
|
+
const destPath = filePath.slice(0, -4);
|
|
217
|
+
if (content.trim()) {
|
|
218
|
+
import_node_fs.default.writeFileSync(destPath, content);
|
|
219
|
+
}
|
|
220
|
+
import_node_fs.default.unlinkSync(filePath);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function getAllFiles(dir) {
|
|
225
|
+
const results = [];
|
|
226
|
+
const entries = import_node_fs.default.readdirSync(dir, { withFileTypes: true });
|
|
227
|
+
for (const entry of entries) {
|
|
228
|
+
const fullPath = import_node_path.default.join(dir, entry.name);
|
|
229
|
+
if (entry.isDirectory()) {
|
|
230
|
+
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
231
|
+
results.push(...getAllFiles(fullPath));
|
|
232
|
+
} else {
|
|
233
|
+
results.push(fullPath);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return results;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// src/utils/deepMerge.ts
|
|
240
|
+
function sortDependencies(pkg) {
|
|
241
|
+
const sorted = { ...pkg };
|
|
242
|
+
const depsFields = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
243
|
+
for (const field of depsFields) {
|
|
244
|
+
if (sorted[field]) {
|
|
245
|
+
sorted[field] = Object.fromEntries(
|
|
246
|
+
Object.entries(sorted[field]).sort(([a], [b]) => a.localeCompare(b))
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return sorted;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/generator.ts
|
|
254
|
+
async function generate(options, targetDir) {
|
|
255
|
+
const templateRoot = import_node_path2.default.resolve(__dirname, "..", "template");
|
|
256
|
+
const baseDir = import_node_path2.default.join(templateRoot, "base");
|
|
257
|
+
if (import_node_fs2.default.existsSync(baseDir)) {
|
|
258
|
+
await renderTemplate(baseDir, targetDir, options);
|
|
259
|
+
}
|
|
260
|
+
const authDir = import_node_path2.default.join(templateRoot, options.auth === "zhihuishu" ? "auth-zhihuishu" : "auth-art");
|
|
261
|
+
if (import_node_fs2.default.existsSync(authDir)) {
|
|
262
|
+
await renderTemplate(authDir, targetDir, options);
|
|
263
|
+
}
|
|
264
|
+
if (options.scaffold.docGovernance) {
|
|
265
|
+
const dgDir = import_node_path2.default.join(templateRoot, "scaffold-doc-governance");
|
|
266
|
+
if (import_node_fs2.default.existsSync(dgDir)) {
|
|
267
|
+
mergeTemplatePackageJson(dgDir, targetDir);
|
|
268
|
+
await renderTemplate(dgDir, targetDir, options, ["package.json"]);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const templateFeatures = options.features.filter((f) => hasTemplateDir(f));
|
|
272
|
+
for (const feature of templateFeatures) {
|
|
273
|
+
const featureDir = import_node_path2.default.join(templateRoot, `feature-${feature}`);
|
|
274
|
+
if (import_node_fs2.default.existsSync(featureDir)) {
|
|
275
|
+
mergeTemplatePackageJson(featureDir, targetDir);
|
|
276
|
+
await renderTemplate(featureDir, targetDir, options, ["package.json"]);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
mergeFeatureDeps(targetDir, options);
|
|
280
|
+
await renderEjsInPlace(targetDir, options);
|
|
281
|
+
removeEmptyDirs(targetDir);
|
|
282
|
+
sortPackageJson(targetDir);
|
|
283
|
+
}
|
|
284
|
+
function mergeFeatureDeps(targetDir, options) {
|
|
285
|
+
const pkgPath = import_node_path2.default.join(targetDir, "package.json");
|
|
286
|
+
if (!import_node_fs2.default.existsSync(pkgPath)) return;
|
|
287
|
+
const pkg = JSON.parse(import_node_fs2.default.readFileSync(pkgPath, "utf-8"));
|
|
288
|
+
const { deps, devDeps } = getFeatureDeps(options.features);
|
|
289
|
+
if (Object.keys(deps).length > 0) {
|
|
290
|
+
pkg.dependencies = { ...pkg.dependencies, ...deps };
|
|
291
|
+
}
|
|
292
|
+
if (Object.keys(devDeps).length > 0) {
|
|
293
|
+
pkg.devDependencies = { ...pkg.devDependencies, ...devDeps };
|
|
294
|
+
}
|
|
295
|
+
const cliPkgPath = import_node_path2.default.resolve(__dirname, "..", "package.json");
|
|
296
|
+
const cliVersion = import_node_fs2.default.existsSync(cliPkgPath) ? JSON.parse(import_node_fs2.default.readFileSync(cliPkgPath, "utf-8")).version : "0.0.0";
|
|
297
|
+
pkg["create-art-app-pino"] = { version: cliVersion };
|
|
298
|
+
import_node_fs2.default.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
299
|
+
}
|
|
300
|
+
function mergeTemplatePackageJson(featureDir, targetDir) {
|
|
301
|
+
const featurePkgPath = import_node_path2.default.join(featureDir, "package.json");
|
|
302
|
+
if (!import_node_fs2.default.existsSync(featurePkgPath)) return;
|
|
303
|
+
const targetPkgPath = import_node_path2.default.join(targetDir, "package.json");
|
|
304
|
+
if (!import_node_fs2.default.existsSync(targetPkgPath)) return;
|
|
305
|
+
const featurePkg = JSON.parse(import_node_fs2.default.readFileSync(featurePkgPath, "utf-8"));
|
|
306
|
+
const targetPkg = JSON.parse(import_node_fs2.default.readFileSync(targetPkgPath, "utf-8"));
|
|
307
|
+
if (featurePkg.dependencies) {
|
|
308
|
+
targetPkg.dependencies = { ...targetPkg.dependencies, ...featurePkg.dependencies };
|
|
309
|
+
}
|
|
310
|
+
if (featurePkg.devDependencies) {
|
|
311
|
+
targetPkg.devDependencies = { ...targetPkg.devDependencies, ...featurePkg.devDependencies };
|
|
312
|
+
}
|
|
313
|
+
import_node_fs2.default.writeFileSync(targetPkgPath, JSON.stringify(targetPkg, null, 2) + "\n");
|
|
314
|
+
}
|
|
315
|
+
function sortPackageJson(targetDir) {
|
|
316
|
+
const pkgPath = import_node_path2.default.join(targetDir, "package.json");
|
|
317
|
+
if (!import_node_fs2.default.existsSync(pkgPath)) return;
|
|
318
|
+
const pkg = JSON.parse(import_node_fs2.default.readFileSync(pkgPath, "utf-8"));
|
|
319
|
+
const sorted = sortDependencies(pkg);
|
|
320
|
+
import_node_fs2.default.writeFileSync(pkgPath, JSON.stringify(sorted, null, 2) + "\n");
|
|
321
|
+
}
|
|
322
|
+
function removeEmptyDirs(dir) {
|
|
323
|
+
const entries = import_node_fs2.default.readdirSync(dir, { withFileTypes: true });
|
|
324
|
+
for (const entry of entries) {
|
|
325
|
+
if (entry.isDirectory()) {
|
|
326
|
+
const fullPath = import_node_path2.default.join(dir, entry.name);
|
|
327
|
+
if (entry.name === ".git") continue;
|
|
328
|
+
removeEmptyDirs(fullPath);
|
|
329
|
+
const remaining = import_node_fs2.default.readdirSync(fullPath);
|
|
330
|
+
if (remaining.length === 0) {
|
|
331
|
+
import_node_fs2.default.rmdirSync(fullPath);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// src/postActions.ts
|
|
338
|
+
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
339
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
340
|
+
var import_node_child_process = require("child_process");
|
|
341
|
+
var import_kolorist2 = require("kolorist");
|
|
342
|
+
async function postGenerate(options, targetDir) {
|
|
343
|
+
if (options.scaffold.reference) {
|
|
344
|
+
await cloneReference(targetDir);
|
|
345
|
+
}
|
|
346
|
+
await initGit(targetDir);
|
|
347
|
+
console.log();
|
|
348
|
+
console.log((0, import_kolorist2.green)(" \u9879\u76EE\u521B\u5EFA\u5B8C\u6210\uFF01"));
|
|
349
|
+
console.log();
|
|
350
|
+
console.log(` ${(0, import_kolorist2.cyan)("cd")} ${options.projectName}`);
|
|
351
|
+
console.log(` ${(0, import_kolorist2.cyan)(`${options.packageManager} install`)}`);
|
|
352
|
+
console.log(` ${(0, import_kolorist2.cyan)(`${options.packageManager === "npm" ? "npm run" : options.packageManager} dev`)}`);
|
|
353
|
+
if (options.scaffold.docGovernance) {
|
|
354
|
+
console.log(` ${(0, import_kolorist2.cyan)(`${options.packageManager === "npm" ? "npm run" : options.packageManager} docs:lint`)} # \u6587\u6863\u6CBB\u7406\u68C0\u67E5`);
|
|
355
|
+
}
|
|
356
|
+
console.log();
|
|
357
|
+
}
|
|
358
|
+
async function cloneReference(targetDir) {
|
|
359
|
+
const refDir = import_node_path3.default.join(targetDir, ".reference", "art-design-pro");
|
|
360
|
+
console.log(` ${(0, import_kolorist2.cyan)("\u23F3")} \u514B\u9686 .reference/art-design-pro ...`);
|
|
361
|
+
try {
|
|
362
|
+
import_node_fs3.default.mkdirSync(import_node_path3.default.join(targetDir, ".reference"), { recursive: true });
|
|
363
|
+
(0, import_node_child_process.execSync)(
|
|
364
|
+
`git clone --depth 1 https://github.com/Daymychen/art-design-pro.git "${refDir}"`,
|
|
365
|
+
{ stdio: "pipe" }
|
|
366
|
+
);
|
|
367
|
+
const gitDir = import_node_path3.default.join(refDir, ".git");
|
|
368
|
+
if (import_node_fs3.default.existsSync(gitDir)) {
|
|
369
|
+
import_node_fs3.default.rmSync(gitDir, { recursive: true });
|
|
370
|
+
}
|
|
371
|
+
console.log(` ${(0, import_kolorist2.green)("\u2714")} .reference/art-design-pro \u514B\u9686\u5B8C\u6210`);
|
|
372
|
+
} catch {
|
|
373
|
+
console.log(` ${(0, import_kolorist2.yellow)("\u26A0")} .reference \u514B\u9686\u5931\u8D25\uFF0C\u53EF\u7A0D\u540E\u624B\u52A8\u6267\u884C\uFF1A`);
|
|
374
|
+
console.log(` git clone --depth 1 https://github.com/Daymychen/art-design-pro.git .reference/art-design-pro`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
async function initGit(targetDir) {
|
|
378
|
+
try {
|
|
379
|
+
(0, import_node_child_process.execSync)("git init", { cwd: targetDir, stdio: "pipe" });
|
|
380
|
+
console.log(` ${(0, import_kolorist2.green)("\u2714")} Git \u4ED3\u5E93\u5DF2\u521D\u59CB\u5316`);
|
|
381
|
+
} catch {
|
|
382
|
+
console.log(` ${(0, import_kolorist2.yellow)("\u26A0")} Git \u521D\u59CB\u5316\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u6267\u884C git init`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// src/index.ts
|
|
387
|
+
async function main() {
|
|
388
|
+
const argv = (0, import_minimist.default)(process.argv.slice(2), {
|
|
389
|
+
boolean: ["default", "history", "hash"],
|
|
390
|
+
string: ["auth"]
|
|
391
|
+
});
|
|
392
|
+
showBanner();
|
|
393
|
+
const options = await getProjectOptions(argv);
|
|
394
|
+
if (!options) {
|
|
395
|
+
logError("\u64CD\u4F5C\u5DF2\u53D6\u6D88");
|
|
396
|
+
process.exit(1);
|
|
397
|
+
}
|
|
398
|
+
const cwd = process.cwd();
|
|
399
|
+
const targetDir = import_node_path4.default.join(cwd, options.projectName);
|
|
400
|
+
if (import_node_fs4.default.existsSync(targetDir)) {
|
|
401
|
+
const entries = import_node_fs4.default.readdirSync(targetDir);
|
|
402
|
+
if (entries.length > 0) {
|
|
403
|
+
logError(`\u76EE\u5F55 ${options.projectName} \u5DF2\u5B58\u5728\u4E14\u4E0D\u4E3A\u7A7A`);
|
|
404
|
+
process.exit(1);
|
|
405
|
+
}
|
|
406
|
+
} else {
|
|
407
|
+
import_node_fs4.default.mkdirSync(targetDir, { recursive: true });
|
|
408
|
+
}
|
|
409
|
+
console.log();
|
|
410
|
+
console.log(` \u6B63\u5728\u521B\u5EFA\u9879\u76EE ${options.projectName} ...`);
|
|
411
|
+
console.log();
|
|
412
|
+
await generate(options, targetDir);
|
|
413
|
+
await postGenerate(options, targetDir);
|
|
414
|
+
}
|
|
415
|
+
main().catch((err) => {
|
|
416
|
+
logError(err.message || "\u672A\u77E5\u9519\u8BEF");
|
|
417
|
+
process.exit(1);
|
|
418
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-art-app-pino",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI scaffold tool for creating Art Design Pro based projects",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-art-app-pino": "dist/index.cjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"template"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"cli",
|
|
15
|
+
"scaffold",
|
|
16
|
+
"vue",
|
|
17
|
+
"art-design-pro",
|
|
18
|
+
"create-app"
|
|
19
|
+
],
|
|
20
|
+
"author": "pino",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"ejs": "^3.1.10",
|
|
24
|
+
"kolorist": "^1.8.0",
|
|
25
|
+
"minimist": "^1.2.8",
|
|
26
|
+
"prompts": "^2.4.2"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/ejs": "^3.1.5",
|
|
30
|
+
"@types/minimist": "^1.2.5",
|
|
31
|
+
"@types/node": "^22.10.0",
|
|
32
|
+
"@types/prompts": "^2.4.9",
|
|
33
|
+
"tsup": "^8.3.5",
|
|
34
|
+
"typescript": "^5.7.2"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"registry": "https://registry.npmjs.org"
|
|
38
|
+
},
|
|
39
|
+
"scripts": {
|
|
40
|
+
"dev": "tsup --watch",
|
|
41
|
+
"build": "tsup",
|
|
42
|
+
"start": "node dist/index.cjs"
|
|
43
|
+
}
|
|
44
|
+
}
|