@auto-engineer/server-generator-apollo-emmett 1.104.0 → 1.105.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +6 -6
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +66 -0
- package/dist/src/codegen/scaffoldFromSchema.d.ts +10 -0
- package/dist/src/codegen/scaffoldFromSchema.d.ts.map +1 -1
- package/dist/src/codegen/scaffoldFromSchema.js +55 -20
- package/dist/src/codegen/scaffoldFromSchema.js.map +1 -1
- package/dist/src/codegen/templates/command/decide.specs.ts +16 -4
- package/dist/src/codegen/templates/command/decide.ts.ejs +4 -1
- package/dist/src/codegen/templates/command/evolve.specs.ts +16 -15
- package/dist/src/codegen/templates/command/evolve.ts.ejs +16 -15
- package/dist/src/codegen/templates/command/handle.specs.ts +146 -0
- package/dist/src/codegen/templates/command/handle.ts.ejs +21 -1
- package/dist/src/codegen/templates/query/projection.specs.ts +4 -1
- package/dist/src/codegen/templates/query/projection.ts.ejs +7 -1
- package/dist/src/codegen/templates/react/react.specs.specs.ts +0 -32
- package/dist/src/codegen/templates/react/react.ts.specs.ts +0 -49
- package/dist/src/commands/generate-server.d.ts +4 -0
- package/dist/src/commands/generate-server.d.ts.map +1 -1
- package/dist/src/commands/generate-server.js +37 -3
- package/dist/src/commands/generate-server.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/ketchup-plan.md +2 -0
- package/package.json +4 -4
- package/src/codegen/formatTsValue.specs.ts +12 -0
- package/src/codegen/formatTsValueSimple.specs.ts +1 -1
- package/src/codegen/scaffoldErrors.specs.ts +40 -0
- package/src/codegen/scaffoldFromSchema.ts +70 -31
- package/src/codegen/templates/command/decide.specs.ts +16 -4
- package/src/codegen/templates/command/decide.ts.ejs +4 -1
- package/src/codegen/templates/command/evolve.specs.ts +16 -15
- package/src/codegen/templates/command/evolve.ts.ejs +16 -15
- package/src/codegen/templates/command/handle.specs.ts +146 -0
- package/src/codegen/templates/command/handle.ts.ejs +21 -1
- package/src/codegen/templates/query/projection.specs.ts +4 -1
- package/src/codegen/templates/query/projection.ts.ejs +7 -1
- package/src/codegen/templates/react/react.specs.specs.ts +0 -32
- package/src/codegen/templates/react/react.ts.specs.ts +0 -49
- package/src/commands/generate-server.specs.ts +71 -0
- package/src/commands/generate-server.ts +45 -2
|
@@ -72,14 +72,6 @@ describe('react.specs.ts.ejs (react slice)', () => {
|
|
|
72
72
|
name: 'Send notification to host',
|
|
73
73
|
server: {
|
|
74
74
|
description: 'Sends a host notification command in response to BookingRequested',
|
|
75
|
-
data: {
|
|
76
|
-
items: [
|
|
77
|
-
{
|
|
78
|
-
target: { type: 'Command', name: 'NotifyHost' },
|
|
79
|
-
destination: { type: 'stream', pattern: 'booking-${hostId}' },
|
|
80
|
-
},
|
|
81
|
-
],
|
|
82
|
-
},
|
|
83
75
|
specs: [
|
|
84
76
|
{
|
|
85
77
|
type: 'gherkin',
|
|
@@ -291,14 +283,6 @@ describe('react.specs.ts.ejs (react slice)', () => {
|
|
|
291
283
|
name: 'Process tip after completion',
|
|
292
284
|
server: {
|
|
293
285
|
description: 'Processes tip command after appointment completion',
|
|
294
|
-
data: {
|
|
295
|
-
items: [
|
|
296
|
-
{
|
|
297
|
-
target: { type: 'Command', name: 'ProcessTip' },
|
|
298
|
-
destination: { type: 'stream', pattern: 'tips-${appointmentId}' },
|
|
299
|
-
},
|
|
300
|
-
],
|
|
301
|
-
},
|
|
302
286
|
specs: [
|
|
303
287
|
{
|
|
304
288
|
type: 'gherkin',
|
|
@@ -409,14 +393,6 @@ describe('react.specs.ts.ejs (react slice)', () => {
|
|
|
409
393
|
name: 'notify milestone',
|
|
410
394
|
server: {
|
|
411
395
|
description: 'Notifies on milestone',
|
|
412
|
-
data: {
|
|
413
|
-
items: [
|
|
414
|
-
{
|
|
415
|
-
target: { type: 'Command', name: 'SendNotification' },
|
|
416
|
-
destination: { type: 'stream', pattern: 'notif-${memberId}' },
|
|
417
|
-
},
|
|
418
|
-
],
|
|
419
|
-
},
|
|
420
396
|
specs: [
|
|
421
397
|
{
|
|
422
398
|
type: 'gherkin',
|
|
@@ -532,14 +508,6 @@ describe('react.specs.ts.ejs (react slice)', () => {
|
|
|
532
508
|
name: 'notify barber of cancellation',
|
|
533
509
|
server: {
|
|
534
510
|
description: 'Notifies barber when appointment is cancelled',
|
|
535
|
-
data: {
|
|
536
|
-
items: [
|
|
537
|
-
{
|
|
538
|
-
target: { type: 'Command', name: 'NotifyBarber' },
|
|
539
|
-
destination: { type: 'stream', pattern: 'barber-${barberId}' },
|
|
540
|
-
},
|
|
541
|
-
],
|
|
542
|
-
},
|
|
543
511
|
specs: [
|
|
544
512
|
{
|
|
545
513
|
type: 'gherkin',
|
|
@@ -15,14 +15,6 @@ describe('react.ts.ejs', () => {
|
|
|
15
15
|
name: 'missing-when-slice',
|
|
16
16
|
server: {
|
|
17
17
|
description: 'A react slice with no When step',
|
|
18
|
-
data: {
|
|
19
|
-
items: [
|
|
20
|
-
{
|
|
21
|
-
target: { type: 'Command', name: 'DoSomething' },
|
|
22
|
-
destination: { type: 'stream', pattern: 'things-${id}' },
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
},
|
|
26
18
|
specs: [
|
|
27
19
|
{
|
|
28
20
|
type: 'gherkin',
|
|
@@ -113,14 +105,6 @@ describe('react.ts.ejs', () => {
|
|
|
113
105
|
name: 'Send order confirmation',
|
|
114
106
|
server: {
|
|
115
107
|
description: 'Sends confirmation after order placed',
|
|
116
|
-
data: {
|
|
117
|
-
items: [
|
|
118
|
-
{
|
|
119
|
-
target: { type: 'Command', name: 'SendConfirmation' },
|
|
120
|
-
destination: { type: 'stream', pattern: 'confirmations-${orderId}' },
|
|
121
|
-
},
|
|
122
|
-
],
|
|
123
|
-
},
|
|
124
108
|
specs: [
|
|
125
109
|
{
|
|
126
110
|
type: 'gherkin',
|
|
@@ -238,14 +222,6 @@ describe('react.ts.ejs', () => {
|
|
|
238
222
|
name: 'Notify Barber of Cancellation',
|
|
239
223
|
server: {
|
|
240
224
|
description: 'Notifies barber when appointment is cancelled',
|
|
241
|
-
data: {
|
|
242
|
-
items: [
|
|
243
|
-
{
|
|
244
|
-
target: { type: 'Command', name: 'NotifyBarber' },
|
|
245
|
-
destination: { type: 'stream', pattern: 'barber-${barberId}' },
|
|
246
|
-
},
|
|
247
|
-
],
|
|
248
|
-
},
|
|
249
225
|
specs: [
|
|
250
226
|
{
|
|
251
227
|
type: 'gherkin',
|
|
@@ -335,7 +311,6 @@ describe('react.ts.ejs', () => {
|
|
|
335
311
|
items: [
|
|
336
312
|
{
|
|
337
313
|
target: { type: 'Event', name: 'BarberNotified' },
|
|
338
|
-
destination: { type: 'stream', pattern: 'barber-${barberId}' },
|
|
339
314
|
},
|
|
340
315
|
],
|
|
341
316
|
},
|
|
@@ -466,14 +441,6 @@ export type BarberNotified = Event<
|
|
|
466
441
|
name: 'notify barber of cancellation',
|
|
467
442
|
server: {
|
|
468
443
|
description: 'Notifies barber when appointment is cancelled',
|
|
469
|
-
data: {
|
|
470
|
-
items: [
|
|
471
|
-
{
|
|
472
|
-
target: { type: 'Command', name: 'NotifyBarber' },
|
|
473
|
-
destination: { type: 'stream', pattern: 'barber-${barberId}' },
|
|
474
|
-
},
|
|
475
|
-
],
|
|
476
|
-
},
|
|
477
444
|
specs: [
|
|
478
445
|
{
|
|
479
446
|
type: 'gherkin',
|
|
@@ -607,14 +574,6 @@ export type BarberNotified = Event<
|
|
|
607
574
|
name: 'notify milestone',
|
|
608
575
|
server: {
|
|
609
576
|
description: 'Notifies on milestone',
|
|
610
|
-
data: {
|
|
611
|
-
items: [
|
|
612
|
-
{
|
|
613
|
-
target: { type: 'Command', name: 'SendNotification' },
|
|
614
|
-
destination: { type: 'stream', pattern: 'notif-${memberId}' },
|
|
615
|
-
},
|
|
616
|
-
],
|
|
617
|
-
},
|
|
618
577
|
specs: [
|
|
619
578
|
{
|
|
620
579
|
type: 'gherkin',
|
|
@@ -728,14 +687,6 @@ export type BarberNotified = Event<
|
|
|
728
687
|
name: 'check record updates',
|
|
729
688
|
server: {
|
|
730
689
|
description: 'Updates records after workout',
|
|
731
|
-
data: {
|
|
732
|
-
items: [
|
|
733
|
-
{
|
|
734
|
-
target: { type: 'Command', name: 'UpdateRecord' },
|
|
735
|
-
destination: { type: 'stream', pattern: 'records-${memberId}' },
|
|
736
|
-
},
|
|
737
|
-
],
|
|
738
|
-
},
|
|
739
690
|
specs: [
|
|
740
691
|
{
|
|
741
692
|
type: 'gherkin',
|
|
@@ -5,9 +5,11 @@ import { join } from 'node:path';
|
|
|
5
5
|
import type { CommandSlice, Model, Narrative, QuerySlice } from '@auto-engineer/narrative';
|
|
6
6
|
import fs from 'fs-extra';
|
|
7
7
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
8
|
+
import { ScaffoldError, TemplateRenderError } from '../codegen/scaffoldFromSchema';
|
|
8
9
|
import type { GenerateServerCommand, GenerateServerEvents, GenerationState } from './generate-server';
|
|
9
10
|
import {
|
|
10
11
|
cleanServerDir,
|
|
12
|
+
createServerFailureEvent,
|
|
11
13
|
createSliceGeneratedEvent,
|
|
12
14
|
deriveModelPath,
|
|
13
15
|
emitSliceGeneratedForAffected,
|
|
@@ -472,3 +474,72 @@ describe('emitSliceGenerationFailedForDuplicates', () => {
|
|
|
472
474
|
]);
|
|
473
475
|
});
|
|
474
476
|
});
|
|
477
|
+
|
|
478
|
+
describe('createServerFailureEvent', () => {
|
|
479
|
+
it('extracts flow/slice/type and template from ScaffoldError wrapping TemplateRenderError', () => {
|
|
480
|
+
const rootCause = new TypeError('Cannot read properties of undefined');
|
|
481
|
+
const templateErr = new TemplateRenderError('decide.ts.ejs', rootCause);
|
|
482
|
+
const scaffoldErr = new ScaffoldError('Checkout', 'PlaceOrder', 'command', templateErr);
|
|
483
|
+
|
|
484
|
+
const event = createServerFailureEvent(makeCommand(), scaffoldErr);
|
|
485
|
+
|
|
486
|
+
expect(event).toEqual({
|
|
487
|
+
type: 'ServerGenerationFailed',
|
|
488
|
+
data: {
|
|
489
|
+
modelPath: path.join(path.resolve('.'), '.context', 'schema.json'),
|
|
490
|
+
destination: '.',
|
|
491
|
+
error: expect.stringContaining('[template=decide.ts.ejs]'),
|
|
492
|
+
model: makeModel(),
|
|
493
|
+
flowName: 'Checkout',
|
|
494
|
+
sliceName: 'PlaceOrder',
|
|
495
|
+
sliceType: 'command',
|
|
496
|
+
},
|
|
497
|
+
timestamp: expect.any(Date),
|
|
498
|
+
requestId: 'req-1',
|
|
499
|
+
correlationId: 'cor-1',
|
|
500
|
+
});
|
|
501
|
+
expect(event.data.error).toContain('Cannot read properties of undefined');
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('returns undefined flow/slice/type for plain Error', () => {
|
|
505
|
+
const plainError = new Error('something went wrong');
|
|
506
|
+
|
|
507
|
+
const event = createServerFailureEvent(makeCommand(), plainError);
|
|
508
|
+
|
|
509
|
+
expect(event).toEqual({
|
|
510
|
+
type: 'ServerGenerationFailed',
|
|
511
|
+
data: {
|
|
512
|
+
modelPath: path.join(path.resolve('.'), '.context', 'schema.json'),
|
|
513
|
+
destination: '.',
|
|
514
|
+
error: expect.stringContaining('something went wrong'),
|
|
515
|
+
model: makeModel(),
|
|
516
|
+
flowName: undefined,
|
|
517
|
+
sliceName: undefined,
|
|
518
|
+
sliceType: undefined,
|
|
519
|
+
},
|
|
520
|
+
timestamp: expect.any(Date),
|
|
521
|
+
requestId: 'req-1',
|
|
522
|
+
correlationId: 'cor-1',
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
it('returns Unknown error for non-Error value', () => {
|
|
527
|
+
const event = createServerFailureEvent(makeCommand(), 'string error');
|
|
528
|
+
|
|
529
|
+
expect(event).toEqual({
|
|
530
|
+
type: 'ServerGenerationFailed',
|
|
531
|
+
data: {
|
|
532
|
+
modelPath: path.join(path.resolve('.'), '.context', 'schema.json'),
|
|
533
|
+
destination: '.',
|
|
534
|
+
error: 'Unknown error occurred',
|
|
535
|
+
model: makeModel(),
|
|
536
|
+
flowName: undefined,
|
|
537
|
+
sliceName: undefined,
|
|
538
|
+
sliceType: undefined,
|
|
539
|
+
},
|
|
540
|
+
timestamp: expect.any(Date),
|
|
541
|
+
requestId: 'req-1',
|
|
542
|
+
correlationId: 'cor-1',
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
});
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
type DuplicateCommandInfo,
|
|
12
12
|
type FieldIssue,
|
|
13
13
|
generateScaffoldFilePlans,
|
|
14
|
+
ScaffoldError,
|
|
15
|
+
TemplateRenderError,
|
|
14
16
|
writeScaffoldFilePlans,
|
|
15
17
|
} from '../codegen/scaffoldFromSchema';
|
|
16
18
|
import { ensureDirExists, ensureDirPath, toKebabCase } from '../codegen/utils/path';
|
|
@@ -80,6 +82,9 @@ export type ServerGenerationFailedEvent = Event<
|
|
|
80
82
|
destination: string;
|
|
81
83
|
error: string;
|
|
82
84
|
model: Model;
|
|
85
|
+
flowName?: string;
|
|
86
|
+
sliceName?: string;
|
|
87
|
+
sliceType?: string;
|
|
83
88
|
}
|
|
84
89
|
>;
|
|
85
90
|
|
|
@@ -309,9 +314,36 @@ function stripAnsiCodes(text: string): string {
|
|
|
309
314
|
return text.replace(/\x1B\[[0-9;]*m/g, '');
|
|
310
315
|
}
|
|
311
316
|
|
|
312
|
-
function createServerFailureEvent(command: GenerateServerCommand, error: unknown): ServerGenerationFailedEvent {
|
|
317
|
+
export function createServerFailureEvent(command: GenerateServerCommand, error: unknown): ServerGenerationFailedEvent {
|
|
313
318
|
debug('Server generation failed with error: %O', error);
|
|
314
|
-
|
|
319
|
+
|
|
320
|
+
let flowName: string | undefined;
|
|
321
|
+
let sliceName: string | undefined;
|
|
322
|
+
let sliceType: string | undefined;
|
|
323
|
+
let templateFile: string | undefined;
|
|
324
|
+
let errorMessage: string;
|
|
325
|
+
|
|
326
|
+
if (error instanceof Error) {
|
|
327
|
+
let current: unknown = error;
|
|
328
|
+
while (current instanceof Error) {
|
|
329
|
+
if (current instanceof ScaffoldError) {
|
|
330
|
+
flowName = current.flowName;
|
|
331
|
+
sliceName = current.sliceName;
|
|
332
|
+
sliceType = current.sliceType;
|
|
333
|
+
}
|
|
334
|
+
if (current instanceof TemplateRenderError) {
|
|
335
|
+
templateFile = current.templateFile;
|
|
336
|
+
}
|
|
337
|
+
current = current.cause;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const rootError = findRootCause(error);
|
|
341
|
+
const baseMessage = stripAnsiCodes(rootError.stack ?? rootError.message);
|
|
342
|
+
errorMessage = templateFile !== undefined ? `[template=${templateFile}] ${baseMessage}` : baseMessage;
|
|
343
|
+
} else {
|
|
344
|
+
errorMessage = 'Unknown error occurred';
|
|
345
|
+
}
|
|
346
|
+
|
|
315
347
|
return {
|
|
316
348
|
type: 'ServerGenerationFailed',
|
|
317
349
|
data: {
|
|
@@ -319,6 +351,9 @@ function createServerFailureEvent(command: GenerateServerCommand, error: unknown
|
|
|
319
351
|
destination: command.data.destination,
|
|
320
352
|
error: errorMessage,
|
|
321
353
|
model: command.data.model,
|
|
354
|
+
flowName,
|
|
355
|
+
sliceName,
|
|
356
|
+
sliceType,
|
|
322
357
|
},
|
|
323
358
|
timestamp: new Date(),
|
|
324
359
|
requestId: command.requestId,
|
|
@@ -326,6 +361,14 @@ function createServerFailureEvent(command: GenerateServerCommand, error: unknown
|
|
|
326
361
|
};
|
|
327
362
|
}
|
|
328
363
|
|
|
364
|
+
function findRootCause(error: Error): Error {
|
|
365
|
+
let current: Error = error;
|
|
366
|
+
while (current.cause instanceof Error) {
|
|
367
|
+
current = current.cause;
|
|
368
|
+
}
|
|
369
|
+
return current;
|
|
370
|
+
}
|
|
371
|
+
|
|
329
372
|
export function createSliceGeneratedEvent(
|
|
330
373
|
flow: Narrative,
|
|
331
374
|
slice: Slice,
|