@auto-engineer/server-generator-apollo-emmett 1.130.0 → 1.131.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/package.json CHANGED
@@ -32,8 +32,8 @@
32
32
  "uuid": "^13.0.0",
33
33
  "web-streams-polyfill": "^4.1.0",
34
34
  "zod": "^3.22.4",
35
- "@auto-engineer/narrative": "1.130.0",
36
- "@auto-engineer/message-bus": "1.130.0"
35
+ "@auto-engineer/message-bus": "1.131.0",
36
+ "@auto-engineer/narrative": "1.131.0"
37
37
  },
38
38
  "publishConfig": {
39
39
  "access": "public"
@@ -44,9 +44,9 @@
44
44
  "typescript": "^5.8.3",
45
45
  "vitest": "^3.2.4",
46
46
  "tsx": "^4.19.2",
47
- "@auto-engineer/cli": "1.130.0"
47
+ "@auto-engineer/cli": "1.131.0"
48
48
  },
49
- "version": "1.130.0",
49
+ "version": "1.131.0",
50
50
  "scripts": {
51
51
  "generate:server": "tsx src/cli/index.ts",
52
52
  "build": "tsc && tsx ../../scripts/fix-esm-imports.ts && rm -rf dist/src/codegen/templates && mkdir -p dist/src/codegen && cp -r src/codegen/templates dist/src/codegen/templates && cp src/server.ts dist/src && cp -r src/utils dist/src && cp -r src/domain dist/src",
@@ -51,14 +51,6 @@ export function groupEventImports(context: CrossSliceImportContext): ImportGroup
51
51
  }));
52
52
  }
53
53
 
54
- /**
55
- * Filters events to only include those from the current slice (source === 'then').
56
- * Used for generating local event definitions.
57
- */
58
- export function getLocalEvents(events: Message[]): Message[] {
59
- return events.filter((event) => event.source === 'then');
60
- }
61
-
62
54
  /**
63
55
  * Extracts all unique event types from a list of events.
64
56
  */
@@ -37,7 +37,6 @@ import {
37
37
  extractProjectionName,
38
38
  findPrimitiveLinkingField,
39
39
  getAllEventTypes,
40
- getLocalEvents,
41
40
  groupEventImports,
42
41
  isPrimitiveTsType,
43
42
  isValidTsIdentifier,
@@ -84,7 +83,7 @@ const defaultFilesByType: Record<string, string[]> = {
84
83
  'decide.specs.ts.ejs',
85
84
  'register.ts.ejs',
86
85
  ],
87
- query: ['projection.ts.ejs', 'state.ts.ejs', 'projection.specs.ts.ejs', 'query.resolver.ts.ejs'],
86
+ query: ['events.ts.ejs', 'projection.ts.ejs', 'state.ts.ejs', 'projection.specs.ts.ejs', 'query.resolver.ts.ejs'],
88
87
  react: ['events.ts.ejs', 'react.ts.ejs', 'react.specs.ts.ejs', 'register.ts.ejs'],
89
88
  };
90
89
 
@@ -667,7 +666,10 @@ async function prepareTemplateData(
667
666
  const eventImportGroups = groupEventImports({ currentSliceName: slice.name, currentFlowName: flow.name, events });
668
667
  const allEventTypesArray = getAllEventTypes(events);
669
668
  const allEventTypes = createEventUnionType(events);
670
- const localEvents = getLocalEvents(events);
669
+ const selfImportedTypes = new Set(
670
+ eventImportGroups.filter((g) => g.importPath === './events').flatMap((g) => g.eventTypes),
671
+ );
672
+ const localEvents = events.filter((e) => selfImportedTypes.has(e.type));
671
673
 
672
674
  const messagesByName = new Map((allMessages ?? []).map((m) => [m.name, m]));
673
675
  const targetName = 'server' in slice ? slice.server?.data?.items?.[0]?.target?.name : undefined;
@@ -0,0 +1,112 @@
1
+ import type { Model } from '@auto-engineer/narrative';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { generateScaffoldFilePlans } from '../../scaffoldFromSchema';
4
+
5
+ describe('query events.ts.ejs', () => {
6
+ it('generates events.ts for orphan events not produced by any command slice', async () => {
7
+ const spec: Model = {
8
+ variant: 'specs',
9
+ narratives: [
10
+ {
11
+ name: 'appointment-flow',
12
+ slices: [
13
+ {
14
+ type: 'query',
15
+ name: 'view-appointments',
16
+ stream: 'appointments',
17
+ client: { specs: [] },
18
+ server: {
19
+ description: 'projection for booked appointments',
20
+ data: {
21
+ items: [
22
+ {
23
+ target: { type: 'State', name: 'Appointment' },
24
+ origin: {
25
+ type: 'projection',
26
+ name: 'AppointmentsProjection',
27
+ idField: 'appointmentId',
28
+ },
29
+ },
30
+ ],
31
+ },
32
+ specs: [
33
+ {
34
+ type: 'gherkin',
35
+ feature: 'View appointments query',
36
+ rules: [
37
+ {
38
+ name: 'Should project appointments',
39
+ examples: [
40
+ {
41
+ name: 'Appointment booked shows in list',
42
+ steps: [
43
+ {
44
+ keyword: 'When',
45
+ text: 'AppointmentBooked',
46
+ docString: {
47
+ appointmentId: 'appt_1',
48
+ date: '2024-06-15',
49
+ },
50
+ },
51
+ {
52
+ keyword: 'Then',
53
+ text: 'Appointment',
54
+ docString: {
55
+ appointmentId: 'appt_1',
56
+ date: '2024-06-15',
57
+ },
58
+ },
59
+ ],
60
+ },
61
+ ],
62
+ },
63
+ ],
64
+ },
65
+ ],
66
+ },
67
+ },
68
+ ],
69
+ },
70
+ ],
71
+ messages: [
72
+ {
73
+ type: 'event',
74
+ name: 'AppointmentBooked',
75
+ source: 'internal',
76
+ fields: [
77
+ { name: 'appointmentId', type: 'string', required: true },
78
+ { name: 'date', type: 'string', required: true },
79
+ ],
80
+ },
81
+ {
82
+ type: 'state',
83
+ name: 'Appointment',
84
+ fields: [
85
+ { name: 'appointmentId', type: 'string', required: true },
86
+ { name: 'date', type: 'string', required: true },
87
+ ],
88
+ },
89
+ ],
90
+ };
91
+
92
+ const { plans } = await generateScaffoldFilePlans(spec.narratives, spec.messages, undefined, 'src/domain/flows');
93
+
94
+ const eventFile = plans.find((p) => p.outputPath.endsWith('view-appointments/events.ts'));
95
+ expect(eventFile).toBeDefined();
96
+ expect(eventFile?.contents).toMatchInlineSnapshot(`
97
+ "import type { Event } from '@event-driven-io/emmett';
98
+
99
+ export type AppointmentBooked = Event<
100
+ 'AppointmentBooked',
101
+ {
102
+ appointmentId: string;
103
+ date: string;
104
+ }
105
+ >;
106
+ "
107
+ `);
108
+
109
+ const projectionFile = plans.find((p) => p.outputPath.endsWith('view-appointments/projection.ts'));
110
+ expect(projectionFile?.contents).toContain("import type { AppointmentBooked } from './events'");
111
+ });
112
+ });
@@ -0,0 +1,17 @@
1
+ <%
2
+ const enumList = collectEnumNames(localEvents.flatMap(e => e.fields));
3
+ %><% if (localEvents.length) { -%>
4
+ import type { Event } from '@event-driven-io/emmett';
5
+ <% if (enumList.length > 0) { %>import { <%= enumList.join(', ') %> } from '../../../shared';
6
+ <% } %>
7
+ <% for (const event of localEvents) { -%>
8
+ export type <%= pascalCase(event.type) %> = Event<
9
+ '<%= event.type %>',
10
+ {
11
+ <% for (const field of event.fields) { -%>
12
+ <%- field.name %>: <%- toTsFieldType(field.tsType) %>;
13
+ <% } -%>
14
+ }
15
+ >;
16
+ <% } -%>
17
+ <% } -%>