@izara_project/izara-core-generate-service-code 1.0.94 → 1.0.96
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/emit/attributeTree/emitAttributeTreeSchemas.js +29 -48
- package/src/emit/attributeTree/emitAttributeTreeTargetSchemas.js +153 -0
- package/src/emit/attributeTree/resolveTargetServicePath.js +111 -0
- package/src/emit/coreFunction/emitCoreFunctionArtifacts.js +1 -26
- package/src/emit/coreFunction/templates/InitialSetupConfig.ejs +0 -30
- package/src/emit/custom/customFlowPaths.js +3 -16
- package/src/emit/custom/customFlowSteps.js +33 -45
- package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +1 -47
- package/src/emit/custom/templates/FlowEndpoint_Main.ejs +68 -6
- package/src/emit/custom/templates/FlowStep_Main.ejs +27 -0
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +7 -7
- package/src/emit/relationship/templates/CreateRelationship_Main.ejs +5 -5
- package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +3 -3
- package/src/emit/relationship/templates/GetRelationship_Main.ejs +1 -1
- package/src/emit/relationship/templates/MoveRelationship_Main.ejs +5 -5
- package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +5 -5
- package/src/emit/resource/iamResourceArtifacts.js +1 -5
- package/src/emit/resource/resourceState.js +3 -9
- package/src/generate.js +57 -1
- package/test/attributeTreeSchemas.test.js +88 -6
- package/test/customFlowApplicationArtifacts.test.js +256 -0
- package/test/relationshipApplicationArtifacts.test.js +29 -0
package/src/generate.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
1
3
|
import { buildGenerationPlan } from './plan/buildGenerationPlan.js';
|
|
2
4
|
import { commitArtifacts } from './output/commitArtifacts.js';
|
|
3
5
|
import { compileProject } from './compile/compileProject.js';
|
|
@@ -59,7 +61,9 @@ import {
|
|
|
59
61
|
emitAttributeTreeObjectSchemas,
|
|
60
62
|
emitAttributeTreeRelationshipSchemas,
|
|
61
63
|
attributeTreeObjectSchemaManagedPaths,
|
|
62
|
-
attributeTreeRelationshipSchemaManagedPaths
|
|
64
|
+
attributeTreeRelationshipSchemaManagedPaths,
|
|
65
|
+
resolveTargetServicePath,
|
|
66
|
+
emitAttributeTreeTargetSchemas
|
|
63
67
|
} from './emit/attributeTree/emitAttributeTreeSchemas.js';
|
|
64
68
|
import {
|
|
65
69
|
emitErrorSchemas,
|
|
@@ -147,6 +151,11 @@ export async function generate(rootPath, options = {}) {
|
|
|
147
151
|
)
|
|
148
152
|
);
|
|
149
153
|
}
|
|
154
|
+
await _emitTargetServiceAttributeTreeSchemas({
|
|
155
|
+
project,
|
|
156
|
+
objects,
|
|
157
|
+
logger: options.logger
|
|
158
|
+
});
|
|
150
159
|
const durationMs = Date.now() - startedAt;
|
|
151
160
|
console.log(
|
|
152
161
|
`[INFO] [Generate] STATUS=FINISHED | ` +
|
|
@@ -343,3 +352,50 @@ async function _emitGroups({
|
|
|
343
352
|
}
|
|
344
353
|
];
|
|
345
354
|
}
|
|
355
|
+
|
|
356
|
+
async function _emitTargetServiceAttributeTreeSchemas({
|
|
357
|
+
project,
|
|
358
|
+
objects,
|
|
359
|
+
logger
|
|
360
|
+
}) {
|
|
361
|
+
if (!Array.isArray(objects)) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
for (const object of objects) {
|
|
365
|
+
if (!Array.isArray(object?.addOnDataStructure)) {
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
for (const addOn of object.addOnDataStructure) {
|
|
369
|
+
if (addOn?.type === 'attributeTree' && addOn?.attributeTreeTag) {
|
|
370
|
+
const attributeTag = addOn.attributeTreeTag;
|
|
371
|
+
const targetServiceRoot = resolveTargetServicePath({
|
|
372
|
+
currentServiceRoot: project.rootPath,
|
|
373
|
+
attributeTag
|
|
374
|
+
});
|
|
375
|
+
if (targetServiceRoot) {
|
|
376
|
+
const artifacts = emitAttributeTreeTargetSchemas({
|
|
377
|
+
attributeTag,
|
|
378
|
+
targetServiceRoot
|
|
379
|
+
});
|
|
380
|
+
for (const artifact of artifacts) {
|
|
381
|
+
await fs.promises.mkdir(path.dirname(artifact.path), {
|
|
382
|
+
recursive: true
|
|
383
|
+
});
|
|
384
|
+
await fs.promises.writeFile(
|
|
385
|
+
artifact.path,
|
|
386
|
+
artifact.content,
|
|
387
|
+
'utf8'
|
|
388
|
+
);
|
|
389
|
+
}
|
|
390
|
+
if (logger && typeof logger.info === 'function') {
|
|
391
|
+
logger.info(
|
|
392
|
+
`[INFO] [AttributeTree] Target schemas emitted for ` +
|
|
393
|
+
`tag=${attributeTag} to ${targetServiceRoot}`
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
@@ -8,7 +8,9 @@ import {
|
|
|
8
8
|
emitAttributeTreeObjectSchemas,
|
|
9
9
|
emitAttributeTreeRelationshipSchemas,
|
|
10
10
|
attributeTreeObjectSchemaManagedPaths,
|
|
11
|
-
attributeTreeRelationshipSchemaManagedPaths
|
|
11
|
+
attributeTreeRelationshipSchemaManagedPaths,
|
|
12
|
+
resolveTargetServicePath,
|
|
13
|
+
emitAttributeTreeTargetSchemas
|
|
12
14
|
} from '../src/emit/attributeTree/emitAttributeTreeSchemas.js';
|
|
13
15
|
import { generate } from '../src/generate.js';
|
|
14
16
|
|
|
@@ -22,7 +24,7 @@ after(async () => {
|
|
|
22
24
|
);
|
|
23
25
|
});
|
|
24
26
|
|
|
25
|
-
test('emitAttributeTreeObjectSchemas returns
|
|
27
|
+
test('emitAttributeTreeObjectSchemas returns 3 object schemas per attributeTree tag', () => {
|
|
26
28
|
const objects = [
|
|
27
29
|
{
|
|
28
30
|
objectType: 'sellOffer',
|
|
@@ -47,16 +49,21 @@ test('emitAttributeTreeObjectSchemas returns 4 object schemas per attributeTree
|
|
|
47
49
|
];
|
|
48
50
|
|
|
49
51
|
const artifacts = emitAttributeTreeObjectSchemas({ objects });
|
|
50
|
-
assert.equal(artifacts.length,
|
|
52
|
+
assert.equal(artifacts.length, 3);
|
|
51
53
|
|
|
52
54
|
const paths = artifacts.map((a) => a.path);
|
|
53
55
|
assert.deepEqual(paths, [
|
|
54
56
|
'app/src/schemas/ObjectSchemas/generatedAttributeTree/sellOfferTermLink.js',
|
|
55
|
-
'app/src/schemas/ObjectSchemas/generatedAttributeTree/
|
|
56
|
-
'app/src/schemas/ObjectSchemas/generatedAttributeTree/sellOfferTermLabel.js'
|
|
57
|
-
'app/src/schemas/ObjectSchemas/generatedAttributeTree/sellOfferTermValueStandard.js'
|
|
57
|
+
'app/src/schemas/ObjectSchemas/generatedAttributeTree/sellOfferTermValue.js',
|
|
58
|
+
'app/src/schemas/ObjectSchemas/generatedAttributeTree/sellOfferTermLabel.js'
|
|
58
59
|
]);
|
|
59
60
|
|
|
61
|
+
const valueArtifact = artifacts.find((a) =>
|
|
62
|
+
a.path.endsWith('sellOfferTermValue.js')
|
|
63
|
+
);
|
|
64
|
+
assert.match(valueArtifact.content, /"objectType": "sellOfferTermValue"/);
|
|
65
|
+
assert.match(valueArtifact.content, /"sellOfferTermValueId"/);
|
|
66
|
+
|
|
60
67
|
for (const artifact of artifacts) {
|
|
61
68
|
assert.doesNotMatch(artifact.content, /dynamoDB/);
|
|
62
69
|
assert.match(artifact.content, /GraphHandler/);
|
|
@@ -101,6 +108,31 @@ test('emitAttributeTreeRelationshipSchemas returns 4 relationship schemas per at
|
|
|
101
108
|
'app/src/schemas/RelationshipSchemas/generatedAttributeTree/isSellOfferTermLabel.js'
|
|
102
109
|
]);
|
|
103
110
|
|
|
111
|
+
const hasRel = artifacts.find((a) => a.path.endsWith('hasSellOfferTermLink.js'));
|
|
112
|
+
assert.match(hasRel.content, /"generatedBy": "user"/);
|
|
113
|
+
assert.match(hasRel.content, /"requiredOnCreate": true/);
|
|
114
|
+
|
|
115
|
+
const disabledRel = artifacts.find((a) =>
|
|
116
|
+
a.path.endsWith('disabledSellOfferTermLink.js')
|
|
117
|
+
);
|
|
118
|
+
assert.match(disabledRel.content, /"generatedBy": "user"/);
|
|
119
|
+
|
|
120
|
+
const isRel = artifacts.find((a) => a.path.endsWith('isSellOfferTerm.js'));
|
|
121
|
+
assert.match(isRel.content, /"generatedBy": "systemNoUser"/);
|
|
122
|
+
assert.match(isRel.content, /"objectType": "sellOfferTermValue"/);
|
|
123
|
+
assert.match(isRel.content, /"requiredOnCreate": true/);
|
|
124
|
+
|
|
125
|
+
const isLabelRel = artifacts.find((a) =>
|
|
126
|
+
a.path.endsWith('isSellOfferTermLabel.js')
|
|
127
|
+
);
|
|
128
|
+
assert.match(isLabelRel.content, /"generatedBy": "systemNoUser"/);
|
|
129
|
+
assert.match(isLabelRel.content, /"requiredOnCreate": true/);
|
|
130
|
+
// from objType should be sellOfferTermValue
|
|
131
|
+
assert.match(
|
|
132
|
+
isLabelRel.content,
|
|
133
|
+
/"from":\s*\{\s*"objType":\s*\{[^}]*"objectType": "sellOfferTermValue"/
|
|
134
|
+
);
|
|
135
|
+
|
|
104
136
|
for (const artifact of artifacts) {
|
|
105
137
|
assert.doesNotMatch(artifact.content, /dynamoDB/);
|
|
106
138
|
assert.match(artifact.content, /GraphHandler/);
|
|
@@ -217,3 +249,53 @@ async function createProjectWithAttributeTree({
|
|
|
217
249
|
|
|
218
250
|
return rootPath;
|
|
219
251
|
}
|
|
252
|
+
|
|
253
|
+
test('resolveTargetServicePath prioritizes dev suffix and matches attributeTag', async () => {
|
|
254
|
+
const tmpRoot = await mkdtemp(join(tmpdir(), 'izara-services-test-'));
|
|
255
|
+
projectRoots.add(tmpRoot);
|
|
256
|
+
|
|
257
|
+
const currentServiceDir = join(
|
|
258
|
+
tmpRoot,
|
|
259
|
+
'izara-market-products-sell-offer-manager-pong'
|
|
260
|
+
);
|
|
261
|
+
const targetWithSuffix = join(
|
|
262
|
+
tmpRoot,
|
|
263
|
+
'izara-market-products-sell-offer-term-pong'
|
|
264
|
+
);
|
|
265
|
+
const targetOtherDev = join(
|
|
266
|
+
tmpRoot,
|
|
267
|
+
'izara-market-products-sell-offer-term-alice'
|
|
268
|
+
);
|
|
269
|
+
const unrelatedService = join(
|
|
270
|
+
tmpRoot,
|
|
271
|
+
'izara-market-products-cart-pong'
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
await mkdir(join(currentServiceDir, 'app/src'), { recursive: true });
|
|
275
|
+
await mkdir(join(targetWithSuffix, 'app/src'), { recursive: true });
|
|
276
|
+
await mkdir(join(targetOtherDev, 'app/src'), { recursive: true });
|
|
277
|
+
await mkdir(join(unrelatedService, 'app/src'), { recursive: true });
|
|
278
|
+
|
|
279
|
+
const resolved = resolveTargetServicePath({
|
|
280
|
+
currentServiceRoot: currentServiceDir,
|
|
281
|
+
attributeTag: 'sellOfferTerm'
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
assert.equal(resolved, targetWithSuffix);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
test('emitAttributeTreeTargetSchemas produces expected standard schemas', () => {
|
|
288
|
+
const targetDir = '/dummy/path/izara-market-products-sellOfferTerm';
|
|
289
|
+
const artifacts = emitAttributeTreeTargetSchemas({
|
|
290
|
+
attributeTag: 'sellOfferTerm',
|
|
291
|
+
targetServiceRoot: targetDir
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
assert.equal(artifacts.length, 3);
|
|
295
|
+
const paths = artifacts.map((a) => a.path);
|
|
296
|
+
|
|
297
|
+
assert.ok(paths.some((p) => p.endsWith('sellOfferTermValueStandardPropertyLabel.js')));
|
|
298
|
+
assert.ok(paths.some((p) => p.endsWith('sellOfferTermValueStandardPropertyValue.js')));
|
|
299
|
+
assert.ok(paths.some((p) => p.endsWith('sellOfferTermValueStandard.js')));
|
|
300
|
+
});
|
|
301
|
+
|
|
@@ -88,6 +88,15 @@ test('emits handlers, function YAML, and IAM roles for supported custom flow eve
|
|
|
88
88
|
assert.match(iam, /ApiRole:/);
|
|
89
89
|
assert.match(iam, /OwnRole:/);
|
|
90
90
|
assert.match(iam, /UploadRole:/);
|
|
91
|
+
const customSqsYaml = await readFile(
|
|
92
|
+
join(
|
|
93
|
+
rootPath,
|
|
94
|
+
'resource/sls_yaml/generatedCode/source/generated-sns-sqs-custom-flows.yml'
|
|
95
|
+
),
|
|
96
|
+
'utf8'
|
|
97
|
+
);
|
|
98
|
+
assert.match(customSqsYaml, /ExtHdrSqs:/);
|
|
99
|
+
assert.doesNotMatch(customSqsYaml, /ProcessExtHdrSqs/);
|
|
91
100
|
assert.match(
|
|
92
101
|
await readFile(
|
|
93
102
|
join(
|
|
@@ -1412,4 +1421,251 @@ test('emits early return cacheMain on cache hit in FlowEndpoint_Main for storedC
|
|
|
1412
1421
|
await parseAsEsm(mainPath);
|
|
1413
1422
|
});
|
|
1414
1423
|
|
|
1424
|
+
test('emits canonical checkStatusField and hooks in FlowEndpoint_Main for statusField', async () => {
|
|
1425
|
+
const rootPath = await createProject();
|
|
1426
|
+
await writeFile(
|
|
1427
|
+
join(rootPath, 'app/src/schemas/FlowSchemas/StatusFieldFlow.js'),
|
|
1428
|
+
`export default {
|
|
1429
|
+
flowTag: 'statusFieldOrder',
|
|
1430
|
+
event: ['ownTopic'],
|
|
1431
|
+
statusType: 'statusField',
|
|
1432
|
+
objType: { objectType: 'order', serviceTag: 'Current' },
|
|
1433
|
+
flowSteps: [{ stepName: 'Start' }]
|
|
1434
|
+
};\n`
|
|
1435
|
+
);
|
|
1436
|
+
|
|
1437
|
+
await generateCustomFlowApplicationArtifacts(rootPath);
|
|
1438
|
+
|
|
1439
|
+
const mainPath = join(
|
|
1440
|
+
rootPath,
|
|
1441
|
+
'app/src/generatedCode/FlowSchemas/StatusFieldOrder/source/StatusFieldOrder_Main.js'
|
|
1442
|
+
);
|
|
1443
|
+
const mainContent = await readFile(mainPath, 'utf8');
|
|
1444
|
+
assert.match(
|
|
1445
|
+
mainContent,
|
|
1446
|
+
/import statusFieldSharedLib from '@izara_project\/izara-core-library-status-field';/
|
|
1447
|
+
);
|
|
1448
|
+
assert.match(mainContent, /statusFieldSharedLib\.checkStatusField/);
|
|
1449
|
+
assert.match(mainContent, /\/\/\(<beforeCheckedStatusField>\)/);
|
|
1450
|
+
assert.match(mainContent, /\/\/\(<identifiers>\)/);
|
|
1451
|
+
assert.match(mainContent, /\/\/\(<overwriteUniqueRequestId>\)/);
|
|
1452
|
+
assert.match(mainContent, /\/\/\(<afterCheckStatusField>\)/);
|
|
1453
|
+
assert.match(mainContent, /\/\/\(<afterValidateStatusField>\)/);
|
|
1454
|
+
assert.match(mainContent, /\/\/\(<checkStatusFieldHook>\)/);
|
|
1455
|
+
assert.match(mainContent, /\/\/\(<endpointHook>\)/);
|
|
1456
|
+
assert.match(mainContent, /\/\/\(<beforeCompleteStatusField>\)/);
|
|
1457
|
+
assert.match(mainContent, /statusFieldSharedLib\.completeStatusField/);
|
|
1458
|
+
assert.match(mainContent, /\/\/\(<statusField>\)/);
|
|
1459
|
+
assert.match(mainContent, /\/\/\(<errorFounds>\)/);
|
|
1460
|
+
assert.match(mainContent, /\/\/\(<afterCompleteStatusField>\)/);
|
|
1461
|
+
assert.match(
|
|
1462
|
+
mainContent,
|
|
1463
|
+
/_izContext\.logger\.debug\('\[StatusFieldOrder_Main\] started', \{\s*requestParams,\s*callingFlowConfig\s*\}\);/
|
|
1464
|
+
);
|
|
1465
|
+
await parseAsEsm(mainPath);
|
|
1466
|
+
});
|
|
1467
|
+
|
|
1468
|
+
test('does not emit RbacCallback artifacts or duplicate artifact paths for custom flow with RBAC', async () => {
|
|
1469
|
+
const { generate } = await import('../src/generate.js');
|
|
1470
|
+
const rootPath = await createProject();
|
|
1471
|
+
await writeFile(
|
|
1472
|
+
join(rootPath, 'app/src/schemas/ObjectSchemas/ComAcc.js'),
|
|
1473
|
+
`export default {
|
|
1474
|
+
objectType: 'comAcc',
|
|
1475
|
+
belongTo: {
|
|
1476
|
+
objectType: 'user',
|
|
1477
|
+
serviceTag: 'UserAccount'
|
|
1478
|
+
}
|
|
1479
|
+
};\n`
|
|
1480
|
+
);
|
|
1481
|
+
await writeFile(
|
|
1482
|
+
join(
|
|
1483
|
+
rootPath,
|
|
1484
|
+
'app/src/schemas/FlowSchemas/CreateBusinessToComAcc.js'
|
|
1485
|
+
),
|
|
1486
|
+
`export default {
|
|
1487
|
+
flowTag: 'createBusinessToComAcc',
|
|
1488
|
+
event: ['lambdaSyncInv', 'ownTopic'],
|
|
1489
|
+
objType: {
|
|
1490
|
+
objectType: 'comAcc',
|
|
1491
|
+
serviceTag: 'ComAcc'
|
|
1492
|
+
},
|
|
1493
|
+
flowSteps: [{ stepName: 'Start' }]
|
|
1494
|
+
};\n`
|
|
1495
|
+
);
|
|
1496
|
+
|
|
1497
|
+
const result = await generate(rootPath, {
|
|
1498
|
+
serviceTag: 'BusinessService'
|
|
1499
|
+
});
|
|
1500
|
+
assert.ok(result);
|
|
1501
|
+
|
|
1502
|
+
const sourceDir = join(
|
|
1503
|
+
rootPath,
|
|
1504
|
+
'app/src/generatedCode/FlowSchemas/CreateBusinessToComAcc/source'
|
|
1505
|
+
);
|
|
1506
|
+
const mainPath = join(sourceDir, 'CreateBusinessToComAcc_Main.js');
|
|
1507
|
+
const mainContent = await readFile(mainPath, 'utf8');
|
|
1508
|
+
assert.match(mainContent, /checkRbacPermission/);
|
|
1509
|
+
assert.doesNotMatch(mainContent, /CreateBusinessToComAccRbacCallback/);
|
|
1510
|
+
|
|
1511
|
+
await assert.rejects(
|
|
1512
|
+
() =>
|
|
1513
|
+
readFile(
|
|
1514
|
+
join(sourceDir, 'CreateBusinessToComAccRbacCallback_Main.js'),
|
|
1515
|
+
'utf8'
|
|
1516
|
+
),
|
|
1517
|
+
{ code: 'ENOENT' }
|
|
1518
|
+
);
|
|
1519
|
+
await assert.rejects(
|
|
1520
|
+
() =>
|
|
1521
|
+
readFile(
|
|
1522
|
+
join(sourceDir, 'CreateBusinessToComAccRbacCallback_HdrSqs.js'),
|
|
1523
|
+
'utf8'
|
|
1524
|
+
),
|
|
1525
|
+
{ code: 'ENOENT' }
|
|
1526
|
+
);
|
|
1527
|
+
|
|
1528
|
+
const initialSetupConfigContent = await readFile(
|
|
1529
|
+
join(
|
|
1530
|
+
rootPath,
|
|
1531
|
+
'app/src/generatedCode/CoreFunctions/InitialSetupConfig.js'
|
|
1532
|
+
),
|
|
1533
|
+
'utf8'
|
|
1534
|
+
);
|
|
1535
|
+
assert.doesNotMatch(
|
|
1536
|
+
initialSetupConfigContent,
|
|
1537
|
+
/CreateBusinessToComAccRbacCallbackHdrSqs/
|
|
1538
|
+
);
|
|
1539
|
+
});
|
|
1540
|
+
|
|
1541
|
+
test('skips checkRbacPermission in FlowEndpoint_Main when initiateBy is systemNoUser', async () => {
|
|
1542
|
+
const { generate } = await import('../src/generate.js');
|
|
1543
|
+
const rootPath = await createProject();
|
|
1544
|
+
await writeFile(
|
|
1545
|
+
join(rootPath, 'app/src/schemas/ObjectSchemas/ComAcc.js'),
|
|
1546
|
+
`export default {
|
|
1547
|
+
objectType: 'comAcc',
|
|
1548
|
+
belongTo: {
|
|
1549
|
+
objectType: 'user',
|
|
1550
|
+
serviceTag: 'UserAccount'
|
|
1551
|
+
}
|
|
1552
|
+
};\n`
|
|
1553
|
+
);
|
|
1554
|
+
await writeFile(
|
|
1555
|
+
join(
|
|
1556
|
+
rootPath,
|
|
1557
|
+
'app/src/schemas/FlowSchemas/SystemCronFlow.js'
|
|
1558
|
+
),
|
|
1559
|
+
`export default {
|
|
1560
|
+
flowTag: 'systemCronFlow',
|
|
1561
|
+
event: ['ownTopic'],
|
|
1562
|
+
initiateBy: 'systemNoUser',
|
|
1563
|
+
objType: {
|
|
1564
|
+
objectType: 'comAcc',
|
|
1565
|
+
serviceTag: 'ComAcc'
|
|
1566
|
+
},
|
|
1567
|
+
flowSteps: [{ stepName: 'Start' }]
|
|
1568
|
+
};\n`
|
|
1569
|
+
);
|
|
1570
|
+
|
|
1571
|
+
const result = await generate(rootPath, {
|
|
1572
|
+
serviceTag: 'BusinessService'
|
|
1573
|
+
});
|
|
1574
|
+
assert.ok(result);
|
|
1575
|
+
|
|
1576
|
+
const mainPath = join(
|
|
1577
|
+
rootPath,
|
|
1578
|
+
'app/src/generatedCode/FlowSchemas/SystemCronFlow/source/SystemCronFlow_Main.js'
|
|
1579
|
+
);
|
|
1580
|
+
const mainContent = await readFile(mainPath, 'utf8');
|
|
1581
|
+
assert.doesNotMatch(mainContent, /checkRbacPermission/);
|
|
1582
|
+
await parseAsEsm(mainPath);
|
|
1583
|
+
});
|
|
1584
|
+
|
|
1585
|
+
test('emits completeStatusField only in the final flowStep for statusType statusField', async () => {
|
|
1586
|
+
const rootPath = await createProject();
|
|
1587
|
+
await writeFile(
|
|
1588
|
+
join(rootPath, 'app/src/schemas/FlowSchemas/MultiStepStatus.js'),
|
|
1589
|
+
`export default {
|
|
1590
|
+
flowTag: 'multiStepStatus',
|
|
1591
|
+
event: ['ownTopic'],
|
|
1592
|
+
statusType: 'statusField',
|
|
1593
|
+
objType: { objectType: 'order', serviceTag: 'Current' },
|
|
1594
|
+
flowSteps: [
|
|
1595
|
+
{
|
|
1596
|
+
stepName: 'Start',
|
|
1597
|
+
nextSteps: [
|
|
1598
|
+
{
|
|
1599
|
+
targetType: 'extTopic',
|
|
1600
|
+
serviceTag: 'PaymentService',
|
|
1601
|
+
topicName: 'Process_In',
|
|
1602
|
+
toStepNames: ['Process']
|
|
1603
|
+
}
|
|
1604
|
+
]
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
stepName: 'Process',
|
|
1608
|
+
event: ['extTopic'],
|
|
1609
|
+
previousSteps: [{ sourceType: 'ownTopic', stepName: 'Start' }],
|
|
1610
|
+
nextSteps: [
|
|
1611
|
+
{
|
|
1612
|
+
targetType: 'extTopic',
|
|
1613
|
+
serviceTag: 'PaymentService',
|
|
1614
|
+
topicName: 'Finalize_In',
|
|
1615
|
+
toStepNames: ['Finalize']
|
|
1616
|
+
}
|
|
1617
|
+
]
|
|
1618
|
+
},
|
|
1619
|
+
{
|
|
1620
|
+
stepName: 'Finalize',
|
|
1621
|
+
event: ['extTopic'],
|
|
1622
|
+
previousSteps: [{ sourceType: 'extTopic', serviceTag: 'PaymentService', topicName: 'Process_Out', fromStepNames: ['Process'] }]
|
|
1623
|
+
}
|
|
1624
|
+
]
|
|
1625
|
+
};\n`
|
|
1626
|
+
);
|
|
1627
|
+
|
|
1628
|
+
await generateCustomFlowApplicationArtifacts(rootPath);
|
|
1629
|
+
|
|
1630
|
+
// 1. Start step (FlowEndpoint_Main) has checkStatusField, NOT completeStatusField
|
|
1631
|
+
const startPath = join(
|
|
1632
|
+
rootPath,
|
|
1633
|
+
'app/src/generatedCode/FlowSchemas/MultiStepStatus/source/MultiStepStatus_Main.js'
|
|
1634
|
+
);
|
|
1635
|
+
const startContent = await readFile(startPath, 'utf8');
|
|
1636
|
+
assert.match(startContent, /statusFieldSharedLib\.checkStatusField/);
|
|
1637
|
+
assert.doesNotMatch(startContent, /completeStatusField/);
|
|
1638
|
+
await parseAsEsm(startPath);
|
|
1639
|
+
|
|
1640
|
+
// 2. Middle step (Process) is not the last step, so NO completeStatusField
|
|
1641
|
+
const processPath = join(
|
|
1642
|
+
rootPath,
|
|
1643
|
+
'app/src/generatedCode/FlowSchemas/MultiStepStatus/source/MultiStepStatusProcess_Main.js'
|
|
1644
|
+
);
|
|
1645
|
+
const processContent = await readFile(processPath, 'utf8');
|
|
1646
|
+
assert.doesNotMatch(processContent, /statusFieldSharedLib/);
|
|
1647
|
+
assert.doesNotMatch(processContent, /completeStatusField/);
|
|
1648
|
+
await parseAsEsm(processPath);
|
|
1649
|
+
|
|
1650
|
+
// 3. Final step (Finalize) IS the last step, so it has completeStatusField and canonical hooks
|
|
1651
|
+
const finalizePath = join(
|
|
1652
|
+
rootPath,
|
|
1653
|
+
'app/src/generatedCode/FlowSchemas/MultiStepStatus/source/MultiStepStatusFinalize_Main.js'
|
|
1654
|
+
);
|
|
1655
|
+
const finalizeContent = await readFile(finalizePath, 'utf8');
|
|
1656
|
+
assert.match(
|
|
1657
|
+
finalizeContent,
|
|
1658
|
+
/import statusFieldSharedLib from '@izara_project\/izara-core-library-status-field';/
|
|
1659
|
+
);
|
|
1660
|
+
assert.match(finalizeContent, /\/\/\(<beforeCompleteStatusField>\)/);
|
|
1661
|
+
assert.match(finalizeContent, /statusFieldSharedLib\.completeStatusField/);
|
|
1662
|
+
assert.match(finalizeContent, /flowTag:\s*'multiStepStatus'/);
|
|
1663
|
+
assert.match(finalizeContent, /\/\/\(<identifiers>\)/);
|
|
1664
|
+
assert.match(finalizeContent, /\/\/\(<statusField>\)/);
|
|
1665
|
+
assert.match(finalizeContent, /\/\/\(<errorFounds>\)/);
|
|
1666
|
+
assert.match(finalizeContent, /\/\/\(<afterCompleteStatusField>\)/);
|
|
1667
|
+
await parseAsEsm(finalizePath);
|
|
1668
|
+
});
|
|
1669
|
+
|
|
1670
|
+
|
|
1415
1671
|
|
|
@@ -125,6 +125,35 @@ test('emits relationship action and complete handlers with data-first function Y
|
|
|
125
125
|
assert.match(yaml, /CreateRelationshipCompleteHdrSqs:/);
|
|
126
126
|
});
|
|
127
127
|
|
|
128
|
+
test('emits valid hook tags without trailing periods and with correct callingFlowProperties placement in relationship Main files', async () => {
|
|
129
|
+
const rootPath = await createProject(true);
|
|
130
|
+
await generateRelationshipApplicationArtifacts(rootPath, {
|
|
131
|
+
serviceTag: 'orders'
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const actions = ['Create', 'Update', 'Delete', 'Move', 'Change'];
|
|
135
|
+
for (const action of actions) {
|
|
136
|
+
const mainContent = await readFile(
|
|
137
|
+
join(
|
|
138
|
+
rootPath,
|
|
139
|
+
`app/src/generatedCode/FlowRelationships/${action}Relationship/source/${action}Relationship_Main.js`
|
|
140
|
+
),
|
|
141
|
+
'utf8'
|
|
142
|
+
);
|
|
143
|
+
assert.doesNotMatch(mainContent, /\/\/\(<\/[^>]+>\)\./);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const changeMain = await readFile(
|
|
147
|
+
join(
|
|
148
|
+
rootPath,
|
|
149
|
+
'app/src/generatedCode/FlowRelationships/ChangeRelationship/source/ChangeRelationship_Main.js'
|
|
150
|
+
),
|
|
151
|
+
'utf8'
|
|
152
|
+
);
|
|
153
|
+
assert.match(changeMain, /\/\/\(<requestParamChangeRel>\)/);
|
|
154
|
+
assert.doesNotMatch(changeMain, /\/\/\(<requestParamCreateRel>\)/);
|
|
155
|
+
});
|
|
156
|
+
|
|
128
157
|
test('removes managed relationship artifacts after relationships are removed', async () => {
|
|
129
158
|
const rootPath = await createProject(true);
|
|
130
159
|
await generateRelationshipApplicationArtifacts(rootPath, {
|