@izara_project/izara-core-generate-service-code 1.0.90 → 1.0.92

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.
Files changed (82) hide show
  1. package/package.json +7 -10
  2. package/src/compile/flowValidator.js +6 -0
  3. package/src/compile/loadSchemas.js +177 -69
  4. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +2 -2
  5. package/src/emit/crud/generateCrudApplicationArtifacts.js +15 -17
  6. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +16 -21
  7. package/src/emit/crud/loadLocalSchemaArrays.js +4 -8
  8. package/src/emit/crud/templates/CreateAfterHookCallback_Main.ejs +6 -6
  9. package/src/emit/crud/templates/CreateBeforeHookCallback_Main.ejs +3 -3
  10. package/src/emit/crud/templates/CreateComplete_Main.ejs +22 -22
  11. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +18 -18
  12. package/src/emit/crud/templates/CreateLogicalLib.ejs +47 -47
  13. package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +24 -24
  14. package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +5 -5
  15. package/src/emit/crud/templates/DeleteBeforeHookCallback_Main.ejs +3 -3
  16. package/src/emit/crud/templates/DeleteComplete_Main.ejs +23 -23
  17. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +15 -15
  18. package/src/emit/crud/templates/DeleteLogicalLib.ejs +19 -19
  19. package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +3 -3
  20. package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +5 -5
  21. package/src/emit/crud/templates/UpdateBeforeHookCallback_Main.ejs +3 -3
  22. package/src/emit/crud/templates/UpdateComplete_Main.ejs +22 -22
  23. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +15 -15
  24. package/src/emit/crud/templates/UpdateLogicalLib.ejs +33 -33
  25. package/src/emit/custom/customFlowPaths.js +149 -0
  26. package/src/emit/custom/customFlowS3.js +156 -0
  27. package/src/emit/custom/customFlowSteps.js +385 -0
  28. package/src/emit/custom/customFlowTemplates.js +28 -0
  29. package/src/emit/custom/customFlows.js +48 -19
  30. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +57 -692
  31. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +27 -25
  32. package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +7 -7
  33. package/src/emit/custom/templates/s3/ConfirmReserved_HdrSqs.ejs +3 -3
  34. package/src/emit/custom/templates/s3/ConfirmReserved_Main.ejs +3 -3
  35. package/src/emit/custom/templates/s3/CreatePreSignUrl_HdrSqs.ejs +3 -3
  36. package/src/emit/custom/templates/s3/CreatePreSignUrl_Main.ejs +4 -4
  37. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +26 -6
  38. package/src/emit/rbac/emitRbacApplicationArtifacts.js +40 -13
  39. package/src/emit/rbac/generateCreateTargetRoleHandler.js +11 -13
  40. package/src/emit/rbac/generateDynamicRbacFlowSchemas.js +14 -18
  41. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +13 -7
  42. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
  43. package/src/emit/relationship/generateDynamicRelationshipFlowSchemas.js +16 -19
  44. package/src/emit/relationship/generateRelationshipApplicationArtifacts.js +19 -19
  45. package/src/emit/relationship/templates/ChangeRelationshipComplete_HdrSqs.ejs +2 -2
  46. package/src/emit/relationship/templates/ChangeRelationshipComplete_Main.ejs +6 -6
  47. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +17 -17
  48. package/src/emit/relationship/templates/CreateRelationshipComplete_HdrSqs.ejs +2 -2
  49. package/src/emit/relationship/templates/CreateRelationshipComplete_Main.ejs +6 -6
  50. package/src/emit/relationship/templates/CreateRelationship_Main.ejs +14 -14
  51. package/src/emit/relationship/templates/DeleteRelationshipComplete_HdrSqs.ejs +2 -2
  52. package/src/emit/relationship/templates/DeleteRelationshipComplete_Main.ejs +6 -6
  53. package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +10 -10
  54. package/src/emit/relationship/templates/GetRelationshipComplete_HdrSqs.ejs +2 -2
  55. package/src/emit/relationship/templates/GetRelationshipComplete_Main.ejs +5 -5
  56. package/src/emit/relationship/templates/GetRelationship_Main.ejs +9 -9
  57. package/src/emit/relationship/templates/MoveRelationshipComplete_HdrSqs.ejs +2 -2
  58. package/src/emit/relationship/templates/MoveRelationshipComplete_Main.ejs +6 -6
  59. package/src/emit/relationship/templates/MoveRelationship_Main.ejs +15 -15
  60. package/src/emit/relationship/templates/UpdateRelationshipComplete_HdrSqs.ejs +2 -2
  61. package/src/emit/relationship/templates/UpdateRelationshipComplete_Main.ejs +6 -6
  62. package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +11 -11
  63. package/src/emit/resource/dynamoResourceArtifacts.js +18 -0
  64. package/src/emit/resource/emitResourceArtifacts.js +13 -1251
  65. package/src/emit/resource/generateResourceArtifacts.js +20 -20
  66. package/src/emit/resource/iamResourceArtifacts.js +612 -0
  67. package/src/emit/resource/resourceState.js +564 -0
  68. package/src/emit/resource/resourceTemplate.js +30 -0
  69. package/src/emit/resource/s3ResourceArtifacts.js +14 -0
  70. package/src/emit/resource/sqsResourceArtifacts.js +113 -0
  71. package/src/emit/shared/runSubsystemGeneration.js +55 -0
  72. package/src/emit/shared/templates/FindData_Main.ejs +19 -19
  73. package/src/emit/shared/templates/PaginateProcessLogical_Main.ejs +3 -3
  74. package/src/emit/shared/templates/ProcessLogical_Main.ejs +15 -15
  75. package/src/emit/system/emitSystemWebSocketArtifacts.js +2 -1
  76. package/test/createTargetRoleHandler.test.js +62 -4
  77. package/test/crudApplicationArtifacts.test.js +75 -3
  78. package/test/customFlowApplicationArtifacts.test.js +98 -0
  79. package/test/dynamicCrudFlowSchemas.test.js +2 -2
  80. package/test/dynamicRbacFlowSchemas.test.js +32 -4
  81. package/test/relationshipApplicationArtifacts.test.js +1 -1
  82. package/test/resourceArtifacts.test.js +99 -0
@@ -1173,3 +1173,101 @@ test('renders previousSteps extTopic subscriptions in InitialSetupConfig', async
1173
1173
  /sqsEndpoint: 'OrderBuildOrderSellOfferLinkAndReserveOrderDataHdrSqs'/
1174
1174
  );
1175
1175
  });
1176
+
1177
+ test('emits handlers, YAML and templates for flow with event generateCode and invocationType ownTopic', async () => {
1178
+ const rootPath = await mkdtemp(
1179
+ join(tmpdir(), 'generate-service-code-v2-custom-gen-own-')
1180
+ );
1181
+ roots.add(rootPath);
1182
+ const schemaRoot = join(rootPath, 'app/src/schemas/FlowSchemas');
1183
+ await mkdir(schemaRoot, { recursive: true });
1184
+ await writeFile(
1185
+ join(schemaRoot, 'GenOwn.js'),
1186
+ `export default {
1187
+ flowTag: 'genOwn',
1188
+ event: ['generateCode'],
1189
+ generatedCodeConfig: {
1190
+ generateCodeTag: 'create',
1191
+ codeHookTag: 'before',
1192
+ invocationType: 'ownTopic'
1193
+ },
1194
+ flowSteps: [{ stepName: 'Start', properties: ['dummyId'] }],
1195
+ stepProperties: { dummyId: { type: 'string' } }
1196
+ };\n`
1197
+ );
1198
+
1199
+ await generateCustomFlowApplicationArtifacts(rootPath);
1200
+
1201
+ const mainPath = join(
1202
+ rootPath,
1203
+ 'app/src/generatedCode/FlowSchemas/GenOwn/source/GenOwn_Main.js'
1204
+ );
1205
+ const hdrSqsPath = join(
1206
+ rootPath,
1207
+ 'app/src/generatedCode/FlowSchemas/GenOwn/source/GenOwn_HdrSqs.js'
1208
+ );
1209
+ const wbsMainPath = join(
1210
+ rootPath,
1211
+ 'app/src/generatedCode/FlowSchemas/GenOwn/source/GenOwn_WbsMain.js'
1212
+ );
1213
+ const hdrWbsPath = join(
1214
+ rootPath,
1215
+ 'app/src/generatedCode/FlowSchemas/GenOwn/source/GenOwn_HdrWbs.js'
1216
+ );
1217
+
1218
+ assert.match(await readFile(mainPath, 'utf8'), /asyncFlowSharedLib/);
1219
+ assert.match(await readFile(hdrSqsPath, 'utf8'), /GenOwn_Main/);
1220
+ assert.match(await readFile(wbsMainPath, 'utf8'), /GenOwn_WbsMain/);
1221
+ assert.match(await readFile(hdrWbsPath, 'utf8'), /GenOwn_WbsMain/);
1222
+
1223
+ const yaml = await readFile(
1224
+ join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'),
1225
+ 'utf8'
1226
+ );
1227
+ assert.match(yaml, /GenOwnHdrWbs:/);
1228
+ assert.match(yaml, /GenOwnHdrSqs:/);
1229
+ });
1230
+
1231
+ test('emits handler and YAML for flow with event generateCode and invocationType lambdaSyncInv', async () => {
1232
+ const rootPath = await mkdtemp(
1233
+ join(tmpdir(), 'generate-service-code-v2-custom-gen-sync-')
1234
+ );
1235
+ roots.add(rootPath);
1236
+ const schemaRoot = join(rootPath, 'app/src/schemas/FlowSchemas');
1237
+ await mkdir(schemaRoot, { recursive: true });
1238
+ await writeFile(
1239
+ join(schemaRoot, 'GenSync.js'),
1240
+ `export default {
1241
+ flowTag: 'genSync',
1242
+ event: ['generateCode'],
1243
+ generatedCodeConfig: {
1244
+ generateCodeTag: 'create',
1245
+ codeHookTag: 'before',
1246
+ invocationType: 'lambdaSyncInv'
1247
+ },
1248
+ flowSteps: [{ stepName: 'Start', properties: ['dummyId'] }],
1249
+ stepProperties: { dummyId: { type: 'string' } }
1250
+ };\n`
1251
+ );
1252
+
1253
+ await generateCustomFlowApplicationArtifacts(rootPath);
1254
+
1255
+ const mainPath = join(
1256
+ rootPath,
1257
+ 'app/src/generatedCode/FlowSchemas/GenSync/source/GenSync_Main.js'
1258
+ );
1259
+ const hdrInvPath = join(
1260
+ rootPath,
1261
+ 'app/src/generatedCode/FlowSchemas/GenSync/source/GenSync_HdrInv.js'
1262
+ );
1263
+
1264
+ assert.match(await readFile(mainPath, 'utf8'), /export default async function GenSync/);
1265
+ assert.match(await readFile(hdrInvPath, 'utf8'), /GenSync_Main/);
1266
+
1267
+ const yaml = await readFile(
1268
+ join(rootPath, 'app/sls_yaml/generatedCode/source/flow-schema.yml'),
1269
+ 'utf8'
1270
+ );
1271
+ assert.match(yaml, /GenSyncHdrInv:/);
1272
+ });
1273
+
@@ -197,7 +197,7 @@ test('uses CreateNodeCallback step when Graph storage is present with sync RBAC'
197
197
  'returnValue',
198
198
  'parentFlowId',
199
199
  'status',
200
- 'errorsFound',
200
+ 'foundErrors',
201
201
  'graphServiceTag'
202
202
  ]);
203
203
  });
@@ -237,7 +237,7 @@ test('chains Start and Complete for Update with RBAC and Graph', async () => {
237
237
  'returnValue',
238
238
  'parentFlowId',
239
239
  'status',
240
- 'errorsFound',
240
+ 'foundErrors',
241
241
  'graphServiceTag'
242
242
  ]);
243
243
  });
@@ -67,8 +67,36 @@ test('generates shared and object-specific RBAC flow schemas', async () => {
67
67
  properties: ['returnResult'],
68
68
  messageAttributes: []
69
69
  });
70
- assert.deepEqual(user.event, ['ownTopic']);
71
- assert.equal(user.steps, undefined);
70
+ assert.deepEqual(user.event, ['lambdaSyncInv', 'lambdaSyncApi']);
71
+ assert.equal(user.initiateBy, 'systemWithUser');
72
+ assert.deepEqual(user.stepProperties, {
73
+ parentFlowId: {
74
+ propertyName: 'parentFlowId',
75
+ type: 'string'
76
+ },
77
+ flowTypeConcat: {
78
+ propertyName: 'flowTypeConcat',
79
+ type: 'string'
80
+ },
81
+ parameterGroups: {
82
+ propertyName: 'parameterGroups',
83
+ type: 'object'
84
+ }
85
+ });
86
+ assert.deepEqual(user.stepMessageAttributes, {
87
+ submittedByUserId: {
88
+ propertyName: 'x-correlation-submitted-by-user-id',
89
+ type: 'string'
90
+ }
91
+ });
92
+ assert.deepEqual(user.flowSteps[0].properties, [
93
+ { key: 'parentFlowId', required: false },
94
+ { key: 'flowTypeConcat', required: true },
95
+ { key: 'parameterGroups', default: {} }
96
+ ]);
97
+ assert.deepEqual(user.flowSteps[0].messageAttributes, [
98
+ { key: 'submittedByUserId', required: false }
99
+ ]);
72
100
 
73
101
  const confirmUsage = await readGeneratedFlow(
74
102
  rootPath,
@@ -98,7 +126,7 @@ test('removes RBAC schemas when the last RBAC object is removed', async () => {
98
126
  await generateDynamicRbacFlowSchemas(rootPath, { serviceTag: 'UserAccount' });
99
127
  await writeFile(
100
128
  objectPath,
101
- "export default { objectType: 'user', addOnDataStructure: [] };\n"
129
+ "export default { objectType: 'user', generatedBy: 'user', fieldNames: { userId: { type: 'string', canUpdate: false, storageResourceTags: ['main'] } }, identifiers: [{ type: 'partitionKey', fieldName: 'userId' }], storageResources: { main: { storageType: 'dynamoDB', tableName: 'Users' } }, addOnDataStructure: [] };\n"
102
130
  );
103
131
 
104
132
  const result = await generateDynamicRbacFlowSchemas(rootPath);
@@ -160,7 +188,7 @@ async function createProject({ hasRbac = false } = {}) {
160
188
  await mkdir(objectDirectory, { recursive: true });
161
189
  await writeFile(
162
190
  join(objectDirectory, 'User.js'),
163
- `export default { objectType: 'user', fieldNames: [], identifiers: [], addOnDataStructure: ${hasRbac ? "[{ type: 'rbac' }]" : '[]'} };\n`
191
+ `export default { objectType: 'user', generatedBy: 'user', fieldNames: { userId: { type: 'string', canUpdate: false, storageResourceTags: ['main'] } }, identifiers: [{ type: 'partitionKey', fieldName: 'userId' }], storageResources: { main: { storageType: 'dynamoDB', tableName: 'Users' } }, addOnDataStructure: ${hasRbac ? "[{ type: 'rbac' }]" : '[]'} };\n`
164
192
  );
165
193
  return rootPath;
166
194
  }
@@ -115,7 +115,7 @@ test('emits relationship action and complete handlers with data-first function Y
115
115
  );
116
116
  assert.match(
117
117
  createCompleteContent,
118
- /const {\s*returnValue,\s*parentFlowId,\s*status,\s*errorsFound,\s*graphServiceTag\s*} = requestParams;/
118
+ /const {\s*returnValue,\s*parentFlowId,\s*status,\s*foundErrors,\s*graphServiceTag\s*} = requestParams;/
119
119
  );
120
120
  assert.doesNotMatch(
121
121
  createCompleteContent,
@@ -672,6 +672,105 @@ test('emits SQS queues and deduplicated IAM policies when generateCodeTag is an
672
672
  assert.strictEqual(notifyTopicMatches?.length, 1);
673
673
  });
674
674
 
675
+ test('rejects flow schema with event generateCode missing generatedCodeConfig', async () => {
676
+ const rootPath = await createProject();
677
+ const flowDirectory = join(rootPath, 'app/src/schemas/FlowSchemas');
678
+ await writeFile(
679
+ join(flowDirectory, 'MissingConfig.js'),
680
+ "export default { flowTag: 'missingConfig', event: ['generateCode'] };\n"
681
+ );
682
+
683
+ await assert.rejects(
684
+ generateResourceArtifacts(rootPath),
685
+ /flow with event 'generateCode' requires generatedCodeConfig/
686
+ );
687
+ });
688
+
689
+ test('rejects flow schema with event generateCode and invalid invocationType', async () => {
690
+ const rootPath = await createProject();
691
+ const flowDirectory = join(rootPath, 'app/src/schemas/FlowSchemas');
692
+ await writeFile(
693
+ join(flowDirectory, 'InvalidInvocation.js'),
694
+ "export default { flowTag: 'invalidInvocation', event: ['generateCode'], " +
695
+ "generatedCodeConfig: { invocationType: 'invalidType' } };\n"
696
+ );
697
+
698
+ await assert.rejects(
699
+ generateResourceArtifacts(rootPath),
700
+ /invocationType 'invalidType' is invalid/
701
+ );
702
+ });
703
+
704
+ test('emits SQS resources, SNS topics, and IAM role when flow has event generateCode with invocationType ownTopic', async () => {
705
+ const rootPath = await createProject();
706
+ const schemas = join(rootPath, 'app/src/schemas');
707
+ await writeFile(
708
+ join(schemas, 'FlowSchemas/GenOwnHook.js'),
709
+ "export default { flowTag: 'genOwnHook', event: ['generateCode'], " +
710
+ "generatedCodeConfig: { generateCodeTag: 'create', codeHookTag: 'before', " +
711
+ "invocationType: 'ownTopic' }, objType: { objectType: 'order' } };\n"
712
+ );
713
+ await generateResourceArtifacts(rootPath);
714
+
715
+ const crudResources = await readFile(
716
+ join(
717
+ rootPath,
718
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-crud.yml'
719
+ ),
720
+ 'utf8'
721
+ );
722
+ assert.match(crudResources, /^ CreateBeforeHookCallbackHdrSqs:/m);
723
+
724
+ const customResources = await readFile(
725
+ join(
726
+ rootPath,
727
+ 'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml'
728
+ ),
729
+ 'utf8'
730
+ );
731
+ assert.match(customResources, /^ GenOwnHookHdrSqs:/m);
732
+ assert.match(customResources, /^ InGenOwnHook:/m);
733
+
734
+ const iam = await readFile(
735
+ join(
736
+ rootPath,
737
+ 'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'
738
+ ),
739
+ 'utf8'
740
+ );
741
+ const flowRole = roleBlock(iam, 'FlowObjectsRole');
742
+ assert.match(flowRole, /CreateBeforeHookCallbackHdrSqs/);
743
+ assert.match(flowRole, /GenOwnHook_In/);
744
+
745
+ const customRole = roleBlock(iam, 'GenOwnHookRole');
746
+ assert.match(customRole, /GenOwnHookHdrSqs/);
747
+ assert.match(customRole, /GenOwnHook_In/);
748
+ });
749
+
750
+ test('emits lambda:InvokeFunction in FlowObjectsRole when flow has event generateCode with invocationType lambdaSyncInv', async () => {
751
+ const rootPath = await createProject();
752
+ const schemas = join(rootPath, 'app/src/schemas');
753
+ await writeFile(
754
+ join(schemas, 'FlowSchemas/GenSyncHook.js'),
755
+ "export default { flowTag: 'genSyncHook', event: ['generateCode'], " +
756
+ "generatedCodeConfig: { generateCodeTag: 'create', codeHookTag: 'before', " +
757
+ "invocationType: 'lambdaSyncInv' }, objType: { objectType: 'order' } };\n"
758
+ );
759
+ await generateResourceArtifacts(rootPath);
760
+
761
+ const iam = await readFile(
762
+ join(
763
+ rootPath,
764
+ 'app/sls_yaml/generatedCode/source/generate-shared-resource.yml'
765
+ ),
766
+ 'utf8'
767
+ );
768
+ const role = roleBlock(iam, 'FlowObjectsRole');
769
+ assert.match(role, /lambda:InvokeFunction/);
770
+ assert.match(role, /GenSyncHook/);
771
+ });
772
+
773
+
675
774
  function roleBlock(iam, roleName) {
676
775
  const match = iam.match(
677
776
  new RegExp(