@pattern-stack/codegen 0.6.8 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/src/cli/index.js +516 -73
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/index.d.ts +208 -1
- package/dist/src/index.js +147 -0
- package/dist/src/index.js.map +1 -1
- package/package.json +1 -1
- package/src/patterns/library/base-junction-fields.ts +32 -0
- package/src/patterns/library/index.ts +7 -0
- package/src/patterns/library/junction.pattern.ts +41 -0
- package/templates/entity/new/backend/application/queries/get-by-id.ejs.t +3 -3
- package/templates/entity/new/backend/application/queries/grouped-index.ejs.t +5 -5
- package/templates/entity/new/backend/application/queries/index.ejs.t +3 -0
- package/templates/entity/new/backend/application/queries/list.ejs.t +3 -3
- package/templates/entity/new/backend/application/queries/relationships.queries.ejs.t +147 -0
- package/templates/entity/new/backend/database/repository.ejs.t +36 -176
- package/templates/entity/new/backend/domain/entity.ejs.t +0 -44
- package/templates/entity/new/backend/domain/grouped-index.ejs.t +4 -60
- package/templates/entity/new/backend/domain/index.ejs.t +2 -2
- package/templates/entity/new/backend/domain/repository-interface.ejs.t +16 -17
- package/templates/entity/new/backend/modules/core/module.ejs.t +10 -0
- package/templates/entity/new/backend/presentation/controller.ejs.t +2 -34
- package/templates/entity/new/clean-lite-ps/entity.ejs.t +15 -2
- package/templates/entity/new/clean-lite-ps/module.ejs.t +27 -2
- package/templates/entity/new/clean-lite-ps/prompt-extension.js +72 -5
- package/templates/entity/new/clean-lite-ps/repository.ejs.t +33 -1
- package/templates/entity/new/clean-lite-ps/service.ejs.t +79 -0
- package/templates/entity/new/prompt.js +1 -0
- package/templates/junction/new/_inject-parent-module-clp-left.ejs.t +8 -0
- package/templates/junction/new/_inject-parent-module-clp-right.ejs.t +8 -0
- package/templates/junction/new/_inject-parent-module-forwardref-clp-left.ejs.t +8 -0
- package/templates/junction/new/_inject-parent-module-forwardref-clp-right.ejs.t +8 -0
- package/templates/junction/new/_inject-parent-module-import-clp-left.ejs.t +8 -0
- package/templates/junction/new/_inject-parent-module-import-clp-right.ejs.t +8 -0
- package/templates/junction/new/_inject-parent-service-clp-left.ejs.t +51 -0
- package/templates/junction/new/_inject-parent-service-clp-right.ejs.t +48 -0
- package/templates/junction/new/_inject-parent-service-counterparty-clp-left.ejs.t +7 -0
- package/templates/junction/new/_inject-parent-service-counterparty-clp-right.ejs.t +7 -0
- package/templates/junction/new/_inject-parent-service-forwardref-clp-left.ejs.t +8 -0
- package/templates/junction/new/_inject-parent-service-forwardref-clp-right.ejs.t +8 -0
- package/templates/junction/new/_inject-parent-service-import-clp-left.ejs.t +9 -0
- package/templates/junction/new/_inject-parent-service-import-clp-right.ejs.t +9 -0
- package/templates/junction/new/entity.ejs.t +111 -0
- package/templates/junction/new/index.ejs.t +15 -0
- package/templates/junction/new/module.ejs.t +37 -0
- package/templates/junction/new/prompt.js +492 -0
- package/templates/junction/new/repository.ejs.t +67 -0
- package/templates/junction/new/service.ejs.t +174 -0
package/dist/src/cli/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __decorateParam = (index2, decorator) => (target, key) => decorator(target,
|
|
|
14
14
|
// src/cli/index.ts
|
|
15
15
|
import { readFileSync as readFileSync6 } from "fs";
|
|
16
16
|
import { join as join11 } from "path";
|
|
17
|
-
import { Builtins, Cli, Command as
|
|
17
|
+
import { Builtins, Cli, Command as Command11 } from "clipanion";
|
|
18
18
|
|
|
19
19
|
// src/cli/noun-module.ts
|
|
20
20
|
import { Command, Option } from "clipanion";
|
|
@@ -986,13 +986,13 @@ function renderPane(pane) {
|
|
|
986
986
|
}
|
|
987
987
|
|
|
988
988
|
// src/cli/ui/hints.ts
|
|
989
|
-
function renderHints(
|
|
989
|
+
function renderHints(hints9) {
|
|
990
990
|
if (isJsonMode()) return;
|
|
991
|
-
if (
|
|
991
|
+
if (hints9.length === 0) return;
|
|
992
992
|
console.log("");
|
|
993
993
|
console.log(theme.muted(" Next:"));
|
|
994
|
-
const maxCmd = Math.max(...
|
|
995
|
-
for (const h of
|
|
994
|
+
const maxCmd = Math.max(...hints9.map((h) => h.command.length));
|
|
995
|
+
for (const h of hints9) {
|
|
996
996
|
const pad = " ".repeat(maxCmd - h.command.length + 2);
|
|
997
997
|
console.log(` ${theme.system(h.command)}${pad}${theme.muted(h.description)}`);
|
|
998
998
|
}
|
|
@@ -1017,13 +1017,13 @@ function buildNounSummaryCommand(noun) {
|
|
|
1017
1017
|
json: this.json,
|
|
1018
1018
|
verbose: this.verbose
|
|
1019
1019
|
});
|
|
1020
|
-
const [pane,
|
|
1020
|
+
const [pane, hints9] = await Promise.all([noun.summary(ctx), noun.hints(ctx)]);
|
|
1021
1021
|
if (isJsonMode()) {
|
|
1022
|
-
printJson({ noun: noun.name, summary: pane, hints:
|
|
1022
|
+
printJson({ noun: noun.name, summary: pane, hints: hints9 });
|
|
1023
1023
|
return 0;
|
|
1024
1024
|
}
|
|
1025
1025
|
renderPane(pane);
|
|
1026
|
-
renderHints(
|
|
1026
|
+
renderHints(hints9);
|
|
1027
1027
|
return 0;
|
|
1028
1028
|
}
|
|
1029
1029
|
}
|
|
@@ -2791,6 +2791,80 @@ function deriveUniqueConstraint(config) {
|
|
|
2791
2791
|
return columns;
|
|
2792
2792
|
}
|
|
2793
2793
|
|
|
2794
|
+
// src/schema/junction-definition.schema.ts
|
|
2795
|
+
import { z as z6 } from "zod";
|
|
2796
|
+
|
|
2797
|
+
// src/patterns/library/base-junction-fields.ts
|
|
2798
|
+
var BaseJunctionFields = [
|
|
2799
|
+
{ name: "is_primary", type: "boolean" },
|
|
2800
|
+
{ name: "started_at", type: "timestamp" },
|
|
2801
|
+
{ name: "ended_at", type: "timestamp" },
|
|
2802
|
+
{ name: "sourced_from", type: "text" },
|
|
2803
|
+
{ name: "confidence", type: "numeric(5,4)" },
|
|
2804
|
+
{ name: "matched_at", type: "timestamp" }
|
|
2805
|
+
];
|
|
2806
|
+
var BASE_JUNCTION_FIELD_NAMES = new Set(
|
|
2807
|
+
BaseJunctionFields.map((c) => c.name)
|
|
2808
|
+
);
|
|
2809
|
+
|
|
2810
|
+
// src/schema/junction-definition.schema.ts
|
|
2811
|
+
var EntityNameSchema = z6.string().regex(/^[a-z][a-z0-9_]*$/, "Entity reference must be snake_case");
|
|
2812
|
+
var JunctionDefinitionSchema = z6.object({
|
|
2813
|
+
/** Discriminator literal — `pattern: Junction`. */
|
|
2814
|
+
pattern: z6.literal("Junction"),
|
|
2815
|
+
/**
|
|
2816
|
+
* Exactly two endpoint entity names. Both intra- and cross-domain
|
|
2817
|
+
* pairings are accepted; entity existence is validated by the
|
|
2818
|
+
* analyzer in a later leaf.
|
|
2819
|
+
*/
|
|
2820
|
+
between: z6.tuple([EntityNameSchema, EntityNameSchema]),
|
|
2821
|
+
/**
|
|
2822
|
+
* Emit BaseJunctionFields temporal columns (`started_at`, `ended_at`,
|
|
2823
|
+
* `matched_at`). Default true. Matches Relationship's `temporal` toggle.
|
|
2824
|
+
*/
|
|
2825
|
+
temporal: z6.boolean().optional().default(true),
|
|
2826
|
+
/**
|
|
2827
|
+
* Emit BaseJunctionFields sourcing columns (`sourced_from`,
|
|
2828
|
+
* `confidence`). Default true. Matches Relationship's `sourced` toggle.
|
|
2829
|
+
*/
|
|
2830
|
+
sourced: z6.boolean().optional().default(true),
|
|
2831
|
+
/**
|
|
2832
|
+
* Junction-specific fields beyond `BaseJunctionFields`. Includes the
|
|
2833
|
+
* per-pairing role enum (declared inline; never shared across
|
|
2834
|
+
* pairings). Shape is validated downstream by the codegen layer
|
|
2835
|
+
* using the existing entity FieldDefinitionSchema.
|
|
2836
|
+
*/
|
|
2837
|
+
fields: z6.record(z6.string(), z6.any()).optional(),
|
|
2838
|
+
/**
|
|
2839
|
+
* Declarative queries — same syntax as entity queries. Shape is
|
|
2840
|
+
* validated downstream by the codegen layer.
|
|
2841
|
+
*/
|
|
2842
|
+
queries: z6.array(z6.any()).optional(),
|
|
2843
|
+
/**
|
|
2844
|
+
* Per-side opt-out for parent-service fan-out (CGP-60). When a side
|
|
2845
|
+
* is `false`, the `_inject-parent-service-*` templates emit nothing
|
|
2846
|
+
* on that side (and the corresponding module wiring is skipped).
|
|
2847
|
+
* The junction service body is always emitted regardless. Defaults
|
|
2848
|
+
* to `{ left: true, right: true }`.
|
|
2849
|
+
*/
|
|
2850
|
+
expose_on_parent: z6.object({
|
|
2851
|
+
left: z6.boolean().optional().default(true),
|
|
2852
|
+
right: z6.boolean().optional().default(true)
|
|
2853
|
+
}).optional().default({ left: true, right: true })
|
|
2854
|
+
}).strict().refine((d) => d.between[0] !== d.between[1], {
|
|
2855
|
+
message: "`between` endpoints must be distinct",
|
|
2856
|
+
path: ["between"]
|
|
2857
|
+
}).refine(
|
|
2858
|
+
(d) => {
|
|
2859
|
+
const fieldNames = Object.keys(d.fields ?? {});
|
|
2860
|
+
return !fieldNames.some((n) => BASE_JUNCTION_FIELD_NAMES.has(n));
|
|
2861
|
+
},
|
|
2862
|
+
{
|
|
2863
|
+
message: "`fields:` block redeclares a reserved BaseJunctionFields column (is_primary, started_at, ended_at, sourced_from, confidence, matched_at)",
|
|
2864
|
+
path: ["fields"]
|
|
2865
|
+
}
|
|
2866
|
+
);
|
|
2867
|
+
|
|
2794
2868
|
// src/utils/yaml-loader.ts
|
|
2795
2869
|
function loadEntityFromYaml(filePath) {
|
|
2796
2870
|
if (!existsSync6(filePath)) {
|
|
@@ -2839,8 +2913,8 @@ function loadEntityFromYaml(filePath) {
|
|
|
2839
2913
|
}
|
|
2840
2914
|
function formatZodErrors(error) {
|
|
2841
2915
|
return error.errors.map((err) => {
|
|
2842
|
-
const
|
|
2843
|
-
const location =
|
|
2916
|
+
const path30 = err.path.join(".");
|
|
2917
|
+
const location = path30 ? `at '${path30}'` : "at root";
|
|
2844
2918
|
return `${err.message} ${location}`;
|
|
2845
2919
|
});
|
|
2846
2920
|
}
|
|
@@ -2934,12 +3008,58 @@ function loadEventFromYaml(filePath) {
|
|
|
2934
3008
|
filePath
|
|
2935
3009
|
};
|
|
2936
3010
|
}
|
|
3011
|
+
function loadJunctionFromYaml(filePath) {
|
|
3012
|
+
if (!existsSync6(filePath)) {
|
|
3013
|
+
return {
|
|
3014
|
+
success: false,
|
|
3015
|
+
error: `File not found: ${filePath}`,
|
|
3016
|
+
filePath
|
|
3017
|
+
};
|
|
3018
|
+
}
|
|
3019
|
+
let content;
|
|
3020
|
+
try {
|
|
3021
|
+
content = readFileSync4(filePath, "utf-8");
|
|
3022
|
+
} catch (err) {
|
|
3023
|
+
return {
|
|
3024
|
+
success: false,
|
|
3025
|
+
error: `Failed to read file: ${filePath}`,
|
|
3026
|
+
details: [err instanceof Error ? err.message : String(err)],
|
|
3027
|
+
filePath
|
|
3028
|
+
};
|
|
3029
|
+
}
|
|
3030
|
+
let parsed;
|
|
3031
|
+
try {
|
|
3032
|
+
parsed = parseYaml(content);
|
|
3033
|
+
} catch (err) {
|
|
3034
|
+
return {
|
|
3035
|
+
success: false,
|
|
3036
|
+
error: `Invalid YAML syntax in ${filePath}`,
|
|
3037
|
+
details: [err instanceof Error ? err.message : String(err)],
|
|
3038
|
+
filePath
|
|
3039
|
+
};
|
|
3040
|
+
}
|
|
3041
|
+
const result = JunctionDefinitionSchema.safeParse(parsed);
|
|
3042
|
+
if (!result.success) {
|
|
3043
|
+
return {
|
|
3044
|
+
success: false,
|
|
3045
|
+
error: `Validation failed for ${filePath}`,
|
|
3046
|
+
details: formatZodErrors(result.error),
|
|
3047
|
+
filePath
|
|
3048
|
+
};
|
|
3049
|
+
}
|
|
3050
|
+
return {
|
|
3051
|
+
success: true,
|
|
3052
|
+
definition: result.data,
|
|
3053
|
+
filePath
|
|
3054
|
+
};
|
|
3055
|
+
}
|
|
2937
3056
|
function detectYamlType(filePath) {
|
|
2938
3057
|
if (!existsSync6(filePath)) return "unknown";
|
|
2939
3058
|
try {
|
|
2940
3059
|
const content = readFileSync4(filePath, "utf-8");
|
|
2941
3060
|
const parsed = parseYaml(content);
|
|
2942
3061
|
if (parsed && typeof parsed === "object") {
|
|
3062
|
+
if (parsed.pattern === "Junction") return "junction";
|
|
2943
3063
|
if ("entity" in parsed) return "entity";
|
|
2944
3064
|
if ("relationship" in parsed) return "relationship";
|
|
2945
3065
|
}
|
|
@@ -3392,19 +3512,19 @@ function findCircularDependencies(graph) {
|
|
|
3392
3512
|
const cycles = [];
|
|
3393
3513
|
const visited = /* @__PURE__ */ new Set();
|
|
3394
3514
|
const recursionStack = /* @__PURE__ */ new Set();
|
|
3395
|
-
function dfs(node,
|
|
3515
|
+
function dfs(node, path30) {
|
|
3396
3516
|
visited.add(node);
|
|
3397
3517
|
recursionStack.add(node);
|
|
3398
3518
|
const outgoingEdges = graph.edges.filter((e) => e.from === node);
|
|
3399
3519
|
for (const edge of outgoingEdges) {
|
|
3400
3520
|
if (!visited.has(edge.to)) {
|
|
3401
|
-
dfs(edge.to, [...
|
|
3521
|
+
dfs(edge.to, [...path30, edge.to]);
|
|
3402
3522
|
} else if (recursionStack.has(edge.to)) {
|
|
3403
|
-
const cycleStart =
|
|
3523
|
+
const cycleStart = path30.indexOf(edge.to);
|
|
3404
3524
|
if (cycleStart !== -1) {
|
|
3405
|
-
cycles.push([...
|
|
3525
|
+
cycles.push([...path30.slice(cycleStart), edge.to]);
|
|
3406
3526
|
} else {
|
|
3407
|
-
cycles.push([...
|
|
3527
|
+
cycles.push([...path30, edge.to]);
|
|
3408
3528
|
}
|
|
3409
3529
|
}
|
|
3410
3530
|
}
|
|
@@ -4001,8 +4121,8 @@ function suggestTransitiveRelationships(graph, options) {
|
|
|
4001
4121
|
for (const [entityName, entity] of graph.entities) {
|
|
4002
4122
|
if (shouldExcludeEntity(entityName, opts)) continue;
|
|
4003
4123
|
const paths = findTransitivePaths(graph, entityName, opts);
|
|
4004
|
-
for (const
|
|
4005
|
-
suggestions.push(createSuggestion(
|
|
4124
|
+
for (const path30 of paths) {
|
|
4125
|
+
suggestions.push(createSuggestion(path30));
|
|
4006
4126
|
}
|
|
4007
4127
|
}
|
|
4008
4128
|
return suggestions;
|
|
@@ -4033,7 +4153,7 @@ function findTransitivePaths(graph, sourceEntity, opts) {
|
|
|
4033
4153
|
while (queue.length > 0) {
|
|
4034
4154
|
const current = queue.shift();
|
|
4035
4155
|
if (!current) continue;
|
|
4036
|
-
const { entity, depth, path:
|
|
4156
|
+
const { entity, depth, path: path30, visited } = current;
|
|
4037
4157
|
if (depth >= opts.maxDepth) continue;
|
|
4038
4158
|
const currentEntity = graph.entities.get(entity);
|
|
4039
4159
|
if (!currentEntity) continue;
|
|
@@ -4044,7 +4164,7 @@ function findTransitivePaths(graph, sourceEntity, opts) {
|
|
|
4044
4164
|
if (shouldExcludeEntity(target, opts)) continue;
|
|
4045
4165
|
if (visited.has(target)) continue;
|
|
4046
4166
|
const newPath = [
|
|
4047
|
-
...
|
|
4167
|
+
...path30,
|
|
4048
4168
|
{
|
|
4049
4169
|
via: entity,
|
|
4050
4170
|
relationship: relName,
|
|
@@ -4112,15 +4232,15 @@ function generateYamlSnippet(name, target, throughPath) {
|
|
|
4112
4232
|
target: ${target}
|
|
4113
4233
|
through: "${throughPath}"`;
|
|
4114
4234
|
}
|
|
4115
|
-
function createSuggestion(
|
|
4116
|
-
const pathDescription = [
|
|
4235
|
+
function createSuggestion(path30) {
|
|
4236
|
+
const pathDescription = [path30.source, ...path30.hops.map((h) => h.via), path30.target].join(" -> ");
|
|
4117
4237
|
return {
|
|
4118
4238
|
severity: "info",
|
|
4119
4239
|
type: "transitive_suggestion",
|
|
4120
|
-
entity:
|
|
4240
|
+
entity: path30.source,
|
|
4121
4241
|
message: `Potential transitive relationship: ${pathDescription}`,
|
|
4122
|
-
suggestion: `Add "${
|
|
4123
|
-
path:
|
|
4242
|
+
suggestion: `Add "${path30.suggestedName}" relationship via "${path30.throughPath}"`,
|
|
4243
|
+
path: path30
|
|
4124
4244
|
};
|
|
4125
4245
|
}
|
|
4126
4246
|
|
|
@@ -5277,6 +5397,16 @@ var BasePattern = definePattern({
|
|
|
5277
5397
|
description: "Identity pattern \u2014 base CRUD, no extra columns or methods"
|
|
5278
5398
|
});
|
|
5279
5399
|
|
|
5400
|
+
// src/patterns/library/junction.pattern.ts
|
|
5401
|
+
import { z as z7 } from "zod";
|
|
5402
|
+
var JunctionPatternConfigSchema = z7.object({}).strict();
|
|
5403
|
+
var JunctionPattern = definePattern({
|
|
5404
|
+
name: "Junction",
|
|
5405
|
+
description: "Explicit many-to-many junction with role + temporal + sourcing metadata",
|
|
5406
|
+
columns: [...BaseJunctionFields],
|
|
5407
|
+
configSchema: JunctionPatternConfigSchema
|
|
5408
|
+
});
|
|
5409
|
+
|
|
5280
5410
|
// src/patterns/library/knowledge.pattern.ts
|
|
5281
5411
|
var KnowledgePattern = definePattern({
|
|
5282
5412
|
name: "Knowledge",
|
|
@@ -5341,6 +5471,7 @@ registerLibraryPattern(SyncedPattern);
|
|
|
5341
5471
|
registerLibraryPattern(ActivityPattern);
|
|
5342
5472
|
registerLibraryPattern(KnowledgePattern);
|
|
5343
5473
|
registerLibraryPattern(MetadataPattern);
|
|
5474
|
+
registerLibraryPattern(JunctionPattern);
|
|
5344
5475
|
|
|
5345
5476
|
// src/index.ts
|
|
5346
5477
|
async function analyzeDomain(entitiesDir, relationshipsOrOptions) {
|
|
@@ -5448,6 +5579,14 @@ function invokeRelationshipNew(absoluteYamlPath, cwd) {
|
|
|
5448
5579
|
cwd
|
|
5449
5580
|
});
|
|
5450
5581
|
}
|
|
5582
|
+
function invokeJunctionNew(absoluteYamlPath, cwd) {
|
|
5583
|
+
return invokeHygen({
|
|
5584
|
+
generator: "junction",
|
|
5585
|
+
action: "new",
|
|
5586
|
+
args: ["--yaml", absoluteYamlPath],
|
|
5587
|
+
cwd
|
|
5588
|
+
});
|
|
5589
|
+
}
|
|
5451
5590
|
|
|
5452
5591
|
// src/cli/shared/git-safety.ts
|
|
5453
5592
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -5538,6 +5677,27 @@ function collectRelationships(relationshipsDir) {
|
|
|
5538
5677
|
junctions.sort((a, b) => a.name.localeCompare(b.name));
|
|
5539
5678
|
return junctions;
|
|
5540
5679
|
}
|
|
5680
|
+
function listJunctionYamls(junctionsDir) {
|
|
5681
|
+
if (!fs2.existsSync(junctionsDir)) return [];
|
|
5682
|
+
return fs2.readdirSync(junctionsDir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml")).map((f) => path4.join(junctionsDir, f)).filter((full) => detectYamlType(full) === "junction").sort();
|
|
5683
|
+
}
|
|
5684
|
+
function deriveJunctionName(def) {
|
|
5685
|
+
return def.name ?? `${def.between[0]}_${def.between[1]}`;
|
|
5686
|
+
}
|
|
5687
|
+
function collectJunctions(junctionsDir) {
|
|
5688
|
+
const files = listJunctionYamls(junctionsDir);
|
|
5689
|
+
const junctions = [];
|
|
5690
|
+
for (const file of files) {
|
|
5691
|
+
const result = loadJunctionFromYaml(file);
|
|
5692
|
+
if (!result.success) continue;
|
|
5693
|
+
const def = result.definition;
|
|
5694
|
+
const name = deriveJunctionName(def);
|
|
5695
|
+
const plural = def.table ?? pluralize(name);
|
|
5696
|
+
junctions.push({ name, plural });
|
|
5697
|
+
}
|
|
5698
|
+
junctions.sort((a, b) => a.name.localeCompare(b.name));
|
|
5699
|
+
return junctions;
|
|
5700
|
+
}
|
|
5541
5701
|
function entityFilePaths(info, architecture, backendSrc) {
|
|
5542
5702
|
const name = info.name;
|
|
5543
5703
|
const plural = info.plural;
|
|
@@ -5605,6 +5765,7 @@ async function regenerateBarrels(opts) {
|
|
|
5605
5765
|
ctx,
|
|
5606
5766
|
entitiesDir,
|
|
5607
5767
|
relationshipsDir = path4.resolve(ctx.cwd, "relationships"),
|
|
5768
|
+
junctionsDir = path4.resolve(ctx.cwd, "junctions"),
|
|
5608
5769
|
generatedDir,
|
|
5609
5770
|
architecture,
|
|
5610
5771
|
backendSrc = resolveBackendSrc(ctx),
|
|
@@ -5613,7 +5774,8 @@ async function regenerateBarrels(opts) {
|
|
|
5613
5774
|
const cwd = ctx.cwd;
|
|
5614
5775
|
const entities = [
|
|
5615
5776
|
...collectEntities(entitiesDir),
|
|
5616
|
-
...collectRelationships(relationshipsDir)
|
|
5777
|
+
...collectRelationships(relationshipsDir),
|
|
5778
|
+
...collectJunctions(junctionsDir)
|
|
5617
5779
|
].sort((a, b) => a.name.localeCompare(b.name));
|
|
5618
5780
|
const generatedRel = path4.relative(cwd, generatedDir) || path4.basename(generatedDir);
|
|
5619
5781
|
const modulesRel = path4.posix.join(
|
|
@@ -12434,11 +12596,291 @@ var relationshipNoun = {
|
|
|
12434
12596
|
};
|
|
12435
12597
|
var relationship_default = relationshipNoun;
|
|
12436
12598
|
|
|
12599
|
+
// src/cli/commands/junction.ts
|
|
12600
|
+
import path27 from "path";
|
|
12601
|
+
import { Command as Command8, Option as Option8 } from "clipanion";
|
|
12602
|
+
function summarizeJunctionFile(filePath) {
|
|
12603
|
+
const result = loadJunctionFromYaml(filePath);
|
|
12604
|
+
if (!result.success) return null;
|
|
12605
|
+
const def = result.definition;
|
|
12606
|
+
const name = def.name ?? `${def.between[0]}_${def.between[1]}`;
|
|
12607
|
+
const roleChoices = def.fields?.role?.choices;
|
|
12608
|
+
const hasRole = Array.isArray(roleChoices) && roleChoices.length > 0;
|
|
12609
|
+
return {
|
|
12610
|
+
name,
|
|
12611
|
+
left: def.between[0],
|
|
12612
|
+
right: def.between[1],
|
|
12613
|
+
hasRole,
|
|
12614
|
+
temporal: def.temporal ?? true,
|
|
12615
|
+
sourced: def.sourced ?? true,
|
|
12616
|
+
file: filePath
|
|
12617
|
+
};
|
|
12618
|
+
}
|
|
12619
|
+
function padRight3(s, n) {
|
|
12620
|
+
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
12621
|
+
}
|
|
12622
|
+
async function summary6(ctx) {
|
|
12623
|
+
const junctionDir = path27.resolve(ctx.cwd, "junctions");
|
|
12624
|
+
const files = listJunctionYamls(junctionDir);
|
|
12625
|
+
if (files.length === 0) {
|
|
12626
|
+
return {
|
|
12627
|
+
title: "junctions",
|
|
12628
|
+
body: [
|
|
12629
|
+
"No junction definitions found.",
|
|
12630
|
+
"",
|
|
12631
|
+
`Create one at ${theme.system("junctions/<name>.yaml")} to get started.`
|
|
12632
|
+
]
|
|
12633
|
+
};
|
|
12634
|
+
}
|
|
12635
|
+
const rows = files.map(summarizeJunctionFile).filter((r) => r !== null);
|
|
12636
|
+
const nameCol = Math.max(4, ...rows.map((r) => r.name.length));
|
|
12637
|
+
const pairingCol = Math.max(7, ...rows.map((r) => `${r.left} \xD7 ${r.right}`.length));
|
|
12638
|
+
const body = rows.map((r) => {
|
|
12639
|
+
const pairing = `${r.left} \xD7 ${r.right}`;
|
|
12640
|
+
const flags = [
|
|
12641
|
+
r.hasRole ? "role" : "",
|
|
12642
|
+
r.temporal ? "temporal" : "",
|
|
12643
|
+
r.sourced ? "sourced" : ""
|
|
12644
|
+
].filter(Boolean).join(", ");
|
|
12645
|
+
return `${theme.system(icons.bullet)} ${padRight3(r.name, nameCol)} ${theme.muted(
|
|
12646
|
+
padRight3(pairing, pairingCol)
|
|
12647
|
+
)} ${theme.muted(flags)}`;
|
|
12648
|
+
});
|
|
12649
|
+
return {
|
|
12650
|
+
title: "junctions",
|
|
12651
|
+
body,
|
|
12652
|
+
footer: `${rows.length} junctions`
|
|
12653
|
+
};
|
|
12654
|
+
}
|
|
12655
|
+
async function hints6(_ctx) {
|
|
12656
|
+
return [
|
|
12657
|
+
{ command: "codegen junction new <file>", description: "Generate one junction" },
|
|
12658
|
+
{ command: "codegen junction new --all", description: "Generate all junctions" },
|
|
12659
|
+
{ command: "codegen junction list", description: "List junction definitions" }
|
|
12660
|
+
];
|
|
12661
|
+
}
|
|
12662
|
+
var JunctionNewCommand = class extends Command8 {
|
|
12663
|
+
static paths = [["junction", "new"]];
|
|
12664
|
+
static usage = Command8.Usage({
|
|
12665
|
+
description: "Generate code for one or more junctions from YAML",
|
|
12666
|
+
examples: [
|
|
12667
|
+
["Generate a single junction", "codegen junction new junctions/opportunity_contact.yaml"],
|
|
12668
|
+
["Generate all junctions", "codegen junction new --all"],
|
|
12669
|
+
["Preview without writing", "codegen junction new junctions/opportunity_contact.yaml --dry-run"]
|
|
12670
|
+
]
|
|
12671
|
+
});
|
|
12672
|
+
yaml = Option8.String({ required: false });
|
|
12673
|
+
all = Option8.Boolean("--all", false);
|
|
12674
|
+
dryRun = Option8.Boolean("--dry-run", false);
|
|
12675
|
+
force = Option8.Boolean("--force", false);
|
|
12676
|
+
json = Option8.Boolean("--json", false);
|
|
12677
|
+
cwd = Option8.String("--cwd", { required: false });
|
|
12678
|
+
configPath = Option8.String("--config", { required: false });
|
|
12679
|
+
async execute() {
|
|
12680
|
+
if (this.json) setJsonMode(true);
|
|
12681
|
+
const ctx = await loadContext({
|
|
12682
|
+
cwd: this.cwd,
|
|
12683
|
+
configPath: this.configPath,
|
|
12684
|
+
json: this.json,
|
|
12685
|
+
skipDetection: true
|
|
12686
|
+
});
|
|
12687
|
+
if (this.all && this.yaml) {
|
|
12688
|
+
printError("Pass either a YAML path or --all, not both.");
|
|
12689
|
+
return 2;
|
|
12690
|
+
}
|
|
12691
|
+
let targets = [];
|
|
12692
|
+
if (this.all) {
|
|
12693
|
+
const dir = path27.resolve(ctx.cwd, "junctions");
|
|
12694
|
+
targets = listJunctionYamls(dir);
|
|
12695
|
+
if (targets.length === 0) {
|
|
12696
|
+
printError(`No junction YAML files found in ${dir}`);
|
|
12697
|
+
return 1;
|
|
12698
|
+
}
|
|
12699
|
+
} else if (this.yaml) {
|
|
12700
|
+
targets = [path27.resolve(ctx.cwd, this.yaml)];
|
|
12701
|
+
} else {
|
|
12702
|
+
printError("Missing YAML path. Pass a file or --all.");
|
|
12703
|
+
return 2;
|
|
12704
|
+
}
|
|
12705
|
+
const validated = [];
|
|
12706
|
+
const invalid = [];
|
|
12707
|
+
for (const file of targets) {
|
|
12708
|
+
const result = loadJunctionFromYaml(file);
|
|
12709
|
+
if (result.success) {
|
|
12710
|
+
const def = result.definition;
|
|
12711
|
+
const name = def.name ?? `${def.between[0]}_${def.between[1]}`;
|
|
12712
|
+
validated.push({ file, name });
|
|
12713
|
+
} else {
|
|
12714
|
+
invalid.push({ file, message: result.error });
|
|
12715
|
+
}
|
|
12716
|
+
}
|
|
12717
|
+
if (invalid.length > 0) {
|
|
12718
|
+
for (const i of invalid) {
|
|
12719
|
+
printError(`${path27.basename(i.file)} \u2014 ${i.message}`);
|
|
12720
|
+
}
|
|
12721
|
+
if (!isJsonMode()) return 1;
|
|
12722
|
+
}
|
|
12723
|
+
if (!this.force) {
|
|
12724
|
+
const gitCheck = checkGitSafety(["src"], ctx.cwd);
|
|
12725
|
+
if (gitCheck.inRepo && !gitCheck.clean) {
|
|
12726
|
+
printWarning(
|
|
12727
|
+
`Uncommitted changes in ${gitCheck.dirty.length} files under src/. Pass --force to overwrite.`
|
|
12728
|
+
);
|
|
12729
|
+
if (!isJsonMode()) return 1;
|
|
12730
|
+
}
|
|
12731
|
+
}
|
|
12732
|
+
if (this.dryRun) {
|
|
12733
|
+
if (isJsonMode()) {
|
|
12734
|
+
printJson({
|
|
12735
|
+
command: "junction new",
|
|
12736
|
+
dryRun: true,
|
|
12737
|
+
junctions: validated.map((v) => ({ name: v.name, file: v.file })),
|
|
12738
|
+
totals: { planned: validated.length, invalid: invalid.length }
|
|
12739
|
+
});
|
|
12740
|
+
} else {
|
|
12741
|
+
printInfo(`Dry run \u2014 ${validated.length} junctions would be generated:`);
|
|
12742
|
+
for (const v of validated) {
|
|
12743
|
+
console.log(` ${theme.muted(icons.arrow)} ${v.name} ${theme.muted(v.file)}`);
|
|
12744
|
+
}
|
|
12745
|
+
}
|
|
12746
|
+
return invalid.length > 0 ? 1 : 0;
|
|
12747
|
+
}
|
|
12748
|
+
const succeeded = [];
|
|
12749
|
+
const failed = [
|
|
12750
|
+
...invalid.map((i) => ({ name: path27.basename(i.file), file: i.file, message: i.message }))
|
|
12751
|
+
];
|
|
12752
|
+
for (const v of validated) {
|
|
12753
|
+
if (!isJsonMode()) {
|
|
12754
|
+
printInfo(`generating ${v.name}`);
|
|
12755
|
+
}
|
|
12756
|
+
const res = invokeJunctionNew(v.file, ctx.cwd);
|
|
12757
|
+
if (res.ok) {
|
|
12758
|
+
succeeded.push(v.name);
|
|
12759
|
+
if (!isJsonMode()) printSuccess(`${v.name}`);
|
|
12760
|
+
} else {
|
|
12761
|
+
failed.push({
|
|
12762
|
+
name: v.name,
|
|
12763
|
+
file: v.file,
|
|
12764
|
+
message: res.stderr ?? "Hygen invocation failed"
|
|
12765
|
+
});
|
|
12766
|
+
if (!isJsonMode()) printError(`${v.name} \u2014 ${res.stderr ?? "failed"}`);
|
|
12767
|
+
}
|
|
12768
|
+
}
|
|
12769
|
+
const entitiesDir = ctx.entitiesDir ?? path27.resolve(ctx.cwd, "entities");
|
|
12770
|
+
const relationshipsDir = path27.resolve(ctx.cwd, "relationships");
|
|
12771
|
+
const junctionsDir = path27.resolve(ctx.cwd, "junctions");
|
|
12772
|
+
const generatedDir = resolveGeneratedDir(ctx);
|
|
12773
|
+
const architecture = resolveArchitecture(ctx);
|
|
12774
|
+
let barrelResult = null;
|
|
12775
|
+
try {
|
|
12776
|
+
barrelResult = await regenerateBarrels({
|
|
12777
|
+
ctx,
|
|
12778
|
+
entitiesDir,
|
|
12779
|
+
relationshipsDir,
|
|
12780
|
+
junctionsDir,
|
|
12781
|
+
generatedDir,
|
|
12782
|
+
architecture
|
|
12783
|
+
});
|
|
12784
|
+
} catch (err) {
|
|
12785
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12786
|
+
if (!isJsonMode()) {
|
|
12787
|
+
printWarning(`barrel regeneration failed \u2014 ${msg}`);
|
|
12788
|
+
}
|
|
12789
|
+
}
|
|
12790
|
+
if (isJsonMode()) {
|
|
12791
|
+
printJson({
|
|
12792
|
+
command: "junction new",
|
|
12793
|
+
totals: {
|
|
12794
|
+
succeeded: succeeded.length,
|
|
12795
|
+
failed: failed.length
|
|
12796
|
+
},
|
|
12797
|
+
succeeded,
|
|
12798
|
+
failed,
|
|
12799
|
+
barrels: barrelResult ? {
|
|
12800
|
+
modules: barrelResult.modulesBarrel,
|
|
12801
|
+
schema: barrelResult.schemaBarrel,
|
|
12802
|
+
entityCount: barrelResult.entityCount
|
|
12803
|
+
} : null
|
|
12804
|
+
});
|
|
12805
|
+
} else {
|
|
12806
|
+
const total = validated.length + invalid.length;
|
|
12807
|
+
console.log("");
|
|
12808
|
+
if (failed.length === 0) {
|
|
12809
|
+
printSuccess(`${total} junctions \xB7 ${succeeded.length} succeeded`);
|
|
12810
|
+
} else {
|
|
12811
|
+
printWarning(
|
|
12812
|
+
`${total} junctions \xB7 ${succeeded.length} succeeded \xB7 ${failed.length} failed`
|
|
12813
|
+
);
|
|
12814
|
+
}
|
|
12815
|
+
if (barrelResult) {
|
|
12816
|
+
printInfo(
|
|
12817
|
+
`barrels regenerated (${barrelResult.entityCount} modules) \u2192 ${path27.relative(ctx.cwd, barrelResult.modulesBarrel)}, ${path27.relative(ctx.cwd, barrelResult.schemaBarrel)}`
|
|
12818
|
+
);
|
|
12819
|
+
}
|
|
12820
|
+
}
|
|
12821
|
+
return failed.length === 0 ? 0 : 1;
|
|
12822
|
+
}
|
|
12823
|
+
};
|
|
12824
|
+
var JunctionListCommand = class extends Command8 {
|
|
12825
|
+
static paths = [["junction", "list"]];
|
|
12826
|
+
static usage = Command8.Usage({
|
|
12827
|
+
description: "List defined junctions as a table"
|
|
12828
|
+
});
|
|
12829
|
+
json = Option8.Boolean("--json", false);
|
|
12830
|
+
cwd = Option8.String("--cwd", { required: false });
|
|
12831
|
+
configPath = Option8.String("--config", { required: false });
|
|
12832
|
+
async execute() {
|
|
12833
|
+
if (this.json) setJsonMode(true);
|
|
12834
|
+
const ctx = await loadContext({
|
|
12835
|
+
cwd: this.cwd,
|
|
12836
|
+
configPath: this.configPath,
|
|
12837
|
+
json: this.json,
|
|
12838
|
+
skipDetection: true
|
|
12839
|
+
});
|
|
12840
|
+
const junctionDir = path27.resolve(ctx.cwd, "junctions");
|
|
12841
|
+
const files = listJunctionYamls(junctionDir);
|
|
12842
|
+
if (files.length === 0) {
|
|
12843
|
+
printInfo("No junction definitions found.");
|
|
12844
|
+
return 0;
|
|
12845
|
+
}
|
|
12846
|
+
const rows = files.map(summarizeJunctionFile).filter((r) => r !== null);
|
|
12847
|
+
if (isJsonMode()) {
|
|
12848
|
+
printJson({
|
|
12849
|
+
command: "junction list",
|
|
12850
|
+
junctions: rows
|
|
12851
|
+
});
|
|
12852
|
+
return 0;
|
|
12853
|
+
}
|
|
12854
|
+
const nameW = Math.max(4, ...rows.map((r) => r.name.length));
|
|
12855
|
+
const leftW = Math.max(4, ...rows.map((r) => r.left.length));
|
|
12856
|
+
const rightW = Math.max(5, ...rows.map((r) => r.right.length));
|
|
12857
|
+
console.log(
|
|
12858
|
+
theme.muted(
|
|
12859
|
+
`${padRight3("NAME", nameW)} ${padRight3("LEFT", leftW)} ${padRight3("RIGHT", rightW)} ROLE FLAGS`
|
|
12860
|
+
)
|
|
12861
|
+
);
|
|
12862
|
+
for (const r of rows) {
|
|
12863
|
+
const flags = [r.temporal ? "T" : "", r.sourced ? "S" : ""].filter(Boolean).join(",");
|
|
12864
|
+
console.log(
|
|
12865
|
+
`${padRight3(r.name, nameW)} ${padRight3(r.left, leftW)} ${padRight3(r.right, rightW)} ${padRight3(r.hasRole ? "yes" : "no", 4)} ${flags}`
|
|
12866
|
+
);
|
|
12867
|
+
}
|
|
12868
|
+
return 0;
|
|
12869
|
+
}
|
|
12870
|
+
};
|
|
12871
|
+
var junctionNoun = {
|
|
12872
|
+
name: "junction",
|
|
12873
|
+
commandClasses: [JunctionNewCommand, JunctionListCommand],
|
|
12874
|
+
summary: summary6,
|
|
12875
|
+
hints: hints6
|
|
12876
|
+
};
|
|
12877
|
+
var junction_default = junctionNoun;
|
|
12878
|
+
|
|
12437
12879
|
// src/cli/commands/events.ts
|
|
12438
12880
|
import fs16 from "fs";
|
|
12439
|
-
import
|
|
12881
|
+
import path28 from "path";
|
|
12440
12882
|
import ts2 from "typescript";
|
|
12441
|
-
import { Command as
|
|
12883
|
+
import { Command as Command9, Option as Option9 } from "clipanion";
|
|
12442
12884
|
function scanSourceFileForConsumers(sourceFile, filePath, eventType) {
|
|
12443
12885
|
const tier2 = [];
|
|
12444
12886
|
const tier1 = [];
|
|
@@ -12572,7 +13014,7 @@ function suggestEventTypes(target, known, limit = 3) {
|
|
|
12572
13014
|
return known.map((t) => ({ t, d: levenshtein(target, t) })).sort((a, b) => a.d - b.d).slice(0, limit).map((x) => x.t);
|
|
12573
13015
|
}
|
|
12574
13016
|
function renderConsumerReport(result, cwd) {
|
|
12575
|
-
const rel = (p) =>
|
|
13017
|
+
const rel = (p) => path28.relative(cwd, p) || p;
|
|
12576
13018
|
const lines = [];
|
|
12577
13019
|
const total = result.tier3.length + result.tier2.length + result.tier1.length;
|
|
12578
13020
|
lines.push(`Event: ${result.eventType}`);
|
|
@@ -12608,7 +13050,7 @@ function renderConsumerReport(result, cwd) {
|
|
|
12608
13050
|
return lines;
|
|
12609
13051
|
}
|
|
12610
13052
|
function runConsumersScan(opts) {
|
|
12611
|
-
const scanRoot = opts.scanRoot ??
|
|
13053
|
+
const scanRoot = opts.scanRoot ?? path28.join(opts.cwd, "src");
|
|
12612
13054
|
const handlersDir = opts.handlersDir ?? scanRoot;
|
|
12613
13055
|
const allTriggers = scanHandlerFiles(handlersDir);
|
|
12614
13056
|
const tier3 = allTriggers.filter((t) => t.event === opts.eventType).map((t) => ({
|
|
@@ -12618,7 +13060,7 @@ function runConsumersScan(opts) {
|
|
|
12618
13060
|
sourceLine: t.sourceLine
|
|
12619
13061
|
}));
|
|
12620
13062
|
const tier21 = fs16.existsSync(scanRoot) ? scanDirectoryForConsumers(scanRoot, opts.eventType) : { tier2: [], tier1: [], hasEventFlowImport: false };
|
|
12621
|
-
const eventsGeneratedDir = opts.eventsGeneratedDir ??
|
|
13063
|
+
const eventsGeneratedDir = opts.eventsGeneratedDir ?? path28.join(
|
|
12622
13064
|
resolveSubsystemsRootFromContext(opts.cwd, opts.config),
|
|
12623
13065
|
"events",
|
|
12624
13066
|
"generated"
|
|
@@ -12639,15 +13081,15 @@ function runConsumersScan(opts) {
|
|
|
12639
13081
|
function resolveSubsystemsRootFromContext(cwd, config) {
|
|
12640
13082
|
const configured = config?.paths?.subsystems;
|
|
12641
13083
|
if (typeof configured === "string" && configured.length > 0) {
|
|
12642
|
-
return
|
|
13084
|
+
return path28.resolve(cwd, configured);
|
|
12643
13085
|
}
|
|
12644
13086
|
const backendSrc = config?.paths?.backend_src;
|
|
12645
13087
|
const base = typeof backendSrc === "string" && backendSrc.length > 0 ? backendSrc : "src";
|
|
12646
|
-
return
|
|
13088
|
+
return path28.resolve(cwd, base, "shared", "subsystems");
|
|
12647
13089
|
}
|
|
12648
|
-
var EventsConsumersCommand = class extends
|
|
13090
|
+
var EventsConsumersCommand = class extends Command9 {
|
|
12649
13091
|
static paths = [["events", "consumers"]];
|
|
12650
|
-
static usage =
|
|
13092
|
+
static usage = Command9.Usage({
|
|
12651
13093
|
description: "List all consumers of an event across the three tiers",
|
|
12652
13094
|
examples: [
|
|
12653
13095
|
[
|
|
@@ -12656,10 +13098,10 @@ var EventsConsumersCommand = class extends Command8 {
|
|
|
12656
13098
|
]
|
|
12657
13099
|
]
|
|
12658
13100
|
});
|
|
12659
|
-
eventType =
|
|
12660
|
-
json =
|
|
12661
|
-
cwd =
|
|
12662
|
-
configPath =
|
|
13101
|
+
eventType = Option9.String({ required: true });
|
|
13102
|
+
json = Option9.Boolean("--json", false);
|
|
13103
|
+
cwd = Option9.String("--cwd", { required: false });
|
|
13104
|
+
configPath = Option9.String("--config", { required: false });
|
|
12663
13105
|
async execute() {
|
|
12664
13106
|
if (this.json) setJsonMode(true);
|
|
12665
13107
|
const ctx = await loadContext({
|
|
@@ -12704,7 +13146,7 @@ var EventsConsumersCommand = class extends Command8 {
|
|
|
12704
13146
|
return 0;
|
|
12705
13147
|
}
|
|
12706
13148
|
};
|
|
12707
|
-
async function
|
|
13149
|
+
async function summary7(_ctx) {
|
|
12708
13150
|
return {
|
|
12709
13151
|
title: "events",
|
|
12710
13152
|
body: [
|
|
@@ -12715,7 +13157,7 @@ async function summary6(_ctx) {
|
|
|
12715
13157
|
]
|
|
12716
13158
|
};
|
|
12717
13159
|
}
|
|
12718
|
-
async function
|
|
13160
|
+
async function hints7(_ctx) {
|
|
12719
13161
|
return [
|
|
12720
13162
|
{
|
|
12721
13163
|
command: "codegen events consumers <type>",
|
|
@@ -12726,14 +13168,14 @@ async function hints6(_ctx) {
|
|
|
12726
13168
|
var eventsNoun = {
|
|
12727
13169
|
name: "events",
|
|
12728
13170
|
commandClasses: [EventsConsumersCommand],
|
|
12729
|
-
summary:
|
|
12730
|
-
hints:
|
|
13171
|
+
summary: summary7,
|
|
13172
|
+
hints: hints7
|
|
12731
13173
|
};
|
|
12732
13174
|
var events_default = eventsNoun;
|
|
12733
13175
|
|
|
12734
13176
|
// src/cli/commands/orchestration.ts
|
|
12735
|
-
import
|
|
12736
|
-
import { Command as
|
|
13177
|
+
import path29 from "path";
|
|
13178
|
+
import { Command as Command10, Option as Option10 } from "clipanion";
|
|
12737
13179
|
var DEFAULT_PATTERN_GLOBS = ["src/patterns/*.pattern.ts"];
|
|
12738
13180
|
function resolvePatternGlobs(ctx) {
|
|
12739
13181
|
const fromConfig = ctx.config?.patterns;
|
|
@@ -12746,26 +13188,26 @@ function resolveOrchestrationOutputRoot(ctx) {
|
|
|
12746
13188
|
const paths = ctx.config?.paths;
|
|
12747
13189
|
const explicit = paths?.orchestration_src;
|
|
12748
13190
|
if (typeof explicit === "string" && explicit.length > 0) {
|
|
12749
|
-
return
|
|
13191
|
+
return path29.resolve(ctx.cwd, explicit);
|
|
12750
13192
|
}
|
|
12751
13193
|
const backendSrc = typeof paths?.backend_src === "string" && paths.backend_src.length > 0 ? paths.backend_src : "app/backend/src";
|
|
12752
|
-
return
|
|
13194
|
+
return path29.resolve(ctx.cwd, backendSrc, "orchestration");
|
|
12753
13195
|
}
|
|
12754
13196
|
async function reloadRegistry(ctx) {
|
|
12755
13197
|
_resetRegistryForTests({ includeLibrary: false });
|
|
12756
13198
|
return loadAppPatterns(resolvePatternGlobs(ctx), ctx.cwd);
|
|
12757
13199
|
}
|
|
12758
|
-
var OrchestrationGenCommand = class extends
|
|
13200
|
+
var OrchestrationGenCommand = class extends Command10 {
|
|
12759
13201
|
static paths = [["orchestration", "gen"]];
|
|
12760
|
-
static usage =
|
|
13202
|
+
static usage = Command10.Usage({
|
|
12761
13203
|
description: "Emit token / providers / dispatcher / module files per orchestration pattern (ADR-032 Phase 3-2/3)."
|
|
12762
13204
|
});
|
|
12763
|
-
pattern =
|
|
12764
|
-
all =
|
|
12765
|
-
dryRun =
|
|
12766
|
-
json =
|
|
12767
|
-
cwd =
|
|
12768
|
-
configPath =
|
|
13205
|
+
pattern = Option10.String("--pattern", { required: false });
|
|
13206
|
+
all = Option10.Boolean("--all", false);
|
|
13207
|
+
dryRun = Option10.Boolean("--dry-run", false);
|
|
13208
|
+
json = Option10.Boolean("--json", false);
|
|
13209
|
+
cwd = Option10.String("--cwd", { required: false });
|
|
13210
|
+
configPath = Option10.String("--config", { required: false });
|
|
12769
13211
|
async execute() {
|
|
12770
13212
|
if (this.json) setJsonMode(true);
|
|
12771
13213
|
const ctx = await loadContext({
|
|
@@ -12838,12 +13280,12 @@ var OrchestrationGenCommand = class extends Command9 {
|
|
|
12838
13280
|
);
|
|
12839
13281
|
for (const f of result.files) {
|
|
12840
13282
|
console.log(
|
|
12841
|
-
` ${theme.muted(icons.arrow)} ${
|
|
13283
|
+
` ${theme.muted(icons.arrow)} ${path29.relative(ctx.cwd, f.outputPath)}`
|
|
12842
13284
|
);
|
|
12843
13285
|
}
|
|
12844
13286
|
} else {
|
|
12845
13287
|
printSuccess(
|
|
12846
|
-
`Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${
|
|
13288
|
+
`Emitted ${result.files.length} file(s) across ${targets.length} pattern(s) \u2192 ${path29.relative(ctx.cwd, outputRoot)}`
|
|
12847
13289
|
);
|
|
12848
13290
|
}
|
|
12849
13291
|
return 0;
|
|
@@ -12856,14 +13298,14 @@ var OrchestrationGenCommand = class extends Command9 {
|
|
|
12856
13298
|
}
|
|
12857
13299
|
}
|
|
12858
13300
|
};
|
|
12859
|
-
var OrchestrationListCommand = class extends
|
|
13301
|
+
var OrchestrationListCommand = class extends Command10 {
|
|
12860
13302
|
static paths = [["orchestration", "list"]];
|
|
12861
|
-
static usage =
|
|
13303
|
+
static usage = Command10.Usage({
|
|
12862
13304
|
description: "List registered orchestration patterns"
|
|
12863
13305
|
});
|
|
12864
|
-
json =
|
|
12865
|
-
cwd =
|
|
12866
|
-
configPath =
|
|
13306
|
+
json = Option10.Boolean("--json", false);
|
|
13307
|
+
cwd = Option10.String("--cwd", { required: false });
|
|
13308
|
+
configPath = Option10.String("--config", { required: false });
|
|
12867
13309
|
async execute() {
|
|
12868
13310
|
if (this.json) setJsonMode(true);
|
|
12869
13311
|
const ctx = await loadContext({
|
|
@@ -12907,14 +13349,14 @@ var OrchestrationListCommand = class extends Command9 {
|
|
|
12907
13349
|
return 0;
|
|
12908
13350
|
}
|
|
12909
13351
|
};
|
|
12910
|
-
var OrchestrationValidateCommand = class extends
|
|
13352
|
+
var OrchestrationValidateCommand = class extends Command10 {
|
|
12911
13353
|
static paths = [["orchestration", "validate"]];
|
|
12912
|
-
static usage =
|
|
13354
|
+
static usage = Command10.Usage({
|
|
12913
13355
|
description: "Run the Phase 3-1 project-level orchestration validator (ADR-032)"
|
|
12914
13356
|
});
|
|
12915
|
-
json =
|
|
12916
|
-
cwd =
|
|
12917
|
-
configPath =
|
|
13357
|
+
json = Option10.Boolean("--json", false);
|
|
13358
|
+
cwd = Option10.String("--cwd", { required: false });
|
|
13359
|
+
configPath = Option10.String("--config", { required: false });
|
|
12918
13360
|
async execute() {
|
|
12919
13361
|
if (this.json) setJsonMode(true);
|
|
12920
13362
|
const ctx = await loadContext({
|
|
@@ -12950,7 +13392,7 @@ var OrchestrationValidateCommand = class extends Command9 {
|
|
|
12950
13392
|
return errors.length === 0 && loadResult.errors.length === 0 ? 0 : 1;
|
|
12951
13393
|
}
|
|
12952
13394
|
};
|
|
12953
|
-
async function
|
|
13395
|
+
async function summary8(ctx) {
|
|
12954
13396
|
try {
|
|
12955
13397
|
await reloadRegistry(ctx);
|
|
12956
13398
|
} catch {
|
|
@@ -12964,7 +13406,7 @@ async function summary7(ctx) {
|
|
|
12964
13406
|
]
|
|
12965
13407
|
};
|
|
12966
13408
|
}
|
|
12967
|
-
async function
|
|
13409
|
+
async function hints8(_ctx) {
|
|
12968
13410
|
return [
|
|
12969
13411
|
{
|
|
12970
13412
|
command: "codegen orchestration gen",
|
|
@@ -12987,8 +13429,8 @@ var orchestrationNoun = {
|
|
|
12987
13429
|
OrchestrationListCommand,
|
|
12988
13430
|
OrchestrationValidateCommand
|
|
12989
13431
|
],
|
|
12990
|
-
summary:
|
|
12991
|
-
hints:
|
|
13432
|
+
summary: summary8,
|
|
13433
|
+
hints: hints8
|
|
12992
13434
|
};
|
|
12993
13435
|
var orchestration_default = orchestrationNoun;
|
|
12994
13436
|
|
|
@@ -13009,9 +13451,9 @@ function readVersion() {
|
|
|
13009
13451
|
return "0.0.0";
|
|
13010
13452
|
}
|
|
13011
13453
|
}
|
|
13012
|
-
var RootSummaryCommand = class extends
|
|
13013
|
-
static paths = [
|
|
13014
|
-
static usage =
|
|
13454
|
+
var RootSummaryCommand = class extends Command11 {
|
|
13455
|
+
static paths = [Command11.Default];
|
|
13456
|
+
static usage = Command11.Usage({
|
|
13015
13457
|
description: "Show project status and available noun commands"
|
|
13016
13458
|
});
|
|
13017
13459
|
async execute() {
|
|
@@ -13055,6 +13497,7 @@ var nouns = [
|
|
|
13055
13497
|
project_default,
|
|
13056
13498
|
dev_default,
|
|
13057
13499
|
relationship_default,
|
|
13500
|
+
junction_default,
|
|
13058
13501
|
events_default,
|
|
13059
13502
|
orchestration_default
|
|
13060
13503
|
];
|