@mingfuyun/star-allinone 0.2.0 → 0.3.1
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 +17 -10
- package/examples/AGENTS.md +26 -0
- package/examples/projects/starlink-frontend.star-allinone.json +7 -0
- package/examples/projects/starscope-frontend.star-allinone.json +7 -0
- package/examples/skills/custom-domain-invariants/SKILL.md +16 -0
- package/package.json +5 -3
- package/scripts/cli.js +52 -13
- package/scripts/gen/fixtures/run.js +104 -0
- package/scripts/gen/fixtures/widgets.openapi.json +194 -0
- package/scripts/gen/names.js +117 -0
- package/scripts/gen/page.js +483 -0
- package/scripts/gen/project.js +154 -0
- package/scripts/gen/service.js +264 -0
- package/scripts/gen/spec.js +220 -0
- package/scripts/gen/ts.js +121 -0
- package/skills/README.md +45 -188
- package/skills/shared/api-to-service/SKILL.md +18 -10
- package/skills/shared/{api-mock/SKILL.md → api-to-service/references/mock.md} +3 -10
- package/skills/shared/design-to-page/SKILL.md +45 -6
- package/skills/shared/design-to-page/references/list-page-template.md +44 -0
- package/skills/shared/design-to-page/references/page-conventions.md +1 -1
- package/skills/shared/i-have-adhd/{SKILL.md → i-have-adhd.md} +0 -10
- package/skills/shared/project-conventions/references/architecture.md +3 -0
- package/skills/shared/publish-test/SKILL.md +4 -2
- package/skills/shared/review-and-submit/SKILL.md +8 -16
- package/skills/shared/{ai-review/SKILL.md → review-and-submit/references/ai-review.md} +4 -11
- package/skills/shared/{commit-current-changes/SKILL.md → review-and-submit/references/commit.md} +4 -12
- package/skills/shared/{impact-analysis/SKILL.md → review-and-submit/references/impact-analysis.md} +1 -10
- package/skills/shared/{verify/SKILL.md → review-and-submit/references/verify.md} +4 -11
- package/skills/shared/project-conventions/SKILL.md +0 -34
- /package/skills/shared/{api-mock → api-to-service}/references/mock-conventions.md +0 -0
package/README.md
CHANGED
|
@@ -17,9 +17,10 @@ pnpm add @mingfuyun/star-allinone
|
|
|
17
17
|
公共 skill 由本仓库维护,随 `@mingfuyun/star-allinone` 发布。业务项目用 CLI 同步到自己的 `.agents/skills/shared-*` 并提交。Codex / Cursor 直接从业务仓库发现 skill,不写入 `~/.codex/skills`,团队成员也不需要本仓库源码。
|
|
18
18
|
|
|
19
19
|
```text
|
|
20
|
+
AGENTS.md ← 常驻约定,不要加 .cursor/rules
|
|
20
21
|
.agents/skills/
|
|
21
|
-
├── shared-*
|
|
22
|
-
└── custom-*
|
|
22
|
+
├── shared-* ← npm 包同步,不能在业务项目直接改
|
|
23
|
+
└── custom-* ← 业务项目自己维护
|
|
23
24
|
```
|
|
24
25
|
|
|
25
26
|
完整约定见 [skills/README.md](skills/README.md)。
|
|
@@ -32,9 +33,13 @@ pnpm add @mingfuyun/star-allinone
|
|
|
32
33
|
pnpm exec star-allinone skills list
|
|
33
34
|
pnpm exec star-allinone skills sync --dry-run
|
|
34
35
|
pnpm exec star-allinone skills sync
|
|
36
|
+
pnpm exec star-allinone gen service --operation "GET /api/v1/devices/"
|
|
37
|
+
pnpm exec star-allinone gen page --feature Widgets --route /widgets --title 组件管理 --list-operation "GET /api/v1/widgets/"
|
|
35
38
|
```
|
|
36
39
|
|
|
37
|
-
`
|
|
40
|
+
`gen service` 按 OpenAPI/Swagger 写一条 `MFRequest` 方法和对应类型。`gen page` 生成标准列表页骨架,并可先生成相关 Service。
|
|
41
|
+
|
|
42
|
+
`list` 查看包内公共 skill。`sync` 把它们写入当前项目的 `.agents/skills/shared-*`,会整体替换过期的 `shared-*`,但不会改 `custom-*`。仓库根没有 `AGENTS.md` 时,会从 `examples/AGENTS.md` 补一份,已有文件不覆盖。
|
|
38
43
|
|
|
39
44
|
### 维护者:改公共 skill
|
|
40
45
|
|
|
@@ -72,26 +77,28 @@ StarLink 示例见 `examples/projects/`。
|
|
|
72
77
|
pnpm exec star-allinone skills sync
|
|
73
78
|
```
|
|
74
79
|
|
|
75
|
-
4. 把真正的业务特例放到 `.agents/skills/custom
|
|
80
|
+
4. 把真正的业务特例放到 `.agents/skills/custom-*`。审查、提交、发布、单接口、页面生成不要做成 `custom-*`。全量契约重建(若需要)必须 `disable-model-invocation`,并在 `AGENTS.md` 写清命令。
|
|
81
|
+
|
|
82
|
+
5. 仓库根放 `AGENTS.md`(可从包内 `examples/AGENTS.md` 复制)。`skills sync` 只在该文件缺失时补一份,不会覆盖已有内容。常驻约定只写这一份,不要加 `.cursor/rules`。
|
|
76
83
|
|
|
77
|
-
|
|
84
|
+
6. 提交配置和 skill:
|
|
78
85
|
|
|
79
86
|
```bash
|
|
80
|
-
git add .star-allinone.json .agents/skills
|
|
87
|
+
git add .star-allinone.json AGENTS.md .agents/skills
|
|
81
88
|
git commit -m "chore(skill): 接入公共 skill"
|
|
82
89
|
```
|
|
83
90
|
|
|
84
91
|
### 业务项目:日常调用
|
|
85
92
|
|
|
86
|
-
|
|
93
|
+
只使用下面这些**用户入口**。
|
|
87
94
|
|
|
88
95
|
```text
|
|
89
96
|
使用 $shared-api-to-service,为 GET /api/v1/devices/ 生成类型、Service 和 JSON Mock。
|
|
90
97
|
```
|
|
91
98
|
|
|
92
99
|
```text
|
|
93
|
-
使用 $shared-design-to-page
|
|
94
|
-
|
|
100
|
+
使用 $shared-design-to-page,生成 /widgets 页面。
|
|
101
|
+
标准列表接口 GET /api/v1/widgets/。
|
|
95
102
|
```
|
|
96
103
|
|
|
97
104
|
```text
|
|
@@ -103,7 +110,7 @@ git commit -m "chore(skill): 接入公共 skill"
|
|
|
103
110
|
使用 $shared-publish-test,把当前分支发布到测试环境。
|
|
104
111
|
```
|
|
105
112
|
|
|
106
|
-
公共流程用 `shared-*`,项目专属规则用 `custom
|
|
113
|
+
公共流程用 `shared-*`,项目专属规则用 `custom-*`。`custom-*` 不能再实现一遍 Service/页面生成/审查。全量契约重建若需要,写成不可调用的脚本,并在 `AGENTS.md` 写命令。业务定制需要复用公共流程时,读取对应的 `.agents/skills/shared-*/SKILL.md`,不要再抛一个入口。
|
|
107
114
|
|
|
108
115
|
### 业务项目:更新公共 skill
|
|
109
116
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Agent instructions
|
|
2
|
+
|
|
3
|
+
This is a Umi Max + Ant Design 5 PC admin app. Shared skills live in `.agents/skills/shared-*` and are synced from `@mingfuyun/star-allinone`. Do not edit `shared-*`. Put project-only rules in `.agents/skills/custom-*` or `.agents/project/`.
|
|
4
|
+
|
|
5
|
+
Always-on instructions are this file. Do not add `.cursor/rules`.
|
|
6
|
+
|
|
7
|
+
## Default workflow
|
|
8
|
+
|
|
9
|
+
User-facing shared entries only:
|
|
10
|
+
|
|
11
|
+
- One endpoint: `pnpm exec star-allinone gen service --operation "METHOD /path/"` or `$shared-api-to-service`.
|
|
12
|
+
- Pages: `$shared-design-to-page`. Standard lists run `pnpm exec star-allinone gen page` inside that skill.
|
|
13
|
+
- Review and commit: `$shared-review-and-submit`. Wait for confirmation.
|
|
14
|
+
- Test publish: `$shared-publish-test` after explicit pipeline confirmation.
|
|
15
|
+
|
|
16
|
+
## Hard rules
|
|
17
|
+
|
|
18
|
+
- For non-trivial changes, read `.agents/skills/shared-project-conventions/references/architecture.md`.
|
|
19
|
+
- Pages use `import Service from '@/services'`. Do not call axios or `src/services/request.tsx` from pages.
|
|
20
|
+
- Lists: `MFProTable`. Forms: `ProForm`. Overlays: `CustomDrawer`, `BaseModal`, `HocModal` from `@mingfuyun/star-allinone`.
|
|
21
|
+
- Keep columns and actions in `const.tsx`. Empty cells render as `-`.
|
|
22
|
+
- Keep DTOs in the domain `typings.d.ts` namespace. Preserve backend snake_case.
|
|
23
|
+
- Do not edit `src/services/request.tsx` for a single endpoint.
|
|
24
|
+
- Every `await` uses try/catch. Do not use `Modal.confirm`.
|
|
25
|
+
- After TypeScript changes run `pnpm typecheck`.
|
|
26
|
+
- If `.agents/project/conventions.md` or `.agents/project/review-rules.md` exists, apply them as additions only.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: custom-domain-invariants
|
|
3
|
+
description: Internal. Project domain extras for review. Do not invoke. Not a generate, page, or review entry.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Domain invariants
|
|
8
|
+
|
|
9
|
+
Not a user-facing entry. Pages, services, and review still go through `$shared-design-to-page`, `$shared-api-to-service`, and `$shared-review-and-submit`.
|
|
10
|
+
|
|
11
|
+
Read this file only as extra checks after those shared skills. Do not generate pages, services, or mocks here.
|
|
12
|
+
|
|
13
|
+
Example extras (replace with the project's real invariants):
|
|
14
|
+
|
|
15
|
+
- IPv4 and IPv6 branches must both be checked.
|
|
16
|
+
- Do not invent query param aliases that are missing from swagger.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mingfuyun/star-allinone",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "星系运维前端能力包",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -30,7 +30,9 @@
|
|
|
30
30
|
"dist",
|
|
31
31
|
"README.md",
|
|
32
32
|
"scripts/cli.js",
|
|
33
|
-
"
|
|
33
|
+
"scripts/gen",
|
|
34
|
+
"skills",
|
|
35
|
+
"examples"
|
|
34
36
|
],
|
|
35
37
|
"scripts": {
|
|
36
38
|
"build": "webpack --env format=umd --mode=none && webpack --env format=esm --mode=none",
|
|
@@ -39,7 +41,7 @@
|
|
|
39
41
|
"skills:sync": "node scripts/cli.js skills sync",
|
|
40
42
|
"skills:list": "node scripts/cli.js skills list",
|
|
41
43
|
"prepublishOnly": "npm run build",
|
|
42
|
-
"test": "
|
|
44
|
+
"test": "node scripts/gen/fixtures/run.js",
|
|
43
45
|
"dev": "webpack --mode=none --watch",
|
|
44
46
|
"clean": "rm -rf dist"
|
|
45
47
|
},
|
package/scripts/cli.js
CHANGED
|
@@ -17,11 +17,17 @@ function usage() {
|
|
|
17
17
|
console.log(`Usage:
|
|
18
18
|
star-allinone skills list
|
|
19
19
|
star-allinone skills sync [--target <dir>] [--dry-run]
|
|
20
|
+
star-allinone gen service --operation "GET /api/v1/devices/" [--spec <file>] [--domain Devices] [--mock-file] [--dry-run]
|
|
21
|
+
star-allinone gen page --feature Widgets --route /widgets --title 组件管理 --list-operation "GET /api/v1/widgets/" [--create-operation ...] [--update-operation ...] [--delete-operation ...] [--dry-run]
|
|
20
22
|
|
|
21
|
-
Run
|
|
23
|
+
Run from a business project containing .star-allinone.json.
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
It never writes ~/.codex/skills and never modifies custom-* skills
|
|
25
|
+
skills sync writes package skills/shared/* to <project>/.agents/skills/shared-*.
|
|
26
|
+
It never writes ~/.codex/skills and never modifies custom-* skills.
|
|
27
|
+
If <project>/AGENTS.md is missing, it copies examples/AGENTS.md once.
|
|
28
|
+
|
|
29
|
+
gen service writes one MFRequest method and types from OpenAPI/Swagger.
|
|
30
|
+
gen page scaffolds a list + drawer + confirm page and can generate services first.`);
|
|
25
31
|
process.exitCode = 1;
|
|
26
32
|
}
|
|
27
33
|
|
|
@@ -33,8 +39,12 @@ function listSharedSkillNames() {
|
|
|
33
39
|
.sort();
|
|
34
40
|
}
|
|
35
41
|
|
|
42
|
+
function hasSkillMarkdown(name) {
|
|
43
|
+
return fs.existsSync(path.join(skillsRoot, name, 'SKILL.md'));
|
|
44
|
+
}
|
|
45
|
+
|
|
36
46
|
function listSkills() {
|
|
37
|
-
const skills = listSharedSkillNames();
|
|
47
|
+
const skills = listSharedSkillNames().filter(hasSkillMarkdown);
|
|
38
48
|
if (!skills.length) {
|
|
39
49
|
console.log('No shared skills found.');
|
|
40
50
|
return;
|
|
@@ -50,8 +60,12 @@ function parseArgs(args) {
|
|
|
50
60
|
for (let index = 0; index < args.length; index += 1) {
|
|
51
61
|
const arg = args[index];
|
|
52
62
|
if (arg === '--dry-run') options.dryRun = true;
|
|
53
|
-
else if (arg === '--
|
|
54
|
-
else
|
|
63
|
+
else if (arg === '--mock-file') options.mockFile = true;
|
|
64
|
+
else if (arg === '--force') options.force = true;
|
|
65
|
+
else if (arg.startsWith('--')) {
|
|
66
|
+
const key = arg.slice(2).replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
|
|
67
|
+
options[key] = args[++index];
|
|
68
|
+
} else positional.push(arg);
|
|
55
69
|
}
|
|
56
70
|
return { options, positional };
|
|
57
71
|
}
|
|
@@ -132,12 +146,14 @@ function pruneStaleShared(destination, prefix, syncedNames, options) {
|
|
|
132
146
|
|
|
133
147
|
function selectedSharedSkills(config) {
|
|
134
148
|
const available = listSharedSkillNames();
|
|
149
|
+
const support = available.filter((name) => !hasSkillMarkdown(name));
|
|
135
150
|
if (!config.sharedSkills) return available;
|
|
136
151
|
const missing = config.sharedSkills.filter((name) => !available.includes(name));
|
|
137
152
|
if (missing.length) {
|
|
138
153
|
throw new Error(`Unknown sharedSkills: ${missing.join(', ')}`);
|
|
139
154
|
}
|
|
140
|
-
|
|
155
|
+
const selected = available.filter((name) => config.sharedSkills.includes(name));
|
|
156
|
+
return [...new Set([...support, ...selected])];
|
|
141
157
|
}
|
|
142
158
|
|
|
143
159
|
function syncProject(options) {
|
|
@@ -158,17 +174,40 @@ function syncProject(options) {
|
|
|
158
174
|
copySkill(path.join(skillsRoot, skillName), destination, skillName, prefix, variables, options);
|
|
159
175
|
}
|
|
160
176
|
pruneStaleShared(destination, prefix, syncedNames, options);
|
|
177
|
+
seedAgentsMarkdown(target, options);
|
|
161
178
|
console.log(`${options.dryRun ? 'Would sync' : 'Synced'} shared skills -> ${destination}`);
|
|
162
179
|
}
|
|
163
180
|
|
|
181
|
+
function seedAgentsMarkdown(target, options) {
|
|
182
|
+
const dest = path.join(target, 'AGENTS.md');
|
|
183
|
+
const source = path.join(root, 'examples', 'AGENTS.md');
|
|
184
|
+
if (fs.existsSync(dest) || !fs.existsSync(source)) return;
|
|
185
|
+
console.log(`${options.dryRun ? '[dry-run] ' : ''}AGENTS.md`);
|
|
186
|
+
if (!options.dryRun) fs.copyFileSync(source, dest);
|
|
187
|
+
}
|
|
188
|
+
|
|
164
189
|
function main() {
|
|
165
190
|
const [group, command, ...rest] = process.argv.slice(2);
|
|
166
|
-
if (group
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
191
|
+
if (group === 'skills') {
|
|
192
|
+
if (command === 'list') return listSkills();
|
|
193
|
+
if (command !== 'sync') return usage();
|
|
194
|
+
const { options, positional } = parseArgs(rest);
|
|
195
|
+
if (positional.length) return usage();
|
|
196
|
+
return syncProject(options);
|
|
197
|
+
}
|
|
198
|
+
if (group === 'gen') {
|
|
199
|
+
const { options, positional } = parseArgs(rest);
|
|
200
|
+
if (positional.length) return usage();
|
|
201
|
+
if (command === 'service') {
|
|
202
|
+
if (!options.operation) return usage();
|
|
203
|
+
return require('./gen/service').generateService(process.cwd(), options);
|
|
204
|
+
}
|
|
205
|
+
if (command === 'page') {
|
|
206
|
+
if (!options.feature) return usage();
|
|
207
|
+
return require('./gen/page').generatePage(process.cwd(), options);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return usage();
|
|
172
211
|
}
|
|
173
212
|
|
|
174
213
|
try {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const { generateService } = require('../service');
|
|
5
|
+
const { generatePage } = require('../page');
|
|
6
|
+
|
|
7
|
+
function assert(condition, message) {
|
|
8
|
+
if (!condition) throw new Error(message);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function makeProject() {
|
|
12
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'star-allinone-gen-'));
|
|
13
|
+
fs.writeFileSync(
|
|
14
|
+
path.join(root, '.star-allinone.json'),
|
|
15
|
+
JSON.stringify(
|
|
16
|
+
{
|
|
17
|
+
project: 'fixture',
|
|
18
|
+
serviceDir: 'src/services',
|
|
19
|
+
openapi: 'openapi.json',
|
|
20
|
+
},
|
|
21
|
+
null,
|
|
22
|
+
2,
|
|
23
|
+
),
|
|
24
|
+
);
|
|
25
|
+
fs.copyFileSync(
|
|
26
|
+
path.join(__dirname, 'widgets.openapi.json'),
|
|
27
|
+
path.join(root, 'openapi.json'),
|
|
28
|
+
);
|
|
29
|
+
fs.mkdirSync(path.join(root, 'src/services'), { recursive: true });
|
|
30
|
+
fs.writeFileSync(
|
|
31
|
+
path.join(root, 'src/services/request.tsx'),
|
|
32
|
+
'const MFRequest = { get() {}, post() {}, patch() {}, delete() {} };\nexport default MFRequest;\n',
|
|
33
|
+
);
|
|
34
|
+
fs.writeFileSync(
|
|
35
|
+
path.join(root, 'src/services/index.ts'),
|
|
36
|
+
'export default {};\n',
|
|
37
|
+
);
|
|
38
|
+
fs.mkdirSync(path.join(root, 'config'), { recursive: true });
|
|
39
|
+
fs.writeFileSync(
|
|
40
|
+
path.join(root, 'config/route.ts'),
|
|
41
|
+
`export default [
|
|
42
|
+
{ path: '/', redirect: '/home' },
|
|
43
|
+
{ path: '/*', component: '@/pages/404', name: '404' },
|
|
44
|
+
];
|
|
45
|
+
`,
|
|
46
|
+
);
|
|
47
|
+
fs.mkdirSync(path.join(root, 'src/components/CommonTable'), { recursive: true });
|
|
48
|
+
fs.mkdirSync(path.join(root, 'src/pages'), { recursive: true });
|
|
49
|
+
return root;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function main() {
|
|
53
|
+
const root = makeProject();
|
|
54
|
+
const first = generateService(root, {
|
|
55
|
+
operation: 'GET /api/v1/widgets/',
|
|
56
|
+
mockFile: true,
|
|
57
|
+
});
|
|
58
|
+
assert(first.fn === 'widgetsList', `fn ${first.fn}`);
|
|
59
|
+
assert(first.domain === 'Widgets', `domain ${first.domain}`);
|
|
60
|
+
const service = fs.readFileSync(first.servicePath, 'utf8');
|
|
61
|
+
assert(service.includes("MFRequest.get<WIDGETS_API.WidgetList>('/api/v1/widgets/', params)"), service);
|
|
62
|
+
const typings = fs.readFileSync(first.typingsPath, 'utf8');
|
|
63
|
+
assert(typings.includes('type Widget ='), typings);
|
|
64
|
+
assert(typings.includes('type WidgetList ='), typings);
|
|
65
|
+
assert(typings.includes('results?: Widget[]'), typings);
|
|
66
|
+
assert(typings.includes('status?: string | null'), typings);
|
|
67
|
+
assert(typings.includes('type WidgetsListQuery'), typings);
|
|
68
|
+
const mockFile = path.join(root, 'mock/api/v1/widgets/get.json');
|
|
69
|
+
assert(fs.existsSync(mockFile), 'missing mock file');
|
|
70
|
+
const index = fs.readFileSync(path.join(root, 'src/services/index.ts'), 'utf8');
|
|
71
|
+
assert(index.includes("from './Widgets/widgets'"), index);
|
|
72
|
+
|
|
73
|
+
const reused = generateService(root, { operation: 'GET /api/v1/widgets/' });
|
|
74
|
+
assert(reused.status === 'reuse', 'expected reuse on second run');
|
|
75
|
+
|
|
76
|
+
generateService(root, { operation: 'PATCH /api/v1/widgets/{id}/' });
|
|
77
|
+
const patched = fs.readFileSync(first.servicePath, 'utf8');
|
|
78
|
+
assert(patched.includes('widgetsPartialUpdate'), patched);
|
|
79
|
+
assert(patched.includes('MFRequest.patch<WIDGETS_API.Widget>'), patched);
|
|
80
|
+
|
|
81
|
+
generatePage(root, {
|
|
82
|
+
feature: 'Widgets',
|
|
83
|
+
route: '/widgets',
|
|
84
|
+
title: '组件管理',
|
|
85
|
+
listOperation: 'GET /api/v1/widgets/',
|
|
86
|
+
createOperation: 'POST /api/v1/widgets/',
|
|
87
|
+
updateOperation: 'PATCH /api/v1/widgets/{id}/',
|
|
88
|
+
deleteOperation: 'DELETE /api/v1/widgets/{id}/',
|
|
89
|
+
});
|
|
90
|
+
const page = fs.readFileSync(path.join(root, 'src/pages/Widgets/index.tsx'), 'utf8');
|
|
91
|
+
assert(page.includes('Service.widgetsList'), page);
|
|
92
|
+
assert(page.includes("rowKey=\"id\""), page);
|
|
93
|
+
const route = fs.readFileSync(path.join(root, 'config/route.ts'), 'utf8');
|
|
94
|
+
assert(route.includes("path: '/widgets'"), route);
|
|
95
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
96
|
+
console.log('codegen fixtures passed');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
main();
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error(error.stack || error.message);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
{
|
|
2
|
+
"openapi": "3.0.3",
|
|
3
|
+
"info": {
|
|
4
|
+
"title": "codegen fixture",
|
|
5
|
+
"version": "1.0.0"
|
|
6
|
+
},
|
|
7
|
+
"paths": {
|
|
8
|
+
"/api/v1/widgets/": {
|
|
9
|
+
"get": {
|
|
10
|
+
"operationId": "widgets_list",
|
|
11
|
+
"tags": ["Widgets"],
|
|
12
|
+
"summary": "获取组件列表",
|
|
13
|
+
"parameters": [
|
|
14
|
+
{
|
|
15
|
+
"in": "query",
|
|
16
|
+
"name": "page",
|
|
17
|
+
"required": true,
|
|
18
|
+
"schema": { "type": "integer" }
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"in": "query",
|
|
22
|
+
"name": "page_size",
|
|
23
|
+
"required": true,
|
|
24
|
+
"schema": { "type": "integer" }
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"in": "query",
|
|
28
|
+
"name": "keyword",
|
|
29
|
+
"schema": { "type": "string" }
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"responses": {
|
|
33
|
+
"200": {
|
|
34
|
+
"description": "ok",
|
|
35
|
+
"content": {
|
|
36
|
+
"application/json": {
|
|
37
|
+
"schema": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"properties": {
|
|
40
|
+
"code": { "type": "integer" },
|
|
41
|
+
"message": { "type": "string" },
|
|
42
|
+
"data": {
|
|
43
|
+
"$ref": "#/components/schemas/WidgetList"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"post": {
|
|
53
|
+
"operationId": "widgets_create",
|
|
54
|
+
"tags": ["Widgets"],
|
|
55
|
+
"summary": "创建组件",
|
|
56
|
+
"requestBody": {
|
|
57
|
+
"content": {
|
|
58
|
+
"application/json": {
|
|
59
|
+
"schema": {
|
|
60
|
+
"$ref": "#/components/schemas/WidgetBody"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"responses": {
|
|
66
|
+
"201": {
|
|
67
|
+
"description": "created",
|
|
68
|
+
"content": {
|
|
69
|
+
"application/json": {
|
|
70
|
+
"schema": {
|
|
71
|
+
"type": "object",
|
|
72
|
+
"properties": {
|
|
73
|
+
"code": { "type": "integer" },
|
|
74
|
+
"message": { "type": "string" },
|
|
75
|
+
"data": {
|
|
76
|
+
"$ref": "#/components/schemas/Widget"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"/api/v1/widgets/{id}/": {
|
|
87
|
+
"patch": {
|
|
88
|
+
"operationId": "widgets_partial_update",
|
|
89
|
+
"tags": ["Widgets"],
|
|
90
|
+
"summary": "更新组件",
|
|
91
|
+
"parameters": [
|
|
92
|
+
{
|
|
93
|
+
"in": "path",
|
|
94
|
+
"name": "id",
|
|
95
|
+
"required": true,
|
|
96
|
+
"schema": { "type": "string" }
|
|
97
|
+
}
|
|
98
|
+
],
|
|
99
|
+
"requestBody": {
|
|
100
|
+
"content": {
|
|
101
|
+
"application/json": {
|
|
102
|
+
"schema": {
|
|
103
|
+
"$ref": "#/components/schemas/WidgetBody"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"responses": {
|
|
109
|
+
"200": {
|
|
110
|
+
"description": "ok",
|
|
111
|
+
"content": {
|
|
112
|
+
"application/json": {
|
|
113
|
+
"schema": {
|
|
114
|
+
"type": "object",
|
|
115
|
+
"properties": {
|
|
116
|
+
"code": { "type": "integer" },
|
|
117
|
+
"message": { "type": "string" },
|
|
118
|
+
"data": {
|
|
119
|
+
"$ref": "#/components/schemas/Widget"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
"delete": {
|
|
129
|
+
"operationId": "widgets_destroy",
|
|
130
|
+
"tags": ["Widgets"],
|
|
131
|
+
"summary": "删除组件",
|
|
132
|
+
"parameters": [
|
|
133
|
+
{
|
|
134
|
+
"in": "path",
|
|
135
|
+
"name": "id",
|
|
136
|
+
"required": true,
|
|
137
|
+
"schema": { "type": "string" }
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
"responses": {
|
|
141
|
+
"200": {
|
|
142
|
+
"description": "ok",
|
|
143
|
+
"content": {
|
|
144
|
+
"application/json": {
|
|
145
|
+
"schema": {
|
|
146
|
+
"type": "object",
|
|
147
|
+
"properties": {
|
|
148
|
+
"code": { "type": "integer" },
|
|
149
|
+
"message": { "type": "string" },
|
|
150
|
+
"data": { "type": "object" }
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"components": {
|
|
161
|
+
"schemas": {
|
|
162
|
+
"Widget": {
|
|
163
|
+
"type": "object",
|
|
164
|
+
"required": ["id", "name"],
|
|
165
|
+
"properties": {
|
|
166
|
+
"id": { "type": "string" },
|
|
167
|
+
"name": { "type": "string" },
|
|
168
|
+
"status": { "type": "string", "nullable": true },
|
|
169
|
+
"count": { "type": "integer" }
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"WidgetBody": {
|
|
173
|
+
"type": "object",
|
|
174
|
+
"required": ["name"],
|
|
175
|
+
"properties": {
|
|
176
|
+
"name": { "type": "string" },
|
|
177
|
+
"status": { "type": "string" }
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"WidgetList": {
|
|
181
|
+
"type": "object",
|
|
182
|
+
"properties": {
|
|
183
|
+
"results": {
|
|
184
|
+
"type": "array",
|
|
185
|
+
"items": {
|
|
186
|
+
"$ref": "#/components/schemas/Widget"
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
"count": { "type": "integer" }
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|