@izara_project/izara-core-generate-service-code 1.0.60 → 1.0.61
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 +7 -3
- package/src/codeGenerators/app/initial_setup/InitialSetupGenerator.js +7 -7
- package/src/codeGenerators/app/sls_yaml/FunctionYamlGenerator.js +4 -5
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowObjects/EndpointsGenerator.js +3 -2
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowRbac/RbacFlowGenerator.js +4 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowRelationships/RelationshipFlowGenerator.js +2 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/BaseDsqHandler.js +64 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/BaseSqsHandler.js +9 -9
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/__tests__/BaseDsqHandler.test.js +93 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/dsq.js +5 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/lambdaSyncApi.js +9 -9
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/lambdaSyncInv.js +9 -9
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/registry.js +3 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrApi.ejs +3 -3
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrDsq.ejs +129 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrInv.ejs +3 -3
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrSqs.ejs +15 -8
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/eventTypes.js +2 -2
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowEntryPointBase.js +1 -0
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowMainFunctionBase.js +11 -11
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowSelection.js +0 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepBase.js +3 -2
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepNormalizer.js +47 -1
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowValidator.js +13 -15
- package/src/codeGenerators/app/src/generatedCode/libs/templates/Consts.ejs +10 -10
- package/src/codeGenerators/resource/sls_yaml/FlowResourceYamlGenerator.js +2 -2
- package/src/generateCode.js +69 -24
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicFlowSchemaTemplate.ejs +3 -3
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicRbacFlowSchemaTemplate.ejs +1 -1
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/RelationshipFlowSchemaTemplate.ejs +2 -2
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/UserRbacFlowSchemaTemplate.ejs +1 -1
- package/test_generate.js +7 -0
- package/test_normalize.js +17 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@izara_project/izara-core-generate-service-code",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.61",
|
|
4
4
|
"description": "Code for locally generating per service files",
|
|
5
5
|
"homepage": "https://bitbucket.org/izara-core-support-services/izara-core-support-services-generate-service-code#readme",
|
|
6
6
|
"repository": {
|
|
@@ -22,15 +22,19 @@
|
|
|
22
22
|
"@izara_project/izara-core-library-core": "^1.0.32",
|
|
23
23
|
"@izara_project/izara-core-library-logger": "^1.0.9",
|
|
24
24
|
"@izara_project/izara-core-library-s3": "^1.0.10",
|
|
25
|
-
"@izara_project/izara-core-library-service-schemas": "^1.0.155",
|
|
26
25
|
"@izara_project/izara-property-nodes": "^1.0.16",
|
|
27
26
|
"@izara_project/izara-shared-core": "^1.0.12",
|
|
28
|
-
"@izara_project/izara-shared-service-schemas": "^1.0.64",
|
|
29
27
|
"ejs": "^5.0.1",
|
|
30
28
|
"js-beautify": "^1.15.4",
|
|
31
29
|
"yaml": "^2.9.0"
|
|
32
30
|
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"@izara_project/izara-core-library-service-schemas": "^1.0.157",
|
|
33
|
+
"@izara_project/izara-shared-service-schemas": "^1.0.65"
|
|
34
|
+
},
|
|
33
35
|
"devDependencies": {
|
|
36
|
+
"@izara_project/izara-core-library-service-schemas": "^1.0.157",
|
|
37
|
+
"@izara_project/izara-shared-service-schemas": "^1.0.65",
|
|
34
38
|
"jest": "^30.4.2"
|
|
35
39
|
}
|
|
36
40
|
}
|
|
@@ -98,37 +98,37 @@ export async function generateInitialSetup(allSchemas, options) {
|
|
|
98
98
|
{
|
|
99
99
|
serviceTag: 'GraphHandler',
|
|
100
100
|
topicName: 'UpdateRelationship_Out',
|
|
101
|
-
sqsEndpoint: '
|
|
101
|
+
sqsEndpoint: 'UpdateRelationshipCompleteHdrSqs'
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
serviceTag: 'GraphHandler',
|
|
105
105
|
topicName: 'CreateRelationship_Out',
|
|
106
|
-
sqsEndpoint: '
|
|
106
|
+
sqsEndpoint: 'CreateRelationshipCompleteHdrSqs'
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
109
|
serviceTag: 'GraphHandler',
|
|
110
110
|
topicName: 'DeleteRelationship_Out',
|
|
111
|
-
sqsEndpoint: '
|
|
111
|
+
sqsEndpoint: 'DeleteRelationshipCompleteHdrSqs'
|
|
112
112
|
},
|
|
113
113
|
{
|
|
114
114
|
serviceTag: 'GraphHandler',
|
|
115
115
|
topicName: 'UpdateNode_Out',
|
|
116
|
-
sqsEndpoint: '
|
|
116
|
+
sqsEndpoint: 'UpdateCompleteHdrSqs'
|
|
117
117
|
},
|
|
118
118
|
{
|
|
119
119
|
serviceTag: 'GraphHandler',
|
|
120
120
|
topicName: 'CreateNode_Out',
|
|
121
|
-
sqsEndpoint: '
|
|
121
|
+
sqsEndpoint: 'CreateCompleteHdrSqs'
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
serviceTag: 'GraphHandler',
|
|
125
125
|
topicName: 'ChangeRelationshipType_Out',
|
|
126
|
-
sqsEndpoint: '
|
|
126
|
+
sqsEndpoint: 'ChangeRelationshipCompleteHdrSqs'
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
serviceTag: 'GraphHandler',
|
|
130
130
|
topicName: 'MoveRelationship_Out',
|
|
131
|
-
sqsEndpoint: '
|
|
131
|
+
sqsEndpoint: 'MoveRelationshipCompleteHdrSqs'
|
|
132
132
|
}
|
|
133
133
|
];
|
|
134
134
|
const snsTpl = await fs.readFile(
|
|
@@ -163,15 +163,14 @@ export async function generateFunctionYaml(allSchemas, options) {
|
|
|
163
163
|
functionNameConfig = `${upperCase(flowTag).replace('Relationship', 'Rel')}${suffixType}`;
|
|
164
164
|
}
|
|
165
165
|
if (handlerBaseName.endsWith('Complete')) {
|
|
166
|
-
// e.g.
|
|
166
|
+
// e.g. CreateCompleteHdrSqs or CreateCompleteSqs
|
|
167
167
|
if (isCrud) {
|
|
168
|
-
// Legacy:
|
|
168
|
+
// Legacy: DeleteCompleteHdrSqs, UpdateCompleteHdrSqs, CreateCompleteHdrSqs
|
|
169
169
|
const crudType = upperCase(flowTag);
|
|
170
|
-
|
|
171
|
-
else functionNameConfig = `${crudType}NodeComp`;
|
|
170
|
+
functionNameConfig = `${crudType}CompleteHdrSqs`;
|
|
172
171
|
} else if (isRel) {
|
|
173
172
|
// Legacy: UpdateRelComp
|
|
174
|
-
functionNameConfig = `${upperCase(flowTag)
|
|
173
|
+
functionNameConfig = `${upperCase(flowTag)}CompleteHdrSqs`;
|
|
175
174
|
} else {
|
|
176
175
|
functionNameConfig = `${handlerBaseName}${suffixType}`;
|
|
177
176
|
}
|
|
@@ -27,6 +27,7 @@ export async function generateEndpointsFlow(allSchemas, options) {
|
|
|
27
27
|
|
|
28
28
|
const sharedTemplates = {
|
|
29
29
|
sqs: await fs.readFile(path.join(__dirname, '..', '_shared', 'handlers', 'FlowHandler_HdrSqs.ejs'), 'utf-8'),
|
|
30
|
+
dsq: await fs.readFile(path.join(__dirname, '..', '_shared', 'handlers', 'FlowHandler_HdrDsq.ejs'), 'utf-8'),
|
|
30
31
|
api: await fs.readFile(path.join(__dirname, '..', '_shared', 'handlers', 'FlowHandler_HdrApi.ejs'), 'utf-8'),
|
|
31
32
|
inv: await fs.readFile(path.join(__dirname, '..', '_shared', 'handlers', 'FlowHandler_HdrInv.ejs'), 'utf-8'),
|
|
32
33
|
wbsMain: await fs.readFile(path.join(__dirname, '..', 'FlowSchemas', 'templates', 'endpoint', 'FlowMain_Wbs.ejs'), 'utf-8').catch(() => ''),
|
|
@@ -70,7 +71,7 @@ export async function generateEndpointsFlow(allSchemas, options) {
|
|
|
70
71
|
topicArn: `${upperAction}_In`,
|
|
71
72
|
generateCode: generateCode,
|
|
72
73
|
flow: mockFlow,
|
|
73
|
-
|
|
74
|
+
startConfig: null
|
|
74
75
|
});
|
|
75
76
|
await fs.writeFile(path.join(flowOutputDir, `${mainFileName}.js`), mainContent, 'utf-8');
|
|
76
77
|
generatedCount++;
|
|
@@ -88,7 +89,7 @@ export async function generateEndpointsFlow(allSchemas, options) {
|
|
|
88
89
|
upperCaseFlowTag: upperAction,
|
|
89
90
|
generateCode: generateCode,
|
|
90
91
|
flow: mockFlow,
|
|
91
|
-
|
|
92
|
+
startConfig: null
|
|
92
93
|
});
|
|
93
94
|
await fs.writeFile(path.join(flowOutputDir, `${beforeLogicalFileName}.js`), beforeLogicalContent, 'utf-8');
|
|
94
95
|
generatedCount++;
|
|
@@ -35,6 +35,10 @@ export async function generateRbacFlows(allSchemas, options) {
|
|
|
35
35
|
path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrSqs.ejs'),
|
|
36
36
|
'utf-8'
|
|
37
37
|
),
|
|
38
|
+
dsq: await fs.readFile(
|
|
39
|
+
path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrDsq.ejs'),
|
|
40
|
+
'utf-8'
|
|
41
|
+
),
|
|
38
42
|
api: await fs.readFile(
|
|
39
43
|
path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrApi.ejs'),
|
|
40
44
|
'utf-8'
|
package/src/codeGenerators/app/src/generatedCode/Flow/FlowRelationships/RelationshipFlowGenerator.js
CHANGED
|
@@ -25,6 +25,7 @@ export async function generateRelationshipFlows(allSchemas, options) {
|
|
|
25
25
|
// Read standard handler templates for reuse
|
|
26
26
|
const templates = {
|
|
27
27
|
sqs: await fs.readFile(path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrSqs.ejs'), 'utf-8'),
|
|
28
|
+
dsq: await fs.readFile(path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrDsq.ejs'), 'utf-8'),
|
|
28
29
|
api: await fs.readFile(path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrApi.ejs'), 'utf-8'),
|
|
29
30
|
inv: await fs.readFile(path.join(templateDir, '..', '..', '_shared', 'handlers', 'FlowHandler_HdrInv.ejs'), 'utf-8')
|
|
30
31
|
};
|
|
@@ -98,7 +99,7 @@ export async function generateRelationshipFlows(allSchemas, options) {
|
|
|
98
99
|
generatedCount++;
|
|
99
100
|
} else if (event === 'dsq') {
|
|
100
101
|
handlerFunctionName = `${processFunction}_HdrDsq`;
|
|
101
|
-
handlerContent = ejs.render(templates.sqs, {
|
|
102
|
+
handlerContent = ejs.render(templates.dsq || templates.sqs, {
|
|
102
103
|
flowTag: flowTag,
|
|
103
104
|
flowStepName: '',
|
|
104
105
|
mainFileName: actionFileName,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import ejs from 'ejs';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
export async function generateDsqHandler(flow, stepName, suffix, flowOutputDir, mainFileName, templates) {
|
|
6
|
+
const upperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
7
|
+
const flowTag = flow.flowTag;
|
|
8
|
+
|
|
9
|
+
// For entry point stepName is empty
|
|
10
|
+
const handlerFileName = stepName ? `${flowTag}${stepName}_${suffix}` : `Process${upperCase(flowTag)}_${suffix}`;
|
|
11
|
+
|
|
12
|
+
// Function name: matches default export in the referenced _Main.js
|
|
13
|
+
const functionName = stepName ? `${flowTag}${stepName}` : `Process${upperCase(flowTag)}`;
|
|
14
|
+
|
|
15
|
+
// Queue name: keep the full handler suffix so handler code matches
|
|
16
|
+
const queueNameSuffix = suffix;
|
|
17
|
+
let queueName = '';
|
|
18
|
+
if (stepName) {
|
|
19
|
+
queueName = `${flowTag}${stepName}${queueNameSuffix}`;
|
|
20
|
+
} else {
|
|
21
|
+
if (flow.event && flow.event.includes('ownTopic')) {
|
|
22
|
+
queueName = `${flowTag}${queueNameSuffix}`;
|
|
23
|
+
} else {
|
|
24
|
+
queueName = `${functionName}${queueNameSuffix}`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let startConfig = null;
|
|
29
|
+
if (!stepName && flow.flowSteps) {
|
|
30
|
+
const startStep = flow.flowSteps.find(s => s.stepName === 'start');
|
|
31
|
+
if (startStep) {
|
|
32
|
+
startConfig = { ...startStep };
|
|
33
|
+
// Map properties
|
|
34
|
+
if (startConfig.properties && Array.isArray(startConfig.properties)) {
|
|
35
|
+
startConfig.properties = startConfig.properties.map(p => {
|
|
36
|
+
if (typeof p === 'string') {
|
|
37
|
+
return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
|
|
38
|
+
}
|
|
39
|
+
return p;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// Map messageAttributes
|
|
43
|
+
if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
|
|
44
|
+
startConfig.messageAttributes = startConfig.messageAttributes.map(p => {
|
|
45
|
+
if (typeof p === 'string') {
|
|
46
|
+
return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
|
|
47
|
+
}
|
|
48
|
+
return p;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const handlerContent = ejs.render(templates.dsq || templates.sqs, {
|
|
55
|
+
flowTag: flowTag,
|
|
56
|
+
flowStepName: stepName || '',
|
|
57
|
+
mainFileName: mainFileName,
|
|
58
|
+
functionName: functionName,
|
|
59
|
+
queueName: queueName,
|
|
60
|
+
startConfig: startConfig
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await fs.writeFile(path.join(flowOutputDir, `${handlerFileName}.js`), handlerContent, 'utf-8');
|
|
64
|
+
}
|
|
@@ -28,14 +28,14 @@ export async function generateSqsHandler(flow, stepName, suffix, flowOutputDir,
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
let
|
|
31
|
+
let startConfig = null;
|
|
32
32
|
if (!stepName && flow.flowSteps) {
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
|
|
33
|
+
const startStep = flow.flowSteps.find(s => s.stepName === 'start');
|
|
34
|
+
if (startStep) {
|
|
35
|
+
startConfig = { ...startStep };
|
|
36
36
|
// Map properties
|
|
37
|
-
if (
|
|
38
|
-
|
|
37
|
+
if (startConfig.properties && Array.isArray(startConfig.properties)) {
|
|
38
|
+
startConfig.properties = startConfig.properties.map(p => {
|
|
39
39
|
if (typeof p === 'string') {
|
|
40
40
|
return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
|
|
41
41
|
}
|
|
@@ -43,8 +43,8 @@ export async function generateSqsHandler(flow, stepName, suffix, flowOutputDir,
|
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
45
|
// Map messageAttributes
|
|
46
|
-
if (
|
|
47
|
-
|
|
46
|
+
if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
|
|
47
|
+
startConfig.messageAttributes = startConfig.messageAttributes.map(p => {
|
|
48
48
|
if (typeof p === 'string') {
|
|
49
49
|
return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
|
|
50
50
|
}
|
|
@@ -60,7 +60,7 @@ export async function generateSqsHandler(flow, stepName, suffix, flowOutputDir,
|
|
|
60
60
|
mainFileName: mainFileName,
|
|
61
61
|
functionName: functionName,
|
|
62
62
|
queueName: queueName,
|
|
63
|
-
|
|
63
|
+
startConfig: startConfig
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
await fs.writeFile(path.join(flowOutputDir, `${handlerFileName}.js`), handlerContent, 'utf-8');
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from '@jest/globals';
|
|
2
|
+
import fs from 'fs/promises';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { generateDsqHandler } from '../BaseDsqHandler.js';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
describe('generateDsqHandler', () => {
|
|
12
|
+
let tmpDir;
|
|
13
|
+
beforeEach(async () => {
|
|
14
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'iz-dsq-handler-'));
|
|
15
|
+
});
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('generates a DSQ handler file containing reformatDsqMessage and setValidatorSchema', async () => {
|
|
21
|
+
// Read the template
|
|
22
|
+
const templatePath = path.join(__dirname, '..', '..', 'handlers', 'FlowHandler_HdrDsq.ejs');
|
|
23
|
+
const dsqTemplate = await fs.readFile(templatePath, 'utf-8');
|
|
24
|
+
const templates = { dsq: dsqTemplate };
|
|
25
|
+
|
|
26
|
+
const mockFlow = {
|
|
27
|
+
flowTag: 'createOrder',
|
|
28
|
+
event: ['dsq']
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
await generateDsqHandler(
|
|
32
|
+
mockFlow,
|
|
33
|
+
'', // entry point
|
|
34
|
+
'HdrDsq', // suffix
|
|
35
|
+
tmpDir, // flowOutputDir
|
|
36
|
+
'ProcessCreateOrder_Main', // mainFileName
|
|
37
|
+
templates
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const generatedFilePath = path.join(tmpDir, 'ProcessCreateOrder_HdrDsq.js');
|
|
41
|
+
const generatedContent = await fs.readFile(generatedFilePath, 'utf-8');
|
|
42
|
+
|
|
43
|
+
// Verify it contains setValidatorSchema on line 39 (approx or exactly depending on formatting, let's verify substring)
|
|
44
|
+
expect(generatedContent).toContain('middleware.setValidatorSchema(recordHandlerSharedLib.baseValidatorSchema(');
|
|
45
|
+
expect(generatedContent).toContain('type: "object"');
|
|
46
|
+
expect(generatedContent).toContain('required: [\'body\', \'messageAttributes\']');
|
|
47
|
+
|
|
48
|
+
// Verify it contains reformatDsqMessage
|
|
49
|
+
expect(generatedContent).toContain('record = recordHandlerSharedLib.reformatDsqMessage(record._izContext, record);');
|
|
50
|
+
expect(generatedContent).toContain('record._izContext.logger.debug(\'record ReceiveMsgOutHdrSqs\', record);');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('generates a DSQ handler for step containing step properties mapping', async () => {
|
|
54
|
+
const templatePath = path.join(__dirname, '..', '..', 'handlers', 'FlowHandler_HdrDsq.ejs');
|
|
55
|
+
const dsqTemplate = await fs.readFile(templatePath, 'utf-8');
|
|
56
|
+
const templates = { dsq: dsqTemplate };
|
|
57
|
+
|
|
58
|
+
const mockFlow = {
|
|
59
|
+
flowTag: 'createOrder',
|
|
60
|
+
event: ['dsq'],
|
|
61
|
+
flowSteps: [
|
|
62
|
+
{
|
|
63
|
+
stepName: 'Start',
|
|
64
|
+
properties: ['orderId'],
|
|
65
|
+
messageAttributes: ['userId']
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
stepProperties: {
|
|
69
|
+
orderId: { propertyName: 'orderId', type: 'string', required: true }
|
|
70
|
+
},
|
|
71
|
+
stepMessageAttributes: {
|
|
72
|
+
userId: { propertyName: 'userId', type: 'string', required: true }
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
await generateDsqHandler(
|
|
77
|
+
mockFlow,
|
|
78
|
+
'StepOne', // step name
|
|
79
|
+
'HdrDsq', // suffix
|
|
80
|
+
tmpDir, // flowOutputDir
|
|
81
|
+
'CreateOrderStepOne_Main', // mainFileName
|
|
82
|
+
templates
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
const generatedFilePath = path.join(tmpDir, 'createOrderStepOne_HdrDsq.js');
|
|
86
|
+
const generatedContent = await fs.readFile(generatedFilePath, 'utf-8');
|
|
87
|
+
|
|
88
|
+
// Verify template rendering and function names
|
|
89
|
+
expect(generatedContent).toContain('import createOrderStepOne from \'./CreateOrderStepOne_Main.js\';');
|
|
90
|
+
expect(generatedContent).toContain('createOrderStepOne');
|
|
91
|
+
expect(generatedContent).toContain('"createOrderStepOneHdrDsq"');
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -13,14 +13,14 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
13
13
|
// Function name matches default export of the referenced _Main.js
|
|
14
14
|
const functionName = stepName ? `${flowTag}${stepName}` : `Process${upperCase(flowTag)}`;
|
|
15
15
|
|
|
16
|
-
let
|
|
16
|
+
let startConfig = null;
|
|
17
17
|
if (!stepName && flow.flowSteps) {
|
|
18
|
-
const
|
|
19
|
-
if (
|
|
20
|
-
|
|
18
|
+
const startStep = flow.flowSteps.find(s => s.stepName === 'start');
|
|
19
|
+
if (startStep) {
|
|
20
|
+
startConfig = { ...startStep };
|
|
21
21
|
// Map properties
|
|
22
|
-
if (
|
|
23
|
-
|
|
22
|
+
if (startConfig.properties && Array.isArray(startConfig.properties)) {
|
|
23
|
+
startConfig.properties = startConfig.properties.map(p => {
|
|
24
24
|
if (typeof p === 'string') {
|
|
25
25
|
return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
|
|
26
26
|
}
|
|
@@ -28,8 +28,8 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
// Map messageAttributes
|
|
31
|
-
if (
|
|
32
|
-
|
|
31
|
+
if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
|
|
32
|
+
startConfig.messageAttributes = startConfig.messageAttributes.map(p => {
|
|
33
33
|
if (typeof p === 'string') {
|
|
34
34
|
return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
|
|
35
35
|
}
|
|
@@ -45,7 +45,7 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
45
45
|
mainFileName: mainFileName,
|
|
46
46
|
functionName: functionName,
|
|
47
47
|
queueName: queueName,
|
|
48
|
-
|
|
48
|
+
startConfig: startConfig
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
await fs.writeFile(path.join(flowOutputDir, `${handlerFileName}.js`), handlerContent, 'utf-8');
|
|
@@ -13,14 +13,14 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
13
13
|
// Function name matches default export of the referenced _Main.js
|
|
14
14
|
const functionName = stepName ? `${flowTag}${stepName}` : `Process${upperCase(flowTag)}`;
|
|
15
15
|
|
|
16
|
-
let
|
|
16
|
+
let startConfig = null;
|
|
17
17
|
if (!stepName && flow.flowSteps) {
|
|
18
|
-
const
|
|
19
|
-
if (
|
|
20
|
-
|
|
18
|
+
const startStep = flow.flowSteps.find(s => s.stepName === 'start');
|
|
19
|
+
if (startStep) {
|
|
20
|
+
startConfig = { ...startStep };
|
|
21
21
|
// Map properties
|
|
22
|
-
if (
|
|
23
|
-
|
|
22
|
+
if (startConfig.properties && Array.isArray(startConfig.properties)) {
|
|
23
|
+
startConfig.properties = startConfig.properties.map(p => {
|
|
24
24
|
if (typeof p === 'string') {
|
|
25
25
|
return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
|
|
26
26
|
}
|
|
@@ -28,8 +28,8 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
28
28
|
});
|
|
29
29
|
}
|
|
30
30
|
// Map messageAttributes
|
|
31
|
-
if (
|
|
32
|
-
|
|
31
|
+
if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
|
|
32
|
+
startConfig.messageAttributes = startConfig.messageAttributes.map(p => {
|
|
33
33
|
if (typeof p === 'string') {
|
|
34
34
|
return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
|
|
35
35
|
}
|
|
@@ -45,7 +45,7 @@ export default async function generate(flow, stepName, flowOutputDir, mainFileNa
|
|
|
45
45
|
mainFileName: mainFileName,
|
|
46
46
|
functionName: functionName,
|
|
47
47
|
queueName: queueName,
|
|
48
|
-
|
|
48
|
+
startConfig: startConfig
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
await fs.writeFile(path.join(flowOutputDir, `${handlerFileName}.js`), handlerContent, 'utf-8');
|
|
@@ -4,6 +4,7 @@ import lambdaSyncInv from './lambdaSyncInv.js';
|
|
|
4
4
|
import lambdaSyncApi from './lambdaSyncApi.js';
|
|
5
5
|
import eventBridge from './eventBridge.js';
|
|
6
6
|
import s3 from './s3.js';
|
|
7
|
+
import dsq from './dsq.js';
|
|
7
8
|
|
|
8
9
|
export const EVENT_HANDLERS = {
|
|
9
10
|
ownTopic,
|
|
@@ -11,5 +12,6 @@ export const EVENT_HANDLERS = {
|
|
|
11
12
|
lambdaSyncInv,
|
|
12
13
|
lambdaSyncApi,
|
|
13
14
|
eventBridge,
|
|
14
|
-
s3
|
|
15
|
+
s3,
|
|
16
|
+
dsq
|
|
15
17
|
};
|
package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrApi.ejs
CHANGED
|
@@ -5,14 +5,14 @@ import <%= functionName %> from './<%= mainFileName %>.js';
|
|
|
5
5
|
|
|
6
6
|
const validatorSchema = {
|
|
7
7
|
//(<validatorSchema>)
|
|
8
|
-
<% if (typeof
|
|
8
|
+
<% if (typeof startConfig !== 'undefined' && startConfig !== null && startConfig.properties && startConfig.properties.length > 0) { -%>
|
|
9
9
|
type: 'object',
|
|
10
10
|
properties: {
|
|
11
|
-
<%
|
|
11
|
+
<% startConfig.properties.forEach(prop => { -%>
|
|
12
12
|
<%- prop.propertyName %>: { type: '<%- prop.type || 'string' %>' },
|
|
13
13
|
<% }) -%>
|
|
14
14
|
},
|
|
15
|
-
required: [ <%-
|
|
15
|
+
required: [ <%- startConfig.properties.filter(p => p.required !== false).map(p => `'${p.propertyName}'`).join(', ') %> ]
|
|
16
16
|
<% } -%>
|
|
17
17
|
//(</validatorSchema>)
|
|
18
18
|
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2020 Sven Mason <http://izara.io>
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Affero General Public License as
|
|
6
|
+
published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { middlewareHandler as middleware } from "@izara_project/izara-middleware";
|
|
19
|
+
import { recordHandlerSharedLib } from "@izara_project/izara-core-library-record-handler";
|
|
20
|
+
import Logger from '@izara_project/izara-core-library-logger';
|
|
21
|
+
import callingFlowSharedLib from '@izara_project/izara-core-library-calling-flow';
|
|
22
|
+
import <%= functionName %> from './<%= mainFileName %>.js';
|
|
23
|
+
|
|
24
|
+
// validate event properties in body.Message of sqs event
|
|
25
|
+
let perRecordsValidatorSchema = {
|
|
26
|
+
//(<validatorSchema>)
|
|
27
|
+
<% if (typeof startConfig !== 'undefined' && startConfig !== null && startConfig.properties && startConfig.properties.length > 0) { -%>
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
<% startConfig.properties.forEach(prop => { -%>
|
|
31
|
+
'<%- prop.propertyName %>': { type: '<%- prop.type || 'string' %>' },
|
|
32
|
+
<% }) -%>
|
|
33
|
+
},
|
|
34
|
+
required: [ <%- startConfig.properties.filter(p => p.required !== false).map(p => `'${p.propertyName}'`).join(', ') %> ]
|
|
35
|
+
<% } -%>
|
|
36
|
+
//(</validatorSchema>)
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
<% if (typeof startConfig !== 'undefined' && startConfig !== null && startConfig.messageAttributes && startConfig.messageAttributes.length > 0) { -%>
|
|
40
|
+
let messageAttributeValidatorSchema = {
|
|
41
|
+
type: 'object',
|
|
42
|
+
properties: {
|
|
43
|
+
<% startConfig.messageAttributes.forEach(prop => { -%>
|
|
44
|
+
'<%- prop.propertyName %>': {
|
|
45
|
+
type: 'object',
|
|
46
|
+
properties: {
|
|
47
|
+
Type: { type: 'string' },
|
|
48
|
+
Value: { type: '<%- prop.type || 'string' %>' }
|
|
49
|
+
},
|
|
50
|
+
required: ['Type', 'Value']
|
|
51
|
+
},
|
|
52
|
+
<% }) -%>
|
|
53
|
+
},
|
|
54
|
+
required: [ <%- startConfig.messageAttributes.filter(p => p.required !== false).map(p => `'${p.propertyName}'`).join(', ') %> ]
|
|
55
|
+
};
|
|
56
|
+
<% } else { -%>
|
|
57
|
+
let messageAttributeValidatorSchema = null;
|
|
58
|
+
<% } -%>
|
|
59
|
+
|
|
60
|
+
middleware.setValidatorSchema(recordHandlerSharedLib.baseValidatorSchema(
|
|
61
|
+
{
|
|
62
|
+
type: "object",
|
|
63
|
+
required: ['body', 'messageAttributes'],
|
|
64
|
+
properties: {
|
|
65
|
+
body: {
|
|
66
|
+
type: 'object',
|
|
67
|
+
},
|
|
68
|
+
messageAttributes: {
|
|
69
|
+
type: 'object'
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
export const main = middleware.wrap(async (event, context) => {
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
|
|
78
|
+
let recordPromises = [];
|
|
79
|
+
|
|
80
|
+
// loop each record and send to mainFunction
|
|
81
|
+
await Promise.all(event.Records.map(async record => { // promise.all for map() function
|
|
82
|
+
|
|
83
|
+
let passOnProperties = []
|
|
84
|
+
record = recordHandlerSharedLib.reformatDsqMessage(record._izContext, record);
|
|
85
|
+
record._izContext.logger.debug('record ReceiveMsgOutHdrSqs', record);
|
|
86
|
+
|
|
87
|
+
//validate message (and MessageAttributes)
|
|
88
|
+
await recordHandlerSharedLib.validateRecord(
|
|
89
|
+
record, // one record will send to mainFunction
|
|
90
|
+
"<%= queueName %>", // queue name that need to retry or send to dlq
|
|
91
|
+
perRecordsValidatorSchema, // schema for record.Message
|
|
92
|
+
messageAttributeValidatorSchema
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// add argument (to invoke lambda) to passOnProperties[]
|
|
96
|
+
passOnProperties.push(record.body.Message);
|
|
97
|
+
passOnProperties.push(callingFlowSharedLib.addCallingFlowToPassOnProperties(record.body.Message));
|
|
98
|
+
//(<additionalParams>)
|
|
99
|
+
//(</additionalParams>)
|
|
100
|
+
record._izContext.logger.debug('passOnProperties in handler', passOnProperties);
|
|
101
|
+
|
|
102
|
+
// call recordHandlerSharedLib.recordHandler with 3 parameters and return promise(resolve)
|
|
103
|
+
let recordPromise = recordHandlerSharedLib.recordHandler(
|
|
104
|
+
record, // one record will send to mainFunction
|
|
105
|
+
<%= functionName %>, // mainFunction that need to invoke.
|
|
106
|
+
"<%= queueName %>", // queue name that need to retry or send to dlq
|
|
107
|
+
passOnProperties, // all parameters that mainFunction needed.
|
|
108
|
+
);
|
|
109
|
+
record._izContext.logger.debug('after recordPromise in handler');
|
|
110
|
+
recordPromises.push(recordPromise); // push promise to recordPromises
|
|
111
|
+
}))
|
|
112
|
+
|
|
113
|
+
Logger.debug('before Promise.all(recordPromises) in handler');
|
|
114
|
+
try {
|
|
115
|
+
// --- main await all promises
|
|
116
|
+
await Promise.all(recordPromises); // await all promises
|
|
117
|
+
|
|
118
|
+
return event.Records // return all for local testing
|
|
119
|
+
|
|
120
|
+
} catch {
|
|
121
|
+
Logger.debug('Promise.all(recordPromises) in handler threw error (at least one record did no resolve)');
|
|
122
|
+
}
|
|
123
|
+
Logger.debug('after Promise.all(recordPromises) in handler');
|
|
124
|
+
|
|
125
|
+
} catch (err) {
|
|
126
|
+
Logger.error('Unhandled Error, LambdaFunctionHdrSqs: ', err);
|
|
127
|
+
throw (err);
|
|
128
|
+
}
|
|
129
|
+
});
|
package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrInv.ejs
CHANGED
|
@@ -5,14 +5,14 @@ import <%= functionName %> from './<%= mainFileName %>.js';
|
|
|
5
5
|
|
|
6
6
|
const validatorSchema = {
|
|
7
7
|
//(<validatorSchema>)
|
|
8
|
-
<% if (typeof
|
|
8
|
+
<% if (typeof startConfig !== 'undefined' && startConfig !== null && startConfig.properties && startConfig.properties.length > 0) { -%>
|
|
9
9
|
type: 'object',
|
|
10
10
|
properties: {
|
|
11
|
-
<%
|
|
11
|
+
<% startConfig.properties.forEach(prop => { -%>
|
|
12
12
|
<%- prop.propertyName %>: { type: '<%- prop.type || 'string' %>' },
|
|
13
13
|
<% }) -%>
|
|
14
14
|
},
|
|
15
|
-
required: [ <%-
|
|
15
|
+
required: [ <%- startConfig.properties.filter(p => p.required !== false).map(p => `'${p.propertyName}'`).join(', ') %> ]
|
|
16
16
|
<% } -%>
|
|
17
17
|
//(</validatorSchema>)
|
|
18
18
|
};
|
package/src/codeGenerators/app/src/generatedCode/Flow/_shared/handlers/FlowHandler_HdrSqs.ejs
CHANGED
|
@@ -24,27 +24,34 @@ import <%= functionName %> from './<%= mainFileName %>.js';
|
|
|
24
24
|
// validate event properties in body.Message of sqs event
|
|
25
25
|
let perRecordsValidatorSchema = {
|
|
26
26
|
//(<validatorSchema>)
|
|
27
|
-
<% if (typeof
|
|
27
|
+
<% if (typeof startConfig !== 'undefined' && startConfig !== null && startConfig.properties && startConfig.properties.length > 0) { -%>
|
|
28
28
|
type: 'object',
|
|
29
29
|
properties: {
|
|
30
|
-
<%
|
|
31
|
-
<%- prop.propertyName
|
|
30
|
+
<% startConfig.properties.forEach(prop => { -%>
|
|
31
|
+
'<%- prop.propertyName %>': { type: '<%- prop.type || 'string' %>' },
|
|
32
32
|
<% }) -%>
|
|
33
33
|
},
|
|
34
|
-
required: [ <%-
|
|
34
|
+
required: [ <%- startConfig.properties.filter(p => p.required !== false).map(p => `'${p.propertyName}'`).join(', ') %> ]
|
|
35
35
|
<% } -%>
|
|
36
36
|
//(</validatorSchema>)
|
|
37
37
|
};
|
|
38
38
|
|
|
39
|
-
<% if (typeof
|
|
39
|
+
<% if (typeof startConfig !== 'undefined' && startConfig !== null && startConfig.messageAttributes && startConfig.messageAttributes.length > 0) { -%>
|
|
40
40
|
let messageAttributeValidatorSchema = {
|
|
41
41
|
type: 'object',
|
|
42
42
|
properties: {
|
|
43
|
-
<%
|
|
44
|
-
<%- prop.propertyName
|
|
43
|
+
<% startConfig.messageAttributes.forEach(prop => { -%>
|
|
44
|
+
'<%- prop.propertyName %>': {
|
|
45
|
+
type: 'object',
|
|
46
|
+
properties: {
|
|
47
|
+
Type: { type: 'string' },
|
|
48
|
+
Value: { type: '<%- prop.type || 'string' %>' }
|
|
49
|
+
},
|
|
50
|
+
required: ['Type', 'Value']
|
|
51
|
+
},
|
|
45
52
|
<% }) -%>
|
|
46
53
|
},
|
|
47
|
-
required: [ <%-
|
|
54
|
+
required: [ <%- startConfig.messageAttributes.filter(p => p.required !== false).map(p => `'${p.propertyName}'`).join(', ') %> ]
|
|
48
55
|
};
|
|
49
56
|
<% } else { -%>
|
|
50
57
|
let messageAttributeValidatorSchema = null;
|
|
@@ -2,7 +2,7 @@ export const STEP_EVENT_HANDLER_CONFIG = {
|
|
|
2
2
|
sqs: { suffix: 'HdrSqs', template: 'sqs' },
|
|
3
3
|
ownTopic: { suffix: 'HdrSqs', template: 'sqs' },
|
|
4
4
|
extTopic: { suffix: 'HdrSqs', template: 'sqs' },
|
|
5
|
-
dsq: { suffix: 'HdrDsq', template: '
|
|
5
|
+
dsq: { suffix: 'HdrDsq', template: 'dsq' },
|
|
6
6
|
lambdaSyncInv: { suffix: 'HdrInv', template: 'inv' },
|
|
7
7
|
lambdaSyncApi: { suffix: 'HdrApi', template: 'api' }
|
|
8
8
|
};
|
|
@@ -17,7 +17,7 @@ export function getStepEventHandlerConfig(eventType) {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function normalizeEvents(events, fallback = ['
|
|
20
|
+
export function normalizeEvents(events, fallback = ['extTopic']) {
|
|
21
21
|
if (!events) return [...fallback];
|
|
22
22
|
return Array.isArray(events) ? [...events] : [events];
|
|
23
23
|
}
|
|
@@ -18,6 +18,7 @@ export async function generateFlowEntryPoint(allSchemas, options) {
|
|
|
18
18
|
|
|
19
19
|
const templates = {
|
|
20
20
|
sqs: await fs.readFile(path.join(__dirname, '..', 'handlers', 'FlowHandler_HdrSqs.ejs'), 'utf-8'),
|
|
21
|
+
dsq: await fs.readFile(path.join(__dirname, '..', 'handlers', 'FlowHandler_HdrDsq.ejs'), 'utf-8'),
|
|
21
22
|
api: await fs.readFile(path.join(__dirname, '..', 'handlers', 'FlowHandler_HdrApi.ejs'), 'utf-8'),
|
|
22
23
|
inv: await fs.readFile(path.join(__dirname, '..', 'handlers', 'FlowHandler_HdrInv.ejs'), 'utf-8'),
|
|
23
24
|
endpointMain: await fs.readFile(path.join(__dirname, '..', '..', 'FlowSchemas', 'templates', 'endpoint', 'FlowEndpoint_Main.ejs'), 'utf-8'),
|
package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowMainFunctionBase.js
CHANGED
|
@@ -75,22 +75,22 @@ export async function generateFlowMainFunction(allSchemas, options) {
|
|
|
75
75
|
'utf-8'
|
|
76
76
|
);
|
|
77
77
|
|
|
78
|
-
const
|
|
79
|
-
s => s.stepName === '
|
|
78
|
+
const startStep = flow.flowSteps && flow.flowSteps.find(
|
|
79
|
+
s => s.stepName === 'start'
|
|
80
80
|
);
|
|
81
|
-
let
|
|
81
|
+
let startConfig = startStep ? { ...startStep } : null;
|
|
82
82
|
|
|
83
|
-
if (
|
|
84
|
-
if (
|
|
85
|
-
|
|
83
|
+
if (startConfig) {
|
|
84
|
+
if (startConfig.properties && Array.isArray(startConfig.properties)) {
|
|
85
|
+
startConfig.properties = startConfig.properties.map(p => {
|
|
86
86
|
if (typeof p === 'string') {
|
|
87
87
|
return (flow.stepProperties && flow.stepProperties[p]) ? flow.stepProperties[p] : { propertyName: p, type: 'string' };
|
|
88
88
|
}
|
|
89
89
|
return p;
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
|
-
if (
|
|
93
|
-
|
|
92
|
+
if (startConfig.messageAttributes && Array.isArray(startConfig.messageAttributes)) {
|
|
93
|
+
startConfig.messageAttributes = startConfig.messageAttributes.map(p => {
|
|
94
94
|
if (typeof p === 'string') {
|
|
95
95
|
return (flow.stepMessageAttributes && flow.stepMessageAttributes[p]) ? flow.stepMessageAttributes[p] : { propertyName: p, type: 'string' };
|
|
96
96
|
}
|
|
@@ -118,7 +118,7 @@ export async function generateFlowMainFunction(allSchemas, options) {
|
|
|
118
118
|
topicArn: topicArn,
|
|
119
119
|
generateCode: generateCode,
|
|
120
120
|
flow: flow,
|
|
121
|
-
|
|
121
|
+
startConfig: startConfig,
|
|
122
122
|
tableName: tableName
|
|
123
123
|
});
|
|
124
124
|
await fs.writeFile(
|
|
@@ -138,7 +138,7 @@ export async function generateFlowMainFunction(allSchemas, options) {
|
|
|
138
138
|
upperCaseFlowTag: upperCaseFlowTag,
|
|
139
139
|
generateCode: generateCode,
|
|
140
140
|
flow: flow,
|
|
141
|
-
|
|
141
|
+
startConfig: startConfig,
|
|
142
142
|
tableName: tableName
|
|
143
143
|
});
|
|
144
144
|
await fs.writeFile(
|
|
@@ -162,7 +162,7 @@ export async function generateFlowMainFunction(allSchemas, options) {
|
|
|
162
162
|
upperCaseFlowTag: upperCaseFlowTag,
|
|
163
163
|
generateCode: generateCode,
|
|
164
164
|
flow: flow,
|
|
165
|
-
|
|
165
|
+
startConfig: startConfig
|
|
166
166
|
});
|
|
167
167
|
|
|
168
168
|
await fs.writeFile(
|
|
@@ -20,6 +20,7 @@ export async function generateFlowSteps(allSchemas, options) {
|
|
|
20
20
|
main: await fs.readFile(path.join(__dirname, '..', '..', 'FlowSchemas', 'templates', 'step', 'FlowStep_Main.ejs'), 'utf-8'),
|
|
21
21
|
complete: await fs.readFile(path.join(__dirname, '..', '..', 'FlowSchemas', 'templates', 'step', 'FlowEndpointComplete_Main.ejs'), 'utf-8'),
|
|
22
22
|
sqs: await fs.readFile(path.join(__dirname, '..', 'handlers', 'FlowHandler_HdrSqs.ejs'), 'utf-8'),
|
|
23
|
+
dsq: await fs.readFile(path.join(__dirname, '..', 'handlers', 'FlowHandler_HdrDsq.ejs'), 'utf-8'),
|
|
23
24
|
api: await fs.readFile(path.join(__dirname, '..', 'handlers', 'FlowHandler_HdrApi.ejs'), 'utf-8'),
|
|
24
25
|
inv: await fs.readFile(path.join(__dirname, '..', 'handlers', 'FlowHandler_HdrInv.ejs'), 'utf-8'),
|
|
25
26
|
|
|
@@ -53,7 +54,7 @@ export async function generateFlowSteps(allSchemas, options) {
|
|
|
53
54
|
|
|
54
55
|
for (const stepConfig of normalizeFlowSteps(flow.flowSteps)) {
|
|
55
56
|
const stepName = stepConfig.stepName;
|
|
56
|
-
if (['In', '
|
|
57
|
+
if (['In', 'start', 'Out', 'beforeLogical'].includes(stepName)) continue;
|
|
57
58
|
|
|
58
59
|
if (!createdDir) {
|
|
59
60
|
await fs.mkdir(flowOutputDir, { recursive: true });
|
|
@@ -179,7 +180,7 @@ export async function generateFlowSteps(allSchemas, options) {
|
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
// 2. Generate Handlers based on stepConfig.event
|
|
182
|
-
const events = normalizeEvents(stepConfig.event, ['
|
|
183
|
+
const events = normalizeEvents(stepConfig.event, ['extTopic']); // Default to extTopic if missing
|
|
183
184
|
for (const ev of events) {
|
|
184
185
|
if (ev === 'sns') continue;
|
|
185
186
|
const handlerConfig = getStepEventHandlerConfig(ev);
|
|
@@ -21,8 +21,54 @@ export function hasFlowStep(flowSteps, stepName) {
|
|
|
21
21
|
function inferStepName(step) {
|
|
22
22
|
const reservedKeys = new Set([
|
|
23
23
|
'event', 'settings', 'plugInHooks', 'properties', 'messageAttributes',
|
|
24
|
-
'returnValues', '
|
|
24
|
+
'returnValues', 'startStep', 'stepName'
|
|
25
25
|
]);
|
|
26
26
|
const key = Object.keys(step).find(item => !reservedKeys.has(item));
|
|
27
27
|
return typeof step[key] === 'string' ? step[key] : key;
|
|
28
28
|
}
|
|
29
|
+
|
|
30
|
+
export function normalizeUnifiedFlows(rawFlows) {
|
|
31
|
+
return rawFlows.map(flow => {
|
|
32
|
+
if (!flow.flowSteps) return flow;
|
|
33
|
+
|
|
34
|
+
// Handle both array and object empty cases
|
|
35
|
+
if (Array.isArray(flow.flowSteps) && flow.flowSteps.length === 0) return flow;
|
|
36
|
+
if (!Array.isArray(flow.flowSteps) && Object.keys(flow.flowSteps).length === 0) return flow;
|
|
37
|
+
|
|
38
|
+
const normalizedSteps = normalizeFlowSteps(flow.flowSteps);
|
|
39
|
+
|
|
40
|
+
// Ensure flowSteps is always an Array for the rest of the generation process
|
|
41
|
+
flow.flowSteps = normalizedSteps;
|
|
42
|
+
|
|
43
|
+
const hasStart = flow.flowSteps.some(s => s.stepName?.toLowerCase() === 'start');
|
|
44
|
+
|
|
45
|
+
if (flow.event) {
|
|
46
|
+
if (!hasStart) {
|
|
47
|
+
flow.flowSteps.unshift({
|
|
48
|
+
stepName: 'Start',
|
|
49
|
+
properties: flow.properties || [],
|
|
50
|
+
messageAttributes: flow.messageAttributes || []
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
const firstStep = flow.flowSteps[0];
|
|
55
|
+
|
|
56
|
+
if (firstStep) {
|
|
57
|
+
flow.event = firstStep.event;
|
|
58
|
+
if (firstStep.generatedCodeConfig) flow.generatedCodeConfig = firstStep.generatedCodeConfig;
|
|
59
|
+
if (firstStep.schedules) flow.schedules = firstStep.schedules;
|
|
60
|
+
if (firstStep.bucketName) flow.bucketName = firstStep.bucketName;
|
|
61
|
+
if (firstStep.createBucket !== undefined) flow.createBucket = firstStep.createBucket;
|
|
62
|
+
|
|
63
|
+
if (!hasStart) {
|
|
64
|
+
flow.flowSteps.unshift({
|
|
65
|
+
stepName: 'Start',
|
|
66
|
+
properties: firstStep.properties || [],
|
|
67
|
+
messageAttributes: firstStep.messageAttributes || []
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return flow;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
const
|
|
1
|
+
const ALLOWED_EVENTS = ['ownTopic', 'extTopic', 'lambdaSyncInv', 'lambdaSyncApi', 'eventBridge', 's3', 'dsq'];
|
|
2
2
|
const MAIN_ASYNC_EVENTS = ['ownTopic', 'extTopic', 's3'];
|
|
3
|
-
const ALLOWED_STEP_EVENTS = ['sqs', 'ownTopic', 'extTopic', 'dsq', 'lambdaSyncInv', 'lambdaSyncApi'];
|
|
4
3
|
const RESERVED_SYSTEM_FLOW_TAGS = new Set([
|
|
5
4
|
'Create',
|
|
6
5
|
'Update',
|
|
@@ -73,9 +72,9 @@ export function validateFlowsForGeneration(flows) {
|
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
const events = asArray(flow.event);
|
|
76
|
-
const invalidMainEvents = events.filter(event => !
|
|
75
|
+
const invalidMainEvents = events.filter(event => !ALLOWED_EVENTS.includes(event));
|
|
77
76
|
if (invalidMainEvents.length > 0) {
|
|
78
|
-
errors.push(`Flow '${flowTag}' uses unsupported main events: ${invalidMainEvents.join(', ')}. Allowed are: ${
|
|
77
|
+
errors.push(`Flow '${flowTag}' uses unsupported main events: ${invalidMainEvents.join(', ')}. Allowed are: ${ALLOWED_EVENTS.join(', ')}.`);
|
|
79
78
|
}
|
|
80
79
|
|
|
81
80
|
const mainAsyncEvents = events.filter(event => MAIN_ASYNC_EVENTS.includes(event));
|
|
@@ -86,7 +85,7 @@ export function validateFlowsForGeneration(flows) {
|
|
|
86
85
|
const flowSteps = Array.isArray(flow.flowSteps) ? flow.flowSteps : [];
|
|
87
86
|
const seenStepNames = new Set();
|
|
88
87
|
let anyStepHasPlugInHooks = false;
|
|
89
|
-
let
|
|
88
|
+
let startStepCount = 0;
|
|
90
89
|
|
|
91
90
|
for (const step of flowSteps) {
|
|
92
91
|
const stepName = step?.stepName;
|
|
@@ -101,10 +100,10 @@ export function validateFlowsForGeneration(flows) {
|
|
|
101
100
|
seenStepNames.add(stepName);
|
|
102
101
|
|
|
103
102
|
if (stepName === 'In') {
|
|
104
|
-
errors.push(`Flow '${flowTag}' uses legacy stepName 'In'. Use '
|
|
103
|
+
errors.push(`Flow '${flowTag}' uses legacy stepName 'In'. Use 'start'.`);
|
|
105
104
|
}
|
|
106
|
-
if (stepName === '
|
|
107
|
-
|
|
105
|
+
if (stepName === 'start') {
|
|
106
|
+
startStepCount += 1;
|
|
108
107
|
}
|
|
109
108
|
|
|
110
109
|
if (step.plugInHooks && step.plugInHooks.length > 0) {
|
|
@@ -112,22 +111,21 @@ export function validateFlowsForGeneration(flows) {
|
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
const stepEvents = asArray(step.event);
|
|
115
|
-
const invalidStepEvents = stepEvents.filter(event => !
|
|
114
|
+
const invalidStepEvents = stepEvents.filter(event => !ALLOWED_EVENTS.includes(event));
|
|
116
115
|
if (invalidStepEvents.length > 0) {
|
|
117
|
-
errors.push(`Flow '${flowTag}' step '${stepName}' uses unsupported step events: ${invalidStepEvents.join(', ')}. Allowed are: ${
|
|
116
|
+
errors.push(`Flow '${flowTag}' step '${stepName}' uses unsupported step events: ${invalidStepEvents.join(', ')}. Allowed are: ${ALLOWED_EVENTS.join(', ')}.`);
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
validateNamedRefs(flowTag, stepName, step.properties, flow.stepProperties, 'properties', errors);
|
|
121
120
|
validateNamedRefs(flowTag, stepName, step.messageAttributes, flow.stepMessageAttributes, 'messageAttributes', errors);
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
if (
|
|
125
|
-
errors.push(`Flow '${flowTag}' has multiple '
|
|
123
|
+
if (startStepCount > 1) {
|
|
124
|
+
errors.push(`Flow '${flowTag}' has multiple 'start' steps. Only one is allowed.`);
|
|
126
125
|
}
|
|
127
126
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
127
|
+
// ponytail: relaxed anyStepHasPlugInHooks && startStepCount === 0 requirement
|
|
128
|
+
// since unified entry points (step 0) can now handle plugins directly without start.
|
|
131
129
|
|
|
132
130
|
if (anyStepHasPlugInHooks) {
|
|
133
131
|
const forbiddenEvents = ['lambdaSyncInv', 'lambdaSyncApi', 's3', 'eventBridge'];
|
|
@@ -316,30 +316,30 @@ const TOPIC_NAME_GRAPH_HANDLER = {
|
|
|
316
316
|
};
|
|
317
317
|
|
|
318
318
|
const TOPIC_NAME_GENERATE_CODE = {
|
|
319
|
-
updateRelComplete: '
|
|
320
|
-
createRelComplete: '
|
|
321
|
-
deleteRelComplete: '
|
|
322
|
-
getRelComplete: '
|
|
319
|
+
updateRelComplete: 'UpdateRelationshipCompleteHdrSqs',
|
|
320
|
+
createRelComplete: 'CreateRelationshipCompleteHdrSqs',
|
|
321
|
+
deleteRelComplete: 'DeleteRelationshipCompleteHdrSqs',
|
|
322
|
+
getRelComplete: 'GetRelationshipCompleteHdrSqs',
|
|
323
323
|
outUpdateRelComplete: 'UpdateRelationship_Out',
|
|
324
324
|
outCreateRelComplete: 'CreateRelationship_Out',
|
|
325
325
|
outDeleteRelComplete: 'DeleteRelationship_Out',
|
|
326
326
|
outGetRelComplete: 'GetRelationship_Out',
|
|
327
|
-
updateNodeComplete: '
|
|
327
|
+
updateNodeComplete: 'UpdateCompleteHdrSqs',
|
|
328
328
|
outUpdateNodeComplete: 'Update_Out',
|
|
329
|
-
createNodeComplete: '
|
|
329
|
+
createNodeComplete: 'CreateCompleteHdrSqs',
|
|
330
330
|
outCreateNodeComplete: 'Create_Out',
|
|
331
|
-
deleteNodeComplete: '
|
|
331
|
+
deleteNodeComplete: 'DeleteCompleteHdrSqs',
|
|
332
332
|
outDeleteNodeComplete: 'Delete_Out',
|
|
333
|
-
getNodeComplete: '
|
|
333
|
+
getNodeComplete: 'GetCompleteHdrSqs',
|
|
334
334
|
outGetNodeComplete: 'Get_Out',
|
|
335
335
|
reservedLimitComplete: 'ReservedLimitComplete',
|
|
336
336
|
createPreSignUrl: 'CreatePreSignUrl',
|
|
337
337
|
flowSchemaOwnTopicComplete: 'FlowSchemaOwnTopicComplete',
|
|
338
338
|
flowSchemaOwnTopicEndpointComplete: 'FlowSchemaOwnTopicEndpointComplete',
|
|
339
339
|
createRecordComplete: 'CreateRecordComplete',
|
|
340
|
-
changeRelationshipComplete: '
|
|
340
|
+
changeRelationshipComplete: 'ChangeRelationshipCompleteHdrSqs',
|
|
341
341
|
outChangeRelationshipComplete: 'ChangeRelationship_Out',
|
|
342
|
-
moveRelationshipComplete: '
|
|
342
|
+
moveRelationshipComplete: 'MoveRelationshipCompleteHdrSqs',
|
|
343
343
|
outMoveRelationshipComplete: 'MoveRelationship_Out'
|
|
344
344
|
};
|
|
345
345
|
|
|
@@ -79,9 +79,9 @@ export async function generateFlowResourceYaml(allSchemas, options) {
|
|
|
79
79
|
if (Array.isArray(flow.flowSteps)) {
|
|
80
80
|
for (const stepConfig of flow.flowSteps) {
|
|
81
81
|
const stepName = stepConfig.stepName;
|
|
82
|
-
if (stepName === '
|
|
82
|
+
if (stepName === 'start') continue;
|
|
83
83
|
|
|
84
|
-
const events = stepConfig.event || ['
|
|
84
|
+
const events = stepConfig.event || ['extTopic'];
|
|
85
85
|
for (const ev of events) {
|
|
86
86
|
let queueName = `${flowTag}${stepName}`;
|
|
87
87
|
if (stepName === 'Complete') {
|
package/src/generateCode.js
CHANGED
|
@@ -8,6 +8,7 @@ import { parseFlowSchemas } from './parsers/flowSchemaParser.js';
|
|
|
8
8
|
import { generateFlowEntryPoint } from './codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowEntryPointBase.js';
|
|
9
9
|
import { generateFlowMainFunction } from './codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowMainFunctionBase.js';
|
|
10
10
|
import { generateFlowSteps } from './codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepBase.js';
|
|
11
|
+
import { normalizeUnifiedFlows } from './codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepNormalizer.js';
|
|
11
12
|
|
|
12
13
|
import { generateEndpointsFlow } from './codeGenerators/app/src/generatedCode/Flow/FlowObjects/EndpointsGenerator.js';
|
|
13
14
|
import { generateFlowOut } from './codeGenerators/resource/sls_yaml/FlowOutGenerator.js';
|
|
@@ -189,25 +190,19 @@ export async function generateCode(rootPath, options = {}) {
|
|
|
189
190
|
}
|
|
190
191
|
}
|
|
191
192
|
|
|
193
|
+
let cleanupStarted = false;
|
|
194
|
+
let generationSucceeded = false;
|
|
195
|
+
const backedUpDirs = new Set();
|
|
196
|
+
const dirsToBackup = [
|
|
197
|
+
generatedCodePath,
|
|
198
|
+
path.join(outputPath, 'app', 'sls_yaml', 'generatedCode'),
|
|
199
|
+
path.join(outputPath, 'resource', 'sls_yaml', 'generatedCode')
|
|
200
|
+
];
|
|
201
|
+
|
|
192
202
|
// ponytail: ensure hooks are restored even if generation fails
|
|
193
203
|
try {
|
|
194
|
-
|
|
195
|
-
'[INFO] [generateCode] STATUS=CLEANUP | Removing old generatedCode directories...'
|
|
196
|
-
);
|
|
197
|
-
await fs.promises.rm(generatedCodePath, {
|
|
198
|
-
recursive: true,
|
|
199
|
-
force: true
|
|
200
|
-
});
|
|
201
|
-
await fs.promises.rm(
|
|
202
|
-
path.join(outputPath, 'app', 'sls_yaml', 'generatedCode'),
|
|
203
|
-
{ recursive: true, force: true }
|
|
204
|
-
);
|
|
205
|
-
await fs.promises.rm(
|
|
206
|
-
path.join(outputPath, 'resource', 'sls_yaml', 'generatedCode'),
|
|
207
|
-
{ recursive: true, force: true }
|
|
208
|
-
);
|
|
204
|
+
policyRegistry.clear();
|
|
209
205
|
|
|
210
|
-
policyRegistry.clear();
|
|
211
206
|
|
|
212
207
|
// 1. Parsing & Hydration Pipeline
|
|
213
208
|
console.log('[INFO] [generateCode] STATUS=PARSING | ObjectSchemas...');
|
|
@@ -227,9 +222,34 @@ export async function generateCode(rootPath, options = {}) {
|
|
|
227
222
|
flowsForGeneration: flowData.flows || []
|
|
228
223
|
};
|
|
229
224
|
|
|
225
|
+
console.log('[INFO] [generateCode] STATUS=NORMALIZING | Adapting Unified Flows...');
|
|
226
|
+
normalizeUnifiedFlows(allSchemas.flowsForGeneration);
|
|
227
|
+
|
|
230
228
|
console.log('[INFO] [generateCode] STATUS=VALIDATING | Validating Flows...');
|
|
231
229
|
validateFlowsForGeneration(allSchemas.flowsForGeneration);
|
|
232
230
|
|
|
231
|
+
console.log(
|
|
232
|
+
'[INFO] [generateCode] STATUS=BACKUP_DIRS | Backing up old generatedCode directories...'
|
|
233
|
+
);
|
|
234
|
+
for (const dir of dirsToBackup) {
|
|
235
|
+
if (fs.existsSync(dir)) {
|
|
236
|
+
if (fs.existsSync(`${dir}.bak`)) {
|
|
237
|
+
await fs.promises.rm(`${dir}.bak`, { recursive: true, force: true });
|
|
238
|
+
}
|
|
239
|
+
await fs.promises.rename(dir, `${dir}.bak`);
|
|
240
|
+
backedUpDirs.add(dir);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
cleanupStarted = true;
|
|
245
|
+
|
|
246
|
+
console.log(
|
|
247
|
+
'[INFO] [generateCode] STATUS=CLEANUP | Removing old generatedCode directories before generating new files...'
|
|
248
|
+
);
|
|
249
|
+
for (const dir of dirsToBackup) {
|
|
250
|
+
await fs.promises.rm(dir, { recursive: true, force: true });
|
|
251
|
+
}
|
|
252
|
+
|
|
233
253
|
// 2. Generation Pipeline
|
|
234
254
|
await generateEndpointsFlow(allSchemas, generatorOptions);
|
|
235
255
|
await generateFlowMainFunction(allSchemas, generatorOptions);
|
|
@@ -263,8 +283,28 @@ export async function generateCode(rootPath, options = {}) {
|
|
|
263
283
|
await generateSharedResourceYaml(allSchemas, generatorOptions);
|
|
264
284
|
await generateInitialSetup(allSchemas, generatorOptions);
|
|
265
285
|
|
|
286
|
+
generationSucceeded = true;
|
|
266
287
|
|
|
267
288
|
} finally {
|
|
289
|
+
if (generationSucceeded) {
|
|
290
|
+
console.log('[INFO] [generateCode] STATUS=CLEANUP_BAK | Generation successful, removing .bak directories...');
|
|
291
|
+
for (const dir of dirsToBackup) {
|
|
292
|
+
if (fs.existsSync(`${dir}.bak`)) {
|
|
293
|
+
await fs.promises.rm(`${dir}.bak`, { recursive: true, force: true });
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
} else if (cleanupStarted) {
|
|
297
|
+
console.log('[INFO] [generateCode] STATUS=FAILED | Generation failed, rolling back directories...');
|
|
298
|
+
for (const dir of dirsToBackup) {
|
|
299
|
+
if (fs.existsSync(dir)) {
|
|
300
|
+
await fs.promises.rm(dir, { recursive: true, force: true });
|
|
301
|
+
}
|
|
302
|
+
if (backedUpDirs.has(dir) && fs.existsSync(`${dir}.bak`)) {
|
|
303
|
+
await fs.promises.rename(`${dir}.bak`, dir);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
268
308
|
// Restore backed-up hooks
|
|
269
309
|
if (hookDirs.size > 0 || hookBackups.length > 0) {
|
|
270
310
|
console.log(
|
|
@@ -279,14 +319,19 @@ export async function generateCode(rootPath, options = {}) {
|
|
|
279
319
|
}
|
|
280
320
|
}
|
|
281
321
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
322
|
+
if (generationSucceeded) {
|
|
323
|
+
console.log(
|
|
324
|
+
'[INFO] [generateCode] STATUS=HOOKS | Processing hook folders beside source folders...'
|
|
325
|
+
);
|
|
326
|
+
processSourceHooks(generatorOptions.outputPath);
|
|
286
327
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
328
|
+
console.log(
|
|
329
|
+
'[INFO] [generateCode] STATUS=FINISHED | Code generation complete.'
|
|
330
|
+
);
|
|
331
|
+
} else {
|
|
332
|
+
console.log(
|
|
333
|
+
'[INFO] [generateCode] STATUS=FAILED | Code generation failed. Hook files were restored, but processSourceHooks was skipped.'
|
|
334
|
+
);
|
|
335
|
+
}
|
|
290
336
|
}
|
|
291
337
|
}
|
|
292
|
-
|
package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicFlowSchemaTemplate.ejs
CHANGED
|
@@ -17,14 +17,14 @@ export default {
|
|
|
17
17
|
},
|
|
18
18
|
flowSteps: [
|
|
19
19
|
{
|
|
20
|
-
stepName: '
|
|
20
|
+
stepName: 'start',
|
|
21
21
|
properties: [],
|
|
22
22
|
messageAttributes: ['userId', 'correlationId']
|
|
23
23
|
},
|
|
24
24
|
<% if (hasBeforeLogicalStep) { %>
|
|
25
25
|
{
|
|
26
26
|
stepName: 'BeforeLogical',
|
|
27
|
-
event: ['
|
|
27
|
+
event: ['extTopic'],
|
|
28
28
|
properties: [],
|
|
29
29
|
messageAttributes: ['userId', 'correlationId']
|
|
30
30
|
},
|
|
@@ -32,7 +32,7 @@ export default {
|
|
|
32
32
|
<% if (['Create', 'Update', 'Delete'].includes(action)) { %>
|
|
33
33
|
{
|
|
34
34
|
stepName: 'Complete',
|
|
35
|
-
event: ['
|
|
35
|
+
event: ['extTopic'],
|
|
36
36
|
properties: [],
|
|
37
37
|
messageAttributes: ['userId', 'correlationId']
|
|
38
38
|
}
|
|
@@ -17,14 +17,14 @@ export default {
|
|
|
17
17
|
},
|
|
18
18
|
flowSteps: [
|
|
19
19
|
{
|
|
20
|
-
stepName: '
|
|
20
|
+
stepName: 'start',
|
|
21
21
|
properties: [],
|
|
22
22
|
messageAttributes: ['userId', 'correlationId']
|
|
23
23
|
}
|
|
24
24
|
<% if (hasCompleteStep) { %>,
|
|
25
25
|
{
|
|
26
26
|
stepName: 'Complete',
|
|
27
|
-
event: ['
|
|
27
|
+
event: ['extTopic'],
|
|
28
28
|
properties: [],
|
|
29
29
|
messageAttributes: ['userId', 'correlationId']
|
|
30
30
|
}
|
package/test_generate.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { normalizeUnifiedFlows, normalizeFlowSteps } from './src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepNormalizer.js';
|
|
2
|
+
|
|
3
|
+
const rawFlows = [
|
|
4
|
+
{
|
|
5
|
+
event: 'api',
|
|
6
|
+
flowSteps: {
|
|
7
|
+
MyStep: { properties: [] }
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const result = normalizeUnifiedFlows(rawFlows);
|
|
14
|
+
console.log(JSON.stringify(result, null, 2));
|
|
15
|
+
} catch (e) {
|
|
16
|
+
console.error(e.message);
|
|
17
|
+
}
|