@auto-engineer/narrative 1.139.0 → 1.140.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +5 -5
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +32 -0
- package/README.md +8 -8
- package/dist/scripts/convert-flow-exec.js +2 -2
- package/dist/scripts/convert-flow-exec.js.map +1 -1
- package/dist/scripts/print-schema.js +5 -5
- package/dist/scripts/print-schema.js.map +1 -1
- package/dist/src/fluent-builder.d.ts +29 -29
- package/dist/src/fluent-builder.d.ts.map +1 -1
- package/dist/src/fluent-builder.js +81 -81
- package/dist/src/fluent-builder.js.map +1 -1
- package/dist/src/{getNarratives.d.ts → getScenes.d.ts} +6 -6
- package/dist/src/getScenes.d.ts.map +1 -0
- package/dist/src/{getNarratives.js → getScenes.js} +16 -16
- package/dist/src/getScenes.js.map +1 -0
- package/dist/src/id/addAutoIds.d.ts.map +1 -1
- package/dist/src/id/addAutoIds.js +22 -22
- package/dist/src/id/addAutoIds.js.map +1 -1
- package/dist/src/id/hasAllIds.d.ts.map +1 -1
- package/dist/src/id/hasAllIds.js +2 -2
- package/dist/src/id/hasAllIds.js.map +1 -1
- package/dist/src/index.d.ts +8 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/loader/index.js +1 -1
- package/dist/src/loader/index.js.map +1 -1
- package/dist/src/loader/runtime-cjs.js +1 -1
- package/dist/src/loader/runtime-cjs.js.map +1 -1
- package/dist/src/narrative-context.d.ts +9 -9
- package/dist/src/narrative-context.d.ts.map +1 -1
- package/dist/src/narrative-context.js +47 -47
- package/dist/src/narrative-context.js.map +1 -1
- package/dist/src/narrative-registry.d.ts +6 -6
- package/dist/src/narrative-registry.d.ts.map +1 -1
- package/dist/src/narrative-registry.js +26 -26
- package/dist/src/narrative-registry.js.map +1 -1
- package/dist/src/narrative.d.ts +5 -5
- package/dist/src/narrative.d.ts.map +1 -1
- package/dist/src/narrative.js +26 -27
- package/dist/src/narrative.js.map +1 -1
- package/dist/src/parse-graphql-request.d.ts +1 -1
- package/dist/src/parse-graphql-request.d.ts.map +1 -1
- package/dist/src/parse-graphql-request.js +3 -3
- package/dist/src/parse-graphql-request.js.map +1 -1
- package/dist/src/samples/items.narrative.js +2 -2
- package/dist/src/samples/items.narrative.js.map +1 -1
- package/dist/src/samples/mixed-given-types.narrative.js +2 -2
- package/dist/src/samples/mixed-given-types.narrative.js.map +1 -1
- package/dist/src/samples/place-order.narrative.js +2 -2
- package/dist/src/samples/place-order.narrative.js.map +1 -1
- package/dist/src/samples/questionnaires.narrative.js +2 -2
- package/dist/src/samples/questionnaires.narrative.js.map +1 -1
- package/dist/src/samples/seasonal-assistant.schema.json +2 -2
- package/dist/src/samples/test-with-ids.narrative.js +2 -2
- package/dist/src/samples/test-with-ids.narrative.js.map +1 -1
- package/dist/src/schema.d.ts +136 -136
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +76 -76
- package/dist/src/schema.js.map +1 -1
- package/dist/src/slice-builder.d.ts +6 -6
- package/dist/src/slice-builder.d.ts.map +1 -1
- package/dist/src/slice-builder.js +21 -21
- package/dist/src/slice-builder.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/analysis/lint-helpers.js +1 -1
- package/dist/src/transformers/model-to-narrative/analysis/lint-helpers.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/cross-module-imports.js +4 -4
- package/dist/src/transformers/model-to-narrative/cross-module-imports.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/compose.js +3 -3
- package/dist/src/transformers/model-to-narrative/generators/compose.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/flow.d.ts +2 -2
- package/dist/src/transformers/model-to-narrative/generators/flow.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/flow.js +20 -20
- package/dist/src/transformers/model-to-narrative/generators/flow.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/imports.d.ts +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 -1
- package/dist/src/transformers/model-to-narrative/generators/imports.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/module-code.js +14 -14
- package/dist/src/transformers/model-to-narrative/generators/module-code.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/index.d.ts +4 -4
- package/dist/src/transformers/model-to-narrative/index.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/index.js +1 -1
- package/dist/src/transformers/model-to-narrative/spec-traversal.d.ts +2 -2
- package/dist/src/transformers/model-to-narrative/spec-traversal.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/spec-traversal.js +5 -5
- package/dist/src/transformers/model-to-narrative/spec-traversal.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/types.d.ts +1 -1
- package/dist/src/transformers/model-to-narrative/types.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/utils/integration-extractor.d.ts +1 -1
- package/dist/src/transformers/model-to-narrative/utils/integration-extractor.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/utils/integration-extractor.js +4 -4
- package/dist/src/transformers/model-to-narrative/utils/integration-extractor.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/validate-modules.d.ts +1 -1
- package/dist/src/transformers/model-to-narrative/validate-modules.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/validate-modules.js +19 -19
- package/dist/src/transformers/model-to-narrative/validate-modules.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/assemble.d.ts +2 -2
- package/dist/src/transformers/narrative-to-model/assemble.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/assemble.js +10 -3
- package/dist/src/transformers/narrative-to-model/assemble.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/debug.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/debug.js +1 -1
- package/dist/src/transformers/narrative-to-model/debug.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/derive-modules.d.ts +2 -2
- package/dist/src/transformers/narrative-to-model/derive-modules.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/derive-modules.js +9 -9
- package/dist/src/transformers/narrative-to-model/derive-modules.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/index.d.ts +2 -2
- package/dist/src/transformers/narrative-to-model/index.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/index.js +39 -39
- package/dist/src/transformers/narrative-to-model/index.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/spec-processors.js +1 -1
- package/dist/src/transformers/narrative-to-model/spec-processors.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/strings.d.ts +1 -1
- package/dist/src/transformers/narrative-to-model/strings.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/strings.js +6 -6
- package/dist/src/transformers/narrative-to-model/strings.js.map +1 -1
- package/dist/src/validate-slice-requests.d.ts +4 -4
- package/dist/src/validate-slice-requests.d.ts.map +1 -1
- package/dist/src/validate-slice-requests.js +34 -34
- package/dist/src/validate-slice-requests.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/scripts/convert-flow-exec.ts +2 -2
- package/scripts/print-schema.ts +8 -8
- package/src/fluent-builder.specs.ts +3 -3
- package/src/fluent-builder.ts +141 -141
- package/src/{getNarratives.cache.specs.ts → getScenes.cache.specs.ts} +45 -45
- package/src/{getNarratives.specs.ts → getScenes.specs.ts} +302 -300
- package/src/{getNarratives.ts → getScenes.ts} +20 -20
- package/src/id/addAutoIds.specs.ts +105 -105
- package/src/id/addAutoIds.ts +26 -26
- package/src/id/hasAllIds.specs.ts +59 -59
- package/src/id/hasAllIds.ts +6 -6
- package/src/index.ts +12 -13
- package/src/loader/index.ts +1 -1
- package/src/loader/runtime-cjs.ts +1 -1
- package/src/model-to-narrative.specs.ts +133 -135
- package/src/narrative-context.specs.ts +24 -24
- package/src/narrative-context.ts +61 -61
- package/src/narrative-registry.ts +31 -31
- package/src/narrative.ts +31 -33
- package/src/parse-graphql-request.specs.ts +5 -5
- package/src/parse-graphql-request.ts +3 -3
- package/src/samples/items.narrative.ts +2 -2
- package/src/samples/mixed-given-types.narrative.ts +2 -2
- package/src/samples/place-order.narrative.ts +2 -2
- package/src/samples/questionnaires.narrative.ts +2 -2
- package/src/samples/seasonal-assistant.schema.json +2 -2
- package/src/samples/test-with-ids.narrative.ts +2 -2
- package/src/schema.specs.ts +99 -91
- package/src/schema.ts +89 -89
- package/src/slice-builder.ts +30 -30
- package/src/transformers/model-to-narrative/analysis/lint-helpers.ts +1 -1
- package/src/transformers/model-to-narrative/cross-module-imports.specs.ts +43 -43
- package/src/transformers/model-to-narrative/cross-module-imports.ts +4 -4
- package/src/transformers/model-to-narrative/generators/compose.ts +4 -4
- package/src/transformers/model-to-narrative/generators/flow.ts +36 -36
- package/src/transformers/model-to-narrative/generators/imports.ts +1 -1
- package/src/transformers/model-to-narrative/generators/module-code.ts +15 -15
- package/src/transformers/model-to-narrative/index.ts +4 -4
- package/src/transformers/model-to-narrative/modules.specs.ts +58 -58
- package/src/transformers/model-to-narrative/spec-traversal.specs.ts +43 -43
- package/src/transformers/model-to-narrative/spec-traversal.ts +6 -6
- package/src/transformers/model-to-narrative/types.ts +1 -1
- package/src/transformers/model-to-narrative/utils/integration-extractor.ts +5 -5
- package/src/transformers/model-to-narrative/validate-modules.ts +22 -22
- package/src/transformers/narrative-to-model/assemble.ts +12 -4
- package/src/transformers/narrative-to-model/debug.ts +1 -1
- package/src/transformers/narrative-to-model/derive-modules.specs.ts +35 -35
- package/src/transformers/narrative-to-model/derive-modules.ts +11 -11
- package/src/transformers/narrative-to-model/index.ts +47 -47
- package/src/transformers/narrative-to-model/spec-processors.ts +1 -1
- package/src/transformers/narrative-to-model/strings.ts +6 -6
- package/src/transformers/narrative-to-model/type-inference.specs.ts +11 -11
- package/src/validate-slice-requests.specs.ts +113 -113
- package/src/validate-slice-requests.ts +49 -49
- package/dist/src/getNarratives.d.ts.map +0 -1
- package/dist/src/getNarratives.js.map +0 -1
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
2
|
+
import type { Scene } from '../../index';
|
|
3
|
+
import { collectMessageKeysFromScenes } from './spec-traversal';
|
|
4
4
|
|
|
5
|
-
describe('
|
|
6
|
-
it('returns empty set for empty
|
|
7
|
-
const keys =
|
|
5
|
+
describe('collectMessageKeysFromScenes', () => {
|
|
6
|
+
it('returns empty set for empty scenes array', () => {
|
|
7
|
+
const keys = collectMessageKeysFromScenes([]);
|
|
8
8
|
|
|
9
9
|
expect(keys.size).toBe(0);
|
|
10
10
|
});
|
|
11
11
|
|
|
12
|
-
it('returns empty set for
|
|
13
|
-
const
|
|
12
|
+
it('returns empty set for scenes with no slices', () => {
|
|
13
|
+
const scenes: Scene[] = [{ name: 'Empty', moments: [] }];
|
|
14
14
|
|
|
15
|
-
const keys =
|
|
15
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
16
16
|
|
|
17
17
|
expect(keys.size).toBe(0);
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
it('ignores experience slices', () => {
|
|
21
|
-
const
|
|
21
|
+
const scenes: Scene[] = [
|
|
22
22
|
{
|
|
23
23
|
name: 'Test',
|
|
24
|
-
|
|
24
|
+
moments: [
|
|
25
25
|
{
|
|
26
26
|
name: 'Homepage',
|
|
27
27
|
type: 'experience',
|
|
@@ -31,16 +31,16 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
31
31
|
},
|
|
32
32
|
];
|
|
33
33
|
|
|
34
|
-
const keys =
|
|
34
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
35
35
|
|
|
36
36
|
expect(keys.size).toBe(0);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
it('collects command keys from When steps', () => {
|
|
40
|
-
const
|
|
40
|
+
const scenes: Scene[] = [
|
|
41
41
|
{
|
|
42
42
|
name: 'Test',
|
|
43
|
-
|
|
43
|
+
moments: [
|
|
44
44
|
{
|
|
45
45
|
name: 'create order',
|
|
46
46
|
type: 'command',
|
|
@@ -70,16 +70,16 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
70
70
|
},
|
|
71
71
|
];
|
|
72
72
|
|
|
73
|
-
const keys =
|
|
73
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
74
74
|
|
|
75
75
|
expect(keys.has('command:CreateOrder')).toBe(true);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
it('collects event and state keys from Given steps', () => {
|
|
79
|
-
const
|
|
79
|
+
const scenes: Scene[] = [
|
|
80
80
|
{
|
|
81
81
|
name: 'Test',
|
|
82
|
-
|
|
82
|
+
moments: [
|
|
83
83
|
{
|
|
84
84
|
name: 'view order',
|
|
85
85
|
type: 'query',
|
|
@@ -109,17 +109,17 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
109
109
|
},
|
|
110
110
|
];
|
|
111
111
|
|
|
112
|
-
const keys =
|
|
112
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
113
113
|
|
|
114
114
|
expect(keys.has('event:OrderCreated')).toBe(true);
|
|
115
115
|
expect(keys.has('state:OrderCreated')).toBe(true);
|
|
116
116
|
});
|
|
117
117
|
|
|
118
118
|
it('collects event and state keys from And steps', () => {
|
|
119
|
-
const
|
|
119
|
+
const scenes: Scene[] = [
|
|
120
120
|
{
|
|
121
121
|
name: 'Test',
|
|
122
|
-
|
|
122
|
+
moments: [
|
|
123
123
|
{
|
|
124
124
|
name: 'test',
|
|
125
125
|
type: 'react',
|
|
@@ -148,17 +148,17 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
148
148
|
},
|
|
149
149
|
];
|
|
150
150
|
|
|
151
|
-
const keys =
|
|
151
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
152
152
|
|
|
153
153
|
expect(keys.has('event:UserLoggedIn')).toBe(true);
|
|
154
154
|
expect(keys.has('state:UserLoggedIn')).toBe(true);
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
it('collects event and state keys from Then steps', () => {
|
|
158
|
-
const
|
|
158
|
+
const scenes: Scene[] = [
|
|
159
159
|
{
|
|
160
160
|
name: 'Test',
|
|
161
|
-
|
|
161
|
+
moments: [
|
|
162
162
|
{
|
|
163
163
|
name: 'test',
|
|
164
164
|
type: 'command',
|
|
@@ -188,17 +188,17 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
188
188
|
},
|
|
189
189
|
];
|
|
190
190
|
|
|
191
|
-
const keys =
|
|
191
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
192
192
|
|
|
193
193
|
expect(keys.has('event:OrderCompleted')).toBe(true);
|
|
194
194
|
expect(keys.has('state:OrderCompleted')).toBe(true);
|
|
195
195
|
});
|
|
196
196
|
|
|
197
197
|
it('handles slices without server specs', () => {
|
|
198
|
-
const
|
|
198
|
+
const scenes: Scene[] = [
|
|
199
199
|
{
|
|
200
200
|
name: 'Test',
|
|
201
|
-
|
|
201
|
+
moments: [
|
|
202
202
|
{
|
|
203
203
|
name: 'test',
|
|
204
204
|
type: 'experience',
|
|
@@ -208,16 +208,16 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
208
208
|
},
|
|
209
209
|
];
|
|
210
210
|
|
|
211
|
-
const keys =
|
|
211
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
212
212
|
|
|
213
213
|
expect(keys.size).toBe(0);
|
|
214
214
|
});
|
|
215
215
|
|
|
216
216
|
it('handles specs without rules', () => {
|
|
217
|
-
const
|
|
217
|
+
const scenes: Scene[] = [
|
|
218
218
|
{
|
|
219
219
|
name: 'Test',
|
|
220
|
-
|
|
220
|
+
moments: [
|
|
221
221
|
{
|
|
222
222
|
name: 'test',
|
|
223
223
|
type: 'command',
|
|
@@ -231,16 +231,16 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
231
231
|
},
|
|
232
232
|
];
|
|
233
233
|
|
|
234
|
-
const keys =
|
|
234
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
235
235
|
|
|
236
236
|
expect(keys.size).toBe(0);
|
|
237
237
|
});
|
|
238
238
|
|
|
239
239
|
it('handles rules without examples', () => {
|
|
240
|
-
const
|
|
240
|
+
const scenes: Scene[] = [
|
|
241
241
|
{
|
|
242
242
|
name: 'Test',
|
|
243
|
-
|
|
243
|
+
moments: [
|
|
244
244
|
{
|
|
245
245
|
name: 'test',
|
|
246
246
|
type: 'command',
|
|
@@ -260,16 +260,16 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
260
260
|
},
|
|
261
261
|
];
|
|
262
262
|
|
|
263
|
-
const keys =
|
|
263
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
264
264
|
|
|
265
265
|
expect(keys.size).toBe(0);
|
|
266
266
|
});
|
|
267
267
|
|
|
268
268
|
it('handles examples without steps', () => {
|
|
269
|
-
const
|
|
269
|
+
const scenes: Scene[] = [
|
|
270
270
|
{
|
|
271
271
|
name: 'Test',
|
|
272
|
-
|
|
272
|
+
moments: [
|
|
273
273
|
{
|
|
274
274
|
name: 'test',
|
|
275
275
|
type: 'command',
|
|
@@ -294,16 +294,16 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
294
294
|
},
|
|
295
295
|
];
|
|
296
296
|
|
|
297
|
-
const keys =
|
|
297
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
298
298
|
|
|
299
299
|
expect(keys.size).toBe(0);
|
|
300
300
|
});
|
|
301
301
|
|
|
302
302
|
it('handles steps with empty text', () => {
|
|
303
|
-
const
|
|
303
|
+
const scenes: Scene[] = [
|
|
304
304
|
{
|
|
305
305
|
name: 'Test',
|
|
306
|
-
|
|
306
|
+
moments: [
|
|
307
307
|
{
|
|
308
308
|
name: 'test',
|
|
309
309
|
type: 'command',
|
|
@@ -333,16 +333,16 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
333
333
|
},
|
|
334
334
|
];
|
|
335
335
|
|
|
336
|
-
const keys =
|
|
336
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
337
337
|
|
|
338
338
|
expect(keys.size).toBe(0);
|
|
339
339
|
});
|
|
340
340
|
|
|
341
|
-
it('collects keys from multiple
|
|
342
|
-
const
|
|
341
|
+
it('collects keys from multiple scenes and slices', () => {
|
|
342
|
+
const scenes: Scene[] = [
|
|
343
343
|
{
|
|
344
344
|
name: 'Orders',
|
|
345
|
-
|
|
345
|
+
moments: [
|
|
346
346
|
{
|
|
347
347
|
name: 'create',
|
|
348
348
|
type: 'command',
|
|
@@ -375,7 +375,7 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
375
375
|
},
|
|
376
376
|
{
|
|
377
377
|
name: 'Users',
|
|
378
|
-
|
|
378
|
+
moments: [
|
|
379
379
|
{
|
|
380
380
|
name: 'register',
|
|
381
381
|
type: 'command',
|
|
@@ -408,7 +408,7 @@ describe('collectMessageKeysFromNarratives', () => {
|
|
|
408
408
|
},
|
|
409
409
|
];
|
|
410
410
|
|
|
411
|
-
const keys =
|
|
411
|
+
const keys = collectMessageKeysFromScenes(scenes);
|
|
412
412
|
|
|
413
413
|
expect(keys.has('command:CreateOrder')).toBe(true);
|
|
414
414
|
expect(keys.has('event:OrderCreated')).toBe(true);
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Scene } from '../../index';
|
|
2
2
|
|
|
3
|
-
export function
|
|
3
|
+
export function collectMessageKeysFromScenes(scenes: Scene[]): Set<string> {
|
|
4
4
|
const usedKeys = new Set<string>();
|
|
5
5
|
|
|
6
|
-
for (const
|
|
7
|
-
for (const slice of
|
|
8
|
-
|
|
6
|
+
for (const scene of scenes) {
|
|
7
|
+
for (const slice of scene.moments) {
|
|
8
|
+
collectMessageKeysFromMoment(slice, usedKeys);
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
return usedKeys;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
function
|
|
15
|
+
function collectMessageKeysFromMoment(slice: Scene['moments'][number], usedKeys: Set<string>): void {
|
|
16
16
|
if (slice.type !== 'command' && slice.type !== 'query' && slice.type !== 'react') {
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
@@ -44,14 +44,14 @@ function processDataItem(dataItem: Record<string, unknown>, set: Set<string>): v
|
|
|
44
44
|
* @param flows Array of flow specifications to analyze
|
|
45
45
|
* @returns Array of integration type names found in the flows
|
|
46
46
|
*/
|
|
47
|
-
export function extractTypeIntegrationNames(flows: Array<{ name: string;
|
|
47
|
+
export function extractTypeIntegrationNames(flows: Array<{ name: string; moments: unknown[] }>): string[] {
|
|
48
48
|
const set = new Set<string>();
|
|
49
49
|
|
|
50
50
|
for (const fl of flows) {
|
|
51
|
-
const
|
|
52
|
-
for (const sl of
|
|
53
|
-
const
|
|
54
|
-
const server =
|
|
51
|
+
const moments = fl.moments ?? [];
|
|
52
|
+
for (const sl of moments) {
|
|
53
|
+
const momentData = sl as Record<string, unknown>;
|
|
54
|
+
const server = momentData.server as Record<string, unknown> | undefined;
|
|
55
55
|
const data = server?.data as unknown[] | undefined;
|
|
56
56
|
|
|
57
57
|
if (!Array.isArray(data)) continue;
|
|
@@ -4,11 +4,11 @@ import { toMessageKey } from './ordering';
|
|
|
4
4
|
export interface ValidationError {
|
|
5
5
|
type:
|
|
6
6
|
| 'duplicate_sourceFile'
|
|
7
|
-
| '
|
|
8
|
-
| '
|
|
7
|
+
| 'scene_unassigned'
|
|
8
|
+
| 'scene_multi_assigned'
|
|
9
9
|
| 'message_multi_declared'
|
|
10
10
|
| 'message_undeclared'
|
|
11
|
-
| '
|
|
11
|
+
| 'scene_not_found';
|
|
12
12
|
message: string;
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -27,7 +27,7 @@ export function validateModules(model: Model): ValidationError[] {
|
|
|
27
27
|
return errors;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
errors.push(...
|
|
30
|
+
errors.push(...validateSceneAssignments(authoredModules, model));
|
|
31
31
|
errors.push(...validateMessageDeclarations(authoredModules, model));
|
|
32
32
|
|
|
33
33
|
return errors;
|
|
@@ -53,42 +53,42 @@ function validateUniqueSourceFiles(modules: Model['modules']): ValidationError[]
|
|
|
53
53
|
return errors;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function
|
|
56
|
+
function validateSceneAssignments(authoredModules: Model['modules'], model: Model): ValidationError[] {
|
|
57
57
|
const errors: ValidationError[] = [];
|
|
58
|
-
const
|
|
58
|
+
const sceneAssignments = new Map<string, string[]>();
|
|
59
59
|
|
|
60
60
|
for (const module of authoredModules) {
|
|
61
|
-
for (const
|
|
62
|
-
if (!
|
|
63
|
-
|
|
61
|
+
for (const sceneId of module.contains.sceneIds) {
|
|
62
|
+
if (!sceneAssignments.has(sceneId)) {
|
|
63
|
+
sceneAssignments.set(sceneId, []);
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
sceneAssignments.get(sceneId)!.push(module.sourceFile);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
const
|
|
69
|
+
const modelSceneIds = new Set(model.scenes.map((n) => n.id).filter((id): id is string => id !== undefined));
|
|
70
70
|
|
|
71
|
-
for (const [
|
|
72
|
-
if (!
|
|
71
|
+
for (const [sceneId, moduleSourceFiles] of sceneAssignments) {
|
|
72
|
+
if (!modelSceneIds.has(sceneId)) {
|
|
73
73
|
errors.push({
|
|
74
|
-
type: '
|
|
75
|
-
message: `
|
|
74
|
+
type: 'scene_not_found',
|
|
75
|
+
message: `Scene '${sceneId}' referenced by module(s) [${moduleSourceFiles.join(', ')}] does not exist`,
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
if (moduleSourceFiles.length > 1) {
|
|
79
79
|
errors.push({
|
|
80
|
-
type: '
|
|
81
|
-
message: `
|
|
80
|
+
type: 'scene_multi_assigned',
|
|
81
|
+
message: `Scene '${sceneId}' is assigned to multiple modules: [${moduleSourceFiles.join(', ')}]`,
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
const
|
|
87
|
-
for (const
|
|
88
|
-
if (
|
|
86
|
+
const assignedSceneIds = new Set(sceneAssignments.keys());
|
|
87
|
+
for (const scene of model.scenes) {
|
|
88
|
+
if (scene.id && !assignedSceneIds.has(scene.id)) {
|
|
89
89
|
errors.push({
|
|
90
|
-
type: '
|
|
91
|
-
message: `
|
|
90
|
+
type: 'scene_unassigned',
|
|
91
|
+
message: `Scene '${scene.id}' (${scene.name}) is not assigned to any module`,
|
|
92
92
|
});
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import type { Message, Model, Narrative } from '../../index';
|
|
1
|
+
import type { Message, Model, Narrative, Scene } from '../../index';
|
|
2
2
|
import { deriveModules } from './derive-modules';
|
|
3
3
|
|
|
4
|
-
export function assembleSpecs(
|
|
4
|
+
export function assembleSpecs(scenes: Scene[], messages: unknown[], integrations: unknown[]): Model {
|
|
5
5
|
const typedMessages = messages as Message[];
|
|
6
|
-
const modules = deriveModules(
|
|
6
|
+
const modules = deriveModules(scenes, typedMessages);
|
|
7
|
+
|
|
8
|
+
const narratives: Narrative[] = [
|
|
9
|
+
{
|
|
10
|
+
name: 'Default',
|
|
11
|
+
sceneIds: scenes.filter((s) => s.id).map((s) => s.id!),
|
|
12
|
+
},
|
|
13
|
+
];
|
|
7
14
|
|
|
8
15
|
return {
|
|
9
16
|
variant: 'specs' as const,
|
|
10
|
-
|
|
17
|
+
scenes,
|
|
11
18
|
messages: typedMessages,
|
|
12
19
|
integrations: integrations as Model['integrations'],
|
|
13
20
|
modules,
|
|
21
|
+
narratives,
|
|
14
22
|
};
|
|
15
23
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import createDebug from 'debug';
|
|
2
2
|
|
|
3
|
-
export const debugIntegrations = createDebug('auto:flow:
|
|
3
|
+
export const debugIntegrations = createDebug('auto:flow:getScenes:integrations');
|
|
4
4
|
if (typeof debugIntegrations === 'object' && debugIntegrations !== null && 'color' in debugIntegrations) {
|
|
5
5
|
(debugIntegrations as { color: string }).color = '6';
|
|
6
6
|
}
|
|
@@ -1,64 +1,64 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import type { Message,
|
|
2
|
+
import type { Message, Scene } from '../../index';
|
|
3
3
|
import { deriveModules } from './derive-modules';
|
|
4
4
|
|
|
5
5
|
describe('deriveModules', () => {
|
|
6
|
-
it('groups
|
|
7
|
-
const
|
|
8
|
-
{ name: 'Orders', id: 'orders-1', sourceFile: 'orders.narrative.ts',
|
|
9
|
-
{ name: 'Users', id: 'users-1', sourceFile: 'users.narrative.ts',
|
|
6
|
+
it('groups scenes by sourceFile into separate modules', () => {
|
|
7
|
+
const scenes: Scene[] = [
|
|
8
|
+
{ name: 'Orders', id: 'orders-1', sourceFile: 'orders.narrative.ts', moments: [] },
|
|
9
|
+
{ name: 'Users', id: 'users-1', sourceFile: 'users.narrative.ts', moments: [] },
|
|
10
10
|
];
|
|
11
11
|
const messages: Message[] = [];
|
|
12
12
|
|
|
13
|
-
const modules = deriveModules(
|
|
13
|
+
const modules = deriveModules(scenes, messages);
|
|
14
14
|
|
|
15
15
|
expect(modules).toHaveLength(2);
|
|
16
16
|
expect(modules.map((m) => m.sourceFile).sort()).toEqual(['orders.narrative.ts', 'users.narrative.ts']);
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
it('uses default sourceFile when
|
|
20
|
-
const
|
|
19
|
+
it('uses default sourceFile when scene has no sourceFile', () => {
|
|
20
|
+
const scenes: Scene[] = [{ name: 'Default', id: 'default-1', moments: [] }];
|
|
21
21
|
const messages: Message[] = [];
|
|
22
22
|
|
|
23
|
-
const modules = deriveModules(
|
|
23
|
+
const modules = deriveModules(scenes, messages);
|
|
24
24
|
|
|
25
25
|
expect(modules).toHaveLength(1);
|
|
26
26
|
expect(modules[0].sourceFile).toBe('generated.narrative.ts');
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
it('generates synthetic
|
|
30
|
-
const
|
|
31
|
-
{ name: 'First',
|
|
32
|
-
{ name: 'Second',
|
|
29
|
+
it('generates synthetic scene IDs when scenes have no ID', () => {
|
|
30
|
+
const scenes: Scene[] = [
|
|
31
|
+
{ name: 'First', moments: [] },
|
|
32
|
+
{ name: 'Second', moments: [] },
|
|
33
33
|
];
|
|
34
34
|
const messages: Message[] = [];
|
|
35
35
|
|
|
36
|
-
const modules = deriveModules(
|
|
36
|
+
const modules = deriveModules(scenes, messages);
|
|
37
37
|
|
|
38
38
|
expect(modules).toHaveLength(1);
|
|
39
|
-
expect(modules[0].contains.
|
|
39
|
+
expect(modules[0].contains.sceneIds).toEqual(['__derived_0_0_First', '__derived_0_1_Second']);
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
it('sets isDerived to true for all generated modules', () => {
|
|
43
|
-
const
|
|
43
|
+
const scenes: Scene[] = [{ name: 'Test', id: 'test-1', moments: [] }];
|
|
44
44
|
const messages: Message[] = [];
|
|
45
45
|
|
|
46
|
-
const modules = deriveModules(
|
|
46
|
+
const modules = deriveModules(scenes, messages);
|
|
47
47
|
|
|
48
48
|
expect(modules[0].isDerived).toBe(true);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
it('includes all messages in declares for each module', () => {
|
|
52
|
-
const
|
|
53
|
-
{ name: 'Orders', id: 'orders-1', sourceFile: 'orders.narrative.ts',
|
|
54
|
-
{ name: 'Users', id: 'users-1', sourceFile: 'users.narrative.ts',
|
|
52
|
+
const scenes: Scene[] = [
|
|
53
|
+
{ name: 'Orders', id: 'orders-1', sourceFile: 'orders.narrative.ts', moments: [] },
|
|
54
|
+
{ name: 'Users', id: 'users-1', sourceFile: 'users.narrative.ts', moments: [] },
|
|
55
55
|
];
|
|
56
56
|
const messages: Message[] = [
|
|
57
57
|
{ type: 'command', name: 'CreateOrder', fields: [] },
|
|
58
58
|
{ type: 'event', source: 'internal', name: 'OrderCreated', fields: [] },
|
|
59
59
|
];
|
|
60
60
|
|
|
61
|
-
const modules = deriveModules(
|
|
61
|
+
const modules = deriveModules(scenes, messages);
|
|
62
62
|
|
|
63
63
|
for (const mod of modules) {
|
|
64
64
|
expect(mod.declares.messages).toEqual([
|
|
@@ -69,14 +69,14 @@ describe('deriveModules', () => {
|
|
|
69
69
|
});
|
|
70
70
|
|
|
71
71
|
it('sorts declared messages by kind:name', () => {
|
|
72
|
-
const
|
|
72
|
+
const scenes: Scene[] = [{ name: 'Test', id: 'test-1', moments: [] }];
|
|
73
73
|
const messages: Message[] = [
|
|
74
74
|
{ type: 'state', name: 'ZState', fields: [] },
|
|
75
75
|
{ type: 'command', name: 'ACommand', fields: [] },
|
|
76
76
|
{ type: 'event', source: 'internal', name: 'MEvent', fields: [] },
|
|
77
77
|
];
|
|
78
78
|
|
|
79
|
-
const modules = deriveModules(
|
|
79
|
+
const modules = deriveModules(scenes, messages);
|
|
80
80
|
|
|
81
81
|
expect(modules[0].declares.messages).toEqual([
|
|
82
82
|
{ kind: 'command', name: 'ACommand' },
|
|
@@ -86,35 +86,35 @@ describe('deriveModules', () => {
|
|
|
86
86
|
});
|
|
87
87
|
|
|
88
88
|
it('creates independent message arrays for each module', () => {
|
|
89
|
-
const
|
|
90
|
-
{ name: 'A', id: 'a', sourceFile: 'a.ts',
|
|
91
|
-
{ name: 'B', id: 'b', sourceFile: 'b.ts',
|
|
89
|
+
const scenes: Scene[] = [
|
|
90
|
+
{ name: 'A', id: 'a', sourceFile: 'a.ts', moments: [] },
|
|
91
|
+
{ name: 'B', id: 'b', sourceFile: 'b.ts', moments: [] },
|
|
92
92
|
];
|
|
93
93
|
const messages: Message[] = [{ type: 'event', source: 'internal', name: 'SharedEvent', fields: [] }];
|
|
94
94
|
|
|
95
|
-
const modules = deriveModules(
|
|
95
|
+
const modules = deriveModules(scenes, messages);
|
|
96
96
|
|
|
97
97
|
expect(modules[0].declares.messages).not.toBe(modules[1].declares.messages);
|
|
98
98
|
expect(modules[0].declares.messages).toEqual(modules[1].declares.messages);
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
-
it('returns empty array when no
|
|
101
|
+
it('returns empty array when no scenes provided', () => {
|
|
102
102
|
const modules = deriveModules([], []);
|
|
103
103
|
|
|
104
104
|
expect(modules).toEqual([]);
|
|
105
105
|
});
|
|
106
106
|
|
|
107
|
-
it('groups multiple
|
|
108
|
-
const
|
|
109
|
-
{ name: 'Flow1', id: 'flow-1', sourceFile: 'shared.ts',
|
|
110
|
-
{ name: 'Flow2', id: 'flow-2', sourceFile: 'shared.ts',
|
|
111
|
-
{ name: 'Flow3', id: 'flow-3', sourceFile: 'shared.ts',
|
|
107
|
+
it('groups multiple scenes with same sourceFile into one module', () => {
|
|
108
|
+
const scenes: Scene[] = [
|
|
109
|
+
{ name: 'Flow1', id: 'flow-1', sourceFile: 'shared.ts', moments: [] },
|
|
110
|
+
{ name: 'Flow2', id: 'flow-2', sourceFile: 'shared.ts', moments: [] },
|
|
111
|
+
{ name: 'Flow3', id: 'flow-3', sourceFile: 'shared.ts', moments: [] },
|
|
112
112
|
];
|
|
113
113
|
const messages: Message[] = [];
|
|
114
114
|
|
|
115
|
-
const modules = deriveModules(
|
|
115
|
+
const modules = deriveModules(scenes, messages);
|
|
116
116
|
|
|
117
117
|
expect(modules).toHaveLength(1);
|
|
118
|
-
expect(modules[0].contains.
|
|
118
|
+
expect(modules[0].contains.sceneIds).toEqual(['flow-1', 'flow-2', 'flow-3']);
|
|
119
119
|
});
|
|
120
120
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type { Message, Module,
|
|
1
|
+
import type { Message, Module, Scene } from '../../index';
|
|
2
2
|
|
|
3
3
|
const DEFAULT_SOURCE_FILE = 'generated.narrative.ts';
|
|
4
4
|
|
|
5
|
-
export function deriveModules(
|
|
6
|
-
const bySourceFile =
|
|
5
|
+
export function deriveModules(scenes: Scene[], messages: Message[]): Module[] {
|
|
6
|
+
const bySourceFile = groupScenesBySourceFile(scenes);
|
|
7
7
|
|
|
8
|
-
return Array.from(bySourceFile.entries()).map(([sourceFile,
|
|
9
|
-
const
|
|
8
|
+
return Array.from(bySourceFile.entries()).map(([sourceFile, scns], index) => {
|
|
9
|
+
const sceneIds = scns.map((n, i) => n.id ?? `__derived_${index}_${i}_${n.name}`);
|
|
10
10
|
const messageRefs = messages
|
|
11
11
|
.map((m) => ({ kind: m.type, name: m.name }))
|
|
12
12
|
.sort((a, b) => `${a.kind}:${a.name}`.localeCompare(`${b.kind}:${b.name}`));
|
|
@@ -14,21 +14,21 @@ export function deriveModules(narratives: Narrative[], messages: Message[]): Mod
|
|
|
14
14
|
return {
|
|
15
15
|
sourceFile,
|
|
16
16
|
isDerived: true,
|
|
17
|
-
contains: {
|
|
17
|
+
contains: { sceneIds },
|
|
18
18
|
declares: { messages: messageRefs },
|
|
19
19
|
};
|
|
20
20
|
});
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
function
|
|
24
|
-
const groups = new Map<string,
|
|
23
|
+
function groupScenesBySourceFile(scenes: Scene[]): Map<string, Scene[]> {
|
|
24
|
+
const groups = new Map<string, Scene[]>();
|
|
25
25
|
|
|
26
|
-
for (const
|
|
27
|
-
const sourceFile =
|
|
26
|
+
for (const scene of scenes) {
|
|
27
|
+
const sourceFile = scene.sourceFile ?? DEFAULT_SOURCE_FILE;
|
|
28
28
|
if (!groups.has(sourceFile)) {
|
|
29
29
|
groups.set(sourceFile, []);
|
|
30
30
|
}
|
|
31
|
-
groups.get(sourceFile)!.push(
|
|
31
|
+
groups.get(sourceFile)!.push(scene);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
return groups;
|