@api-client/core 0.14.0 → 0.14.1

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 (140) hide show
  1. package/build/src/amf/AmfTypes.d.ts +1 -1
  2. package/build/src/amf/AmfTypes.js +1 -1
  3. package/build/src/amf/AmfTypes.js.map +1 -1
  4. package/build/src/amf/Utils.d.ts +0 -6
  5. package/build/src/amf/Utils.d.ts.map +1 -1
  6. package/build/src/amf/Utils.js +0 -14
  7. package/build/src/amf/Utils.js.map +1 -1
  8. package/build/src/browser.d.ts +1 -0
  9. package/build/src/browser.d.ts.map +1 -1
  10. package/build/src/browser.js +1 -0
  11. package/build/src/browser.js.map +1 -1
  12. package/build/src/index.d.ts +1 -0
  13. package/build/src/index.d.ts.map +1 -1
  14. package/build/src/index.js +1 -0
  15. package/build/src/index.js.map +1 -1
  16. package/build/src/legacy.d.ts +0 -8
  17. package/build/src/legacy.d.ts.map +1 -1
  18. package/build/src/legacy.js +0 -9
  19. package/build/src/legacy.js.map +1 -1
  20. package/build/src/modeling/Bindings.d.ts +1 -1
  21. package/build/src/modeling/Bindings.js.map +1 -1
  22. package/build/src/modeling/DataDomain.js +2 -2
  23. package/build/src/modeling/DataDomain.js.map +1 -1
  24. package/build/src/modeling/DataFormat.d.ts +0 -40
  25. package/build/src/modeling/DataFormat.d.ts.map +1 -1
  26. package/build/src/modeling/DataFormat.js +0 -27
  27. package/build/src/modeling/DataFormat.js.map +1 -1
  28. package/build/src/modeling/DomainAssociation.d.ts +28 -0
  29. package/build/src/modeling/DomainAssociation.d.ts.map +1 -1
  30. package/build/src/modeling/DomainAssociation.js +73 -4
  31. package/build/src/modeling/DomainAssociation.js.map +1 -1
  32. package/build/src/modeling/DomainEntity.d.ts +25 -9
  33. package/build/src/modeling/DomainEntity.d.ts.map +1 -1
  34. package/build/src/modeling/DomainEntity.js +65 -21
  35. package/build/src/modeling/DomainEntity.js.map +1 -1
  36. package/build/src/modeling/DomainFile.d.ts +1 -1
  37. package/build/src/modeling/DomainFile.js +1 -1
  38. package/build/src/modeling/DomainFile.js.map +1 -1
  39. package/build/src/modeling/DomainImpactAnalysis.d.ts +1 -1
  40. package/build/src/modeling/DomainImpactAnalysis.d.ts.map +1 -1
  41. package/build/src/modeling/DomainImpactAnalysis.js +3 -3
  42. package/build/src/modeling/DomainImpactAnalysis.js.map +1 -1
  43. package/build/src/modeling/DomainModel.d.ts +2 -2
  44. package/build/src/modeling/DomainModel.js +2 -2
  45. package/build/src/modeling/DomainModel.js.map +1 -1
  46. package/build/src/modeling/DomainProperty.d.ts +28 -12
  47. package/build/src/modeling/DomainProperty.d.ts.map +1 -1
  48. package/build/src/modeling/DomainProperty.js +61 -26
  49. package/build/src/modeling/DomainProperty.js.map +1 -1
  50. package/build/src/modeling/Semantics.d.ts +109 -0
  51. package/build/src/modeling/Semantics.d.ts.map +1 -0
  52. package/build/src/modeling/Semantics.js +97 -0
  53. package/build/src/modeling/Semantics.js.map +1 -0
  54. package/build/src/models/kinds.d.ts +0 -24
  55. package/build/src/models/kinds.d.ts.map +1 -1
  56. package/build/src/models/kinds.js +0 -24
  57. package/build/src/models/kinds.js.map +1 -1
  58. package/build/src/models/store/data_catalog.d.ts +1 -1
  59. package/build/src/models/store/data_catalog.js.map +1 -1
  60. package/build/tsconfig.tsbuildinfo +1 -1
  61. package/data/models/example-generator-api.json +11 -11
  62. package/package.json +1 -1
  63. package/src/amf/AmfTypes.ts +1 -1
  64. package/src/amf/Utils.ts +0 -15
  65. package/src/modeling/Bindings.ts +1 -1
  66. package/src/modeling/DataDomain.ts +2 -2
  67. package/src/modeling/DataFormat.ts +0 -48
  68. package/src/modeling/DomainAssociation.ts +66 -3
  69. package/src/modeling/DomainEntity.ts +56 -17
  70. package/src/modeling/DomainFile.ts +1 -1
  71. package/src/modeling/DomainImpactAnalysis.ts +3 -3
  72. package/src/modeling/DomainModel.ts +2 -2
  73. package/src/modeling/DomainProperty.ts +60 -21
  74. package/src/modeling/Semantics.ts +178 -0
  75. package/src/modeling/graph.md +14 -14
  76. package/src/modeling/readme.md +29 -29
  77. package/src/models/kinds.ts +0 -25
  78. package/src/models/store/data_catalog.ts +1 -1
  79. package/tests/unit/modeling/data_domain_change_observers.spec.ts +11 -10
  80. package/tests/unit/modeling/data_domain_entities.spec.ts +129 -1
  81. package/tests/unit/modeling/data_domain_property.spec.ts +1 -1
  82. package/tests/unit/modeling/domain_asociation.spec.ts +177 -0
  83. package/tests/unit/modeling/domain_entity.spec.ts +27 -26
  84. package/tests/unit/modeling/domain_entity_example_generator_json.spec.ts +11 -11
  85. package/tests/unit/modeling/domain_entity_example_generator_xml.spec.ts +10 -10
  86. package/tests/unit/modeling/{domain.property.spec.ts → domain_property.spec.ts} +139 -23
  87. package/build/src/amf/AmfShapeGenerator.d.ts +0 -103
  88. package/build/src/amf/AmfShapeGenerator.d.ts.map +0 -1
  89. package/build/src/amf/AmfShapeGenerator.js +0 -416
  90. package/build/src/amf/AmfShapeGenerator.js.map +0 -1
  91. package/build/src/modeling/legacy/DataAssociation.d.ts +0 -284
  92. package/build/src/modeling/legacy/DataAssociation.d.ts.map +0 -1
  93. package/build/src/modeling/legacy/DataAssociation.js +0 -443
  94. package/build/src/modeling/legacy/DataAssociation.js.map +0 -1
  95. package/build/src/modeling/legacy/DataEntity.d.ts +0 -358
  96. package/build/src/modeling/legacy/DataEntity.d.ts.map +0 -1
  97. package/build/src/modeling/legacy/DataEntity.js +0 -855
  98. package/build/src/modeling/legacy/DataEntity.js.map +0 -1
  99. package/build/src/modeling/legacy/DataEntityBuilder.d.ts +0 -162
  100. package/build/src/modeling/legacy/DataEntityBuilder.d.ts.map +0 -1
  101. package/build/src/modeling/legacy/DataEntityBuilder.js +0 -221
  102. package/build/src/modeling/legacy/DataEntityBuilder.js.map +0 -1
  103. package/build/src/modeling/legacy/DataImpactAnalysis.d.ts +0 -298
  104. package/build/src/modeling/legacy/DataImpactAnalysis.d.ts.map +0 -1
  105. package/build/src/modeling/legacy/DataImpactAnalysis.js +0 -441
  106. package/build/src/modeling/legacy/DataImpactAnalysis.js.map +0 -1
  107. package/build/src/modeling/legacy/DataModel.d.ts +0 -99
  108. package/build/src/modeling/legacy/DataModel.d.ts.map +0 -1
  109. package/build/src/modeling/legacy/DataModel.js +0 -237
  110. package/build/src/modeling/legacy/DataModel.js.map +0 -1
  111. package/build/src/modeling/legacy/DataNamespace.d.ts +0 -340
  112. package/build/src/modeling/legacy/DataNamespace.d.ts.map +0 -1
  113. package/build/src/modeling/legacy/DataNamespace.js +0 -784
  114. package/build/src/modeling/legacy/DataNamespace.js.map +0 -1
  115. package/build/src/modeling/legacy/DataProperty.d.ts +0 -332
  116. package/build/src/modeling/legacy/DataProperty.d.ts.map +0 -1
  117. package/build/src/modeling/legacy/DataProperty.js +0 -415
  118. package/build/src/modeling/legacy/DataProperty.js.map +0 -1
  119. package/build/src/models/store/DataFile.d.ts +0 -29
  120. package/build/src/models/store/DataFile.d.ts.map +0 -1
  121. package/build/src/models/store/DataFile.js +0 -87
  122. package/build/src/models/store/DataFile.js.map +0 -1
  123. package/src/amf/AmfShapeGenerator.ts +0 -477
  124. package/src/modeling/legacy/DataAssociation.ts +0 -554
  125. package/src/modeling/legacy/DataEntity.ts +0 -1019
  126. package/src/modeling/legacy/DataEntityBuilder.ts +0 -236
  127. package/src/modeling/legacy/DataImpactAnalysis.ts +0 -530
  128. package/src/modeling/legacy/DataModel.ts +0 -276
  129. package/src/modeling/legacy/DataNamespace.ts +0 -929
  130. package/src/modeling/legacy/DataProperty.ts +0 -630
  131. package/src/models/store/DataFile.ts +0 -95
  132. package/tests/unit/modeling/legacy/amf_shape_generator.spec.ts +0 -1041
  133. package/tests/unit/modeling/legacy/data_association.spec.ts +0 -710
  134. package/tests/unit/modeling/legacy/data_entity.spec.ts +0 -2061
  135. package/tests/unit/modeling/legacy/data_entity_generator_json.spec.ts +0 -987
  136. package/tests/unit/modeling/legacy/data_entity_generator_xml.spec.ts +0 -1451
  137. package/tests/unit/modeling/legacy/data_model.spec.ts +0 -395
  138. package/tests/unit/modeling/legacy/data_namespace.spec.ts +0 -1312
  139. package/tests/unit/modeling/legacy/data_property.spec.ts +0 -887
  140. package/tests/unit/modeling/legacy/impact_analysis.spec.ts +0 -373
@@ -1,6 +1,7 @@
1
1
  import { test } from '@japa/runner'
2
2
  import { DataDomain } from '../../../src/modeling/DataDomain.js'
3
3
  import { DomainEntity } from '../../../src/modeling/DomainEntity.js'
4
+ import { SemanticType } from '../../../src/modeling/Semantics.js'
4
5
 
5
6
  test.group('DataDomain.addEntity()', () => {
6
7
  test('addEntity adds an entity to the graph', ({ assert }) => {
@@ -70,7 +71,7 @@ test.group('DataDomain.addEntity()', () => {
70
71
  assert.throws(() => {
71
72
  // @ts-expect-error For testing purposes, we are passing undefined
72
73
  dataDomain.addEntity(undefined, { key: 'test-entity' })
73
- }, `An entity expects a DataModel parent`)
74
+ }, `An entity expects a DomainModel parent`)
74
75
  })
75
76
 
76
77
  test('addEntity throws when adding the same entity twice', ({ assert }) => {
@@ -328,6 +329,133 @@ test.group('DataDomain.findEntity()', () => {
328
329
  })
329
330
  })
330
331
 
332
+ test.group('DomainEntity.addSemantic()', () => {
333
+ test('adds a new semantic to the entity', ({ assert }) => {
334
+ const dataDomain = new DataDomain()
335
+ const model = dataDomain.addModel({ key: 'test-model' })
336
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
337
+ const semantic = { id: SemanticType.User }
338
+ entity.addSemantic(semantic)
339
+ assert.deepInclude(entity.semantics, semantic)
340
+ })
341
+
342
+ test('updates an existing semantic', ({ assert }) => {
343
+ const dataDomain = new DataDomain()
344
+ const model = dataDomain.addModel({ key: 'test-model' })
345
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
346
+ const semantic1 = { id: SemanticType.User, config: { value: 'old' } }
347
+ const semantic2 = { id: SemanticType.User, config: { value: 'new' } }
348
+ entity.addSemantic(semantic1)
349
+ entity.addSemantic(semantic2)
350
+ assert.lengthOf(entity.semantics, 1)
351
+ assert.deepInclude(entity.semantics, semantic2)
352
+ })
353
+
354
+ test('throws an error if the semantic is not an entity semantic', ({ assert }) => {
355
+ const dataDomain = new DataDomain()
356
+ const model = dataDomain.addModel({ key: 'test-model' })
357
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
358
+ const semantic = { id: SemanticType.CreatedTimestamp } // CreatedTimestamp is a Property semantic
359
+ assert.throws(() => {
360
+ entity.addSemantic(semantic)
361
+ }, `Invalid semantic type: ${SemanticType.CreatedTimestamp}. Expected an entity semantic.`)
362
+ })
363
+
364
+ test('notifies change when adding a new semantic', async ({ assert }) => {
365
+ const dataDomain = new DataDomain()
366
+ const model = dataDomain.addModel({ key: 'test-model' })
367
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
368
+ const semantic = { id: SemanticType.User }
369
+ entity.addSemantic(semantic)
370
+ await assert.dispatches(dataDomain, 'change', { timeout: 20 })
371
+ })
372
+
373
+ test('notifies change when updating an existing semantic', async ({ assert }) => {
374
+ const dataDomain = new DataDomain()
375
+ const model = dataDomain.addModel({ key: 'test-model' })
376
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
377
+ const semantic1 = { id: SemanticType.User, config: { value: 'old' } }
378
+ const semantic2 = { id: SemanticType.User, config: { value: 'new' } }
379
+ entity.addSemantic(semantic1)
380
+ // Clear the event queue before the second add
381
+ await new Promise((resolve) => setTimeout(resolve, 0))
382
+ entity.addSemantic(semantic2)
383
+ await assert.dispatches(dataDomain, 'change', { timeout: 20 })
384
+ })
385
+ })
386
+
387
+ test.group('DomainEntity.removeSemantic()', () => {
388
+ test('removes an existing semantic from the entity', ({ assert }) => {
389
+ const dataDomain = new DataDomain()
390
+ const model = dataDomain.addModel({ key: 'test-model' })
391
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
392
+ const semantic = { id: SemanticType.User }
393
+ entity.addSemantic(semantic)
394
+ assert.deepInclude(entity.semantics, semantic)
395
+ entity.removeSemantic(SemanticType.User)
396
+ assert.notDeepInclude(entity.semantics, semantic)
397
+ assert.lengthOf(entity.semantics, 0)
398
+ })
399
+
400
+ test('does nothing if the semantic to remove does not exist', ({ assert }) => {
401
+ const dataDomain = new DataDomain()
402
+ const model = dataDomain.addModel({ key: 'test-model' })
403
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
404
+ const semantic = { id: SemanticType.User }
405
+ entity.addSemantic(semantic)
406
+ const initialSemantics = [...entity.semantics]
407
+ entity.removeSemantic('non-existent-semantic-id' as SemanticType)
408
+ assert.deepEqual(entity.semantics, initialSemantics)
409
+ })
410
+
411
+ test('notifies change when a semantic is removed', async ({ assert }) => {
412
+ const dataDomain = new DataDomain()
413
+ const model = dataDomain.addModel({ key: 'test-model' })
414
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
415
+ const semantic = { id: SemanticType.User }
416
+ entity.addSemantic(semantic)
417
+ // Clear the event queue before removal
418
+ await new Promise((resolve) => setTimeout(resolve, 0))
419
+ entity.removeSemantic(SemanticType.User)
420
+ await assert.dispatches(dataDomain, 'change', { timeout: 20 })
421
+ })
422
+
423
+ test('does not notify change if the semantic to remove does not exist', async ({ assert }) => {
424
+ const dataDomain = new DataDomain()
425
+ const model = dataDomain.addModel({ key: 'test-model' })
426
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
427
+ // Clear the event queue before removal
428
+ await new Promise((resolve) => setTimeout(resolve, 0))
429
+ entity.removeSemantic('non-existent-semantic-id' as SemanticType)
430
+ await assert.notDispatches(dataDomain, 'change', { timeout: 20 })
431
+ })
432
+ })
433
+
434
+ test.group('DomainEntity.hasSemantic()', () => {
435
+ test('returns true if the entity has the specified semantic', ({ assert }) => {
436
+ const dataDomain = new DataDomain()
437
+ const model = dataDomain.addModel({ key: 'test-model' })
438
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
439
+ const semantic = { id: SemanticType.User }
440
+ entity.addSemantic(semantic)
441
+ assert.isTrue(entity.hasSemantic(SemanticType.User))
442
+ })
443
+
444
+ test('returns false if the entity does not have the specified semantic', ({ assert }) => {
445
+ const dataDomain = new DataDomain()
446
+ const model = dataDomain.addModel({ key: 'test-model' })
447
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
448
+ assert.isFalse(entity.hasSemantic(SemanticType.User))
449
+ })
450
+
451
+ test('returns false for an empty semantics array', ({ assert }) => {
452
+ const dataDomain = new DataDomain()
453
+ const model = dataDomain.addModel({ key: 'test-model' })
454
+ const entity = dataDomain.addEntity(model.key, { key: 'test-entity' })
455
+ assert.isFalse(entity.hasSemantic(SemanticType.User))
456
+ })
457
+ })
458
+
331
459
  test.group('DataDomain.moveEntity()', () => {
332
460
  test('moves an entity from one model to another', ({ assert }) => {
333
461
  const dataDomain = new DataDomain()
@@ -67,7 +67,7 @@ test.group('DataDomain.addProperty()', () => {
67
67
  assert.throws(() => {
68
68
  // @ts-expect-error For testing purposes, we are passing undefined
69
69
  dataDomain.addProperty(undefined)
70
- }, 'A property expects a DataEntity parent')
70
+ }, 'A property expects a DomainEntity parent')
71
71
  })
72
72
 
73
73
  test('addProperty throws when adding property to a foreign entity', ({ assert }) => {
@@ -7,6 +7,7 @@ import {
7
7
  AssociationBinding,
8
8
  DataDomain,
9
9
  DataFormat,
10
+ SemanticType,
10
11
  } from '../../../src/index.js'
11
12
 
12
13
  test.group('DomainAssociation.createSchema()', () => {
@@ -21,6 +22,7 @@ test.group('DomainAssociation.createSchema()', () => {
21
22
  assert.isUndefined(schema.required)
22
23
  assert.isUndefined(schema.bindings)
23
24
  assert.isUndefined(schema.targets)
25
+ assert.deepEqual(schema.semantics, [])
24
26
  })
25
27
 
26
28
  test('creates a schema with provided key', ({ assert }) => {
@@ -35,6 +37,12 @@ test.group('DomainAssociation.createSchema()', () => {
35
37
  assert.deepEqual(schema.info, Thing.fromJSON(info).toJSON())
36
38
  })
37
39
 
40
+ test('creates a schema with provided semantics', ({ assert }) => {
41
+ const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
42
+ const schema = DomainAssociation.createSchema({ semantics })
43
+ assert.deepEqual(schema.semantics, semantics)
44
+ })
45
+
38
46
  test('creates a schema with provided schema', ({ assert }) => {
39
47
  const schemaDefinition: AmfShapes.IApiAssociationShape = { linked: false }
40
48
  const schema = DomainAssociation.createSchema({ schema: schemaDefinition })
@@ -71,6 +79,7 @@ test.group('DomainAssociation.createSchema()', () => {
71
79
  const required = true
72
80
  const bindings: AssociationBinding[] = [{ type: 'web', schema: { hidden: false } }]
73
81
  const targets = [{ key: 'target1', domain: 'domain1' }, { key: 'target2' }]
82
+ const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
74
83
 
75
84
  const schema = DomainAssociation.createSchema({
76
85
  key,
@@ -80,6 +89,7 @@ test.group('DomainAssociation.createSchema()', () => {
80
89
  required,
81
90
  bindings,
82
91
  targets,
92
+ semantics,
83
93
  })
84
94
 
85
95
  assert.equal(schema.key, key)
@@ -89,6 +99,7 @@ test.group('DomainAssociation.createSchema()', () => {
89
99
  assert.equal(schema.required, required)
90
100
  assert.deepEqual(schema.bindings, bindings)
91
101
  assert.deepEqual(schema.targets, targets)
102
+ assert.deepEqual(schema.semantics, semantics)
92
103
  })
93
104
 
94
105
  test('creates a schema with cloned bindings', ({ assert }) => {
@@ -98,6 +109,13 @@ test.group('DomainAssociation.createSchema()', () => {
98
109
  assert.notStrictEqual(schema.bindings, bindings)
99
110
  })
100
111
 
112
+ test('creates a schema with cloned semantics', ({ assert }) => {
113
+ const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
114
+ const schema = DomainAssociation.createSchema({ semantics })
115
+ assert.deepEqual(schema.semantics, semantics)
116
+ assert.notStrictEqual(schema.semantics, semantics)
117
+ })
118
+
101
119
  test('creates a schema with cloned targets', ({ assert }) => {
102
120
  const targets = [{ key: 'target1', domain: 'domain1' }, { key: 'target2' }]
103
121
  const schema = DomainAssociation.createSchema({ targets })
@@ -126,6 +144,7 @@ test.group('DomainAssociation.constructor()', () => {
126
144
  assert.isUndefined(association.required)
127
145
  assert.deepEqual(association.bindings, [])
128
146
  assert.deepEqual(association.targets, [])
147
+ assert.deepEqual(association.semantics, [])
129
148
  })
130
149
 
131
150
  test('creates an instance with provided key', ({ assert }) => {
@@ -136,6 +155,14 @@ test.group('DomainAssociation.constructor()', () => {
136
155
  assert.equal(association.key, key)
137
156
  })
138
157
 
158
+ test('creates an instance with provided semantics', ({ assert }) => {
159
+ const dataDomain = new DataDomain()
160
+ const parentKey = 'test-parent'
161
+ const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
162
+ const association = new DomainAssociation(dataDomain, parentKey, { semantics })
163
+ assert.deepEqual(association.semantics, semantics)
164
+ })
165
+
139
166
  test('creates an instance with provided info', ({ assert }) => {
140
167
  const dataDomain = new DataDomain()
141
168
  const parentKey = 'test-parent'
@@ -192,6 +219,7 @@ test.group('DomainAssociation.constructor()', () => {
192
219
  const required = true
193
220
  const bindings: AssociationBinding[] = [{ type: 'web', schema: { hidden: false } }]
194
221
  const targets = [{ key: 'target1', domain: 'domain1' }, { key: 'target2' }]
222
+ const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
195
223
 
196
224
  const association = new DomainAssociation(dataDomain, parentKey, {
197
225
  key,
@@ -201,6 +229,7 @@ test.group('DomainAssociation.constructor()', () => {
201
229
  required,
202
230
  bindings,
203
231
  targets,
232
+ semantics,
204
233
  })
205
234
 
206
235
  assert.equal(association.key, key)
@@ -210,6 +239,7 @@ test.group('DomainAssociation.constructor()', () => {
210
239
  assert.equal(association.required, required)
211
240
  assert.deepEqual(association.bindings, bindings)
212
241
  assert.deepEqual(association.targets, targets)
242
+ assert.deepEqual(association.semantics, semantics)
213
243
  })
214
244
 
215
245
  test('creates an instance with cloned bindings', ({ assert }) => {
@@ -221,6 +251,15 @@ test.group('DomainAssociation.constructor()', () => {
221
251
  assert.notStrictEqual(association.bindings, bindings)
222
252
  })
223
253
 
254
+ test('creates an instance with cloned semantics', ({ assert }) => {
255
+ const dataDomain = new DataDomain()
256
+ const parentKey = 'test-parent'
257
+ const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
258
+ const association = new DomainAssociation(dataDomain, parentKey, { semantics })
259
+ assert.deepEqual(association.semantics, semantics)
260
+ assert.notStrictEqual(association.semantics, semantics)
261
+ })
262
+
224
263
  test('creates an instance with cloned targets', ({ assert }) => {
225
264
  const dataDomain = new DataDomain()
226
265
  const parentKey = 'test-parent'
@@ -254,6 +293,7 @@ test.group('DomainAssociation.toJSON()', () => {
254
293
  assert.isUndefined(json.required)
255
294
  assert.isUndefined(json.bindings)
256
295
  assert.isUndefined(json.targets)
296
+ assert.isUndefined(json.semantics)
257
297
  })
258
298
 
259
299
  test('returns a JSON representation with provided key', ({ assert }) => {
@@ -265,6 +305,15 @@ test.group('DomainAssociation.toJSON()', () => {
265
305
  assert.equal(json.key, key)
266
306
  })
267
307
 
308
+ test('returns a JSON representation with provided semantics', ({ assert }) => {
309
+ const dataDomain = new DataDomain()
310
+ const parentKey = 'test-parent'
311
+ const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
312
+ const association = new DomainAssociation(dataDomain, parentKey, { semantics })
313
+ const json = association.toJSON()
314
+ assert.deepEqual(json.semantics, semantics)
315
+ })
316
+
268
317
  test('returns a JSON representation with provided info', ({ assert }) => {
269
318
  const dataDomain = new DataDomain()
270
319
  const parentKey = 'test-parent'
@@ -330,6 +379,7 @@ test.group('DomainAssociation.toJSON()', () => {
330
379
  const required = true
331
380
  const bindings: AssociationBinding[] = [{ type: 'web', schema: { hidden: false } }]
332
381
  const targets = [{ key: 'target1', domain: 'domain1' }, { key: 'target2' }]
382
+ const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
333
383
 
334
384
  const association = new DomainAssociation(dataDomain, parentKey, {
335
385
  key,
@@ -339,6 +389,7 @@ test.group('DomainAssociation.toJSON()', () => {
339
389
  required,
340
390
  bindings,
341
391
  targets,
392
+ semantics,
342
393
  })
343
394
 
344
395
  const json = association.toJSON()
@@ -350,6 +401,7 @@ test.group('DomainAssociation.toJSON()', () => {
350
401
  assert.equal(json.required, required)
351
402
  assert.deepEqual(json.bindings, bindings)
352
403
  assert.deepEqual(json.targets, targets)
404
+ assert.deepEqual(json.semantics, semantics)
353
405
  })
354
406
 
355
407
  test('returns a JSON representation with cloned bindings', ({ assert }) => {
@@ -362,6 +414,16 @@ test.group('DomainAssociation.toJSON()', () => {
362
414
  assert.notStrictEqual(json.bindings, bindings)
363
415
  })
364
416
 
417
+ test('returns a JSON representation with cloned semantics when it is set after creation', ({ assert }) => {
418
+ const dataDomain = new DataDomain()
419
+ const parentKey = 'test-parent'
420
+ const association = new DomainAssociation(dataDomain, parentKey)
421
+ const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
422
+ association.semantics = semantics
423
+ const json = association.toJSON()
424
+ assert.deepEqual(json.semantics, semantics)
425
+ })
426
+
365
427
  test('returns a JSON representation with cloned targets', ({ assert }) => {
366
428
  const dataDomain = new DataDomain()
367
429
  const parentKey = 'test-parent'
@@ -641,3 +703,118 @@ test.group('DomainAssociation.readBinding()', () => {
641
703
  assert.isUndefined(webBindings)
642
704
  })
643
705
  })
706
+
707
+ test.group('DomainAssociation.addSemantic()', () => {
708
+ test('adds a new semantic to the association', ({ assert }) => {
709
+ const dataDomain = new DataDomain()
710
+ const association = new DomainAssociation(dataDomain, 'test-parent')
711
+ const semantic = { id: SemanticType.ResourceOwnerIdentifier }
712
+ association.addSemantic(semantic)
713
+ assert.deepInclude(association.semantics, semantic)
714
+ })
715
+
716
+ test('updates an existing semantic', ({ assert }) => {
717
+ const dataDomain = new DataDomain()
718
+ const association = new DomainAssociation(dataDomain, 'test-parent')
719
+ const semantic1 = { id: SemanticType.ResourceOwnerIdentifier, config: { value: 'old' } }
720
+ const semantic2 = { id: SemanticType.ResourceOwnerIdentifier, config: { value: 'new' } }
721
+ association.addSemantic(semantic1)
722
+ association.addSemantic(semantic2)
723
+ assert.lengthOf(association.semantics, 1)
724
+ assert.deepInclude(association.semantics, semantic2)
725
+ })
726
+
727
+ test('throws an error if the semantic is not an association semantic', ({ assert }) => {
728
+ const dataDomain = new DataDomain()
729
+ const association = new DomainAssociation(dataDomain, 'test-parent')
730
+ const semantic = { id: SemanticType.User } // User is an Entity semantic
731
+ assert.throws(() => {
732
+ association.addSemantic(semantic)
733
+ }, `Invalid semantic type: ${SemanticType.User}. Expected an association semantic.`)
734
+ })
735
+
736
+ test('notifies change when adding a new semantic', async ({ assert }) => {
737
+ const dataDomain = new DataDomain()
738
+ const association = new DomainAssociation(dataDomain, 'test-parent')
739
+ const semantic = { id: SemanticType.ResourceOwnerIdentifier }
740
+ association.addSemantic(semantic)
741
+ await assert.dispatches(dataDomain, 'change', { timeout: 20 })
742
+ })
743
+
744
+ test('notifies change when updating an existing semantic', async ({ assert }) => {
745
+ const dataDomain = new DataDomain()
746
+ const association = new DomainAssociation(dataDomain, 'test-parent')
747
+ const semantic1 = { id: SemanticType.ResourceOwnerIdentifier, config: { value: 'old' } }
748
+ const semantic2 = { id: SemanticType.ResourceOwnerIdentifier, config: { value: 'new' } }
749
+ association.addSemantic(semantic1)
750
+ // Clear the event queue before the second add
751
+ await new Promise((resolve) => setTimeout(resolve, 0))
752
+ association.addSemantic(semantic2)
753
+ await assert.dispatches(dataDomain, 'change', { timeout: 20 })
754
+ })
755
+ })
756
+
757
+ test.group('DomainAssociation.removeSemantic()', () => {
758
+ test('removes an existing semantic from the association', ({ assert }) => {
759
+ const dataDomain = new DataDomain()
760
+ const association = new DomainAssociation(dataDomain, 'test-parent')
761
+ const semantic = { id: SemanticType.ResourceOwnerIdentifier }
762
+ association.addSemantic(semantic)
763
+ assert.deepInclude(association.semantics, semantic)
764
+ association.removeSemantic(SemanticType.ResourceOwnerIdentifier)
765
+ assert.notDeepInclude(association.semantics, semantic)
766
+ assert.lengthOf(association.semantics, 0)
767
+ })
768
+
769
+ test('does nothing if the semantic to remove does not exist', ({ assert }) => {
770
+ const dataDomain = new DataDomain()
771
+ const association = new DomainAssociation(dataDomain, 'test-parent')
772
+ const semantic = { id: SemanticType.ResourceOwnerIdentifier }
773
+ association.addSemantic(semantic)
774
+ const initialSemantics = [...association.semantics]
775
+ association.removeSemantic('non-existent-semantic-id' as SemanticType)
776
+ assert.deepEqual(association.semantics, initialSemantics)
777
+ })
778
+
779
+ test('notifies change when a semantic is removed', async ({ assert }) => {
780
+ const dataDomain = new DataDomain()
781
+ const association = new DomainAssociation(dataDomain, 'test-parent')
782
+ const semantic = { id: SemanticType.ResourceOwnerIdentifier }
783
+ association.addSemantic(semantic)
784
+ // Clear the event queue before removal
785
+ await new Promise((resolve) => setTimeout(resolve, 0))
786
+ association.removeSemantic(SemanticType.ResourceOwnerIdentifier)
787
+ await assert.dispatches(dataDomain, 'change', { timeout: 20 })
788
+ })
789
+
790
+ test('does not notify change if the semantic to remove does not exist', async ({ assert }) => {
791
+ const dataDomain = new DataDomain()
792
+ const association = new DomainAssociation(dataDomain, 'test-parent')
793
+ // Clear the event queue before removal
794
+ await new Promise((resolve) => setTimeout(resolve, 0))
795
+ association.removeSemantic('non-existent-semantic-id' as SemanticType)
796
+ await assert.notDispatches(dataDomain, 'change', { timeout: 20 })
797
+ })
798
+ })
799
+
800
+ test.group('DomainAssociation.hasSemantic()', () => {
801
+ test('returns true if the association has the specified semantic', ({ assert }) => {
802
+ const dataDomain = new DataDomain()
803
+ const association = new DomainAssociation(dataDomain, 'test-parent')
804
+ const semantic = { id: SemanticType.ResourceOwnerIdentifier }
805
+ association.addSemantic(semantic)
806
+ assert.isTrue(association.hasSemantic(SemanticType.ResourceOwnerIdentifier))
807
+ })
808
+
809
+ test('returns false if the association does not have the specified semantic', ({ assert }) => {
810
+ const dataDomain = new DataDomain()
811
+ const association = new DomainAssociation(dataDomain, 'test-parent')
812
+ assert.isFalse(association.hasSemantic(SemanticType.ResourceOwnerIdentifier))
813
+ })
814
+
815
+ test('returns false for an empty semantics array', ({ assert }) => {
816
+ const dataDomain = new DataDomain()
817
+ const association = new DomainAssociation(dataDomain, 'test-parent')
818
+ assert.isFalse(association.hasSemantic(SemanticType.ResourceOwnerIdentifier))
819
+ })
820
+ })
@@ -9,6 +9,7 @@ import {
9
9
  Thing,
10
10
  } from '../../../src/index.js'
11
11
  import type { EntityOrderedItem } from '../../../src/modeling/DomainEntity.js'
12
+ import { SemanticType } from '../../../src/modeling/Semantics.js'
12
13
 
13
14
  test.group('DomainEntity.createSchema()', () => {
14
15
  test('creates a schema with default values', ({ assert }) => {
@@ -18,7 +19,7 @@ test.group('DomainEntity.createSchema()', () => {
18
19
  assert.isNotEmpty(schema.key)
19
20
  assert.deepInclude(schema.info, { name: 'New entity' })
20
21
  assert.isUndefined(schema.tags)
21
- assert.isUndefined(schema.taxonomy)
22
+ assert.isUndefined(schema.semantics)
22
23
  assert.isUndefined(schema.fields)
23
24
  assert.isUndefined(schema.deprecated)
24
25
  })
@@ -28,7 +29,7 @@ test.group('DomainEntity.createSchema()', () => {
28
29
  key: 'test-entity',
29
30
  info: { name: 'Test Entity', description: 'A test entity' },
30
31
  tags: ['tag1', 'tag2'],
31
- taxonomy: ['tax1', 'tax2'],
32
+ semantics: [{ id: SemanticType.User }],
32
33
  fields: [{ key: 'test-property', type: 'property' }],
33
34
  deprecated: true,
34
35
  })
@@ -36,7 +37,7 @@ test.group('DomainEntity.createSchema()', () => {
36
37
  assert.equal(schema.key, 'test-entity')
37
38
  assert.deepInclude(schema.info, { name: 'Test Entity', description: 'A test entity' })
38
39
  assert.deepEqual(schema.tags, ['tag1', 'tag2'])
39
- assert.deepEqual(schema.taxonomy, ['tax1', 'tax2'])
40
+ assert.deepEqual(schema.semantics, [{ id: SemanticType.User }])
40
41
  assert.deepEqual(schema.fields, [{ key: 'test-property', type: 'property' }])
41
42
  assert.isTrue(schema.deprecated)
42
43
  })
@@ -72,15 +73,15 @@ test.group('DomainEntity.createSchema()', () => {
72
73
  assert.deepEqual(schema.tags, ['tag1', 'tag2'])
73
74
  })
74
75
 
75
- test('creates a schema with taxonomy', ({ assert }) => {
76
+ test('creates a schema with semantics', ({ assert }) => {
76
77
  const schema = DomainEntity.createSchema({
77
- taxonomy: ['tax1', 'tax2'],
78
+ semantics: [{ id: SemanticType.User }],
78
79
  })
79
80
  assert.equal(schema.kind, DomainEntityKind)
80
81
  assert.typeOf(schema.key, 'string')
81
82
  assert.isNotEmpty(schema.key)
82
83
  assert.deepInclude(schema.info, { name: 'New entity' })
83
- assert.deepEqual(schema.taxonomy, ['tax1', 'tax2'])
84
+ assert.deepEqual(schema.semantics, [{ id: SemanticType.User }])
84
85
  })
85
86
 
86
87
  test('creates a schema with fields', ({ assert }) => {
@@ -134,10 +135,10 @@ test.group('DomainEntity.createSchema()', () => {
134
135
  assert.deepEqual(schema.tags, customTags)
135
136
  })
136
137
 
137
- test('creates a schema with custom taxonomy', ({ assert }) => {
138
- const customTaxonomy = ['custom-tax1', 'custom-tax2']
139
- const schema = DomainEntity.createSchema({ taxonomy: customTaxonomy })
140
- assert.deepEqual(schema.taxonomy, customTaxonomy)
138
+ test('creates a schema with custom semantics', ({ assert }) => {
139
+ const customSemantics = [{ id: SemanticType.User }]
140
+ const schema = DomainEntity.createSchema({ semantics: customSemantics })
141
+ assert.deepEqual(schema.semantics, customSemantics)
141
142
  })
142
143
 
143
144
  test('creates a schema with custom fields', ({ assert }) => {
@@ -165,7 +166,7 @@ test.group('DomainEntity.constructor()', () => {
165
166
  assert.instanceOf(entity.info, Thing)
166
167
  assert.equal(entity.info.name, 'New entity')
167
168
  assert.deepEqual(entity.tags, [])
168
- assert.deepEqual(entity.taxonomy, [])
169
+ assert.deepEqual(entity.semantics, [])
169
170
  assert.deepEqual(entity.fields, [])
170
171
  assert.isUndefined(entity.deprecated)
171
172
  })
@@ -176,7 +177,7 @@ test.group('DomainEntity.constructor()', () => {
176
177
  key: 'test-entity',
177
178
  info: { name: 'Test Entity', description: 'A test entity' },
178
179
  tags: ['tag1', 'tag2'],
179
- taxonomy: ['tax1', 'tax2'],
180
+ semantics: [{ id: SemanticType.User }],
180
181
  fields: [{ key: 'test-property', type: 'property' }],
181
182
  deprecated: true,
182
183
  })
@@ -186,7 +187,7 @@ test.group('DomainEntity.constructor()', () => {
186
187
  assert.equal(entity.info.name, 'Test Entity')
187
188
  assert.equal(entity.info.description, 'A test entity')
188
189
  assert.deepEqual(entity.tags, ['tag1', 'tag2'])
189
- assert.deepEqual(entity.taxonomy, ['tax1', 'tax2'])
190
+ assert.deepEqual(entity.semantics, [{ id: SemanticType.User }])
190
191
  assert.deepEqual(entity.fields, [{ key: 'test-property', type: 'property' }])
191
192
  assert.isTrue(entity.deprecated)
192
193
  })
@@ -228,17 +229,17 @@ test.group('DomainEntity.constructor()', () => {
228
229
  assert.deepEqual(entity.tags, ['tag1', 'tag2'])
229
230
  })
230
231
 
231
- test('creates a new DomainEntity with taxonomy', ({ assert }) => {
232
+ test('creates a new DomainEntity with semantics', ({ assert }) => {
232
233
  const dataDomain = new DataDomain()
233
234
  const entity = new DomainEntity(dataDomain, {
234
- taxonomy: ['tax1', 'tax2'],
235
+ semantics: [{ id: SemanticType.User }],
235
236
  })
236
237
  assert.equal(entity.kind, DomainEntityKind)
237
238
  assert.typeOf(entity.key, 'string')
238
239
  assert.isNotEmpty(entity.key)
239
240
  assert.instanceOf(entity.info, Thing)
240
241
  assert.equal(entity.info.name, 'New entity')
241
- assert.deepEqual(entity.taxonomy, ['tax1', 'tax2'])
242
+ assert.deepEqual(entity.semantics, [{ id: SemanticType.User }])
242
243
  })
243
244
 
244
245
  test('creates a new DomainEntity with fields', ({ assert }) => {
@@ -300,11 +301,11 @@ test.group('DomainEntity.constructor()', () => {
300
301
  assert.deepEqual(entity.tags, customTags)
301
302
  })
302
303
 
303
- test('creates a new DomainEntity with custom taxonomy', ({ assert }) => {
304
+ test('creates a new DomainEntity with custom semantics', ({ assert }) => {
304
305
  const dataDomain = new DataDomain()
305
- const customTaxonomy = ['custom-tax1', 'custom-tax2']
306
- const entity = new DomainEntity(dataDomain, { taxonomy: customTaxonomy })
307
- assert.deepEqual(entity.taxonomy, customTaxonomy)
306
+ const customSemantics = [{ id: SemanticType.User }]
307
+ const entity = new DomainEntity(dataDomain, { semantics: customSemantics })
308
+ assert.deepEqual(entity.semantics, customSemantics)
308
309
  })
309
310
 
310
311
  test('creates a new DomainEntity with custom fields', ({ assert }) => {
@@ -351,7 +352,7 @@ test.group('DomainEntity.toJSON()', () => {
351
352
  assert.equal(json.key, entity.key)
352
353
  assert.deepInclude(json.info, { name: 'New entity' })
353
354
  assert.isUndefined(json.tags)
354
- assert.isUndefined(json.taxonomy)
355
+ assert.isUndefined(json.semantics)
355
356
  assert.isUndefined(json.fields)
356
357
  assert.isUndefined(json.deprecated)
357
358
  })
@@ -362,7 +363,7 @@ test.group('DomainEntity.toJSON()', () => {
362
363
  key: 'test-entity',
363
364
  info: { name: 'Test Entity', description: 'A test entity' },
364
365
  tags: ['tag1', 'tag2'],
365
- taxonomy: ['tax1', 'tax2'],
366
+ semantics: [{ id: SemanticType.User }],
366
367
  fields: [{ key: 'test-property', type: 'property' }],
367
368
  deprecated: true,
368
369
  })
@@ -371,7 +372,7 @@ test.group('DomainEntity.toJSON()', () => {
371
372
  assert.equal(json.key, 'test-entity')
372
373
  assert.deepInclude(json.info, { name: 'Test Entity', description: 'A test entity' })
373
374
  assert.deepEqual(json.tags, ['tag1', 'tag2'])
374
- assert.deepEqual(json.taxonomy, ['tax1', 'tax2'])
375
+ assert.deepEqual(json.semantics, [{ id: SemanticType.User }])
375
376
  assert.deepEqual(json.fields, [{ key: 'test-property', type: 'property' }])
376
377
  assert.isTrue(json.deprecated)
377
378
  })
@@ -455,15 +456,15 @@ test.group('DomainEntity.toJSON()', () => {
455
456
  assert.deepEqual(json.tags, ['tag1', 'tag2'])
456
457
  })
457
458
 
458
- test('serializes the "taxonomy" property', ({ assert }) => {
459
+ test('serializes the "semantics" property', ({ assert }) => {
459
460
  const dataDomain = new DataDomain()
460
461
  const model = dataDomain.addModel()
461
462
  const entity = model.addEntity({
462
463
  key: 'test-entity',
463
- taxonomy: ['tax1', 'tax2'],
464
+ semantics: [{ id: SemanticType.User }],
464
465
  })
465
466
  const json = entity.toJSON()
466
- assert.deepEqual(json.taxonomy, ['tax1', 'tax2'])
467
+ assert.deepEqual(json.semantics, [{ id: SemanticType.User }])
467
468
  })
468
469
  })
469
470