@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
package/dist/server.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { ApolloServer } from 'apollo-server';
|
|
3
|
+
import { buildSchema } from 'type-graphql';
|
|
4
|
+
import { loadProjections, loadRegisterFiles, loadResolvers } from './utils';
|
|
5
|
+
import {
|
|
6
|
+
getInMemoryEventStore,
|
|
7
|
+
getInMemoryMessageBus,
|
|
8
|
+
projections,
|
|
9
|
+
forwardToMessageBus,
|
|
10
|
+
} from '@event-driven-io/emmett';
|
|
11
|
+
|
|
12
|
+
async function start() {
|
|
13
|
+
const loadedProjections = await loadProjections('src/domain/flows/**/projection.{ts,js}');
|
|
14
|
+
const registrations = await loadRegisterFiles('src/domain/flows/**/register.{ts,js}');
|
|
15
|
+
|
|
16
|
+
const messageBus = getInMemoryMessageBus();
|
|
17
|
+
|
|
18
|
+
const eventStore = getInMemoryEventStore({
|
|
19
|
+
projections: projections.inline(loadedProjections),
|
|
20
|
+
hooks: {
|
|
21
|
+
onAfterCommit: forwardToMessageBus(messageBus),
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
await Promise.all(registrations.map((r) => r.register(messageBus, eventStore)));
|
|
26
|
+
|
|
27
|
+
const resolvers = await loadResolvers('src/domain/flows/**/*.resolver.{ts,js}');
|
|
28
|
+
const schema = await buildSchema({
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
resolvers: resolvers as unknown as [(...args: any[]) => any, ...Array<(...args: any[]) => any>],
|
|
31
|
+
});
|
|
32
|
+
const server = new ApolloServer({
|
|
33
|
+
schema,
|
|
34
|
+
context: () => ({
|
|
35
|
+
eventStore,
|
|
36
|
+
messageBus,
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
39
|
+
const { url } = await server.listen({ port: 4000 });
|
|
40
|
+
console.log(`🚀 GraphQL server ready at ${url}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void start();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadProjections.d.ts","sourceRoot":"","sources":["../../src/utils/loadProjections.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEpE,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAoBrF"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export async function loadProjections(source) {
|
|
4
|
+
const files = await fg(source, { absolute: true });
|
|
5
|
+
const modules = await Promise.all(files.map(async (file) => {
|
|
6
|
+
const mod = await import(pathToFileUrl(file).href);
|
|
7
|
+
if (typeof mod === 'object' && mod !== null && 'projection' in mod) {
|
|
8
|
+
const projectionModule = mod;
|
|
9
|
+
if (projectionModule.projection == null) {
|
|
10
|
+
console.warn(`⚠️ Projection file "${file}" does not export "projection"`);
|
|
11
|
+
}
|
|
12
|
+
return projectionModule.projection;
|
|
13
|
+
}
|
|
14
|
+
console.warn(`⚠️ Projection file "${file}" does not export "projection"`);
|
|
15
|
+
return undefined;
|
|
16
|
+
}));
|
|
17
|
+
return modules.filter((p) => p != null);
|
|
18
|
+
}
|
|
19
|
+
function pathToFileUrl(filePath) {
|
|
20
|
+
const resolved = path.resolve(filePath);
|
|
21
|
+
return new URL(`file://${resolved}`);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=loadProjections.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadProjections.js","sourceRoot":"","sources":["../../src/utils/loadProjections.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc;IAClD,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAEnD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACvB,MAAM,GAAG,GAAY,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAE5D,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,YAAY,IAAI,GAAG,EAAE,CAAC;YACnE,MAAM,gBAAgB,GAAG,GAA4C,CAAC;YACtE,IAAI,gBAAgB,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC;gBACxC,OAAO,CAAC,IAAI,CAAC,uBAAuB,IAAI,gCAAgC,CAAC,CAAC;YAC5E,CAAC;YACD,OAAO,gBAAgB,CAAC,UAAU,CAAC;QACrC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,uBAAuB,IAAI,gCAAgC,CAAC,CAAC;QAC1E,OAAO,SAAS,CAAC;IACnB,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAA6B,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,OAAO,IAAI,GAAG,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import type { ProjectionDefinition } from '@event-driven-io/emmett';
|
|
4
|
+
|
|
5
|
+
export async function loadProjections(source: string): Promise<ProjectionDefinition[]> {
|
|
6
|
+
const files = await fg(source, { absolute: true });
|
|
7
|
+
|
|
8
|
+
const modules = await Promise.all(
|
|
9
|
+
files.map(async (file) => {
|
|
10
|
+
const mod: unknown = await import(pathToFileUrl(file).href);
|
|
11
|
+
|
|
12
|
+
if (typeof mod === 'object' && mod !== null && 'projection' in mod) {
|
|
13
|
+
const projectionModule = mod as { projection?: ProjectionDefinition };
|
|
14
|
+
if (projectionModule.projection == null) {
|
|
15
|
+
console.warn(`⚠️ Projection file "${file}" does not export "projection"`);
|
|
16
|
+
}
|
|
17
|
+
return projectionModule.projection;
|
|
18
|
+
}
|
|
19
|
+
console.warn(`⚠️ Projection file "${file}" does not export "projection"`);
|
|
20
|
+
return undefined;
|
|
21
|
+
}),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return modules.filter((p): p is ProjectionDefinition => p != null);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function pathToFileUrl(filePath: string): URL {
|
|
28
|
+
const resolved = path.resolve(filePath);
|
|
29
|
+
return new URL(`file://${resolved}`);
|
|
30
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CommandProcessor, EventStore } from '@event-driven-io/emmett';
|
|
2
|
+
export interface SliceRegistration {
|
|
3
|
+
register: (messageBus: CommandProcessor, eventStore: EventStore) => Promise<unknown> | void;
|
|
4
|
+
}
|
|
5
|
+
export declare function loadRegisterFiles(source: string): Promise<SliceRegistration[]>;
|
|
6
|
+
//# sourceMappingURL=loadRegisterFiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadRegisterFiles.d.ts","sourceRoot":"","sources":["../../src/utils/loadRegisterFiles.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE5E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,CAAC,UAAU,EAAE,gBAAgB,EAAE,UAAU,EAAE,UAAU,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC7F;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CA2BpF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
export async function loadRegisterFiles(source) {
|
|
4
|
+
const files = await fg(source, { absolute: true });
|
|
5
|
+
const modules = await Promise.all(files.map(async (file) => {
|
|
6
|
+
try {
|
|
7
|
+
const mod = await import(pathToFileUrl(file).href);
|
|
8
|
+
if (typeof mod === 'object' &&
|
|
9
|
+
mod !== null &&
|
|
10
|
+
'register' in mod &&
|
|
11
|
+
typeof mod.register === 'function') {
|
|
12
|
+
return mod;
|
|
13
|
+
}
|
|
14
|
+
console.warn('⚠️ Skipping invalid register.ts at', file);
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
console.error('❌ Failed to import', file, ':', error);
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}));
|
|
22
|
+
return modules.filter((m) => m !== null);
|
|
23
|
+
}
|
|
24
|
+
function pathToFileUrl(filePath) {
|
|
25
|
+
const resolved = path.resolve(filePath);
|
|
26
|
+
return new URL(`file://${resolved}`);
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=loadRegisterFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadRegisterFiles.js","sourceRoot":"","sources":["../../src/utils/loadRegisterFiles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,WAAW,CAAC;AAC3B,OAAO,IAAI,MAAM,MAAM,CAAC;AAOxB,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAAc;IACpD,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAEnD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACvB,IAAI,CAAC;YACH,MAAM,GAAG,GAAY,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;YAE5D,IACE,OAAO,GAAG,KAAK,QAAQ;gBACvB,GAAG,KAAK,IAAI;gBACZ,UAAU,IAAI,GAAG;gBACjB,OAAQ,GAAyB,CAAC,QAAQ,KAAK,UAAU,EACzD,CAAC;gBACD,OAAO,GAAwB,CAAC;YAClC,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE,IAAI,CAAC,CAAC;YACzD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,oBAAoB,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;YACtD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAA0B,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB;IACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,OAAO,IAAI,GAAG,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import type { CommandProcessor, EventStore } from '@event-driven-io/emmett';
|
|
4
|
+
|
|
5
|
+
export interface SliceRegistration {
|
|
6
|
+
register: (messageBus: CommandProcessor, eventStore: EventStore) => Promise<unknown> | void;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function loadRegisterFiles(source: string): Promise<SliceRegistration[]> {
|
|
10
|
+
const files = await fg(source, { absolute: true });
|
|
11
|
+
|
|
12
|
+
const modules = await Promise.all(
|
|
13
|
+
files.map(async (file) => {
|
|
14
|
+
try {
|
|
15
|
+
const mod: unknown = await import(pathToFileUrl(file).href);
|
|
16
|
+
|
|
17
|
+
if (
|
|
18
|
+
typeof mod === 'object' &&
|
|
19
|
+
mod !== null &&
|
|
20
|
+
'register' in mod &&
|
|
21
|
+
typeof (mod as SliceRegistration).register === 'function'
|
|
22
|
+
) {
|
|
23
|
+
return mod as SliceRegistration;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.warn('⚠️ Skipping invalid register.ts at', file);
|
|
27
|
+
return null;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error('❌ Failed to import', file, ':', error);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return modules.filter((m): m is SliceRegistration => m !== null);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function pathToFileUrl(filePath: string): URL {
|
|
39
|
+
const resolved = path.resolve(filePath);
|
|
40
|
+
return new URL(`file://${resolved}`);
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadResolvers.d.ts","sourceRoot":"","sources":["../../src/utils/loadResolvers.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;CAC/B;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CA6BvE"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
export async function loadResolvers(source) {
|
|
3
|
+
const files = await fg(source, {
|
|
4
|
+
absolute: true,
|
|
5
|
+
});
|
|
6
|
+
const modules = await Promise.all(files.map((file) => import(file)));
|
|
7
|
+
const allResolvers = [];
|
|
8
|
+
for (const mod of modules) {
|
|
9
|
+
if (typeof mod !== 'object' || mod === null) {
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
for (const key of Object.keys(mod)) {
|
|
13
|
+
const exported = mod[key];
|
|
14
|
+
if (typeof exported === 'function') {
|
|
15
|
+
allResolvers.push(exported);
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(exported) && exported.every((r) => typeof r === 'function')) {
|
|
18
|
+
allResolvers.push(...exported);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
if (allResolvers.length === 0) {
|
|
23
|
+
throw new Error('❌ No resolvers found for any slices.');
|
|
24
|
+
}
|
|
25
|
+
return allResolvers;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=loadResolvers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadResolvers.js","sourceRoot":"","sources":["../../src/utils/loadResolvers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,WAAW,CAAC;AAM3B,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc;IAChD,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE;QAC7B,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IACH,MAAM,OAAO,GAAc,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChF,MAAM,YAAY,GAAe,EAAE,CAAC;IAEpC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAI,GAA+B,CAAC,GAAG,CAAC,CAAC;YAEvD,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;gBACnC,YAAY,CAAC,IAAI,CAAC,QAAoB,CAAC,CAAC;YAC1C,CAAC;YAED,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,UAAU,CAAC,EAAE,CAAC;gBAC9E,YAAY,CAAC,IAAI,CAAC,GAAI,QAAuB,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;IACH,CAAC;IAED,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
|
|
3
|
+
export interface Resolver {
|
|
4
|
+
(...args: unknown[]): unknown;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export async function loadResolvers(source: string): Promise<Resolver[]> {
|
|
8
|
+
const files = await fg(source, {
|
|
9
|
+
absolute: true,
|
|
10
|
+
});
|
|
11
|
+
const modules: unknown[] = await Promise.all(files.map((file) => import(file)));
|
|
12
|
+
const allResolvers: Resolver[] = [];
|
|
13
|
+
|
|
14
|
+
for (const mod of modules) {
|
|
15
|
+
if (typeof mod !== 'object' || mod === null) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const key of Object.keys(mod)) {
|
|
20
|
+
const exported = (mod as Record<string, unknown>)[key];
|
|
21
|
+
|
|
22
|
+
if (typeof exported === 'function') {
|
|
23
|
+
allResolvers.push(exported as Resolver);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (Array.isArray(exported) && exported.every((r) => typeof r === 'function')) {
|
|
27
|
+
allResolvers.push(...(exported as Resolver[]));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (allResolvers.length === 0) {
|
|
33
|
+
throw new Error('❌ No resolvers found for any slices.');
|
|
34
|
+
}
|
|
35
|
+
return allResolvers;
|
|
36
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@auto-engineer/server-generator-apollo-emmett",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@auto-engineer/flow": "^0.1.1",
|
|
15
|
+
"@auto-engineer/message-bus": "^0.5.2",
|
|
16
|
+
"@event-driven-io/emmett": "^0.38.2",
|
|
17
|
+
"apollo-server": "^3.13.0",
|
|
18
|
+
"apollo-server-express": "^3.13.0",
|
|
19
|
+
"change-case": "^5.4.4",
|
|
20
|
+
"ejs": "^3.1.10",
|
|
21
|
+
"execa": "^9.6.0",
|
|
22
|
+
"express": "^4.21.2",
|
|
23
|
+
"fast-glob": "^3.3.3",
|
|
24
|
+
"fs-extra": "^11.3.0",
|
|
25
|
+
"graphql": "^16.11.0",
|
|
26
|
+
"graphql-scalars": "^1.24.2",
|
|
27
|
+
"prettier": "^3.6.1",
|
|
28
|
+
"reflect-metadata": "^0.2.2",
|
|
29
|
+
"type-fest": "^4.41.0",
|
|
30
|
+
"type-graphql": "^2.0.0-rc.2",
|
|
31
|
+
"uuid": "^10.0.0",
|
|
32
|
+
"web-streams-polyfill": "^4.1.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@auto-engineer/cli": "^0.7.2",
|
|
39
|
+
"@types/ejs": "^3.1.5",
|
|
40
|
+
"@types/fs-extra": "^11.0.4"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"generate:server": "tsx src/cli/index.ts",
|
|
44
|
+
"build": "tsc && tsx ../../scripts/fix-esm-imports.ts && rm -rf dist/codegen/templates && mkdir -p dist/codegen && cp -r src/codegen/templates dist/codegen/templates && cp src/server.ts dist/ && cp -r src/utils dist/ && cp -r src/domain dist/",
|
|
45
|
+
"dev": "tsc --watch",
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"type-check": "tsc --noEmit --project tsconfig.json",
|
|
48
|
+
"lint": "eslint 'src/**/*.ts' --ignore-pattern '**/*.specs.ts' --ignore-pattern '**/.tmp/**' --max-warnings 0 --config ../../eslint.config.ts",
|
|
49
|
+
"format": "prettier --write \"**/*.{js,ts,json,md,yml,yaml}\" --ignore-path ../../.prettierignore",
|
|
50
|
+
"lint:fix": "eslint 'src/**/*.ts' --ignore-pattern '**/*.specs.ts' --ignore-pattern '**/.tmp/**' --fix --config ../../eslint.config.ts",
|
|
51
|
+
"format:fix": "prettier --write \"**/*.{js,ts,json,md,yml,yaml}\" --ignore-path ../../.prettierignore",
|
|
52
|
+
"link:dev": "pnpm build && pnpm link --global",
|
|
53
|
+
"unlink:dev": "pnpm unlink --global"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CliManifest } from '@auto-engineer/cli/manifest-types';
|
|
2
|
+
import { generateServerManifest } from './commands/generate-server';
|
|
3
|
+
|
|
4
|
+
export const CLI_MANIFEST: CliManifest = {
|
|
5
|
+
category: '@auto-engineer/server-generator-apollo-emmett',
|
|
6
|
+
commands: {
|
|
7
|
+
'generate:server': generateServerManifest,
|
|
8
|
+
},
|
|
9
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { CommandExample, EventExample } from '@auto-engineer/flow';
|
|
2
|
+
import { Message, MessageDefinition } from '../types';
|
|
3
|
+
import { extractFieldsFromMessage } from './fields';
|
|
4
|
+
import { ReactGwtSpec } from './messages';
|
|
5
|
+
|
|
6
|
+
function createCommandMessage(
|
|
7
|
+
commandRef: string,
|
|
8
|
+
allMessages: MessageDefinition[],
|
|
9
|
+
source: 'when' | 'then',
|
|
10
|
+
): Message | undefined {
|
|
11
|
+
const fields = extractFieldsFromMessage(commandRef, 'command', allMessages);
|
|
12
|
+
|
|
13
|
+
if (fields.length === 0 && source === 'then') {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
type: commandRef,
|
|
19
|
+
fields,
|
|
20
|
+
source,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function extractCommandsFromGwt(
|
|
25
|
+
gwtSpecs: Array<{
|
|
26
|
+
given?: EventExample[];
|
|
27
|
+
when: CommandExample;
|
|
28
|
+
then: Array<EventExample | { errorType: string; message?: string }>;
|
|
29
|
+
}>,
|
|
30
|
+
allMessages: MessageDefinition[],
|
|
31
|
+
): { commands: Message[]; commandSchemasByName: Record<string, Message> } {
|
|
32
|
+
const commandSchemasByName: Record<string, Message> = {};
|
|
33
|
+
|
|
34
|
+
const commands: Message[] = gwtSpecs
|
|
35
|
+
.map((gwt): Message | undefined => {
|
|
36
|
+
const cmd = gwt.when;
|
|
37
|
+
if (!cmd.commandRef) return undefined;
|
|
38
|
+
|
|
39
|
+
const command = createCommandMessage(cmd.commandRef, allMessages, 'when');
|
|
40
|
+
if (command) {
|
|
41
|
+
commandSchemasByName[cmd.commandRef] = command;
|
|
42
|
+
}
|
|
43
|
+
return command;
|
|
44
|
+
})
|
|
45
|
+
.filter((cmd): cmd is Message => cmd !== undefined);
|
|
46
|
+
|
|
47
|
+
return { commands, commandSchemasByName };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function extractCommandsFromThen(
|
|
51
|
+
gwtSpecs: ReactGwtSpec[],
|
|
52
|
+
allMessages: MessageDefinition[],
|
|
53
|
+
): { commands: Message[]; commandSchemasByName: Record<string, Message> } {
|
|
54
|
+
const commands: Message[] = [];
|
|
55
|
+
const commandSchemasByName: Record<string, Message> = {};
|
|
56
|
+
|
|
57
|
+
for (const gwt of gwtSpecs) {
|
|
58
|
+
if (!Array.isArray(gwt.then)) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const commandExample of gwt.then) {
|
|
63
|
+
if (!commandExample.commandRef) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const commandRef = commandExample.commandRef;
|
|
68
|
+
if (!(commandRef in commandSchemasByName)) {
|
|
69
|
+
const command = createCommandMessage(commandRef, allMessages, 'then');
|
|
70
|
+
if (command) {
|
|
71
|
+
commands.push(command);
|
|
72
|
+
commandSchemasByName[commandRef] = command;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { commands, commandSchemasByName };
|
|
79
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CommandExample, DataSink, Slice } from '@auto-engineer/flow';
|
|
2
|
+
import { CommandGwtSpec, QueryGwtSpec, ReactGwtSpec } from './messages';
|
|
3
|
+
|
|
4
|
+
function resolveStreamId(stream: string, exampleData: Record<string, unknown>): string {
|
|
5
|
+
return stream.replace(/\$\{([^}]+)\}/g, (_, key: string) => String(exampleData?.[key] ?? 'unknown'));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// eslint-disable-next-line complexity
|
|
9
|
+
export function getStreamFromSink(slice: Slice): { streamPattern?: string; streamId?: string } {
|
|
10
|
+
let streamPattern: string | undefined;
|
|
11
|
+
let streamId: string | undefined;
|
|
12
|
+
const gwtSpecs =
|
|
13
|
+
slice.type === 'command'
|
|
14
|
+
? (slice.server?.gwt as CommandGwtSpec[])
|
|
15
|
+
: slice.type === 'query'
|
|
16
|
+
? (slice.server?.gwt as QueryGwtSpec[])
|
|
17
|
+
: slice.type === 'react'
|
|
18
|
+
? (slice.server?.gwt as ReactGwtSpec[])
|
|
19
|
+
: [];
|
|
20
|
+
let exampleData: Record<string, unknown> = {};
|
|
21
|
+
switch (slice.type) {
|
|
22
|
+
case 'react':
|
|
23
|
+
exampleData = (gwtSpecs as ReactGwtSpec[])[0].when?.[0]?.exampleData ?? {};
|
|
24
|
+
break;
|
|
25
|
+
case 'command': {
|
|
26
|
+
const then = (gwtSpecs as CommandGwtSpec[])[0]?.then as (CommandExample | { errorType: string })[];
|
|
27
|
+
const firstExample = then.find((t): t is CommandExample => 'exampleData' in t);
|
|
28
|
+
exampleData = firstExample?.exampleData ?? {};
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case 'query':
|
|
32
|
+
exampleData = (gwtSpecs as QueryGwtSpec[])[0]?.given?.[0]?.exampleData ?? {};
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
const sink = (slice.server?.data ?? []).find((item) => (item as DataSink)?.destination?.type === 'stream') as
|
|
36
|
+
| DataSink
|
|
37
|
+
| undefined;
|
|
38
|
+
if (sink && sink.destination.type === 'stream' && 'pattern' in sink.destination) {
|
|
39
|
+
streamPattern = sink.destination.pattern;
|
|
40
|
+
if (streamPattern != null) {
|
|
41
|
+
streamId = resolveStreamId(streamPattern, exampleData);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return { streamPattern, streamId };
|
|
45
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { EventExample } from '@auto-engineer/flow';
|
|
2
|
+
import { Message, MessageDefinition } from '../types';
|
|
3
|
+
import { extractFieldsFromMessage } from './fields';
|
|
4
|
+
import { ReactGwtSpec } from './messages';
|
|
5
|
+
|
|
6
|
+
function createEventMessage(
|
|
7
|
+
eventRef: string | undefined,
|
|
8
|
+
source: 'given' | 'then' | 'when',
|
|
9
|
+
allMessages: MessageDefinition[],
|
|
10
|
+
): Message | undefined {
|
|
11
|
+
if (eventRef == null) return undefined;
|
|
12
|
+
const fields = extractFieldsFromMessage(eventRef, 'event', allMessages);
|
|
13
|
+
return { type: eventRef, fields, source };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function extractEventsFromThen(
|
|
17
|
+
thenItems: Array<EventExample | { errorType: string; message?: string }>,
|
|
18
|
+
allMessages: MessageDefinition[],
|
|
19
|
+
): Message[] {
|
|
20
|
+
return thenItems
|
|
21
|
+
.map((then): Message | undefined => {
|
|
22
|
+
if (!('eventRef' in then)) return undefined;
|
|
23
|
+
return createEventMessage(then.eventRef, 'then', allMessages);
|
|
24
|
+
})
|
|
25
|
+
.filter((event): event is Message => event !== undefined);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function extractEventsFromGiven(
|
|
29
|
+
givenEvents: EventExample[] | undefined,
|
|
30
|
+
allMessages: MessageDefinition[],
|
|
31
|
+
): Message[] {
|
|
32
|
+
if (!givenEvents) return [];
|
|
33
|
+
|
|
34
|
+
return givenEvents
|
|
35
|
+
.map((given) => createEventMessage(given.eventRef, 'given', allMessages))
|
|
36
|
+
.filter((event): event is Message => event !== undefined);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function extractEventsFromWhen(gwtSpecs: ReactGwtSpec[], allMessages: MessageDefinition[]): Message[] {
|
|
40
|
+
return gwtSpecs.flatMap((gwt) => {
|
|
41
|
+
if (!Array.isArray(gwt.when)) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
return gwt.when.flatMap((eventExample) => extractEventsFromGiven([eventExample], allMessages));
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Field, MessageDefinition } from '../types';
|
|
2
|
+
|
|
3
|
+
export function extractFieldsFromMessage(
|
|
4
|
+
messageName: string,
|
|
5
|
+
messageType: 'command' | 'event' | 'state',
|
|
6
|
+
allMessages: MessageDefinition[],
|
|
7
|
+
): Field[] {
|
|
8
|
+
const messageDef = allMessages.find((m) => m.type === messageType && m.name === messageName);
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
messageDef?.fields?.map((f) => ({
|
|
12
|
+
name: f.name,
|
|
13
|
+
tsType: f.type,
|
|
14
|
+
required: f.required ?? true,
|
|
15
|
+
})) ?? []
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { parse, OperationDefinitionNode, TypeNode, print } from 'graphql';
|
|
2
|
+
|
|
3
|
+
export interface ParsedArg {
|
|
4
|
+
name: string;
|
|
5
|
+
tsType: string;
|
|
6
|
+
graphqlType: string;
|
|
7
|
+
nullable: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ParsedGraphQlQuery {
|
|
11
|
+
queryName: string;
|
|
12
|
+
args: ParsedArg[];
|
|
13
|
+
returnType: string;
|
|
14
|
+
tsReturnType: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function getTypeName(typeNode: TypeNode): { graphqlType: string; nullable: boolean } {
|
|
18
|
+
if (typeNode.kind === 'NamedType') {
|
|
19
|
+
return { graphqlType: typeNode.name.value, nullable: true };
|
|
20
|
+
} else if (typeNode.kind === 'NonNullType') {
|
|
21
|
+
const inner = getTypeName(typeNode.type);
|
|
22
|
+
return { ...inner, nullable: false };
|
|
23
|
+
} else {
|
|
24
|
+
return getTypeName(typeNode.type);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function graphqlToTs(type: string): string {
|
|
29
|
+
switch (type) {
|
|
30
|
+
case 'String':
|
|
31
|
+
return 'string';
|
|
32
|
+
case 'Int':
|
|
33
|
+
case 'Float':
|
|
34
|
+
case 'Number':
|
|
35
|
+
return 'number';
|
|
36
|
+
case 'Boolean':
|
|
37
|
+
return 'boolean';
|
|
38
|
+
case 'Date':
|
|
39
|
+
return 'Date';
|
|
40
|
+
default:
|
|
41
|
+
return type;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function convertJsonAstToSdl(request: string): string {
|
|
46
|
+
// Handle JSON-serialized AST
|
|
47
|
+
if (request.startsWith('{') && request.includes('"kind"')) {
|
|
48
|
+
try {
|
|
49
|
+
const ast = JSON.parse(request) as unknown;
|
|
50
|
+
if (typeof ast === 'object' && ast !== null && 'kind' in ast && ast.kind === 'Document') {
|
|
51
|
+
// Convert AST to SDL string - cast is safe here as we've validated it's a Document
|
|
52
|
+
return print(ast as Parameters<typeof print>[0]);
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
// If parsing fails, assume it's already a GraphQL string
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return request;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function parseGraphQlRequest(request: string): ParsedGraphQlQuery {
|
|
62
|
+
const sdlRequest = convertJsonAstToSdl(request);
|
|
63
|
+
|
|
64
|
+
const ast = parse(sdlRequest);
|
|
65
|
+
const op = ast.definitions.find(
|
|
66
|
+
(d): d is OperationDefinitionNode => d.kind === 'OperationDefinition' && d.operation === 'query',
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (!op) throw new Error('No query operation found');
|
|
70
|
+
|
|
71
|
+
const queryName = op.name?.value;
|
|
72
|
+
if (queryName == null) throw new Error('Query must have a name');
|
|
73
|
+
|
|
74
|
+
const args: ParsedArg[] = (op.variableDefinitions ?? []).map((def) => {
|
|
75
|
+
const varName = def.variable.name.value;
|
|
76
|
+
const { graphqlType, nullable } = getTypeName(def.type);
|
|
77
|
+
return {
|
|
78
|
+
name: varName,
|
|
79
|
+
graphqlType,
|
|
80
|
+
tsType: graphqlToTs(graphqlType),
|
|
81
|
+
nullable,
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const field = op.selectionSet.selections[0];
|
|
86
|
+
if (field?.kind !== 'Field' || !field.name.value) {
|
|
87
|
+
throw new Error('Query selection must be a field');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const baseName = field.name.value;
|
|
91
|
+
const returnType = pascalCase(baseName) + 'View';
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
queryName: baseName,
|
|
95
|
+
args,
|
|
96
|
+
returnType,
|
|
97
|
+
tsReturnType: `${returnType}[]`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function pascalCase(input: string): string {
|
|
102
|
+
return input.replace(/(^\w|_\w)/g, (match) => match.replace('_', '').toUpperCase());
|
|
103
|
+
}
|