@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.
Files changed (85) hide show
  1. package/dist/bin.d.ts +9 -0
  2. package/dist/bin.d.ts.map +1 -0
  3. package/dist/bin.js +10 -0
  4. package/dist/catalogs/capability.d.ts +54 -0
  5. package/dist/catalogs/capability.d.ts.map +1 -0
  6. package/dist/catalogs/capability.js +129 -0
  7. package/dist/catalogs/crud.d.ts +64 -0
  8. package/dist/catalogs/crud.d.ts.map +1 -0
  9. package/dist/catalogs/crud.js +83 -0
  10. package/dist/catalogs/source.d.ts +16 -0
  11. package/dist/catalogs/source.d.ts.map +1 -0
  12. package/dist/catalogs/source.js +8 -0
  13. package/dist/catalogs/standard-crud.d.ts +51 -0
  14. package/dist/catalogs/standard-crud.d.ts.map +1 -0
  15. package/dist/catalogs/standard-crud.js +100 -0
  16. package/dist/cli.d.ts +20 -0
  17. package/dist/cli.d.ts.map +1 -0
  18. package/dist/cli.js +86 -0
  19. package/dist/commands/capabilities.d.ts +78 -0
  20. package/dist/commands/capabilities.d.ts.map +1 -0
  21. package/dist/commands/capabilities.js +72 -0
  22. package/dist/commands/contracts.d.ts +16 -0
  23. package/dist/commands/contracts.d.ts.map +1 -0
  24. package/dist/commands/contracts.js +83 -0
  25. package/dist/commands/create-frontend-module.d.ts +8 -0
  26. package/dist/commands/create-frontend-module.d.ts.map +1 -0
  27. package/dist/commands/create-frontend-module.js +90 -0
  28. package/dist/commands/create-package.d.ts +17 -0
  29. package/dist/commands/create-package.d.ts.map +1 -0
  30. package/dist/commands/create-package.js +75 -0
  31. package/dist/commands/create-registry.d.ts +32 -0
  32. package/dist/commands/create-registry.d.ts.map +1 -0
  33. package/dist/commands/create-registry.js +20 -0
  34. package/dist/commands/create.d.ts +23 -0
  35. package/dist/commands/create.d.ts.map +1 -0
  36. package/dist/commands/create.js +111 -0
  37. package/dist/commands/doctor.d.ts +17 -0
  38. package/dist/commands/doctor.d.ts.map +1 -0
  39. package/dist/commands/doctor.js +150 -0
  40. package/dist/commands/inspect.d.ts +139 -0
  41. package/dist/commands/inspect.d.ts.map +1 -0
  42. package/dist/commands/inspect.js +379 -0
  43. package/dist/generators/frontend-module.d.ts +81 -0
  44. package/dist/generators/frontend-module.d.ts.map +1 -0
  45. package/dist/generators/frontend-module.js +358 -0
  46. package/dist/generators/package.d.ts +46 -0
  47. package/dist/generators/package.d.ts.map +1 -0
  48. package/dist/generators/package.js +230 -0
  49. package/dist/index.d.ts +26 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +24 -0
  52. package/dist/kernel/arguments.d.ts +44 -0
  53. package/dist/kernel/arguments.d.ts.map +1 -0
  54. package/dist/kernel/arguments.js +127 -0
  55. package/dist/kernel/command.d.ts +71 -0
  56. package/dist/kernel/command.d.ts.map +1 -0
  57. package/dist/kernel/command.js +120 -0
  58. package/dist/kernel/fs-plan.d.ts +50 -0
  59. package/dist/kernel/fs-plan.d.ts.map +1 -0
  60. package/dist/kernel/fs-plan.js +82 -0
  61. package/dist/kernel/help.d.ts +54 -0
  62. package/dist/kernel/help.d.ts.map +1 -0
  63. package/dist/kernel/help.js +109 -0
  64. package/dist/kernel/lockfile.d.ts +73 -0
  65. package/dist/kernel/lockfile.d.ts.map +1 -0
  66. package/dist/kernel/lockfile.js +117 -0
  67. package/dist/kernel/manifests-wiring.d.ts +44 -0
  68. package/dist/kernel/manifests-wiring.d.ts.map +1 -0
  69. package/dist/kernel/manifests-wiring.js +165 -0
  70. package/dist/kernel/plan-runner.d.ts +81 -0
  71. package/dist/kernel/plan-runner.d.ts.map +1 -0
  72. package/dist/kernel/plan-runner.js +176 -0
  73. package/dist/kernel/process-runner.d.ts +25 -0
  74. package/dist/kernel/process-runner.d.ts.map +1 -0
  75. package/dist/kernel/process-runner.js +29 -0
  76. package/dist/kernel/render.d.ts +20 -0
  77. package/dist/kernel/render.d.ts.map +1 -0
  78. package/dist/kernel/render.js +63 -0
  79. package/dist/kernel/result.d.ts +66 -0
  80. package/dist/kernel/result.d.ts.map +1 -0
  81. package/dist/kernel/result.js +36 -0
  82. package/dist/kernel/workspace.d.ts +31 -0
  83. package/dist/kernel/workspace.d.ts.map +1 -0
  84. package/dist/kernel/workspace.js +66 -0
  85. package/package.json +31 -0
@@ -0,0 +1,379 @@
1
+ /**
2
+ * `yoyo-admin inspect <subject>`
3
+ *
4
+ * Agent-facing 只读事实查询:**只投影已有正式事实源**(generated crud catalog /
5
+ * capability catalog),不解析业务源码猜事实、不复制 JSON reader、不 import generator。
6
+ *
7
+ * 设计要点:
8
+ * - `inspect` 本身**永不写文件**(descriptor `authoring: false`);
9
+ * - 「资源不是 standard-crud」是**观察结果**(`standardCrud.eligible: false`),
10
+ * 不是命令失败 —— 只有 resourceKey / permissionName / prefix 根本不存在才 exit 2;
11
+ * - `--json` 输出稳定:所有数组都按确定顺序排序(resourceKey / operation / name)。
12
+ *
13
+ * 明确不做 `inspect module`:module/navigation 的真相是可执行 TypeScript
14
+ * (`app/manifests.ts` → `appModuleManifests` → createYoyoAdminManifestRegistry),
15
+ * 没有静态 navigation manifest catalog。用正则/AST 猜 route/page 会重新制造
16
+ * 「双维护事实」,因此本轮不提供,等宿主给出正式的 machine projection 再消费。
17
+ */
18
+ import { defineCommand, requireWorkspace } from '../kernel/command.js';
19
+ import { renderRecipeHelp, renderRecipeListHelp, } from '../kernel/help.js';
20
+ import { YoyoAdminCliUsageError, ok } from '../kernel/result.js';
21
+ import { loadCrudCatalog, loadCrudResourceDescriptor, } from '../catalogs/crud.js';
22
+ import { loadCapabilityCatalog, loadPermissionDescriptor, matchPermissionPrefix, } from '../catalogs/capability.js';
23
+ import { deriveStandardCrudCompatibility } from '../catalogs/standard-crud.js';
24
+ import { optionalOption, requirePositional } from '../kernel/arguments.js';
25
+ const subjects = [
26
+ {
27
+ name: 'resources',
28
+ summary: '列出生成的 CRUD resource catalog 中的全部真实资源(resourceKey / serviceName / operations)。',
29
+ usage: 'yoyo-admin inspect resources [--json]',
30
+ arguments: [],
31
+ options: [],
32
+ run: context => inspectResources(context),
33
+ },
34
+ {
35
+ name: 'resource',
36
+ summary: '投影单个资源的完整契约:operations + operationId、requestSchemas、list 查询参数、' +
37
+ 'getForEdit idParameter、create/update 字段映射,以及 standard-crud compatibility。',
38
+ usage: 'yoyo-admin inspect resource <resourceKey> [--json]',
39
+ arguments: [
40
+ { name: 'resourceKey', required: true, description: 'camelCase 资源 key,例如 measuringUnit。' },
41
+ ],
42
+ options: [],
43
+ run: (context, args) => inspectResource(context, requirePositional(context.parsed, 1, 'resourceKey')),
44
+ },
45
+ {
46
+ name: 'permissions',
47
+ summary: '列出 capability catalog 中的权限(含 displayName / parent / multiTenancySides / source);可只取某前缀。',
48
+ usage: 'yoyo-admin inspect permissions [--prefix <prefix>] [--json]',
49
+ arguments: [],
50
+ options: [
51
+ {
52
+ flag: '--prefix',
53
+ required: false,
54
+ description: '只返回该前缀本身及其后代;无匹配时 exit 2(避免拼错前缀拿到空列表)。',
55
+ },
56
+ ],
57
+ run: context => inspectPermissions(context),
58
+ },
59
+ {
60
+ name: 'permission',
61
+ summary: '精确查询单条权限,并投影 catalog 关系:ancestors / directChildren。',
62
+ usage: 'yoyo-admin inspect permission <permissionName> [--json]',
63
+ arguments: [
64
+ { name: 'permissionName', required: true, description: '完整权限名,例如 Pages.Administration.Tenants.Query。' },
65
+ ],
66
+ options: [],
67
+ run: (context, args) => inspectPermission(context, requirePositional(context.parsed, 1, 'permissionName')),
68
+ },
69
+ ];
70
+ export function listInspectSubjects() {
71
+ return [...subjects].sort((left, right) => left.name.localeCompare(right.name));
72
+ }
73
+ export function resolveInspectSubject(name) {
74
+ return subjects.find(subject => subject.name === name);
75
+ }
76
+ const INSPECT_KINDS = new Set(['resources', 'resource', 'permissions', 'permission']);
77
+ export function isInspectPayload(value) {
78
+ if (typeof value !== 'object' || value === null)
79
+ return false;
80
+ const kind = value.kind;
81
+ return typeof kind === 'string' && INSPECT_KINDS.has(kind);
82
+ }
83
+ /* ------------------------------------------------------------------ runners */
84
+ function inspectResources(context) {
85
+ const catalog = loadCrudCatalog(requireWorkspace(context).repoRoot);
86
+ const payload = {
87
+ kind: 'resources',
88
+ source: catalog.source,
89
+ resources: catalog.resources
90
+ .map(resource => ({
91
+ resourceKey: resource.resourceKey,
92
+ serviceName: resource.serviceName,
93
+ operations: Object.keys(resource.operations).sort(),
94
+ }))
95
+ .sort((left, right) => left.resourceKey.localeCompare(right.resourceKey)),
96
+ };
97
+ return ok('inspect resources', [], payload);
98
+ }
99
+ function inspectResource(context, resourceKey) {
100
+ const repoRoot = requireWorkspace(context).repoRoot;
101
+ // 只有 resourceKey 不存在才失败;「不是 standard-crud」是观察结果。
102
+ const descriptor = loadCrudResourceDescriptor(repoRoot, resourceKey);
103
+ const catalog = loadCrudCatalog(repoRoot);
104
+ const payload = {
105
+ kind: 'resource',
106
+ source: catalog.source,
107
+ resource: projectResource(descriptor),
108
+ };
109
+ return ok(`inspect resource ${resourceKey}`, [], payload);
110
+ }
111
+ function projectResource(descriptor) {
112
+ const binding = descriptor.binding;
113
+ const compatibility = deriveStandardCrudCompatibility(descriptor);
114
+ return {
115
+ resourceKey: descriptor.resourceKey,
116
+ serviceName: descriptor.serviceName,
117
+ operations: Object.entries(descriptor.operations)
118
+ .map(([operation, operationId]) => ({ operation, operationId }))
119
+ .sort((left, right) => left.operation.localeCompare(right.operation)),
120
+ requestSchemas: Object.entries(descriptor.requestSchemas)
121
+ .map(([operation, schemaRef]) => ({ operation, schemaRef }))
122
+ .sort((left, right) => left.operation.localeCompare(right.operation)),
123
+ binding: {
124
+ ...(binding?.list === undefined
125
+ ? {}
126
+ : {
127
+ list: {
128
+ queryParameters: Object.entries(binding.list.query ?? {})
129
+ .map(([parameter, field]) => ({ parameter, field }))
130
+ .sort((left, right) => left.parameter.localeCompare(right.parameter)),
131
+ itemsPath: [...(binding.list.itemsPath ?? [])],
132
+ totalCountPath: [...(binding.list.totalCountPath ?? [])],
133
+ },
134
+ }),
135
+ ...(binding?.getForEdit === undefined
136
+ ? {}
137
+ : {
138
+ getForEdit: {
139
+ idParameter: binding.getForEdit.idParameter ?? '',
140
+ entityPath: [...(binding.getForEdit.entityPath ?? [])],
141
+ },
142
+ }),
143
+ ...(binding?.create?.fieldMappings === undefined
144
+ ? {}
145
+ : { create: { fieldMappings: projectFieldMappings(binding.create.fieldMappings) } }),
146
+ ...(binding?.update?.fieldMappings === undefined
147
+ ? {}
148
+ : { update: { fieldMappings: projectFieldMappings(binding.update.fieldMappings) } }),
149
+ ...(binding?.setEnabled?.fieldMappings === undefined
150
+ ? {}
151
+ : { setEnabled: { fieldMappings: projectFieldMappings(binding.setEnabled.fieldMappings) } }),
152
+ ...(binding?.remove?.idParameter === undefined
153
+ ? {}
154
+ : { remove: { idParameter: binding.remove.idParameter } }),
155
+ },
156
+ standardCrud: compatibility.eligible
157
+ ? {
158
+ eligible: true,
159
+ rowKey: compatibility.shape.rowKey,
160
+ formFields: compatibility.shape.formFields.map(field => ({
161
+ key: field.key,
162
+ editableOn: field.editableOn,
163
+ })),
164
+ operations: {
165
+ create: compatibility.shape.canCreate,
166
+ update: compatibility.shape.canUpdate,
167
+ setEnabled: compatibility.shape.canSetEnabled,
168
+ remove: compatibility.shape.canRemove,
169
+ },
170
+ }
171
+ : { eligible: false, code: compatibility.code, message: compatibility.message },
172
+ };
173
+ }
174
+ function projectFieldMappings(mappings) {
175
+ return mappings.map(mapping => ({ source: mapping.source, target: [...mapping.target] }));
176
+ }
177
+ function inspectPermissions(context) {
178
+ const repoRoot = requireWorkspace(context).repoRoot;
179
+ const prefix = optionalOption(context.parsed, '--prefix');
180
+ const catalog = loadCapabilityCatalog(repoRoot);
181
+ if (prefix === undefined) {
182
+ const payload = {
183
+ kind: 'permissions',
184
+ source: catalog.source,
185
+ prefix: null,
186
+ permissions: [...catalog.permissions].sort((left, right) => left.name.localeCompare(right.name)),
187
+ };
188
+ return ok('inspect permissions', [], payload);
189
+ }
190
+ const matched = matchPermissionPrefix(repoRoot, prefix);
191
+ if (matched.length === 0) {
192
+ // 前缀拼错必须 exit 2:不能给 Agent 一个「成功的空列表」。
193
+ throw new YoyoAdminCliUsageError('permission-prefix-not-found', `capability catalog 中没有任何权限匹配前缀 "${prefix}"。` +
194
+ '请用 `yoyo-admin inspect permissions --json` 查看真实权限名;拼错前缀会导致生成的模块在 vue-tsc 编译失败。');
195
+ }
196
+ const payload = {
197
+ kind: 'permissions',
198
+ source: catalog.source,
199
+ prefix,
200
+ permissions: matched,
201
+ };
202
+ return ok('inspect permissions', [], payload);
203
+ }
204
+ function inspectPermission(context, permissionName) {
205
+ const repoRoot = requireWorkspace(context).repoRoot;
206
+ const catalog = loadCapabilityCatalog(repoRoot);
207
+ const permission = loadPermissionDescriptor(repoRoot, permissionName);
208
+ const byName = new Map(catalog.permissions.map(entry => [entry.name, entry]));
209
+ const ancestors = [];
210
+ const seen = new Set([permission.name]);
211
+ let cursor = permission.parent;
212
+ while (cursor !== null && !seen.has(cursor)) {
213
+ ancestors.unshift(cursor);
214
+ seen.add(cursor);
215
+ cursor = byName.get(cursor)?.parent ?? null;
216
+ }
217
+ const payload = {
218
+ kind: 'permission',
219
+ source: catalog.source,
220
+ permission,
221
+ ancestors,
222
+ directChildren: catalog.permissions
223
+ .filter(entry => entry.parent === permission.name)
224
+ .map(entry => entry.name)
225
+ .sort((left, right) => left.localeCompare(right)),
226
+ };
227
+ return ok(`inspect permission ${permissionName}`, [], payload);
228
+ }
229
+ /* ------------------------------------------------------------------ wiring */
230
+ function inspectArgumentSpec(positionals) {
231
+ const subjectName = positionals[0];
232
+ const subject = subjectName === undefined ? undefined : resolveInspectSubject(subjectName);
233
+ return {
234
+ booleanFlags: [],
235
+ valueOptions: (subject?.options ?? []).map(option => option.flag),
236
+ };
237
+ }
238
+ /** `inspect` 的 help 投影面:与 create 共用同一套渲染器。 */
239
+ export const INSPECT_HELP_SURFACE = {
240
+ command: 'inspect',
241
+ title: '只读查询生成契约事实源',
242
+ itemLabel: 'subject',
243
+ usageSuffix: '[arguments] [--json]',
244
+ itemUsageHint: '完整参数:yoyo-admin inspect <subject> --help',
245
+ };
246
+ function inspectHelp(positionals) {
247
+ const subjectName = positionals[0];
248
+ const subject = subjectName === undefined ? undefined : resolveInspectSubject(subjectName);
249
+ // help 请求本身永不失败:未知 subject 回落到 subject 清单。
250
+ return subject === undefined
251
+ ? renderRecipeListHelp(projectSubjectsForHelp(), INSPECT_HELP_SURFACE)
252
+ : renderRecipeHelp(projectSubjectForHelp(subject), INSPECT_HELP_SURFACE);
253
+ }
254
+ function projectSubjectForHelp(subject) {
255
+ return {
256
+ name: subject.name,
257
+ summary: subject.summary,
258
+ usage: subject.usage,
259
+ kinds: [],
260
+ options: subject.options,
261
+ };
262
+ }
263
+ function projectSubjectsForHelp() {
264
+ return listInspectSubjects().map(projectSubjectForHelp);
265
+ }
266
+ /** `inspect` 的选项投影:所有 subject 选项按 flag 去重并标注来源 subject。 */
267
+ function projectSubjectOptions() {
268
+ const byFlag = new Map();
269
+ for (const subject of listInspectSubjects()) {
270
+ for (const option of subject.options) {
271
+ const entry = byFlag.get(option.flag) ?? { flag: option.flag, descriptions: [], values: new Set() };
272
+ entry.descriptions.push(`${subject.name}: ${option.description}`);
273
+ for (const value of option.values ?? [])
274
+ entry.values.add(value);
275
+ byFlag.set(option.flag, entry);
276
+ }
277
+ }
278
+ return [...byFlag.values()].map(entry => ({
279
+ flag: entry.flag,
280
+ description: entry.descriptions.join(' '),
281
+ ...(entry.values.size === 0 ? {} : { values: [...entry.values] }),
282
+ }));
283
+ }
284
+ export function runInspect(context) {
285
+ const subjectName = context.parsed.positionals[0];
286
+ const available = listInspectSubjects().map(subject => subject.name).join('、');
287
+ if (subjectName === undefined || subjectName.length === 0) {
288
+ throw new YoyoAdminCliUsageError('unknown-inspect-subject', `缺少 inspect 子命令。当前支持:${available}。`);
289
+ }
290
+ const subject = resolveInspectSubject(subjectName);
291
+ if (subject === undefined) {
292
+ throw new YoyoAdminCliUsageError('unknown-inspect-subject', `未知 inspect 子命令 ${subjectName}。当前支持:${available}。`);
293
+ }
294
+ return subject.run(context, context.parsed.positionals.slice(1));
295
+ }
296
+ export const inspectCommand = defineCommand({
297
+ descriptor: {
298
+ name: 'inspect',
299
+ summary: `只读查询生成契约事实源。当前支持:${listInspectSubjects().map(subject => subject.name).join(' / ')}。`,
300
+ usage: `yoyo-admin inspect <${listInspectSubjects().map(subject => subject.name).join('|')}> [arguments] [--json]`,
301
+ arguments: [
302
+ {
303
+ name: 'subject',
304
+ required: true,
305
+ description: `查询对象,当前支持:${listInspectSubjects().map(subject => subject.name).join('、')}。`,
306
+ },
307
+ ],
308
+ options: projectSubjectOptions(),
309
+ authoring: false,
310
+ capability: 'agent-facing-fact-inspection',
311
+ },
312
+ argumentSpec: inspectArgumentSpec,
313
+ renderHelp: inspectHelp,
314
+ run: runInspect,
315
+ });
316
+ /* ------------------------------------------------------------------ rendering */
317
+ /** 人类可读输出(`--json` 走结果信封,不经过这里)。 */
318
+ export function renderInspectPayload(payload) {
319
+ const lines = [];
320
+ if (payload.kind === 'resources') {
321
+ lines.push(`source: ${payload.source.path}`);
322
+ lines.push('');
323
+ for (const resource of payload.resources) {
324
+ lines.push(` ${resource.resourceKey} (${resource.serviceName})`);
325
+ lines.push(` operations: ${resource.operations.join(', ') || '(none)'}`);
326
+ }
327
+ return `${lines.join('\n')}\n`;
328
+ }
329
+ if (payload.kind === 'resource') {
330
+ const resource = payload.resource;
331
+ lines.push(`resource: ${resource.resourceKey} (${resource.serviceName})`);
332
+ lines.push(`source: ${payload.source.path}`);
333
+ lines.push('');
334
+ lines.push('operations:');
335
+ for (const operation of resource.operations) {
336
+ lines.push(` ${operation.operation} → ${operation.operationId}`);
337
+ }
338
+ lines.push('');
339
+ lines.push('binding:');
340
+ for (const [key, value] of Object.entries(resource.binding)) {
341
+ lines.push(` ${key}: ${JSON.stringify(value)}`);
342
+ }
343
+ lines.push('');
344
+ lines.push('standardCrud:');
345
+ if (resource.standardCrud.eligible) {
346
+ lines.push(` eligible: true rowKey: ${resource.standardCrud.rowKey}`);
347
+ lines.push(` operations: ${JSON.stringify(resource.standardCrud.operations)}`);
348
+ lines.push(' formFields:');
349
+ for (const field of resource.standardCrud.formFields) {
350
+ lines.push(` ${field.key} (${field.editableOn})`);
351
+ }
352
+ return `${lines.join('\n')}\n`;
353
+ }
354
+ lines.push(` eligible: false`);
355
+ lines.push(` code: ${resource.standardCrud.code}`);
356
+ lines.push(` message: ${resource.standardCrud.message}`);
357
+ return `${lines.join('\n')}\n`;
358
+ }
359
+ if (payload.kind === 'permissions') {
360
+ lines.push(`source: ${payload.source.path}`);
361
+ lines.push(`prefix: ${payload.prefix ?? '(all)'}`);
362
+ lines.push('');
363
+ for (const permission of payload.permissions) {
364
+ lines.push(` ${permission.name}`);
365
+ lines.push(` displayName: ${permission.displayName} parent: ${permission.parent ?? '(root)'} sides: ${permission.multiTenancySides ?? '(unknown)'}`);
366
+ }
367
+ return `${lines.join('\n')}\n`;
368
+ }
369
+ lines.push(`permission: ${payload.permission.name}`);
370
+ lines.push(`source: ${payload.source.path}`);
371
+ lines.push('');
372
+ lines.push(` displayName: ${payload.permission.displayName}`);
373
+ lines.push(` parent: ${payload.permission.parent ?? '(root)'}`);
374
+ lines.push(` multiTenancySides: ${payload.permission.multiTenancySides ?? '(unknown)'}`);
375
+ lines.push(` source: ${payload.permission.source ?? '(unknown)'}`);
376
+ lines.push(` ancestors: ${payload.ancestors.join(' → ') || '(none)'}`);
377
+ lines.push(` directChildren: ${payload.directChildren.join(', ') || '(none)'}`);
378
+ return `${lines.join('\n')}\n`;
379
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * `yoyo-admin create frontend-module --kind standard-crud`
3
+ *
4
+ * **Contract-driven**:从生成的 CRUD resource catalog 读取该资源的完整
5
+ * descriptor(operations / binding),actions、权限与最小表单字段全部由
6
+ * 真实契约派生 —— 不猜业务事实:
7
+ * - 资源没有 `remove` operation → 绝不生成 delete action / Delete 权限;
8
+ * - 字段取自 `binding.create.fieldMappings[].source`(排除系统字段),
9
+ * 生命周期按 `binding.update.fieldMappings` 派生;
10
+ * 不再硬编码任何资源特定字段(v1 的 name/enabled/creationTime 已移除);
11
+ * - 表格列只含 rowKey(来自 `binding.getForEdit.idParameter`),
12
+ * 查询字段与展示列由作者补齐。
13
+ *
14
+ * 生成**当前正式作者面**,不多不少:
15
+ * - 模块 `manifest.ts`(纯 standard-crud definition)
16
+ * - feature `schema.ts`(唯一的页面契约作者面)
17
+ * - 并接线 `app/manifests.ts`
18
+ *
19
+ * 明确不生成(治理裁决):
20
+ * `page-contract.ts`、通用 `service.ts`、通用 `validation.ts`、
21
+ * 空 `index.vue`、binding。这些属于 typed extension,
22
+ * 只在真实复杂业务需要时作为独立 recipe/option 增加。
23
+ *
24
+ * Plan-time fail-closed 校验:
25
+ * - resourceKey 必须存在于生成的 CRUD resource catalog;
26
+ * - 权限前缀派生的全部权限必须已存在于 capability catalog
27
+ * (admin-vue 的 YoyoAdminPermissionKey 是类型化字面量联合,假前缀在
28
+ * vue-tsc 下必然编译失败,提前到计划期 fail-closed);
29
+ * - moduleKey / pageKey / routePath 不得与既有模块重复。
30
+ */
31
+ import { type FsPlan } from '../kernel/fs-plan.js';
32
+ import { type StandardCrudShape } from '../catalogs/standard-crud.js';
33
+ import { type YoyoAdminWorkspace } from '../kernel/workspace.js';
34
+ export declare const STANDARD_CRUD_KIND = "standard-crud";
35
+ export { deriveStandardCrudShape, RUNTIME_SUPPLIED_FIELDS, type StandardCrudShape, type StandardCrudShapeField, } from '../catalogs/standard-crud.js';
36
+ export interface FrontendModuleRequest {
37
+ readonly moduleKey: string;
38
+ readonly resourceKey: string;
39
+ readonly routePath: string;
40
+ readonly title: string;
41
+ readonly description: string;
42
+ readonly order: number;
43
+ readonly group: string;
44
+ readonly permissionPrefix: string;
45
+ readonly kind: string;
46
+ /** 显式指定 datasourceId;缺省按 `${camel(moduleKey)}.${resourceKey}` 推导。 */
47
+ readonly datasource?: string;
48
+ /** 显式虚拟化意图;外部输入在 plan-time 校验,仅接受 fixed。 */
49
+ readonly virtualization?: string;
50
+ }
51
+ /** 生成合法的 TypeScript 单引号字符串字面量(转义 '/\/控制字符/行分隔符)。 */
52
+ export declare function toTsStringLiteral(value: string): string;
53
+ export declare function validateFrontendModuleRequest(request: FrontendModuleRequest): void;
54
+ /** 对 moduleKey / pageKey / routePath 做既有清单重复检测(fail-closed)。 */
55
+ export declare function assertNoDuplicates(workspace: YoyoAdminWorkspace, request: FrontendModuleRequest, pageKey: string): void;
56
+ export declare function camelCase(value: string): string;
57
+ export declare function kebabCase(value: string): string;
58
+ /** datasourceId 的唯一推导点:schema 与 manifest 共用,不可能漂移。 */
59
+ export declare function datasourceIdFor(request: FrontendModuleRequest): string;
60
+ export declare function pageKeyFor(request: FrontendModuleRequest): string;
61
+ /** 按 shape 派生的权限集合;缺失的能力不产生对应键(消费侧类型 optional)。 */
62
+ export interface StandardCrudPermissionSet {
63
+ readonly page: readonly string[];
64
+ readonly create?: string;
65
+ readonly update?: string;
66
+ readonly setEnabled?: string;
67
+ readonly remove?: string;
68
+ }
69
+ export declare function deriveStandardCrudPermissions(permissionPrefix: string, shape: StandardCrudShape): StandardCrudPermissionSet;
70
+ /** 平铺权限集合(plan-time capability catalog 校验用)。 */
71
+ export declare function permissionNamesOf(permissions: StandardCrudPermissionSet): readonly string[];
72
+ export interface FrontendModulePlan extends FsPlan {
73
+ readonly moduleKey: string;
74
+ readonly directory: string;
75
+ readonly pageKey: string;
76
+ readonly datasourceId: string;
77
+ readonly shape: StandardCrudShape;
78
+ readonly permissions: StandardCrudPermissionSet;
79
+ }
80
+ export declare function planStandardCrudFrontendModule(workspace: YoyoAdminWorkspace, request: FrontendModuleRequest): FrontendModulePlan;
81
+ //# sourceMappingURL=frontend-module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontend-module.d.ts","sourceRoot":"","sources":["../../src/generators/frontend-module.ts"],"names":[],"mappings":"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"}