@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
package/src/generate.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import { buildGenerationPlan } from './plan/buildGenerationPlan.js';
|
|
3
2
|
import { resolveEmissionGroups } from './plan/domainRegistry.js';
|
|
4
3
|
import { commitArtifacts } from './output/commitArtifacts.js';
|
|
@@ -8,10 +7,6 @@ import {
|
|
|
8
7
|
resolveExtendedObjectSchemas,
|
|
9
8
|
resolveGraphServiceTags
|
|
10
9
|
} from './compile/loadSchemas.js';
|
|
11
|
-
import {
|
|
12
|
-
resolveTargetServicePath,
|
|
13
|
-
emitAttributeTreeTargetSchemas
|
|
14
|
-
} from './emit/schemas/attributeTree/emitAttributeTreeSchemas.js';
|
|
15
10
|
|
|
16
11
|
export async function generate(rootPath, options = {}) {
|
|
17
12
|
const startedAt = Date.now();
|
|
@@ -29,9 +24,17 @@ export async function generate(rootPath, options = {}) {
|
|
|
29
24
|
errors
|
|
30
25
|
] = await Promise.all([
|
|
31
26
|
loadLocalSchemaDirectory(project, 'ObjectSchemas', schemaLoadOptions),
|
|
32
|
-
loadLocalSchemaDirectory(
|
|
27
|
+
loadLocalSchemaDirectory(
|
|
28
|
+
project,
|
|
29
|
+
'RelationshipSchemas',
|
|
30
|
+
schemaLoadOptions
|
|
31
|
+
),
|
|
33
32
|
loadLocalSchemaDirectory(project, 'FlowSchemas', schemaLoadOptions),
|
|
34
|
-
loadLocalSchemaDirectory(
|
|
33
|
+
loadLocalSchemaDirectory(
|
|
34
|
+
project,
|
|
35
|
+
'NotificationSchemas',
|
|
36
|
+
schemaLoadOptions
|
|
37
|
+
),
|
|
35
38
|
loadLocalSchemaDirectory(project, 'ErrorSchemas', schemaLoadOptions)
|
|
36
39
|
]);
|
|
37
40
|
const schemaBucketName =
|
|
@@ -101,14 +104,6 @@ export async function generate(rootPath, options = {}) {
|
|
|
101
104
|
)
|
|
102
105
|
);
|
|
103
106
|
}
|
|
104
|
-
const targetFiles = await _emitTargetServiceAttributeTreeSchemas({
|
|
105
|
-
project,
|
|
106
|
-
objects,
|
|
107
|
-
logger: options.logger
|
|
108
|
-
});
|
|
109
|
-
for (const targetFile of targetFiles) {
|
|
110
|
-
files.push(targetFile);
|
|
111
|
-
}
|
|
112
107
|
const durationMs = Date.now() - startedAt;
|
|
113
108
|
console.log(
|
|
114
109
|
`[INFO] [Generate] STATUS=FINISHED | ` +
|
|
@@ -126,61 +121,3 @@ export async function generate(rootPath, options = {}) {
|
|
|
126
121
|
}
|
|
127
122
|
}
|
|
128
123
|
|
|
129
|
-
async function _emitTargetServiceAttributeTreeSchemas({
|
|
130
|
-
project,
|
|
131
|
-
objects,
|
|
132
|
-
logger
|
|
133
|
-
}) {
|
|
134
|
-
if (!Array.isArray(objects)) {
|
|
135
|
-
return [];
|
|
136
|
-
}
|
|
137
|
-
const committedFiles = [];
|
|
138
|
-
for (const object of objects) {
|
|
139
|
-
if (!Array.isArray(object?.addOnDataStructure)) {
|
|
140
|
-
continue;
|
|
141
|
-
}
|
|
142
|
-
for (const addOn of object.addOnDataStructure) {
|
|
143
|
-
if (addOn?.type === 'attributeTree' && addOn?.attributeTreeTag) {
|
|
144
|
-
const attributeTag = addOn.attributeTreeTag;
|
|
145
|
-
const targetServiceRoot = resolveTargetServicePath({
|
|
146
|
-
currentServiceRoot: project.rootPath,
|
|
147
|
-
attributeTag
|
|
148
|
-
});
|
|
149
|
-
if (targetServiceRoot) {
|
|
150
|
-
const artifacts = emitAttributeTreeTargetSchemas({
|
|
151
|
-
attributeTag,
|
|
152
|
-
targetServiceRoot
|
|
153
|
-
});
|
|
154
|
-
const relativeArtifacts = artifacts.map((artifact) => {
|
|
155
|
-
return {
|
|
156
|
-
path: path.relative(targetServiceRoot, artifact.path),
|
|
157
|
-
content: artifact.content
|
|
158
|
-
};
|
|
159
|
-
});
|
|
160
|
-
const targetPlan = buildGenerationPlan(
|
|
161
|
-
{ outputPath: targetServiceRoot },
|
|
162
|
-
relativeArtifacts,
|
|
163
|
-
{
|
|
164
|
-
managedScopes: {
|
|
165
|
-
'attribute-tree-target-schemas': relativeArtifacts.map(
|
|
166
|
-
(a) => a.path
|
|
167
|
-
)
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
);
|
|
171
|
-
const targetFiles = await commitArtifacts(targetPlan);
|
|
172
|
-
for (const targetFile of targetFiles) {
|
|
173
|
-
committedFiles.push(targetFile);
|
|
174
|
-
}
|
|
175
|
-
if (logger && typeof logger.info === 'function') {
|
|
176
|
-
logger.info(
|
|
177
|
-
`[INFO] [AttributeTree] Target schemas emitted for ` +
|
|
178
|
-
`tag=${attributeTag} to ${targetServiceRoot}`
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return committedFiles;
|
|
186
|
-
}
|
package/src/output/mergeHooks.js
CHANGED
|
@@ -24,7 +24,10 @@ async function mergeHook(outputRoot, artifact) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
const skipWrite =
|
|
28
|
+
artifact.writeWhenFileExist === false ||
|
|
29
|
+
artifact.writeWhenFileExists === false;
|
|
30
|
+
if (sourceContent !== null && skipWrite) {
|
|
28
31
|
return sourceContent;
|
|
29
32
|
}
|
|
30
33
|
|
|
@@ -37,32 +40,183 @@ async function mergeHook(outputRoot, artifact) {
|
|
|
37
40
|
return artifact.content;
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
_validateHookIntegrity(artifact.path, sourceContent);
|
|
44
|
+
_warnOrphanedHooks(
|
|
45
|
+
artifact.path,
|
|
46
|
+
sourceContent,
|
|
47
|
+
artifact.content,
|
|
48
|
+
matchers
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const tagOccurrences = new Map();
|
|
40
52
|
return artifact.content.replace(
|
|
41
53
|
matchers.anyTag,
|
|
42
54
|
(_match, p1, _body1, p2) => {
|
|
43
|
-
const tagName = p1
|
|
44
|
-
|
|
45
|
-
|
|
55
|
+
const tagName = _extractTagName(p1, p2);
|
|
56
|
+
if (!tagName) {
|
|
57
|
+
return _match;
|
|
58
|
+
}
|
|
59
|
+
let count = 0;
|
|
60
|
+
if (tagOccurrences.has(tagName)) {
|
|
61
|
+
count = tagOccurrences.get(tagName);
|
|
62
|
+
}
|
|
63
|
+
tagOccurrences.set(tagName, count + 1);
|
|
64
|
+
|
|
65
|
+
const matches = sourceContent.match(matchers.tagPattern(tagName));
|
|
66
|
+
if (!matches || count >= matches.length) {
|
|
67
|
+
return _match;
|
|
68
|
+
}
|
|
69
|
+
const hookBlock = matches[count];
|
|
70
|
+
if (hookBlock !== null && hookBlock !== undefined) {
|
|
71
|
+
return _normalizeHookBlock(hookBlock, tagName);
|
|
72
|
+
}
|
|
73
|
+
return _match;
|
|
46
74
|
}
|
|
47
75
|
);
|
|
48
76
|
}
|
|
49
77
|
|
|
78
|
+
function _validateHookIntegrity(filePath, content) {
|
|
79
|
+
const lower = filePath.toLowerCase();
|
|
80
|
+
let openCount = 0;
|
|
81
|
+
let closeCount = 0;
|
|
82
|
+
|
|
83
|
+
if (
|
|
84
|
+
lower.endsWith('.js') ||
|
|
85
|
+
lower.endsWith('.mjs') ||
|
|
86
|
+
lower.endsWith('.cjs')
|
|
87
|
+
) {
|
|
88
|
+
const openP1 = content.match(/\/\/\s*\(<\s*[\w.-]+/g);
|
|
89
|
+
const closeP1 = content.match(/\/\/\s*\(<\/\s*[\w.-]+/g);
|
|
90
|
+
const openP2 = content.match(/\/\/\s*<#\s*[\w.-]+/g);
|
|
91
|
+
const closeP2 = content.match(/\/\/\s*<#\/\s*[\w.-]+/g);
|
|
92
|
+
|
|
93
|
+
if (openP1) {
|
|
94
|
+
openCount += openP1.length;
|
|
95
|
+
}
|
|
96
|
+
if (closeP1) {
|
|
97
|
+
closeCount += closeP1.length;
|
|
98
|
+
}
|
|
99
|
+
if (openP2) {
|
|
100
|
+
openCount += openP2.length;
|
|
101
|
+
}
|
|
102
|
+
if (closeP2) {
|
|
103
|
+
closeCount += closeP2.length;
|
|
104
|
+
}
|
|
105
|
+
} else if (lower.endsWith('.yml') || lower.endsWith('.yaml')) {
|
|
106
|
+
const openYml = content.match(/#\s*<#\s*[\w.-]+/g);
|
|
107
|
+
const closeYml = content.match(/#\s*<#\/\s*[\w.-]+/g);
|
|
108
|
+
|
|
109
|
+
if (openYml) {
|
|
110
|
+
openCount += openYml.length;
|
|
111
|
+
}
|
|
112
|
+
if (closeYml) {
|
|
113
|
+
closeCount += closeYml.length;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (openCount !== closeCount) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`[mergeHooks] Malformed hook tags in '${filePath}': found ` +
|
|
120
|
+
`${openCount} open tag(s) but ${closeCount} close tag(s). ` +
|
|
121
|
+
`Aborting to prevent code loss.`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function _warnOrphanedHooks(
|
|
127
|
+
filePath,
|
|
128
|
+
sourceContent,
|
|
129
|
+
artifactContent,
|
|
130
|
+
matchers
|
|
131
|
+
) {
|
|
132
|
+
const anyTagRegex = new RegExp(matchers.anyTag.source, 'gm');
|
|
133
|
+
let match = anyTagRegex.exec(sourceContent);
|
|
134
|
+
|
|
135
|
+
while (match !== null) {
|
|
136
|
+
const tagName = _extractTagName(match[1], match[3]);
|
|
137
|
+
let body = '';
|
|
138
|
+
if (typeof match[2] === 'string') {
|
|
139
|
+
body = match[2];
|
|
140
|
+
} else if (typeof match[4] === 'string') {
|
|
141
|
+
body = match[4];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (tagName && body.trim().length > 0) {
|
|
145
|
+
const templatePattern = matchers.tagPattern(tagName);
|
|
146
|
+
const existsInTemplate = templatePattern.test(artifactContent);
|
|
147
|
+
if (!existsInTemplate) {
|
|
148
|
+
console.warn(
|
|
149
|
+
`[WARN] [mergeHooks] Hook '${tagName}' in '${filePath}' ` +
|
|
150
|
+
`contains custom code but is no longer present in template.`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
match = anyTagRegex.exec(sourceContent);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function _normalizeHookBlock(hookBlock, tagName) {
|
|
159
|
+
if (typeof hookBlock !== 'string' || hookBlock.length === 0) {
|
|
160
|
+
return hookBlock;
|
|
161
|
+
}
|
|
162
|
+
const esc = tagName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
163
|
+
const openRegex = new RegExp(`(//\\s*\\(<\\s*${esc}\\s*)(?!>)\\)`);
|
|
164
|
+
const closeRegex = new RegExp(`(//\\s*\\(<\\/\\s*${esc}\\s*)(?!>)\\)`);
|
|
165
|
+
let normalized = hookBlock.replace(openRegex, '$1>)');
|
|
166
|
+
normalized = normalized.replace(closeRegex, '$1>)');
|
|
167
|
+
return normalized;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function _extractTagName(p1, p2) {
|
|
171
|
+
if (typeof p1 === 'string' && p1.length > 0) {
|
|
172
|
+
return p1;
|
|
173
|
+
}
|
|
174
|
+
if (typeof p2 === 'string' && p2.length > 0) {
|
|
175
|
+
return p2;
|
|
176
|
+
}
|
|
177
|
+
return '';
|
|
178
|
+
}
|
|
179
|
+
|
|
50
180
|
function hookMatchers(filePath) {
|
|
51
|
-
|
|
181
|
+
const lower = filePath.toLowerCase();
|
|
182
|
+
if (
|
|
183
|
+
lower.endsWith('.js') ||
|
|
184
|
+
lower.endsWith('.mjs') ||
|
|
185
|
+
lower.endsWith('.cjs')
|
|
186
|
+
) {
|
|
187
|
+
const jsP1 =
|
|
188
|
+
'\\/\\/\\s*\\(<\\s*([\\w.-]+)\\s*>?\\s*\\)([\\s\\S]*?)' +
|
|
189
|
+
'\\/\\/\\s*\\(<\\/\\s*\\1\\s*>?\\s*\\)';
|
|
190
|
+
const jsP2 =
|
|
191
|
+
'\\/\\/\\s*<#\\s*([\\w.-]+)\\s*#>([\\s\\S]*?)' +
|
|
192
|
+
'\\/\\/\\s*<#\\/\\s*\\3\\s*#>';
|
|
52
193
|
return {
|
|
53
|
-
anyTag:
|
|
54
|
-
tagPattern: (name) =>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
194
|
+
anyTag: new RegExp(`(?:${jsP1}|${jsP2})`, 'gm'),
|
|
195
|
+
tagPattern: (name) => {
|
|
196
|
+
const esc = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
197
|
+
const p1 =
|
|
198
|
+
`\\/\\/\\s*\\(<\\s*${esc}\\s*>?\\s*\\)([\\s\\S]*?)` +
|
|
199
|
+
`\\/\\/\\s*\\(<\\/\\s*${esc}\\s*>?\\s*\\)`;
|
|
200
|
+
const p2 =
|
|
201
|
+
`\\/\\/\\s*<#\\s*${esc}\\s*#>([\\s\\S]*?)` +
|
|
202
|
+
`\\/\\/\\s*<#\\/\\s*${esc}\\s*#>`;
|
|
203
|
+
return new RegExp(`(?:${p1}|${p2})`, 'gm');
|
|
204
|
+
}
|
|
59
205
|
};
|
|
60
206
|
}
|
|
61
|
-
if (
|
|
207
|
+
if (lower.endsWith('.yml') || lower.endsWith('.yaml')) {
|
|
208
|
+
const ymlPattern =
|
|
209
|
+
'#\\s*<#\\s*([\\w.-]+)\\s*#>([\\s\\S]*?)' +
|
|
210
|
+
'#\\s*<#\\/\\s*\\1\\s*#>';
|
|
62
211
|
return {
|
|
63
|
-
anyTag:
|
|
64
|
-
tagPattern: (name) =>
|
|
65
|
-
|
|
212
|
+
anyTag: new RegExp(ymlPattern, 'gm'),
|
|
213
|
+
tagPattern: (name) => {
|
|
214
|
+
const esc = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
215
|
+
return new RegExp(
|
|
216
|
+
`#\\s*<#\\s*${esc}\\s*#>([\\s\\S]*?)#\\s*<#\\/\\s*${esc}\\s*#>`,
|
|
217
|
+
'gm'
|
|
218
|
+
);
|
|
219
|
+
}
|
|
66
220
|
};
|
|
67
221
|
}
|
|
68
222
|
return null;
|
|
@@ -58,6 +58,12 @@ import {
|
|
|
58
58
|
ledgerObjectSchemaManagedPaths,
|
|
59
59
|
ledgerRelationshipSchemaManagedPaths
|
|
60
60
|
} from '../emit/schemas/ledger/emitLedgerSchemas.js';
|
|
61
|
+
import {
|
|
62
|
+
emitPropertyValueObjectSchemas,
|
|
63
|
+
emitPropertyValueRelationshipSchemas,
|
|
64
|
+
propertyValueObjectSchemaManagedPaths,
|
|
65
|
+
propertyValueRelationshipSchemaManagedPaths
|
|
66
|
+
} from '../emit/schemas/propertyValue/emitPropertyValueSchemas.js';
|
|
61
67
|
import {
|
|
62
68
|
emitErrorSchemas,
|
|
63
69
|
errorSchemaManagedPaths
|
|
@@ -85,7 +91,9 @@ export async function resolveEmissionGroups(context) {
|
|
|
85
91
|
resource,
|
|
86
92
|
coreFunction,
|
|
87
93
|
systemText,
|
|
88
|
-
errorSchemas
|
|
94
|
+
errorSchemas,
|
|
95
|
+
ledgerObjectArtifacts,
|
|
96
|
+
ledgerRelationshipArtifacts
|
|
89
97
|
] = await Promise.all([
|
|
90
98
|
emitCrudApplicationArtifacts({
|
|
91
99
|
objects,
|
|
@@ -125,6 +133,14 @@ export async function resolveEmissionGroups(context) {
|
|
|
125
133
|
project,
|
|
126
134
|
errors,
|
|
127
135
|
objectGraphServiceTags
|
|
136
|
+
}),
|
|
137
|
+
emitLedgerObjectSchemas({
|
|
138
|
+
objects,
|
|
139
|
+
serviceTag: project.serviceTag
|
|
140
|
+
}),
|
|
141
|
+
emitLedgerRelationshipSchemas({
|
|
142
|
+
objects,
|
|
143
|
+
serviceTag: project.serviceTag
|
|
128
144
|
})
|
|
129
145
|
]);
|
|
130
146
|
|
|
@@ -204,15 +220,25 @@ export async function resolveEmissionGroups(context) {
|
|
|
204
220
|
{
|
|
205
221
|
scope: 'ledger-object-schemas',
|
|
206
222
|
managedPaths: ledgerObjectSchemaManagedPaths(objects),
|
|
207
|
-
artifacts:
|
|
223
|
+
artifacts: ledgerObjectArtifacts
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
scope: 'ledger-relationship-schemas',
|
|
227
|
+
managedPaths: ledgerRelationshipSchemaManagedPaths(objects),
|
|
228
|
+
artifacts: ledgerRelationshipArtifacts
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
scope: 'property-value-object-schemas',
|
|
232
|
+
managedPaths: propertyValueObjectSchemaManagedPaths(objects),
|
|
233
|
+
artifacts: emitPropertyValueObjectSchemas({
|
|
208
234
|
objects,
|
|
209
235
|
serviceTag: project.serviceTag
|
|
210
236
|
})
|
|
211
237
|
},
|
|
212
238
|
{
|
|
213
|
-
scope: '
|
|
214
|
-
managedPaths:
|
|
215
|
-
artifacts:
|
|
239
|
+
scope: 'property-value-relationship-schemas',
|
|
240
|
+
managedPaths: propertyValueRelationshipSchemaManagedPaths(objects),
|
|
241
|
+
artifacts: emitPropertyValueRelationshipSchemas({
|
|
216
242
|
objects,
|
|
217
243
|
serviceTag: project.serviceTag
|
|
218
244
|
})
|
package/task.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Task Checklist: Attribute Tree Single-Service Code Generation Consolidation
|
|
2
|
+
|
|
3
|
+
> **Canonical Architecture Plan**: [[10.Systems/GenerateServiceCode/30-Generation/Task Roadmap - Attribute Tree Per-Repo Generation Refactoring|Task Roadmap in Obsidian]]
|
|
4
|
+
> **Selected Design**: **Single Main Service (Self-Repo Consolidation)** + **Style 1 (`generatedCode/<domain>/`)**
|
|
5
|
+
> **Repository**: `IzaraCore-SupportServices-GenerateServiceCode-Seagame`
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 🎯 Target Architecture: Single Unified Service (Self-Repo)
|
|
10
|
+
|
|
11
|
+
All schemas for an `attributeTree` (Tree nodes, Standard Value Handler node, and cascading PropertyValue nodes) are emitted directly inside the **Main Service** workspace:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
app/src/schemas/
|
|
15
|
+
├── ObjectSchemas/
|
|
16
|
+
│ ├── sellOffer.js <-- Source ObjectSchema
|
|
17
|
+
│ └── generatedCode/
|
|
18
|
+
│ ├── attributeTree/
|
|
19
|
+
│ │ ├── sellOfferTermLink.js <-- Link Node
|
|
20
|
+
│ │ ├── sellOfferTermValue.js <-- Value Node
|
|
21
|
+
│ │ ├── sellOfferTermLabel.js <-- Label Node
|
|
22
|
+
│ │ └── sellOfferTermValueStandard.js <-- Handler Node (Self-Repo)
|
|
23
|
+
│ │
|
|
24
|
+
│ └── propertyValue/ <-- Cascading from ValueStandard
|
|
25
|
+
│ ├── sellOfferTermValueStandardPropertyLabel.js
|
|
26
|
+
│ └── sellOfferTermValueStandardPropertyValue.js
|
|
27
|
+
│
|
|
28
|
+
└── RelationshipSchemas/
|
|
29
|
+
└── generatedCode/
|
|
30
|
+
├── attributeTree/
|
|
31
|
+
│ ├── hasSellOfferTermLink.js
|
|
32
|
+
│ ├── disabledSellOfferTermLink.js
|
|
33
|
+
│ ├── isSellOfferTerm.js
|
|
34
|
+
│ └── isSellOfferTermLabel.js
|
|
35
|
+
│
|
|
36
|
+
└── propertyValue/
|
|
37
|
+
├── hasSellOfferTermValueStandardPropertyValue.js
|
|
38
|
+
├── disabledSellOfferTermValueStandardPropertyValue.js
|
|
39
|
+
└── isSellOfferTermValueStandardPropertyLabel.js
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 📋 Implementation Checklist
|
|
45
|
+
|
|
46
|
+
- [x] **TASK-01: Recursive Schema Loading & Directives Loader**
|
|
47
|
+
- **File**: `src/compile/loadSchemas.js`
|
|
48
|
+
- **Acceptance Criteria**: `loadLocalSchemaDirectory(project, 'ObjectSchemas')` discovers and validates schemas nested inside `generatedCode/**`.
|
|
49
|
+
|
|
50
|
+
- [x] **TASK-02: Consolidate ValueStandard into `emitAttributeTreeSchemas.js`**
|
|
51
|
+
- **File**: `src/emit/schemas/attributeTree/emitAttributeTreeSchemas.js`
|
|
52
|
+
- **Action**:
|
|
53
|
+
1. Emit `${tag}ValueStandard.js` directly within `emitAttributeTreeObjectSchemas`.
|
|
54
|
+
2. Add `${tag}ValueStandard.js` to `attributeTreeObjectSchemaManagedPaths`.
|
|
55
|
+
3. Include preservation hook `//(<addOnDataStructure${tag}ValueStandard>)` with commented `propertyValue` addOn template.
|
|
56
|
+
- **Acceptance Criteria**: Single-service attributeTree generates all 4 ObjectSchemas (`Link`, `Value`, `Label`, `ValueStandard`).
|
|
57
|
+
|
|
58
|
+
- [x] **TASK-03: Remove Target Directive Scope & Dead Code**
|
|
59
|
+
- **Files**:
|
|
60
|
+
- `src/plan/domainRegistry.js` (Removed `attribute-tree-target-value-standard` scope & unused `directives` param)
|
|
61
|
+
- `src/emit/schemas/attributeTree/emitAttributeTreeTargetValueStandard.js` (Deleted dead file)
|
|
62
|
+
- `src/compile/loadSchemas.js` (Removed obsolete `loadGenerateDirectives`)
|
|
63
|
+
- `src/generate.js` (Removed `loadGenerateDirectives` call & `directives` passing)
|
|
64
|
+
- `test/unit/schemas/attributeTreeSingleService.test.js` (Removed obsolete directive loader tests)
|
|
65
|
+
- **Acceptance Criteria**: Clean scope tracking under `attribute-tree-object-schemas` with zero dead directive loading.
|
|
66
|
+
|
|
67
|
+
- [x] **TASK-04: Single-Service & Cascading Integration Verification**
|
|
68
|
+
- **File**: `test/unit/schemas/attributeTreeSingleService.test.js`
|
|
69
|
+
- **Action**: Verifies single-service generation and cascading generation to `propertyValue` within the same repository.
|
|
70
|
+
- **Acceptance Criteria**: 100% passing tests with zero cross-repo write or external directive needed.
|
|
71
|
+
|
|
72
|
+
- [x] **TASK-05: Synchronize Vault & Documentation**
|
|
73
|
+
- **Vault Files**:
|
|
74
|
+
- `10.Systems/GenerateServiceCode/20-Schema/Dynamic Schema.md`
|
|
75
|
+
- `40.Vault/Operations/timeline-log.md`
|
|
76
|
+
- `40.Vault/Memory/active-context.md`
|
|
@@ -544,6 +544,64 @@ test('validateFlowSchema passes for s3 event with valid bucketName', () => {
|
|
|
544
544
|
);
|
|
545
545
|
});
|
|
546
546
|
|
|
547
|
+
test('validateFlowSchema passes for s3 event with explicit S3 flowSteps', () => {
|
|
548
|
+
assert.equal(
|
|
549
|
+
validateFlowSchema({
|
|
550
|
+
flowTag: 'uploadFlow',
|
|
551
|
+
event: ['s3'],
|
|
552
|
+
bucketName: 'MyUploadBucket',
|
|
553
|
+
flowSteps: [
|
|
554
|
+
{ stepName: 'CreateObject', event: ['wbs'] },
|
|
555
|
+
{ stepName: 'ReservedLimit', event: ['sqs'] },
|
|
556
|
+
{ stepName: 'CreatePreSignUrl', event: ['sqs'] },
|
|
557
|
+
{ stepName: 'ProcessAfterUpload', event: ['s3'] },
|
|
558
|
+
{ stepName: 'ConfirmAfterUpload', event: ['sqs'] }
|
|
559
|
+
]
|
|
560
|
+
}),
|
|
561
|
+
true
|
|
562
|
+
);
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
test('validateFlowSchema passes for s3 event without flowSteps', () => {
|
|
566
|
+
assert.equal(
|
|
567
|
+
validateFlowSchema({
|
|
568
|
+
flowTag: 'uploadFlow',
|
|
569
|
+
event: ['s3'],
|
|
570
|
+
bucketName: 'MyUploadBucket'
|
|
571
|
+
}),
|
|
572
|
+
true
|
|
573
|
+
);
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
test('validateFlowSchema rejects s3 event with invalid entry stepName', () => {
|
|
577
|
+
assert.throws(
|
|
578
|
+
() =>
|
|
579
|
+
validateFlowSchema({
|
|
580
|
+
flowTag: 'uploadFlow',
|
|
581
|
+
event: ['s3'],
|
|
582
|
+
bucketName: 'MyUploadBucket',
|
|
583
|
+
flowSteps: [{ stepName: 'InvalidEntry' }]
|
|
584
|
+
}),
|
|
585
|
+
/Entry step flowSteps\[0\] for s3 flow must have stepName 'CreateObject' or 'Start'/
|
|
586
|
+
);
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
test('validateFlowSchema rejects s3 event with invalid non-entry stepName', () => {
|
|
590
|
+
assert.throws(
|
|
591
|
+
() =>
|
|
592
|
+
validateFlowSchema({
|
|
593
|
+
flowTag: 'uploadFlow',
|
|
594
|
+
event: ['s3'],
|
|
595
|
+
bucketName: 'MyUploadBucket',
|
|
596
|
+
flowSteps: [
|
|
597
|
+
{ stepName: 'CreateObject' },
|
|
598
|
+
{ stepName: 'InvalidStep' }
|
|
599
|
+
]
|
|
600
|
+
}),
|
|
601
|
+
/is invalid for s3 flow/
|
|
602
|
+
);
|
|
603
|
+
});
|
|
604
|
+
|
|
547
605
|
test('validateFlowSchema rejects event with storedCache or triggerCache as invalid event', () => {
|
|
548
606
|
assert.throws(
|
|
549
607
|
() =>
|
|
@@ -208,7 +208,7 @@ test('generate commits the system WebSocket completion path for own-topic flows'
|
|
|
208
208
|
assert.match(webSocketComplete, /\(\<createIdentifiersFlow\>\)/);
|
|
209
209
|
assert.match(webSocketComplete, /\(\<beforePostMessage\>\)/);
|
|
210
210
|
assert.match(webSocketComplete, /postToConnection\(_izContext,/);
|
|
211
|
-
|
|
211
|
+
const webSocketHandler = await readFile(
|
|
212
212
|
join(
|
|
213
213
|
rootPath,
|
|
214
214
|
'app/src/generatedCode/SystemFlowSchemas/WebSocketMain/source/WebSocketComplete_HdrSqs.js'
|
|
@@ -217,6 +217,49 @@ test('generate commits the system WebSocket completion path for own-topic flows'
|
|
|
217
217
|
);
|
|
218
218
|
assert.match(webSocketHandler, /record\.body\.TopicArn/);
|
|
219
219
|
assert.match(webSocketHandler, /addCallingFlowToPassOnProperties/);
|
|
220
|
+
|
|
221
|
+
const registerComplete = await readFile(
|
|
222
|
+
join(
|
|
223
|
+
rootPath,
|
|
224
|
+
'app/src/generatedCode/SystemFlowSchemas/Register/source/RegisterComplete_Main.js'
|
|
225
|
+
),
|
|
226
|
+
'utf8'
|
|
227
|
+
);
|
|
228
|
+
assert.match(registerComplete, /getFlowSchema\.getFlowSchemaS3WithCache/);
|
|
229
|
+
assert.doesNotMatch(registerComplete, /getObjectSchema\.getFlowSchemaS3WithCache/);
|
|
230
|
+
|
|
231
|
+
const registerMain = await readFile(
|
|
232
|
+
join(
|
|
233
|
+
rootPath,
|
|
234
|
+
'app/src/generatedCode/SystemFlowSchemas/Register/source/Register_Main.js'
|
|
235
|
+
),
|
|
236
|
+
'utf8'
|
|
237
|
+
);
|
|
238
|
+
assert.match(registerMain, /getFlowSchema\.getFlowSchemaS3WithCache/);
|
|
239
|
+
assert.doesNotMatch(registerMain, /getObjectSchema\.getFlowSchemaS3WithCache/);
|
|
240
|
+
|
|
241
|
+
assert.match(webSocketComplete, /getFlowSchema\.getFlowSchemaS3WithCache/);
|
|
242
|
+
assert.doesNotMatch(webSocketComplete, /getObjectSchema\.getFlowSchemaS3WithCache/);
|
|
243
|
+
|
|
244
|
+
const trackHdrWbs = await readFile(
|
|
245
|
+
join(
|
|
246
|
+
rootPath,
|
|
247
|
+
'app/src/generatedCode/FlowSchemas/Track/source/Track_HdrWbs.js'
|
|
248
|
+
),
|
|
249
|
+
'utf8'
|
|
250
|
+
);
|
|
251
|
+
assert.match(trackHdrWbs, /getFlowSchema\.getFlowSchemaS3WithCache/);
|
|
252
|
+
assert.doesNotMatch(trackHdrWbs, /getObjectSchema\.getFlowSchemaS3WithCache/);
|
|
253
|
+
|
|
254
|
+
const trackWbsMain = await readFile(
|
|
255
|
+
join(
|
|
256
|
+
rootPath,
|
|
257
|
+
'app/src/generatedCode/FlowSchemas/Track/source/Track_WbsMain.js'
|
|
258
|
+
),
|
|
259
|
+
'utf8'
|
|
260
|
+
);
|
|
261
|
+
assert.match(trackWbsMain, /getFlowSchema\.getFlowSchemaS3WithCache/);
|
|
262
|
+
assert.doesNotMatch(trackWbsMain, /getObjectSchema\.getFlowSchemaS3WithCache/);
|
|
220
263
|
});
|
|
221
264
|
|
|
222
265
|
test('generate commits the trigger-cache suite with its queues when triggerFlowTypes is set', async () => {
|
|
@@ -245,6 +288,16 @@ test('generate commits the trigger-cache suite with its queues when triggerFlowT
|
|
|
245
288
|
),
|
|
246
289
|
/CartCheckTriggerFlowsHdrSqs/
|
|
247
290
|
);
|
|
291
|
+
|
|
292
|
+
const cartCheckTrigger = await readFile(
|
|
293
|
+
join(
|
|
294
|
+
rootPath,
|
|
295
|
+
'app/src/generatedCode/FlowSchemas/Cart/source/CartCheckTriggerFlows_Main.js'
|
|
296
|
+
),
|
|
297
|
+
'utf8'
|
|
298
|
+
);
|
|
299
|
+
assert.match(cartCheckTrigger, /getFlowSchema\.getFlowSchemaS3WithCache/);
|
|
300
|
+
assert.doesNotMatch(cartCheckTrigger, /getObjectSchema\.getFlowSchemaS3WithCache/);
|
|
248
301
|
});
|
|
249
302
|
|
|
250
303
|
test('generate removes the system WebSocket path when the last own-topic flow is removed', async () => {
|