@izara_project/izara-core-generate-service-code 1.0.78 → 1.0.79
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/package.json +2 -2
- package/src/compile/flowValidator.js +163 -0
- package/src/compile/loadSchemas.js +15 -5
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +137 -7
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +132 -17
- package/src/emit/crud/crudActionPlan.js +82 -0
- package/src/emit/crud/emitCrudApplicationArtifacts.js +162 -112
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +43 -65
- package/src/emit/crud/generateDynamicCrudFlowSchemas.js +4 -1
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +84 -512
- package/src/emit/crud/templates/CreateLogicalLib.ejs +536 -0
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +87 -202
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +213 -0
- package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +217 -0
- package/src/emit/crud/templates/GetEndpoint_Main.ejs +1 -1
- package/src/emit/crud/templates/GetRangeEndpoint_Main.ejs +9 -2
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +87 -444
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +472 -0
- package/src/emit/custom/customFlows.js +27 -2
- package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +1 -2
- package/src/emit/custom/templates/FlowEndpoint_Main.ejs +10 -3
- package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
- package/src/emit/custom/templates/s3/CreateObject_Main.ejs +1 -1
- package/src/emit/custom/templates/triggerCache/CheckTriggerCache_HdrSqs.ejs +2 -2
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +3 -9
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +21 -16
- package/src/emit/rbac/rbacFlowTag.js +2 -7
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +148 -21
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +4 -2
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/CreateRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/GetRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/MoveRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +1 -1
- package/src/emit/resource/emitResourceArtifacts.js +83 -68
- package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +31 -5
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +21 -0
- package/src/emit/resource/templates/WebSocketSubscription_Yaml.ejs +7 -0
- package/src/emit/shared/templates/FlowHandler_HdrApi.ejs +1 -1
- package/src/emit/shared/templates/FlowHandler_HdrDsq.ejs +2 -2
- package/src/emit/shared/templates/FlowHandler_HdrInv.ejs +1 -1
- package/src/emit/shared/templates/FlowHandler_HdrSqs.ejs +2 -2
- package/src/emit/systemText/emitSystemTextSchemas.js +246 -0
- package/src/emit/systemText/templates/SystemTextSchemas.ejs +10 -0
- package/src/generate.js +55 -8
- package/test/crudApplicationArtifacts.test.js +147 -19
- package/test/customFlowApplicationArtifacts.test.js +308 -16
- package/test/dynamicCrudFlowSchemas.test.js +150 -14
- package/test/dynamicRbacFlowSchemas.test.js +2 -2
- package/test/dynamicRelationshipFlowSchemas.test.js +1 -1
- package/test/graphDrivenFlowSchema.test.js +257 -0
- package/test/publicApi.test.js +14 -5
- package/test/resourceArtifacts.test.js +25 -19
- package/test/systemTextSchemas.test.js +154 -0
- package/src/emit/crud/templates/CreateComplete_HdrSqs.ejs +0 -99
- package/src/emit/crud/templates/DeleteComplete_HdrSqs.ejs +0 -99
- package/src/emit/crud/templates/FlowEndpointBeforeLogical_Main.ejs +0 -174
- package/src/emit/crud/templates/FlowEndpointComplete_Main.ejs +0 -187
- package/src/emit/crud/templates/UpdateComplete_HdrSqs.ejs +0 -99
- package/src/emit/resource/templates/ResourceBeforeLogicalYaml.ejs +0 -47
|
@@ -13,6 +13,7 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
13
13
|
import { promisify } from 'node:util';
|
|
14
14
|
import test, { after } from 'node:test';
|
|
15
15
|
|
|
16
|
+
import { generate } from '../src/generate.js';
|
|
16
17
|
import { generateCustomFlowApplicationArtifacts } from '../src/emit/custom/generateCustomFlowApplicationArtifacts.js';
|
|
17
18
|
import { generateResourceArtifacts } from '../src/emit/resource/generateResourceArtifacts.js';
|
|
18
19
|
import { renderEventBridgeFunctionYaml } from '../src/emit/function/functionYamlArtifact.js';
|
|
@@ -107,16 +108,15 @@ test('emits handlers, function YAML, and IAM roles for supported custom flow eve
|
|
|
107
108
|
),
|
|
108
109
|
/Own_Main/
|
|
109
110
|
);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
'app/src/generatedCode/FlowSchemas/Own/source/Own_Main.js'
|
|
115
|
-
),
|
|
116
|
-
'utf8'
|
|
111
|
+
const ownMain = await readFile(
|
|
112
|
+
join(
|
|
113
|
+
rootPath,
|
|
114
|
+
'app/src/generatedCode/FlowSchemas/Own/source/Own_Main.js'
|
|
117
115
|
),
|
|
118
|
-
|
|
116
|
+
'utf8'
|
|
119
117
|
);
|
|
118
|
+
assert.match(ownMain, /asyncFlowSharedLib/);
|
|
119
|
+
assert.match(ownMain, /callingFlowConfig = {},\s*\/\/\(<additionalParams>\)/);
|
|
120
120
|
assert.match(
|
|
121
121
|
await readFile(
|
|
122
122
|
join(
|
|
@@ -302,15 +302,17 @@ test('emits and removes ext-topic handlers declared by custom flow steps', async
|
|
|
302
302
|
'app/src/generatedCode/FlowSchemas/DsqStep/source/DsqStepRetryDsq_HdrDsq.js'
|
|
303
303
|
)
|
|
304
304
|
);
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
'app/src/generatedCode/FlowSchemas/Stepped/source/SteppedComplete_Main.js'
|
|
310
|
-
),
|
|
311
|
-
'utf8'
|
|
305
|
+
const steppedCompleteMain = await readFile(
|
|
306
|
+
join(
|
|
307
|
+
rootPath,
|
|
308
|
+
'app/src/generatedCode/FlowSchemas/Stepped/source/SteppedComplete_Main.js'
|
|
312
309
|
),
|
|
313
|
-
|
|
310
|
+
'utf8'
|
|
311
|
+
);
|
|
312
|
+
assert.match(steppedCompleteMain, /identifierUuid/);
|
|
313
|
+
assert.match(
|
|
314
|
+
steppedCompleteMain,
|
|
315
|
+
/callingFlowConfig = {},\s*\/\/\(<additionalParams>\)/
|
|
314
316
|
);
|
|
315
317
|
assert.match(
|
|
316
318
|
await readFile(
|
|
@@ -819,3 +821,293 @@ test('renders nextSteps IAM permissions in InitialSetupConfig', async () => {
|
|
|
819
821
|
);
|
|
820
822
|
});
|
|
821
823
|
|
|
824
|
+
test('registers SQS queue, SNS subscription, and SNS out topic for custom flowSchema with outputTopic set to true', async () => {
|
|
825
|
+
const { generate } = await import('../src/generate.js');
|
|
826
|
+
const rootPath = await mkdtemp(
|
|
827
|
+
join(tmpdir(), 'generate-service-code-v2-outputtopic-')
|
|
828
|
+
);
|
|
829
|
+
roots.add(rootPath);
|
|
830
|
+
const schemaRoot = join(rootPath, 'app/src/schemas/FlowSchemas');
|
|
831
|
+
await mkdir(schemaRoot, { recursive: true });
|
|
832
|
+
|
|
833
|
+
await writeFile(
|
|
834
|
+
join(schemaRoot, 'MyCustomFlow.js'),
|
|
835
|
+
`export default [
|
|
836
|
+
{
|
|
837
|
+
flowTag: 'MyCustomFlow',
|
|
838
|
+
initiateBy: 'user',
|
|
839
|
+
handleObj: 'one',
|
|
840
|
+
statusType: 'none',
|
|
841
|
+
objType: {
|
|
842
|
+
objectType: 'myObj',
|
|
843
|
+
serviceTag: 'TST'
|
|
844
|
+
},
|
|
845
|
+
event: ['ownTopic'],
|
|
846
|
+
outputTopic: true
|
|
847
|
+
}
|
|
848
|
+
];\n`
|
|
849
|
+
);
|
|
850
|
+
|
|
851
|
+
const result = await generate(rootPath, {
|
|
852
|
+
serviceTag: 'TestService'
|
|
853
|
+
});
|
|
854
|
+
assert.ok(result);
|
|
855
|
+
|
|
856
|
+
const snsInSqs = await readFile(
|
|
857
|
+
join(
|
|
858
|
+
rootPath,
|
|
859
|
+
'resource/sls_yaml/generatedCode/source/generated-sns-in-sqs.yml'
|
|
860
|
+
),
|
|
861
|
+
'utf8'
|
|
862
|
+
);
|
|
863
|
+
assert.match(snsInSqs, /^ MyCustomFlowCompleteHdrSqs:/m);
|
|
864
|
+
|
|
865
|
+
const snsOut = await readFile(
|
|
866
|
+
join(
|
|
867
|
+
rootPath,
|
|
868
|
+
'resource/sls_yaml/generatedCode/source/generated-sns-out.yml'
|
|
869
|
+
),
|
|
870
|
+
'utf8'
|
|
871
|
+
);
|
|
872
|
+
assert.match(snsOut, /^\s*OutMyCustomFlow:/m);
|
|
873
|
+
assert.match(snsOut, /MyCustomFlow_Out/);
|
|
874
|
+
|
|
875
|
+
const initialSetupConfigContent = await readFile(
|
|
876
|
+
join(
|
|
877
|
+
rootPath,
|
|
878
|
+
'app/src/generatedCode/CoreFunctions/InitialSetupConfig.js'
|
|
879
|
+
),
|
|
880
|
+
'utf8'
|
|
881
|
+
);
|
|
882
|
+
assert.match(initialSetupConfigContent, /serviceTag: 'TST'/);
|
|
883
|
+
assert.match(initialSetupConfigContent, /topicName: 'MyCustomFlow_Out'/);
|
|
884
|
+
assert.match(
|
|
885
|
+
initialSetupConfigContent,
|
|
886
|
+
/sqsEndpoint: 'MyCustomFlowCompleteHdrSqs'/
|
|
887
|
+
);
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
test('renders RBAC Validator subscriptions in InitialSetupConfig when object has belongTo to external RBAC service', async () => {
|
|
891
|
+
const rootPath = await createProject();
|
|
892
|
+
await writeFile(
|
|
893
|
+
join(rootPath, 'app/src/schemas/ObjectSchemas/Member.js'),
|
|
894
|
+
`export default {
|
|
895
|
+
objectType: 'member',
|
|
896
|
+
belongTo: {
|
|
897
|
+
objectType: 'user',
|
|
898
|
+
serviceTag: 'UserAccount'
|
|
899
|
+
}
|
|
900
|
+
};\n`
|
|
901
|
+
);
|
|
902
|
+
|
|
903
|
+
const result = await generate(rootPath, {
|
|
904
|
+
serviceTag: 'MembershipService'
|
|
905
|
+
});
|
|
906
|
+
assert.ok(result);
|
|
907
|
+
|
|
908
|
+
const initialSetupConfigContent = await readFile(
|
|
909
|
+
join(
|
|
910
|
+
rootPath,
|
|
911
|
+
'app/src/generatedCode/CoreFunctions/InitialSetupConfig.js'
|
|
912
|
+
),
|
|
913
|
+
'utf8'
|
|
914
|
+
);
|
|
915
|
+
assert.match(initialSetupConfigContent, /serviceTag: 'UserAccount'/);
|
|
916
|
+
assert.match(initialSetupConfigContent, /topicName: 'ValidatorRbac_Out'/);
|
|
917
|
+
assert.match(initialSetupConfigContent, /sqsEndpoint: 'CreateCompleteHdrSqs'/);
|
|
918
|
+
assert.match(initialSetupConfigContent, /sqsEndpoint: 'UpdateCompleteHdrSqs'/);
|
|
919
|
+
assert.match(initialSetupConfigContent, /sqsEndpoint: 'DeleteCompleteHdrSqs'/);
|
|
920
|
+
});
|
|
921
|
+
|
|
922
|
+
test('deduplicates duplicate nextSteps topics across flowSteps in InitialSetupConfig', async () => {
|
|
923
|
+
const { generate } = await import('../src/generate.js');
|
|
924
|
+
const rootPath = await mkdtemp(
|
|
925
|
+
join(tmpdir(), 'generate-service-code-v2-dedupe-nextsteps-')
|
|
926
|
+
);
|
|
927
|
+
roots.add(rootPath);
|
|
928
|
+
const schemaRoot = join(rootPath, 'app/src/schemas/FlowSchemas');
|
|
929
|
+
await mkdir(schemaRoot, { recursive: true });
|
|
930
|
+
|
|
931
|
+
await writeFile(
|
|
932
|
+
join(schemaRoot, 'DuplicateTopicFlow.js'),
|
|
933
|
+
`export default {
|
|
934
|
+
flowTag: 'DuplicateTopicFlow',
|
|
935
|
+
event: ['ownTopic'],
|
|
936
|
+
flowSteps: [
|
|
937
|
+
{
|
|
938
|
+
stepName: 'StepOne',
|
|
939
|
+
nextSteps: [
|
|
940
|
+
{
|
|
941
|
+
targetType: 'extTopic',
|
|
942
|
+
serviceTag: 'GraphHandler',
|
|
943
|
+
topic: 'GetDeepPathSearch_In'
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
targetType: 'lambdaSyncInv',
|
|
947
|
+
serviceTag: 'SharedService',
|
|
948
|
+
functionName: 'ValidateSomething'
|
|
949
|
+
}
|
|
950
|
+
]
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
stepName: 'StepTwo',
|
|
954
|
+
event: ['extTopic'],
|
|
955
|
+
nextSteps: [
|
|
956
|
+
{
|
|
957
|
+
targetType: 'extTopic',
|
|
958
|
+
serviceTag: 'GraphHandler',
|
|
959
|
+
topic: 'GetDeepPathSearch_In'
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
targetType: 'lambdaSyncInv',
|
|
963
|
+
serviceTag: 'SharedService',
|
|
964
|
+
functionName: 'ValidateSomething'
|
|
965
|
+
}
|
|
966
|
+
]
|
|
967
|
+
}
|
|
968
|
+
]
|
|
969
|
+
};\n`
|
|
970
|
+
);
|
|
971
|
+
|
|
972
|
+
const result = await generate(rootPath, {
|
|
973
|
+
serviceTag: 'DuplicateTestService'
|
|
974
|
+
});
|
|
975
|
+
assert.ok(result);
|
|
976
|
+
|
|
977
|
+
const initialSetupConfigContent = await readFile(
|
|
978
|
+
join(
|
|
979
|
+
rootPath,
|
|
980
|
+
'app/src/generatedCode/CoreFunctions/InitialSetupConfig.js'
|
|
981
|
+
),
|
|
982
|
+
'utf8'
|
|
983
|
+
);
|
|
984
|
+
|
|
985
|
+
const snsMatches = initialSetupConfigContent.match(
|
|
986
|
+
/GetDeepPathSearch_In/g
|
|
987
|
+
);
|
|
988
|
+
assert.equal(
|
|
989
|
+
snsMatches?.length,
|
|
990
|
+
1,
|
|
991
|
+
'SNS topic GetDeepPathSearch_In should appear exactly once in externalLambdaRole'
|
|
992
|
+
);
|
|
993
|
+
|
|
994
|
+
const lambdaMatches = initialSetupConfigContent.match(
|
|
995
|
+
/ValidateSomething/g
|
|
996
|
+
);
|
|
997
|
+
assert.equal(
|
|
998
|
+
lambdaMatches?.length,
|
|
999
|
+
1,
|
|
1000
|
+
'Lambda function ValidateSomething should appear exactly once in externalLambdaRole'
|
|
1001
|
+
);
|
|
1002
|
+
|
|
1003
|
+
assert.doesNotMatch(
|
|
1004
|
+
initialSetupConfigContent,
|
|
1005
|
+
/<#|#>/,
|
|
1006
|
+
'InitialSetupConfig.js should not contain invalid <#...#> hook tags'
|
|
1007
|
+
);
|
|
1008
|
+
assert.match(
|
|
1009
|
+
initialSetupConfigContent,
|
|
1010
|
+
/\/\/\(<InitialSetupConfig_ExternalServices>\)/
|
|
1011
|
+
);
|
|
1012
|
+
assert.match(
|
|
1013
|
+
initialSetupConfigContent,
|
|
1014
|
+
/\/\/\(<\/InitialSetupConfig_ExternalServices>\)/
|
|
1015
|
+
);
|
|
1016
|
+
assert.match(
|
|
1017
|
+
initialSetupConfigContent,
|
|
1018
|
+
/\/\/\(<InitialSetupConfig_Prod_Config_TableConfig>\)/
|
|
1019
|
+
);
|
|
1020
|
+
assert.match(
|
|
1021
|
+
initialSetupConfigContent,
|
|
1022
|
+
/\/\/\(<InitialSetupConfig_Test_Config_TableConfig>\)/
|
|
1023
|
+
);
|
|
1024
|
+
});
|
|
1025
|
+
|
|
1026
|
+
test('renders multi-type array for mixed property and messageAttribute type in handler validator schema', async () => {
|
|
1027
|
+
const rootPath = await mkdtemp(
|
|
1028
|
+
join(tmpdir(), 'generate-service-code-v2-mixed-type-')
|
|
1029
|
+
);
|
|
1030
|
+
roots.add(rootPath);
|
|
1031
|
+
const schemaRoot = join(rootPath, 'app/src/schemas/FlowSchemas');
|
|
1032
|
+
await mkdir(schemaRoot, { recursive: true });
|
|
1033
|
+
|
|
1034
|
+
await writeFile(
|
|
1035
|
+
join(schemaRoot, 'MixedFlow.js'),
|
|
1036
|
+
`export default {
|
|
1037
|
+
flowTag: 'MixedFlow',
|
|
1038
|
+
event: ['ownTopic', 'lambdaSyncApi', 'lambdaSyncInv', 'dsq'],
|
|
1039
|
+
stepProperties: {
|
|
1040
|
+
payload: { propertyName: 'payload', type: 'mixed' }
|
|
1041
|
+
},
|
|
1042
|
+
stepMessageAttributes: {
|
|
1043
|
+
attr: { propertyName: 'attr', type: 'mixed' }
|
|
1044
|
+
},
|
|
1045
|
+
flowSteps: [
|
|
1046
|
+
{
|
|
1047
|
+
stepName: 'Start',
|
|
1048
|
+
properties: ['payload'],
|
|
1049
|
+
messageAttributes: ['attr']
|
|
1050
|
+
}
|
|
1051
|
+
]
|
|
1052
|
+
};\n`
|
|
1053
|
+
);
|
|
1054
|
+
|
|
1055
|
+
const result = await generateCustomFlowApplicationArtifacts(rootPath);
|
|
1056
|
+
assert.ok(result);
|
|
1057
|
+
|
|
1058
|
+
const sqsHdr = await readFile(
|
|
1059
|
+
join(
|
|
1060
|
+
rootPath,
|
|
1061
|
+
'app/src/generatedCode/FlowSchemas/MixedFlow/source/MixedFlow_HdrSqs.js'
|
|
1062
|
+
),
|
|
1063
|
+
'utf8'
|
|
1064
|
+
);
|
|
1065
|
+
assert.match(
|
|
1066
|
+
sqsHdr,
|
|
1067
|
+
/payload:\s*\{\s*type:\s*\['string',\s*'number',\s*'integer',\s*'boolean',\s*'null',\s*'object',\s*'array'\]/
|
|
1068
|
+
);
|
|
1069
|
+
assert.match(
|
|
1070
|
+
sqsHdr,
|
|
1071
|
+
/Value:\s*\{\s*type:\s*\['string',\s*'number',\s*'integer',\s*'boolean',\s*'null',\s*'object',\s*'array'\]/
|
|
1072
|
+
);
|
|
1073
|
+
|
|
1074
|
+
const apiHdr = await readFile(
|
|
1075
|
+
join(
|
|
1076
|
+
rootPath,
|
|
1077
|
+
'app/src/generatedCode/FlowSchemas/MixedFlow/source/MixedFlow_HdrApi.js'
|
|
1078
|
+
),
|
|
1079
|
+
'utf8'
|
|
1080
|
+
);
|
|
1081
|
+
assert.match(
|
|
1082
|
+
apiHdr,
|
|
1083
|
+
/payload:\s*\{\s*type:\s*\['string',\s*'number',\s*'integer',\s*'boolean',\s*'null',\s*'object',\s*'array'\]/
|
|
1084
|
+
);
|
|
1085
|
+
|
|
1086
|
+
const invHdr = await readFile(
|
|
1087
|
+
join(
|
|
1088
|
+
rootPath,
|
|
1089
|
+
'app/src/generatedCode/FlowSchemas/MixedFlow/source/MixedFlow_HdrInv.js'
|
|
1090
|
+
),
|
|
1091
|
+
'utf8'
|
|
1092
|
+
);
|
|
1093
|
+
assert.match(
|
|
1094
|
+
invHdr,
|
|
1095
|
+
/payload:\s*\{\s*type:\s*\['string',\s*'number',\s*'integer',\s*'boolean',\s*'null',\s*'object',\s*'array'\]/
|
|
1096
|
+
);
|
|
1097
|
+
|
|
1098
|
+
const dsqHdr = await readFile(
|
|
1099
|
+
join(
|
|
1100
|
+
rootPath,
|
|
1101
|
+
'app/src/generatedCode/FlowSchemas/MixedFlow/source/MixedFlow_HdrDsq.js'
|
|
1102
|
+
),
|
|
1103
|
+
'utf8'
|
|
1104
|
+
);
|
|
1105
|
+
assert.match(
|
|
1106
|
+
dsqHdr,
|
|
1107
|
+
/payload:\s*\{\s*type:\s*\['string',\s*'number',\s*'integer',\s*'boolean',\s*'null',\s*'object',\s*'array'\]/
|
|
1108
|
+
);
|
|
1109
|
+
assert.match(
|
|
1110
|
+
dsqHdr,
|
|
1111
|
+
/Value:\s*\{\s*type:\s*\['string',\s*'number',\s*'integer',\s*'boolean',\s*'null',\s*'object',\s*'array'\]/
|
|
1112
|
+
);
|
|
1113
|
+
});
|
|
@@ -9,8 +9,7 @@ import { generateDynamicCrudFlowSchemas } from '../src/emit/crud/generateDynamic
|
|
|
9
9
|
|
|
10
10
|
test('generates dynamic CRUD schemas from local schema modules', async () => {
|
|
11
11
|
const rootPath = await createProject({
|
|
12
|
-
generatedBy: 'userGenerated'
|
|
13
|
-
flow: createHookFlow(['ownTopic'])
|
|
12
|
+
generatedBy: 'userGenerated'
|
|
14
13
|
});
|
|
15
14
|
|
|
16
15
|
const result = await generateDynamicCrudFlowSchemas(rootPath);
|
|
@@ -29,7 +28,7 @@ test('generates dynamic CRUD schemas from local schema modules', async () => {
|
|
|
29
28
|
assert.deepEqual(create.event, ['ownTopic']);
|
|
30
29
|
assert.deepEqual(
|
|
31
30
|
create.flowSteps.map((step) => step.stepName),
|
|
32
|
-
['
|
|
31
|
+
['Start', 'Complete']
|
|
33
32
|
);
|
|
34
33
|
assert.deepEqual(create.flowSteps[0].returnValues.messageAttributes, [
|
|
35
34
|
'userId',
|
|
@@ -43,7 +42,6 @@ test('generates dynamic CRUD schemas from local schema modules', async () => {
|
|
|
43
42
|
test('accepts singleton object exports used by existing schema files', async () => {
|
|
44
43
|
const rootPath = await createProject({
|
|
45
44
|
generatedBy: 'userGenerated',
|
|
46
|
-
flow: createHookFlow(['ownTopic']),
|
|
47
45
|
singletonExports: true
|
|
48
46
|
});
|
|
49
47
|
|
|
@@ -54,7 +52,7 @@ test('accepts singleton object exports used by existing schema files', async ()
|
|
|
54
52
|
(await readGeneratedFlow(rootPath, 'Create')).flowSteps.map(
|
|
55
53
|
(step) => step.stepName
|
|
56
54
|
),
|
|
57
|
-
['
|
|
55
|
+
['Start', 'Complete']
|
|
58
56
|
);
|
|
59
57
|
});
|
|
60
58
|
|
|
@@ -101,25 +99,163 @@ test('rejects source modules that do not default-export schema objects or arrays
|
|
|
101
99
|
);
|
|
102
100
|
});
|
|
103
101
|
|
|
104
|
-
test('
|
|
102
|
+
test('rejects deprecated FlowHook schemas before generating CRUD schemas', async () => {
|
|
105
103
|
const rootPath = await createProject({
|
|
106
104
|
generatedBy: 'systemGenerated',
|
|
107
105
|
flow: createHookFlow(['ownTopic'])
|
|
108
106
|
});
|
|
109
|
-
|
|
107
|
+
|
|
108
|
+
await assert.rejects(
|
|
109
|
+
generateDynamicCrudFlowSchemas(rootPath),
|
|
110
|
+
/generatedCodeConfig\.codeHookTag is no longer supported/
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('generates a direct Complete step for RBAC-only Update flows', async () => {
|
|
115
|
+
const rootPath = await mkdtemp(
|
|
116
|
+
join(tmpdir(), 'generate-service-code-v2-crud-rbac-')
|
|
117
|
+
);
|
|
118
|
+
const objectDirectory = join(rootPath, 'app/src/schemas/ObjectSchemas');
|
|
119
|
+
await mkdir(objectDirectory, { recursive: true });
|
|
120
|
+
await writeFile(
|
|
121
|
+
join(objectDirectory, 'Order.js'),
|
|
122
|
+
`export default [{
|
|
123
|
+
objectType: 'order',
|
|
124
|
+
generatedBy: 'userGenerated',
|
|
125
|
+
belongTo: { serviceTag: 'UserAccount', objectType: 'user' }
|
|
126
|
+
}];\n`
|
|
127
|
+
);
|
|
110
128
|
|
|
111
129
|
await generateDynamicCrudFlowSchemas(rootPath);
|
|
112
|
-
|
|
130
|
+
const update = await readGeneratedFlow(rootPath, 'Update');
|
|
131
|
+
assert.deepEqual(
|
|
132
|
+
update.flowSteps.map((step) => step.stepName),
|
|
133
|
+
['Start', 'Complete']
|
|
134
|
+
);
|
|
135
|
+
assert.deepEqual(update.flowSteps[0].nextSteps, [
|
|
136
|
+
{ targetType: 'ownTopic', stepName: 'Complete' }
|
|
137
|
+
]);
|
|
138
|
+
assert.deepEqual(update.flowSteps[1].previousSteps, [
|
|
139
|
+
{ sourceType: 'ownTopic', stepName: 'Start' }
|
|
140
|
+
]);
|
|
141
|
+
assert.equal(update.flowSteps[1].properties.length, 0);
|
|
142
|
+
});
|
|
113
143
|
|
|
144
|
+
test('ignores RBAC for Create even when Graph storage is present', async () => {
|
|
145
|
+
const rootPath = await createProject({
|
|
146
|
+
generatedBy: 'userGenerated',
|
|
147
|
+
});
|
|
114
148
|
await writeFile(
|
|
115
|
-
|
|
116
|
-
`export default [
|
|
149
|
+
join(rootPath, 'app/src/schemas/ObjectSchemas/Order.js'),
|
|
150
|
+
`export default [{
|
|
151
|
+
objectType: 'order',
|
|
152
|
+
generatedBy: 'userGenerated',
|
|
153
|
+
belongTo: { serviceTag: 'UserAccount', objectType: 'user' }
|
|
154
|
+
, storageResources: { graph: { storageType: 'graph' } }
|
|
155
|
+
}];\n`
|
|
117
156
|
);
|
|
157
|
+
|
|
118
158
|
await generateDynamicCrudFlowSchemas(rootPath);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
159
|
+
const create = await readGeneratedFlow(rootPath, 'Create');
|
|
160
|
+
assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
|
|
161
|
+
'Start',
|
|
162
|
+
'Complete'
|
|
163
|
+
]);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('uses the renamed RBAC callback step when Graph storage is present', async () => {
|
|
167
|
+
const rootPath = await mkdtemp(
|
|
168
|
+
join(tmpdir(), 'generate-service-code-v2-crud-rbac-graph-')
|
|
169
|
+
);
|
|
170
|
+
const objectDirectory = join(rootPath, 'app/src/schemas/ObjectSchemas');
|
|
171
|
+
await mkdir(objectDirectory, { recursive: true });
|
|
172
|
+
await writeFile(
|
|
173
|
+
join(objectDirectory, 'Order.js'),
|
|
174
|
+
`export default [{
|
|
175
|
+
objectType: 'order',
|
|
176
|
+
generatedBy: 'userGenerated',
|
|
177
|
+
belongTo: { serviceTag: 'UserAccount', objectType: 'user' },
|
|
178
|
+
storageResources: { graph: { storageType: 'graph' } }
|
|
179
|
+
}];\n`
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
await generateDynamicCrudFlowSchemas(rootPath);
|
|
183
|
+
const create = await readGeneratedFlow(rootPath, 'Create');
|
|
184
|
+
assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
|
|
185
|
+
'Start',
|
|
186
|
+
'Complete'
|
|
187
|
+
]);
|
|
188
|
+
assert.deepEqual(create.flowSteps[1].properties, [
|
|
189
|
+
'returnValue',
|
|
190
|
+
'parentFlowId',
|
|
191
|
+
'status',
|
|
192
|
+
'errorsFound',
|
|
193
|
+
'graphServiceTag'
|
|
194
|
+
]);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test('chains RbacCallback and Complete for Update with RBAC and Graph', async () => {
|
|
198
|
+
const rootPath = await mkdtemp(
|
|
199
|
+
join(tmpdir(), 'generate-service-code-v2-crud-update-rbac-graph-')
|
|
200
|
+
);
|
|
201
|
+
const objectDirectory = join(rootPath, 'app/src/schemas/ObjectSchemas');
|
|
202
|
+
await mkdir(objectDirectory, { recursive: true });
|
|
203
|
+
await writeFile(
|
|
204
|
+
join(objectDirectory, 'Order.js'),
|
|
205
|
+
`export default [{
|
|
206
|
+
objectType: 'order',
|
|
207
|
+
generatedBy: 'userGenerated',
|
|
208
|
+
belongTo: { serviceTag: 'UserAccount', objectType: 'user' },
|
|
209
|
+
storageResources: { graph: { storageType: 'graph' } }
|
|
210
|
+
}];\n`
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
await generateDynamicCrudFlowSchemas(rootPath);
|
|
214
|
+
const update = await readGeneratedFlow(rootPath, 'Update');
|
|
215
|
+
assert.deepEqual(update.flowSteps.map((step) => step.stepName), [
|
|
216
|
+
'Start',
|
|
217
|
+
'RbacCallback',
|
|
218
|
+
'Complete'
|
|
219
|
+
]);
|
|
220
|
+
assert.deepEqual(update.flowSteps[0].nextSteps, [
|
|
221
|
+
{ targetType: 'ownTopic', stepName: 'RbacCallback' }
|
|
222
|
+
]);
|
|
223
|
+
assert.deepEqual(update.flowSteps[1].nextSteps, [
|
|
224
|
+
{ targetType: 'ownTopic', stepName: 'Complete' }
|
|
225
|
+
]);
|
|
226
|
+
assert.deepEqual(update.flowSteps[2].properties, [
|
|
227
|
+
'returnValue',
|
|
228
|
+
'parentFlowId',
|
|
229
|
+
'status',
|
|
230
|
+
'errorsFound',
|
|
231
|
+
'graphServiceTag'
|
|
232
|
+
]);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test('omits Complete step when no graph storage resources exist', async () => {
|
|
236
|
+
const rootPath = await mkdtemp(
|
|
237
|
+
join(tmpdir(), 'generate-service-code-v2-crud-no-graph-')
|
|
238
|
+
);
|
|
239
|
+
const objectDirectory = join(rootPath, 'app/src/schemas/ObjectSchemas');
|
|
240
|
+
await mkdir(objectDirectory, { recursive: true });
|
|
241
|
+
await writeFile(
|
|
242
|
+
join(objectDirectory, 'Order.js'),
|
|
243
|
+
`export default [{
|
|
244
|
+
objectType: 'order',
|
|
245
|
+
generatedBy: 'userGenerated',
|
|
246
|
+
storageResources: {
|
|
247
|
+
myTable: { storageType: 'dynamoDB', tableName: 'OrderTable' }
|
|
248
|
+
}
|
|
249
|
+
}];\n`
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
await generateDynamicCrudFlowSchemas(rootPath);
|
|
253
|
+
const create = await readGeneratedFlow(rootPath, 'Create');
|
|
254
|
+
assert.deepEqual(
|
|
255
|
+
create.flowSteps.map((step) => step.stepName),
|
|
256
|
+
['Start']
|
|
122
257
|
);
|
|
258
|
+
assert.equal(create.flowSteps[0].nextSteps, undefined);
|
|
123
259
|
});
|
|
124
260
|
|
|
125
261
|
async function createProject({ generatedBy, flow, singletonExports = false }) {
|
|
@@ -134,7 +270,7 @@ async function createProject({ generatedBy, flow, singletonExports = false }) {
|
|
|
134
270
|
await mkdir(join(rootPath, 'app/src/schemas/FlowSchemas'), {
|
|
135
271
|
recursive: true
|
|
136
272
|
});
|
|
137
|
-
const object = `{ objectType: 'order', generatedBy: '${generatedBy}' }`;
|
|
273
|
+
const object = `{ objectType: 'order', generatedBy: '${generatedBy}', storageResources: { graph: { storageType: 'graph' } } }`;
|
|
138
274
|
await writeFile(
|
|
139
275
|
objectPath,
|
|
140
276
|
`export default ${singletonExports ? object : `[${object}]`};\n`
|
|
@@ -42,14 +42,14 @@ test('generates shared and object-specific RBAC flow schemas', async () => {
|
|
|
42
42
|
(action) =>
|
|
43
43
|
`app/src/schemas/FlowSchemas/generateCode/FlowRbac/${action}.js`
|
|
44
44
|
),
|
|
45
|
-
'app/src/schemas/FlowSchemas/generateCode/FlowRbac/
|
|
45
|
+
'app/src/schemas/FlowSchemas/generateCode/FlowRbac/ValidatorRbac.js'
|
|
46
46
|
]
|
|
47
47
|
);
|
|
48
48
|
const createTargetRole = await readGeneratedFlow(
|
|
49
49
|
rootPath,
|
|
50
50
|
'CreateTargetRole'
|
|
51
51
|
);
|
|
52
|
-
const user = await readGeneratedFlow(rootPath, '
|
|
52
|
+
const user = await readGeneratedFlow(rootPath, 'ValidatorRbac');
|
|
53
53
|
assert.deepEqual(createTargetRole.flowSteps[0].returnValues, {
|
|
54
54
|
properties: ['returnResult'],
|
|
55
55
|
messageAttributes: []
|
|
@@ -54,7 +54,7 @@ test('generates dynamic relationship schemas when declared relationships exist',
|
|
|
54
54
|
assert.deepEqual(create.event, ['ownTopic']);
|
|
55
55
|
assert.deepEqual(
|
|
56
56
|
create.flowSteps.map((step) => step.stepName),
|
|
57
|
-
['
|
|
57
|
+
['Start', 'Complete']
|
|
58
58
|
);
|
|
59
59
|
assert.deepEqual(create.flowSteps[0].returnValues.messageAttributes, [
|
|
60
60
|
'userId',
|