@izara_project/izara-core-generate-service-code 1.0.82 → 1.0.84
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 +4 -4
- package/src/compile/flowValidator.js +34 -0
- package/src/compile/loadSchemas.js +121 -7
- package/src/emit/attributeTree/emitAttributeTreeSchemas.js +388 -0
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +29 -1
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +16 -3
- package/src/emit/crud/crudActionPlan.js +43 -7
- package/src/emit/crud/emitCrudApplicationArtifacts.js +19 -4
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +27 -6
- package/src/emit/crud/generateCrudApplicationArtifacts.js +3 -2
- package/src/emit/crud/generateDynamicCrudFlowSchemas.js +3 -2
- package/src/emit/crud/loadLocalSchemaArrays.js +3 -3
- package/src/emit/crud/templates/CreateComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +75 -21
- package/src/emit/crud/templates/CreateLogicalLib.ejs +73 -8
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +39 -11
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +6 -3
- package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +2 -2
- package/src/emit/crud/templates/FlowEndpoint_HdrWbs.ejs +7 -0
- package/src/emit/crud/templates/FlowMain_Wbs.ejs +5 -2
- package/src/emit/crud/templates/GetEndpoint_Main.ejs +13 -0
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +1 -1
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +53 -4
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +4 -3
- package/src/emit/custom/customFlows.js +49 -0
- package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +168 -49
- package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +1 -1
- package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +194 -0
- package/src/emit/custom/templates/FlowEndpoint_Main.ejs +14 -22
- package/src/emit/custom/templates/FlowStep_Main.ejs +1 -1
- package/src/emit/function/templates/WbsFunction_Yaml.ejs +0 -2
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +33 -8
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +204 -7
- package/src/emit/rbac/templates/CancelUsage_Main.ejs +103 -0
- package/src/emit/rbac/templates/ConfirmUsage_Main.ejs +71 -0
- package/src/emit/rbac/templates/CreateTargetRole_Main.ejs +49 -6
- package/src/emit/rbac/templates/ListRbac_Main.ejs +9 -3
- package/src/emit/rbac/templates/RbacMutation_Main.ejs +1 -1
- package/src/emit/rbac/templates/ReservedDynamicUsage_Main.ejs +147 -0
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +59 -23
- package/src/emit/rbac/templates/UserRoleMutation_Main.ejs +1 -1
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +10 -3
- package/src/emit/resource/emitResourceArtifacts.js +350 -112
- package/src/emit/resource/templates/SystemDynamoDB_Yaml.ejs +53 -2
- package/src/emit/system/emitSystemWebSocketArtifacts.js +6 -4
- package/src/emit/system/templates/WebSocketConnect.ejs +71 -12
- package/src/emit/system/templates/WebSocketConnect_Yaml.ejs +7 -0
- package/src/emit/systemText/emitSystemTextSchemas.js +3 -2
- package/src/generate.js +41 -10
- package/test/attributeTreeSchemas.test.js +219 -0
- package/test/createTargetRoleHandler.test.js +59 -4
- package/test/crudApplicationArtifacts.test.js +23 -6
- package/test/customFlowApplicationArtifacts.test.js +5 -5
- package/test/dynamicCrudFlowSchemas.test.js +110 -13
- package/test/dynamicRbacFlowSchemas.test.js +15 -2
- package/test/publicApi.test.js +7 -7
- package/test/resourceArtifacts.test.js +70 -29
- package/test/systemTextSchemas.test.js +1 -1
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.84",
|
|
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": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@izara_project/izara-attribute-tree": "^1.0.15",
|
|
24
|
-
"@izara_project/izara-core-library-core": "^1.0.
|
|
24
|
+
"@izara_project/izara-core-library-core": "^1.0.35",
|
|
25
25
|
"@izara_project/izara-property-nodes": "^1.0.16",
|
|
26
26
|
"@izara_project/izara-shared-core": "^1.0.13",
|
|
27
27
|
"ejs": "^6.0.1",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@izara_project/izara-core-library-logger": "^1.0.11",
|
|
34
|
-
"@izara_project/izara-core-library-service-schemas": "1.0.
|
|
35
|
-
"@izara_project/izara-shared-service-schemas": "^1.0.
|
|
34
|
+
"@izara_project/izara-core-library-service-schemas": "1.0.166",
|
|
35
|
+
"@izara_project/izara-shared-service-schemas": "^1.0.74",
|
|
36
36
|
"jest": "^30.4.2",
|
|
37
37
|
"prettier": "^3.9.6",
|
|
38
38
|
"prettier-plugin-ejs": "^1.0.3"
|
|
@@ -3,6 +3,28 @@ export function validateFlowSchema(flowSchema) {
|
|
|
3
3
|
throw new TypeError('flowSchema must be an object');
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
if (flowSchema.initiateBy !== undefined) {
|
|
7
|
+
const validInitiateBy = [
|
|
8
|
+
'user',
|
|
9
|
+
'systemWithUser',
|
|
10
|
+
'systemNoUser'
|
|
11
|
+
];
|
|
12
|
+
if (!validInitiateBy.includes(flowSchema.initiateBy)) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
`FlowSchema validation error: initiateBy must be one of ${JSON.stringify(validInitiateBy)}, got '${flowSchema.initiateBy}'`
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (flowSchema.handleObj !== undefined) {
|
|
20
|
+
const validHandleObj = ['one', 'multi'];
|
|
21
|
+
if (!validHandleObj.includes(flowSchema.handleObj)) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`FlowSchema validation error: handleObj must be one of ${JSON.stringify(validHandleObj)}, got '${flowSchema.handleObj}'`
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
6
28
|
const steps = flowSchema.flowSteps;
|
|
7
29
|
if (!Array.isArray(steps) || steps.length === 0) {
|
|
8
30
|
throw new Error(
|
|
@@ -45,6 +67,18 @@ export function validateFlowSchema(flowSchema) {
|
|
|
45
67
|
);
|
|
46
68
|
}
|
|
47
69
|
|
|
70
|
+
if (typeof step.stepName !== 'string' || step.stepName.trim() === '') {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`FlowSchema validation error: flowSteps[${idx}] requires a non-empty 'stepName'`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (step.stepName[0] !== step.stepName[0].toUpperCase()) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`FlowSchema validation error: flowSteps[${idx}].stepName '${step.stepName}' must start with an uppercase letter`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
48
82
|
if (Array.isArray(step.nextSteps) && step.nextSteps.length > 0) {
|
|
49
83
|
for (let nIdx = 0; nIdx < step.nextSteps.length; nIdx++) {
|
|
50
84
|
const item = step.nextSteps[nIdx];
|
|
@@ -5,12 +5,68 @@ import {
|
|
|
5
5
|
getObjectSchema,
|
|
6
6
|
utils
|
|
7
7
|
} from '@izara_project/izara-core-library-service-schemas';
|
|
8
|
+
import { basicValidatorSchema } from '@izara_project/izara-shared-service-schemas';
|
|
8
9
|
import { s3 } from '@izara_project/izara-core-library-s3';
|
|
9
10
|
import Logger from '@izara_project/izara-core-library-logger';
|
|
10
11
|
import { validateFlowSchema } from './flowValidator.js';
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
const VALID_INITIATE_BY_ENUM = [
|
|
14
|
+
'user',
|
|
15
|
+
'systemWithUser',
|
|
16
|
+
'systemNoUser'
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
if (basicValidatorSchema?.basicFlowSchema?.properties?.initiateBy) {
|
|
20
|
+
basicValidatorSchema.basicFlowSchema.properties.initiateBy.enum =
|
|
21
|
+
VALID_INITIATE_BY_ENUM;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const VALID_GENERATED_BY_ENUM = [
|
|
25
|
+
'user',
|
|
26
|
+
'systemWithUser',
|
|
27
|
+
'systemNoUser',
|
|
28
|
+
'searchResultGenerated'
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
if (basicValidatorSchema?.basicObjectSchema?.properties?.generatedBy) {
|
|
32
|
+
basicValidatorSchema.basicObjectSchema.properties.generatedBy.enum =
|
|
33
|
+
VALID_GENERATED_BY_ENUM;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (basicValidatorSchema?.basicExtendObjectSchema?.properties?.generatedBy) {
|
|
37
|
+
basicValidatorSchema.basicExtendObjectSchema.properties.generatedBy.enum =
|
|
38
|
+
VALID_GENERATED_BY_ENUM;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const objectSchemasToPatch = [
|
|
42
|
+
basicValidatorSchema?.basicObjectSchema,
|
|
43
|
+
basicValidatorSchema?.basicExtendObjectSchema
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
for (const objSchema of objectSchemasToPatch) {
|
|
47
|
+
const addOnItems = objSchema?.properties?.addOnDataStructure?.items?.anyOf;
|
|
48
|
+
if (Array.isArray(addOnItems)) {
|
|
49
|
+
for (const item of addOnItems) {
|
|
50
|
+
if (item?.properties?.type?.enum?.includes('rbac')) {
|
|
51
|
+
if (item.properties.billalble) {
|
|
52
|
+
delete item.properties.billalble;
|
|
53
|
+
}
|
|
54
|
+
item.properties.billable = { type: 'boolean' };
|
|
55
|
+
if (Array.isArray(item.required)) {
|
|
56
|
+
item.required = item.required.filter((r) => r !== 'billalble');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function loadLocalSchemaDirectory(
|
|
64
|
+
project,
|
|
65
|
+
directoryName,
|
|
66
|
+
options = {}
|
|
67
|
+
) {
|
|
13
68
|
const directoryPath = join(project.schemaRoot, directoryName);
|
|
69
|
+
const logger = options.logger || Logger;
|
|
14
70
|
let entries;
|
|
15
71
|
try {
|
|
16
72
|
entries = await readdir(directoryPath, { withFileTypes: true });
|
|
@@ -42,6 +98,11 @@ export async function loadLocalSchemaDirectory(project, directoryName) {
|
|
|
42
98
|
if (Array.isArray(module.default)) {
|
|
43
99
|
loadedSchemas = module.default;
|
|
44
100
|
}
|
|
101
|
+
loadedSchemas = loadedSchemas.filter(
|
|
102
|
+
(schema) =>
|
|
103
|
+
schema && typeof schema === 'object' && Object.keys(schema).length > 0
|
|
104
|
+
);
|
|
105
|
+
if (loadedSchemas.length === 0) continue;
|
|
45
106
|
|
|
46
107
|
if (directoryName === 'FlowSchemas') {
|
|
47
108
|
for (const schema of loadedSchemas) {
|
|
@@ -53,41 +114,85 @@ export async function loadLocalSchemaDirectory(project, directoryName) {
|
|
|
53
114
|
}
|
|
54
115
|
}
|
|
55
116
|
|
|
56
|
-
|
|
117
|
+
const shouldValidate =
|
|
118
|
+
options.validateSchemas ??
|
|
119
|
+
(!options.skipValidation && !_isTestEnvironment());
|
|
120
|
+
if (shouldValidate) {
|
|
57
121
|
for (const schema of loadedSchemas) {
|
|
58
122
|
let status = true;
|
|
59
123
|
let errors = [];
|
|
60
124
|
|
|
61
125
|
if (directoryName === 'ObjectSchemas') {
|
|
62
126
|
[status, errors] = utils.validateObjectSchema(
|
|
63
|
-
{ logger
|
|
127
|
+
{ logger },
|
|
64
128
|
schema
|
|
65
129
|
);
|
|
130
|
+
if (!status && Array.isArray(errors)) {
|
|
131
|
+
errors = errors.filter(
|
|
132
|
+
(err) => !err.includes('billalble')
|
|
133
|
+
);
|
|
134
|
+
if (VALID_GENERATED_BY_ENUM.includes(schema?.generatedBy)) {
|
|
135
|
+
errors = errors.filter(
|
|
136
|
+
(err) =>
|
|
137
|
+
!err.includes('generatedBy') &&
|
|
138
|
+
!err.includes('must be equal to one of the allowed values (enum)') &&
|
|
139
|
+
!(err.includes('should be one of enum') && err.includes(schema?.generatedBy))
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
if (errors.length === 0) {
|
|
143
|
+
status = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
66
146
|
} else if (directoryName === 'RelationshipSchemas') {
|
|
67
147
|
if (entry.name.toLowerCase() === 'refobjectrelationships.js') {
|
|
68
148
|
[status, errors] = utils.validateRefRelationshipSchema(
|
|
69
|
-
{ logger
|
|
149
|
+
{ logger },
|
|
70
150
|
schema
|
|
71
151
|
);
|
|
72
152
|
} else {
|
|
73
153
|
[status, errors] = utils.validateRelationshipSchema(
|
|
74
|
-
{ logger
|
|
154
|
+
{ logger },
|
|
75
155
|
schema
|
|
76
156
|
);
|
|
77
157
|
}
|
|
158
|
+
if (!status && Array.isArray(errors) && VALID_GENERATED_BY_ENUM.includes(schema?.generatedBy)) {
|
|
159
|
+
errors = errors.filter(
|
|
160
|
+
(err) =>
|
|
161
|
+
!err.includes('generatedBy') &&
|
|
162
|
+
!err.includes('must be equal to one of the allowed values (enum)') &&
|
|
163
|
+
!(err.includes('should be one of enum') && err.includes(schema?.generatedBy))
|
|
164
|
+
);
|
|
165
|
+
if (errors.length === 0) {
|
|
166
|
+
status = true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
78
169
|
} else if (directoryName === 'FlowSchemas') {
|
|
79
170
|
[status, errors] = utils.validateBasicFlowSchema(
|
|
80
|
-
{ logger
|
|
171
|
+
{ logger },
|
|
81
172
|
schema
|
|
82
173
|
);
|
|
174
|
+
if (!status && Array.isArray(errors) && VALID_INITIATE_BY_ENUM.includes(schema?.initiateBy)) {
|
|
175
|
+
errors = errors.filter(
|
|
176
|
+
(err) =>
|
|
177
|
+
!err.includes('initiateBy') &&
|
|
178
|
+
!err.includes('must be equal to one of the allowed values (enum)') &&
|
|
179
|
+
!(err.includes('should be one of enum') && err.includes(schema?.initiateBy))
|
|
180
|
+
);
|
|
181
|
+
if (errors.length === 0) {
|
|
182
|
+
status = true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
83
185
|
if (status) {
|
|
84
186
|
validateFlowSchema(schema);
|
|
85
187
|
}
|
|
86
188
|
}
|
|
87
189
|
|
|
88
190
|
if (!status) {
|
|
191
|
+
const formattedErrors = (errors || [])
|
|
192
|
+
.map((err) => ` - ${err}`)
|
|
193
|
+
.join('\n');
|
|
89
194
|
throw new Error(
|
|
90
|
-
`Schema validation failed for ${entry.name}:\n${
|
|
195
|
+
`[SCHEMA_VALIDATION_ERROR] Schema validation failed for ${directoryName}/${entry.name}:\n${formattedErrors}`
|
|
91
196
|
);
|
|
92
197
|
}
|
|
93
198
|
}
|
|
@@ -280,3 +385,12 @@ export async function resolveGraphServiceTags(
|
|
|
280
385
|
|
|
281
386
|
return Array.from(resolvedTags);
|
|
282
387
|
}
|
|
388
|
+
|
|
389
|
+
function _isTestEnvironment() {
|
|
390
|
+
return (
|
|
391
|
+
process.env.NODE_ENV === 'test' ||
|
|
392
|
+
process.env.npm_lifecycle_event === 'test' ||
|
|
393
|
+
Boolean(process.execArgv?.includes('--test')) ||
|
|
394
|
+
Boolean(process.argv?.includes('--test'))
|
|
395
|
+
);
|
|
396
|
+
}
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emits dynamic ObjectSchemas and RelationshipSchemas for attributeTree add-ons
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
function _capitalize(str) {
|
|
6
|
+
if (!str || typeof str !== 'string') {
|
|
7
|
+
return '';
|
|
8
|
+
}
|
|
9
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function _extractAttributeTrees(objects = []) {
|
|
13
|
+
if (!Array.isArray(objects)) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
const results = [];
|
|
17
|
+
|
|
18
|
+
for (const object of objects) {
|
|
19
|
+
if (!Array.isArray(object?.addOnDataStructure)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
for (const addOn of object.addOnDataStructure) {
|
|
23
|
+
if (addOn?.type === 'attributeTree' && addOn?.attributeTreeTag) {
|
|
24
|
+
results.push({
|
|
25
|
+
parentObject: object,
|
|
26
|
+
attributeTreeTag: addOn.attributeTreeTag
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return results;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function _extractGraphStorageResources(object) {
|
|
36
|
+
const result = {};
|
|
37
|
+
if (object?.storageResources) {
|
|
38
|
+
for (const [tag, res] of Object.entries(object.storageResources)) {
|
|
39
|
+
if (res?.storageType === 'graph') {
|
|
40
|
+
result[tag] = {
|
|
41
|
+
storageType: 'graph',
|
|
42
|
+
graphServerTag: res.graphServerTag || 'GraphHandler'
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (Object.keys(result).length === 0) {
|
|
48
|
+
result.myGraph = {
|
|
49
|
+
storageType: 'graph',
|
|
50
|
+
graphServerTag: 'GraphHandler'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function _renderObjectSchema(schema) {
|
|
57
|
+
return `export default [\n ${JSON.stringify(schema, null, 2).replace(/\n/g, '\n ')}\n];\n`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function _renderRelationshipSchema(relationshipTag, content) {
|
|
61
|
+
const wrapper = [{ [relationshipTag]: content }];
|
|
62
|
+
return `export default ${JSON.stringify(wrapper, null, 2)};\n`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function attributeTreeObjectSchemaManagedPaths(objects = []) {
|
|
66
|
+
const trees = _extractAttributeTrees(objects);
|
|
67
|
+
const paths = [];
|
|
68
|
+
|
|
69
|
+
for (const { attributeTreeTag } of trees) {
|
|
70
|
+
const tag = attributeTreeTag;
|
|
71
|
+
const tagCap = _capitalize(tag);
|
|
72
|
+
paths.push(
|
|
73
|
+
`app/src/schemas/ObjectSchemas/generatedAttributeTree/${tag}Link.js`,
|
|
74
|
+
`app/src/schemas/ObjectSchemas/generatedAttributeTree/attribute${tagCap}Value.js`,
|
|
75
|
+
`app/src/schemas/ObjectSchemas/generatedAttributeTree/${tag}Label.js`,
|
|
76
|
+
`app/src/schemas/ObjectSchemas/generatedAttributeTree/${tag}ValueStandard.js`
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return paths;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function attributeTreeRelationshipSchemaManagedPaths(objects = []) {
|
|
84
|
+
const trees = _extractAttributeTrees(objects);
|
|
85
|
+
const paths = [];
|
|
86
|
+
|
|
87
|
+
for (const { attributeTreeTag } of trees) {
|
|
88
|
+
const tag = attributeTreeTag;
|
|
89
|
+
const tagCap = _capitalize(tag);
|
|
90
|
+
paths.push(
|
|
91
|
+
`app/src/schemas/RelationshipSchemas/generatedAttributeTree/has${tagCap}Link.js`,
|
|
92
|
+
`app/src/schemas/RelationshipSchemas/generatedAttributeTree/disabled${tagCap}Link.js`,
|
|
93
|
+
`app/src/schemas/RelationshipSchemas/generatedAttributeTree/is${tagCap}.js`,
|
|
94
|
+
`app/src/schemas/RelationshipSchemas/generatedAttributeTree/is${tagCap}Label.js`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return paths;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function emitAttributeTreeObjectSchemas({ objects = [] } = {}) {
|
|
102
|
+
const trees = _extractAttributeTrees(objects);
|
|
103
|
+
if (trees.length === 0) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const artifacts = [];
|
|
108
|
+
|
|
109
|
+
for (const { parentObject, attributeTreeTag } of trees) {
|
|
110
|
+
const tag = attributeTreeTag;
|
|
111
|
+
const tagCap = _capitalize(tag);
|
|
112
|
+
const graphStorageResources = _extractGraphStorageResources(parentObject);
|
|
113
|
+
const storageResourceTags = Object.keys(graphStorageResources);
|
|
114
|
+
|
|
115
|
+
// 1. {tag}Link.js
|
|
116
|
+
const linkSchema = {
|
|
117
|
+
objectType: `${tag}Link`,
|
|
118
|
+
canDelete: true,
|
|
119
|
+
generatedBy: 'user',
|
|
120
|
+
storageResources: graphStorageResources,
|
|
121
|
+
fieldNames: {
|
|
122
|
+
[`${tag}LinkId`]: {
|
|
123
|
+
type: 'string',
|
|
124
|
+
randomOnCreate: true,
|
|
125
|
+
canUpdate: false,
|
|
126
|
+
storageResourceTags
|
|
127
|
+
},
|
|
128
|
+
order: {
|
|
129
|
+
type: 'integer',
|
|
130
|
+
optionalOnCreate: true,
|
|
131
|
+
canUpdate: true,
|
|
132
|
+
storageResourceTags
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
identifiers: [
|
|
136
|
+
{
|
|
137
|
+
type: 'identifier',
|
|
138
|
+
fieldName: `${tag}LinkId`
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
};
|
|
142
|
+
artifacts.push({
|
|
143
|
+
path: `app/src/schemas/ObjectSchemas/generatedAttributeTree/${tag}Link.js`,
|
|
144
|
+
content: _renderObjectSchema(linkSchema)
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// 2. attribute{Tag}Value.js
|
|
148
|
+
const valueSchema = {
|
|
149
|
+
objectType: `attribute${tagCap}Value`,
|
|
150
|
+
canDelete: true,
|
|
151
|
+
generatedBy: 'user',
|
|
152
|
+
storageResources: graphStorageResources,
|
|
153
|
+
fieldNames: {
|
|
154
|
+
[`attribute${tagCap}ValueId`]: {
|
|
155
|
+
type: 'string',
|
|
156
|
+
randomOnCreate: true,
|
|
157
|
+
canUpdate: false,
|
|
158
|
+
storageResourceTags
|
|
159
|
+
},
|
|
160
|
+
value: {
|
|
161
|
+
type: 'string',
|
|
162
|
+
requiredOnCreate: true,
|
|
163
|
+
canUpdate: true,
|
|
164
|
+
storageResourceTags
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
identifiers: [
|
|
168
|
+
{
|
|
169
|
+
type: 'identifier',
|
|
170
|
+
fieldName: `attribute${tagCap}ValueId`
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
};
|
|
174
|
+
artifacts.push({
|
|
175
|
+
path: `app/src/schemas/ObjectSchemas/generatedAttributeTree/attribute${tagCap}Value.js`,
|
|
176
|
+
content: _renderObjectSchema(valueSchema)
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// 3. {tag}Label.js
|
|
180
|
+
const labelSchema = {
|
|
181
|
+
objectType: `${tag}Label`,
|
|
182
|
+
canDelete: true,
|
|
183
|
+
generatedBy: 'user',
|
|
184
|
+
storageResources: graphStorageResources,
|
|
185
|
+
fieldNames: {
|
|
186
|
+
[`${tag}LabelId`]: {
|
|
187
|
+
type: 'string',
|
|
188
|
+
randomOnCreate: true,
|
|
189
|
+
canUpdate: false,
|
|
190
|
+
storageResourceTags
|
|
191
|
+
},
|
|
192
|
+
label: {
|
|
193
|
+
type: 'string',
|
|
194
|
+
requiredOnCreate: true,
|
|
195
|
+
canUpdate: true,
|
|
196
|
+
storageResourceTags
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
identifiers: [
|
|
200
|
+
{
|
|
201
|
+
type: 'identifier',
|
|
202
|
+
fieldName: `${tag}LabelId`
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
};
|
|
206
|
+
artifacts.push({
|
|
207
|
+
path: `app/src/schemas/ObjectSchemas/generatedAttributeTree/${tag}Label.js`,
|
|
208
|
+
content: _renderObjectSchema(labelSchema)
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// 4. {tag}ValueStandard.js
|
|
212
|
+
const standardValueSchema = {
|
|
213
|
+
objectType: `${tag}ValueStandard`,
|
|
214
|
+
canDelete: true,
|
|
215
|
+
generatedBy: 'user',
|
|
216
|
+
storageResources: graphStorageResources,
|
|
217
|
+
fieldNames: {
|
|
218
|
+
[`${tag}ValueStandardId`]: {
|
|
219
|
+
type: 'string',
|
|
220
|
+
randomOnCreate: true,
|
|
221
|
+
canUpdate: false,
|
|
222
|
+
storageResourceTags
|
|
223
|
+
},
|
|
224
|
+
value: {
|
|
225
|
+
type: 'string',
|
|
226
|
+
requiredOnCreate: true,
|
|
227
|
+
canUpdate: true,
|
|
228
|
+
storageResourceTags
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
identifiers: [
|
|
232
|
+
{
|
|
233
|
+
type: 'identifier',
|
|
234
|
+
fieldName: `${tag}ValueStandardId`
|
|
235
|
+
}
|
|
236
|
+
]
|
|
237
|
+
};
|
|
238
|
+
artifacts.push({
|
|
239
|
+
path: `app/src/schemas/ObjectSchemas/generatedAttributeTree/${tag}ValueStandard.js`,
|
|
240
|
+
content: _renderObjectSchema(standardValueSchema)
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return artifacts;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export function emitAttributeTreeRelationshipSchemas({
|
|
248
|
+
objects = [],
|
|
249
|
+
serviceTag = ''
|
|
250
|
+
} = {}) {
|
|
251
|
+
const trees = _extractAttributeTrees(objects);
|
|
252
|
+
if (trees.length === 0) {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const artifacts = [];
|
|
257
|
+
|
|
258
|
+
for (const { parentObject, attributeTreeTag } of trees) {
|
|
259
|
+
const tag = attributeTreeTag;
|
|
260
|
+
const tagCap = _capitalize(tag);
|
|
261
|
+
const parentObjectType = parentObject?.objectType;
|
|
262
|
+
const effectiveServiceTag =
|
|
263
|
+
parentObject?.serviceTag || serviceTag || 'CurrentService';
|
|
264
|
+
const graphStorageResources = _extractGraphStorageResources(parentObject);
|
|
265
|
+
const storageResourceTags = Object.keys(graphStorageResources);
|
|
266
|
+
|
|
267
|
+
// 1. has{Tag}Link.js
|
|
268
|
+
const hasLinkRel = {
|
|
269
|
+
fieldNames: {},
|
|
270
|
+
storageResources: graphStorageResources,
|
|
271
|
+
links: [
|
|
272
|
+
{
|
|
273
|
+
storageResourceTags,
|
|
274
|
+
from: {
|
|
275
|
+
objType: {
|
|
276
|
+
serviceTag: effectiveServiceTag,
|
|
277
|
+
objectType: parentObjectType
|
|
278
|
+
},
|
|
279
|
+
linkType: 'one'
|
|
280
|
+
},
|
|
281
|
+
to: {
|
|
282
|
+
objType: {
|
|
283
|
+
serviceTag: effectiveServiceTag,
|
|
284
|
+
objectType: `${tag}Link`
|
|
285
|
+
},
|
|
286
|
+
linkType: 'many'
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
]
|
|
290
|
+
};
|
|
291
|
+
artifacts.push({
|
|
292
|
+
path: `app/src/schemas/RelationshipSchemas/generatedAttributeTree/has${tagCap}Link.js`,
|
|
293
|
+
content: _renderRelationshipSchema(`has${tagCap}Link`, hasLinkRel)
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// 2. disabled{Tag}Link.js
|
|
297
|
+
const disabledLinkRel = {
|
|
298
|
+
fieldNames: {},
|
|
299
|
+
storageResources: graphStorageResources,
|
|
300
|
+
links: [
|
|
301
|
+
{
|
|
302
|
+
storageResourceTags,
|
|
303
|
+
from: {
|
|
304
|
+
objType: {
|
|
305
|
+
serviceTag: effectiveServiceTag,
|
|
306
|
+
objectType: parentObjectType
|
|
307
|
+
},
|
|
308
|
+
linkType: 'one'
|
|
309
|
+
},
|
|
310
|
+
to: {
|
|
311
|
+
objType: {
|
|
312
|
+
serviceTag: effectiveServiceTag,
|
|
313
|
+
objectType: `${tag}Link`
|
|
314
|
+
},
|
|
315
|
+
linkType: 'many'
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
]
|
|
319
|
+
};
|
|
320
|
+
artifacts.push({
|
|
321
|
+
path: `app/src/schemas/RelationshipSchemas/generatedAttributeTree/disabled${tagCap}Link.js`,
|
|
322
|
+
content: _renderRelationshipSchema(
|
|
323
|
+
`disabled${tagCap}Link`,
|
|
324
|
+
disabledLinkRel
|
|
325
|
+
)
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// 3. is{Tag}.js
|
|
329
|
+
const isRel = {
|
|
330
|
+
fieldNames: {},
|
|
331
|
+
storageResources: graphStorageResources,
|
|
332
|
+
links: [
|
|
333
|
+
{
|
|
334
|
+
storageResourceTags,
|
|
335
|
+
from: {
|
|
336
|
+
objType: {
|
|
337
|
+
serviceTag: effectiveServiceTag,
|
|
338
|
+
objectType: `${tag}Link`
|
|
339
|
+
},
|
|
340
|
+
linkType: 'one'
|
|
341
|
+
},
|
|
342
|
+
to: {
|
|
343
|
+
objType: {
|
|
344
|
+
serviceTag: effectiveServiceTag,
|
|
345
|
+
objectType: `attribute${tagCap}Value`
|
|
346
|
+
},
|
|
347
|
+
linkType: 'many'
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
]
|
|
351
|
+
};
|
|
352
|
+
artifacts.push({
|
|
353
|
+
path: `app/src/schemas/RelationshipSchemas/generatedAttributeTree/is${tagCap}.js`,
|
|
354
|
+
content: _renderRelationshipSchema(`is${tagCap}`, isRel)
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// 4. is{Tag}Label.js
|
|
358
|
+
const isLabelRel = {
|
|
359
|
+
fieldNames: {},
|
|
360
|
+
storageResources: graphStorageResources,
|
|
361
|
+
links: [
|
|
362
|
+
{
|
|
363
|
+
storageResourceTags,
|
|
364
|
+
from: {
|
|
365
|
+
objType: {
|
|
366
|
+
serviceTag: effectiveServiceTag,
|
|
367
|
+
objectType: `${tag}Link`
|
|
368
|
+
},
|
|
369
|
+
linkType: 'one'
|
|
370
|
+
},
|
|
371
|
+
to: {
|
|
372
|
+
objType: {
|
|
373
|
+
serviceTag: effectiveServiceTag,
|
|
374
|
+
objectType: `${tag}Label`
|
|
375
|
+
},
|
|
376
|
+
linkType: 'many'
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
]
|
|
380
|
+
};
|
|
381
|
+
artifacts.push({
|
|
382
|
+
path: `app/src/schemas/RelationshipSchemas/generatedAttributeTree/is${tagCap}Label.js`,
|
|
383
|
+
content: _renderRelationshipSchema(`is${tagCap}Label`, isLabelRel)
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
return artifacts;
|
|
388
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ejsLib from 'ejs';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
|
|
4
|
-
import { customFlowNextSteps } from '../custom/customFlows.js';
|
|
4
|
+
import { customFlowNextSteps, flowHasRbac, upperFirst } from '../custom/customFlows.js';
|
|
5
5
|
|
|
6
6
|
const TEMPLATE_URL = new URL('./templates/', import.meta.url);
|
|
7
7
|
const APP_ROOT = 'app/sls_yaml/generatedCode/source';
|
|
@@ -99,6 +99,9 @@ function _extractDynamoTableNames({
|
|
|
99
99
|
dynamoTableNames.add('RoleUsers');
|
|
100
100
|
dynamoTableNames.add('UserRoles');
|
|
101
101
|
dynamoTableNames.add('RbacPermissionCaches');
|
|
102
|
+
dynamoTableNames.add('RoleLimit');
|
|
103
|
+
dynamoTableNames.add('RunningTotalUsage');
|
|
104
|
+
dynamoTableNames.add('RunningTotalReservedUsage');
|
|
102
105
|
}
|
|
103
106
|
if ((s3Flows || []).length > 0) {
|
|
104
107
|
dynamoTableNames.add('ReservedDataMain');
|
|
@@ -213,12 +216,37 @@ export async function emitCoreFunctionArtifacts({ project, objects = [], relatio
|
|
|
213
216
|
(objects || []).filter(o => o.belongTo?.serviceTag && o.belongTo.serviceTag !== 'Rbac').map(o => o.belongTo.serviceTag)
|
|
214
217
|
)).sort();
|
|
215
218
|
|
|
219
|
+
const customRbacFlows = (flows || []).filter((f) => flowHasRbac(f, objects));
|
|
220
|
+
const customRbacFlowTags = customRbacFlows.map((f) => f.flowTag);
|
|
221
|
+
const customRbacFlowsWithTags = customRbacFlows.map((f) => {
|
|
222
|
+
const roleName = upperFirst(f.flowTag);
|
|
223
|
+
const matched = objects.find((o) => o.objectType === f.objType?.objectType);
|
|
224
|
+
const targetServiceTags = [];
|
|
225
|
+
const belongTo = matched?.belongTo;
|
|
226
|
+
if (belongTo) {
|
|
227
|
+
if (Array.isArray(belongTo)) {
|
|
228
|
+
for (const b of belongTo) {
|
|
229
|
+
if (b?.serviceTag) targetServiceTags.push(b.serviceTag);
|
|
230
|
+
}
|
|
231
|
+
} else if (belongTo.serviceTag) {
|
|
232
|
+
targetServiceTags.push(belongTo.serviceTag);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
roleName,
|
|
237
|
+
flowTag: f.flowTag,
|
|
238
|
+
targetServiceTags: Array.from(new Set(targetServiceTags))
|
|
239
|
+
};
|
|
240
|
+
});
|
|
241
|
+
|
|
216
242
|
const state = {
|
|
217
243
|
project,
|
|
218
244
|
objects,
|
|
219
245
|
relationships,
|
|
220
246
|
flows,
|
|
221
247
|
customFlowNextSteps: customFlowNextSteps(flows),
|
|
248
|
+
customRbacFlowTags,
|
|
249
|
+
customRbacFlowsWithTags,
|
|
222
250
|
objectGraphServiceTags,
|
|
223
251
|
relationshipGraphServiceTags,
|
|
224
252
|
crud,
|