@specverse/engines 6.7.8 → 6.16.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/dist/ai/behavior-ai-service.js +2 -2
- package/dist/ai/behavior-ai-service.js.map +1 -1
- package/dist/inference/core/specly-converter.d.ts.map +1 -1
- package/dist/inference/core/specly-converter.js +20 -0
- package/dist/inference/core/specly-converter.js.map +1 -1
- package/dist/inference/index.d.ts.map +1 -1
- package/dist/inference/index.js +72 -22
- package/dist/inference/index.js.map +1 -1
- package/dist/inference/logical/generators/controller-generator.d.ts.map +1 -1
- package/dist/inference/logical/generators/controller-generator.js +26 -4
- package/dist/inference/logical/generators/controller-generator.js.map +1 -1
- package/dist/libs/instance-factories/applications/templates/generic/backend-package-json-generator.js +22 -5
- package/dist/libs/instance-factories/controllers/templates/fastify/routes-generator.js +50 -15
- package/dist/libs/instance-factories/controllers/templates/fastify/server-generator.js +26 -6
- package/dist/libs/instance-factories/services/postgres-native-services.yaml +90 -0
- package/dist/libs/instance-factories/services/templates/_shared/step-matching.js +44 -0
- package/dist/libs/instance-factories/services/templates/mongodb-native/controller-generator.js +68 -13
- package/dist/libs/instance-factories/services/templates/mongodb-native/step-conventions.js +515 -0
- package/dist/libs/instance-factories/services/templates/postgres-native/client-generator.js +165 -0
- package/dist/libs/instance-factories/services/templates/postgres-native/controller-generator.js +300 -0
- package/dist/libs/instance-factories/services/templates/postgres-native/ddl-generator.js +169 -0
- package/dist/libs/instance-factories/services/templates/postgres-native/service-generator.js +65 -0
- package/dist/libs/instance-factories/services/templates/postgres-native/step-conventions.js +433 -0
- package/dist/libs/instance-factories/services/templates/prisma/ai-behaviors-generator.js +27 -4
- package/dist/libs/instance-factories/services/templates/prisma/step-conventions.js +7 -34
- package/dist/parser/processors/ExecutableProcessor.d.ts.map +1 -1
- package/dist/parser/processors/ExecutableProcessor.js +14 -1
- package/dist/parser/processors/ExecutableProcessor.js.map +1 -1
- package/dist/realize/index.d.ts.map +1 -1
- package/dist/realize/index.js +30 -3
- package/dist/realize/index.js.map +1 -1
- package/libs/instance-factories/applications/templates/generic/backend-package-json-generator.ts +46 -24
- package/libs/instance-factories/controllers/templates/fastify/routes-generator.ts +80 -21
- package/libs/instance-factories/controllers/templates/fastify/server-generator.ts +48 -7
- package/libs/instance-factories/services/postgres-native-services.yaml +90 -0
- package/libs/instance-factories/services/templates/_shared/step-matching.ts +103 -0
- package/libs/instance-factories/services/templates/mongodb-native/controller-generator.ts +97 -23
- package/libs/instance-factories/services/templates/mongodb-native/step-conventions.ts +691 -0
- package/libs/instance-factories/services/templates/postgres-native/__tests__/controller-generator.test.ts +193 -0
- package/libs/instance-factories/services/templates/postgres-native/client-generator.ts +178 -0
- package/libs/instance-factories/services/templates/postgres-native/controller-generator.ts +372 -0
- package/libs/instance-factories/services/templates/postgres-native/ddl-generator.ts +236 -0
- package/libs/instance-factories/services/templates/postgres-native/service-generator.ts +84 -0
- package/libs/instance-factories/services/templates/postgres-native/step-conventions.ts +539 -0
- package/libs/instance-factories/services/templates/prisma/ai-behaviors-generator.ts +61 -7
- package/libs/instance-factories/services/templates/prisma/step-conventions.ts +21 -68
- package/package.json +4 -3
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
name: PostgresNativeDriver
|
|
2
|
+
version: "1.0.0"
|
|
3
|
+
category: service
|
|
4
|
+
description: "Business logic services using the native node-postgres (pg) driver — raw SQL, no ORM layer"
|
|
5
|
+
|
|
6
|
+
metadata:
|
|
7
|
+
author: "SpecVerse Team"
|
|
8
|
+
license: "MIT"
|
|
9
|
+
tags: [services, business-logic, postgres, pg, native-driver, controllers]
|
|
10
|
+
|
|
11
|
+
compatibility:
|
|
12
|
+
specverse: ">=5.0.0"
|
|
13
|
+
node: ">=18.0.0"
|
|
14
|
+
|
|
15
|
+
# Same shape as MongoDBNativeDriver — the pg pool IS the data layer; no ORM
|
|
16
|
+
# layer to swap in independently. This single factory therefore provides
|
|
17
|
+
# both the orm.* capabilities and the service-layer capabilities.
|
|
18
|
+
capabilities:
|
|
19
|
+
provides:
|
|
20
|
+
- "orm.schema" # Emits the pg pool client + DDL (the connection IS the schema layer)
|
|
21
|
+
- "orm.client"
|
|
22
|
+
- "orm.postgres.native"
|
|
23
|
+
- "service.controller"
|
|
24
|
+
- "service.business"
|
|
25
|
+
- "service.crud"
|
|
26
|
+
requires:
|
|
27
|
+
- "storage.database.relational"
|
|
28
|
+
|
|
29
|
+
technology:
|
|
30
|
+
runtime: "node"
|
|
31
|
+
language: "typescript"
|
|
32
|
+
orm: "postgres-native"
|
|
33
|
+
version: "^8.11.0"
|
|
34
|
+
|
|
35
|
+
dependencies:
|
|
36
|
+
runtime:
|
|
37
|
+
- name: "pg"
|
|
38
|
+
version: "^8.11.0"
|
|
39
|
+
|
|
40
|
+
dev:
|
|
41
|
+
- name: "@types/pg"
|
|
42
|
+
version: "^8.11.0"
|
|
43
|
+
- name: "@types/node"
|
|
44
|
+
version: "^20.8.0"
|
|
45
|
+
- name: "typescript"
|
|
46
|
+
version: "^5.2.0"
|
|
47
|
+
|
|
48
|
+
codeTemplates:
|
|
49
|
+
# `schema` slot emits the pg pool singleton + a co-located CREATE TABLE
|
|
50
|
+
# script (schema.sql) so users can bootstrap a database without pulling
|
|
51
|
+
# in an external migrator. The pool generator owns the runtime
|
|
52
|
+
# connection; the DDL generator owns the static SQL.
|
|
53
|
+
schema:
|
|
54
|
+
engine: typescript
|
|
55
|
+
generator: "libs/instance-factories/services/templates/postgres-native/client-generator.ts"
|
|
56
|
+
outputPattern: "{backendDir}/src/db/pgClient.ts"
|
|
57
|
+
|
|
58
|
+
ddl:
|
|
59
|
+
engine: typescript
|
|
60
|
+
generator: "libs/instance-factories/services/templates/postgres-native/ddl-generator.ts"
|
|
61
|
+
outputPattern: "{backendDir}/src/db/schema.sql"
|
|
62
|
+
|
|
63
|
+
controllers:
|
|
64
|
+
engine: typescript
|
|
65
|
+
generator: "libs/instance-factories/services/templates/postgres-native/controller-generator.ts"
|
|
66
|
+
outputPattern: "{backendDir}/src/controllers/{model}Controller.ts"
|
|
67
|
+
|
|
68
|
+
services:
|
|
69
|
+
engine: typescript
|
|
70
|
+
generator: "libs/instance-factories/services/templates/postgres-native/service-generator.ts"
|
|
71
|
+
outputPattern: "{backendDir}/src/services/{service}.ts"
|
|
72
|
+
|
|
73
|
+
configuration:
|
|
74
|
+
outputStructure: "monorepo"
|
|
75
|
+
backendDir: "backend"
|
|
76
|
+
tableNaming: "lowercase-pluralized" # User → users, OrderItem → orderitems
|
|
77
|
+
validation: true
|
|
78
|
+
eventPublishing: true
|
|
79
|
+
errorHandling: "throw"
|
|
80
|
+
|
|
81
|
+
requirements:
|
|
82
|
+
dependencies:
|
|
83
|
+
npm:
|
|
84
|
+
dependencies:
|
|
85
|
+
"pg": "^8.11.0"
|
|
86
|
+
environment:
|
|
87
|
+
- name: "POSTGRES_URL"
|
|
88
|
+
description: "PostgreSQL connection string (e.g. postgres://user:pass@localhost:5432/myapp)"
|
|
89
|
+
required: true
|
|
90
|
+
configuration: {}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared step-matching machinery — common helpers + the canonical
|
|
3
|
+
* `matchAgainstConventions` walker that any ORM-specific step-conventions
|
|
4
|
+
* library can compose with.
|
|
5
|
+
*
|
|
6
|
+
* Each ORM library (prisma, mongodb-native) exports its own
|
|
7
|
+
* `STEP_CONVENTIONS` array of `{name, pattern, generateCall}` items
|
|
8
|
+
* describing what code to emit for matched patterns. The matcher itself
|
|
9
|
+
* is identical across libraries: walk the conventions in order, first
|
|
10
|
+
* match wins; if nothing matches, compute the AI-fallback shape
|
|
11
|
+
* (functionName + inputs + resultVar) deterministically.
|
|
12
|
+
*
|
|
13
|
+
* Extracted from prisma/step-conventions.ts and mongodb-native/step-conventions.ts
|
|
14
|
+
* so future ORM libraries can drop in just the conventions array
|
|
15
|
+
* without re-implementing matching logic. (#43K-D)
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Camel-case a step's text into a TS identifier. Identical algorithm
|
|
19
|
+
* across all ORM libraries — function names emitted in `aiBehaviors.<X>(...)`
|
|
20
|
+
* calls must agree with the function declarations the AI-behaviors-generator
|
|
21
|
+
* emits. Both sides go through this. */
|
|
22
|
+
export function toMethod(words: string): string {
|
|
23
|
+
const cleaned = words.trim().replace(/[^A-Za-z0-9\s]+/g, ' ');
|
|
24
|
+
const camel = cleaned.replace(/\s+(.)/g, (_, c) => c.toUpperCase()).replace(/^\w/, (c) => c.toLowerCase());
|
|
25
|
+
const safe = camel.replace(/[^A-Za-z0-9_$]/g, '');
|
|
26
|
+
return safe || 'unnamedStep';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function toVar(name: string): string {
|
|
30
|
+
return name.charAt(0).toLowerCase() + name.slice(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface SharedStepContext {
|
|
34
|
+
modelName: string;
|
|
35
|
+
serviceName: string;
|
|
36
|
+
operationName: string;
|
|
37
|
+
stepNum: number;
|
|
38
|
+
parameterNames?: string[];
|
|
39
|
+
declaredVars?: Set<string>;
|
|
40
|
+
resultName?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface SharedConvention<C extends SharedStepContext = SharedStepContext> {
|
|
44
|
+
name: string;
|
|
45
|
+
pattern: RegExp;
|
|
46
|
+
/** Emit inline code for this step. Return empty string to signal
|
|
47
|
+
* "regex matched but I can't safely emit" (caller falls through to AI). */
|
|
48
|
+
generateCall: (match: RegExpMatchArray, ctx: C) => string;
|
|
49
|
+
/** Optional helper-method body that some libraries (e.g. prisma's
|
|
50
|
+
* `check {condition}` convention) emit alongside the call site. */
|
|
51
|
+
generateMethod?: (match: RegExpMatchArray, ctx: C) => string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface MatchResult {
|
|
55
|
+
matched: boolean;
|
|
56
|
+
call: string;
|
|
57
|
+
helperMethod?: string;
|
|
58
|
+
functionName?: string;
|
|
59
|
+
inputs?: string[];
|
|
60
|
+
resultVar?: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Walk conventions in order. First match wins (with empty-string fallthrough).
|
|
64
|
+
* Unmatched: compute the AI-delegate call site shape so the controller and
|
|
65
|
+
* the AI-behaviors-generator agree on function name + inputs + resultVar. */
|
|
66
|
+
export function matchAgainstConventions<C extends SharedStepContext>(
|
|
67
|
+
step: string,
|
|
68
|
+
ctx: C,
|
|
69
|
+
conventions: ReadonlyArray<SharedConvention<C>>,
|
|
70
|
+
aiArgsExpr: (inputs: string[], paramNames: string[]) => string,
|
|
71
|
+
): MatchResult {
|
|
72
|
+
for (const convention of conventions) {
|
|
73
|
+
const m = step.match(convention.pattern);
|
|
74
|
+
if (m) {
|
|
75
|
+
const call = convention.generateCall(m, ctx);
|
|
76
|
+
if (call) {
|
|
77
|
+
return {
|
|
78
|
+
matched: true,
|
|
79
|
+
call,
|
|
80
|
+
helperMethod: convention.generateMethod?.(m, ctx),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// AI fallback shape — same across all ORMs.
|
|
87
|
+
const functionName = toMethod(step);
|
|
88
|
+
const declared = Array.from(ctx.declaredVars || []);
|
|
89
|
+
const paramNames = ctx.parameterNames || [];
|
|
90
|
+
const inputs = [...paramNames, ...declared];
|
|
91
|
+
const resultVar = ctx.resultName || `step${ctx.stepNum}Result`;
|
|
92
|
+
if (ctx.declaredVars) ctx.declaredVars.add(resultVar);
|
|
93
|
+
const inputObj = aiArgsExpr(inputs, paramNames);
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
matched: false,
|
|
97
|
+
call: ` // Step ${ctx.stepNum}: ${step} [AI-generated — pure transform]
|
|
98
|
+
const ${resultVar} = await aiBehaviors.${functionName}(${inputObj});`,
|
|
99
|
+
functionName,
|
|
100
|
+
inputs,
|
|
101
|
+
resultVar,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
@@ -26,7 +26,7 @@ import type { TemplateContext } from '@specverse/types';
|
|
|
26
26
|
import { buildTransitionMap, isAutoField } from '@specverse/types/spec-rules';
|
|
27
27
|
|
|
28
28
|
export default function generateMongoNativeController(context: TemplateContext): string {
|
|
29
|
-
const { controller, model } = context;
|
|
29
|
+
const { controller, model, models } = context as any;
|
|
30
30
|
if (!controller) throw new Error('Controller is required in template context');
|
|
31
31
|
if (!model) throw new Error('Model is required for controller generation');
|
|
32
32
|
|
|
@@ -36,7 +36,17 @@ export default function generateMongoNativeController(context: TemplateContext):
|
|
|
36
36
|
const collection = collectionName(model);
|
|
37
37
|
const curedOps = controller.cured || {};
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
// Build a name → ModelSpec registry once so step-conventions can read
|
|
40
|
+
// attribute defaults (level: 1, totalResources: '', etc.) and FK targets
|
|
41
|
+
// when emitting create/insertMany code (#43K-A).
|
|
42
|
+
const modelRegistry: Record<string, any> = {};
|
|
43
|
+
if (Array.isArray(models)) {
|
|
44
|
+
for (const m of models) if (m?.name) modelRegistry[m.name] = m;
|
|
45
|
+
} else if (models && typeof models === 'object') {
|
|
46
|
+
Object.assign(modelRegistry, models);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const customActions = generateCustomActions(controller, modelRegistry);
|
|
40
50
|
|
|
41
51
|
const validate = generateValidateMethod(model, modelName);
|
|
42
52
|
const create = curedOps.create ? generateCreateMethod(model, modelName, modelVar, collection) : '';
|
|
@@ -55,7 +65,8 @@ export default function generateMongoNativeController(context: TemplateContext):
|
|
|
55
65
|
*/
|
|
56
66
|
import { ObjectId, type Filter, type Document } from 'mongodb';
|
|
57
67
|
import { getCollection } from '../db/mongoClient.js';
|
|
58
|
-
${hasEventPublishing ? `import { eventBus } from '../events/eventBus.js';` : ''}
|
|
68
|
+
${hasEventPublishing || customActions.needsAiBehaviors ? `import { eventBus } from '../events/eventBus.js';` : ''}
|
|
69
|
+
${customActions.needsAiBehaviors ? `import * as aiBehaviors from '../behaviors/${controllerName}.ai.js';` : ''}
|
|
59
70
|
|
|
60
71
|
const COLLECTION_NAME = '${collection}';
|
|
61
72
|
|
|
@@ -275,29 +286,96 @@ function generateDeleteMethod(modelName: string, modelVar: string, collection: s
|
|
|
275
286
|
|
|
276
287
|
interface CustomActionsResult {
|
|
277
288
|
code: string;
|
|
289
|
+
needsAiBehaviors: boolean;
|
|
278
290
|
}
|
|
279
291
|
|
|
280
292
|
/**
|
|
281
|
-
* Custom actions emit
|
|
293
|
+
* Custom actions emit a per-step body using `matchMongoStep`. The same
|
|
294
|
+
* matcher is passed to the AI-behaviors-generator (via realize/index.ts)
|
|
295
|
+
* so both sides accumulate the same `declaredVars` set and produce
|
|
296
|
+
* matching function names + inputs for unmatched steps.
|
|
282
297
|
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
* Real implementation of action bodies is deferred to the MongoDB-native
|
|
289
|
-
* step-conventions library (#43F follow-up — mirror Prisma's
|
|
290
|
-
* step-conventions.ts but emit native-driver collection calls).
|
|
298
|
+
* Per step:
|
|
299
|
+
* - matched → emit conventional native-driver code inline
|
|
300
|
+
* - unmatched → emit `const stepNResult = await aiBehaviors.<funcName>({...});`
|
|
301
|
+
* (the aiBehaviors function comes from the controller's `*.ai.ts`
|
|
302
|
+
* file, generated by AI-behaviors-generator using the SAME matcher).
|
|
291
303
|
*/
|
|
292
|
-
|
|
304
|
+
import { matchMongoStep, type MongoStepContext } from './step-conventions.js';
|
|
305
|
+
|
|
306
|
+
function generateCustomActions(controller: any, modelRegistry: Record<string, any> = {}): CustomActionsResult {
|
|
293
307
|
if (!controller.actions || Object.keys(controller.actions).length === 0) {
|
|
294
|
-
return { code: '' };
|
|
308
|
+
return { code: '', needsAiBehaviors: false };
|
|
295
309
|
}
|
|
310
|
+
const CRUD_NAMES = new Set(['create', 'retrieve', 'retrieveAll', 'update', 'evolve', 'delete', 'validate']);
|
|
311
|
+
const modelName = controller.model || (controller.name || '').replace(/Controller$/, '') || 'Model';
|
|
312
|
+
const collectionName = modelName.toLowerCase() + 's';
|
|
296
313
|
const out: string[] = [];
|
|
314
|
+
let needsAiBehaviors = false;
|
|
297
315
|
for (const [actionName, action] of Object.entries<any>(controller.actions)) {
|
|
298
|
-
|
|
299
|
-
|
|
316
|
+
if (CRUD_NAMES.has(actionName)) {
|
|
317
|
+
// Surface the collision so spec authors aren't silently losing
|
|
318
|
+
// a declared action. Going forward this could escalate to an
|
|
319
|
+
// error or auto-rename; for now a warning keeps existing specs
|
|
320
|
+
// building while making the dropped behaviour visible.
|
|
321
|
+
console.warn(
|
|
322
|
+
`⚠️ ${controller.name || 'Controller'}.${actionName} — behaviour-derived action collides with the auto-generated CURVED \`${actionName}\` op. Dropped to avoid TS2393 duplicate-implementation. Rename the behaviour (e.g. \`${actionName}Soft\` / \`hardDelete\`) if you need the custom logic.`
|
|
323
|
+
);
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
const steps: any[] = Array.isArray(action.steps) ? action.steps : [];
|
|
327
|
+
const stepsHeader = steps.length > 0
|
|
328
|
+
? steps.map((s: any) => ` * - ${typeof s === 'string' ? s : (s.action || JSON.stringify(s))}`).join('\n')
|
|
300
329
|
: ' * (no spec steps declared)';
|
|
330
|
+
|
|
331
|
+
const declaredVars = new Set<string>();
|
|
332
|
+
const stepBodies: string[] = [];
|
|
333
|
+
let usesArgs = false;
|
|
334
|
+
let actionRefersToAi = false;
|
|
335
|
+
steps.forEach((rawStep: any, i: number) => {
|
|
336
|
+
const stepText = typeof rawStep === 'string' ? rawStep : (rawStep?.step || rawStep?.action);
|
|
337
|
+
if (typeof stepText !== 'string') {
|
|
338
|
+
stepBodies.push(` // Step ${i + 1}: (non-string step ignored)`);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const ctx: MongoStepContext = {
|
|
342
|
+
modelName,
|
|
343
|
+
collectionName,
|
|
344
|
+
serviceName: controller.name || 'Controller',
|
|
345
|
+
operationName: actionName,
|
|
346
|
+
stepNum: i + 1,
|
|
347
|
+
parameterNames: Object.keys(action.parameters || {}),
|
|
348
|
+
declaredVars,
|
|
349
|
+
models: modelRegistry,
|
|
350
|
+
};
|
|
351
|
+
const result = matchMongoStep(stepText, ctx);
|
|
352
|
+
stepBodies.push(result.call);
|
|
353
|
+
if (/\bargs\./.test(result.call)) usesArgs = true;
|
|
354
|
+
if (!result.matched) actionRefersToAi = true;
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
if (actionRefersToAi) needsAiBehaviors = true;
|
|
358
|
+
const argsParam = usesArgs ? 'args: any = {}' : '_args: any = {}';
|
|
359
|
+
let combined = stepBodies.join('\n\n');
|
|
360
|
+
// Drop the `const stepNResult =` declaration when no later step
|
|
361
|
+
// references the result. Strict tsc's noUnusedLocals applies to
|
|
362
|
+
// locals regardless of underscore prefix, so the only safe fix is
|
|
363
|
+
// to omit the assignment entirely. The await still fires.
|
|
364
|
+
const stepResultRe = /const\s+(step\d+Result)\s*=/g;
|
|
365
|
+
let mres: RegExpExecArray | null;
|
|
366
|
+
const declared: string[] = [];
|
|
367
|
+
while ((mres = stepResultRe.exec(combined)) !== null) declared.push(mres[1]);
|
|
368
|
+
for (const name of declared) {
|
|
369
|
+
const refCount = (combined.match(new RegExp(`\\b${name}\\b`, 'g')) || []).length;
|
|
370
|
+
if (refCount <= 1) {
|
|
371
|
+
// Only the declaration itself — drop the binding, keep the await.
|
|
372
|
+
combined = combined.replace(new RegExp(`const\\s+${name}\\s*=\\s*`), '');
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
const body = steps.length > 0
|
|
376
|
+
? combined + `\n return { success: true };`
|
|
377
|
+
: ` throw new Error('${controller.name || 'Controller'}.${actionName} is not implemented');`;
|
|
378
|
+
|
|
301
379
|
out.push(`
|
|
302
380
|
/**
|
|
303
381
|
* ${actionName}
|
|
@@ -306,14 +384,10 @@ function generateCustomActions(controller: any): CustomActionsResult {
|
|
|
306
384
|
* Spec steps:
|
|
307
385
|
${stepsHeader}
|
|
308
386
|
*/
|
|
309
|
-
public async ${actionName}(
|
|
310
|
-
|
|
311
|
-
// via a mongodb-native step-conventions library (mirror of the prisma
|
|
312
|
-
// one). For now this is a stub so realize completes and the action
|
|
313
|
-
// surface is callable for parity tests.
|
|
314
|
-
throw new Error('${controller.name}.${actionName} is not implemented');
|
|
387
|
+
public async ${actionName}(${argsParam}): Promise<any> {
|
|
388
|
+
${body}
|
|
315
389
|
}
|
|
316
390
|
`);
|
|
317
391
|
}
|
|
318
|
-
return { code: out.join('\n') };
|
|
392
|
+
return { code: out.join('\n'), needsAiBehaviors };
|
|
319
393
|
}
|