@izara_project/izara-core-generate-service-code 1.0.97 → 1.0.98

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.
Files changed (37) hide show
  1. package/package.json +1 -1
  2. package/src/compile/loadSchemas.js +29 -6
  3. package/src/emit/application/crud/templates/FlowEndpoint_HdrWbs.ejs +2 -2
  4. package/src/emit/application/crud/templates/FlowMain_Wbs.ejs +2 -2
  5. package/src/emit/application/custom/templates/s3/CreateObject_Main.ejs +5 -2
  6. package/src/emit/application/custom/templates/triggerCache/CheckTriggerCache_Main.ejs +2 -2
  7. package/src/emit/application/relationship/templates/ChangeRelationship_Main.ejs +3 -2
  8. package/src/emit/application/relationship/templates/CreateRelationship_Main.ejs +3 -2
  9. package/src/emit/application/relationship/templates/DeleteRelationship_Main.ejs +3 -2
  10. package/src/emit/application/relationship/templates/GetRelationship_Main.ejs +3 -2
  11. package/src/emit/application/relationship/templates/MoveRelationship_Main.ejs +3 -2
  12. package/src/emit/application/relationship/templates/UpdateRelationship_Main.ejs +3 -2
  13. package/src/emit/application/system/templates/RegisterComplete_Main.ejs +6 -2
  14. package/src/emit/application/system/templates/Register_Main.ejs +6 -2
  15. package/src/emit/application/system/templates/WebSocketComplete_Main.ejs +3 -3
  16. package/src/emit/infrastructure/resources/iamResourceArtifacts.js +1 -1
  17. package/src/emit/schemas/attributeTree/emitAttributeTreeSchemas.js +14 -22
  18. package/src/emit/schemas/attributeTree/emitAttributeTreeTargetValueStandard.js +132 -0
  19. package/src/emit/schemas/ledger/emitLedgerSchemas.js +33 -11
  20. package/src/emit/schemas/ledger/templates/LedgerObjectSchema.ejs +3 -0
  21. package/src/emit/schemas/ledger/templates/LedgerRelationshipSchema.ejs +1 -0
  22. package/src/emit/schemas/propertyValue/emitPropertyValueSchemas.js +329 -0
  23. package/src/generate.js +16 -75
  24. package/src/output/mergeHooks.js +69 -15
  25. package/src/plan/domainRegistry.js +41 -5
  26. package/task.md +132 -0
  27. package/test/integration/publicApi.test.js +54 -1
  28. package/test/unit/application/customFlowApplicationArtifacts.test.js +9 -0
  29. package/test/unit/application/relationshipApplicationArtifacts.test.js +30 -0
  30. package/test/unit/infrastructure/resourceArtifacts.test.js +1 -0
  31. package/test/unit/output/mergeHooks.test.js +268 -0
  32. package/test/unit/schemas/attributeTreeDirectives.test.js +177 -0
  33. package/test/unit/schemas/attributeTreeSchemas.test.js +10 -61
  34. package/test/unit/schemas/ledgerSchemas.test.js +33 -7
  35. package/test/unit/schemas/propertyValueSchemas.test.js +265 -0
  36. package/src/emit/schemas/attributeTree/emitAttributeTreeTargetSchemas.js +0 -153
  37. package/src/emit/schemas/attributeTree/resolveTargetServicePath.js +0 -111
@@ -0,0 +1,177 @@
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
+ });
@@ -8,9 +8,7 @@ import {
8
8
  emitAttributeTreeObjectSchemas,
9
9
  emitAttributeTreeRelationshipSchemas,
10
10
  attributeTreeObjectSchemaManagedPaths,
11
- attributeTreeRelationshipSchemaManagedPaths,
12
- resolveTargetServicePath,
13
- emitAttributeTreeTargetSchemas
11
+ attributeTreeRelationshipSchemaManagedPaths
14
12
  } from '../../../src/emit/schemas/attributeTree/emitAttributeTreeSchemas.js';
15
13
  import { generate } from '../../../src/generate.js';
16
14
  import {
@@ -54,9 +52,9 @@ test('emitAttributeTreeObjectSchemas returns 3 object schemas per attributeTree
54
52
 
55
53
  const paths = artifacts.map((a) => a.path);
56
54
  assert.deepEqual(paths, [
57
- 'app/src/schemas/ObjectSchemas/generatedAttributeTree/sellOfferTermLink.js',
58
- 'app/src/schemas/ObjectSchemas/generatedAttributeTree/sellOfferTermValue.js',
59
- 'app/src/schemas/ObjectSchemas/generatedAttributeTree/sellOfferTermLabel.js'
55
+ 'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermLink.js',
56
+ 'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermValue.js',
57
+ 'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermLabel.js'
60
58
  ]);
61
59
 
62
60
  const valueArtifact = artifacts.find((a) =>
@@ -103,10 +101,10 @@ test('emitAttributeTreeRelationshipSchemas returns 4 relationship schemas per at
103
101
 
104
102
  const paths = artifacts.map((a) => a.path);
105
103
  assert.deepEqual(paths, [
106
- 'app/src/schemas/RelationshipSchemas/generatedAttributeTree/hasSellOfferTermLink.js',
107
- 'app/src/schemas/RelationshipSchemas/generatedAttributeTree/disabledSellOfferTermLink.js',
108
- 'app/src/schemas/RelationshipSchemas/generatedAttributeTree/isSellOfferTerm.js',
109
- 'app/src/schemas/RelationshipSchemas/generatedAttributeTree/isSellOfferTermLabel.js'
104
+ 'app/src/schemas/RelationshipSchemas/generatedCode/attributeTree/hasSellOfferTermLink.js',
105
+ 'app/src/schemas/RelationshipSchemas/generatedCode/attributeTree/disabledSellOfferTermLink.js',
106
+ 'app/src/schemas/RelationshipSchemas/generatedCode/attributeTree/isSellOfferTerm.js',
107
+ 'app/src/schemas/RelationshipSchemas/generatedCode/attributeTree/isSellOfferTermLabel.js'
110
108
  ]);
111
109
 
112
110
  const hasRel = artifacts.find((a) => a.path.endsWith('hasSellOfferTermLink.js'));
@@ -153,9 +151,9 @@ test('generate commits and cleans up attributeTree dynamic schemas', async () =>
153
151
  await generate(rootPath);
154
152
 
155
153
  const objectRelPath =
156
- 'app/src/schemas/ObjectSchemas/generatedAttributeTree/sellOfferTermLink.js';
154
+ 'app/src/schemas/ObjectSchemas/generatedCode/attributeTree/sellOfferTermLink.js';
157
155
  const relRelPath =
158
- 'app/src/schemas/RelationshipSchemas/generatedAttributeTree/hasSellOfferTermLink.js';
156
+ 'app/src/schemas/RelationshipSchemas/generatedCode/attributeTree/hasSellOfferTermLink.js';
159
157
 
160
158
  const objectContent = await readProjectFile(rootPath, objectRelPath);
161
159
  assert.match(objectContent, /sellOfferTermLink/);
@@ -244,53 +242,4 @@ async function createProjectWithAttributeTree({
244
242
  });
245
243
  }
246
244
 
247
- test('resolveTargetServicePath prioritizes dev suffix and matches attributeTag', async () => {
248
- const tmpRoot = trackTestProject(
249
- await mkdtemp(join(tmpdir(), 'izara-services-test-'))
250
- );
251
-
252
- const currentServiceDir = join(
253
- tmpRoot,
254
- 'izara-market-products-sell-offer-manager-pong'
255
- );
256
- const targetWithSuffix = join(
257
- tmpRoot,
258
- 'izara-market-products-sell-offer-term-pong'
259
- );
260
- const targetOtherDev = join(
261
- tmpRoot,
262
- 'izara-market-products-sell-offer-term-alice'
263
- );
264
- const unrelatedService = join(
265
- tmpRoot,
266
- 'izara-market-products-cart-pong'
267
- );
268
-
269
- await mkdir(join(currentServiceDir, 'app/src'), { recursive: true });
270
- await mkdir(join(targetWithSuffix, 'app/src'), { recursive: true });
271
- await mkdir(join(targetOtherDev, 'app/src'), { recursive: true });
272
- await mkdir(join(unrelatedService, 'app/src'), { recursive: true });
273
-
274
- const resolved = resolveTargetServicePath({
275
- currentServiceRoot: currentServiceDir,
276
- attributeTag: 'sellOfferTerm'
277
- });
278
-
279
- assert.equal(resolved, targetWithSuffix);
280
- });
281
-
282
- test('emitAttributeTreeTargetSchemas produces expected standard schemas', () => {
283
- const targetDir = '/dummy/path/izara-market-products-sellOfferTerm';
284
- const artifacts = emitAttributeTreeTargetSchemas({
285
- attributeTag: 'sellOfferTerm',
286
- targetServiceRoot: targetDir
287
- });
288
-
289
- assert.equal(artifacts.length, 3);
290
- const paths = artifacts.map((a) => a.path);
291
-
292
- assert.ok(paths.some((p) => p.endsWith('sellOfferTermValueStandardPropertyLabel.js')));
293
- assert.ok(paths.some((p) => p.endsWith('sellOfferTermValueStandardPropertyValue.js')));
294
- assert.ok(paths.some((p) => p.endsWith('sellOfferTermValueStandard.js')));
295
- });
296
245
 
@@ -19,7 +19,7 @@ after(async () => {
19
19
  await cleanupTestProjects();
20
20
  });
21
21
 
22
- test('emitLedgerObjectSchemas returns 1 object schema per ledger addOn', () => {
22
+ test('emitLedgerObjectSchemas returns 1 object schema per ledger addOn', async () => {
23
23
  const objects = [
24
24
  {
25
25
  objectType: 'unitStandard',
@@ -61,7 +61,7 @@ test('emitLedgerObjectSchemas returns 1 object schema per ledger addOn', () => {
61
61
  }
62
62
  ];
63
63
 
64
- const artifacts = emitLedgerObjectSchemas({ objects });
64
+ const artifacts = await emitLedgerObjectSchemas({ objects });
65
65
  assert.equal(artifacts.length, 2);
66
66
 
67
67
  const paths = artifacts.map((a) => a.path);
@@ -81,7 +81,7 @@ test('emitLedgerObjectSchemas returns 1 object schema per ledger addOn', () => {
81
81
  assert.match(entryArtifact.content, /GraphHandler/);
82
82
  });
83
83
 
84
- test('emitLedgerRelationshipSchemas returns current, old, and is relationship schemas per ledger addOn', () => {
84
+ test('emitLedgerRelationshipSchemas returns current, old, and is relationship schemas per ledger addOn', async () => {
85
85
  const objects = [
86
86
  {
87
87
  objectType: 'unitStandard',
@@ -113,7 +113,7 @@ test('emitLedgerRelationshipSchemas returns current, old, and is relationship sc
113
113
  }
114
114
  ];
115
115
 
116
- const artifacts = emitLedgerRelationshipSchemas({
116
+ const artifacts = await emitLedgerRelationshipSchemas({
117
117
  objects,
118
118
  serviceTag: 'UnitStandard'
119
119
  });
@@ -156,14 +156,40 @@ test('emitLedgerRelationshipSchemas returns current, old, and is relationship sc
156
156
  assert.match(isRel.content, /"generatedBy": "systemNoUser"/);
157
157
  assert.match(isRel.content, /"supplyLocation"/);
158
158
  assert.match(isRel.content, /"unitPacking"/);
159
+
160
+ // 4. Verify requiredOnCreate is false in links
161
+ const _parseRel = (content) => {
162
+ const raw = content
163
+ .replace(/^export default\s+/, '')
164
+ .replace(/;\s*$/, '');
165
+ return JSON.parse(raw)[0];
166
+ };
167
+
168
+ const currentRelData = Object.values(_parseRel(currentRel.content))[0];
169
+ for (const link of currentRelData.links) {
170
+ assert.equal(link.from.requiredOnCreate, false);
171
+ assert.equal(link.to.requiredOnCreate, false);
172
+ }
173
+
174
+ const oldRelData = Object.values(_parseRel(oldRel.content))[0];
175
+ for (const link of oldRelData.links) {
176
+ assert.equal(link.from.requiredOnCreate, false);
177
+ assert.equal(link.to.requiredOnCreate, false);
178
+ }
179
+
180
+ const isRelData = Object.values(_parseRel(isRel.content))[0];
181
+ for (const link of isRelData.links) {
182
+ assert.equal(link.from.requiredOnCreate, false);
183
+ assert.equal(link.to.requiredOnCreate, false);
184
+ }
159
185
  });
160
186
 
161
- test('managed paths return empty array when no ledger is present', () => {
187
+ test('managed paths return empty array when no ledger is present', async () => {
162
188
  const objects = [{ objectType: 'user', addOnDataStructure: [] }];
163
189
  assert.deepEqual(ledgerObjectSchemaManagedPaths(objects), []);
164
190
  assert.deepEqual(ledgerRelationshipSchemaManagedPaths(objects), []);
165
- assert.deepEqual(emitLedgerObjectSchemas({ objects }), []);
166
- assert.deepEqual(emitLedgerRelationshipSchemas({ objects }), []);
191
+ assert.deepEqual(await emitLedgerObjectSchemas({ objects }), []);
192
+ assert.deepEqual(await emitLedgerRelationshipSchemas({ objects }), []);
167
193
  });
168
194
 
169
195
  test('generate commits and cleans up ledger dynamic schemas', async () => {
@@ -0,0 +1,265 @@
1
+ import assert from 'node:assert/strict';
2
+ import test, { after } from 'node:test';
3
+
4
+ import {
5
+ emitPropertyValueObjectSchemas,
6
+ emitPropertyValueRelationshipSchemas,
7
+ propertyValueObjectSchemaManagedPaths,
8
+ propertyValueRelationshipSchemaManagedPaths
9
+ } from '../../../src/emit/schemas/propertyValue/emitPropertyValueSchemas.js';
10
+ import { generate } from '../../../src/generate.js';
11
+ import {
12
+ createTestProject,
13
+ readProjectFile,
14
+ writeProjectFile,
15
+ cleanupTestProjects
16
+ } from '../../helpers/testProject.js';
17
+
18
+ after(async () => {
19
+ await cleanupTestProjects();
20
+ });
21
+
22
+ test('emitPropertyValueObjectSchemas returns 2 object schemas per propertyValue addOn', () => {
23
+ const objects = [
24
+ {
25
+ objectType: 'item',
26
+ serviceTag: 'ItemService',
27
+ storageResources: {
28
+ dynamoDB: {
29
+ storageType: 'dynamoDB',
30
+ tableName: 'ItemRecords'
31
+ },
32
+ myGraph: {
33
+ storageType: 'graph',
34
+ graphServerTag: 'GraphHandler'
35
+ }
36
+ },
37
+ addOnDataStructure: [
38
+ {
39
+ type: 'propertyValue',
40
+ propertyValuePrefix: 'itemProperty'
41
+ }
42
+ ]
43
+ },
44
+ {
45
+ objectType: 'supplyNetwork',
46
+ serviceTag: 'SupplyService',
47
+ storageResources: {
48
+ myGraph: {
49
+ storageType: 'graph',
50
+ graphServerTag: 'GraphHandler'
51
+ }
52
+ },
53
+ addOnDataStructure: [
54
+ {
55
+ type: 'propertyValue'
56
+ }
57
+ ]
58
+ }
59
+ ];
60
+
61
+ const artifacts = emitPropertyValueObjectSchemas({ objects });
62
+ assert.equal(artifacts.length, 4);
63
+
64
+ const paths = artifacts.map((a) => a.path);
65
+ assert.deepEqual(paths, [
66
+ 'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/itemPropertyPropertyLabel.js',
67
+ 'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/itemPropertyPropertyValue.js',
68
+ 'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/supplyNetworkPropertyLabel.js',
69
+ 'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/supplyNetworkPropertyValue.js'
70
+ ]);
71
+
72
+ const labelArtifact = artifacts[0];
73
+ assert.match(
74
+ labelArtifact.content,
75
+ /"objectType": "itemPropertyPropertyLabel"/
76
+ );
77
+ assert.match(labelArtifact.content, /"itemPropertyPropertyLabelId"/);
78
+ assert.match(labelArtifact.content, /"generatedBy": "user"/);
79
+ assert.match(labelArtifact.content, /"canDelete": true/);
80
+ assert.doesNotMatch(labelArtifact.content, /dynamoDB/);
81
+ assert.match(labelArtifact.content, /GraphHandler/);
82
+
83
+ const valueArtifact = artifacts[1];
84
+ assert.match(
85
+ valueArtifact.content,
86
+ /"objectType": "itemPropertyPropertyValue"/
87
+ );
88
+ assert.match(valueArtifact.content, /"itemPropertyPropertyValueId"/);
89
+ });
90
+
91
+ test('emitPropertyValueRelationshipSchemas returns 3 relationship schemas per propertyValue addOn', () => {
92
+ const objects = [
93
+ {
94
+ objectType: 'item',
95
+ serviceTag: 'ItemService',
96
+ storageResources: {
97
+ myGraph: {
98
+ storageType: 'graph',
99
+ graphServerTag: 'GraphHandler'
100
+ }
101
+ },
102
+ addOnDataStructure: [
103
+ {
104
+ type: 'propertyValue',
105
+ propertyValuePrefix: 'item'
106
+ }
107
+ ]
108
+ }
109
+ ];
110
+
111
+ const artifacts = emitPropertyValueRelationshipSchemas({
112
+ objects,
113
+ serviceTag: 'ItemService'
114
+ });
115
+ assert.equal(artifacts.length, 3);
116
+
117
+ const paths = artifacts.map((a) => a.path);
118
+ assert.deepEqual(paths, [
119
+ 'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/hasItemPropertyValue.js',
120
+ 'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/disabledItemPropertyValue.js',
121
+ 'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/isItemPropertyLabel.js'
122
+ ]);
123
+
124
+ // 1. hasItemPropertyValue
125
+ const hasRel = artifacts[0];
126
+ assert.match(hasRel.content, /"hasItemPropertyValue"/);
127
+ assert.match(hasRel.content, /"generatedBy": "user"/);
128
+ assert.match(hasRel.content, /"objectType": "item"/);
129
+ assert.match(hasRel.content, /"objectType": "itemPropertyValue"/);
130
+ assert.match(hasRel.content, /"linkType": "one"/);
131
+ assert.match(hasRel.content, /"linkType": "many"/);
132
+
133
+ // 2. disabledItemPropertyValue
134
+ const disabledRel = artifacts[1];
135
+ assert.match(disabledRel.content, /"disabledItemPropertyValue"/);
136
+ assert.match(disabledRel.content, /"generatedBy": "user"/);
137
+
138
+ // 3. isItemPropertyLabel
139
+ const isRel = artifacts[2];
140
+ assert.match(isRel.content, /"isItemPropertyLabel"/);
141
+ assert.match(isRel.content, /"generatedBy": "systemNoUser"/);
142
+ assert.match(isRel.content, /"objectType": "itemPropertyLabel"/);
143
+ });
144
+
145
+ test('managed paths return empty array when no propertyValue is present', () => {
146
+ const objects = [{ objectType: 'user', addOnDataStructure: [] }];
147
+ assert.deepEqual(propertyValueObjectSchemaManagedPaths(objects), []);
148
+ assert.deepEqual(propertyValueRelationshipSchemaManagedPaths(objects), []);
149
+ assert.deepEqual(emitPropertyValueObjectSchemas({ objects }), []);
150
+ assert.deepEqual(emitPropertyValueRelationshipSchemas({ objects }), []);
151
+ });
152
+
153
+ test('generate commits and cleans up propertyValue dynamic schemas', async () => {
154
+ const rootPath = await createProjectWithPropertyValue({ hasAddOn: true });
155
+ await generate(rootPath);
156
+
157
+ const labelPath =
158
+ 'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/itemPropertyLabel.js';
159
+ const valuePath =
160
+ 'app/src/schemas/ObjectSchemas/generatedCode/propertyValue/itemPropertyValue.js';
161
+ const hasRelPath =
162
+ 'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/hasItemPropertyValue.js';
163
+ const disabledRelPath =
164
+ 'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/disabledItemPropertyValue.js';
165
+ const isRelPath =
166
+ 'app/src/schemas/RelationshipSchemas/generatedCode/propertyValue/isItemPropertyLabel.js';
167
+
168
+ const labelContent = await readProjectFile(rootPath, labelPath);
169
+ assert.match(labelContent, /itemPropertyLabel/);
170
+ assert.match(labelContent, /GraphHandler/);
171
+
172
+ const valueContent = await readProjectFile(rootPath, valuePath);
173
+ assert.match(valueContent, /itemPropertyValue/);
174
+
175
+ const hasRelContent = await readProjectFile(rootPath, hasRelPath);
176
+ assert.match(hasRelContent, /hasItemPropertyValue/);
177
+
178
+ const disabledRelContent = await readProjectFile(rootPath, disabledRelPath);
179
+ assert.match(disabledRelContent, /disabledItemPropertyValue/);
180
+
181
+ const isRelContent = await readProjectFile(rootPath, isRelPath);
182
+ assert.match(isRelContent, /isItemPropertyLabel/);
183
+
184
+ // Re-run without addOn to verify stale file cleanup
185
+ await createProjectWithPropertyValue({ rootPath, hasAddOn: false });
186
+ await generate(rootPath);
187
+
188
+ await assert.rejects(readProjectFile(rootPath, labelPath), {
189
+ code: 'ENOENT'
190
+ });
191
+ await assert.rejects(readProjectFile(rootPath, valuePath), {
192
+ code: 'ENOENT'
193
+ });
194
+ await assert.rejects(readProjectFile(rootPath, hasRelPath), {
195
+ code: 'ENOENT'
196
+ });
197
+ await assert.rejects(readProjectFile(rootPath, disabledRelPath), {
198
+ code: 'ENOENT'
199
+ });
200
+ await assert.rejects(readProjectFile(rootPath, isRelPath), {
201
+ code: 'ENOENT'
202
+ });
203
+ });
204
+
205
+ async function createProjectWithPropertyValue({
206
+ rootPath: existingRoot,
207
+ hasAddOn = true
208
+ } = {}) {
209
+ let addOnContent = ' addOnDataStructure: [],';
210
+ if (hasAddOn) {
211
+ addOnContent = `
212
+ addOnDataStructure: [
213
+ {
214
+ type: 'propertyValue',
215
+ propertyValuePrefix: 'item'
216
+ }
217
+ ],`;
218
+ }
219
+
220
+ const schemaContent = `export default [
221
+ {
222
+ objectType: 'item',
223
+ canDelete: false,
224
+ generatedBy: 'user',${addOnContent}
225
+ storageResources: {
226
+ graph: {
227
+ storageType: 'graph',
228
+ graphServerTag: 'GraphHandler'
229
+ }
230
+ },
231
+ fieldNames: {
232
+ itemId: {
233
+ type: 'string',
234
+ randomOnCreate: true,
235
+ canUpdate: false,
236
+ storageResourceTags: ['graph']
237
+ }
238
+ },
239
+ identifiers: [
240
+ {
241
+ type: 'partitionKey',
242
+ fieldName: 'itemId'
243
+ }
244
+ ]
245
+ }
246
+ ];
247
+ `;
248
+
249
+ if (existingRoot) {
250
+ await writeProjectFile(
251
+ existingRoot,
252
+ 'app/src/schemas/ObjectSchemas/Item.js',
253
+ schemaContent
254
+ );
255
+ return existingRoot;
256
+ }
257
+
258
+ return await createTestProject({
259
+ prefix: 'izara-property-value-test-',
260
+ serviceTag: 'ItemService',
261
+ schemas: {
262
+ 'ObjectSchemas/Item.js': schemaContent
263
+ }
264
+ });
265
+ }