@auto-engineer/server-generator-apollo-emmett 0.1.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/.tmp/server-test-output/server/package.json +26 -0
- package/.tmp/server-test-output/server/scripts/generate-schema.ts +31 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/create-item/commands.ts +8 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/create-item/decide.specs.ts +36 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/create-item/decide.ts +33 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/create-item/events.ts +10 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/create-item/evolve.ts +28 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/create-item/handle.ts +24 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/create-item/mutation.resolver.ts +25 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/create-item/register.ts +7 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/create-item/state.ts +47 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/get-available-items/projection.specs.ts +46 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/get-available-items/projection.ts +38 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/get-available-items/query.resolver.ts +39 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/get-available-items/state.ts +5 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-new-item/commands.ts +8 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-new-item/decide.specs.ts +36 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-new-item/decide.ts +33 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-new-item/events.ts +3 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-new-item/evolve.ts +28 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-new-item/handle.ts +24 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-new-item/mutation.resolver.ts +25 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-new-item/register.ts +7 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-new-item/state.ts +47 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-on-new-item/react.specs.ts +49 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-on-new-item/react.ts +43 -0
- package/.tmp/server-test-output/server/src/domain/flows/add-item/notify-on-new-item/register.ts +24 -0
- package/.tmp/server-test-output/server/src/domain/shared/ReadModel.ts +26 -0
- package/.tmp/server-test-output/server/src/domain/shared/index.ts +4 -0
- package/.tmp/server-test-output/server/src/domain/shared/reactorSpecification.ts +257 -0
- package/.tmp/server-test-output/server/src/domain/shared/sendCommand.ts +21 -0
- package/.tmp/server-test-output/server/src/domain/shared/types.ts +31 -0
- package/.tmp/server-test-output/server/src/server.ts +43 -0
- package/.tmp/server-test-output/server/src/utils/index.ts +3 -0
- package/.tmp/server-test-output/server/src/utils/loadProjections.ts +30 -0
- package/.tmp/server-test-output/server/src/utils/loadRegisterFiles.ts +41 -0
- package/.tmp/server-test-output/server/src/utils/loadResolvers.ts +36 -0
- package/.tmp/server-test-output/server/tsconfig.json +19 -0
- package/.tmp/server-test-output/server/vitest.config.ts +7 -0
- package/.turbo/turbo-build.log +5 -0
- package/.turbo/turbo-format.log +57 -0
- package/.turbo/turbo-lint.log +5 -0
- package/.turbo/turbo-test.log +113 -0
- package/.turbo/turbo-type-check.log +4 -0
- package/CHANGELOG.md +141 -0
- package/DEBUG.md +177 -0
- package/LICENSE +10 -0
- package/README.md +185 -0
- package/dist/cli-manifest.d.ts +3 -0
- package/dist/cli-manifest.d.ts.map +1 -0
- package/dist/cli-manifest.js +8 -0
- package/dist/cli-manifest.js.map +1 -0
- package/dist/codegen/extract/commands.d.ts +19 -0
- package/dist/codegen/extract/commands.d.ts.map +1 -0
- package/dist/codegen/extract/commands.js +52 -0
- package/dist/codegen/extract/commands.js.map +1 -0
- package/dist/codegen/extract/data-sink.d.ts +6 -0
- package/dist/codegen/extract/data-sink.d.ts.map +1 -0
- package/dist/codegen/extract/data-sink.js +39 -0
- package/dist/codegen/extract/data-sink.js.map +1 -0
- package/dist/codegen/extract/events.d.ts +10 -0
- package/dist/codegen/extract/events.d.ts.map +1 -0
- package/dist/codegen/extract/events.js +32 -0
- package/dist/codegen/extract/events.js.map +1 -0
- package/dist/codegen/extract/fields.d.ts +3 -0
- package/dist/codegen/extract/fields.d.ts.map +1 -0
- package/dist/codegen/extract/fields.js +9 -0
- package/dist/codegen/extract/fields.js.map +1 -0
- package/dist/codegen/extract/graphql.d.ts +14 -0
- package/dist/codegen/extract/graphql.d.ts.map +1 -0
- package/dist/codegen/extract/graphql.js +81 -0
- package/dist/codegen/extract/graphql.js.map +1 -0
- package/dist/codegen/extract/gwt.d.ts +6 -0
- package/dist/codegen/extract/gwt.d.ts.map +1 -0
- package/dist/codegen/extract/gwt.js +61 -0
- package/dist/codegen/extract/gwt.js.map +1 -0
- package/dist/codegen/extract/index.d.ts +8 -0
- package/dist/codegen/extract/index.d.ts.map +1 -0
- package/dist/codegen/extract/index.js +8 -0
- package/dist/codegen/extract/index.js.map +1 -0
- package/dist/codegen/extract/messages.d.ts +24 -0
- package/dist/codegen/extract/messages.d.ts.map +1 -0
- package/dist/codegen/extract/messages.js +131 -0
- package/dist/codegen/extract/messages.js.map +1 -0
- package/dist/codegen/extract/projection.d.ts +4 -0
- package/dist/codegen/extract/projection.d.ts.map +1 -0
- package/dist/codegen/extract/projection.js +30 -0
- package/dist/codegen/extract/projection.js.map +1 -0
- package/dist/codegen/extract/query.d.ts +11 -0
- package/dist/codegen/extract/query.d.ts.map +1 -0
- package/dist/codegen/extract/query.js +11 -0
- package/dist/codegen/extract/query.js.map +1 -0
- package/dist/codegen/extract/states.d.ts +5 -0
- package/dist/codegen/extract/states.d.ts.map +1 -0
- package/dist/codegen/extract/states.js +35 -0
- package/dist/codegen/extract/states.js.map +1 -0
- package/dist/codegen/scaffoldFromSchema.d.ts +9 -0
- package/dist/codegen/scaffoldFromSchema.d.ts.map +1 -0
- package/dist/codegen/scaffoldFromSchema.integration.specs.d.ts +2 -0
- package/dist/codegen/scaffoldFromSchema.integration.specs.d.ts.map +1 -0
- package/dist/codegen/scaffoldFromSchema.integration.specs.js +59 -0
- package/dist/codegen/scaffoldFromSchema.integration.specs.js.map +1 -0
- package/dist/codegen/scaffoldFromSchema.js +326 -0
- package/dist/codegen/scaffoldFromSchema.js.map +1 -0
- package/dist/codegen/templates/command/commands.specs.ts +90 -0
- package/dist/codegen/templates/command/commands.ts.ejs +11 -0
- package/dist/codegen/templates/command/decide.specs.specs.ts +265 -0
- package/dist/codegen/templates/command/decide.specs.ts +542 -0
- package/dist/codegen/templates/command/decide.specs.ts.ejs +51 -0
- package/dist/codegen/templates/command/decide.ts.ejs +107 -0
- package/dist/codegen/templates/command/events.specs.ts +106 -0
- package/dist/codegen/templates/command/events.ts.ejs +14 -0
- package/dist/codegen/templates/command/evolve.specs.ts +102 -0
- package/dist/codegen/templates/command/evolve.ts.ejs +39 -0
- package/dist/codegen/templates/command/handle.specs.ts +313 -0
- package/dist/codegen/templates/command/handle.ts.ejs +111 -0
- package/dist/codegen/templates/command/mutation.resolver.specs.ts +115 -0
- package/dist/codegen/templates/command/mutation.resolver.ts.ejs +25 -0
- package/dist/codegen/templates/command/register.specs.ts +107 -0
- package/dist/codegen/templates/command/register.ts.ejs +12 -0
- package/dist/codegen/templates/command/state.specs.ts +127 -0
- package/dist/codegen/templates/command/state.ts.ejs +47 -0
- package/dist/codegen/templates/query/projection.specs.specs..ts +276 -0
- package/dist/codegen/templates/query/projection.specs.ts +348 -0
- package/dist/codegen/templates/query/projection.specs.ts.ejs +71 -0
- package/dist/codegen/templates/query/projection.ts.ejs +121 -0
- package/dist/codegen/templates/query/query.resolver.specs.ts +254 -0
- package/dist/codegen/templates/query/query.resolver.ts.ejs +98 -0
- package/dist/codegen/templates/query/state.specs.ts +70 -0
- package/dist/codegen/templates/query/state.ts.ejs +7 -0
- package/dist/codegen/templates/react/react.specs.specs.ts +214 -0
- package/dist/codegen/templates/react/react.specs.ts +241 -0
- package/dist/codegen/templates/react/react.specs.ts.ejs +80 -0
- package/dist/codegen/templates/react/react.ts.ejs +56 -0
- package/dist/codegen/templates/react/register.specs.ts +222 -0
- package/dist/codegen/templates/react/register.ts.ejs +39 -0
- package/dist/codegen/test-data/specVariant1.d.ts +4 -0
- package/dist/codegen/test-data/specVariant1.d.ts.map +1 -0
- package/dist/codegen/test-data/specVariant1.js +185 -0
- package/dist/codegen/test-data/specVariant1.js.map +1 -0
- package/dist/codegen/types.d.ts +35 -0
- package/dist/codegen/types.d.ts.map +1 -0
- package/dist/codegen/types.js +2 -0
- package/dist/codegen/types.js.map +1 -0
- package/dist/codegen/utils/path.d.ts +4 -0
- package/dist/codegen/utils/path.d.ts.map +1 -0
- package/dist/codegen/utils/path.js +18 -0
- package/dist/codegen/utils/path.js.map +1 -0
- package/dist/commands/generate-server.d.ts +81 -0
- package/dist/commands/generate-server.d.ts.map +1 -0
- package/dist/commands/generate-server.js +383 -0
- package/dist/commands/generate-server.js.map +1 -0
- package/dist/domain/shared/ReadModel.d.ts +10 -0
- package/dist/domain/shared/ReadModel.d.ts.map +1 -0
- package/dist/domain/shared/ReadModel.js +19 -0
- package/dist/domain/shared/ReadModel.js.map +1 -0
- package/dist/domain/shared/ReadModel.ts +26 -0
- package/dist/domain/shared/index.d.ts +5 -0
- package/dist/domain/shared/index.d.ts.map +1 -0
- package/dist/domain/shared/index.js +5 -0
- package/dist/domain/shared/index.js.map +1 -0
- package/dist/domain/shared/index.ts +4 -0
- package/dist/domain/shared/reactorSpecification.d.ts +35 -0
- package/dist/domain/shared/reactorSpecification.d.ts.map +1 -0
- package/dist/domain/shared/reactorSpecification.js +155 -0
- package/dist/domain/shared/reactorSpecification.js.map +1 -0
- package/dist/domain/shared/reactorSpecification.ts +257 -0
- package/dist/domain/shared/sendCommand.d.ts +4 -0
- package/dist/domain/shared/sendCommand.d.ts.map +1 -0
- package/dist/domain/shared/sendCommand.js +17 -0
- package/dist/domain/shared/sendCommand.js.map +1 -0
- package/dist/domain/shared/sendCommand.ts +21 -0
- package/dist/domain/shared/types.d.ts +19 -0
- package/dist/domain/shared/types.d.ts.map +1 -0
- package/dist/domain/shared/types.js +39 -0
- package/dist/domain/shared/types.js.map +1 -0
- package/dist/domain/shared/types.ts +31 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +33 -0
- package/dist/server.js.map +1 -0
- package/dist/server.ts +43 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/index.ts +3 -0
- package/dist/utils/loadProjections.d.ts +3 -0
- package/dist/utils/loadProjections.d.ts.map +1 -0
- package/dist/utils/loadProjections.js +23 -0
- package/dist/utils/loadProjections.js.map +1 -0
- package/dist/utils/loadProjections.ts +30 -0
- package/dist/utils/loadRegisterFiles.d.ts +6 -0
- package/dist/utils/loadRegisterFiles.d.ts.map +1 -0
- package/dist/utils/loadRegisterFiles.js +28 -0
- package/dist/utils/loadRegisterFiles.js.map +1 -0
- package/dist/utils/loadRegisterFiles.ts +41 -0
- package/dist/utils/loadResolvers.d.ts +5 -0
- package/dist/utils/loadResolvers.d.ts.map +1 -0
- package/dist/utils/loadResolvers.js +27 -0
- package/dist/utils/loadResolvers.js.map +1 -0
- package/dist/utils/loadResolvers.ts +36 -0
- package/package.json +55 -0
- package/src/cli-manifest.ts +9 -0
- package/src/codegen/extract/commands.ts +79 -0
- package/src/codegen/extract/data-sink.ts +45 -0
- package/src/codegen/extract/events.ts +46 -0
- package/src/codegen/extract/fields.ts +17 -0
- package/src/codegen/extract/graphql.ts +103 -0
- package/src/codegen/extract/gwt.ts +75 -0
- package/src/codegen/extract/index.ts +7 -0
- package/src/codegen/extract/messages.ts +196 -0
- package/src/codegen/extract/projection.ts +47 -0
- package/src/codegen/extract/query.ts +18 -0
- package/src/codegen/extract/states.ts +45 -0
- package/src/codegen/scaffoldFromSchema.integration.specs.ts +71 -0
- package/src/codegen/scaffoldFromSchema.ts +440 -0
- package/src/codegen/templates/command/commands.specs.ts +90 -0
- package/src/codegen/templates/command/commands.ts.ejs +11 -0
- package/src/codegen/templates/command/decide.specs.specs.ts +265 -0
- package/src/codegen/templates/command/decide.specs.ts +542 -0
- package/src/codegen/templates/command/decide.specs.ts.ejs +51 -0
- package/src/codegen/templates/command/decide.ts.ejs +107 -0
- package/src/codegen/templates/command/events.specs.ts +106 -0
- package/src/codegen/templates/command/events.ts.ejs +14 -0
- package/src/codegen/templates/command/evolve.specs.ts +102 -0
- package/src/codegen/templates/command/evolve.ts.ejs +39 -0
- package/src/codegen/templates/command/handle.specs.ts +313 -0
- package/src/codegen/templates/command/handle.ts.ejs +111 -0
- package/src/codegen/templates/command/mutation.resolver.specs.ts +115 -0
- package/src/codegen/templates/command/mutation.resolver.ts.ejs +25 -0
- package/src/codegen/templates/command/register.specs.ts +107 -0
- package/src/codegen/templates/command/register.ts.ejs +12 -0
- package/src/codegen/templates/command/state.specs.ts +127 -0
- package/src/codegen/templates/command/state.ts.ejs +47 -0
- package/src/codegen/templates/query/projection.specs.specs..ts +276 -0
- package/src/codegen/templates/query/projection.specs.ts +348 -0
- package/src/codegen/templates/query/projection.specs.ts.ejs +71 -0
- package/src/codegen/templates/query/projection.ts.ejs +121 -0
- package/src/codegen/templates/query/query.resolver.specs.ts +254 -0
- package/src/codegen/templates/query/query.resolver.ts.ejs +98 -0
- package/src/codegen/templates/query/state.specs.ts +70 -0
- package/src/codegen/templates/query/state.ts.ejs +7 -0
- package/src/codegen/templates/react/react.specs.specs.ts +214 -0
- package/src/codegen/templates/react/react.specs.ts +241 -0
- package/src/codegen/templates/react/react.specs.ts.ejs +80 -0
- package/src/codegen/templates/react/react.ts.ejs +56 -0
- package/src/codegen/templates/react/register.specs.ts +222 -0
- package/src/codegen/templates/react/register.ts.ejs +39 -0
- package/src/codegen/test-data/specVariant1.json +212 -0
- package/src/codegen/test-data/specVariant1.ts +188 -0
- package/src/codegen/test-data/specVariant2.json +396 -0
- package/src/codegen/types.ts +35 -0
- package/src/codegen/utils/path.ts +20 -0
- package/src/commands/generate-server.ts +517 -0
- package/src/domain/shared/ReadModel.ts +26 -0
- package/src/domain/shared/index.ts +4 -0
- package/src/domain/shared/reactorSpecification.ts +257 -0
- package/src/domain/shared/sendCommand.ts +21 -0
- package/src/domain/shared/types.ts +31 -0
- package/src/index.ts +2 -0
- package/src/server.ts +43 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/loadProjections.ts +30 -0
- package/src/utils/loadRegisterFiles.ts +41 -0
- package/src/utils/loadResolvers.ts +36 -0
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Slice } from '@auto-engineer/flow';
|
|
2
|
+
import { GwtCondition } from '../types';
|
|
3
|
+
|
|
4
|
+
export function buildCommandGwtMapping(slice: Slice): Record<string, (GwtCondition & { failingFields?: string[] })[]> {
|
|
5
|
+
if (slice.type !== 'command') {
|
|
6
|
+
return {};
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const gwtSpecs = slice.server?.gwt ?? [];
|
|
10
|
+
const mapping: Record<string, GwtCondition[]> = {};
|
|
11
|
+
|
|
12
|
+
for (const gwt of gwtSpecs) {
|
|
13
|
+
const command = gwt.when?.commandRef;
|
|
14
|
+
if (command) {
|
|
15
|
+
mapping[command] = mapping[command] ?? [];
|
|
16
|
+
mapping[command].push({
|
|
17
|
+
given: gwt.given,
|
|
18
|
+
when: gwt.when,
|
|
19
|
+
then: gwt.then,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const enhancedMapping: Record<string, (GwtCondition & { failingFields?: string[] })[]> = {};
|
|
25
|
+
|
|
26
|
+
for (const command in mapping) {
|
|
27
|
+
const merged = mergeGwtConditions(mapping[command]);
|
|
28
|
+
const successfulData = findSuccessfulExampleData(merged);
|
|
29
|
+
|
|
30
|
+
enhancedMapping[command] = merged.map((gwt) => ({
|
|
31
|
+
...gwt,
|
|
32
|
+
failingFields: findFailingFields(gwt, successfulData),
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return enhancedMapping;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function mergeGwtConditions(gwts: GwtCondition[]): GwtCondition[] {
|
|
40
|
+
const map = new Map<string, GwtCondition[]>();
|
|
41
|
+
|
|
42
|
+
for (const gwt of gwts) {
|
|
43
|
+
const key = JSON.stringify(gwt.when.exampleData);
|
|
44
|
+
const existing = map.get(key) ?? [];
|
|
45
|
+
map.set(key, [...existing, gwt]);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return Array.from(map.values()).map((conditions) => {
|
|
49
|
+
const first = conditions[0];
|
|
50
|
+
const combinedThen = conditions.flatMap((g) => g.then);
|
|
51
|
+
return {
|
|
52
|
+
given: conditions.flatMap((g) => g.given ?? []),
|
|
53
|
+
when: first.when,
|
|
54
|
+
then: combinedThen,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function findSuccessfulExampleData(gwts: GwtCondition[]): Record<string, unknown> {
|
|
60
|
+
const successful = gwts.find((gwt) => gwt.then.some((t) => typeof t === 'object' && t !== null && 'eventRef' in t));
|
|
61
|
+
return successful?.when.exampleData ?? {};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function findFailingFields(gwt: GwtCondition, successfulData: Record<string, unknown>): string[] {
|
|
65
|
+
const hasError = gwt.then.some((t) => typeof t === 'object' && t !== null && 'errorType' in t);
|
|
66
|
+
|
|
67
|
+
if (!hasError) return [];
|
|
68
|
+
|
|
69
|
+
return Object.entries(gwt.when.exampleData)
|
|
70
|
+
.filter(([key, val]) => {
|
|
71
|
+
const successVal = successfulData[key];
|
|
72
|
+
return val === '' && successVal !== '' && successVal !== undefined;
|
|
73
|
+
})
|
|
74
|
+
.map(([key]) => key);
|
|
75
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { extractCommandsFromGwt, extractCommandsFromThen } from './commands';
|
|
2
|
+
import { CommandExample, ErrorExample, EventExample, Slice, StateExample } from '@auto-engineer/flow';
|
|
3
|
+
import { Message, MessageDefinition } from '../types';
|
|
4
|
+
import { extractEventsFromGiven, extractEventsFromThen, extractEventsFromWhen } from './events';
|
|
5
|
+
import { extractProjectionIdField } from './projection';
|
|
6
|
+
import { extractStatesFromData, extractStatesFromTarget } from './states';
|
|
7
|
+
import createDebug from 'debug';
|
|
8
|
+
|
|
9
|
+
const debug = createDebug('emmett:extract:messages');
|
|
10
|
+
const debugCommand = createDebug('emmett:extract:messages:command');
|
|
11
|
+
const debugQuery = createDebug('emmett:extract:messages:query');
|
|
12
|
+
const debugReact = createDebug('emmett:extract:messages:react');
|
|
13
|
+
const debugDedupe = createDebug('emmett:extract:messages:dedupe');
|
|
14
|
+
|
|
15
|
+
export interface ExtractedMessages {
|
|
16
|
+
commands: Message[];
|
|
17
|
+
events: Message[];
|
|
18
|
+
states: Message[];
|
|
19
|
+
commandSchemasByName: Record<string, Message>;
|
|
20
|
+
projectionIdField?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ReactGwtSpec {
|
|
24
|
+
when: EventExample[];
|
|
25
|
+
then: CommandExample[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface CommandGwtSpec {
|
|
29
|
+
given?: EventExample[];
|
|
30
|
+
when: CommandExample;
|
|
31
|
+
then: Array<EventExample | ErrorExample>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface QueryGwtSpec {
|
|
35
|
+
given: EventExample[];
|
|
36
|
+
then: StateExample[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const EMPTY_EXTRACTED_MESSAGES: ExtractedMessages = {
|
|
40
|
+
commands: [],
|
|
41
|
+
events: [],
|
|
42
|
+
states: [],
|
|
43
|
+
commandSchemasByName: {},
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function deduplicateMessages<T extends Message>(messages: T[]): T[] {
|
|
47
|
+
debugDedupe('Deduplicating %d messages', messages.length);
|
|
48
|
+
const uniqueMap = new Map<string, T>();
|
|
49
|
+
for (const message of messages) {
|
|
50
|
+
if (!uniqueMap.has(message.type)) {
|
|
51
|
+
uniqueMap.set(message.type, message);
|
|
52
|
+
debugDedupe(' Added unique message: %s', message.type);
|
|
53
|
+
} else {
|
|
54
|
+
debugDedupe(' Skipped duplicate message: %s', message.type);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const result = Array.from(uniqueMap.values());
|
|
58
|
+
debugDedupe('Result: %d unique messages from %d total', result.length, messages.length);
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function extractMessagesForCommand(slice: Slice, allMessages: MessageDefinition[]): ExtractedMessages {
|
|
63
|
+
debugCommand('Extracting messages for command slice: %s', slice.name);
|
|
64
|
+
|
|
65
|
+
if (slice.type !== 'command') {
|
|
66
|
+
debugCommand(' Slice type is not command, returning empty');
|
|
67
|
+
return EMPTY_EXTRACTED_MESSAGES;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const gwtSpecs = slice.server?.gwt ?? [];
|
|
71
|
+
debugCommand(' Found %d GWT specs', gwtSpecs.length);
|
|
72
|
+
|
|
73
|
+
const { commands, commandSchemasByName } = extractCommandsFromGwt(gwtSpecs, allMessages);
|
|
74
|
+
debugCommand(' Extracted %d commands', commands.length);
|
|
75
|
+
debugCommand(' Command schemas: %o', Object.keys(commandSchemasByName));
|
|
76
|
+
|
|
77
|
+
const events: Message[] = gwtSpecs.flatMap((gwt): Message[] => {
|
|
78
|
+
const givenEvents = extractEventsFromGiven(gwt.given, allMessages);
|
|
79
|
+
const thenEvents = extractEventsFromThen(gwt.then, allMessages);
|
|
80
|
+
debugCommand(' GWT: given=%d events, then=%d events', givenEvents.length, thenEvents.length);
|
|
81
|
+
return [...givenEvents, ...thenEvents];
|
|
82
|
+
});
|
|
83
|
+
debugCommand(' Total events extracted: %d', events.length);
|
|
84
|
+
|
|
85
|
+
const result = {
|
|
86
|
+
commands,
|
|
87
|
+
events: deduplicateMessages(events),
|
|
88
|
+
states: [],
|
|
89
|
+
commandSchemasByName,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
debugCommand(' Final result: %d commands, %d events', result.commands.length, result.events.length);
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function extractMessagesForQuery(slice: Slice, allMessages: MessageDefinition[]): ExtractedMessages {
|
|
97
|
+
debugQuery('Extracting messages for query slice: %s', slice.name);
|
|
98
|
+
|
|
99
|
+
if (slice.type !== 'query') {
|
|
100
|
+
debugQuery(' Slice type is not query, returning empty');
|
|
101
|
+
return EMPTY_EXTRACTED_MESSAGES;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const gwtSpecs = slice.server?.gwt ?? [];
|
|
105
|
+
debugQuery(' Found %d GWT specs', gwtSpecs.length);
|
|
106
|
+
|
|
107
|
+
const projectionIdField = extractProjectionIdField(slice);
|
|
108
|
+
debugQuery(' Projection ID field: %s', projectionIdField ?? 'none');
|
|
109
|
+
|
|
110
|
+
const events: Message[] = gwtSpecs.flatMap((gwt) => extractEventsFromGiven(gwt.given, allMessages));
|
|
111
|
+
debugQuery(' Extracted %d events from given', events.length);
|
|
112
|
+
|
|
113
|
+
const states: Message[] = extractStatesFromTarget(slice, allMessages);
|
|
114
|
+
debugQuery(' Extracted %d states from target', states.length);
|
|
115
|
+
|
|
116
|
+
const result = {
|
|
117
|
+
commands: [],
|
|
118
|
+
events: deduplicateMessages(events),
|
|
119
|
+
states,
|
|
120
|
+
commandSchemasByName: {},
|
|
121
|
+
projectionIdField,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
debugQuery(' Final result: %d events, %d states', result.events.length, result.states.length);
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function extractMessagesForReact(slice: Slice, allMessages: MessageDefinition[]): ExtractedMessages {
|
|
129
|
+
debugReact('Extracting messages for react slice: %s', slice.name);
|
|
130
|
+
|
|
131
|
+
if (slice.type !== 'react') {
|
|
132
|
+
debugReact(' Slice type is not react, returning empty');
|
|
133
|
+
return EMPTY_EXTRACTED_MESSAGES;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const gwtSpecs = slice.server?.gwt ?? [];
|
|
137
|
+
debugReact(' Found %d GWT specs', gwtSpecs.length);
|
|
138
|
+
|
|
139
|
+
const events = extractEventsFromWhen(gwtSpecs, allMessages);
|
|
140
|
+
debugReact(' Extracted %d events from when', events.length);
|
|
141
|
+
|
|
142
|
+
const { commands, commandSchemasByName } = extractCommandsFromThen(gwtSpecs, allMessages);
|
|
143
|
+
debugReact(' Extracted %d commands from then', commands.length);
|
|
144
|
+
debugReact(' Command schemas: %o', Object.keys(commandSchemasByName));
|
|
145
|
+
|
|
146
|
+
const states = extractStatesFromData(slice, allMessages);
|
|
147
|
+
debugReact(' Extracted %d states from data', states.length);
|
|
148
|
+
|
|
149
|
+
const result = {
|
|
150
|
+
commands,
|
|
151
|
+
events: deduplicateMessages(events),
|
|
152
|
+
states,
|
|
153
|
+
commandSchemasByName,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
debugReact(
|
|
157
|
+
' Final result: %d commands, %d events, %d states',
|
|
158
|
+
result.commands.length,
|
|
159
|
+
result.events.length,
|
|
160
|
+
result.states.length,
|
|
161
|
+
);
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export function extractMessagesFromSpecs(slice: Slice, allMessages: MessageDefinition[]): ExtractedMessages {
|
|
166
|
+
debug('Extracting messages from slice: %s (type: %s)', slice.name, slice.type);
|
|
167
|
+
debug(' Total message definitions available: %d', allMessages.length);
|
|
168
|
+
|
|
169
|
+
let result: ExtractedMessages;
|
|
170
|
+
|
|
171
|
+
switch (slice.type) {
|
|
172
|
+
case 'command':
|
|
173
|
+
result = extractMessagesForCommand(slice, allMessages);
|
|
174
|
+
break;
|
|
175
|
+
case 'query':
|
|
176
|
+
result = extractMessagesForQuery(slice, allMessages);
|
|
177
|
+
break;
|
|
178
|
+
case 'react':
|
|
179
|
+
result = extractMessagesForReact(slice, allMessages);
|
|
180
|
+
break;
|
|
181
|
+
default: {
|
|
182
|
+
const unknownSlice = slice as Slice;
|
|
183
|
+
debug(' Unknown slice type: %s, returning empty', unknownSlice.type);
|
|
184
|
+
result = EMPTY_EXTRACTED_MESSAGES;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
debug(
|
|
189
|
+
' Extraction complete: %d commands, %d events, %d states',
|
|
190
|
+
result.commands.length,
|
|
191
|
+
result.events.length,
|
|
192
|
+
result.states.length,
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
return result;
|
|
196
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Slice } from '@auto-engineer/flow';
|
|
2
|
+
|
|
3
|
+
interface ProjectionOrigin {
|
|
4
|
+
type: 'projection';
|
|
5
|
+
idField?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface HasOrigin {
|
|
10
|
+
origin: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function hasOrigin(dataSource: unknown): dataSource is HasOrigin {
|
|
14
|
+
return typeof dataSource === 'object' && dataSource !== null && 'origin' in dataSource;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function isProjectionOrigin(origin: unknown): origin is ProjectionOrigin {
|
|
18
|
+
if (typeof origin !== 'object' || origin === null) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const obj = origin as Record<string, unknown>;
|
|
23
|
+
return obj.type === 'projection';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function extractProjectionField<K extends keyof ProjectionOrigin>(slice: Slice, fieldName: K): string | undefined {
|
|
27
|
+
const dataSource = slice.server?.data?.[0];
|
|
28
|
+
if (!hasOrigin(dataSource)) return undefined;
|
|
29
|
+
|
|
30
|
+
const origin = dataSource.origin;
|
|
31
|
+
if (isProjectionOrigin(origin)) {
|
|
32
|
+
const value = origin[fieldName];
|
|
33
|
+
if (typeof value === 'string') {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function extractProjectionIdField(slice: Slice): string | undefined {
|
|
42
|
+
return extractProjectionField(slice, 'idField');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function extractProjectionName(slice: Slice): string | undefined {
|
|
46
|
+
return extractProjectionField(slice, 'name');
|
|
47
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { EventExample, Slice } from '@auto-engineer/flow';
|
|
2
|
+
|
|
3
|
+
interface QueryGwtCondition {
|
|
4
|
+
given: EventExample[];
|
|
5
|
+
then: Array<{ stateRef: string; exampleData: Record<string, unknown> }>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function buildQueryGwtMapping(slice: Slice): QueryGwtCondition[] {
|
|
9
|
+
if (slice.type !== 'query') {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const gwtSpecs = slice.server?.gwt ?? [];
|
|
14
|
+
return gwtSpecs.map((gwt) => ({
|
|
15
|
+
given: gwt.given,
|
|
16
|
+
then: gwt.then,
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Slice } from '@auto-engineer/flow';
|
|
2
|
+
import { Message, MessageDefinition } from '../types';
|
|
3
|
+
import { extractFieldsFromMessage } from './fields';
|
|
4
|
+
|
|
5
|
+
function createStateMessage(stateName: string, allMessages: MessageDefinition[]): Message {
|
|
6
|
+
return {
|
|
7
|
+
type: stateName,
|
|
8
|
+
fields: extractFieldsFromMessage(stateName, 'state', allMessages),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function extractStatesFromTarget(slice: Slice, allMessages: MessageDefinition[]): Message[] {
|
|
13
|
+
const targets = slice.server?.data?.map((d) => d.target?.name).filter(Boolean) as string[];
|
|
14
|
+
const uniqueTargets = Array.from(new Set(targets));
|
|
15
|
+
|
|
16
|
+
return uniqueTargets.map((name) => createStateMessage(name, allMessages));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function extractStatesFromData(slice: Slice, allMessages: MessageDefinition[]): Message[] {
|
|
20
|
+
if (!slice.server?.data) {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const states: Message[] = [];
|
|
25
|
+
const seenStates = new Set<string>();
|
|
26
|
+
|
|
27
|
+
for (const dataItem of slice.server.data) {
|
|
28
|
+
if (!('origin' in dataItem) || !dataItem.target?.name) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const stateName = dataItem.target.name;
|
|
33
|
+
if (seenStates.has(stateName)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const fields = extractFieldsFromMessage(stateName, 'state', allMessages);
|
|
38
|
+
if (fields.length > 0) {
|
|
39
|
+
states.push(createStateMessage(stateName, allMessages));
|
|
40
|
+
seenStates.add(stateName);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return states;
|
|
45
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, it } from 'vitest';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { mkdir, readdir, rm } from 'fs/promises';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
|
|
9
|
+
async function findTestFiles(dir: string): Promise<string[]> {
|
|
10
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
11
|
+
const testFiles: string[] = [];
|
|
12
|
+
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
const fullPath = path.join(dir, entry.name);
|
|
15
|
+
if (entry.isDirectory()) {
|
|
16
|
+
testFiles.push(...(await findTestFiles(fullPath)));
|
|
17
|
+
} else if (entry.name.endsWith('.specs.ts')) {
|
|
18
|
+
testFiles.push(fullPath);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return testFiles;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe.skip('generateServer integration test', { timeout: 20000 }, () => {
|
|
25
|
+
it('should scaffold a working server with valid TS and passing tests', async () => {
|
|
26
|
+
const tmpDir = path.resolve(__dirname, '../../.tmp/server-test-output');
|
|
27
|
+
const specPath = path.resolve(__dirname, './test-data/specVariant1.json');
|
|
28
|
+
|
|
29
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
30
|
+
await mkdir(tmpDir, { recursive: true });
|
|
31
|
+
|
|
32
|
+
await execa('pnpm', ['generate:server', specPath, tmpDir], {
|
|
33
|
+
cwd: path.resolve(__dirname, '../../'),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const serverDir = path.join(tmpDir, 'server');
|
|
37
|
+
const tsconfigPath = path.join(serverDir, 'tsconfig.json');
|
|
38
|
+
const testFiles = await findTestFiles(serverDir);
|
|
39
|
+
|
|
40
|
+
if (testFiles.length === 0) {
|
|
41
|
+
throw new Error(`❌ No test files found in: ${serverDir}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const typecheck = await execa('npx', ['tsc', '--noEmit', '-p', tsconfigPath], {
|
|
45
|
+
cwd: serverDir,
|
|
46
|
+
reject: false,
|
|
47
|
+
});
|
|
48
|
+
if (typecheck.exitCode !== 0) {
|
|
49
|
+
console.error('❌ TypeScript errors:\n', typecheck.stderr || typecheck.stdout);
|
|
50
|
+
throw new Error('❌ TypeScript type-check failed');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const testResult = await execa('npx', ['vitest', 'run', '--dir', serverDir], {
|
|
54
|
+
reject: false,
|
|
55
|
+
});
|
|
56
|
+
const output = testResult.stdout + '\n' + testResult.stderr;
|
|
57
|
+
|
|
58
|
+
const notYetImplementedMatches = output.match(/Not yet implemented: \w+/g) ?? [];
|
|
59
|
+
const otherFailures = output.includes('FAIL') && !output.includes('Not yet implemented') ? output : '';
|
|
60
|
+
|
|
61
|
+
if (testResult.exitCode !== 0 && otherFailures) {
|
|
62
|
+
throw new Error(`❌ Unexpected test failures:\n${otherFailures}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (notYetImplementedMatches.length > 0) {
|
|
66
|
+
console.warn(`ℹ️ Ignored test files awaiting implementation:\n${notYetImplementedMatches.join('\n')}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
70
|
+
});
|
|
71
|
+
});
|