@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 {
@@ -29,11 +29,11 @@ export async function emitRbacApplicationArtifacts(objects) {
29
29
  ...objects.filter(hasRbacAddOn).map(createUserRbacFlowHandler)
30
30
  ]);
31
31
  return [
32
- ...handlers.flatMap(handler => handler.artifacts),
32
+ ...handlers.flatMap((handler) => handler.artifacts),
33
33
  {
34
34
  path: FLOW_RBAC_YAML_PATH,
35
35
  content: handlers
36
- .flatMap(handler => handler.functions)
36
+ .flatMap((handler) => handler.functions)
37
37
  .map(renderFunctionYaml)
38
38
  .join('\n')
39
39
  }
@@ -109,7 +109,7 @@ export function rbacApplicationManagedPaths(objects = []) {
109
109
  `app/src/generatedCode/FlowRbac/${flowTag}/source/${flowTag}_WbsMain.js`,
110
110
  `app/src/generatedCode/FlowRbac/${flowTag}/source/${flowTag}_HdrWbs.js`
111
111
  ]),
112
- ...objects.filter(hasRbacAddOn).flatMap(object => {
112
+ ...objects.filter(hasRbacAddOn).flatMap((object) => {
113
113
  const flowTag = rbacFlowTag(object);
114
114
  const sourcePath = `app/src/generatedCode/FlowRbac/${flowTag}/source`;
115
115
  return [
@@ -124,7 +124,7 @@ export function rbacApplicationManagedPaths(objects = []) {
124
124
  function hasRbacAddOn(object) {
125
125
  return (
126
126
  Array.isArray(object?.addOnDataStructure) &&
127
- object.addOnDataStructure.some(addOn => addOn?.type === 'rbac')
127
+ object.addOnDataStructure.some((addOn) => addOn?.type === 'rbac')
128
128
  );
129
129
  }
130
130
 
@@ -362,7 +362,7 @@ function renderRbacTemplate(templateName, data = {}) {
362
362
  }
363
363
 
364
364
  async function renderTemplate(templateUrl, templateName, data) {
365
- return ejs.render(
365
+ return ejsLib.render(
366
366
  await readFile(new URL(templateName, templateUrl), 'utf8'),
367
367
  data
368
368
  );
@@ -11,9 +11,11 @@ export async function generateCreateTargetRoleHandler(rootPath, options = {}) {
11
11
  const project = compileProject({ ...options, rootPath });
12
12
  const objects = await loadLocalSchemaDirectory(project, 'ObjectSchemas');
13
13
  const artifacts = await emitRbacApplicationArtifacts(objects);
14
- const files = await commitArtifacts(buildGenerationPlan(project, artifacts, {
15
- managedPaths: rbacApplicationManagedPaths(),
16
- managedScope: 'rbac-application'
17
- }));
14
+ const files = await commitArtifacts(
15
+ buildGenerationPlan(project, artifacts, {
16
+ managedPaths: rbacApplicationManagedPaths(),
17
+ managedScope: 'rbac-application'
18
+ })
19
+ );
18
20
  return { project, files };
19
21
  }
@@ -12,8 +12,14 @@ export async function generateDynamicRbacFlowSchemas(rootPath, options = {}) {
12
12
  const objects = await loadLocalSchemaDirectory(project, 'ObjectSchemas');
13
13
  const plan = buildGenerationPlan(
14
14
  project,
15
- await emitDynamicRbacFlowSchemas({ objects, serviceTag: project.serviceTag }),
16
- { managedPaths: rbacFlowSchemaManagedPaths(objects), managedScope: 'rbac-flow-schemas' }
15
+ await emitDynamicRbacFlowSchemas({
16
+ objects,
17
+ serviceTag: project.serviceTag
18
+ }),
19
+ {
20
+ managedPaths: rbacFlowSchemaManagedPaths(objects),
21
+ managedScope: 'rbac-flow-schemas'
22
+ }
17
23
  );
18
24
  const files = await commitArtifacts(plan);
19
25
 
@@ -1,7 +1,9 @@
1
1
  export function rbacFlowTag(object) {
2
2
  const objectType = object?.objectType;
3
3
  if (typeof objectType !== 'string' || objectType.trim() === '') {
4
- throw new TypeError('RBAC ObjectSchema.objectType must be a non-empty string');
4
+ throw new TypeError(
5
+ 'RBAC ObjectSchema.objectType must be a non-empty string'
6
+ );
5
7
  }
6
8
  return `${objectType[0].toUpperCase()}${objectType.slice(1)}RbacFlow`;
7
9
  }
@@ -143,7 +143,7 @@ function _matchesParameterGroups(groups, input) {
143
143
  if (val && typeof val === 'object') {
144
144
  val = val[key];
145
145
  } else {
146
- val = undefined;
146
+ val = null;
147
147
  break;
148
148
  }
149
149
  }
@@ -1,5 +1,3 @@
1
- import { renderDynamicRelationshipFlowSchema } from './dynamicRelationshipFlowSchemaTemplate.js';
2
-
3
1
  const ACTIONS = [
4
2
  'CreateRelationship',
5
3
  'UpdateRelationship',
@@ -11,17 +9,33 @@ const ACTIONS = [
11
9
  const MESSAGE_ATTRIBUTES = ['userId', 'correlationId'];
12
10
 
13
11
  export const dynamicRelationshipFlowSchemaPaths = ACTIONS.map(
14
- action => `app/src/schemas/FlowSchemas/generateCode/FlowRelationship/${action}.js`
12
+ (action) =>
13
+ `app/src/schemas/FlowSchemas/generateCode/FlowRelationship/${action}.js`
15
14
  );
16
15
 
17
16
  export function emitDynamicRelationshipFlowSchemas() {
18
17
  // Keep legacy compatibility: relationship flow endpoints exist even before a relationship is declared.
19
18
  return ACTIONS.map((action, index) => ({
20
19
  path: dynamicRelationshipFlowSchemaPaths[index],
21
- content: renderDynamicRelationshipFlowSchema(action, createDynamicRelationshipFlow(action))
20
+ content: _renderDynamicRelationshipFlowSchema(
21
+ action,
22
+ createDynamicRelationshipFlow(action)
23
+ )
22
24
  }));
23
25
  }
24
26
 
27
+ function _renderDynamicRelationshipFlowSchema(action, flow) {
28
+ return [
29
+ '/**',
30
+ ' * GENERATED DYNAMIC RELATIONSHIP FLOW SCHEMA',
31
+ ` * Action: ${action}`,
32
+ ' * Description: Handles dynamic relationship actions for all allowed RelationshipTypes via SQS/DSQ',
33
+ ' */',
34
+ `export default ${JSON.stringify(flow, null, 2)};`,
35
+ ''
36
+ ].join('\n');
37
+ }
38
+
25
39
  function createDynamicRelationshipFlow(action) {
26
40
  const outputTopic = action !== 'GetRelationship';
27
41
  const flowSteps = [
@@ -29,12 +43,14 @@ function createDynamicRelationshipFlow(action) {
29
43
  stepName: 'start',
30
44
  properties: [],
31
45
  messageAttributes: MESSAGE_ATTRIBUTES,
32
- ...(outputTopic ? {
33
- returnValues: {
34
- properties: [],
35
- messageAttributes: MESSAGE_ATTRIBUTES
36
- }
37
- } : {})
46
+ ...(outputTopic
47
+ ? {
48
+ returnValues: {
49
+ properties: [],
50
+ messageAttributes: MESSAGE_ATTRIBUTES
51
+ }
52
+ }
53
+ : {})
38
54
  }
39
55
  ];
40
56
 
@@ -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 {
@@ -19,22 +19,36 @@ const ACTIONS = [
19
19
  const YAML_PATH = 'app/sls_yaml/generatedCode/source/flow-relationships.yml';
20
20
  const TEMPLATE_URL = new URL('./templates/', import.meta.url);
21
21
 
22
- export async function emitRelationshipApplicationArtifacts({ relationships, flows = [], serviceTag }) {
22
+ export async function emitRelationshipApplicationArtifacts({
23
+ relationships,
24
+ flows = [],
25
+ serviceTag
26
+ }) {
23
27
  if (!Array.isArray(relationships) || !Array.isArray(flows)) {
24
28
  throw new TypeError('relationships and flows must be arrays');
25
29
  }
26
30
  if (relationships.length === 0) return [];
27
31
 
28
- const handlers = await Promise.all(ACTIONS.map(action => emitAction(action, relationships, flows, serviceTag)));
32
+ const handlers = await Promise.all(
33
+ ACTIONS.map((action) =>
34
+ emitAction(action, relationships, flows, serviceTag)
35
+ )
36
+ );
29
37
  return [
30
- ...handlers.flatMap(handler => handler.artifacts),
31
- { path: YAML_PATH, content: handlers.flatMap(handler => handler.functions).map(renderFunction).join('\n') }
38
+ ...handlers.flatMap((handler) => handler.artifacts),
39
+ {
40
+ path: YAML_PATH,
41
+ content: handlers
42
+ .flatMap((handler) => handler.functions)
43
+ .map(renderFunction)
44
+ .join('\n')
45
+ }
32
46
  ];
33
47
  }
34
48
 
35
49
  export function relationshipApplicationManagedPaths() {
36
50
  return [
37
- ...ACTIONS.flatMap(action => {
51
+ ...ACTIONS.flatMap((action) => {
38
52
  const source = `app/src/generatedCode/FlowRelationships/${action}/source`;
39
53
  return [
40
54
  `${source}/${action}_Main.js`,
@@ -55,75 +69,200 @@ export function relationshipApplicationManagedPaths() {
55
69
  async function emitAction(action, relationships, flows, serviceTag) {
56
70
  const source = `app/src/generatedCode/FlowRelationships/${action}/source`;
57
71
  const handlerRoot = `src/generatedCode/FlowRelationships/${action}/source`;
58
- const flow = flows.find(candidate => candidate?.flowTag === action);
59
- const events = normalizeEvents(flow?.event, action === 'GetRelationship'
60
- ? ['lambdaSyncInv', 'lambdaSyncApi', 'dsq', 'ownTopic']
61
- : ['ownTopic']);
62
- const shared = { flowTag: action, flowStepName: '', mainFileName: `${action}_Main`, functionName: action, startConfig: null };
63
- const artifacts = [{ path: `${source}/${action}_Main.js`, content: await render(`${action}_Main.ejs`, { functionName: action, upperFunctionName: action }) }];
72
+ const flow = flows.find((candidate) => candidate?.flowTag === action);
73
+ const events = normalizeEvents(
74
+ flow?.event,
75
+ action === 'GetRelationship'
76
+ ? ['lambdaSyncInv', 'lambdaSyncApi', 'dsq', 'ownTopic']
77
+ : ['ownTopic']
78
+ );
79
+ const shared = {
80
+ flowTag: action,
81
+ flowStepName: '',
82
+ mainFileName: `${action}_Main`,
83
+ functionName: action,
84
+ startConfig: null
85
+ };
86
+ const artifacts = [
87
+ {
88
+ path: `${source}/${action}_Main.js`,
89
+ content: await render(`${action}_Main.ejs`, {
90
+ functionName: action,
91
+ upperFunctionName: action
92
+ })
93
+ }
94
+ ];
64
95
  const functions = [];
65
96
 
66
97
  if (events.includes('ownTopic')) {
67
98
  artifacts.push(
68
- { path: `${source}/${action}_WbsMain.js`, content: await renderShared('FlowMain_Wbs.ejs', { flowTag: action, upperCaseFlowTag: action, functionName: action }) },
69
- { path: `${source}/${action}_HdrWbs.js`, content: await renderShared('FlowEndpoint_HdrWbs.ejs', { flowTag: action, upperCaseFlowTag: action, functionName: action, mainFileName: `${action}_WbsMain`, route: action }) }
99
+ {
100
+ path: `${source}/${action}_WbsMain.js`,
101
+ content: await renderShared('FlowMain_Wbs.ejs', {
102
+ flowTag: action,
103
+ upperCaseFlowTag: action,
104
+ functionName: action
105
+ })
106
+ },
107
+ {
108
+ path: `${source}/${action}_HdrWbs.js`,
109
+ content: await renderShared('FlowEndpoint_HdrWbs.ejs', {
110
+ flowTag: action,
111
+ upperCaseFlowTag: action,
112
+ functionName: action,
113
+ mainFileName: `${action}_WbsMain`,
114
+ route: action
115
+ })
116
+ }
70
117
  );
71
- functions.push({ type: 'wbs', functionName: `${action}HdrWbs`, handlerPath: `${handlerRoot}/${action}_HdrWbs.main`, roleName: 'FlowRelationshipRole', routeName: action, flowTag: action, flowStepName: '' });
118
+ functions.push({
119
+ type: 'wbs',
120
+ functionName: `${action}HdrWbs`,
121
+ handlerPath: `${handlerRoot}/${action}_HdrWbs.main`,
122
+ roleName: 'FlowRelationshipRole',
123
+ routeName: action,
124
+ flowTag: action,
125
+ flowStepName: ''
126
+ });
72
127
  }
73
128
 
74
129
  for (const event of events) {
75
- const handler = eventHandler(event, action, handlerRoot, relationships, serviceTag);
130
+ const handler = eventHandler(
131
+ event,
132
+ action,
133
+ handlerRoot,
134
+ relationships,
135
+ serviceTag
136
+ );
76
137
  if (!handler) continue;
77
- artifacts.push({ path: `${source}/${handler.fileName}.js`, content: await render(handler.template, { ...shared, queueName: handler.queueName }) });
138
+ artifacts.push({
139
+ path: `${source}/${handler.fileName}.js`,
140
+ content: await render(handler.template, {
141
+ ...shared,
142
+ queueName: handler.queueName
143
+ })
144
+ });
78
145
  functions.push(handler.descriptor);
79
146
  }
80
147
 
81
148
  const complete = `${action}Complete`;
82
149
  artifacts.push(
83
- { path: `${source}/${complete}_Main.js`, content: await render(`${action}Complete_Main.ejs`, { functionName: complete, upperFunctionName: complete }) },
84
- { path: `${source}/${complete}_HdrSqs.js`, content: await renderShared('FlowHandler_HdrSqs.ejs', { ...shared, flowStepName: 'Complete', mainFileName: `${complete}_Main`, functionName: complete, queueName: `${complete}HdrSqs` }) }
150
+ {
151
+ path: `${source}/${complete}_Main.js`,
152
+ content: await render(`${action}Complete_Main.ejs`, {
153
+ functionName: complete,
154
+ upperFunctionName: complete
155
+ })
156
+ },
157
+ {
158
+ path: `${source}/${complete}_HdrSqs.js`,
159
+ content: await renderShared('FlowHandler_HdrSqs.ejs', {
160
+ ...shared,
161
+ flowStepName: 'Complete',
162
+ mainFileName: `${complete}_Main`,
163
+ functionName: complete,
164
+ queueName: `${complete}HdrSqs`
165
+ })
166
+ }
85
167
  );
86
- functions.push({ type: 'sqs', functionName: `${action}CompleteHdrSqs`, handlerPath: `${handlerRoot}/${complete}_HdrSqs.main`, roleName: 'FlowRelationshipRole', queueName: `${complete}HdrSqs`, flowTag: action, flowStepName: 'Complete' });
168
+ functions.push({
169
+ type: 'sqs',
170
+ functionName: `${action}CompleteHdrSqs`,
171
+ handlerPath: `${handlerRoot}/${complete}_HdrSqs.main`,
172
+ roleName: 'FlowRelationshipRole',
173
+ queueName: `${complete}HdrSqs`,
174
+ flowTag: action,
175
+ flowStepName: 'Complete'
176
+ });
87
177
  return { artifacts, functions };
88
178
  }
89
179
 
90
180
  function eventHandler(event, action, handlerRoot, relationships, serviceTag) {
91
181
  if (event === 'ownTopic' || event === 'extTopic') {
92
182
  return {
93
- fileName: `${action}_HdrSqs`, template: 'FlowHandler_HdrSqs.ejs', queueName: `${action}HdrSqs`,
94
- descriptor: { type: 'sqs', functionName: `${action.replace('Relationship', 'Rel')}HdrSqs`, handlerPath: `${handlerRoot}/${action}_HdrSqs.main`, roleName: 'FlowRelationshipRole', queueName: `${action}HdrSqs`, flowTag: action, flowStepName: '' }
183
+ fileName: `${action}_HdrSqs`,
184
+ template: 'FlowHandler_HdrSqs.ejs',
185
+ queueName: `${action}HdrSqs`,
186
+ descriptor: {
187
+ type: 'sqs',
188
+ functionName: `${action.replace('Relationship', 'Rel')}HdrSqs`,
189
+ handlerPath: `${handlerRoot}/${action}_HdrSqs.main`,
190
+ roleName: 'FlowRelationshipRole',
191
+ queueName: `${action}HdrSqs`,
192
+ flowTag: action,
193
+ flowStepName: ''
194
+ }
95
195
  };
96
196
  }
97
197
  if (event === 'dsq') {
98
198
  return {
99
- fileName: `${action}_HdrDsq`, template: 'FlowHandler_HdrDsq.ejs', queueName: `${action}HdrDsq`,
100
- descriptor: { type: 'sqs', functionName: `${action.replace('Relationship', 'Rel')}HdrDsq`, handlerPath: `${handlerRoot}/${action}_HdrDsq.main`, roleName: 'FlowRelationshipRole', queueName: `${action}HdrDsq`, flowTag: action, flowStepName: '' }
199
+ fileName: `${action}_HdrDsq`,
200
+ template: 'FlowHandler_HdrDsq.ejs',
201
+ queueName: `${action}HdrDsq`,
202
+ descriptor: {
203
+ type: 'sqs',
204
+ functionName: `${action.replace('Relationship', 'Rel')}HdrDsq`,
205
+ handlerPath: `${handlerRoot}/${action}_HdrDsq.main`,
206
+ roleName: 'FlowRelationshipRole',
207
+ queueName: `${action}HdrDsq`,
208
+ flowTag: action,
209
+ flowStepName: ''
210
+ }
101
211
  };
102
212
  }
103
213
  if (event === 'lambdaSyncInv') {
104
214
  return {
105
- fileName: `${action}_HdrInv`, template: 'FlowHandler_HdrInv.ejs',
106
- descriptor: { type: 'inv', functionName: `${action.replace('Relationship', 'Rel')}HdrInv`, handlerPath: `${handlerRoot}/${action}_HdrInv.main`, roleName: 'FlowRelationshipRole', flowTag: action, flowStepName: '' }
215
+ fileName: `${action}_HdrInv`,
216
+ template: 'FlowHandler_HdrInv.ejs',
217
+ descriptor: {
218
+ type: 'inv',
219
+ functionName: `${action.replace('Relationship', 'Rel')}HdrInv`,
220
+ handlerPath: `${handlerRoot}/${action}_HdrInv.main`,
221
+ roleName: 'FlowRelationshipRole',
222
+ flowTag: action,
223
+ flowStepName: ''
224
+ }
107
225
  };
108
226
  }
109
227
  if (event === 'lambdaSyncApi') {
110
228
  return {
111
- fileName: `${action}_HdrApi`, template: 'FlowHandler_HdrApi.ejs',
229
+ fileName: `${action}_HdrApi`,
230
+ template: 'FlowHandler_HdrApi.ejs',
112
231
  descriptor: {
113
- type: 'api', functionName: `${action.replace('Relationship', 'Rel')}HdrApi`, handlerPath: `${handlerRoot}/${action}_HdrApi.main`, roleName: 'FlowRelationshipRole',
114
- flowTag: action, flowStepName: '',
115
- routes: relationships.map(relationship => {
116
- const name = relationship.relationshipTag ?? Object.keys(relationship)[0];
117
- return { path: `/${serviceTag ?? '${self:custom.iz_serviceName}'}/${name}/${action.toLowerCase().replace('relationship', '')}`, upperName: upperFirst(name) };
232
+ type: 'api',
233
+ functionName: `${action.replace('Relationship', 'Rel')}HdrApi`,
234
+ handlerPath: `${handlerRoot}/${action}_HdrApi.main`,
235
+ roleName: 'FlowRelationshipRole',
236
+ flowTag: action,
237
+ flowStepName: '',
238
+ routes: relationships.map((relationship) => {
239
+ let name = Object.keys(relationship)[0];
240
+ if (relationship.relationshipTag) {
241
+ name = relationship.relationshipTag;
242
+ }
243
+ let targetServiceTag = '${self:custom.iz_serviceName}';
244
+ if (serviceTag) {
245
+ targetServiceTag = serviceTag;
246
+ }
247
+ return {
248
+ path: `/${targetServiceTag}/${name}/${action.toLowerCase().replace('relationship', '')}`,
249
+ upperName: upperFirst(name)
250
+ };
118
251
  })
119
252
  }
120
253
  };
121
254
  }
122
- return undefined;
255
+ return null;
123
256
  }
124
257
 
125
258
  function normalizeEvents(events, fallback) {
126
- return events === undefined ? fallback : (Array.isArray(events) ? events : [events]);
259
+ if (events === undefined) {
260
+ return fallback;
261
+ }
262
+ if (Array.isArray(events)) {
263
+ return events;
264
+ }
265
+ return [events];
127
266
  }
128
267
 
129
268
  function upperFirst(value) {
@@ -132,12 +271,15 @@ function upperFirst(value) {
132
271
 
133
272
  async function render(templateName, data) {
134
273
  const template = await readFile(new URL(templateName, TEMPLATE_URL), 'utf8');
135
- return ejs.render(template, data);
274
+ return ejsLib.render(template, data);
136
275
  }
137
276
 
138
277
  async function renderShared(templateName, data) {
139
- const template = await readFile(new URL(`../crud/templates/${templateName}`, import.meta.url), 'utf8');
140
- return ejs.render(template, data);
278
+ const template = await readFile(
279
+ new URL(`../crud/templates/${templateName}`, import.meta.url),
280
+ 'utf8'
281
+ );
282
+ return ejsLib.render(template, data);
141
283
  }
142
284
 
143
285
  function renderFunction(descriptor) {
@@ -7,7 +7,10 @@ import {
7
7
  emitDynamicRelationshipFlowSchemas
8
8
  } from './emitDynamicRelationshipFlowSchemas.js';
9
9
 
10
- export async function generateDynamicRelationshipFlowSchemas(rootPath, options = {}) {
10
+ export async function generateDynamicRelationshipFlowSchemas(
11
+ rootPath,
12
+ options = {}
13
+ ) {
11
14
  const project = compileProject({ ...options, rootPath });
12
15
  // The legacy generator creates these endpoints even with no relationships. Load now to
13
16
  // validate the V2 source-module contract before later slices consume relationship data.
@@ -15,7 +18,10 @@ export async function generateDynamicRelationshipFlowSchemas(rootPath, options =
15
18
  const plan = buildGenerationPlan(
16
19
  project,
17
20
  emitDynamicRelationshipFlowSchemas(),
18
- { managedPaths: dynamicRelationshipFlowSchemaPaths, managedScope: 'relationship-flow-schemas' }
21
+ {
22
+ managedPaths: dynamicRelationshipFlowSchemaPaths,
23
+ managedScope: 'relationship-flow-schemas'
24
+ }
19
25
  );
20
26
  const files = await commitArtifacts(plan);
21
27
 
@@ -7,16 +7,25 @@ import {
7
7
  relationshipApplicationManagedPaths
8
8
  } from './emitRelationshipApplicationArtifacts.js';
9
9
 
10
- export async function generateRelationshipApplicationArtifacts(rootPath, options = {}) {
10
+ export async function generateRelationshipApplicationArtifacts(
11
+ rootPath,
12
+ options = {}
13
+ ) {
11
14
  const project = compileProject({ ...options, rootPath });
12
15
  const [relationships, flows] = await Promise.all([
13
16
  loadLocalSchemaDirectory(project, 'RelationshipSchemas'),
14
17
  loadLocalSchemaDirectory(project, 'FlowSchemas')
15
18
  ]);
16
- const artifacts = await emitRelationshipApplicationArtifacts({ relationships, flows, serviceTag: project.serviceTag });
17
- const files = await commitArtifacts(buildGenerationPlan(project, artifacts, {
18
- managedPaths: relationshipApplicationManagedPaths(),
19
- managedScope: 'relationship-application'
20
- }));
19
+ const artifacts = await emitRelationshipApplicationArtifacts({
20
+ relationships,
21
+ flows,
22
+ serviceTag: project.serviceTag
23
+ });
24
+ const files = await commitArtifacts(
25
+ buildGenerationPlan(project, artifacts, {
26
+ managedPaths: relationshipApplicationManagedPaths(),
27
+ managedScope: 'relationship-application'
28
+ })
29
+ );
21
30
  return { project, files };
22
31
  }