@api-client/core 0.13.6 → 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 (174) 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 +3 -4
  37. package/build/src/modeling/DomainFile.d.ts.map +1 -1
  38. package/build/src/modeling/DomainFile.js +5 -9
  39. package/build/src/modeling/DomainFile.js.map +1 -1
  40. package/build/src/modeling/DomainImpactAnalysis.d.ts +1 -1
  41. package/build/src/modeling/DomainImpactAnalysis.d.ts.map +1 -1
  42. package/build/src/modeling/DomainImpactAnalysis.js +3 -3
  43. package/build/src/modeling/DomainImpactAnalysis.js.map +1 -1
  44. package/build/src/modeling/DomainModel.d.ts +2 -2
  45. package/build/src/modeling/DomainModel.js +2 -2
  46. package/build/src/modeling/DomainModel.js.map +1 -1
  47. package/build/src/modeling/DomainProperty.d.ts +28 -12
  48. package/build/src/modeling/DomainProperty.d.ts.map +1 -1
  49. package/build/src/modeling/DomainProperty.js +61 -26
  50. package/build/src/modeling/DomainProperty.js.map +1 -1
  51. package/build/src/modeling/Semantics.d.ts +109 -0
  52. package/build/src/modeling/Semantics.d.ts.map +1 -0
  53. package/build/src/modeling/Semantics.js +97 -0
  54. package/build/src/modeling/Semantics.js.map +1 -0
  55. package/build/src/models/CertificateFile.d.ts +2 -3
  56. package/build/src/models/CertificateFile.d.ts.map +1 -1
  57. package/build/src/models/CertificateFile.js +4 -8
  58. package/build/src/models/CertificateFile.js.map +1 -1
  59. package/build/src/models/Folder.d.ts +1 -2
  60. package/build/src/models/Folder.d.ts.map +1 -1
  61. package/build/src/models/Folder.js +2 -4
  62. package/build/src/models/Folder.js.map +1 -1
  63. package/build/src/models/Project.d.ts +2 -3
  64. package/build/src/models/Project.d.ts.map +1 -1
  65. package/build/src/models/Project.js +4 -8
  66. package/build/src/models/Project.js.map +1 -1
  67. package/build/src/models/kinds.d.ts +0 -24
  68. package/build/src/models/kinds.d.ts.map +1 -1
  69. package/build/src/models/kinds.js +0 -24
  70. package/build/src/models/kinds.js.map +1 -1
  71. package/build/src/models/store/File.d.ts +1 -21
  72. package/build/src/models/store/File.d.ts.map +1 -1
  73. package/build/src/models/store/File.js +3 -23
  74. package/build/src/models/store/File.js.map +1 -1
  75. package/build/src/models/store/data_catalog.d.ts +1 -1
  76. package/build/src/models/store/data_catalog.js.map +1 -1
  77. package/build/src/sdk/FilesSdk.js +1 -1
  78. package/build/src/sdk/FilesSdk.js.map +1 -1
  79. package/build/tsconfig.tsbuildinfo +1 -1
  80. package/data/models/example-generator-api.json +22 -22
  81. package/eslint.config.js +1 -0
  82. package/package.json +5 -5
  83. package/src/amf/AmfTypes.ts +1 -1
  84. package/src/amf/Utils.ts +0 -15
  85. package/src/modeling/Bindings.ts +1 -1
  86. package/src/modeling/DataDomain.ts +2 -2
  87. package/src/modeling/DataFormat.ts +0 -48
  88. package/src/modeling/DomainAssociation.ts +66 -3
  89. package/src/modeling/DomainEntity.ts +56 -17
  90. package/src/modeling/DomainFile.ts +5 -9
  91. package/src/modeling/DomainImpactAnalysis.ts +3 -3
  92. package/src/modeling/DomainModel.ts +2 -2
  93. package/src/modeling/DomainProperty.ts +60 -21
  94. package/src/modeling/Semantics.ts +178 -0
  95. package/src/modeling/graph.md +14 -14
  96. package/src/modeling/readme.md +29 -29
  97. package/src/models/CertificateFile.ts +4 -12
  98. package/src/models/Folder.ts +2 -4
  99. package/src/models/Project.ts +4 -8
  100. package/src/models/kinds.ts +0 -25
  101. package/src/models/store/File.ts +4 -35
  102. package/src/models/store/data_catalog.ts +1 -1
  103. package/src/sdk/FilesSdk.ts +1 -1
  104. package/tests/unit/modeling/data_domain_change_observers.spec.ts +11 -10
  105. package/tests/unit/modeling/data_domain_entities.spec.ts +129 -1
  106. package/tests/unit/modeling/data_domain_property.spec.ts +1 -1
  107. package/tests/unit/modeling/domain_asociation.spec.ts +177 -0
  108. package/tests/unit/modeling/domain_entity.spec.ts +27 -26
  109. package/tests/unit/modeling/domain_entity_example_generator_json.spec.ts +11 -11
  110. package/tests/unit/modeling/domain_entity_example_generator_xml.spec.ts +10 -10
  111. package/tests/unit/modeling/domain_file.spec.ts +4 -27
  112. package/tests/unit/modeling/{domain.property.spec.ts → domain_property.spec.ts} +139 -23
  113. package/tests/unit/models/Certificate/from_name.spec.ts +3 -15
  114. package/tests/unit/models/File/constructor.spec.ts +0 -1
  115. package/tests/unit/models/File/new.spec.ts +0 -13
  116. package/tests/unit/models/File/shortcutTo.spec.ts +1 -2
  117. package/tests/unit/models/File/toJSON.spec.ts +0 -13
  118. package/tests/unit/models/File/updateByMeMeta.spec.ts +4 -6
  119. package/tests/unit/models/Folder/create.spec.ts +2 -23
  120. package/tests/unit/models/Project/create.spec.ts +6 -32
  121. package/build/src/amf/AmfShapeGenerator.d.ts +0 -103
  122. package/build/src/amf/AmfShapeGenerator.d.ts.map +0 -1
  123. package/build/src/amf/AmfShapeGenerator.js +0 -416
  124. package/build/src/amf/AmfShapeGenerator.js.map +0 -1
  125. package/build/src/modeling/legacy/DataAssociation.d.ts +0 -284
  126. package/build/src/modeling/legacy/DataAssociation.d.ts.map +0 -1
  127. package/build/src/modeling/legacy/DataAssociation.js +0 -443
  128. package/build/src/modeling/legacy/DataAssociation.js.map +0 -1
  129. package/build/src/modeling/legacy/DataEntity.d.ts +0 -358
  130. package/build/src/modeling/legacy/DataEntity.d.ts.map +0 -1
  131. package/build/src/modeling/legacy/DataEntity.js +0 -855
  132. package/build/src/modeling/legacy/DataEntity.js.map +0 -1
  133. package/build/src/modeling/legacy/DataEntityBuilder.d.ts +0 -162
  134. package/build/src/modeling/legacy/DataEntityBuilder.d.ts.map +0 -1
  135. package/build/src/modeling/legacy/DataEntityBuilder.js +0 -221
  136. package/build/src/modeling/legacy/DataEntityBuilder.js.map +0 -1
  137. package/build/src/modeling/legacy/DataImpactAnalysis.d.ts +0 -298
  138. package/build/src/modeling/legacy/DataImpactAnalysis.d.ts.map +0 -1
  139. package/build/src/modeling/legacy/DataImpactAnalysis.js +0 -441
  140. package/build/src/modeling/legacy/DataImpactAnalysis.js.map +0 -1
  141. package/build/src/modeling/legacy/DataModel.d.ts +0 -99
  142. package/build/src/modeling/legacy/DataModel.d.ts.map +0 -1
  143. package/build/src/modeling/legacy/DataModel.js +0 -237
  144. package/build/src/modeling/legacy/DataModel.js.map +0 -1
  145. package/build/src/modeling/legacy/DataNamespace.d.ts +0 -340
  146. package/build/src/modeling/legacy/DataNamespace.d.ts.map +0 -1
  147. package/build/src/modeling/legacy/DataNamespace.js +0 -784
  148. package/build/src/modeling/legacy/DataNamespace.js.map +0 -1
  149. package/build/src/modeling/legacy/DataProperty.d.ts +0 -332
  150. package/build/src/modeling/legacy/DataProperty.d.ts.map +0 -1
  151. package/build/src/modeling/legacy/DataProperty.js +0 -415
  152. package/build/src/modeling/legacy/DataProperty.js.map +0 -1
  153. package/build/src/models/store/DataFile.d.ts +0 -31
  154. package/build/src/models/store/DataFile.d.ts.map +0 -1
  155. package/build/src/models/store/DataFile.js +0 -92
  156. package/build/src/models/store/DataFile.js.map +0 -1
  157. package/src/amf/AmfShapeGenerator.ts +0 -477
  158. package/src/modeling/legacy/DataAssociation.ts +0 -554
  159. package/src/modeling/legacy/DataEntity.ts +0 -1019
  160. package/src/modeling/legacy/DataEntityBuilder.ts +0 -236
  161. package/src/modeling/legacy/DataImpactAnalysis.ts +0 -530
  162. package/src/modeling/legacy/DataModel.ts +0 -276
  163. package/src/modeling/legacy/DataNamespace.ts +0 -929
  164. package/src/modeling/legacy/DataProperty.ts +0 -630
  165. package/src/models/store/DataFile.ts +0 -100
  166. package/tests/unit/modeling/legacy/amf_shape_generator.spec.ts +0 -1041
  167. package/tests/unit/modeling/legacy/data_association.spec.ts +0 -710
  168. package/tests/unit/modeling/legacy/data_entity.spec.ts +0 -2061
  169. package/tests/unit/modeling/legacy/data_entity_generator_json.spec.ts +0 -987
  170. package/tests/unit/modeling/legacy/data_entity_generator_xml.spec.ts +0 -1451
  171. package/tests/unit/modeling/legacy/data_model.spec.ts +0 -395
  172. package/tests/unit/modeling/legacy/data_namespace.spec.ts +0 -1312
  173. package/tests/unit/modeling/legacy/data_property.spec.ts +0 -887
  174. package/tests/unit/modeling/legacy/impact_analysis.spec.ts +0 -373
@@ -1,1019 +0,0 @@
1
- import { IThing, Thing } from '../../models/Thing.js'
2
- import { nanoid } from '../../nanoid.js'
3
- import { DataNamespace } from './DataNamespace.js'
4
- import { DataProperty } from './DataProperty.js'
5
- import { type DataPropertyType } from '../DataFormat.js'
6
- import { DataAssociation } from './DataAssociation.js'
7
- import { FileBreadcrumb } from '../../models/store/File.js'
8
- import { DataEntityKind } from '../../models/kinds.js'
9
- import { DataModel } from './DataModel.js'
10
- import { IApiNodeShape, IShapeUnion } from '../../amf/definitions/Shapes.js'
11
- import { AmfShapeGenerator } from '../../amf/AmfShapeGenerator.js'
12
- import { ApiSchemaGenerator } from '../../amf/ApiSchemaGenerator.js'
13
- import { IShapeRenderOptions } from '../../amf/shape/ShapeBase.js'
14
- import { RemovePropertyException } from '../../exceptions/remove_property_exception.js'
15
- import { RemoveAssociationException } from '../../exceptions/remove_association_exception.js'
16
- import { ValidationError, type FieldValidationMessage } from '../../exceptions/validation_error.js'
17
- import { RemoveEntityException } from '../../exceptions/remove_entity_exception.js'
18
- import { ForeignAssociationException } from '../../exceptions/foreign_association_exception.js'
19
- import type { DataDomainRemoveOptions } from '../types.js'
20
-
21
- /**
22
- * @deprecated
23
- */
24
- interface OrderedItem {
25
- /**
26
- * The type of the ordered item.
27
- */
28
- type: 'property' | 'association'
29
- /**
30
- * The key of the ordered item.
31
- */
32
- key: string
33
- }
34
-
35
- /**
36
- * Data entity is the smallest description of a data in the system
37
- * It contains properties and associations. At least one entity describe a data model.
38
- * @deprecated
39
- */
40
- export interface IDataEntity {
41
- kind: typeof DataEntityKind
42
- /**
43
- * The key of the namespace.
44
- */
45
- key: string
46
- /**
47
- * The data entity description.
48
- */
49
- info: IThing
50
-
51
- /**
52
- * Optional general purpose tags for the UI.
53
- */
54
- tags?: string[]
55
-
56
- /**
57
- * For future use.
58
- *
59
- * The keys of the taxonomy items associated with the entity.
60
- */
61
- taxonomy?: string[]
62
-
63
- /**
64
- * The list of keys of properties that belong to this entity.
65
- */
66
- properties?: string[]
67
-
68
- /**
69
- * The list of keys of associations that belong to this entity.
70
- */
71
- associations?: string[]
72
-
73
- /**
74
- * The ordered list of fields (properties and associations) in the schema.
75
- * These only keep references to the properties and associations.
76
- * The order of the fields is important as it defines the order of the
77
- * properties in the schema.
78
- */
79
- fields?: OrderedItem[]
80
-
81
- /**
82
- * The list of keys of entities that are parents to this entity.
83
- *
84
- * This potentially may cause a conflict when two parents declare the same
85
- * property. In such situation this entity should define own property
86
- * with the same name to shadow parent property. When the property is
87
- * not shadowed this may cause unexpected results as the processing could result
88
- * with inconsistent definition of a schema because the last read property wins.
89
- *
90
- * @todo(jarrodek): This should also hold a reference to a namespace to support
91
- * foreign entities as parents.
92
- */
93
- parents?: string[]
94
-
95
- /**
96
- * Whether this entity is deprecated.
97
- */
98
- deprecated?: boolean
99
-
100
- /**
101
- * The schema allowing to translate the model into a specific format (like JSON, RAML, XML, etc.)
102
- */
103
- schema?: IApiNodeShape
104
- }
105
-
106
- /**
107
- * Data entity is the smallest description of a data in the system
108
- * It contains properties and associations. At least one entity describe a data model.
109
- * @deprecated
110
- */
111
- export class DataEntity {
112
- kind = DataEntityKind
113
-
114
- key = ''
115
-
116
- /**
117
- * The description of the data namespace.
118
- */
119
- info: Thing = Thing.fromName('')
120
-
121
- /**
122
- * Optional general purpose tags for the UI.
123
- */
124
- tags: string[] = []
125
-
126
- /**
127
- * Reserved for future use.
128
- *
129
- * The keys of the taxonomy items associated with the entity.
130
- */
131
- taxonomy: string[] = []
132
-
133
- /**
134
- * The list of keys of properties that belong to this entity.
135
- */
136
- properties: DataProperty[] = []
137
-
138
- /**
139
- * The list of keys of associations that belong to this entity.
140
- */
141
- associations: DataAssociation[] = []
142
-
143
- /**
144
- * The ordered list of fields (properties and associations) in the schema.
145
- * These only keep references to the properties and associations.
146
- * The order of the fields is important as it defines the order of the
147
- * properties in the schema.
148
- */
149
- fields: OrderedItem[] = []
150
-
151
- /**
152
- * The list of keys of entities that are parents to this entity.
153
- *
154
- * This potentially may cause a conflict when two parents declare the same
155
- * property. In such situation this entity should define own property
156
- * with the same name to shadow parent property. When the property is
157
- * not shadowed this may cause unexpected results as the processing could result
158
- * with inconsistent definition of a schema because the last read property wins.
159
- */
160
- parents: string[] = []
161
-
162
- /**
163
- * Whether this entity is deprecated.
164
- */
165
- deprecated?: boolean
166
-
167
- static fromName(root: DataNamespace, name: string): DataEntity {
168
- const entity = new DataEntity(root)
169
- entity.info = Thing.fromName(name)
170
- return entity
171
- }
172
-
173
- /**
174
- * @param input The data entity definition to restore.
175
- */
176
- constructor(
177
- public root: DataNamespace,
178
- input?: string | IDataEntity
179
- ) {
180
- let init: IDataEntity
181
- if (typeof input === 'string') {
182
- init = JSON.parse(input)
183
- } else if (typeof input === 'object') {
184
- init = input
185
- } else {
186
- init = {
187
- kind: DataEntityKind,
188
- key: nanoid(),
189
- info: Thing.fromName('').toJSON(),
190
- }
191
- }
192
- this.new(init)
193
- }
194
-
195
- new(init: IDataEntity): void {
196
- DataEntity.validate(init)
197
- const {
198
- info,
199
- key = nanoid(),
200
- kind = DataEntityKind,
201
- tags,
202
- taxonomy,
203
- parents,
204
- properties,
205
- associations,
206
- fields,
207
- deprecated,
208
- } = init
209
- this.kind = kind
210
- this.key = key
211
- if (info) {
212
- this.info = new Thing(info)
213
- } else {
214
- this.info = Thing.fromName('')
215
- }
216
- if (Array.isArray(tags)) {
217
- this.tags = [...tags]
218
- } else {
219
- this.tags = []
220
- }
221
- if (Array.isArray(taxonomy)) {
222
- this.taxonomy = [...taxonomy]
223
- } else {
224
- this.taxonomy = []
225
- }
226
- if (Array.isArray(parents)) {
227
- this.parents = [...parents]
228
- } else {
229
- this.parents = []
230
- }
231
- this.properties = []
232
- if (Array.isArray(properties)) {
233
- properties.forEach((key) => {
234
- const value = this._readProperty(key)
235
- if (value) {
236
- this.properties.push(value)
237
- }
238
- })
239
- }
240
- this.associations = []
241
- if (Array.isArray(associations)) {
242
- associations.forEach((key) => {
243
- const value = this._readAssociation(key)
244
- if (value) {
245
- this.associations.push(value)
246
- }
247
- })
248
- }
249
- if (Array.isArray(fields)) {
250
- this.fields = [...fields]
251
- } else {
252
- this.fields = this.createOrderedFields()
253
- }
254
- if (typeof deprecated === 'boolean') {
255
- this.deprecated = deprecated
256
- } else {
257
- this.deprecated = undefined
258
- }
259
- }
260
-
261
- private createOrderedFields(): OrderedItem[] {
262
- const result: OrderedItem[] = []
263
- this.properties.forEach((i) => {
264
- result.push({
265
- type: 'property',
266
- key: i.key,
267
- })
268
- })
269
- this.associations.forEach((i) => {
270
- result.push({
271
- type: 'association',
272
- key: i.key,
273
- })
274
- })
275
- return result
276
- }
277
-
278
- static validate(input: unknown): void {
279
- const typed = input as IDataEntity
280
- const messages: FieldValidationMessage[] = []
281
- if (!typed) {
282
- messages.push({
283
- field: '',
284
- message: 'The input is required. None given',
285
- rule: 'required',
286
- })
287
- throw new ValidationError(messages)
288
- }
289
- if (typed.kind !== DataEntityKind) {
290
- messages.push({
291
- field: 'kind',
292
- message: `The kind property must be ${DataEntityKind}`,
293
- rule: 'invalid',
294
- })
295
- }
296
- if (messages.length) {
297
- throw new ValidationError(messages, { message: 'Invalid data entity definition.' })
298
- }
299
- }
300
-
301
- toJSON(): IDataEntity {
302
- const result: IDataEntity = {
303
- kind: DataEntityKind,
304
- key: this.key,
305
- info: this.info.toJSON(),
306
- }
307
- if (Array.isArray(this.tags) && this.tags.length) {
308
- result.tags = [...this.tags]
309
- }
310
- if (Array.isArray(this.taxonomy) && this.taxonomy.length) {
311
- result.taxonomy = [...this.taxonomy]
312
- }
313
- if (Array.isArray(this.parents) && this.parents.length) {
314
- result.parents = [...this.parents]
315
- }
316
- if (Array.isArray(this.properties) && this.properties.length) {
317
- result.properties = this.properties.map((i) => i.key)
318
- }
319
- if (Array.isArray(this.associations) && this.associations.length) {
320
- result.associations = this.associations.map((i) => i.key)
321
- }
322
- if (Array.isArray(this.fields) && this.fields.length) {
323
- result.fields = [...this.fields]
324
- }
325
- if (Array.isArray(this.taxonomy) && this.taxonomy.length) {
326
- result.taxonomy = [...this.taxonomy]
327
- }
328
- if (Array.isArray(this.tags) && this.tags.length) {
329
- result.tags = [...this.tags]
330
- }
331
- if (typeof this.deprecated === 'boolean') {
332
- result.deprecated = this.deprecated
333
- }
334
- return result
335
- }
336
-
337
- protected _readAssociation(key: string): DataAssociation | undefined {
338
- return this.root.definitions.associations.find((i) => i.key === key)
339
- }
340
-
341
- protected _readProperty(key: string): DataProperty | undefined {
342
- return this.root.definitions.properties.find((i) => i.key === key)
343
- }
344
-
345
- /**
346
- * Creates a property with a passed type.
347
- * @param type The type of the property
348
- * @returns The created property
349
- */
350
- addTypedProperty(type: DataPropertyType, name?: string): DataProperty {
351
- const property = DataProperty.fromType(this.root, type)
352
- if (name) {
353
- property.info.name = name
354
- }
355
- this.root.definitions.properties.push(property)
356
- this.properties.push(property)
357
- this.fields.push({ type: 'property', key: property.key })
358
- return property
359
- }
360
-
361
- /**
362
- * Creates a property with a passed type.
363
- * @param name The name of the property.
364
- * @returns The created property
365
- */
366
- addNamedProperty(name: string): DataProperty {
367
- const property = DataProperty.fromName(this.root, name)
368
- this.root.definitions.properties.push(property)
369
- this.properties.push(property)
370
- this.fields.push({ type: 'property', key: property.key })
371
- return property
372
- }
373
-
374
- /**
375
- * Removes the property from the entity and namespace definitions.
376
- * @param key The key of the property to remove.
377
- */
378
- removeProperty(key: string): void {
379
- const thisIndex = this.properties.findIndex((i) => i.key === key)
380
- if (thisIndex < 0) {
381
- throw new RemovePropertyException(`Trying to remove the ${key} property, but it doesn't exist.`)
382
- }
383
- const propertyToRemove = this.properties[thisIndex]
384
- this.properties.splice(thisIndex, 1)
385
- const defIndex = this.root.definitions.properties.findIndex((i) => i.key === key)
386
- if (defIndex >= 0) {
387
- this.root.definitions.properties.splice(defIndex, 1)
388
- }
389
- this.removeField(key)
390
- propertyToRemove.remove()
391
- }
392
-
393
- private removeField(key: string): void {
394
- this.fields = this.fields.filter((item) => item.key !== key)
395
- }
396
-
397
- /**
398
- * Lists all properties for this Entity.
399
- * @returns The list of properties that belong to this entity.
400
- */
401
- listProperties(): DataProperty[] {
402
- return [...this.properties]
403
- }
404
-
405
- /**
406
- * Lists all associations for this Entity.
407
- * @returns The list of associations that belong to this entity.
408
- */
409
- listAssociations(): DataAssociation[] {
410
- return [...this.associations]
411
- }
412
-
413
- /**
414
- * Generates an ordered list of fields (properties and associations) for this entity.
415
- *
416
- * @returns The list of fields (properties and associations) that belong to this entity.
417
- */
418
- listFields(): (DataAssociation | DataProperty)[] {
419
- const result: (DataAssociation | DataProperty)[] = []
420
- this.fields.forEach((i) => {
421
- if (i.type === 'property') {
422
- const property = this.properties.find((p) => p.key === i.key)
423
- if (property) {
424
- result.push(property)
425
- }
426
- } else if (i.type === 'association') {
427
- const association = this.associations.find((a) => a.key === i.key)
428
- if (association) {
429
- result.push(association)
430
- }
431
- }
432
- })
433
- return result
434
- }
435
-
436
- /**
437
- * Moves the field to a new index.
438
- * @param key The key of the field to move.
439
- * @param toIndex The new index to which move the field to.
440
- */
441
- moveField(key: string, toIndex: number): void {
442
- const fromIndex = this.fields.findIndex((i) => i.key === key)
443
- if (fromIndex < 0) {
444
- throw new ValidationError([{ field: 'fields', message: `Field ${key} not found.`, rule: 'not-found' }])
445
- }
446
- if (toIndex < 0 || toIndex >= this.fields.length) {
447
- throw new ValidationError([{ field: 'fields', message: `Invalid index ${toIndex}.`, rule: 'invalid' }])
448
- }
449
- const [item] = this.fields.splice(fromIndex, 1)
450
- this.fields.splice(toIndex, 0, item)
451
- }
452
-
453
- /**
454
- * Creates an association for a given name, adds it to definitions, and returns it.
455
- * @param name The name of the association
456
- * @returns The created association
457
- */
458
- addNamedAssociation(name: string): DataAssociation {
459
- const result = DataAssociation.fromName(this.root, name)
460
- this.root.definitions.associations.push(result)
461
- this.associations.push(result)
462
- this.fields.push({ type: 'association', key: result.key })
463
- return result
464
- }
465
-
466
- /**
467
- * Creates an association for a given target, adds it to definitions, and returns it.
468
- *
469
- * @param target The target entity key of the association
470
- * @param namespace The target entity namespace when different to the current namespace.
471
- * @param name Optional name.
472
- * @returns The created association
473
- */
474
- addTargetAssociation(target: string | DataEntity, name?: string): DataAssociation {
475
- let key: string
476
- if (typeof target === 'string') {
477
- key = target
478
- } else {
479
- key = target.key
480
- }
481
- const result = DataAssociation.fromTarget(this.root, key)
482
- if (name) {
483
- result.info.name = name
484
- }
485
- this.root.definitions.associations.push(result)
486
- this.associations.push(result)
487
- this.fields.push({ type: 'association', key: result.key })
488
- return result
489
- }
490
-
491
- /**
492
- * Creates an association for a given target that is in another namespace
493
- * @param target The target entity key of the association
494
- * @param namespace The target entity namespace when different to the current namespace.
495
- * @param name Optional name.
496
- * @returns The created association
497
- */
498
- addForeignAssociation(target: string | DataEntity, namespace: string, name?: string): DataAssociation {
499
- let key: string
500
- if (typeof target === 'string') {
501
- key = target
502
- } else {
503
- key = target.key
504
- }
505
- if (!this.root.hasForeignNamespace(namespace)) {
506
- throw new ForeignAssociationException(
507
- `Trying to add a foreign association but the foreign namespace is not defined.`
508
- )
509
- }
510
- const result = DataAssociation.fromTarget(this.root, key, namespace)
511
- if (name) {
512
- result.info.name = name
513
- }
514
- this.root.definitions.associations.push(result)
515
- this.associations.push(result)
516
- this.fields.push({ type: 'association', key: result.key })
517
- return result
518
- }
519
-
520
- /**
521
- * Removes an association from the entity and, namespace definitions.
522
- * @param key The key of the association to remove.
523
- */
524
- removeAssociation(key: string): void {
525
- const thisIndex = this.associations.findIndex((i) => i.key === key)
526
- if (thisIndex < 0) {
527
- // return
528
- throw new RemoveAssociationException(`Trying to remove the ${key} association, but it doesn't exist.`)
529
- }
530
- const associationToRemove = this.associations[thisIndex]
531
- this.associations.splice(thisIndex, 1)
532
- const defIndex = this.root.definitions.associations.findIndex((i) => i.key === key)
533
- if (defIndex >= 0) {
534
- this.root.definitions.associations.splice(defIndex, 1)
535
- }
536
- this.removeField(key)
537
- associationToRemove.remove()
538
- }
539
-
540
- /**
541
- * Reads the list of parents for the entity, inside the root namespace. The computed list contains the list of all
542
- * parents in the inheritance chain in no particular order.
543
- * @param recursive Whether to include parent's parents as well.
544
- */
545
- getComputedParents(recursive?: boolean): DataEntity[] {
546
- const { entities } = this.root.definitions
547
- let result: DataEntity[] = []
548
- this.parents.forEach((key) => {
549
- const parent = entities.find((i) => i.key === key)
550
- if (parent) {
551
- result.push(parent)
552
- if (recursive) {
553
- result = result.concat(parent.getComputedParents())
554
- }
555
- }
556
- })
557
- return result
558
- }
559
-
560
- /**
561
- * Computes list of all children, inside the root namespace, that extends this entity.
562
- * The children are not ordered.
563
- */
564
- getComputedChildren(): DataEntity[] {
565
- const { entities } = this.root.definitions
566
- return entities.filter((i) => i.parents.includes(this.key))
567
- }
568
-
569
- /**
570
- * Computes a list of entities that are associated with the current entity.
571
- * This is the association-out (out-edge) direction.
572
- */
573
- getComputedAssociations(): DataEntity[] {
574
- const { associations } = this
575
- const result: DataEntity[] = []
576
- associations.forEach((assoc) => {
577
- if (!assoc.targets.length) {
578
- return
579
- }
580
- const entities = this.root.findAssociatedEntities(assoc.targets)
581
- entities.forEach((entity) => {
582
- if (entity) {
583
- result.push(entity)
584
- }
585
- })
586
- })
587
- return result
588
- }
589
-
590
- /**
591
- * Removes self from the namespace with all properties and attributes.
592
- */
593
- remove(opts: DataDomainRemoveOptions = {}): void {
594
- const { key, properties, associations, root } = this
595
- // check if some entity has reference to this entity as a target
596
- const toEdges = this.root.definitions.associations.filter((a) => a.targets.some((t) => t.key === this.key))
597
- if (toEdges.length > 0) {
598
- const result = toEdges.reduce<{ entity: DataEntity; association: DataAssociation }[]>((acc, association) => {
599
- const entity = root.definitions.entities.find((e) => e.associations.some((a) => a.key === association.key))
600
- if (entity) {
601
- acc.push({ entity, association })
602
- }
603
- return acc
604
- }, [])
605
- if (opts.force) {
606
- // remove the association from the entity
607
- result.forEach(({ entity: item, association }) => {
608
- item.removeAssociation(association.key)
609
- })
610
- } else {
611
- const entitiesNames = result.map(({ entity }) => entity.info.getLabel(entity.key))
612
- throw new RemoveEntityException(
613
- `Cannot remove entity ${this.info.getLabel()} because it is used as a target in associations in entities: ${entitiesNames.join(', ')}.`
614
- )
615
- }
616
- }
617
-
618
- const children = this.getComputedChildren()
619
- if (children.length > 0) {
620
- if (opts.force) {
621
- children.forEach((child) => {
622
- child.parents = child.parents.filter((i) => i !== this.key)
623
- })
624
- } else {
625
- const childrenNames = children.map((i) => i.info.getLabel(i.key))
626
- throw new RemoveEntityException(
627
- `Cannot remove entity ${this.info.getLabel()} because it is a parent for the following entities: ${childrenNames.join(', ')}.`
628
- )
629
- }
630
- }
631
-
632
- // remove own stuff
633
- properties.forEach((p) => this.removeProperty(p.key))
634
- associations.forEach((a) => this.removeAssociation(a.key))
635
- // remove from the root
636
- const index = root.definitions.entities.findIndex((i) => i.key === key)
637
- if (index >= 0) {
638
- root.definitions.entities.splice(index, 1)
639
- }
640
- // remove from the parent
641
- const model = this.getParentInstance()
642
- if (model) {
643
- const entityIndex = model.entities.findIndex((e) => e.key === this.key)
644
- model.entities.splice(entityIndex, 1)
645
- }
646
- }
647
-
648
- /**
649
- * @deprecated Use the `getParentInstance()` method instead.
650
- */
651
- // This method name collides with the `getParents()` method.
652
- getParent(): DataModel | undefined {
653
- return this.getParentInstance()
654
- }
655
-
656
- /**
657
- * Returns a parent data model where this entity exist.
658
- */
659
- getParentInstance(): DataModel | undefined {
660
- return this.root.definitions.models.find((m) => m.entities.some((e) => e.key === this.key))
661
- }
662
-
663
- /**
664
- * Adds a parent reference to this entity.
665
- * This will not add the parent to the namespace. It only adds a reference to the parent.
666
- * @param key The key of the parent entity to add.
667
- * @returns `this` for chaining.
668
- */
669
- addParent(key: string): this {
670
- // Prevent adding self as parent
671
- if (key === this.key) {
672
- const message = 'Entity cannot be a parent of itself.'
673
- throw new ValidationError(
674
- [
675
- {
676
- field: 'parents',
677
- message,
678
- rule: 'circular',
679
- },
680
- ],
681
- { message }
682
- )
683
- }
684
- // check if parent exists
685
- const parent = this.root.definitions.entities.find((i) => i.key === key)
686
- if (!parent) {
687
- const message = `Entity with key "${key}" not found.`
688
- throw new ValidationError(
689
- [
690
- {
691
- field: 'parents',
692
- message,
693
- rule: 'not-exists',
694
- },
695
- ],
696
- { message }
697
- )
698
- }
699
- // Check for circular inheritance
700
- if (this.hasCircularParent(key)) {
701
- const message = `Circular inheritance detected. Cannot add ${key} as a parent.`
702
- throw new ValidationError(
703
- [
704
- {
705
- field: 'parents',
706
- message,
707
- rule: 'circular',
708
- },
709
- ],
710
- { message }
711
- )
712
- }
713
- const has = this.parents.some((i) => i === key)
714
- if (has) {
715
- const message = `Parent ${key} already exists.`
716
- throw new ValidationError(
717
- [
718
- {
719
- field: 'parents',
720
- message,
721
- rule: 'unique',
722
- },
723
- ],
724
- { message }
725
- )
726
- }
727
- this.parents.push(key)
728
- return this
729
- }
730
-
731
- /**
732
- * Removes a parent reference from this entity.
733
- * It keeps the parent as is.
734
- *
735
- * @param key The key of the parent entity to remove.
736
- * @throws ValidationError when the parent is not found.
737
- * @returns Self for chaining.
738
- */
739
- removeParent(key: string): this {
740
- const index = this.parents.findIndex((i) => i === key)
741
- if (index < 0) {
742
- const message = `Parent ${key} not found.`
743
- throw new ValidationError(
744
- [
745
- {
746
- field: 'parents',
747
- message,
748
- rule: 'not-found',
749
- },
750
- ],
751
- { message }
752
- )
753
- }
754
- this.parents.splice(index, 1)
755
- return this
756
- }
757
-
758
- /**
759
- * Checks if the entity has a circular parent relationship when attempting to add a new parent.
760
- * @param key The key of the parent being added.
761
- * @returns true if adding this parent would create a circular relationship.
762
- */
763
- hasCircularParent(key: string): boolean {
764
- const { entities } = this.root.definitions
765
- // Check if new parent is one of the children.
766
- const children = this.getComputedChildren()
767
- if (children.some((c) => c.key === key)) {
768
- return true
769
- }
770
- // check if this entity is in parents chain.
771
- let current: DataEntity | undefined = entities.find((e) => e.key === key)
772
- while (current) {
773
- if (current.key === this.key) {
774
- return true
775
- }
776
- // for (const parentKey of current.parents) {
777
- // current = parentKey ? entities.find((e) => e.key === parentKey) : undefined
778
- // }
779
- const parentKey = current.parents[0] // Assuming single inheritance
780
- current = parentKey ? entities.find((e) => e.key === parentKey) : undefined
781
- }
782
- return false
783
- }
784
-
785
- /**
786
- * Tests whether one entity is associated with another.
787
- *
788
- * @param entity1 The source entity
789
- * @param entity2 The target entity
790
- * @returns true when there's any path from one entity to another.
791
- */
792
- static isAssociated(entity1: DataEntity, entity2: DataEntity): boolean {
793
- return entity1.isAssociated(entity2.key)
794
- }
795
-
796
- /**
797
- * Tests whether this entity is somehow associated with another entity.
798
- * @param target The key of the target entity to test for association with.
799
- * @returns true if this entity has any association to the `target` entity.
800
- */
801
- isAssociated(target: string): boolean {
802
- const it = this.associationPath(target)
803
- const path = it.next().value
804
- return !!path
805
- }
806
-
807
- /**
808
- * Prints out all associations from one entity to another through all entities that may be in between.
809
- * @param toEntity The key to the target entity
810
- * @yields The path containing keys of entities from this entity to the `toEntity`
811
- * (inclusive) and all entities in between.
812
- */
813
- *associationPath(toEntity: string): Generator<string[]> {
814
- const graph = this.root.associationGraph()
815
- for (const path of this.root.associationPath(this.key, toEntity, graph)) {
816
- yield path
817
- }
818
- }
819
-
820
- /**
821
- * Returns a list of entities that are associated with this entity as a target.
822
- *
823
- * This method identifies entities that have an association where this entity is a target.
824
- * In other words, it finds entities that "point to" this entity through an association.
825
- *
826
- * For example, consider the following relationships:
827
- *
828
- * ```plain
829
- * A -> B (A has an association that targets B)
830
- * C -> B (C has an association that targets B)
831
- * B -> D (B has an association that targets D)
832
- *
833
- * Calling `getRelatedEntities()` on B would return [A, C]
834
- * Calling `getRelatedEntities()` on D would return [B]
835
- * Calling `getRelatedEntities()` on A would return []
836
- * ```
837
- *
838
- * Note, this method only returns entities that are directly associated with this entity as a target.
839
- * It does not traverse the association graph to find indirectly related entities.
840
- *
841
- * @returns An array of `DataEntity` instances that have an association targeting this entity.
842
- */
843
- getRelatedEntities(): DataEntity[] {
844
- const { key, root } = this
845
- const result = DataEntity.getRelatedEntities(root, key)
846
- root.foreign.forEach((ns) => {
847
- const other = DataEntity.getRelatedEntities(ns, key)
848
- other.forEach((entity) => {
849
- if (!result.includes(entity)) {
850
- result.push(entity)
851
- }
852
- })
853
- })
854
- return result
855
- }
856
-
857
- static getRelatedEntities(namespace: DataNamespace, entityKey: string): DataEntity[] {
858
- const result: DataEntity[] = []
859
- const inverse = namespace.definitions.associations.filter((i) => i.targets.some((j) => j.key === entityKey))
860
- inverse.forEach((assoc) => {
861
- const entity = namespace.definitions.entities.find((e) => e.associations.includes(assoc))
862
- if (entity && !result.includes(entity)) {
863
- result.push(entity)
864
- }
865
- })
866
- return result
867
- }
868
-
869
- /**
870
- * Creates breadcrumbs from this entity to the root namespace.
871
- */
872
- breadcrumbs(): FileBreadcrumb[] {
873
- const result: FileBreadcrumb[] = []
874
- result.push({
875
- key: this.key,
876
- name: this.info.getLabel('Unnamed entity'),
877
- kind: DataEntityKind,
878
- })
879
- const model = this.getParentInstance()
880
- if (model) {
881
- result.push({
882
- key: model.key,
883
- kind: model.kind,
884
- name: model.info.getLabel('Unnamed model'),
885
- })
886
- let parent = model.getParentInstance()
887
- while (parent && parent !== this.root) {
888
- result.push({
889
- key: parent.key,
890
- kind: parent.kind,
891
- name: parent.info.getLabel('Unnamed namespace'),
892
- })
893
- parent = parent.getParentInstance()
894
- }
895
- }
896
- result.push({
897
- key: this.root.key,
898
- name: this.root.info.getLabel('Unnamed data domain'),
899
- kind: this.root.kind,
900
- })
901
- return result.reverse()
902
- }
903
-
904
- /**
905
- * Adds a new tag to the property. It also populates the root namespace's tags when tag is new.
906
- *
907
- * Note, it does nothing when the tag is already defined.
908
- *
909
- * @param tag The tag to add.
910
- */
911
- addTag(tag: string): void {
912
- if (!tag) {
913
- return
914
- }
915
- const lower = tag.toLowerCase()
916
- const { tags } = this
917
- if (tags.some((t) => t.toLowerCase() === lower)) {
918
- return
919
- }
920
- tags.push(tag)
921
- const { definitions } = this.root
922
- if (!definitions.tags.some((t) => t.toLowerCase() === lower)) {
923
- definitions.tags.push(tag)
924
- }
925
- }
926
-
927
- /**
928
- * Removes a tag from the property. Unlike the `addTag()` this won't remove a `tag` from the root namespace.
929
- *
930
- * @param tag The tag to remove.
931
- */
932
- removeTag(tag: string): void {
933
- if (!tag) {
934
- return
935
- }
936
- const lower = tag.toLowerCase()
937
- const { tags } = this
938
- const index = tags.findIndex((t) => t.toLowerCase() === lower)
939
- if (index >= 0) {
940
- tags.splice(index, 1)
941
- }
942
- }
943
-
944
- /**
945
- * Creates a Shape of AMF.
946
- * The property itself is auto-generated. If the `schema` is defined then it is used
947
- * as the `range` of the property. Otherwise basic shape is generated for the range.
948
- *
949
- * This is a preferred way of reading the AMF shape as this synchronizes changed
950
- * data properties with the shape definition.
951
- *
952
- * @returns AMF property shape definition.
953
- */
954
- toApiShape(): IShapeUnion {
955
- const serializer = new AmfShapeGenerator()
956
- return serializer.entity(this)
957
- }
958
-
959
- /**
960
- * Reads the schema of the Entity and generates an example for it.
961
- */
962
- toExample(mime: string, opts: IShapeRenderOptions = {}): string | number | boolean | null | undefined {
963
- const shape = this.toApiShape()
964
- const generator = new ApiSchemaGenerator(mime, {
965
- renderExamples: typeof opts.renderExamples === 'boolean' ? opts.renderExamples : true,
966
- renderMocked: typeof opts.renderMocked === 'boolean' ? opts.renderMocked : true,
967
- renderOptional: typeof opts.renderOptional === 'boolean' ? opts.renderOptional : true,
968
- selectedUnions: opts.selectedUnions,
969
- })
970
- return generator.generate(shape)
971
- }
972
-
973
- hasClosedCycle(rootEntity: string, targetEntity: string): boolean {
974
- if (targetEntity === this.key) {
975
- // self association
976
- return true
977
- }
978
- const g = this.root.associationGraph()
979
- const selfPaths: string[][] = []
980
- const targetPaths: string[][] = []
981
- for (const path of this.root.associationPath(rootEntity, this.key, g)) {
982
- selfPaths.push(path)
983
- }
984
- for (const path of this.root.associationPath(targetEntity, this.key, g)) {
985
- targetPaths.push(path)
986
- }
987
- const checker = (arr: string[], target: string[]): boolean => target.every((v) => arr.includes(v))
988
- for (const sp of selfPaths) {
989
- for (const tp of targetPaths) {
990
- const result = checker(sp, tp)
991
- if (result) {
992
- return result
993
- }
994
- }
995
- }
996
- return false
997
- }
998
-
999
- /**
1000
- * Checks whether the entity is a child of the given namespace or data model.
1001
- * The relationship doesn't have to be direct, as long as the entity is in the hierarchy it will return true.
1002
- *
1003
- * @param key The key of the parent to check.
1004
- * @returns True if this entity is a child of the given namespace or data model.
1005
- */
1006
- isChildOf(key: string): boolean {
1007
- if (this.key === key) {
1008
- return false
1009
- }
1010
- const parent = this.getParentInstance()
1011
- if (!parent) {
1012
- return false
1013
- }
1014
- if (parent.key === key) {
1015
- return true
1016
- }
1017
- return parent.isChildOf(key)
1018
- }
1019
- }