@izara_project/izara-core-generate-service-code 1.0.54 → 1.0.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/codeGenerators/app/sls_yaml/FunctionYamlGenerator.js +15 -15
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/StatusFieldGenerator.js +1 -8
- package/src/codeGenerators/app/src/generatedCode/Flow/FlowSchemas/WebSocketGenerator.js +1 -7
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/events/BaseSqsHandler.js +3 -3
- package/src/codeGenerators/app/src/generatedCode/Flow/_shared/shared/triggerCacheBase.js +1 -7
- package/src/codeGenerators/app/src/generatedCode/SystemFlowSchemas/RegisterGenerator.js +1 -7
- package/src/codeGenerators/resource/sls_yaml/DynamoDBGenerator.js +8 -8
- package/src/codeGenerators/resource/sls_yaml/FlowOutGenerator.js +59 -51
- package/src/codeGenerators/resource/sls_yaml/FlowResourceYamlGenerator.js +148 -175
- package/src/codeGenerators/resource/sls_yaml/templates/crud/ResourceYaml.ejs +10 -10
- package/src/generateCode.js +174 -142
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicFlowSchemaTemplate.ejs +12 -10
- package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/RelationshipFlowSchemaTemplate.ejs +6 -5
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.55",
|
|
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": {
|
|
@@ -103,7 +103,7 @@ export async function generateFunctionYaml(allSchemas, options) {
|
|
|
103
103
|
|
|
104
104
|
// Function Name Config
|
|
105
105
|
// e.g. ProcessCreateSqs or CreateCompleteSqs or GetApi
|
|
106
|
-
|
|
106
|
+
let suffixType = handlerSuffix.startsWith('Hdr') ? handlerSuffix : handlerSuffix.replace('Hdr', '');
|
|
107
107
|
let functionNameConfig = `${handlerBaseName}${suffixType}`;
|
|
108
108
|
if (isCrud && handlerBaseName === `Process${upperCase(flowTag)}`) {
|
|
109
109
|
// Legacy matches: CreateSqs, GetApi instead of ProcessCreateSqs
|
|
@@ -133,19 +133,19 @@ export async function generateFunctionYaml(allSchemas, options) {
|
|
|
133
133
|
|
|
134
134
|
if (isCrud || isRel) {
|
|
135
135
|
queueName = handlerBaseName.replace('Process', '');
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
if (handlerSuffix === 'HdrSqs' || handlerSuffix === 'HdrDsq') {
|
|
137
|
+
queueName += handlerSuffix;
|
|
138
|
+
}
|
|
139
139
|
} else {
|
|
140
140
|
// For Custom Flows (e.g. OwnTopicFlowProcess, ProcessExtTopicFlow)
|
|
141
141
|
// The queue name exactly matches the handler name without the underscore.
|
|
142
142
|
if (handlerSuffix === 'HdrSqs' || handlerSuffix === 'HdrDsq') {
|
|
143
143
|
if (handlerBaseName === `Process${upperCase(flowTag)}` && flowDefForQueue && flowDefForQueue.event && flowDefForQueue.event.includes('ownTopic')) {
|
|
144
144
|
// ownTopic flows in FlowResourceYamlGenerator omit 'Process' for the queue
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
queueName = flowTag + handlerSuffix;
|
|
146
|
+
} else {
|
|
147
|
+
queueName = handlerBaseName + handlerSuffix;
|
|
148
|
+
}
|
|
149
149
|
} else {
|
|
150
150
|
queueName = handlerBaseName;
|
|
151
151
|
}
|
|
@@ -153,7 +153,7 @@ export async function generateFunctionYaml(allSchemas, options) {
|
|
|
153
153
|
|
|
154
154
|
// Api routes
|
|
155
155
|
let apiRoutes = [];
|
|
156
|
-
|
|
156
|
+
if (suffixType === 'HdrApi' || suffixType === 'Api') {
|
|
157
157
|
const routesList = isCrud ? crudApiRoutes : (isRel ? relApiRoutes : []);
|
|
158
158
|
const actionPath = flowTag.toLowerCase().replace('relationship', '');
|
|
159
159
|
apiRoutes = routesList.map(r => ({
|
|
@@ -166,7 +166,7 @@ export async function generateFunctionYaml(allSchemas, options) {
|
|
|
166
166
|
const handlerPath = `src/generatedCode/${subDir}/${flowTag}/source/${fileNameWithoutExt}.main`;
|
|
167
167
|
|
|
168
168
|
let filterPatterns = '';
|
|
169
|
-
|
|
169
|
+
if (handlerBaseName.endsWith('Complete') && (suffixType === 'HdrSqs' || suffixType === 'HdrDsq' || suffixType === 'Sqs' || suffixType === 'Dsq')) {
|
|
170
170
|
filterPatterns = ` filterPatterns: #**** need to update serverless framework upper v.2.69.1
|
|
171
171
|
- body: {"MessageAttributes":{"callingFlow":{"Value":["\${self:custom.iz_resourcePrefix}${functionNameConfig}"]}}} # functionName of callingFlow
|
|
172
172
|
- body: {"MessageAttributes":{"callingFlow":{"Value":[{"exists":false}]}}}`;
|
|
@@ -190,15 +190,15 @@ export async function generateFunctionYaml(allSchemas, options) {
|
|
|
190
190
|
};
|
|
191
191
|
|
|
192
192
|
let yamlBlock = '';
|
|
193
|
-
if (schedules.length > 0 && suffixType === 'Inv') {
|
|
193
|
+
if (schedules.length > 0 && (suffixType === 'HdrInv' || suffixType === 'Inv')) {
|
|
194
194
|
yamlBlock = ejs.render(templates.eventBridge, renderVars);
|
|
195
|
-
|
|
195
|
+
} else if (suffixType === 'HdrSqs' || suffixType === 'HdrDsq' || suffixType === 'Sqs' || suffixType === 'Dsq') {
|
|
196
196
|
yamlBlock = ejs.render(templates.sqs, renderVars);
|
|
197
|
-
} else if (suffixType === 'Inv') {
|
|
197
|
+
} else if (suffixType === 'HdrInv' || suffixType === 'Inv') {
|
|
198
198
|
yamlBlock = ejs.render(templates.inv, renderVars);
|
|
199
|
-
} else if (suffixType === 'Api') {
|
|
199
|
+
} else if (suffixType === 'HdrApi' || suffixType === 'Api') {
|
|
200
200
|
yamlBlock = ejs.render(templates.api, renderVars);
|
|
201
|
-
|
|
201
|
+
} else if (suffixType === 'HdrWbs' || suffixType === 'Wbs') {
|
|
202
202
|
renderVars.routeName = flowTag;
|
|
203
203
|
yamlBlock = ejs.render(templates.wbs, renderVars);
|
|
204
204
|
} else {
|
|
@@ -17,14 +17,7 @@ function lowerCase(str) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function shortNameHandler(handlerType) {
|
|
20
|
-
|
|
21
|
-
const map = {
|
|
22
|
-
'HdrSqs': 'Sqs',
|
|
23
|
-
'HdrApi': 'Api',
|
|
24
|
-
'HdrWbs': 'Wbs',
|
|
25
|
-
'HdrDsq': 'Dsq'
|
|
26
|
-
};
|
|
27
|
-
return map[handlerType] || handlerType;
|
|
20
|
+
return handlerType;
|
|
28
21
|
}
|
|
29
22
|
|
|
30
23
|
export async function generateStatusField(flowSchema, appPath, outputBaseDir) {
|
|
@@ -12,13 +12,7 @@ function upperCase(str) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
function shortNameHandler(handlerType) {
|
|
15
|
-
|
|
16
|
-
'HdrSqs': 'Sqs',
|
|
17
|
-
'HdrApi': 'Api',
|
|
18
|
-
'HdrWbs': 'Wbs',
|
|
19
|
-
'HdrDsq': 'Dsq'
|
|
20
|
-
};
|
|
21
|
-
return map[handlerType] || handlerType;
|
|
15
|
+
return handlerType;
|
|
22
16
|
}
|
|
23
17
|
|
|
24
18
|
export async function generateWebSocket(allLocalFlowSchemas, appPath, outputBaseDir) {
|
|
@@ -14,9 +14,9 @@ export async function generateSqsHandler(flow, stepName, suffix, flowOutputDir,
|
|
|
14
14
|
// For steps: ${flowTag}${flowStepName} (e.g. OwnTopicFlowProcess)
|
|
15
15
|
const functionName = stepName ? `${flowTag}${stepName}` : `Process${upperCase(flowTag)}`;
|
|
16
16
|
|
|
17
|
-
// Queue name:
|
|
18
|
-
//
|
|
19
|
-
const queueNameSuffix = suffix
|
|
17
|
+
// Queue name: keep the full handler suffix so handler code matches
|
|
18
|
+
// the generated queue/resource names.
|
|
19
|
+
const queueNameSuffix = suffix;
|
|
20
20
|
let queueName = '';
|
|
21
21
|
if (stepName) {
|
|
22
22
|
queueName = `${flowTag}${stepName}${queueNameSuffix}`;
|
|
@@ -13,13 +13,7 @@ function upperCase(str) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function shortNameHandler(handlerType) {
|
|
16
|
-
|
|
17
|
-
'HdrSqs': 'Sqs',
|
|
18
|
-
'HdrApi': 'Api',
|
|
19
|
-
'HdrWbs': 'Wbs',
|
|
20
|
-
'HdrDsq': 'Dsq'
|
|
21
|
-
};
|
|
22
|
-
return map[handlerType] || handlerType;
|
|
16
|
+
return handlerType;
|
|
23
17
|
}
|
|
24
18
|
|
|
25
19
|
export async function generateTriggerCache(flowSchema, appPath, outputBaseDir) {
|
|
@@ -14,13 +14,7 @@ function upperCase(str) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function shortNameHandler(handlerType) {
|
|
17
|
-
|
|
18
|
-
HdrSqs: 'Sqs',
|
|
19
|
-
HdrApi: 'Api',
|
|
20
|
-
HdrWbs: 'Wbs',
|
|
21
|
-
HdrDsq: 'Dsq'
|
|
22
|
-
};
|
|
23
|
-
return map[handlerType] || handlerType;
|
|
17
|
+
return handlerType;
|
|
24
18
|
}
|
|
25
19
|
|
|
26
20
|
export async function generateRegisterFlow(allLocalFlowSchemas, _appPath, outputBaseDir) {
|
|
@@ -72,15 +72,15 @@ export async function generateDynamoDBTables(allSchemas, options) {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
let generatedCount = 0;
|
|
76
|
+
const yamlOutputPath = path.join(resourceYamlDir, 'generated-dynamoDB-table.yml');
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
// Generate system tables first
|
|
79
|
+
const systemYamlTplPath = path.join(__dirname, 'templates', 'SystemDynamoDB_Yaml.ejs');
|
|
80
|
+
const systemYamlTpl = await fs.readFile(systemYamlTplPath, 'utf-8');
|
|
81
|
+
const systemYamlContent = ejs.render(systemYamlTpl, {});
|
|
82
|
+
await fs.writeFile(yamlOutputPath, `${systemYamlContent}\n`, 'utf-8');
|
|
83
|
+
generatedCount += 8; // 8 system tables
|
|
84
84
|
|
|
85
85
|
for (const [tableName, keys] of tables.entries()) {
|
|
86
86
|
const yamlContent = ejs.render(yamlTpl, {
|
|
@@ -2,72 +2,80 @@ import path from 'path';
|
|
|
2
2
|
import fs from 'fs/promises';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import ejs from 'ejs';
|
|
5
|
+
|
|
5
6
|
import { getFlowsForGeneration } from '../../app/src/generatedCode/Flow/_shared/shared/flowSelection.js';
|
|
6
7
|
|
|
7
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
9
|
const __dirname = path.dirname(__filename);
|
|
9
10
|
|
|
10
11
|
async function appendToFile(filePath, content) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
try {
|
|
13
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
14
|
+
await fs.appendFile(filePath, `${content}\n`, 'utf-8');
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error(`[Error] Failed to append file: ${filePath}`, error);
|
|
17
|
+
}
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export async function generateFlowOut(allSchemas, options) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
console.log(' [FlowOutGenerator] Generating Flow Out nodes (SNS Topics)...');
|
|
22
|
+
|
|
23
|
+
const resourceYamlDir = path.join(options.outputPath, 'resource', 'sls_yaml', 'generatedCode', 'source');
|
|
24
|
+
await fs.mkdir(resourceYamlDir, { recursive: true });
|
|
25
|
+
|
|
26
|
+
const yamlTplPath = path.join(__dirname, 'templates', 'FlowOut_Yaml.ejs');
|
|
27
|
+
const yamlTpl = await fs.readFile(yamlTplPath, 'utf-8');
|
|
24
28
|
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
let generatedCount = 0;
|
|
30
|
+
const yamlOutputPath = path.join(resourceYamlDir, 'generated-sns-out.yml');
|
|
31
|
+
await fs.writeFile(yamlOutputPath, '', 'utf-8');
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
const yamlOutputPath = path.join(resourceYamlDir, 'generated-sns-out.yml');
|
|
33
|
+
const generatedTopics = new Set();
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (flow.outputTopic === true) {
|
|
34
|
-
const upperCase = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
|
35
|
-
const topicName = upperCase(flow.flowTag);
|
|
35
|
+
async function appendTopic(topicName) {
|
|
36
|
+
if (generatedTopics.has(topicName)) return;
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
generatedTopics.add(topicName);
|
|
39
|
+
const yamlContent = ejs.render(yamlTpl, { topicName });
|
|
40
|
+
await appendToFile(yamlOutputPath, yamlContent);
|
|
41
|
+
generatedCount++;
|
|
42
|
+
}
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
const flows = getFlowsForGeneration(allSchemas);
|
|
45
|
+
for (const flow of flows) {
|
|
46
|
+
if (flow.outputTopic !== true) continue;
|
|
47
|
+
await appendTopic(flow.flowTag.charAt(0).toUpperCase() + flow.flowTag.slice(1));
|
|
48
|
+
}
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
50
|
+
const systemTopics = [
|
|
51
|
+
'CreateObjectComplete',
|
|
52
|
+
'DeleteNodeComplete',
|
|
53
|
+
'UpdateNodeComplete',
|
|
54
|
+
'ProcessLogicalComplete',
|
|
55
|
+
'FindDataComplete',
|
|
56
|
+
'Create',
|
|
57
|
+
'Update',
|
|
58
|
+
'Delete',
|
|
59
|
+
'CreateRelationship',
|
|
60
|
+
'UpdateRelationship',
|
|
61
|
+
'DeleteRelationship',
|
|
62
|
+
'GetRelationship',
|
|
63
|
+
'ChangeRelationship',
|
|
64
|
+
'MoveRelationship',
|
|
65
|
+
'CreateTargetRole',
|
|
66
|
+
'ListTargetRole',
|
|
67
|
+
'DeleteTargetRole',
|
|
68
|
+
'CreateRolePermissions',
|
|
69
|
+
'ListRolePermissions',
|
|
70
|
+
'DeleteRolePermissions',
|
|
71
|
+
'CreateUserRole',
|
|
72
|
+
'ListUserInRoles',
|
|
73
|
+
'DeleteUserFromRole'
|
|
74
|
+
];
|
|
63
75
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
});
|
|
68
|
-
await appendToFile(yamlOutputPath, yamlContent);
|
|
69
|
-
generatedCount++;
|
|
70
|
-
}
|
|
76
|
+
for (const topic of systemTopics) {
|
|
77
|
+
await appendTopic(topic);
|
|
78
|
+
}
|
|
71
79
|
|
|
72
|
-
|
|
80
|
+
console.log(` [FlowOutGenerator] Generated ${generatedCount} SNS Topics for Flow Out nodes.`);
|
|
73
81
|
}
|
|
@@ -2,198 +2,171 @@ import path from 'path';
|
|
|
2
2
|
import fs from 'fs/promises';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import ejs from 'ejs';
|
|
5
|
+
|
|
5
6
|
import { getFlowsForGeneration } from '../../app/src/generatedCode/Flow/_shared/shared/flowSelection.js';
|
|
6
7
|
|
|
7
8
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
9
|
const __dirname = path.dirname(__filename);
|
|
9
10
|
|
|
10
11
|
async function appendToFile(filePath, content) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
try {
|
|
13
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
14
|
+
await fs.appendFile(filePath, `${content}\n`, 'utf-8');
|
|
15
|
+
} catch (error) {
|
|
16
|
+
console.error(`[Error] Failed to append file: ${filePath}`, error);
|
|
17
|
+
}
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
export async function generateFlowResourceYaml(allSchemas, options) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const resourceYamlDir = path.join(options.outputPath, 'resource', 'sls_yaml', 'generatedCode', 'source');
|
|
23
|
-
await fs.mkdir(resourceYamlDir, { recursive: true });
|
|
24
|
-
|
|
25
|
-
const resourceYamlTplPath = path.join(__dirname, 'templates', 'crud', 'ResourceYaml.ejs');
|
|
26
|
-
const resourceBeforeLogicalYamlTplPath = path.join(__dirname, 'templates', 'crud', 'ResourceBeforeLogicalYaml.ejs');
|
|
27
|
-
|
|
28
|
-
const resourceYamlTpl = await fs.readFile(resourceYamlTplPath, 'utf-8');
|
|
29
|
-
const resourceBeforeLogicalYamlTpl = await fs.readFile(resourceBeforeLogicalYamlTplPath, 'utf-8');
|
|
30
|
-
|
|
31
|
-
let generatedCount = 0;
|
|
32
|
-
const yamlOutputPath = path.join(resourceYamlDir, 'generated-sns-in-sqs.yml');
|
|
33
|
-
|
|
34
|
-
const flows = getFlowsForGeneration(allSchemas);
|
|
35
|
-
for (const flow of flows) {
|
|
36
|
-
const flowTag = flow.flowTag;
|
|
37
|
-
|
|
38
|
-
// Generate In-Queue resources for any flow that listens on its own topic
|
|
39
|
-
if (flow.event && flow.event.includes('ownTopic')) {
|
|
40
|
-
// Render main ResourceYaml.ejs (e.g., InCreate, CreateHdrSqs)
|
|
41
|
-
const yamlContent = ejs.render(resourceYamlTpl, {
|
|
42
|
-
queueName: flowTag
|
|
43
|
-
});
|
|
44
|
-
await appendToFile(yamlOutputPath, yamlContent);
|
|
45
|
-
generatedCount++;
|
|
46
|
-
|
|
47
|
-
// Check if there are beforeLogical configs for this flow
|
|
48
|
-
const generateCodeConfigs = flows
|
|
49
|
-
.filter(f => f.generatedCodeConfig && f.generatedCodeConfig.generatedCodeTag.toLowerCase() === flowTag.toLowerCase())
|
|
50
|
-
.map(f => ({
|
|
51
|
-
...f.generatedCodeConfig,
|
|
52
|
-
flowTag: f.flowTag
|
|
53
|
-
}));
|
|
54
|
-
|
|
55
|
-
const beforeLogicalConfigs = generateCodeConfigs.filter(c => c.codeHookTag === 'beforeLogical');
|
|
56
|
-
|
|
57
|
-
if (beforeLogicalConfigs.length > 0) {
|
|
58
|
-
// Collect unique flowTags (like ValidateUnitTrackedProperty) from the beforeLogical configs
|
|
59
|
-
const uniqueFlowTags = [...new Set(beforeLogicalConfigs.map(c => c.flowTag))];
|
|
60
|
-
|
|
61
|
-
const beforeLogicalYamlContent = ejs.render(resourceBeforeLogicalYamlTpl, {
|
|
62
|
-
queueName: `${flowTag}BeforeLogical`,
|
|
63
|
-
flowTags: uniqueFlowTags
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
await appendToFile(yamlOutputPath, beforeLogicalYamlContent);
|
|
67
|
-
generatedCount++;
|
|
68
|
-
}
|
|
69
|
-
} else if (flow.event && flow.event.includes('extTopic')) {
|
|
70
|
-
// Custom flows using extTopic do not have ownTopic, but need an entry queue
|
|
71
|
-
const resourceSqsYamlTplPath = path.join(__dirname, 'templates', 'crud', 'ResourceSqsYaml.ejs');
|
|
72
|
-
const resourceSqsYamlTpl = await fs.readFile(resourceSqsYamlTplPath, 'utf-8');
|
|
73
|
-
const yamlContent = ejs.render(resourceSqsYamlTpl, {
|
|
74
|
-
queueName: `Process${flowTag}Sqs`
|
|
75
|
-
});
|
|
76
|
-
await appendToFile(yamlOutputPath, yamlContent);
|
|
77
|
-
generatedCount++;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Generate Complete queues for custom FlowSchema
|
|
81
|
-
// Also generate queues for any flowStep that uses sqs, dsq, or extTopic
|
|
82
|
-
if (flow.flowSteps && Array.isArray(flow.flowSteps)) {
|
|
83
|
-
for (const stepConfig of flow.flowSteps) {
|
|
84
|
-
const stepName = stepConfig.stepName;
|
|
85
|
-
if (stepName === 'InTag') continue;
|
|
86
|
-
|
|
87
|
-
const events = stepConfig.event || ['sqs'];
|
|
88
|
-
for (const ev of events) {
|
|
89
|
-
let queueName = flowTag + stepName;
|
|
90
|
-
if (stepName === 'Complete') {
|
|
91
|
-
queueName = flowTag + 'Complete';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (ev === 'sqs' || ev === 'ownTopic') {
|
|
95
|
-
// sqs and ownTopic create SNS Topic + Subscription + SQS Queue
|
|
96
|
-
const yamlContent = ejs.render(resourceYamlTpl, {
|
|
97
|
-
queueName: queueName
|
|
98
|
-
});
|
|
99
|
-
await appendToFile(yamlOutputPath, yamlContent);
|
|
100
|
-
generatedCount++;
|
|
101
|
-
} else if (ev === 'dsq' || ev === 'extTopic') {
|
|
102
|
-
// extTopic and dsq create ONLY SQS Queue
|
|
103
|
-
const resourceSqsYamlTplPath = path.join(__dirname, 'templates', 'crud', 'ResourceSqsYaml.ejs');
|
|
104
|
-
const resourceSqsYamlTpl = await fs.readFile(resourceSqsYamlTplPath, 'utf-8');
|
|
105
|
-
const yamlContent = ejs.render(resourceSqsYamlTpl, {
|
|
106
|
-
queueName: queueName
|
|
107
|
-
});
|
|
108
|
-
await appendToFile(yamlOutputPath, yamlContent);
|
|
109
|
-
generatedCount++;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
21
|
+
console.log(' [FlowResourceYamlGenerator] Generating SQS/SNS YAML resources for flows...');
|
|
114
22
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const queueNames = [
|
|
118
|
-
`${flowTag}CreatePreSignUrlSqs`,
|
|
119
|
-
`${flowTag}ReservedLimitSqs`
|
|
120
|
-
];
|
|
121
|
-
|
|
122
|
-
for (const qName of queueNames) {
|
|
123
|
-
const resourceSqsYamlTplPath = path.join(__dirname, 'templates', 'crud', 'ResourceSqsYaml.ejs');
|
|
124
|
-
const resourceSqsYamlTpl = await fs.readFile(resourceSqsYamlTplPath, 'utf-8');
|
|
125
|
-
const yamlContent = ejs.render(resourceSqsYamlTpl, {
|
|
126
|
-
queueName: qName
|
|
127
|
-
});
|
|
128
|
-
await appendToFile(yamlOutputPath, yamlContent);
|
|
129
|
-
generatedCount++;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
23
|
+
const resourceYamlDir = path.join(options.outputPath, 'resource', 'sls_yaml', 'generatedCode', 'source');
|
|
24
|
+
await fs.mkdir(resourceYamlDir, { recursive: true });
|
|
132
25
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
26
|
+
const resourceYamlTplPath = path.join(__dirname, 'templates', 'crud', 'ResourceYaml.ejs');
|
|
27
|
+
const resourceBeforeLogicalYamlTplPath = path.join(__dirname, 'templates', 'crud', 'ResourceBeforeLogicalYaml.ejs');
|
|
28
|
+
const resourceSqsYamlTplPath = path.join(__dirname, 'templates', 'crud', 'ResourceSqsYaml.ejs');
|
|
29
|
+
|
|
30
|
+
const resourceYamlTpl = await fs.readFile(resourceYamlTplPath, 'utf-8');
|
|
31
|
+
const resourceBeforeLogicalYamlTpl = await fs.readFile(resourceBeforeLogicalYamlTplPath, 'utf-8');
|
|
32
|
+
const resourceSqsYamlTpl = await fs.readFile(resourceSqsYamlTplPath, 'utf-8');
|
|
33
|
+
|
|
34
|
+
let generatedCount = 0;
|
|
35
|
+
const yamlOutputPath = path.join(resourceYamlDir, 'generated-sns-in-sqs.yml');
|
|
36
|
+
await fs.writeFile(yamlOutputPath, '', 'utf-8');
|
|
37
|
+
|
|
38
|
+
const generatedResources = new Set();
|
|
39
|
+
|
|
40
|
+
async function appendUnique(resourceKey, template, templateData) {
|
|
41
|
+
if (generatedResources.has(resourceKey)) return;
|
|
42
|
+
|
|
43
|
+
generatedResources.add(resourceKey);
|
|
44
|
+
const yamlContent = ejs.render(template, templateData);
|
|
45
|
+
await appendToFile(yamlOutputPath, yamlContent);
|
|
46
|
+
generatedCount++;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const flows = getFlowsForGeneration(allSchemas);
|
|
50
|
+
|
|
51
|
+
for (const flow of flows) {
|
|
52
|
+
const flowTag = flow.flowTag;
|
|
53
|
+
|
|
54
|
+
if (flow.event && flow.event.includes('ownTopic')) {
|
|
55
|
+
await appendUnique(flowTag, resourceYamlTpl, { queueName: flowTag });
|
|
56
|
+
|
|
57
|
+
const generateCodeConfigs = flows
|
|
58
|
+
.filter((candidate) => candidate.generatedCodeConfig
|
|
59
|
+
&& candidate.generatedCodeConfig.generatedCodeTag?.toLowerCase() === flowTag.toLowerCase())
|
|
60
|
+
.map((candidate) => ({
|
|
61
|
+
...candidate.generatedCodeConfig,
|
|
62
|
+
flowTag: candidate.flowTag
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
const beforeLogicalConfigs = generateCodeConfigs.filter((config) => config.codeHookTag === 'beforeLogical');
|
|
66
|
+
if (beforeLogicalConfigs.length > 0) {
|
|
67
|
+
const uniqueFlowTags = [...new Set(beforeLogicalConfigs.map((config) => config.flowTag))];
|
|
68
|
+
await appendUnique(`${flowTag}BeforeLogical`, resourceBeforeLogicalYamlTpl, {
|
|
69
|
+
queueName: `${flowTag}BeforeLogical`,
|
|
70
|
+
flowTags: uniqueFlowTags
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
} else if (flow.event && flow.event.includes('extTopic')) {
|
|
74
|
+
await appendUnique(`Process${flowTag}HdrSqs`, resourceSqsYamlTpl, {
|
|
75
|
+
queueName: `Process${flowTag}HdrSqs`
|
|
76
|
+
});
|
|
145
77
|
}
|
|
146
78
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
79
|
+
if (Array.isArray(flow.flowSteps)) {
|
|
80
|
+
for (const stepConfig of flow.flowSteps) {
|
|
81
|
+
const stepName = stepConfig.stepName;
|
|
82
|
+
if (stepName === 'InTag') continue;
|
|
83
|
+
|
|
84
|
+
const events = stepConfig.event || ['sqs'];
|
|
85
|
+
for (const ev of events) {
|
|
86
|
+
let queueName = `${flowTag}${stepName}`;
|
|
87
|
+
if (stepName === 'Complete') {
|
|
88
|
+
queueName = `${flowTag}Complete`;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (ev === 'sqs' || ev === 'ownTopic') {
|
|
92
|
+
await appendUnique(queueName, resourceYamlTpl, { queueName });
|
|
93
|
+
} else if (ev === 'dsq' || ev === 'extTopic') {
|
|
94
|
+
await appendUnique(`${queueName}HdrDsq`, resourceSqsYamlTpl, {
|
|
95
|
+
queueName: `${queueName}HdrDsq`
|
|
96
|
+
});
|
|
97
|
+
}
|
|
162
98
|
}
|
|
99
|
+
}
|
|
163
100
|
}
|
|
164
101
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const yamlContent = ejs.render(resourceSqsYamlTpl, { queueName: action + 'Dsq' });
|
|
171
|
-
await appendToFile(yamlOutputPath, yamlContent);
|
|
172
|
-
generatedCount++;
|
|
173
|
-
}
|
|
102
|
+
if (flow.event && flow.event.includes('s3')) {
|
|
103
|
+
const queueNames = [
|
|
104
|
+
`${flowTag}CreatePreSignUrlHdrSqs`,
|
|
105
|
+
`${flowTag}ReservedLimitHdrSqs`
|
|
106
|
+
];
|
|
174
107
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
'PaginateProcessLogical',
|
|
179
|
-
'FindData',
|
|
180
|
-
'Register',
|
|
181
|
-
'WebSocket',
|
|
182
|
-
'CreateObjectComplete',
|
|
183
|
-
'UpdateNodeComplete',
|
|
184
|
-
'DeleteNodeComplete',
|
|
185
|
-
'GetNodeComplete'
|
|
186
|
-
];
|
|
187
|
-
|
|
188
|
-
const resourceSqsYamlTplGlobal = await fs.readFile(resourceSqsYamlTplPath, 'utf-8');
|
|
189
|
-
|
|
190
|
-
for (const sysQueue of systemQueues) {
|
|
191
|
-
const yamlContent = ejs.render(resourceSqsYamlTplGlobal, {
|
|
192
|
-
queueName: sysQueue
|
|
193
|
-
});
|
|
194
|
-
await appendToFile(yamlOutputPath, yamlContent);
|
|
195
|
-
generatedCount++;
|
|
108
|
+
for (const queueName of queueNames) {
|
|
109
|
+
await appendUnique(queueName, resourceSqsYamlTpl, { queueName });
|
|
110
|
+
}
|
|
196
111
|
}
|
|
197
112
|
|
|
198
|
-
|
|
113
|
+
if (flow.isDynamicRelationshipType) {
|
|
114
|
+
const queueName = `${flowTag}HdrDsq`;
|
|
115
|
+
await appendUnique(queueName, resourceSqsYamlTpl, { queueName });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const systemOwnTopicFlows = [
|
|
120
|
+
'Create',
|
|
121
|
+
'Update',
|
|
122
|
+
'Delete',
|
|
123
|
+
'CreateRelationship',
|
|
124
|
+
'UpdateRelationship',
|
|
125
|
+
'DeleteRelationship',
|
|
126
|
+
'ChangeRelationship',
|
|
127
|
+
'MoveRelationship',
|
|
128
|
+
'CreateTargetRole',
|
|
129
|
+
'DeleteTargetRole',
|
|
130
|
+
'CreateRolePermissions',
|
|
131
|
+
'DeleteRolePermissions',
|
|
132
|
+
'CreateUserRole',
|
|
133
|
+
'DeleteUserFromRole'
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
for (const flowTag of systemOwnTopicFlows) {
|
|
137
|
+
await appendUnique(flowTag, resourceYamlTpl, { queueName: flowTag });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const relationshipActions = [
|
|
141
|
+
'CreateRelationship',
|
|
142
|
+
'UpdateRelationship',
|
|
143
|
+
'DeleteRelationship',
|
|
144
|
+
'GetRelationship',
|
|
145
|
+
'ChangeRelationship',
|
|
146
|
+
'MoveRelationship'
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
for (const action of relationshipActions) {
|
|
150
|
+
const queueName = `${action}HdrDsq`;
|
|
151
|
+
await appendUnique(queueName, resourceSqsYamlTpl, { queueName });
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const systemQueues = [
|
|
155
|
+
'ProcessLogical',
|
|
156
|
+
'PaginateProcessLogical',
|
|
157
|
+
'FindData',
|
|
158
|
+
'Register',
|
|
159
|
+
'WebSocket',
|
|
160
|
+
'CreateObjectComplete',
|
|
161
|
+
'UpdateNodeComplete',
|
|
162
|
+
'DeleteNodeComplete',
|
|
163
|
+
'GetNodeComplete'
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
for (const sysQueue of systemQueues) {
|
|
167
|
+
const queueName = `${sysQueue}HdrSqs`;
|
|
168
|
+
await appendUnique(queueName, resourceSqsYamlTpl, { queueName });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.log(` [FlowResourceYamlGenerator] Appended ${generatedCount} sections to generated-sns-in-sqs.yml.`);
|
|
199
172
|
}
|
|
@@ -10,30 +10,30 @@
|
|
|
10
10
|
Type: AWS::SNS::Subscription
|
|
11
11
|
Properties:
|
|
12
12
|
TopicArn: !Ref In<%- queueName %>
|
|
13
|
-
Endpoint: "arn:aws:sqs:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_resourcePrefix}<%- queueName %>
|
|
13
|
+
Endpoint: "arn:aws:sqs:${self:custom.iz_region}:${self:custom.iz_accountId}:${self:custom.iz_resourcePrefix}<%- queueName %>HdrSqs"
|
|
14
14
|
Protocol: "sqs"
|
|
15
15
|
|
|
16
16
|
##===== [Queue]
|
|
17
|
-
<%- queueName %>
|
|
17
|
+
<%- queueName %>HdrSqs:
|
|
18
18
|
Type: "AWS::SQS::Queue"
|
|
19
19
|
Properties:
|
|
20
|
-
QueueName: ${self:custom.iz_resourcePrefix}<%- queueName %>
|
|
20
|
+
QueueName: ${self:custom.iz_resourcePrefix}<%- queueName %>HdrSqs
|
|
21
21
|
RedrivePolicy:
|
|
22
22
|
deadLetterTargetArn:
|
|
23
23
|
Fn::GetAtt:
|
|
24
|
-
- <%- queueName %>
|
|
24
|
+
- <%- queueName %>HdrSqsDLQ
|
|
25
25
|
- Arn
|
|
26
26
|
maxReceiveCount: 3
|
|
27
27
|
VisibilityTimeout: 120
|
|
28
28
|
|
|
29
29
|
##===== [Queue DLQ]
|
|
30
|
-
<%- queueName %>
|
|
30
|
+
<%- queueName %>HdrSqsDLQ:
|
|
31
31
|
Type: AWS::SQS::Queue
|
|
32
32
|
Properties:
|
|
33
|
-
QueueName: ${self:custom.iz_resourcePrefix}<%- queueName %>
|
|
33
|
+
QueueName: ${self:custom.iz_resourcePrefix}<%- queueName %>HdrSqsDLQ
|
|
34
34
|
|
|
35
35
|
##===== [Queue Policy]
|
|
36
|
-
<%- queueName %>
|
|
36
|
+
<%- queueName %>HdrSqsPolicy:
|
|
37
37
|
Type: AWS::SQS::QueuePolicy
|
|
38
38
|
Properties:
|
|
39
39
|
PolicyDocument:
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
Principal: "*"
|
|
45
45
|
Resource:
|
|
46
46
|
Fn::GetAtt:
|
|
47
|
-
- <%- queueName %>
|
|
47
|
+
- <%- queueName %>HdrSqs
|
|
48
48
|
- Arn
|
|
49
49
|
Action: "SQS:SendMessage"
|
|
50
50
|
Queues:
|
|
51
|
-
- Ref: <%- queueName %>
|
|
51
|
+
- Ref: <%- queueName %>HdrSqs
|
|
52
52
|
|
|
53
53
|
#<#<%- queueName %>QueueSetting#>
|
|
54
|
-
#<#/<%- queueName %>QueueSetting#>
|
|
54
|
+
#<#/<%- queueName %>QueueSetting#>
|
package/src/generateCode.js
CHANGED
|
@@ -5,8 +5,6 @@ import { parseObjectSchemas } from './parsers/objectSchemaParser.js';
|
|
|
5
5
|
import { parseRelationshipSchemas } from './parsers/relationshipSchemaParser.js';
|
|
6
6
|
import { parseFlowSchemas } from './parsers/flowSchemaParser.js';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
8
|
import { generateFlowEntryPoint } from './codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowEntryPointBase.js';
|
|
11
9
|
import { generateFlowMainFunction } from './codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowMainFunctionBase.js';
|
|
12
10
|
import { generateFlowSteps } from './codeGenerators/app/src/generatedCode/Flow/_shared/shared/flowStepBase.js';
|
|
@@ -33,85 +31,106 @@ import { generateFindDataYaml } from './codeGenerators/app/sls_yaml/FindDataYaml
|
|
|
33
31
|
import { policyRegistry } from './codeGenerators/app/sls_yaml/_policy/PolicyRegistry.js';
|
|
34
32
|
import { emitManagedPolicies } from './codeGenerators/app/sls_yaml/_policy/PolicyEmitter.js';
|
|
35
33
|
|
|
36
|
-
|
|
34
|
+
function createGeneratorOptions(rootPath, options = {}) {
|
|
35
|
+
return {
|
|
36
|
+
outputPath: options.outputPath || rootPath
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function generateCode(rootPath, options = {}) {
|
|
37
41
|
console.log(
|
|
38
42
|
'[INFO] [generateCode] STATUS=STARTING | Generating code files from all schemas...'
|
|
39
43
|
);
|
|
40
44
|
|
|
45
|
+
const generatorOptions = createGeneratorOptions(rootPath, options);
|
|
46
|
+
const { outputPath } = generatorOptions;
|
|
47
|
+
|
|
41
48
|
// Clean workspace
|
|
42
|
-
const
|
|
43
|
-
|
|
49
|
+
const generatedCodePath = path.join(
|
|
50
|
+
outputPath,
|
|
51
|
+
'app',
|
|
52
|
+
'src',
|
|
53
|
+
'generatedCode'
|
|
54
|
+
);
|
|
44
55
|
|
|
45
56
|
// Backup existing hook files to prevent them from being wiped out
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
57
|
+
const hookBackups = [];
|
|
58
|
+
const hookDirs = new Set();
|
|
59
|
+
|
|
60
|
+
function getHookTagMatchers(filePath) {
|
|
61
|
+
if (filePath.endsWith('.js')) {
|
|
62
|
+
return {
|
|
63
|
+
anyTag: /\/\/\(<(\w+)>\)([\s\S]*?)\/\/\(<\/\1>\)/gm,
|
|
64
|
+
tagPattern: name =>
|
|
65
|
+
new RegExp(
|
|
66
|
+
`\\/\\/\\(<${name}>\\)([\\s\\S]*?)\\/\\/\\(<\\/${name}>\\)`,
|
|
67
|
+
'gm'
|
|
68
|
+
)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (filePath.endsWith('.yml') || filePath.endsWith('.yaml')) {
|
|
73
|
+
return {
|
|
74
|
+
anyTag: /#<#(\w+)#>([\s\S]*?)#<#\/\1#>/gm,
|
|
75
|
+
tagPattern: name =>
|
|
76
|
+
new RegExp(`#<#${name}#>([\\s\\S]*?)#<#\\/${name}#>`, 'gm')
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function mergeHookIntoSource(sourceContent, hookContent, filePath) {
|
|
84
|
+
const matchers = getHookTagMatchers(filePath);
|
|
85
|
+
if (!matchers) return hookContent;
|
|
86
|
+
|
|
87
|
+
return sourceContent.replace(
|
|
88
|
+
matchers.anyTag,
|
|
89
|
+
(match, tagName) =>
|
|
90
|
+
hookContent.match(matchers.tagPattern(tagName))?.[0] ?? match
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function collectHookBackups(currentDir) {
|
|
95
|
+
if (!fs.existsSync(currentDir)) return;
|
|
96
|
+
|
|
97
|
+
const items = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
98
|
+
const hasSource = items.some(
|
|
99
|
+
item => item.isDirectory() && item.name === 'source'
|
|
100
|
+
);
|
|
101
|
+
const hasHook = items.some(
|
|
102
|
+
item => item.isDirectory() && item.name === 'hook'
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
if (hasSource && hasHook) {
|
|
106
|
+
const hookPath = path.join(currentDir, 'hook');
|
|
107
|
+
hookDirs.add(path.relative(outputPath, hookPath));
|
|
108
|
+
const hookItems = fs.readdirSync(hookPath, { withFileTypes: true });
|
|
109
|
+
|
|
110
|
+
for (const hookItem of hookItems) {
|
|
111
|
+
if (!hookItem.isFile()) continue;
|
|
112
|
+
const hookFilePath = path.join(hookPath, hookItem.name);
|
|
113
|
+
hookBackups.push({
|
|
114
|
+
relativePath: path.relative(outputPath, hookPath),
|
|
115
|
+
name: hookItem.name,
|
|
116
|
+
content: fs.readFileSync(hookFilePath)
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
for (const item of items) {
|
|
122
|
+
if (!item.isDirectory() || item.name === 'source' || item.name === 'hook')
|
|
123
|
+
continue;
|
|
124
|
+
collectHookBackups(path.join(currentDir, item.name));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log(
|
|
129
|
+
'[INFO] [generateCode] STATUS=BACKUP | Backing up existing hook files...'
|
|
130
|
+
);
|
|
131
|
+
collectHookBackups(outputPath);
|
|
132
|
+
|
|
133
|
+
console.log(
|
|
115
134
|
'[INFO] [generateCode] STATUS=CLEANUP | Removing old generatedCode and resource directories...'
|
|
116
135
|
);
|
|
117
136
|
await fs.promises.rm(generatedCodePath, {
|
|
@@ -150,8 +169,6 @@ console.log(
|
|
|
150
169
|
console.log('[INFO] [generateCode] STATUS=VALIDATING | Validating Flows...');
|
|
151
170
|
validateFlowsForGeneration(allSchemas.flowsForGeneration);
|
|
152
171
|
|
|
153
|
-
const generatorOptions = { outputPath: options.outputPath || rootPath };
|
|
154
|
-
|
|
155
172
|
// 2. Generation Pipeline
|
|
156
173
|
await generateEndpointsFlow(allSchemas, generatorOptions);
|
|
157
174
|
await generateFlowMainFunction(allSchemas, generatorOptions);
|
|
@@ -161,11 +178,19 @@ console.log(
|
|
|
161
178
|
await generateFlowResourceYaml(allSchemas, generatorOptions);
|
|
162
179
|
await generateRbacFlows(allSchemas, generatorOptions);
|
|
163
180
|
await generateRelationshipFlows(allSchemas, generatorOptions);
|
|
164
|
-
await generateWebSocket(
|
|
165
|
-
|
|
181
|
+
await generateWebSocket(
|
|
182
|
+
allSchemas.flowsForGeneration,
|
|
183
|
+
'',
|
|
184
|
+
generatorOptions.outputPath
|
|
185
|
+
);
|
|
186
|
+
await generateRegisterFlow(
|
|
187
|
+
allSchemas.flowsForGeneration,
|
|
188
|
+
'',
|
|
189
|
+
generatorOptions.outputPath
|
|
190
|
+
);
|
|
166
191
|
|
|
167
192
|
// Call FunctionYamlGenerator after all Handlers have been generated
|
|
168
|
-
await generateFunctionYaml(allSchemas,
|
|
193
|
+
await generateFunctionYaml(allSchemas, generatorOptions);
|
|
169
194
|
await generateDynamoDBTables(allSchemas, generatorOptions);
|
|
170
195
|
await generateFindData(allSchemas, generatorOptions);
|
|
171
196
|
await generateCodeLibs(generatorOptions);
|
|
@@ -178,69 +203,76 @@ console.log(
|
|
|
178
203
|
await generateInitialSetup(allSchemas, generatorOptions);
|
|
179
204
|
|
|
180
205
|
// 3. Hook Integration
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
206
|
+
console.log(
|
|
207
|
+
'[INFO] [generateCode] STATUS=HOOKS | Processing hook folders beside source folders...'
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
function processSourceHooks(currentDir) {
|
|
211
|
+
if (!fs.existsSync(currentDir)) return;
|
|
212
|
+
|
|
213
|
+
const items = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
214
|
+
const hasSource = items.some(
|
|
215
|
+
item => item.isDirectory() && item.name === 'source'
|
|
216
|
+
);
|
|
217
|
+
const hasHook = items.some(
|
|
218
|
+
item => item.isDirectory() && item.name === 'hook'
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
if (hasSource && hasHook) {
|
|
222
|
+
const sourcePath = path.join(currentDir, 'source');
|
|
223
|
+
const hookPath = path.join(currentDir, 'hook');
|
|
224
|
+
const hookItems = fs.readdirSync(hookPath, { withFileTypes: true });
|
|
225
|
+
|
|
226
|
+
for (const hookItem of hookItems) {
|
|
227
|
+
if (!hookItem.isFile()) continue;
|
|
228
|
+
|
|
229
|
+
const hookFile = path.join(hookPath, hookItem.name);
|
|
230
|
+
const sourceFile = path.join(sourcePath, hookItem.name);
|
|
231
|
+
|
|
232
|
+
if (!fs.existsSync(sourceFile)) {
|
|
233
|
+
fs.copyFileSync(hookFile, sourceFile);
|
|
234
|
+
console.log(
|
|
235
|
+
`[INFO] [generateCode] HOOK APPLIED: Created ${hookItem.name} from hook.`
|
|
236
|
+
);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const mergedContent = mergeHookIntoSource(
|
|
241
|
+
fs.readFileSync(sourceFile, 'utf8'),
|
|
242
|
+
fs.readFileSync(hookFile, 'utf8'),
|
|
243
|
+
sourceFile
|
|
244
|
+
);
|
|
245
|
+
fs.writeFileSync(sourceFile, mergedContent);
|
|
246
|
+
console.log(
|
|
247
|
+
`[INFO] [generateCode] HOOK APPLIED: Merged ${hookItem.name} into source.`
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
} else if (hasSource) {
|
|
251
|
+
fs.mkdirSync(path.join(currentDir, 'hook'), { recursive: true });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
for (const item of items) {
|
|
255
|
+
if (!item.isDirectory() || item.name === 'source' || item.name === 'hook')
|
|
256
|
+
continue;
|
|
257
|
+
processSourceHooks(path.join(currentDir, item.name));
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Restore backed-up hooks
|
|
262
|
+
if (hookDirs.size > 0 || hookBackups.length > 0) {
|
|
263
|
+
console.log(
|
|
264
|
+
`[INFO] [generateCode] STATUS=RESTORE | Restoring ${hookBackups.length} hook files...`
|
|
265
|
+
);
|
|
266
|
+
for (const relativeHookDir of hookDirs) {
|
|
267
|
+
fs.mkdirSync(path.join(outputPath, relativeHookDir), { recursive: true });
|
|
268
|
+
}
|
|
269
|
+
for (const backup of hookBackups) {
|
|
270
|
+
const hookDir = path.join(outputPath, backup.relativePath);
|
|
271
|
+
fs.writeFileSync(path.join(hookDir, backup.name), backup.content);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
processSourceHooks(generatorOptions.outputPath);
|
|
244
276
|
|
|
245
277
|
console.log(
|
|
246
278
|
'[INFO] [generateCode] STATUS=FINISHED | Code generation complete.'
|
package/src/schemaGenerators/app/src/schemas/FlowSchemas/templates/DynamicFlowSchemaTemplate.ejs
CHANGED
|
@@ -22,18 +22,20 @@ export default {
|
|
|
22
22
|
messageAttributes: ['userId', 'correlationId']
|
|
23
23
|
},
|
|
24
24
|
<% if (hasBeforeLogicalStep) { %>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
{
|
|
26
|
+
stepName: 'beforeLogical',
|
|
27
|
+
event: ['sqs'],
|
|
28
|
+
properties: [],
|
|
29
|
+
messageAttributes: ['userId', 'correlationId']
|
|
30
|
+
},
|
|
30
31
|
<% } %>
|
|
31
32
|
<% if (['Create', 'Update', 'Delete'].includes(action)) { %>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
{
|
|
34
|
+
stepName: 'Complete',
|
|
35
|
+
event: ['sqs'],
|
|
36
|
+
properties: [],
|
|
37
|
+
messageAttributes: ['userId', 'correlationId']
|
|
38
|
+
}
|
|
37
39
|
<% } %>
|
|
38
40
|
]
|
|
39
41
|
};
|
|
@@ -22,11 +22,12 @@ export default {
|
|
|
22
22
|
messageAttributes: ['userId', 'correlationId']
|
|
23
23
|
}
|
|
24
24
|
<% if (hasCompleteStep) { %>,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
{
|
|
26
|
+
stepName: 'Complete',
|
|
27
|
+
event: ['sqs'],
|
|
28
|
+
properties: [],
|
|
29
|
+
messageAttributes: ['userId', 'correlationId']
|
|
30
|
+
}
|
|
30
31
|
<% } %>
|
|
31
32
|
]
|
|
32
33
|
};
|