@auto-engineer/narrative 1.157.0 → 1.158.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 +72 -0
- package/dist/src/fluent-builder.d.ts +9 -1
- package/dist/src/fluent-builder.d.ts.map +1 -1
- package/dist/src/fluent-builder.js +36 -0
- package/dist/src/fluent-builder.js.map +1 -1
- package/dist/src/id/addAutoIds.d.ts.map +1 -1
- package/dist/src/id/addAutoIds.js +14 -0
- package/dist/src/id/addAutoIds.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/loader/index.d.ts.map +1 -1
- package/dist/src/loader/index.js +2 -0
- package/dist/src/loader/index.js.map +1 -1
- package/dist/src/model-level-registry.d.ts +42 -0
- package/dist/src/model-level-registry.d.ts.map +1 -0
- package/dist/src/model-level-registry.js +42 -0
- package/dist/src/model-level-registry.js.map +1 -0
- package/dist/src/narrative-context.d.ts +2 -0
- package/dist/src/narrative-context.d.ts.map +1 -1
- package/dist/src/narrative-context.js +10 -0
- package/dist/src/narrative-context.js.map +1 -1
- package/dist/src/narrative.d.ts +16 -0
- package/dist/src/narrative.d.ts.map +1 -1
- package/dist/src/narrative.js +39 -1
- package/dist/src/narrative.js.map +1 -1
- package/dist/src/schema.d.ts +879 -1
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +45 -1
- package/dist/src/schema.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/flow.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/flow.js +45 -1
- 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 +6 -1
- package/dist/src/transformers/model-to-narrative/generators/imports.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/generators/metadata.d.ts +10 -0
- package/dist/src/transformers/model-to-narrative/generators/metadata.d.ts.map +1 -0
- package/dist/src/transformers/model-to-narrative/generators/metadata.js +93 -0
- package/dist/src/transformers/model-to-narrative/generators/metadata.js.map +1 -0
- package/dist/src/transformers/model-to-narrative/index.d.ts.map +1 -1
- package/dist/src/transformers/model-to-narrative/index.js +21 -1
- package/dist/src/transformers/model-to-narrative/index.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/assemble.d.ts +10 -2
- package/dist/src/transformers/narrative-to-model/assemble.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/assemble.js +47 -11
- package/dist/src/transformers/narrative-to-model/assemble.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/index.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/index.js +9 -1
- package/dist/src/transformers/narrative-to-model/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/ketchup-plan.md +14 -4
- package/package.json +4 -4
- package/src/fluent-builder.specs.ts +60 -0
- package/src/fluent-builder.ts +53 -1
- package/src/id/addAutoIds.ts +15 -0
- package/src/index.ts +5 -0
- package/src/loader/index.ts +2 -0
- package/src/model-level-registry.specs.ts +217 -0
- package/src/model-level-registry.ts +60 -0
- package/src/model-to-narrative.specs.ts +102 -0
- package/src/narrative-context.ts +10 -0
- package/src/narrative.ts +48 -0
- package/src/schema.specs.ts +290 -0
- package/src/schema.ts +55 -0
- package/src/transformers/model-to-narrative/generators/flow.ts +52 -1
- package/src/transformers/model-to-narrative/generators/imports.ts +6 -1
- package/src/transformers/model-to-narrative/generators/metadata.specs.ts +40 -0
- package/src/transformers/model-to-narrative/generators/metadata.ts +140 -0
- package/src/transformers/model-to-narrative/index.ts +25 -2
- package/src/transformers/narrative-to-model/assemble.specs.ts +82 -0
- package/src/transformers/narrative-to-model/assemble.ts +61 -12
- package/src/transformers/narrative-to-model/index.ts +22 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type tsNS from 'typescript';
|
|
2
|
+
import type { Model, Narrative } from '../../../index';
|
|
3
|
+
import { jsonToExpr } from '../ast/emit-helpers';
|
|
4
|
+
|
|
5
|
+
export function buildAssumptionsCall(
|
|
6
|
+
ts: typeof import('typescript'),
|
|
7
|
+
f: tsNS.NodeFactory,
|
|
8
|
+
items: string[],
|
|
9
|
+
): tsNS.Statement {
|
|
10
|
+
return f.createExpressionStatement(
|
|
11
|
+
f.createCallExpression(
|
|
12
|
+
f.createIdentifier('assumptions'),
|
|
13
|
+
undefined,
|
|
14
|
+
items.map((s) => f.createStringLiteral(s)),
|
|
15
|
+
),
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function buildRequirementsCall(f: tsNS.NodeFactory, doc: string): tsNS.Statement {
|
|
20
|
+
return f.createExpressionStatement(
|
|
21
|
+
f.createCallExpression(f.createIdentifier('requirements'), undefined, [f.createStringLiteral(doc)]),
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function buildActorCall(
|
|
26
|
+
ts: typeof import('typescript'),
|
|
27
|
+
f: tsNS.NodeFactory,
|
|
28
|
+
actorDef: Model['actors'] extends (infer T)[] | undefined ? T : never,
|
|
29
|
+
): tsNS.Statement {
|
|
30
|
+
return f.createExpressionStatement(
|
|
31
|
+
f.createCallExpression(f.createIdentifier('actor'), undefined, [jsonToExpr(ts, f, actorDef)]),
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function buildEntityCall(
|
|
36
|
+
ts: typeof import('typescript'),
|
|
37
|
+
f: tsNS.NodeFactory,
|
|
38
|
+
entityDef: Model['entities'] extends (infer T)[] | undefined ? T : never,
|
|
39
|
+
): tsNS.Statement {
|
|
40
|
+
return f.createExpressionStatement(
|
|
41
|
+
f.createCallExpression(f.createIdentifier('entity'), undefined, [jsonToExpr(ts, f, entityDef)]),
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function buildModelMetadataStatements(ts: typeof import('typescript'), model: Model): tsNS.Statement[] {
|
|
46
|
+
const f = ts.factory;
|
|
47
|
+
const statements: tsNS.Statement[] = [];
|
|
48
|
+
|
|
49
|
+
if (model.actors?.length) {
|
|
50
|
+
for (const a of model.actors) statements.push(buildActorCall(ts, f, a));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (model.entities?.length) {
|
|
54
|
+
for (const e of model.entities) statements.push(buildEntityCall(ts, f, e));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (model.assumptions?.length) {
|
|
58
|
+
statements.push(buildAssumptionsCall(ts, f, model.assumptions));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (model.requirements) {
|
|
62
|
+
statements.push(buildRequirementsCall(f, model.requirements));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return statements;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function buildNarrativeCall(
|
|
69
|
+
ts: typeof import('typescript'),
|
|
70
|
+
f: tsNS.NodeFactory,
|
|
71
|
+
nar: Narrative,
|
|
72
|
+
sceneIdToName: Map<string, string>,
|
|
73
|
+
): tsNS.Statement {
|
|
74
|
+
const configProps: tsNS.ObjectLiteralElementLike[] = [];
|
|
75
|
+
|
|
76
|
+
if (nar.outcome) configProps.push(f.createPropertyAssignment('outcome', f.createStringLiteral(nar.outcome)));
|
|
77
|
+
if (nar.impact) configProps.push(f.createPropertyAssignment('impact', f.createStringLiteral(nar.impact)));
|
|
78
|
+
if (nar.actors?.length) configProps.push(f.createPropertyAssignment('actors', jsonToExpr(ts, f, nar.actors)));
|
|
79
|
+
if (nar.sceneIds.length > 0) {
|
|
80
|
+
const sceneNames = nar.sceneIds.map((id) => sceneIdToName.get(id) ?? id);
|
|
81
|
+
configProps.push(f.createPropertyAssignment('scenes', jsonToExpr(ts, f, sceneNames)));
|
|
82
|
+
}
|
|
83
|
+
if (nar.assumptions?.length)
|
|
84
|
+
configProps.push(f.createPropertyAssignment('assumptions', jsonToExpr(ts, f, nar.assumptions)));
|
|
85
|
+
if (nar.requirements)
|
|
86
|
+
configProps.push(f.createPropertyAssignment('requirements', f.createStringLiteral(nar.requirements)));
|
|
87
|
+
|
|
88
|
+
const args: tsNS.Expression[] = [f.createStringLiteral(nar.name)];
|
|
89
|
+
if (nar.id) args.push(f.createStringLiteral(nar.id));
|
|
90
|
+
args.push(f.createObjectLiteralExpression(configProps, configProps.length > 2));
|
|
91
|
+
|
|
92
|
+
return f.createExpressionStatement(f.createCallExpression(f.createIdentifier('narrative'), undefined, args));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function hasNarrativeMetadata(nar: Narrative): boolean {
|
|
96
|
+
return (
|
|
97
|
+
nar.outcome !== undefined ||
|
|
98
|
+
nar.impact !== undefined ||
|
|
99
|
+
(nar.actors?.length ?? 0) > 0 ||
|
|
100
|
+
(nar.assumptions?.length ?? 0) > 0 ||
|
|
101
|
+
nar.requirements !== undefined
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function modelHasMetadata(model: Model): boolean {
|
|
106
|
+
return (
|
|
107
|
+
(model.actors?.length ?? 0) > 0 ||
|
|
108
|
+
(model.entities?.length ?? 0) > 0 ||
|
|
109
|
+
(model.assumptions?.length ?? 0) > 0 ||
|
|
110
|
+
model.requirements !== undefined ||
|
|
111
|
+
model.narratives?.some(hasNarrativeMetadata)
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function buildAllMetadataStatements(
|
|
116
|
+
ts: typeof import('typescript'),
|
|
117
|
+
model: Model,
|
|
118
|
+
): { statements: tsNS.Statement[]; usedFunctions: Set<string> } | null {
|
|
119
|
+
if (!modelHasMetadata(model)) return null;
|
|
120
|
+
|
|
121
|
+
const f = ts.factory;
|
|
122
|
+
const usedFunctions = new Set<string>();
|
|
123
|
+
const modelStatements = buildModelMetadataStatements(ts, model);
|
|
124
|
+
|
|
125
|
+
if (model.actors?.length) usedFunctions.add('actor');
|
|
126
|
+
if (model.entities?.length) usedFunctions.add('entity');
|
|
127
|
+
if (model.assumptions?.length) usedFunctions.add('assumptions');
|
|
128
|
+
if (model.requirements) usedFunctions.add('requirements');
|
|
129
|
+
|
|
130
|
+
const sceneIdToName = new Map(model.scenes.map((s) => [s.id ?? s.name, s.name]));
|
|
131
|
+
const narrativeStatements: tsNS.Statement[] = [];
|
|
132
|
+
for (const nar of model.narratives) {
|
|
133
|
+
if (hasNarrativeMetadata(nar)) {
|
|
134
|
+
narrativeStatements.push(buildNarrativeCall(ts, f, nar, sceneIdToName));
|
|
135
|
+
usedFunctions.add('narrative');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return { statements: [...modelStatements, ...narrativeStatements], usedFunctions };
|
|
140
|
+
}
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
1
2
|
import type { Model } from '../../index';
|
|
2
3
|
import { formatWithPrettier } from './formatting/prettier';
|
|
4
|
+
import { buildImports } from './generators/imports';
|
|
5
|
+
import { buildAllMetadataStatements } from './generators/metadata';
|
|
3
6
|
import { generateAllModulesCode } from './generators/module-code';
|
|
4
|
-
import type { GeneratedScenes } from './types';
|
|
7
|
+
import type { GeneratedFile, GeneratedScenes } from './types';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Converts a schema specification to TypeScript flow DSL code files.
|
|
@@ -17,7 +20,9 @@ export async function modelToNarrative(model: Model): Promise<GeneratedScenes> {
|
|
|
17
20
|
const flowImport = '@auto-engineer/narrative';
|
|
18
21
|
const integrationImport = extractIntegrationImportFromModel(model);
|
|
19
22
|
|
|
20
|
-
const
|
|
23
|
+
const moduleFiles = generateAllModulesCode(model, { flowImport, integrationImport });
|
|
24
|
+
const metadataFile = generateMetadataFile(model, flowImport);
|
|
25
|
+
const rawFiles = metadataFile ? [metadataFile, ...moduleFiles] : moduleFiles;
|
|
21
26
|
|
|
22
27
|
const formattedFiles = await Promise.all(
|
|
23
28
|
rawFiles.map(async (file) => ({
|
|
@@ -29,6 +34,24 @@ export async function modelToNarrative(model: Model): Promise<GeneratedScenes> {
|
|
|
29
34
|
return { files: formattedFiles };
|
|
30
35
|
}
|
|
31
36
|
|
|
37
|
+
function generateMetadataFile(model: Model, flowImport: string): GeneratedFile | null {
|
|
38
|
+
const result = buildAllMetadataStatements(ts, model);
|
|
39
|
+
if (!result) return null;
|
|
40
|
+
|
|
41
|
+
const f = ts.factory;
|
|
42
|
+
const { statements, usedFunctions } = result;
|
|
43
|
+
|
|
44
|
+
const imports = buildImports(ts, { flowImport, integrationImport: '' }, [], [], [], Array.from(usedFunctions));
|
|
45
|
+
const allStatements: ts.Statement[] = [];
|
|
46
|
+
if (imports.importFlowValues) allStatements.push(imports.importFlowValues);
|
|
47
|
+
allStatements.push(...statements);
|
|
48
|
+
|
|
49
|
+
const file = f.createSourceFile(allStatements, f.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None);
|
|
50
|
+
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
51
|
+
|
|
52
|
+
return { path: 'model.narrative.ts', code: printer.printFile(file) };
|
|
53
|
+
}
|
|
54
|
+
|
|
32
55
|
function extractIntegrationImportFromModel(model: Model): string {
|
|
33
56
|
if (model.integrations && model.integrations.length > 0) {
|
|
34
57
|
return model.integrations[0].source;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import type { NarrativeDefinition } from '../../model-level-registry';
|
|
3
|
+
import { assembleSpecs } from './assemble';
|
|
4
|
+
|
|
5
|
+
describe('assembleSpecs', () => {
|
|
6
|
+
it('backward compat: no metadata produces Default narrative', () => {
|
|
7
|
+
const scenes = [{ name: 'Step', id: 's-1', moments: [] }];
|
|
8
|
+
const messages = [{ type: 'command' as const, name: 'DoIt', fields: [] }];
|
|
9
|
+
|
|
10
|
+
const model = assembleSpecs(scenes, messages);
|
|
11
|
+
|
|
12
|
+
expect(model).toEqual({
|
|
13
|
+
variant: 'specs',
|
|
14
|
+
scenes,
|
|
15
|
+
messages,
|
|
16
|
+
integrations: undefined,
|
|
17
|
+
modules: expect.any(Array),
|
|
18
|
+
narratives: [{ name: 'Default', sceneIds: ['s-1'] }],
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('passes through model-level metadata', () => {
|
|
23
|
+
const model = assembleSpecs([], [], undefined, {
|
|
24
|
+
actors: [{ name: 'Op', kind: 'person' as const, description: 'Runs it' }],
|
|
25
|
+
entities: [{ name: 'Item', description: 'A thing' }],
|
|
26
|
+
assumptions: ['Always online'],
|
|
27
|
+
requirements: 'Must be fast',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(model.actors).toEqual([{ name: 'Op', kind: 'person', description: 'Runs it' }]);
|
|
31
|
+
expect(model.entities).toEqual([{ name: 'Item', description: 'A thing' }]);
|
|
32
|
+
expect(model.assumptions).toEqual(['Always online']);
|
|
33
|
+
expect(model.requirements).toBe('Must be fast');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('resolves narrative sceneNames to sceneIds', () => {
|
|
37
|
+
const scenes = [
|
|
38
|
+
{ name: 'Add to Cart', id: 'n-1', moments: [] },
|
|
39
|
+
{ name: 'Payment', id: 'n-2', moments: [] },
|
|
40
|
+
];
|
|
41
|
+
const defs: NarrativeDefinition[] = [
|
|
42
|
+
{
|
|
43
|
+
name: 'Checkout',
|
|
44
|
+
outcome: 'Items purchased',
|
|
45
|
+
impact: 'critical',
|
|
46
|
+
actors: ['Buyer'],
|
|
47
|
+
scenes: ['Add to Cart', 'Payment'],
|
|
48
|
+
assumptions: ['Gateway up'],
|
|
49
|
+
requirements: 'PCI',
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const model = assembleSpecs(scenes, [], undefined, undefined, defs);
|
|
54
|
+
|
|
55
|
+
expect(model.narratives).toEqual([
|
|
56
|
+
{
|
|
57
|
+
name: 'Checkout',
|
|
58
|
+
sceneIds: ['n-1', 'n-2'],
|
|
59
|
+
outcome: 'Items purchased',
|
|
60
|
+
impact: 'critical',
|
|
61
|
+
actors: ['Buyer'],
|
|
62
|
+
assumptions: ['Gateway up'],
|
|
63
|
+
requirements: 'PCI',
|
|
64
|
+
},
|
|
65
|
+
]);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('creates Default narrative for uncovered scenes', () => {
|
|
69
|
+
const scenes = [
|
|
70
|
+
{ name: 'Covered', id: 'n-1', moments: [] },
|
|
71
|
+
{ name: 'Uncovered', id: 'n-2', moments: [] },
|
|
72
|
+
];
|
|
73
|
+
const defs: NarrativeDefinition[] = [{ name: 'Flow', scenes: ['Covered'] }];
|
|
74
|
+
|
|
75
|
+
const model = assembleSpecs(scenes, [], undefined, undefined, defs);
|
|
76
|
+
|
|
77
|
+
expect(model.narratives).toEqual([
|
|
78
|
+
{ name: 'Flow', sceneIds: ['n-1'] },
|
|
79
|
+
{ name: 'Default', sceneIds: ['n-2'] },
|
|
80
|
+
]);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -1,23 +1,72 @@
|
|
|
1
|
-
import type { Message, Model, Narrative, Scene } from '../../index';
|
|
1
|
+
import type { Actor, Entity, Message, Model, Narrative, Scene } from '../../index';
|
|
2
|
+
import type { NarrativeDefinition } from '../../model-level-registry';
|
|
2
3
|
import { deriveModules } from './derive-modules';
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
type ModelMetadata = {
|
|
6
|
+
actors?: Actor[];
|
|
7
|
+
entities?: Entity[];
|
|
8
|
+
assumptions?: string[];
|
|
9
|
+
requirements?: string;
|
|
10
|
+
};
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
]
|
|
12
|
+
export function assembleSpecs(
|
|
13
|
+
scenes: Scene[],
|
|
14
|
+
messages: Message[],
|
|
15
|
+
integrations?: Model['integrations'],
|
|
16
|
+
modelMetadata?: ModelMetadata,
|
|
17
|
+
narrativeDefinitions?: NarrativeDefinition[],
|
|
18
|
+
): Model {
|
|
19
|
+
const modules = deriveModules(scenes, messages);
|
|
20
|
+
|
|
21
|
+
const narratives = buildNarratives(scenes, narrativeDefinitions);
|
|
14
22
|
|
|
15
23
|
return {
|
|
16
24
|
variant: 'specs' as const,
|
|
17
25
|
scenes,
|
|
18
|
-
messages
|
|
19
|
-
integrations
|
|
26
|
+
messages,
|
|
27
|
+
integrations,
|
|
20
28
|
modules,
|
|
21
29
|
narratives,
|
|
30
|
+
...(modelMetadata?.actors?.length ? { actors: modelMetadata.actors } : {}),
|
|
31
|
+
...(modelMetadata?.entities?.length ? { entities: modelMetadata.entities } : {}),
|
|
32
|
+
...(modelMetadata?.assumptions?.length ? { assumptions: modelMetadata.assumptions } : {}),
|
|
33
|
+
...(modelMetadata?.requirements ? { requirements: modelMetadata.requirements } : {}),
|
|
22
34
|
};
|
|
23
35
|
}
|
|
36
|
+
|
|
37
|
+
function buildNarratives(scenes: Scene[], definitions?: NarrativeDefinition[]): Narrative[] {
|
|
38
|
+
if (!definitions || definitions.length === 0) {
|
|
39
|
+
return [
|
|
40
|
+
{
|
|
41
|
+
name: 'Default',
|
|
42
|
+
sceneIds: scenes.filter((s) => s.id).map((s) => s.id!),
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const nameToId = new Map(scenes.filter((s) => s.id).map((s) => [s.name, s.id!]));
|
|
48
|
+
const coveredSceneIds = new Set<string>();
|
|
49
|
+
|
|
50
|
+
const narratives: Narrative[] = definitions.map((def) => {
|
|
51
|
+
const sceneIds = (def.scenes ?? [])
|
|
52
|
+
.map((name) => nameToId.get(name))
|
|
53
|
+
.filter((id): id is string => id !== undefined);
|
|
54
|
+
for (const id of sceneIds) coveredSceneIds.add(id);
|
|
55
|
+
|
|
56
|
+
const nar: Narrative = { name: def.name, sceneIds };
|
|
57
|
+
if (def.id) nar.id = def.id;
|
|
58
|
+
if (def.outcome) nar.outcome = def.outcome;
|
|
59
|
+
if (def.impact) nar.impact = def.impact;
|
|
60
|
+
if (def.actors?.length) nar.actors = def.actors;
|
|
61
|
+
if (def.assumptions?.length) nar.assumptions = def.assumptions;
|
|
62
|
+
if (def.requirements) nar.requirements = def.requirements;
|
|
63
|
+
return nar;
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const uncoveredIds = scenes.filter((s) => s.id && !coveredSceneIds.has(s.id)).map((s) => s.id!);
|
|
67
|
+
if (uncoveredIds.length > 0) {
|
|
68
|
+
narratives.push({ name: 'Default', sceneIds: uncoveredIds });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return narratives;
|
|
72
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { Message, Model, Moment, Scene } from '../../index';
|
|
|
2
2
|
import { integrationExportRegistry } from '../../integration-export-registry';
|
|
3
3
|
import { globalIntegrationRegistry } from '../../integration-registry';
|
|
4
4
|
import type { TypeInfo } from '../../loader/ts-utils';
|
|
5
|
+
import { modelLevelRegistry } from '../../model-level-registry';
|
|
5
6
|
import { assembleSpecs } from './assemble';
|
|
6
7
|
import { applyExampleShapeHints, type ExampleShapeHints } from './example-shapes';
|
|
7
8
|
import { inlineAllMessageFieldTypes } from './inlining';
|
|
@@ -340,5 +341,25 @@ export const scenesToModel = (scenes: Scene[], typesByFile?: Map<string, Map<str
|
|
|
340
341
|
inlineAllMessageFieldTypes(messages, unionTypes);
|
|
341
342
|
}
|
|
342
343
|
|
|
343
|
-
|
|
344
|
+
const {
|
|
345
|
+
actors,
|
|
346
|
+
entities,
|
|
347
|
+
assumptions: modelAssumptions,
|
|
348
|
+
requirements: modelRequirements,
|
|
349
|
+
narrativeDefinitions,
|
|
350
|
+
} = modelLevelRegistry.getAll();
|
|
351
|
+
const modelMetadata = {
|
|
352
|
+
...(actors.length > 0 ? { actors } : {}),
|
|
353
|
+
...(entities.length > 0 ? { entities } : {}),
|
|
354
|
+
...(modelAssumptions.length > 0 ? { assumptions: modelAssumptions } : {}),
|
|
355
|
+
...(modelRequirements ? { requirements: modelRequirements } : {}),
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
return assembleSpecs(
|
|
359
|
+
scenes,
|
|
360
|
+
Array.from(messages.values()),
|
|
361
|
+
Array.from(integrations.values()),
|
|
362
|
+
Object.keys(modelMetadata).length > 0 ? modelMetadata : undefined,
|
|
363
|
+
narrativeDefinitions.length > 0 ? narrativeDefinitions : undefined,
|
|
364
|
+
);
|
|
344
365
|
};
|