@izara_project/izara-core-generate-service-code 1.0.98 → 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 +0 -3
- 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/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/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/infrastructure/functions/functionYamlArtifact.js +28 -0
- package/src/emit/infrastructure/functions/templates/DssFunction_Yaml.ejs +21 -0
- package/src/emit/infrastructure/resources/iamResourceArtifacts.js +45 -5
- package/src/emit/infrastructure/resources/templates/GeneratedLambdaRoleServiceConfig.ejs +5 -3
- package/src/emit/schemas/attributeTree/emitAttributeTreeSchemas.js +62 -1
- package/src/generate.js +2 -6
- package/src/output/mergeHooks.js +105 -5
- package/src/plan/domainRegistry.js +0 -10
- package/task.md +40 -96
- package/test/integration/graphDrivenFlowSchema.test.js +58 -0
- package/test/unit/application/createTargetRoleHandler.test.js +70 -1
- package/test/unit/application/crudApplicationArtifacts.test.js +4 -0
- package/test/unit/infrastructure/resourceArtifacts.test.js +52 -0
- package/test/unit/output/mergeHooks.test.js +137 -0
- package/test/unit/schemas/attributeTreeSchemas.test.js +32 -3
- package/test/unit/schemas/attributeTreeSingleService.test.js +175 -0
- package/test/unit/templates/hookTagsValidation.test.js +83 -0
- package/src/emit/schemas/attributeTree/emitAttributeTreeTargetValueStandard.js +0 -132
- package/test/unit/schemas/attributeTreeDirectives.test.js +0 -177
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test, { after } from 'node:test';
|
|
3
|
+
import { generate } from '../../../src/generate.js';
|
|
4
|
+
import {
|
|
5
|
+
createTestProject,
|
|
6
|
+
readProjectFile,
|
|
7
|
+
writeProjectFile,
|
|
8
|
+
cleanupTestProjects
|
|
9
|
+
} from '../../helpers/testProject.js';
|
|
10
|
+
|
|
11
|
+
after(async () => {
|
|
12
|
+
await cleanupTestProjects();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('single-service attributeTree generation and propertyValue cascading', async () => {
|
|
16
|
+
const initialSchema = `export default [
|
|
17
|
+
{
|
|
18
|
+
objectType: 'sellOffer',
|
|
19
|
+
canDelete: false,
|
|
20
|
+
generatedBy: 'user',
|
|
21
|
+
addOnDataStructure: [
|
|
22
|
+
{
|
|
23
|
+
type: 'attributeTree',
|
|
24
|
+
attributeTreeTag: 'sellOfferTerm'
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
storageResources: {
|
|
28
|
+
dynamoDB: {
|
|
29
|
+
storageType: 'dynamoDB',
|
|
30
|
+
tableName: 'SellOfferRecords',
|
|
31
|
+
serviceTag: 'SellOfferManager'
|
|
32
|
+
},
|
|
33
|
+
myGraph: {
|
|
34
|
+
storageType: 'graph',
|
|
35
|
+
graphServerTag: 'GraphHandler'
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
fieldNames: {
|
|
39
|
+
sellOfferId: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
randomOnCreate: true,
|
|
42
|
+
canUpdate: false,
|
|
43
|
+
storageResourceTags: ['dynamoDB', 'myGraph']
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
identifiers: [
|
|
47
|
+
{
|
|
48
|
+
type: 'partitionKey',
|
|
49
|
+
fieldName: 'sellOfferId'
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
const rootPath = await createTestProject({
|
|
57
|
+
prefix: 'izara-single-service-attr-tree-',
|
|
58
|
+
serviceTag: 'SellOfferManager',
|
|
59
|
+
schemas: {
|
|
60
|
+
'ObjectSchemas/SellOffer.js': initialSchema
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Phase 1: generate produces all 4 ObjectSchemas and 4 RelationshipSchemas
|
|
65
|
+
await generate(rootPath);
|
|
66
|
+
|
|
67
|
+
const linkPath =
|
|
68
|
+
'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermLink.js';
|
|
69
|
+
const valuePath =
|
|
70
|
+
'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermValue.js';
|
|
71
|
+
const labelPath =
|
|
72
|
+
'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermLabel.js';
|
|
73
|
+
const valueStandardPath =
|
|
74
|
+
'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermValueStandard.js';
|
|
75
|
+
|
|
76
|
+
const linkContent = await readProjectFile(rootPath, linkPath);
|
|
77
|
+
assert.match(linkContent, /sellOfferTermLink/);
|
|
78
|
+
|
|
79
|
+
const valueContent = await readProjectFile(rootPath, valuePath);
|
|
80
|
+
assert.match(valueContent, /sellOfferTermValue/);
|
|
81
|
+
|
|
82
|
+
const labelContent = await readProjectFile(rootPath, labelPath);
|
|
83
|
+
assert.match(labelContent, /sellOfferTermLabel/);
|
|
84
|
+
|
|
85
|
+
const valueStandardContent = await readProjectFile(
|
|
86
|
+
rootPath,
|
|
87
|
+
valueStandardPath
|
|
88
|
+
);
|
|
89
|
+
assert.match(valueStandardContent, /sellOfferTermValueStandard/);
|
|
90
|
+
assert.match(
|
|
91
|
+
valueStandardContent,
|
|
92
|
+
/\/\/\(<addOnDataStructuresellOfferTermValueStandard>\)/
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// Check relationship schemas
|
|
96
|
+
const hasLinkRelPath =
|
|
97
|
+
'app/src/schemas/RelationshipSchemas/generatedCode/attributeTree/hasSellOfferTermLink.js';
|
|
98
|
+
const hasLinkRel = await readProjectFile(rootPath, hasLinkRelPath);
|
|
99
|
+
assert.match(hasLinkRel, /hasSellOfferTermLink/);
|
|
100
|
+
|
|
101
|
+
// Phase 2: developer uncomments propertyValue addOn in ValueStandard
|
|
102
|
+
const modifiedValueStandard = valueStandardContent.replace(
|
|
103
|
+
'//(<addOnDataStructuresellOfferTermValueStandard>)\n // {\n // type: \'propertyValue\',\n // propertyValuePrefix: \'sellOfferTermValueStandard\'\n // }\n //(</addOnDataStructuresellOfferTermValueStandard>)',
|
|
104
|
+
'//(<addOnDataStructuresellOfferTermValueStandard>)\n {\n type: \'propertyValue\',\n propertyValuePrefix: \'sellOfferTermValueStandard\'\n }\n //(</addOnDataStructuresellOfferTermValueStandard>)'
|
|
105
|
+
);
|
|
106
|
+
await writeProjectFile(rootPath, valueStandardPath, modifiedValueStandard);
|
|
107
|
+
|
|
108
|
+
await generate(rootPath);
|
|
109
|
+
|
|
110
|
+
// Verify hook preservation
|
|
111
|
+
const reloadedValueStandard = await readProjectFile(
|
|
112
|
+
rootPath,
|
|
113
|
+
valueStandardPath
|
|
114
|
+
);
|
|
115
|
+
assert.match(reloadedValueStandard, /type:\s*'propertyValue'/);
|
|
116
|
+
|
|
117
|
+
// Verify cascading generation: propertyValue domain in the same repo
|
|
118
|
+
const propLabelPath =
|
|
119
|
+
'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/sellOfferTermValueStandardPropertyLabel.js';
|
|
120
|
+
const propValuePath =
|
|
121
|
+
'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/sellOfferTermValueStandardPropertyValue.js';
|
|
122
|
+
const hasPropRelPath =
|
|
123
|
+
'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/hasSellOfferTermValueStandardPropertyValue.js';
|
|
124
|
+
const disPropRelPath =
|
|
125
|
+
'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/disabledSellOfferTermValueStandardPropertyValue.js';
|
|
126
|
+
const isPropRelPath =
|
|
127
|
+
'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/isSellOfferTermValueStandardPropertyLabel.js';
|
|
128
|
+
|
|
129
|
+
const propLabel = await readProjectFile(rootPath, propLabelPath);
|
|
130
|
+
assert.match(propLabel, /sellOfferTermValueStandardPropertyLabel/);
|
|
131
|
+
|
|
132
|
+
const propValue = await readProjectFile(rootPath, propValuePath);
|
|
133
|
+
assert.match(propValue, /sellOfferTermValueStandardPropertyValue/);
|
|
134
|
+
|
|
135
|
+
const hasPropRel = await readProjectFile(rootPath, hasPropRelPath);
|
|
136
|
+
assert.match(hasPropRel, /hasSellOfferTermValueStandardPropertyValue/);
|
|
137
|
+
|
|
138
|
+
const disPropRel = await readProjectFile(rootPath, disPropRelPath);
|
|
139
|
+
assert.match(disPropRel, /disabledSellOfferTermValueStandardPropertyValue/);
|
|
140
|
+
|
|
141
|
+
const isPropRel = await readProjectFile(rootPath, isPropRelPath);
|
|
142
|
+
assert.match(isPropRel, /isSellOfferTermValueStandardPropertyLabel/);
|
|
143
|
+
|
|
144
|
+
// Cleanup check: remove attributeTree addOn from base schema
|
|
145
|
+
const cleanSchema = `export default [
|
|
146
|
+
{
|
|
147
|
+
objectType: 'sellOffer',
|
|
148
|
+
canDelete: false,
|
|
149
|
+
generatedBy: 'user',
|
|
150
|
+
addOnDataStructure: [],
|
|
151
|
+
storageResources: {
|
|
152
|
+
myGraph: { storageType: 'graph', graphServerTag: 'GraphHandler' }
|
|
153
|
+
},
|
|
154
|
+
fieldNames: {
|
|
155
|
+
sellOfferId: { type: 'string', storageResourceTags: ['myGraph'] }
|
|
156
|
+
},
|
|
157
|
+
identifiers: [{ type: 'partitionKey', fieldName: 'sellOfferId' }]
|
|
158
|
+
}
|
|
159
|
+
];
|
|
160
|
+
`;
|
|
161
|
+
await writeProjectFile(
|
|
162
|
+
rootPath,
|
|
163
|
+
'app/src/schemas/ObjectSchemas/SellOffer.js',
|
|
164
|
+
cleanSchema
|
|
165
|
+
);
|
|
166
|
+
await generate(rootPath);
|
|
167
|
+
|
|
168
|
+
// All attributeTree schemas should be removed
|
|
169
|
+
await assert.rejects(readProjectFile(rootPath, linkPath), { code: 'ENOENT' });
|
|
170
|
+
await assert.rejects(readProjectFile(rootPath, valuePath), { code: 'ENOENT' });
|
|
171
|
+
await assert.rejects(readProjectFile(rootPath, labelPath), { code: 'ENOENT' });
|
|
172
|
+
await assert.rejects(readProjectFile(rootPath, valueStandardPath), {
|
|
173
|
+
code: 'ENOENT'
|
|
174
|
+
});
|
|
175
|
+
});
|
|
@@ -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,132 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Emits target ValueStandard ObjectSchema for attributeTreeTarget directives
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
function _extractTargetDirectives(directives = []) {
|
|
6
|
-
if (!Array.isArray(directives)) {
|
|
7
|
-
return [];
|
|
8
|
-
}
|
|
9
|
-
const results = [];
|
|
10
|
-
const seenTags = new Set();
|
|
11
|
-
|
|
12
|
-
for (const directive of directives) {
|
|
13
|
-
if (
|
|
14
|
-
directive?.type === 'attributeTreeTarget' &&
|
|
15
|
-
directive?.attributeTreeTag
|
|
16
|
-
) {
|
|
17
|
-
const tag = directive.attributeTreeTag;
|
|
18
|
-
if (seenTags.has(tag)) {
|
|
19
|
-
continue;
|
|
20
|
-
}
|
|
21
|
-
seenTags.add(tag);
|
|
22
|
-
results.push(directive);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return results;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function _extractStorageResources(directive) {
|
|
30
|
-
if (directive?.storageResources) {
|
|
31
|
-
return directive.storageResources;
|
|
32
|
-
}
|
|
33
|
-
return {
|
|
34
|
-
myGraph: {
|
|
35
|
-
storageType: 'graph',
|
|
36
|
-
graphServerTag: 'GraphHandler'
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function _renderTargetValueStandardSchema(tag, storageResources) {
|
|
42
|
-
const storageResourceTags = Object.keys(storageResources);
|
|
43
|
-
if (storageResourceTags.length === 0) {
|
|
44
|
-
storageResourceTags.push('myGraph');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const storageJson = JSON.stringify(storageResources, null, 2)
|
|
48
|
-
.replace(/\n/g, '\n ');
|
|
49
|
-
const tagsJson = JSON.stringify(storageResourceTags);
|
|
50
|
-
|
|
51
|
-
return `export default [
|
|
52
|
-
{
|
|
53
|
-
objectType: '${tag}ValueStandard',
|
|
54
|
-
canDelete: true,
|
|
55
|
-
generatedBy: 'user',
|
|
56
|
-
storageResources: ${storageJson},
|
|
57
|
-
addOnDataStructure: [
|
|
58
|
-
//(<addOnDataStructure${tag}ValueStandard>)
|
|
59
|
-
// {
|
|
60
|
-
// type: 'propertyValue',
|
|
61
|
-
// propertyValuePrefix: '${tag}ValueStandard'
|
|
62
|
-
// }
|
|
63
|
-
//(</addOnDataStructure${tag}ValueStandard>)
|
|
64
|
-
],
|
|
65
|
-
fieldNames: {
|
|
66
|
-
${tag}ValueStandardId: {
|
|
67
|
-
type: 'string',
|
|
68
|
-
randomOnCreate: true,
|
|
69
|
-
canUpdate: false,
|
|
70
|
-
storageResourceTags: ${tagsJson}
|
|
71
|
-
},
|
|
72
|
-
label: {
|
|
73
|
-
type: 'string',
|
|
74
|
-
canUpdate: true,
|
|
75
|
-
storageResourceTags: ${tagsJson}
|
|
76
|
-
},
|
|
77
|
-
value: {
|
|
78
|
-
type: 'string',
|
|
79
|
-
requiredOnCreate: true,
|
|
80
|
-
canUpdate: true,
|
|
81
|
-
storageResourceTags: ${tagsJson}
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
identifiers: [
|
|
85
|
-
{
|
|
86
|
-
type: 'identifier',
|
|
87
|
-
fieldName: '${tag}ValueStandardId'
|
|
88
|
-
}
|
|
89
|
-
]
|
|
90
|
-
}
|
|
91
|
-
];
|
|
92
|
-
`;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function attributeTreeTargetValueStandardManagedPaths(directives = []) {
|
|
96
|
-
const targets = _extractTargetDirectives(directives);
|
|
97
|
-
const paths = [];
|
|
98
|
-
|
|
99
|
-
for (const directive of targets) {
|
|
100
|
-
const tag = directive.attributeTreeTag;
|
|
101
|
-
paths.push(
|
|
102
|
-
`app/src/schemas/ObjectSchemas/generatedCode/attributeTree/` +
|
|
103
|
-
`${tag}ValueStandard.js`
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return paths;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function emitAttributeTreeTargetValueStandard({
|
|
111
|
-
directives = []
|
|
112
|
-
} = {}) {
|
|
113
|
-
const targets = _extractTargetDirectives(directives);
|
|
114
|
-
if (targets.length === 0) {
|
|
115
|
-
return [];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const artifacts = [];
|
|
119
|
-
|
|
120
|
-
for (const directive of targets) {
|
|
121
|
-
const tag = directive.attributeTreeTag;
|
|
122
|
-
const storageResources = _extractStorageResources(directive);
|
|
123
|
-
artifacts.push({
|
|
124
|
-
path:
|
|
125
|
-
`app/src/schemas/ObjectSchemas/generatedCode/attributeTree/` +
|
|
126
|
-
`${tag}ValueStandard.js`,
|
|
127
|
-
content: _renderTargetValueStandardSchema(tag, storageResources)
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return artifacts;
|
|
132
|
-
}
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import test, { after } from 'node:test';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
loadGenerateDirectives
|
|
6
|
-
} from '../../../src/compile/loadSchemas.js';
|
|
7
|
-
import {
|
|
8
|
-
emitAttributeTreeTargetValueStandard,
|
|
9
|
-
attributeTreeTargetValueStandardManagedPaths
|
|
10
|
-
} from '../../../src/emit/schemas/attributeTree/emitAttributeTreeTargetValueStandard.js';
|
|
11
|
-
import { generate } from '../../../src/generate.js';
|
|
12
|
-
import {
|
|
13
|
-
createTestProject,
|
|
14
|
-
readProjectFile,
|
|
15
|
-
writeProjectFile,
|
|
16
|
-
cleanupTestProjects
|
|
17
|
-
} from '../../helpers/testProject.js';
|
|
18
|
-
|
|
19
|
-
after(async () => {
|
|
20
|
-
await cleanupTestProjects();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test('loadGenerateDirectives returns empty array when directory missing', async () => {
|
|
24
|
-
const rootPath = await createTestProject({
|
|
25
|
-
prefix: 'izara-no-directives-test-',
|
|
26
|
-
serviceTag: 'TestService'
|
|
27
|
-
});
|
|
28
|
-
const project = { schemaRoot: `${rootPath}/app/src/schemas` };
|
|
29
|
-
const directives = await loadGenerateDirectives(project);
|
|
30
|
-
assert.deepEqual(directives, []);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('loadGenerateDirectives loads directives from GenerateDirectives folder', async () => {
|
|
34
|
-
const rootPath = await createTestProject({
|
|
35
|
-
prefix: 'izara-directives-load-test-',
|
|
36
|
-
serviceTag: 'SellOfferTermManager',
|
|
37
|
-
schemas: {
|
|
38
|
-
'GenerateDirectives/sellOfferTermValueStandard.js': `export default {
|
|
39
|
-
type: 'attributeTreeTarget',
|
|
40
|
-
attributeTreeTag: 'sellOfferTerm'
|
|
41
|
-
};
|
|
42
|
-
`
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
const project = { schemaRoot: `${rootPath}/app/src/schemas` };
|
|
46
|
-
const directives = await loadGenerateDirectives(project);
|
|
47
|
-
assert.equal(directives.length, 1);
|
|
48
|
-
assert.equal(directives[0].type, 'attributeTreeTarget');
|
|
49
|
-
assert.equal(directives[0].attributeTreeTag, 'sellOfferTerm');
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('emitAttributeTreeTargetValueStandard emits expected schema with hook', () => {
|
|
53
|
-
const directives = [
|
|
54
|
-
{
|
|
55
|
-
type: 'attributeTreeTarget',
|
|
56
|
-
attributeTreeTag: 'sellOfferTerm'
|
|
57
|
-
}
|
|
58
|
-
];
|
|
59
|
-
|
|
60
|
-
const managedPaths =
|
|
61
|
-
attributeTreeTargetValueStandardManagedPaths(directives);
|
|
62
|
-
assert.deepEqual(managedPaths, [
|
|
63
|
-
'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermValueStandard.js'
|
|
64
|
-
]);
|
|
65
|
-
|
|
66
|
-
const artifacts = emitAttributeTreeTargetValueStandard({ directives });
|
|
67
|
-
assert.equal(artifacts.length, 1);
|
|
68
|
-
|
|
69
|
-
const artifact = artifacts[0];
|
|
70
|
-
assert.equal(
|
|
71
|
-
artifact.path,
|
|
72
|
-
'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermValueStandard.js'
|
|
73
|
-
);
|
|
74
|
-
assert.match(
|
|
75
|
-
artifact.content,
|
|
76
|
-
/objectType:\s*['"]sellOfferTermValueStandard['"]/
|
|
77
|
-
);
|
|
78
|
-
assert.match(artifact.content, /sellOfferTermValueStandardId/);
|
|
79
|
-
assert.match(
|
|
80
|
-
artifact.content,
|
|
81
|
-
/\/\/\(<addOnDataStructuresellOfferTermValueStandard>\)/
|
|
82
|
-
);
|
|
83
|
-
assert.match(
|
|
84
|
-
artifact.content,
|
|
85
|
-
/\/\/\(<\/addOnDataStructuresellOfferTermValueStandard>\)/
|
|
86
|
-
);
|
|
87
|
-
assert.match(artifact.content, /propertyValue/);
|
|
88
|
-
assert.match(artifact.content, /GraphHandler/);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
test('managed paths and emitter return empty when no matching directives', () => {
|
|
92
|
-
assert.deepEqual(attributeTreeTargetValueStandardManagedPaths([]), []);
|
|
93
|
-
assert.deepEqual(
|
|
94
|
-
attributeTreeTargetValueStandardManagedPaths([{ type: 'other' }]),
|
|
95
|
-
[]
|
|
96
|
-
);
|
|
97
|
-
assert.deepEqual(emitAttributeTreeTargetValueStandard({ directives: [] }), []);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test('generate commits and cleans up attributeTreeTarget dynamic schemas', async () => {
|
|
101
|
-
const rootPath = await createTestProject({
|
|
102
|
-
prefix: 'izara-directives-gen-test-',
|
|
103
|
-
serviceTag: 'SellOfferTermManager',
|
|
104
|
-
schemas: {
|
|
105
|
-
'GenerateDirectives/sellOfferTermValueStandard.js': `export default {
|
|
106
|
-
type: 'attributeTreeTarget',
|
|
107
|
-
attributeTreeTag: 'sellOfferTerm'
|
|
108
|
-
};
|
|
109
|
-
`
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
await generate(rootPath);
|
|
114
|
-
|
|
115
|
-
const targetRelPath =
|
|
116
|
-
'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermValueStandard.js';
|
|
117
|
-
const content = await readProjectFile(rootPath, targetRelPath);
|
|
118
|
-
assert.match(content, /sellOfferTermValueStandard/);
|
|
119
|
-
assert.match(
|
|
120
|
-
content,
|
|
121
|
-
/\/\/\(<addOnDataStructuresellOfferTermValueStandard>\)/
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
// Regeneration preserves user changes inside the hook
|
|
125
|
-
const modifiedContent = content.replace(
|
|
126
|
-
'//(<addOnDataStructuresellOfferTermValueStandard>)\n // {\n // type: \'propertyValue\',\n // propertyValuePrefix: \'sellOfferTermValueStandard\'\n // }\n //(</addOnDataStructuresellOfferTermValueStandard>)',
|
|
127
|
-
'//(<addOnDataStructuresellOfferTermValueStandard>)\n {\n type: \'propertyValue\',\n propertyValuePrefix: \'sellOfferTermValueStandard\'\n }\n //(</addOnDataStructuresellOfferTermValueStandard>)'
|
|
128
|
-
);
|
|
129
|
-
await writeProjectFile(rootPath, targetRelPath, modifiedContent);
|
|
130
|
-
|
|
131
|
-
await generate(rootPath);
|
|
132
|
-
|
|
133
|
-
const regeneratedContent = await readProjectFile(rootPath, targetRelPath);
|
|
134
|
-
assert.match(
|
|
135
|
-
regeneratedContent,
|
|
136
|
-
/type:\s*'propertyValue'/
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
// Cascading verification: PropertyValue schemas generated in phase 2
|
|
140
|
-
const propLabelPath =
|
|
141
|
-
'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/sellOfferTermValueStandardPropertyLabel.js';
|
|
142
|
-
const propValuePath =
|
|
143
|
-
'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/sellOfferTermValueStandardPropertyValue.js';
|
|
144
|
-
const hasPropRelPath =
|
|
145
|
-
'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/hasSellOfferTermValueStandardPropertyValue.js';
|
|
146
|
-
const disPropRelPath =
|
|
147
|
-
'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/disabledSellOfferTermValueStandardPropertyValue.js';
|
|
148
|
-
const isPropRelPath =
|
|
149
|
-
'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/isSellOfferTermValueStandardPropertyLabel.js';
|
|
150
|
-
|
|
151
|
-
const propLabelContent = await readProjectFile(rootPath, propLabelPath);
|
|
152
|
-
assert.match(propLabelContent, /sellOfferTermValueStandardPropertyLabel/);
|
|
153
|
-
|
|
154
|
-
const propValueContent = await readProjectFile(rootPath, propValuePath);
|
|
155
|
-
assert.match(propValueContent, /sellOfferTermValueStandardPropertyValue/);
|
|
156
|
-
|
|
157
|
-
const hasPropRelContent = await readProjectFile(rootPath, hasPropRelPath);
|
|
158
|
-
assert.match(hasPropRelContent, /hasSellOfferTermValueStandardPropertyValue/);
|
|
159
|
-
|
|
160
|
-
const disPropRelContent = await readProjectFile(rootPath, disPropRelPath);
|
|
161
|
-
assert.match(disPropRelContent, /disabledSellOfferTermValueStandardPropertyValue/);
|
|
162
|
-
|
|
163
|
-
const isPropRelContent = await readProjectFile(rootPath, isPropRelPath);
|
|
164
|
-
assert.match(isPropRelContent, /isSellOfferTermValueStandardPropertyLabel/);
|
|
165
|
-
|
|
166
|
-
// When directive removed, file is cleaned up
|
|
167
|
-
await writeProjectFile(
|
|
168
|
-
rootPath,
|
|
169
|
-
'app/src/schemas/GenerateDirectives/sellOfferTermValueStandard.js',
|
|
170
|
-
'export default { type: "disabled" };\n'
|
|
171
|
-
);
|
|
172
|
-
await generate(rootPath);
|
|
173
|
-
|
|
174
|
-
await assert.rejects(readProjectFile(rootPath, targetRelPath), {
|
|
175
|
-
code: 'ENOENT'
|
|
176
|
-
});
|
|
177
|
-
});
|