@topogram/cli 0.3.54 → 0.3.56
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/CHANGELOG.md +18 -0
- package/package.json +1 -1
- package/src/adoption/review-groups.js +3 -3
- package/src/agent-ops/query-builders.js +34 -34
- package/src/archive/schema.js +1 -1
- package/src/cli.js +173 -20
- package/src/generator/adapters.js +23 -7
- package/src/generator/context/domain-coverage.js +2 -2
- package/src/generator/context/shared.js +6 -22
- package/src/generator/context/slice.js +10 -10
- package/src/generator/docs.js +1 -1
- package/src/generator/registry.js +1 -1
- package/src/generator/runtime/app-bundle.js +8 -6
- package/src/generator/runtime/compile-check.js +7 -5
- package/src/generator/runtime/deployment.js +6 -4
- package/src/generator/runtime/environment.js +31 -28
- package/src/generator/runtime/shared.js +53 -39
- package/src/generator/surfaces/contracts.js +1 -1
- package/src/generator/surfaces/databases/index.js +5 -3
- package/src/generator/surfaces/databases/lifecycle-shared.js +1 -1
- package/src/generator/surfaces/databases/postgres/drizzle.js +1 -1
- package/src/generator/surfaces/databases/postgres/prisma.js +1 -1
- package/src/generator/surfaces/databases/shared.js +3 -3
- package/src/generator/surfaces/databases/sqlite/prisma.js +1 -1
- package/src/generator/surfaces/index.js +5 -3
- package/src/generator/surfaces/services/index.js +10 -6
- package/src/generator/surfaces/services/persistence-wiring.js +1 -1
- package/src/generator/surfaces/services/server-contract.js +1 -1
- package/src/generator/surfaces/shared.js +1 -1
- package/src/generator/surfaces/web/index.js +5 -3
- package/src/generator/surfaces/web/ui-surface-contract.js +1 -1
- package/src/generator/widget-conformance.js +6 -6
- package/src/generator/widgets.js +1 -1
- package/src/generator-policy.js +10 -10
- package/src/import/core/runner.js +60 -50
- package/src/project-config.js +5 -42
- package/src/proofs/contract-audit.js +1 -1
- package/src/realization/backend/build-backend-runtime-realization.js +3 -3
- package/src/realization/ui/build-ui-shared-realization.js +9 -9
- package/src/realization/ui/build-web-realization.js +3 -3
- package/src/reconcile/journeys.js +1 -1
- package/src/resolver/enrich/widget.js +2 -2
- package/src/resolver/index.js +4 -23
- package/src/validator/index.js +10 -10
- package/src/workflows.js +49 -49
|
@@ -27,8 +27,10 @@ import { defaultProjectConfigForGraph, validateProjectConfig } from "../../proje
|
|
|
27
27
|
* @property {string|null} [api]
|
|
28
28
|
* @property {string|null} [database]
|
|
29
29
|
* @property {Record<string, string>} [env]
|
|
30
|
-
* @property {RuntimeComponent|null} [
|
|
31
|
-
* @property {RuntimeComponent|null} [
|
|
30
|
+
* @property {RuntimeComponent|null} [apiRuntime]
|
|
31
|
+
* @property {RuntimeComponent|null} [databaseRuntime]
|
|
32
|
+
* @property {RuntimeComponent|null} [apiComponent] Legacy adapter alias for apiRuntime.
|
|
33
|
+
* @property {RuntimeComponent|null} [databaseComponent] Legacy adapter alias for databaseRuntime.
|
|
32
34
|
*/
|
|
33
35
|
|
|
34
36
|
/**
|
|
@@ -39,10 +41,13 @@ import { defaultProjectConfigForGraph, validateProjectConfig } from "../../proje
|
|
|
39
41
|
* @typedef {Object} RuntimeTopology
|
|
40
42
|
* @property {import("../../project-config.js").ProjectConfig} config
|
|
41
43
|
* @property {RuntimeComponent[]} runtimes
|
|
42
|
-
* @property {RuntimeComponent[]}
|
|
43
|
-
* @property {RuntimeComponent[]}
|
|
44
|
-
* @property {RuntimeComponent[]}
|
|
45
|
-
* @property {RuntimeComponent[]}
|
|
44
|
+
* @property {RuntimeComponent[]} apiRuntimes
|
|
45
|
+
* @property {RuntimeComponent[]} webRuntimes
|
|
46
|
+
* @property {RuntimeComponent[]} dbRuntimes
|
|
47
|
+
* @property {RuntimeComponent[]} components Legacy alias for runtimes.
|
|
48
|
+
* @property {RuntimeComponent[]} apiComponents Legacy alias for apiRuntimes.
|
|
49
|
+
* @property {RuntimeComponent[]} webComponents Legacy alias for webRuntimes.
|
|
50
|
+
* @property {RuntimeComponent[]} dbComponents Legacy alias for dbRuntimes.
|
|
46
51
|
* @property {RuntimeComponent|null} primaryApi
|
|
47
52
|
* @property {RuntimeComponent|null} primaryWeb
|
|
48
53
|
* @property {RuntimeComponent|null} primaryDb
|
|
@@ -65,7 +70,8 @@ import { defaultProjectConfigForGraph, validateProjectConfig } from "../../proje
|
|
|
65
70
|
* @property {string} [dbProjectionId]
|
|
66
71
|
* @property {string} [configDir]
|
|
67
72
|
* @property {string} [projectRoot]
|
|
68
|
-
* @property {RuntimeComponent} [
|
|
73
|
+
* @property {RuntimeComponent} [runtime]
|
|
74
|
+
* @property {RuntimeComponent} [component] Legacy alias for runtime.
|
|
69
75
|
*/
|
|
70
76
|
|
|
71
77
|
/**
|
|
@@ -229,7 +235,7 @@ function apiProjectionCandidates(graph) {
|
|
|
229
235
|
*/
|
|
230
236
|
function uiWebProjectionCandidates(graph) {
|
|
231
237
|
return (graph.byKind.projection || []).filter(
|
|
232
|
-
(projection) => projection.
|
|
238
|
+
(projection) => projection.type === "web_surface" && (projection.uiRoutes || []).length > 0
|
|
233
239
|
);
|
|
234
240
|
}
|
|
235
241
|
|
|
@@ -247,7 +253,7 @@ const DEFAULT_NATIVE_UI_PLATFORM_ORDER = ["proj_ios_surface__swiftui"];
|
|
|
247
253
|
*/
|
|
248
254
|
function uiIosProjectionCandidates(graph) {
|
|
249
255
|
return (graph.byKind.projection || []).filter(
|
|
250
|
-
(projection) => projection.
|
|
256
|
+
(projection) => projection.type === "ios_surface" && (projection.uiRoutes || []).length > 0
|
|
251
257
|
);
|
|
252
258
|
}
|
|
253
259
|
|
|
@@ -300,7 +306,7 @@ export function pickDefaultUiWebProjection(graph) {
|
|
|
300
306
|
*/
|
|
301
307
|
export function getDefaultEnvironmentProjections(graph, options = {}) {
|
|
302
308
|
const topology = resolveRuntimeTopology(graph, options);
|
|
303
|
-
const dbCandidates = graph.byKind.projection?.filter((projection) => ["db_contract", "db_contract"].includes(projection.
|
|
309
|
+
const dbCandidates = graph.byKind.projection?.filter((projection) => ["db_contract", "db_contract"].includes(projection.type)) || [];
|
|
304
310
|
const apiProjection = /** @type {RuntimeStatement|null} */ (topology.primaryApi?.projection ||
|
|
305
311
|
(options.projectionId ? getProjection(graph, options.projectionId) : null) ||
|
|
306
312
|
apiProjectionCandidates(graph).find((projection) => projection.id === "proj_api") ||
|
|
@@ -327,14 +333,15 @@ export function getDefaultEnvironmentProjections(graph, options = {}) {
|
|
|
327
333
|
*/
|
|
328
334
|
export function generateServerBundle(graph, projectionId, options = {}) {
|
|
329
335
|
const topology = resolveRuntimeTopology(graph, options);
|
|
330
|
-
const
|
|
331
|
-
if (!
|
|
332
|
-
throw new Error(`No api
|
|
336
|
+
const runtime = options.runtime || options.component || topology.apiRuntimes.find((entry) => entry.projection.id === projectionId);
|
|
337
|
+
if (!runtime) {
|
|
338
|
+
throw new Error(`No api runtime found for projection '${projectionId}'`);
|
|
333
339
|
}
|
|
334
340
|
return generateWithComponentGenerator({
|
|
335
341
|
graph,
|
|
336
|
-
projection:
|
|
337
|
-
|
|
342
|
+
projection: runtime.projection,
|
|
343
|
+
runtime,
|
|
344
|
+
component: runtime,
|
|
338
345
|
topology,
|
|
339
346
|
implementation: options.implementation || null,
|
|
340
347
|
options: { ...options, projectionId }
|
|
@@ -349,14 +356,15 @@ export function generateServerBundle(graph, projectionId, options = {}) {
|
|
|
349
356
|
*/
|
|
350
357
|
export function generateWebBundle(graph, projectionId, options = {}) {
|
|
351
358
|
const topology = resolveRuntimeTopology(graph, options);
|
|
352
|
-
const
|
|
353
|
-
if (!
|
|
354
|
-
throw new Error(`No web
|
|
359
|
+
const runtime = options.runtime || options.component || topology.webRuntimes.find((entry) => entry.projection.id === projectionId);
|
|
360
|
+
if (!runtime) {
|
|
361
|
+
throw new Error(`No web runtime found for projection '${projectionId}'`);
|
|
355
362
|
}
|
|
356
363
|
return generateWithComponentGenerator({
|
|
357
364
|
graph,
|
|
358
|
-
projection:
|
|
359
|
-
|
|
365
|
+
projection: runtime.projection,
|
|
366
|
+
runtime,
|
|
367
|
+
component: runtime,
|
|
360
368
|
topology,
|
|
361
369
|
implementation: options.implementation || null,
|
|
362
370
|
options: { ...options, projectionId }
|
|
@@ -371,14 +379,15 @@ export function generateWebBundle(graph, projectionId, options = {}) {
|
|
|
371
379
|
*/
|
|
372
380
|
export function generateDbBundle(graph, projectionId, options = {}) {
|
|
373
381
|
const topology = resolveRuntimeTopology(graph, options);
|
|
374
|
-
const
|
|
375
|
-
if (!
|
|
376
|
-
throw new Error(`No database
|
|
382
|
+
const runtime = options.runtime || options.component || topology.dbRuntimes.find((entry) => entry.projection.id === projectionId);
|
|
383
|
+
if (!runtime) {
|
|
384
|
+
throw new Error(`No database runtime found for projection '${projectionId}'`);
|
|
377
385
|
}
|
|
378
386
|
return generateWithComponentGenerator({
|
|
379
387
|
graph,
|
|
380
388
|
projection: getProjection(graph, projectionId),
|
|
381
|
-
|
|
389
|
+
runtime,
|
|
390
|
+
component: runtime,
|
|
382
391
|
topology,
|
|
383
392
|
implementation: options.implementation || null,
|
|
384
393
|
options: { ...options, projectionId }
|
|
@@ -426,22 +435,24 @@ export function dbEnvVarsForComponent(component, options = {}) {
|
|
|
426
435
|
*/
|
|
427
436
|
function decorateRuntimes(graph, config) {
|
|
428
437
|
const byProjectionId = new Map((graph.byKind.projection || []).map((projection) => [projection.id, projection]));
|
|
429
|
-
const rawRuntimes = config.topology?.runtimes ||
|
|
438
|
+
const rawRuntimes = config.topology?.runtimes || [];
|
|
430
439
|
/** @type {RuntimeComponent[]} */
|
|
431
440
|
const runtimes = rawRuntimes.map((runtime) => ({
|
|
432
441
|
...runtime,
|
|
433
|
-
kind: runtime.kind ||
|
|
434
|
-
api: runtime.uses_api ??
|
|
435
|
-
database: runtime.uses_database ??
|
|
442
|
+
kind: runtime.kind || null,
|
|
443
|
+
api: runtime.uses_api ?? null,
|
|
444
|
+
database: runtime.uses_database ?? null,
|
|
436
445
|
projection: byProjectionId.get(runtime.projection) || {}
|
|
437
446
|
}));
|
|
438
447
|
const byId = new Map(runtimes.map((runtime) => [runtime.id, runtime]));
|
|
439
448
|
for (const runtime of runtimes) {
|
|
440
449
|
if (runtime.kind === "api_service" && runtime.database) {
|
|
441
|
-
runtime.
|
|
450
|
+
runtime.databaseRuntime = byId.get(runtime.database) || null;
|
|
451
|
+
runtime.databaseComponent = runtime.databaseRuntime;
|
|
442
452
|
}
|
|
443
453
|
if (runtime.kind === "web_surface" && runtime.api) {
|
|
444
|
-
runtime.
|
|
454
|
+
runtime.apiRuntime = byId.get(runtime.api) || null;
|
|
455
|
+
runtime.apiComponent = runtime.apiRuntime;
|
|
445
456
|
}
|
|
446
457
|
}
|
|
447
458
|
return runtimes;
|
|
@@ -462,20 +473,23 @@ export function resolveRuntimeTopology(graph, options = {}) {
|
|
|
462
473
|
throw new Error(validation.errors.map((error) => error.message).join("\n"));
|
|
463
474
|
}
|
|
464
475
|
const runtimes = decorateRuntimes(graph, config);
|
|
465
|
-
const
|
|
466
|
-
const
|
|
467
|
-
const
|
|
468
|
-
const primaryApi =
|
|
469
|
-
const primaryWeb =
|
|
470
|
-
const primaryDb = primaryApi?.
|
|
476
|
+
const apiRuntimes = runtimes.filter((runtime) => runtime.kind === "api_service");
|
|
477
|
+
const webRuntimes = runtimes.filter((runtime) => runtime.kind === "web_surface");
|
|
478
|
+
const dbRuntimes = runtimes.filter((runtime) => runtime.kind === "database");
|
|
479
|
+
const primaryApi = apiRuntimes[0] || null;
|
|
480
|
+
const primaryWeb = webRuntimes[0] || null;
|
|
481
|
+
const primaryDb = primaryApi?.databaseRuntime || dbRuntimes[0] || null;
|
|
471
482
|
|
|
472
483
|
return {
|
|
473
484
|
config,
|
|
474
485
|
runtimes,
|
|
475
486
|
components: runtimes,
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
487
|
+
apiRuntimes,
|
|
488
|
+
webRuntimes,
|
|
489
|
+
dbRuntimes,
|
|
490
|
+
apiComponents: apiRuntimes,
|
|
491
|
+
webComponents: webRuntimes,
|
|
492
|
+
dbComponents: dbRuntimes,
|
|
479
493
|
primaryApi,
|
|
480
494
|
primaryWeb,
|
|
481
495
|
primaryDb,
|
|
@@ -17,7 +17,7 @@ export function generateUiContractDebug(graph, options = {}) {
|
|
|
17
17
|
for (const contract of contracts) {
|
|
18
18
|
lines.push(`## \`${contract.projection.id}\` - ${contract.projection.name}`);
|
|
19
19
|
lines.push("");
|
|
20
|
-
lines.push(`
|
|
20
|
+
lines.push(`Projection type: \`${contract.projection.type}\``);
|
|
21
21
|
lines.push(`Realizes: ${refList(contract.realizes)}`);
|
|
22
22
|
lines.push(`Outputs: ${symbolList(contract.outputs)}`);
|
|
23
23
|
if (contract.appShell) {
|
|
@@ -57,11 +57,13 @@ export function generateDbTarget(target, graph, options = {}) {
|
|
|
57
57
|
: generatePostgresDbLifecyclePlan(graph, options);
|
|
58
58
|
}
|
|
59
59
|
if (target === "db-lifecycle-bundle") {
|
|
60
|
-
|
|
60
|
+
const runtime = options.runtime || options.component;
|
|
61
|
+
if (runtime?.generator?.id) {
|
|
61
62
|
return generateWithComponentGenerator({
|
|
62
63
|
graph,
|
|
63
|
-
projection:
|
|
64
|
-
|
|
64
|
+
projection: runtime.projection,
|
|
65
|
+
runtime,
|
|
66
|
+
component: runtime,
|
|
65
67
|
topology: options.topology || null,
|
|
66
68
|
implementation: options.implementation || null,
|
|
67
69
|
options
|
|
@@ -87,7 +87,7 @@ function renderEmptySnapshotForProjection(projection) {
|
|
|
87
87
|
projection: {
|
|
88
88
|
id: projection.id,
|
|
89
89
|
name: projection.name || projection.id,
|
|
90
|
-
type: projection.type || projection.
|
|
90
|
+
type: projection.type || projection.type
|
|
91
91
|
},
|
|
92
92
|
profile,
|
|
93
93
|
generatorDefaults: generatorDefaultsMap(projection),
|
|
@@ -50,7 +50,7 @@ function drizzleColumnBuilder(column, relation, targetTableVar) {
|
|
|
50
50
|
export function generatePostgresDrizzleSchema(graph, options = {}) {
|
|
51
51
|
resolvePostgresCapabilities(options.profileId);
|
|
52
52
|
const projection = getProjection(graph, options.projectionId);
|
|
53
|
-
const projectionType = projection.type || projection.
|
|
53
|
+
const projectionType = projection.type || projection.type;
|
|
54
54
|
if (projectionType !== "db_contract") {
|
|
55
55
|
throw new Error(`Drizzle schema generation currently supports db_contract projections only, found '${projectionType}'`);
|
|
56
56
|
}
|
|
@@ -40,7 +40,7 @@ function prismaDefaultForColumn(column, byId) {
|
|
|
40
40
|
export function generatePostgresPrismaSchema(graph, options = {}) {
|
|
41
41
|
resolvePostgresCapabilities(options.profileId);
|
|
42
42
|
const projection = getProjection(graph, options.projectionId);
|
|
43
|
-
const projectionType = projection.type || projection.
|
|
43
|
+
const projectionType = projection.type || projection.type;
|
|
44
44
|
if (projectionType !== "db_contract") {
|
|
45
45
|
throw new Error(`Prisma schema generation currently supports db_contract projections only, found '${projectionType}'`);
|
|
46
46
|
}
|
|
@@ -42,8 +42,8 @@ export function indexGraphStatements(graph) {
|
|
|
42
42
|
export function dbProjectionCandidates(graph) {
|
|
43
43
|
return (graph.byKind.projection || []).filter(
|
|
44
44
|
(projection) =>
|
|
45
|
-
(projection.type || projection.
|
|
46
|
-
projection.
|
|
45
|
+
(projection.type || projection.type) === "db_contract" ||
|
|
46
|
+
projection.type?.startsWith("db_") ||
|
|
47
47
|
(projection.dbTables || []).length > 0 ||
|
|
48
48
|
(projection.dbColumns || []).length > 0 ||
|
|
49
49
|
(projection.dbRelations || []).length > 0
|
|
@@ -278,7 +278,7 @@ export function buildDbProjectionContract(graph, projection) {
|
|
|
278
278
|
projection: {
|
|
279
279
|
id: projection.id,
|
|
280
280
|
name: projection.name || projection.id,
|
|
281
|
-
type: projection.type || projection.
|
|
281
|
+
type: projection.type || projection.type
|
|
282
282
|
},
|
|
283
283
|
profile: dbProfileForProjection(projection),
|
|
284
284
|
generatorDefaults: generatorDefaultsMap(projection),
|
|
@@ -45,7 +45,7 @@ function prismaDefaultForColumn(column) {
|
|
|
45
45
|
export function generateSqlitePrismaSchema(graph, options = {}) {
|
|
46
46
|
resolveSqliteCapabilities(options.profileId);
|
|
47
47
|
const projection = getProjection(graph, options.projectionId);
|
|
48
|
-
const projectionType = projection.type || projection.
|
|
48
|
+
const projectionType = projection.type || projection.type;
|
|
49
49
|
if (projectionType !== "db_contract") {
|
|
50
50
|
throw new Error(`Prisma schema generation currently supports db_contract projections only, found '${projectionType}'`);
|
|
51
51
|
}
|
|
@@ -8,11 +8,13 @@ export function generateAppTarget(target, graph, options = {}) {
|
|
|
8
8
|
return generateBackendTarget(target, graph, options);
|
|
9
9
|
}
|
|
10
10
|
if (target === "swiftui-app") {
|
|
11
|
-
|
|
11
|
+
const runtime = options.runtime || options.component;
|
|
12
|
+
if (runtime?.generator?.id) {
|
|
12
13
|
return generateWithComponentGenerator({
|
|
13
14
|
graph,
|
|
14
|
-
projection:
|
|
15
|
-
|
|
15
|
+
projection: runtime.projection,
|
|
16
|
+
runtime,
|
|
17
|
+
component: runtime,
|
|
16
18
|
topology: options.topology || null,
|
|
17
19
|
implementation: options.implementation || null,
|
|
18
20
|
options
|
|
@@ -12,11 +12,13 @@ export function generateBackendTarget(target, graph, options = {}) {
|
|
|
12
12
|
return generatePersistenceScaffold(graph, options);
|
|
13
13
|
}
|
|
14
14
|
if (target === "hono-server") {
|
|
15
|
-
|
|
15
|
+
const runtime = options.runtime || options.component;
|
|
16
|
+
if (runtime?.generator?.id) {
|
|
16
17
|
return generateWithComponentGenerator({
|
|
17
18
|
graph,
|
|
18
|
-
projection:
|
|
19
|
-
|
|
19
|
+
projection: runtime.projection,
|
|
20
|
+
runtime,
|
|
21
|
+
component: runtime,
|
|
20
22
|
topology: options.topology || null,
|
|
21
23
|
implementation: options.implementation || null,
|
|
22
24
|
options
|
|
@@ -25,11 +27,13 @@ export function generateBackendTarget(target, graph, options = {}) {
|
|
|
25
27
|
return generateHonoServer(graph, options);
|
|
26
28
|
}
|
|
27
29
|
if (target === "express-server") {
|
|
28
|
-
|
|
30
|
+
const runtime = options.runtime || options.component;
|
|
31
|
+
if (runtime?.generator?.id) {
|
|
29
32
|
return generateWithComponentGenerator({
|
|
30
33
|
graph,
|
|
31
|
-
projection:
|
|
32
|
-
|
|
34
|
+
projection: runtime.projection,
|
|
35
|
+
runtime,
|
|
36
|
+
component: runtime,
|
|
33
37
|
topology: options.topology || null,
|
|
34
38
|
implementation: options.implementation || null,
|
|
35
39
|
options
|
|
@@ -155,7 +155,7 @@ export function generatePersistenceScaffold(graph, options = {}) {
|
|
|
155
155
|
const drizzleRepositoryClassName = repositoryReference.drizzleRepositoryClassName;
|
|
156
156
|
const drizzleHint = repositoryReference.drizzleHint;
|
|
157
157
|
const projection = getProjection(graph, options.projectionId);
|
|
158
|
-
const projectionType = projection.type || projection.
|
|
158
|
+
const projectionType = projection.type || projection.type;
|
|
159
159
|
if (projectionType !== "db_contract") {
|
|
160
160
|
throw new Error(`Persistence scaffold generation currently supports db_contract projections only, found '${projectionType}'`);
|
|
161
161
|
}
|
|
@@ -30,7 +30,7 @@ function buildServerContract(graph, projection) {
|
|
|
30
30
|
projection: {
|
|
31
31
|
id: projection.id,
|
|
32
32
|
name: projection.name || projection.id,
|
|
33
|
-
type: projection.type || projection.
|
|
33
|
+
type: projection.type || projection.type
|
|
34
34
|
},
|
|
35
35
|
routes: realizedCapabilities.map((capability) => {
|
|
36
36
|
const apiContract = generateApiContractGraph(graph, { capabilityId: capability.id });
|
|
@@ -38,7 +38,7 @@ export function uiProjectionCandidates(graph) {
|
|
|
38
38
|
(projection.uiAppShell || []).length > 0 ||
|
|
39
39
|
(projection.uiNavigation || []).length > 0 ||
|
|
40
40
|
(projection.uiScreenRegions || []).length > 0 ||
|
|
41
|
-
(projection.
|
|
41
|
+
(projection.widgetBindings || []).length > 0 ||
|
|
42
42
|
(projection.uiDesign || []).length > 0
|
|
43
43
|
);
|
|
44
44
|
}
|
|
@@ -15,17 +15,19 @@ import {
|
|
|
15
15
|
|
|
16
16
|
export function generateWebApp(graph, options = {}) {
|
|
17
17
|
const projection = getProjection(graph, options.projectionId);
|
|
18
|
-
|
|
18
|
+
const runtime = options.runtime || options.component;
|
|
19
|
+
if (runtime?.generator?.id) {
|
|
19
20
|
return generateWithComponentGenerator({
|
|
20
21
|
graph,
|
|
21
22
|
projection,
|
|
22
|
-
|
|
23
|
+
runtime,
|
|
24
|
+
component: runtime,
|
|
23
25
|
topology: options.topology || null,
|
|
24
26
|
implementation: options.implementation || null,
|
|
25
27
|
options: { ...options, projectionId: projection.id }
|
|
26
28
|
}).files;
|
|
27
29
|
}
|
|
28
|
-
const profile = generatorProfile(
|
|
30
|
+
const profile = generatorProfile(runtime?.generator?.id, null) || generatorDefaultsMap(projection).profile || "sveltekit";
|
|
29
31
|
if (profile === "vanilla") {
|
|
30
32
|
return generateVanillaWebApp(graph, options);
|
|
31
33
|
}
|
|
@@ -3,7 +3,7 @@ import { buildWebRealization } from "../../../realization/ui/index.js";
|
|
|
3
3
|
export function generateUiSurfaceContract(graph, options = {}) {
|
|
4
4
|
if (!options.projectionId) {
|
|
5
5
|
const output = {};
|
|
6
|
-
for (const projection of (graph.byKind.projection || []).filter((entry) => (entry.type || entry.
|
|
6
|
+
for (const projection of (graph.byKind.projection || []).filter((entry) => (entry.type || entry.type) === "web_surface")) {
|
|
7
7
|
output[projection.id] = buildWebRealization(graph, { ...options, projectionId: projection.id }).contract;
|
|
8
8
|
}
|
|
9
9
|
return output;
|
|
@@ -22,7 +22,7 @@ function summarizeProjection(projection) {
|
|
|
22
22
|
? {
|
|
23
23
|
id: projection.id,
|
|
24
24
|
name: projection.name || projection.id,
|
|
25
|
-
type: projection.type || projection.
|
|
25
|
+
type: projection.type || projection.type || null,
|
|
26
26
|
status: projection.status || null,
|
|
27
27
|
source_path: sourcePath(projection)
|
|
28
28
|
}
|
|
@@ -479,14 +479,14 @@ function projectionUsageEntries(graph, projection) {
|
|
|
479
479
|
const sharedProjection = sharedUiProjectionForWeb(graph, projection);
|
|
480
480
|
const entries = [];
|
|
481
481
|
if (sharedProjection) {
|
|
482
|
-
entries.push(...(sharedProjection.
|
|
482
|
+
entries.push(...(sharedProjection.widgetBindings || []).map((usage, index) => ({
|
|
483
483
|
projection,
|
|
484
484
|
sourceProjection: sharedProjection,
|
|
485
485
|
usage,
|
|
486
486
|
index
|
|
487
487
|
})));
|
|
488
488
|
}
|
|
489
|
-
entries.push(...(projection.
|
|
489
|
+
entries.push(...(projection.widgetBindings || []).map((usage, index) => ({
|
|
490
490
|
projection,
|
|
491
491
|
sourceProjection: projection,
|
|
492
492
|
usage,
|
|
@@ -499,10 +499,10 @@ function candidateProjections(graph, projectionId) {
|
|
|
499
499
|
if (projectionId) {
|
|
500
500
|
return [getProjection(graph, projectionId)];
|
|
501
501
|
}
|
|
502
|
-
const direct = uiProjectionCandidates(graph).filter((projection) => (projection.
|
|
502
|
+
const direct = uiProjectionCandidates(graph).filter((projection) => (projection.widgetBindings || []).length > 0);
|
|
503
503
|
const inherited = (graph.byKind.projection || []).filter((projection) => {
|
|
504
|
-
if ((projection.
|
|
505
|
-
return Boolean(sharedUiProjectionForWeb(graph, projection)?.
|
|
504
|
+
if ((projection.widgetBindings || []).length > 0) return false;
|
|
505
|
+
return Boolean(sharedUiProjectionForWeb(graph, projection)?.widgetBindings?.length);
|
|
506
506
|
});
|
|
507
507
|
return [...direct, ...inherited].sort((a, b) => a.id.localeCompare(b.id));
|
|
508
508
|
}
|
package/src/generator/widgets.js
CHANGED
|
@@ -27,7 +27,7 @@ function widgetContract(widget) {
|
|
|
27
27
|
export function generateUiWidgetContract(graph, options = {}) {
|
|
28
28
|
const widgetId = options.widgetId || options.componentId;
|
|
29
29
|
if (widgetId) {
|
|
30
|
-
const widget = (graph?.byKind?.widget ||
|
|
30
|
+
const widget = (graph?.byKind?.widget || []).find((entry) => entry.id === widgetId);
|
|
31
31
|
if (!widget) {
|
|
32
32
|
throw new Error(`No widget found with id '${widgetId}'`);
|
|
33
33
|
}
|
package/src/generator-policy.js
CHANGED
|
@@ -31,7 +31,7 @@ export const GENERATOR_POLICY_FILE = "topogram.generator-policy.json";
|
|
|
31
31
|
* @property {string|null} path
|
|
32
32
|
* @property {string|null} suggestedFix
|
|
33
33
|
* @property {string|null} step
|
|
34
|
-
* @property {string|null} [
|
|
34
|
+
* @property {string|null} [runtimeId]
|
|
35
35
|
* @property {string|null} [generatorId]
|
|
36
36
|
* @property {string|null} [packageName]
|
|
37
37
|
* @property {string|null} [version]
|
|
@@ -39,8 +39,8 @@ export const GENERATOR_POLICY_FILE = "topogram.generator-policy.json";
|
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
41
|
* @typedef {Object} PackageGeneratorBinding
|
|
42
|
-
* @property {string}
|
|
43
|
-
* @property {string}
|
|
42
|
+
* @property {string} runtimeId
|
|
43
|
+
* @property {string} runtimeKind
|
|
44
44
|
* @property {string} projection
|
|
45
45
|
* @property {string} generatorId
|
|
46
46
|
* @property {string} version
|
|
@@ -59,7 +59,7 @@ function generatorPolicyDiagnostic(input) {
|
|
|
59
59
|
path: typeof input.path === "string" ? input.path : null,
|
|
60
60
|
suggestedFix: typeof input.suggestedFix === "string" ? input.suggestedFix : null,
|
|
61
61
|
step: typeof input.step === "string" ? input.step : null,
|
|
62
|
-
|
|
62
|
+
runtimeId: typeof input.runtimeId === "string" ? input.runtimeId : null,
|
|
63
63
|
generatorId: typeof input.generatorId === "string" ? input.generatorId : null,
|
|
64
64
|
packageName: typeof input.packageName === "string" ? input.packageName : null,
|
|
65
65
|
version: typeof input.version === "string" ? input.version : null
|
|
@@ -179,8 +179,8 @@ export function packageBackedGeneratorBindings(projectConfig) {
|
|
|
179
179
|
return runtimes
|
|
180
180
|
.filter((runtime) => typeof runtime?.generator?.package === "string" && runtime.generator.package.length > 0)
|
|
181
181
|
.map((runtime) => ({
|
|
182
|
-
|
|
183
|
-
|
|
182
|
+
runtimeId: String(runtime.id || "unknown"),
|
|
183
|
+
runtimeKind: String(runtime.kind || "unknown"),
|
|
184
184
|
projection: String(runtime.projection || "unknown"),
|
|
185
185
|
generatorId: String(runtime.generator.id || "unknown"),
|
|
186
186
|
version: String(runtime.generator.version || "unknown"),
|
|
@@ -263,11 +263,11 @@ export function generatorPolicyDiagnosticsForBindings(policyInfo, bindings, step
|
|
|
263
263
|
const allowedPackages = policy.allowedPackages.join(", ") || "(none)";
|
|
264
264
|
diagnostics.push(generatorPolicyDiagnostic({
|
|
265
265
|
code: "generator_package_denied",
|
|
266
|
-
message: `
|
|
266
|
+
message: `Runtime '${binding.runtimeId}' generator package '${binding.packageName}' is not allowed by ${GENERATOR_POLICY_FILE}.`,
|
|
267
267
|
path: policyInfo.path,
|
|
268
268
|
suggestedFix: `Review '${binding.packageName}', then run \`topogram generator policy pin ${binding.packageName}@${binding.version}\` or add '${scope || binding.packageName}' to ${GENERATOR_POLICY_FILE}.`,
|
|
269
269
|
step,
|
|
270
|
-
|
|
270
|
+
runtimeId: binding.runtimeId,
|
|
271
271
|
generatorId: binding.generatorId,
|
|
272
272
|
packageName: binding.packageName,
|
|
273
273
|
version: binding.version
|
|
@@ -278,11 +278,11 @@ export function generatorPolicyDiagnosticsForBindings(policyInfo, bindings, step
|
|
|
278
278
|
if (pinnedVersion && pinnedVersion !== binding.version) {
|
|
279
279
|
diagnostics.push(generatorPolicyDiagnostic({
|
|
280
280
|
code: "generator_version_mismatch",
|
|
281
|
-
message: `
|
|
281
|
+
message: `Runtime '${binding.runtimeId}' generator '${binding.generatorId}' uses version '${binding.version}', but ${GENERATOR_POLICY_FILE} pins '${binding.packageName}' to '${pinnedVersion}'.`,
|
|
282
282
|
path: policyInfo.path,
|
|
283
283
|
suggestedFix: `Use generator version '${pinnedVersion}', or run \`topogram generator policy pin ${binding.packageName}@${binding.version}\` after review.`,
|
|
284
284
|
step,
|
|
285
|
-
|
|
285
|
+
runtimeId: binding.runtimeId,
|
|
286
286
|
generatorId: binding.generatorId,
|
|
287
287
|
packageName: binding.packageName,
|
|
288
288
|
version: binding.version
|