@api-client/core 0.11.11 → 0.12.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 (338) hide show
  1. package/Testing.md +1 -1
  2. package/bin/plugins/events/EventPlugin.ts +61 -0
  3. package/bin/plugins/events/assert.ts +193 -0
  4. package/bin/plugins/events/types.ts +6 -0
  5. package/bin/test.ts +8 -1
  6. package/build/src/amf/AmfShapeGenerator.d.ts +6 -3
  7. package/build/src/amf/AmfShapeGenerator.d.ts.map +1 -1
  8. package/build/src/amf/AmfShapeGenerator.js +7 -4
  9. package/build/src/amf/AmfShapeGenerator.js.map +1 -1
  10. package/build/src/amf/AmfTypes.d.ts +2 -2
  11. package/build/src/amf/AmfTypes.d.ts.map +1 -1
  12. package/build/src/amf/AmfTypes.js.map +1 -1
  13. package/build/src/amf/DataValueGenerator.d.ts +15 -15
  14. package/build/src/amf/DataValueGenerator.d.ts.map +1 -1
  15. package/build/src/amf/DataValueGenerator.js +17 -16
  16. package/build/src/amf/DataValueGenerator.js.map +1 -1
  17. package/build/src/amf/models/AmfDataNode.d.ts.map +1 -1
  18. package/build/src/amf/models/AmfDataNode.js +2 -2
  19. package/build/src/amf/models/AmfDataNode.js.map +1 -1
  20. package/build/src/browser.d.ts +12 -9
  21. package/build/src/browser.d.ts.map +1 -1
  22. package/build/src/browser.js +11 -8
  23. package/build/src/browser.js.map +1 -1
  24. package/build/src/exceptions/attach_exception.d.ts +11 -0
  25. package/build/src/exceptions/attach_exception.d.ts.map +1 -0
  26. package/build/src/exceptions/attach_exception.js +11 -0
  27. package/build/src/exceptions/attach_exception.js.map +1 -0
  28. package/build/src/exceptions/detach_exception.d.ts +11 -0
  29. package/build/src/exceptions/detach_exception.d.ts.map +1 -0
  30. package/build/src/exceptions/detach_exception.js +11 -0
  31. package/build/src/exceptions/detach_exception.js.map +1 -0
  32. package/build/src/exceptions/remove_model_exception.d.ts +8 -0
  33. package/build/src/exceptions/remove_model_exception.d.ts.map +1 -0
  34. package/build/src/exceptions/remove_model_exception.js +8 -0
  35. package/build/src/exceptions/remove_model_exception.js.map +1 -0
  36. package/build/src/exceptions/remove_namespace_exception.d.ts +8 -0
  37. package/build/src/exceptions/remove_namespace_exception.d.ts.map +1 -0
  38. package/build/src/exceptions/remove_namespace_exception.js +8 -0
  39. package/build/src/exceptions/remove_namespace_exception.js.map +1 -0
  40. package/build/src/index.d.ts +12 -9
  41. package/build/src/index.d.ts.map +1 -1
  42. package/build/src/index.js +11 -8
  43. package/build/src/index.js.map +1 -1
  44. package/build/src/legacy.d.ts +8 -0
  45. package/build/src/legacy.d.ts.map +1 -1
  46. package/build/src/legacy.js +9 -0
  47. package/build/src/legacy.js.map +1 -1
  48. package/build/src/lib/uuid.d.ts +1 -1
  49. package/build/src/lib/uuid.js +1 -1
  50. package/build/src/lib/uuid.js.map +1 -1
  51. package/build/src/mocking/lib/History.js +8 -8
  52. package/build/src/mocking/lib/History.js.map +1 -1
  53. package/build/src/mocking/lib/HostRules.js +1 -1
  54. package/build/src/mocking/lib/HostRules.js.map +1 -1
  55. package/build/src/mocking/lib/User.js +2 -2
  56. package/build/src/mocking/lib/User.js.map +1 -1
  57. package/build/src/modeling/Bindings.d.ts +2 -2
  58. package/build/src/modeling/Bindings.d.ts.map +1 -1
  59. package/build/src/modeling/Bindings.js.map +1 -1
  60. package/build/src/modeling/DataDomain.d.ts +601 -0
  61. package/build/src/modeling/DataDomain.d.ts.map +1 -0
  62. package/build/src/modeling/DataDomain.js +1141 -0
  63. package/build/src/modeling/DataDomain.js.map +1 -0
  64. package/build/src/modeling/DataFormat.d.ts +42 -41
  65. package/build/src/modeling/DataFormat.d.ts.map +1 -1
  66. package/build/src/modeling/DataFormat.js +30 -131
  67. package/build/src/modeling/DataFormat.js.map +1 -1
  68. package/build/src/modeling/DomainAssociation.d.ts +281 -0
  69. package/build/src/modeling/DomainAssociation.d.ts.map +1 -0
  70. package/build/src/modeling/DomainAssociation.js +440 -0
  71. package/build/src/modeling/DomainAssociation.js.map +1 -0
  72. package/build/src/modeling/DomainElement.d.ts +33 -0
  73. package/build/src/modeling/DomainElement.d.ts.map +1 -0
  74. package/build/src/modeling/DomainElement.js +32 -0
  75. package/build/src/modeling/DomainElement.js.map +1 -0
  76. package/build/src/modeling/DomainEntity.d.ts +383 -0
  77. package/build/src/modeling/DomainEntity.d.ts.map +1 -0
  78. package/build/src/modeling/DomainEntity.js +718 -0
  79. package/build/src/modeling/DomainEntity.js.map +1 -0
  80. package/build/src/modeling/DomainFile.d.ts +25 -0
  81. package/build/src/modeling/DomainFile.d.ts.map +1 -0
  82. package/build/src/modeling/DomainFile.js +86 -0
  83. package/build/src/modeling/DomainFile.js.map +1 -0
  84. package/build/src/modeling/DomainImpactAnalysis.d.ts +60 -47
  85. package/build/src/modeling/DomainImpactAnalysis.d.ts.map +1 -1
  86. package/build/src/modeling/DomainImpactAnalysis.js +201 -132
  87. package/build/src/modeling/DomainImpactAnalysis.js.map +1 -1
  88. package/build/src/modeling/DomainModel.d.ts +226 -0
  89. package/build/src/modeling/DomainModel.d.ts.map +1 -0
  90. package/build/src/modeling/DomainModel.js +401 -0
  91. package/build/src/modeling/DomainModel.js.map +1 -0
  92. package/build/src/modeling/DomainNamespace.d.ts +268 -0
  93. package/build/src/modeling/DomainNamespace.d.ts.map +1 -0
  94. package/build/src/modeling/DomainNamespace.js +512 -0
  95. package/build/src/modeling/DomainNamespace.js.map +1 -0
  96. package/build/src/modeling/DomainProperty.d.ts +281 -0
  97. package/build/src/modeling/DomainProperty.d.ts.map +1 -0
  98. package/build/src/modeling/DomainProperty.js +560 -0
  99. package/build/src/modeling/DomainProperty.js.map +1 -0
  100. package/build/src/modeling/DomainSerialization.d.ts +40 -0
  101. package/build/src/modeling/DomainSerialization.d.ts.map +1 -0
  102. package/build/src/modeling/DomainSerialization.js +288 -0
  103. package/build/src/modeling/DomainSerialization.js.map +1 -0
  104. package/build/src/modeling/DomainVersioning.d.ts +17 -0
  105. package/build/src/modeling/DomainVersioning.d.ts.map +1 -0
  106. package/build/src/modeling/DomainVersioning.js +124 -0
  107. package/build/src/modeling/DomainVersioning.js.map +1 -0
  108. package/build/src/modeling/GraphUtils.d.ts +8 -0
  109. package/build/src/modeling/GraphUtils.d.ts.map +1 -0
  110. package/build/src/modeling/GraphUtils.js +26 -0
  111. package/build/src/modeling/GraphUtils.js.map +1 -0
  112. package/build/src/modeling/amf/ShapeGenerator.d.ts +164 -0
  113. package/build/src/modeling/amf/ShapeGenerator.d.ts.map +1 -0
  114. package/build/src/modeling/amf/ShapeGenerator.js +492 -0
  115. package/build/src/modeling/amf/ShapeGenerator.js.map +1 -0
  116. package/build/src/modeling/{DataAssociation.d.ts → legacy/DataAssociation.d.ts} +10 -5
  117. package/build/src/modeling/legacy/DataAssociation.d.ts.map +1 -0
  118. package/build/src/modeling/{DataAssociation.js → legacy/DataAssociation.js} +11 -8
  119. package/build/src/modeling/legacy/DataAssociation.js.map +1 -0
  120. package/build/src/modeling/{DataEntity.d.ts → legacy/DataEntity.d.ts} +12 -7
  121. package/build/src/modeling/legacy/DataEntity.d.ts.map +1 -0
  122. package/build/src/modeling/{DataEntity.js → legacy/DataEntity.js} +21 -20
  123. package/build/src/modeling/legacy/DataEntity.js.map +1 -0
  124. package/build/src/modeling/{DataEntityBuilder.d.ts → legacy/DataEntityBuilder.d.ts} +3 -2
  125. package/build/src/modeling/legacy/DataEntityBuilder.d.ts.map +1 -0
  126. package/build/src/modeling/{DataEntityBuilder.js → legacy/DataEntityBuilder.js} +4 -3
  127. package/build/src/modeling/legacy/DataEntityBuilder.js.map +1 -0
  128. package/build/src/modeling/legacy/DataImpactAnalysis.d.ts +298 -0
  129. package/build/src/modeling/legacy/DataImpactAnalysis.d.ts.map +1 -0
  130. package/build/src/modeling/legacy/DataImpactAnalysis.js +441 -0
  131. package/build/src/modeling/legacy/DataImpactAnalysis.js.map +1 -0
  132. package/build/src/modeling/{DataModel.d.ts → legacy/DataModel.d.ts} +6 -4
  133. package/build/src/modeling/legacy/DataModel.d.ts.map +1 -0
  134. package/build/src/modeling/{DataModel.js → legacy/DataModel.js} +9 -8
  135. package/build/src/modeling/legacy/DataModel.js.map +1 -0
  136. package/build/src/modeling/{DataNamespace.d.ts → legacy/DataNamespace.d.ts} +22 -3
  137. package/build/src/modeling/legacy/DataNamespace.d.ts.map +1 -0
  138. package/build/src/modeling/{DataNamespace.js → legacy/DataNamespace.js} +9 -5
  139. package/build/src/modeling/legacy/DataNamespace.js.map +1 -0
  140. package/build/src/modeling/{DataProperty.d.ts → legacy/DataProperty.d.ts} +13 -5
  141. package/build/src/modeling/legacy/DataProperty.d.ts.map +1 -0
  142. package/build/src/modeling/{DataProperty.js → legacy/DataProperty.js} +10 -7
  143. package/build/src/modeling/legacy/DataProperty.js.map +1 -0
  144. package/build/src/modeling/observed.d.ts +67 -0
  145. package/build/src/modeling/observed.d.ts.map +1 -0
  146. package/build/src/modeling/observed.js +230 -0
  147. package/build/src/modeling/observed.js.map +1 -0
  148. package/build/src/modeling/types.d.ts +165 -1
  149. package/build/src/modeling/types.d.ts.map +1 -1
  150. package/build/src/modeling/types.js.map +1 -1
  151. package/build/src/models/AuthorizationData.js +3 -3
  152. package/build/src/models/AuthorizationData.js.map +1 -1
  153. package/build/src/models/CertificateFile.js +2 -2
  154. package/build/src/models/CertificateFile.js.map +1 -1
  155. package/build/src/models/ClientCertificate.js +5 -5
  156. package/build/src/models/ClientCertificate.js.map +1 -1
  157. package/build/src/models/Environment.js +6 -6
  158. package/build/src/models/Environment.js.map +1 -1
  159. package/build/src/models/Folder.js +2 -2
  160. package/build/src/models/Folder.js.map +1 -1
  161. package/build/src/models/HostRule.js +4 -4
  162. package/build/src/models/HostRule.js.map +1 -1
  163. package/build/src/models/HttpProject.js +12 -12
  164. package/build/src/models/HttpProject.js.map +1 -1
  165. package/build/src/models/Project.d.ts.map +1 -1
  166. package/build/src/models/Project.js +2 -2
  167. package/build/src/models/Project.js.map +1 -1
  168. package/build/src/models/ProjectFolder.d.ts.map +1 -1
  169. package/build/src/models/ProjectFolder.js +6 -6
  170. package/build/src/models/ProjectFolder.js.map +1 -1
  171. package/build/src/models/ProjectRequest.d.ts.map +1 -1
  172. package/build/src/models/ProjectRequest.js +8 -8
  173. package/build/src/models/ProjectRequest.js.map +1 -1
  174. package/build/src/models/ProjectSchema.js +6 -6
  175. package/build/src/models/ProjectSchema.js.map +1 -1
  176. package/build/src/models/Thing.d.ts +26 -5
  177. package/build/src/models/Thing.d.ts.map +1 -1
  178. package/build/src/models/Thing.js +193 -91
  179. package/build/src/models/Thing.js.map +1 -1
  180. package/build/src/models/kinds.d.ts +31 -6
  181. package/build/src/models/kinds.d.ts.map +1 -1
  182. package/build/src/models/kinds.js +31 -6
  183. package/build/src/models/kinds.js.map +1 -1
  184. package/build/src/models/store/DataFile.d.ts +3 -1
  185. package/build/src/models/store/DataFile.d.ts.map +1 -1
  186. package/build/src/models/store/DataFile.js +4 -2
  187. package/build/src/models/store/DataFile.js.map +1 -1
  188. package/build/src/models/store/File.d.ts.map +1 -1
  189. package/build/src/models/store/File.js +3 -3
  190. package/build/src/models/store/File.js.map +1 -1
  191. package/build/src/models/store/Organization.js +3 -3
  192. package/build/src/models/store/Organization.js.map +1 -1
  193. package/build/src/models/store/Permission.js +7 -7
  194. package/build/src/models/store/Permission.js.map +1 -1
  195. package/build/src/models/store/UserIdentity.js +3 -3
  196. package/build/src/models/store/UserIdentity.js.map +1 -1
  197. package/build/src/models/transformers/ArcDexieTransformer.js +4 -4
  198. package/build/src/models/transformers/ArcDexieTransformer.js.map +1 -1
  199. package/build/src/models/transformers/ArcLegacyTransformer.js +3 -3
  200. package/build/src/models/transformers/ArcLegacyTransformer.js.map +1 -1
  201. package/build/src/models/transformers/ArcPouchTransformer.js +2 -2
  202. package/build/src/models/transformers/ArcPouchTransformer.js.map +1 -1
  203. package/build/src/models/transformers/PostmanV21Transformer.js +2 -2
  204. package/build/src/models/transformers/PostmanV21Transformer.js.map +1 -1
  205. package/build/src/models/transformers/PostmanV2Transformer.js +2 -2
  206. package/build/src/models/transformers/PostmanV2Transformer.js.map +1 -1
  207. package/build/src/models/types.d.ts +12 -0
  208. package/build/src/models/types.d.ts.map +1 -0
  209. package/build/src/models/types.js +2 -0
  210. package/build/src/models/types.js.map +1 -0
  211. package/build/src/patch/PatchClient.js +2 -2
  212. package/build/src/patch/PatchClient.js.map +1 -1
  213. package/build/src/runtime/store/FilesSdk.d.ts +2 -2
  214. package/build/src/runtime/store/FilesSdk.d.ts.map +1 -1
  215. package/build/src/runtime/store/FilesSdk.js +3 -3
  216. package/build/src/runtime/store/FilesSdk.js.map +1 -1
  217. package/data/models/example-generator-api.json +8 -8
  218. package/package.json +20 -6
  219. package/readme.md +1 -1
  220. package/src/amf/AmfShapeGenerator.ts +10 -7
  221. package/src/amf/AmfTypes.ts +2 -2
  222. package/src/amf/DataValueGenerator.ts +24 -23
  223. package/src/amf/models/AmfDataNode.ts +2 -2
  224. package/src/exceptions/attach_exception.ts +11 -0
  225. package/src/exceptions/detach_exception.ts +11 -0
  226. package/src/exceptions/remove_model_exception.ts +8 -0
  227. package/src/exceptions/remove_namespace_exception.ts +8 -0
  228. package/src/lib/uuid.ts +1 -1
  229. package/src/mocking/lib/History.ts +8 -8
  230. package/src/mocking/lib/HostRules.ts +1 -1
  231. package/src/mocking/lib/User.ts +2 -2
  232. package/src/modeling/Bindings.ts +2 -2
  233. package/src/modeling/DataDomain.ts +1220 -0
  234. package/src/modeling/DataFormat.ts +54 -163
  235. package/src/modeling/DomainAssociation.ts +476 -0
  236. package/src/modeling/DomainElement.ts +50 -0
  237. package/src/modeling/DomainEntity.ts +769 -0
  238. package/src/modeling/DomainFile.ts +94 -0
  239. package/src/modeling/DomainImpactAnalysis.ts +218 -144
  240. package/src/modeling/DomainModel.ts +421 -0
  241. package/src/modeling/DomainNamespace.ts +537 -0
  242. package/src/modeling/DomainProperty.ts +548 -0
  243. package/src/modeling/DomainSerialization.ts +312 -0
  244. package/src/modeling/DomainVersioning.ts +144 -0
  245. package/src/modeling/GraphUtils.ts +28 -0
  246. package/src/modeling/amf/ShapeGenerator.ts +552 -0
  247. package/src/modeling/graph.md +115 -0
  248. package/src/modeling/{DataAssociation.ts → legacy/DataAssociation.ts} +15 -10
  249. package/src/modeling/{DataEntity.ts → legacy/DataEntity.ts} +30 -25
  250. package/src/modeling/{DataEntityBuilder.ts → legacy/DataEntityBuilder.ts} +5 -4
  251. package/src/modeling/legacy/DataImpactAnalysis.ts +530 -0
  252. package/src/modeling/{DataModel.ts → legacy/DataModel.ts} +12 -10
  253. package/src/modeling/{DataNamespace.ts → legacy/DataNamespace.ts} +25 -7
  254. package/src/modeling/{DataProperty.ts → legacy/DataProperty.ts} +17 -9
  255. package/src/modeling/observed.ts +267 -0
  256. package/src/modeling/types.ts +174 -1
  257. package/src/models/AuthorizationData.ts +3 -3
  258. package/src/models/CertificateFile.ts +2 -2
  259. package/src/models/ClientCertificate.ts +5 -5
  260. package/src/models/Environment.ts +6 -6
  261. package/src/models/Folder.ts +2 -2
  262. package/src/models/HostRule.ts +4 -4
  263. package/src/models/HttpProject.ts +12 -12
  264. package/src/models/Project.ts +2 -2
  265. package/src/models/ProjectFolder.ts +6 -6
  266. package/src/models/ProjectRequest.ts +8 -8
  267. package/src/models/ProjectSchema.ts +6 -6
  268. package/src/models/Thing.ts +70 -5
  269. package/src/models/kinds.ts +32 -6
  270. package/src/models/store/DataFile.ts +5 -3
  271. package/src/models/store/File.ts +3 -3
  272. package/src/models/store/Organization.ts +3 -3
  273. package/src/models/store/Permission.ts +7 -7
  274. package/src/models/store/UserIdentity.ts +3 -3
  275. package/src/models/transformers/ArcDexieTransformer.ts +4 -4
  276. package/src/models/transformers/ArcLegacyTransformer.ts +3 -3
  277. package/src/models/transformers/ArcPouchTransformer.ts +2 -2
  278. package/src/models/transformers/PostmanV21Transformer.ts +2 -2
  279. package/src/models/transformers/PostmanV2Transformer.ts +2 -2
  280. package/src/models/types.ts +11 -0
  281. package/src/patch/PatchClient.ts +2 -2
  282. package/src/runtime/store/FilesSdk.ts +5 -5
  283. package/tests/unit/amf/data_value_generator.spec.ts +15 -15
  284. package/tests/unit/legacy-transformers/ARC-legacy-import.spec.ts +1 -1
  285. package/tests/unit/modeling/amf/shape_generator.spec.ts +1174 -0
  286. package/tests/unit/modeling/data_domain.spec.ts +444 -0
  287. package/tests/unit/modeling/data_domain_associations.spec.ts +279 -0
  288. package/tests/unit/modeling/data_domain_change_observers.spec.ts +681 -0
  289. package/tests/unit/modeling/data_domain_entities.spec.ts +449 -0
  290. package/tests/unit/modeling/data_domain_foreign.spec.ts +355 -0
  291. package/tests/unit/modeling/data_domain_models.spec.ts +658 -0
  292. package/tests/unit/modeling/data_domain_namespaces.spec.ts +668 -0
  293. package/tests/unit/modeling/data_domain_property.spec.ts +264 -0
  294. package/tests/unit/modeling/data_domain_serialization.spec.ts +294 -0
  295. package/tests/unit/modeling/domain.property.spec.ts +822 -0
  296. package/tests/unit/modeling/domain_asociation.spec.ts +643 -0
  297. package/tests/unit/modeling/domain_asociation_targets.spec.ts +350 -0
  298. package/tests/unit/modeling/domain_entity.spec.ts +730 -0
  299. package/tests/unit/modeling/domain_entity_associations.spec.ts +330 -0
  300. package/tests/unit/modeling/domain_entity_example_generator_json.spec.ts +988 -0
  301. package/tests/unit/modeling/domain_entity_example_generator_xml.spec.ts +1451 -0
  302. package/tests/unit/modeling/domain_entity_fields.spec.ts +113 -0
  303. package/tests/unit/modeling/domain_entity_generators.spec.ts +20 -0
  304. package/tests/unit/modeling/domain_entity_parents.spec.ts +291 -0
  305. package/tests/unit/modeling/domain_entity_properties.spec.ts +305 -0
  306. package/tests/unit/modeling/{data_file.spec.ts → domain_file.spec.ts} +29 -85
  307. package/tests/unit/modeling/domain_impact_analysis.spec.ts +452 -0
  308. package/tests/unit/modeling/domain_model.spec.ts +568 -0
  309. package/tests/unit/modeling/domain_model_entities.spec.ts +408 -0
  310. package/tests/unit/modeling/domain_namespace.spec.ts +514 -0
  311. package/tests/unit/modeling/domain_namespace_models.spec.ts +324 -0
  312. package/tests/unit/modeling/domain_namespace_namespaces.spec.ts +404 -0
  313. package/tests/unit/modeling/domain_versioning.spec.ts +140 -0
  314. package/tests/unit/{amf → modeling/legacy}/amf_shape_generator.spec.ts +11 -11
  315. package/tests/unit/modeling/{data_association.spec.ts → legacy/data_association.spec.ts} +3 -11
  316. package/tests/unit/modeling/{data_entity.spec.ts → legacy/data_entity.spec.ts} +10 -8
  317. package/tests/unit/modeling/{data_entity_generator_json.spec.ts → legacy/data_entity_generator_json.spec.ts} +1 -1
  318. package/tests/unit/modeling/{data_entity_generator_xml.spec.ts → legacy/data_entity_generator_xml.spec.ts} +1 -1
  319. package/tests/unit/modeling/{data_model.spec.ts → legacy/data_model.spec.ts} +3 -3
  320. package/tests/unit/modeling/{data_namespace.spec.ts → legacy/data_namespace.spec.ts} +3 -10
  321. package/tests/unit/modeling/{data_property.spec.ts → legacy/data_property.spec.ts} +3 -6
  322. package/tests/unit/modeling/{impact_analysis.spec.ts → legacy/impact_analysis.spec.ts} +9 -9
  323. package/tests/unit/models/File/new.spec.ts +1 -1
  324. package/tests/unit/models/HttpProject.spec.ts +3 -3
  325. package/tests/unit/runtime/proxy/HttpProjectProxy.spec.ts +8 -8
  326. package/tsconfig.node.json +35 -0
  327. package/build/src/modeling/DataAssociation.d.ts.map +0 -1
  328. package/build/src/modeling/DataAssociation.js.map +0 -1
  329. package/build/src/modeling/DataEntity.d.ts.map +0 -1
  330. package/build/src/modeling/DataEntity.js.map +0 -1
  331. package/build/src/modeling/DataEntityBuilder.d.ts.map +0 -1
  332. package/build/src/modeling/DataEntityBuilder.js.map +0 -1
  333. package/build/src/modeling/DataModel.d.ts.map +0 -1
  334. package/build/src/modeling/DataModel.js.map +0 -1
  335. package/build/src/modeling/DataNamespace.d.ts.map +0 -1
  336. package/build/src/modeling/DataNamespace.js.map +0 -1
  337. package/build/src/modeling/DataProperty.d.ts.map +0 -1
  338. package/build/src/modeling/DataProperty.js.map +0 -1
@@ -0,0 +1,1220 @@
1
+ import { nanoid } from 'nanoid'
2
+ import { Graph } from '@api-client/graph'
3
+ import {
4
+ DomainAssociationKind,
5
+ DataDomainKind,
6
+ DomainEntityKind,
7
+ DomainModelKind,
8
+ DomainNamespaceKind,
9
+ DomainPropertyKind,
10
+ } from '../models/kinds.js'
11
+ import type {
12
+ AssociationAddOptions,
13
+ DomainGraphEdge,
14
+ DomainGraphNodeType,
15
+ ForeignDomainDependency,
16
+ SerializedGraph,
17
+ } from './types.js'
18
+ import { type DomainNamespaceSchema, DomainNamespace, type NamespaceOrderedItem } from './DomainNamespace.js'
19
+ import { type DomainModelSchema, DomainModel } from './DomainModel.js'
20
+ import { type DomainEntitySchema, DomainEntity } from './DomainEntity.js'
21
+ import { DomainAssociation } from './DomainAssociation.js'
22
+ import { DomainProperty, DomainPropertySchema } from './DomainProperty.js'
23
+ import { type IThing, Thing } from '../models/Thing.js'
24
+ import { removeGraphNode } from './GraphUtils.js'
25
+ import { serialize, deserialize, mergeGraph, removeForeignGraph } from './DomainSerialization.js'
26
+
27
+ export interface DataDomainSchema {
28
+ info: IThing
29
+ kind: typeof DataDomainKind
30
+ key: string
31
+ graph?: SerializedGraph
32
+ dependencyList?: ForeignDomainDependency[]
33
+ /**
34
+ * The ordered list of fields (namespace and models) in the schema.
35
+ * These only keep references to define the order of these properties
36
+ * in the schema as graph won't do it.
37
+ */
38
+ fields?: NamespaceOrderedItem[]
39
+ }
40
+
41
+ /**
42
+ * Represents the root of a data domain model.
43
+ *
44
+ * The `DataDomain` class serves as the top-level container
45
+ * for a collection of data models, namespaces, entities,
46
+ * properties, and associations. It provides methods for
47
+ * managing and manipulating these data elements, enabling
48
+ * the creation of complex and interconnected data
49
+ * structures.
50
+ *
51
+ * **Key Features:**
52
+ *
53
+ * - **Root Container:** Holds all data elements within a domain.
54
+ * - **Graph-Based Structure:** Uses a graph to represent relationships between data elements.
55
+ * - **Namespace Management:** Supports creating and managing namespaces to organize data models.
56
+ * - **Data Model Management:** Supports creating and managing data models to group entities.
57
+ * - **Entity Management:** Supports creating and managing entities, which define the structure of data.
58
+ * - **Property Management:** Supports creating and managing properties, which define the data elements
59
+ * within entities.
60
+ * - **Association Management:** Supports creating and managing associations, which define relationships
61
+ * between entities.
62
+ * - **Foreign Domain Support:** Allows registering and integrating data from external domains.
63
+ * - **Change Notification:** Notifies listeners when changes occur within the data domain.
64
+ *
65
+ * **Usage:**
66
+ *
67
+ * 1. Create an instance of the `DataDomain`.
68
+ * 2. Use methods like `addNamespace()`, `addModel()`,
69
+ * `addEntity()`, `addProperty()`, and `addAssociation()`
70
+ * to build the data domain structure.
71
+ * 3. Use methods like `findNamespace()`, `findModel()`,
72
+ * `findEntity()`, `findProperty()`, and
73
+ * `findAssociation()` to retrieve data elements.
74
+ * 4. Use methods like `listNamespaces()`, `listGraphNamespaces()`, `listModels()`,
75
+ * and `listEntities()` to iterate over collections of
76
+ * data elements.
77
+ * 5. Use `registerForeignDomain()` to integrate data from
78
+ * external domains.
79
+ * 6. Listen for the `change` event to be notified of
80
+ * changes within the data domain.
81
+ *
82
+ * **Example:**
83
+ *
84
+ * ```typescript
85
+ * const dataDomain = new DataDomain();
86
+ * const userNamespace = dataDomain.addNamespace({
87
+ * key: 'userNamespace',
88
+ * });
89
+ * const userModel = userNamespace.addModel({
90
+ * key: 'userModel',
91
+ * });
92
+ * const userEntity = userModel.addEntity({
93
+ * key: 'user',
94
+ * });
95
+ * const nameProperty = userEntity.addProperty({
96
+ * key: 'name',
97
+ * type: 'string',
98
+ * });
99
+ * ```
100
+ *
101
+ * @fires DataDomain#change {Event} - Fired when the data
102
+ * domain changes.
103
+ *
104
+ * @todo: Implement a mechanism to move an entity to a new
105
+ * parent model.
106
+ */
107
+ export class DataDomain extends EventTarget {
108
+ /**
109
+ * The kind of the domain element.
110
+ */
111
+ kind: typeof DataDomainKind
112
+ /**
113
+ * The unique key of the domain element.
114
+ */
115
+ key: string
116
+
117
+ /**
118
+ * The graph used to store the data domain structure.
119
+ */
120
+ graph: Graph<unknown, DomainGraphNodeType, DomainGraphEdge>
121
+
122
+ /**
123
+ * A map of foreign data domains.
124
+ * Key: The unique identifier of the foreign domain.
125
+ * Value: The foreign DataDomain instance.
126
+ */
127
+ dependencies: Map<string, DataDomain> = new Map<string, DataDomain>()
128
+
129
+ /**
130
+ * The list of foreign domain dependencies.
131
+ */
132
+ dependencyList: ForeignDomainDependency[] = []
133
+
134
+ /**
135
+ * The description of the domain property.
136
+ */
137
+ accessor info: Thing
138
+
139
+ /**
140
+ * When the initializing flag is set to true,
141
+ * the domain is not notified of changes.
142
+ */
143
+ #initializing = true
144
+
145
+ /**
146
+ * When the notifying flag is set to true,
147
+ * the domain is pending a notification.
148
+ * No other notifications will be sent until
149
+ * the current notification is sent.
150
+ */
151
+ #notifying = false
152
+
153
+ /**
154
+ * This is to keep it consistent with the domain elements.
155
+ */
156
+ get domain(): DataDomain {
157
+ return this
158
+ }
159
+
160
+ /**
161
+ * The ordered list of fields (namespace and models) in the schema.
162
+ * These only keep references to define the order of these properties
163
+ * in the schema as graph won't do it.
164
+ */
165
+ accessor fields: NamespaceOrderedItem[]
166
+
167
+ static createSchema(input: Partial<DataDomainSchema> = {}): DataDomainSchema {
168
+ const { key = nanoid(), fields } = input
169
+ const info = Thing.fromJSON(input.info, { name: 'Unnamed domain' }).toJSON()
170
+ const result: DataDomainSchema = {
171
+ kind: DataDomainKind,
172
+ key,
173
+ info,
174
+ }
175
+ if (input.dependencyList) {
176
+ result.dependencyList = structuredClone(input.dependencyList)
177
+ }
178
+ if (input.graph) {
179
+ result.graph = input.graph
180
+ }
181
+ if (Array.isArray(fields)) {
182
+ result.fields = [...fields]
183
+ }
184
+ return result
185
+ }
186
+
187
+ /**
188
+ * Creates a new instance of the `DataDomain` class.
189
+ *
190
+ * When creating a new Data Domain arguments should not be set.
191
+ * When restoring a Data Domain from a previous state, you should provide
192
+ * the serialized graph state as well as the same list of dependencies
193
+ * used when the graph was deserialized. Edges to missing dependency nodes
194
+ * will be ignored.
195
+ *
196
+ * @param state The previously serialized state of the graph.
197
+ * @param dependencies An array of foreign data domains to register with this domain.
198
+ */
199
+ constructor(state?: Partial<DataDomainSchema>, dependencies?: DataDomain[]) {
200
+ super()
201
+ const init = DataDomain.createSchema(state)
202
+ this.kind = init.kind
203
+ this.key = init.key
204
+ this.info = new Thing(init.info)
205
+ this.graph = deserialize(this, init.graph, dependencies)
206
+ if (Array.isArray(init.fields)) {
207
+ this.fields = [...init.fields]
208
+ } else {
209
+ this.fields = []
210
+ }
211
+ if (Array.isArray(init.dependencyList)) {
212
+ this.dependencyList = [...init.dependencyList]
213
+ } else {
214
+ this.dependencyList = []
215
+ }
216
+ this.#initializing = false
217
+ this.info.addEventListener('change', () => {
218
+ this.notifyChange()
219
+ })
220
+ }
221
+
222
+ /**
223
+ * Serializes the DataDomain instance to a JSON object.
224
+ * It does not serialize the foreign domain dependencies. The serialized nodes
225
+ * are the ones that are local to this data domain.
226
+ * @returns The serialized data domain ready for storage or transport.
227
+ */
228
+ toJSON(): DataDomainSchema {
229
+ const result: DataDomainSchema = {
230
+ info: this.info.toJSON(),
231
+ kind: this.kind,
232
+ key: this.key,
233
+ graph: serialize(this.graph, this.key),
234
+ }
235
+ if (this.dependencyList.length > 0) {
236
+ result.dependencyList = structuredClone(this.dependencyList)
237
+ }
238
+ if (Array.isArray(this.fields) && this.fields.length) {
239
+ result.fields = [...this.fields]
240
+ }
241
+ return result
242
+ }
243
+
244
+ /**
245
+ * This function is used internally by all domain elements to notify that something has changed.
246
+ * Since we want to notify listeners after the operation commits, we use microtask
247
+ * to ensure that the event is dispatched after the current operation.
248
+ */
249
+ notifyChange() {
250
+ if (this.#notifying || this.#initializing) {
251
+ return
252
+ }
253
+ this.#notifying = true
254
+ queueMicrotask(() => {
255
+ this.#notifying = false
256
+ const event = new Event('change')
257
+ this.dispatchEvent(event)
258
+ })
259
+ }
260
+
261
+ private removeField(key: string): void {
262
+ this.fields = this.fields.filter((item) => item.key !== key)
263
+ }
264
+
265
+ /**
266
+ * Checks if this data domain has any fields (namespace and models).
267
+ *
268
+ * @returns True if the data domain has fields.
269
+ * @example
270
+ * ```typescript
271
+ * if (domain.hasFields()) {
272
+ * // ...
273
+ * }
274
+ * ```
275
+ */
276
+ hasFields(): boolean {
277
+ return this.fields.length > 0
278
+ }
279
+
280
+ /**
281
+ * Lists all fields (namespace and models) of this namespace.
282
+ *
283
+ * @returns A generator that yields each `DomainAssociation` or `DomainProperty`.
284
+ * @example
285
+ * ```typescript
286
+ * for (const field of namespace.listFields()) {
287
+ * console.log(field.key);
288
+ * }
289
+ * ```
290
+ */
291
+ *listFields(): Generator<DomainNamespace | DomainModel> {
292
+ for (const { key } of this.fields) {
293
+ const node = this.graph.node(key)
294
+ if (!node) {
295
+ continue
296
+ }
297
+ if (node.kind === DomainNamespaceKind || node.kind === DomainModelKind) {
298
+ yield node
299
+ }
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Adds a new data domain instance to the graph.
305
+ *
306
+ * @param value The partial namespace schema. All missing
307
+ * values will be filled with default values.
308
+ * @param parent The parent namespace key. If not provided,
309
+ * the new namespace will be added to the root of the
310
+ * graph.
311
+ * @returns The created namespace instance.
312
+ * @throws Error When the parent does not exist or is not
313
+ * a namespace.
314
+ * @example
315
+ * ```typescript
316
+ * const newNamespace = dataDomain.addNamespace({
317
+ * key: 'newNamespace',
318
+ * });
319
+ * ```
320
+ */
321
+ addNamespace(value?: Partial<DomainNamespaceSchema>, parent?: string): DomainNamespace {
322
+ if (parent) {
323
+ if (!this.graph.hasNode(parent)) {
324
+ throw new Error(`Parent namespace ${parent} does not exist`)
325
+ }
326
+ const instance = this.graph.node(parent) as DomainNamespace
327
+ if (!instance || instance.kind !== DomainNamespaceKind) {
328
+ throw new Error(`Parent namespace ${parent} is not a valid namespace`)
329
+ }
330
+ if (instance.domain.key !== this.key) {
331
+ throw new Error(`Cannot add a namespace to a foreign domain`)
332
+ }
333
+ return instance.addNamespace(value)
334
+ }
335
+ const item = new DomainNamespace(this, value)
336
+ this.graph.setNode(item.key, item)
337
+ this.fields.push({
338
+ type: 'namespace',
339
+ key: item.key,
340
+ })
341
+ this.notifyChange()
342
+ return item
343
+ }
344
+
345
+ /**
346
+ * Removes a namespace from the graph.
347
+ *
348
+ * @param key The key of the namespace to remove.
349
+ * @returns The current DataDomain instance.
350
+ * @throws Error When the namespace does not exist.
351
+ * @example
352
+ * ```typescript
353
+ * dataDomain.removeNamespace('userNamespace');
354
+ * ```
355
+ */
356
+ removeNamespace(key: string): this {
357
+ if (!this.graph.hasNode(key)) {
358
+ throw new Error(`Namespace ${key} does not exist`)
359
+ }
360
+ const ns = this.graph.node(key) as DomainNamespace
361
+ if (!ns || ns.kind !== DomainNamespaceKind) {
362
+ throw new Error(`Namespace ${key} not found`)
363
+ }
364
+ if (ns.domain.key !== this.key) {
365
+ throw new Error(`Cannot remove a namespace from a foreign domain`)
366
+ }
367
+ const parent = ns.getParentInstance()
368
+ if (parent === this) {
369
+ removeGraphNode(this.graph, key)
370
+ this.removeField(key)
371
+ this.notifyChange()
372
+ } else {
373
+ parent.removeNamespace(key)
374
+ }
375
+ return this
376
+ }
377
+
378
+ /**
379
+ * Lists all namespaces of this data domain that are direct children of it.
380
+ *
381
+ * Note, it accounts for the order of the namespaces as defined in the `fields` array.
382
+ *
383
+ * @returns A generator that yields each `DomainNamespace`.
384
+ * @example
385
+ * ```typescript
386
+ * for (const ns of domain.listNamespaces()) {
387
+ * console.log(ns.key);
388
+ * }
389
+ * ```
390
+ */
391
+ *listNamespaces(): Generator<DomainNamespace> {
392
+ for (const { key, type } of this.fields) {
393
+ if (type !== 'namespace') {
394
+ continue
395
+ }
396
+ const node = this.graph.node(key)
397
+ if (!node || node.kind !== DomainNamespaceKind) {
398
+ continue
399
+ }
400
+ yield node
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Checks if this data domain has any namespaces.
406
+ *
407
+ * @returns True if the data domain has namespaces.
408
+ * @example
409
+ * ```typescript
410
+ * if (domain.hasNamespaces()) {
411
+ * // ...
412
+ * }
413
+ * ```
414
+ */
415
+ hasNamespaces(): boolean {
416
+ return this.fields.some((item) => item.type === 'namespace')
417
+ }
418
+
419
+ /**
420
+ * Lists all namespaces in the graph.
421
+ *
422
+ * @param parent The key of the parent namespace. If not
423
+ * provided, all root namespaces will be listed.
424
+ * @returns A generator that yields each `DomainNamespace`.
425
+ * @example
426
+ * ```typescript
427
+ * for (const ns of dataDomain.listGraphNamespaces()) {
428
+ * console.log(ns.key);
429
+ * }
430
+ * ```
431
+ */
432
+ *listGraphNamespaces(parent?: string): Generator<DomainNamespace> {
433
+ for (const node of this.graph.children(parent)) {
434
+ const value = this.graph.node(node) as DomainGraphNodeType
435
+ if (value.kind === DomainNamespaceKind && value.domain.key === this.key) {
436
+ yield value
437
+ }
438
+ }
439
+ }
440
+
441
+ /**
442
+ * Finds a namespace by its key.
443
+ *
444
+ * @param key The key of the namespace to find.
445
+ * @returns The namespace instance or undefined if not
446
+ * found.
447
+ * @example
448
+ * ```typescript
449
+ * const ns = dataDomain.findNamespace('userNamespace');
450
+ * if (ns) {
451
+ * console.log(ns.key);
452
+ * }
453
+ * ```
454
+ */
455
+ findNamespace(key: string): DomainNamespace | undefined {
456
+ const result = this.graph.node(key) as DomainNamespace | undefined
457
+ if (result && result.kind === DomainNamespaceKind) {
458
+ return result
459
+ }
460
+ }
461
+
462
+ /**
463
+ * Moves a namespace to a new parent.
464
+ *
465
+ * @param key The key of the namespace to move.
466
+ * @param parent The new parent namespace key. If
467
+ * undefined, the namespace will be moved to the root.
468
+ * @returns The current DataDomain instance.
469
+ * @throws Error When the namespace or parent does not
470
+ * exist, or when a namespace is moved to itself or
471
+ * its own child.
472
+ * @example
473
+ * ```typescript
474
+ * dataDomain.moveNamespace('userNamespace', 'root');
475
+ * ```
476
+ */
477
+ moveNamespace(key: string, parent?: string): this {
478
+ if (!this.graph.hasNode(key)) {
479
+ throw new Error(`Namespace ${key} does not exist`)
480
+ }
481
+
482
+ const namespace = this.findNamespace(key)
483
+ if (!namespace) {
484
+ throw new Error(`Namespace ${key} not found in the graph`)
485
+ }
486
+
487
+ if (parent) {
488
+ const instance = this.findNamespace(parent)
489
+ if (instance && instance.domain.key !== this.key) {
490
+ throw new Error(`Cannot move a namespace to a foreign domain`)
491
+ }
492
+ if (!instance) {
493
+ throw new Error(`Parent namespace ${parent} does not exist`)
494
+ }
495
+ }
496
+
497
+ if (key === parent) {
498
+ throw new Error(`Cannot move a namespace to itself`)
499
+ }
500
+
501
+ if (namespace.domain.key !== this.key) {
502
+ throw new Error(`Cannot move a namespace from a foreign domain`)
503
+ }
504
+ let parentNamespace: DomainNamespace | undefined
505
+ if (parent) {
506
+ parentNamespace = this.findNamespace(parent)
507
+ if (!parentNamespace) {
508
+ throw new Error(`Parent namespace ${parent} not found`)
509
+ }
510
+ if (this.isChildOf(parent, key)) {
511
+ throw new Error(`Cannot move a namespace to its own child`)
512
+ }
513
+ }
514
+
515
+ // namespaces can only have one parent
516
+ const currentParentKey = this.graph.parent(key)
517
+ if (currentParentKey && !parent) {
518
+ // The new parent namespace will detach the namespace when attaching to self.
519
+ const currentParent = this.graph.node(currentParentKey) as DomainNamespace
520
+ currentParent.detachNamespace(key)
521
+ } else if (!currentParentKey) {
522
+ // The namespace is a root namespace.
523
+ this.removeField(key)
524
+ }
525
+ // Add to new parent
526
+ if (parent && parentNamespace) {
527
+ parentNamespace.attachNamespace(key)
528
+ } else {
529
+ // The namespace is a root namespace.
530
+ this.fields.push({
531
+ type: 'namespace',
532
+ key,
533
+ })
534
+ }
535
+ this.notifyChange()
536
+ return this
537
+ }
538
+
539
+ /**
540
+ * Checks if a namespace is a child of another namespace.
541
+ * @param parentKey The key of the parent namespace.
542
+ * @param childKey The key of the child namespace.
543
+ * @returns True if the namespace is a child of another namespace.
544
+ */
545
+ private isChildOf(parentKey: string, childKey: string): boolean {
546
+ const children = this.graph.children(childKey)
547
+ for (const child of children) {
548
+ if (child === parentKey) {
549
+ return true
550
+ }
551
+ if (this.isChildOf(parentKey, child)) {
552
+ return true
553
+ }
554
+ }
555
+ return false
556
+ }
557
+
558
+ /**
559
+ * Adds a data model to the graph.
560
+ *
561
+ * @param input The partial data model schema.
562
+ * @param parent The parent namespace key. If not
563
+ * provided, the new data model will be added to the
564
+ * root of the graph.
565
+ * @returns The created data model instance.
566
+ * @throws Error When the parent does not exist or is not
567
+ * a namespace.
568
+ * @example
569
+ * ```typescript
570
+ * const newModel = dataDomain.addModel({
571
+ * key: 'newModel',
572
+ * });
573
+ * ```
574
+ */
575
+ addModel(input?: Partial<DomainModelSchema>, parent?: string): DomainModel {
576
+ if (parent) {
577
+ if (!this.graph.hasNode(parent)) {
578
+ throw new Error(`Parent ${parent} does not exist`)
579
+ }
580
+ const instance = this.findNamespace(parent)
581
+ if (!instance) {
582
+ throw new Error(`Parent namespace ${parent} is not a valid namespace`)
583
+ }
584
+ if (instance.domain.key !== this.key) {
585
+ throw new Error(`Cannot add a model to a foreign domain`)
586
+ }
587
+ return instance.addModel(input)
588
+ }
589
+ const item = new DomainModel(this, input)
590
+ this.graph.setNode(item.key, item)
591
+ this.fields.push({
592
+ type: 'model',
593
+ key: item.key,
594
+ })
595
+ return item
596
+ }
597
+
598
+ /**
599
+ * Removes a data model from the graph.
600
+ *
601
+ * @param key The key of the data model to remove.
602
+ * @returns The current DataDomain instance.
603
+ * @throws Error When the data model does not exist.
604
+ * @example
605
+ * ```typescript
606
+ * dataDomain.removeModel('userModel');
607
+ * ```
608
+ */
609
+ removeModel(key: string): this {
610
+ if (!this.graph.hasNode(key)) {
611
+ throw new Error(`Data model ${key} does not exist`)
612
+ }
613
+ const model = this.graph.node(key) as DomainModel
614
+ if (!model || model.kind !== DomainModelKind) {
615
+ throw new Error(`Data model ${key} not found`)
616
+ }
617
+ if (model.domain.key !== this.key) {
618
+ throw new Error(`Cannot remove a model from a foreign domain`)
619
+ }
620
+ const parent = model.getParentInstance()
621
+ if (parent === this) {
622
+ removeGraphNode(this.graph, key)
623
+ this.removeField(key)
624
+ this.notifyChange()
625
+ } else {
626
+ parent.removeModel(key)
627
+ }
628
+ return this
629
+ }
630
+
631
+ /**
632
+ * Lists all models of this data domain that are direct children of it.
633
+ *
634
+ * Note, it accounts for the order of the models as
635
+ * defined in the `fields` array.
636
+ *
637
+ * @returns A generator that yields each `DomainModel`.
638
+ * @example
639
+ * ```typescript
640
+ * for (const ns of namespace.listModels()) {
641
+ * console.log(ns.key);
642
+ * }
643
+ * ```
644
+ */
645
+ *listModels(): Generator<DomainModel> {
646
+ for (const { key, type } of this.fields) {
647
+ if (type !== 'model') {
648
+ continue
649
+ }
650
+ const node = this.graph.node(key)
651
+ if (!node || node.kind !== DomainModelKind) {
652
+ continue
653
+ }
654
+ yield node
655
+ }
656
+ }
657
+
658
+ /**
659
+ * Checks if this data domain has any direct models.
660
+ *
661
+ * @returns True if the data domain has models.
662
+ * @example
663
+ * ```typescript
664
+ * if (domain.hasModels()) {
665
+ * // ...
666
+ * }
667
+ * ```
668
+ */
669
+ hasModels(): boolean {
670
+ return this.fields.some((item) => item.type === 'model')
671
+ }
672
+
673
+ /**
674
+ * Lists all data models in the graph.
675
+ *
676
+ * @param parent The key of the parent namespace. If not
677
+ * provided, all root data models will be listed.
678
+ * @returns A generator that yields each `DomainModel`.
679
+ * @example
680
+ * ```typescript
681
+ * for (const model of dataDomain.listGraphModels()) {
682
+ * console.log(model.key);
683
+ * }
684
+ * ```
685
+ */
686
+ *listGraphModels(parent?: string): Generator<DomainModel> {
687
+ for (const node of this.graph.children(parent)) {
688
+ const value = this.graph.node(node) as DomainGraphNodeType
689
+ if (value.kind === DomainModelKind && value.domain.key === this.key) {
690
+ yield value
691
+ }
692
+ }
693
+ }
694
+
695
+ /**
696
+ * Finds a data model by its key.
697
+ *
698
+ * @param key The key of the data model to find.
699
+ * @returns The data model instance or undefined if not
700
+ * found.
701
+ * @example
702
+ * ```typescript
703
+ * const model = dataDomain.findModel('userModel');
704
+ * if (model) {
705
+ * console.log(model.key);
706
+ * }
707
+ * ```
708
+ */
709
+ findModel(key: string): DomainModel | undefined {
710
+ const value = this.graph.node(key) as DomainModel | undefined
711
+ if (value && value.kind === DomainModelKind) {
712
+ return value
713
+ }
714
+ return undefined
715
+ }
716
+
717
+ /**
718
+ * Moves a data model to a new parent.
719
+ *
720
+ * @param key The key of the data model to move.
721
+ * @param parent The new parent namespace key. If
722
+ * undefined, the data model will be moved to the root.
723
+ * @returns The current DataDomain instance.
724
+ * @throws Error When the data model or parent does not
725
+ * exist, or when a data model is moved to a foreign
726
+ * domain.
727
+ * @example
728
+ * ```typescript
729
+ * dataDomain.moveModel('userModel', 'newNamespace');
730
+ * ```
731
+ */
732
+ moveModel(key: string, parent?: string): this {
733
+ if (!this.graph.hasNode(key)) {
734
+ throw new Error(`Data model ${key} does not exist`)
735
+ }
736
+
737
+ const model = this.findModel(key)
738
+ if (!model) {
739
+ throw new Error(`Data model ${key} not found in the graph`)
740
+ }
741
+
742
+ if (parent) {
743
+ const instance = this.findNamespace(parent)
744
+ if (instance && instance.domain.key !== this.key) {
745
+ throw new Error(`Cannot move a model to a foreign domain`)
746
+ }
747
+ if (!instance) {
748
+ throw new Error(`Parent namespace ${parent} does not exist`)
749
+ }
750
+ }
751
+
752
+ if (model.domain.key !== this.key) {
753
+ throw new Error(`Cannot move a data model to a foreign domain`)
754
+ }
755
+
756
+ // namespaces can only have one parent
757
+ const currentParentKey = this.graph.parent(key)
758
+ // Remove from current parent
759
+ if (currentParentKey && !parent) {
760
+ // The new parent namespace will detach the model when attaching to self.
761
+ const currentParent = this.findNamespace(currentParentKey)
762
+ if (!currentParent) {
763
+ throw new Error(`The parent namespace ${currentParentKey} not found`)
764
+ }
765
+ currentParent.detachModel(key)
766
+ } else if (!currentParentKey) {
767
+ // The model is a root model.
768
+ this.removeField(key)
769
+ }
770
+
771
+ // Add to new parent
772
+ if (parent) {
773
+ const parentNamespace = this.findNamespace(parent) as DomainNamespace
774
+ parentNamespace.attachModel(key)
775
+ } else {
776
+ // The model is becoming a root model.
777
+ this.fields.push({
778
+ type: 'model',
779
+ key,
780
+ })
781
+ }
782
+
783
+ this.notifyChange()
784
+ return this
785
+ }
786
+
787
+ /**
788
+ * Adds an entity to a data model.
789
+ *
790
+ * @param input The partial entity schema.
791
+ * @param parent The key of the parent data model.
792
+ * @returns The created entity instance.
793
+ * @throws {Error} When the parent does not exist or is not a data model.
794
+ * @example
795
+ * ```typescript
796
+ * const userEntity = dataDomain.addEntity({
797
+ * key: 'user',
798
+ * }, 'userModel');
799
+ * ```
800
+ */
801
+ addEntity(parent: string, input?: Partial<DomainEntitySchema>): DomainEntity {
802
+ if (!parent) {
803
+ throw new Error(`An entity expects a DataModel parent`)
804
+ }
805
+ if (!this.graph.hasNode(parent)) {
806
+ throw new Error(`The parent ${parent} does not exist`)
807
+ }
808
+ const instance = this.findModel(parent)
809
+ if (!instance) {
810
+ throw new Error(`Parent model ${parent} is not a valid model`)
811
+ }
812
+ if (instance.domain.key !== this.key) {
813
+ throw new Error(`Cannot add an entity to a foreign domain`)
814
+ }
815
+ return instance.addEntity(input)
816
+ }
817
+
818
+ /**
819
+ * Removes an entity from the graph.
820
+ *
821
+ * @param key The key of the entity to remove.
822
+ * @returns The current DataDomain instance.
823
+ * @throws Error When the entity does not exist.
824
+ * @example
825
+ * ```typescript
826
+ * dataDomain.removeEntity('user');
827
+ * ```
828
+ */
829
+ removeEntity(key: string): this {
830
+ if (!this.graph.hasNode(key)) {
831
+ throw new Error(`Entity ${key} does not exist`)
832
+ }
833
+ const parentKey = this.graph.parent(key)
834
+ if (!parentKey) {
835
+ throw new Error(`Parent model not found for entity ${key}`)
836
+ }
837
+ const parent = this.findModel(parentKey)
838
+ if (!parent) {
839
+ throw new Error(`Parent model ${parentKey} not found`)
840
+ }
841
+ if (parent.domain.key !== this.key) {
842
+ throw new Error(`Cannot remove an entity from a foreign domain`)
843
+ }
844
+ parent.removeEntity(key)
845
+ return this
846
+ }
847
+
848
+ /**
849
+ * Lists all entities in a data model, or, if the model key is not provided,
850
+ * all entities in the domain.
851
+ *
852
+ * @param parent The key of the parent data model.
853
+ * @returns A generator that yields each `DomainEntity`.
854
+ * @example
855
+ * ```typescript
856
+ * for (const entity of dataDomain.listEntities('userModel')) {
857
+ * console.log(entity.key);
858
+ * }
859
+ * ```
860
+ */
861
+ *listEntities(parent?: string): Generator<DomainEntity> {
862
+ const iterator = parent ? this.graph.children(parent) : this.graph.nodes()
863
+ for (const node of iterator) {
864
+ const value = this.graph.node(node) as DomainGraphNodeType
865
+ if (value.kind === DomainEntityKind && value.domain.key === this.key) {
866
+ yield value
867
+ }
868
+ }
869
+ }
870
+
871
+ /**
872
+ * Finds an entity by its key.
873
+ *
874
+ * @param key The key of the entity to find.
875
+ * @returns The entity instance or undefined if not found.
876
+ * @example
877
+ * ```typescript
878
+ * const entity = dataDomain.findEntity('user');
879
+ * if (entity) {
880
+ * console.log(entity.key);
881
+ * }
882
+ * ```
883
+ */
884
+ findEntity(key: string): DomainEntity | undefined {
885
+ const node = this.graph.node(key) as DomainEntity | undefined
886
+ if (node && node.kind === DomainEntityKind) {
887
+ return node
888
+ }
889
+ return undefined
890
+ }
891
+
892
+ /**
893
+ * Moves an entity from one model to another.
894
+ *
895
+ * @param entityKey The key of the entity to move.
896
+ * @param sourceModelKey The key of the source model.
897
+ * @param targetModelKey The key of the target model.
898
+ * @throws Error When the entity, source model, or target model does not exist.
899
+ * @throws Error When the entity is not in the same domain.
900
+ * @throws Error When the source and target models are the same.
901
+ * @throws Error When moving to an unsupported object.
902
+ */
903
+ moveEntity(entityKey: string, sourceModelKey: string, targetModelKey: string): void {
904
+ if (sourceModelKey === targetModelKey) {
905
+ throw new Error(`Cannot move an entity to the same model`)
906
+ }
907
+ if (!this.graph.hasNode(entityKey)) {
908
+ throw new Error(`Entity ${entityKey} does not exist`)
909
+ }
910
+ if (!this.graph.hasNode(sourceModelKey)) {
911
+ throw new Error(`Source model ${sourceModelKey} does not exist`)
912
+ }
913
+ if (!this.graph.hasNode(targetModelKey)) {
914
+ throw new Error(`Target model ${targetModelKey} does not exist`)
915
+ }
916
+
917
+ const entity = this.findEntity(entityKey)
918
+ const sourceModel = this.findModel(sourceModelKey)
919
+ const targetModel = this.findModel(targetModelKey)
920
+
921
+ if (!entity || !sourceModel || !targetModel) {
922
+ throw new Error(`Entity or models not found in the graph`)
923
+ }
924
+
925
+ if (entity.domain.key !== this.key) {
926
+ // this also applied to the parent model.
927
+ throw new Error(`Cannot move an entity from a foreign domain`)
928
+ }
929
+ if (targetModel.domain.key !== this.key) {
930
+ throw new Error(`Cannot move an entity to a foreign domain`)
931
+ }
932
+ // The target model detaches the entity when attaching to self.
933
+ targetModel.attachEntity(entityKey)
934
+ this.notifyChange()
935
+ }
936
+
937
+ /**
938
+ * Adds an association between two entities.
939
+ *
940
+ * This function is a shortcut that finds the entity and
941
+ * calls the `addAssociation` method on it.
942
+ *
943
+ * @param source The key of the source entity.
944
+ * @param init The association options.
945
+ * @returns The created association.
946
+ * @throws Error When the source entity does not exist.
947
+ * @example
948
+ * ```typescript
949
+ * const addressAssociation = dataDomain.addAssociation(
950
+ * 'user', { key: 'address' }
951
+ * );
952
+ * ```
953
+ */
954
+ addAssociation(source: string, init?: AssociationAddOptions): DomainAssociation {
955
+ if (!this.graph.hasNode(source)) {
956
+ throw new Error(`Source entity ${source} not found`)
957
+ }
958
+ const entity = this.findEntity(source)
959
+ if (!entity) {
960
+ throw new Error(`Source entity ${source} not found`)
961
+ }
962
+ if (entity.domain.key !== this.key) {
963
+ throw new Error(`Cannot add an association to a foreign domain`)
964
+ }
965
+ return entity.addAssociation(init)
966
+ }
967
+
968
+ /**
969
+ * Removes an association from the graph.
970
+ *
971
+ * @param key The key of the association to remove.
972
+ * @returns The current DataDomain instance.
973
+ * @throws Error When the association does not exist or
974
+ * when the parent entity is not found.
975
+ * @example
976
+ * ```typescript
977
+ * dataDomain.removeAssociation('address');
978
+ * ```
979
+ */
980
+ removeAssociation(key: string): this {
981
+ if (!this.graph.hasNode(key)) {
982
+ throw new Error(`Association ${key} does not exist`)
983
+ }
984
+ const instance = this.graph.node(key) as DomainAssociation
985
+ if (!instance || instance.kind !== DomainAssociationKind) {
986
+ throw new Error(`Association ${key} not found`)
987
+ }
988
+ const entity = instance.getParentInstance()
989
+ if (!entity) {
990
+ throw new Error(`Parent entity not found for association ${key}`)
991
+ }
992
+ if (entity.domain.key !== this.key) {
993
+ throw new Error(`Cannot remove an association from a foreign domain`)
994
+ }
995
+ entity.removeAssociation(key)
996
+ return this
997
+ }
998
+
999
+ /**
1000
+ * Finds an association by its key.
1001
+ *
1002
+ * @param key The key of the association to find.
1003
+ * @returns The association instance or undefined if not
1004
+ * found.
1005
+ * @example
1006
+ * ```typescript
1007
+ * const assoc = dataDomain.findAssociation('address');
1008
+ * if (assoc) {
1009
+ * console.log(assoc.key);
1010
+ * }
1011
+ * ```
1012
+ */
1013
+ findAssociation(key: string): DomainAssociation | undefined {
1014
+ const node = this.graph.node(key) as DomainAssociation | undefined
1015
+ if (node && node.kind === DomainAssociationKind) {
1016
+ return node
1017
+ }
1018
+ return undefined
1019
+ }
1020
+
1021
+ /**
1022
+ * Adds a property to an entity.
1023
+ *
1024
+ * @param parent The key of the parent entity.
1025
+ * @param property The partial property schema.
1026
+ * @returns The created property instance.
1027
+ * @throws Error When the parent does not exist or is not
1028
+ * an entity.
1029
+ * @example
1030
+ * ```typescript
1031
+ * const nameProperty = dataDomain.addProperty(
1032
+ * 'user', { key: 'name', type: 'string' }
1033
+ * );
1034
+ * ```
1035
+ */
1036
+ addProperty(parent: string, property?: Partial<DomainPropertySchema>): DomainProperty {
1037
+ if (!parent) {
1038
+ throw new Error(`A property expects a DataEntity parent`)
1039
+ }
1040
+ if (!this.graph.hasNode(parent)) {
1041
+ throw new Error(`Parent entity ${parent} does not exist`)
1042
+ }
1043
+ const entity = this.findEntity(parent)
1044
+ if (!entity) {
1045
+ throw new Error(`Parent entity ${parent} not found`)
1046
+ }
1047
+ if (entity.domain.key !== this.key) {
1048
+ throw new Error(`Cannot add a property to a foreign domain`)
1049
+ }
1050
+ return entity.addProperty(property)
1051
+ }
1052
+
1053
+ /**
1054
+ * Removes a property from the graph.
1055
+ *
1056
+ * @param key The key of the property to remove.
1057
+ * @returns The current DataDomain instance.
1058
+ * @throws Error When the property does not exist or when
1059
+ * the parent entity is not found.
1060
+ * @example
1061
+ * ```typescript
1062
+ * dataDomain.removeProperty('name');
1063
+ * ```
1064
+ */
1065
+ removeProperty(key: string): this {
1066
+ if (!this.graph.hasNode(key)) {
1067
+ throw new Error(`Property ${key} does not exist`)
1068
+ }
1069
+ const instance = this.graph.node(key) as DomainProperty
1070
+ if (!instance || instance.kind !== DomainPropertyKind) {
1071
+ throw new Error(`Property ${key} not found`)
1072
+ }
1073
+ const entity = instance.getParentInstance()
1074
+ if (!entity) {
1075
+ throw new Error(`Parent entity not found for property ${key}`)
1076
+ }
1077
+ if (entity.domain.key !== this.key) {
1078
+ throw new Error(`Cannot remove a property from a foreign domain`)
1079
+ }
1080
+ entity.removeProperty(key)
1081
+ return this
1082
+ }
1083
+
1084
+ /**
1085
+ * Finds a property by its key.
1086
+ *
1087
+ * @param key The key of the property to find.
1088
+ * @returns The property instance or undefined if not
1089
+ * found.
1090
+ * @example
1091
+ * ```typescript
1092
+ * const prop = dataDomain.findProperty('name');
1093
+ * if (prop) {
1094
+ * console.log(prop.key);
1095
+ * }
1096
+ * ```
1097
+ */
1098
+ findProperty(key: string): DomainProperty | undefined {
1099
+ const node = this.graph.node(key) as DomainProperty | undefined
1100
+ if (node && node.kind === DomainPropertyKind) {
1101
+ return node
1102
+ }
1103
+ return undefined
1104
+ }
1105
+
1106
+ /**
1107
+ * Registers a foreign DataDomain.
1108
+ *
1109
+ * @param domain The foreign DataDomain instance.
1110
+ * @param key The unique identifier for the foreign
1111
+ * domain.
1112
+ * @param version The version of the foreign domain.
1113
+ * @throws Error When a foreign domain with the same key is already registered.
1114
+ * @example
1115
+ * ```typescript
1116
+ * dataDomain.registerForeignDomain(
1117
+ * foreignDomain, 'foreignDomain', '1.0.0'
1118
+ * );
1119
+ * ```
1120
+ */
1121
+ registerForeignDomain(domain: DataDomain): void {
1122
+ const { info, key } = domain
1123
+ if (!info.version) {
1124
+ // @TODO: make the data domain immutable after a version is set.
1125
+ // This will prevent the user from changing the version
1126
+ // after the domain is registered.
1127
+ throw new Error(`Foreign domain ${key} does not have a version set`)
1128
+ }
1129
+ if (this.dependencies.has(key)) {
1130
+ throw new Error(`Foreign domain with key ${key} already registered`)
1131
+ }
1132
+ this.dependencies.set(key, domain)
1133
+ this.dependencyList.push({ key, version: info.version })
1134
+ // Copy the relevant parts of the foreign domain's graph into the local graph.
1135
+ // this.copyForeignDomainGraph(domain)
1136
+ mergeGraph(this.graph, domain.graph, domain.key)
1137
+ this.notifyChange()
1138
+ }
1139
+
1140
+ /**
1141
+ * Un-registers a foreign DataDomain. It removes all defined by the foreign domain
1142
+ * information from the graph.
1143
+ * @param key The key of the foreign domain to unregister.
1144
+ */
1145
+ unregisterForeignDomain(key: string): void {
1146
+ const foreignDomain = this.dependencies.get(key)
1147
+ if (!foreignDomain) {
1148
+ throw new Error(`Foreign domain with key ${key} not found`)
1149
+ }
1150
+ this.dependencies.delete(key)
1151
+ this.dependencyList = this.dependencyList.filter((dependency) => dependency.key !== key)
1152
+ // Remove the foreign domain's nodes from the local graph.
1153
+ removeForeignGraph(this.graph, foreignDomain.key)
1154
+ this.notifyChange()
1155
+ }
1156
+
1157
+ /**
1158
+ * Finds an entity in a foreign domain.
1159
+ *
1160
+ * @param entityKey The key of the entity to find.
1161
+ * @param domainKey The key of the foreign domain.
1162
+ * @returns The entity instance or undefined if not
1163
+ * found.
1164
+ * @example
1165
+ * ```typescript
1166
+ * const foreignUser = dataDomain.findForeignEntity(
1167
+ * 'user', 'foreignDomain'
1168
+ * );
1169
+ * if (foreignUser) {
1170
+ * console.log(foreignUser.key);
1171
+ * }
1172
+ * ```
1173
+ */
1174
+ findForeignEntity(entityKey: string, domainKey: string): DomainEntity | undefined {
1175
+ const foreignDomain = this.dependencies.get(domainKey)
1176
+ if (!foreignDomain) {
1177
+ return undefined
1178
+ }
1179
+ const foreignKey = `${domainKey}:${entityKey}`
1180
+ const node = this.graph.node(foreignKey)
1181
+ if (node && node.kind === DomainEntityKind) {
1182
+ return node as DomainEntity
1183
+ }
1184
+ return undefined
1185
+ }
1186
+
1187
+ /**
1188
+ * A convenience function to remove an object from the
1189
+ * namespace.
1190
+ *
1191
+ * @param key The key of the object to remove.
1192
+ * @param kind The kind of the object to remove.
1193
+ * @throws Error when the kind is not known.
1194
+ * @example
1195
+ * ```typescript
1196
+ * dataDomain.removeDomainElement('user', DomainEntityKind);
1197
+ * ```
1198
+ */
1199
+ removeDomainElement(key: string, kind: string): void {
1200
+ switch (kind) {
1201
+ case DomainNamespaceKind:
1202
+ this.removeNamespace(key)
1203
+ break
1204
+ case DomainModelKind:
1205
+ this.removeModel(key)
1206
+ break
1207
+ case DomainEntityKind:
1208
+ this.removeEntity(key)
1209
+ break
1210
+ case DomainPropertyKind:
1211
+ this.removeProperty(key)
1212
+ break
1213
+ case DomainAssociationKind:
1214
+ this.removeAssociation(key)
1215
+ break
1216
+ default:
1217
+ throw new Error(`Unknown kind ${kind} for the object ${key}`)
1218
+ }
1219
+ }
1220
+ }