@izara_project/izara-core-generate-service-code 1.0.68 → 1.0.69

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 (81) hide show
  1. package/package.json +1 -1
  2. package/scripts/format-ejs.js +1 -2
  3. package/src/compile/compileProject.js +26 -10
  4. package/src/compile/loadSchemas.js +47 -23
  5. package/src/emit/crud/emitCrudApplicationArtifacts.js +188 -41
  6. package/src/emit/crud/emitDynamicCrudFlowSchemas.js +34 -17
  7. package/src/emit/crud/generateCrudApplicationArtifacts.js +14 -6
  8. package/src/emit/crud/generateDynamicCrudFlowSchemas.js +4 -1
  9. package/src/emit/crud/templates/GetEndpoint_Main.ejs +1 -1
  10. package/src/emit/custom/customFlows.js +23 -13
  11. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +515 -113
  12. package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +28 -8
  13. package/src/emit/custom/templates/s3/FlowHandler_HdrS3.ejs +2 -2
  14. package/src/emit/custom/templates/s3/ReservedLimit_HdrSqs.ejs +1 -1
  15. package/src/emit/function/functionYamlArtifact.js +270 -97
  16. package/src/emit/function/templates/ApiFunction_Yaml.ejs +7 -0
  17. package/src/emit/function/templates/EventBridgeFunction_Yaml.ejs +6 -0
  18. package/src/emit/function/templates/InvFunction_Yaml.ejs +5 -0
  19. package/src/emit/function/templates/S3Function_Yaml.ejs +16 -0
  20. package/src/emit/function/templates/SqsFunction_Yaml.ejs +10 -0
  21. package/src/emit/function/templates/WbsFunction_Yaml.ejs +10 -0
  22. package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +28 -30
  23. package/src/emit/rbac/emitRbacApplicationArtifacts.js +6 -6
  24. package/src/emit/rbac/generateCreateTargetRoleHandler.js +6 -4
  25. package/src/emit/rbac/generateDynamicRbacFlowSchemas.js +8 -2
  26. package/src/emit/rbac/rbacFlowTag.js +3 -1
  27. package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +1 -1
  28. package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +26 -10
  29. package/src/emit/relationship/emitRelationshipApplicationArtifacts.js +179 -37
  30. package/src/emit/relationship/generateDynamicRelationshipFlowSchemas.js +8 -2
  31. package/src/emit/relationship/generateRelationshipApplicationArtifacts.js +15 -6
  32. package/src/emit/resource/emitResourceArtifacts.js +187 -114
  33. package/src/emit/resource/generateResourceArtifacts.js +15 -6
  34. package/src/emit/resource/templates/DynamoDBTable_Yaml.ejs +18 -18
  35. package/src/emit/resource/templates/FlowOut_Yaml.ejs +5 -5
  36. package/src/emit/resource/templates/GeneratedLambdaRoleServiceConfig.ejs +10 -9
  37. package/src/emit/resource/templates/ResourceBeforeLogicalYaml.ejs +44 -44
  38. package/src/emit/resource/templates/ResourceSqsYaml.ejs +36 -36
  39. package/src/emit/resource/templates/ResourceYaml.ejs +48 -48
  40. package/src/emit/resource/templates/S3Subscription_Yaml.ejs +7 -0
  41. package/src/emit/resource/templates/SharedResource_Yaml.ejs +11 -11
  42. package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +105 -105
  43. package/src/emit/resource/templates/WebSocketSubscription_Yaml.ejs +7 -0
  44. package/src/emit/system/emitSystemWebSocketArtifacts.js +61 -165
  45. package/src/emit/system/templates/WebSocketComplete_HdrSqs.ejs +32 -0
  46. package/src/emit/system/templates/WebSocketComplete_Main.ejs +46 -0
  47. package/src/emit/system/templates/WebSocketComplete_Yaml.ejs +19 -0
  48. package/src/emit/system/templates/WebSocketConnect.ejs +25 -0
  49. package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +11 -0
  50. package/src/generate.js +136 -33
  51. package/src/generateIntTest.js +76 -28
  52. package/src/generateResourceIntTest.js +35 -12
  53. package/src/generateResources/IntTest/generateResources/generateResources.js +5 -2
  54. package/src/generateResources/IntTest/generateResources/templateResources.ejs +18 -30
  55. package/src/generateResources/IntTest/generateTests/events/events.js +1 -1
  56. package/src/generateResources/IntTest/generateTests/events/templateEvents.ejs +13 -10
  57. package/src/generateResources/IntTest/generateTests/generateTemplate.js +2 -2
  58. package/src/generateResources/IntTest/generateTests/pathIntTest/pathIntTest.js +2 -1
  59. package/src/generateResources/IntTest/generateTests/pathIntTest/template.ejs +1 -3
  60. package/src/generateResources/IntTest/generateTests/tests/templateTests.ejs +1 -1
  61. package/src/generateResources/IntTest/generateTests/tests/tests.js +7 -3
  62. package/src/generateResources/IntTest/libs/{libs.js → IntTestGenerateLib.js} +34 -23
  63. package/src/generateResources/IntTest/upload/uploadIntTest.js +33 -19
  64. package/src/intTestGeneratorShared.js +15 -10
  65. package/src/output/commitArtifacts.js +99 -39
  66. package/src/output/mergeHooks.js +24 -10
  67. package/src/output/validateArtifacts.js +37 -27
  68. package/src/plan/buildGenerationPlan.js +24 -13
  69. package/test/core.test.js +116 -49
  70. package/test/createTargetRoleHandler.test.js +1 -1
  71. package/test/crudApplicationArtifacts.test.js +128 -23
  72. package/test/customFlowApplicationArtifacts.test.js +353 -71
  73. package/test/dynamicCrudFlowSchemas.test.js +74 -26
  74. package/test/dynamicRbacFlowSchemas.test.js +61 -14
  75. package/test/dynamicRelationshipFlowSchemas.test.js +65 -18
  76. package/test/functionYamlArtifact.test.js +67 -10
  77. package/test/intTestApi.test.js +9 -10
  78. package/test/publicApi.test.js +176 -34
  79. package/test/relationshipApplicationArtifacts.test.js +90 -19
  80. package/test/resourceArtifacts.test.js +172 -32
  81. package/src/emit/relationship/dynamicRelationshipFlowSchemaTemplate.js +0 -11
@@ -1,4 +1,4 @@
1
- import ejs from 'ejs';
1
+ import ejsLib from 'ejs';
2
2
  import { readFile } from 'node:fs/promises';
3
3
 
4
4
  import {
@@ -92,7 +92,7 @@ export async function emitResourceArtifacts({
92
92
  renderLambdaRoleConfig(state),
93
93
  renderS3(state)
94
94
  ]);
95
- return [
95
+ const artifacts = [
96
96
  {
97
97
  path: `${RESOURCE_ROOT}/generated-sns-in-sqs.yml`,
98
98
  content: normalizeYaml(inSqs)
@@ -105,10 +105,6 @@ export async function emitResourceArtifacts({
105
105
  path: `${RESOURCE_ROOT}/generated-dynamoDB-table.yml`,
106
106
  content: normalizeYaml(dynamo)
107
107
  },
108
- {
109
- path: `${RESOURCE_ROOT}/generated-s3.yml`,
110
- content: normalizeYaml(s3)
111
- },
112
108
  {
113
109
  path: `${APP_ROOT}/generate-shared-resource.yml`,
114
110
  content: normalizeYaml(iam)
@@ -118,6 +114,13 @@ export async function emitResourceArtifacts({
118
114
  content: lambdaRoleConfig
119
115
  }
120
116
  ];
117
+ if (state.s3Buckets.length > 0) {
118
+ artifacts.push({
119
+ path: `${RESOURCE_ROOT}/generated-s3.yml`,
120
+ content: normalizeYaml(s3)
121
+ });
122
+ }
123
+ return artifacts;
121
124
  }
122
125
 
123
126
  export const resourceArtifactPaths = [
@@ -134,62 +137,60 @@ function createResourceState({ objects, relationships, flows }) {
134
137
  const rbac = objects.some(hasRbacAddOn);
135
138
  const ownTopics = new Set(
136
139
  flows
137
- .filter(flow => includesEvent(flow, 'ownTopic'))
138
- .map(flow => upperFirst(flow.flowTag))
140
+ .filter((flow) => includesEvent(flow, 'ownTopic'))
141
+ .map((flow) => upperFirst(flow.flowTag))
139
142
  );
140
143
  const sqsQueues = new Set([
141
144
  ...LEGACY_PROCESS_QUEUES,
142
145
  ...flows
143
- .filter(flow => includesEvent(flow, 'extTopic'))
144
- .map(flow => `Process${upperFirst(flow.flowTag)}HdrSqs`)
146
+ .filter((flow) => includesEvent(flow, 'extTopic'))
147
+ .map((flow) => `Process${upperFirst(flow.flowTag)}HdrSqs`)
145
148
  ]);
146
- flowExtTopicSteps(flows).forEach(({ flowTag, stepName }) =>
147
- sqsQueues.add(`${flowTag}${stepName}HdrSqs`)
148
- );
149
- flows
150
- .filter(flow => includesEvent(flow, 's3'))
151
- .forEach(flow => {
152
- const tag = upperFirst(flow.flowTag);
153
- sqsQueues.add(`${tag}CreatePreSignUrlHdrSqs`);
154
- sqsQueues.add(`${tag}ReservedLimitHdrSqs`);
155
- sqsQueues.add(`${tag}ConfirmAfterUploadHdrSqs`);
156
- });
149
+ for (const { flowTag, stepName } of flowExtTopicSteps(flows)) {
150
+ sqsQueues.add(`${flowTag}${stepName}HdrSqs`);
151
+ }
152
+ for (const flow of flows.filter((flow) => includesEvent(flow, 's3'))) {
153
+ const tag = upperFirst(flow.flowTag);
154
+ sqsQueues.add(`${tag}CreatePreSignUrlHdrSqs`);
155
+ sqsQueues.add(`${tag}ReservedLimitHdrSqs`);
156
+ sqsQueues.add(`${tag}ConfirmAfterUploadHdrSqs`);
157
+ }
157
158
  const dsqQueues = new Set(
158
159
  flows
159
- .filter(flow => includesEvent(flow, 'dsq'))
160
- .map(flow => `${upperFirst(flow.flowTag)}HdrDsq`)
161
- );
162
- flowDsqSteps(flows).forEach(({ flowTag, stepName }) =>
163
- dsqQueues.add(`${flowTag}${stepName}HdrDsq`)
160
+ .filter((flow) => includesEvent(flow, 'dsq'))
161
+ .map((flow) => `${upperFirst(flow.flowTag)}HdrDsq`)
164
162
  );
163
+ for (const { flowTag, stepName } of flowDsqSteps(flows)) {
164
+ dsqQueues.add(`${flowTag}${stepName}HdrDsq`);
165
+ }
165
166
  if (crud) {
166
- CRUD_ACTIONS.forEach(action => ownTopics.add(action));
167
- ['Create', 'Update', 'Delete'].forEach(action =>
168
- sqsQueues.add(`${action}CompleteHdrSqs`)
169
- );
167
+ for (const action of CRUD_ACTIONS) {
168
+ ownTopics.add(action);
169
+ }
170
+ for (const action of ['Create', 'Update', 'Delete']) {
171
+ sqsQueues.add(`${action}CompleteHdrSqs`);
172
+ }
170
173
  }
171
174
  if (relationships.length > 0) {
172
- RELATIONSHIP_ACTIONS.forEach(action => {
175
+ for (const action of RELATIONSHIP_ACTIONS) {
173
176
  ownTopics.add(action);
174
177
  sqsQueues.add(`${action}CompleteHdrSqs`);
175
- });
178
+ }
176
179
  dsqQueues.add('GetRelationshipHdrDsq');
177
180
  }
178
181
  if (rbac) {
179
- RBAC_ACTIONS.forEach(action => {
182
+ for (const action of RBAC_ACTIONS) {
180
183
  ownTopics.add(action);
181
184
  sqsQueues.add(`Process${action}HdrSqs`);
182
- });
183
- objects
184
- .filter(hasRbacAddOn)
185
- .forEach(object => {
186
- const flowTag = upperFirst(object.objectType) + 'RbacFlow';
187
- ownTopics.add(flowTag);
188
- });
185
+ }
186
+ for (const object of objects.filter(hasRbacAddOn)) {
187
+ const flowTag = upperFirst(object.objectType) + 'RbacFlow';
188
+ ownTopics.add(flowTag);
189
+ }
189
190
  }
190
191
  const beforeLogicalByAction = new Map();
191
192
  for (const flow of flows.filter(
192
- flow => flow?.generatedCodeConfig?.codeHookTag === 'beforeLogical'
193
+ (flow) => flow?.generatedCodeConfig?.codeHookTag === 'beforeLogical'
193
194
  )) {
194
195
  const action = upperFirst(flow.generatedCodeConfig.generatedCodeTag);
195
196
  if (!action || !flow.flowTag) continue;
@@ -202,10 +203,10 @@ function createResourceState({ objects, relationships, flows }) {
202
203
  );
203
204
  const customRoles = [
204
205
  ...new Set([
205
- ...supportedCustomFlows(flows).map(flow =>
206
+ ...supportedCustomFlows(flows).map((flow) =>
206
207
  customFlowRoleName(flow.flowTag)
207
208
  ),
208
- ...generatedOwnTopicFlows(flows).map(flow =>
209
+ ...generatedOwnTopicFlows(flows).map((flow) =>
209
210
  customFlowRoleName(flow.flowTag)
210
211
  ),
211
212
  ...flowExtTopicSteps(flows).map(({ flow }) =>
@@ -217,21 +218,28 @@ function createResourceState({ objects, relationships, flows }) {
217
218
  const websocket = hasSystemWebSocket(flows, {
218
219
  includeRelationshipOwnTopic: true
219
220
  });
220
- const webSocketRoles = new Set(websocket ? ['WebSocketMainRole'] : []);
221
+ const webSocketRoles = new Set();
222
+ if (websocket) {
223
+ webSocketRoles.add('WebSocketMainRole');
224
+ }
221
225
  if (crud) webSocketRoles.add('FlowObjectsRole');
222
226
  if (relationships.length > 0) webSocketRoles.add('FlowRelationshipRole');
223
227
  if (rbac) webSocketRoles.add('FlowRbacRole');
224
- [...supportedCustomFlows(flows), ...generatedOwnTopicFlows(flows)]
225
- .filter(
226
- flow => includesEvent(flow, 'ownTopic') || includesEvent(flow, 's3')
227
- )
228
- .forEach(flow => webSocketRoles.add(customFlowRoleName(flow.flowTag)));
228
+ const filteredWsFlows = [
229
+ ...supportedCustomFlows(flows),
230
+ ...generatedOwnTopicFlows(flows)
231
+ ].filter(
232
+ (flow) => includesEvent(flow, 'ownTopic') || includesEvent(flow, 's3')
233
+ );
234
+ for (const flow of filteredWsFlows) {
235
+ webSocketRoles.add(customFlowRoleName(flow.flowTag));
236
+ }
229
237
  const outTopics = new Set([
230
238
  ...ownTopics,
231
239
  ...beforeLogical.map(({ action }) => action),
232
240
  ...flows
233
- .filter(flow => flow?.outputTopic && upperFirst(flow.flowTag))
234
- .map(flow => upperFirst(flow.flowTag))
241
+ .filter((flow) => flow?.outputTopic && upperFirst(flow.flowTag))
242
+ .map((flow) => upperFirst(flow.flowTag))
235
243
  ]);
236
244
  const objectTableNames = [...collectTables(objects).keys()];
237
245
  const relationshipTableNames = [...collectTables(relationships).keys()];
@@ -240,15 +248,36 @@ function createResourceState({ objects, relationships, flows }) {
240
248
  ...collectTables(relationships)
241
249
  ]);
242
250
  const externalDynamoTables = objects.flatMap(
243
- object => object.externalDynamoResources ?? []
251
+ (object) => object.externalDynamoResources ?? []
244
252
  );
245
253
  const s3Buckets = flows
246
- .filter(flow => includesEvent(flow, 's3') && flow.createBucket === true)
247
- .map(flow => flow.bucketName)
254
+ .filter((flow) => includesEvent(flow, 's3') && flow.createBucket === true)
255
+ .map((flow) => flow.bucketName)
248
256
  .filter(Boolean);
257
+ const s3FlowTags = flows
258
+ .filter((flow) => includesEvent(flow, 's3'))
259
+ .map((flow) => upperFirst(flow.flowTag));
260
+ const s3Subscriptions = flows
261
+ .filter((flow) => includesEvent(flow, 's3'))
262
+ .map((flow) => {
263
+ const tag = upperFirst(flow.flowTag);
264
+ const topicName = flow.outputTopic
265
+ ? flow.outputTopic.startsWith('Out')
266
+ ? flow.outputTopic
267
+ : `Out${upperFirst(flow.outputTopic)}`
268
+ : flow.s3Subscription?.topicName || 'OutCreate';
269
+ const queueName =
270
+ flow.s3Subscription?.queueName || `${tag}ReservedLimitHdrSqs`;
271
+ const subscriptionName =
272
+ flow.s3Subscription?.subscriptionName ||
273
+ `Subscription${topicName}To${queueName}`;
274
+ return { subscriptionName, topicName, queueName };
275
+ });
249
276
  return {
250
277
  crud,
251
278
  rbac,
279
+ s3Subscriptions,
280
+ s3FlowTags,
252
281
  relationships: relationships.length > 0,
253
282
  ownTopics: [...ownTopics].filter(Boolean).sort(),
254
283
  sqsQueues: [...sqsQueues].filter(Boolean).sort(),
@@ -260,9 +289,9 @@ function createResourceState({ objects, relationships, flows }) {
260
289
  webSocketSubscriptions: websocket
261
290
  ? [...outTopics]
262
291
  .filter(
263
- topic =>
292
+ (topic) =>
264
293
  flows.some(
265
- flow =>
294
+ (flow) =>
266
295
  (flow?.outputTopic ||
267
296
  (includesEvent(flow, 'ownTopic') &&
268
297
  flow.initiateBy === 'user')) &&
@@ -285,10 +314,10 @@ function createResourceState({ objects, relationships, flows }) {
285
314
  externalDynamoTables,
286
315
  objectTablesByType: new Map(
287
316
  objects
288
- .map(object => [
317
+ .map((object) => [
289
318
  object.objectType,
290
319
  Object.values(object.storageResources ?? {}).find(
291
- resource => resource?.storageType === 'dynamoDB'
320
+ (resource) => resource?.storageType === 'dynamoDB'
292
321
  )?.tableName
293
322
  ])
294
323
  .filter(([, tableName]) => tableName)
@@ -300,22 +329,25 @@ function createResourceState({ objects, relationships, flows }) {
300
329
 
301
330
  async function renderS3(state) {
302
331
  if (state.s3Buckets.length === 0) return 'Resources:';
303
- const template = await readFile(new URL('S3Bucket_Yaml.ejs', TEMPLATE_URL), 'utf8');
332
+ const template = await readFile(
333
+ new URL('S3Bucket_Yaml.ejs', TEMPLATE_URL),
334
+ 'utf8'
335
+ );
304
336
  const chunks = await Promise.all(
305
- state.s3Buckets.map(bucketName => ejs.render(template, { bucketName }))
337
+ state.s3Buckets.map((bucketName) => ejsLib.render(template, { bucketName }))
306
338
  );
307
339
  return `Resources:\n${chunks.join('\n')}`;
308
340
  }
309
341
 
310
342
  async function renderInSqs(state) {
311
343
  const chunks = await Promise.all([
312
- ...state.ownTopics.map(queueName =>
344
+ ...state.ownTopics.map((queueName) =>
313
345
  render('ResourceYaml.ejs', { queueName })
314
346
  ),
315
- ...state.sqsQueues.map(queueName =>
347
+ ...state.sqsQueues.map((queueName) =>
316
348
  render('ResourceSqsYaml.ejs', { queueName })
317
349
  ),
318
- ...state.dsqQueues.map(queueName =>
350
+ ...state.dsqQueues.map((queueName) =>
319
351
  render('ResourceSqsYaml.ejs', { queueName })
320
352
  ),
321
353
  ...state.beforeLogical.map(({ action, flowTags }) =>
@@ -332,17 +364,39 @@ async function renderInSqs(state) {
332
364
  ]
333
365
  : [])
334
366
  ]);
335
- return `Resources:\n${chunks.join('\n')}\n${state.webSocketSubscriptions.map(renderWebSocketSubscription).join('\n')}`;
367
+ const webSocketSubscriptions = await Promise.all(
368
+ state.webSocketSubscriptions.map((topicName) =>
369
+ renderWebSocketSubscription(topicName)
370
+ )
371
+ );
372
+ const s3Subscriptions = await Promise.all(
373
+ (state.s3Subscriptions ?? []).map(
374
+ ({ subscriptionName, topicName, queueName }) =>
375
+ render('S3Subscription_Yaml.ejs', {
376
+ subscriptionName,
377
+ topicName,
378
+ queueName
379
+ })
380
+ )
381
+ );
382
+ const parts = [chunks.join('\n')];
383
+ if (webSocketSubscriptions.length > 0) {
384
+ parts.push(webSocketSubscriptions.join('\n'));
385
+ }
386
+ if (s3Subscriptions.length > 0) {
387
+ parts.push(s3Subscriptions.join('\n'));
388
+ }
389
+ return `Resources:\n${parts.join('\n')}`;
336
390
  }
337
391
 
338
392
  async function renderOut(state) {
339
- return `Resources:\n${(await Promise.all(state.outTopics.map(topicName => render('FlowOut_Yaml.ejs', { topicName })))).join('\n')}`;
393
+ return `Resources:\n${(await Promise.all(state.outTopics.map((topicName) => render('FlowOut_Yaml.ejs', { topicName })))).join('\n')}`;
340
394
  }
341
395
 
342
396
  async function renderDynamo(state) {
343
397
  const [system, ...tables] = await Promise.all([
344
398
  render('SystemDynamoDB_Yaml.ejs', {}),
345
- ...state.tables.map(table => render('DynamoDBTable_Yaml.ejs', table))
399
+ ...state.tables.map((table) => render('DynamoDBTable_Yaml.ejs', table))
346
400
  ]);
347
401
  return `${system}\n${tables.join('\n')}`;
348
402
  }
@@ -355,7 +409,7 @@ async function renderIam(state) {
355
409
  if (state.websocket) roles.push('WebSocketMainRole');
356
410
  roles.push(...state.customRoles);
357
411
  return render('SharedResource_Yaml.ejs', {
358
- roles: roles.sort().map(roleName => ({
412
+ roles: roles.sort().map((roleName) => ({
359
413
  roleName,
360
414
  statements: roleStatements(state, roleName)
361
415
  }))
@@ -364,8 +418,8 @@ async function renderIam(state) {
364
418
 
365
419
  async function renderLambdaRoleConfig(state) {
366
420
  const s3Flows = state.flows
367
- .filter(flow => includesEvent(flow, 's3'))
368
- .map(flow => ({
421
+ .filter((flow) => includesEvent(flow, 's3'))
422
+ .map((flow) => ({
369
423
  roleName: upperFirst(flow.flowTag)
370
424
  }));
371
425
  return render('GeneratedLambdaRoleServiceConfig.ejs', {
@@ -385,14 +439,10 @@ function roleStatements(state, roleName) {
385
439
  ]
386
440
  });
387
441
  }
388
- addStatement(
389
- statements,
390
- dynamoActionsForRole(roleName),
391
- [
392
- ...dynamoArns(roleTableNames(state, roleName)),
393
- ...externalDynamoArns(roleExternalDynamoTables(state, roleName))
394
- ]
395
- );
442
+ addStatement(statements, dynamoActionsForRole(roleName), [
443
+ ...dynamoArns(roleTableNames(state, roleName)),
444
+ ...externalDynamoArns(roleExternalDynamoTables(state, roleName))
445
+ ]);
396
446
  addStatement(
397
447
  statements,
398
448
  SQS_CONSUMER_ACTIONS,
@@ -452,7 +502,7 @@ function roleTableNames(state, roleName) {
452
502
  'LogicalResultsData'
453
503
  ];
454
504
  const flow = state.flows.find(
455
- candidate => customFlowRoleName(candidate?.flowTag ?? '') === roleName
505
+ (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
456
506
  );
457
507
  if (!flow) return [];
458
508
  const tables = [];
@@ -477,68 +527,91 @@ function dynamoActionsForRole(roleName) {
477
527
  }
478
528
 
479
529
  function roleQueueNames(state, roleName) {
480
- if (roleName === 'ProcFindDataRole') return LEGACY_PROCESS_QUEUES;
481
- if (roleName === 'WebSocketMainRole')
482
- return state.websocket ? ['WebSocketCompleteHdrSqs'] : [];
483
- if (roleName === 'FlowObjectsRole')
530
+ if (roleName === 'ProcFindDataRole') {
531
+ return LEGACY_PROCESS_QUEUES;
532
+ }
533
+ if (roleName === 'WebSocketMainRole') {
534
+ if (state.websocket) {
535
+ return ['WebSocketCompleteHdrSqs'];
536
+ }
537
+ return [];
538
+ }
539
+ if (roleName === 'FlowObjectsRole') {
484
540
  return [
485
- ...CRUD_ACTIONS.map(action => `${action}HdrSqs`),
486
- ...CRUD_ACTIONS.filter(action => action !== 'Get').map(
487
- action => `${action}CompleteHdrSqs`
541
+ ...CRUD_ACTIONS.map((action) => `${action}HdrSqs`),
542
+ ...CRUD_ACTIONS.filter((action) => action !== 'Get').map(
543
+ (action) => `${action}CompleteHdrSqs`
488
544
  ),
489
545
  ...state.beforeLogical
490
546
  .filter(({ action }) => CRUD_ACTIONS.includes(action))
491
547
  .map(({ action }) => `${action}BeforeLogicalHdrSqs`)
492
548
  ];
493
- if (roleName === 'FlowRelationshipRole')
549
+ }
550
+ if (roleName === 'FlowRelationshipRole') {
494
551
  return [
495
- ...RELATIONSHIP_ACTIONS.flatMap(action => [
552
+ ...RELATIONSHIP_ACTIONS.flatMap((action) => [
496
553
  `${action}HdrSqs`,
497
554
  `${action}CompleteHdrSqs`
498
555
  ]),
499
556
  'GetRelationshipHdrDsq'
500
557
  ];
501
- if (roleName === 'FlowRbacRole')
502
- return RBAC_ACTIONS.flatMap(action => [
558
+ }
559
+ if (roleName === 'FlowRbacRole') {
560
+ return RBAC_ACTIONS.flatMap((action) => [
503
561
  `${action}HdrSqs`,
504
562
  `Process${action}HdrSqs`
505
563
  ]);
564
+ }
506
565
  const flow = state.flows.find(
507
- candidate => customFlowRoleName(candidate?.flowTag ?? '') === roleName
566
+ (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
508
567
  );
509
- if (!flow) return [];
568
+ if (!flow) {
569
+ return [];
570
+ }
510
571
  const tag = upperFirst(flow.flowTag);
511
- return [
512
- ...(includesEvent(flow, 'extTopic') ? [`${tag}HdrSqs`] : []),
513
- ...(includesEvent(flow, 'ownTopic') ? [`${tag}HdrSqs`] : []),
514
- ...(includesEvent(flow, 'dsq') ? [`${tag}HdrDsq`] : []),
572
+ const queueList = [];
573
+ if (includesEvent(flow, 'extTopic')) {
574
+ queueList.push(`${tag}HdrSqs`);
575
+ }
576
+ if (includesEvent(flow, 'ownTopic')) {
577
+ queueList.push(`${tag}HdrSqs`);
578
+ }
579
+ if (includesEvent(flow, 'dsq')) {
580
+ queueList.push(`${tag}HdrDsq`);
581
+ }
582
+ queueList.push(
515
583
  ...flowExtTopicSteps([flow]).map(
516
584
  ({ flowTag, stepName }) => `${flowTag}${stepName}HdrSqs`
517
- ),
585
+ )
586
+ );
587
+ queueList.push(
518
588
  ...flowDsqSteps([flow]).map(
519
589
  ({ flowTag, stepName }) => `${flowTag}${stepName}HdrDsq`
520
- ),
590
+ )
591
+ );
592
+ queueList.push(
521
593
  ...state.sqsQueues.filter(
522
- queueName => includesEvent(flow, 's3') && queueName.startsWith(tag)
594
+ (queueName) => includesEvent(flow, 's3') && queueName.startsWith(tag)
523
595
  )
524
- ];
596
+ );
597
+ return queueList;
525
598
  }
526
599
 
527
600
  function roleTopicNames(state, roleName) {
528
601
  if (roleName === 'ProcFindDataRole') return [];
529
602
  if (roleName === 'FlowObjectsRole')
530
- return state.outTopics.filter(topic => CRUD_ACTIONS.includes(topic));
603
+ return state.outTopics.filter((topic) => CRUD_ACTIONS.includes(topic));
531
604
  if (roleName === 'FlowRelationshipRole')
532
- return state.outTopics.filter(topic =>
605
+ return state.outTopics.filter((topic) =>
533
606
  RELATIONSHIP_ACTIONS.includes(topic)
534
607
  );
535
608
  if (roleName === 'FlowRbacRole')
536
- return state.outTopics.filter(topic => RBAC_ACTIONS.includes(topic));
609
+ return state.outTopics.filter((topic) => RBAC_ACTIONS.includes(topic));
537
610
  const flow = state.flows.find(
538
- candidate => customFlowRoleName(candidate?.flowTag ?? '') === roleName
611
+ (candidate) => customFlowRoleName(candidate?.flowTag ?? '') === roleName
539
612
  );
540
613
  return flow
541
- ? state.outTopics.filter(topic => topic === upperFirst(flow.flowTag))
614
+ ? state.outTopics.filter((topic) => topic === upperFirst(flow.flowTag))
542
615
  : [];
543
616
  }
544
617
 
@@ -546,7 +619,7 @@ function dynamoArns(tableNames) {
546
619
  return [...new Set(tableNames)]
547
620
  .sort()
548
621
  .map(
549
- tableName =>
622
+ (tableName) =>
550
623
  `arn:aws:dynamodb:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:table/${'${self:custom.iz_resourcePrefix}'}${tableName}`
551
624
  );
552
625
  }
@@ -601,7 +674,7 @@ function queueArns(queueNames) {
601
674
  return [...new Set(queueNames)]
602
675
  .sort()
603
676
  .map(
604
- queueName =>
677
+ (queueName) =>
605
678
  `arn:aws:sqs:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_resourcePrefix}'}${queueName}`
606
679
  );
607
680
  }
@@ -610,13 +683,13 @@ function topicArns(topicNames) {
610
683
  return [...new Set(topicNames)]
611
684
  .sort()
612
685
  .map(
613
- topic =>
686
+ (topic) =>
614
687
  `arn:aws:sns:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_serviceTag}'}_${'${self:custom.iz_stage}'}_${topic}_Out`
615
688
  );
616
689
  }
617
690
 
618
691
  function renderWebSocketSubscription(topicName) {
619
- return `##===== WebSocket completion subscription\n SubscriptionToOut${topicName}WebSocketComplete:\n Type: AWS::SNS::Subscription\n Properties:\n TopicArn: !Ref Out${topicName}\n Endpoint: "arn:aws:sqs:${'${self:custom.iz_region}'}:${'${self:custom.iz_accountId}'}:${'${self:custom.iz_resourcePrefix}'}WebSocketCompleteHdrSqs"\n Protocol: "sqs"`;
692
+ return render('WebSocketSubscription_Yaml.ejs', { topicName });
620
693
  }
621
694
 
622
695
  function collectTables(schemas) {
@@ -629,13 +702,13 @@ function collectTables(schemas) {
629
702
  const pk =
630
703
  keyName(
631
704
  identifiers.find(
632
- identifier =>
705
+ (identifier) =>
633
706
  identifier.type === 'partitionKey' ||
634
707
  identifier.type === 'identifier'
635
708
  )
636
709
  ) ?? 'PK';
637
710
  const sk = keyName(
638
- identifiers.find(identifier => identifier.type === 'sortKey')
711
+ identifiers.find((identifier) => identifier.type === 'sortKey')
639
712
  );
640
713
  for (const resource of Object.values(schema.storageResources)) {
641
714
  if (
@@ -650,13 +723,13 @@ function collectTables(schemas) {
650
723
  }
651
724
 
652
725
  function keyName(identifier) {
653
- if (!identifier) return undefined;
726
+ if (!identifier) return null;
654
727
  return (
655
728
  identifier.name ??
656
729
  identifier.fieldName ??
657
730
  (Array.isArray(identifier.fieldNames)
658
731
  ? identifier.fieldNames.join(identifier.deliminator ?? '_')
659
- : undefined)
732
+ : null)
660
733
  );
661
734
  }
662
735
 
@@ -669,7 +742,7 @@ function isCrudObject(object) {
669
742
  function hasRbacAddOn(object) {
670
743
  return (
671
744
  Array.isArray(object?.addOnDataStructure) &&
672
- object.addOnDataStructure.some(addOn => addOn?.type === 'rbac')
745
+ object.addOnDataStructure.some((addOn) => addOn?.type === 'rbac')
673
746
  );
674
747
  }
675
748
  function includesEvent(flow, event) {
@@ -684,7 +757,7 @@ function normalizeYaml(content) {
684
757
  return `${content.trimEnd()}\n`;
685
758
  }
686
759
  async function render(templateName, data) {
687
- return ejs.render(
760
+ return ejsLib.render(
688
761
  await readFile(new URL(templateName, TEMPLATE_URL), 'utf8'),
689
762
  { resourceQueueName: data.queueName, ...data }
690
763
  );
@@ -2,7 +2,10 @@ import { buildGenerationPlan } from '../../plan/buildGenerationPlan.js';
2
2
  import { commitArtifacts } from '../../output/commitArtifacts.js';
3
3
  import { compileProject } from '../../compile/compileProject.js';
4
4
  import { loadLocalSchemaDirectory } from '../../compile/loadSchemas.js';
5
- import { emitResourceArtifacts, resourceArtifactPaths } from './emitResourceArtifacts.js';
5
+ import {
6
+ emitResourceArtifacts,
7
+ resourceArtifactPaths
8
+ } from './emitResourceArtifacts.js';
6
9
 
7
10
  export async function generateResourceArtifacts(rootPath, options = {}) {
8
11
  const project = compileProject({ ...options, rootPath });
@@ -11,10 +14,16 @@ export async function generateResourceArtifacts(rootPath, options = {}) {
11
14
  loadLocalSchemaDirectory(project, 'RelationshipSchemas'),
12
15
  loadLocalSchemaDirectory(project, 'FlowSchemas')
13
16
  ]);
14
- const artifacts = await emitResourceArtifacts({ objects, relationships, flows });
15
- const files = await commitArtifacts(buildGenerationPlan(project, artifacts, {
16
- managedPaths: resourceArtifactPaths,
17
- managedScope: 'shared-resources'
18
- }));
17
+ const artifacts = await emitResourceArtifacts({
18
+ objects,
19
+ relationships,
20
+ flows
21
+ });
22
+ const files = await commitArtifacts(
23
+ buildGenerationPlan(project, artifacts, {
24
+ managedPaths: resourceArtifactPaths,
25
+ managedScope: 'shared-resources'
26
+ })
27
+ );
19
28
  return { project, files };
20
29
  }
@@ -1,20 +1,20 @@
1
1
  ##===== [DynamoDB Table: <%- tableName %>]
2
- <%- tableName %>Table:
3
- Type: AWS::DynamoDB::Table
4
- Properties:
5
- TableName: ${self:custom.iz_resourcePrefix}<%- tableName %>
6
- BillingMode: PAY_PER_REQUEST
7
- AttributeDefinitions:
8
- - AttributeName: '<%- pk %>'
9
- AttributeType: 'S'
10
- <% if (sk) { %>
11
- - AttributeName: '<%- sk %>'
12
- AttributeType: 'S'
13
- <% } %>
14
- KeySchema:
15
- - AttributeName: '<%- pk %>'
16
- KeyType: 'HASH'
17
- <% if (sk) { %>
18
- - AttributeName: '<%- sk %>'
19
- KeyType: 'RANGE'
2
+ <%- tableName %>Table:
3
+ Type: AWS::DynamoDB::Table
4
+ Properties:
5
+ TableName: ${self:custom.iz_resourcePrefix}<%- tableName %>
6
+ BillingMode: PAY_PER_REQUEST
7
+ AttributeDefinitions:
8
+ - AttributeName: "<%- pk %>"
9
+ AttributeType: "S"
10
+ <% if (sk) { %>
11
+ - AttributeName: "<%- sk %>"
12
+ AttributeType: "S"
13
+ <% } %>
14
+ KeySchema:
15
+ - AttributeName: "<%- pk %>"
16
+ KeyType: "HASH"
17
+ <% if (sk) { %>
18
+ - AttributeName: "<%- sk %>"
19
+ KeyType: "RANGE"
20
20
  <% } %>
@@ -1,6 +1,6 @@
1
1
  ##===== [Topic Out]
2
- Out<%- topicName %>:
3
- Type: AWS::SNS::Topic
4
- Properties:
5
- DisplayName: 'SNS Message out'
6
- TopicName: ${self:custom.iz_serviceTag}_${self:custom.iz_stage}_<%- topicName %>_Out
2
+ Out<%- topicName %>:
3
+ Type: AWS::SNS::Topic
4
+ Properties:
5
+ DisplayName: "SNS Message out"
6
+ TopicName: ${self:custom.iz_serviceTag}_${self:custom.iz_stage}_<%- topicName %>_Out