@api-client/core 0.14.1 → 0.14.3

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 (96) hide show
  1. package/build/src/browser.d.ts +1 -1
  2. package/build/src/browser.d.ts.map +1 -1
  3. package/build/src/browser.js.map +1 -1
  4. package/build/src/index.d.ts +2 -1
  5. package/build/src/index.d.ts.map +1 -1
  6. package/build/src/index.js +1 -0
  7. package/build/src/index.js.map +1 -1
  8. package/build/src/modeling/ApiFile.d.ts +23 -0
  9. package/build/src/modeling/ApiFile.d.ts.map +1 -0
  10. package/build/src/modeling/ApiFile.js +44 -0
  11. package/build/src/modeling/ApiFile.js.map +1 -0
  12. package/build/src/modeling/ApiModel.d.ts +159 -0
  13. package/build/src/modeling/ApiModel.d.ts.map +1 -0
  14. package/build/src/modeling/ApiModel.js +237 -0
  15. package/build/src/modeling/ApiModel.js.map +1 -0
  16. package/build/src/modeling/DataDomain.d.ts +1 -1
  17. package/build/src/modeling/DataDomain.d.ts.map +1 -1
  18. package/build/src/modeling/DataDomain.js +1 -3
  19. package/build/src/modeling/DataDomain.js.map +1 -1
  20. package/build/src/modeling/DomainAssociation.d.ts +35 -0
  21. package/build/src/modeling/DomainAssociation.d.ts.map +1 -1
  22. package/build/src/modeling/DomainAssociation.js +42 -5
  23. package/build/src/modeling/DomainAssociation.js.map +1 -1
  24. package/build/src/modeling/DomainEntity.js +1 -1
  25. package/build/src/modeling/DomainEntity.js.map +1 -1
  26. package/build/src/modeling/DomainFile.d.ts +1 -2
  27. package/build/src/modeling/DomainFile.d.ts.map +1 -1
  28. package/build/src/modeling/DomainFile.js +3 -41
  29. package/build/src/modeling/DomainFile.js.map +1 -1
  30. package/build/src/modeling/Semantics.d.ts +62 -7
  31. package/build/src/modeling/Semantics.d.ts.map +1 -1
  32. package/build/src/modeling/Semantics.js +76 -7
  33. package/build/src/modeling/Semantics.js.map +1 -1
  34. package/build/src/modeling/amf/ShapeGenerator.d.ts.map +1 -1
  35. package/build/src/modeling/amf/ShapeGenerator.js.map +1 -1
  36. package/build/src/modeling/types.d.ts +491 -0
  37. package/build/src/modeling/types.d.ts.map +1 -1
  38. package/build/src/modeling/types.js.map +1 -1
  39. package/build/src/models/kinds.d.ts +2 -0
  40. package/build/src/models/kinds.d.ts.map +1 -1
  41. package/build/src/models/kinds.js +2 -0
  42. package/build/src/models/kinds.js.map +1 -1
  43. package/build/src/models/store/File.d.ts +19 -2
  44. package/build/src/models/store/File.d.ts.map +1 -1
  45. package/build/src/models/store/File.js +100 -13
  46. package/build/src/models/store/File.js.map +1 -1
  47. package/build/tsconfig.tsbuildinfo +1 -1
  48. package/data/models/APIC-187.json +3 -3
  49. package/data/models/APIC-188.json +3 -3
  50. package/data/models/APIC-233.json +1 -1
  51. package/data/models/APIC-391.json +2 -2
  52. package/data/models/APIC-483.json +1 -1
  53. package/data/models/APIC-487.json +1 -1
  54. package/data/models/APIC-655.json +1 -1
  55. package/data/models/APIC-689.json +1 -1
  56. package/data/models/APIC-690.json +5 -5
  57. package/data/models/SE-10469.json +1 -1
  58. package/data/models/SE-13092.json +5 -5
  59. package/data/models/SE-22063.json +12 -2
  60. package/data/models/amf-helper-api.json +154 -14
  61. package/data/models/arc-demo-api.json +95 -15
  62. package/data/models/async-api.json +1 -1
  63. package/data/models/example-generator-api.json +361 -21
  64. package/data/models/expanded-api.json +1 -1
  65. package/data/models/flattened-api.json +1 -1
  66. package/data/models/multiple-servers.json +1 -1
  67. package/data/models/oas-3-api.json +1 -1
  68. package/data/models/oas-date.json +1 -1
  69. package/data/models/oas-types.json +1 -1
  70. package/data/models/oas-unions.json +1 -1
  71. package/data/models/petstore.json +1 -1
  72. package/data/models/raml-date.json +1 -1
  73. package/data/models/recursive.json +1 -1
  74. package/data/models/schema-api.json +62 -2
  75. package/data/models/secured-api.json +16 -16
  76. package/data/models/tracked-to-linked.json +4 -4
  77. package/package.json +3 -4
  78. package/src/modeling/ApiFile.ts +53 -0
  79. package/src/modeling/ApiModel.ts +327 -0
  80. package/src/modeling/DataDomain.ts +1 -1
  81. package/src/modeling/DomainAssociation.ts +56 -0
  82. package/src/modeling/DomainEntity.ts +1 -1
  83. package/src/modeling/DomainFile.ts +3 -40
  84. package/src/modeling/Semantics.ts +79 -7
  85. package/src/modeling/amf/ShapeGenerator.ts +1 -1
  86. package/src/modeling/types.ts +545 -0
  87. package/src/models/kinds.ts +2 -0
  88. package/src/models/store/File.ts +100 -13
  89. package/tests/unit/modeling/api_model.spec.ts +291 -0
  90. package/tests/unit/modeling/domain_asociation.spec.ts +92 -2
  91. package/tests/unit/modeling/domain_entity.spec.ts +15 -15
  92. package/tests/unit/modeling/domain_file.spec.ts +1 -11
  93. package/tests/unit/modeling/domain_model_entities.spec.ts +2 -2
  94. package/tests/unit/modeling/semantics.spec.ts +146 -0
  95. package/tests/unit/models/File/constructor.spec.ts +3 -2
  96. package/tests/unit/models/File/shortcutTo.spec.ts +1 -1
@@ -0,0 +1,291 @@
1
+ import { test } from '@japa/runner'
2
+ import {
3
+ ApiModel,
4
+ ApiModelKind,
5
+ DataDomain,
6
+ type RolesBasedAccessControl,
7
+ type ApiModelSchema,
8
+ type ExposedEntity,
9
+ } from '../../../src/index.js'
10
+
11
+ test.group('ApiModel.createSchema()', () => {
12
+ test('creates a schema with default values', ({ assert }) => {
13
+ const schema = ApiModel.createSchema()
14
+ assert.equal(schema.kind, ApiModelKind)
15
+ assert.typeOf(schema.key, 'string')
16
+ assert.isNotEmpty(schema.key)
17
+ assert.deepInclude(schema.info, { name: 'Unnamed API' })
18
+ assert.deepEqual(schema.exposes, [])
19
+ assert.isUndefined(schema.userKey)
20
+ assert.isUndefined(schema.domain)
21
+ assert.isUndefined(schema.authentication)
22
+ assert.isUndefined(schema.authorization)
23
+ assert.isUndefined(schema.session)
24
+ assert.isUndefined(schema.accessRule)
25
+ assert.isUndefined(schema.rateLimiting)
26
+ })
27
+
28
+ test('creates a schema with provided values', ({ assert }) => {
29
+ const input: Partial<ApiModelSchema> = {
30
+ key: 'test-api',
31
+ info: { name: 'Test API', description: 'A test API' },
32
+ exposes: [{ key: 'entity1', actions: [] }],
33
+ userKey: 'user-entity',
34
+ domain: { key: 'domain1', version: '1.0.0' },
35
+ authentication: { strategy: 'UsernamePassword' },
36
+ authorization: { strategy: 'RBAC', roleKey: 'role' } as RolesBasedAccessControl,
37
+ session: { secret: 'secret', properties: ['email'] },
38
+ accessRule: [{ type: 'public' }],
39
+ rateLimiting: { rules: [] },
40
+ }
41
+ const schema = ApiModel.createSchema(input)
42
+
43
+ assert.equal(schema.kind, ApiModelKind)
44
+ assert.equal(schema.key, 'test-api')
45
+ assert.deepInclude(schema.info, { name: 'Test API', description: 'A test API' })
46
+ assert.deepEqual(schema.exposes, [{ key: 'entity1', actions: [] }])
47
+ assert.equal(schema.userKey, 'user-entity')
48
+ assert.deepEqual(schema.domain, { key: 'domain1', version: '1.0.0' })
49
+ assert.deepEqual(schema.authentication, { strategy: 'UsernamePassword' })
50
+ assert.deepEqual(schema.authorization, { strategy: 'RBAC', roleKey: 'role' })
51
+ assert.deepEqual(schema.session, { secret: 'secret', properties: ['email'] })
52
+ assert.deepEqual(schema.accessRule, [{ type: 'public' }])
53
+ assert.deepEqual(schema.rateLimiting, { rules: [] })
54
+ })
55
+
56
+ test('creates a schema with partial info', ({ assert }) => {
57
+ const schema = ApiModel.createSchema({ info: { name: 'Partial API' } })
58
+ assert.deepInclude(schema.info, { name: 'Partial API' })
59
+ })
60
+
61
+ test('creates a schema with empty info', ({ assert }) => {
62
+ const schema = ApiModel.createSchema({ info: {} })
63
+ assert.deepInclude(schema.info, { name: 'Unnamed API' })
64
+ })
65
+ })
66
+
67
+ test.group('ApiModel.constructor()', () => {
68
+ test('creates an instance with default values', ({ assert }) => {
69
+ const model = new ApiModel()
70
+ assert.equal(model.kind, ApiModelKind)
71
+ assert.typeOf(model.key, 'string')
72
+ assert.isNotEmpty(model.key)
73
+ assert.equal(model.info.name, 'Unnamed API')
74
+ assert.deepEqual(model.exposes, [])
75
+ assert.isUndefined(model.userKey)
76
+ assert.isUndefined(model.domain)
77
+ assert.isUndefined(model.authentication)
78
+ assert.isUndefined(model.authorization)
79
+ assert.isUndefined(model.session)
80
+ assert.isUndefined(model.accessRule)
81
+ assert.isUndefined(model.rateLimiting)
82
+ assert.isUndefined(model.dataDomain)
83
+ })
84
+
85
+ test('creates an instance with provided schema values', ({ assert }) => {
86
+ const schema: ApiModelSchema = {
87
+ kind: ApiModelKind,
88
+ key: 'test-api',
89
+ info: { name: 'Test API', description: 'A test API' },
90
+ exposes: [{ key: 'entity1', actions: [] }],
91
+ userKey: 'user-entity',
92
+ domain: { key: 'domain1', version: '1.0.0' },
93
+ authentication: { strategy: 'UsernamePassword' },
94
+ authorization: { strategy: 'RBAC', roleKey: 'role' } as RolesBasedAccessControl,
95
+ session: { secret: 'secret', properties: ['email'] },
96
+ accessRule: [{ type: 'public' }],
97
+ rateLimiting: { rules: [] },
98
+ }
99
+ const model = new ApiModel(schema)
100
+
101
+ assert.equal(model.key, 'test-api')
102
+ assert.equal(model.info.name, 'Test API')
103
+ assert.deepEqual(model.exposes, [{ key: 'entity1', actions: [] }])
104
+ assert.equal(model.userKey, 'user-entity')
105
+ assert.deepEqual(model.domain, { key: 'domain1', version: '1.0.0' })
106
+ assert.deepEqual(model.authentication, { strategy: 'UsernamePassword' })
107
+ assert.deepEqual(model.authorization, { strategy: 'RBAC', roleKey: 'role' })
108
+ assert.deepEqual(model.session, { secret: 'secret', properties: ['email'] })
109
+ assert.deepEqual(model.accessRule, [{ type: 'public' }])
110
+ assert.deepEqual(model.rateLimiting, { rules: [] })
111
+ assert.isUndefined(model.dataDomain)
112
+ })
113
+
114
+ test('creates an instance with a DataDomain', ({ assert }) => {
115
+ const domainSchema = DataDomain.createSchema({ key: 'my-domain' })
116
+ const model = new ApiModel({}, domainSchema)
117
+ assert.isDefined(model.dataDomain)
118
+ assert.instanceOf(model.dataDomain, DataDomain)
119
+ assert.equal(model.dataDomain!.key, 'my-domain')
120
+ })
121
+
122
+ test('notifies change when info is modified', async ({ assert }) => {
123
+ const model = new ApiModel()
124
+ let notified = false
125
+ model.addEventListener('change', () => {
126
+ notified = true
127
+ })
128
+ model.info.name = 'New Name'
129
+ await Promise.resolve() // Allow microtask to run
130
+ assert.isTrue(notified)
131
+ })
132
+ })
133
+
134
+ test.group('ApiModel.toJSON()', () => {
135
+ test('serializes default values', ({ assert }) => {
136
+ const model = new ApiModel()
137
+ const json = model.toJSON()
138
+
139
+ assert.equal(json.kind, ApiModelKind)
140
+ assert.equal(json.key, model.key)
141
+ assert.deepInclude(json.info, { name: 'Unnamed API' })
142
+ assert.deepEqual(json.exposes, [])
143
+ assert.isUndefined(json.userKey)
144
+ assert.isUndefined(json.domain)
145
+ assert.isUndefined(json.authentication)
146
+ assert.isUndefined(json.authorization)
147
+ assert.isUndefined(json.session)
148
+ assert.isUndefined(json.accessRule)
149
+ assert.isUndefined(json.rateLimiting)
150
+ })
151
+
152
+ test('serializes all provided values', ({ assert }) => {
153
+ const schema: ApiModelSchema = {
154
+ kind: ApiModelKind,
155
+ key: 'test-api',
156
+ info: { name: 'Test API', description: 'A test API' },
157
+ exposes: [{ key: 'entity1', actions: [] }],
158
+ userKey: 'user-entity',
159
+ domain: { key: 'domain1', version: '1.0.0' },
160
+ authentication: { strategy: 'UsernamePassword' },
161
+ authorization: { strategy: 'RBAC', roleKey: 'role' } as RolesBasedAccessControl,
162
+ session: { secret: 'secret', properties: ['email'] },
163
+ accessRule: [{ type: 'public' }],
164
+ rateLimiting: { rules: [] },
165
+ }
166
+ const model = new ApiModel(schema)
167
+ const json = model.toJSON()
168
+
169
+ assert.equal(json.key, 'test-api')
170
+ assert.deepInclude(json.info, { name: 'Test API', description: 'A test API' })
171
+ assert.deepEqual(json.exposes, [{ key: 'entity1', actions: [] }])
172
+ assert.equal(json.userKey, 'user-entity')
173
+ assert.deepEqual(json.domain, { key: 'domain1', version: '1.0.0' })
174
+ assert.deepEqual(json.authentication, { strategy: 'UsernamePassword' })
175
+ assert.deepEqual(json.authorization, { strategy: 'RBAC', roleKey: 'role' })
176
+ assert.deepEqual(json.session, { secret: 'secret', properties: ['email'] })
177
+ assert.deepEqual(json.accessRule, [{ type: 'public' }])
178
+ assert.deepEqual(json.rateLimiting, { rules: [] })
179
+ })
180
+ })
181
+
182
+ test.group('ApiModel.exposeEntity()', () => {
183
+ test('exposes a new entity', ({ assert }) => {
184
+ const model = new ApiModel()
185
+ const entityKey = 'new-entity'
186
+ const exposedEntity = model.exposeEntity(entityKey)
187
+
188
+ assert.isDefined(exposedEntity)
189
+ assert.equal(exposedEntity.key, entityKey)
190
+ assert.deepEqual(exposedEntity.actions, [])
191
+ assert.includeDeepMembers(model.exposes, [exposedEntity])
192
+ })
193
+
194
+ test('returns an existing entity if already exposed', ({ assert }) => {
195
+ const model = new ApiModel()
196
+ const entityKey = 'existing-entity'
197
+ const initialExposedEntity = model.exposeEntity(entityKey)
198
+ const retrievedExposedEntity = model.exposeEntity(entityKey)
199
+
200
+ assert.strictEqual(retrievedExposedEntity, initialExposedEntity)
201
+ assert.lengthOf(model.exposes, 1)
202
+ })
203
+
204
+ test('notifies change when a new entity is exposed', async ({ assert }) => {
205
+ const model = new ApiModel()
206
+ let notified = false
207
+ model.addEventListener('change', () => {
208
+ notified = true
209
+ })
210
+ model.exposeEntity('notify-entity')
211
+ await Promise.resolve() // Allow microtask to run
212
+ assert.isTrue(notified)
213
+ })
214
+
215
+ test('does not notify change if entity already exposed', async ({ assert }) => {
216
+ const model = new ApiModel()
217
+ model.exposeEntity('no-notify-entity') // First exposure
218
+ await Promise.resolve() // Allow microtask to run
219
+ let notified = false
220
+ model.addEventListener('change', () => {
221
+ notified = true
222
+ })
223
+ model.exposeEntity('no-notify-entity') // Second exposure
224
+ await Promise.resolve() // Allow microtask to run
225
+ assert.isFalse(notified)
226
+ })
227
+ })
228
+
229
+ test.group('ApiModel.removeEntity()', () => {
230
+ test('removes an existing entity', ({ assert }) => {
231
+ const model = new ApiModel()
232
+ const entityKey = 'entity-to-remove'
233
+ model.exposeEntity(entityKey)
234
+ assert.lengthOf(model.exposes, 1)
235
+
236
+ model.removeEntity(entityKey)
237
+ assert.lengthOf(model.exposes, 0)
238
+ })
239
+
240
+ test('does nothing if entity does not exist', ({ assert }) => {
241
+ const model = new ApiModel()
242
+ model.exposeEntity('existing-entity')
243
+ const initialExposes = [...model.exposes]
244
+
245
+ model.removeEntity('non-existing-entity')
246
+ assert.deepEqual(model.exposes, initialExposes)
247
+ })
248
+
249
+ test('notifies change when an entity is removed', async ({ assert }) => {
250
+ const model = new ApiModel()
251
+ const entityKey = 'notify-remove-entity'
252
+ model.exposeEntity(entityKey)
253
+
254
+ let notified = false
255
+ model.addEventListener('change', () => {
256
+ notified = true
257
+ })
258
+ model.removeEntity(entityKey)
259
+ await Promise.resolve() // Allow microtask to run
260
+ assert.isTrue(notified)
261
+ })
262
+
263
+ test('does not notify change if entity to remove does not exist', async ({ assert }) => {
264
+ const model = new ApiModel()
265
+ let notified = false
266
+ model.addEventListener('change', () => {
267
+ notified = true
268
+ })
269
+ model.removeEntity('no-notify-remove-entity')
270
+ await Promise.resolve() // Allow microtask to run
271
+ assert.isFalse(notified)
272
+ })
273
+ })
274
+
275
+ test.group('ApiModel.getExposedEntity()', () => {
276
+ test('returns an existing exposed entity', ({ assert }) => {
277
+ const model = new ApiModel()
278
+ const entityKey = 'get-entity'
279
+ const exposed: ExposedEntity = { key: entityKey, actions: [] }
280
+ model.exposes.push(exposed)
281
+
282
+ const retrievedEntity = model.getExposedEntity(entityKey)
283
+ assert.deepEqual(retrievedEntity, exposed)
284
+ })
285
+
286
+ test('returns undefined if entity is not exposed', ({ assert }) => {
287
+ const model = new ApiModel()
288
+ const retrievedEntity = model.getExposedEntity('non-exposed-entity')
289
+ assert.isUndefined(retrievedEntity)
290
+ })
291
+ })
@@ -8,6 +8,7 @@ import {
8
8
  DataDomain,
9
9
  DataFormat,
10
10
  SemanticType,
11
+ type OnDeleteRule,
11
12
  } from '../../../src/index.js'
12
13
 
13
14
  test.group('DomainAssociation.createSchema()', () => {
@@ -23,6 +24,8 @@ test.group('DomainAssociation.createSchema()', () => {
23
24
  assert.isUndefined(schema.bindings)
24
25
  assert.isUndefined(schema.targets)
25
26
  assert.deepEqual(schema.semantics, [])
27
+ assert.isUndefined(schema.onDelete)
28
+ assert.isUndefined(schema.readOnly)
26
29
  })
27
30
 
28
31
  test('creates a schema with provided key', ({ assert }) => {
@@ -43,6 +46,17 @@ test.group('DomainAssociation.createSchema()', () => {
43
46
  assert.deepEqual(schema.semantics, semantics)
44
47
  })
45
48
 
49
+ test('creates a schema with provided onDelete rule', ({ assert }) => {
50
+ const onDelete: OnDeleteRule = 'cascade'
51
+ const schema = DomainAssociation.createSchema({ onDelete })
52
+ assert.equal(schema.onDelete, onDelete)
53
+ })
54
+
55
+ test('creates a schema with provided readOnly rule', ({ assert }) => {
56
+ const schema = DomainAssociation.createSchema({ readOnly: true })
57
+ assert.isTrue(schema.readOnly)
58
+ })
59
+
46
60
  test('creates a schema with provided schema', ({ assert }) => {
47
61
  const schemaDefinition: AmfShapes.IApiAssociationShape = { linked: false }
48
62
  const schema = DomainAssociation.createSchema({ schema: schemaDefinition })
@@ -80,6 +94,8 @@ test.group('DomainAssociation.createSchema()', () => {
80
94
  const bindings: AssociationBinding[] = [{ type: 'web', schema: { hidden: false } }]
81
95
  const targets = [{ key: 'target1', domain: 'domain1' }, { key: 'target2' }]
82
96
  const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
97
+ const readOnly = true
98
+ const onDelete: OnDeleteRule = 'restrict'
83
99
 
84
100
  const schema = DomainAssociation.createSchema({
85
101
  key,
@@ -90,6 +106,8 @@ test.group('DomainAssociation.createSchema()', () => {
90
106
  bindings,
91
107
  targets,
92
108
  semantics,
109
+ onDelete,
110
+ readOnly,
93
111
  })
94
112
 
95
113
  assert.equal(schema.key, key)
@@ -100,6 +118,8 @@ test.group('DomainAssociation.createSchema()', () => {
100
118
  assert.deepEqual(schema.bindings, bindings)
101
119
  assert.deepEqual(schema.targets, targets)
102
120
  assert.deepEqual(schema.semantics, semantics)
121
+ assert.equal(schema.onDelete, onDelete)
122
+ assert.isTrue(schema.readOnly)
103
123
  })
104
124
 
105
125
  test('creates a schema with cloned bindings', ({ assert }) => {
@@ -145,6 +165,8 @@ test.group('DomainAssociation.constructor()', () => {
145
165
  assert.deepEqual(association.bindings, [])
146
166
  assert.deepEqual(association.targets, [])
147
167
  assert.deepEqual(association.semantics, [])
168
+ assert.isUndefined(association.onDelete)
169
+ assert.isUndefined(association.readOnly)
148
170
  })
149
171
 
150
172
  test('creates an instance with provided key', ({ assert }) => {
@@ -163,6 +185,22 @@ test.group('DomainAssociation.constructor()', () => {
163
185
  assert.deepEqual(association.semantics, semantics)
164
186
  })
165
187
 
188
+ test('creates an instance with provided onDelete rule', ({ assert }) => {
189
+ const dataDomain = new DataDomain()
190
+ const parentKey = 'test-parent'
191
+ const onDelete: OnDeleteRule = 'setNull'
192
+ const association = new DomainAssociation(dataDomain, parentKey, { onDelete })
193
+ assert.equal(association.onDelete, onDelete)
194
+ })
195
+
196
+ test('creates an instance with provided readOnly rule', ({ assert }) => {
197
+ const dataDomain = new DataDomain()
198
+ const parentKey = 'test-parent'
199
+ const readOnly = true
200
+ const association = new DomainAssociation(dataDomain, parentKey, { readOnly })
201
+ assert.isTrue(association.readOnly)
202
+ })
203
+
166
204
  test('creates an instance with provided info', ({ assert }) => {
167
205
  const dataDomain = new DataDomain()
168
206
  const parentKey = 'test-parent'
@@ -220,6 +258,8 @@ test.group('DomainAssociation.constructor()', () => {
220
258
  const bindings: AssociationBinding[] = [{ type: 'web', schema: { hidden: false } }]
221
259
  const targets = [{ key: 'target1', domain: 'domain1' }, { key: 'target2' }]
222
260
  const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
261
+ const readOnly = false
262
+ const onDelete: OnDeleteRule = 'cascade'
223
263
 
224
264
  const association = new DomainAssociation(dataDomain, parentKey, {
225
265
  key,
@@ -230,6 +270,8 @@ test.group('DomainAssociation.constructor()', () => {
230
270
  bindings,
231
271
  targets,
232
272
  semantics,
273
+ onDelete,
274
+ readOnly,
233
275
  })
234
276
 
235
277
  assert.equal(association.key, key)
@@ -240,6 +282,8 @@ test.group('DomainAssociation.constructor()', () => {
240
282
  assert.deepEqual(association.bindings, bindings)
241
283
  assert.deepEqual(association.targets, targets)
242
284
  assert.deepEqual(association.semantics, semantics)
285
+ assert.equal(association.onDelete, onDelete)
286
+ assert.isFalse(association.readOnly)
243
287
  })
244
288
 
245
289
  test('creates an instance with cloned bindings', ({ assert }) => {
@@ -294,6 +338,8 @@ test.group('DomainAssociation.toJSON()', () => {
294
338
  assert.isUndefined(json.bindings)
295
339
  assert.isUndefined(json.targets)
296
340
  assert.isUndefined(json.semantics)
341
+ assert.isUndefined(json.onDelete)
342
+ assert.isUndefined(json.readOnly)
297
343
  })
298
344
 
299
345
  test('returns a JSON representation with provided key', ({ assert }) => {
@@ -311,7 +357,25 @@ test.group('DomainAssociation.toJSON()', () => {
311
357
  const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
312
358
  const association = new DomainAssociation(dataDomain, parentKey, { semantics })
313
359
  const json = association.toJSON()
314
- assert.deepEqual(json.semantics, semantics)
360
+ assert.deepEqual(json.semantics, semantics, 'Semantics are serialized')
361
+ })
362
+
363
+ test('returns a JSON representation with provided onDelete rule', ({ assert }) => {
364
+ const dataDomain = new DataDomain()
365
+ const parentKey = 'test-parent'
366
+ const onDelete: OnDeleteRule = 'cascade'
367
+ const association = new DomainAssociation(dataDomain, parentKey, { onDelete })
368
+ const json = association.toJSON()
369
+ assert.equal(json.onDelete, onDelete, 'onDelete is serialized')
370
+ })
371
+
372
+ test('returns a JSON representation with provided readOnly rule', ({ assert }) => {
373
+ const dataDomain = new DataDomain()
374
+ const parentKey = 'test-parent'
375
+ const readOnly = true
376
+ const association = new DomainAssociation(dataDomain, parentKey, { readOnly })
377
+ const json = association.toJSON()
378
+ assert.isTrue(json.readOnly, 'readOnly is serialized when true')
315
379
  })
316
380
 
317
381
  test('returns a JSON representation with provided info', ({ assert }) => {
@@ -380,6 +444,8 @@ test.group('DomainAssociation.toJSON()', () => {
380
444
  const bindings: AssociationBinding[] = [{ type: 'web', schema: { hidden: false } }]
381
445
  const targets = [{ key: 'target1', domain: 'domain1' }, { key: 'target2' }]
382
446
  const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
447
+ const readOnly = true
448
+ const onDelete: OnDeleteRule = 'restrict'
383
449
 
384
450
  const association = new DomainAssociation(dataDomain, parentKey, {
385
451
  key,
@@ -390,6 +456,8 @@ test.group('DomainAssociation.toJSON()', () => {
390
456
  bindings,
391
457
  targets,
392
458
  semantics,
459
+ onDelete,
460
+ readOnly,
393
461
  })
394
462
 
395
463
  const json = association.toJSON()
@@ -402,6 +470,8 @@ test.group('DomainAssociation.toJSON()', () => {
402
470
  assert.deepEqual(json.bindings, bindings)
403
471
  assert.deepEqual(json.targets, targets)
404
472
  assert.deepEqual(json.semantics, semantics)
473
+ assert.equal(json.onDelete, onDelete)
474
+ assert.isTrue(json.readOnly)
405
475
  })
406
476
 
407
477
  test('returns a JSON representation with cloned bindings', ({ assert }) => {
@@ -421,7 +491,27 @@ test.group('DomainAssociation.toJSON()', () => {
421
491
  const semantics = [{ id: SemanticType.ResourceOwnerIdentifier }]
422
492
  association.semantics = semantics
423
493
  const json = association.toJSON()
424
- assert.deepEqual(json.semantics, semantics)
494
+ assert.deepEqual(json.semantics, semantics, 'Semantics are serialized after creation')
495
+ })
496
+
497
+ test('returns a JSON representation with onDelete rule when it is set after creation', ({ assert }) => {
498
+ const dataDomain = new DataDomain()
499
+ const parentKey = 'test-parent'
500
+ const association = new DomainAssociation(dataDomain, parentKey)
501
+ const onDelete: OnDeleteRule = 'setNull'
502
+ association.onDelete = onDelete
503
+ const json = association.toJSON()
504
+ assert.equal(json.onDelete, onDelete, 'onDelete is serialized after creation')
505
+ })
506
+
507
+ test('returns a JSON representation with readOnly rule when it is set after creation', ({ assert }) => {
508
+ const dataDomain = new DataDomain()
509
+ const parentKey = 'test-parent'
510
+ const association = new DomainAssociation(dataDomain, parentKey)
511
+ const readOnly = true
512
+ association.readOnly = readOnly
513
+ const json = association.toJSON()
514
+ assert.isTrue(json.readOnly, 'readOnly is serialized after creation when true')
425
515
  })
426
516
 
427
517
  test('returns a JSON representation with cloned targets', ({ assert }) => {
@@ -17,7 +17,7 @@ test.group('DomainEntity.createSchema()', () => {
17
17
  assert.equal(schema.kind, DomainEntityKind)
18
18
  assert.typeOf(schema.key, 'string')
19
19
  assert.isNotEmpty(schema.key)
20
- assert.deepInclude(schema.info, { name: 'New entity' })
20
+ assert.deepInclude(schema.info, { name: 'new_entity' })
21
21
  assert.isUndefined(schema.tags)
22
22
  assert.isUndefined(schema.semantics)
23
23
  assert.isUndefined(schema.fields)
@@ -59,7 +59,7 @@ test.group('DomainEntity.createSchema()', () => {
59
59
  assert.equal(schema.kind, DomainEntityKind)
60
60
  assert.typeOf(schema.key, 'string')
61
61
  assert.isNotEmpty(schema.key)
62
- assert.deepInclude(schema.info, { name: 'New entity' })
62
+ assert.deepInclude(schema.info, { name: 'new_entity' })
63
63
  })
64
64
 
65
65
  test('creates a schema with tags', ({ assert }) => {
@@ -69,7 +69,7 @@ test.group('DomainEntity.createSchema()', () => {
69
69
  assert.equal(schema.kind, DomainEntityKind)
70
70
  assert.typeOf(schema.key, 'string')
71
71
  assert.isNotEmpty(schema.key)
72
- assert.deepInclude(schema.info, { name: 'New entity' })
72
+ assert.deepInclude(schema.info, { name: 'new_entity' })
73
73
  assert.deepEqual(schema.tags, ['tag1', 'tag2'])
74
74
  })
75
75
 
@@ -80,7 +80,7 @@ test.group('DomainEntity.createSchema()', () => {
80
80
  assert.equal(schema.kind, DomainEntityKind)
81
81
  assert.typeOf(schema.key, 'string')
82
82
  assert.isNotEmpty(schema.key)
83
- assert.deepInclude(schema.info, { name: 'New entity' })
83
+ assert.deepInclude(schema.info, { name: 'new_entity' })
84
84
  assert.deepEqual(schema.semantics, [{ id: SemanticType.User }])
85
85
  })
86
86
 
@@ -91,7 +91,7 @@ test.group('DomainEntity.createSchema()', () => {
91
91
  assert.equal(schema.kind, DomainEntityKind)
92
92
  assert.typeOf(schema.key, 'string')
93
93
  assert.isNotEmpty(schema.key)
94
- assert.deepInclude(schema.info, { name: 'New entity' })
94
+ assert.deepInclude(schema.info, { name: 'new_entity' })
95
95
  assert.deepEqual(schema.fields, [{ key: 'test-property', type: 'property' }])
96
96
  })
97
97
 
@@ -102,7 +102,7 @@ test.group('DomainEntity.createSchema()', () => {
102
102
  assert.equal(schema.kind, DomainEntityKind)
103
103
  assert.typeOf(schema.key, 'string')
104
104
  assert.isNotEmpty(schema.key)
105
- assert.deepInclude(schema.info, { name: 'New entity' })
105
+ assert.deepInclude(schema.info, { name: 'new_entity' })
106
106
  assert.isTrue(schema.deprecated)
107
107
  })
108
108
 
@@ -113,7 +113,7 @@ test.group('DomainEntity.createSchema()', () => {
113
113
  assert.equal(schema.kind, DomainEntityKind)
114
114
  assert.typeOf(schema.key, 'string')
115
115
  assert.isNotEmpty(schema.key)
116
- assert.deepInclude(schema.info, { name: 'New entity' })
116
+ assert.deepInclude(schema.info, { name: 'new_entity' })
117
117
  assert.isFalse(schema.deprecated)
118
118
  })
119
119
 
@@ -164,7 +164,7 @@ test.group('DomainEntity.constructor()', () => {
164
164
  assert.typeOf(entity.key, 'string')
165
165
  assert.isNotEmpty(entity.key)
166
166
  assert.instanceOf(entity.info, Thing)
167
- assert.equal(entity.info.name, 'New entity')
167
+ assert.equal(entity.info.name, 'new_entity')
168
168
  assert.deepEqual(entity.tags, [])
169
169
  assert.deepEqual(entity.semantics, [])
170
170
  assert.deepEqual(entity.fields, [])
@@ -213,7 +213,7 @@ test.group('DomainEntity.constructor()', () => {
213
213
  assert.typeOf(entity.key, 'string')
214
214
  assert.isNotEmpty(entity.key)
215
215
  assert.instanceOf(entity.info, Thing)
216
- assert.equal(entity.info.name, 'New entity')
216
+ assert.equal(entity.info.name, 'new_entity')
217
217
  })
218
218
 
219
219
  test('creates a new DomainEntity with tags', ({ assert }) => {
@@ -225,7 +225,7 @@ test.group('DomainEntity.constructor()', () => {
225
225
  assert.typeOf(entity.key, 'string')
226
226
  assert.isNotEmpty(entity.key)
227
227
  assert.instanceOf(entity.info, Thing)
228
- assert.equal(entity.info.name, 'New entity')
228
+ assert.equal(entity.info.name, 'new_entity')
229
229
  assert.deepEqual(entity.tags, ['tag1', 'tag2'])
230
230
  })
231
231
 
@@ -238,7 +238,7 @@ test.group('DomainEntity.constructor()', () => {
238
238
  assert.typeOf(entity.key, 'string')
239
239
  assert.isNotEmpty(entity.key)
240
240
  assert.instanceOf(entity.info, Thing)
241
- assert.equal(entity.info.name, 'New entity')
241
+ assert.equal(entity.info.name, 'new_entity')
242
242
  assert.deepEqual(entity.semantics, [{ id: SemanticType.User }])
243
243
  })
244
244
 
@@ -251,7 +251,7 @@ test.group('DomainEntity.constructor()', () => {
251
251
  assert.typeOf(entity.key, 'string')
252
252
  assert.isNotEmpty(entity.key)
253
253
  assert.instanceOf(entity.info, Thing)
254
- assert.equal(entity.info.name, 'New entity')
254
+ assert.equal(entity.info.name, 'new_entity')
255
255
  assert.deepEqual(entity.fields, [{ key: 'test-property', type: 'property' }])
256
256
  })
257
257
 
@@ -264,7 +264,7 @@ test.group('DomainEntity.constructor()', () => {
264
264
  assert.typeOf(entity.key, 'string')
265
265
  assert.isNotEmpty(entity.key)
266
266
  assert.instanceOf(entity.info, Thing)
267
- assert.equal(entity.info.name, 'New entity')
267
+ assert.equal(entity.info.name, 'new_entity')
268
268
  assert.isTrue(entity.deprecated)
269
269
  })
270
270
 
@@ -277,7 +277,7 @@ test.group('DomainEntity.constructor()', () => {
277
277
  assert.typeOf(entity.key, 'string')
278
278
  assert.isNotEmpty(entity.key)
279
279
  assert.instanceOf(entity.info, Thing)
280
- assert.equal(entity.info.name, 'New entity')
280
+ assert.equal(entity.info.name, 'new_entity')
281
281
  assert.isFalse(entity.deprecated)
282
282
  })
283
283
 
@@ -350,7 +350,7 @@ test.group('DomainEntity.toJSON()', () => {
350
350
  const json = entity.toJSON()
351
351
  assert.equal(json.kind, DomainEntityKind)
352
352
  assert.equal(json.key, entity.key)
353
- assert.deepInclude(json.info, { name: 'New entity' })
353
+ assert.deepInclude(json.info, { name: 'new_entity' })
354
354
  assert.isUndefined(json.tags)
355
355
  assert.isUndefined(json.semantics)
356
356
  assert.isUndefined(json.fields)
@@ -99,22 +99,12 @@ test.group('constructor()', () => {
99
99
  ],
100
100
  lastModified: { byMe: false, time: 0, user: 'id', name: 'test' },
101
101
  }
102
- const result = new DomainFile(JSON.stringify(schema))
102
+ const result = new DomainFile(schema)
103
103
  assert.equal(result.kind, DomainFileKind)
104
104
  assert.equal(result.info.name, 'hello')
105
105
  assert.equal(result.key, '123')
106
106
  assert.deepEqual(result.lastModified, schema.lastModified)
107
107
  })
108
-
109
- test('throws when invalid schema', ({ assert }) => {
110
- assert.throws(() => {
111
- new DomainFile(
112
- JSON.stringify({
113
- name: 'a name',
114
- })
115
- )
116
- })
117
- })
118
108
  })
119
109
 
120
110
  test.group('toJSON()', () => {
@@ -9,7 +9,7 @@ test.group('DomainModel.addEntity()', () => {
9
9
  assert.instanceOf(entity, DomainEntity)
10
10
  assert.equal(entity.kind, DomainEntityKind)
11
11
  assert.equal(entity.key, 'test-entity')
12
- assert.deepInclude(entity.info, { name: 'New entity' })
12
+ assert.deepInclude(entity.info, { name: 'new_entity' })
13
13
  assert.isTrue(dataDomain.graph.hasNode(entity.key))
14
14
  assert.equal(dataDomain.graph.parent(entity.key), model.key)
15
15
  })
@@ -22,7 +22,7 @@ test.group('DomainModel.addEntity()', () => {
22
22
  assert.equal(entity.kind, DomainEntityKind)
23
23
  assert.typeOf(entity.key, 'string')
24
24
  assert.isNotEmpty(entity.key)
25
- assert.deepInclude(entity.info, { name: 'New entity' })
25
+ assert.deepInclude(entity.info, { name: 'new_entity' })
26
26
  assert.isTrue(dataDomain.graph.hasNode(entity.key))
27
27
  assert.equal(dataDomain.graph.parent(entity.key), model.key)
28
28
  })