@izara_project/izara-core-generate-service-code 1.0.97 → 1.0.99
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/compile/flowValidator.js +45 -8
- package/src/compile/loadSchemas.js +26 -6
- package/src/emit/application/coreFunction/emitCoreFunctionArtifacts.js +15 -1
- package/src/emit/application/coreFunction/templates/InitialSetupConfig.ejs +8 -4
- package/src/emit/application/crud/templates/CreateEndpoint_Main.ejs +4 -4
- package/src/emit/application/crud/templates/CreateLogicalLib.ejs +60 -8
- package/src/emit/application/crud/templates/DeleteEndpoint_Main.ejs +4 -4
- package/src/emit/application/crud/templates/FlowEndpoint_HdrWbs.ejs +2 -2
- package/src/emit/application/crud/templates/FlowMain_Wbs.ejs +2 -2
- package/src/emit/application/crud/templates/UpdateEndpoint_Main.ejs +4 -4
- package/src/emit/application/custom/customFlowS3.js +4 -4
- package/src/emit/application/custom/templates/FlowEndpoint_Main.ejs +2 -2
- package/src/emit/application/custom/templates/s3/CreateObject_Main.ejs +5 -2
- package/src/emit/application/custom/templates/triggerCache/CheckTriggerCache_Main.ejs +2 -2
- package/src/emit/application/rbac/emitDynamicRbacFlowSchemas.js +4 -1
- package/src/emit/application/rbac/emitRbacApplicationArtifacts.js +76 -1
- package/src/emit/application/rbac/templates/ReservedDynamicUsage_Main.ejs +2 -0
- package/src/emit/application/rbac/templates/ReservedUsageTtlExpired_HdrDss.ejs +176 -0
- package/src/emit/application/relationship/templates/ChangeRelationship_Main.ejs +3 -2
- package/src/emit/application/relationship/templates/CreateRelationship_Main.ejs +3 -2
- package/src/emit/application/relationship/templates/DeleteRelationship_Main.ejs +3 -2
- package/src/emit/application/relationship/templates/GetRelationship_Main.ejs +3 -2
- package/src/emit/application/relationship/templates/MoveRelationship_Main.ejs +3 -2
- package/src/emit/application/relationship/templates/UpdateRelationship_Main.ejs +3 -2
- package/src/emit/application/system/templates/RegisterComplete_Main.ejs +6 -2
- package/src/emit/application/system/templates/Register_Main.ejs +6 -2
- package/src/emit/application/system/templates/WebSocketComplete_Main.ejs +3 -3
- package/src/emit/infrastructure/functions/functionYamlArtifact.js +28 -0
- package/src/emit/infrastructure/functions/templates/DssFunction_Yaml.ejs +21 -0
- package/src/emit/infrastructure/resources/iamResourceArtifacts.js +46 -6
- package/src/emit/infrastructure/resources/templates/GeneratedLambdaRoleServiceConfig.ejs +5 -3
- package/src/emit/schemas/attributeTree/emitAttributeTreeSchemas.js +75 -22
- package/src/emit/schemas/ledger/emitLedgerSchemas.js +33 -11
- package/src/emit/schemas/ledger/templates/LedgerObjectSchema.ejs +3 -0
- package/src/emit/schemas/ledger/templates/LedgerRelationshipSchema.ejs +1 -0
- package/src/emit/schemas/propertyValue/emitPropertyValueSchemas.js +329 -0
- package/src/generate.js +10 -73
- package/src/output/mergeHooks.js +169 -15
- package/src/plan/domainRegistry.js +31 -5
- package/task.md +76 -0
- package/test/integration/graphDrivenFlowSchema.test.js +58 -0
- package/test/integration/publicApi.test.js +54 -1
- package/test/unit/application/createTargetRoleHandler.test.js +70 -1
- package/test/unit/application/crudApplicationArtifacts.test.js +4 -0
- package/test/unit/application/customFlowApplicationArtifacts.test.js +9 -0
- package/test/unit/application/relationshipApplicationArtifacts.test.js +30 -0
- package/test/unit/infrastructure/resourceArtifacts.test.js +53 -0
- package/test/unit/output/mergeHooks.test.js +405 -0
- package/test/unit/schemas/attributeTreeSchemas.test.js +41 -63
- package/test/unit/schemas/attributeTreeSingleService.test.js +175 -0
- package/test/unit/schemas/ledgerSchemas.test.js +33 -7
- package/test/unit/schemas/propertyValueSchemas.test.js +265 -0
- package/test/unit/templates/hookTagsValidation.test.js +83 -0
- package/src/emit/schemas/attributeTree/emitAttributeTreeTargetSchemas.js +0 -153
- package/src/emit/schemas/attributeTree/resolveTargetServicePath.js +0 -111
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import test from 'node:test';
|
|
5
|
+
|
|
6
|
+
async function getTemplateFiles(dir) {
|
|
7
|
+
let results = [];
|
|
8
|
+
const entries = await readdir(dir);
|
|
9
|
+
for (const entry of entries) {
|
|
10
|
+
const fullPath = join(dir, entry);
|
|
11
|
+
const entryStat = await stat(fullPath);
|
|
12
|
+
if (entryStat.isDirectory()) {
|
|
13
|
+
const subResults = await getTemplateFiles(fullPath);
|
|
14
|
+
results = results.concat(subResults);
|
|
15
|
+
} else if (entry.endsWith('.ejs') || entry.endsWith('.js')) {
|
|
16
|
+
results.push(fullPath);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return results;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test('all template files have valid hook tag syntax and matching pairs', async () => {
|
|
23
|
+
const emitDir = join(process.cwd(), 'src/emit');
|
|
24
|
+
const templateFiles = await getTemplateFiles(emitDir);
|
|
25
|
+
assert.ok(templateFiles.length > 0, 'Should find template files in src/emit');
|
|
26
|
+
|
|
27
|
+
const syntaxErrors = [];
|
|
28
|
+
|
|
29
|
+
for (const filePath of templateFiles) {
|
|
30
|
+
const content = await readFile(filePath, 'utf8');
|
|
31
|
+
const lines = content.split('\n');
|
|
32
|
+
|
|
33
|
+
const openTags = [];
|
|
34
|
+
const closeTags = [];
|
|
35
|
+
|
|
36
|
+
lines.forEach((line, lineIndex) => {
|
|
37
|
+
// Mask EJS expressions to avoid evaluating dynamic tags
|
|
38
|
+
const stripped = line.replace(/<%[\s\S]*?%>/g, 'DYNAMIC');
|
|
39
|
+
|
|
40
|
+
// Check for malformed hook opening/closing missing '>' before ')'
|
|
41
|
+
// e.g. //(<foo) or //(</foo) without closing angle bracket
|
|
42
|
+
const malformedMatch = stripped.match(/\/\/\s*\(\s*<\/?[^>\n]*\)/);
|
|
43
|
+
if (malformedMatch) {
|
|
44
|
+
syntaxErrors.push({
|
|
45
|
+
file: filePath,
|
|
46
|
+
line: lineIndex + 1,
|
|
47
|
+
type: 'MISSING_CLOSING_ANGLE_BRACKET',
|
|
48
|
+
snippet: line.trim()
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Collect normalized hook tags for matching
|
|
53
|
+
const openMatches = stripped.matchAll(/\/\/\s*\(<\s*([\w.-]+)\s*>\)/g);
|
|
54
|
+
for (const m of openMatches) {
|
|
55
|
+
openTags.push({ tag: m[1], line: lineIndex + 1 });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const closeMatches = stripped.matchAll(/\/\/\s*\(<\/\s*([\w.-]+)\s*>\)/g);
|
|
59
|
+
for (const m of closeMatches) {
|
|
60
|
+
closeTags.push({ tag: m[1], line: lineIndex + 1 });
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Check count of open and close tags
|
|
65
|
+
if (openTags.length !== closeTags.length) {
|
|
66
|
+
syntaxErrors.push({
|
|
67
|
+
file: filePath,
|
|
68
|
+
type: 'MISMATCHED_HOOK_PAIR_COUNT',
|
|
69
|
+
openCount: openTags.length,
|
|
70
|
+
closeCount: closeTags.length,
|
|
71
|
+
openTags: openTags.map((t) => t.tag),
|
|
72
|
+
closeTags: closeTags.map((t) => t.tag)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
assert.deepEqual(
|
|
78
|
+
syntaxErrors,
|
|
79
|
+
[],
|
|
80
|
+
`Found ${syntaxErrors.length} template hook syntax error(s):\n` +
|
|
81
|
+
JSON.stringify(syntaxErrors, null, 2)
|
|
82
|
+
);
|
|
83
|
+
});
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
|
|
3
|
-
function _renderObjectSchema(schema) {
|
|
4
|
-
return `export default [\n ${JSON.stringify(schema, null, 2).replace(/\n/g, '\n ')}\n];\n`;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Emits standard schemas into target service folder for attributeTree.
|
|
9
|
-
*
|
|
10
|
-
* @param {Object} params
|
|
11
|
-
* @param {string} params.attributeTag - e.g. 'sellOfferTerm'
|
|
12
|
-
* @param {string} params.targetServiceRoot - Target service root directory
|
|
13
|
-
* @param {Object} [params.graphStorageResources] - Graph storage resources
|
|
14
|
-
* @returns {Array<{ path: string, content: string }>} Emitted target artifacts
|
|
15
|
-
*/
|
|
16
|
-
export function emitAttributeTreeTargetSchemas({
|
|
17
|
-
attributeTag,
|
|
18
|
-
targetServiceRoot,
|
|
19
|
-
graphStorageResources = {
|
|
20
|
-
myGraph: {
|
|
21
|
-
storageType: 'graph',
|
|
22
|
-
graphServerTag: 'GraphHandler'
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
} = {}) {
|
|
26
|
-
if (!attributeTag || !targetServiceRoot) {
|
|
27
|
-
return [];
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const tag = attributeTag;
|
|
31
|
-
const storageResourceTags = Object.keys(graphStorageResources);
|
|
32
|
-
|
|
33
|
-
// 1. {tag}ValueStandardPropertyLabel.js
|
|
34
|
-
const labelSchema = {
|
|
35
|
-
objectType: `${tag}ValueStandardPropertyLabel`,
|
|
36
|
-
canDelete: true,
|
|
37
|
-
generatedBy: 'user',
|
|
38
|
-
storageResources: graphStorageResources,
|
|
39
|
-
fieldNames: {
|
|
40
|
-
[`${tag}ValueStandardPropertyLabelId`]: {
|
|
41
|
-
type: 'string',
|
|
42
|
-
randomOnCreate: true,
|
|
43
|
-
canUpdate: false,
|
|
44
|
-
storageResourceTags
|
|
45
|
-
},
|
|
46
|
-
label: {
|
|
47
|
-
type: 'string',
|
|
48
|
-
requiredOnCreate: true,
|
|
49
|
-
canUpdate: true,
|
|
50
|
-
storageResourceTags
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
identifiers: [
|
|
54
|
-
{
|
|
55
|
-
type: 'identifier',
|
|
56
|
-
fieldName: `${tag}ValueStandardPropertyLabelId`
|
|
57
|
-
}
|
|
58
|
-
]
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// 2. {tag}ValueStandardPropertyValue.js
|
|
62
|
-
const valueSchema = {
|
|
63
|
-
objectType: `${tag}ValueStandardPropertyValue`,
|
|
64
|
-
canDelete: true,
|
|
65
|
-
generatedBy: 'user',
|
|
66
|
-
storageResources: graphStorageResources,
|
|
67
|
-
fieldNames: {
|
|
68
|
-
[`${tag}ValueStandardPropertyValueId`]: {
|
|
69
|
-
type: 'string',
|
|
70
|
-
randomOnCreate: true,
|
|
71
|
-
canUpdate: false,
|
|
72
|
-
storageResourceTags
|
|
73
|
-
},
|
|
74
|
-
value: {
|
|
75
|
-
type: 'string',
|
|
76
|
-
requiredOnCreate: true,
|
|
77
|
-
canUpdate: true,
|
|
78
|
-
storageResourceTags
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
identifiers: [
|
|
82
|
-
{
|
|
83
|
-
type: 'identifier',
|
|
84
|
-
fieldName: `${tag}ValueStandardPropertyValueId`
|
|
85
|
-
}
|
|
86
|
-
]
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
// 3. {tag}ValueStandard.js
|
|
90
|
-
const standardValueSchema = {
|
|
91
|
-
objectType: `${tag}ValueStandard`,
|
|
92
|
-
canDelete: true,
|
|
93
|
-
generatedBy: 'user',
|
|
94
|
-
storageResources: graphStorageResources,
|
|
95
|
-
fieldNames: {
|
|
96
|
-
[`${tag}ValueStandardId`]: {
|
|
97
|
-
type: 'string',
|
|
98
|
-
randomOnCreate: true,
|
|
99
|
-
canUpdate: false,
|
|
100
|
-
storageResourceTags
|
|
101
|
-
},
|
|
102
|
-
value: {
|
|
103
|
-
type: 'string',
|
|
104
|
-
requiredOnCreate: true,
|
|
105
|
-
canUpdate: true,
|
|
106
|
-
storageResourceTags
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
|
-
identifiers: [
|
|
110
|
-
{
|
|
111
|
-
type: 'identifier',
|
|
112
|
-
fieldName: `${tag}ValueStandardId`
|
|
113
|
-
}
|
|
114
|
-
]
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
const relDir = path.join(
|
|
118
|
-
'app',
|
|
119
|
-
'src',
|
|
120
|
-
'schemas',
|
|
121
|
-
'ObjectSchemas',
|
|
122
|
-
'generatedCode',
|
|
123
|
-
'attributeTree',
|
|
124
|
-
'propertyValue'
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
return [
|
|
128
|
-
{
|
|
129
|
-
path: path.join(
|
|
130
|
-
targetServiceRoot,
|
|
131
|
-
relDir,
|
|
132
|
-
`${tag}ValueStandardPropertyLabel.js`
|
|
133
|
-
),
|
|
134
|
-
content: _renderObjectSchema(labelSchema)
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
path: path.join(
|
|
138
|
-
targetServiceRoot,
|
|
139
|
-
relDir,
|
|
140
|
-
`${tag}ValueStandardPropertyValue.js`
|
|
141
|
-
),
|
|
142
|
-
content: _renderObjectSchema(valueSchema)
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
path: path.join(
|
|
146
|
-
targetServiceRoot,
|
|
147
|
-
relDir,
|
|
148
|
-
`${tag}ValueStandard.js`
|
|
149
|
-
),
|
|
150
|
-
content: _renderObjectSchema(standardValueSchema)
|
|
151
|
-
}
|
|
152
|
-
];
|
|
153
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Resolves target service root path based on attributeTag and developer suffix.
|
|
6
|
-
*
|
|
7
|
-
* @param {Object} params
|
|
8
|
-
* @param {string} params.currentServiceRoot - Root path of the current service
|
|
9
|
-
* @param {string} params.attributeTag - The attribute tag, e.g. 'sellOfferTerm'
|
|
10
|
-
* @param {string} [params.customOverridePath] - Optional custom path override
|
|
11
|
-
* @returns {string|null} Resolved absolute path or null if not found
|
|
12
|
-
*/
|
|
13
|
-
export function resolveTargetServicePath({
|
|
14
|
-
currentServiceRoot,
|
|
15
|
-
attributeTag,
|
|
16
|
-
customOverridePath
|
|
17
|
-
} = {}) {
|
|
18
|
-
if (!currentServiceRoot || !attributeTag) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (customOverridePath) {
|
|
23
|
-
const resolvedCustom = path.resolve(
|
|
24
|
-
currentServiceRoot,
|
|
25
|
-
customOverridePath
|
|
26
|
-
);
|
|
27
|
-
if (fs.existsSync(resolvedCustom)) {
|
|
28
|
-
return resolvedCustom;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const currentFolderName = path.basename(currentServiceRoot);
|
|
33
|
-
const parentDir = path.resolve(currentServiceRoot, '..');
|
|
34
|
-
|
|
35
|
-
if (!fs.existsSync(parentDir)) {
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
let entries = [];
|
|
40
|
-
try {
|
|
41
|
-
entries = fs.readdirSync(parentDir, { withFileTypes: true });
|
|
42
|
-
} catch (err) {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const suffixMatch = currentFolderName.match(/-([a-zA-Z0-9]+)$/);
|
|
47
|
-
let devSuffix = '';
|
|
48
|
-
if (suffixMatch && suffixMatch[1]) {
|
|
49
|
-
devSuffix = suffixMatch[1].toLowerCase();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const normalizedTag = attributeTag.toLowerCase();
|
|
53
|
-
const kebabTag = attributeTag
|
|
54
|
-
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
55
|
-
.toLowerCase();
|
|
56
|
-
|
|
57
|
-
const priority1Matches = [];
|
|
58
|
-
const priority2Matches = [];
|
|
59
|
-
const priority3Matches = [];
|
|
60
|
-
|
|
61
|
-
for (const entry of entries) {
|
|
62
|
-
if (!entry.isDirectory()) {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (entry.name === currentFolderName) {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const folderNameLower = entry.name.toLowerCase();
|
|
71
|
-
const hasTagMatch =
|
|
72
|
-
folderNameLower.includes(normalizedTag) ||
|
|
73
|
-
folderNameLower.includes(kebabTag);
|
|
74
|
-
|
|
75
|
-
if (!hasTagMatch) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const fullPath = path.join(parentDir, entry.name);
|
|
80
|
-
const hasStructure =
|
|
81
|
-
fs.existsSync(path.join(fullPath, 'app', 'src')) ||
|
|
82
|
-
fs.existsSync(path.join(fullPath, 'package.json'));
|
|
83
|
-
|
|
84
|
-
if (!hasStructure) {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (devSuffix !== '' && folderNameLower.endsWith('-' + devSuffix)) {
|
|
89
|
-
priority1Matches.push(fullPath);
|
|
90
|
-
} else if (
|
|
91
|
-
folderNameLower.endsWith(normalizedTag) ||
|
|
92
|
-
folderNameLower.endsWith(kebabTag)
|
|
93
|
-
) {
|
|
94
|
-
priority2Matches.push(fullPath);
|
|
95
|
-
} else {
|
|
96
|
-
priority3Matches.push(fullPath);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (priority1Matches.length > 0) {
|
|
101
|
-
return priority1Matches[0];
|
|
102
|
-
}
|
|
103
|
-
if (priority2Matches.length > 0) {
|
|
104
|
-
return priority2Matches[0];
|
|
105
|
-
}
|
|
106
|
-
if (priority3Matches.length > 0) {
|
|
107
|
-
return priority3Matches[0];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return null;
|
|
111
|
-
}
|