@auto-engineer/narrative 0.26.0 → 0.26.2
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 +33 -0
- package/dist/src/id/addAutoIds.d.ts.map +1 -1
- package/dist/src/id/addAutoIds.js +0 -15
- 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 +1 -6
- package/dist/src/id/hasAllIds.js.map +1 -1
- package/dist/src/schema.d.ts +86 -94
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +1 -2
- package/dist/src/schema.js.map +1 -1
- package/dist/src/transformers/model-to-narrative/cross-module-imports.js +1 -1
- package/dist/src/transformers/model-to-narrative/cross-module-imports.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 +16 -29
- package/dist/src/transformers/model-to-narrative/validate-modules.js.map +1 -1
- package/dist/src/transformers/narrative-to-model/derive-modules.d.ts.map +1 -1
- package/dist/src/transformers/narrative-to-model/derive-modules.js +0 -1
- package/dist/src/transformers/narrative-to-model/derive-modules.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/id/addAutoIds.specs.ts +0 -168
- package/src/id/addAutoIds.ts +1 -16
- package/src/id/hasAllIds.specs.ts +0 -78
- package/src/id/hasAllIds.ts +2 -10
- package/src/model-to-narrative.specs.ts +0 -13
- package/src/schema.ts +1 -2
- package/src/transformers/model-to-narrative/cross-module-imports.ts +1 -1
- package/src/transformers/model-to-narrative/modules.specs.ts +6 -52
- package/src/transformers/model-to-narrative/validate-modules.ts +17 -34
- package/src/transformers/narrative-to-model/derive-modules.specs.ts +0 -1
- package/src/transformers/narrative-to-model/derive-modules.ts +0 -1
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/
|
|
27
|
-
"@auto-engineer/
|
|
28
|
-
"@auto-engineer/
|
|
26
|
+
"@auto-engineer/file-store": "0.26.2",
|
|
27
|
+
"@auto-engineer/message-bus": "0.26.2",
|
|
28
|
+
"@auto-engineer/id": "0.26.2"
|
|
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": "0.26.
|
|
38
|
+
"version": "0.26.2",
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsx scripts/build.ts",
|
|
41
41
|
"test": "vitest run --reporter=dot",
|
|
@@ -954,172 +954,4 @@ describe('addAutoIds', () => {
|
|
|
954
954
|
}
|
|
955
955
|
});
|
|
956
956
|
});
|
|
957
|
-
|
|
958
|
-
describe('module ID generation', () => {
|
|
959
|
-
const AUTO_ID_REGEX = /^[A-Za-z0-9_]{9}$/;
|
|
960
|
-
|
|
961
|
-
it('should assign ID to derived module equal to sourceFile', () => {
|
|
962
|
-
const model: Model = {
|
|
963
|
-
variant: 'specs',
|
|
964
|
-
narratives: [],
|
|
965
|
-
messages: [],
|
|
966
|
-
integrations: [],
|
|
967
|
-
modules: [
|
|
968
|
-
{
|
|
969
|
-
id: '',
|
|
970
|
-
sourceFile: 'orders.narrative.ts',
|
|
971
|
-
isDerived: true,
|
|
972
|
-
contains: { narrativeIds: [] },
|
|
973
|
-
declares: { messages: [] },
|
|
974
|
-
},
|
|
975
|
-
],
|
|
976
|
-
};
|
|
977
|
-
|
|
978
|
-
const result = addAutoIds(model);
|
|
979
|
-
|
|
980
|
-
expect(result.modules[0].id).toBe('orders.narrative.ts');
|
|
981
|
-
});
|
|
982
|
-
|
|
983
|
-
it('should generate auto ID for authored module without ID', () => {
|
|
984
|
-
const model: Model = {
|
|
985
|
-
variant: 'specs',
|
|
986
|
-
narratives: [],
|
|
987
|
-
messages: [],
|
|
988
|
-
integrations: [],
|
|
989
|
-
modules: [
|
|
990
|
-
{
|
|
991
|
-
id: '',
|
|
992
|
-
sourceFile: 'features/orders.ts',
|
|
993
|
-
isDerived: false,
|
|
994
|
-
contains: { narrativeIds: [] },
|
|
995
|
-
declares: { messages: [] },
|
|
996
|
-
},
|
|
997
|
-
],
|
|
998
|
-
};
|
|
999
|
-
|
|
1000
|
-
const result = addAutoIds(model);
|
|
1001
|
-
|
|
1002
|
-
expect(result.modules[0].id).toMatch(AUTO_ID_REGEX);
|
|
1003
|
-
});
|
|
1004
|
-
|
|
1005
|
-
it('should preserve existing ID for authored module', () => {
|
|
1006
|
-
const model: Model = {
|
|
1007
|
-
variant: 'specs',
|
|
1008
|
-
narratives: [],
|
|
1009
|
-
messages: [],
|
|
1010
|
-
integrations: [],
|
|
1011
|
-
modules: [
|
|
1012
|
-
{
|
|
1013
|
-
id: 'EXISTING-MODULE-001',
|
|
1014
|
-
sourceFile: 'features/orders.ts',
|
|
1015
|
-
isDerived: false,
|
|
1016
|
-
contains: { narrativeIds: [] },
|
|
1017
|
-
declares: { messages: [] },
|
|
1018
|
-
},
|
|
1019
|
-
],
|
|
1020
|
-
};
|
|
1021
|
-
|
|
1022
|
-
const result = addAutoIds(model);
|
|
1023
|
-
|
|
1024
|
-
expect(result.modules[0].id).toBe('EXISTING-MODULE-001');
|
|
1025
|
-
});
|
|
1026
|
-
|
|
1027
|
-
it('should not mutate original modules', () => {
|
|
1028
|
-
const model: Model = {
|
|
1029
|
-
variant: 'specs',
|
|
1030
|
-
narratives: [],
|
|
1031
|
-
messages: [],
|
|
1032
|
-
integrations: [],
|
|
1033
|
-
modules: [
|
|
1034
|
-
{
|
|
1035
|
-
id: '',
|
|
1036
|
-
sourceFile: 'test.ts',
|
|
1037
|
-
isDerived: false,
|
|
1038
|
-
contains: { narrativeIds: [] },
|
|
1039
|
-
declares: { messages: [] },
|
|
1040
|
-
},
|
|
1041
|
-
],
|
|
1042
|
-
};
|
|
1043
|
-
|
|
1044
|
-
const originalId = model.modules[0].id;
|
|
1045
|
-
addAutoIds(model);
|
|
1046
|
-
|
|
1047
|
-
expect(model.modules[0].id).toBe(originalId);
|
|
1048
|
-
});
|
|
1049
|
-
|
|
1050
|
-
it('should generate unique IDs for multiple authored modules', () => {
|
|
1051
|
-
const model: Model = {
|
|
1052
|
-
variant: 'specs',
|
|
1053
|
-
narratives: [],
|
|
1054
|
-
messages: [],
|
|
1055
|
-
integrations: [],
|
|
1056
|
-
modules: [
|
|
1057
|
-
{
|
|
1058
|
-
id: '',
|
|
1059
|
-
sourceFile: 'orders.ts',
|
|
1060
|
-
isDerived: false,
|
|
1061
|
-
contains: { narrativeIds: [] },
|
|
1062
|
-
declares: { messages: [] },
|
|
1063
|
-
},
|
|
1064
|
-
{
|
|
1065
|
-
id: '',
|
|
1066
|
-
sourceFile: 'users.ts',
|
|
1067
|
-
isDerived: false,
|
|
1068
|
-
contains: { narrativeIds: [] },
|
|
1069
|
-
declares: { messages: [] },
|
|
1070
|
-
},
|
|
1071
|
-
],
|
|
1072
|
-
};
|
|
1073
|
-
|
|
1074
|
-
const result = addAutoIds(model);
|
|
1075
|
-
|
|
1076
|
-
expect(result.modules[0].id).toMatch(AUTO_ID_REGEX);
|
|
1077
|
-
expect(result.modules[1].id).toMatch(AUTO_ID_REGEX);
|
|
1078
|
-
expect(result.modules[0].id).not.toBe(result.modules[1].id);
|
|
1079
|
-
});
|
|
1080
|
-
|
|
1081
|
-
it('should handle mixed derived and authored modules', () => {
|
|
1082
|
-
const model: Model = {
|
|
1083
|
-
variant: 'specs',
|
|
1084
|
-
narratives: [],
|
|
1085
|
-
messages: [],
|
|
1086
|
-
integrations: [],
|
|
1087
|
-
modules: [
|
|
1088
|
-
{
|
|
1089
|
-
id: '',
|
|
1090
|
-
sourceFile: 'derived.narrative.ts',
|
|
1091
|
-
isDerived: true,
|
|
1092
|
-
contains: { narrativeIds: [] },
|
|
1093
|
-
declares: { messages: [] },
|
|
1094
|
-
},
|
|
1095
|
-
{
|
|
1096
|
-
id: '',
|
|
1097
|
-
sourceFile: 'authored.ts',
|
|
1098
|
-
isDerived: false,
|
|
1099
|
-
contains: { narrativeIds: [] },
|
|
1100
|
-
declares: { messages: [] },
|
|
1101
|
-
},
|
|
1102
|
-
],
|
|
1103
|
-
};
|
|
1104
|
-
|
|
1105
|
-
const result = addAutoIds(model);
|
|
1106
|
-
|
|
1107
|
-
expect(result.modules[0].id).toBe('derived.narrative.ts');
|
|
1108
|
-
expect(result.modules[1].id).toMatch(AUTO_ID_REGEX);
|
|
1109
|
-
});
|
|
1110
|
-
|
|
1111
|
-
it('should handle empty modules array', () => {
|
|
1112
|
-
const model: Model = {
|
|
1113
|
-
variant: 'specs',
|
|
1114
|
-
narratives: [],
|
|
1115
|
-
messages: [],
|
|
1116
|
-
integrations: [],
|
|
1117
|
-
modules: [],
|
|
1118
|
-
};
|
|
1119
|
-
|
|
1120
|
-
const result = addAutoIds(model);
|
|
1121
|
-
|
|
1122
|
-
expect(result.modules).toEqual([]);
|
|
1123
|
-
});
|
|
1124
|
-
});
|
|
1125
957
|
});
|
package/src/id/addAutoIds.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientSpecNode, Example, Model,
|
|
1
|
+
import type { ClientSpecNode, Example, Model, Rule, Slice, Spec, Step } from '../index';
|
|
2
2
|
import { generateAutoId } from './generators';
|
|
3
3
|
|
|
4
4
|
function ensureId(item: { id?: string }): void {
|
|
@@ -110,18 +110,6 @@ function processSlice(slice: Slice): Slice {
|
|
|
110
110
|
return sliceCopy;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
function processModules(modules: Module[]): Module[] {
|
|
114
|
-
return modules.map((module) => {
|
|
115
|
-
const moduleCopy = { ...module };
|
|
116
|
-
if (module.isDerived) {
|
|
117
|
-
moduleCopy.id = module.sourceFile;
|
|
118
|
-
} else {
|
|
119
|
-
ensureId(moduleCopy);
|
|
120
|
-
}
|
|
121
|
-
return moduleCopy;
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
|
|
125
113
|
export function addAutoIds(specs: Model): Model {
|
|
126
114
|
const result = structuredClone(specs);
|
|
127
115
|
result.narratives = result.narratives.map((narrative) => {
|
|
@@ -130,8 +118,5 @@ export function addAutoIds(specs: Model): Model {
|
|
|
130
118
|
narrativeCopy.slices = narrative.slices.map(processSlice);
|
|
131
119
|
return narrativeCopy;
|
|
132
120
|
});
|
|
133
|
-
if (result.modules) {
|
|
134
|
-
result.modules = processModules(result.modules);
|
|
135
|
-
}
|
|
136
121
|
return result;
|
|
137
122
|
}
|
|
@@ -719,82 +719,4 @@ describe('hasAllIds', () => {
|
|
|
719
719
|
expect(hasAllIds(model)).toBe(true);
|
|
720
720
|
});
|
|
721
721
|
});
|
|
722
|
-
|
|
723
|
-
describe('module ID validation', () => {
|
|
724
|
-
it('should return true when all modules have IDs', () => {
|
|
725
|
-
const model: Model = {
|
|
726
|
-
variant: 'specs',
|
|
727
|
-
narratives: [],
|
|
728
|
-
messages: [],
|
|
729
|
-
integrations: [],
|
|
730
|
-
modules: [
|
|
731
|
-
{
|
|
732
|
-
id: 'module-1',
|
|
733
|
-
sourceFile: 'test.ts',
|
|
734
|
-
isDerived: false,
|
|
735
|
-
contains: { narrativeIds: [] },
|
|
736
|
-
declares: { messages: [] },
|
|
737
|
-
},
|
|
738
|
-
],
|
|
739
|
-
};
|
|
740
|
-
expect(hasAllIds(model)).toBe(true);
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
it('should return false when module has empty ID', () => {
|
|
744
|
-
const model: Model = {
|
|
745
|
-
variant: 'specs',
|
|
746
|
-
narratives: [],
|
|
747
|
-
messages: [],
|
|
748
|
-
integrations: [],
|
|
749
|
-
modules: [
|
|
750
|
-
{
|
|
751
|
-
id: '',
|
|
752
|
-
sourceFile: 'test.ts',
|
|
753
|
-
isDerived: false,
|
|
754
|
-
contains: { narrativeIds: [] },
|
|
755
|
-
declares: { messages: [] },
|
|
756
|
-
},
|
|
757
|
-
],
|
|
758
|
-
};
|
|
759
|
-
expect(hasAllIds(model)).toBe(false);
|
|
760
|
-
});
|
|
761
|
-
|
|
762
|
-
it('should return false when any module is missing ID among valid narratives', () => {
|
|
763
|
-
const model: Model = {
|
|
764
|
-
variant: 'specs',
|
|
765
|
-
narratives: [{ name: 'Test', id: 'FLOW-001', slices: [] }],
|
|
766
|
-
messages: [],
|
|
767
|
-
integrations: [],
|
|
768
|
-
modules: [
|
|
769
|
-
{
|
|
770
|
-
id: '',
|
|
771
|
-
sourceFile: 'test.ts',
|
|
772
|
-
isDerived: true,
|
|
773
|
-
contains: { narrativeIds: ['FLOW-001'] },
|
|
774
|
-
declares: { messages: [] },
|
|
775
|
-
},
|
|
776
|
-
],
|
|
777
|
-
};
|
|
778
|
-
expect(hasAllIds(model)).toBe(false);
|
|
779
|
-
});
|
|
780
|
-
|
|
781
|
-
it('should return true for derived module with valid ID', () => {
|
|
782
|
-
const model: Model = {
|
|
783
|
-
variant: 'specs',
|
|
784
|
-
narratives: [],
|
|
785
|
-
messages: [],
|
|
786
|
-
integrations: [],
|
|
787
|
-
modules: [
|
|
788
|
-
{
|
|
789
|
-
id: 'derived.ts',
|
|
790
|
-
sourceFile: 'derived.ts',
|
|
791
|
-
isDerived: true,
|
|
792
|
-
contains: { narrativeIds: [] },
|
|
793
|
-
declares: { messages: [] },
|
|
794
|
-
},
|
|
795
|
-
],
|
|
796
|
-
};
|
|
797
|
-
expect(hasAllIds(model)).toBe(true);
|
|
798
|
-
});
|
|
799
|
-
});
|
|
800
722
|
});
|
package/src/id/hasAllIds.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClientSpecNode, Example, Model,
|
|
1
|
+
import type { ClientSpecNode, Example, Model, Rule, Slice, Spec, Step } from '../index';
|
|
2
2
|
|
|
3
3
|
function hasValidId(item: { id?: string }): boolean {
|
|
4
4
|
return item.id !== undefined && item.id !== '';
|
|
@@ -62,14 +62,6 @@ function hasSliceIds(slice: Slice): boolean {
|
|
|
62
62
|
return hasValidId(slice) && hasServerSpecIds(slice) && hasClientSpecIds(slice) && hasDataIds(slice);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
function hasModuleIds(modules: Module[]): boolean {
|
|
66
|
-
return modules.every(hasValidId);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
65
|
export function hasAllIds(specs: Model): boolean {
|
|
70
|
-
|
|
71
|
-
(narrative) => hasValidId(narrative) && narrative.slices.every(hasSliceIds),
|
|
72
|
-
);
|
|
73
|
-
const modulesValid = hasModuleIds(specs.modules ?? []);
|
|
74
|
-
return narrativesValid && modulesValid;
|
|
66
|
+
return specs.narratives.every((narrative) => hasValidId(narrative) && narrative.slices.every(hasSliceIds));
|
|
75
67
|
}
|
|
@@ -2562,14 +2562,12 @@ narrative('All Projection Types', 'ALL-PROJ', () => {
|
|
|
2562
2562
|
integrations: [],
|
|
2563
2563
|
modules: [
|
|
2564
2564
|
{
|
|
2565
|
-
id: 'orders.narrative.ts',
|
|
2566
2565
|
sourceFile: 'orders.narrative.ts',
|
|
2567
2566
|
isDerived: true,
|
|
2568
2567
|
contains: { narrativeIds: ['orders-flow'] },
|
|
2569
2568
|
declares: { messages: [] },
|
|
2570
2569
|
},
|
|
2571
2570
|
{
|
|
2572
|
-
id: 'users.narrative.ts',
|
|
2573
2571
|
sourceFile: 'users.narrative.ts',
|
|
2574
2572
|
isDerived: true,
|
|
2575
2573
|
contains: { narrativeIds: ['users-flow'] },
|
|
@@ -2608,14 +2606,12 @@ narrative('All Projection Types', 'ALL-PROJ', () => {
|
|
|
2608
2606
|
integrations: [],
|
|
2609
2607
|
modules: [
|
|
2610
2608
|
{
|
|
2611
|
-
id: 'a.narrative.ts',
|
|
2612
2609
|
sourceFile: 'a.narrative.ts',
|
|
2613
2610
|
isDerived: true,
|
|
2614
2611
|
contains: { narrativeIds: ['flow-a'] },
|
|
2615
2612
|
declares: { messages: [{ kind: 'event', name: 'SharedEvent' }] },
|
|
2616
2613
|
},
|
|
2617
2614
|
{
|
|
2618
|
-
id: 'b.narrative.ts',
|
|
2619
2615
|
sourceFile: 'b.narrative.ts',
|
|
2620
2616
|
isDerived: true,
|
|
2621
2617
|
contains: { narrativeIds: ['flow-b'] },
|
|
@@ -2690,14 +2686,12 @@ narrative('All Projection Types', 'ALL-PROJ', () => {
|
|
|
2690
2686
|
integrations: [],
|
|
2691
2687
|
modules: [
|
|
2692
2688
|
{
|
|
2693
|
-
id: 'shared',
|
|
2694
2689
|
sourceFile: 'shared/types.narrative.ts',
|
|
2695
2690
|
isDerived: false,
|
|
2696
2691
|
contains: { narrativeIds: ['shared-types'] },
|
|
2697
2692
|
declares: { messages: [{ kind: 'event', name: 'OrderCreated' }] },
|
|
2698
2693
|
},
|
|
2699
2694
|
{
|
|
2700
|
-
id: 'orders',
|
|
2701
2695
|
sourceFile: 'features/orders.narrative.ts',
|
|
2702
2696
|
isDerived: false,
|
|
2703
2697
|
contains: { narrativeIds: ['orders-flow'] },
|
|
@@ -2766,14 +2760,12 @@ narrative('All Projection Types', 'ALL-PROJ', () => {
|
|
|
2766
2760
|
integrations: [],
|
|
2767
2761
|
modules: [
|
|
2768
2762
|
{
|
|
2769
|
-
id: 'core',
|
|
2770
2763
|
sourceFile: 'src/core/types.narrative.ts',
|
|
2771
2764
|
isDerived: false,
|
|
2772
2765
|
contains: { narrativeIds: ['core'] },
|
|
2773
2766
|
declares: { messages: [{ kind: 'event', name: 'CoreEvent' }] },
|
|
2774
2767
|
},
|
|
2775
2768
|
{
|
|
2776
|
-
id: 'feature',
|
|
2777
2769
|
sourceFile: 'src/features/sub/feature.narrative.ts',
|
|
2778
2770
|
isDerived: false,
|
|
2779
2771
|
contains: { narrativeIds: ['feature'] },
|
|
@@ -2836,7 +2828,6 @@ narrative('All Projection Types', 'ALL-PROJ', () => {
|
|
|
2836
2828
|
integrations: [],
|
|
2837
2829
|
modules: [
|
|
2838
2830
|
{
|
|
2839
|
-
id: 'shared',
|
|
2840
2831
|
sourceFile: 'shared.narrative.ts',
|
|
2841
2832
|
isDerived: false,
|
|
2842
2833
|
contains: { narrativeIds: ['shared'] },
|
|
@@ -2848,7 +2839,6 @@ narrative('All Projection Types', 'ALL-PROJ', () => {
|
|
|
2848
2839
|
},
|
|
2849
2840
|
},
|
|
2850
2841
|
{
|
|
2851
|
-
id: 'consumer',
|
|
2852
2842
|
sourceFile: 'consumer.narrative.ts',
|
|
2853
2843
|
isDerived: false,
|
|
2854
2844
|
contains: { narrativeIds: ['consumer'] },
|
|
@@ -2914,21 +2904,18 @@ narrative('All Projection Types', 'ALL-PROJ', () => {
|
|
|
2914
2904
|
integrations: [],
|
|
2915
2905
|
modules: [
|
|
2916
2906
|
{
|
|
2917
|
-
id: 'z-types',
|
|
2918
2907
|
sourceFile: 'z-types.narrative.ts',
|
|
2919
2908
|
isDerived: false,
|
|
2920
2909
|
contains: { narrativeIds: ['z-types'] },
|
|
2921
2910
|
declares: { messages: [{ kind: 'event', name: 'ZEvent' }] },
|
|
2922
2911
|
},
|
|
2923
2912
|
{
|
|
2924
|
-
id: 'a-types',
|
|
2925
2913
|
sourceFile: 'a-types.narrative.ts',
|
|
2926
2914
|
isDerived: false,
|
|
2927
2915
|
contains: { narrativeIds: ['a-types'] },
|
|
2928
2916
|
declares: { messages: [{ kind: 'event', name: 'AEvent' }] },
|
|
2929
2917
|
},
|
|
2930
2918
|
{
|
|
2931
|
-
id: 'consumer',
|
|
2932
2919
|
sourceFile: 'consumer.narrative.ts',
|
|
2933
2920
|
isDerived: false,
|
|
2934
2921
|
contains: { narrativeIds: ['consumer'] },
|
package/src/schema.ts
CHANGED
|
@@ -11,8 +11,7 @@ export const MessageRefSchema = z
|
|
|
11
11
|
// Module schema for type ownership and file grouping
|
|
12
12
|
export const ModuleSchema = z
|
|
13
13
|
.object({
|
|
14
|
-
|
|
15
|
-
sourceFile: z.string().describe('Output file path for this module'),
|
|
14
|
+
sourceFile: z.string().describe('Output file path for this module (also serves as unique identifier)'),
|
|
16
15
|
isDerived: z.boolean().describe('True if auto-derived from sourceFile grouping, false if user-authored'),
|
|
17
16
|
contains: z
|
|
18
17
|
.object({
|
|
@@ -70,7 +70,7 @@ function collectUsedMessageKeysForModule(module: Module, model: Model): Set<stri
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
function findDeclaringModule(messageKey: string, allModules: Module[], currentModule: Module): Module | undefined {
|
|
73
|
-
const authoredModules = allModules.filter((m) => !m.isDerived && m.
|
|
73
|
+
const authoredModules = allModules.filter((m) => !m.isDerived && m.sourceFile !== currentModule.sourceFile);
|
|
74
74
|
|
|
75
75
|
for (const mod of authoredModules) {
|
|
76
76
|
const declares = mod.declares.messages.some((m) => toMessageKey(m.kind, m.name) === messageKey);
|
|
@@ -33,14 +33,12 @@ describe('module functionality', () => {
|
|
|
33
33
|
integrations: [],
|
|
34
34
|
modules: [
|
|
35
35
|
{
|
|
36
|
-
id: 'orders.narrative.ts',
|
|
37
36
|
sourceFile: 'orders.narrative.ts',
|
|
38
37
|
isDerived: true,
|
|
39
38
|
contains: { narrativeIds: ['orders-flow'] },
|
|
40
39
|
declares: { messages: [{ kind: 'event', name: 'SharedEvent' }] },
|
|
41
40
|
},
|
|
42
41
|
{
|
|
43
|
-
id: 'users.narrative.ts',
|
|
44
42
|
sourceFile: 'users.narrative.ts',
|
|
45
43
|
isDerived: true,
|
|
46
44
|
contains: { narrativeIds: ['users-flow'] },
|
|
@@ -132,7 +130,6 @@ describe('module functionality', () => {
|
|
|
132
130
|
integrations: [],
|
|
133
131
|
modules: [
|
|
134
132
|
{
|
|
135
|
-
id: 'shared',
|
|
136
133
|
sourceFile: 'shared/types.narrative.ts',
|
|
137
134
|
isDerived: false,
|
|
138
135
|
contains: { narrativeIds: ['shared-types'] },
|
|
@@ -141,7 +138,6 @@ describe('module functionality', () => {
|
|
|
141
138
|
},
|
|
142
139
|
},
|
|
143
140
|
{
|
|
144
|
-
id: 'orders',
|
|
145
141
|
sourceFile: 'features/orders.narrative.ts',
|
|
146
142
|
isDerived: false,
|
|
147
143
|
contains: { narrativeIds: ['orders-flow'] },
|
|
@@ -166,22 +162,20 @@ describe('module functionality', () => {
|
|
|
166
162
|
});
|
|
167
163
|
|
|
168
164
|
describe('validation', () => {
|
|
169
|
-
it('detects duplicate
|
|
165
|
+
it('detects duplicate sourceFiles', () => {
|
|
170
166
|
const model: Model = {
|
|
171
167
|
variant: 'specs',
|
|
172
168
|
narratives: [],
|
|
173
169
|
messages: [],
|
|
174
170
|
modules: [
|
|
175
171
|
{
|
|
176
|
-
|
|
177
|
-
sourceFile: 'file1.ts',
|
|
172
|
+
sourceFile: 'same-file.ts',
|
|
178
173
|
isDerived: false,
|
|
179
174
|
contains: { narrativeIds: [] },
|
|
180
175
|
declares: { messages: [] },
|
|
181
176
|
},
|
|
182
177
|
{
|
|
183
|
-
|
|
184
|
-
sourceFile: 'file2.ts',
|
|
178
|
+
sourceFile: 'same-file.ts',
|
|
185
179
|
isDerived: false,
|
|
186
180
|
contains: { narrativeIds: [] },
|
|
187
181
|
declares: { messages: [] },
|
|
@@ -192,30 +186,8 @@ describe('module functionality', () => {
|
|
|
192
186
|
const errors = validateModules(model);
|
|
193
187
|
|
|
194
188
|
expect(errors).toHaveLength(1);
|
|
195
|
-
expect(errors[0].type).toBe('
|
|
196
|
-
expect(errors[0].message).toContain('same-
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('detects derived module ID not matching sourceFile', () => {
|
|
200
|
-
const model: Model = {
|
|
201
|
-
variant: 'specs',
|
|
202
|
-
narratives: [],
|
|
203
|
-
messages: [],
|
|
204
|
-
modules: [
|
|
205
|
-
{
|
|
206
|
-
id: 'wrong-id',
|
|
207
|
-
sourceFile: 'correct-path.ts',
|
|
208
|
-
isDerived: true,
|
|
209
|
-
contains: { narrativeIds: [] },
|
|
210
|
-
declares: { messages: [] },
|
|
211
|
-
},
|
|
212
|
-
],
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
const errors = validateModules(model);
|
|
216
|
-
|
|
217
|
-
expect(errors).toHaveLength(1);
|
|
218
|
-
expect(errors[0].type).toBe('derived_id_mismatch');
|
|
189
|
+
expect(errors[0].type).toBe('duplicate_sourceFile');
|
|
190
|
+
expect(errors[0].message).toContain('same-file.ts');
|
|
219
191
|
});
|
|
220
192
|
|
|
221
193
|
it('detects narrative assigned to multiple authored modules', () => {
|
|
@@ -225,14 +197,12 @@ describe('module functionality', () => {
|
|
|
225
197
|
messages: [],
|
|
226
198
|
modules: [
|
|
227
199
|
{
|
|
228
|
-
id: 'module-a',
|
|
229
200
|
sourceFile: 'a.ts',
|
|
230
201
|
isDerived: false,
|
|
231
202
|
contains: { narrativeIds: ['test-narrative'] },
|
|
232
203
|
declares: { messages: [] },
|
|
233
204
|
},
|
|
234
205
|
{
|
|
235
|
-
id: 'module-b',
|
|
236
206
|
sourceFile: 'b.ts',
|
|
237
207
|
isDerived: false,
|
|
238
208
|
contains: { narrativeIds: ['test-narrative'] },
|
|
@@ -253,14 +223,12 @@ describe('module functionality', () => {
|
|
|
253
223
|
messages: [{ type: 'event', source: 'internal', name: 'SharedEvent', fields: [] }],
|
|
254
224
|
modules: [
|
|
255
225
|
{
|
|
256
|
-
id: 'module-a',
|
|
257
226
|
sourceFile: 'a.ts',
|
|
258
227
|
isDerived: false,
|
|
259
228
|
contains: { narrativeIds: [] },
|
|
260
229
|
declares: { messages: [{ kind: 'event', name: 'SharedEvent' }] },
|
|
261
230
|
},
|
|
262
231
|
{
|
|
263
|
-
id: 'module-b',
|
|
264
232
|
sourceFile: 'b.ts',
|
|
265
233
|
isDerived: false,
|
|
266
234
|
contains: { narrativeIds: [] },
|
|
@@ -281,14 +249,12 @@ describe('module functionality', () => {
|
|
|
281
249
|
messages: [{ type: 'event', source: 'internal', name: 'SharedEvent', fields: [] }],
|
|
282
250
|
modules: [
|
|
283
251
|
{
|
|
284
|
-
id: 'file1.ts',
|
|
285
252
|
sourceFile: 'file1.ts',
|
|
286
253
|
isDerived: true,
|
|
287
254
|
contains: { narrativeIds: [] },
|
|
288
255
|
declares: { messages: [{ kind: 'event', name: 'SharedEvent' }] },
|
|
289
256
|
},
|
|
290
257
|
{
|
|
291
|
-
id: 'file2.ts',
|
|
292
258
|
sourceFile: 'file2.ts',
|
|
293
259
|
isDerived: true,
|
|
294
260
|
contains: { narrativeIds: [] },
|
|
@@ -322,7 +288,6 @@ describe('module functionality', () => {
|
|
|
322
288
|
messages: [],
|
|
323
289
|
modules: [
|
|
324
290
|
{
|
|
325
|
-
id: 'module-a',
|
|
326
291
|
sourceFile: 'a.ts',
|
|
327
292
|
isDerived: false,
|
|
328
293
|
contains: { narrativeIds: ['nonexistent-narrative'] },
|
|
@@ -344,7 +309,6 @@ describe('module functionality', () => {
|
|
|
344
309
|
messages: [],
|
|
345
310
|
modules: [
|
|
346
311
|
{
|
|
347
|
-
id: 'module-a',
|
|
348
312
|
sourceFile: 'a.ts',
|
|
349
313
|
isDerived: false,
|
|
350
314
|
contains: { narrativeIds: [] },
|
|
@@ -366,7 +330,6 @@ describe('module functionality', () => {
|
|
|
366
330
|
messages: [{ type: 'event', source: 'internal', name: 'UndeclaredEvent', fields: [] }],
|
|
367
331
|
modules: [
|
|
368
332
|
{
|
|
369
|
-
id: 'module-a',
|
|
370
333
|
sourceFile: 'a.ts',
|
|
371
334
|
isDerived: false,
|
|
372
335
|
contains: { narrativeIds: [] },
|
|
@@ -382,7 +345,7 @@ describe('module functionality', () => {
|
|
|
382
345
|
});
|
|
383
346
|
|
|
384
347
|
it('throwOnValidationErrors throws when errors exist', () => {
|
|
385
|
-
const errors = [{ type: '
|
|
348
|
+
const errors = [{ type: 'duplicate_sourceFile' as const, message: 'Test error' }];
|
|
386
349
|
|
|
387
350
|
expect(() => throwOnValidationErrors(errors)).toThrow('Module validation failed');
|
|
388
351
|
expect(() => throwOnValidationErrors(errors)).toThrow('Test error');
|
|
@@ -423,7 +386,6 @@ describe('module functionality', () => {
|
|
|
423
386
|
integrations: [],
|
|
424
387
|
modules: [
|
|
425
388
|
{
|
|
426
|
-
id: 'orders.narrative.ts',
|
|
427
389
|
sourceFile: 'orders.narrative.ts',
|
|
428
390
|
isDerived: true,
|
|
429
391
|
contains: { narrativeIds: ['orders-flow'] },
|
|
@@ -435,7 +397,6 @@ describe('module functionality', () => {
|
|
|
435
397
|
},
|
|
436
398
|
},
|
|
437
399
|
{
|
|
438
|
-
id: 'users.narrative.ts',
|
|
439
400
|
sourceFile: 'users.narrative.ts',
|
|
440
401
|
isDerived: true,
|
|
441
402
|
contains: { narrativeIds: ['users-flow'] },
|
|
@@ -479,14 +440,12 @@ describe('module functionality', () => {
|
|
|
479
440
|
integrations: [],
|
|
480
441
|
modules: [
|
|
481
442
|
{
|
|
482
|
-
id: 'a.narrative.ts',
|
|
483
443
|
sourceFile: 'a.narrative.ts',
|
|
484
444
|
isDerived: true,
|
|
485
445
|
contains: { narrativeIds: ['flow-a'] },
|
|
486
446
|
declares: { messages: [{ kind: 'event', name: 'SharedEvent' }] },
|
|
487
447
|
},
|
|
488
448
|
{
|
|
489
|
-
id: 'b.narrative.ts',
|
|
490
449
|
sourceFile: 'b.narrative.ts',
|
|
491
450
|
isDerived: true,
|
|
492
451
|
contains: { narrativeIds: ['flow-b'] },
|
|
@@ -554,14 +513,12 @@ describe('module functionality', () => {
|
|
|
554
513
|
integrations: [],
|
|
555
514
|
modules: [
|
|
556
515
|
{
|
|
557
|
-
id: 'shared',
|
|
558
516
|
sourceFile: 'shared/types.narrative.ts',
|
|
559
517
|
isDerived: false,
|
|
560
518
|
contains: { narrativeIds: ['shared-types'] },
|
|
561
519
|
declares: { messages: [{ kind: 'event', name: 'OrderCreated' }] },
|
|
562
520
|
},
|
|
563
521
|
{
|
|
564
|
-
id: 'orders',
|
|
565
522
|
sourceFile: 'features/orders.narrative.ts',
|
|
566
523
|
isDerived: false,
|
|
567
524
|
contains: { narrativeIds: ['orders-flow'] },
|
|
@@ -594,21 +551,18 @@ describe('module functionality', () => {
|
|
|
594
551
|
integrations: [],
|
|
595
552
|
modules: [
|
|
596
553
|
{
|
|
597
|
-
id: 'z.narrative.ts',
|
|
598
554
|
sourceFile: 'z.narrative.ts',
|
|
599
555
|
isDerived: true,
|
|
600
556
|
contains: { narrativeIds: ['z'] },
|
|
601
557
|
declares: { messages: [] },
|
|
602
558
|
},
|
|
603
559
|
{
|
|
604
|
-
id: 'a.narrative.ts',
|
|
605
560
|
sourceFile: 'a.narrative.ts',
|
|
606
561
|
isDerived: true,
|
|
607
562
|
contains: { narrativeIds: ['a'] },
|
|
608
563
|
declares: { messages: [] },
|
|
609
564
|
},
|
|
610
565
|
{
|
|
611
|
-
id: 'm.narrative.ts',
|
|
612
566
|
sourceFile: 'm.narrative.ts',
|
|
613
567
|
isDerived: true,
|
|
614
568
|
contains: { narrativeIds: ['m'] },
|