@izara_project/izara-core-generate-service-code 1.0.88 → 1.0.90
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 +1 -1
- package/src/compile/flowValidator.js +25 -0
- package/src/compile/loadSchemas.js +154 -0
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +3 -7
- package/src/emit/crud/crudActionPlan.js +67 -9
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +15 -32
- package/src/emit/crud/templates/CreateComplete_Main.ejs +135 -10
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +33 -27
- package/src/emit/crud/templates/CreateLogicalLib.ejs +282 -95
- package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +38 -21
- package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +118 -0
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +124 -10
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +26 -16
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +113 -4
- package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +120 -0
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +104 -10
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +34 -22
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +121 -4
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +8 -2
- package/src/emit/rbac/templates/CancelUsage_Main.ejs +34 -14
- package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +34 -14
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +20 -13
- package/src/emit/resource/emitResourceArtifacts.js +55 -14
- package/test/createTargetRoleHandler.test.js +11 -8
- package/test/crudApplicationArtifacts.test.js +440 -0
- package/test/dynamicCrudFlowSchemas.test.js +10 -5
- package/test/dynamicRbacFlowSchemas.test.js +24 -2
- package/test/graphDrivenFlowSchema.test.js +36 -0
- package/test/resourceArtifacts.test.js +113 -0
|
@@ -46,6 +46,30 @@ test('emits CRUD handlers and function YAML from schema data without reading gen
|
|
|
46
46
|
createMain,
|
|
47
47
|
/validateFieldNames\(_izContext, requestParams, objectSchemas, errorsFound\)/
|
|
48
48
|
);
|
|
49
|
+
assert.doesNotMatch(
|
|
50
|
+
createMain,
|
|
51
|
+
/const \{ createDataDetailsLib \} = dataDetailsLib;/
|
|
52
|
+
);
|
|
53
|
+
const createLogicalLib = await readFile(
|
|
54
|
+
join(
|
|
55
|
+
rootPath,
|
|
56
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateLogicalLib.js'
|
|
57
|
+
),
|
|
58
|
+
'utf8'
|
|
59
|
+
);
|
|
60
|
+
assert.match(
|
|
61
|
+
createLogicalLib,
|
|
62
|
+
/export async function resolveAndGenerateIdentifiers\(\s*_izContext,\s*requestParams,\s*objectSchema,\s*errorsFound\s*\)/
|
|
63
|
+
);
|
|
64
|
+
assert.match(createLogicalLib, /return \{\s*objectSchemas\s*\};/);
|
|
65
|
+
assert.match(
|
|
66
|
+
createLogicalLib,
|
|
67
|
+
/export function validateFieldNames\(\s*_izContext,\s*requestParams,\s*objectSchemas,\s*errorsFound\s*\)/
|
|
68
|
+
);
|
|
69
|
+
assert.doesNotMatch(
|
|
70
|
+
createLogicalLib,
|
|
71
|
+
/targetIdentifiers\.submittedByUserId\s*=/
|
|
72
|
+
);
|
|
49
73
|
assert.doesNotMatch(createMain, /FlowHook|beforeLogical|codeHookTag/);
|
|
50
74
|
const yaml = await readFile(
|
|
51
75
|
join(rootPath, 'app/sls_yaml/generatedCode/source/flow-objects.yml'),
|
|
@@ -277,6 +301,26 @@ test('emits Complete handlers and inlines sync RBAC for Update with Graph', asyn
|
|
|
277
301
|
);
|
|
278
302
|
});
|
|
279
303
|
|
|
304
|
+
test('omits CreateComplete_Main and CreateCompleteHdrSqs when hasCreateNodeCallback is true', async () => {
|
|
305
|
+
const rootPath = await createRbacProject(false, true);
|
|
306
|
+
const result = await generateCrudApplicationArtifacts(rootPath, {
|
|
307
|
+
serviceTag: 'orders'
|
|
308
|
+
});
|
|
309
|
+
const createPaths = result.files
|
|
310
|
+
.map((file) => file.path)
|
|
311
|
+
.filter((path) => path.includes('/FlowObjects/Create/source/'));
|
|
312
|
+
|
|
313
|
+
assert.ok(createPaths.includes(
|
|
314
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateNodeCallback_Main.js'
|
|
315
|
+
));
|
|
316
|
+
assert.ok(!createPaths.includes(
|
|
317
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateComplete_Main.js'
|
|
318
|
+
));
|
|
319
|
+
assert.ok(!createPaths.includes(
|
|
320
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateComplete_HdrSqs.js'
|
|
321
|
+
));
|
|
322
|
+
});
|
|
323
|
+
|
|
280
324
|
test('rejects deprecated FlowHook schemas', async () => {
|
|
281
325
|
const rootPath = await createRbacProject(true);
|
|
282
326
|
|
|
@@ -402,6 +446,22 @@ test('emits targetIdentifiers passed directly to checkRbacPermission options in
|
|
|
402
446
|
serviceTag: 'orders'
|
|
403
447
|
});
|
|
404
448
|
|
|
449
|
+
const createMain = await readFile(
|
|
450
|
+
join(
|
|
451
|
+
rootPath,
|
|
452
|
+
'app/src/generatedCode/FlowObjects/Create/source/Create_Main.js'
|
|
453
|
+
),
|
|
454
|
+
'utf8'
|
|
455
|
+
);
|
|
456
|
+
assert.match(
|
|
457
|
+
createMain,
|
|
458
|
+
/targetIdentifiers:\s*requestParams\.rbacTargetIdentifiers\s*\|\|\s*requestParams\.targetIdentifiers/
|
|
459
|
+
);
|
|
460
|
+
assert.doesNotMatch(
|
|
461
|
+
createMain,
|
|
462
|
+
/const\s*\{[^}]*targetIdentifiers[^}]*\}\s*=\s*await\s*resolveSchemaAndIdentity/
|
|
463
|
+
);
|
|
464
|
+
|
|
405
465
|
const updateMain = await readFile(
|
|
406
466
|
join(
|
|
407
467
|
rootPath,
|
|
@@ -581,6 +641,31 @@ test('emits async after-hook callback and SNS publish in CreateLogicalLib and fl
|
|
|
581
641
|
{ stdio: 'inherit' }
|
|
582
642
|
);
|
|
583
643
|
|
|
644
|
+
const createCompleteMain = await readFile(
|
|
645
|
+
join(
|
|
646
|
+
rootPath,
|
|
647
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateComplete_Main.js'
|
|
648
|
+
),
|
|
649
|
+
'utf8'
|
|
650
|
+
);
|
|
651
|
+
assert.match(
|
|
652
|
+
createCompleteMain,
|
|
653
|
+
/snsTopicArnByFlowSchema\(\s*_izContext,\s*'notifyAfterCreate_In'\s*\)/
|
|
654
|
+
);
|
|
655
|
+
assert.match(createCompleteMain, /CreateAfterHookCallbackHdrSqs/);
|
|
656
|
+
|
|
657
|
+
execFileSync(
|
|
658
|
+
process.execPath,
|
|
659
|
+
[
|
|
660
|
+
'--check',
|
|
661
|
+
join(
|
|
662
|
+
rootPath,
|
|
663
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateComplete_Main.js'
|
|
664
|
+
)
|
|
665
|
+
],
|
|
666
|
+
{ stdio: 'inherit' }
|
|
667
|
+
);
|
|
668
|
+
|
|
584
669
|
const yaml = await readFile(
|
|
585
670
|
join(rootPath, 'app/sls_yaml/generatedCode/source/flow-objects.yml'),
|
|
586
671
|
'utf8'
|
|
@@ -948,6 +1033,361 @@ test('emits sync before-hook in Delete_Main with abort check', async () => {
|
|
|
948
1033
|
);
|
|
949
1034
|
});
|
|
950
1035
|
|
|
1036
|
+
test('emits hooks across multiple endpoints when generateCodeTag is an array', async () => {
|
|
1037
|
+
const rootPath = await createProject(true);
|
|
1038
|
+
const schemas = join(rootPath, 'app/src/schemas');
|
|
1039
|
+
await writeFile(
|
|
1040
|
+
join(schemas, 'FlowSchemas/CheckOrderMulti.js'),
|
|
1041
|
+
"export default { flowTag: 'checkOrderMulti', event: ['lambdaSyncInv'], " +
|
|
1042
|
+
"generatedCodeConfig: { generateCodeTag: ['create', 'update'], " +
|
|
1043
|
+
"codeHookTag: 'before', invocationType: 'lambdaSyncInv' }, " +
|
|
1044
|
+
"objType: { objectType: 'order' } };\n"
|
|
1045
|
+
);
|
|
1046
|
+
await generateCrudApplicationArtifacts(rootPath, {
|
|
1047
|
+
serviceTag: 'orders'
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
const createMain = await readFile(
|
|
1051
|
+
join(
|
|
1052
|
+
rootPath,
|
|
1053
|
+
'app/src/generatedCode/FlowObjects/Create/source/Create_Main.js'
|
|
1054
|
+
),
|
|
1055
|
+
'utf8'
|
|
1056
|
+
);
|
|
1057
|
+
const updateMain = await readFile(
|
|
1058
|
+
join(
|
|
1059
|
+
rootPath,
|
|
1060
|
+
'app/src/generatedCode/FlowObjects/Update/source/Update_Main.js'
|
|
1061
|
+
),
|
|
1062
|
+
'utf8'
|
|
1063
|
+
);
|
|
1064
|
+
const deleteMain = await readFile(
|
|
1065
|
+
join(
|
|
1066
|
+
rootPath,
|
|
1067
|
+
'app/src/generatedCode/FlowObjects/Delete/source/Delete_Main.js'
|
|
1068
|
+
),
|
|
1069
|
+
'utf8'
|
|
1070
|
+
);
|
|
1071
|
+
|
|
1072
|
+
assert.match(createMain, /'checkOrderMulti'/);
|
|
1073
|
+
assert.match(updateMain, /'checkOrderMulti'/);
|
|
1074
|
+
assert.doesNotMatch(deleteMain, /'checkOrderMulti'/);
|
|
1075
|
+
});
|
|
1076
|
+
|
|
1077
|
+
test('emits ownTopic before-hook callbacks across multiple endpoints when generateCodeTag is an array', async () => {
|
|
1078
|
+
const rootPath = await createProject(true);
|
|
1079
|
+
const schemas = join(rootPath, 'app/src/schemas');
|
|
1080
|
+
await writeFile(
|
|
1081
|
+
join(schemas, 'FlowSchemas/ValidateOrderMulti.js'),
|
|
1082
|
+
"export default { flowTag: 'validateOrderMulti', event: ['ownTopic'], " +
|
|
1083
|
+
"generatedCodeConfig: { generateCodeTag: ['update', 'delete'], " +
|
|
1084
|
+
"codeHookTag: 'before', invocationType: 'ownTopic' }, " +
|
|
1085
|
+
"objType: { objectType: 'order' } };\n"
|
|
1086
|
+
);
|
|
1087
|
+
const result = await generateCrudApplicationArtifacts(rootPath, {
|
|
1088
|
+
serviceTag: 'orders'
|
|
1089
|
+
});
|
|
1090
|
+
|
|
1091
|
+
const updateCallbackExists = result.files.some((f) =>
|
|
1092
|
+
f.path.includes('UpdateBeforeHookCallback_Main.js')
|
|
1093
|
+
);
|
|
1094
|
+
const deleteCallbackExists = result.files.some((f) =>
|
|
1095
|
+
f.path.includes('DeleteBeforeHookCallback_Main.js')
|
|
1096
|
+
);
|
|
1097
|
+
const createCallbackExists = result.files.some((f) =>
|
|
1098
|
+
f.path.includes('CreateBeforeHookCallback_Main.js')
|
|
1099
|
+
);
|
|
1100
|
+
|
|
1101
|
+
assert.strictEqual(updateCallbackExists, true);
|
|
1102
|
+
assert.strictEqual(deleteCallbackExists, true);
|
|
1103
|
+
assert.strictEqual(createCallbackExists, false);
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
test('emits synchronous ConfirmUsage and CancelUsage invocation in CreateLogicalLib when object has rbac and graph', async () => {
|
|
1107
|
+
const rootPath = await createRbacProject(false, true);
|
|
1108
|
+
await generateCrudApplicationArtifacts(rootPath, { serviceTag: 'orders' });
|
|
1109
|
+
|
|
1110
|
+
const createLogicalLib = await readFile(
|
|
1111
|
+
join(
|
|
1112
|
+
rootPath,
|
|
1113
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateLogicalLib.js'
|
|
1114
|
+
),
|
|
1115
|
+
'utf8'
|
|
1116
|
+
);
|
|
1117
|
+
|
|
1118
|
+
assert.match(createLogicalLib, /ConfirmUsageHdrInv/);
|
|
1119
|
+
assert.match(createLogicalLib, /CancelUsageHdrInv/);
|
|
1120
|
+
assert.match(createLogicalLib, /lambda\.invokeSync\(/);
|
|
1121
|
+
assert.match(createLogicalLib, /publishCompletionMessage\(/);
|
|
1122
|
+
});
|
|
1123
|
+
|
|
1124
|
+
test('emits synchronous AfterHook invocation in Update and Delete handlers', async () => {
|
|
1125
|
+
const rootPath = await createProject(true);
|
|
1126
|
+
const schemas = join(rootPath, 'app/src/schemas');
|
|
1127
|
+
await writeFile(
|
|
1128
|
+
join(schemas, 'FlowSchemas/AuditOrderMulti.js'),
|
|
1129
|
+
"export default { flowTag: 'auditOrderMulti', event: ['lambdaSyncInv'], " +
|
|
1130
|
+
"generatedCodeConfig: { generateCodeTag: ['update', 'delete'], " +
|
|
1131
|
+
"codeHookTag: 'after', invocationType: 'lambdaSyncInv' }, " +
|
|
1132
|
+
"objType: { objectType: 'order' } };\n"
|
|
1133
|
+
);
|
|
1134
|
+
await generateCrudApplicationArtifacts(rootPath, {
|
|
1135
|
+
serviceTag: 'orders'
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
const updateComplete = await readFile(
|
|
1139
|
+
join(
|
|
1140
|
+
rootPath,
|
|
1141
|
+
'app/src/generatedCode/FlowObjects/Update/source/UpdateComplete_Main.js'
|
|
1142
|
+
),
|
|
1143
|
+
'utf8'
|
|
1144
|
+
);
|
|
1145
|
+
const updateLogicalLib = await readFile(
|
|
1146
|
+
join(
|
|
1147
|
+
rootPath,
|
|
1148
|
+
'app/src/generatedCode/FlowObjects/Update/source/UpdateLogicalLib.js'
|
|
1149
|
+
),
|
|
1150
|
+
'utf8'
|
|
1151
|
+
);
|
|
1152
|
+
const deleteComplete = await readFile(
|
|
1153
|
+
join(
|
|
1154
|
+
rootPath,
|
|
1155
|
+
'app/src/generatedCode/FlowObjects/Delete/source/DeleteComplete_Main.js'
|
|
1156
|
+
),
|
|
1157
|
+
'utf8'
|
|
1158
|
+
);
|
|
1159
|
+
const deleteLogicalLib = await readFile(
|
|
1160
|
+
join(
|
|
1161
|
+
rootPath,
|
|
1162
|
+
'app/src/generatedCode/FlowObjects/Delete/source/DeleteLogicalLib.js'
|
|
1163
|
+
),
|
|
1164
|
+
'utf8'
|
|
1165
|
+
);
|
|
1166
|
+
|
|
1167
|
+
assert.match(updateComplete, /'auditOrderMulti'/);
|
|
1168
|
+
assert.match(updateComplete, /lambda\.invokeSync\(/);
|
|
1169
|
+
assert.match(updateLogicalLib, /'auditOrderMulti'/);
|
|
1170
|
+
assert.match(updateLogicalLib, /lambda\.invokeSync\(/);
|
|
1171
|
+
assert.match(deleteComplete, /'auditOrderMulti'/);
|
|
1172
|
+
assert.match(deleteComplete, /lambda\.invokeSync\(/);
|
|
1173
|
+
assert.match(deleteLogicalLib, /'auditOrderMulti'/);
|
|
1174
|
+
assert.match(deleteLogicalLib, /lambda\.invokeSync\(/);
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
test('emits ownTopic after-hook callbacks and dispatch for update and delete', async () => {
|
|
1178
|
+
const rootPath = await createProject(true);
|
|
1179
|
+
const schemas = join(rootPath, 'app/src/schemas');
|
|
1180
|
+
await writeFile(
|
|
1181
|
+
join(schemas, 'FlowSchemas/NotifyOrderMulti.js'),
|
|
1182
|
+
"export default { flowTag: 'notifyOrderMulti', event: ['ownTopic'], " +
|
|
1183
|
+
"generatedCodeConfig: { generateCodeTag: ['update', 'delete'], " +
|
|
1184
|
+
"codeHookTag: 'after', invocationType: 'ownTopic' }, " +
|
|
1185
|
+
"objType: { objectType: 'order' } };\n"
|
|
1186
|
+
);
|
|
1187
|
+
const result = await generateCrudApplicationArtifacts(rootPath, {
|
|
1188
|
+
serviceTag: 'orders'
|
|
1189
|
+
});
|
|
1190
|
+
|
|
1191
|
+
const updateCallbackExists = result.files.some((f) =>
|
|
1192
|
+
f.path.includes('UpdateAfterHookCallback_Main.js')
|
|
1193
|
+
);
|
|
1194
|
+
const deleteCallbackExists = result.files.some((f) =>
|
|
1195
|
+
f.path.includes('DeleteAfterHookCallback_Main.js')
|
|
1196
|
+
);
|
|
1197
|
+
assert.strictEqual(updateCallbackExists, true);
|
|
1198
|
+
assert.strictEqual(deleteCallbackExists, true);
|
|
1199
|
+
|
|
1200
|
+
const updateComplete = await readFile(
|
|
1201
|
+
join(
|
|
1202
|
+
rootPath,
|
|
1203
|
+
'app/src/generatedCode/FlowObjects/Update/source/UpdateComplete_Main.js'
|
|
1204
|
+
),
|
|
1205
|
+
'utf8'
|
|
1206
|
+
);
|
|
1207
|
+
const updateLogicalLib = await readFile(
|
|
1208
|
+
join(
|
|
1209
|
+
rootPath,
|
|
1210
|
+
'app/src/generatedCode/FlowObjects/Update/source/UpdateLogicalLib.js'
|
|
1211
|
+
),
|
|
1212
|
+
'utf8'
|
|
1213
|
+
);
|
|
1214
|
+
const deleteComplete = await readFile(
|
|
1215
|
+
join(
|
|
1216
|
+
rootPath,
|
|
1217
|
+
'app/src/generatedCode/FlowObjects/Delete/source/DeleteComplete_Main.js'
|
|
1218
|
+
),
|
|
1219
|
+
'utf8'
|
|
1220
|
+
);
|
|
1221
|
+
const deleteLogicalLib = await readFile(
|
|
1222
|
+
join(
|
|
1223
|
+
rootPath,
|
|
1224
|
+
'app/src/generatedCode/FlowObjects/Delete/source/DeleteLogicalLib.js'
|
|
1225
|
+
),
|
|
1226
|
+
'utf8'
|
|
1227
|
+
);
|
|
1228
|
+
|
|
1229
|
+
assert.match(updateComplete, /'notifyOrderMulti_In'/);
|
|
1230
|
+
assert.match(updateComplete, /UpdateAfterHookCallbackHdrSqs/);
|
|
1231
|
+
assert.match(updateLogicalLib, /'notifyOrderMulti_In'/);
|
|
1232
|
+
assert.match(updateLogicalLib, /UpdateAfterHookCallbackHdrSqs/);
|
|
1233
|
+
assert.match(deleteComplete, /'notifyOrderMulti_In'/);
|
|
1234
|
+
assert.match(deleteComplete, /DeleteAfterHookCallbackHdrSqs/);
|
|
1235
|
+
assert.match(deleteLogicalLib, /'notifyOrderMulti_In'/);
|
|
1236
|
+
assert.match(deleteLogicalLib, /DeleteAfterHookCallbackHdrSqs/);
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
test('supports objType in generatedCodeConfig with string, array, and global hook', async () => {
|
|
1240
|
+
const rootPath = await createProject(true);
|
|
1241
|
+
const schemaRoot = join(rootPath, 'app/src/schemas');
|
|
1242
|
+
await writeFile(
|
|
1243
|
+
join(schemaRoot, 'ObjectSchemas/Cart.js'),
|
|
1244
|
+
"export default { objectType: 'cart', generatedBy: 'user' };\n"
|
|
1245
|
+
);
|
|
1246
|
+
await writeFile(
|
|
1247
|
+
join(schemaRoot, 'FlowSchemas/HookWithCustomObjType.js'),
|
|
1248
|
+
`export default {
|
|
1249
|
+
flowTag: 'hookWithCustomObj',
|
|
1250
|
+
objType: { objectType: 'rootAudit' },
|
|
1251
|
+
event: ['lambdaSyncInv'],
|
|
1252
|
+
generatedCodeConfig: {
|
|
1253
|
+
generateCodeTag: 'create',
|
|
1254
|
+
codeHookTag: 'before',
|
|
1255
|
+
invocationType: 'lambdaSyncInv',
|
|
1256
|
+
objType: 'cart'
|
|
1257
|
+
}
|
|
1258
|
+
};\n`
|
|
1259
|
+
);
|
|
1260
|
+
await writeFile(
|
|
1261
|
+
join(schemaRoot, 'FlowSchemas/HookWithMultiObjType.js'),
|
|
1262
|
+
`export default {
|
|
1263
|
+
flowTag: 'hookWithMultiObj',
|
|
1264
|
+
objType: { objectType: 'rootAudit' },
|
|
1265
|
+
event: ['ownTopic'],
|
|
1266
|
+
outputTopic: true,
|
|
1267
|
+
generatedCodeConfig: {
|
|
1268
|
+
generateCodeTag: 'update',
|
|
1269
|
+
codeHookTag: 'after',
|
|
1270
|
+
invocationType: 'ownTopic',
|
|
1271
|
+
objType: ['order', 'cart']
|
|
1272
|
+
}
|
|
1273
|
+
};\n`
|
|
1274
|
+
);
|
|
1275
|
+
await writeFile(
|
|
1276
|
+
join(schemaRoot, 'FlowSchemas/GlobalHook.js'),
|
|
1277
|
+
`export default {
|
|
1278
|
+
flowTag: 'globalDeleteHook',
|
|
1279
|
+
event: ['lambdaSyncInv'],
|
|
1280
|
+
generatedCodeConfig: {
|
|
1281
|
+
generateCodeTag: 'delete',
|
|
1282
|
+
codeHookTag: 'before',
|
|
1283
|
+
invocationType: 'lambdaSyncInv'
|
|
1284
|
+
}
|
|
1285
|
+
};\n`
|
|
1286
|
+
);
|
|
1287
|
+
|
|
1288
|
+
await generateCrudApplicationArtifacts(rootPath, {
|
|
1289
|
+
serviceTag: 'orders'
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
// 1. Before hook with custom objType 'cart' should be attached to cart, not rootAudit
|
|
1293
|
+
const createMain = await readFile(
|
|
1294
|
+
join(
|
|
1295
|
+
rootPath,
|
|
1296
|
+
'app/src/generatedCode/FlowObjects/Create/source/Create_Main.js'
|
|
1297
|
+
),
|
|
1298
|
+
'utf8'
|
|
1299
|
+
);
|
|
1300
|
+
assert.match(createMain, /if \(requestParams\.objectType === 'cart'\)/);
|
|
1301
|
+
assert.match(createMain, /hookPayload_hookWithCustomObj/);
|
|
1302
|
+
|
|
1303
|
+
// 2. After hook with multi objType ['order', 'cart'] should check array
|
|
1304
|
+
const updateComplete = await readFile(
|
|
1305
|
+
join(
|
|
1306
|
+
rootPath,
|
|
1307
|
+
'app/src/generatedCode/FlowObjects/Update/source/UpdateComplete_Main.js'
|
|
1308
|
+
),
|
|
1309
|
+
'utf8'
|
|
1310
|
+
);
|
|
1311
|
+
assert.match(updateComplete, /\["order","cart"\]\.includes/);
|
|
1312
|
+
assert.match(updateComplete, /hookPayload_hookWithMultiObj/);
|
|
1313
|
+
|
|
1314
|
+
// 3. Global delete hook without objType should be present
|
|
1315
|
+
const deleteMain = await readFile(
|
|
1316
|
+
join(
|
|
1317
|
+
rootPath,
|
|
1318
|
+
'app/src/generatedCode/FlowObjects/Delete/source/Delete_Main.js'
|
|
1319
|
+
),
|
|
1320
|
+
'utf8'
|
|
1321
|
+
);
|
|
1322
|
+
assert.match(deleteMain, /hookPayload_globalDeleteHook/);
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
test('omits autoProvisionOwnerTargetRole in CreateNodeCallback when service only has child RBAC objects', async () => {
|
|
1326
|
+
const rootPath = await createRbacProject(false, true);
|
|
1327
|
+
await generateCrudApplicationArtifacts(rootPath, {
|
|
1328
|
+
serviceTag: 'orders'
|
|
1329
|
+
});
|
|
1330
|
+
|
|
1331
|
+
const callbackMain = await readFile(
|
|
1332
|
+
join(
|
|
1333
|
+
rootPath,
|
|
1334
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateNodeCallback_Main.js'
|
|
1335
|
+
),
|
|
1336
|
+
'utf8'
|
|
1337
|
+
);
|
|
1338
|
+
assert.doesNotMatch(callbackMain, /autoProvisionOwnerTargetRole\(_izContext/);
|
|
1339
|
+
|
|
1340
|
+
const logicalLib = await readFile(
|
|
1341
|
+
join(
|
|
1342
|
+
rootPath,
|
|
1343
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateLogicalLib.js'
|
|
1344
|
+
),
|
|
1345
|
+
'utf8'
|
|
1346
|
+
);
|
|
1347
|
+
assert.match(logicalLib, /const ROOT_RBAC_OBJECT_TYPES = new Set\(\[\s*\]\);/);
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
test('emits autoProvisionOwnerTargetRole in CreateNodeCallback when service has root RBAC object', async () => {
|
|
1351
|
+
const rootPath = await mkdtemp(
|
|
1352
|
+
join(tmpdir(), 'generate-service-code-v2-crud-root-rbac-')
|
|
1353
|
+
);
|
|
1354
|
+
roots.add(rootPath);
|
|
1355
|
+
const schemaRoot = join(rootPath, 'app/src/schemas');
|
|
1356
|
+
await mkdir(join(schemaRoot, 'ObjectSchemas'), { recursive: true });
|
|
1357
|
+
await mkdir(join(schemaRoot, 'FlowSchemas'), { recursive: true });
|
|
1358
|
+
await writeFile(
|
|
1359
|
+
join(schemaRoot, 'ObjectSchemas/Workspace.js'),
|
|
1360
|
+
"export default { objectType: 'workspace', generatedBy: 'user', addOnDataStructure: [{ type: 'rbac' }], storageResources: { graph: { storageType: 'graph' } } };\n"
|
|
1361
|
+
);
|
|
1362
|
+
await generateCrudApplicationArtifacts(rootPath, {
|
|
1363
|
+
serviceTag: 'workspaces'
|
|
1364
|
+
});
|
|
1365
|
+
|
|
1366
|
+
const callbackMain = await readFile(
|
|
1367
|
+
join(
|
|
1368
|
+
rootPath,
|
|
1369
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateNodeCallback_Main.js'
|
|
1370
|
+
),
|
|
1371
|
+
'utf8'
|
|
1372
|
+
);
|
|
1373
|
+
assert.match(
|
|
1374
|
+
callbackMain,
|
|
1375
|
+
/await autoProvisionOwnerTargetRole\(_izContext,\s*\{\s*node,\s*submittedByUserId,\s*objType: returnValue\?\.requestParams\?\.objType\s*\}\);/
|
|
1376
|
+
);
|
|
1377
|
+
|
|
1378
|
+
const logicalLib = await readFile(
|
|
1379
|
+
join(
|
|
1380
|
+
rootPath,
|
|
1381
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateLogicalLib.js'
|
|
1382
|
+
),
|
|
1383
|
+
'utf8'
|
|
1384
|
+
);
|
|
1385
|
+
assert.match(
|
|
1386
|
+
logicalLib,
|
|
1387
|
+
/const ROOT_RBAC_OBJECT_TYPES = new Set\(\[\s*'workspace',\s*\]\);/
|
|
1388
|
+
);
|
|
1389
|
+
});
|
|
1390
|
+
|
|
951
1391
|
async function createProject(withCrudObject) {
|
|
952
1392
|
const rootPath = await mkdtemp(
|
|
953
1393
|
join(tmpdir(), 'generate-service-code-v2-crud-application-')
|
|
@@ -142,7 +142,7 @@ test('generates a direct Complete step for RBAC-only Update flows', async () =>
|
|
|
142
142
|
assert.equal(update.flowSteps[1].properties.length, 0);
|
|
143
143
|
});
|
|
144
144
|
|
|
145
|
-
test('generates CreateNodeCallback
|
|
145
|
+
test('generates CreateNodeCallback for Create when RBAC and Graph are present', async () => {
|
|
146
146
|
const rootPath = await createProject({
|
|
147
147
|
generatedBy: 'user',
|
|
148
148
|
});
|
|
@@ -160,8 +160,14 @@ test('generates CreateNodeCallback and Complete for Create when RBAC and Graph a
|
|
|
160
160
|
const create = await readGeneratedFlow(rootPath, 'Create');
|
|
161
161
|
assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
|
|
162
162
|
'Start',
|
|
163
|
-
'CreateNodeCallback'
|
|
164
|
-
|
|
163
|
+
'CreateNodeCallback'
|
|
164
|
+
]);
|
|
165
|
+
assert.deepEqual(create.flowSteps[1].nextSteps, [
|
|
166
|
+
{
|
|
167
|
+
targetType: 'lambdaSyncInv',
|
|
168
|
+
serviceTag: 'Rbac',
|
|
169
|
+
functionName: 'ConfirmUsageHdrInv'
|
|
170
|
+
}
|
|
165
171
|
]);
|
|
166
172
|
});
|
|
167
173
|
|
|
@@ -185,8 +191,7 @@ test('uses CreateNodeCallback step when Graph storage is present with sync RBAC'
|
|
|
185
191
|
const create = await readGeneratedFlow(rootPath, 'Create');
|
|
186
192
|
assert.deepEqual(create.flowSteps.map((step) => step.stepName), [
|
|
187
193
|
'Start',
|
|
188
|
-
'CreateNodeCallback'
|
|
189
|
-
'Complete'
|
|
194
|
+
'CreateNodeCallback'
|
|
190
195
|
]);
|
|
191
196
|
assert.deepEqual(create.flowSteps[1].properties, [
|
|
192
197
|
'returnValue',
|
|
@@ -69,6 +69,27 @@ test('generates shared and object-specific RBAC flow schemas', async () => {
|
|
|
69
69
|
});
|
|
70
70
|
assert.deepEqual(user.event, ['ownTopic']);
|
|
71
71
|
assert.equal(user.steps, undefined);
|
|
72
|
+
|
|
73
|
+
const confirmUsage = await readGeneratedFlow(
|
|
74
|
+
rootPath,
|
|
75
|
+
'ConfirmUsage',
|
|
76
|
+
'FlowLimit'
|
|
77
|
+
);
|
|
78
|
+
const cancelUsage = await readGeneratedFlow(
|
|
79
|
+
rootPath,
|
|
80
|
+
'CancelUsage',
|
|
81
|
+
'FlowLimit'
|
|
82
|
+
);
|
|
83
|
+
assert.deepEqual(confirmUsage.event, [
|
|
84
|
+
'ownTopic',
|
|
85
|
+
'lambdaSyncInv',
|
|
86
|
+
'lambdaSyncApi'
|
|
87
|
+
]);
|
|
88
|
+
assert.deepEqual(cancelUsage.event, [
|
|
89
|
+
'ownTopic',
|
|
90
|
+
'lambdaSyncInv',
|
|
91
|
+
'lambdaSyncApi'
|
|
92
|
+
]);
|
|
72
93
|
});
|
|
73
94
|
|
|
74
95
|
test('removes RBAC schemas when the last RBAC object is removed', async () => {
|
|
@@ -144,10 +165,11 @@ async function createProject({ hasRbac = false } = {}) {
|
|
|
144
165
|
return rootPath;
|
|
145
166
|
}
|
|
146
167
|
|
|
147
|
-
async function readGeneratedFlow(rootPath, flowTag) {
|
|
168
|
+
async function readGeneratedFlow(rootPath, flowTag, folder = 'FlowRbac') {
|
|
148
169
|
const filePath = join(
|
|
149
170
|
rootPath,
|
|
150
|
-
'app/src/schemas/FlowSchemas/generateCode
|
|
171
|
+
'app/src/schemas/FlowSchemas/generateCode',
|
|
172
|
+
folder,
|
|
151
173
|
`${flowTag}.js`
|
|
152
174
|
);
|
|
153
175
|
const module = await import(
|
|
@@ -255,3 +255,39 @@ test('validateFlowSchema rejects lambdaSyncInv nextSteps missing functionName',
|
|
|
255
255
|
/lambdaSyncInv target requires non-empty 'functionName'/
|
|
256
256
|
);
|
|
257
257
|
});
|
|
258
|
+
|
|
259
|
+
test('validateFlowSchema passes for mixed sync and async events with single Start step', () => {
|
|
260
|
+
const mixedSingleStepSchema = {
|
|
261
|
+
flowTag: 'ConfirmUsage',
|
|
262
|
+
event: ['ownTopic', 'lambdaSyncInv', 'lambdaSyncApi'],
|
|
263
|
+
flowSteps: [
|
|
264
|
+
{
|
|
265
|
+
stepName: 'Start'
|
|
266
|
+
}
|
|
267
|
+
]
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
assert.equal(validateFlowSchema(mixedSingleStepSchema), true);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
test('validateFlowSchema rejects flow with synchronous events having multiple flowSteps', () => {
|
|
274
|
+
const mixedMultiStepSchema = {
|
|
275
|
+
flowTag: 'ConfirmUsage',
|
|
276
|
+
event: ['ownTopic', 'lambdaSyncInv'],
|
|
277
|
+
flowSteps: [
|
|
278
|
+
{
|
|
279
|
+
stepName: 'Start',
|
|
280
|
+
nextSteps: [{ targetType: 'ownTopic', stepName: 'StepTwo' }]
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
stepName: 'StepTwo',
|
|
284
|
+
previousSteps: [{ sourceType: 'ownTopic', stepName: 'Start' }]
|
|
285
|
+
}
|
|
286
|
+
]
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
assert.throws(
|
|
290
|
+
() => validateFlowSchema(mixedMultiStepSchema),
|
|
291
|
+
/Flow 'ConfirmUsage' with synchronous events .* must only define a single entry step 'Start'/
|
|
292
|
+
);
|
|
293
|
+
});
|