@yoyoboot/yoyo-admin-cli 10.5.5
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/dist/bin.d.ts +9 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +10 -0
- package/dist/catalogs/capability.d.ts +54 -0
- package/dist/catalogs/capability.d.ts.map +1 -0
- package/dist/catalogs/capability.js +129 -0
- package/dist/catalogs/crud.d.ts +64 -0
- package/dist/catalogs/crud.d.ts.map +1 -0
- package/dist/catalogs/crud.js +83 -0
- package/dist/catalogs/source.d.ts +16 -0
- package/dist/catalogs/source.d.ts.map +1 -0
- package/dist/catalogs/source.js +8 -0
- package/dist/catalogs/standard-crud.d.ts +51 -0
- package/dist/catalogs/standard-crud.d.ts.map +1 -0
- package/dist/catalogs/standard-crud.js +100 -0
- package/dist/cli.d.ts +20 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +86 -0
- package/dist/commands/capabilities.d.ts +78 -0
- package/dist/commands/capabilities.d.ts.map +1 -0
- package/dist/commands/capabilities.js +72 -0
- package/dist/commands/contracts.d.ts +16 -0
- package/dist/commands/contracts.d.ts.map +1 -0
- package/dist/commands/contracts.js +83 -0
- package/dist/commands/create-frontend-module.d.ts +8 -0
- package/dist/commands/create-frontend-module.d.ts.map +1 -0
- package/dist/commands/create-frontend-module.js +90 -0
- package/dist/commands/create-package.d.ts +17 -0
- package/dist/commands/create-package.d.ts.map +1 -0
- package/dist/commands/create-package.js +75 -0
- package/dist/commands/create-registry.d.ts +32 -0
- package/dist/commands/create-registry.d.ts.map +1 -0
- package/dist/commands/create-registry.js +20 -0
- package/dist/commands/create.d.ts +23 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +111 -0
- package/dist/commands/doctor.d.ts +17 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +150 -0
- package/dist/commands/inspect.d.ts +139 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +379 -0
- package/dist/generators/frontend-module.d.ts +81 -0
- package/dist/generators/frontend-module.d.ts.map +1 -0
- package/dist/generators/frontend-module.js +358 -0
- package/dist/generators/package.d.ts +46 -0
- package/dist/generators/package.d.ts.map +1 -0
- package/dist/generators/package.js +230 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/kernel/arguments.d.ts +44 -0
- package/dist/kernel/arguments.d.ts.map +1 -0
- package/dist/kernel/arguments.js +127 -0
- package/dist/kernel/command.d.ts +71 -0
- package/dist/kernel/command.d.ts.map +1 -0
- package/dist/kernel/command.js +120 -0
- package/dist/kernel/fs-plan.d.ts +50 -0
- package/dist/kernel/fs-plan.d.ts.map +1 -0
- package/dist/kernel/fs-plan.js +82 -0
- package/dist/kernel/help.d.ts +54 -0
- package/dist/kernel/help.d.ts.map +1 -0
- package/dist/kernel/help.js +109 -0
- package/dist/kernel/lockfile.d.ts +73 -0
- package/dist/kernel/lockfile.d.ts.map +1 -0
- package/dist/kernel/lockfile.js +117 -0
- package/dist/kernel/manifests-wiring.d.ts +44 -0
- package/dist/kernel/manifests-wiring.d.ts.map +1 -0
- package/dist/kernel/manifests-wiring.js +165 -0
- package/dist/kernel/plan-runner.d.ts +81 -0
- package/dist/kernel/plan-runner.d.ts.map +1 -0
- package/dist/kernel/plan-runner.js +176 -0
- package/dist/kernel/process-runner.d.ts +25 -0
- package/dist/kernel/process-runner.d.ts.map +1 -0
- package/dist/kernel/process-runner.js +29 -0
- package/dist/kernel/render.d.ts +20 -0
- package/dist/kernel/render.d.ts.map +1 -0
- package/dist/kernel/render.js +63 -0
- package/dist/kernel/result.d.ts +66 -0
- package/dist/kernel/result.d.ts.map +1 -0
- package/dist/kernel/result.js +36 -0
- package/dist/kernel/workspace.d.ts +31 -0
- package/dist/kernel/workspace.d.ts.map +1 -0
- package/dist/kernel/workspace.js +66 -0
- package/package.json +31 -0
package/dist/bin.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;GAKG"}
|
package/dist/bin.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生成的 capability catalog 读取层(**共享事实读取层**)。
|
|
3
|
+
*
|
|
4
|
+
* 权限事实源:`Yoyo.Admin.CapabilityExporter` 以最小 ABP boot 枚举权限后
|
|
5
|
+
* 写入 admin-core 生成边缘;admin-vue 的 `YoyoAdminPermissionKey` 类型化
|
|
6
|
+
* 字面量联合与 catalog 同源。
|
|
7
|
+
*
|
|
8
|
+
* 消费方:
|
|
9
|
+
* - frontend-module generator 在 plan-time 校验权限前缀存在性;
|
|
10
|
+
* - `inspect permissions` / `inspect permission` 把完整 descriptor
|
|
11
|
+
* (displayName / parent / multiTenancySides / source)原样投影给 Agent。
|
|
12
|
+
*
|
|
13
|
+
* 因此本层返回**完整 descriptor**,不再退化成 `string[]`。
|
|
14
|
+
* catalog 缺失 / 为空 / 不可解析 / 条目残缺一律 fail-closed。
|
|
15
|
+
*/
|
|
16
|
+
import type { CatalogSource } from './source.js';
|
|
17
|
+
/** 生成的 capability catalog 位置(随 admin-core 生成边缘更新)。 */
|
|
18
|
+
export declare const CAPABILITY_CATALOG_RELATIVE = "packages/yoyo-admin/admin-core/src/contracts/generated/capability/capability-catalog.json";
|
|
19
|
+
export interface CapabilityPermissionDescriptor {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly displayName: string;
|
|
22
|
+
/** 父权限名;根权限为 null。 */
|
|
23
|
+
readonly parent: string | null;
|
|
24
|
+
/** catalog 原样值,例如 `Host` / `Tenant` / `Host|Tenant`。 */
|
|
25
|
+
readonly multiTenancySides: string | null;
|
|
26
|
+
readonly source: string | null;
|
|
27
|
+
}
|
|
28
|
+
export interface CapabilityFeatureDescriptor {
|
|
29
|
+
readonly name: string;
|
|
30
|
+
readonly scope: string | null;
|
|
31
|
+
readonly defaultValue: string | null;
|
|
32
|
+
readonly displayName: string | null;
|
|
33
|
+
readonly description: string | null;
|
|
34
|
+
readonly source: string | null;
|
|
35
|
+
}
|
|
36
|
+
export interface CapabilityCatalogDocument {
|
|
37
|
+
readonly source: CatalogSource;
|
|
38
|
+
readonly permissions: readonly CapabilityPermissionDescriptor[];
|
|
39
|
+
readonly features: readonly CapabilityFeatureDescriptor[];
|
|
40
|
+
}
|
|
41
|
+
/** 读取完整 capability catalog 文档;缺失/为空/不可解析/条目残缺时 fail-closed。 */
|
|
42
|
+
export declare function loadCapabilityCatalog(repoRoot: string): CapabilityCatalogDocument;
|
|
43
|
+
/** 全部权限名(frontend-module 的 plan-time 前缀校验用)。 */
|
|
44
|
+
export declare function loadKnownPermissionNames(repoRoot: string): readonly string[];
|
|
45
|
+
/** 精确读取单条权限;不存在时 fail-closed。 */
|
|
46
|
+
export declare function loadPermissionDescriptor(repoRoot: string, permissionName: string): CapabilityPermissionDescriptor;
|
|
47
|
+
/**
|
|
48
|
+
* 前缀匹配:前缀本身(若存在)+ 其全部后代。
|
|
49
|
+
*
|
|
50
|
+
* 无任何匹配时返回空数组,由调用方决定 fail-closed(inspect 会报
|
|
51
|
+
* `permission-prefix-not-found`),避免 Agent 拼错前缀却拿到「成功的空列表」。
|
|
52
|
+
*/
|
|
53
|
+
export declare function matchPermissionPrefix(repoRoot: string, prefix: string): readonly CapabilityPermissionDescriptor[];
|
|
54
|
+
//# sourceMappingURL=capability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.d.ts","sourceRoot":"","sources":["../../src/catalogs/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,sDAAsD;AACtD,eAAO,MAAM,2BAA2B,8FACqD,CAAA;AAE7F,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,sBAAsB;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,wDAAwD;IACxD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAA;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC/B;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,QAAQ,CAAC,WAAW,EAAE,SAAS,8BAA8B,EAAE,CAAA;IAC/D,QAAQ,CAAC,QAAQ,EAAE,SAAS,2BAA2B,EAAE,CAAA;CAC1D;AAyCD,+DAA+D;AAC/D,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,yBAAyB,CA2EjF;AAED,gDAAgD;AAChD,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAE5E;AAED,iCAAiC;AACjC,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,GACrB,8BAA8B,CAYhC;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,SAAS,8BAA8B,EAAE,CAO3C"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生成的 capability catalog 读取层(**共享事实读取层**)。
|
|
3
|
+
*
|
|
4
|
+
* 权限事实源:`Yoyo.Admin.CapabilityExporter` 以最小 ABP boot 枚举权限后
|
|
5
|
+
* 写入 admin-core 生成边缘;admin-vue 的 `YoyoAdminPermissionKey` 类型化
|
|
6
|
+
* 字面量联合与 catalog 同源。
|
|
7
|
+
*
|
|
8
|
+
* 消费方:
|
|
9
|
+
* - frontend-module generator 在 plan-time 校验权限前缀存在性;
|
|
10
|
+
* - `inspect permissions` / `inspect permission` 把完整 descriptor
|
|
11
|
+
* (displayName / parent / multiTenancySides / source)原样投影给 Agent。
|
|
12
|
+
*
|
|
13
|
+
* 因此本层返回**完整 descriptor**,不再退化成 `string[]`。
|
|
14
|
+
* catalog 缺失 / 为空 / 不可解析 / 条目残缺一律 fail-closed。
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { YoyoAdminCliUsageError } from '../kernel/result.js';
|
|
19
|
+
/** 生成的 capability catalog 位置(随 admin-core 生成边缘更新)。 */
|
|
20
|
+
export const CAPABILITY_CATALOG_RELATIVE = 'packages/yoyo-admin/admin-core/src/contracts/generated/capability/capability-catalog.json';
|
|
21
|
+
function isRecord(value) {
|
|
22
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
23
|
+
}
|
|
24
|
+
function readCatalogEntries(value, kind) {
|
|
25
|
+
if (value === undefined)
|
|
26
|
+
return [];
|
|
27
|
+
if (!Array.isArray(value)) {
|
|
28
|
+
throw new YoyoAdminCliUsageError('capability-catalog-unreadable', `capability catalog 的 ${kind} 必须是数组。`);
|
|
29
|
+
}
|
|
30
|
+
const names = new Set();
|
|
31
|
+
return value.map((entry) => {
|
|
32
|
+
if (!isRecord(entry) || typeof entry.name !== 'string' || entry.name.trim().length === 0) {
|
|
33
|
+
throw new YoyoAdminCliUsageError('capability-catalog-unreadable', `capability catalog 的 ${kind} 中存在缺少有效 name 的条目;拒绝按残缺契约工作。`);
|
|
34
|
+
}
|
|
35
|
+
const name = entry.name;
|
|
36
|
+
if (names.has(name)) {
|
|
37
|
+
throw new YoyoAdminCliUsageError('capability-catalog-unreadable', `capability catalog 的 ${kind} 中存在重复 name:${name}。`);
|
|
38
|
+
}
|
|
39
|
+
names.add(name);
|
|
40
|
+
return { ...entry, name };
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function readOptionalString(value) {
|
|
44
|
+
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
45
|
+
}
|
|
46
|
+
/** 读取完整 capability catalog 文档;缺失/为空/不可解析/条目残缺时 fail-closed。 */
|
|
47
|
+
export function loadCapabilityCatalog(repoRoot) {
|
|
48
|
+
const absolute = join(repoRoot, CAPABILITY_CATALOG_RELATIVE);
|
|
49
|
+
if (!existsSync(absolute)) {
|
|
50
|
+
throw new YoyoAdminCliUsageError('capability-catalog-missing', `未找到生成的 capability catalog:${CAPABILITY_CATALOG_RELATIVE}。` +
|
|
51
|
+
'请先在 aspnet-core 运行 CapabilityExporter 刷新 admin-core 生成边缘。');
|
|
52
|
+
}
|
|
53
|
+
let parsed;
|
|
54
|
+
try {
|
|
55
|
+
parsed = JSON.parse(readFileSync(absolute, 'utf8'));
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
throw new YoyoAdminCliUsageError('capability-catalog-unreadable', `capability catalog 解析失败:${error instanceof Error ? error.message : String(error)}`);
|
|
59
|
+
}
|
|
60
|
+
if (!isRecord(parsed)) {
|
|
61
|
+
throw new YoyoAdminCliUsageError('capability-catalog-unreadable', 'capability catalog 必须是 JSON 对象。');
|
|
62
|
+
}
|
|
63
|
+
const catalog = parsed;
|
|
64
|
+
const rawPermissions = readCatalogEntries(catalog.permissions, 'permissions');
|
|
65
|
+
const permissions = [];
|
|
66
|
+
for (const permission of rawPermissions) {
|
|
67
|
+
const name = permission.name;
|
|
68
|
+
permissions.push({
|
|
69
|
+
name,
|
|
70
|
+
displayName: readOptionalString(permission.displayName) ?? name,
|
|
71
|
+
parent: readOptionalString(permission.parent),
|
|
72
|
+
multiTenancySides: readOptionalString(permission.multiTenancySides),
|
|
73
|
+
source: readOptionalString(permission.source),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (permissions.length === 0) {
|
|
77
|
+
throw new YoyoAdminCliUsageError('capability-catalog-empty', 'capability catalog 中没有任何权限;无法校验 --permission-prefix。');
|
|
78
|
+
}
|
|
79
|
+
const features = readCatalogEntries(catalog.features, 'features').map((feature) => ({
|
|
80
|
+
name: feature.name,
|
|
81
|
+
scope: readOptionalString(feature.scope),
|
|
82
|
+
defaultValue: readOptionalString(feature.defaultValue),
|
|
83
|
+
displayName: readOptionalString(feature.displayName),
|
|
84
|
+
description: readOptionalString(feature.description),
|
|
85
|
+
source: readOptionalString(feature.source),
|
|
86
|
+
}));
|
|
87
|
+
return {
|
|
88
|
+
source: {
|
|
89
|
+
path: CAPABILITY_CATALOG_RELATIVE,
|
|
90
|
+
...(typeof catalog.schemaVersion === 'string'
|
|
91
|
+
? { schemaVersion: catalog.schemaVersion }
|
|
92
|
+
: {}),
|
|
93
|
+
...(typeof catalog.generator === 'string' ? { generator: catalog.generator } : {}),
|
|
94
|
+
...(typeof catalog.generatorVersion === 'string'
|
|
95
|
+
? { generatorVersion: catalog.generatorVersion }
|
|
96
|
+
: {}),
|
|
97
|
+
...(typeof catalog.sourceHash === 'string' ? { sourceHash: catalog.sourceHash } : {}),
|
|
98
|
+
},
|
|
99
|
+
permissions,
|
|
100
|
+
features,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** 全部权限名(frontend-module 的 plan-time 前缀校验用)。 */
|
|
104
|
+
export function loadKnownPermissionNames(repoRoot) {
|
|
105
|
+
return loadCapabilityCatalog(repoRoot).permissions.map((permission) => permission.name);
|
|
106
|
+
}
|
|
107
|
+
/** 精确读取单条权限;不存在时 fail-closed。 */
|
|
108
|
+
export function loadPermissionDescriptor(repoRoot, permissionName) {
|
|
109
|
+
const permissions = loadCapabilityCatalog(repoRoot).permissions;
|
|
110
|
+
const permission = permissions.find((candidate) => candidate.name === permissionName);
|
|
111
|
+
if (permission === undefined) {
|
|
112
|
+
throw new YoyoAdminCliUsageError('unknown-permission-key', `权限 "${permissionName}" 不在 capability catalog 中。` +
|
|
113
|
+
'请用 `yoyo-admin inspect permissions` 查看真实权限名;新权限先在 aspnet-core 的授权 Provider 定义,' +
|
|
114
|
+
'再运行 CapabilityExporter 刷新生成物。');
|
|
115
|
+
}
|
|
116
|
+
return permission;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 前缀匹配:前缀本身(若存在)+ 其全部后代。
|
|
120
|
+
*
|
|
121
|
+
* 无任何匹配时返回空数组,由调用方决定 fail-closed(inspect 会报
|
|
122
|
+
* `permission-prefix-not-found`),避免 Agent 拼错前缀却拿到「成功的空列表」。
|
|
123
|
+
*/
|
|
124
|
+
export function matchPermissionPrefix(repoRoot, prefix) {
|
|
125
|
+
const descendants = `${prefix}.`;
|
|
126
|
+
return loadCapabilityCatalog(repoRoot)
|
|
127
|
+
.permissions.filter((permission) => permission.name === prefix || permission.name.startsWith(descendants))
|
|
128
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
129
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生成的 CRUD resource catalog 读取层(**共享事实读取层**)。
|
|
3
|
+
*
|
|
4
|
+
* 位置:`src/catalogs/` 是「生成契约事实」的唯一读取层,`generators/`(recipe)
|
|
5
|
+
* 与 `commands/`(doctor / inspect)共同消费它 —— inspect 不 import generator,
|
|
6
|
+
* 也不复制第二套 JSON reader。
|
|
7
|
+
*
|
|
8
|
+
* 这是 frontend-module generator 与 `inspect resource` 的**契约事实源**:
|
|
9
|
+
* 读取完整 `crudResources[]` descriptor(operations / requestSchemas / binding),
|
|
10
|
+
* 由消费方按真实契约派生 actions、权限、最小表单字段与 compatibility 判定。
|
|
11
|
+
*
|
|
12
|
+
* catalog 缺失 / 为空 / 不可解析一律 fail-closed,不静默降级。
|
|
13
|
+
*/
|
|
14
|
+
import type { CatalogSource } from './source.js';
|
|
15
|
+
/** 生成的 CRUD resource catalog 位置(随 api-client 生成边缘更新)。 */
|
|
16
|
+
export declare const CRUD_CATALOG_RELATIVE = "apps/yoyo-admin/admin-vue/api-client/src/generated/api-contract-catalog.json";
|
|
17
|
+
export interface CrudFieldMapping {
|
|
18
|
+
readonly source: string;
|
|
19
|
+
readonly target: readonly string[];
|
|
20
|
+
}
|
|
21
|
+
/** catalog 中单个 CRUD 资源的完整 descriptor(只取消费方关心的切片)。 */
|
|
22
|
+
export interface CrudResourceDescriptor {
|
|
23
|
+
readonly resourceKey: string;
|
|
24
|
+
readonly serviceName: string;
|
|
25
|
+
/** operation 名 → OpenAPI operationId;key 集合即该资源真实具备的能力。 */
|
|
26
|
+
readonly operations: Readonly<Record<string, string>>;
|
|
27
|
+
/** operation 名 → 请求体 schema 引用。 */
|
|
28
|
+
readonly requestSchemas: Readonly<Record<string, string>>;
|
|
29
|
+
readonly binding?: {
|
|
30
|
+
readonly list?: {
|
|
31
|
+
/** 查询参数名(camelCase)→ 后端字段名。 */
|
|
32
|
+
readonly query?: Readonly<Record<string, string>>;
|
|
33
|
+
readonly itemsPath?: readonly string[];
|
|
34
|
+
readonly totalCountPath?: readonly string[];
|
|
35
|
+
};
|
|
36
|
+
readonly getForEdit?: {
|
|
37
|
+
readonly idParameter?: string;
|
|
38
|
+
readonly entityPath?: readonly string[];
|
|
39
|
+
};
|
|
40
|
+
readonly create?: {
|
|
41
|
+
readonly fieldMappings?: readonly CrudFieldMapping[];
|
|
42
|
+
};
|
|
43
|
+
readonly update?: {
|
|
44
|
+
readonly fieldMappings?: readonly CrudFieldMapping[];
|
|
45
|
+
};
|
|
46
|
+
readonly setEnabled?: {
|
|
47
|
+
readonly fieldMappings?: readonly CrudFieldMapping[];
|
|
48
|
+
};
|
|
49
|
+
readonly remove?: {
|
|
50
|
+
readonly idParameter?: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
export interface CrudCatalogDocument {
|
|
55
|
+
readonly source: CatalogSource;
|
|
56
|
+
readonly resources: readonly CrudResourceDescriptor[];
|
|
57
|
+
}
|
|
58
|
+
/** 读取完整 catalog 文档(含生成元信息);catalog 缺失/为空/不可解析时 fail-closed。 */
|
|
59
|
+
export declare function loadCrudCatalog(repoRoot: string): CrudCatalogDocument;
|
|
60
|
+
export declare function loadCrudResourceDescriptors(repoRoot: string): readonly CrudResourceDescriptor[];
|
|
61
|
+
export declare function loadKnownResourceKeys(repoRoot: string): readonly string[];
|
|
62
|
+
/** 按资源 key 读取单个 descriptor;不存在时 fail-closed。 */
|
|
63
|
+
export declare function loadCrudResourceDescriptor(repoRoot: string, resourceKey: string): CrudResourceDescriptor;
|
|
64
|
+
//# sourceMappingURL=crud.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/catalogs/crud.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEhD,yDAAyD;AACzD,eAAO,MAAM,qBAAqB,iFAC8C,CAAA;AAEhF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CACnC;AAED,qDAAqD;AACrD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACrD,mCAAmC;IACnC,QAAQ,CAAC,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE;QACjB,QAAQ,CAAC,IAAI,CAAC,EAAE;YACd,+BAA+B;YAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;YACjD,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;YACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;SAC5C,CAAA;QACD,QAAQ,CAAC,UAAU,CAAC,EAAE;YAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,CAAA;QAChG,QAAQ,CAAC,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;SAAE,CAAA;QAC1E,QAAQ,CAAC,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;SAAE,CAAA;QAC1E,QAAQ,CAAC,UAAU,CAAC,EAAE;YAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAA;SAAE,CAAA;QAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE;YAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KACpD,CAAA;CACF;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAA;IAC9B,QAAQ,CAAC,SAAS,EAAE,SAAS,sBAAsB,EAAE,CAAA;CACtD;AAeD,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,CA+DrE;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,sBAAsB,EAAE,CAE/F;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAEzE;AAED,gDAAgD;AAChD,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,sBAAsB,CAYxB"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生成的 CRUD resource catalog 读取层(**共享事实读取层**)。
|
|
3
|
+
*
|
|
4
|
+
* 位置:`src/catalogs/` 是「生成契约事实」的唯一读取层,`generators/`(recipe)
|
|
5
|
+
* 与 `commands/`(doctor / inspect)共同消费它 —— inspect 不 import generator,
|
|
6
|
+
* 也不复制第二套 JSON reader。
|
|
7
|
+
*
|
|
8
|
+
* 这是 frontend-module generator 与 `inspect resource` 的**契约事实源**:
|
|
9
|
+
* 读取完整 `crudResources[]` descriptor(operations / requestSchemas / binding),
|
|
10
|
+
* 由消费方按真实契约派生 actions、权限、最小表单字段与 compatibility 判定。
|
|
11
|
+
*
|
|
12
|
+
* catalog 缺失 / 为空 / 不可解析一律 fail-closed,不静默降级。
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { YoyoAdminCliUsageError } from '../kernel/result.js';
|
|
17
|
+
/** 生成的 CRUD resource catalog 位置(随 api-client 生成边缘更新)。 */
|
|
18
|
+
export const CRUD_CATALOG_RELATIVE = 'apps/yoyo-admin/admin-vue/api-client/src/generated/api-contract-catalog.json';
|
|
19
|
+
/** 读取完整 catalog 文档(含生成元信息);catalog 缺失/为空/不可解析时 fail-closed。 */
|
|
20
|
+
export function loadCrudCatalog(repoRoot) {
|
|
21
|
+
const absolute = join(repoRoot, CRUD_CATALOG_RELATIVE);
|
|
22
|
+
if (!existsSync(absolute)) {
|
|
23
|
+
throw new YoyoAdminCliUsageError('crud-catalog-missing', `未找到生成的 CRUD resource catalog:${CRUD_CATALOG_RELATIVE}。` +
|
|
24
|
+
'请先在 admin-vue 执行 api:update 生成契约边缘。');
|
|
25
|
+
}
|
|
26
|
+
let catalog;
|
|
27
|
+
try {
|
|
28
|
+
catalog = JSON.parse(readFileSync(absolute, 'utf8'));
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
throw new YoyoAdminCliUsageError('crud-catalog-unreadable', `CRUD resource catalog 解析失败:${error instanceof Error ? error.message : String(error)}`);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const resources = (catalog.crudResources ?? []).map((resource) => {
|
|
35
|
+
if (typeof resource.resourceKey !== 'string' || resource.resourceKey.length === 0) {
|
|
36
|
+
throw new YoyoAdminCliUsageError('crud-catalog-unreadable', 'CRUD resource catalog 中存在缺少 resourceKey 的资源条目;拒绝按残缺契约工作。');
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
resourceKey: resource.resourceKey,
|
|
40
|
+
serviceName: typeof resource.serviceName === 'string' ? resource.serviceName : resource.resourceKey,
|
|
41
|
+
operations: resource.operations ?? {},
|
|
42
|
+
requestSchemas: resource.requestSchemas ?? {},
|
|
43
|
+
...(resource.binding !== undefined ? { binding: resource.binding } : {}),
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
if (resources.length === 0) {
|
|
47
|
+
throw new YoyoAdminCliUsageError('crud-catalog-empty', 'CRUD resource catalog 中没有任何资源;无法校验 --resource。');
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
source: {
|
|
51
|
+
path: CRUD_CATALOG_RELATIVE,
|
|
52
|
+
...(typeof catalog.schemaVersion === 'string' ? { schemaVersion: catalog.schemaVersion } : {}),
|
|
53
|
+
...(typeof catalog.generatorVersion === 'string'
|
|
54
|
+
? { generatorVersion: catalog.generatorVersion }
|
|
55
|
+
: {}),
|
|
56
|
+
...(typeof catalog.sourceHash === 'string' ? { sourceHash: catalog.sourceHash } : {}),
|
|
57
|
+
},
|
|
58
|
+
resources,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (error instanceof YoyoAdminCliUsageError)
|
|
63
|
+
throw error;
|
|
64
|
+
throw new YoyoAdminCliUsageError('crud-catalog-unreadable', `CRUD resource catalog 结构无法识别:${error instanceof Error ? error.message : String(error)}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function loadCrudResourceDescriptors(repoRoot) {
|
|
68
|
+
return loadCrudCatalog(repoRoot).resources;
|
|
69
|
+
}
|
|
70
|
+
export function loadKnownResourceKeys(repoRoot) {
|
|
71
|
+
return loadCrudResourceDescriptors(repoRoot).map(descriptor => descriptor.resourceKey);
|
|
72
|
+
}
|
|
73
|
+
/** 按资源 key 读取单个 descriptor;不存在时 fail-closed。 */
|
|
74
|
+
export function loadCrudResourceDescriptor(repoRoot, resourceKey) {
|
|
75
|
+
const descriptors = loadCrudResourceDescriptors(repoRoot);
|
|
76
|
+
const descriptor = descriptors.find(candidate => candidate.resourceKey === resourceKey);
|
|
77
|
+
if (descriptor === undefined) {
|
|
78
|
+
throw new YoyoAdminCliUsageError('unknown-resource-key', `resourceKey "${resourceKey}" 不在生成的 CRUD resource catalog 中` +
|
|
79
|
+
`(当前可用:${descriptors.map(item => item.resourceKey).join(', ')})。` +
|
|
80
|
+
'请先确认后端契约已生成;如属新资源,先走 api:update 刷新生成边缘。');
|
|
81
|
+
}
|
|
82
|
+
return descriptor;
|
|
83
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 生成契约事实源的公共元信息。
|
|
3
|
+
*
|
|
4
|
+
* 每个 catalog 文档都带一份**生成元信息**(谁生成的、哪个 schema 版本、
|
|
5
|
+
* 基于哪个 sourceHash)。`inspect` 把它原样投影给 Agent —— 让 Agent 知道
|
|
6
|
+
* 自己读到的是不是当前边缘,而不是只看到一堆条目。
|
|
7
|
+
*/
|
|
8
|
+
export interface CatalogSource {
|
|
9
|
+
/** 仓库根相对路径。 */
|
|
10
|
+
readonly path: string;
|
|
11
|
+
readonly schemaVersion?: string;
|
|
12
|
+
readonly generator?: string;
|
|
13
|
+
readonly generatorVersion?: string;
|
|
14
|
+
readonly sourceHash?: string;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/catalogs/source.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,aAAa;IAC5B,eAAe;IACf,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAC7B"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* standard-crud 兼容性派生(**纯契约派生,generator 与 inspect 共用**)。
|
|
3
|
+
*
|
|
4
|
+
* 只有一处派生逻辑:`deriveStandardCrudCompatibility()` 读真实 descriptor,
|
|
5
|
+
* 返回**可观察结果**而不是抛错;两边的差异只在呈现方式:
|
|
6
|
+
* - `generators/frontend-module.ts` 用 `deriveStandardCrudShape()` 把
|
|
7
|
+
* `eligible: false` 转成 plan-time fail-closed(YoyoAdminCliUsageError);
|
|
8
|
+
* - `inspect resource` 把同一个结果原样投影给 Agent —— 「资源不是 standard-crud」
|
|
9
|
+
* 是**观察结果**,不是 inspect 命令失败。
|
|
10
|
+
*
|
|
11
|
+
* 契约事实:actions/权限/最小表单字段全部由 descriptor 派生,不猜业务事实:
|
|
12
|
+
* - 资源没有 `remove` operation → 绝不生成 delete action / Delete 权限;
|
|
13
|
+
* - form 字段取自 `binding.create.fieldMappings[].source`(排除系统字段),
|
|
14
|
+
* 生命周期按 `binding.update.fieldMappings` 派生(create∩update → both;
|
|
15
|
+
* create-only → `editableOn: 'create'`),保证宿主 YVAL005 校验通过;
|
|
16
|
+
* - rowKey 来自 `binding.getForEdit.idParameter`。
|
|
17
|
+
*/
|
|
18
|
+
import type { CrudResourceDescriptor } from './crud.js';
|
|
19
|
+
/** 运行时供给的字段:出现在 update 契约但不属于表单(与 admin-schema compiler 对齐)。 */
|
|
20
|
+
export declare const RUNTIME_SUPPLIED_FIELDS: ReadonlySet<string>;
|
|
21
|
+
export interface StandardCrudShapeField {
|
|
22
|
+
readonly key: string;
|
|
23
|
+
/** 'both' = create+edit 均可编辑(缺省声明);'create' = 仅 create 阶段可编辑。 */
|
|
24
|
+
readonly editableOn: 'create' | 'both';
|
|
25
|
+
}
|
|
26
|
+
export interface StandardCrudShape {
|
|
27
|
+
readonly rowKey: string;
|
|
28
|
+
readonly formFields: readonly StandardCrudShapeField[];
|
|
29
|
+
readonly canCreate: boolean;
|
|
30
|
+
readonly canUpdate: boolean;
|
|
31
|
+
readonly canSetEnabled: boolean;
|
|
32
|
+
readonly canRemove: boolean;
|
|
33
|
+
}
|
|
34
|
+
export type StandardCrudCompatibility = {
|
|
35
|
+
readonly eligible: true;
|
|
36
|
+
readonly shape: StandardCrudShape;
|
|
37
|
+
} | {
|
|
38
|
+
readonly eligible: false;
|
|
39
|
+
readonly code: string;
|
|
40
|
+
readonly message: string;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* 纯派生:从 descriptor 判定 standard-crud 兼容性。
|
|
44
|
+
*
|
|
45
|
+
* 不抛错、不做 IO —— 失败以 `{ eligible: false, code, message }` 表达,
|
|
46
|
+
* 让调用方自己决定是 fail-closed(generator)还是如实上报(inspect)。
|
|
47
|
+
*/
|
|
48
|
+
export declare function deriveStandardCrudCompatibility(descriptor: CrudResourceDescriptor): StandardCrudCompatibility;
|
|
49
|
+
/** generator 视图:`eligible: false` 即 plan-time fail-closed。 */
|
|
50
|
+
export declare function deriveStandardCrudShape(descriptor: CrudResourceDescriptor): StandardCrudShape;
|
|
51
|
+
//# sourceMappingURL=standard-crud.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standard-crud.d.ts","sourceRoot":"","sources":["../../src/catalogs/standard-crud.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAEvD,gEAAgE;AAChE,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,MAAM,CAItD,CAAA;AAEF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,iEAAiE;IACjE,QAAQ,CAAC,UAAU,EAAE,QAAQ,GAAG,MAAM,CAAA;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,sBAAsB,EAAE,CAAA;IACtD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAA;IAC/B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAA;CAC5B;AAED,MAAM,MAAM,yBAAyB,GACjC;IAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAA;CAAE,GAC9D;IAAE,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEjF;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,UAAU,EAAE,sBAAsB,GACjC,yBAAyB,CAkE3B;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,sBAAsB,GAAG,iBAAiB,CAM7F"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* standard-crud 兼容性派生(**纯契约派生,generator 与 inspect 共用**)。
|
|
3
|
+
*
|
|
4
|
+
* 只有一处派生逻辑:`deriveStandardCrudCompatibility()` 读真实 descriptor,
|
|
5
|
+
* 返回**可观察结果**而不是抛错;两边的差异只在呈现方式:
|
|
6
|
+
* - `generators/frontend-module.ts` 用 `deriveStandardCrudShape()` 把
|
|
7
|
+
* `eligible: false` 转成 plan-time fail-closed(YoyoAdminCliUsageError);
|
|
8
|
+
* - `inspect resource` 把同一个结果原样投影给 Agent —— 「资源不是 standard-crud」
|
|
9
|
+
* 是**观察结果**,不是 inspect 命令失败。
|
|
10
|
+
*
|
|
11
|
+
* 契约事实:actions/权限/最小表单字段全部由 descriptor 派生,不猜业务事实:
|
|
12
|
+
* - 资源没有 `remove` operation → 绝不生成 delete action / Delete 权限;
|
|
13
|
+
* - form 字段取自 `binding.create.fieldMappings[].source`(排除系统字段),
|
|
14
|
+
* 生命周期按 `binding.update.fieldMappings` 派生(create∩update → both;
|
|
15
|
+
* create-only → `editableOn: 'create'`),保证宿主 YVAL005 校验通过;
|
|
16
|
+
* - rowKey 来自 `binding.getForEdit.idParameter`。
|
|
17
|
+
*/
|
|
18
|
+
import { YoyoAdminCliUsageError } from '../kernel/result.js';
|
|
19
|
+
/** 运行时供给的字段:出现在 update 契约但不属于表单(与 admin-schema compiler 对齐)。 */
|
|
20
|
+
export const RUNTIME_SUPPLIED_FIELDS = new Set([
|
|
21
|
+
'id',
|
|
22
|
+
'concurrencyToken',
|
|
23
|
+
'concurrencyStamp',
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* 纯派生:从 descriptor 判定 standard-crud 兼容性。
|
|
27
|
+
*
|
|
28
|
+
* 不抛错、不做 IO —— 失败以 `{ eligible: false, code, message }` 表达,
|
|
29
|
+
* 让调用方自己决定是 fail-closed(generator)还是如实上报(inspect)。
|
|
30
|
+
*/
|
|
31
|
+
export function deriveStandardCrudCompatibility(descriptor) {
|
|
32
|
+
const idParameter = descriptor.binding?.getForEdit?.idParameter;
|
|
33
|
+
if (idParameter === undefined || idParameter.length === 0) {
|
|
34
|
+
return {
|
|
35
|
+
eligible: false,
|
|
36
|
+
code: 'resource-binding-incomplete',
|
|
37
|
+
message: `资源 ${descriptor.resourceKey} 的 catalog binding 缺少 getForEdit.idParameter,` +
|
|
38
|
+
'无法确定 rowKey;standard-crud 不可用。',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const has = (operation) => Object.prototype.hasOwnProperty.call(descriptor.operations, operation);
|
|
42
|
+
// update 契约字段集合(去运行时供给字段);资源声明 update 能力时必须提供,
|
|
43
|
+
// 否则无法确定字段生命周期(宿主 YVAL005 校验必然失败)。
|
|
44
|
+
const updateFieldKeys = new Set();
|
|
45
|
+
if (has('update')) {
|
|
46
|
+
const updateMappings = descriptor.binding?.update?.fieldMappings;
|
|
47
|
+
if (updateMappings === undefined) {
|
|
48
|
+
return {
|
|
49
|
+
eligible: false,
|
|
50
|
+
code: 'resource-binding-incomplete',
|
|
51
|
+
message: `资源 ${descriptor.resourceKey} 声明了 update operation,但 catalog binding 缺少 ` +
|
|
52
|
+
'update.fieldMappings,无法确定表单字段生命周期(宿主 YVAL005 校验需要);standard-crud 不可用。',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
for (const mapping of updateMappings) {
|
|
56
|
+
if (!RUNTIME_SUPPLIED_FIELDS.has(mapping.source))
|
|
57
|
+
updateFieldKeys.add(mapping.source);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const createMappings = descriptor.binding?.create?.fieldMappings ?? [];
|
|
61
|
+
const formFields = [];
|
|
62
|
+
for (const mapping of createMappings) {
|
|
63
|
+
if (RUNTIME_SUPPLIED_FIELDS.has(mapping.source))
|
|
64
|
+
continue;
|
|
65
|
+
if (formFields.some(field => field.key === mapping.source))
|
|
66
|
+
continue;
|
|
67
|
+
formFields.push({
|
|
68
|
+
key: mapping.source,
|
|
69
|
+
editableOn: updateFieldKeys.has(mapping.source) ? 'both' : 'create',
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (formFields.length === 0) {
|
|
73
|
+
return {
|
|
74
|
+
eligible: false,
|
|
75
|
+
code: 'resource-has-no-creatable-fields',
|
|
76
|
+
message: `资源 ${descriptor.resourceKey} 的 create fieldMappings 未提供任何业务字段;` +
|
|
77
|
+
'standard-crud 无法构成最小表单。请先确认后端契约与 api:update 生成边缘,' +
|
|
78
|
+
'或按 typed extension 处理该资源。',
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
eligible: true,
|
|
83
|
+
shape: {
|
|
84
|
+
rowKey: idParameter,
|
|
85
|
+
formFields,
|
|
86
|
+
canCreate: has('create'),
|
|
87
|
+
canUpdate: has('update'),
|
|
88
|
+
canSetEnabled: has('setEnabled'),
|
|
89
|
+
canRemove: has('remove'),
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** generator 视图:`eligible: false` 即 plan-time fail-closed。 */
|
|
94
|
+
export function deriveStandardCrudShape(descriptor) {
|
|
95
|
+
const compatibility = deriveStandardCrudCompatibility(descriptor);
|
|
96
|
+
if (!compatibility.eligible) {
|
|
97
|
+
throw new YoyoAdminCliUsageError(compatibility.code, compatibility.message);
|
|
98
|
+
}
|
|
99
|
+
return compatibility.shape;
|
|
100
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yoyo-admin` CLI 入口。
|
|
3
|
+
*
|
|
4
|
+
* 退出码约定:
|
|
5
|
+
* 0 = 成功(含 `--help`)
|
|
6
|
+
* 2 = 预期失败(用户输入或仓库状态不允许执行)
|
|
7
|
+
* 1 = 未预期失败(程序缺陷)
|
|
8
|
+
*/
|
|
9
|
+
import { YoyoAdminCliRegistry } from './kernel/command.js';
|
|
10
|
+
export declare const EXIT_OK = 0;
|
|
11
|
+
export declare const EXIT_UNEXPECTED = 1;
|
|
12
|
+
export declare const EXIT_USAGE = 2;
|
|
13
|
+
export interface RunCliOptions {
|
|
14
|
+
readonly write?: (text: string) => void;
|
|
15
|
+
/** 仓库查找起点;被 `--repo <path>` 覆盖。缺省 `process.cwd()`。 */
|
|
16
|
+
readonly startDirectory?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function createRegistry(): YoyoAdminCliRegistry;
|
|
19
|
+
export declare function runCli(argv: readonly string[], options?: RunCliOptions): number;
|
|
20
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAY,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAWpE,eAAO,MAAM,OAAO,IAAI,CAAA;AACxB,eAAO,MAAM,eAAe,IAAI,CAAA;AAChC,eAAO,MAAM,UAAU,IAAI,CAAA;AAE3B,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,sDAAsD;IACtD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CACjC;AAED,wBAAgB,cAAc,IAAI,oBAAoB,CAMrD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CA4BnF"}
|