@yss123/cage-cli 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +18 -2
- package/bin/cage.js +6 -0
- package/bin/create-cage-app.js +6 -0
- package/dist/analyze.d.ts +18 -0
- package/dist/analyze.js +26 -0
- package/dist/analyze.js.map +1 -0
- package/dist/baseline.d.ts +5 -0
- package/dist/baseline.js +50 -0
- package/dist/baseline.js.map +1 -0
- package/dist/budget.d.ts +7 -0
- package/dist/budget.js +52 -0
- package/dist/budget.js.map +1 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/create.d.ts +1 -0
- package/dist/create.js +47 -0
- package/dist/create.js.map +1 -0
- package/dist/database.d.ts +5 -0
- package/dist/database.js +70 -0
- package/dist/database.js.map +1 -0
- package/dist/derive.d.ts +14 -0
- package/dist/derive.js +163 -0
- package/dist/derive.js.map +1 -0
- package/dist/dev.d.ts +2 -0
- package/dist/dev.js +155 -0
- package/dist/dev.js.map +1 -0
- package/dist/env.d.ts +1 -0
- package/dist/env.js +15 -0
- package/dist/env.js.map +1 -0
- package/dist/findings.d.ts +11 -0
- package/dist/findings.js +13 -0
- package/dist/findings.js.map +1 -0
- package/dist/gen/contracts.d.ts +6 -0
- package/dist/gen/contracts.js +167 -0
- package/dist/gen/contracts.js.map +1 -0
- package/dist/gen/index.d.ts +19 -0
- package/dist/gen/index.js +137 -0
- package/dist/gen/index.js.map +1 -0
- package/dist/gen/zod-code.d.ts +7 -0
- package/dist/gen/zod-code.js +161 -0
- package/dist/gen/zod-code.js.map +1 -0
- package/dist/graph-snapshot.d.ts +13 -0
- package/dist/graph-snapshot.js +46 -0
- package/dist/graph-snapshot.js.map +1 -0
- package/dist/graph.d.ts +11 -0
- package/dist/graph.js +87 -0
- package/dist/graph.js.map +1 -0
- package/dist/impact.d.ts +28 -0
- package/dist/impact.js +223 -0
- package/dist/impact.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/load.d.ts +6 -0
- package/dist/load.js +17 -0
- package/dist/load.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +176 -0
- package/dist/main.js.map +1 -0
- package/dist/migrate.d.ts +7 -0
- package/dist/migrate.js +69 -0
- package/dist/migrate.js.map +1 -0
- package/dist/ontology.d.ts +41 -0
- package/dist/ontology.js +270 -0
- package/dist/ontology.js.map +1 -0
- package/dist/process.d.ts +6 -0
- package/dist/process.js +39 -0
- package/dist/process.js.map +1 -0
- package/dist/rules.d.ts +23 -0
- package/dist/rules.js +251 -0
- package/dist/rules.js.map +1 -0
- package/dist/static-check.d.ts +23 -0
- package/dist/static-check.js +225 -0
- package/dist/static-check.js.map +1 -0
- package/dist/sync.d.ts +5 -0
- package/dist/sync.js +46 -0
- package/dist/sync.js.map +1 -0
- package/dist/upgrade.d.ts +10 -0
- package/dist/upgrade.js +81 -0
- package/dist/upgrade.js.map +1 -0
- package/dist/verify.d.ts +7 -0
- package/dist/verify.js +88 -0
- package/dist/verify.js.map +1 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/graph-ui/app.js +1065 -0
- package/graph-ui/index.html +197 -0
- package/graph-ui/model.js +141 -0
- package/graph-ui/relations.js +125 -0
- package/graph-ui/structure.js +74 -0
- package/graph-ui/style.css +1698 -0
- package/managed/errors/CAGE-APPR-001.md +32 -0
- package/managed/errors/CAGE-APPR-002.md +32 -0
- package/managed/errors/CAGE-APPR-003.md +32 -0
- package/managed/errors/CAGE-APPR-004.md +32 -0
- package/managed/errors/CAGE-APPR-005.md +32 -0
- package/managed/errors/CAGE-APPR-006.md +32 -0
- package/managed/errors/CAGE-APPR-007.md +32 -0
- package/managed/errors/CAGE-APPR-010.md +32 -0
- package/managed/errors/CAGE-AUTH-001.md +32 -0
- package/managed/errors/CAGE-BUDGET-001.md +32 -0
- package/managed/errors/CAGE-BUDGET-002.md +32 -0
- package/managed/errors/CAGE-BUDGET-003.md +32 -0
- package/managed/errors/CAGE-CMD-002.md +32 -0
- package/managed/errors/CAGE-CMD-003.md +34 -0
- package/managed/errors/CAGE-CONN-001.md +32 -0
- package/managed/errors/CAGE-CONN-002.md +32 -0
- package/managed/errors/CAGE-CONN-003.md +32 -0
- package/managed/errors/CAGE-CONN-004.md +32 -0
- package/managed/errors/CAGE-CONN-005.md +32 -0
- package/managed/errors/CAGE-CONN-006.md +32 -0
- package/managed/errors/CAGE-CONN-007.md +32 -0
- package/managed/errors/CAGE-CONN-008.md +32 -0
- package/managed/errors/CAGE-CONN-009.md +32 -0
- package/managed/errors/CAGE-CONN-010.md +32 -0
- package/managed/errors/CAGE-CONN-011.md +32 -0
- package/managed/errors/CAGE-CONN-012.md +32 -0
- package/managed/errors/CAGE-CREATE-001.md +32 -0
- package/managed/errors/CAGE-DECL-001.md +34 -0
- package/managed/errors/CAGE-DECL-002.md +34 -0
- package/managed/errors/CAGE-DECL-003.md +34 -0
- package/managed/errors/CAGE-DECL-004.md +34 -0
- package/managed/errors/CAGE-DEP-001.md +34 -0
- package/managed/errors/CAGE-DEP-002.md +34 -0
- package/managed/errors/CAGE-DEP-003.md +34 -0
- package/managed/errors/CAGE-DEP-004.md +34 -0
- package/managed/errors/CAGE-DEP-005.md +34 -0
- package/managed/errors/CAGE-DLQ-001.md +32 -0
- package/managed/errors/CAGE-ENV-001.md +32 -0
- package/managed/errors/CAGE-EVENT-001.md +32 -0
- package/managed/errors/CAGE-EVENT-002.md +32 -0
- package/managed/errors/CAGE-FIELD-001.md +32 -0
- package/managed/errors/CAGE-FIELD-002.md +32 -0
- package/managed/errors/CAGE-FIELD-003.md +32 -0
- package/managed/errors/CAGE-FIELD-004.md +32 -0
- package/managed/errors/CAGE-GEN-001.md +33 -0
- package/managed/errors/CAGE-GEN-002.md +33 -0
- package/managed/errors/CAGE-GRANT-001.md +32 -0
- package/managed/errors/CAGE-GRANT-002.md +32 -0
- package/managed/errors/CAGE-GRANT-003.md +32 -0
- package/managed/errors/CAGE-IMPACT-001.md +32 -0
- package/managed/errors/CAGE-JOB-001.md +32 -0
- package/managed/errors/CAGE-JOB-002.md +32 -0
- package/managed/errors/CAGE-JOB-003.md +32 -0
- package/managed/errors/CAGE-LINT-001.md +32 -0
- package/managed/errors/CAGE-MIG-001.md +32 -0
- package/managed/errors/CAGE-MIG-002.md +32 -0
- package/managed/errors/CAGE-MIG-003.md +32 -0
- package/managed/errors/CAGE-MIG-004.md +32 -0
- package/managed/errors/CAGE-MIG-005.md +32 -0
- package/managed/errors/CAGE-NAME-001.md +32 -0
- package/managed/errors/CAGE-NAME-002.md +32 -0
- package/managed/errors/CAGE-NAME-003.md +32 -0
- package/managed/errors/CAGE-NAME-004.md +32 -0
- package/managed/errors/CAGE-NAME-005.md +32 -0
- package/managed/errors/CAGE-NAME-006.md +32 -0
- package/managed/errors/CAGE-ORG-001.md +32 -0
- package/managed/errors/CAGE-PAIR-002.md +33 -0
- package/managed/errors/CAGE-QUERY-001.md +32 -0
- package/managed/errors/CAGE-QUERY-002.md +32 -0
- package/managed/errors/CAGE-QUERY-003.md +32 -0
- package/managed/errors/CAGE-REACT-001.md +32 -0
- package/managed/errors/CAGE-REACT-002.md +32 -0
- package/managed/errors/CAGE-READS-001.md +32 -0
- package/managed/errors/CAGE-REG-001.md +32 -0
- package/managed/errors/CAGE-REG-002.md +32 -0
- package/managed/errors/CAGE-REG-003.md +32 -0
- package/managed/errors/CAGE-ROUTE-001.md +32 -0
- package/managed/errors/CAGE-SCOPE-001.md +32 -0
- package/managed/errors/CAGE-SCOPE-002.md +32 -0
- package/managed/errors/CAGE-SECRET-001.md +32 -0
- package/managed/errors/CAGE-SECRET-002.md +32 -0
- package/managed/errors/CAGE-SENS-001.md +32 -0
- package/managed/errors/CAGE-SQL-001.md +32 -0
- package/managed/errors/CAGE-SQL-002.md +32 -0
- package/managed/errors/CAGE-STATE-001.md +32 -0
- package/managed/errors/CAGE-STATE-002.md +32 -0
- package/managed/errors/CAGE-STATE-003.md +32 -0
- package/managed/errors/CAGE-STATE-004.md +32 -0
- package/managed/errors/CAGE-STATE-005.md +32 -0
- package/managed/errors/CAGE-STATE-010.md +32 -0
- package/managed/errors/CAGE-STATE-011.md +32 -0
- package/managed/errors/CAGE-SYNC-001.md +35 -0
- package/managed/errors/CAGE-TEST-001.md +33 -0
- package/managed/errors/CAGE-UNSAFE-001.md +32 -0
- package/managed/errors/CAGE-UPGRADE-001.md +32 -0
- package/managed/errors/README.md +99 -0
- package/package.json +60 -3
- package/templates/app/.dockerignore +10 -0
- package/templates/app/.env.example +17 -0
- package/templates/app/.github/workflows/cage.yml +44 -0
- package/templates/app/AGENTS.md +13 -0
- package/templates/app/Dockerfile +23 -0
- package/templates/app/README.md +58 -0
- package/templates/app/apps/api/package.json +16 -0
- package/templates/app/apps/api/src/main.ts +10 -0
- package/templates/app/apps/api/src/worker.ts +14 -0
- package/templates/app/apps/api/tsconfig.json +5 -0
- package/templates/app/apps/web/index.html +13 -0
- package/templates/app/apps/web/package.json +22 -0
- package/templates/app/apps/web/src/main.tsx +552 -0
- package/templates/app/apps/web/src/style.css +663 -0
- package/templates/app/apps/web/tsconfig.json +11 -0
- package/templates/app/apps/web/vite.config.ts +16 -0
- package/templates/app/cage.config.json +114 -0
- package/templates/app/compose.yaml +39 -0
- package/templates/app/db/migrations/0001_init.sql +112 -0
- package/templates/app/package.json +25 -0
- package/templates/app/packages/contracts/package.json +16 -0
- package/templates/app/packages/contracts/src/dept.ts +74 -0
- package/templates/app/packages/contracts/src/index.ts +81 -0
- package/templates/app/packages/contracts/src/inventory-lock.ts +52 -0
- package/templates/app/packages/contracts/src/inventory.ts +57 -0
- package/templates/app/packages/contracts/src/purchase-order.ts +72 -0
- package/templates/app/packages/contracts/src/queries.ts +17 -0
- package/templates/app/packages/contracts/src/role.ts +85 -0
- package/templates/app/packages/contracts/src/user.ts +89 -0
- package/templates/app/packages/contracts/tsconfig.json +5 -0
- package/templates/app/packages/domain/package.json +23 -0
- package/templates/app/packages/domain/src/approvals.ts +18 -0
- package/templates/app/packages/domain/src/erp.ts +36 -0
- package/templates/app/packages/domain/src/index.ts +9 -0
- package/templates/app/packages/domain/src/inventory.ts +43 -0
- package/templates/app/packages/domain/src/jobs.ts +13 -0
- package/templates/app/packages/domain/src/purchase-order.test.ts +137 -0
- package/templates/app/packages/domain/src/purchase-order.ts +122 -0
- package/templates/app/packages/domain/src/queries.ts +10 -0
- package/templates/app/packages/domain/src/reactions.ts +24 -0
- package/templates/app/packages/domain/tsconfig.json +5 -0
- package/templates/app/pnpm-workspace.yaml +10 -0
- package/templates/app/renovate.json +5 -0
- package/templates/app/tsconfig.base.json +8 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// cage gen:从声明生成 contracts、路由清单、安全视图与策略 DDL、迁移草稿、状态图、本体图。
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { kebab } from '@yss123/cage-kernel';
|
|
5
|
+
import { createTableSql, diffSchemas, embedSnapshot, latestSnapshot, readMigrations, safeLayerSql, schemaModel, } from '@yss123/cage-kernel/db';
|
|
6
|
+
import { abs } from '../config.js';
|
|
7
|
+
import { statesHoldingResources } from '../rules.js';
|
|
8
|
+
import { contractsFiles } from './contracts.js';
|
|
9
|
+
export function stateDiagram(g, agg) {
|
|
10
|
+
const lines = ['stateDiagram-v2'];
|
|
11
|
+
const states = g.nodes.filter((n) => n.kind === 'state' && n.id.startsWith(`${agg}.`));
|
|
12
|
+
const short = (id) => id.slice(agg.length + 1);
|
|
13
|
+
for (const t of g.edges.filter((e) => e.kind === 'transition' && e.to.startsWith(`${agg}.`))) {
|
|
14
|
+
const from = t.from.endsWith('.[new]') ? '[*]' : short(t.from);
|
|
15
|
+
lines.push(` ${from} --> ${short(t.to)} : ${t.via.slice(agg.length + 1)}`);
|
|
16
|
+
}
|
|
17
|
+
for (const s of states)
|
|
18
|
+
if (s.attrs.terminal)
|
|
19
|
+
lines.push(` ${short(s.id)} --> [*]`);
|
|
20
|
+
for (const h of statesHoldingResources(g).filter((x) => x.state.startsWith(`${agg}.`))) {
|
|
21
|
+
lines.push(` note right of ${short(h.state)} : 持有 ${h.resource}`);
|
|
22
|
+
}
|
|
23
|
+
return lines.join('\n') + '\n';
|
|
24
|
+
}
|
|
25
|
+
function writeIf(path, content, check, written, findings, code = 'CAGE-GEN-001') {
|
|
26
|
+
const cur = existsSync(path) ? readFileSync(path, 'utf8') : null;
|
|
27
|
+
if (cur === content)
|
|
28
|
+
return;
|
|
29
|
+
if (check) {
|
|
30
|
+
findings.push({
|
|
31
|
+
code,
|
|
32
|
+
at: path,
|
|
33
|
+
reason: '生成物和声明不一致(有人手改了生成物,或声明改了没有重新生成)',
|
|
34
|
+
fix: '运行 cage gen,并提交生成结果',
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
39
|
+
writeFileSync(path, content);
|
|
40
|
+
written.push(path);
|
|
41
|
+
}
|
|
42
|
+
export function generate(cfg, reg, g, sites, opts = {}) {
|
|
43
|
+
const check = !!opts.check;
|
|
44
|
+
const written = [];
|
|
45
|
+
const findings = [];
|
|
46
|
+
const gen = abs(cfg, cfg.generated);
|
|
47
|
+
// 不入库的生成物:直接覆盖(check 模式不比较)
|
|
48
|
+
if (!check) {
|
|
49
|
+
const put = (rel, content) => {
|
|
50
|
+
const p = join(gen, rel);
|
|
51
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
52
|
+
writeFileSync(p, content);
|
|
53
|
+
written.push(p);
|
|
54
|
+
};
|
|
55
|
+
mkdirSync(abs(cfg, '.cage'), { recursive: true });
|
|
56
|
+
writeFileSync(abs(cfg, '.cage/ontology.json'), JSON.stringify(g, null, 2));
|
|
57
|
+
const model = schemaModel(reg);
|
|
58
|
+
put('sql/schema.sql', `-- 生成物:期望的表结构(不要手改)\n\n${model.tables.map(createTableSql).join('\n\n')}\n`);
|
|
59
|
+
put('sql/safe-layer.sql', `-- 生成物:安全层(函数、行级策略、安全视图),cage migrate 每次整体重建\n${safeLayerSql(reg)}\n`);
|
|
60
|
+
put('capabilities.json', JSON.stringify(reg.capabilityCatalog(), null, 2));
|
|
61
|
+
put('routes.json', JSON.stringify(routes(reg), null, 2));
|
|
62
|
+
const md = ['# 状态图(生成物)', ''];
|
|
63
|
+
for (const a of reg.aggregates) {
|
|
64
|
+
const d = stateDiagram(g, a.name);
|
|
65
|
+
put(`diagrams/${a.name}.mmd`, d);
|
|
66
|
+
md.push(`## ${a.description ?? a.name}(${a.name})`, '', '```mermaid', d.trimEnd(), '```', '');
|
|
67
|
+
}
|
|
68
|
+
put('diagrams/README.md', md.join('\n'));
|
|
69
|
+
}
|
|
70
|
+
// 入库的生成物:前端契约
|
|
71
|
+
const files = contractsFiles(reg, sites);
|
|
72
|
+
for (const [name, content] of Object.entries(files))
|
|
73
|
+
writeIf(join(abs(cfg, cfg.contracts), name), content, check, written, findings);
|
|
74
|
+
// 迁移草稿:声明的期望结构 vs 最后一个迁移里内嵌的结构快照
|
|
75
|
+
const dir = abs(cfg, cfg.migrations);
|
|
76
|
+
const migrations = readMigrations(dir);
|
|
77
|
+
const model = schemaModel(reg);
|
|
78
|
+
const stmts = diffSchemas(latestSnapshot(migrations), model);
|
|
79
|
+
let migrationDraft;
|
|
80
|
+
if (stmts.length > 0) {
|
|
81
|
+
if (check) {
|
|
82
|
+
findings.push({
|
|
83
|
+
code: 'CAGE-GEN-002',
|
|
84
|
+
at: cfg.migrations,
|
|
85
|
+
reason: `声明的表结构与迁移不一致(${stmts.length} 处变化)`,
|
|
86
|
+
fix: '运行 cage gen 生成迁移草稿,人审后提交',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const n = String(migrations.length + 1).padStart(4, '0');
|
|
91
|
+
const name = `${n}_${migrations.length === 0 ? 'init' : 'draft'}.sql`;
|
|
92
|
+
const body = [
|
|
93
|
+
`-- 迁移草稿:由 cage gen 生成,人审后提交;已发布的迁移不要修改`,
|
|
94
|
+
`-- 破坏性变更按「先扩展再收缩」分多次发布`,
|
|
95
|
+
'',
|
|
96
|
+
stmts.join('\n\n'),
|
|
97
|
+
].join('\n');
|
|
98
|
+
mkdirSync(dir, { recursive: true });
|
|
99
|
+
migrationDraft = join(dir, name);
|
|
100
|
+
writeFileSync(migrationDraft, embedSnapshot(body, model));
|
|
101
|
+
written.push(migrationDraft);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { written, findings, migrationDraft };
|
|
105
|
+
}
|
|
106
|
+
export function routes(reg) {
|
|
107
|
+
const out = [];
|
|
108
|
+
for (const c of reg.commands) {
|
|
109
|
+
if (!c.cmd.invokedBy.includes('user'))
|
|
110
|
+
continue;
|
|
111
|
+
const base = `/api/${kebab(c.cmd.agg.name)}`;
|
|
112
|
+
out.push({
|
|
113
|
+
method: 'POST',
|
|
114
|
+
url: c.cmd.from === 'new' ? `${base}/${kebab(c.name)}` : `${base}/:id/${kebab(c.name)}`,
|
|
115
|
+
capability: c.capability,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
for (const a of reg.aggregates) {
|
|
119
|
+
const base = `/api/${kebab(a.name)}`;
|
|
120
|
+
out.push({ method: 'GET', url: base, capability: `${a.name}.read` }, { method: 'GET', url: `${base}/:id`, capability: `${a.name}.read` }, { method: 'POST', url: `${base}/export`, capability: `${a.name}.export` });
|
|
121
|
+
}
|
|
122
|
+
for (const q of reg.queries)
|
|
123
|
+
out.push({
|
|
124
|
+
method: 'GET',
|
|
125
|
+
url: `/api/queries/${kebab(q.name)}`,
|
|
126
|
+
capability: q.reads.map((r) => `${r.name}.read`).join(' + '),
|
|
127
|
+
});
|
|
128
|
+
for (const e of reg.extensions)
|
|
129
|
+
if (e.kind === 'INBOUND')
|
|
130
|
+
out.push({
|
|
131
|
+
method: 'POST',
|
|
132
|
+
url: `/hooks/${e.value.connector.name}/${kebab(e.value.event)}`,
|
|
133
|
+
capability: `验签 ${e.value.verify.secret}`,
|
|
134
|
+
});
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gen/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AnyField, Fields } from '@yss123/cage-kernel';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare function zodCodeOf(schema: z.ZodType): string;
|
|
4
|
+
export declare function jsonToZod(s: any, root: any): string;
|
|
5
|
+
/** 读侧快照的字段 schema:敏感字段返回的是掩码值,所以只校验为字符串 */
|
|
6
|
+
export declare function fieldReadCode(f: AnyField): string;
|
|
7
|
+
export declare function snapshotCode(fields: Fields, states: readonly string[]): string;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const str = (s) => JSON.stringify(s);
|
|
3
|
+
export function zodCodeOf(schema) {
|
|
4
|
+
let js;
|
|
5
|
+
try {
|
|
6
|
+
js = z.toJSONSchema(schema, { unrepresentable: 'any', io: 'input' });
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return 'z.unknown()';
|
|
10
|
+
}
|
|
11
|
+
return jsonToZod(js, js);
|
|
12
|
+
}
|
|
13
|
+
function withChecks(base, s) {
|
|
14
|
+
let out = base;
|
|
15
|
+
if (s.type === 'string' || base.startsWith('z.string')) {
|
|
16
|
+
if (typeof s.minLength === 'number')
|
|
17
|
+
out += `.min(${s.minLength})`;
|
|
18
|
+
if (typeof s.maxLength === 'number')
|
|
19
|
+
out += `.max(${s.maxLength})`;
|
|
20
|
+
if (typeof s.pattern === 'string' && !s.format)
|
|
21
|
+
out += `.regex(new RegExp(${str(s.pattern)}))`;
|
|
22
|
+
}
|
|
23
|
+
if (s.type === 'number' || s.type === 'integer') {
|
|
24
|
+
if (typeof s.minimum === 'number')
|
|
25
|
+
out += `.min(${s.minimum})`;
|
|
26
|
+
if (typeof s.maximum === 'number')
|
|
27
|
+
out += `.max(${s.maximum})`;
|
|
28
|
+
if (typeof s.exclusiveMinimum === 'number')
|
|
29
|
+
out += `.gt(${s.exclusiveMinimum})`;
|
|
30
|
+
if (typeof s.exclusiveMaximum === 'number')
|
|
31
|
+
out += `.lt(${s.exclusiveMaximum})`;
|
|
32
|
+
}
|
|
33
|
+
if (s.type === 'array') {
|
|
34
|
+
if (typeof s.minItems === 'number')
|
|
35
|
+
out += `.min(${s.minItems})`;
|
|
36
|
+
if (typeof s.maxItems === 'number')
|
|
37
|
+
out += `.max(${s.maxItems})`;
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
export function jsonToZod(s, root) {
|
|
42
|
+
if (!s || typeof s !== 'object' || Object.keys(s).length === 0)
|
|
43
|
+
return 'z.unknown()';
|
|
44
|
+
if (s.$ref) {
|
|
45
|
+
const name = String(s.$ref).split('/').pop();
|
|
46
|
+
const def = root.$defs?.[name] ?? root.definitions?.[name];
|
|
47
|
+
return def ? jsonToZod(def, root) : 'z.unknown()';
|
|
48
|
+
}
|
|
49
|
+
if (s.const !== undefined)
|
|
50
|
+
return `z.literal(${JSON.stringify(s.const)})`;
|
|
51
|
+
if (Array.isArray(s.enum)) {
|
|
52
|
+
if (s.enum.every((v) => typeof v === 'string'))
|
|
53
|
+
return `z.enum([${s.enum.map(str).join(', ')}])`;
|
|
54
|
+
return `z.union([${s.enum.map((v) => `z.literal(${JSON.stringify(v)})`).join(', ')}])`;
|
|
55
|
+
}
|
|
56
|
+
const variants = s.anyOf ?? s.oneOf;
|
|
57
|
+
if (Array.isArray(variants)) {
|
|
58
|
+
const nonNull = variants.filter((v) => v.type !== 'null');
|
|
59
|
+
const nullable = nonNull.length !== variants.length;
|
|
60
|
+
const inner = nonNull.length === 1
|
|
61
|
+
? jsonToZod(nonNull[0], root)
|
|
62
|
+
: `z.union([${nonNull.map((v) => jsonToZod(v, root)).join(', ')}])`;
|
|
63
|
+
return nullable ? `${inner}.nullable()` : inner;
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(s.type)) {
|
|
66
|
+
const nonNull = s.type.filter((t) => t !== 'null');
|
|
67
|
+
const inner = nonNull.length === 1 ? jsonToZod({ ...s, type: nonNull[0] }, root) : 'z.unknown()';
|
|
68
|
+
return s.type.includes('null') ? `${inner}.nullable()` : inner;
|
|
69
|
+
}
|
|
70
|
+
switch (s.type) {
|
|
71
|
+
case 'string': {
|
|
72
|
+
if (s.format === 'uuid')
|
|
73
|
+
return 'z.string().uuid()';
|
|
74
|
+
if (s.format === 'email')
|
|
75
|
+
return withChecks('z.string().email()', { ...s, pattern: undefined });
|
|
76
|
+
if (s.format === 'date-time')
|
|
77
|
+
return 'z.string().datetime({ offset: true })';
|
|
78
|
+
return withChecks('z.string()', s);
|
|
79
|
+
}
|
|
80
|
+
case 'integer':
|
|
81
|
+
return withChecks('z.number().int()', s);
|
|
82
|
+
case 'number':
|
|
83
|
+
return withChecks('z.number()', s);
|
|
84
|
+
case 'boolean':
|
|
85
|
+
return 'z.boolean()';
|
|
86
|
+
case 'null':
|
|
87
|
+
return 'z.null()';
|
|
88
|
+
case 'array':
|
|
89
|
+
return withChecks(`z.array(${jsonToZod(s.items ?? {}, root)})`, s);
|
|
90
|
+
case 'object': {
|
|
91
|
+
const props = Object.entries(s.properties ?? {});
|
|
92
|
+
if (props.length === 0 && s.additionalProperties && typeof s.additionalProperties === 'object') {
|
|
93
|
+
return `z.record(z.string(), ${jsonToZod(s.additionalProperties, root)})`;
|
|
94
|
+
}
|
|
95
|
+
if (props.length === 0)
|
|
96
|
+
return 'z.record(z.string(), z.unknown())';
|
|
97
|
+
const req = new Set(s.required ?? []);
|
|
98
|
+
const body = props
|
|
99
|
+
.map(([k, v]) => `${/^[A-Za-z_$][\w$]*$/.test(k) ? k : str(k)}: ${jsonToZod(v, root)}${req.has(k) ? '' : '.optional()'}`)
|
|
100
|
+
.join(', ');
|
|
101
|
+
return `z.object({ ${body} })`;
|
|
102
|
+
}
|
|
103
|
+
default:
|
|
104
|
+
return 'z.unknown()';
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** 读侧快照的字段 schema:敏感字段返回的是掩码值,所以只校验为字符串 */
|
|
108
|
+
export function fieldReadCode(f) {
|
|
109
|
+
let base;
|
|
110
|
+
if (f.sensitiveKind)
|
|
111
|
+
base = 'z.string()';
|
|
112
|
+
else {
|
|
113
|
+
switch (f.kind) {
|
|
114
|
+
case 'int':
|
|
115
|
+
base = 'z.number().int()';
|
|
116
|
+
break;
|
|
117
|
+
case 'number':
|
|
118
|
+
base = 'z.number()';
|
|
119
|
+
break;
|
|
120
|
+
case 'bool':
|
|
121
|
+
base = 'z.boolean()';
|
|
122
|
+
break;
|
|
123
|
+
case 'id':
|
|
124
|
+
case 'ref':
|
|
125
|
+
base = 'z.string().uuid()';
|
|
126
|
+
break;
|
|
127
|
+
case 'enum':
|
|
128
|
+
base = `z.enum([${(f.values ?? []).map(str).join(', ')}])`;
|
|
129
|
+
break;
|
|
130
|
+
case 'list': {
|
|
131
|
+
const shape = f.shape ?? {};
|
|
132
|
+
if ('item' in shape && Object.keys(shape).length === 1)
|
|
133
|
+
base = `z.array(${fieldReadCode(shape.item)})`;
|
|
134
|
+
else if (Object.keys(shape).length === 0)
|
|
135
|
+
base = 'z.record(z.string(), z.unknown())';
|
|
136
|
+
else
|
|
137
|
+
base = `z.array(z.object({ ${Object.entries(shape)
|
|
138
|
+
.map(([k, sf]) => `${k}: ${fieldReadCode(sf)}`)
|
|
139
|
+
.join(', ')} }))`;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
default:
|
|
143
|
+
base = 'z.string()';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return f.isOptional ? `${base}.nullable().optional()` : base;
|
|
147
|
+
}
|
|
148
|
+
export function snapshotCode(fields, states) {
|
|
149
|
+
const lines = [
|
|
150
|
+
'id: z.string().uuid()',
|
|
151
|
+
...Object.entries(fields)
|
|
152
|
+
.filter(([, f]) => !f.isHidden)
|
|
153
|
+
.map(([k, f]) => `${k}: ${fieldReadCode(f)}`),
|
|
154
|
+
`status: z.enum([${states.map(str).join(', ')}])`,
|
|
155
|
+
'version: z.number().int()',
|
|
156
|
+
'createdAt: z.string()',
|
|
157
|
+
'updatedAt: z.string()',
|
|
158
|
+
];
|
|
159
|
+
return `z.object({\n${lines.map((l) => ` ${l},`).join('\n')}\n})`;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=zod-code.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zod-code.js","sourceRoot":"","sources":["../../src/gen/zod-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Finding } from './findings.js';
|
|
2
|
+
import type { Ontology } from './ontology.js';
|
|
3
|
+
export interface GraphSnapshot {
|
|
4
|
+
project: string;
|
|
5
|
+
domain: string;
|
|
6
|
+
generatedAt: string;
|
|
7
|
+
graph: Ontology;
|
|
8
|
+
findings: Finding[];
|
|
9
|
+
presentation: {
|
|
10
|
+
title: string;
|
|
11
|
+
labels: Record<string, string>;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// 图谱每次刷新都在独立进程抽取。ESM 会缓存 domain 及其依赖;只给入口添加
|
|
2
|
+
// 时间戳无法刷新所有间接导入,因此不在常驻 Web 服务里重复 import domain。
|
|
3
|
+
import { analyze } from './analyze.js';
|
|
4
|
+
import { loadConfig } from './config.js';
|
|
5
|
+
async function collect() {
|
|
6
|
+
const cfg = loadConfig(process.argv[2]);
|
|
7
|
+
const result = await analyze(cfg, { write: true });
|
|
8
|
+
if (!result.graph) {
|
|
9
|
+
throw new Error(result.findings.map((f) => `[${f.code}] ${f.reason}`).join('\n'));
|
|
10
|
+
}
|
|
11
|
+
// 优先复用声明已有的描述。图谱文案单独传递,不给本体节点改名或改哈希,
|
|
12
|
+
// 避免一次中文标题调整被误认为命令、能力点或数据库结构发生变化。
|
|
13
|
+
const labels = {};
|
|
14
|
+
const remember = (kind, id, description) => {
|
|
15
|
+
if (description)
|
|
16
|
+
labels[`${kind}:${id}`] = description;
|
|
17
|
+
};
|
|
18
|
+
const registry = result.registry;
|
|
19
|
+
for (const a of registry.aggregates)
|
|
20
|
+
remember('aggregate', a.name, a.description);
|
|
21
|
+
for (const c of registry.commands)
|
|
22
|
+
remember('command', c.capability, c.cmd.description);
|
|
23
|
+
for (const e of registry.events)
|
|
24
|
+
remember('event', e.name, e.description);
|
|
25
|
+
for (const q of registry.queries)
|
|
26
|
+
remember('query', q.name, q.description);
|
|
27
|
+
for (const j of registry.jobs)
|
|
28
|
+
remember('job', j.name, j.description);
|
|
29
|
+
// 有图规则问题时仍展示图和问题列表,开发者可以借助关系图定位错误。
|
|
30
|
+
const snapshot = {
|
|
31
|
+
project: cfg.name,
|
|
32
|
+
domain: cfg.domain,
|
|
33
|
+
generatedAt: new Date().toISOString(),
|
|
34
|
+
graph: result.graph,
|
|
35
|
+
findings: result.findings,
|
|
36
|
+
presentation: { title: cfg.graph?.title ?? cfg.name, labels: { ...labels, ...cfg.graph?.labels } },
|
|
37
|
+
};
|
|
38
|
+
process.send({ snapshot });
|
|
39
|
+
}
|
|
40
|
+
collect()
|
|
41
|
+
.catch((error) => {
|
|
42
|
+
process.send({ error: error.message });
|
|
43
|
+
process.exitCode = 1;
|
|
44
|
+
})
|
|
45
|
+
.finally(() => process.disconnect());
|
|
46
|
+
//# sourceMappingURL=graph-snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-snapshot.js","sourceRoot":"","sources":["../src/graph-snapshot.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,gDAAgD;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAazC,KAAK,UAAU,OAAO;IACpB,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACpF,CAAC;IACD,qCAAqC;IACrC,kCAAkC;IAClC,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAU,EAAE,WAAoB,EAAE,EAAE;QAClE,IAAI,WAAW;YAAE,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC,GAAG,WAAW,CAAC;IACzD,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAS,CAAC;IAClC,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,UAAU;QAAE,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAClF,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ;QAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACxF,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,MAAM;QAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1E,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,OAAO;QAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAC3E,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,IAAI;QAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IACtE,mCAAmC;IACnC,MAAM,QAAQ,GAAkB;QAC9B,OAAO,EAAE,GAAG,CAAC,IAAI;QACjB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,YAAY,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;KACnG,CAAC;IACF,OAAO,CAAC,IAAK,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED,OAAO,EAAE;KACN,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;IACtB,OAAO,CAAC,IAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC;KACD,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC"}
|
package/dist/graph.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CageConfig } from './config.js';
|
|
2
|
+
import type { GraphSnapshot } from './graph-snapshot.js';
|
|
3
|
+
/** 只采集声明元数据,不连接业务数据库。子进程的 IPC 把日志和 JSON 分开,
|
|
4
|
+
* domain 的普通日志不会污染响应,也不会把进程环境变量发送给浏览器。 */
|
|
5
|
+
export declare function collectGraph(root: string): Promise<GraphSnapshot>;
|
|
6
|
+
/** 本地开发工具只监听回环地址;固定路由表不接受文件路径,不能拿来读取
|
|
7
|
+
* 项目的 .env、源码或任意本机文件。它不挂载到业务 API 或生产 /admin。 */
|
|
8
|
+
export declare function serveGraph(cfg: CageConfig, port?: number): Promise<{
|
|
9
|
+
server: import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>;
|
|
10
|
+
url: string;
|
|
11
|
+
}>;
|
package/dist/graph.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { fork } from 'node:child_process';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { createServer } from 'node:http';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
/** 只采集声明元数据,不连接业务数据库。子进程的 IPC 把日志和 JSON 分开,
|
|
6
|
+
* domain 的普通日志不会污染响应,也不会把进程环境变量发送给浏览器。 */
|
|
7
|
+
export function collectGraph(root) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const child = fork(fileURLToPath(new URL('./graph-snapshot.js', import.meta.url)), [root], {
|
|
10
|
+
windowsHide: true,
|
|
11
|
+
stdio: ['ignore', 'ignore', 'pipe', 'ipc'],
|
|
12
|
+
});
|
|
13
|
+
let failure = '';
|
|
14
|
+
child.stderr.on('data', (chunk) => {
|
|
15
|
+
failure += String(chunk);
|
|
16
|
+
});
|
|
17
|
+
child.once('message', (message) => {
|
|
18
|
+
if (message.snapshot)
|
|
19
|
+
resolve(message.snapshot);
|
|
20
|
+
else
|
|
21
|
+
reject(new Error(message.error));
|
|
22
|
+
});
|
|
23
|
+
child.once('error', reject);
|
|
24
|
+
child.once('exit', (code) => reject(new Error(failure || `本体抽取进程退出(${code})`)));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** 本地开发工具只监听回环地址;固定路由表不接受文件路径,不能拿来读取
|
|
28
|
+
* 项目的 .env、源码或任意本机文件。它不挂载到业务 API 或生产 /admin。 */
|
|
29
|
+
export async function serveGraph(cfg, port = 15418) {
|
|
30
|
+
let snapshot = await collectGraph(cfg.root);
|
|
31
|
+
let refreshing;
|
|
32
|
+
const assets = new Map([
|
|
33
|
+
['/', ['index.html', 'text/html; charset=utf-8']],
|
|
34
|
+
['/app.js', ['app.js', 'text/javascript; charset=utf-8']],
|
|
35
|
+
['/model.js', ['model.js', 'text/javascript; charset=utf-8']],
|
|
36
|
+
['/relations.js', ['relations.js', 'text/javascript; charset=utf-8']],
|
|
37
|
+
['/structure.js', ['structure.js', 'text/javascript; charset=utf-8']],
|
|
38
|
+
['/style.css', ['style.css', 'text/css; charset=utf-8']],
|
|
39
|
+
]);
|
|
40
|
+
let origin = '';
|
|
41
|
+
const server = createServer(async (req, res) => {
|
|
42
|
+
res.setHeader('Cache-Control', 'no-store');
|
|
43
|
+
res.setHeader('X-Content-Type-Options', 'nosniff');
|
|
44
|
+
res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data:; object-src 'none'; base-uri 'none'; frame-ancestors 'none'");
|
|
45
|
+
const json = (status, data) => {
|
|
46
|
+
res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8' });
|
|
47
|
+
res.end(JSON.stringify(data));
|
|
48
|
+
};
|
|
49
|
+
// 限制 Host 和刷新来源,避免其他网站借用户浏览器触发本地模块求值。
|
|
50
|
+
if (req.headers.host !== new URL(origin).host)
|
|
51
|
+
return json(403, { error: '请使用终端输出的本地地址访问' });
|
|
52
|
+
const path = new URL(req.url, origin).pathname;
|
|
53
|
+
try {
|
|
54
|
+
if (req.method === 'GET' && path === '/api/graph')
|
|
55
|
+
return json(200, snapshot);
|
|
56
|
+
if (req.method === 'POST' && path === '/api/refresh') {
|
|
57
|
+
if (req.headers.origin !== origin)
|
|
58
|
+
return json(403, { error: '刷新必须由本地图谱页面发起' });
|
|
59
|
+
// 同时点击刷新共享一次抽取;失败向页面报告,不伪装成新图。
|
|
60
|
+
refreshing ??= collectGraph(cfg.root).finally(() => {
|
|
61
|
+
refreshing = undefined;
|
|
62
|
+
});
|
|
63
|
+
snapshot = await refreshing;
|
|
64
|
+
return json(200, snapshot);
|
|
65
|
+
}
|
|
66
|
+
const asset = req.method === 'GET' ? assets.get(path) : undefined;
|
|
67
|
+
if (!asset)
|
|
68
|
+
return json(404, { error: '页面不存在' });
|
|
69
|
+
const content = await readFile(new URL(`../graph-ui/${asset[0]}`, import.meta.url));
|
|
70
|
+
res.writeHead(200, { 'Content-Type': asset[1] });
|
|
71
|
+
res.end(content);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
json(500, { error: error.message });
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
await new Promise((resolve, reject) => {
|
|
78
|
+
server.once('error', reject);
|
|
79
|
+
server.listen(port, '127.0.0.1', () => {
|
|
80
|
+
const address = server.address();
|
|
81
|
+
origin = `http://127.0.0.1:${address.port}`;
|
|
82
|
+
resolve();
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
return { server, url: origin };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
|
package/dist/impact.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DerivedTest } from './derive.js';
|
|
2
|
+
import { type NodeDiff, type Ontology } from './ontology.js';
|
|
3
|
+
import type { Finding } from './findings.js';
|
|
4
|
+
export interface ImpactResult {
|
|
5
|
+
diff: NodeDiff;
|
|
6
|
+
start: string[];
|
|
7
|
+
affected: string[];
|
|
8
|
+
/** 受影响节点 → 通过哪条边、以什么身份受影响 */
|
|
9
|
+
reasons: Map<string, string>;
|
|
10
|
+
tests: DerivedTest[];
|
|
11
|
+
projectTests: string[];
|
|
12
|
+
confirm: string[];
|
|
13
|
+
unsafe: {
|
|
14
|
+
base: number;
|
|
15
|
+
head: number;
|
|
16
|
+
};
|
|
17
|
+
findings: Finding[];
|
|
18
|
+
}
|
|
19
|
+
export declare function isGitRepo(root: string): boolean;
|
|
20
|
+
export declare function changedFiles(root: string, base: string): string[];
|
|
21
|
+
export declare function readOntology(path: string): Ontology;
|
|
22
|
+
export declare function impact(base: Ontology, head: Ontology, files: string[], tests?: DerivedTest[], projectTestFiles?: string[]): ImpactResult;
|
|
23
|
+
export declare function formatImpact(r: ImpactResult, head: Ontology, opts: {
|
|
24
|
+
base: string;
|
|
25
|
+
format: 'text' | 'md';
|
|
26
|
+
title?: string;
|
|
27
|
+
gates?: string;
|
|
28
|
+
}): string;
|