@auto-engineer/narrative 1.3.3 → 1.4.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 +31 -0
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/loader/ts-utils.d.ts +2 -2
- package/dist/src/loader/ts-utils.d.ts.map +1 -1
- package/dist/src/loader/ts-utils.js +7 -1
- package/dist/src/loader/ts-utils.js.map +1 -1
- package/dist/src/schema.d.ts +226 -20
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +6 -3
- package/dist/src/schema.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/imports.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/imports.js +1 -0
- package/dist/src/transformers/model-to-narrative/generators/imports.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/module-code.js +10 -2
- package/dist/src/transformers/model-to-narrative/generators/module-code.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/types.d.ts +1 -1
- package/dist/src/transformers/model-to-narrative/generators/types.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/types.js +2 -1
- package/dist/src/transformers/model-to-narrative/generators/types.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/index.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/messages.d.ts +1 -1
- package/dist/src/transformers/narrative-to-model/messages.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/messages.js +9 -1
- package/dist/src/transformers/narrative-to-model/messages.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/spec-processors.d.ts +22 -1
- package/dist/src/transformers/narrative-to-model/spec-processors.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/spec-processors.js +81 -0
- package/dist/src/transformers/narrative-to-model/spec-processors.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/type-inference.d.ts +1 -1
- package/dist/src/transformers/narrative-to-model/type-inference.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/type-inference.js.map +1 -1
- package/dist/src/types.d.ts +4 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/index.ts +4 -0
- package/src/loader/ts-utils.ts +16 -10
- package/src/model-to-narrative.specs.ts +123 -0
- package/src/schema.ts +7 -2
- package/src/transformers/model-to-narrative/generators/imports.ts +1 -0
- package/src/transformers/model-to-narrative/generators/module-code.ts +11 -2
- package/src/transformers/model-to-narrative/generators/types.ts +4 -5
- package/src/transformers/narrative-to-model/index.ts +5 -5
- package/src/transformers/narrative-to-model/messages.ts +12 -3
- package/src/transformers/narrative-to-model/spec-processors.specs.ts +241 -0
- package/src/transformers/narrative-to-model/spec-processors.ts +91 -4
- package/src/transformers/narrative-to-model/type-inference.ts +4 -4
- package/src/types.ts +5 -0
package/package.json
CHANGED
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"typescript": "^5.9.2",
|
|
24
24
|
"zod": "^3.22.4",
|
|
25
25
|
"zod-to-json-schema": "^3.22.3",
|
|
26
|
-
"@auto-engineer/file-store": "1.
|
|
27
|
-
"@auto-engineer/id": "1.
|
|
28
|
-
"@auto-engineer/message-bus": "1.
|
|
26
|
+
"@auto-engineer/file-store": "1.4.0",
|
|
27
|
+
"@auto-engineer/id": "1.4.0",
|
|
28
|
+
"@auto-engineer/message-bus": "1.4.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^20.0.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"publishConfig": {
|
|
36
36
|
"access": "public"
|
|
37
37
|
},
|
|
38
|
-
"version": "1.
|
|
38
|
+
"version": "1.4.0",
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsx scripts/build.ts",
|
|
41
41
|
"test": "vitest run --reporter=dot",
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export type {
|
|
|
19
19
|
Integration,
|
|
20
20
|
MessageTarget,
|
|
21
21
|
Origin,
|
|
22
|
+
Query,
|
|
22
23
|
State,
|
|
23
24
|
} from './types';
|
|
24
25
|
export { createIntegration } from './types';
|
|
@@ -81,6 +82,7 @@ export {
|
|
|
81
82
|
modelSchema,
|
|
82
83
|
NarrativeNamesSchema as NarrativeNamesSystemSchema,
|
|
83
84
|
NarrativeSchema,
|
|
85
|
+
QuerySchema,
|
|
84
86
|
QuerySliceSchema,
|
|
85
87
|
ReactSliceSchema,
|
|
86
88
|
RuleSchema,
|
|
@@ -135,3 +137,5 @@ export type MessageRef = z.infer<typeof MessageRefSchema>;
|
|
|
135
137
|
// ID assignment utilities
|
|
136
138
|
export { addAutoIds, hasAllIds } from './id';
|
|
137
139
|
export type { ClientSpecNode } from './schema';
|
|
140
|
+
|
|
141
|
+
export { detectQueryAction, extractQueryNameFromRequest } from './transformers/narrative-to-model/spec-processors';
|
package/src/loader/ts-utils.ts
CHANGED
|
@@ -77,7 +77,7 @@ export function parseImports(ts: typeof import('typescript'), fileName: string,
|
|
|
77
77
|
|
|
78
78
|
export interface TypeInfo {
|
|
79
79
|
stringLiteral: string;
|
|
80
|
-
classification?: 'command' | 'event' | 'state';
|
|
80
|
+
classification?: 'command' | 'event' | 'state' | 'query';
|
|
81
81
|
dataFields?: { name: string; type: string; required: boolean }[];
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -93,7 +93,7 @@ export interface GivenTypeInfo {
|
|
|
93
93
|
column: number;
|
|
94
94
|
ordinal: number; // Sequential position within the file
|
|
95
95
|
typeName: string;
|
|
96
|
-
classification: 'command' | 'event' | 'state';
|
|
96
|
+
classification: 'command' | 'event' | 'state' | 'query';
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
function extractDataFieldsFromTypeLiteral(
|
|
@@ -136,7 +136,7 @@ function processTypeAlias(
|
|
|
136
136
|
const baseName = getBaseName(typeRef.typeName);
|
|
137
137
|
if (typeof baseName !== 'string') return;
|
|
138
138
|
|
|
139
|
-
if (!['Command', 'Event', 'State'].includes(baseName)) return;
|
|
139
|
+
if (!['Command', 'Event', 'State', 'Query'].includes(baseName)) return;
|
|
140
140
|
|
|
141
141
|
const typeArgs = typeRef.typeArguments ?? [];
|
|
142
142
|
if (typeArgs.length === 0) return;
|
|
@@ -145,7 +145,7 @@ function processTypeAlias(
|
|
|
145
145
|
if (!ts.isLiteralTypeNode(firstArg) || !ts.isStringLiteral(firstArg.literal)) return;
|
|
146
146
|
|
|
147
147
|
const stringLiteral = firstArg.literal.text;
|
|
148
|
-
const classification = baseName.toLowerCase() as 'command' | 'event' | 'state';
|
|
148
|
+
const classification = baseName.toLowerCase() as 'command' | 'event' | 'state' | 'query';
|
|
149
149
|
|
|
150
150
|
// Try to extract the data fields from the 2nd generic arg (if present)
|
|
151
151
|
let dataFields: { name: string; type: string; required: boolean }[] | undefined;
|
|
@@ -271,7 +271,7 @@ function extractDataFields(
|
|
|
271
271
|
return dataFields;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
function inferClassificationFromName(stringLiteral: string): 'command' | 'event' | 'state' | undefined {
|
|
274
|
+
function inferClassificationFromName(stringLiteral: string): 'command' | 'event' | 'state' | 'query' | undefined {
|
|
275
275
|
const eventPatterns = ['ed', 'Created', 'Updated', 'Deleted', 'Placed', 'Added', 'Removed', 'Changed'];
|
|
276
276
|
if (eventPatterns.some((pattern) => stringLiteral.endsWith(pattern))) {
|
|
277
277
|
return 'event';
|
|
@@ -282,6 +282,11 @@ function inferClassificationFromName(stringLiteral: string): 'command' | 'event'
|
|
|
282
282
|
return 'command';
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
// Query patterns: View*, Get*, List*, Find*, Search*, Fetch*
|
|
286
|
+
if (/^(View|Get|List|Find|Search|Fetch)[A-Z]/.test(stringLiteral)) {
|
|
287
|
+
return 'query';
|
|
288
|
+
}
|
|
289
|
+
|
|
285
290
|
const statePatterns = ['Summary', 'View', 'Items', 'List', 'Data', 'Info'];
|
|
286
291
|
if (statePatterns.some((pattern) => stringLiteral.endsWith(pattern))) {
|
|
287
292
|
return 'state';
|
|
@@ -463,7 +468,7 @@ function classifyBaseGeneric(
|
|
|
463
468
|
ts: typeof import('typescript'),
|
|
464
469
|
checker: import('typescript').TypeChecker,
|
|
465
470
|
typeRef: import('typescript').TypeReferenceNode,
|
|
466
|
-
): 'event' | 'command' | 'state' | null {
|
|
471
|
+
): 'event' | 'command' | 'state' | 'query' | null {
|
|
467
472
|
// Resolve base symbol (handles aliases and qualified names)
|
|
468
473
|
let sym: import('typescript').Symbol | undefined;
|
|
469
474
|
if (ts.isIdentifier(typeRef.typeName) || ts.isQualifiedName(typeRef.typeName)) {
|
|
@@ -476,6 +481,7 @@ function classifyBaseGeneric(
|
|
|
476
481
|
if (base.endsWith('Event')) return 'event';
|
|
477
482
|
if (base.endsWith('Command')) return 'command';
|
|
478
483
|
if (base.endsWith('State')) return 'state';
|
|
484
|
+
if (base.endsWith('Query')) return 'query';
|
|
479
485
|
return null;
|
|
480
486
|
}
|
|
481
487
|
|
|
@@ -483,7 +489,7 @@ function tryUnwrapDirectGeneric(
|
|
|
483
489
|
ts: typeof import('typescript'),
|
|
484
490
|
typeArg: import('typescript').TypeReferenceNode,
|
|
485
491
|
checker: import('typescript').TypeChecker,
|
|
486
|
-
): { typeName: string; classification: 'event' | 'command' | 'state' } | null {
|
|
492
|
+
): { typeName: string; classification: 'event' | 'command' | 'state' | 'query' } | null {
|
|
487
493
|
if (typeArg.typeArguments === undefined || typeArg.typeArguments.length === 0) return null;
|
|
488
494
|
|
|
489
495
|
const kind = classifyBaseGeneric(ts, checker, typeArg);
|
|
@@ -504,7 +510,7 @@ function tryUnwrapTypeAlias(
|
|
|
504
510
|
typeArg: import('typescript').TypeReferenceNode,
|
|
505
511
|
typeMap: Map<string, TypeInfo>,
|
|
506
512
|
typesByFile: Map<string, Map<string, TypeInfo>>,
|
|
507
|
-
): { typeName: string; classification: 'event' | 'command' | 'state' } | null {
|
|
513
|
+
): { typeName: string; classification: 'event' | 'command' | 'state' | 'query' } | null {
|
|
508
514
|
if (!ts.isIdentifier(typeArg.typeName)) return null;
|
|
509
515
|
|
|
510
516
|
const typeName = typeArg.typeName.text;
|
|
@@ -526,7 +532,7 @@ function tryUnwrapGeneric(
|
|
|
526
532
|
checker: import('typescript').TypeChecker,
|
|
527
533
|
typeMap: Map<string, TypeInfo>,
|
|
528
534
|
typesByFile: Map<string, Map<string, TypeInfo>>,
|
|
529
|
-
): { typeName: string; classification: 'event' | 'command' | 'state' } | null {
|
|
535
|
+
): { typeName: string; classification: 'event' | 'command' | 'state' | 'query' } | null {
|
|
530
536
|
if (!ts.isTypeReferenceNode(typeArg)) return null;
|
|
531
537
|
|
|
532
538
|
return tryUnwrapDirectGeneric(ts, typeArg, checker) ?? tryUnwrapTypeAlias(ts, typeArg, typeMap, typesByFile);
|
|
@@ -554,7 +560,7 @@ function createGivenTypeInfo(
|
|
|
554
560
|
node: import('typescript').CallExpression,
|
|
555
561
|
ordinal: number,
|
|
556
562
|
typeName: string,
|
|
557
|
-
classification: 'event' | 'command' | 'state',
|
|
563
|
+
classification: 'event' | 'command' | 'state' | 'query',
|
|
558
564
|
): GivenTypeInfo {
|
|
559
565
|
const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
560
566
|
return {
|
|
@@ -658,6 +658,59 @@ narrative('Test Flow with Rule IDs', 'FLOW-456', () => {
|
|
|
658
658
|
`);
|
|
659
659
|
});
|
|
660
660
|
|
|
661
|
+
it('should correctly generate Query type alias for query messages', async () => {
|
|
662
|
+
const modelWithQueryMessage: Model = {
|
|
663
|
+
variant: 'specs',
|
|
664
|
+
narratives: [
|
|
665
|
+
{
|
|
666
|
+
name: 'Workout Flow',
|
|
667
|
+
id: 'FLOW-001',
|
|
668
|
+
slices: [],
|
|
669
|
+
},
|
|
670
|
+
],
|
|
671
|
+
messages: [
|
|
672
|
+
{
|
|
673
|
+
type: 'query',
|
|
674
|
+
name: 'GetWorkoutHistory',
|
|
675
|
+
fields: [
|
|
676
|
+
{ name: 'memberId', type: 'string', required: true },
|
|
677
|
+
{ name: 'limit', type: 'number', required: false },
|
|
678
|
+
],
|
|
679
|
+
metadata: { version: 1 },
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
type: 'event',
|
|
683
|
+
name: 'WorkoutRecorded',
|
|
684
|
+
fields: [{ name: 'workoutId', type: 'string', required: true }],
|
|
685
|
+
source: 'internal',
|
|
686
|
+
metadata: { version: 1 },
|
|
687
|
+
},
|
|
688
|
+
],
|
|
689
|
+
integrations: [],
|
|
690
|
+
modules: [],
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
const code = getCode(await modelToNarrative(modelWithQueryMessage));
|
|
694
|
+
|
|
695
|
+
expect(code).toEqual(`import { narrative } from '@auto-engineer/narrative';
|
|
696
|
+
import type { Event, Query } from '@auto-engineer/narrative';
|
|
697
|
+
type GetWorkoutHistory = Query<
|
|
698
|
+
'GetWorkoutHistory',
|
|
699
|
+
{
|
|
700
|
+
memberId: string;
|
|
701
|
+
limit?: number;
|
|
702
|
+
}
|
|
703
|
+
>;
|
|
704
|
+
type WorkoutRecorded = Event<
|
|
705
|
+
'WorkoutRecorded',
|
|
706
|
+
{
|
|
707
|
+
workoutId: string;
|
|
708
|
+
}
|
|
709
|
+
>;
|
|
710
|
+
narrative('Workout Flow', 'FLOW-001', () => {});
|
|
711
|
+
`);
|
|
712
|
+
});
|
|
713
|
+
|
|
661
714
|
it('should correctly resolve Date types in messages', async () => {
|
|
662
715
|
const modelWithDateTypes: Model = {
|
|
663
716
|
variant: 'specs',
|
|
@@ -3370,4 +3423,74 @@ narrative('All Projection Types', 'ALL-PROJ', () => {
|
|
|
3370
3423
|
expect(code).toContain("command('Perform Check-In'");
|
|
3371
3424
|
});
|
|
3372
3425
|
});
|
|
3426
|
+
|
|
3427
|
+
it('generates all declared types for authored modules regardless of usage analysis', async () => {
|
|
3428
|
+
const model: Model = {
|
|
3429
|
+
variant: 'specs',
|
|
3430
|
+
narratives: [
|
|
3431
|
+
{
|
|
3432
|
+
id: 'narrative-1',
|
|
3433
|
+
name: 'Gym Goal Setting',
|
|
3434
|
+
slices: [
|
|
3435
|
+
{
|
|
3436
|
+
type: 'command',
|
|
3437
|
+
name: 'Set Fitness Goal',
|
|
3438
|
+
client: { specs: [] },
|
|
3439
|
+
server: {
|
|
3440
|
+
description: 'Set a fitness goal',
|
|
3441
|
+
specs: [
|
|
3442
|
+
{
|
|
3443
|
+
type: 'gherkin',
|
|
3444
|
+
feature: 'Goal Setting',
|
|
3445
|
+
rules: [
|
|
3446
|
+
{
|
|
3447
|
+
name: 'Create goal',
|
|
3448
|
+
examples: [
|
|
3449
|
+
{
|
|
3450
|
+
name: 'Create fitness goal',
|
|
3451
|
+
steps: [
|
|
3452
|
+
{ keyword: 'When', text: 'SetFitnessGoal', docString: { name: 'Lose weight' } },
|
|
3453
|
+
{ keyword: 'Then', text: 'FitnessGoalCreated', docString: { goalId: '123' } },
|
|
3454
|
+
],
|
|
3455
|
+
},
|
|
3456
|
+
],
|
|
3457
|
+
},
|
|
3458
|
+
],
|
|
3459
|
+
},
|
|
3460
|
+
],
|
|
3461
|
+
},
|
|
3462
|
+
},
|
|
3463
|
+
],
|
|
3464
|
+
sourceFile: '/narratives/goal-setting.narrative.ts',
|
|
3465
|
+
},
|
|
3466
|
+
],
|
|
3467
|
+
messages: [
|
|
3468
|
+
{ type: 'command', name: 'SetFitnessGoal', fields: [] },
|
|
3469
|
+
{ type: 'event', name: 'FitnessGoalCreated', fields: [], source: 'internal' },
|
|
3470
|
+
{ type: 'state', name: 'FitnessGoalsView', fields: [] },
|
|
3471
|
+
],
|
|
3472
|
+
modules: [
|
|
3473
|
+
{
|
|
3474
|
+
sourceFile: '/narratives/goal-setting.narrative.ts',
|
|
3475
|
+
isDerived: false,
|
|
3476
|
+
contains: { narrativeIds: ['narrative-1'] },
|
|
3477
|
+
declares: {
|
|
3478
|
+
messages: [
|
|
3479
|
+
{ kind: 'command', name: 'SetFitnessGoal' },
|
|
3480
|
+
{ kind: 'event', name: 'FitnessGoalCreated' },
|
|
3481
|
+
{ kind: 'state', name: 'FitnessGoalsView' },
|
|
3482
|
+
],
|
|
3483
|
+
},
|
|
3484
|
+
},
|
|
3485
|
+
],
|
|
3486
|
+
};
|
|
3487
|
+
|
|
3488
|
+
const result = await modelToNarrative(model);
|
|
3489
|
+
const code = getCode(result);
|
|
3490
|
+
|
|
3491
|
+
// All 3 declared types should be generated
|
|
3492
|
+
expect(code).toContain("type SetFitnessGoal = Command<'SetFitnessGoal'");
|
|
3493
|
+
expect(code).toContain("type FitnessGoalCreated = Event<'FitnessGoalCreated'");
|
|
3494
|
+
expect(code).toContain("type FitnessGoalsView = State<'FitnessGoalsView'");
|
|
3495
|
+
});
|
|
3373
3496
|
});
|
package/src/schema.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
// Message reference for module type ownership
|
|
4
4
|
export const MessageRefSchema = z
|
|
5
5
|
.object({
|
|
6
|
-
kind: z.enum(['command', 'event', 'state']).describe('Message kind'),
|
|
6
|
+
kind: z.enum(['command', 'event', 'state', 'query']).describe('Message kind'),
|
|
7
7
|
name: z.string().describe('Message name'),
|
|
8
8
|
})
|
|
9
9
|
.describe('Reference to a message type');
|
|
@@ -174,7 +174,11 @@ const StateSchema = BaseMessageSchema.extend({
|
|
|
174
174
|
type: z.literal('state'),
|
|
175
175
|
}).describe('State/Read Model representing a view of data');
|
|
176
176
|
|
|
177
|
-
const
|
|
177
|
+
const QuerySchema = BaseMessageSchema.extend({
|
|
178
|
+
type: z.literal('query'),
|
|
179
|
+
}).describe('Query representing a read operation');
|
|
180
|
+
|
|
181
|
+
const MessageSchema = z.discriminatedUnion('type', [CommandSchema, EventSchema, StateSchema, QuerySchema]);
|
|
178
182
|
|
|
179
183
|
const BaseSliceSchema = z
|
|
180
184
|
.object({
|
|
@@ -417,6 +421,7 @@ export {
|
|
|
417
421
|
CommandSchema,
|
|
418
422
|
EventSchema,
|
|
419
423
|
StateSchema,
|
|
424
|
+
QuerySchema,
|
|
420
425
|
IntegrationSchema,
|
|
421
426
|
CommandSliceSchema,
|
|
422
427
|
QuerySliceSchema,
|
|
@@ -102,13 +102,22 @@ function generateModuleCode(
|
|
|
102
102
|
|
|
103
103
|
const usedMessages = messages.filter((msg) => {
|
|
104
104
|
const isImportedFromIntegration = usedTypeIntegrationNames.includes(msg.name);
|
|
105
|
-
const isUsedInFlow = usageAnalysis.usedTypes.has(msg.name);
|
|
106
|
-
const hasEmptyFlowSlices = narratives.length === 0 || narratives.every((flow) => flow.slices.length === 0);
|
|
107
105
|
|
|
106
|
+
// Don't generate local definitions for types imported from integrations
|
|
108
107
|
if (isImportedFromIntegration) {
|
|
109
108
|
return false;
|
|
110
109
|
}
|
|
111
110
|
|
|
111
|
+
// For authored modules, trust the declares list - all declared messages should be generated
|
|
112
|
+
// (messages is already filtered to only include declared messages at line 60-61)
|
|
113
|
+
if (!module.isDerived) {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// For derived modules, only include types that are actually used in flow code
|
|
118
|
+
// or when there's no flow code (hasEmptyFlowSlices)
|
|
119
|
+
const isUsedInFlow = usageAnalysis.usedTypes.has(msg.name);
|
|
120
|
+
const hasEmptyFlowSlices = narratives.length === 0 || narratives.every((flow) => flow.slices.length === 0);
|
|
112
121
|
return isUsedInFlow || hasEmptyFlowSlices;
|
|
113
122
|
});
|
|
114
123
|
|
|
@@ -2,7 +2,7 @@ import type tsNS from 'typescript';
|
|
|
2
2
|
import { typeFromString } from '../ast/emit-helpers';
|
|
3
3
|
|
|
4
4
|
type Message = {
|
|
5
|
-
type: 'command' | 'event' | 'state';
|
|
5
|
+
type: 'command' | 'event' | 'state' | 'query';
|
|
6
6
|
name: string;
|
|
7
7
|
fields: { name: string; type: string; required: boolean }[];
|
|
8
8
|
};
|
|
@@ -33,10 +33,9 @@ export function buildTypeAliases(ts: typeof tsNS, messages: Message[]): tsNS.Sta
|
|
|
33
33
|
|
|
34
34
|
const name = f.createIdentifier(m.name);
|
|
35
35
|
|
|
36
|
-
const
|
|
37
|
-
m.type === 'event' ? 'Event' : m.type === 'command' ? 'Command' : 'State'
|
|
38
|
-
|
|
39
|
-
);
|
|
36
|
+
const baseTypeName =
|
|
37
|
+
m.type === 'event' ? 'Event' : m.type === 'command' ? 'Command' : m.type === 'query' ? 'Query' : 'State';
|
|
38
|
+
const rhs = f.createTypeReferenceNode(baseTypeName, typeArgs);
|
|
40
39
|
|
|
41
40
|
return f.createTypeAliasDeclaration(
|
|
42
41
|
undefined, // No export keyword
|
|
@@ -12,7 +12,7 @@ import { resolveInferredType } from './type-inference';
|
|
|
12
12
|
|
|
13
13
|
type TypeResolver = (
|
|
14
14
|
t: string,
|
|
15
|
-
expected?: 'command' | 'event' | 'state',
|
|
15
|
+
expected?: 'command' | 'event' | 'state' | 'query',
|
|
16
16
|
exampleData?: unknown,
|
|
17
17
|
) => { resolvedName: string; typeInfo: TypeInfo | undefined };
|
|
18
18
|
|
|
@@ -47,7 +47,7 @@ function getTypesForNarrative(
|
|
|
47
47
|
function tryResolveFromNarrativeTypes(
|
|
48
48
|
t: string,
|
|
49
49
|
narrativeSpecificTypes: Map<string, TypeInfo>,
|
|
50
|
-
expected?: 'command' | 'event' | 'state',
|
|
50
|
+
expected?: 'command' | 'event' | 'state' | 'query',
|
|
51
51
|
exampleData?: unknown,
|
|
52
52
|
): { resolvedName: string; typeInfo: TypeInfo | undefined } {
|
|
53
53
|
if (t !== 'InferredType') {
|
|
@@ -68,7 +68,7 @@ function tryFallbackToUnionTypes(
|
|
|
68
68
|
resolvedName: string,
|
|
69
69
|
typeInfo: TypeInfo | undefined,
|
|
70
70
|
unionTypes: Map<string, TypeInfo>,
|
|
71
|
-
expected?: 'command' | 'event' | 'state',
|
|
71
|
+
expected?: 'command' | 'event' | 'state' | 'query',
|
|
72
72
|
exampleData?: unknown,
|
|
73
73
|
): { resolvedName: string; typeInfo: TypeInfo | undefined } {
|
|
74
74
|
if (resolvedName !== 'InferredType' && typeInfo) {
|
|
@@ -88,7 +88,7 @@ function tryFallbackToUnionTypes(
|
|
|
88
88
|
function tryResolveFromUnionTypes(
|
|
89
89
|
t: string,
|
|
90
90
|
unionTypes: Map<string, TypeInfo>,
|
|
91
|
-
expected?: 'command' | 'event' | 'state',
|
|
91
|
+
expected?: 'command' | 'event' | 'state' | 'query',
|
|
92
92
|
exampleData?: unknown,
|
|
93
93
|
): { resolvedName: string; typeInfo: TypeInfo | undefined } {
|
|
94
94
|
if (t !== 'InferredType') {
|
|
@@ -110,7 +110,7 @@ function createTypeResolver(
|
|
|
110
110
|
) {
|
|
111
111
|
return (
|
|
112
112
|
t: string,
|
|
113
|
-
expected?: 'command' | 'event' | 'state',
|
|
113
|
+
expected?: 'command' | 'event' | 'state' | 'query',
|
|
114
114
|
exampleData?: unknown,
|
|
115
115
|
): { resolvedName: string; typeInfo: TypeInfo | undefined } => {
|
|
116
116
|
if (narrativeSpecificTypes) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { Message } from '../../index';
|
|
2
2
|
import type { TypeInfo } from '../../loader/ts-utils';
|
|
3
3
|
|
|
4
|
-
function mapKindToMessageType(k: 'command' | 'query' | 'reaction'): 'command' | 'event' | 'state' {
|
|
4
|
+
function mapKindToMessageType(k: 'command' | 'query' | 'reaction'): 'command' | 'event' | 'state' | 'query' {
|
|
5
5
|
if (k === 'command') return 'command';
|
|
6
|
-
if (k === 'query') return '
|
|
6
|
+
if (k === 'query') return 'query';
|
|
7
7
|
return 'event';
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -52,7 +52,7 @@ function processStateFields(
|
|
|
52
52
|
export function createMessage(
|
|
53
53
|
name: string,
|
|
54
54
|
typeInfo: TypeInfo | undefined,
|
|
55
|
-
messageType: 'command' | 'event' | 'state',
|
|
55
|
+
messageType: 'command' | 'event' | 'state' | 'query',
|
|
56
56
|
): Message {
|
|
57
57
|
let fields = buildInitialFields(typeInfo);
|
|
58
58
|
|
|
@@ -81,6 +81,15 @@ export function createMessage(
|
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
if (messageType === 'query') {
|
|
85
|
+
return {
|
|
86
|
+
type: 'query',
|
|
87
|
+
name,
|
|
88
|
+
fields,
|
|
89
|
+
metadata,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
84
93
|
return {
|
|
85
94
|
type: 'state',
|
|
86
95
|
name,
|